<commit_before>#include "../includes/NSFW.h"

#if defined(_WIN32)
#include <windows.h>
#define sleep_for_ms(ms) Sleep(ms)
#else
#include <unistd.h>
#define sleep_for_ms(ms) usleep(ms * 1000)
#endif

#pragma unmanaged
Persistent<v8::Function> NSFW::constructor;

NSFW::NSFW(uint32_t debounceMS, std::string path, Callback *eventCallback, Callback *errorCallback):
  mDebounceMS(debounceMS),
  mErrorCallback(errorCallback),
  mEventCallback(eventCallback),
  mInterface(NULL),
  mInterfaceLockValid(false),
  mPath(path),
  mRunning(false) {
    HandleScope scope;
    v8::Local<v8::Object> obj = New<v8::Object>();
    mPersistentHandle.Reset(obj);
    mInterfaceLockValid = uv_mutex_init(&mInterfaceLock) == 0;
  }

NSFW::~NSFW() {
  if (mInterface != NULL) {
    delete mInterface;
  }
  delete mEventCallback;
  delete mErrorCallback;

  if (mInterfaceLockValid) {
    uv_mutex_destroy(&mInterfaceLock);
  }
}

void NSFW::cleanupEventCallback(void *arg) {
  EventBaton *baton = (EventBaton *)arg;
  for (uint32_t i = 0; i < baton->events->size(); ++i) {
    delete (*baton->events)[i];
    (*baton->events)[i] = NULL;
  }
  delete baton->events;
  delete baton;
}

void NSFW::fireErrorCallback(uv_async_t *handle) {
  Nan::HandleScope scope;
  ErrorBaton *baton = (ErrorBaton *)handle->data;
  v8::Local<v8::Value> argv[] = {
    New<v8::String>(baton->error).ToLocalChecked()
  };
  baton->nsfw->mErrorCallback->Call(1, argv);
  delete baton;
}

void NSFW::fireEventCallback(uv_async_t *handle) {
  Nan::HandleScope scope;
  EventBaton *baton = (EventBaton *)handle->data;
  if (baton->events->empty()) {
    uv_thread_t cleanup;
    uv_thread_create(&cleanup, NSFW::cleanupEventCallback, baton);
    return;
  }

  std::vector< v8::Local<v8::Object> > *jsEventObjects = new std::vector< v8::Local<v8::Object> >;
  jsEventObjects->reserve(baton->events->size());

  for (auto i = baton->events->begin(); i != baton->events->end(); ++i) {
    v8::Local<v8::Object> anEvent = New<v8::Object>();

    anEvent->Set(New<v8::String>("action").ToLocalChecked(), New<v8::Number>((*i)->type));
    anEvent->Set(New<v8::String>("directory").ToLocalChecked(), New<v8::String>((*i)->directory).ToLocalChecked());

    if ((*i)->type == RENAMED) {
      anEvent->Set(New<v8::String>("oldFile").ToLocalChecked(), New<v8::String>((*i)->fileA).ToLocalChecked());
      anEvent->Set(New<v8::String>("newFile").ToLocalChecked(), New<v8::String>((*i)->fileB).ToLocalChecked());
    } else {
      anEvent->Set(New<v8::String>("file").ToLocalChecked(), New<v8::String>((*i)->fileA).ToLocalChecked());
    }

    jsEventObjects->push_back(anEvent);
  }

  v8::Local<v8::Array> eventArray = New<v8::Array>((int)jsEventObjects->size());

  for (unsigned int i = 0; i < jsEventObjects->size(); ++i) {
    eventArray->Set(i, (*jsEventObjects)[i]);
  }

  v8::Local<v8::Value> argv[] = {
    eventArray
  };

  baton->nsfw->mEventCallback->Call(1, argv);

  delete jsEventObjects;

  uv_thread_t cleanup;
  uv_thread_create(&cleanup, NSFW::cleanupEventCallback, baton);
}

void NSFW::pollForEvents(void *arg) {
  NSFW *nsfw = (NSFW *)arg;
  while(nsfw->mRunning) {
    uv_mutex_lock(&nsfw->mInterfaceLock);

    if (nsfw->mInterface->hasErrored()) {
      ErrorBaton *baton = new ErrorBaton;
      baton->nsfw = nsfw;
      baton->error = nsfw->mInterface->getError();

      nsfw->mErrorCallbackAsync.data = (void *)baton;
      uv_async_send(&nsfw->mErrorCallbackAsync);
      nsfw->mRunning = false;
      uv_mutex_unlock(&nsfw->mInterfaceLock);
      break;
    }
    std::vector<Event *> *events = nsfw->mInterface->getEvents();
    if (events == NULL) {
      uv_mutex_unlock(&nsfw->mInterfaceLock);
      sleep_for_ms(50);
      continue;
    }

    EventBaton *baton = new EventBaton;
    baton->nsfw = nsfw;
    baton->events = events;

    nsfw->mEventCallbackAsync.data = (void *)baton;
    uv_async_send(&nsfw->mEventCallbackAsync);

    uv_mutex_unlock(&nsfw->mInterfaceLock);

    sleep_for_ms(nsfw->mDebounceMS);
  }
}

NAN_MODULE_INIT(NSFW::Init) {
  Nan::HandleScope scope;

  v8::Local<v8::FunctionTemplate> tpl = New<v8::FunctionTemplate>(JSNew);
  tpl->SetClassName(New<v8::String>("NSFW").ToLocalChecked());
  tpl->InstanceTemplate()->SetInternalFieldCount(1);

  SetPrototypeMethod(tpl, "start", Start);
  SetPrototypeMethod(tpl, "stop", Stop);

  constructor.Reset(tpl->GetFunction());
  Set(target, New<v8::String>("NSFW").ToLocalChecked(), tpl->GetFunction());
}

NAN_METHOD(NSFW::JSNew) {
  if (!info.IsConstructCall()) {
    v8::Local<v8::Function> cons = New<v8::Function>(constructor);
    info.GetReturnValue().Set(cons->NewInstance());
    return;
  }

  if (info.Length() < 1 || !info[0]->IsUint32()) {
    return ThrowError("First argument of constructor must be a positive integer.");
  }
  if (info.Length() < 2 || !info[1]->IsString()) {
    return ThrowError("Second argument of constructor must be a path.");
  }
  if (info.Length() < 3 || !info[2]->IsFunction()) {
    return ThrowError("Third argument of constructor must be a callback.");
  }
  if (info.Length() < 4 || !info[3]->IsFunction()) {
    return ThrowError("Fourth argument of constructor must be a callback.");
  }

  uint32_t debounceMS = info[0]->Uint32Value();
  v8::String::Utf8Value utf8Value(info[1]->ToString());
  std::string path = std::string(*utf8Value);
  Callback *eventCallback = new Callback(info[2].As<v8::Function>());
  Callback *errorCallback = new Callback(info[3].As<v8::Function>());

  NSFW *nsfw = new NSFW(debounceMS, path, eventCallback, errorCallback);
  nsfw->Wrap(info.This());
  info.GetReturnValue().Set(info.This());
}

NAN_METHOD(NSFW::Start) {
  Nan::HandleScope scope;

  NSFW *nsfw = ObjectWrap::Unwrap<NSFW>(info.This());
  if (!nsfw->mInterfaceLockValid) {
    return ThrowError("NSFW failed to initialize properly. Try creating a new NSFW.");
  }

  if (
    info.Length() < 1 ||
    !info[0]->IsFunction()
  ) {
    return ThrowError("Must provide callback to start.");
  }

  Callback *callback = new Callback(info[0].As<v8::Function>());

  if (nsfw->mInterface != NULL) {
    v8::Local<v8::Value> argv[1] = {
      Nan::Error("This NSFW cannot be started, because it is already running.")
    };
    callback->Call(1, argv);
    delete callback;
    return;
  }

  New(nsfw->mPersistentHandle)->Set(New("nsfw").ToLocalChecked(), info.This());

  AsyncQueueWorker(new StartWorker(nsfw, callback));
}

NSFW::StartWorker::StartWorker(NSFW *nsfw, Callback *callback):
  AsyncWorker(callback), mNSFW(nsfw) {
    uv_async_init(uv_default_loop(), &nsfw->mErrorCallbackAsync, &NSFW::fireErrorCallback);
    uv_async_init(uv_default_loop(), &nsfw->mEventCallbackAsync, &NSFW::fireEventCallback);
  }

void NSFW::StartWorker::Execute() {
  uv_mutex_lock(&mNSFW->mInterfaceLock);

  if (mNSFW->mInterface != NULL) {
    uv_mutex_unlock(&mNSFW->mInterfaceLock);
    return;
  }

  mNSFW->mInterface = new NativeInterface(mNSFW->mPath);
  if (mNSFW->mInterface->isWatching()) {
    mNSFW->mRunning = true;
    uv_thread_create(&mNSFW->mPollThread, NSFW::pollForEvents, mNSFW);
  } else {
    delete mNSFW->mInterface;
    mNSFW->mInterface = NULL;
  }

  uv_mutex_unlock(&mNSFW->mInterfaceLock);
}

void NSFW::StartWorker::HandleOKCallback() {
  HandleScope();
  if (mNSFW->mInterface == NULL) {
    if (!mNSFW->mPersistentHandle.IsEmpty()) {
      v8::Local<v8::Object> obj = New<v8::Object>();
      mNSFW->mPersistentHandle.Reset(obj);
    }
    v8::Local<v8::Value> argv[1] = {
      Nan::Error("NSFW was unable to start watching that directory.")
    };
    callback->Call(1, argv);
  } else {
    callback->Call(0, NULL);
  }
}

NAN_METHOD(NSFW::Stop) {
  Nan::HandleScope scope;

  NSFW *nsfw = ObjectWrap::Unwrap<NSFW>(info.This());
  if (!nsfw->mInterfaceLockValid) {
    return ThrowError("NSFW failed to initialize properly. Try creating a new NSFW.");
  }

  if (
    info.Length() < 1 ||
    !info[0]->IsFunction()
  ) {
    return ThrowError("Must provide callback to stop.");
  }

  Callback *callback = new Callback(info[0].As<v8::Function>());

  if (nsfw->mInterface == NULL) {
    v8::Local<v8::Value> argv[1] = {
      Nan::Error("This NSFW cannot be stopped, because it is not running.")
    };
    callback->Call(1, argv);
    delete callback;
    return;
  }

  AsyncQueueWorker(new StopWorker(nsfw, callback));
}

NSFW::StopWorker::StopWorker(NSFW *nsfw, Callback *callback):
  AsyncWorker(callback), mNSFW(nsfw) {}

void NSFW::StopWorker::Execute() {
  uv_mutex_lock(&mNSFW->mInterfaceLock);
  if (mNSFW->mInterface == NULL) {
    uv_mutex_unlock(&mNSFW->mInterfaceLock);
    return;
  }
  uv_mutex_unlock(&mNSFW->mInterfaceLock);

  // unlock the mInterfaceLock mutex while operate on the running identifier
  mNSFW->mRunning = false;

  uv_thread_join(&mNSFW->mPollThread);

  uv_mutex_lock(&mNSFW->mInterfaceLock);
  delete mNSFW->mInterface;
  mNSFW->mInterface = NULL;

  uv_mutex_unlock(&mNSFW->mInterfaceLock);
}

void NSFW::StopWorker::HandleOKCallback() {
  HandleScope();

  if (!mNSFW->mPersistentHandle.IsEmpty()) {
    v8::Local<v8::Object> obj = New<v8::Object>();
    mNSFW->mPersistentHandle.Reset(obj);
  }

  uv_close(reinterpret_cast<uv_handle_t*>(&mNSFW->mErrorCallbackAsync), nullptr);
  uv_close(reinterpret_cast<uv_handle_t*>(&mNSFW->mEventCallbackAsync), nullptr);

  callback->Call(0, NULL);
}

NODE_MODULE(nsfw, NSFW::Init)
<commit_msg>Fix node 10 compilation error<commit_after>#include "../includes/NSFW.h"

#if defined(_WIN32)
#include <windows.h>
#define sleep_for_ms(ms) Sleep(ms)
#else
#include <unistd.h>
#define sleep_for_ms(ms) usleep(ms * 1000)
#endif

#pragma unmanaged
Persistent<v8::Function> NSFW::constructor;

NSFW::NSFW(uint32_t debounceMS, std::string path, Callback *eventCallback, Callback *errorCallback):
  mDebounceMS(debounceMS),
  mErrorCallback(errorCallback),
  mEventCallback(eventCallback),
  mInterface(NULL),
  mInterfaceLockValid(false),
  mPath(path),
  mRunning(false) {
    HandleScope scope;
    v8::Local<v8::Object> obj = New<v8::Object>();
    mPersistentHandle.Reset(obj);
    mInterfaceLockValid = uv_mutex_init(&mInterfaceLock) == 0;
  }

NSFW::~NSFW() {
  if (mInterface != NULL) {
    delete mInterface;
  }
  delete mEventCallback;
  delete mErrorCallback;

  if (mInterfaceLockValid) {
    uv_mutex_destroy(&mInterfaceLock);
  }
}

void NSFW::cleanupEventCallback(void *arg) {
  EventBaton *baton = (EventBaton *)arg;
  for (uint32_t i = 0; i < baton->events->size(); ++i) {
    delete (*baton->events)[i];
    (*baton->events)[i] = NULL;
  }
  delete baton->events;
  delete baton;
}

void NSFW::fireErrorCallback(uv_async_t *handle) {
  Nan::HandleScope scope;
  ErrorBaton *baton = (ErrorBaton *)handle->data;
  v8::Local<v8::Value> argv[] = {
    New<v8::String>(baton->error).ToLocalChecked()
  };
  baton->nsfw->mErrorCallback->Call(1, argv);
  delete baton;
}

