<commit_before>/*************************************************************************

MrEd interface to various garbage collectors, including the Boehm
 collector, SenoraGC, and MzScheme's precise collector.

Copyright (c) 2004-2007 PLT Scheme Inc.

*************************************************************************/

/*************************************************************************
Based On:

Copyright (c) 1994 by Xerox Corporation.  All rights reserved.

THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.

    Last modified on Sat Nov 19 19:31:14 PST 1994 by ellis
                  on Sat Jun  8 15:10:00 PST 1994 by boehm

Permission is hereby granted to copy this code for any purpose,
provided the above notices are retained on all copies.

Authors: John R. Ellis and Jesse Hull

**************************************************************************/
/* Boehm, December 20, 1994 7:26 pm PST */

#include <stddef.h>
#include "wxGC.h"

/* With extensions, or with x86 Mac OS X, MrEd's `new' gets used by
   libraries that shouldn't use it. So we can't define `new' on that
   platform. For PPC, we define `new' and `delete' to use malloc() and
   free(); for some reason, linking fails in Mac OS X 10.3 if we just
   omit `new' and `delete'. There should be no problem under Windows,
   due to the way DLL linking works. */

#ifndef wx_msw
# if defined(OS_X) && defined(__POWERPC__)
#  define MALLOC_FOR_BUILTIN_NEW
#  include <stdio.h>
#  include <stdlib.h>
# else
#  define DONT_DEFINE_BUILTIN_NEW
# endif
#endif

#ifdef COMPACT_BACKTRACE_GC
# include <stdio.h>
#endif

#ifdef MPW_CPLUS
extern "C" {
  typedef void (*GC_F_PTR)(void *, void *);
}
# define CAST_GCP (GC_F_PTR)
# define CAST_GCPP (GC_F_PTR *)
#else
# define CAST_GCP /* empty */
# define CAST_GCPP /* empty */
#endif

#ifdef USE_SENORA_GC
struct GC_Set *cpp_objects;
typedef void (*GC_finalization_proc)(void *, void *);
#if SGC_STD_DEBUGGING
# define USE_WXOBJECT_TRACE_COUNTER
#endif
#endif

#ifndef DONT_DEFINE_BUILTIN_NEW

void *operator new(size_t size)
{
#ifdef MALLOC_FOR_BUILTIN_NEW
  return malloc(size);
#else
# ifdef USE_SENORA_GC
  if (!cpp_objects)
    cpp_objects = GC_new_set("C++", NULL, NULL, NULL, NULL, NULL, 0);

  return GC_malloc_specific(size, cpp_objects);
# else
  return GC_malloc(size);
#endif
#endif
}

void operator delete(void *obj)
{
#ifdef MALLOC_FOR_BUILTIN_NEW
  free(obj);
#endif
}

#endif

void gc_cleanup::install_cleanup(void)
{
  GC_finalization_proc old_fn;
  void *old_data;

# ifdef MZ_PRECISE_GC
#  define ALLOW_NON_BASE 0
#  define CHECK_BASE 0
# else
#  ifdef wx_xt
#   define ALLOW_NON_BASE 0
#   define CHECK_BASE 0
#  else
#   ifdef WIN32
#    define ALLOW_NON_BASE 0
#    define CHECK_BASE 1
#    define CRASH_ON_NONBASE 1
#   else
#    define ALLOW_NON_BASE 1
#    define CHECK_BASE 0
#   endif
#  endif
# endif

# if CHECK_BASE || ALLOW_NON_BASE
  if (GC_base(this) != (void *)this) {
#  if ALLOW_NON_BASE
    return;
#  else
#   ifdef CRASH_ON_NONBASE
    *(long *)0x0 = 1;
#   else
    printf("Clean-up object is not the base object\n");
    abort();
#   endif
#  endif
  }
# endif

  GC_register_finalizer_ignore_self(gcOBJ_TO_PTR(this),
				    CAST_GCP GC_cleanup, NULL,
				    CAST_GCPP &old_fn, &old_data);

# if CHECK_BASE
  if (old_fn) {
#  ifdef CRASH_ON_NONBASE
	*(long *)0x0 = 1;
#  else
    printf("Object already has a clean-up\n");
    abort();
#  endif
  }
# endif
}

#define SHOW_CLEANUP_TIMES 0

#if SHOW_CLEANUP_TIMES
extern "C" long scheme_get_process_milliseconds();
#endif

void GC_cleanup(void *obj, void *)
{
  gc *clean = (gc *)gcPTR_TO_OBJ(obj);

#ifdef MZ_PRECISE_GC
# ifdef COMPACT_BACKTRACE_GC
#  if SHOW_CLEANUP_TIMES
  long start;
  start = scheme_get_process_milliseconds();
  char *s;
  s = clean->gcGetName();
  printf("Cleanup: %s\n", s ? s : "???");
#  endif
# endif

  GC_cpp_delete(clean);

# ifdef COMPACT_BACKTRACE_GC
#  if SHOW_CLEANUP_TIMES
  start = scheme_get_process_milliseconds() - start;
  printf("  done %d\n", start);
#  endif
# endif
#else
  clean->~gc();
#endif
}

/**********************************************************************/

#ifdef OPERATOR_NEW_ARRAY
# ifndef DONT_DEFINE_BUILTIN_NEW

void* operator new[](size_t size)
{
#ifdef MALLOC_FOR_BUILTIN_NEW
  return malloc(size);
#else
# ifdef USE_SENORA_GC
  if (!cpp_objects)
    cpp_objects = GC_new_set("C++", NULL, NULL, NULL, NULL, NULL, 0);

  return GC_malloc_specific(size, cpp_objects);
# else
  return GC_malloc(size);
# endif
#endif
}

void operator delete[](void *obj)
{
#ifdef MALLOC_FOR_BUILTIN_NEW
  free(obj);
#endif
}

# endif
#endif

/**********************************************************************/

#ifdef USE_SENORA_GC

struct GC_Set *wx_objects;

# ifdef USE_WXOBJECT_TRACE_COUNTER
extern void wxTraceCount(void *, int);
extern void wxTracePath(void *, unsigned long, void *);
extern void wxTraceInit(void);
extern void wxTraceDone(void);
extern void wxObjectFinalize(void *);
# endif

void *GC_cpp_malloc(size_t size)
{
  if (!wx_objects)
    wx_objects = GC_new_set("wxObjects",
# ifdef USE_WXOBJECT_TRACE_COUNTER
			    wxTraceInit,
			    wxTraceDone,
			    wxTraceCount,
			    wxTracePath,
			    wxObjectFinalize,
# else
			    NULL, NULL, NULL, NULL, NULL,
# endif
			    0);

  return GC_malloc_specific(size, wx_objects);
}

# ifdef SGC_STD_DEBUGGING

void GC_cpp_for_each(void (*f)(void *, int, void *), void *data)
{
  if (wx_objects)
    GC_for_each_element(wx_objects, f, data);
}

int GC_is_wx_object(void *v)
{
  return wx_objects && (GC_set(v) == wx_objects);
}

# endif

#endif

/**********************************************************************/

#ifdef MZ_PRECISE_GC

# define ZERO_OUT_DISPATCH 1

# ifdef COMPACT_BACKTRACE_GC
static char *get_xtagged_name(void *p);
extern char *(*GC_get_xtagged_name)(void *p);
# endif

typedef struct {
  short tag;
  short filler_used_for_hashing;
  void *val;
} GC_WB;

void *GC_weak_box_val(void *b)
{
  return ((GC_WB *)b)->val;
}

#include "scheme.h"

static void mark_cpp_object(void *p)
{
  gc *obj = (gc *)p;

#if ZERO_OUT_DISPATCH
  if (*(long *)obj)
#endif
    obj->gcMark();
}

static void fixup_cpp_object(void *p)
{
  gc *obj = (gc *)p;

#if ZERO_OUT_DISPATCH
  if (*(long *)obj)
#endif
    obj->gcFixup();
}

static int is_initialized;

static void initize(void)
{
  /* Initialize: */
  GC_mark_xtagged = mark_cpp_object;
  GC_fixup_xtagged = fixup_cpp_object;

# ifdef COMPACT_BACKTRACE_GC
  GC_get_xtagged_name = get_xtagged_name;
# endif

  is_initialized = 1;
}

void *GC_cpp_malloc(size_t size)
{
  void *p;

  if (!is_initialized)
    initize();

  p = GC_malloc_one_xtagged(size);

  return p;
}

void GC_cpp_delete(gc *v)
{
  v->~gc();
#if ZERO_OUT_DISPATCH
  ((long *)v)[0] = 0;
#endif
}

# ifdef COMPACT_BACKTRACE_GC

static char name_buffer[256];

static char *get_xtagged_name(void *p)
{
  char *s;
  s = ((gc *)gcPTR_TO_OBJ(p))->gcGetName();
  sprintf(name_buffer, "<%s>", (s ? s : "XTAGGED"));
  return name_buffer;
}

char *gc::gcGetName() {
  return NULL;
}

# endif

#endif

/**********************************************************************/

/* The accounting shadow serves two purposes. First, it allocates
   largely untouched atomic memory to reflect the allocation of
   bitmaps outside the GC space, so that the nominal allocation total
   is related to the total taking into accoun bitmaps. Second, because
   bitmaps are released through finalizers, the accounting shadow
   forces a GC more frequently than might otherwise happen as the
   total size of bitmaps grows. */

static long total, accum = 1024 * 1024 * 5;

void *GC_malloc_accounting_shadow(long a)
{
  long *p;
  if (a < (long)sizeof(long))
    a = sizeof(long);
  total += a;
  accum -= a;
  if (accum <= 0) {
    GC_gcollect();
    accum = total >> 1;
  }
  p = (long *)GC_malloc_atomic(a);
  *p = a;
  return (void *)p;
}

void GC_free_accounting_shadow(void *p)
{
  if (p) {
    total -= *(long *)p;
    accum += *(long *)p;
  }
}
<commit_msg>fix global definition of new and new[] for windows<commit_after>/*************************************************************************

MrEd interface to various garbage collectors, including the Boehm
 collector, SenoraGC, and MzScheme's precise collector.

Copyright (c) 2004-2007 PLT Scheme Inc.

*************************************************************************/

/*************************************************************************
Based On:

Copyright (c) 1994 by Xerox Corporation.  All rights reserved.

THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.

    Last modified on Sat Nov 19 19:31:14 PST 1994 by ellis
                  on Sat Jun  8 15:10:00 PST 1994 by boehm

Permission is hereby granted to copy this code for any purpose,
provided the above notices are retained on all copies.

Authors: John R. Ellis and Jesse Hull

**************************************************************************/
/* Boehm, December 20, 1994 7:26 pm PST */

#include <stddef.h>
#include "wxGC.h"

/* With extensions, or with x86 Mac OS X, MrEd's `new' gets used by
   libraries that shouldn't use it. So we can't define `new' on that
   platform. For PPC, we define `new' and `delete' to use malloc() and
   free(); for some reason, linking fails in Mac OS X 10.3 if we just
   omit `new' and `delete'. There should be no problem under Windows,
   due to the way DLL linking works. */

#ifndef WIN32
# if defined(OS_X) && defined(__POWERPC__)
#  define MALLOC_FOR_BUILTIN_NEW
#  include <stdio.h>
#  include <stdlib.h>
# else
#  define DONT_DEFINE_BUILTIN_NEW
# endif
#endif

#ifdef COMPACT_BACKTRACE_GC
# include <stdio.h>
#endif

#ifdef MPW_CPLUS
extern "C" {
  typedef void (*GC_F_PTR)(void *, void *);
}
# define CAST_GCP (GC_F_PTR)
# define CAST_GCPP (GC_F_PTR *)
#else
# define CAST_GCP /* empty */
# define CAST_GCPP /* empty */
#endif

#ifdef USE_SENORA_GC
struct GC_Set *cpp_objects;
typedef void (*GC_finalization_proc)(void *, void *);
#if SGC_STD_DEBUGGING
# define USE_WXOBJECT_TRACE_COUNTER
#endif
#endif

#ifndef DONT_DEFINE_BUILTIN_NEW

void *operator new(size_t size)
{
#ifdef MALLOC_FOR_BUILTIN_NEW
  return malloc(size);
#else
# ifdef USE_SENORA_GC
  if (!cpp_objects)
    cpp_objects = GC_new_set("C++", NULL, NULL, NULL, NULL, NULL, 0);

  return GC_malloc_specific(size, cpp_objects);
# else
  return GC_malloc(size);
#endif
#endif
}

void operator delete(void *obj)
{
#ifdef MALLOC_FOR_BUILTIN_NEW
  free(obj);
#endif
}

#endif

void gc_cleanup::install_cleanup(void)
{
  GC_finalization_proc old_fn;
  void *old_data;

# ifdef MZ_PRECISE_GC
#  define ALLOW_NON_BASE 0
#  define CHECK_BASE 0
# else
#  ifdef wx_xt
#   define ALLOW_NON_BASE 0
#   define CHECK_BASE 0
#  else
#   ifdef WIN32
#    define ALLOW_NON_BASE 0
#    define CHECK_BASE 1
#    define CRASH_ON_NONBASE 1
#   else
#    define ALLOW_NON_BASE 1
#    define CHECK_BASE 0
#   endif
#  endif
# endif

# if CHECK_BASE || ALLOW_NON_BASE
  if (GC_base(this) != (void *)this) {
#  if ALLOW_NON_BASE
    return;
#  else
#   ifdef CRASH_ON_NONBASE
    *(long *)0x0 = 1;
#   else
    printf("Clean-up object is not the base object\n");
    abort();
#   endif
#  endif
  }
# endif

  GC_register_finalizer_ignore_self(gcOBJ_TO_PTR(this),
				    CAST_GCP GC_cleanup, NULL,
				    CAST_GCPP &old_fn, &old_data);

# if CHECK_BASE
  if (old_fn) {
#  ifdef CRASH_ON_NONBASE
	*(long *)0x0 = 1;
#  else
    printf("Object already has a clean-up\n");
    abort();
#  endif
  }
# endif
}

