<commit_before>#include <cstring>
#include <deque>
#include <vector>

#include <iostream>
#include <string>

#include <node.h>
#include <node_buffer.h>
#include <node_object_wrap.h>
#include <v8.h>

#include "MemoryPool.h"

using namespace v8;

/**
 * A string whose characters are stored elsewhere.
 *
 * The argument-free constructor will return a "null string". Basically, it's
 * a hack that probably behaves the way you expect. (Its memory address is
 * NULL.)
 */
struct SimpleString
{
  const char* s;
  size_t len;

  SimpleString(const char* aS, size_t aLen) : s(aS), len(aLen) {}
  SimpleString() : s(NULL), len(0) {}
  SimpleString(const SimpleString& rhs) : s(rhs.s), len(rhs.len) {}

  inline bool isNull() const { return s == NULL; }
};

struct TSTNode
{
  char ch;
  TSTNode* left;
  TSTNode* eq;
  TSTNode* right;
  const SimpleString* value; // value != NULL iff this is a leaf node

  explicit TSTNode(char aCh)
    : ch(aCh),
      left(NULL),
      eq(NULL),
      right(NULL),
      value(NULL) {}

  ~TSTNode()
  {
    if (this->left) delete this->left;
    if (this->eq) delete this->eq;
    if (this->right) delete this->right;
  }
};

static const size_t NodePoolChunkSize = 65536; // 4096 is slower, according to perf.js

/**
 * Ternary search tree.
 *
 * Every string inserted into this tree will be an external one. That means the
 * caller must ensure none of those strings are freed until the TST is deleted.
 */
class TST
{
public:
  void insert(const SimpleString& key, const SimpleString* value)
  {
    if (key.len == 0) return; // We don't store zero-length strings

    this->_insert(&this->root, key.s, key.len, value);
  }

  bool contains(const char* s, size_t len) const
  {
    const TSTNode* node = this->getNode(s, len);

    return node != NULL;
  }

  const SimpleString* get(const char* s, size_t len) const
  {
    const TSTNode* node = this->getNode(s, len);

    if (node == NULL) {
      return NULL;
    } else if (node->value->isNull()) {
      // Every leaf node has a value, but it might be a null string.
      return NULL;
    } else {
      return node->value;
    }
  }

  explicit TST() : root(NULL) {}

private:
  TSTNode* root;
  MemoryPool<TSTNode,NodePoolChunkSize> pool;

  void _insert(TSTNode** nodeAddress, const char* s, size_t len, const SimpleString* value) {
    char ch = *s;

    if (*nodeAddress == NULL) {
      *nodeAddress = pool.newElement(ch);
      // All the nodes get deleted by the MemoryPool when we destroy the TST
    }

    TSTNode* node = *nodeAddress;

    if (ch < node->ch) {
      this->_insert(&node->left, s, len, value);
    } else if (ch > node->ch) {
      this->_insert(&node->right, s, len, value);
    } else if (len > 1) {
      this->_insert(&node->eq, &s[1], len - 1, value);
    } else {
      node->value = value;
    }
  }

  const TSTNode* getNode(const char* s, size_t len) const {
    if (len == 0) return NULL; // We don't store zero-length strings

    return this->_getNode(this->root, s, len); // recursive search
  }

  const TSTNode* _getNode(const TSTNode* node, const char* s, size_t len) const {
    // Assume len > 0
    for (;;) {
      if (node == NULL) return NULL; // No match

      char ch = *s;

      if (ch < node->ch) {
        node = node->left;
      } else if (ch > node->ch) {
        node = node->right;
      } else if (len > 1) {
        node = node->eq;
        s++;
        len--;
      } else if (node->value != NULL) {
        return node; // match
      } else {
        return NULL; // end of search
      }
    }
  }
};

class TernaryBufferTree : public node::ObjectWrap {
public:
  static void Init(Handle<Object> exports);
  static Persistent<Function> constructor;

  inline bool contains(const char* s, size_t len) const;
  const SimpleString* get(const char* s, size_t len) const;
  std::vector<SimpleString> findAllMatches(const char* s, size_t len, size_t maxNgramSize);

private:
  char* mem = NULL;
  SimpleString* strings = NULL;
  TST tree;

  explicit TernaryBufferTree(const char* s, size_t len);
  ~TernaryBufferTree();

  static void New(const FunctionCallbackInfo<Value>& args);
  static void Contains(const FunctionCallbackInfo<Value>& args);
  static void Get(const FunctionCallbackInfo<Value>& args);
  static void FindAllMatches(const FunctionCallbackInfo<Value>& args);
};

Persistent<Function> TernaryBufferTree::constructor;

static size_t
count_char_in_str(char ch, const char* s, size_t len) {
  size_t ret = 0;

  while (len > 0) {
    if (*s == ch) ret++;
    len--;
    s++;
  }

  return ret;
}

/**
 * Insert Strings into a TST.
 *
 * We assume the Strings are sorted. Insert the median first, then recurse.
 * That's described in "Better Insertion Orders" at
 * http://www.drdobbs.com/database/ternary-search-trees/184410528?pgno=2
 *
 * The `tokens` passed here are in *pairs*: that is, tokens[0] is a key,
 * tokens[1] is its value; tokens[2] is the next key with tokens[3] as its
 * value; etc. The `begin` and `end` describe the *pairs*, not the tokens:
 * when `begin == end == 1`, then the key is `tokens[2]` and the value is
 * `tokens[3]`.
 */
static void
insert_many(TST& tree, SimpleString tokens[], size_t begin, size_t end)
{
  if (end == begin) return;

  size_t mid = (begin + end - 1) >> 1;
  tree.insert(tokens[mid * 2], &tokens[mid * 2 + 1]);

  if (mid > begin) insert_many(tree, tokens, begin, mid);
  if (mid < end - 1) insert_many(tree, tokens, mid + 1, end);
}

TernaryBufferTree::TernaryBufferTree(const char* s, size_t len)
{
  this->mem = new char[len];
  memcpy(this->mem, s, len);

  size_t nTokens = count_char_in_str('\n', s, len) + 1;
  this->strings = new SimpleString[nTokens * 2];

  SimpleString* curString = &this->strings[0];
  bool foundTabThisLine = false;

  curString->s = this->mem;

  const char* end = this->mem + len;
  for (const char* p = this->mem; p < end; p++) {
    switch (*p) {
      case '\n':
        curString->len = p - curString->s;
        curString++;

        if (!foundTabThisLine) {
          curString++; // There's no value
        }
        foundTabThisLine = false;

        curString->s = &p[1]; // Start parsing the next line
        break;
      case '\t':
        curString->len = p - curString->s;
        curString++;
        foundTabThisLine = true;
        curString->s = &p[1]; // Start parsing the value
        break;
    }
  }
  curString->len = end - curString->s;

  insert_many(this->tree, this->strings, 0, nTokens);
}

TernaryBufferTree::~TernaryBufferTree()
{
  delete[] this->mem;
  delete[] this->strings;
}

bool
TernaryBufferTree::contains(const char* s, size_t len) const
{
  return this->tree.contains(s, len);
}

const SimpleString*
TernaryBufferTree::get(const char* s, size_t len) const
{
  return this->tree.get(s, len);
}

std::vector<SimpleString>
TernaryBufferTree::findAllMatches(const char* s, size_t len, size_t maxNgramSize) {
  std::vector<SimpleString> ret;
  std::deque<const char*> tokenStarts;
  const char* lastP = s;
  const char* end = s + len;

  tokenStarts.push_back(s);

  while (true) {
    const char* p = static_cast<const char*>(memchr(lastP, ' ', end - lastP));
    if (p == NULL) p = s + len;

    // Add s[tokenStarts[0],pos), s[tokenStarts[1],pos), ... for every token
    // in the set
    for (auto i = tokenStarts.begin(); i < tokenStarts.end(); i++) {
      const char* tokenStart = *i;
      if (this->tree.contains(tokenStart, p - tokenStart)) {
        ret.push_back(SimpleString(tokenStart, p - tokenStart));
      }
    }

    if (tokenStarts.size() == maxNgramSize) tokenStarts.pop_front();

    if (p == s + len) break;

    lastP = p + 1;
    tokenStarts.push_back(lastP);
  }

  return ret;
}

void
TernaryBufferTree::Init(Handle<Object> exports) {
  Isolate* isolate = Isolate::GetCurrent();

  // Prepare constructor template
  Local<FunctionTemplate> tpl = FunctionTemplate::New(isolate, New);
  tpl->SetClassName(String::NewFromUtf8(isolate, "TernaryBufferTree"));
  tpl->InstanceTemplate()->SetInternalFieldCount(1);

  // Prototype
  NODE_SET_PROTOTYPE_METHOD(tpl, "contains", Contains);
  NODE_SET_PROTOTYPE_METHOD(tpl, "get", Get);
  NODE_SET_PROTOTYPE_METHOD(tpl, "findAllMatches", FindAllMatches);

  constructor.Reset(isolate, tpl->GetFunction());
  exports->Set(String::NewFromUtf8(isolate, "TernaryBufferTree"), tpl->GetFunction());
}

void
TernaryBufferTree::New(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = Isolate::GetCurrent();
  HandleScope scope(isolate);

  if (args.IsConstructCall()) {
    // Invoked as constructor: `new MyObject(...)`
    const char* s = node::Buffer::Data(args[0]);
    const size_t len = node::Buffer::Length(args[0]);
    TernaryBufferTree* obj = new TernaryBufferTree(s, len);
    obj->Wrap(args.This());
    args.GetReturnValue().Set(args.This());
  } else {
    // Invoked as plain function `MyObject(...)`, turn into construct call
    Local<Value> argv[1] = { args[0] };
    Local<Function> cons = Local<Function>::New(isolate, constructor);
    args.GetReturnValue().Set(cons->NewInstance(1, argv));
  }
}