void NSFW::fireEventCallback(uv_async_t *handle) {
  Nan::HandleScope scope;
  EventBaton *baton = (EventBaton *)handle->data;
  if (baton->events->empty()) {
    uv_thread_t cleanup;
    uv_thread_create(&cleanup, NSFW::cleanupEventCallback, baton);
    return;
  }

  std::vector< v8::Local<v8::Object> > *jsEventObjects = new std::vector< v8::Local<v8::Object> >;
  jsEventObjects->reserve(baton->events->size());

  for (auto i = baton->events->begin(); i != baton->events->end(); ++i) {
    v8::Local<v8::Object> anEvent = New<v8::Object>();

    anEvent->Set(New<v8::String>("action").ToLocalChecked(), New<v8::Number>((*i)->type));
    anEvent->Set(New<v8::String>("directory").ToLocalChecked(), New<v8::String>((*i)->directory).ToLocalChecked());

    if ((*i)->type == RENAMED) {
      anEvent->Set(New<v8::String>("oldFile").ToLocalChecked(), New<v8::String>((*i)->fileA).ToLocalChecked());
      anEvent->Set(New<v8::String>("newFile").ToLocalChecked(), New<v8::String>((*i)->fileB).ToLocalChecked());
    } else {
      anEvent->Set(New<v8::String>("file").ToLocalChecked(), New<v8::String>((*i)->fileA).ToLocalChecked());
    }

    jsEventObjects->push_back(anEvent);
  }

  v8::Local<v8::Array> eventArray = New<v8::Array>((int)jsEventObjects->size());

  for (unsigned int i = 0; i < jsEventObjects->size(); ++i) {
    eventArray->Set(i, (*jsEventObjects)[i]);
  }

  v8::Local<v8::Value> argv[] = {
    eventArray
  };

  baton->nsfw->mEventCallback->Call(1, argv);

  delete jsEventObjects;

  uv_thread_t cleanup;
  uv_thread_create(&cleanup, NSFW::cleanupEventCallback, baton);
}

void NSFW::pollForEvents(void *arg) {
  NSFW *nsfw = (NSFW *)arg;
  while(nsfw->mRunning) {
    uv_mutex_lock(&nsfw->mInterfaceLock);

    if (nsfw->mInterface->hasErrored()) {
      ErrorBaton *baton = new ErrorBaton;
      baton->nsfw = nsfw;
      baton->error = nsfw->mInterface->getError();

      nsfw->mErrorCallbackAsync.data = (void *)baton;
      uv_async_send(&nsfw->mErrorCallbackAsync);
      nsfw->mRunning = false;
      uv_mutex_unlock(&nsfw->mInterfaceLock);
      break;
    }
    std::vector<Event *> *events = nsfw->mInterface->getEvents();
    if (events == NULL) {
      uv_mutex_unlock(&nsfw->mInterfaceLock);
      sleep_for_ms(50);
      continue;
    }

    EventBaton *baton = new EventBaton;
    baton->nsfw = nsfw;
    baton->events = events;

    nsfw->mEventCallbackAsync.data = (void *)baton;
    uv_async_send(&nsfw->mEventCallbackAsync);

    uv_mutex_unlock(&nsfw->mInterfaceLock);

    sleep_for_ms(nsfw->mDebounceMS);
  }
}

NAN_MODULE_INIT(NSFW::Init) {
  Nan::HandleScope scope;

  v8::Local<v8::FunctionTemplate> tpl = New<v8::FunctionTemplate>(JSNew);
  tpl->SetClassName(New<v8::String>("NSFW").ToLocalChecked());
  tpl->InstanceTemplate()->SetInternalFieldCount(1);

  SetPrototypeMethod(tpl, "start", Start);
  SetPrototypeMethod(tpl, "stop", Stop);

  constructor.Reset(tpl->GetFunction());
  Set(target, New<v8::String>("NSFW").ToLocalChecked(), tpl->GetFunction());
}

NAN_METHOD(NSFW::JSNew) {
  if (!info.IsConstructCall()) {
    const int argc = 4;
    v8::Isolate *isolate = info.GetIsolate();
    v8::Local<v8::Value> argv[argc] = {info[0], info[1], info[2], info[3]};
    v8::Local<v8::Context> context = isolate->GetCurrentContext();
    v8::Local<v8::Function> cons = v8::Local<v8::Function>::New(isolate, constructor);
    info.GetReturnValue().Set(cons->NewInstance(context, argc, argv).ToLocalChecked());
    return;
  }

  if (info.Length() < 1 || !info[0]->IsUint32()) {
    return ThrowError("First argument of constructor must be a positive integer.");
  }
  if (info.Length() < 2 || !info[1]->IsString()) {
    return ThrowError("Second argument of constructor must be a path.");
  }
  if (info.Length() < 3 || !info[2]->IsFunction()) {
    return ThrowError("Third argument of constructor must be a callback.");
  }
  if (info.Length() < 4 || !info[3]->IsFunction()) {
    return ThrowError("Fourth argument of constructor must be a callback.");
  }

  uint32_t debounceMS = info[0]->Uint32Value();
  v8::String::Utf8Value utf8Value(info[1]->ToString());
  std::string path = std::string(*utf8Value);
  Callback *eventCallback = new Callback(info[2].As<v8::Function>());
  Callback *errorCallback = new Callback(info[3].As<v8::Function>());

  NSFW *nsfw = new NSFW(debounceMS, path, eventCallback, errorCallback);
  nsfw->Wrap(info.This());
  info.GetReturnValue().Set(info.This());
}

NAN_METHOD(NSFW::Start) {
  Nan::HandleScope scope;

  NSFW *nsfw = ObjectWrap::Unwrap<NSFW>(info.This());
  if (!nsfw->mInterfaceLockValid) {
    return ThrowError("NSFW failed to initialize properly. Try creating a new NSFW.");
  }

  if (
    info.Length() < 1 ||
    !info[0]->IsFunction()
  ) {
    return ThrowError("Must provide callback to start.");
  }

  Callback *callback = new Callback(info[0].As<v8::Function>());

  if (nsfw->mInterface != NULL) {
    v8::Local<v8::Value> argv[1] = {
      Nan::Error("This NSFW cannot be started, because it is already running.")
    };
    callback->Call(1, argv);
    delete callback;
    return;
  }

  New(nsfw->mPersistentHandle)->Set(New("nsfw").ToLocalChecked(), info.This());

  AsyncQueueWorker(new StartWorker(nsfw, callback));
}

NSFW::StartWorker::StartWorker(NSFW *nsfw, Callback *callback):
  AsyncWorker(callback), mNSFW(nsfw) {
    uv_async_init(uv_default_loop(), &nsfw->mErrorCallbackAsync, &NSFW::fireErrorCallback);
    uv_async_init(uv_default_loop(), &nsfw->mEventCallbackAsync, &NSFW::fireEventCallback);
  }

void NSFW::StartWorker::Execute() {
  uv_mutex_lock(&mNSFW->mInterfaceLock);

  if (mNSFW->mInterface != NULL) {
    uv_mutex_unlock(&mNSFW->mInterfaceLock);
    return;
  }

  mNSFW->mInterface = new NativeInterface(mNSFW->mPath);
  if (mNSFW->mInterface->isWatching()) {
    mNSFW->mRunning = true;
    uv_thread_create(&mNSFW->mPollThread, NSFW::pollForEvents, mNSFW);
  } else {
    delete mNSFW->mInterface;
    mNSFW->mInterface = NULL;
  }

  uv_mutex_unlock(&mNSFW->mInterfaceLock);
}

void NSFW::StartWorker::HandleOKCallback() {
  HandleScope();
  if (mNSFW->mInterface == NULL) {
    if (!mNSFW->mPersistentHandle.IsEmpty()) {
      v8::Local<v8::Object> obj = New<v8::Object>();
      mNSFW->mPersistentHandle.Reset(obj);
    }
    v8::Local<v8::Value> argv[1] = {
      Nan::Error("NSFW was unable to start watching that directory.")
    };
    callback->Call(1, argv);
  } else {
    callback->Call(0, NULL);
  }
}

NAN_METHOD(NSFW::Stop) {
  Nan::HandleScope scope;

  NSFW *nsfw = ObjectWrap::Unwrap<NSFW>(info.This());
  if (!nsfw->mInterfaceLockValid) {
    return ThrowError("NSFW failed to initialize properly. Try creating a new NSFW.");
  }

  if (
    info.Length() < 1 ||
    !info[0]->IsFunction()
  ) {
    return ThrowError("Must provide callback to stop.");
  }

  Callback *callback = new Callback(info[0].As<v8::Function>());

  if (nsfw->mInterface == NULL) {
    v8::Local<v8::Value> argv[1] = {
      Nan::Error("This NSFW cannot be stopped, because it is not running.")
    };
    callback->Call(1, argv);
    delete callback;
    return;
  }

  AsyncQueueWorker(new StopWorker(nsfw, callback));
}

NSFW::StopWorker::StopWorker(NSFW *nsfw, Callback *callback):
  AsyncWorker(callback), mNSFW(nsfw) {}

void NSFW::StopWorker::Execute() {
  uv_mutex_lock(&mNSFW->mInterfaceLock);
  if (mNSFW->mInterface == NULL) {
    uv_mutex_unlock(&mNSFW->mInterfaceLock);
    return;
  }
  uv_mutex_unlock(&mNSFW->mInterfaceLock);

  // unlock the mInterfaceLock mutex while operate on the running identifier
  mNSFW->mRunning = false;

  uv_thread_join(&mNSFW->mPollThread);

  uv_mutex_lock(&mNSFW->mInterfaceLock);
  delete mNSFW->mInterface;
  mNSFW->mInterface = NULL;

  uv_mutex_unlock(&mNSFW->mInterfaceLock);
}

void NSFW::StopWorker::HandleOKCallback() {
  HandleScope();

  if (!mNSFW->mPersistentHandle.IsEmpty()) {
    v8::Local<v8::Object> obj = New<v8::Object>();
    mNSFW->mPersistentHandle.Reset(obj);
  }

  uv_close(reinterpret_cast<uv_handle_t*>(&mNSFW->mErrorCallbackAsync), nullptr);
  uv_close(reinterpret_cast<uv_handle_t*>(&mNSFW->mEventCallbackAsync), nullptr);

  callback->Call(0, NULL);
}

NODE_MODULE(nsfw, NSFW::Init)
<|endoftext|>


<commit_before><commit_msg>Adds more debugging code to WindowImpl. Crash data seems to indicate the wndproc isn't getting called at all for this window. I'm curious to see if our windowproc is no longer registered. I'm also changing the HINSTNACE argument to RegisterClassEx to actually pass in a module.<commit_after><|endoftext|>


<commit_before>// This file is part of RBDyn.
//
// RBDyn 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 3 of the License, or
// (at your option) any later version.
//
// RBDyn 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 RBDyn.  If not, see <http://www.gnu.org/licenses/>.

// check memory allocation in some method

// includes
// std
#include <iostream>

// boost
#define BOOST_TEST_MODULE Statics
#include <boost/test/unit_test.hpp>
#include <boost/math/constants/constants.hpp>

// SpaceVecAlg
#include <SpaceVecAlg/SpaceVecAlg>

// RBDyn
#include "FK.h"
#include "FV.h"
#include "FD.h"
#include "IS.h"
#include "Body.h"
#include "Joint.h"
#include "MultiBody.h"
#include "MultiBodyConfig.h"
#include "MultiBodyGraph.h"
#include "util.hh"
#include "fixture.hh"

// arm
#include "XXXarm.h"

namespace rbd
{
using namespace Eigen;
Eigen::IOFormat cleanFmt(2, 0, ", ", "\n", "[", "]");

void test(boost::shared_ptr<boost::test_tools::output_test_stream> output,
          rbd::MultiBody& mb, rbd::MultiBodyConfig& mbc,
          rbd::InverseStatics& IS, Eigen::Vector3d q)
{
  Eigen::MatrixXd jacQ(3,3);
  Eigen::MatrixXd jacF(3,24);
  std::vector<Eigen::MatrixXd> jacMomentAndForces(4);
  (*output) << "\n\n\nChange config to " << q.transpose() << std::endl;
  mbc.q[1][0] = q(0);
  mbc.q[2][0] = q(1);
  mbc.q[3][0] = q(2);
  forwardKinematics(mb, mbc);
  forwardVelocity(mb, mbc);
  IS.inverseStatics(mb, mbc);
  IS.computeTorqueJacobianJoint(mb, mbc, jacMomentAndForces);

  (*output) << "========================================" << std::endl;
  (*output) << "Results for mbc.q =" << mbc.q << std::endl;
  (*output) << "mbc.jointTorque =\n" << mbc.jointTorque << std::endl;
  for (auto e : IS.f())
    (*output) << "IS.f().vector =\n" << e.vector() << std::endl;
  (*output) << "IS.jointTorqueDiff =\n" << IS.jointTorqueDiff() << std::endl;
}

BOOST_AUTO_TEST_CASE(XXXArmTorqueJacobian)
{
  boost::shared_ptr<boost::test_tools::output_test_stream> output =
      retrievePattern("InverseStaticsTest");

  rbd::MultiBody mb;
  rbd::MultiBodyConfig mbc;
  rbd::MultiBodyGraph mbg;
  std::tie(mb, mbc, mbg) = makeXXXarm();
  rbd::InverseStatics IS(mb);

  test(output, mb, mbc, IS, Vector3d(0, 0, 0));
  test(output, mb, mbc, IS, Vector3d(M_PI, 0, 0));
  test(output, mb, mbc, IS, Vector3d(0, M_PI / 2, 0));
  test(output, mb, mbc, IS, Vector3d(0.4, 0.1, 0.2));

  std::cout << output->str() << std::endl;
  BOOST_CHECK(output->match_pattern());
}  // end of namespace rbd
}

<commit_msg>Skip IS test with i386<commit_after>// This file is part of RBDyn.
//
// RBDyn 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 3 of the License, or
// (at your option) any later version.
//
// RBDyn 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 RBDyn.  If not, see <http://www.gnu.org/licenses/>.

// check memory allocation in some method

// includes
// std
#include <iostream>

// boost
#define BOOST_TEST_MODULE Statics
#include <boost/test/unit_test.hpp>
#include <boost/math/constants/constants.hpp>

// SpaceVecAlg
#include <SpaceVecAlg/SpaceVecAlg>

// RBDyn
#include "FK.h"
#include "FV.h"
#include "FD.h"
#include "IS.h"
#include "Body.h"
#include "Joint.h"
#include "MultiBody.h"
#include "MultiBodyConfig.h"
#include "MultiBodyGraph.h"
#include "util.hh"
#include "fixture.hh"

// arm
#include "XXXarm.h"