#define SHOW_CLEANUP_TIMES 0

#if SHOW_CLEANUP_TIMES
extern "C" long scheme_get_process_milliseconds();
#endif

void GC_cleanup(void *obj, void *)
{
  gc *clean = (gc *)gcPTR_TO_OBJ(obj);

#ifdef MZ_PRECISE_GC
# ifdef COMPACT_BACKTRACE_GC
#  if SHOW_CLEANUP_TIMES
  long start;
  start = scheme_get_process_milliseconds();
  char *s;
  s = clean->gcGetName();
  printf("Cleanup: %s\n", s ? s : "???");
#  endif
# endif

  GC_cpp_delete(clean);

# ifdef COMPACT_BACKTRACE_GC
#  if SHOW_CLEANUP_TIMES
  start = scheme_get_process_milliseconds() - start;
  printf("  done %d\n", start);
#  endif
# endif
#else
  clean->~gc();
#endif
}

/**********************************************************************/

#ifdef OPERATOR_NEW_ARRAY
# ifndef DONT_DEFINE_BUILTIN_NEW

void* operator new[](size_t size)
{
#ifdef MALLOC_FOR_BUILTIN_NEW
  return malloc(size);
#else
# ifdef USE_SENORA_GC
  if (!cpp_objects)
    cpp_objects = GC_new_set("C++", NULL, NULL, NULL, NULL, NULL, 0);

  return GC_malloc_specific(size, cpp_objects);
# else
  return GC_malloc(size);
# endif
#endif
}

void operator delete[](void *obj)
{
#ifdef MALLOC_FOR_BUILTIN_NEW
  free(obj);
#endif
}

# endif
#endif

/**********************************************************************/

#ifdef USE_SENORA_GC

struct GC_Set *wx_objects;

# ifdef USE_WXOBJECT_TRACE_COUNTER
extern void wxTraceCount(void *, int);
extern void wxTracePath(void *, unsigned long, void *);
extern void wxTraceInit(void);
extern void wxTraceDone(void);
extern void wxObjectFinalize(void *);
# endif

void *GC_cpp_malloc(size_t size)
{
  if (!wx_objects)
    wx_objects = GC_new_set("wxObjects",
# ifdef USE_WXOBJECT_TRACE_COUNTER
			    wxTraceInit,
			    wxTraceDone,
			    wxTraceCount,
			    wxTracePath,
			    wxObjectFinalize,
# else
			    NULL, NULL, NULL, NULL, NULL,
# endif
			    0);

  return GC_malloc_specific(size, wx_objects);
}

# ifdef SGC_STD_DEBUGGING

void GC_cpp_for_each(void (*f)(void *, int, void *), void *data)
{
  if (wx_objects)
    GC_for_each_element(wx_objects, f, data);
}

int GC_is_wx_object(void *v)
{
  return wx_objects && (GC_set(v) == wx_objects);
}

# endif

#endif

/**********************************************************************/

#ifdef MZ_PRECISE_GC

# define ZERO_OUT_DISPATCH 1

# ifdef COMPACT_BACKTRACE_GC
static char *get_xtagged_name(void *p);
extern char *(*GC_get_xtagged_name)(void *p);
# endif

typedef struct {
  short tag;
  short filler_used_for_hashing;
  void *val;
} GC_WB;

void *GC_weak_box_val(void *b)
{
  return ((GC_WB *)b)->val;
}

#include "scheme.h"

static void mark_cpp_object(void *p)
{
  gc *obj = (gc *)p;

#if ZERO_OUT_DISPATCH
  if (*(long *)obj)
#endif
    obj->gcMark();
}

static void fixup_cpp_object(void *p)
{
  gc *obj = (gc *)p;

#if ZERO_OUT_DISPATCH
  if (*(long *)obj)
#endif
    obj->gcFixup();
}

static int is_initialized;

static void initize(void)
{
  /* Initialize: */
  GC_mark_xtagged = mark_cpp_object;
  GC_fixup_xtagged = fixup_cpp_object;

# ifdef COMPACT_BACKTRACE_GC
  GC_get_xtagged_name = get_xtagged_name;
# endif

  is_initialized = 1;
}

void *GC_cpp_malloc(size_t size)
{
  void *p;

  if (!is_initialized)
    initize();

  p = GC_malloc_one_xtagged(size);

  return p;
}

void GC_cpp_delete(gc *v)
{
  v->~gc();
#if ZERO_OUT_DISPATCH
  ((long *)v)[0] = 0;
#endif
}

# ifdef COMPACT_BACKTRACE_GC

static char name_buffer[256];

static char *get_xtagged_name(void *p)
{
  char *s;
  s = ((gc *)gcPTR_TO_OBJ(p))->gcGetName();
  sprintf(name_buffer, "<%s>", (s ? s : "XTAGGED"));
  return name_buffer;
}

char *gc::gcGetName() {
  return NULL;
}

# endif

#endif

/**********************************************************************/

/* The accounting shadow serves two purposes. First, it allocates
   largely untouched atomic memory to reflect the allocation of
   bitmaps outside the GC space, so that the nominal allocation total
   is related to the total taking into accoun bitmaps. Second, because
   bitmaps are released through finalizers, the accounting shadow
   forces a GC more frequently than might otherwise happen as the
   total size of bitmaps grows. */

static long total, accum = 1024 * 1024 * 5;

void *GC_malloc_accounting_shadow(long a)
{
  long *p;
  if (a < (long)sizeof(long))
    a = sizeof(long);
  total += a;
  accum -= a;
  if (accum <= 0) {
    GC_gcollect();
    accum = total >> 1;
  }
  p = (long *)GC_malloc_atomic(a);
  *p = a;
  return (void *)p;
}

void GC_free_accounting_shadow(void *p)
{
  if (p) {
    total -= *(long *)p;
    accum += *(long *)p;
  }
}
<|endoftext|>


<commit_before>#include "oniguruma.h"
#include "onig-scanner.h"
#include "onig-reg-exp.h"
#include "onig-result.h"

using namespace v8;

void OnigScanner::Init(Handle<Object> target) {
  Local<FunctionTemplate> tpl = FunctionTemplate::New(OnigScanner::New);
  tpl->SetClassName(v8::String::NewSymbol("OnigScanner"));
  tpl->InstanceTemplate()->SetInternalFieldCount(1);
  tpl->PrototypeTemplate()->Set(v8::String::NewSymbol("findNextMatch"), FunctionTemplate::New(OnigScanner::FindNextMatch)->GetFunction());

  Persistent<Function> constructor = Persistent<Function>::New(tpl->GetFunction());
  target->Set(v8::String::NewSymbol("OnigScanner"), constructor);
}

NODE_MODULE(onig_scanner, OnigScanner::Init)

Handle<Value> OnigScanner::New(const Arguments& args) {
  HandleScope scope;
  OnigScanner* scanner = new OnigScanner(Local<Array>::Cast(args[0]));
  scanner->Wrap(args.This());
  return args.This();
}

Handle<Value> OnigScanner::FindNextMatch(const Arguments& args) {
  HandleScope scope;
  OnigScanner* scanner = node::ObjectWrap::Unwrap<OnigScanner>(args.This());
  return scope.Close(scanner->FindNextMatch(Local<String>::Cast(args[0]), Local<Number>::Cast(args[1])));
}

OnigScanner::OnigScanner(Handle<Array> sources) {
  int length = sources->Length();
  regExps.resize(length);
  cachedResults.resize(length);

  for (int i = 0; i < length; i++) {
    String::Utf8Value utf8Value(sources->Get(i));
    regExps[i] = std::unique_ptr<OnigRegExp>(new OnigRegExp(std::string(*utf8Value)));
  }
};

OnigScanner::~OnigScanner() {};

Handle<Value> OnigScanner::FindNextMatch(Handle<String> v8String, Handle<Number> v8StartLocation) {
  String::Utf8Value utf8Value(v8String);
  std::string string(*utf8Value);
  int startLocation = v8StartLocation->Value();
  int bestIndex = -1;
  int bestLocation = NULL;
  OnigResult* bestResult = NULL;

  bool useCachedResults = (string == lastMatchedString && startLocation >= lastStartLocation);
  lastStartLocation = startLocation;

  if (!useCachedResults) {
    ClearCachedResults();
    lastMatchedString = string;
  }

  std::vector<std::unique_ptr<OnigRegExp>>::iterator iter = regExps.begin();
  int index = 0;
  while (iter < regExps.end()) {
    OnigRegExp *regExp = (*iter).get();

    bool useCachedResult = false;
    OnigResult *result = nullptr;

    // In Oniguruma, \G is based on the start position of the match, so the result
    // changes based on the start position. So it can't be cached.
    bool containsBackslashG = regExp->Contains("\\G");
    if (useCachedResults && index <= maxCachedIndex && ! containsBackslashG) {
      result = cachedResults[index].get();
      useCachedResult = (result == NULL || result->LocationAt(0) >= startLocation);
    }

    if (!useCachedResult) {
      result = regExp->Search(string, startLocation);
      cachedResults[index] = std::unique_ptr<OnigResult>(result);
      maxCachedIndex = index;
    }

    if (result && result->Count() > 0) {
      int location = result->LocationAt(0);
      if (bestIndex == -1 || location < bestLocation) {
        bestLocation = location;
        bestResult = result;
        bestIndex = index;
      }

      if (location == startLocation) {
        break;
      }
    }

    iter++;
    index++;
  }

  if (bestIndex >= 0) {
    Local<Object> result = Object::New();
    result->Set(String::NewSymbol("index"), Number::New(bestIndex));
    result->Set(String::NewSymbol("captureIndices"), CaptureIndicesForMatch(bestResult));
    return result;
  }
  else {
    return Null();
  }
}

void OnigScanner::ClearCachedResults() {
  maxCachedIndex = -1;
  cachedResults.clear();
}

Handle<Value> OnigScanner::CaptureIndicesForMatch(OnigResult* result) {
  int resultCount = result->Count();
  Local<Array> array = Array::New(resultCount * 3);
  int i = 0;
  for (int index = 0; index < resultCount; index++) {
    int captureLength = result->LengthAt(index);
    int captureStart = result->LocationAt(index);

    array->Set(i++, Number::New(index));
    array->Set(i++, Number::New(captureStart));
    array->Set(i++, Number::New(captureStart + captureLength));
  }

  return array;
}
<commit_msg>Use std namespace<commit_after>#include "oniguruma.h"
#include "onig-scanner.h"
#include "onig-reg-exp.h"
#include "onig-result.h"

using namespace v8;
using namespace std;

void OnigScanner::Init(Handle<Object> target) {
  Local<FunctionTemplate> tpl = FunctionTemplate::New(OnigScanner::New);
  tpl->SetClassName(v8::String::NewSymbol("OnigScanner"));
  tpl->InstanceTemplate()->SetInternalFieldCount(1);
  tpl->PrototypeTemplate()->Set(v8::String::NewSymbol("findNextMatch"), FunctionTemplate::New(OnigScanner::FindNextMatch)->GetFunction());

  Persistent<Function> constructor = Persistent<Function>::New(tpl->GetFunction());
  target->Set(v8::String::NewSymbol("OnigScanner"), constructor);
}

NODE_MODULE(onig_scanner, OnigScanner::Init)

Handle<Value> OnigScanner::New(const Arguments& args) {
  HandleScope scope;
  OnigScanner* scanner = new OnigScanner(Local<Array>::Cast(args[0]));
  scanner->Wrap(args.This());
  return args.This();
}

Handle<Value> OnigScanner::FindNextMatch(const Arguments& args) {
  HandleScope scope;
  OnigScanner* scanner = node::ObjectWrap::Unwrap<OnigScanner>(args.This());
  return scope.Close(scanner->FindNextMatch(Local<String>::Cast(args[0]), Local<Number>::Cast(args[1])));
}

OnigScanner::OnigScanner(Handle<Array> sources) {
  int length = sources->Length();
  regExps.resize(length);
  cachedResults.resize(length);

  for (int i = 0; i < length; i++) {
    String::Utf8Value utf8Value(sources->Get(i));
    regExps[i] = unique_ptr<OnigRegExp>(new OnigRegExp(string(*utf8Value)));
  }
};

OnigScanner::~OnigScanner() {};