void TernaryBufferTree::Contains(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = Isolate::GetCurrent();
  HandleScope scope(isolate);
  TernaryBufferTree* obj = ObjectWrap::Unwrap<TernaryBufferTree>(args.Holder());

  bool ret = false;

  Local<Value> arg = args[0]; // Buffer or String

  if (node::Buffer::HasInstance(arg)) {
    // It's a buffer. Go char-by-char
    const char* data(node::Buffer::Data(arg));
    const size_t len(node::Buffer::Length(arg));

    ret = obj->contains(data, len);
  } else {
    // We can convert it to utf-8. On failure, it's just an empty String.
    String::Utf8Value argString(arg);
    ret = obj->contains(*argString, argString.length());
  }

  args.GetReturnValue().Set(ret);
}

void TernaryBufferTree::Get(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = Isolate::GetCurrent();
  HandleScope scope(isolate);
  TernaryBufferTree* obj = ObjectWrap::Unwrap<TernaryBufferTree>(args.Holder());

  const SimpleString* result;

  Local<Value> arg = args[0]; // Buffer or String

  if (node::Buffer::HasInstance(arg)) {
    // It's a buffer. Go char-by-char
    const char* data(node::Buffer::Data(arg));
    const size_t len(node::Buffer::Length(arg));

    result = obj->get(data, len);
  } else {
    // We can convert it to utf-8. On failure, it's just an empty String.
    String::Utf8Value argString(arg);
    result = obj->get(*argString, argString.length());
  }

  if (result != NULL) {
    Handle<String> ret(String::NewFromUtf8(isolate, result->s, String::NewStringType::kNormalString, result->len));
    args.GetReturnValue().Set(ret);
  }
}

void
TernaryBufferTree::FindAllMatches(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = Isolate::GetCurrent();
  HandleScope scope(isolate);
  TernaryBufferTree* obj = ObjectWrap::Unwrap<TernaryBufferTree>(args.Holder());

  std::vector<SimpleString> ret;
  Handle<Array> retArray;

  Local<Value> arg = args[0]; // Buffer or String
  uint32_t maxNgramSize = args[1]->Uint32Value();
  if (maxNgramSize == 0) maxNgramSize = 1;

  if (node::Buffer::HasInstance(arg)) {
    const char* data(node::Buffer::Data(arg));
    const size_t len(node::Buffer::Length(arg));
    ret = obj->findAllMatches(data, len, maxNgramSize);

    // Icky copy/paste, I know
    size_t size = ret.size();
    retArray = Array::New(isolate, size);
    for (size_t i = 0; i < size; i++) {
      retArray->Set(i, String::NewFromUtf8(isolate, ret[i].s, String::NewStringType::kNormalString, ret[i].len));
    }
  } else {
    // We can convert it to utf-8. On failure, it's just an empty String.
    String::Utf8Value argString(arg);
    ret = obj->findAllMatches(*argString, argString.length(), maxNgramSize);

    // Icky copy/paste, I know
    size_t size = ret.size();
    retArray = Array::New(isolate, size);
    for (size_t i = 0; i < size; i++) {
      retArray->Set(i, String::NewFromUtf8(isolate, ret[i].s, String::NewStringType::kNormalString, ret[i].len));
    }
  }

  args.GetReturnValue().Set(retArray);
}

void
init(Handle<Object> exports, Handle<Object> module) {
  TernaryBufferTree::Init(exports);
}

NODE_MODULE(binding, init);
<commit_msg>Optimize searches<commit_after>#include <cstring>
#include <deque>
#include <vector>

#include <iostream>
#include <string>

#include <node.h>
#include <node_buffer.h>
#include <node_object_wrap.h>
#include <v8.h>

#include "MemoryPool.h"

using namespace v8;

/**
 * A string whose characters are stored elsewhere.
 *
 * The argument-free constructor will return a "null string". Basically, it's
 * a hack that probably behaves the way you expect. (Its memory address is
 * NULL.)
 */
struct SimpleString
{
  const char* s;
  size_t len;

  SimpleString(const char* aS, size_t aLen) : s(aS), len(aLen) {}
  SimpleString() : s(NULL), len(0) {}
  SimpleString(const SimpleString& rhs) : s(rhs.s), len(rhs.len) {}

  inline bool isNull() const { return s == NULL; }
};

struct TSTNode
{
  char ch;
  TSTNode* left;
  TSTNode* eq;
  TSTNode* right;
  const SimpleString* value; // value != NULL iff this is a leaf node

  explicit TSTNode(char aCh)
    : ch(aCh),
      left(NULL),
      eq(NULL),
      right(NULL),
      value(NULL) {}

  ~TSTNode()
  {
    if (this->left) delete this->left;
    if (this->eq) delete this->eq;
    if (this->right) delete this->right;
  }
};

static const size_t NodePoolChunkSize = 65536; // 4096 is slower, according to perf.js

/**
 * Ternary search tree.
 *
 * Every string inserted into this tree will be an external one. That means the
 * caller must ensure none of those strings are freed until the TST is deleted.
 */
class TST
{
public:
  void insert(const SimpleString& key, const SimpleString* value)
  {
    if (key.len == 0) return; // We don't store zero-length strings

    this->_insert(&this->root, key.s, key.len, value);
  }

  bool contains(const char* s, size_t len) const
  {
    const TSTNode* node = this->getNode(s, len);

    return node != NULL;
  }

  const SimpleString* get(const char* s, size_t len) const
  {
    const TSTNode* node = this->getNode(s, len);

    if (node == NULL) {
      return NULL;
    } else if (node->value->isNull()) {
      // Every leaf node has a value, but it might be a null string.
      return NULL;
    } else {
      return node->value;
    }
  }

  explicit TST() : root(NULL) {}

private:
  TSTNode* root;
  MemoryPool<TSTNode,NodePoolChunkSize> pool;

  void _insert(TSTNode** nodeAddress, const char* s, size_t len, const SimpleString* value) {
    char ch = *s;

    if (*nodeAddress == NULL) {
      *nodeAddress = pool.newElement(ch);
      // All the nodes get deleted by the MemoryPool when we destroy the TST
    }

    TSTNode* node = *nodeAddress;

    if (ch < node->ch) {
      this->_insert(&node->left, s, len, value);
    } else if (ch > node->ch) {
      this->_insert(&node->right, s, len, value);
    } else if (len > 1) {
      this->_insert(&node->eq, &s[1], len - 1, value);
    } else {
      node->value = value;
    }
  }

  const TSTNode* getNode(const char* s, size_t len) const {
    if (len == 0) return NULL; // We don't store zero-length strings

    const TSTNode* node = this->root;

    for (;;) {
      if (node == NULL) return NULL; // No match

      char ch = *s;

      if (ch < node->ch) {
        node = node->left;
      } else if (ch > node->ch) {
        node = node->right;
      } else if (len > 1) {
        node = node->eq;
        s++;
        len--;
      } else if (node->value != NULL) {
        return node; // match
      } else {
        return NULL; // end of search
      }
    }
  }
};

class TernaryBufferTree : public node::ObjectWrap {
public:
  static void Init(Handle<Object> exports);
  static Persistent<Function> constructor;

  inline bool contains(const char* s, size_t len) const;
  const SimpleString* get(const char* s, size_t len) const;
  std::vector<SimpleString> findAllMatches(const char* s, size_t len, size_t maxNgramSize);

private:
  char* mem = NULL;
  SimpleString* strings = NULL;
  TST tree;

  explicit TernaryBufferTree(const char* s, size_t len);
  ~TernaryBufferTree();

  static void New(const FunctionCallbackInfo<Value>& args);
  static void Contains(const FunctionCallbackInfo<Value>& args);
  static void Get(const FunctionCallbackInfo<Value>& args);
  static void FindAllMatches(const FunctionCallbackInfo<Value>& args);
};

Persistent<Function> TernaryBufferTree::constructor;

static size_t
count_char_in_str(char ch, const char* s, size_t len) {
  size_t ret = 0;

  while (len > 0) {
    if (*s == ch) ret++;
    len--;
    s++;
  }

  return ret;
}

/**
 * Insert Strings into a TST.
 *
 * We assume the Strings are sorted. Insert the median first, then recurse.
 * That's described in "Better Insertion Orders" at
 * http://www.drdobbs.com/database/ternary-search-trees/184410528?pgno=2
 *
 * The `tokens` passed here are in *pairs*: that is, tokens[0] is a key,
 * tokens[1] is its value; tokens[2] is the next key with tokens[3] as its
 * value; etc. The `begin` and `end` describe the *pairs*, not the tokens:
 * when `begin == end == 1`, then the key is `tokens[2]` and the value is
 * `tokens[3]`.
 */
static void
insert_many(TST& tree, SimpleString tokens[], size_t begin, size_t end)
{
  if (end == begin) return;

  size_t mid = (begin + end - 1) >> 1;
  tree.insert(tokens[mid * 2], &tokens[mid * 2 + 1]);

  if (mid > begin) insert_many(tree, tokens, begin, mid);
  if (mid < end - 1) insert_many(tree, tokens, mid + 1, end);
}