namespace rbd
{
using namespace Eigen;
Eigen::IOFormat cleanFmt(2, 0, ", ", "\n", "[", "]");

void test(boost::shared_ptr<boost::test_tools::output_test_stream> output,
          rbd::MultiBody& mb, rbd::MultiBodyConfig& mbc,
          rbd::InverseStatics& IS, Eigen::Vector3d q)
{
  Eigen::MatrixXd jacQ(3,3);
  Eigen::MatrixXd jacF(3,24);
  std::vector<Eigen::MatrixXd> jacMomentAndForces(4);
  (*output) << "\n\n\nChange config to " << q.transpose() << std::endl;
  mbc.q[1][0] = q(0);
  mbc.q[2][0] = q(1);
  mbc.q[3][0] = q(2);
  forwardKinematics(mb, mbc);
  forwardVelocity(mb, mbc);
  IS.inverseStatics(mb, mbc);
  IS.computeTorqueJacobianJoint(mb, mbc, jacMomentAndForces);

  (*output) << "========================================" << std::endl;
  (*output) << "Results for mbc.q =" << mbc.q << std::endl;
  (*output) << "mbc.jointTorque =\n" << mbc.jointTorque << std::endl;
  for (auto e : IS.f())
    (*output) << "IS.f().vector =\n" << e.vector() << std::endl;
  (*output) << "IS.jointTorqueDiff =\n" << IS.jointTorqueDiff() << std::endl;
}

BOOST_AUTO_TEST_CASE(XXXArmTorqueJacobian)
{
  boost::shared_ptr<boost::test_tools::output_test_stream> output =
      retrievePattern("InverseStaticsTest");

  rbd::MultiBody mb;
  rbd::MultiBodyConfig mbc;
  rbd::MultiBodyGraph mbg;
  std::tie(mb, mbc, mbg) = makeXXXarm();
  rbd::InverseStatics IS(mb);

  test(output, mb, mbc, IS, Vector3d(0, 0, 0));
  test(output, mb, mbc, IS, Vector3d(M_PI, 0, 0));
  test(output, mb, mbc, IS, Vector3d(0, M_PI / 2, 0));
  test(output, mb, mbc, IS, Vector3d(0.4, 0.1, 0.2));

  std::cout << output->str() << std::endl;
#ifndef __i386__
  BOOST_CHECK(output->match_pattern());
#endif
}  // end of namespace rbd
}

<|endoftext|>


<commit_before>/*
 * Copyright (C) 2015 Luke San Antonio
 * All rights reserved.
 */
#include <fstream>
#include <sstream>
#include <cstdlib>
#include <vector>
#include <thread>
#include <future>

#include "common/log.h"

#include "gfx/gl/driver.h"
#include "gfx/camera.h"
#include "gfx/mesh_chunk.h"
#include "gfx/idriver_ui_adapter.h"
#include "gfx/support/load_wavefront.h"
#include "gfx/support/mesh_conversion.h"
#include "gfx/support/generate_aabb.h"
#include "gfx/support/write_data_to_mesh.h"
#include "gfx/support/texture_load.h"
#include "gfx/support/software_texture.h"
#include "gfx/support/unproject.h"

#include "ui/load.h"
#include "ui/freetype_renderer.h"
#include "ui/mouse_logic.h"
#include "ui/simple_controller.h"

#include "map/map.h"
#include "map/water.h"
#include "map/terrain.h"

#include "stratlib/player_state.h"

#include "glad/glad.h"
#include "glfw3.h"

#define GLM_FORCE_RADIANS
#include "glm/glm.hpp"
#include "glm/gtc/matrix_transform.hpp"

#include "uv.h"

#define CATCH_CONFIG_RUNNER
#include "catch/catch.hpp"

glm::vec4 project_point(glm::vec4 pt,
                        glm::mat4 const& model,
                        glm::mat4 const& view,
                        glm::mat4 const& proj) noexcept
{
  pt = proj * view * model * pt;
  pt /= pt.w;
  return pt;
}

void scroll_callback(GLFWwindow* window, double, double deltay)
{
  auto cam_ptr = glfwGetWindowUserPointer(window);
  auto& camera = *((game::gfx::Camera*) cam_ptr);

  camera.fp.pos += -deltay;
}