Handle<Value> OnigScanner::FindNextMatch(Handle<String> v8String, Handle<Number> v8StartLocation) {
  String::Utf8Value utf8Value(v8String);
  string string(*utf8Value);
  int startLocation = v8StartLocation->Value();
  int bestIndex = -1;
  int bestLocation = NULL;
  OnigResult* bestResult = NULL;

  bool useCachedResults = (string == lastMatchedString && startLocation >= lastStartLocation);
  lastStartLocation = startLocation;

  if (!useCachedResults) {
    ClearCachedResults();
    lastMatchedString = string;
  }

  vector<unique_ptr<OnigRegExp>>::iterator iter = regExps.begin();
  int index = 0;
  while (iter < regExps.end()) {
    OnigRegExp *regExp = (*iter).get();

    bool useCachedResult = false;
    OnigResult *result = nullptr;

    // In Oniguruma, \G is based on the start position of the match, so the result
    // changes based on the start position. So it can't be cached.
    bool containsBackslashG = regExp->Contains("\\G");
    if (useCachedResults && index <= maxCachedIndex && ! containsBackslashG) {
      result = cachedResults[index].get();
      useCachedResult = (result == NULL || result->LocationAt(0) >= startLocation);
    }

    if (!useCachedResult) {
      result = regExp->Search(string, startLocation);
      cachedResults[index] = unique_ptr<OnigResult>(result);
      maxCachedIndex = index;
    }

    if (result && result->Count() > 0) {
      int location = result->LocationAt(0);
      if (bestIndex == -1 || location < bestLocation) {
        bestLocation = location;
        bestResult = result;
        bestIndex = index;
      }

      if (location == startLocation) {
        break;
      }
    }

    iter++;
    index++;
  }

  if (bestIndex >= 0) {
    Local<Object> result = Object::New();
    result->Set(String::NewSymbol("index"), Number::New(bestIndex));
    result->Set(String::NewSymbol("captureIndices"), CaptureIndicesForMatch(bestResult));
    return result;
  }
  else {
    return Null();
  }
}

void OnigScanner::ClearCachedResults() {
  maxCachedIndex = -1;
  cachedResults.clear();
}

Handle<Value> OnigScanner::CaptureIndicesForMatch(OnigResult* result) {
  int resultCount = result->Count();
  Local<Array> array = Array::New(resultCount * 3);
  int i = 0;
  for (int index = 0; index < resultCount; index++) {
    int captureLength = result->LengthAt(index);
    int captureStart = result->LocationAt(index);

    array->Set(i++, Number::New(index));
    array->Set(i++, Number::New(captureStart));
    array->Set(i++, Number::New(captureStart + captureLength));
  }

  return array;
}
<|endoftext|>


<commit_before>/* -*- mode: C++; c-basic-offset: 4; -*- */
/* ex: set shiftwidth=4 tabstop=4 expandtab: */
/*
 * Copyright (c) 2016, Rice University
 * All rights reserved.
 *
 * Author(s): Neil T. Dantam <ntd@rice.edu>
 *
 *   Redistribution and use in source and binary forms, with or
 *   without modification, are permitted provided that the following
 *   conditions are met:
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of copyright holder the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 *   CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 *   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 *   MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 *   DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 *   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 *   USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 *   AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *   ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *   POSSIBILITY OF SUCH DAMAGE.
 *
 */

#include "amino.h"
//#include "amino/opt/lp.h"
#include "amino/opt/opt.h"
#include "opt_internal.h"

#include <coin/ClpSimplex.hpp>

typedef ClpSimplex SolverType;

int s_solve( struct aa_opt_cx *cx, size_t n, double *x )
{
    SolverType * M = static_cast<SolverType*>(cx->data);

    /* Solve */
    int r;

    try {
        r = M->initialSolve();
    } catch (CoinError e) {
        e.print();
        return -1;
    } catch(...) {
        return -1;
    }

    /* Result */
    AA_MEM_CPY( x, M->getColSolution(), n );

    return r;
}
int s_destroy( struct aa_opt_cx *cx )
{
    if( cx ) {
        SolverType * M = static_cast<SolverType*>(cx->data);
        if( M ) {
            delete M;
        }
        free(cx);
    }
    return 0;
}

static int
s_set_direction( struct aa_opt_cx *cx, enum aa_opt_direction dir )
{
    SolverType * M = static_cast<SolverType*>(cx->data);
    switch(dir) {
    case AA_OPT_MAXIMIZE:
        M->setOptimizationDirection( -1 );
        return 0;
    case AA_OPT_MINIMIZE:
        M->setOptimizationDirection( 1 );
        return 0;
    }
    return -1;
}

static int s_set_quad_obj_crs( struct aa_opt_cx *cx,
                               size_t n, const double *Q_values, int *Q_cols, int *Q_row_ptr )
{
    //int ni = (int)n;
    // std::vector<int> Q_rows;
    // for( int i = 0; i < ni; i ++ ) {
    //     int k0 = Q_row_ptr[i];
    //     int k1 = Q_row_ptr[i+1];
    //     for( int k = k0; k < k1; k++ ) {
    //         Q_rows.push_back(i);
    //     }
    // }

    // CoinPackedMatrix Q( false, &Q_rows[0], Q_cols, Q_values, (int)Q_rows.size() );

    // Q.dumpMatrix();

    //SolverType * M = static_cast<SolverType*>(cx->data);
    //int n = M->getNumCols();

    // for( int j = 0; j < ni; j ++ ) {
    //     int i0 = Q_row_ptr[j];
    //     int i1 = Q_row_ptr[j+1];
    //     fprintf(stderr, "%d: %d, %d\n", j, i0, i1 );
    //     if( i1 > i0 ) {
    //         Q.appendRow( i1-i0, Q_cols+i0, Q_values+i0 );
    //     }
    // }

    // M->loadQuadraticObjective(Q);
    // M->loadQuadraticObjective( (int)n, Q_row_ptr, Q_cols, Q_values );

    // return 0;
    return -1;
}

static int s_set_type( struct aa_opt_cx *cx, size_t i, enum aa_opt_type type ) {
    return -1;
}

static int
s_set_obj( struct aa_opt_cx *cx, size_t n, const double * c)
{
    SolverType * M = static_cast<SolverType*>(cx->data);
    int ni = (int) n;
    for( int i = 0; i < ni; i ++ ) {
        M->setObjectiveCoefficient( i, c[i] );
    }
    return 0;
}

static int
s_set_bnd( struct aa_opt_cx *cx, size_t n,
           const double * x_min, const double *x_max)
{
    SolverType * M = static_cast<SolverType*>(cx->data);
    int ni = (int) n;
    for( int i = 0; i < ni; i ++ ) {
        double lo = x_min[i];
        double hi = x_max[i];
        M->setColumnBounds( i,
                            aa_isfinite(lo) ? lo : -DBL_MAX,
                            aa_isfinite(hi) ? hi : DBL_MAX );
    }
    return 0;
}

static int
s_set_cstr_mat_gm( struct aa_opt_cx *cx,
                   size_t m, size_t n,
                   const double *A, size_t lda )
{
    SolverType * M = static_cast<SolverType*>(cx->data);
    int mi = (int) m;
    int ni = (int) n;
    for( int j = 0; j < ni; j ++ ) {
        for( int i = 0; i < mi; i ++ ) {
            M->modifyCoefficient( i, j, AA_MATREF(A,lda, i,j) );
        }
    }
    return 0;
}

static int
s_set_cstr_bnd( struct aa_opt_cx *cx, size_t m,
                const double * b_min, const double *b_max )
{
    SolverType * M = static_cast<SolverType*>(cx->data);
    int mi = (int) m;
    for( int i = 0; i < mi; i ++ ) {
        double lo = b_min[i];
        double hi = b_max[i];
        M->setRowBounds(i,
                        aa_isfinite(lo) ? lo : -DBL_MAX,
                        aa_isfinite(hi) ? hi : DBL_MAX );
    }
}

static int
s_set_cstr_gm( struct aa_opt_cx *cx,
               size_t m, size_t n,
               const double *A, size_t lda,
               const double *b_lower, const double *b_upper )
{
    s_set_cstr_mat_gm( cx, m, n, A, lda );
    s_set_cstr_bnd( cx, m, b_lower, b_upper );
    return 0;
}

static struct aa_opt_vtab s_vtab = {
    .solve = s_solve,
    .destroy = s_destroy,
    .set_direction = s_set_direction,
    .set_quad_obj_crs = s_set_quad_obj_crs,
    .set_type = s_set_type,
    .set_obj = s_set_obj,
    .set_bnd = s_set_bnd,
    .set_cstr_gm = s_set_cstr_gm
};

// AA_API struct aa_opt_cx* aa_opt_clp_gmcreate (
//     size_t m, size_t n,
//     const double *A, size_t ldA,
//     const double *b_lower, const double *b_upper,
//     const double *c,
//     const double *x_lower, const double *x_upper
//     )
// {

//     ClpSimplex *pM = new ClpSimplex();
//     ClpSimplex &M = *pM;
//     pM->setLogLevel(0); // shut up

//     int rows[m];
//     int mi = (int)m;
//     int ni = (int)n;
//     M.resize(mi,0);

//     for( int i = 0; i < mi; i ++ ) rows[i] = i;

//     /* A, c, l, u */
//     for( size_t j = 0; j < n; j ++ ) {
//         M.addColumn( mi, rows,
//                      AA_MATCOL(A,ldA,j),
//                      x_lower[j], x_upper[j], c[j] );
//     }

//     /* b */
//     for( int i = 0; i < mi; i ++ ) {
//         M.setRowBounds(i,b_lower[i],b_upper[i]);
//     }

//     M.setOptimizationDirection( -1 );

//     return cx_finish( &s_vtab, pM );
// }

AA_API struct aa_opt_cx* aa_opt_clp_gmcreate (
    size_t m, size_t n,
    const double *A, size_t ldA,
    const double *b_lower, const double *b_upper,
    const double *c,
    const double *x_lower, const double *x_upper
    )
{
    ClpSimplex *pM = new ClpSimplex();
    ClpSimplex &M = *pM;

    struct aa_opt_cx *cx = cx_finish( &s_vtab, pM );

    pM->setLogLevel(0); // shut up

    int mi = (int)m;
    int ni = (int)n;
    M.resize(mi,0);

    /* A, c, l, u */
    int rows[m];
    for( int i = 0; i < mi; i ++ ) rows[i] = i;
    // TODO: is there a better way to initialize?
    for( size_t j = 0; j < n; j ++ ) {
        M.addColumn( mi, rows,
                     AA_MATCOL(A,ldA,j),
                     x_lower[j], x_upper[j], c[j] );
    }
    // s_set_cstr_gm( cx, m, n, A, ldA );

    s_set_bnd( cx, n, x_lower, x_upper );
    s_set_obj( cx, n, c );

    s_set_cstr_bnd( cx, m, b_lower, b_upper );

    M.setOptimizationDirection( -1 );

    return cx;
}

AA_API struct aa_opt_cx* aa_opt_clp_crscreate (
    size_t m, size_t n,
    const double *A_values, int *A_cols, int *A_row_ptr,
    const double *b_lower, const double *b_upper,
    const double *c,
    const double *x_lower, const double *x_upper )
{
    ClpSimplex *pM = new ClpSimplex();
    ClpSimplex &M = *pM;
    int rows[m];
    int mi = (int)m;
    int ni = (int)n;
    M.resize(0,ni);

    /* A, b */
    for( int i = 0; i < mi; i ++ ) {
        int start = A_row_ptr[i];
        int end = A_row_ptr[i + 1];
        M.addRow( end - start,
                  A_cols+start,
                  A_values+start,
                  b_lower[i],
                  b_upper[i] );
    }

    /* c, xl, xu */
    M.chgColumnLower(x_lower);
    M.chgColumnUpper(x_upper);
    M.chgObjCoefficients(c);

    /* Solve */
    M.setOptimizationDirection( -1 );

    return cx_finish( &s_vtab, pM );
}

int aa_opt_lp_clp (
    size_t m, size_t n,
    const double *A, size_t ldA,
    const double *b_lower, const double *b_upper,
    const double *c,
    const double *x_lower, const double *x_upper,
    double *x )
{

    struct aa_opt_cx *cx = aa_opt_clp_gmcreate( m, n,
                                                A, ldA,
                                                b_lower, b_upper,
                                                c,
                                                x_lower, x_upper );
    int r = aa_opt_solve( cx, n, x);
    aa_opt_destroy(cx);

    return r;
}

AA_API int aa_opt_lp_crs_clp (
    size_t m, size_t n,
    const double *A_values, int *A_cols, int *A_row_ptr,
    const double *b_lower, const double *b_upper,
    const double *c,
    const double *x_lower, const double *x_upper,
    double *x )
{
    struct aa_opt_cx *cx = aa_opt_clp_crscreate( m, n,
                                                 A_values, A_cols, A_row_ptr,
                                                 b_lower, b_upper,
                                                 c,
                                                 x_lower, x_upper );
    int r = aa_opt_solve( cx, n, x);
    aa_opt_destroy(cx);

    return r;
}
<commit_msg>Fix return within CLP bindings<commit_after>/* -*- mode: C++; c-basic-offset: 4; -*- */
/* ex: set shiftwidth=4 tabstop=4 expandtab: */
/*
 * Copyright (c) 2016, Rice University
 * All rights reserved.
 *
 * Author(s): Neil T. Dantam <ntd@rice.edu>
 *
 *   Redistribution and use in source and binary forms, with or
 *   without modification, are permitted provided that the following
 *   conditions are met:
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of copyright holder the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 *   CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 *   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 *   MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 *   DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 *   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 *   USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 *   AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *   ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *   POSSIBILITY OF SUCH DAMAGE.
 *
 */

#include "amino.h"
//#include "amino/opt/lp.h"
#include "amino/opt/opt.h"
#include "opt_internal.h"

#include <coin/ClpSimplex.hpp>

typedef ClpSimplex SolverType;