TernaryBufferTree::TernaryBufferTree(const char* s, size_t len)
{
  this->mem = new char[len];
  memcpy(this->mem, s, len);

  size_t nTokens = count_char_in_str('\n', s, len) + 1;
  this->strings = new SimpleString[nTokens * 2];

  SimpleString* curString = &this->strings[0];
  bool foundTabThisLine = false;

  curString->s = this->mem;

  const char* end = this->mem + len;
  for (const char* p = this->mem; p < end; p++) {
    switch (*p) {
      case '\n':
        curString->len = p - curString->s;
        curString++;

        if (!foundTabThisLine) {
          curString++; // There's no value
        }
        foundTabThisLine = false;

        curString->s = &p[1]; // Start parsing the next line
        break;
      case '\t':
        curString->len = p - curString->s;
        curString++;
        foundTabThisLine = true;
        curString->s = &p[1]; // Start parsing the value
        break;
    }
  }
  curString->len = end - curString->s;

  insert_many(this->tree, this->strings, 0, nTokens);
}

TernaryBufferTree::~TernaryBufferTree()
{
  delete[] this->mem;
  delete[] this->strings;
}

bool
TernaryBufferTree::contains(const char* s, size_t len) const
{
  return this->tree.contains(s, len);
}

const SimpleString*
TernaryBufferTree::get(const char* s, size_t len) const
{
  return this->tree.get(s, len);
}

std::vector<SimpleString>
TernaryBufferTree::findAllMatches(const char* s, size_t len, size_t maxNgramSize) {
  std::vector<SimpleString> ret;
  std::deque<const char*> tokenStarts;
  const char* lastP = s;
  const char* end = s + len;

  tokenStarts.push_back(s);

  while (true) {
    const char* p = static_cast<const char*>(memchr(lastP, ' ', end - lastP));
    if (p == NULL) p = s + len;

    // Add s[tokenStarts[0],pos), s[tokenStarts[1],pos), ... for every token
    // in the set
    for (auto i = tokenStarts.begin(); i < tokenStarts.end(); i++) {
      const char* tokenStart = *i;
      if (this->tree.contains(tokenStart, p - tokenStart)) {
        ret.push_back(SimpleString(tokenStart, p - tokenStart));
      }
    }

    if (tokenStarts.size() == maxNgramSize) tokenStarts.pop_front();

    if (p == s + len) break;

    lastP = p + 1;
    tokenStarts.push_back(lastP);
  }

  return ret;
}

void
TernaryBufferTree::Init(Handle<Object> exports) {
  Isolate* isolate = Isolate::GetCurrent();

  // Prepare constructor template
  Local<FunctionTemplate> tpl = FunctionTemplate::New(isolate, New);
  tpl->SetClassName(String::NewFromUtf8(isolate, "TernaryBufferTree"));
  tpl->InstanceTemplate()->SetInternalFieldCount(1);

  // Prototype
  NODE_SET_PROTOTYPE_METHOD(tpl, "contains", Contains);
  NODE_SET_PROTOTYPE_METHOD(tpl, "get", Get);
  NODE_SET_PROTOTYPE_METHOD(tpl, "findAllMatches", FindAllMatches);

  constructor.Reset(isolate, tpl->GetFunction());
  exports->Set(String::NewFromUtf8(isolate, "TernaryBufferTree"), tpl->GetFunction());
}

void
TernaryBufferTree::New(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = Isolate::GetCurrent();
  HandleScope scope(isolate);

  if (args.IsConstructCall()) {
    // Invoked as constructor: `new MyObject(...)`
    const char* s = node::Buffer::Data(args[0]);
    const size_t len = node::Buffer::Length(args[0]);
    TernaryBufferTree* obj = new TernaryBufferTree(s, len);
    obj->Wrap(args.This());
    args.GetReturnValue().Set(args.This());
  } else {
    // Invoked as plain function `MyObject(...)`, turn into construct call
    Local<Value> argv[1] = { args[0] };
    Local<Function> cons = Local<Function>::New(isolate, constructor);
    args.GetReturnValue().Set(cons->NewInstance(1, argv));
  }
}

void TernaryBufferTree::Contains(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = Isolate::GetCurrent();
  HandleScope scope(isolate);
  TernaryBufferTree* obj = ObjectWrap::Unwrap<TernaryBufferTree>(args.Holder());

  bool ret = false;

  Local<Value> arg = args[0]; // Buffer or String

  if (node::Buffer::HasInstance(arg)) {
    // It's a buffer. Go char-by-char
    const char* data(node::Buffer::Data(arg));
    const size_t len(node::Buffer::Length(arg));

    ret = obj->contains(data, len);
  } else {
    // We can convert it to utf-8. On failure, it's just an empty String.
    String::Utf8Value argString(arg);
    ret = obj->contains(*argString, argString.length());
  }

  args.GetReturnValue().Set(ret);
}

void TernaryBufferTree::Get(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = Isolate::GetCurrent();
  HandleScope scope(isolate);
  TernaryBufferTree* obj = ObjectWrap::Unwrap<TernaryBufferTree>(args.Holder());

  const SimpleString* result;

  Local<Value> arg = args[0]; // Buffer or String

  if (node::Buffer::HasInstance(arg)) {
    // It's a buffer. Go char-by-char
    const char* data(node::Buffer::Data(arg));
    const size_t len(node::Buffer::Length(arg));

    result = obj->get(data, len);
  } else {
    // We can convert it to utf-8. On failure, it's just an empty String.
    String::Utf8Value argString(arg);
    result = obj->get(*argString, argString.length());
  }

  if (result != NULL) {
    Handle<String> ret(String::NewFromUtf8(isolate, result->s, String::NewStringType::kNormalString, result->len));
    args.GetReturnValue().Set(ret);
  }
}

void
TernaryBufferTree::FindAllMatches(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = Isolate::GetCurrent();
  HandleScope scope(isolate);
  TernaryBufferTree* obj = ObjectWrap::Unwrap<TernaryBufferTree>(args.Holder());

  std::vector<SimpleString> ret;
  Handle<Array> retArray;

  Local<Value> arg = args[0]; // Buffer or String
  uint32_t maxNgramSize = args[1]->Uint32Value();
  if (maxNgramSize == 0) maxNgramSize = 1;

  if (node::Buffer::HasInstance(arg)) {
    const char* data(node::Buffer::Data(arg));
    const size_t len(node::Buffer::Length(arg));
    ret = obj->findAllMatches(data, len, maxNgramSize);

    // Icky copy/paste, I know
    size_t size = ret.size();
    retArray = Array::New(isolate, size);
    for (size_t i = 0; i < size; i++) {
      retArray->Set(i, String::NewFromUtf8(isolate, ret[i].s, String::NewStringType::kNormalString, ret[i].len));
    }
  } else {
    // We can convert it to utf-8. On failure, it's just an empty String.
    String::Utf8Value argString(arg);
    ret = obj->findAllMatches(*argString, argString.length(), maxNgramSize);

    // Icky copy/paste, I know
    size_t size = ret.size();
    retArray = Array::New(isolate, size);
    for (size_t i = 0; i < size; i++) {
      retArray->Set(i, String::NewFromUtf8(isolate, ret[i].s, String::NewStringType::kNormalString, ret[i].len));
    }
  }

  args.GetReturnValue().Set(retArray);
}

void
init(Handle<Object> exports, Handle<Object> module) {
  TernaryBufferTree::Init(exports);
}

NODE_MODULE(binding, init);
<|endoftext|>


<commit_before>// Filename: mayaSavePview.cxx
// Created by:  drose (27Oct03)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license.  You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////

#include "mayaSavePview.h"

#include <maya/MString.h>
#include <maya/MFnPlugin.h>
#include <maya/MFileIO.h>

#include <stdlib.h>

////////////////////////////////////////////////////////////////////
//     Function: MayaSavePview::Constructor
//       Access: Public
//  Description:
////////////////////////////////////////////////////////////////////
MayaSavePview::
MayaSavePview() {
}

////////////////////////////////////////////////////////////////////
//     Function: MayaSavePview::doIt
//       Access: Public, Virtual
//  Description: Called when the plugin command is invoked.
////////////////////////////////////////////////////////////////////
MStatus MayaSavePview::
doIt(const MArgList &) {
  MStatus result;

  // First, make sure the current buffer is saved.
  result = MFileIO::save(false);
  if (result != MS::kSuccess) {
    return result;
  }

  MString filename = MFileIO::currentFile();
  MString command = MString("pview \"") + filename + MString("\"");

  int command_result = system(command.asChar());
  if (command_result != 0) {
    return MS::kFailure;
  }

  return MS::kSuccess;
}

////////////////////////////////////////////////////////////////////
//     Function: MayaSavePview::creator
//       Access: Public, Static
//  Description: This is used to create a new instance of the plugin.
////////////////////////////////////////////////////////////////////
void *MayaSavePview::
creator() {
  return new MayaSavePview;
}

////////////////////////////////////////////////////////////////////
//     Function: initializePlugin
//  Description: Called by Maya when the plugin is loaded.
////////////////////////////////////////////////////////////////////
EXPCL_MISC MStatus
initializePlugin(MObject obj) {
  MFnPlugin plugin(obj, "VR Studio", "1.0");
  MStatus status;
  status = plugin.registerCommand("savePview", MayaSavePview::creator);
  if (!status) {
    status.perror("registerCommand");
  }

  return status;
}

////////////////////////////////////////////////////////////////////
//     Function: uninitializePlugin
//  Description: Called by Maya when the plugin is unloaded.
////////////////////////////////////////////////////////////////////
EXPCL_MISC MStatus
uninitializePlugin(MObject obj) {
  MFnPlugin plugin(obj);
  MStatus status;
  status = plugin.deregisterCommand("savePview");

  if (!status) {
    status.perror("deregisterCommand");
  }
  return status;
}
<commit_msg>call it pview, and use the -c option<commit_after>// Filename: mayaSavePview.cxx
// Created by:  drose (27Oct03)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license.  You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////

#include "mayaSavePview.h"

#include <maya/MString.h>
#include <maya/MFnPlugin.h>
#include <maya/MFileIO.h>

#include <stdlib.h>