game::ui::Mouse_State gen_mouse_state(GLFWwindow* w)
{
  game::ui::Mouse_State ret;

  ret.button_down =glfwGetMouseButton(w, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS;

  game::Vec<double> pos;
  glfwGetCursorPos(w, &pos.x, &pos.y);
  ret.position = game::vec_cast<int>(pos);

  return ret;
}

void log_gl_limits(game::Log_Severity s) noexcept
{
  GLint i = 0;
  glGetIntegerv(GL_MAX_ELEMENTS_VERTICES, &i);
  log(s, "GL_MAX_ELEMENTS_VERTICES: %", i);
}

struct Command_Options
{
};

Command_Options parse_command_line(int argc, char**)
{
  Command_Options opt;
  for(int i = 0; i < argc; ++i)
  {
    //auto option = argv[i];
  }
  return opt;
}

int main(int argc, char** argv)
{
  using namespace game;

  set_log_level(Log_Severity::Debug);

  uv_chdir("assets/");

  // Initialize logger.
  Scoped_Log_Init log_init_raii_lock{};

  // Parse command line arguments.
  auto options = parse_command_line(argc - 1, argv+1);

  // Init glfw.
  if(!glfwInit())
    return EXIT_FAILURE;

  auto window = glfwCreateWindow(1000, 1000, "Hello World", NULL, NULL);
  if(!window)
  {
    glfwTerminate();
    return EXIT_FAILURE;
  }

  // Init context + load gl functions.
  glfwMakeContextCurrent(window);
  gladLoadGLLoader((GLADloadproc) glfwGetProcAddress);

  // Log glfw version.
  log_i("Initialized GLFW %", glfwGetVersionString());

  int maj = glfwGetWindowAttrib(window, GLFW_CONTEXT_VERSION_MAJOR);
  int min = glfwGetWindowAttrib(window, GLFW_CONTEXT_VERSION_MINOR);
  int rev = glfwGetWindowAttrib(window, GLFW_CONTEXT_REVISION);

  // Log GL profile.
  log_i("OpenGL core profile %.%.%", maj, min, rev);

  {
  // Make an OpenGL driver.
  gfx::gl::Driver driver{Vec<int>{1000, 1000}};

  // Load our default shader.
  auto default_shader = driver.make_shader_repr();
  default_shader->load_vertex_part("shader/basic/v");
  default_shader->load_fragment_part("shader/basic/f");

  default_shader->set_projection_name("proj");
  default_shader->set_view_name("view");
  default_shader->set_model_name("model");
  default_shader->set_sampler_name("tex");
  default_shader->set_diffuse_name("dif");
  driver.use_shader(*default_shader);

  default_shader->set_sampler(0);

  // Load our textures.
  auto grass_tex = driver.make_texture_repr();
  load_png("tex/grass.png", *grass_tex);

  // Make an isometric camera.
  auto cam = gfx::make_isometric_camera();

  // Load the image
  Software_Texture terrain_image;
  load_png("map/default.png", terrain_image);

  // Convert it into a heightmap
  Maybe_Owned<Mesh> terrain = driver.make_mesh_repr();

  auto terrain_heightmap = make_heightmap_from_image(terrain_image);
  auto terrain_data =
    make_terrain_mesh(terrain_heightmap, {20, 20}, .001f, .01);

  auto terrain_model = glm::scale(glm::mat4(1.0f),glm::vec3(5.0f, 1.0f, 5.0f));

  gfx::allocate_mesh_buffers(terrain_data.mesh, *terrain);
  gfx::write_data_to_mesh(terrain_data.mesh, ref_mo(terrain));
  gfx::format_mesh_buffers(*terrain);
  terrain->set_primitive_type(Primitive_Type::Triangle);

  // Map + structures.
  Maybe_Owned<Mesh> structure_mesh = driver.make_mesh_repr();
  Map map({1000, 1000}); // <-- Map size for now
  strat::Player_State player_state{strat::Player_State_Type::Nothing};

  auto structures_future =
    std::async(std::launch::async, load_structures,"structure/structures.json",
               ref_mo(structure_mesh));

  int fps = 0;
  int time = glfwGetTime();

  // Set up some pre-rendering state.
  driver.clear_color_value(Color{0x55, 0x66, 0x77});
  driver.clear_depth_value(1.0);

  glEnable(GL_DEPTH_TEST);
  glDepthFunc(GL_LEQUAL);

  glEnable(GL_CULL_FACE);

  // Our quick hack to avoid splitting into multiple functions and dealing
  // either with global variables or like a bound struct or something.
  bool has_clicked_down = false;

  // Load our ui
  gfx::IDriver_UI_Adapter ui_adapter{driver};
  ui::Freetype_Renderer freetype_font;

  auto ui_load_params = ui::Load_Params{freetype_font, ui_adapter};
  auto hud = ui::load("ui/hud.json", ui_load_params);

  auto controller = ui::Simple_Controller{};

  auto structures = structures_future.get();

  hud->find_child_r("build_house")->add_click_listener([&](auto const& pt)
  {
    player_state.type = strat::Player_State_Type::Building;
    player_state.building.to_build = &structures[0];
  });
  hud->find_child_r("build_gvn_build")->add_click_listener([&](auto const& pt)
  {
    player_state.type = strat::Player_State_Type::Building;
    player_state.building.to_build = &structures[1];
  });

  hud->layout(driver.window_extents());

  controller.add_drag_listener([&](auto const& np, auto const& op)
  {
    auto oworld = gfx::unproject_screen(driver, cam, glm::mat4(1.0f), op);
    auto nworld = gfx::unproject_screen(driver, cam, glm::mat4(1.0f), np);

    cam.fp.pos += oworld - nworld;

    // This will give erroneous results if the user clicks on the part of the
    // screen with nothing drawn on it. So TODO: Put some checks in place so
    // we don't go messing with the camera zoom and whatnot.
  });

  glfwSetWindowUserPointer(window, &cam);
  glfwSetScrollCallback(window, scroll_callback);

  //water_obj.material->diffuse_color = Color{0xaa, 0xaa, 0xff};

  while(!glfwWindowShouldClose(window))
  {
    ++fps;
    glfwPollEvents();

    // Clear the screen and render the terrain.
    driver.clear();
    use_camera(driver, cam);

    driver.bind_texture(*grass_tex, 0);

    default_shader->set_diffuse(colors::white);
    default_shader->set_model(terrain_model);

    // Render the terrain before we calculate the depth of the mouse position.
    terrain->draw_elements(0, terrain_data.mesh.elements.size());

    auto mouse_state = gen_mouse_state(window);

    auto map_coord = gfx::unproject_screen(driver, cam, terrain_model,
                                           mouse_state.position);
    log_i("% %", map_coord.x, map_coord.z);

    controller.step(hud, mouse_state);

    {
      ui::Draw_Scoped_Lock scoped_draw_lock{ui_adapter};
      hud->render(ui_adapter);
    }
    glfwSwapBuffers(window);

    if(int(glfwGetTime()) != time)
    {
      time = glfwGetTime();
      log_d("fps: %", fps);
      fps = 0;
    }

    flush_log();
  }
  }
  glfwTerminate();
  return 0;
}
<commit_msg>We don't need map coordinates from mouse right now. (in main.cpp).<commit_after>/*
 * Copyright (C) 2015 Luke San Antonio
 * All rights reserved.
 */
#include <fstream>
#include <sstream>
#include <cstdlib>
#include <vector>
#include <thread>
#include <future>

#include "common/log.h"

#include "gfx/gl/driver.h"
#include "gfx/camera.h"
#include "gfx/mesh_chunk.h"
#include "gfx/idriver_ui_adapter.h"
#include "gfx/support/load_wavefront.h"
#include "gfx/support/mesh_conversion.h"
#include "gfx/support/generate_aabb.h"
#include "gfx/support/write_data_to_mesh.h"
#include "gfx/support/texture_load.h"
#include "gfx/support/software_texture.h"
#include "gfx/support/unproject.h"

#include "ui/load.h"
#include "ui/freetype_renderer.h"
#include "ui/mouse_logic.h"
#include "ui/simple_controller.h"

#include "map/map.h"
#include "map/water.h"
#include "map/terrain.h"

#include "stratlib/player_state.h"

#include "glad/glad.h"
#include "glfw3.h"

#define GLM_FORCE_RADIANS
#include "glm/glm.hpp"
#include "glm/gtc/matrix_transform.hpp"

#include "uv.h"

#define CATCH_CONFIG_RUNNER
#include "catch/catch.hpp"

glm::vec4 project_point(glm::vec4 pt,
                        glm::mat4 const& model,
                        glm::mat4 const& view,
                        glm::mat4 const& proj) noexcept
{
  pt = proj * view * model * pt;
  pt /= pt.w;
  return pt;
}

void scroll_callback(GLFWwindow* window, double, double deltay)
{
  auto cam_ptr = glfwGetWindowUserPointer(window);
  auto& camera = *((game::gfx::Camera*) cam_ptr);

  camera.fp.pos += -deltay;
}

game::ui::Mouse_State gen_mouse_state(GLFWwindow* w)
{
  game::ui::Mouse_State ret;

  ret.button_down =glfwGetMouseButton(w, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS;

  game::Vec<double> pos;
  glfwGetCursorPos(w, &pos.x, &pos.y);
  ret.position = game::vec_cast<int>(pos);

  return ret;
}

void log_gl_limits(game::Log_Severity s) noexcept
{
  GLint i = 0;
  glGetIntegerv(GL_MAX_ELEMENTS_VERTICES, &i);
  log(s, "GL_MAX_ELEMENTS_VERTICES: %", i);
}

struct Command_Options
{
};

Command_Options parse_command_line(int argc, char**)
{
  Command_Options opt;
  for(int i = 0; i < argc; ++i)
  {
    //auto option = argv[i];
  }
  return opt;
}

int main(int argc, char** argv)
{
  using namespace game;

  set_log_level(Log_Severity::Debug);

  uv_chdir("assets/");

  // Initialize logger.
  Scoped_Log_Init log_init_raii_lock{};

  // Parse command line arguments.
  auto options = parse_command_line(argc - 1, argv+1);

  // Init glfw.
  if(!glfwInit())
    return EXIT_FAILURE;

  auto window = glfwCreateWindow(1000, 1000, "Hello World", NULL, NULL);
  if(!window)
  {
    glfwTerminate();
    return EXIT_FAILURE;
  }

  // Init context + load gl functions.
  glfwMakeContextCurrent(window);
  gladLoadGLLoader((GLADloadproc) glfwGetProcAddress);

  // Log glfw version.
  log_i("Initialized GLFW %", glfwGetVersionString());

  int maj = glfwGetWindowAttrib(window, GLFW_CONTEXT_VERSION_MAJOR);
  int min = glfwGetWindowAttrib(window, GLFW_CONTEXT_VERSION_MINOR);
  int rev = glfwGetWindowAttrib(window, GLFW_CONTEXT_REVISION);

  // Log GL profile.
  log_i("OpenGL core profile %.%.%", maj, min, rev);

  {
  // Make an OpenGL driver.
  gfx::gl::Driver driver{Vec<int>{1000, 1000}};

  // Load our default shader.
  auto default_shader = driver.make_shader_repr();
  default_shader->load_vertex_part("shader/basic/v");
  default_shader->load_fragment_part("shader/basic/f");

  default_shader->set_projection_name("proj");
  default_shader->set_view_name("view");
  default_shader->set_model_name("model");
  default_shader->set_sampler_name("tex");
  default_shader->set_diffuse_name("dif");
  driver.use_shader(*default_shader);

  default_shader->set_sampler(0);

  // Load our textures.
  auto grass_tex = driver.make_texture_repr();
  load_png("tex/grass.png", *grass_tex);

  // Make an isometric camera.
  auto cam = gfx::make_isometric_camera();

  // Load the image
  Software_Texture terrain_image;
  load_png("map/default.png", terrain_image);

  // Convert it into a heightmap
  Maybe_Owned<Mesh> terrain = driver.make_mesh_repr();

  auto terrain_heightmap = make_heightmap_from_image(terrain_image);
  auto terrain_data =
    make_terrain_mesh(terrain_heightmap, {20, 20}, .001f, .01);

  auto terrain_model = glm::scale(glm::mat4(1.0f),glm::vec3(5.0f, 1.0f, 5.0f));

  gfx::allocate_mesh_buffers(terrain_data.mesh, *terrain);
  gfx::write_data_to_mesh(terrain_data.mesh, ref_mo(terrain));
  gfx::format_mesh_buffers(*terrain);
  terrain->set_primitive_type(Primitive_Type::Triangle);

  // Map + structures.
  Maybe_Owned<Mesh> structure_mesh = driver.make_mesh_repr();
  Map map({1000, 1000}); // <-- Map size for now
  strat::Player_State player_state{strat::Player_State_Type::Nothing};

  auto structures_future =
    std::async(std::launch::async, load_structures,"structure/structures.json",
               ref_mo(structure_mesh));

  int fps = 0;
  int time = glfwGetTime();

  // Set up some pre-rendering state.
  driver.clear_color_value(Color{0x55, 0x66, 0x77});
  driver.clear_depth_value(1.0);

  glEnable(GL_DEPTH_TEST);
  glDepthFunc(GL_LEQUAL);

  glEnable(GL_CULL_FACE);

  // Our quick hack to avoid splitting into multiple functions and dealing
  // either with global variables or like a bound struct or something.
  bool has_clicked_down = false;

  // Load our ui
  gfx::IDriver_UI_Adapter ui_adapter{driver};
  ui::Freetype_Renderer freetype_font;

  auto ui_load_params = ui::Load_Params{freetype_font, ui_adapter};
  auto hud = ui::load("ui/hud.json", ui_load_params);

  auto controller = ui::Simple_Controller{};

  auto structures = structures_future.get();

  hud->find_child_r("build_house")->add_click_listener([&](auto const& pt)
  {
    player_state.type = strat::Player_State_Type::Building;
    player_state.building.to_build = &structures[0];
  });
  hud->find_child_r("build_gvn_build")->add_click_listener([&](auto const& pt)
  {
    player_state.type = strat::Player_State_Type::Building;
    player_state.building.to_build = &structures[1];
  });

  hud->layout(driver.window_extents());

  controller.add_drag_listener([&](auto const& np, auto const& op)
  {
    auto oworld = gfx::unproject_screen(driver, cam, glm::mat4(1.0f), op);
    auto nworld = gfx::unproject_screen(driver, cam, glm::mat4(1.0f), np);

    cam.fp.pos += oworld - nworld;

    // This will give erroneous results if the user clicks on the part of the
    // screen with nothing drawn on it. So TODO: Put some checks in place so
    // we don't go messing with the camera zoom and whatnot.
  });

  glfwSetWindowUserPointer(window, &cam);
  glfwSetScrollCallback(window, scroll_callback);

  //water_obj.material->diffuse_color = Color{0xaa, 0xaa, 0xff};

  while(!glfwWindowShouldClose(window))
  {
    ++fps;
    glfwPollEvents();

    // Clear the screen and render the terrain.
    driver.clear();
    use_camera(driver, cam);

    driver.bind_texture(*grass_tex, 0);

    default_shader->set_diffuse(colors::white);
    default_shader->set_model(terrain_model);

    // Render the terrain before we calculate the depth of the mouse position.
    terrain->draw_elements(0, terrain_data.mesh.elements.size());

    auto mouse_state = gen_mouse_state(window);

    controller.step(hud, mouse_state);

    {
      ui::Draw_Scoped_Lock scoped_draw_lock{ui_adapter};
      hud->render(ui_adapter);
    }
    glfwSwapBuffers(window);

    if(int(glfwGetTime()) != time)
    {
      time = glfwGetTime();
      log_d("fps: %", fps);
      fps = 0;
    }

    flush_log();
  }
  }
  glfwTerminate();
  return 0;
}
<|endoftext|>


<commit_before>#include <iostream>
#include <vector>
#include <cmath>
#include "Body.h"

void integrateTracker(std::vector<Body *> &t, float dT, float G);
void calculateAcceleration(std::vector<Body *> &t, float G);
void printTracker(std::vector<Body *> &t);

int main() {
    std::vector<Body *> tracker;
    // Init tracker vector with simple orbital configuration
    tracker.push_back(new Body(100.0, 0.0, 0.0));
    tracker.push_back(new Body(1.0, 10.0, 0.0, 0.0, 1.0));

    for(int i = 0; i < 50; i++) {
        integrateTracker(tracker, 1.0f, 0.1f);
        printTracker(tracker);
    }
}

void integrateTracker(std::vector<Body *> &t, float dT, float G) {
    for(int n = 0; n < t.size(); n++) {
        t[n]->simUpdateVel(dT/2);
    }

    calculateAcceleration(t, G);

    for(int n = 0; n < t.size(); n++) {
        t[n]->simUpdatePos(dT);
    }

    for(int n = 0; n < t.size(); n++) {
        t[n]->simUpdateVel(dT/2);
    }
}

void calculateAcceleration(std::vector<Body *> &t, float G) {
    for(unsigned int i = 0; i < t.size(); i++) {
        t[i]->acc.set(0.0f, 0.0f);
    }

    for(int a = 0; a < t.size(); a++) {
        for(int b = a+1; b < t.size(); b++) {
            Vec2f d = t[a]->pos - t[b]->pos;
            float v = std::sqrt(std::pow(d.get(0),2) + std::pow(d.get(1),2));

            float fP = -(G * t[a]->mass * t[b]->mass) / std::pow(v,3);
            Vec2f fXY = d * fP;

            //std::cout << fXY.get(0) << " " << fXY.get(1) << std::endl;

            t[a]->acc += fXY / t[a]->mass;
            t[b]->acc += -(fXY) / t[b]->mass;
        }
    }
}

void printTracker(std::vector<Body *> &t) {
    for(int n = 0; n < t.size(); n++) {
        std::cout << t[n]->pos.get(0) << " " << t[n]->pos.get(1) << "  ";
    }
    std::cout << std::endl;
}<commit_msg>Fixed integration method.<commit_after>#include <iostream>
#include <vector>
#include <cmath>
#include "Body.h"

void integrateTracker(std::vector<Body *> &t, float dT, float G);
void calculateAcceleration(std::vector<Body *> &t, float G);
void printTracker(std::vector<Body *> &t);

int main() {
    std::vector<Body *> tracker;
    // Init tracker vector with simple orbital configuration
    tracker.push_back(new Body(100.0, 0.0, 0.0));
    tracker.push_back(new Body(1.0, 10.0, 0.0, 0.0, 1.0));

    for(int i = 0; i < 200; i++) {
        integrateTracker(tracker, 1.0f, 0.1f);
        printTracker(tracker);
    }
}

void integrateTracker(std::vector<Body *> &t, float dT, float G) {
    calculateAcceleration(t, G);

    for(int n = 0; n < t.size(); n++) {
        t[n]->simUpdateVel(dT);
    }

    for(int n = 0; n < t.size(); n++) {
        t[n]->simUpdatePos(dT);
    }
}

void calculateAcceleration(std::vector<Body *> &t, float G) {
    for(unsigned int i = 0; i < t.size(); i++) {
        t[i]->acc.set(0.0f, 0.0f);
    }

    for(int a = 0; a < t.size(); a++) {
        for(int b = a+1; b < t.size(); b++) {
            Vec2f d = t[a]->pos - t[b]->pos;
            float v = std::sqrt(std::pow(d.get(0),2) + std::pow(d.get(1),2));

            float fP = -(G * t[a]->mass * t[b]->mass) / std::pow(v,3);
            Vec2f fXY = d * fP;

            //std::cout << fXY.get(0) << " " << fXY.get(1) << std::endl;

            t[a]->acc += fXY / t[a]->mass;
            t[b]->acc += -(fXY) / t[b]->mass;
        }
    }
}

void printTracker(std::vector<Body *> &t) {
    for(int n = 0; n < t.size(); n++) {
        std::cout << t[n]->pos.get(0) << " " << t[n]->pos.get(1) << "  ";
    }
    std::cout << std::endl;
}<|endoftext|>


<commit_before>#include "Util.h"
#include "Introspection.h"
#include "Debug.h"
#include "Error.h"
#include <sstream>
#include <map>
#include <atomic>
#include <mutex>
#include <string>

#ifdef _MSC_VER
#include <io.h>
#else
#include <unistd.h>
#include <stdlib.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>

#ifdef __linux__
#include <linux/limits.h>  // For PATH_MAX
#endif
#ifdef _WIN32
#include <windows.h>
#endif

namespace Halide {
namespace Internal {

using std::string;
using std::vector;
using std::ostringstream;
using std::map;

std::string get_env_variable(char const *env_var_name, size_t &read) {
    if (!env_var_name) {
        return "";
    }
    read = 0;

    #ifdef _MSC_VER
    char lvl[32];
    getenv_s(&read, lvl, env_var_name);
    #else
    char *lvl = getenv(env_var_name);
    read = (lvl)?1:0;
    #endif

    if (read) {
        return std::string(lvl);
    }
    else {
        return "";
    }
}

string running_program_name() {
    // linux specific currently.
    #ifndef __linux__
    return "";
    #else
    string program_name;
    char path[PATH_MAX];
    ssize_t len = ::readlink("/proc/self/exe", path, sizeof(path)-1);
    if (len != -1) {
        path[len] = '\0';
        string tmp = std::string(path);
        program_name = tmp.substr(tmp.find_last_of("/")+1);
    }
    else {
        return "";
    }
    return program_name;
    #endif
}

namespace {
// We use 64K of memory to store unique counters for the purpose of
// making names unique. Using less memory increases the likelihood of
// hash collisions. This wouldn't break anything, but makes stmts
// slightly confusing to read because names that are actually unique
// will get suffixes that falsely hint that they are not.

const int num_unique_name_counters = (1 << 14);
std::atomic<int> unique_name_counters[num_unique_name_counters];

int unique_count(size_t h) {
    h = h & (num_unique_name_counters - 1);
    return unique_name_counters[h]++;
}
}

// There are three possible families of names returned by the methods below:
// 1) char pattern: (char that isn't '$') + number (e.g. v234)
// 2) string pattern: (string without '$') + '$' + number (e.g. fr#nk82$42)
// 3) a string that does not match the patterns above
// There are no collisions within each family, due to the unique_count
// done above, and there can be no collisions across families by
// construction.

string unique_name(char prefix) {
    if (prefix == '$') prefix = '_';
    return prefix + std::to_string(unique_count((size_t)(prefix)));
}

string unique_name(const std::string &prefix) {
    string sanitized = prefix;

    // Does the input string look like something returned from unique_name(char)?
    bool matches_char_pattern = true;

    // Does the input string look like something returned from unique_name(string)?
    bool matches_string_pattern = true;

    // Rewrite '$' to '_'. This is a many-to-one mapping, but that's
    // OK, we're about to hash anyway. It just means that some names
    // will share the same counter.
    int num_dollars = 0;
    for (size_t i = 0; i < sanitized.size(); i++) {
        if (sanitized[i] == '$') {
            num_dollars++;
            sanitized[i] = '_';
        }
        if (i > 0 && !isdigit(sanitized[i])) {
            // Found a non-digit after the first char
            matches_char_pattern = false;
            if (num_dollars) {
                // Found a non-digit after a '$'
                matches_string_pattern = false;
            }
        }
    }
    matches_string_pattern &= num_dollars == 1;
    matches_char_pattern &= prefix.size() > 1;

    // Then add a suffix that's globally unique relative to the hash
    // of the sanitized name.
    int count = unique_count(std::hash<std::string>()(sanitized));
    if (count == 0) {
        // We can return the name as-is if there's no risk of it
        // looking like something unique_name has ever returned in the
        // past or will ever return in the future.
        if (!matches_char_pattern && !matches_string_pattern) {
            return prefix;
        }
    }

    return sanitized + "$" + std::to_string(count);
}

bool starts_with(const string &str, const string &prefix) {
    if (str.size() < prefix.size()) return false;
    for (size_t i = 0; i < prefix.size(); i++) {
        if (str[i] != prefix[i]) return false;
    }
    return true;
}

bool ends_with(const string &str, const string &suffix) {
    if (str.size() < suffix.size()) return false;
    size_t off = str.size() - suffix.size();
    for (size_t i = 0; i < suffix.size(); i++) {
        if (str[off+i] != suffix[i]) return false;
    }
    return true;
}

string replace_all(const string &str, const string &find, const string &replace) {
    size_t pos = 0;
    string result = str;
    while ((pos = result.find(find, pos)) != string::npos) {
        result.replace(pos, find.length(), replace);
        pos += replace.length();
    }
    return result;
}

string base_name(const string &name, char delim) {
    size_t off = name.rfind(delim);
    if (off == string::npos) {
        return name;
    }
    return name.substr(off+1);
}

string make_entity_name(void *stack_ptr, const string &type, char prefix) {
    string name = Introspection::get_variable_name(stack_ptr, type);

    if (name.empty()) {
        return unique_name(prefix);
    } else {
        // Halide names may not contain '.'
        for (size_t i = 0; i < name.size(); i++) {
            if (name[i] == '.') {
                name[i] = ':';
            }
        }
        return unique_name(name);
    }
}

std::vector<std::string> split_string(const std::string &source, const std::string &delim) {
    std::vector<std::string> elements;
    size_t start = 0;
    size_t found = 0;
    while ((found = source.find(delim, start)) != std::string::npos) {
        elements.push_back(source.substr(start, found - start));
        start = found + delim.size();
    }

    // If start is exactly source.size(), the last thing in source is a
    // delimiter, in which case we want to add an empty string to elements.
    if (start <= source.size()) {
        elements.push_back(source.substr(start, std::string::npos));
    }
    return elements;
}

std::string extract_namespaces(const std::string &name, std::vector<std::string> &namespaces) {
    namespaces = split_string(name, "::");
    std::string result = namespaces.back();
    namespaces.pop_back();
    return result;
}

bool file_exists(const std::string &name) {
    #ifdef _MSC_VER
    return _access(name.c_str(), 0) == 0;
    #else
    return ::access(name.c_str(), F_OK) == 0;
    #endif
}

void file_unlink(const std::string &name) {
    #ifdef _MSC_VER
    _unlink(name.c_str());
    #else
    ::unlink(name.c_str());
    #endif
}

FileStat file_stat(const std::string &name) {
    #ifdef _MSC_VER
    struct _stat a;
    if (_stat(name.c_str(), &a) != 0) {
        user_error << "Could not stat " << name << "\n";
    }
    #else
    struct stat a;
    if (::stat(name.c_str(), &a) != 0) {
        user_error << "Could not stat " << name << "\n";
    }
    #endif
    return {static_cast<uint64_t>(a.st_size),
            static_cast<uint32_t>(a.st_mtime),
            static_cast<uint32_t>(a.st_uid),
            static_cast<uint32_t>(a.st_gid),
            static_cast<uint32_t>(a.st_mode)};
}

std::string file_make_temp(const std::string &base, const std::string &ext) {
    #ifdef _MSC_VER
    // Windows implementations of mkstemp() try to create the file in the root
    // directory, which is... problematic.
    TCHAR tmp_path[MAX_PATH], tmp_file[MAX_PATH];
    DWORD ret = GetTempPath(MAX_PATH, tmp_path);
    internal_assert(ret != 0);
    // Note that GetTempFileName() actually creates the file.
    ret = GetTempFileName(tmp_path, base.c_str(), 0, tmp_file);
    internal_assert(ret != 0);
    return std::string(tmp_file);
    #else
    std::string templ = base + "XXXXXX" + ext;
    // Copy into a temporary buffer, since mkstemp modifies the buffer in place.
    std::vector<char> buf(templ.size() + 1);
    strcpy(&buf[0], templ.c_str());
    int fd = mkstemps(&buf[0], ext.size());
    internal_assert(fd != -1) << "Unable to create temp file for " << base << ext;
    close(fd);
    return std::string(&buf[0]);
    #endif
}

}
}
<commit_msg>mingw doesn't have mkstemps, but should have GetTempPath<commit_after>#include "Util.h"
#include "Introspection.h"
#include "Debug.h"
#include "Error.h"
#include <sstream>
#include <map>
#include <atomic>
#include <mutex>
#include <string>

#ifdef _MSC_VER
#include <io.h>
#else
#include <unistd.h>
#include <stdlib.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>

#ifdef __linux__
#include <linux/limits.h>  // For PATH_MAX
#endif
#ifdef _WIN32
#include <windows.h>
#endif

namespace Halide {
namespace Internal {

using std::string;
using std::vector;
using std::ostringstream;
using std::map;

std::string get_env_variable(char const *env_var_name, size_t &read) {
    if (!env_var_name) {
        return "";
    }
    read = 0;

    #ifdef _MSC_VER
    char lvl[32];
    getenv_s(&read, lvl, env_var_name);
    #else
    char *lvl = getenv(env_var_name);
    read = (lvl)?1:0;
    #endif

    if (read) {
        return std::string(lvl);
    }
    else {
        return "";
    }
}

string running_program_name() {
    // linux specific currently.
    #ifndef __linux__
    return "";
    #else
    string program_name;
    char path[PATH_MAX];
    ssize_t len = ::readlink("/proc/self/exe", path, sizeof(path)-1);
    if (len != -1) {
        path[len] = '\0';
        string tmp = std::string(path);
        program_name = tmp.substr(tmp.find_last_of("/")+1);
    }
    else {
        return "";
    }
    return program_name;
    #endif
}

namespace {
// We use 64K of memory to store unique counters for the purpose of
// making names unique. Using less memory increases the likelihood of
// hash collisions. This wouldn't break anything, but makes stmts
// slightly confusing to read because names that are actually unique
// will get suffixes that falsely hint that they are not.

const int num_unique_name_counters = (1 << 14);
std::atomic<int> unique_name_counters[num_unique_name_counters];

int unique_count(size_t h) {
    h = h & (num_unique_name_counters - 1);
    return unique_name_counters[h]++;
}
}

// There are three possible families of names returned by the methods below:
// 1) char pattern: (char that isn't '$') + number (e.g. v234)
// 2) string pattern: (string without '$') + '$' + number (e.g. fr#nk82$42)
// 3) a string that does not match the patterns above
// There are no collisions within each family, due to the unique_count
// done above, and there can be no collisions across families by
// construction.

string unique_name(char prefix) {
    if (prefix == '$') prefix = '_';
    return prefix + std::to_string(unique_count((size_t)(prefix)));
}

string unique_name(const std::string &prefix) {
    string sanitized = prefix;

    // Does the input string look like something returned from unique_name(char)?
    bool matches_char_pattern = true;

    // Does the input string look like something returned from unique_name(string)?
    bool matches_string_pattern = true;

    // Rewrite '$' to '_'. This is a many-to-one mapping, but that's
    // OK, we're about to hash anyway. It just means that some names
    // will share the same counter.
    int num_dollars = 0;
    for (size_t i = 0; i < sanitized.size(); i++) {
        if (sanitized[i] == '$') {
            num_dollars++;
            sanitized[i] = '_';
        }
        if (i > 0 && !isdigit(sanitized[i])) {
            // Found a non-digit after the first char
            matches_char_pattern = false;
            if (num_dollars) {
                // Found a non-digit after a '$'
                matches_string_pattern = false;
            }
        }
    }
    matches_string_pattern &= num_dollars == 1;
    matches_char_pattern &= prefix.size() > 1;

    // Then add a suffix that's globally unique relative to the hash
    // of the sanitized name.
    int count = unique_count(std::hash<std::string>()(sanitized));
    if (count == 0) {
        // We can return the name as-is if there's no risk of it
        // looking like something unique_name has ever returned in the
        // past or will ever return in the future.
        if (!matches_char_pattern && !matches_string_pattern) {
            return prefix;
        }
    }

    return sanitized + "$" + std::to_string(count);
}

bool starts_with(const string &str, const string &prefix) {
    if (str.size() < prefix.size()) return false;
    for (size_t i = 0; i < prefix.size(); i++) {
        if (str[i] != prefix[i]) return false;
    }
    return true;
}

bool ends_with(const string &str, const string &suffix) {
    if (str.size() < suffix.size()) return false;
    size_t off = str.size() - suffix.size();
    for (size_t i = 0; i < suffix.size(); i++) {
        if (str[off+i] != suffix[i]) return false;
    }
    return true;
}

string replace_all(const string &str, const string &find, const string &replace) {
    size_t pos = 0;
    string result = str;
    while ((pos = result.find(find, pos)) != string::npos) {
        result.replace(pos, find.length(), replace);
        pos += replace.length();
    }
    return result;
}

string base_name(const string &name, char delim) {
    size_t off = name.rfind(delim);
    if (off == string::npos) {
        return name;
    }
    return name.substr(off+1);
}

string make_entity_name(void *stack_ptr, const string &type, char prefix) {
    string name = Introspection::get_variable_name(stack_ptr, type);

    if (name.empty()) {
        return unique_name(prefix);
    } else {
        // Halide names may not contain '.'
        for (size_t i = 0; i < name.size(); i++) {
            if (name[i] == '.') {
                name[i] = ':';
            }
        }
        return unique_name(name);
    }
}

std::vector<std::string> split_string(const std::string &source, const std::string &delim) {
    std::vector<std::string> elements;
    size_t start = 0;
    size_t found = 0;
    while ((found = source.find(delim, start)) != std::string::npos) {
        elements.push_back(source.substr(start, found - start));
        start = found + delim.size();
    }

    // If start is exactly source.size(), the last thing in source is a
    // delimiter, in which case we want to add an empty string to elements.
    if (start <= source.size()) {
        elements.push_back(source.substr(start, std::string::npos));
    }
    return elements;
}

std::string extract_namespaces(const std::string &name, std::vector<std::string> &namespaces) {
    namespaces = split_string(name, "::");
    std::string result = namespaces.back();
    namespaces.pop_back();
    return result;
}

bool file_exists(const std::string &name) {
    #ifdef _MSC_VER
    return _access(name.c_str(), 0) == 0;
    #else
    return ::access(name.c_str(), F_OK) == 0;
    #endif
}

void file_unlink(const std::string &name) {
    #ifdef _MSC_VER
    _unlink(name.c_str());
    #else
    ::unlink(name.c_str());
    #endif
}

FileStat file_stat(const std::string &name) {
    #ifdef _MSC_VER
    struct _stat a;
    if (_stat(name.c_str(), &a) != 0) {
        user_error << "Could not stat " << name << "\n";
    }
    #else
    struct stat a;
    if (::stat(name.c_str(), &a) != 0) {
        user_error << "Could not stat " << name << "\n";
    }
    #endif
    return {static_cast<uint64_t>(a.st_size),
            static_cast<uint32_t>(a.st_mtime),
            static_cast<uint32_t>(a.st_uid),
            static_cast<uint32_t>(a.st_gid),
            static_cast<uint32_t>(a.st_mode)};
}

std::string file_make_temp(const std::string &base, const std::string &ext) {
    #ifdef _WIN32
    // Windows implementations of mkstemp() try to create the file in the root
    // directory, which is... problematic.
    TCHAR tmp_path[MAX_PATH], tmp_file[MAX_PATH];
    DWORD ret = GetTempPath(MAX_PATH, tmp_path);
    internal_assert(ret != 0);
    // Note that GetTempFileName() actually creates the file.
    ret = GetTempFileName(tmp_path, base.c_str(), 0, tmp_file);
    internal_assert(ret != 0);
    return std::string(tmp_file);
    #else
    std::string templ = base + "XXXXXX" + ext;
    // Copy into a temporary buffer, since mkstemp modifies the buffer in place.
    std::vector<char> buf(templ.size() + 1);
    strcpy(&buf[0], templ.c_str());
    int fd = mkstemps(&buf[0], ext.size());
    internal_assert(fd != -1) << "Unable to create temp file for " << base << ext;
    close(fd);
    return std::string(&buf[0]);
    #endif
}

}
}
<|endoftext|>


<commit_before>// Copyright (c) 2014, Facebook, Inc.  All rights reserved.
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree. An additional grant
// of patent rights can be found in the PATENTS file in the same directory.

#include "port/likely.h"
#include "util/mutexlock.h"
#include "util/thread_status_impl.h"

namespace rocksdb {

ThreadStatusImpl thread_local_status;

#if ROCKSDB_USING_THREAD_STATUS
__thread ThreadStatusData* ThreadStatusImpl::thread_status_data_ = nullptr;
std::mutex ThreadStatusImpl::thread_list_mutex_;
std::unordered_set<ThreadStatusData*> ThreadStatusImpl::thread_data_set_;
std::unordered_map<const void*, ConstantColumnFamilyInfo*>
    ThreadStatusImpl::cf_info_map_;
std::unordered_map<const void*, std::unordered_set<const void*>>
    ThreadStatusImpl::db_key_map_;

ThreadStatusImpl::~ThreadStatusImpl() {
  std::lock_guard<std::mutex> lck(thread_list_mutex_);
  for (auto* thread_data : thread_data_set_) {
    assert(thread_data->thread_type == ThreadStatus::ThreadType::USER_THREAD);
    delete thread_data;
  }
  assert(thread_data_set_.size() == 0);
  thread_data_set_.clear();
}

void ThreadStatusImpl::UnregisterThread() {
  if (thread_status_data_ != nullptr) {
    std::lock_guard<std::mutex> lck(thread_list_mutex_);
    thread_data_set_.erase(thread_status_data_);
    delete thread_status_data_;
  }
}

void ThreadStatusImpl::SetThreadType(
    ThreadStatus::ThreadType ttype) {
  auto* data = InitAndGet();
  data->thread_type.store(ttype, std::memory_order_relaxed);
}

void ThreadStatusImpl::SetColumnFamilyInfoKey(
    const void* cf_key) {
  auto* data = InitAndGet();
  data->cf_key.store(cf_key, std::memory_order_relaxed);
}

void ThreadStatusImpl::SetEventInfoPtr(
    const ThreadEventInfo* event_info) {
  auto* data = InitAndGet();
  data->event_info.store(event_info, std::memory_order_relaxed);
}

Status ThreadStatusImpl::GetThreadList(
    std::vector<ThreadStatus>* thread_list) const {
  thread_list->clear();
  std::vector<std::shared_ptr<ThreadStatusData>> valid_list;

  std::lock_guard<std::mutex> lck(thread_list_mutex_);
  for (auto* thread_data : thread_data_set_) {
    assert(thread_data);
    auto thread_type = thread_data->thread_type.load(
        std::memory_order_relaxed);
    auto cf_key = thread_data->cf_key.load(
        std::memory_order_relaxed);
    auto iter = cf_info_map_.find(cf_key);
    assert(cf_key == 0 || iter != cf_info_map_.end());
    auto* cf_info = iter != cf_info_map_.end() ?
        iter->second : nullptr;
    auto* event_info = thread_data->event_info.load(
        std::memory_order_relaxed);
    const std::string* db_name = nullptr;
    const std::string* cf_name = nullptr;
    const std::string* event_name = nullptr;
    if (cf_info != nullptr) {
      db_name = &cf_info->db_name;
      cf_name = &cf_info->cf_name;
      // display lower-level info only when higher-level info is available.
      if (event_info != nullptr) {
        event_name = &event_info->event_name;
      }
    }
    thread_list->emplace_back(
        thread_data->thread_id, thread_type,
        db_name ? *db_name : "",
        cf_name ? *cf_name : "",
        event_name ? *event_name : "");
  }

  return Status::OK();
}

ThreadStatusData* ThreadStatusImpl::InitAndGet() {
  if (UNLIKELY(thread_status_data_ == nullptr)) {
    thread_status_data_ = new ThreadStatusData();
    thread_status_data_->thread_id = reinterpret_cast<uint64_t>(
        thread_status_data_);
    std::lock_guard<std::mutex> lck(thread_list_mutex_);
    thread_data_set_.insert(thread_status_data_);
  }
  return thread_status_data_;
}

void ThreadStatusImpl::NewColumnFamilyInfo(
    const void* db_key, const std::string& db_name,
    const void* cf_key, const std::string& cf_name) {
  std::lock_guard<std::mutex> lck(thread_list_mutex_);

  cf_info_map_[cf_key] = new ConstantColumnFamilyInfo(db_key, db_name, cf_name);
  db_key_map_[db_key].insert(cf_key);
}

void ThreadStatusImpl::EraseColumnFamilyInfo(const void* cf_key) {
  std::lock_guard<std::mutex> lck(thread_list_mutex_);
  auto cf_pair = cf_info_map_.find(cf_key);
  assert(cf_pair != cf_info_map_.end());

  auto* cf_info = cf_pair->second;
  assert(cf_info);

  // Remove its entry from db_key_map_ by the following steps:
  // 1. Obtain the entry in db_key_map_ whose set contains cf_key
  // 2. Remove it from the set.
  auto db_pair = db_key_map_.find(cf_info->db_key);
  assert(db_pair != db_key_map_.end());
  size_t result __attribute__((unused)) = db_pair->second.erase(cf_key);
  assert(result);

  delete cf_info;
  result = cf_info_map_.erase(cf_key);
  assert(result);
}

void ThreadStatusImpl::EraseDatabaseInfo(const void* db_key) {
  std::lock_guard<std::mutex> lck(thread_list_mutex_);
  auto db_pair = db_key_map_.find(db_key);
  if (UNLIKELY(db_pair == db_key_map_.end())) {
    // In some occasional cases such as DB::Open fails, we won't
    // register ColumnFamilyInfo for a db.
    return;
  }

  size_t result __attribute__((unused)) = 0;
  for (auto cf_key : db_pair->second) {
    auto cf_pair = cf_info_map_.find(cf_key);
    assert(cf_pair != cf_info_map_.end());
    delete cf_pair->second;
    result = cf_info_map_.erase(cf_key);
    assert(result);
  }
  db_key_map_.erase(db_key);
}

#else

ThreadStatusImpl::~ThreadStatusImpl() {
}

void ThreadStatusImpl::UnregisterThread() {
}

void ThreadStatusImpl::SetThreadType(
    ThreadStatus::ThreadType ttype) {
}

void ThreadStatusImpl::SetColumnFamilyInfoKey(
    const void* cf_key) {
}

void ThreadStatusImpl::SetEventInfoPtr(
    const ThreadEventInfo* event_info) {
}

Status ThreadStatusImpl::GetThreadList(
    std::vector<ThreadStatus>* thread_list) const {
  return Status::NotSupported(
      "GetThreadList is not supported in the current running environment.");
}

void ThreadStatusImpl::NewColumnFamilyInfo(
    const void* db_key, const std::string& db_name,
    const void* cf_key, const std::string& cf_name) {
}

void ThreadStatusImpl::EraseColumnFamilyInfo(const void* cf_key) {
}

void ThreadStatusImpl::EraseDatabaseInfo(const void* db_key) {
}

#endif  // ROCKSDB_USING_THREAD_STATUS
}  // namespace rocksdb
<commit_msg>Fixed ~ThreadStatusImpl().<commit_after>// Copyright (c) 2014, Facebook, Inc.  All rights reserved.
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree. An additional grant
// of patent rights can be found in the PATENTS file in the same directory.

#include "port/likely.h"
#include "util/mutexlock.h"
#include "util/thread_status_impl.h"

namespace rocksdb {

ThreadStatusImpl thread_local_status;

#if ROCKSDB_USING_THREAD_STATUS
__thread ThreadStatusData* ThreadStatusImpl::thread_status_data_ = nullptr;
std::mutex ThreadStatusImpl::thread_list_mutex_;
std::unordered_set<ThreadStatusData*> ThreadStatusImpl::thread_data_set_;
std::unordered_map<const void*, ConstantColumnFamilyInfo*>
    ThreadStatusImpl::cf_info_map_;
std::unordered_map<const void*, std::unordered_set<const void*>>
    ThreadStatusImpl::db_key_map_;

ThreadStatusImpl::~ThreadStatusImpl() {
  assert(thread_data_set_.size() == 0);
}

void ThreadStatusImpl::UnregisterThread() {
  if (thread_status_data_ != nullptr) {
    std::lock_guard<std::mutex> lck(thread_list_mutex_);
    thread_data_set_.erase(thread_status_data_);
    delete thread_status_data_;
    thread_status_data_ = nullptr;
  }
}

void ThreadStatusImpl::SetThreadType(
    ThreadStatus::ThreadType ttype) {
  auto* data = InitAndGet();
  data->thread_type.store(ttype, std::memory_order_relaxed);
}

void ThreadStatusImpl::SetColumnFamilyInfoKey(
    const void* cf_key) {
  auto* data = InitAndGet();
  data->cf_key.store(cf_key, std::memory_order_relaxed);
}

void ThreadStatusImpl::SetEventInfoPtr(
    const ThreadEventInfo* event_info) {
  auto* data = InitAndGet();
  data->event_info.store(event_info, std::memory_order_relaxed);
}

Status ThreadStatusImpl::GetThreadList(
    std::vector<ThreadStatus>* thread_list) const {
  thread_list->clear();
  std::vector<std::shared_ptr<ThreadStatusData>> valid_list;

  std::lock_guard<std::mutex> lck(thread_list_mutex_);
  for (auto* thread_data : thread_data_set_) {
    assert(thread_data);
    auto thread_type = thread_data->thread_type.load(
        std::memory_order_relaxed);
    auto cf_key = thread_data->cf_key.load(
        std::memory_order_relaxed);
    auto iter = cf_info_map_.find(cf_key);
    assert(cf_key == 0 || iter != cf_info_map_.end());
    auto* cf_info = iter != cf_info_map_.end() ?
        iter->second : nullptr;
    auto* event_info = thread_data->event_info.load(
        std::memory_order_relaxed);
    const std::string* db_name = nullptr;
    const std::string* cf_name = nullptr;
    const std::string* event_name = nullptr;
    if (cf_info != nullptr) {
      db_name = &cf_info->db_name;
      cf_name = &cf_info->cf_name;
      // display lower-level info only when higher-level info is available.
      if (event_info != nullptr) {
        event_name = &event_info->event_name;
      }
    }
    thread_list->emplace_back(
        thread_data->thread_id, thread_type,
        db_name ? *db_name : "",
        cf_name ? *cf_name : "",
        event_name ? *event_name : "");
  }

  return Status::OK();
}

ThreadStatusData* ThreadStatusImpl::InitAndGet() {
  if (UNLIKELY(thread_status_data_ == nullptr)) {
    thread_status_data_ = new ThreadStatusData();
    thread_status_data_->thread_id = reinterpret_cast<uint64_t>(
        thread_status_data_);
    std::lock_guard<std::mutex> lck(thread_list_mutex_);
    thread_data_set_.insert(thread_status_data_);
  }
  return thread_status_data_;
}

void ThreadStatusImpl::NewColumnFamilyInfo(
    const void* db_key, const std::string& db_name,
    const void* cf_key, const std::string& cf_name) {
  std::lock_guard<std::mutex> lck(thread_list_mutex_);

  cf_info_map_[cf_key] = new ConstantColumnFamilyInfo(db_key, db_name, cf_name);
  db_key_map_[db_key].insert(cf_key);
}

void ThreadStatusImpl::EraseColumnFamilyInfo(const void* cf_key) {
  std::lock_guard<std::mutex> lck(thread_list_mutex_);
  auto cf_pair = cf_info_map_.find(cf_key);
  assert(cf_pair != cf_info_map_.end());

  auto* cf_info = cf_pair->second;
  assert(cf_info);

  // Remove its entry from db_key_map_ by the following steps:
  // 1. Obtain the entry in db_key_map_ whose set contains cf_key
  // 2. Remove it from the set.
  auto db_pair = db_key_map_.find(cf_info->db_key);
  assert(db_pair != db_key_map_.end());
  size_t result __attribute__((unused)) = db_pair->second.erase(cf_key);
  assert(result);

  delete cf_info;
  result = cf_info_map_.erase(cf_key);
  assert(result);
}

void ThreadStatusImpl::EraseDatabaseInfo(const void* db_key) {
  std::lock_guard<std::mutex> lck(thread_list_mutex_);
  auto db_pair = db_key_map_.find(db_key);
  if (UNLIKELY(db_pair == db_key_map_.end())) {
    // In some occasional cases such as DB::Open fails, we won't
    // register ColumnFamilyInfo for a db.
    return;
  }

  size_t result __attribute__((unused)) = 0;
  for (auto cf_key : db_pair->second) {
    auto cf_pair = cf_info_map_.find(cf_key);
    assert(cf_pair != cf_info_map_.end());
    delete cf_pair->second;
    result = cf_info_map_.erase(cf_key);
    assert(result);
  }
  db_key_map_.erase(db_key);
}

#else

ThreadStatusImpl::~ThreadStatusImpl() {
}

void ThreadStatusImpl::UnregisterThread() {
}

void ThreadStatusImpl::SetThreadType(
    ThreadStatus::ThreadType ttype) {
}

void ThreadStatusImpl::SetColumnFamilyInfoKey(
    const void* cf_key) {
}

void ThreadStatusImpl::SetEventInfoPtr(
    const ThreadEventInfo* event_info) {
}

Status ThreadStatusImpl::GetThreadList(
    std::vector<ThreadStatus>* thread_list) const {
  return Status::NotSupported(
      "GetThreadList is not supported in the current running environment.");
}

void ThreadStatusImpl::NewColumnFamilyInfo(
    const void* db_key, const std::string& db_name,
    const void* cf_key, const std::string& cf_name) {
}

void ThreadStatusImpl::EraseColumnFamilyInfo(const void* cf_key) {
}

void ThreadStatusImpl::EraseDatabaseInfo(const void* db_key) {
}

#endif  // ROCKSDB_USING_THREAD_STATUS
}  // namespace rocksdb
<|endoftext|>


<commit_before>#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ArduinoJson.h>

#include "helpers.hpp"
#include "defaults.hpp"
#include "radio.hpp"
#include "Config.hpp"
#include "TrackingData.hpp"
#include "ConfigServer.hpp"

Config* conf = new Config();
Radio rf(conf);
TrackingData data(conf, 10);
ConfigServer cfgSrv(80);

void setup () {
    // Set up the EEPROM w/ a maximum size of 4096 bytes
    EEPROM.begin(4096);

    /// Set up the built-in LED and turn it on to let the user know the ESP is working
    pinMode(LED_PIN, OUTPUT);
    digitalWrite(LED_PIN, HIGH);

    /// Open up the serial monitor
    Serial.begin(115200);
    Serial.println();

    // If the pin is not pulled to ground read config or write the default one if its not
    if (digitalRead(RESET_CONF_PIN)) {
        conf->read(0);
    } else {
        Serial.println("Restoring factory settings...");
        conf->write(0);
    }

    // Setup the radios according to the configuration
    rf.setup();

    // Setup the OTA server
    OTA();
}

void runServerHandlers() {
    ArduinoOTA.handle();
    cfgSrv.handle();
}

int sleepTimeMS;
void loop() {
    // Check for a WiFi connection and attempt to reestablish it if it died
    if (!rf.connected()) {
        digitalWrite(LED_PIN, LOW);
        if (!rf.connect()) {
            // Enter deep sleep in case the connection failed
            sleepTimeMS = conf->get<int>("wifiReconnectionInterval");
            blink(); blink(); blink();
            Serial.printf("Connection failed. Entering deep sleep mode for %dms ...\n", sleepTimeMS);
            ESP.deepSleep(sleepTimeMS * 1000, WAKE_NO_RFCAL);
        }
        digitalWrite(LED_PIN, HIGH);
    }

    // TODO: The data.send() step takes way too long
    if (conf->get<bool>("active")) {
        /// Update the environment data (scan for networks)
        if (data.update()) {
            // Send the data to the FIND Server
            bool successful = data.send();

            /// Blink to indicate that we have sent our location
            if (successful) blink();
        }
    }

    // Run all kinds of server handlers
    runServerHandlers();

    // Enter a very basic sleep mode and limit the amount of cycles to preserve power
    // (Turn off the radio and wake it up periodically to answer beacon signals from router)
    WiFi.setSleepMode(WIFI_MODEM_SLEEP);
    delay(1000);
}
<commit_msg>Added printf like example functions<commit_after>#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ArduinoJson.h>

#include "helpers.hpp"
#include "defaults.hpp"
#include "radio.hpp"
#include "Config.hpp"
#include "TrackingData.hpp"
#include "ConfigServer.hpp"

Config* conf = new Config();
Radio rf(conf);
TrackingData data(conf, 10);
ConfigServer cfgSrv(80);

// Test functions for remote debugging
int vasprintf(char** strp, const char* fmt, va_list ap) {
    va_list ap2;
    va_copy(ap2, ap);
    char tmp[1];
    int size = vsnprintf(tmp, 1, fmt, ap2);
    if (size <= 0) return size;
    va_end(ap2);
    size += 1;
    *strp = (char*)malloc(size * sizeof(char));
    return vsnprintf(*strp, size, fmt, ap);
}

void pline(char* str, ...) {
	char* buf;
	va_list args;

	va_start(args, str);
	vasprintf(&buf, str, args);
	va_end(args);

	Serial.println(buf);
}
// End of test functions

void setup () {
    // Set up the EEPROM w/ a maximum size of 4096 bytes
    EEPROM.begin(4096);

    /// Set up the built-in LED and turn it on to let the user know the ESP is working
    pinMode(LED_PIN, OUTPUT);
    digitalWrite(LED_PIN, HIGH);

    /// Open up the serial monitor
    Serial.begin(115200);
    Serial.println();

    // If the pin is not pulled to ground read config or write the default one if its not
    if (digitalRead(RESET_CONF_PIN)) {
        conf->read(0);
    } else {
        Serial.println("Restoring factory settings...");
        conf->write(0);
    }

    // Setup the radios according to the configuration
    rf.setup();

    // Setup the OTA server
    OTA();

    pline("test %d", 10);
}

void runServerHandlers() {
    ArduinoOTA.handle();
    cfgSrv.handle();
}

int sleepTimeMS;
void loop() {
    // Check for a WiFi connection and attempt to reestablish it if it died
    if (!rf.connected()) {
        digitalWrite(LED_PIN, LOW);
        if (!rf.connect()) {
            // Enter deep sleep in case the connection failed
            sleepTimeMS = conf->get<int>("wifiReconnectionInterval");
            blink(); blink(); blink();
            Serial.printf("Connection failed. Entering deep sleep mode for %dms ...\n", sleepTimeMS);
            ESP.deepSleep(sleepTimeMS * 1000, WAKE_NO_RFCAL);
        }
        digitalWrite(LED_PIN, HIGH);
    }

    // TODO: The data.send() step takes way too long
    if (conf->get<bool>("active")) {
        /// Update the environment data (scan for networks)
        if (data.update()) {
            // Send the data to the FIND Server
            bool successful = data.send();

            /// Blink to indicate that we have sent our location
            if (successful) blink();
        }
    }

    // Run all kinds of server handlers
    runServerHandlers();

    // Enter a very basic sleep mode and limit the amount of cycles to preserve power
    // (Turn off the radio and wake it up periodically to answer beacon signals from router)
    WiFi.setSleepMode(WIFI_MODEM_SLEEP);
    delay(1000);
}
<|endoftext|>


<commit_before>#include "mainform.h"

#include <QFile>
#include <QMessageBox>
#include "config.h"
#include "linkeditdialog.h"
#include "ui_mainform.h"
#include "widgets/nofocusdelegate.h"

MainForm::MainForm(QWidget* parent) :
	QWidget(parent),
	ui_(new Ui::MainForm),
	linksModel_(new LinksModel(this)),
	sourceModel_(new DirListModel(this)),
	targetModel_(new DirListModel(this))
{
	ui_->setupUi(this);

	connect(ui_->showHiddenButton,
			SIGNAL(toggled(bool)),
			SLOT(onShowHiddenButtonToggled(bool)));

	connect(ui_->showLinkedButton,
			SIGNAL(clicked()),
			SLOT(onShowLinkedButtonClicked()));

	ui_->sourceLabel->setElideMode(Qt::ElideMiddle);
	ui_->targetLabel->setElideMode(Qt::ElideMiddle);

	connect(sourceModel_,
			SIGNAL(currentDirChanged(QString)),
			ui_->sourceLabel,
			SLOT(setText(QString)));

	connect(targetModel_,
			SIGNAL(currentDirChanged(QString)),
			ui_->targetLabel,
			SLOT(setText(QString)));

	ui_->linksView->setTextElideMode(Qt::ElideMiddle);
	ui_->linksView->setRootIsDecorated(false);
	ui_->linksView->setSelectionBehavior(QAbstractItemView::SelectRows);
	ui_->linksView->setModel(linksModel_);

	NoFocusDelegate* delegate = qobject_cast<NoFocusDelegate*>
			(ui_->linksView->itemDelegate());

	delegate->setExtraHeight(4);

	QHeaderView* header = ui_->linksView->header();
	header->setStretchLastSection(false);
	header->setResizeMode(0, QHeaderView::Stretch);
	header->setResizeMode(1, QHeaderView::Stretch);
	header->setResizeMode(2, QHeaderView::ResizeToContents);

	connect(ui_->linksView,
			SIGNAL(selectionUpdated(QItemSelection, QItemSelection)),
			SLOT(onCurrentLinkChanged()));

	sourceModel_->setNameFilters(QStringList() << "*.dll");
	sourceModel_->setDir(QDir::homePath());

	ui_->pluginsView->setModel(sourceModel_);
	ui_->pluginsView->setRootIsDecorated(false);

	connect(ui_->pluginsView,
			SIGNAL(doubleClicked(QModelIndex)),
			SLOT(onDirItemDoubleClicked(QModelIndex)));

	connect(ui_->pluginsView,
			SIGNAL(selectionUpdated(QItemSelection, QItemSelection)),
			SLOT(onCurrentPluginChanged()));

	targetModel_->setNameFilters(QStringList() << "*.so");
	targetModel_->setDir(QDir::homePath());

	ui_->bridgesView->setModel(targetModel_);
	ui_->bridgesView->setRootIsDecorated(false);

	connect(ui_->bridgesView,
			SIGNAL(doubleClicked(QModelIndex)),
			SLOT(onDirItemDoubleClicked(QModelIndex)));

	setWindowTitle(QString(PROJECT_NAME) + " utility");

	ui_->splitter->setStretchFactor(0, 5);
	ui_->splitter->setStretchFactor(1, 4);

	connect(ui_->createLinkButton,
			SIGNAL(clicked()),
			SLOT(onCreateLinkButtonClicked()));

	connect(ui_->editLinkButton,
			SIGNAL(clicked()),
			SLOT(onEditLinkButtonClicked()));

	connect(ui_->removeLinkButton,
			SIGNAL(clicked()),
			SLOT(onRemoveLinkButtonClicked()));

	connect(ui_->recreateLinksButton,
			SIGNAL(clicked()),
			SLOT(onRecreateLinksButtonClicked()));

	onCurrentLinkChanged();
	onCurrentPluginChanged();
}

MainForm::~MainForm()
{
	delete ui_;
}

void MainForm::onShowHiddenButtonToggled(bool value)
{
	sourceModel_->setShowHidden(value);
	targetModel_->setShowHidden(value);
}

void MainForm::onShowLinkedButtonClicked()
{
	int row = ui_->linksView->firstSelectedRow();
	if(row < 0)
		return;

	LinkItem* linkItem = linksModel_->rootItem()->childAt(row);
	if(linkItem) {
		QString dir = linkItem->pluginPath();
		dir = dir.left(dir.lastIndexOf('/'));
		sourceModel_->setDir(dir);

		dir = linkItem->bridgePath();
		dir = dir.left(dir.lastIndexOf('/'));
		targetModel_->setDir(dir);

		DirListItem* item = sourceModel_->rootItem()->firstChild();
		while(item) {
			if(item->fullPath() == linkItem->pluginPath()) {
				ui_->pluginsView->selectRow(item->row());
				break;
			}

			item = item->nextSibling();
		}

		item = targetModel_->rootItem()->firstChild();
		while(item) {
			if(item->fullPath() == linkItem->bridgePath()) {
				ui_->bridgesView->selectRow(item->row());
				break;
			}

			item = item->nextSibling();
		}
	}
}

void MainForm::onDirItemDoubleClicked(const QModelIndex& index)
{
	QTreeView* view = static_cast<QTreeView*>(sender());
	DirListModel* model = static_cast<DirListModel*>(view->model());

	DirListItem* item = model->indexToItem(index);
	if(item && item->isDirectory()) {
		model->setDir(item->path());
	}
}

void MainForm::onCurrentLinkChanged()
{
	bool hasSelection = ui_->linksView->hasSelection();

	ui_->editLinkButton->setEnabled(hasSelection);
	ui_->removeLinkButton->setEnabled(hasSelection);
	ui_->showLinkedButton->setEnabled(hasSelection);
}

void MainForm::onCurrentPluginChanged()
{
	int row = ui_->pluginsView->firstSelectedRow();
	if(row < 0) {
		ui_->createLinkButton->setEnabled(false);
		return;
	}

	DirListItem* item = sourceModel_->rootItem()->childAt(row);
	ui_->createLinkButton->setEnabled(!item->isDirectory());
}

void MainForm::onCreateLinkButtonClicked()
{
	int row = ui_->pluginsView->firstSelectedRow();
	if(row < 0)
		return;

	QString pluginPath = sourceModel_->rootItem()->childAt(row)->name();
	if(!pluginPath.endsWith(".dll"))
		return;

	QString name = pluginPath;
	name.chop(4);	// Cut the ".dll" extension.

	QString bridgePath = targetModel_->currentDir() + '/';

	pluginPath = sourceModel_->rootItem()->childAt(row)->fullPath();

	QString libraryPath = PLUGIN_PATH "/" PLUGIN_BASENAME "-32.so";
	if(!QFile::exists(libraryPath)) {
		QString message = tr("Unable to find airwave template plugin.");
		QMessageBox::critical(this, tr("Error"), message);
		return;
	}

	LinkEditDialog dialog;
	dialog.setLinkName(name);
	if(dialog.exec()) {
		QString fileName = dialog.linkName() + ".so";

		if(!linksModel_->setLink(pluginPath, libraryPath)) {
			QString message = tr("The dll file has uncompatible architecture.");
			QMessageBox::critical(this, tr("Error"), message);
			return;
		}

		QFile::copy(libraryPath, bridgePath + fileName);
	}
}

void MainForm::onEditLinkButtonClicked()
{
	int row = ui_->linksView->firstSelectedRow();
	if(row < 0)
		return;

	QString bridgePath = linksModel_->rootItem()->childAt(row)->bridgePath();

	int pos = bridgePath.lastIndexOf('/');
	QString bridgeName = bridgePath.mid(pos + 1);
	bridgeName.chop(3);	// Cut the ".so" extension.

	LinkEditDialog dialog;
	dialog.setLinkName(bridgeName);
	if(dialog.exec()) {
		QDir dir(bridgePath.left(pos));
		dir.rename(bridgeName + ".so", dialog.linkName() + ".so");

		QString newPath = dir.canonicalPath() + "/" + dialog.linkName() + ".so";
		linksModel_->updateLink(bridgePath, newPath);
	}
}

void MainForm::onRemoveLinkButtonClicked()
{
	int row = ui_->linksView->firstSelectedRow();
	if(row < 0)
		return;

	QString bridgePath = linksModel_->rootItem()->childAt(row)->bridgePath();
	int pos = bridgePath.lastIndexOf('/');

	QString bridgeName = bridgePath.mid(pos + 1);
	QDir dir(bridgePath.left(pos));

	dir.remove(bridgeName);
	linksModel_->removeLink(bridgePath);
}

void MainForm::onRecreateLinksButtonClicked()
{
	QString libraryPath = PLUGIN_PATH "/" PLUGIN_BASENAME "-32.so";
	if(!QFile::exists(libraryPath)) {
		QString message = tr("Unable to find airwave template plugin.");
		QMessageBox::critical(this, tr("Error"), message);
		return;
	}

	LinkItem* item = linksModel_->rootItem()->firstChild();
	while(item) {
		QFile bridgeFile(item->bridgePath());
		if(bridgeFile.exists() && item->bridgePath() != libraryPath)
			bridgeFile.remove();

		QFile::copy(libraryPath, item->bridgePath());
		item = item->nextSibling();
	}
}
<commit_msg>Fix creation of links to the wrong path<commit_after>#include "mainform.h"

#include <QFile>
#include <QMessageBox>
#include "config.h"
#include "linkeditdialog.h"
#include "ui_mainform.h"
#include "widgets/nofocusdelegate.h"

MainForm::MainForm(QWidget* parent) :
	QWidget(parent),
	ui_(new Ui::MainForm),
	linksModel_(new LinksModel(this)),
	sourceModel_(new DirListModel(this)),
	targetModel_(new DirListModel(this))
{
	ui_->setupUi(this);

	connect(ui_->showHiddenButton,
			SIGNAL(toggled(bool)),
			SLOT(onShowHiddenButtonToggled(bool)));

	connect(ui_->showLinkedButton,
			SIGNAL(clicked()),
			SLOT(onShowLinkedButtonClicked()));

	ui_->sourceLabel->setElideMode(Qt::ElideMiddle);
	ui_->targetLabel->setElideMode(Qt::ElideMiddle);

	connect(sourceModel_,
			SIGNAL(currentDirChanged(QString)),
			ui_->sourceLabel,
			SLOT(setText(QString)));

	connect(targetModel_,
			SIGNAL(currentDirChanged(QString)),
			ui_->targetLabel,
			SLOT(setText(QString)));

	ui_->linksView->setTextElideMode(Qt::ElideMiddle);
	ui_->linksView->setRootIsDecorated(false);
	ui_->linksView->setSelectionBehavior(QAbstractItemView::SelectRows);
	ui_->linksView->setModel(linksModel_);

	NoFocusDelegate* delegate = qobject_cast<NoFocusDelegate*>
			(ui_->linksView->itemDelegate());

	delegate->setExtraHeight(4);

	QHeaderView* header = ui_->linksView->header();
	header->setStretchLastSection(false);
	header->setResizeMode(0, QHeaderView::Stretch);
	header->setResizeMode(1, QHeaderView::Stretch);
	header->setResizeMode(2, QHeaderView::ResizeToContents);

	connect(ui_->linksView,
			SIGNAL(selectionUpdated(QItemSelection, QItemSelection)),
			SLOT(onCurrentLinkChanged()));

	sourceModel_->setNameFilters(QStringList() << "*.dll");
	sourceModel_->setDir(QDir::homePath());

	ui_->pluginsView->setModel(sourceModel_);
	ui_->pluginsView->setRootIsDecorated(false);

	connect(ui_->pluginsView,
			SIGNAL(doubleClicked(QModelIndex)),
			SLOT(onDirItemDoubleClicked(QModelIndex)));

	connect(ui_->pluginsView,
			SIGNAL(selectionUpdated(QItemSelection, QItemSelection)),
			SLOT(onCurrentPluginChanged()));

	targetModel_->setNameFilters(QStringList() << "*.so");
	targetModel_->setDir(QDir::homePath());

	ui_->bridgesView->setModel(targetModel_);
	ui_->bridgesView->setRootIsDecorated(false);

	connect(ui_->bridgesView,
			SIGNAL(doubleClicked(QModelIndex)),
			SLOT(onDirItemDoubleClicked(QModelIndex)));

	setWindowTitle(QString(PROJECT_NAME) + " utility");

	ui_->splitter->setStretchFactor(0, 5);
	ui_->splitter->setStretchFactor(1, 4);

	connect(ui_->createLinkButton,
			SIGNAL(clicked()),
			SLOT(onCreateLinkButtonClicked()));

	connect(ui_->editLinkButton,
			SIGNAL(clicked()),
			SLOT(onEditLinkButtonClicked()));

	connect(ui_->removeLinkButton,
			SIGNAL(clicked()),
			SLOT(onRemoveLinkButtonClicked()));

	connect(ui_->recreateLinksButton,
			SIGNAL(clicked()),
			SLOT(onRecreateLinksButtonClicked()));

	onCurrentLinkChanged();
	onCurrentPluginChanged();
}

MainForm::~MainForm()
{
	delete ui_;
}

void MainForm::onShowHiddenButtonToggled(bool value)
{
	sourceModel_->setShowHidden(value);
	targetModel_->setShowHidden(value);
}

void MainForm::onShowLinkedButtonClicked()
{
	int row = ui_->linksView->firstSelectedRow();
	if(row < 0)
		return;

	LinkItem* linkItem = linksModel_->rootItem()->childAt(row);
	if(linkItem) {
		QString dir = linkItem->pluginPath();
		dir = dir.left(dir.lastIndexOf('/'));
		sourceModel_->setDir(dir);

		dir = linkItem->bridgePath();
		dir = dir.left(dir.lastIndexOf('/'));
		targetModel_->setDir(dir);

		DirListItem* item = sourceModel_->rootItem()->firstChild();
		while(item) {
			if(item->fullPath() == linkItem->pluginPath()) {
				ui_->pluginsView->selectRow(item->row());
				break;
			}

			item = item->nextSibling();
		}

		item = targetModel_->rootItem()->firstChild();
		while(item) {
			if(item->fullPath() == linkItem->bridgePath()) {
				ui_->bridgesView->selectRow(item->row());
				break;
			}

			item = item->nextSibling();
		}
	}
}

void MainForm::onDirItemDoubleClicked(const QModelIndex& index)
{
	QTreeView* view = static_cast<QTreeView*>(sender());
	DirListModel* model = static_cast<DirListModel*>(view->model());

	DirListItem* item = model->indexToItem(index);
	if(item && item->isDirectory()) {
		model->setDir(item->path());
	}
}

void MainForm::onCurrentLinkChanged()
{
	bool hasSelection = ui_->linksView->hasSelection();

	ui_->editLinkButton->setEnabled(hasSelection);
	ui_->removeLinkButton->setEnabled(hasSelection);
	ui_->showLinkedButton->setEnabled(hasSelection);
}

void MainForm::onCurrentPluginChanged()
{
	int row = ui_->pluginsView->firstSelectedRow();
	if(row < 0) {
		ui_->createLinkButton->setEnabled(false);
		return;
	}

	DirListItem* item = sourceModel_->rootItem()->childAt(row);
	ui_->createLinkButton->setEnabled(!item->isDirectory());
}

void MainForm::onCreateLinkButtonClicked()
{
	int row = ui_->pluginsView->firstSelectedRow();
	if(row < 0)
		return;

	QString pluginPath = sourceModel_->rootItem()->childAt(row)->name();
	if(!pluginPath.endsWith(".dll"))
		return;

	QString name = pluginPath;
	name.chop(4);	// Cut the ".dll" extension.

	QString bridgePath = targetModel_->currentDir() + '/';

	pluginPath = sourceModel_->rootItem()->childAt(row)->fullPath();

	QString libraryPath = PLUGIN_PATH "/" PLUGIN_BASENAME "-32.so";
	if(!QFile::exists(libraryPath)) {
		QString message = tr("Unable to find airwave template plugin.");
		QMessageBox::critical(this, tr("Error"), message);
		return;
	}

	LinkEditDialog dialog;
	dialog.setLinkName(name);
	if(dialog.exec()) {
		QString fileName = dialog.linkName() + ".so";

		QFile::copy(libraryPath, bridgePath + fileName);
		if(!linksModel_->setLink(pluginPath, bridgePath + fileName)) {
			QFile file(bridgePath + fileName);
			file.remove();
			QString message = tr("The dll file has uncompatible architecture.");
			QMessageBox::critical(this, tr("Error"), message);
			return;
		}
	}
}

void MainForm::onEditLinkButtonClicked()
{
	int row = ui_->linksView->firstSelectedRow();
	if(row < 0)
		return;

	QString bridgePath = linksModel_->rootItem()->childAt(row)->bridgePath();

	int pos = bridgePath.lastIndexOf('/');
	QString bridgeName = bridgePath.mid(pos + 1);
	bridgeName.chop(3);	// Cut the ".so" extension.

	LinkEditDialog dialog;
	dialog.setLinkName(bridgeName);
	if(dialog.exec()) {
		QDir dir(bridgePath.left(pos));
		dir.rename(bridgeName + ".so", dialog.linkName() + ".so");

		QString newPath = dir.canonicalPath() + "/" + dialog.linkName() + ".so";
		linksModel_->updateLink(bridgePath, newPath);
	}
}

void MainForm::onRemoveLinkButtonClicked()
{
	int row = ui_->linksView->firstSelectedRow();
	if(row < 0)
		return;

	QString bridgePath = linksModel_->rootItem()->childAt(row)->bridgePath();
	int pos = bridgePath.lastIndexOf('/');

	QString bridgeName = bridgePath.mid(pos + 1);
	QDir dir(bridgePath.left(pos));

	dir.remove(bridgeName);
	linksModel_->removeLink(bridgePath);
}

void MainForm::onRecreateLinksButtonClicked()
{
	QString libraryPath = PLUGIN_PATH "/" PLUGIN_BASENAME "-32.so";
	if(!QFile::exists(libraryPath)) {
		QString message = tr("Unable to find airwave template plugin.");
		QMessageBox::critical(this, tr("Error"), message);
		return;
	}

	LinkItem* item = linksModel_->rootItem()->firstChild();
	while(item) {
		QFile bridgeFile(item->bridgePath());
		if(bridgeFile.exists() && item->bridgePath() != libraryPath)
			bridgeFile.remove();

		QFile::copy(libraryPath, item->bridgePath());
		item = item->nextSibling();
	}
}
<|endoftext|>


<commit_before>#include <nds.h>
#include "bufferedbitmap.h"
#include "framebuffer.h"
#include "graphics.h"
#include "newtopaz.h"

using namespace WoopsiGfx;

void initGfxMode() {
	powerOn(POWER_ALL_2D);

	videoSetMode( MODE_5_2D | DISPLAY_BG3_ACTIVE );
	videoSetModeSub( MODE_5_2D | DISPLAY_BG3_ACTIVE );

	vramSetBankA( VRAM_A_MAIN_BG );
	vramSetBankC( VRAM_C_SUB_BG );

	// Initialise backgrounds
	bgInit(3, BgType_Bmp16, BgSize_B16_256x256, 0, 0);
	bgInitSub(3, BgType_Bmp16, BgSize_B16_256x256, 0, 0);
}

int main(int argc, char* argv[]) {
	initGfxMode();

	BufferedBitmap bmp(100, 100);						// Bitmap we will draw to
	Rect rect(0, 0, 100, 100);							// Clipping region
	Graphics gfx(&bmp, rect);							// Graphics object we use to draw
	FrameBuffer buffer((u16*)BG_BMP_RAM(0), 256, 192);	// Frame buffer we will copy to
	NewTopaz font;										// Font we will write with

	// Draw a simple picture
	gfx.drawFilledRect(0, 0, 100, 100, woopsiRGB(5, 5, 5));		// Clear background
	gfx.drawLine(0, 0, 100, 100, woopsiRGB(0, 31, 10));			// Green cross
	gfx.drawLine(100, 0, 0, 100, woopsiRGB(0, 31, 10));			// Green cross
	gfx.drawFilledRect(20, 20, 20, 60, woopsiRGB(5, 5, 20));	// Blue box
	gfx.drawFilledEllipse(50, 50, 20, 10, woopsiRGB(31, 0, 0));	// Red ellipse
	gfx.drawFilledRect(10, 80, 60, 5, woopsiRGB(10, 20, 10));	// Green box
	gfx.floodFill(90, 50, woopsiRGB(10, 10, 10));				// Fill right triangle
	gfx.floodFill(50, 90, woopsiRGB(15, 15, 15));				// Fill bottom triangle
	gfx.floodFill(0, 50, woopsiRGB(20, 20, 20));				// Fill left triangle
	gfx.dim(80, 0, 20, 100);									// Dim right edge
	gfx.drawLine(80, 0, 80, 100, woopsiRGB(20, 20, 20));		// Right edge border

	gfx.drawText(17, 0, &font, "Hello World!", 0, 17, woopsiRGB(31, 31, 31));		// Top text
	gfx.drawText(0, 90, &font, "This is some text", 0, 17, woopsiRGB(31, 31, 31));	// Bottom text

	gfx.drawFilledXORRect(0, 0, 50, 100, woopsiRGB(31, 0, 0));	// XOR left of bitmap against red

	// Buffer the current bitmap contents
	bmp.buffer();

	// Get a graphics object to draw to the frame buffer
	Graphics* fbgfx = buffer.newGraphics();

	s16 x = 0;
	s16 y = 0;
	s16 xAdd = 1;

	while(1) {
		swiWaitForVBlank();

		x += xAdd;

		if (x < 0) {
			x = 0;
			xAdd = 1;
		} else if (x > bmp.getWidth() - 1) {
			x = bmp.getWidth() - 1;
			xAdd = -1;
		}

		gfx.drawLine(x, y, 50, 50, woopsiRGB(31, 0, 0));

		// Draw the bitmap to the framebuffer
		fbgfx->drawBitmap(10, 10, 100, 100, &bmp, 0, 0);

		bmp.unbuffer();
	}

	// Clean up the framebuffer graphics object
	delete fbgfx;

	return 0;
}
<commit_msg>Improved buffer test.<commit_after>#include <nds.h>
#include "bufferedbitmap.h"
#include "framebuffer.h"
#include "graphics.h"
#include "newtopaz.h"

using namespace WoopsiGfx;

void initGfxMode() {
	powerOn(POWER_ALL_2D);

	videoSetMode( MODE_5_2D | DISPLAY_BG3_ACTIVE );
	videoSetModeSub( MODE_5_2D | DISPLAY_BG3_ACTIVE );

	vramSetBankA( VRAM_A_MAIN_BG );
	vramSetBankC( VRAM_C_SUB_BG );

	// Initialise backgrounds
	bgInit(3, BgType_Bmp16, BgSize_B16_256x256, 0, 0);
	bgInitSub(3, BgType_Bmp16, BgSize_B16_256x256, 0, 0);
}

int main(int argc, char* argv[]) {
	initGfxMode();

	BufferedBitmap bmp(100, 100);						// Bitmap we will draw to
	Rect rect(0, 0, 100, 100);							// Clipping region
	Graphics gfx(&bmp, rect);							// Graphics object we use to draw
	FrameBuffer buffer((u16*)BG_BMP_RAM(0), 256, 192);	// Frame buffer we will copy to
	NewTopaz font;										// Font we will write with

	// Draw a simple picture
	gfx.drawFilledRect(0, 0, 100, 100, woopsiRGB(5, 5, 5));		// Clear background
	gfx.drawLine(0, 0, 100, 100, woopsiRGB(0, 31, 10));			// Green cross
	gfx.drawLine(100, 0, 0, 100, woopsiRGB(0, 31, 10));			// Green cross
	gfx.drawFilledRect(20, 20, 20, 60, woopsiRGB(5, 5, 20));	// Blue box
	gfx.drawFilledEllipse(50, 50, 20, 10, woopsiRGB(31, 0, 0));	// Red ellipse
	gfx.drawFilledRect(10, 80, 60, 5, woopsiRGB(10, 20, 10));	// Green box
	gfx.floodFill(90, 50, woopsiRGB(10, 10, 10));				// Fill right triangle
	gfx.floodFill(50, 90, woopsiRGB(15, 15, 15));				// Fill bottom triangle
	gfx.floodFill(0, 50, woopsiRGB(20, 20, 20));				// Fill left triangle
	gfx.dim(80, 0, 20, 100);									// Dim right edge
	gfx.drawLine(80, 0, 80, 100, woopsiRGB(20, 20, 20));		// Right edge border

	gfx.drawText(17, 0, &font, "Hello World!", 0, 17, woopsiRGB(31, 31, 31));		// Top text
	gfx.drawText(0, 90, &font, "This is some text", 0, 17, woopsiRGB(31, 31, 31));	// Bottom text

	gfx.drawFilledXORRect(0, 0, 50, 100, woopsiRGB(31, 0, 0));	// XOR left of bitmap against red

	// Buffer the current bitmap contents
	bmp.buffer();

	// Get a graphics object to draw to the frame buffer
	Graphics* fbgfx = buffer.newGraphics();

	s16 x = 10;
	s16 y = 10;
	s16 xAdd = 1;
	s16 yAdd = 1;

	s16 ellipseX = 10;
	s16 ellipseY = 10;
	s16 ellipseXAdd = 1;
	s16 ellipseYAdd = 1;

	while(1) {
		swiWaitForVBlank();

		gfx.drawFilledEllipse(ellipseX, ellipseY, 20, 10, woopsiRGB(31, 0, 0));

		// Clear the existing box
		fbgfx->drawFilledRect(x, y, 100, 100, woopsiRGB(0, 0, 0));

		x += xAdd;
		y += yAdd;

		ellipseX += ellipseXAdd;
		ellipseY += ellipseYAdd;

		// Draw the bitmap to the framebuffer
		fbgfx->drawBitmap(x, y, 100, 100, &bmp, 0, 0);

		// Swap bounce directions
		if ((xAdd < 0) && (x < 0)) {
			xAdd = 1;
		} else if ((xAdd > 0) && (x > 155)) {
			xAdd = -1;
		}

		if ((yAdd < 0) && (y < 0)) {
			yAdd = 1;
		} else if ((yAdd > 0) && (y > 91)) {
			yAdd = -1;
		}

		// Swap ellipse
		if ((ellipseXAdd < 0) && (ellipseX < 0)) {
			ellipseXAdd = 1;
		} else if ((ellipseXAdd > 0) && (ellipseX > 100)) {
			ellipseXAdd = -1;
		}

		if ((ellipseYAdd < 0) && (ellipseY < 0)) {
			ellipseYAdd = 1;
		} else if ((ellipseYAdd > 0) && (ellipseY > 91)) {
			ellipseYAdd = -1;
		}

		bmp.unbuffer();
	}

	// Clean up the framebuffer graphics object
	delete fbgfx;

	return 0;
}
<|endoftext|>