int s_solve( struct aa_opt_cx *cx, size_t n, double *x )
{
    SolverType * M = static_cast<SolverType*>(cx->data);

    /* Solve */
    int r;

    try {
        r = M->initialSolve();
    } catch (CoinError e) {
        e.print();
        return -1;
    } catch(...) {
        return -1;
    }

    /* Result */
    AA_MEM_CPY( x, M->getColSolution(), n );

    return r;
}
int s_destroy( struct aa_opt_cx *cx )
{
    if( cx ) {
        SolverType * M = static_cast<SolverType*>(cx->data);
        if( M ) {
            delete M;
        }
        free(cx);
    }
    return 0;
}

static int
s_set_direction( struct aa_opt_cx *cx, enum aa_opt_direction dir )
{
    SolverType * M = static_cast<SolverType*>(cx->data);
    switch(dir) {
    case AA_OPT_MAXIMIZE:
        M->setOptimizationDirection( -1 );
        return 0;
    case AA_OPT_MINIMIZE:
        M->setOptimizationDirection( 1 );
        return 0;
    }
    return -1;
}

static int s_set_quad_obj_crs( struct aa_opt_cx *cx,
                               size_t n, const double *Q_values, int *Q_cols, int *Q_row_ptr )
{
    //int ni = (int)n;
    // std::vector<int> Q_rows;
    // for( int i = 0; i < ni; i ++ ) {
    //     int k0 = Q_row_ptr[i];
    //     int k1 = Q_row_ptr[i+1];
    //     for( int k = k0; k < k1; k++ ) {
    //         Q_rows.push_back(i);
    //     }
    // }

    // CoinPackedMatrix Q( false, &Q_rows[0], Q_cols, Q_values, (int)Q_rows.size() );

    // Q.dumpMatrix();

    //SolverType * M = static_cast<SolverType*>(cx->data);
    //int n = M->getNumCols();

    // for( int j = 0; j < ni; j ++ ) {
    //     int i0 = Q_row_ptr[j];
    //     int i1 = Q_row_ptr[j+1];
    //     fprintf(stderr, "%d: %d, %d\n", j, i0, i1 );
    //     if( i1 > i0 ) {
    //         Q.appendRow( i1-i0, Q_cols+i0, Q_values+i0 );
    //     }
    // }

    // M->loadQuadraticObjective(Q);
    // M->loadQuadraticObjective( (int)n, Q_row_ptr, Q_cols, Q_values );

    // return 0;
    return -1;
}

static int s_set_type( struct aa_opt_cx *cx, size_t i, enum aa_opt_type type ) {
    return -1;
}

static int
s_set_obj( struct aa_opt_cx *cx, size_t n, const double * c)
{
    SolverType * M = static_cast<SolverType*>(cx->data);
    int ni = (int) n;
    for( int i = 0; i < ni; i ++ ) {
        M->setObjectiveCoefficient( i, c[i] );
    }
    return 0;
}

static int
s_set_bnd( struct aa_opt_cx *cx, size_t n,
           const double * x_min, const double *x_max)
{
    SolverType * M = static_cast<SolverType*>(cx->data);
    int ni = (int) n;
    for( int i = 0; i < ni; i ++ ) {
        double lo = x_min[i];
        double hi = x_max[i];
        M->setColumnBounds( i,
                            aa_isfinite(lo) ? lo : -DBL_MAX,
                            aa_isfinite(hi) ? hi : DBL_MAX );
    }
    return 0;
}

static int
s_set_cstr_mat_gm( struct aa_opt_cx *cx,
                   size_t m, size_t n,
                   const double *A, size_t lda )
{
    SolverType * M = static_cast<SolverType*>(cx->data);
    int mi = (int) m;
    int ni = (int) n;
    for( int j = 0; j < ni; j ++ ) {
        for( int i = 0; i < mi; i ++ ) {
            M->modifyCoefficient( i, j, AA_MATREF(A,lda, i,j) );
        }
    }
    return 0;
}

static int
s_set_cstr_bnd( struct aa_opt_cx *cx, size_t m,
                const double * b_min, const double *b_max )
{
    SolverType * M = static_cast<SolverType*>(cx->data);
    int mi = (int) m;
    for( int i = 0; i < mi; i ++ ) {
        double lo = b_min[i];
        double hi = b_max[i];
        M->setRowBounds(i,
                        aa_isfinite(lo) ? lo : -DBL_MAX,
                        aa_isfinite(hi) ? hi : DBL_MAX );
    }
    return 0;
}

static int
s_set_cstr_gm( struct aa_opt_cx *cx,
               size_t m, size_t n,
               const double *A, size_t lda,
               const double *b_lower, const double *b_upper )
{
    s_set_cstr_mat_gm( cx, m, n, A, lda );
    s_set_cstr_bnd( cx, m, b_lower, b_upper );
    return 0;
}

static struct aa_opt_vtab s_vtab = {
    .solve = s_solve,
    .destroy = s_destroy,
    .set_direction = s_set_direction,
    .set_quad_obj_crs = s_set_quad_obj_crs,
    .set_type = s_set_type,
    .set_obj = s_set_obj,
    .set_bnd = s_set_bnd,
    .set_cstr_gm = s_set_cstr_gm
};

// AA_API struct aa_opt_cx* aa_opt_clp_gmcreate (
//     size_t m, size_t n,
//     const double *A, size_t ldA,
//     const double *b_lower, const double *b_upper,
//     const double *c,
//     const double *x_lower, const double *x_upper
//     )
// {

//     ClpSimplex *pM = new ClpSimplex();
//     ClpSimplex &M = *pM;
//     pM->setLogLevel(0); // shut up

//     int rows[m];
//     int mi = (int)m;
//     int ni = (int)n;
//     M.resize(mi,0);

//     for( int i = 0; i < mi; i ++ ) rows[i] = i;

//     /* A, c, l, u */
//     for( size_t j = 0; j < n; j ++ ) {
//         M.addColumn( mi, rows,
//                      AA_MATCOL(A,ldA,j),
//                      x_lower[j], x_upper[j], c[j] );
//     }

//     /* b */
//     for( int i = 0; i < mi; i ++ ) {
//         M.setRowBounds(i,b_lower[i],b_upper[i]);
//     }

//     M.setOptimizationDirection( -1 );

//     return cx_finish( &s_vtab, pM );
// }

AA_API struct aa_opt_cx* aa_opt_clp_gmcreate (
    size_t m, size_t n,
    const double *A, size_t ldA,
    const double *b_lower, const double *b_upper,
    const double *c,
    const double *x_lower, const double *x_upper
    )
{
    ClpSimplex *pM = new ClpSimplex();
    ClpSimplex &M = *pM;

    struct aa_opt_cx *cx = cx_finish( &s_vtab, pM );

    pM->setLogLevel(0); // shut up

    int mi = (int)m;
    int ni = (int)n;
    M.resize(mi,0);

    /* A, c, l, u */
    int rows[m];
    for( int i = 0; i < mi; i ++ ) rows[i] = i;
    // TODO: is there a better way to initialize?
    for( size_t j = 0; j < n; j ++ ) {
        M.addColumn( mi, rows,
                     AA_MATCOL(A,ldA,j),
                     x_lower[j], x_upper[j], c[j] );
    }
    // s_set_cstr_gm( cx, m, n, A, ldA );

    s_set_bnd( cx, n, x_lower, x_upper );
    s_set_obj( cx, n, c );

    s_set_cstr_bnd( cx, m, b_lower, b_upper );

    M.setOptimizationDirection( -1 );

    return cx;
}

AA_API struct aa_opt_cx* aa_opt_clp_crscreate (
    size_t m, size_t n,
    const double *A_values, int *A_cols, int *A_row_ptr,
    const double *b_lower, const double *b_upper,
    const double *c,
    const double *x_lower, const double *x_upper )
{
    ClpSimplex *pM = new ClpSimplex();
    ClpSimplex &M = *pM;
    int rows[m];
    int mi = (int)m;
    int ni = (int)n;
    M.resize(0,ni);

    /* A, b */
    for( int i = 0; i < mi; i ++ ) {
        int start = A_row_ptr[i];
        int end = A_row_ptr[i + 1];
        M.addRow( end - start,
                  A_cols+start,
                  A_values+start,
                  b_lower[i],
                  b_upper[i] );
    }

    /* c, xl, xu */
    M.chgColumnLower(x_lower);
    M.chgColumnUpper(x_upper);
    M.chgObjCoefficients(c);

    /* Solve */
    M.setOptimizationDirection( -1 );

    return cx_finish( &s_vtab, pM );
}

int aa_opt_lp_clp (
    size_t m, size_t n,
    const double *A, size_t ldA,
    const double *b_lower, const double *b_upper,
    const double *c,
    const double *x_lower, const double *x_upper,
    double *x )
{

    struct aa_opt_cx *cx = aa_opt_clp_gmcreate( m, n,
                                                A, ldA,
                                                b_lower, b_upper,
                                                c,
                                                x_lower, x_upper );
    int r = aa_opt_solve( cx, n, x);
    aa_opt_destroy(cx);

    return r;
}

AA_API int aa_opt_lp_crs_clp (
    size_t m, size_t n,
    const double *A_values, int *A_cols, int *A_row_ptr,
    const double *b_lower, const double *b_upper,
    const double *c,
    const double *x_lower, const double *x_upper,
    double *x )
{
    struct aa_opt_cx *cx = aa_opt_clp_crscreate( m, n,
                                                 A_values, A_cols, A_row_ptr,
                                                 b_lower, b_upper,
                                                 c,
                                                 x_lower, x_upper );
    int r = aa_opt_solve( cx, n, x);
    aa_opt_destroy(cx);

    return r;
}
<|endoftext|>


<commit_before>#pragma once
/*
**  Copyright (C) 2012 Aldebaran Robotics
**  See COPYING for the license
*/

#ifndef _SRC_MESSAGE_HPP_
#define _SRC_MESSAGE_HPP_

#include <qimessaging/api.hpp>
#include <qitype/anyvalue.hpp>
#include <qi/buffer.hpp>
#include <qitype/binarycodec.hpp>
#include <qitype/anyfunction.hpp>
#include <qi/types.hpp>

namespace qi {

  class MessagePrivate
  {
  public:
    typedef struct
    {
      qi::uint32_t magic;
      qi::uint32_t id;
      qi::uint32_t size;
      qi::uint16_t version;
      qi::uint8_t  flags;
      qi::uint8_t  type;
      qi::uint32_t service;
      qi::uint32_t object;
      qi::uint32_t action;
    } MessageHeader;

    MessagePrivate();
    MessagePrivate(const MessagePrivate& b);
    ~MessagePrivate();

    inline void                complete() { header.size = buffer.totalSize(); }
    inline void               *getHeader() { return reinterpret_cast<void *>(&header); }

    Buffer        buffer;
    std::string   signature;
    MessageHeader header;

    static const unsigned int magic = 0x42adde42;
  };

  class MessageAddress {
  public:
    MessageAddress()
      : messageId(0)
      , serviceId(0)
      , objectId(0)
      , functionId(0)
    {}

    MessageAddress(unsigned int messageId,
                   unsigned int serviceId,
                   unsigned int objectId,
                   unsigned int functionId)
      : messageId(messageId)
      , serviceId(serviceId)
      , objectId(objectId)
      , functionId(functionId)
    {}

    unsigned int messageId;
    unsigned int serviceId;
    unsigned int objectId;
    unsigned int functionId;
  };

  /** \class qi::Message
    * This class represent a network message
    */
  class TransportSocket;
  typedef boost::shared_ptr<TransportSocket> TransportSocketPtr;
  class ObjectHost;

  class Message {
  public:
    static unsigned int currentVersion()
    {
      return 0;
    }

    // Fixed service id numbers
    enum Service
    {
      Service_Server           = 0,
      Service_ServiceDirectory = 1,
    };

    enum GenericObject
    {
      GenericObject_None = 0,
      GenericObject_Main = 1
    };

    enum BoundObjectFunction {
      BoundObjectFunction_RegisterEvent     = 0,
      BoundObjectFunction_UnregisterEvent   = 1,
      BoundObjectFunction_MetaObject        = 2,
      BoundObjectFunction_Terminate         = 3,
      BoundObjectFunction_GetProperty       = 5,
      BoundObjectFunction_SetProperty       = 6,
      BoundObjectFunction_Properties        = 7,
      BoundObjectFunction_RegisterEventWithSignature = 8,
    };

    enum ServerFunction
    {
      ServerFunction_Connect           = 4,
    };

    enum ServiceDirectoryAction {
      ServiceDirectoryAction_Service             = 100,
      ServiceDirectoryAction_Services            = 101,
      ServiceDirectoryAction_RegisterService     = 102,
      ServiceDirectoryAction_UnregisterService   = 103,
      ServiceDirectoryAction_ServiceReady        = 104,
      ServiceDirectoryAction_UpdateServiceInfo   = 105,
      ServiceDirectoryAction_ServiceAdded        = 106,
      ServiceDirectoryAction_ServiceRemoved      = 107,
      ServiceDirectoryAction_MachineId           = 108,
    };

    enum Type
    {
      Type_None  = 0,
      // Method call, Client->Server (wait for a Type_Reply or Type_Error)
      Type_Call  = 1,
      // Method return value, Server->Client (only to answer to a Type_Call)
      Type_Reply = 2,
      // Method return error, Server->Client (only to answer to a Type_Call)
      Type_Error = 3,
      // Method call, Client->Server (No answer needed)
      Type_Post  = 4,
      // Event Server->Client
      Type_Event = 5,
      // Advertise capabilities, Server<->Client
      Type_Capability = 6,
    };
    // If flag set, payload is of type m instead of expected type
    static const unsigned int TypeFlag_DynamicPayload = 1;
    /* If flag is set, message payload also contains a type into which
     * the return value must be converted.
     * In that case, Type_DynamicPayload will be set on return message,
     * and signature will be repeated.
     * NOT IMPLEMENTED
     */
    static const unsigned int TypeFlag_ReturnType = 2;