////////////////////////////////////////////////////////////////////
//     Function: MayaSavePview::Constructor
//       Access: Public
//  Description:
////////////////////////////////////////////////////////////////////
MayaSavePview::
MayaSavePview() {
}

////////////////////////////////////////////////////////////////////
//     Function: MayaSavePview::doIt
//       Access: Public, Virtual
//  Description: Called when the plugin command is invoked.
////////////////////////////////////////////////////////////////////
MStatus MayaSavePview::
doIt(const MArgList &) {
  MStatus result;

  // First, make sure the current buffer is saved.
  result = MFileIO::save(false);
  if (result != MS::kSuccess) {
    return result;
  }

  MString filename = MFileIO::currentFile();
  MString command = MString("pview -c \"") + filename + MString("\"");

  int command_result = system(command.asChar());
  if (command_result != 0) {
    return MS::kFailure;
  }

  return MS::kSuccess;
}

////////////////////////////////////////////////////////////////////
//     Function: MayaSavePview::creator
//       Access: Public, Static
//  Description: This is used to create a new instance of the plugin.
////////////////////////////////////////////////////////////////////
void *MayaSavePview::
creator() {
  return new MayaSavePview;
}

////////////////////////////////////////////////////////////////////
//     Function: initializePlugin
//  Description: Called by Maya when the plugin is loaded.
////////////////////////////////////////////////////////////////////
EXPCL_MISC MStatus
initializePlugin(MObject obj) {
  MFnPlugin plugin(obj, "VR Studio", "1.0");
  MStatus status;
  status = plugin.registerCommand("pview", MayaSavePview::creator);
  if (!status) {
    status.perror("registerCommand");
  }

  return status;
}

////////////////////////////////////////////////////////////////////
//     Function: uninitializePlugin
//  Description: Called by Maya when the plugin is unloaded.
////////////////////////////////////////////////////////////////////
EXPCL_MISC MStatus
uninitializePlugin(MObject obj) {
  MFnPlugin plugin(obj);
  MStatus status;
  status = plugin.deregisterCommand("pview");

  if (!status) {
    status.perror("deregisterCommand");
  }
  return status;
}
<|endoftext|>


<commit_before>#include "easyjobserver.h"
#include <votca/csg/nblist.h>
#include <qmnblist.h>
#include <votca/tools/histogramnew.h>

EasyJObserver::EasyJObserver()
{}

EasyJObserver::~EasyJObserver()
{}

void EasyJObserver::Initialize(QMTopology &qmtop, Property &opts)
{
    _qmtop = &qmtop;
    _kT = opts.get("calc_rates.thermal_energy").as<double>();
    _E = opts.get("calc_rates.e_field").as<vec>();
    cout << "E = " << _E << endl;
}

void EasyJObserver::setNNnames(string  nnnames){
    Tokenizer tok(nnnames, " ;");
    Tokenizer::iterator itok = tok.begin();
    for (; itok!= tok.end(); ++itok){
        _nnnames.push_back(*itok);
    }
}
void EasyJObserver::BeginCG(Topology *top, Topology *top_atom)
{
    _qmtop->Initialize(*top);
}

void EasyJObserver::EndCG()
{
    HistogramNew histo;
    histo.Initialize(*(std::min_element( _Js.begin(), _Js.end() )),*(std::max_element( _Js.begin(), _Js.end() ) ) , int(_Js.size() / 10 ));
    histo.ProcessRange(_Js.begin(),_Js.end());
    cout << histo <<endl;
}

/// evaluate current conformation

void EasyJObserver::EvalConfiguration(Topology *top, Topology *top_atom)
{
    _qmtop->Update(*top);
    QMNBList &nblist = _qmtop->nblist();

    BeadList list1;
    Topology *toptmp = dynamic_cast<Topology*>(_qmtop);
    list1.Generate(*toptmp, "*");

    nblist.setCutoff(_cutoff);
    nblist.Generate(list1);
    for(QMNBList::iterator iter = nblist.begin();
        iter!=nblist.end();++iter) {
        CrgUnit *crg1 = (*iter)->first;
        CrgUnit *crg2 = (*iter)->second;
         if(MatchNNnames(crg1, crg2)){
            vector <double> Js = _qmtop->GetJCalc().GetJ(*crg1, *crg2);
            //cout << crg1->GetId() << " " << crg2->GetId() << " ";
            for(int i=0; i<Js.size(); ++i)
            {
                _Js.push_back(Js[i]);
            }
            (*iter)->setJ(Js[0]);
         }
    }
    CalcRates(nblist);
    MakeRatesSIUnits(nblist);
    print_nbs_to_file(nblist);
    cout<<"Falks test\n";
    StateSaver _saver(*_qmtop);
    string outfilename = "falks.dat";
   _saver.Open(outfilename,true);
   _saver.Write_QMBeads(_qmtop);
}

bool EasyJObserver::MatchNNnames(CrgUnit *crg1, CrgUnit* crg2){
    vector <string>::iterator its = _nnnames.begin();
    string namecrg = crg1->GetType()->GetName()+string(":")+crg2->GetType()->GetName();
    for ( ; its!= _nnnames.end(); ++its){
        if(wildcmp(its->c_str(), namecrg.c_str()) ){
            return true;
        }
    }
    return false;
}

void EasyJObserver::CalcRates(QMNBList &nblist){
    for(QMNBList::iterator iter = nblist.begin();iter!=nblist.end();++iter)
    {
        double rate = 0.0;
        double Jeff = (*iter)->j();
        //cout << "Jeff = " << Jeff << endl;
        CrgUnit *crg1 = (*iter)->first;
        CrgUnit *crg2 = (*iter)->second;
        if(MatchNNnames(crg1, crg2))
        {
            double prefactor = 1.0;
            /// reorganization energy in eV as given in list_charges.xml
            double reorg = 0.5 * (crg1->GetType()->GetReorg()+crg2->GetType()->GetReorg());
            /// free energy difference due to electric field, i.e. E*r_ij
            double dG_field = -_E * ((*iter)->r()) * RA * Ang;
            /// free energy difference due to different energy levels of molecules
            double dG_en = crg2->GetNRG() - crg1->GetNRG();
            /// electrostatics are taken into account in qmtopology and are contained in NRG
            /// total free energy difference
            double dG = dG_field + dG_en;
            /// Marcus rate
            rate = prefactor * sqrt(PI/(reorg * _kT)) * Jeff * Jeff *
                exp (-(dG + reorg)*(dG + reorg)/(4*_kT*reorg));
            //cout << "Rate: " << rate << endl;
            //cout << "dG_field = " << dG_field << endl;
        }
        (*iter)->setRate(rate);
    }
}

void EasyJObserver::MakeRatesSIUnits(QMNBList &nblist){
    for(QMNBList::iterator iter = nblist.begin();iter!=nblist.end();++iter)
    {
        (*iter)->rate() *= 1/hbar;
    }
}

void EasyJObserver::print_nbs_to_file(QMNBList &nblist){
    ofstream out_nbl;
    out_nbl.open("nbl_votca.res");
    if(out_nbl!=0){
        out_nbl << "Neighbours, J(0), J_eff, rate, r_ij, abs(r_ij) [Bohr]" << endl;
        QMNBList::iterator iter;
        for ( iter  = nblist.begin(); iter != nblist.end() ; ++iter){
            out_nbl << "(" << (*iter)->first->GetId() << "," << (*iter)->second->GetId() << "): ";
            out_nbl << (*iter)->j() << " " << abs((*iter)->j()) << " " << (*iter)->rate() << " ";
            out_nbl << (*iter)->r().getX() << " " << (*iter)->r().getY() << " " << (*iter)->r().getZ() << " ";
            out_nbl << " " << abs((*iter)->r()) << endl;
        }
    }
    out_nbl.close();
}<commit_msg>added function make_kmc_graph<commit_after>#include "easyjobserver.h"
#include <votca/csg/nblist.h>
#include <qmnblist.h>
#include <votca/tools/histogramnew.h>
#include <kmc/vertex.h>

EasyJObserver::EasyJObserver()
{}

EasyJObserver::~EasyJObserver()
{}

void EasyJObserver::Initialize(QMTopology &qmtop, Property &opts)
{
    _qmtop = &qmtop;
    _kT = opts.get("calc_rates.thermal_energy").as<double>();
    _E = opts.get("calc_rates.e_field").as<vec>();
    cout << "E = " << _E << endl;
}

void EasyJObserver::setNNnames(string  nnnames){
    Tokenizer tok(nnnames, " ;");
    Tokenizer::iterator itok = tok.begin();
    for (; itok!= tok.end(); ++itok){
        _nnnames.push_back(*itok);
    }
}
void EasyJObserver::BeginCG(Topology *top, Topology *top_atom)
{
    _qmtop->Initialize(*top);
}

void EasyJObserver::EndCG()
{
    HistogramNew histo;
    histo.Initialize(*(std::min_element( _Js.begin(), _Js.end() )),*(std::max_element( _Js.begin(), _Js.end() ) ) , int(_Js.size() / 10 ));
    histo.ProcessRange(_Js.begin(),_Js.end());
    cout << histo <<endl;
}

/// evaluate current conformation

void EasyJObserver::EvalConfiguration(Topology *top, Topology *top_atom)
{
    _qmtop->Update(*top);
    QMNBList &nblist = _qmtop->nblist();

    BeadList list1;
    Topology *toptmp = dynamic_cast<Topology*>(_qmtop);
    list1.Generate(*toptmp, "*");

    nblist.setCutoff(_cutoff);
    nblist.Generate(list1);
    for(QMNBList::iterator iter = nblist.begin();
        iter!=nblist.end();++iter) {
        CrgUnit *crg1 = (*iter)->first;
        CrgUnit *crg2 = (*iter)->second;
         if(MatchNNnames(crg1, crg2)){
            vector <double> Js = _qmtop->GetJCalc().GetJ(*crg1, *crg2);
            //cout << crg1->GetId() << " " << crg2->GetId() << " ";
            for(int i=0; i<Js.size(); ++i)
            {
                _Js.push_back(Js[i]);
            }
            (*iter)->setJ(Js[0]);
         }
    }
    CalcRates(nblist);
    MakeRatesSIUnits(nblist);
    print_nbs_to_file(nblist);
    graph kmc_grid;
    make_kmc_graph(&kmc_grid,nblist);

    cout<<"Falks test\n";
    StateSaver _saver(*_qmtop);
    string outfilename = "falks.dat";
   _saver.Open(outfilename,true);
   _saver.Write_QMBeads(_qmtop);
}

bool EasyJObserver::MatchNNnames(CrgUnit *crg1, CrgUnit* crg2){
    vector <string>::iterator its = _nnnames.begin();
    string namecrg = crg1->GetType()->GetName()+string(":")+crg2->GetType()->GetName();
    for ( ; its!= _nnnames.end(); ++its){
        if(wildcmp(its->c_str(), namecrg.c_str()) ){
            return true;
        }
    }
    return false;
}

void EasyJObserver::CalcRates(QMNBList &nblist){
    for(QMNBList::iterator iter = nblist.begin();iter!=nblist.end();++iter)
    {
        double rate_12, rate_21 = 0.0;
        double Jeff = (*iter)->j();
        //cout << "Jeff = " << Jeff << endl;
        CrgUnit *crg1 = (*iter)->first;
        CrgUnit *crg2 = (*iter)->second;
        if(MatchNNnames(crg1, crg2))
        {
            double prefactor = 1.0;
            /// reorganization energy in eV as given in list_charges.xml
            double reorg = 0.5 * (crg1->GetType()->GetReorg()+crg2->GetType()->GetReorg());
            /// free energy difference due to electric field, i.e. E*r_ij
            double dG_field = -_E * ((*iter)->r()) * RA * Ang;
            /// free energy difference due to different energy levels of molecules
            double dG_en = crg2->GetNRG() - crg1->GetNRG();
            /// electrostatics are taken into account in qmtopology and are contained in NRG
            /// total free energy difference
            double dG = dG_field + dG_en;
            /// Marcus rate from first to second
            rate_12 = prefactor * sqrt(PI/(reorg * _kT)) * Jeff * Jeff *
                exp (-(dG + reorg)*(dG + reorg)/(4*_kT*reorg));
            /// Marcus rate from second to first (dG_field -> -dG_field)
            dG = -dG_field + dG_en;
            rate_21 = prefactor * sqrt(PI/(reorg * _kT)) * Jeff * Jeff *
                exp (-(dG + reorg)*(dG + reorg)/(4*_kT*reorg));
        }
        (*iter)->setRate12(rate_12);
        (*iter)->setRate21(rate_21);
    }
}

void EasyJObserver::MakeRatesSIUnits(QMNBList &nblist){
    for(QMNBList::iterator iter = nblist.begin();iter!=nblist.end();++iter)
    {
        (*iter)->rate12() *= 1/hbar;
        (*iter)->rate21() *= 1/hbar;
    }
}

void EasyJObserver::print_nbs_to_file(QMNBList &nblist){
    ofstream out_nbl;
    out_nbl.open("nbl_votca.res");
    if(out_nbl!=0){
        out_nbl << "Neighbours, J(0), J_eff, rate, r_ij, abs(r_ij) [Bohr]" << endl;
        QMNBList::iterator iter;
        for ( iter  = nblist.begin(); iter != nblist.end() ; ++iter){
            out_nbl << "(" << (*iter)->first->GetId() << "," << (*iter)->second->GetId() << "): ";
            out_nbl << (*iter)->j() << " " << abs((*iter)->j()) << " " << (*iter)->rate12() << " ";
            out_nbl << (*iter)->r().getX() << " " << (*iter)->r().getY() << " " << (*iter)->r().getZ() << " ";
            out_nbl << " " << abs((*iter)->r()) << endl;
        }
    }
    out_nbl.close();
}

void EasyJObserver::make_kmc_graph(graph *a, QMNBList &nblist){
    cout << "[make_kmc_graph]: Building KMC Graph...";
    /// assign constants
    a->SetField(_E);
    /// set vertices equal to centers of mass
    BeadContainer::iterator it;
    for(it=_qmtop->Beads().begin(); it!=_qmtop->Beads().end(); ++it){
        a->AddVertex((*it)->getPos(),_E); /// TO DO: remove necessity for E-field at this point
    }
    /// set edges, two edges 1->2 and 2->1 are created per neighboring pair
    for(QMNBList::iterator iter = nblist.begin(); iter!=nblist.end();++iter){
        a->AddEdge((*iter)->first->GetId(), (*iter)->second->GetId(), (*iter)->rate12(),(*iter)->r());
        a->AddEdge((*iter)->second->GetId(), (*iter)->first->GetId(), (*iter)->rate21(),-(*iter)->r());
    }
    cout << " Done." << endl;
}<|endoftext|>


<commit_before>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999 The Apache Software Foundation.  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.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
 * ITS 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.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/**
 * $Log$
 * Revision 1.3  2000/01/19 00:56:59  roddey
 * Changes to get rid of dependence on old utils standard streams and to
 * get rid of the fgLibLocation stuff.
 *
 * Revision 1.2  2000/01/12 00:16:22  roddey
 * Changes to deal with multiply nested, relative pathed, entities and to deal
 * with the new URL class changes.
 *
 * Revision 1.1.1.1  1999/11/09 01:04:55  twl
 * Initial checkin
 *
 * Revision 1.3  1999/11/08 20:45:11  rahul
 * Swat for adding in Product name and CVS comment log variable.
 *
 */

#if !defined(PLATFORMUTILS_HPP)
#define PLATFORMUTILS_HPP

#include <util/XML4CDefs.hpp>
#include <util/XMLException.hpp>
#include <util/XMLUni.hpp>

class XMLMsgLoader;
class XMLNetAccessor;
class XMLTransService;

//
//  Generate an exception for platform utitilities to throw when something
//  goes awry.
//
const XMLCh gXMLPlatformUtilsException_Name[] =
{
        chLatin_X, chLatin_M, chLatin_L, chLatin_P, chLatin_l, chLatin_a
    ,   chLatin_t, chLatin_f, chLatin_o, chLatin_r, chLatin_m, chLatin_E
    ,   chLatin_x, chLatin_c, chLatin_e, chLatin_p, chLatin_t, chLatin_i
    ,   chLatin_o, chLatin_n, chNull
};
MakeXML4CException(XMLPlatformUtilsException, XMLUTIL_EXPORT)

class XMLUTIL_EXPORT XMLPlatformUtils
{
public :
    // -----------------------------------------------------------------------
    //  Public types
    // -----------------------------------------------------------------------
    enum PanicReasons
    {
        Panic_NoTransService
        , Panic_NoDefTranscoder
        , Panic_CantFindLib
        , Panic_UnknownMsgDomain
        , Panic_CantLoadMsgDomain

        , PanicReasons_Count
    };

    // -----------------------------------------------------------------------
    //  Public, static data
    //
    //  fgNetAccessor
    //      This is the network access implementation. This is provided by
    //      the per-platform driver, so each platform can choose what actual
    //      implementation it wants to use.
    //
    //  fgTransService
    //      This is the transcoding service. This is provided by the per
    //      platform driver, so each platform can choose what implemenation
    //      it wants to use.
    // -----------------------------------------------------------------------
    static XMLNetAccessor*      fgNetAccessor;
    static XMLTransService*     fgTransService;

    // -----------------------------------------------------------------------
    //  Initialization method. This must be called first in any client code.
    // -----------------------------------------------------------------------
    static void Initialize();

    // -----------------------------------------------------------------------
    //  The panic mechanism. If, during init, we cannot even get far enough
    //  along to get transcoding up or get message loading working, we call
    //  this.
    //
    //  Each platform can implement it however they want. This method is
    //  expected to display something meaningful and end the process. The
    //  enum indicates why its being called, to allow the per-platform code
    //  to display something more specific if desired.
    // -----------------------------------------------------------------------
    static void panic
    (
        const   PanicReasons    reason
    );

    // -----------------------------------------------------------------------
    //  File methods
    // -----------------------------------------------------------------------
    static unsigned int curFilePos(FileHandle theFile);
    static void closeFile(FileHandle theFile);
    static unsigned int fileSize(FileHandle theFile);
    static FileHandle openFile(const char* const fileName);
    static FileHandle openFile(const XMLCh* const fileName);
    static FileHandle openStdInHandle();
    static unsigned int readFileBuffer
    (
                FileHandle      theFile
        , const unsigned int    toRead
        ,       XMLByte* const  toFill
    );
    static void resetFile(FileHandle theFile);

    // -----------------------------------------------------------------------
    //  File system methods
    // -----------------------------------------------------------------------
    static XMLCh* getFullPath(const XMLCh* const srcPath);
    static bool isRelative(const XMLCh* const toCheck);
    static XMLCh* weavePaths
    (
        const   XMLCh* const    basePath
        , const XMLCh* const    relativePath
    );

    // -----------------------------------------------------------------------
    //  Timing methods
    // -----------------------------------------------------------------------
    static unsigned long getCurrentMillis();

    // -----------------------------------------------------------------------
    //  Mutex methods
    // -----------------------------------------------------------------------
    static void closeMutex(void* const mtxHandle);
    static void lockMutex(void* const mtxHandle);
    static void* makeMutex();
    static void unlockMutex(void* const mtxHandle);