    static const char* typeToString(Type t);
    static const char* actionToString(unsigned int action, unsigned int service);

    ~Message();
    Message();
    Message(Type type, const MessageAddress &address);
    Message(const Message &msg);
    Message &operator=(const Message &msg);

    void setAddress(const MessageAddress &address);

    void         setId(unsigned int id);
    unsigned int id() const;

    void         setVersion(qi::uint16_t type);
    unsigned int version() const;

    void         setType(Type type);
    Type         type() const;

    void         setFlags(qi::uint8_t flags);
    void         addFlags(qi::uint8_t flags);
    qi::uint8_t  flags() const;

    void         setService(qi::uint32_t service);
    unsigned int service() const;

    void         setObject(qi::uint32_t object);
    unsigned int object() const;

    void         setFunction(qi::uint32_t function);
    unsigned int function() const;

    void         setEvent(qi::uint32_t event);
    unsigned int event() const;

    unsigned int action() const;

    void          setBuffer(const Buffer &buffer);
    const Buffer &buffer() const;

    void          setError(const std::string &error);

    ///@return signature, set by setParameters() or setSignature()

    AnyReference value(const Signature &signature, const qi::TransportSocketPtr &socket) const;
    void setValue(const AutoAnyReference& value, const Signature& signature, ObjectHost* context = 0, StreamContext* streamContext = 0);
    void setValues(const std::vector<qi::AnyReference>& values, ObjectHost* context = 0, StreamContext* streamContext = 0);
    /// Convert values to \p targetSignature and assign to payload.
    void setValues(const std::vector<qi::AnyReference>& values, const qi::Signature& targetSignature, ObjectHost* context = 0, StreamContext* streamContext = 0);
    /// Append additional data to payload
    void appendValue(const AutoAnyReference& value, ObjectHost* context = 0, StreamContext* streamContext = 0);
    MessageAddress address() const;

    bool         isValid();

  public:
    boost::shared_ptr<MessagePrivate> _p;
    void         cow();
  };

  QIMESSAGING_API std::ostream& operator<<(std::ostream& os, const qi::MessageAddress &address);
  QIMESSAGING_API std::ostream& operator<<(std::ostream& os, const qi::Message& msg);
}

QI_TYPE_CONCRETE(qi::Message);

#endif  // _SRC_MESSAGE_HPP_
<commit_msg>WireProtocol: Fix reversed fields for backward compatibility.<commit_after>#pragma once
/*
**  Copyright (C) 2012 Aldebaran Robotics
**  See COPYING for the license
*/

#ifndef _SRC_MESSAGE_HPP_
#define _SRC_MESSAGE_HPP_

#include <qimessaging/api.hpp>
#include <qitype/anyvalue.hpp>
#include <qi/buffer.hpp>
#include <qitype/binarycodec.hpp>
#include <qitype/anyfunction.hpp>
#include <qi/types.hpp>

namespace qi {

  class MessagePrivate
  {
  public:
    typedef struct
    {
      qi::uint32_t magic;
      qi::uint32_t id;
      qi::uint32_t size;
      qi::uint16_t version;
      qi::uint8_t  type;
      qi::uint8_t  flags;
      qi::uint32_t service;
      qi::uint32_t object;
      qi::uint32_t action;
    } MessageHeader;

    MessagePrivate();
    MessagePrivate(const MessagePrivate& b);
    ~MessagePrivate();

    inline void                complete() { header.size = buffer.totalSize(); }
    inline void               *getHeader() { return reinterpret_cast<void *>(&header); }

    Buffer        buffer;
    std::string   signature;
    MessageHeader header;

    static const unsigned int magic = 0x42adde42;
  };

  class MessageAddress {
  public:
    MessageAddress()
      : messageId(0)
      , serviceId(0)
      , objectId(0)
      , functionId(0)
    {}

    MessageAddress(unsigned int messageId,
                   unsigned int serviceId,
                   unsigned int objectId,
                   unsigned int functionId)
      : messageId(messageId)
      , serviceId(serviceId)
      , objectId(objectId)
      , functionId(functionId)
    {}

    unsigned int messageId;
    unsigned int serviceId;
    unsigned int objectId;
    unsigned int functionId;
  };

  /** \class qi::Message
    * This class represent a network message
    */
  class TransportSocket;
  typedef boost::shared_ptr<TransportSocket> TransportSocketPtr;
  class ObjectHost;

  class Message {
  public:
    static unsigned int currentVersion()
    {
      return 0;
    }

    // Fixed service id numbers
    enum Service
    {
      Service_Server           = 0,
      Service_ServiceDirectory = 1,
    };

    enum GenericObject
    {
      GenericObject_None = 0,
      GenericObject_Main = 1
    };

    enum BoundObjectFunction {
      BoundObjectFunction_RegisterEvent     = 0,
      BoundObjectFunction_UnregisterEvent   = 1,
      BoundObjectFunction_MetaObject        = 2,
      BoundObjectFunction_Terminate         = 3,
      BoundObjectFunction_GetProperty       = 5,
      BoundObjectFunction_SetProperty       = 6,
      BoundObjectFunction_Properties        = 7,
      BoundObjectFunction_RegisterEventWithSignature = 8,
    };

    enum ServerFunction
    {
      ServerFunction_Connect           = 4,
    };

    enum ServiceDirectoryAction {
      ServiceDirectoryAction_Service             = 100,
      ServiceDirectoryAction_Services            = 101,
      ServiceDirectoryAction_RegisterService     = 102,
      ServiceDirectoryAction_UnregisterService   = 103,
      ServiceDirectoryAction_ServiceReady        = 104,
      ServiceDirectoryAction_UpdateServiceInfo   = 105,
      ServiceDirectoryAction_ServiceAdded        = 106,
      ServiceDirectoryAction_ServiceRemoved      = 107,
      ServiceDirectoryAction_MachineId           = 108,
    };

    enum Type
    {
      Type_None  = 0,
      // Method call, Client->Server (wait for a Type_Reply or Type_Error)
      Type_Call  = 1,
      // Method return value, Server->Client (only to answer to a Type_Call)
      Type_Reply = 2,
      // Method return error, Server->Client (only to answer to a Type_Call)
      Type_Error = 3,
      // Method call, Client->Server (No answer needed)
      Type_Post  = 4,
      // Event Server->Client
      Type_Event = 5,
      // Advertise capabilities, Server<->Client
      Type_Capability = 6,
    };
    // If flag set, payload is of type m instead of expected type
    static const unsigned int TypeFlag_DynamicPayload = 1;
    /* If flag is set, message payload also contains a type into which
     * the return value must be converted.
     * In that case, Type_DynamicPayload will be set on return message,
     * and signature will be repeated.
     * NOT IMPLEMENTED
     */
    static const unsigned int TypeFlag_ReturnType = 2;

    static const char* typeToString(Type t);
    static const char* actionToString(unsigned int action, unsigned int service);

    ~Message();
    Message();
    Message(Type type, const MessageAddress &address);
    Message(const Message &msg);
    Message &operator=(const Message &msg);

    void setAddress(const MessageAddress &address);

    void         setId(unsigned int id);
    unsigned int id() const;

    void         setVersion(qi::uint16_t type);
    unsigned int version() const;

    void         setType(Type type);
    Type         type() const;

    void         setFlags(qi::uint8_t flags);
    void         addFlags(qi::uint8_t flags);
    qi::uint8_t  flags() const;

    void         setService(qi::uint32_t service);
    unsigned int service() const;

    void         setObject(qi::uint32_t object);
    unsigned int object() const;

    void         setFunction(qi::uint32_t function);
    unsigned int function() const;

    void         setEvent(qi::uint32_t event);
    unsigned int event() const;

    unsigned int action() const;

    void          setBuffer(const Buffer &buffer);
    const Buffer &buffer() const;

    void          setError(const std::string &error);

    ///@return signature, set by setParameters() or setSignature()

    AnyReference value(const Signature &signature, const qi::TransportSocketPtr &socket) const;
    void setValue(const AutoAnyReference& value, const Signature& signature, ObjectHost* context = 0, StreamContext* streamContext = 0);
    void setValues(const std::vector<qi::AnyReference>& values, ObjectHost* context = 0, StreamContext* streamContext = 0);
    /// Convert values to \p targetSignature and assign to payload.
    void setValues(const std::vector<qi::AnyReference>& values, const qi::Signature& targetSignature, ObjectHost* context = 0, StreamContext* streamContext = 0);
    /// Append additional data to payload
    void appendValue(const AutoAnyReference& value, ObjectHost* context = 0, StreamContext* streamContext = 0);
    MessageAddress address() const;

    bool         isValid();

  public:
    boost::shared_ptr<MessagePrivate> _p;
    void         cow();
  };

  QIMESSAGING_API std::ostream& operator<<(std::ostream& os, const qi::MessageAddress &address);
  QIMESSAGING_API std::ostream& operator<<(std::ostream& os, const qi::Message& msg);
}

QI_TYPE_CONCRETE(qi::Message);

#endif  // _SRC_MESSAGE_HPP_
<|endoftext|>


<commit_before>// Copyright 2019 Global Phasing Ltd.

#include <cstdio>
#include <algorithm>  // count
#include <stdexcept>
#include "gemmi/blob.hpp"
#include "gemmi/assembly.hpp"  // for expand_ncs
#include "gemmi/polyheur.hpp"  // for remove_hydrogens
#include "gemmi/math.hpp"      // for Variance
#include "gemmi/neighbor.hpp"  // for NeighborSearch
#include "gemmi/read_coor.hpp" // for read_structure_gz
#include "mapcoef.h"

#define GEMMI_PROG blobs
#include "options.h"