    // -----------------------------------------------------------------------
    //  External message support
    // -----------------------------------------------------------------------
    static XMLMsgLoader* loadMsgSet(const XMLCh* const msgDomain);

    // -----------------------------------------------------------------------
    //  Miscellaneous synchronization methods
    // -----------------------------------------------------------------------
    static void* compareAndSwap
    (
                void**      toFill
        , const void* const newValue
        , const void* const toCompare
    );

    // -----------------------------------------------------------------------
    //  Atomic Increment and Decrement
    //
    //  The function return value is positive if the result of the operation
    //  was positive. Zero if the result of the operation was zero. Negative
    //  if the result of the operation was negative. Except for the zero
    //  case, the value returned may differ from the actual result of the
    //  operation - only the sign and zero/nonzero state is guaranteed to be
    //  correct.
    // -----------------------------------------------------------------------
    static int atomicIncrement(int& location);
    static int atomicDecrement(int& location);

private :
    // -----------------------------------------------------------------------
    //  Private static methods. These are provided by the per-platform
    //  implementation files.
    // -----------------------------------------------------------------------
    static XMLMsgLoader* loadAMsgSet(const XMLCh* const msgDomain);
    static XMLNetAccessor* makeNetAccessor();
    static XMLTransService* makeTransService();
    static void platformInit();

    // -----------------------------------------------------------------------
    //  Private static data members
    //
    //  fgInitFlag
    //      This is used to avoid multiple inits if the client code calls us
    //      more than once. They aren't supposed to, but some have trouble
    //      keeping up if they are COM objects and such.
    // -----------------------------------------------------------------------
    static bool     fgInitFlag;
};

#endif
<commit_msg>Added two more 'panic' values, which were requested by folks who needed to report a couple more panic situations.<commit_after>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999 The Apache Software Foundation.  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.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
 * ITS 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.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/**
 * $Log$
 * Revision 1.4  2000/01/25 21:34:23  roddey
 * Added two more 'panic' values, which were requested by folks who needed
 * to report a couple more panic situations.
 *
 * Revision 1.3  2000/01/19 00:56:59  roddey
 * Changes to get rid of dependence on old utils standard streams and to
 * get rid of the fgLibLocation stuff.
 *
 * Revision 1.2  2000/01/12 00:16:22  roddey
 * Changes to deal with multiply nested, relative pathed, entities and to deal
 * with the new URL class changes.
 *
 * Revision 1.1.1.1  1999/11/09 01:04:55  twl
 * Initial checkin
 *
 * Revision 1.3  1999/11/08 20:45:11  rahul
 * Swat for adding in Product name and CVS comment log variable.
 *
 */

#if !defined(PLATFORMUTILS_HPP)
#define PLATFORMUTILS_HPP

#include <util/XML4CDefs.hpp>
#include <util/XMLException.hpp>
#include <util/XMLUni.hpp>

class XMLMsgLoader;
class XMLNetAccessor;
class XMLTransService;

//
//  Generate an exception for platform utitilities to throw when something
//  goes awry.
//
const XMLCh gXMLPlatformUtilsException_Name[] =
{
        chLatin_X, chLatin_M, chLatin_L, chLatin_P, chLatin_l, chLatin_a
    ,   chLatin_t, chLatin_f, chLatin_o, chLatin_r, chLatin_m, chLatin_E
    ,   chLatin_x, chLatin_c, chLatin_e, chLatin_p, chLatin_t, chLatin_i
    ,   chLatin_o, chLatin_n, chNull
};
MakeXML4CException(XMLPlatformUtilsException, XMLUTIL_EXPORT)

class XMLUTIL_EXPORT XMLPlatformUtils
{
public :
    // -----------------------------------------------------------------------
    //  Public types
    // -----------------------------------------------------------------------
    enum PanicReasons
    {
        Panic_NoTransService
        , Panic_NoDefTranscoder
        , Panic_CantFindLib
        , Panic_UnknownMsgDomain
        , Panic_CantLoadMsgDomain
        , Panic_SynchronizationErr
        , Panic_SystemInit

        , PanicReasons_Count
    };

    // -----------------------------------------------------------------------
    //  Public, static data
    //
    //  fgNetAccessor
    //      This is the network access implementation. This is provided by
    //      the per-platform driver, so each platform can choose what actual
    //      implementation it wants to use.
    //
    //  fgTransService
    //      This is the transcoding service. This is provided by the per
    //      platform driver, so each platform can choose what implemenation
    //      it wants to use.
    // -----------------------------------------------------------------------
    static XMLNetAccessor*      fgNetAccessor;
    static XMLTransService*     fgTransService;

    // -----------------------------------------------------------------------
    //  Initialization method. This must be called first in any client code.
    // -----------------------------------------------------------------------
    static void Initialize();

    // -----------------------------------------------------------------------
    //  The panic mechanism. If, during init, we cannot even get far enough
    //  along to get transcoding up or get message loading working, we call
    //  this.
    //
    //  Each platform can implement it however they want. This method is
    //  expected to display something meaningful and end the process. The
    //  enum indicates why its being called, to allow the per-platform code
    //  to display something more specific if desired.
    // -----------------------------------------------------------------------
    static void panic
    (
        const   PanicReasons    reason
    );

    // -----------------------------------------------------------------------
    //  File methods
    // -----------------------------------------------------------------------
    static unsigned int curFilePos(FileHandle theFile);
    static void closeFile(FileHandle theFile);
    static unsigned int fileSize(FileHandle theFile);
    static FileHandle openFile(const char* const fileName);
    static FileHandle openFile(const XMLCh* const fileName);
    static FileHandle openStdInHandle();
    static unsigned int readFileBuffer
    (
                FileHandle      theFile
        , const unsigned int    toRead
        ,       XMLByte* const  toFill
    );
    static void resetFile(FileHandle theFile);

    // -----------------------------------------------------------------------
    //  File system methods
    // -----------------------------------------------------------------------
    static XMLCh* getFullPath(const XMLCh* const srcPath);
    static bool isRelative(const XMLCh* const toCheck);
    static XMLCh* weavePaths
    (
        const   XMLCh* const    basePath
        , const XMLCh* const    relativePath
    );

    // -----------------------------------------------------------------------
    //  Timing methods
    // -----------------------------------------------------------------------
    static unsigned long getCurrentMillis();

    // -----------------------------------------------------------------------
    //  Mutex methods
    // -----------------------------------------------------------------------
    static void closeMutex(void* const mtxHandle);
    static void lockMutex(void* const mtxHandle);
    static void* makeMutex();
    static void unlockMutex(void* const mtxHandle);

    // -----------------------------------------------------------------------
    //  External message support
    // -----------------------------------------------------------------------
    static XMLMsgLoader* loadMsgSet(const XMLCh* const msgDomain);

    // -----------------------------------------------------------------------
    //  Miscellaneous synchronization methods
    // -----------------------------------------------------------------------
    static void* compareAndSwap
    (
                void**      toFill
        , const void* const newValue
        , const void* const toCompare
    );

    // -----------------------------------------------------------------------
    //  Atomic Increment and Decrement
    //
    //  The function return value is positive if the result of the operation
    //  was positive. Zero if the result of the operation was zero. Negative
    //  if the result of the operation was negative. Except for the zero
    //  case, the value returned may differ from the actual result of the
    //  operation - only the sign and zero/nonzero state is guaranteed to be
    //  correct.
    // -----------------------------------------------------------------------
    static int atomicIncrement(int& location);
    static int atomicDecrement(int& location);

private :
    // -----------------------------------------------------------------------
    //  Private static methods. These are provided by the per-platform
    //  implementation files.
    // -----------------------------------------------------------------------
    static XMLMsgLoader* loadAMsgSet(const XMLCh* const msgDomain);
    static XMLNetAccessor* makeNetAccessor();
    static XMLTransService* makeTransService();
    static void platformInit();

    // -----------------------------------------------------------------------
    //  Private static data members
    //
    //  fgInitFlag
    //      This is used to avoid multiple inits if the client code calls us
    //      more than once. They aren't supposed to, but some have trouble
    //      keeping up if they are COM objects and such.
    // -----------------------------------------------------------------------
    static bool     fgInitFlag;
};

#endif
<|endoftext|>


<commit_before>#include <iostream>
#include <vector>
#include <sstream>
#include <algorithm>
#include <chrono>
#include <thread>

#include <cfloat>

#include <GLFW/glfw3.h>

#include "compiler.h"
#include "TCPServer.hpp"

#include "data.hpp"

float lastDeviceUpdateTime = 0;
float UpdateIntervalSeconds = 1;

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
// glfw callbacks
static void error_callback(int error, const char* description)
{
    fprintf(stderr, "GFWL Error: %s\n", description);
}

static void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
    glViewport(0, 0, width, height);
}
#pragma GCC diagnostic pop

#ifdef _WINDOWS
#include <tchar.h>
int wmain(int argc, _TCHAR* argv[]) {
#else
int main(int argc, char** argv) {
#endif

	// defaults
	unsigned int port = 60601;

	// command line params
	if (argc >= 2) {
		port = atoi(argv[1]);
	} else {
		std::cout << "Serving at default port: " << port << std::endl;
		std::cout << "call 'input-logger xxxxxx' to specify the port manually." << std::endl;
	}

    // glfw window setup
    GLFWwindow* window;
    glfwSetErrorCallback(error_callback);

    if (!glfwInit())
        exit(EXIT_FAILURE);

    window = glfwCreateWindow(640, 480, "Joystick Test", NULL, NULL);
    if (!window)
    {
        glfwTerminate();
        exit(EXIT_FAILURE);
    }

    glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);

    glfwMakeContextCurrent(window);
    glfwSwapInterval(1);

    while (!glfwWindowShouldClose(window))
    {

    }

	// setup networking
	boost::asio::io_service io_service;
	TCPServer server(io_service, port);

	// run!

	bool running = true;
	while (running)
	{

        for (int i = GLFW_JOYSTICK_1; i <= GLFW_JOYSTICK_LAST; i++)
        {
            if (glfwJoystickPresent(i)) {
                int count;
                const float* axis = glfwGetJoystickAxes(i, &count);
                for (int j = 0; j < count; j++) {
                    std::cout << "stick: " << i << ", axis: " << j << ": " << axis[j];
                }
            }
        }

		// deschedule this thread to save some resources...
		// time passed to the function is lower bound
		std::this_thread::sleep_for(std::chrono::milliseconds(1));

        running = running &&
        	!glfwWindowShouldClose(window)
            && !(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS);

        glClear(GL_COLOR_BUFFER_BIT);
        glfwSwapBuffers(window);
        glfwPollEvents();
	}

    glfwTerminate();
    exit(EXIT_SUCCESS);
	return 0;
}
<commit_msg>polling works, builds with xcode<commit_after>#include <iostream>
#include <vector>
#include <sstream>
#include <algorithm>
#include <chrono>
#include <thread>

#include <cfloat>

#include <GLFW/glfw3.h>

#include "compiler.h"
#include "TCPServer.hpp"

#include "data.hpp"

float lastDeviceUpdateTime = 0;
float UpdateIntervalSeconds = 1;

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
// glfw callbacks
static void error_callback(int error, const char* description)
{
    fprintf(stderr, "GFWL Error: %s\n", description);
}

static void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
    glViewport(0, 0, width, height);
}
#pragma GCC diagnostic pop

#ifdef _WINDOWS
#include <tchar.h>
int wmain(int argc, _TCHAR* argv[]) {
#else
int main(int argc, char** argv) {
#endif

	// defaults
	unsigned int port = 60601;

	// command line params
	if (argc >= 2) {
		port = atoi(argv[1]);
	} else {
		std::cout << "Serving at default port: " << port << std::endl;
		std::cout << "call 'input-logger xxxxxx' to specify the port manually." << std::endl;
	}

    // glfw window setup
    GLFWwindow* window;
    glfwSetErrorCallback(error_callback);

    if (!glfwInit())
        exit(EXIT_FAILURE);

    window = glfwCreateWindow(640, 480, "Joystick Test", NULL, NULL);
    if (!window)
    {
        glfwTerminate();
        exit(EXIT_FAILURE);
    }

    glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);

    glfwMakeContextCurrent(window);
    glfwSwapInterval(1);

    std::cout << "setting up server..." << std::endl;
	// setup networking
	boost::asio::io_service io_service;
	TCPServer server(io_service, port);

	// run!

	bool running = true;
	while (running)
	{
        for (int i = GLFW_JOYSTICK_1; i <= GLFW_JOYSTICK_LAST; i++)
        {
            if (glfwJoystickPresent(i)) {
                int count;
                const float* axis = glfwGetJoystickAxes(i, &count);
                for (int j = 0; j < count; j++) {
                    std::cout << "stick: " << i << ", axis: " << j << ": " << axis[j] << std:: endl;
                }
            }
        }

		// deschedule this thread to save some resources...
		// time passed to the function is lower bound
		std::this_thread::sleep_for(std::chrono::milliseconds(1));

        running = running &&
        	!glfwWindowShouldClose(window)
            && !(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS);

        glClear(GL_COLOR_BUFFER_BIT);
        glfwSwapBuffers(window);
        glfwPollEvents();
	}

    glfwTerminate();
    exit(EXIT_SUCCESS);
	return 0;
}
<|endoftext|>


<commit_before>/*
 * SimpleTimer.cpp
 *
 * SimpleTimer - A timer library for Arduino.
 * Author: mromani@ottotecnica.com
 * Copyright (c) 2010 OTTOTECNICA Italy
 *
 * Callback function parameters added & compiler warnings
 * removed by Bill Knight <billk@rosw.com> 20March2017
 *
 * This library is free software; you can redistribute it
 * and/or modify it under the terms of the GNU Lesser
 * General Public License as published by the Free Software
 * Foundation; either version 2.1 of the License, or (at
 * your option) any later version.
 *
 * This library is distributed in the hope that it will
 * be useful, but WITHOUT ANY WARRANTY; without even the
 * implied warranty of MERCHANTABILITY or FITNESS FOR A
 * PARTICULAR PURPOSE.  See the GNU Lesser General Public
 * License for more details.
 *
 * You should have received a copy of the GNU Lesser
 * General Public License along with this library; if not,
 * write to the Free Software Foundation, Inc.,
 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
 */

#include "Blynk/BlynkTimer.h"

// Select time function:
//static inline unsigned long elapsed() { return micros(); }
static inline unsigned long elapsed() { return millis(); }

SimpleTimer::SimpleTimer()
    : numTimers (-1)
{
}

void SimpleTimer::init() {
    unsigned long current_millis = elapsed();

    for (int i = 0; i < MAX_TIMERS; i++) {
        memset(&timer[i], 0, sizeof (timer_t));
        timer[i].prev_millis = current_millis;
    }

    numTimers = 0;
}

void SimpleTimer::run() {
    int i;
    unsigned long current_millis;

    // get current time
    current_millis = elapsed();

    for (i = 0; i < MAX_TIMERS; i++) {

        timer[i].toBeCalled = DEFCALL_DONTRUN;

        // no callback == no timer, i.e. jump over empty slots
        if (timer[i].callback != NULL) {

            // is it time to process this timer ?
            // see http://arduino.cc/forum/index.php/topic,124048.msg932592.html#msg932592

            if ((current_millis - timer[i].prev_millis) >= timer[i].delay) {

                // update time
                timer[i].prev_millis += timer[i].delay;

                // check if the timer callback has to be executed
                if (timer[i].enabled) {

                    // "run forever" timers must always be executed
                    if (timer[i].maxNumRuns == RUN_FOREVER) {
                        timer[i].toBeCalled = DEFCALL_RUNONLY;
                    }
                    // other timers get executed the specified number of times
                    else if (timer[i].numRuns < timer[i].maxNumRuns) {
                        timer[i].toBeCalled = DEFCALL_RUNONLY;
                        timer[i].numRuns++;

                        // after the last run, delete the timer
                        if (timer[i].numRuns >= timer[i].maxNumRuns) {
                            timer[i].toBeCalled = DEFCALL_RUNANDDEL;
                        }
                    }
                }
            }
        }
    }

    for (i = 0; i < MAX_TIMERS; i++) {
        if (timer[i].toBeCalled == DEFCALL_DONTRUN)
            continue;

        if (timer[i].hasParam)
            (*(timer_callback_p)timer[i].callback)(timer[i].param);
        else
            (*(timer_callback)timer[i].callback)();

        if (timer[i].toBeCalled == DEFCALL_RUNANDDEL)
            deleteTimer(i);
    }
}

// find the first available slot
// return -1 if none found
int SimpleTimer::findFirstFreeSlot() {
    // all slots are used
    if (numTimers >= MAX_TIMERS) {
        return -1;
    }

    // return the first slot with no callback (i.e. free)
    for (int i = 0; i < MAX_TIMERS; i++) {
        if (timer[i].callback == NULL) {
            return i;
        }
    }

    // no free slots found
    return -1;
}

int SimpleTimer::setupTimer(unsigned long d, void* f, void* p, bool h, unsigned n) {
    int freeTimer;

    if (numTimers < 0) {
        init();
    }

    freeTimer = findFirstFreeSlot();
    if (freeTimer < 0) {
        return -1;
    }

    if (f == NULL) {
        return -1;
    }

    timer[freeTimer].delay = d;
    timer[freeTimer].callback = f;
    timer[freeTimer].param = p;
    timer[freeTimer].hasParam = h;
    timer[freeTimer].maxNumRuns = n;
    timer[freeTimer].enabled = true;
    timer[freeTimer].prev_millis = elapsed();

    numTimers++;

    return freeTimer;
}

int SimpleTimer::setTimer(unsigned long d, timer_callback f, unsigned n) {
  return setupTimer(d, (void *)f, NULL, false, n);
}

int SimpleTimer::setTimer(unsigned long d, timer_callback_p f, void* p, unsigned n) {
  return setupTimer(d, (void *)f, p, true, n);
}

int SimpleTimer::setInterval(unsigned long d, timer_callback f) {
    return setupTimer(d, (void *)f, NULL, false, RUN_FOREVER);
}

int SimpleTimer::setInterval(unsigned long d, timer_callback_p f, void* p) {
  return setupTimer(d, (void *)f, p, true, RUN_FOREVER);
}

int SimpleTimer::setTimeout(unsigned long d, timer_callback f) {
    return setupTimer(d, (void *)f, NULL, false, RUN_ONCE);
}

int SimpleTimer::setTimeout(unsigned long d, timer_callback_p f, void* p) {
  return setupTimer(d, (void *)f, p, true, RUN_ONCE);
}

bool SimpleTimer::changeInterval(unsigned numTimer, unsigned long d) {
    if (numTimer >= MAX_TIMERS) {
        return false;
    }

    // Updates interval of existing specified timer
    if (timer[numTimer].callback != NULL) {
        timer[numTimer].delay = d;
        timer[numTimer].prev_millis = elapsed();
        return true;
    }
    // false return for non-used numTimer, no callback
    return false;
}

void SimpleTimer::deleteTimer(unsigned timerId) {
    if (timerId >= MAX_TIMERS) {
        return;
    }

    // nothing to delete if no timers are in use
    if (numTimers == 0) {
        return;
    }

    // don't decrease the number of timers if the
    // specified slot is already empty
    if (timer[timerId].callback != NULL) {
        memset(&timer[timerId], 0, sizeof (timer_t));
        timer[timerId].prev_millis = elapsed();

        // update number of timers
        numTimers--;
    }
}