namespace {

using std::printf;

enum OptionIndex { SigmaCutoff=AfterMapOptions, AbsCutoff,
                   MaskRadius, MaskWater,
                   MinVolume, MinScore, MinSigma, MinDensity };

const option::Descriptor Usage[] = {
  { NoOp, 0, "", "", Arg::None,
    "Usage:"
    "\n " EXE_NAME " [options] MTZ_OR_MMCIF PDB_OR_MMCIF"
    "\n\nSearch for umodelled blobs of electron density."
    "\n\nOptions:" },
  CommonUsage[Help],
  CommonUsage[Version],
  CommonUsage[Verbose],
  { NoOp, 0, "", "", Arg::None,
    "\nThe area around model is masked to search only unmodelled density." },
  { MaskRadius, 0, "", "mask-radius", Arg::Float,
    "  --mask-radius=NUMBER  \tMask radius (default: 2.0 A)." },
  { MaskWater, 0, "", "mask-waters", Arg::None,
    "  --mask-water  \tMask water (water is not masked by default)." },

  { NoOp, 0, "", "", Arg::None, "\nSearching blobs of density above:" },
  { SigmaCutoff, 0, "", "sigma", Arg::Float,
    "  --sigma=NUMBER  \tSigma (RMSD) level (default: 1.0)." },
  { AbsCutoff, 0, "", "abs", Arg::Float,
    "  --abs=NUMBER  \tAbsolute level in electrons/A^3." },

  { NoOp, 0, "", "", Arg::None, "\nBlob criteria:" },
  { MinVolume, 0, "", "min-volume", Arg::Float,
    "  --min-volume=NUMBER  \tMinimal volume (default: 10.0 A^3)." },
  { MinScore, 0, "", "min-score", Arg::Float,
    "  --min-score=NUMBER  \tMin. this electrons in blob (default: 15.0)." },
  { MinSigma, 0, "", "min-sigma", Arg::Float,
    "  --min-sigma=NUMBER  \tMin. peak rmsd (default: 0.0)." },
  { MinDensity, 0, "", "min-peak", Arg::Float,
    "  --min-peak=NUMBER  \tMin. peak density (default: 0.0 el/A^3)." },

  { NoOp, 0, "", "", Arg::None, "\nOptions for map calculation:" },
  MapUsage[Diff],
  MapUsage[Section],
  MapUsage[FLabel],
  MapUsage[PhLabel],
  MapUsage[WeightLabel],
  MapUsage[GridDims],
  MapUsage[ExactDims],
  MapUsage[Sample],
  MapUsage[GridQuery],
  MapUsage[TimingFft],
  { 0, 0, 0, 0, 0, 0 }
};

gemmi::const_CRA move_near_model(gemmi::NeighborSearch& ns, gemmi::Position& pos) {
  if (const auto* mark = ns.find_nearest_atom(pos)) {
    gemmi::const_CRA cra = mark->to_cra(*ns.model);
    pos = ns.grid.unit_cell.find_nearest_pbc_position(cra.atom->pos, pos,
                                                      mark->image_idx, true);
    return cra;
  }
  return {nullptr, nullptr, nullptr};
}

int run(OptParser& p) {
  std::string sf_path = p.nonOption(0);
  std::string model_path = p.coordinate_input_file(1);

  // read model, remove hydrogens if any
  if (p.options[Verbose])
    printf("Reading coordinates from %s ...\n", model_path.c_str());
  gemmi::Structure st = gemmi::read_structure_gz(model_path);
  if (st.models.empty() || st.models[0].chains.empty()) {
    std::fprintf(stderr, "Not a coordinate file: %s\n", model_path.c_str());
    return 1;
  }
  if (st.models.size() > 1)
    std::fprintf(stderr, "Note: only the first model is used.\n");
  gemmi::Model& model = st.models[0];
  gemmi::remove_hydrogens(model);
  if (!p.options[MaskWater])
    gemmi::remove_waters(model);

  // read map (includes FFT)
  FILE* verbose_output = p.options[Verbose] ? stdout : nullptr;
  gemmi::Grid<float> grid = read_sf_and_fft_to_map(sf_path.c_str(), p.options,
                                                   verbose_output, true);
  if (p.options[Verbose])
    printf("Unit cell: %g A^3, grid points: %zu, volume/point: %g A^3.\n",
           grid.unit_cell.volume, grid.point_count(),
           grid.unit_cell.volume / grid.point_count());
  // move blob position to the symmetry image nearest to the model
  if (st.find_spacegroup() != grid.spacegroup)
    std::fprintf(stderr, "Warning: different space groups in model and data.\n");
  if (!st.cell.approx(grid.unit_cell, 0.1))
    std::fprintf(stderr, "Warning: different unit cells in model and data.\n");

  if (st.ncs_not_expanded()) {
    std::fprintf(stderr, "Note: NCS is expanded, listed blobs may be redundant.\n");
    gemmi::expand_ncs(st, gemmi::HowToNameCopiedChain::AddNumber);
  }

  // calculate map RMSD and setup blob criteria
  gemmi::BlobCriteria criteria;
  gemmi::Variance grid_variance(grid.data.begin(), grid.data.end());
  double rmsd = std::sqrt(grid_variance.for_population());
  double sigma_level = 1.0;
  if (p.options[AbsCutoff]) {
    criteria.cutoff = std::strtod(p.options[SigmaCutoff].arg, nullptr);
    sigma_level = criteria.cutoff / rmsd;
  } else {
    if (p.options[SigmaCutoff])
      sigma_level = std::strtod(p.options[SigmaCutoff].arg, nullptr);
    criteria.cutoff = sigma_level * rmsd;
  }
  // search for blobs
  if (p.options[MinVolume])
    criteria.min_volume = std::strtod(p.options[MinVolume].arg, nullptr);
  if (p.options[MinScore])
    criteria.min_score = std::strtod(p.options[MinScore].arg, nullptr);
  if (p.options[MinSigma])
    criteria.min_peak = std::strtod(p.options[MinSigma].arg, nullptr) * rmsd;
  if (p.options[MinDensity])
    criteria.min_peak = std::strtod(p.options[MinDensity].arg, nullptr);
  printf("Map RMSD: %.3f. Searching blobs above %.3f e/A^3 (%.3f sigma).\n",
         rmsd, criteria.cutoff, sigma_level);

  // mask model by zeroing map values
  double radius = 2.0;
  if (p.options[MaskRadius])
    radius = std::strtod(p.options[MaskRadius].arg, nullptr);
  for (const gemmi::Chain& chain : model.chains)
    for (const gemmi::Residue& res : chain.residues)
      for (const gemmi::Atom& atom : res.atoms)
        grid.set_points_around(atom.pos, radius, -INFINITY);
  grid.symmetrize_min();
  if (p.options[Verbose]) {
    size_t n = std::count(grid.data.begin(), grid.data.end(), -INFINITY);
    printf("Masked points: %zu of %zu.\n", n, grid.point_count());
  }

  // find and sort blobs
  std::vector<gemmi::Blob> blobs = gemmi::find_blobs_by_flood_fill(grid, criteria);
  if (p.options[Verbose])
    printf("%zu blob%s found.\n", blobs.size(), blobs.size() == 1 ? "" : "s");
  std::sort(blobs.begin(), blobs.end(),
            [](const gemmi::Blob& a, const gemmi::Blob& b) { return a.score > b.score; });

  gemmi::NeighborSearch ns(model, grid.unit_cell, 10.0);
  ns.populate();

  // output results
  for (size_t i = 0; i != blobs.size(); ++i) {
    gemmi::const_CRA cra = move_near_model(ns, blobs[i].centroid);
    // Blob::max_pos is left not moved, but we don't use it below
    const gemmi::Blob& b = blobs[i];
    std::string residue_info = "none";
    if (cra.chain && cra.residue)
      residue_info = cra.chain->name + " " + cra.residue->str();
    printf("#%-2zu %5.1f el in %5.1f A^3, %4.1f rmsd,"
           " (%6.1f,%6.1f,%6.1f) near %s\n",
           i, b.score, b.volume, b.max_value / rmsd,
           b.centroid.x, b.centroid.y, b.centroid.z, residue_info.c_str());
  }
  return 0;
}

} // anonymous namespace

int GEMMI_MAIN(int argc, char **argv) {
  OptParser p(EXE_NAME);
  p.simple_parse(argc, argv, Usage);
  p.require_positional_args(2);
  if (p.options[SigmaCutoff] && p.options[AbsCutoff])
    gemmi::fail("cannot use both --sigma and --abs");
  try {
    return run(p);
  } catch (std::runtime_error& e) {
    std::fprintf(stderr, "ERROR: %s\n", e.what());
    return 1;
  }
}

// vim:sw=2:ts=2:et:path^=../include,../third_party
<commit_msg>blobs.cpp: fix<commit_after>// Copyright 2019 Global Phasing Ltd.

#include <cstdio>
#include <algorithm>  // count
#include <stdexcept>
#include "gemmi/blob.hpp"
#include "gemmi/assembly.hpp"  // for expand_ncs
#include "gemmi/polyheur.hpp"  // for remove_hydrogens
#include "gemmi/math.hpp"      // for Variance
#include "gemmi/neighbor.hpp"  // for NeighborSearch
#include "gemmi/read_coor.hpp" // for read_structure_gz
#include "mapcoef.h"

#define GEMMI_PROG blobs
#include "options.h"

namespace {

using std::printf;

enum OptionIndex { SigmaCutoff=AfterMapOptions, AbsCutoff,
                   MaskRadius, MaskWater,
                   MinVolume, MinScore, MinSigma, MinDensity };

const option::Descriptor Usage[] = {
  { NoOp, 0, "", "", Arg::None,
    "Usage:"
    "\n " EXE_NAME " [options] MTZ_OR_MMCIF PDB_OR_MMCIF"
    "\n\nSearch for umodelled blobs of electron density."
    "\n\nOptions:" },
  CommonUsage[Help],
  CommonUsage[Version],
  CommonUsage[Verbose],
  { NoOp, 0, "", "", Arg::None,
    "\nThe area around model is masked to search only unmodelled density." },
  { MaskRadius, 0, "", "mask-radius", Arg::Float,
    "  --mask-radius=NUMBER  \tMask radius (default: 2.0 A)." },
  { MaskWater, 0, "", "mask-waters", Arg::None,
    "  --mask-water  \tMask water (water is not masked by default)." },

  { NoOp, 0, "", "", Arg::None, "\nSearching blobs of density above:" },
  { SigmaCutoff, 0, "", "sigma", Arg::Float,
    "  --sigma=NUMBER  \tSigma (RMSD) level (default: 1.0)." },
  { AbsCutoff, 0, "", "abs", Arg::Float,
    "  --abs=NUMBER  \tAbsolute level in electrons/A^3." },

  { NoOp, 0, "", "", Arg::None, "\nBlob criteria:" },
  { MinVolume, 0, "", "min-volume", Arg::Float,
    "  --min-volume=NUMBER  \tMinimal volume (default: 10.0 A^3)." },
  { MinScore, 0, "", "min-score", Arg::Float,
    "  --min-score=NUMBER  \tMin. this electrons in blob (default: 15.0)." },
  { MinSigma, 0, "", "min-sigma", Arg::Float,
    "  --min-sigma=NUMBER  \tMin. peak rmsd (default: 0.0)." },
  { MinDensity, 0, "", "min-peak", Arg::Float,
    "  --min-peak=NUMBER  \tMin. peak density (default: 0.0 el/A^3)." },

  { NoOp, 0, "", "", Arg::None, "\nOptions for map calculation:" },
  MapUsage[Diff],
  MapUsage[Section],
  MapUsage[FLabel],
  MapUsage[PhLabel],
  MapUsage[WeightLabel],
  MapUsage[GridDims],
  MapUsage[ExactDims],
  MapUsage[Sample],
  MapUsage[GridQuery],
  MapUsage[TimingFft],
  { 0, 0, 0, 0, 0, 0 }
};

gemmi::const_CRA move_near_model(gemmi::NeighborSearch& ns, gemmi::Position& pos) {
  if (const auto* mark = ns.find_nearest_atom(pos)) {
    gemmi::const_CRA cra = mark->to_cra(*ns.model);
    pos = ns.grid.unit_cell.find_nearest_pbc_position(cra.atom->pos, pos,
                                                      mark->image_idx, true);
    return cra;
  }
  return {nullptr, nullptr, nullptr};
}

int run(OptParser& p) {
  std::string sf_path = p.nonOption(0);
  std::string model_path = p.coordinate_input_file(1);

  // read model, remove hydrogens if any
  if (p.options[Verbose])
    printf("Reading coordinates from %s ...\n", model_path.c_str());
  gemmi::Structure st = gemmi::read_structure_gz(model_path);
  if (st.models.empty() || st.models[0].chains.empty()) {
    std::fprintf(stderr, "Not a coordinate file: %s\n", model_path.c_str());
    return 1;
  }
  if (st.models.size() > 1)
    std::fprintf(stderr, "Note: only the first model is used.\n");
  gemmi::Model& model = st.models[0];
  gemmi::remove_hydrogens(model);
  if (!p.options[MaskWater])
    gemmi::remove_waters(model);

  // read map (includes FFT)
  FILE* verbose_output = p.options[Verbose] ? stdout : nullptr;
  gemmi::Grid<float> grid = read_sf_and_fft_to_map(sf_path.c_str(), p.options,
                                                   verbose_output, true);
  if (p.options[Verbose])
    printf("Unit cell: %g A^3, grid points: %zu, volume/point: %g A^3.\n",
           grid.unit_cell.volume, grid.point_count(),
           grid.unit_cell.volume / grid.point_count());
  // move blob position to the symmetry image nearest to the model
  if (st.find_spacegroup() != grid.spacegroup)
    std::fprintf(stderr, "Warning: different space groups in model and data.\n");
  if (!st.cell.approx(grid.unit_cell, 0.1))
    std::fprintf(stderr, "Warning: different unit cells in model and data.\n");

  if (st.ncs_not_expanded()) {
    std::fprintf(stderr, "Note: NCS is expanded, listed blobs may be redundant.\n");
    gemmi::expand_ncs(st, gemmi::HowToNameCopiedChain::AddNumber);
  }

  // calculate map RMSD and setup blob criteria
  gemmi::BlobCriteria criteria;
  gemmi::Variance grid_variance(grid.data.begin(), grid.data.end());
  double rmsd = std::sqrt(grid_variance.for_population());
  double sigma_level = 1.0;
  if (p.options[AbsCutoff]) {
    criteria.cutoff = std::strtod(p.options[AbsCutoff].arg, nullptr);
    sigma_level = criteria.cutoff / rmsd;
  } else {
    if (p.options[SigmaCutoff])
      sigma_level = std::strtod(p.options[SigmaCutoff].arg, nullptr);
    criteria.cutoff = sigma_level * rmsd;
  }
  // search for blobs
  if (p.options[MinVolume])
    criteria.min_volume = std::strtod(p.options[MinVolume].arg, nullptr);
  if (p.options[MinScore])
    criteria.min_score = std::strtod(p.options[MinScore].arg, nullptr);
  if (p.options[MinSigma])
    criteria.min_peak = std::strtod(p.options[MinSigma].arg, nullptr) * rmsd;
  if (p.options[MinDensity])
    criteria.min_peak = std::strtod(p.options[MinDensity].arg, nullptr);
  printf("Map RMSD: %.3f. Searching blobs above %.3f e/A^3 (%.3f sigma).\n",
         rmsd, criteria.cutoff, sigma_level);

  // mask model by zeroing map values
  double radius = 2.0;
  if (p.options[MaskRadius])
    radius = std::strtod(p.options[MaskRadius].arg, nullptr);
  for (const gemmi::Chain& chain : model.chains)
    for (const gemmi::Residue& res : chain.residues)
      for (const gemmi::Atom& atom : res.atoms)
        grid.set_points_around(atom.pos, radius, -INFINITY);
  grid.symmetrize_min();
  if (p.options[Verbose]) {
    size_t n = std::count(grid.data.begin(), grid.data.end(), -INFINITY);
    printf("Masked points: %zu of %zu.\n", n, grid.point_count());
  }

  // find and sort blobs
  std::vector<gemmi::Blob> blobs = gemmi::find_blobs_by_flood_fill(grid, criteria);
  if (p.options[Verbose])
    printf("%zu blob%s found.\n", blobs.size(), blobs.size() == 1 ? "" : "s");
  std::sort(blobs.begin(), blobs.end(),
            [](const gemmi::Blob& a, const gemmi::Blob& b) { return a.score > b.score; });

  gemmi::NeighborSearch ns(model, grid.unit_cell, 10.0);
  ns.populate();

  // output results
  for (size_t i = 0; i != blobs.size(); ++i) {
    gemmi::const_CRA cra = move_near_model(ns, blobs[i].centroid);
    // Blob::max_pos is left not moved, but we don't use it below
    const gemmi::Blob& b = blobs[i];
    std::string residue_info = "none";
    if (cra.chain && cra.residue)
      residue_info = cra.chain->name + " " + cra.residue->str();
    printf("#%-2zu %5.1f el in %5.1f A^3, %4.1f rmsd,"
           " (%6.1f,%6.1f,%6.1f) near %s\n",
           i, b.score, b.volume, b.max_value / rmsd,
           b.centroid.x, b.centroid.y, b.centroid.z, residue_info.c_str());
  }
  return 0;
}

} // anonymous namespace