// function contributed by code@rowansimms.com
void SimpleTimer::restartTimer(unsigned numTimer) {
    if (numTimer >= MAX_TIMERS) {
        return;
    }

    timer[numTimer].prev_millis = elapsed();
}

bool SimpleTimer::isEnabled(unsigned numTimer) {
    if (numTimer >= MAX_TIMERS) {
        return false;
    }

    return timer[numTimer].enabled;
}

void SimpleTimer::enable(unsigned numTimer) {
    if (numTimer >= MAX_TIMERS) {
        return;
    }

    timer[numTimer].enabled = true;
}

void SimpleTimer::disable(unsigned numTimer) {
    if (numTimer >= MAX_TIMERS) {
        return;
    }

    timer[numTimer].enabled = false;
}

void SimpleTimer::enableAll() {
    // Enable all timers with a callback assigned (used)
    for (int i = 0; i < MAX_TIMERS; i++) {
        if (timer[i].callback != NULL) {
            timer[i].enabled = true;
        }
    }
}

void SimpleTimer::disableAll() {
    // Disable all timers with a callback assigned (used)
    for (int i = 0; i < MAX_TIMERS; i++) {
        if (timer[i].callback != NULL) {
            timer[i].enabled = false;
        }
    }
}

void SimpleTimer::toggle(unsigned numTimer) {
    if (numTimer >= MAX_TIMERS) {
        return;
    }

    timer[numTimer].enabled = !timer[numTimer].enabled;
}

unsigned SimpleTimer::getNumTimers() {
    return numTimers;
}
<commit_msg>Added if statements for disable/enable-all (#323)<commit_after>/*
 * SimpleTimer.cpp
 *
 * SimpleTimer - A timer library for Arduino.
 * Author: mromani@ottotecnica.com
 * Copyright (c) 2010 OTTOTECNICA Italy
 *
 * Callback function parameters added & compiler warnings
 * removed by Bill Knight <billk@rosw.com> 20March2017
 *
 * This library is free software; you can redistribute it
 * and/or modify it under the terms of the GNU Lesser
 * General Public License as published by the Free Software
 * Foundation; either version 2.1 of the License, or (at
 * your option) any later version.
 *
 * This library is distributed in the hope that it will
 * be useful, but WITHOUT ANY WARRANTY; without even the
 * implied warranty of MERCHANTABILITY or FITNESS FOR A
 * PARTICULAR PURPOSE.  See the GNU Lesser General Public
 * License for more details.
 *
 * You should have received a copy of the GNU Lesser
 * General Public License along with this library; if not,
 * write to the Free Software Foundation, Inc.,
 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
 */

#include "Blynk/BlynkTimer.h"

// Select time function:
//static inline unsigned long elapsed() { return micros(); }
static inline unsigned long elapsed() { return millis(); }

SimpleTimer::SimpleTimer()
    : numTimers (-1)
{
}

void SimpleTimer::init() {
    unsigned long current_millis = elapsed();

    for (int i = 0; i < MAX_TIMERS; i++) {
        memset(&timer[i], 0, sizeof (timer_t));
        timer[i].prev_millis = current_millis;
    }

    numTimers = 0;
}

void SimpleTimer::run() {
    int i;
    unsigned long current_millis;

    // get current time
    current_millis = elapsed();

    for (i = 0; i < MAX_TIMERS; i++) {

        timer[i].toBeCalled = DEFCALL_DONTRUN;

        // no callback == no timer, i.e. jump over empty slots
        if (timer[i].callback != NULL) {

            // is it time to process this timer ?
            // see http://arduino.cc/forum/index.php/topic,124048.msg932592.html#msg932592

            if ((current_millis - timer[i].prev_millis) >= timer[i].delay) {

                // update time
                timer[i].prev_millis += timer[i].delay;

                // check if the timer callback has to be executed
                if (timer[i].enabled) {

                    // "run forever" timers must always be executed
                    if (timer[i].maxNumRuns == RUN_FOREVER) {
                        timer[i].toBeCalled = DEFCALL_RUNONLY;
                    }
                    // other timers get executed the specified number of times
                    else if (timer[i].numRuns < timer[i].maxNumRuns) {
                        timer[i].toBeCalled = DEFCALL_RUNONLY;
                        timer[i].numRuns++;

                        // after the last run, delete the timer
                        if (timer[i].numRuns >= timer[i].maxNumRuns) {
                            timer[i].toBeCalled = DEFCALL_RUNANDDEL;
                        }
                    }
                }
            }
        }
    }

    for (i = 0; i < MAX_TIMERS; i++) {
        if (timer[i].toBeCalled == DEFCALL_DONTRUN)
            continue;

        if (timer[i].hasParam)
            (*(timer_callback_p)timer[i].callback)(timer[i].param);
        else
            (*(timer_callback)timer[i].callback)();

        if (timer[i].toBeCalled == DEFCALL_RUNANDDEL)
            deleteTimer(i);
    }
}

// find the first available slot
// return -1 if none found
int SimpleTimer::findFirstFreeSlot() {
    // all slots are used
    if (numTimers >= MAX_TIMERS) {
        return -1;
    }

    // return the first slot with no callback (i.e. free)
    for (int i = 0; i < MAX_TIMERS; i++) {
        if (timer[i].callback == NULL) {
            return i;
        }
    }

    // no free slots found
    return -1;
}

int SimpleTimer::setupTimer(unsigned long d, void* f, void* p, bool h, unsigned n) {
    int freeTimer;

    if (numTimers < 0) {
        init();
    }

    freeTimer = findFirstFreeSlot();
    if (freeTimer < 0) {
        return -1;
    }

    if (f == NULL) {
        return -1;
    }

    timer[freeTimer].delay = d;
    timer[freeTimer].callback = f;
    timer[freeTimer].param = p;
    timer[freeTimer].hasParam = h;
    timer[freeTimer].maxNumRuns = n;
    timer[freeTimer].enabled = true;
    timer[freeTimer].prev_millis = elapsed();

    numTimers++;

    return freeTimer;
}

int SimpleTimer::setTimer(unsigned long d, timer_callback f, unsigned n) {
  return setupTimer(d, (void *)f, NULL, false, n);
}

int SimpleTimer::setTimer(unsigned long d, timer_callback_p f, void* p, unsigned n) {
  return setupTimer(d, (void *)f, p, true, n);
}

int SimpleTimer::setInterval(unsigned long d, timer_callback f) {
    return setupTimer(d, (void *)f, NULL, false, RUN_FOREVER);
}

int SimpleTimer::setInterval(unsigned long d, timer_callback_p f, void* p) {
  return setupTimer(d, (void *)f, p, true, RUN_FOREVER);
}

int SimpleTimer::setTimeout(unsigned long d, timer_callback f) {
    return setupTimer(d, (void *)f, NULL, false, RUN_ONCE);
}

int SimpleTimer::setTimeout(unsigned long d, timer_callback_p f, void* p) {
  return setupTimer(d, (void *)f, p, true, RUN_ONCE);
}

bool SimpleTimer::changeInterval(unsigned numTimer, unsigned long d) {
    if (numTimer >= MAX_TIMERS) {
        return false;
    }

    // Updates interval of existing specified timer
    if (timer[numTimer].callback != NULL) {
        timer[numTimer].delay = d;
        timer[numTimer].prev_millis = elapsed();
        return true;
    }
    // false return for non-used numTimer, no callback
    return false;
}

void SimpleTimer::deleteTimer(unsigned timerId) {
    if (timerId >= MAX_TIMERS) {
        return;
    }

    // nothing to delete if no timers are in use
    if (numTimers == 0) {
        return;
    }

    // don't decrease the number of timers if the
    // specified slot is already empty
    if (timer[timerId].callback != NULL) {
        memset(&timer[timerId], 0, sizeof (timer_t));
        timer[timerId].prev_millis = elapsed();

        // update number of timers
        numTimers--;
    }
}

// function contributed by code@rowansimms.com
void SimpleTimer::restartTimer(unsigned numTimer) {
    if (numTimer >= MAX_TIMERS) {
        return;
    }

    timer[numTimer].prev_millis = elapsed();
}

bool SimpleTimer::isEnabled(unsigned numTimer) {
    if (numTimer >= MAX_TIMERS) {
        return false;
    }

    return timer[numTimer].enabled;
}

void SimpleTimer::enable(unsigned numTimer) {
    if (numTimer >= MAX_TIMERS) {
        return;
    }

    timer[numTimer].enabled = true;
}

void SimpleTimer::disable(unsigned numTimer) {
    if (numTimer >= MAX_TIMERS) {
        return;
    }

    timer[numTimer].enabled = false;
}

void SimpleTimer::enableAll() {
    // Enable all timers with a callback assigned (used)
    for (int i = 0; i < MAX_TIMERS; i++) {
        if (timer[i].callback != NULL && numRuns[i] == RUN_FOREVER) {
            timer[i].enabled = true;
        }
    }
}

void SimpleTimer::disableAll() {
    // Disable all timers with a callback assigned (used)
    for (int i = 0; i < MAX_TIMERS; i++) {
        if (timer[i].callback != NULL && numRuns[i] == RUN_FOREVER) {
            timer[i].enabled = false;
        }
    }
}

void SimpleTimer::toggle(unsigned numTimer) {
    if (numTimer >= MAX_TIMERS) {
        return;
    }

    timer[numTimer].enabled = !timer[numTimer].enabled;
}

unsigned SimpleTimer::getNumTimers() {
    return numTimers;
}
<|endoftext|>