int GEMMI_MAIN(int argc, char **argv) {
  OptParser p(EXE_NAME);
  p.simple_parse(argc, argv, Usage);
  p.require_positional_args(2);
  if (p.options[SigmaCutoff] && p.options[AbsCutoff])
    gemmi::fail("cannot use both --sigma and --abs");
  try {
    return run(p);
  } catch (std::runtime_error& e) {
    std::fprintf(stderr, "ERROR: %s\n", e.what());
    return 1;
  }
}

// vim:sw=2:ts=2:et:path^=../include,../third_party
<|endoftext|>


<commit_before>#include "yolo_v2_class.hpp"

#include "network.h"

extern "C" {
#include "detection_layer.h"
#include "region_layer.h"
#include "cost_layer.h"
#include "utils.h"
#include "parser.h"
#include "box.h"
#include "image.h"
#include "demo.h"
#include "option_list.h"
#include "stb_image.h"
}
//#include <sys/time.h>

#include <vector>
#include <iostream>
#include <algorithm>

#define FRAMES 3

struct detector_gpu_t{
	float **probs;
	box *boxes;
	network net;
	image images[FRAMES];
	float *avg;
	float *predictions[FRAMES];
};

YOLODLL_API Detector::Detector(std::string cfg_filename, std::string weight_filename, int gpu_id)
{
	int old_gpu_index;
	cudaGetDevice(&old_gpu_index);

	detector_gpu_ptr = std::make_shared<detector_gpu_t>();
	detector_gpu_t &detector_gpu = *reinterpret_cast<detector_gpu_t *>(detector_gpu_ptr.get());

	cudaSetDevice(gpu_id);
	network &net = detector_gpu.net;
	net.gpu_index = gpu_id;
	//gpu_index = i;

	char *cfgfile = const_cast<char *>(cfg_filename.data());
	char *weightfile = const_cast<char *>(weight_filename.data());

	net = parse_network_cfg(cfgfile);
	if (weightfile) {
		load_weights(&net, weightfile);
	}
	set_batch_network(&net, 1);
	net.gpu_index = gpu_id;

	layer l = net.layers[net.n - 1];
	int j;

	detector_gpu.avg = (float *)calloc(l.outputs, sizeof(float));
	for (j = 0; j < FRAMES; ++j) detector_gpu.predictions[j] = (float *)calloc(l.outputs, sizeof(float));
	for (j = 0; j < FRAMES; ++j) detector_gpu.images[j] = make_image(1, 1, 3);

	detector_gpu.boxes = (box *)calloc(l.w*l.h*l.n, sizeof(box));
	detector_gpu.probs = (float **)calloc(l.w*l.h*l.n, sizeof(float *));
	for (j = 0; j < l.w*l.h*l.n; ++j) detector_gpu.probs[j] = (float *)calloc(l.classes, sizeof(float));

	cudaSetDevice(old_gpu_index);
}

YOLODLL_API Detector::~Detector()
{
	detector_gpu_t &detector_gpu = *reinterpret_cast<detector_gpu_t *>(detector_gpu_ptr.get());
	layer l = detector_gpu.net.layers[detector_gpu.net.n - 1];

	free(detector_gpu.avg);
	for (int j = 0; j < FRAMES; ++j) free(detector_gpu.predictions[j]);
	for (int j = 0; j < FRAMES; ++j) if(detector_gpu.images[j].data) free(detector_gpu.images[j].data);

	free(detector_gpu.boxes);
	free(detector_gpu.probs);
	for (int j = 0; j < l.w*l.h*l.n; ++j) free(detector_gpu.probs[j]);

	int old_gpu_index;
	cudaGetDevice(&old_gpu_index);
	cudaSetDevice(detector_gpu.net.gpu_index);

	free_network(detector_gpu.net);

	cudaSetDevice(old_gpu_index);
}

YOLODLL_API std::vector<bbox_t> Detector::detect(std::string image_filename, float thresh)
{
	std::shared_ptr<image_t> image_ptr(new image_t, [](image_t *img) { if (img->data) free(img->data); delete img; });
	*image_ptr = load_image(image_filename);
	return detect(*image_ptr, thresh);
}

static image load_image_stb(char *filename, int channels)
{
	int w, h, c;
	unsigned char *data = stbi_load(filename, &w, &h, &c, channels);
	if (!data)
		throw std::runtime_error("file not found");
	if (channels) c = channels;
	int i, j, k;
	image im = make_image(w, h, c);
	for (k = 0; k < c; ++k) {
		for (j = 0; j < h; ++j) {
			for (i = 0; i < w; ++i) {
				int dst_index = i + w*j + w*h*k;
				int src_index = k + c*i + c*w*j;
				im.data[dst_index] = (float)data[src_index] / 255.;
			}
		}
	}
	free(data);
	return im;
}

YOLODLL_API image_t Detector::load_image(std::string image_filename)
{
	char *input = const_cast<char *>(image_filename.data());
	image im = load_image_stb(input, 3);

	image_t img;
	img.c = im.c;
	img.data = im.data;
	img.h = im.h;
	img.w = im.w;

	return img;
}

YOLODLL_API void Detector::free_image(image_t m)
{
	if (m.data) {
		free(m.data);
	}
}

YOLODLL_API std::vector<bbox_t> Detector::detect(image_t img, float thresh)
{

	detector_gpu_t &detector_gpu = *reinterpret_cast<detector_gpu_t *>(detector_gpu_ptr.get());
	network &net = detector_gpu.net;
	int old_gpu_index;
	cudaGetDevice(&old_gpu_index);
	cudaSetDevice(net.gpu_index);
	//std::cout << "net.gpu_index = " << net.gpu_index << std::endl;

	float nms = .4;

	image im;
	im.c = img.c;
	im.data = img.data;
	im.h = img.h;
	im.w = img.w;

	image sized = resize_image(im, net.w, net.h);
	layer l = net.layers[net.n - 1];

	float *X = sized.data;

	network_predict(net, X);

	get_region_boxes(l, 1, 1, thresh, detector_gpu.probs, detector_gpu.boxes, 0, 0);
	if (nms) do_nms_sort(detector_gpu.boxes, detector_gpu.probs, l.w*l.h*l.n, l.classes, nms);
	//draw_detections(im, l.w*l.h*l.n, thresh, boxes, probs, names, alphabet, l.classes);

	std::vector<bbox_t> bbox_vec;

	for (size_t i = 0; i < (l.w*l.h*l.n); ++i) {
		box b = detector_gpu.boxes[i];
		int const obj_id = max_index(detector_gpu.probs[i], l.classes);
		float const prob = detector_gpu.probs[i][obj_id];

		if (prob > thresh)
		{
			bbox_t bbox;
			bbox.x = std::max((double)0, (b.x - b.w / 2.)*im.w);
			bbox.y = std::max((double)0, (b.y - b.h / 2.)*im.h);
			bbox.w = b.w*im.w;
			bbox.h = b.h*im.h;
			bbox.obj_id = obj_id;
			bbox.prob = prob;

			bbox_vec.push_back(bbox);
		}
	}

	if(sized.data)
		free(sized.data);

	cudaSetDevice(old_gpu_index);

	return bbox_vec;
}<commit_msg>Fixed sequence of freeing memory.<commit_after>#include "yolo_v2_class.hpp"

#include "network.h"

extern "C" {
#include "detection_layer.h"
#include "region_layer.h"
#include "cost_layer.h"
#include "utils.h"
#include "parser.h"
#include "box.h"
#include "image.h"
#include "demo.h"
#include "option_list.h"
#include "stb_image.h"
}
//#include <sys/time.h>

#include <vector>
#include <iostream>
#include <algorithm>

#define FRAMES 3

struct detector_gpu_t{
	float **probs;
	box *boxes;
	network net;
	image images[FRAMES];
	float *avg;
	float *predictions[FRAMES];
};

YOLODLL_API Detector::Detector(std::string cfg_filename, std::string weight_filename, int gpu_id)
{
	int old_gpu_index;
	cudaGetDevice(&old_gpu_index);

	detector_gpu_ptr = std::make_shared<detector_gpu_t>();
	detector_gpu_t &detector_gpu = *reinterpret_cast<detector_gpu_t *>(detector_gpu_ptr.get());

	cudaSetDevice(gpu_id);
	network &net = detector_gpu.net;
	net.gpu_index = gpu_id;
	//gpu_index = i;

	char *cfgfile = const_cast<char *>(cfg_filename.data());
	char *weightfile = const_cast<char *>(weight_filename.data());

	net = parse_network_cfg(cfgfile);
	if (weightfile) {
		load_weights(&net, weightfile);
	}
	set_batch_network(&net, 1);
	net.gpu_index = gpu_id;

	layer l = net.layers[net.n - 1];
	int j;

	detector_gpu.avg = (float *)calloc(l.outputs, sizeof(float));
	for (j = 0; j < FRAMES; ++j) detector_gpu.predictions[j] = (float *)calloc(l.outputs, sizeof(float));
	for (j = 0; j < FRAMES; ++j) detector_gpu.images[j] = make_image(1, 1, 3);

	detector_gpu.boxes = (box *)calloc(l.w*l.h*l.n, sizeof(box));
	detector_gpu.probs = (float **)calloc(l.w*l.h*l.n, sizeof(float *));
	for (j = 0; j < l.w*l.h*l.n; ++j) detector_gpu.probs[j] = (float *)calloc(l.classes, sizeof(float));

	cudaSetDevice(old_gpu_index);
}

YOLODLL_API Detector::~Detector()
{
	detector_gpu_t &detector_gpu = *reinterpret_cast<detector_gpu_t *>(detector_gpu_ptr.get());
	layer l = detector_gpu.net.layers[detector_gpu.net.n - 1];

	free(detector_gpu.avg);
	for (int j = 0; j < FRAMES; ++j) free(detector_gpu.predictions[j]);
	for (int j = 0; j < FRAMES; ++j) if(detector_gpu.images[j].data) free(detector_gpu.images[j].data);

	for (int j = 0; j < l.w*l.h*l.n; ++j) free(detector_gpu.probs[j]);
	free(detector_gpu.boxes);
	free(detector_gpu.probs);

	int old_gpu_index;
	cudaGetDevice(&old_gpu_index);
	cudaSetDevice(detector_gpu.net.gpu_index);

	free_network(detector_gpu.net);

	cudaSetDevice(old_gpu_index);
}

YOLODLL_API std::vector<bbox_t> Detector::detect(std::string image_filename, float thresh)
{
	std::shared_ptr<image_t> image_ptr(new image_t, [](image_t *img) { if (img->data) free(img->data); delete img; });
	*image_ptr = load_image(image_filename);
	return detect(*image_ptr, thresh);
}

static image load_image_stb(char *filename, int channels)
{
	int w, h, c;
	unsigned char *data = stbi_load(filename, &w, &h, &c, channels);
	if (!data)
		throw std::runtime_error("file not found");
	if (channels) c = channels;
	int i, j, k;
	image im = make_image(w, h, c);
	for (k = 0; k < c; ++k) {
		for (j = 0; j < h; ++j) {
			for (i = 0; i < w; ++i) {
				int dst_index = i + w*j + w*h*k;
				int src_index = k + c*i + c*w*j;
				im.data[dst_index] = (float)data[src_index] / 255.;
			}
		}
	}
	free(data);
	return im;
}

YOLODLL_API image_t Detector::load_image(std::string image_filename)
{
	char *input = const_cast<char *>(image_filename.data());
	image im = load_image_stb(input, 3);

	image_t img;
	img.c = im.c;
	img.data = im.data;
	img.h = im.h;
	img.w = im.w;

	return img;
}

YOLODLL_API void Detector::free_image(image_t m)
{
	if (m.data) {
		free(m.data);
	}
}

YOLODLL_API std::vector<bbox_t> Detector::detect(image_t img, float thresh)
{

	detector_gpu_t &detector_gpu = *reinterpret_cast<detector_gpu_t *>(detector_gpu_ptr.get());
	network &net = detector_gpu.net;
	int old_gpu_index;
	cudaGetDevice(&old_gpu_index);
	cudaSetDevice(net.gpu_index);
	//std::cout << "net.gpu_index = " << net.gpu_index << std::endl;

	float nms = .4;

	image im;
	im.c = img.c;
	im.data = img.data;
	im.h = img.h;
	im.w = img.w;

	image sized = resize_image(im, net.w, net.h);
	layer l = net.layers[net.n - 1];

	float *X = sized.data;

	network_predict(net, X);

	get_region_boxes(l, 1, 1, thresh, detector_gpu.probs, detector_gpu.boxes, 0, 0);
	if (nms) do_nms_sort(detector_gpu.boxes, detector_gpu.probs, l.w*l.h*l.n, l.classes, nms);
	//draw_detections(im, l.w*l.h*l.n, thresh, boxes, probs, names, alphabet, l.classes);

	std::vector<bbox_t> bbox_vec;

	for (size_t i = 0; i < (l.w*l.h*l.n); ++i) {
		box b = detector_gpu.boxes[i];
		int const obj_id = max_index(detector_gpu.probs[i], l.classes);
		float const prob = detector_gpu.probs[i][obj_id];

		if (prob > thresh)
		{
			bbox_t bbox;
			bbox.x = std::max((double)0, (b.x - b.w / 2.)*im.w);
			bbox.y = std::max((double)0, (b.y - b.h / 2.)*im.h);
			bbox.w = b.w*im.w;
			bbox.h = b.h*im.h;
			bbox.obj_id = obj_id;
			bbox.prob = prob;

			bbox_vec.push_back(bbox);
		}
	}

	if(sized.data)
		free(sized.data);

	cudaSetDevice(old_gpu_index);

	return bbox_vec;
}<|endoftext|>


<commit_before>/*
Copyright (C) 2011-2012 Yubico AB.  All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

   1. Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.

   2. Redistributions in binary form must reproduce the above
      copyright notice, this list of conditions and the following
      disclaimer in the documentation and/or other materials provided
      with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "yubikeylogger.h"
#include <QFile>
#include <QDir>
#include <QDebug>
#include <QDateTime>

#define LOG_FILENAME_DEF   "configuration_log.csv"
#define LOG_SEPARATOR      ","

QString YubiKeyLogger::m_filename   = defaultLogFilename();
bool YubiKeyLogger::m_enabled       = true;
bool YubiKeyLogger::m_started       = true;
YubiKeyLogger::Format YubiKeyLogger::m_format = Format_Traditional;

YubiKeyLogger::~YubiKeyLogger() {
}

void YubiKeyLogger::logConfig(YubiKeyConfig *ykConfig) {
    //Check if logging is enabled
    if(!m_enabled) {
        return;
    }

    QFile file(m_filename);

    qDebug() << "Log file name:" << m_filename;

    if (!file.open(QIODevice::WriteOnly | QIODevice::Append)) {
        qDebug() << "File could not be opened for writing";
        return;
    }

    QTextStream out(&file);

    if(m_format == Format_Traditional) {
        logConfigTraditional(ykConfig, out);
    } else {
        logConfigYubico(ykConfig, out);
    }
    file.flush();
    file.close();
}

void YubiKeyLogger::logConfigTraditional(YubiKeyConfig *ykConfig, QTextStream &out) {
    if(m_started) {
        QDateTime ts = QDateTime::currentDateTime();
        out << tr("LOGGING START")
                << LOG_SEPARATOR
                << ts.toString(Qt::SystemLocaleDate)
                << endl;

        m_started = false;
    }

    //Event type...
    QString eventType;

    switch(ykConfig->programmingMode()) {
    case YubiKeyConfig::Mode_YubicoOtp:
        eventType = tr("Yubico OTP");
        break;

    case YubiKeyConfig::Mode_Static:
        eventType = tr("Static Password");

        if(ykConfig->shortTicket()) {
            if(ykConfig->staticTicket()) {
                eventType.append(tr(": Short"));
            } else {
                eventType.append(tr(": Scan Code"));
            }
        }
        break;

    case YubiKeyConfig::Mode_OathHotp:
        eventType = tr("OATH-HOTP");
        break;

    case YubiKeyConfig::Mode_ChalRespYubico:
        eventType = tr("Challenge-Response: Yubico OTP");
        break;

    case YubiKeyConfig::Mode_ChalRespHmac:
        eventType = tr("Challenge-Response: HMAC-SHA1");
        break;

    case YubiKeyConfig::Mode_Update:
        eventType = tr("Configuration Update");
        break;

    case YubiKeyConfig::Mode_Swap:
        eventType = tr("Configuration Swap");
        break;
    }
    out << eventType;

    //Timestamp...
    QDateTime timestamp = QDateTime::currentDateTime();
    out << LOG_SEPARATOR << timestamp.toString(Qt::SystemLocaleDate);

    //Configuration slot...
    out << LOG_SEPARATOR << ykConfig->configSlot();

    //Public ID...
    out << LOG_SEPARATOR << ykConfig->pubIdTxt();

    //Private ID...
    out << LOG_SEPARATOR << ykConfig->pvtIdTxt();

    //Secret Key...
    out << LOG_SEPARATOR << ykConfig->secretKeyTxt();

    //Current Access Code...
    out << LOG_SEPARATOR << ykConfig->currentAccessCodeTxt();

    //New Access Code...
    out << LOG_SEPARATOR << ykConfig->newAccessCodeTxt();

    //OATH-HOTP specific...
    out << LOG_SEPARATOR << (ykConfig->oathFixedModhex1()? 1: 0);
    out << LOG_SEPARATOR << (ykConfig->oathFixedModhex2()? 1: 0);
    out << LOG_SEPARATOR << (ykConfig->oathFixedModhex()? 1: 0);
    if(ykConfig->programmingMode() == YubiKeyConfig::Mode_OathHotp) {
        out << LOG_SEPARATOR << (ykConfig->oathHotp8()? 8: 6);
    } else {
        out << LOG_SEPARATOR << 0;
    }
    out << LOG_SEPARATOR << ykConfig->oathMovingFactorSeed();

    //Static Password specific...
    out << LOG_SEPARATOR << (ykConfig->strongPw1()? 1: 0);
    out << LOG_SEPARATOR << (ykConfig->strongPw2()? 1: 0);
    out << LOG_SEPARATOR << (ykConfig->sendRef()? 1: 0);

    //Challenge-Response specific
    out << LOG_SEPARATOR << (ykConfig->chalBtnTrig()? 1: 0);
    if(ykConfig->programmingMode() == YubiKeyConfig::Mode_ChalRespHmac) {
        out << LOG_SEPARATOR << (ykConfig->hmacLT64()? 1: 0);
    } else {
        out << LOG_SEPARATOR << 0;
    }

    out << endl;
}

void YubiKeyLogger::logConfigYubico(YubiKeyConfig *ykConfig, QTextStream &out) {

}

void YubiKeyLogger::enableLogging() {
    m_enabled = true;
}

void YubiKeyLogger::disableLogging() {
    m_enabled = false;
}

bool YubiKeyLogger::isLogging() {
    return m_enabled;
}

void YubiKeyLogger::setLogFilename(const QString &filename) {
    m_filename = filename;
}

QString YubiKeyLogger::logFilename() {
    return m_filename;
}

QString YubiKeyLogger::defaultLogFilename() {
    return QDir::homePath() + "/" + LOG_FILENAME_DEF;
}

void YubiKeyLogger::setLogFormat(Format format) {
    m_format = format;
}

<commit_msg>implement the yubico logging format<commit_after>/*
Copyright (C) 2011-2012 Yubico AB.  All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

   1. Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.

   2. Redistributions in binary form must reproduce the above
      copyright notice, this list of conditions and the following
      disclaimer in the documentation and/or other materials provided
      with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "yubikeylogger.h"
#include <QFile>
#include <QDir>
#include <QDebug>
#include <QDateTime>

#define LOG_FILENAME_DEF   "configuration_log.csv"
#define LOG_SEPARATOR      ","

QString YubiKeyLogger::m_filename   = defaultLogFilename();
bool YubiKeyLogger::m_enabled       = true;
bool YubiKeyLogger::m_started       = true;
YubiKeyLogger::Format YubiKeyLogger::m_format = Format_Traditional;

YubiKeyLogger::~YubiKeyLogger() {
}

void YubiKeyLogger::logConfig(YubiKeyConfig *ykConfig) {
    //Check if logging is enabled
    if(!m_enabled) {
        return;
    }

    QFile file(m_filename);

    qDebug() << "Log file name:" << m_filename;

    if (!file.open(QIODevice::WriteOnly | QIODevice::Append)) {
        qDebug() << "File could not be opened for writing";
        return;
    }

    QTextStream out(&file);

    if(m_format == Format_Traditional) {
        logConfigTraditional(ykConfig, out);
    } else {
        logConfigYubico(ykConfig, out);
    }
    file.flush();
    file.close();
}

void YubiKeyLogger::logConfigTraditional(YubiKeyConfig *ykConfig, QTextStream &out) {
    if(m_started) {
        QDateTime ts = QDateTime::currentDateTime();
        out << tr("LOGGING START")
                << LOG_SEPARATOR
                << ts.toString(Qt::SystemLocaleDate)
                << endl;

        m_started = false;
    }

    //Event type...
    QString eventType;

    switch(ykConfig->programmingMode()) {
    case YubiKeyConfig::Mode_YubicoOtp:
        eventType = tr("Yubico OTP");
        break;

    case YubiKeyConfig::Mode_Static:
        eventType = tr("Static Password");

        if(ykConfig->shortTicket()) {
            if(ykConfig->staticTicket()) {
                eventType.append(tr(": Short"));
            } else {
                eventType.append(tr(": Scan Code"));
            }
        }
        break;

    case YubiKeyConfig::Mode_OathHotp:
        eventType = tr("OATH-HOTP");
        break;

    case YubiKeyConfig::Mode_ChalRespYubico:
        eventType = tr("Challenge-Response: Yubico OTP");
        break;

    case YubiKeyConfig::Mode_ChalRespHmac:
        eventType = tr("Challenge-Response: HMAC-SHA1");
        break;

    case YubiKeyConfig::Mode_Update:
        eventType = tr("Configuration Update");
        break;

    case YubiKeyConfig::Mode_Swap:
        eventType = tr("Configuration Swap");
        break;
    }
    out << eventType;

    //Timestamp...
    QDateTime timestamp = QDateTime::currentDateTime();
    out << LOG_SEPARATOR << timestamp.toString(Qt::SystemLocaleDate);

    //Configuration slot...
    out << LOG_SEPARATOR << ykConfig->configSlot();

    //Public ID...
    out << LOG_SEPARATOR << ykConfig->pubIdTxt();

    //Private ID...
    out << LOG_SEPARATOR << ykConfig->pvtIdTxt();

    //Secret Key...
    out << LOG_SEPARATOR << ykConfig->secretKeyTxt();

    //Current Access Code...
    out << LOG_SEPARATOR << ykConfig->currentAccessCodeTxt();

    //New Access Code...
    out << LOG_SEPARATOR << ykConfig->newAccessCodeTxt();

    //OATH-HOTP specific...
    out << LOG_SEPARATOR << (ykConfig->oathFixedModhex1()? 1: 0);
    out << LOG_SEPARATOR << (ykConfig->oathFixedModhex2()? 1: 0);
    out << LOG_SEPARATOR << (ykConfig->oathFixedModhex()? 1: 0);
    if(ykConfig->programmingMode() == YubiKeyConfig::Mode_OathHotp) {
        out << LOG_SEPARATOR << (ykConfig->oathHotp8()? 8: 6);
    } else {
        out << LOG_SEPARATOR << 0;
    }
    out << LOG_SEPARATOR << ykConfig->oathMovingFactorSeed();

    //Static Password specific...
    out << LOG_SEPARATOR << (ykConfig->strongPw1()? 1: 0);
    out << LOG_SEPARATOR << (ykConfig->strongPw2()? 1: 0);
    out << LOG_SEPARATOR << (ykConfig->sendRef()? 1: 0);

    //Challenge-Response specific
    out << LOG_SEPARATOR << (ykConfig->chalBtnTrig()? 1: 0);
    if(ykConfig->programmingMode() == YubiKeyConfig::Mode_ChalRespHmac) {
        out << LOG_SEPARATOR << (ykConfig->hmacLT64()? 1: 0);
    } else {
        out << LOG_SEPARATOR << 0;
    }

    out << endl;
}

void YubiKeyLogger::logConfigYubico(YubiKeyConfig *ykConfig, QTextStream &out) {
    if(ykConfig->serial() != "0") {
        out << ykConfig->serial();
    }
    out << LOG_SEPARATOR;
    switch(ykConfig->programmingMode()) {
    case YubiKeyConfig::Mode_YubicoOtp:
        out << ykConfig->pubIdTxt() << LOG_SEPARATOR;
        out << ykConfig->pvtIdTxt() << LOG_SEPARATOR;
        break;
    case YubiKeyConfig::Mode_OathHotp:
        out << ykConfig->pubIdTxt() << LOG_SEPARATOR;
        out << ykConfig->oathMovingFactorSeed() << LOG_SEPARATOR;
        break;
    case YubiKeyConfig::Mode_ChalRespHmac:
        out << LOG_SEPARATOR;
        out << "0" << LOG_SEPARATOR;
        break;
    default:
        qDebug() << "Yubico format has no support for programmingMode " << ykConfig->programmingMode();
        break;
    }
    out << ykConfig->secretKeyTxt() << LOG_SEPARATOR;
    out << ykConfig->newAccessCodeTxt() << LOG_SEPARATOR;
    QDateTime timestamp = QDateTime::currentDateTime();
    out << timestamp.toString("yyyy-MM-ddThh:mm:ss");
    out << LOG_SEPARATOR << endl;
}

void YubiKeyLogger::enableLogging() {
    m_enabled = true;
}

void YubiKeyLogger::disableLogging() {
    m_enabled = false;
}

bool YubiKeyLogger::isLogging() {
    return m_enabled;
}

void YubiKeyLogger::setLogFilename(const QString &filename) {
    m_filename = filename;
}

QString YubiKeyLogger::logFilename() {
    return m_filename;
}

QString YubiKeyLogger::defaultLogFilename() {
    return QDir::homePath() + "/" + LOG_FILENAME_DEF;
}

void YubiKeyLogger::setLogFormat(Format format) {
    m_format = format;
}

<|endoftext|>