<commit_before>// Copyright (c) 2010 - 2013 Leap Motion. All rights reserved. Proprietary and confidential.
#include "stdafx.h"
#include "CoreThreadTest.h"
#include "Autowired.h"
#include "TestFixtures/SimpleThreaded.h"
#include <boost/thread/thread.hpp>
#include <boost/thread.hpp>

class SpamguardTest:
  public CoreThread
{
public:
  SpamguardTest(void):
    m_hit(false),
    m_multiHit(false)
  {
  }

  bool m_hit;
  bool m_multiHit;

  void Run(void) override {
    if(m_hit) {
      m_multiHit = true;
      return;
    }

    m_hit = false;

    boost::unique_lock<boost::mutex> lk(m_lock);
    m_stateCondition.wait(lk, [this] () {return ShouldStop();});
  }
};

TEST_F(CoreThreadTest, VerifyStartSpam) {
  // Create our thread class:
  AutoRequired<SpamguardTest> instance;

  m_create->InitiateCoreThreads();

  // This shouldn't cause another thread to be created:
  instance->Start(std::shared_ptr<Object>(new Object));

  EXPECT_FALSE(instance->m_multiHit) << "Thread was run more than once unexpectedly";
}

class InvokesIndefiniteWait:
  public CoreThread
{
public:
  virtual void Run(void) override {
    AcceptDispatchDelivery();

    // Wait for one event using an indefinite timeout, then quit:
    WaitForEvent(boost::chrono::steady_clock::time_point::max());
  }
};

TEST_F(CoreThreadTest, VerifyIndefiniteDelay) {
  AutoRequired<InvokesIndefiniteWait> instance;
  m_create->InitiateCoreThreads();

  // Verify that the instance does not quit until we pend something:
  ASSERT_FALSE(instance->WaitFor(boost::chrono::milliseconds(10))) << "Thread instance exited prematurely, when it should have been waiting indefinitely";

  // Now we pend an arbitrary event and verify that we can wait:
  *instance += [] {};
  ASSERT_TRUE(instance->WaitFor(boost::chrono::milliseconds(10))) << "Instance did not exit after an event was pended which should have woken up its dispatch loop";
}

TEST_F(CoreThreadTest, VerifyNestedTermination) {
  std::shared_ptr<SimpleThreaded> st;

  // Insert a thread into a second-order subcontext:
  {
    AutoCreateContext outer;
    CurrentContextPusher outerPshr(outer);
    AutoRequired<SimpleThreaded>();
    outer->InitiateCoreThreads();

    {
      AutoCreateContext ctxt;
      CurrentContextPusher pshr(ctxt);
      ctxt->InitiateCoreThreads();
      st = AutoRequired<SimpleThreaded>();
    }
  }

  // Everything should be running by now:
  ASSERT_TRUE(st->IsRunning()) << "Child thread was not running as expected";

  // Shut down the enclosing context:
  m_create->SignalTerminate(true);

  // Verify that the child thread has stopped:
  ASSERT_FALSE(st->IsRunning()) << "Child thread was running even though the enclosing context was terminated";
}

class SleepEvent : public virtual EventReceiver
{
public:
  virtual Deferred SleepFor(int seconds) = 0;
  virtual Deferred SleepForThenThrow(int seconds) = 0;
};

class ListenThread :
  public CoreThread,
  public SleepEvent
{
public:
  ListenThread() : CoreThread("ListenThread") {}

  Deferred SleepFor(int seconds) override {
    boost::this_thread::sleep_for(boost::chrono::milliseconds(1));
    if(ShouldStop())
      throw std::runtime_error("Execution aborted");

    return Deferred(this);
  }

  Deferred SleepForThenThrow(int seconds) override {
    return Deferred(this);
  }
};

TEST_F(CoreThreadTest, VerifyDispatchQueueShutdown) {
  AutoCreateContext ctxt;
  CurrentContextPusher pusher(ctxt);

  AutoRequired<ListenThread> listener;
  try
  {
    ctxt->InitiateCoreThreads();
    listener->DelayUntilCanAccept();

    AutoFired<SleepEvent> evt;

    // Spam in a bunch of events:
    for(size_t i = 100; i--;)
      evt(&SleepEvent::SleepFor)(0);

    // Graceful termination then enclosing context shutdown:
    listener->Stop(true);
    ctxt->SignalShutdown(true);
  }
  catch (...) {}

  ASSERT_EQ(listener->GetDispatchQueueLength(), static_cast<size_t>(0));
}

TEST_F(CoreThreadTest, VerifyNoLeakOnExecptions) {
  AutoCreateContext ctxt;
  CurrentContextPusher pshr(ctxt);

  AutoRequired<ListenThread> listener;
  std::shared_ptr<std::string> value(new std::string("sentinal"));

  std::weak_ptr<std::string> watcher(value);
  try
  {
    ctxt->InitiateCoreThreads();
    listener->DelayUntilCanAccept();

    *listener += [value] { throw std::exception(); };
    value.reset();
    ctxt->SignalShutdown(true);
  }
  catch (...) {}

  ASSERT_TRUE(watcher.expired()) << "Leaked memory on exception in a dispatch event";
}

TEST_F(CoreThreadTest, VerifyDelayedDispatchQueueSimple) {
  // Run our threads immediately, no need to wait
  m_create->InitiateCoreThreads();

  // Create a thread which we'll use just to pend dispatch events:
  AutoRequired<CoreThread> t;

  // Thread should be running by now:
  ASSERT_TRUE(t->IsRunning()) << "Thread added to a running context was not marked running";

  // Delay until the dispatch loop is actually running, then wait an additional 1ms to let the
  // WaitForEvent call catch on:
  t->DelayUntilCanAccept();
  boost::this_thread::sleep_for(boost::chrono::milliseconds(1));

  // These are flags--we'll set them to true as the test proceeds
  std::shared_ptr<bool> x(new bool(false));
  std::shared_ptr<bool> y(new bool(false));

  // Pend a delayed event first, and then an immediate event right afterwards:
  *t += boost::chrono::hours(1), [x] { *x = true; };
  *t += [y] { *y = true; };

  // Verify that, after 10ms, the first event is called and the second event is NOT called:
  boost::this_thread::sleep_for(boost::chrono::milliseconds(10));
  ASSERT_TRUE(*y) << "A simple ready call was not dispatched within 10ms of being pended";
  ASSERT_FALSE(*x) << "An event which should not have been executed for 25ms was executed early";
}

TEST_F(CoreThreadTest, VerifyNoDelayDoubleFree) {
  m_create->InitiateCoreThreads();

  // We won't actually be referencing this, we just want to make sure it's not destroyed early
  std::shared_ptr<bool> x(new bool);

  // This deferred pend will never actually be executed:
  AutoRequired<CoreThread> t;
  t->DelayUntilCanAccept();
  *t += boost::chrono::hours(1), [x] {};

  // Verify that we have exactly one pended event at this point.
  ASSERT_EQ(1UL, t->GetDispatchQueueLength()) << "Dispatch queue had an unexpected number of pended events";

  // Verify that the shared pointer isn't unique at this point.  If it is, it's because our CoreThread deleted
  // the event even though it was supposed to have pended it.
  ASSERT_FALSE(x.unique()) << "A pended event was freed before it was called, and appears to be present in a dispatch queue";
}

TEST_F(CoreThreadTest, VerifyDoublePendedDispatchDelay) {
  // Immediately pend threads:
  m_create->InitiateCoreThreads();

  // Some variables that we will set to true as the test proceeds:
  std::shared_ptr<bool> x(new bool(false));
  std::shared_ptr<bool> y(new bool(false));

  // Create a thread as before, and pend a few events.  The order, here, is important.  We intentionally
  // pend an event that won't happen for awhile, in order to trick the dispatch queue into waiting for
  // a lot longer than it should for the next event.
  AutoRequired<CoreThread> t;
  t->DelayUntilCanAccept();
  *t += boost::chrono::hours(1), [x] { *x = true; };

  // Now pend an event that will be ready just about right away:
  *t += boost::chrono::nanoseconds(1), [y] { *y = true; };

  // Delay for a short period of time, then check our variable states:
  boost::this_thread::sleep_for(boost::chrono::milliseconds(10));

  // This one shouldn't have been hit yet, it isn't scheduled to be hit for 10s
  ASSERT_FALSE(*x) << "A delayed dispatch was invoked extremely early";

  // This one should have been ready almost at the same time as it was pended
  ASSERT_TRUE(*y) << "An out-of-order delayed dispatch was not executed in time as expected";
}

TEST_F(CoreThreadTest, VerifyTimedSort) {
  m_create->InitiateCoreThreads();
  AutoRequired<CoreThread> t;

  std::vector<size_t> v;

  // Pend a stack of lambdas.  Each lambda waits 3i milliseconds, and pushes the value
  // i to the back of a vector.  If the delay method is implemented correctly, the resulting
  // vector will always wind up sorted, no matter how we push elements to the queue.
  // To doubly verify this property, we don't trivially increment i from the minimum to the
  // maximum--rather, we use a simple PRNG called a linear congruential generator and hop around
  // the interval [1...12] instead.
  for(size_t i = 1; i != 0; i = (i * 5 + 1) % 16)
    *t += boost::chrono::milliseconds(i * 3), [&v, i] { v.push_back(i); };

  // Delay 50ms for the thread to finish up.  Technically this is 11ms more than we need.
  boost::this_thread::sleep_for(boost::chrono::seconds(1));

  // Verify that the resulting vector is sorted.
  ASSERT_TRUE(std::is_sorted(v.begin(), v.end())) << "A timed sort implementation did not generate a sorted sequence as expected";
}

TEST_F(CoreThreadTest, VerifyPendByTimePoint) {
  m_create->InitiateCoreThreads();
  AutoRequired<CoreThread> t;
  t->DelayUntilCanAccept();

  // Pend by an absolute time point, nothing really special here
  std::shared_ptr<bool> x(new bool(false));
  *t += (boost::chrono::high_resolution_clock::now() + boost::chrono::milliseconds(1)), [&x] { *x = true; };

  // Verify that we hit this after one ms of delay
  ASSERT_FALSE(*x) << "A timepoint-based delayed dispatch was invoked early";
  boost::this_thread::sleep_for(boost::chrono::milliseconds(2));
  ASSERT_TRUE(*x) << "A timepoint-based delayed dispatch was not invoked in a timely fashion";
}

template<ThreadPriority priority>
class JustIncrementsANumber:
  public CoreThread
{
public:
  JustIncrementsANumber():
    val(0)
  {}

  volatile int64_t val;

  // This will be a hotly contested conditional variable
  AutoRequired<boost::mutex> contended;

  void Run(void) override {
    ElevatePriority p(*this, priority);
    while(!ShouldStop()) {
      // Obtain the lock and then increment our value:
      boost::lock_guard<boost::mutex> lk(*contended);
      val++;
    }
  }
};

#ifdef _MSC_VER
TEST_F(CoreThreadTest, VerifyCanBoostPriority) {
  // Create two spinners and kick them off at the same time:
  AutoRequired<JustIncrementsANumber<ThreadPriority::Normal>> lower;
  AutoRequired<JustIncrementsANumber<ThreadPriority::AboveNormal>> higher;
  m_create->InitiateCoreThreads();

  // Poke the conditional variable a lot:
  AutoRequired<boost::mutex> contended;
  for(size_t i = 100; i--;) {
    // We sleep while holding contention lock to force waiting threads into the sleep queue.  The reason we have to do
    // this is due to the way that mutex is implemented under the hood.  The STL mutex uses a high-frequency variable
    // and attempts to perform a CAS (check-and-set) on this variable.  If it succeeds, the lock is obtained; if it
    // fails, it will put the thread into a non-ready state by calling WaitForSingleObject on Windows or one of the
    // mutex_lock methods on Unix.
    //
    // When a thread can't be run, it's moved from the OS's ready queue to the sleep queue.  The scheduler knows that
    // the thread can be moved back to the ready queue if a particular object is signalled, but in the case of a lock,
    // only one of the threads waiting on the object can actually be moved to the ready queue.  It's at THIS POINT that
    // the operating system consults the thread priority--if only thread can be moved over, then the highest priority
    // thread will wind up in the ready queue every time.
    //
    // Thread priority does _not_ necessarily influence the amount of time the scheduler allocates allocated to a ready
    // thread with respect to other threads of the same process.  This is why we hold the lock for a full millisecond,
    // in order to force the thread over to the sleep queue and ensure that the priority resolution mechanism is
    // directly tested.
    boost::lock_guard<boost::mutex> lk(*contended);
    boost::this_thread::sleep_for(boost::chrono::milliseconds(1));
  }

  // Need to terminate before we try running a comparison.
  m_create->SignalTerminate();

  ASSERT_LE(lower->val, higher->val) << "A lower-priority thread was moved out of the sleep queue more frequently than a high-priority thread";
}
#else
#pragma message "Warning:  SetThreadPriority not implemented on Unix"
#endif<commit_msg>Another test relaxation, required because of our slow Linux server<commit_after>// Copyright (c) 2010 - 2013 Leap Motion. All rights reserved. Proprietary and confidential.
#include "stdafx.h"
#include "CoreThreadTest.h"
#include "Autowired.h"
#include "TestFixtures/SimpleThreaded.h"
#include <boost/thread/thread.hpp>
#include <boost/thread.hpp>

class SpamguardTest:
  public CoreThread
{
public:
  SpamguardTest(void):
    m_hit(false),
    m_multiHit(false)
  {
  }

  bool m_hit;
  bool m_multiHit;

  void Run(void) override {
    if(m_hit) {
      m_multiHit = true;
      return;
    }

    m_hit = false;

    boost::unique_lock<boost::mutex> lk(m_lock);
    m_stateCondition.wait(lk, [this] () {return ShouldStop();});
  }
};

TEST_F(CoreThreadTest, VerifyStartSpam) {
  // Create our thread class:
  AutoRequired<SpamguardTest> instance;

  m_create->InitiateCoreThreads();

  // This shouldn't cause another thread to be created:
  instance->Start(std::shared_ptr<Object>(new Object));

  EXPECT_FALSE(instance->m_multiHit) << "Thread was run more than once unexpectedly";
}

class InvokesIndefiniteWait:
  public CoreThread
{
public:
  virtual void Run(void) override {
    AcceptDispatchDelivery();

    // Wait for one event using an indefinite timeout, then quit:
    WaitForEvent(boost::chrono::steady_clock::time_point::max());
  }
};

TEST_F(CoreThreadTest, VerifyIndefiniteDelay) {
  AutoRequired<InvokesIndefiniteWait> instance;
  m_create->InitiateCoreThreads();

  // Verify that the instance does not quit until we pend something:
  ASSERT_FALSE(instance->WaitFor(boost::chrono::milliseconds(10))) << "Thread instance exited prematurely, when it should have been waiting indefinitely";

  // Now we pend an arbitrary event and verify that we can wait:
  *instance += [] {};
  ASSERT_TRUE(instance->WaitFor(boost::chrono::milliseconds(10))) << "Instance did not exit after an event was pended which should have woken up its dispatch loop";
}

TEST_F(CoreThreadTest, VerifyNestedTermination) {
  std::shared_ptr<SimpleThreaded> st;

  // Insert a thread into a second-order subcontext:
  {
    AutoCreateContext outer;
    CurrentContextPusher outerPshr(outer);
    AutoRequired<SimpleThreaded>();
    outer->InitiateCoreThreads();

    {
      AutoCreateContext ctxt;
      CurrentContextPusher pshr(ctxt);
      ctxt->InitiateCoreThreads();
      st = AutoRequired<SimpleThreaded>();
    }
  }

  // Everything should be running by now:
  ASSERT_TRUE(st->IsRunning()) << "Child thread was not running as expected";

  // Shut down the enclosing context:
  m_create->SignalTerminate(true);

  // Verify that the child thread has stopped:
  ASSERT_FALSE(st->IsRunning()) << "Child thread was running even though the enclosing context was terminated";
}

class SleepEvent : public virtual EventReceiver
{
public:
  virtual Deferred SleepFor(int seconds) = 0;
  virtual Deferred SleepForThenThrow(int seconds) = 0;
};

class ListenThread :
  public CoreThread,
  public SleepEvent
{
public:
  ListenThread() : CoreThread("ListenThread") {}

  Deferred SleepFor(int seconds) override {
    boost::this_thread::sleep_for(boost::chrono::milliseconds(1));
    if(ShouldStop())
      throw std::runtime_error("Execution aborted");

    return Deferred(this);
  }

  Deferred SleepForThenThrow(int seconds) override {
    return Deferred(this);
  }
};

TEST_F(CoreThreadTest, VerifyDispatchQueueShutdown) {
  AutoCreateContext ctxt;
  CurrentContextPusher pusher(ctxt);

  AutoRequired<ListenThread> listener;
  try
  {
    ctxt->InitiateCoreThreads();
    listener->DelayUntilCanAccept();

    AutoFired<SleepEvent> evt;

    // Spam in a bunch of events:
    for(size_t i = 100; i--;)
      evt(&SleepEvent::SleepFor)(0);

    // Graceful termination then enclosing context shutdown:
    listener->Stop(true);
    ctxt->SignalShutdown(true);
  }
  catch (...) {}

  ASSERT_EQ(listener->GetDispatchQueueLength(), static_cast<size_t>(0));
}

TEST_F(CoreThreadTest, VerifyNoLeakOnExecptions) {
  AutoCreateContext ctxt;
  CurrentContextPusher pshr(ctxt);

  AutoRequired<ListenThread> listener;
  std::shared_ptr<std::string> value(new std::string("sentinal"));

  std::weak_ptr<std::string> watcher(value);
  try
  {
    ctxt->InitiateCoreThreads();
    listener->DelayUntilCanAccept();

    *listener += [value] { throw std::exception(); };
    value.reset();
    ctxt->SignalShutdown(true);
  }
  catch (...) {}

  ASSERT_TRUE(watcher.expired()) << "Leaked memory on exception in a dispatch event";
}

TEST_F(CoreThreadTest, VerifyDelayedDispatchQueueSimple) {
  // Run our threads immediately, no need to wait
  m_create->InitiateCoreThreads();

  // Create a thread which we'll use just to pend dispatch events:
  AutoRequired<CoreThread> t;

  // Thread should be running by now:
  ASSERT_TRUE(t->IsRunning()) << "Thread added to a running context was not marked running";

  // Delay until the dispatch loop is actually running, then wait an additional 1ms to let the
  // WaitForEvent call catch on:
  t->DelayUntilCanAccept();
  boost::this_thread::sleep_for(boost::chrono::milliseconds(1));

  // These are flags--we'll set them to true as the test proceeds
  std::shared_ptr<bool> x(new bool(false));
  std::shared_ptr<bool> y(new bool(false));

  // Pend a delayed event first, and then an immediate event right afterwards:
  *t += boost::chrono::hours(1), [x] { *x = true; };
  *t += [y] { *y = true; };

  // Verify that, after 100ms, the first event is called and the second event is NOT called:
  boost::this_thread::sleep_for(boost::chrono::milliseconds(100));
  ASSERT_TRUE(*y) << "A simple ready call was not dispatched within 100ms of being pended";
  ASSERT_FALSE(*x) << "An event which should not have been executed for an hour was executed early";
}

TEST_F(CoreThreadTest, VerifyNoDelayDoubleFree) {
  m_create->InitiateCoreThreads();

  // We won't actually be referencing this, we just want to make sure it's not destroyed early
  std::shared_ptr<bool> x(new bool);

  // This deferred pend will never actually be executed:
  AutoRequired<CoreThread> t;
  t->DelayUntilCanAccept();
  *t += boost::chrono::hours(1), [x] {};

  // Verify that we have exactly one pended event at this point.
  ASSERT_EQ(1UL, t->GetDispatchQueueLength()) << "Dispatch queue had an unexpected number of pended events";

  // Verify that the shared pointer isn't unique at this point.  If it is, it's because our CoreThread deleted
  // the event even though it was supposed to have pended it.
  ASSERT_FALSE(x.unique()) << "A pended event was freed before it was called, and appears to be present in a dispatch queue";
}

TEST_F(CoreThreadTest, VerifyDoublePendedDispatchDelay) {
  // Immediately pend threads:
  m_create->InitiateCoreThreads();

  // Some variables that we will set to true as the test proceeds:
  std::shared_ptr<bool> x(new bool(false));
  std::shared_ptr<bool> y(new bool(false));

  // Create a thread as before, and pend a few events.  The order, here, is important.  We intentionally
  // pend an event that won't happen for awhile, in order to trick the dispatch queue into waiting for
  // a lot longer than it should for the next event.
  AutoRequired<CoreThread> t;
  t->DelayUntilCanAccept();
  *t += boost::chrono::hours(1), [x] { *x = true; };

  // Now pend an event that will be ready just about right away:
  *t += boost::chrono::nanoseconds(1), [y] { *y = true; };

  // Delay for a short period of time, then check our variable states:
  boost::this_thread::sleep_for(boost::chrono::milliseconds(10));

  // This one shouldn't have been hit yet, it isn't scheduled to be hit for 10s
  ASSERT_FALSE(*x) << "A delayed dispatch was invoked extremely early";

  // This one should have been ready almost at the same time as it was pended
  ASSERT_TRUE(*y) << "An out-of-order delayed dispatch was not executed in time as expected";
}

TEST_F(CoreThreadTest, VerifyTimedSort) {
  m_create->InitiateCoreThreads();
  AutoRequired<CoreThread> t;

  std::vector<size_t> v;

  // Pend a stack of lambdas.  Each lambda waits 3i milliseconds, and pushes the value
  // i to the back of a vector.  If the delay method is implemented correctly, the resulting
  // vector will always wind up sorted, no matter how we push elements to the queue.
  // To doubly verify this property, we don't trivially increment i from the minimum to the
  // maximum--rather, we use a simple PRNG called a linear congruential generator and hop around
  // the interval [1...12] instead.
  for(size_t i = 1; i != 0; i = (i * 5 + 1) % 16)
    *t += boost::chrono::milliseconds(i * 3), [&v, i] { v.push_back(i); };

  // Delay 50ms for the thread to finish up.  Technically this is 11ms more than we need.
  boost::this_thread::sleep_for(boost::chrono::seconds(1));

  // Verify that the resulting vector is sorted.
  ASSERT_TRUE(std::is_sorted(v.begin(), v.end())) << "A timed sort implementation did not generate a sorted sequence as expected";
}

TEST_F(CoreThreadTest, VerifyPendByTimePoint) {
  m_create->InitiateCoreThreads();
  AutoRequired<CoreThread> t;
  t->DelayUntilCanAccept();

  // Pend by an absolute time point, nothing really special here
  std::shared_ptr<bool> x(new bool(false));
  *t += (boost::chrono::high_resolution_clock::now() + boost::chrono::milliseconds(1)), [&x] { *x = true; };

  // Verify that we hit this after one ms of delay
  ASSERT_FALSE(*x) << "A timepoint-based delayed dispatch was invoked early";
  boost::this_thread::sleep_for(boost::chrono::milliseconds(2));
  ASSERT_TRUE(*x) << "A timepoint-based delayed dispatch was not invoked in a timely fashion";
}

template<ThreadPriority priority>
class JustIncrementsANumber:
  public CoreThread
{
public:
  JustIncrementsANumber():
    val(0)
  {}

  volatile int64_t val;

  // This will be a hotly contested conditional variable
  AutoRequired<boost::mutex> contended;

  void Run(void) override {
    ElevatePriority p(*this, priority);
    while(!ShouldStop()) {
      // Obtain the lock and then increment our value:
      boost::lock_guard<boost::mutex> lk(*contended);
      val++;
    }
  }
};

#ifdef _MSC_VER
TEST_F(CoreThreadTest, VerifyCanBoostPriority) {
  // Create two spinners and kick them off at the same time:
  AutoRequired<JustIncrementsANumber<ThreadPriority::Normal>> lower;
  AutoRequired<JustIncrementsANumber<ThreadPriority::AboveNormal>> higher;
  m_create->InitiateCoreThreads();

  // Poke the conditional variable a lot:
  AutoRequired<boost::mutex> contended;
  for(size_t i = 100; i--;) {
    // We sleep while holding contention lock to force waiting threads into the sleep queue.  The reason we have to do
    // this is due to the way that mutex is implemented under the hood.  The STL mutex uses a high-frequency variable
    // and attempts to perform a CAS (check-and-set) on this variable.  If it succeeds, the lock is obtained; if it
    // fails, it will put the thread into a non-ready state by calling WaitForSingleObject on Windows or one of the
    // mutex_lock methods on Unix.
    //
    // When a thread can't be run, it's moved from the OS's ready queue to the sleep queue.  The scheduler knows that
    // the thread can be moved back to the ready queue if a particular object is signalled, but in the case of a lock,
    // only one of the threads waiting on the object can actually be moved to the ready queue.  It's at THIS POINT that
    // the operating system consults the thread priority--if only thread can be moved over, then the highest priority
    // thread will wind up in the ready queue every time.
    //
    // Thread priority does _not_ necessarily influence the amount of time the scheduler allocates allocated to a ready
    // thread with respect to other threads of the same process.  This is why we hold the lock for a full millisecond,
    // in order to force the thread over to the sleep queue and ensure that the priority resolution mechanism is
    // directly tested.
    boost::lock_guard<boost::mutex> lk(*contended);
    boost::this_thread::sleep_for(boost::chrono::milliseconds(1));
  }

  // Need to terminate before we try running a comparison.
  m_create->SignalTerminate();

  ASSERT_LE(lower->val, higher->val) << "A lower-priority thread was moved out of the sleep queue more frequently than a high-priority thread";
}
#else
#pragma message "Warning:  SetThreadPriority not implemented on Unix"
#endif<|endoftext|>


<commit_before>#include <iostream>
#include <algorithm>
#include <math.h>
#include <float.h>
#include <random>
using namespace std ;

const double pi = 3.14159265358979323846264338328 ;

vector<double> linspace(double a, double b, int n)
{
	vector<double> array ;
	double step = (b-a)/(n-1) ;
	while (a<=b)
	{
		array.push_back(a) ;
		a += step ;
	}
	return array ;
}

/*double IntNormDist(double mu, double sig, double a)
{
	int n = 1000 ;
	vector<double> x = linspace(a,mu+3*sig,n) ;
	double dx = (x[1]-x[0]) ;

	double integral = 0.0 ;
	for (int i = 0; i < x.size(); i++)
	{
		double fac = 1/(sig*sqrt(2*pi)) ;
		double ind = -(pow(x[i]-mu,2))/(2*pow(sig,2)) ;
		integral += fac*exp(ind)*dx ;
	}
	return integral ;
}*/

double ComputeImprovementProbability(double c_A0, double c_B0, vector<double> mu_A, vector<double> sig_A, vector<double> mu_B, vector<double> sig_B)
{
	double max_3sig = mu_A[0] + 3*sig_A[0] ;
	double min_3sig = mu_A[0] - 3*sig_A[0] ;
	for (int i = 0; i < mu_A.size(); i++)
	{
		if (max_3sig < mu_A[i]+3*sig_A[i])
			max_3sig = mu_A[i]+3*sig_A[i] ;
		if (min_3sig > mu_A[i]-3*sig_A[i])
			min_3sig = mu_A[i]-3*sig_A[i] ;
	}
	for (int i = 0; i < mu_B.size(); i++)
	{
		if (max_3sig < mu_B[i]+3*sig_B[i])
			max_3sig = mu_B[i]+3*sig_B[i] ;
		if (min_3sig > mu_B[i]-3*sig_B[i])
			min_3sig = mu_B[i]-3*sig_B[i] ;
	}

	int n = 100000 ;
	vector<double> x = linspace(min_3sig,max_3sig,n) ;
	double dx = x[1]-x[0] ;
	double pImprove = 0.0 ;
	for (int k = 0; k < x.size(); k++)
	{
		double p_cAi = 0.0 ;
		for (int i = 0; i < mu_A.size(); i++)
		{
			double p_cA1 = (1/(sig_A[i]*sqrt(2*pi)))*exp(-(pow(x[k]-mu_A[i],2))/(2*pow(sig_A[i],2))) ;
			double p_cA2 = 1.0 ;
			for (int j = 0; j < mu_A.size(); j++)
			{
				if (j != i)
					p_cA2 *= 0.5*erfc((x[k]-mu_A[j])/(sig_A[j]*sqrt(2))) ;
			}
			p_cAi += p_cA1*p_cA2 ;
		}
		double p_cBi = 1.0 ;
		for (int i = 0; i < mu_B.size(); i++)
			p_cBi *= 0.5*erfc((x[k]-(c_B0-c_A0)-mu_B[i])/(sig_B[i]*sqrt(2))) ;
		pImprove += (p_cAi)*(1-p_cBi)*dx ;
	}
	return pImprove;
}

int main()
{

	default_random_engine generator ;

	uniform_real_distribution<double> mu_dist(0.0,10.0) ;
	uniform_real_distribution<double> sig_dist(0.0,10.0) ;

	vector<double> mu_A ;
	vector<double> sig_A ;

	int m = 3 ;
	for (int i = 0; i < m; i++)
	{
		mu_A.push_back(mu_dist(generator)) ;
		sig_A.push_back(sig_dist(generator)) ;
	}

	vector<double> mu_B ;
	vector<double> sig_B ;

	int n = 10 ;
	for (int i = 0; i < n; i++)
	{
		mu_B.push_back(mu_dist(generator)) ;
		sig_B.push_back(sig_dist(generator)) ;
	}

	double c_A0 = mu_dist(generator) ;
	double c_B0 = mu_dist(generator) ;

	double pImprove = ComputeImprovementProbability(c_A0,c_B0,mu_A,sig_A,mu_B,sig_B) ;

	cout << "Probability of improvement: " << pImprove << endl ;

	n = 100000 ;
	vector<double> A_cost(n,c_A0) ;
	vector<double> B_cost(n,c_B0) ;

	double pBoverA = 0.0 ;
	for (int k = 0; k < n; k++)
	{
		double best_A = DBL_MAX ;
		for (int i = 0; i < mu_A.size(); i++)
		{
			normal_distribution<double> distribution(mu_A[i],sig_A[i]) ;
			double c_Ai = distribution(generator) ;
				if (c_Ai < best_A)
					best_A = c_Ai ;
		}
		A_cost[k] += best_A ;

		double best_B = DBL_MAX ;
		for (int i = 0; i < mu_B.size(); i++)
		{
			normal_distribution<double> distribution(mu_B[i],sig_B[i]) ;
			double c_Bi = distribution(generator) ;
				if (c_Bi < best_B)
					best_B = c_Bi ;
		}
		B_cost[k] += best_B ;

		if (B_cost[k]<=A_cost[k])
			pBoverA++ ;
	}

	double pBA = pBoverA/n ;
	cout << "Monte Carlo probability: " << pBA << endl ;

	return 0 ;
}
<commit_msg>Included clock time comparison between function and MC trials<commit_after>#include <iostream>
#include <algorithm>
#include <math.h>
#include <float.h>
#include <random>
#include <time.h>
using namespace std ;

const double pi = 3.14159265358979323846264338328 ;

vector<double> linspace(double a, double b, int n)
{
	vector<double> array ;
	double step = (b-a)/(n-1) ;
	while (a<=b)
	{
		array.push_back(a) ;
		a += step ;
	}
	return array ;
}

/*double IntNormDist(double mu, double sig, double a)
{
	int n = 1000 ;
	vector<double> x = linspace(a,mu+3*sig,n) ;
	double dx = (x[1]-x[0]) ;

	double integral = 0.0 ;
	for (int i = 0; i < x.size(); i++)
	{
		double fac = 1/(sig*sqrt(2*pi)) ;
		double ind = -(pow(x[i]-mu,2))/(2*pow(sig,2)) ;
		integral += fac*exp(ind)*dx ;
	}
	return integral ;
}*/

double ComputeImprovementProbability(double c_A0, double c_B0, vector<double> mu_A, vector<double> sig_A, vector<double> mu_B, vector<double> sig_B)
{
	double max_3sig = mu_A[0] + 3*sig_A[0] ;
	double min_3sig = mu_A[0] - 3*sig_A[0] ;
	for (int i = 0; i < mu_A.size(); i++)
	{
		if (max_3sig < mu_A[i]+3*sig_A[i])
			max_3sig = mu_A[i]+3*sig_A[i] ;
		if (min_3sig > mu_A[i]-3*sig_A[i])
			min_3sig = mu_A[i]-3*sig_A[i] ;
	}
	for (int i = 0; i < mu_B.size(); i++)
	{
		if (max_3sig < mu_B[i]+3*sig_B[i])
			max_3sig = mu_B[i]+3*sig_B[i] ;
		if (min_3sig > mu_B[i]-3*sig_B[i])
			min_3sig = mu_B[i]-3*sig_B[i] ;
	}

	int n = 10000 ;
	vector<double> x = linspace(min_3sig,max_3sig,n) ;
	double dx = x[1]-x[0] ;
	double pImprove = 0.0 ;
	for (int k = 0; k < x.size(); k++)
	{
		double p_cAi = 0.0 ;
		for (int i = 0; i < mu_A.size(); i++)
		{
			double p_cA1 = (1/(sig_A[i]*sqrt(2*pi)))*exp(-(pow(x[k]-mu_A[i],2))/(2*pow(sig_A[i],2))) ;
			double p_cA2 = 1.0 ;
			for (int j = 0; j < mu_A.size(); j++)
			{
				if (j != i)
					p_cA2 *= 0.5*erfc((x[k]-mu_A[j])/(sig_A[j]*sqrt(2))) ;
			}
			p_cAi += p_cA1*p_cA2 ;
		}
		double p_cBi = 1.0 ;
		for (int i = 0; i < mu_B.size(); i++)
			p_cBi *= 0.5*erfc((x[k]-(c_B0-c_A0)-mu_B[i])/(sig_B[i]*sqrt(2))) ;
		pImprove += (p_cAi)*(1-p_cBi)*dx ;
	}
	return pImprove;
}

int main()
{

	random_device generator ;

	uniform_real_distribution<double> mu_dist(0.0,10.0) ;
	uniform_real_distribution<double> sig_dist(0.0,10.0) ;

	vector<double> mu_A ;
	vector<double> sig_A ;

	int m = 3 ;
	for (int i = 0; i < m; i++)
	{
		mu_A.push_back(mu_dist(generator)) ;
		sig_A.push_back(sig_dist(generator)) ;
	}

	vector<double> mu_B ;
	vector<double> sig_B ;

	int n = 10 ;
	for (int i = 0; i < n; i++)
	{
		mu_B.push_back(mu_dist(generator)) ;
		sig_B.push_back(sig_dist(generator)) ;
	}

	double c_A0 = mu_dist(generator) ;
	double c_B0 = mu_dist(generator) ;

	clock_t t_fun ;
	t_fun = clock() ;
	double pImprove = ComputeImprovementProbability(c_A0,c_B0,mu_A,sig_A,mu_B,sig_B) ;
	t_fun = clock() - t_fun ;

	cout << "Probability of improvement: " << pImprove << endl ;
	cout << "Tics elapsed: " << t_fun << ", " << ((float)t_fun)/CLOCKS_PER_SEC << "s" << endl ;

	n = 100000 ;
	vector<double> A_cost(n,c_A0) ;
	vector<double> B_cost(n,c_B0) ;

	double pBoverA = 0.0 ;
	clock_t t_MC ;
	t_MC = clock() ;
	for (int k = 0; k < n; k++)
	{
		double best_A = DBL_MAX ;
		for (int i = 0; i < mu_A.size(); i++)
		{
			normal_distribution<double> distribution(mu_A[i],sig_A[i]) ;
			double c_Ai = distribution(generator) ;
				if (c_Ai < best_A)
					best_A = c_Ai ;
		}
		A_cost[k] += best_A ;

		double best_B = DBL_MAX ;
		for (int i = 0; i < mu_B.size(); i++)
		{
			normal_distribution<double> distribution(mu_B[i],sig_B[i]) ;
			double c_Bi = distribution(generator) ;
				if (c_Bi < best_B)
					best_B = c_Bi ;
		}
		B_cost[k] += best_B ;

		if (B_cost[k]<=A_cost[k])
			pBoverA++ ;
	}
	t_MC = clock() - t_MC ;

	double pBA = pBoverA/n ;
	cout << "Monte Carlo probability: " << pBA << endl ;
	cout << "Tics elapsed: " << t_MC << ", " << ((float)t_MC)/CLOCKS_PER_SEC << "s" << endl ;

	return 0 ;
}
<|endoftext|>


<commit_before>{%each args as cbArg %}
  {%if cbArg.isCallbackFunction %}

{{ cbArg.returnType }} {{ cppClassName }}::{{ cppFunctionName }}_{{ cbArg.name }}_cppCallback (
  {% each cbArg.args|argsInfo as arg %}
    {{ arg.cType }} {{ arg.name}}{% if not arg.lastArg %},{% endif %}
  {% endeach %}
) {
  {{ cppFunctionName }}_{{ cbArg.name|titleCase }}Baton* baton = new {{ cppFunctionName }}_{{ cbArg.name|titleCase }}Baton();

  {% each cbArg.args|argsInfo as arg %}
    baton->{{ arg.name }} = {{ arg.name }};
  {% endeach %}

  baton->req.data = baton;
  baton->done = false;

  uv_queue_work(uv_default_loop(), &baton->req, {{ function.cppFunctionName }}_{{ cbArg.name }}_asyncWork, {{ function.cppFunctionName }}_{{ cbArg.name }}_asyncAfter);

  while(!baton->done) {
    this_thread::sleep_for(chrono::milliseconds(1));
  }

  {% each cbArg|returnsInfo true false as _return %}
    *{{ _return.name }} = *baton->{{ _return.name }};
  {% endeach %}

  return baton->result;
}

void {{ cppClassName }}::{{ function.cppFunctionName }}_{{ cbArg.name }}_asyncWork(uv_work_t* req) {
  // We aren't doing any work on a seperate thread, just need to
  // access the main node thread in the async after method.
  // However, this worker method is still needed
}

void {{ cppClassName }}::{{ function.cppFunctionName }}_{{ cbArg.name }}_asyncAfter(uv_work_t* req, int status) {
  NanScope();

  {{ function.cppFunctionName }}_{{ cbArg.name|titleCase }}Baton* baton = static_cast<{{ function.cppFunctionName }}_{{ cbArg.name|titleCase }}Baton*>(req->data);
  {{ cppClassName }}* instance = static_cast<{{ cppClassName }}*>(baton->payload);

  if (instance->{{ cbArg.name }}->IsEmpty()) {
    {% if cbArg.returnType == "int" %}
      baton->result = {{ cbArg.returnNoResults }}; // no results acquired
    {% endif %}

    baton->done = true;
    return;
  }

  CallbackWrapper* cbWrapper = baton->payload;

  Local<Value> argv[{{ cbArg.args|jsArgsCount }}] = {
    {% each cbArg.args|argsInfo as arg %}
      {% if arg.name == "payload" %}
        {%-- payload is always the last arg --%}
        NanNew(cbWrapper->payload)
      {% elsif arg.isJsArg %}
        {% if arg.isEnum %}
          NanNew((int)baton->{{ arg.name }}),
        {% elsif arg.isLibgitType %}
          NanNew({{ arg.cppClassName }}::New(&baton->{{ arg.name }}, false)),
        {% elsif arg.cType == "size_t" %}
          // HACK: NAN should really have an overload for NanNew to support size_t
          NanNew((unsigned int)baton->{{ arg.name }}),
        {% else %}
          NanNew(baton->{{ arg.name }}),
        {% endif %}
      {% endif %}
    {% endeach %}
  };

  TryCatch tryCatch;
  Handle<Value> result = cbWrapper->jsFunction->Call({{ cbArg.args|jsArgsCount }}, argv);

  if (result->IsObject() && result->ToObject()->Has(NanNew("then"))) {
    Handle<Value> thenProp = result->ToObject()->Get(NanNew("then"));

    if (thenProp->IsFunction()) {
      // we can be reasonbly certain that the result is a promise
      Local<Object> promise = result->ToObject();

      NanAssignPersistent(baton->promise, promise);

      uv_queue_work(uv_default_loop(), &baton->req, {{ function.cppFunctionName }}_{{ cbArg.name }}_asyncWork, {{ function.cppFunctionName }}_{{ cbArg.name }}_asyncPromisePolling);
      return;
    }
  }

  {{ cbArg.returnType }} resultStatus;

  {% each cbArg|returnsInfo true false as _return %}
    if (result.IsEmpty() || result->IsNativeError()) {
      baton->result = {{ cbArg.returnError }};
    }
    else if (!result->IsNull() && !result->IsUndefined()) {
      {{ _return.cppClassName }}* wrapper = ObjectWrap::Unwrap<{{ _return.cppClassName }}>(result->ToObject());
      wrapper->selfFreeing = false;

      baton->{{ _return.name }} = wrapper->GetRefValue();
      baton->result = {{ cbArg.returnSuccess }};
    }
    else {
      baton->result = {{ cbArg.returnNoResults }};
    }
  {% endeach %}
  baton->done = true;
}

void {{ cppClassName }}::{{ function.cppFunctionName }}_{{ cbArg.name }}_asyncPromisePolling(uv_work_t* req, int status) {
  NanScope();

  {{ function.cppFunctionName }}_{{ cbArg.name|titleCase }}Baton* baton = static_cast<{{ function.cppFunctionName }}_{{ cbArg.name|titleCase }}Baton*>(req->data);
  Local<Object> promise = NanNew<Object>(baton->promise);
  NanCallback* isPendingFn = new NanCallback(promise->Get(NanNew("isPending")).As<Function>());
  Local<Value> argv[1]; // MSBUILD won't assign an array of length 0
  Local<Boolean> isPending = isPendingFn->Call(0, argv)->ToBoolean();

  if (isPending->Value()) {
    uv_queue_work(uv_default_loop(), &baton->req, {{ function.cppFunctionName }}_{{ cbArg.name }}_asyncWork, {{ function.cppFunctionName }}_{{ cbArg.name }}_asyncPromisePolling);
    return;
  }

  NanCallback* isFulfilledFn = new NanCallback(promise->Get(NanNew("isFulfilled")).As<Function>());
  Local<Boolean> isFulfilled = isFulfilledFn->Call(0, argv)->ToBoolean();

  if (isFulfilled->Value()) {
    NanCallback* resultFn = new NanCallback(promise->Get(NanNew("value")).As<Function>());
    Handle<Value> result = resultFn->Call(0, argv);
    {{ cbArg.returnType }} resultStatus;

    {% each cbArg|returnsInfo true false as _return %}
      if (result.IsEmpty() || result->IsNativeError()) {
        baton->result = {{ cbArg.returnError }};
      }
      else if (!result->IsNull() && !result->IsUndefined()) {
        {{ _return.cppClassName }}* wrapper = ObjectWrap::Unwrap<{{ _return.cppClassName }}>(result->ToObject());
        wrapper->selfFreeing = false;

        baton->{{ _return.name }} = wrapper->GetRefValue();
        baton->result = {{ cbArg.returnSuccess }};
      }
      else {
        baton->result = {{ cbArg.returnNoResults }};
      }
    {% endeach %}
    baton->done = true;
  }
  else {
    // promise was rejected
    baton->result = {{ cbArg.returnError }};
    baton->done = false;
  }
}
  {%endif%}
{%endeach%}
<commit_msg>Fixed error in callback_helpers.cc<commit_after>{%each args as cbArg %}
  {%if cbArg.isCallbackFunction %}

{{ cbArg.returnType }} {{ cppClassName }}::{{ cppFunctionName }}_{{ cbArg.name }}_cppCallback (
  {% each cbArg.args|argsInfo as arg %}
    {{ arg.cType }} {{ arg.name}}{% if not arg.lastArg %},{% endif %}
  {% endeach %}
) {
  {{ cppFunctionName }}_{{ cbArg.name|titleCase }}Baton* baton = new {{ cppFunctionName }}_{{ cbArg.name|titleCase }}Baton();

  {% each cbArg.args|argsInfo as arg %}
    baton->{{ arg.name }} = {{ arg.name }};
  {% endeach %}

  baton->req.data = baton;
  baton->done = false;

  uv_queue_work(uv_default_loop(), &baton->req, {{ cppFunctionName }}_{{ cbArg.name }}_asyncWork, {{ cppFunctionName }}_{{ cbArg.name }}_asyncAfter);

  while(!baton->done) {
    this_thread::sleep_for(chrono::milliseconds(1));
  }

  {% each cbArg|returnsInfo true false as _return %}
    *{{ _return.name }} = *baton->{{ _return.name }};
  {% endeach %}

  return baton->result;
}

void {{ cppClassName }}::{{ cppFunctionName }}_{{ cbArg.name }}_asyncWork(uv_work_t* req) {
  // We aren't doing any work on a seperate thread, just need to
  // access the main node thread in the async after method.
  // However, this worker method is still needed
}

void {{ cppClassName }}::{{ cppFunctionName }}_{{ cbArg.name }}_asyncAfter(uv_work_t* req, int status) {
  NanScope();

  {{ cppFunctionName }}_{{ cbArg.name|titleCase }}Baton* baton = static_cast<{{ cppFunctionName }}_{{ cbArg.name|titleCase }}Baton*>(req->data);
  {{ cppClassName }}* instance = static_cast<{{ cppClassName }}*>(baton->payload);

  if (instance->{{ cbArg.name }}->IsEmpty()) {
    {% if cbArg.returnType == "int" %}
      baton->result = {{ cbArg.returnNoResults }}; // no results acquired
    {% endif %}

    baton->done = true;
    return;
  }

  CallbackWrapper* cbWrapper = baton->payload;

  Local<Value> argv[{{ cbArg.args|jsArgsCount }}] = {
    {% each cbArg.args|argsInfo as arg %}
      {% if arg.name == "payload" %}
        {%-- payload is always the last arg --%}
        NanNew(cbWrapper->payload)
      {% elsif arg.isJsArg %}
        {% if arg.isEnum %}
          NanNew((int)baton->{{ arg.name }}),
        {% elsif arg.isLibgitType %}
          NanNew({{ arg.cppClassName }}::New(&baton->{{ arg.name }}, false)),
        {% elsif arg.cType == "size_t" %}
          // HACK: NAN should really have an overload for NanNew to support size_t
          NanNew((unsigned int)baton->{{ arg.name }}),
        {% else %}
          NanNew(baton->{{ arg.name }}),
        {% endif %}
      {% endif %}
    {% endeach %}
  };

  TryCatch tryCatch;
  Handle<Value> result = cbWrapper->jsFunction->Call({{ cbArg.args|jsArgsCount }}, argv);

  if (result->IsObject() && result->ToObject()->Has(NanNew("then"))) {
    Handle<Value> thenProp = result->ToObject()->Get(NanNew("then"));

    if (thenProp->IsFunction()) {
      // we can be reasonbly certain that the result is a promise
      Local<Object> promise = result->ToObject();

      NanAssignPersistent(baton->promise, promise);

      uv_queue_work(uv_default_loop(), &baton->req, {{ cppFunctionName }}_{{ cbArg.name }}_asyncWork, {{ cppFunctionName }}_{{ cbArg.name }}_asyncPromisePolling);
      return;
    }
  }

  {{ cbArg.returnType }} resultStatus;

  {% each cbArg|returnsInfo true false as _return %}
    if (result.IsEmpty() || result->IsNativeError()) {
      baton->result = {{ cbArg.returnError }};
    }
    else if (!result->IsNull() && !result->IsUndefined()) {
      {{ _return.cppClassName }}* wrapper = ObjectWrap::Unwrap<{{ _return.cppClassName }}>(result->ToObject());
      wrapper->selfFreeing = false;

      baton->{{ _return.name }} = wrapper->GetRefValue();
      baton->result = {{ cbArg.returnSuccess }};
    }
    else {
      baton->result = {{ cbArg.returnNoResults }};
    }
  {% endeach %}
  baton->done = true;
}

void {{ cppClassName }}::{{ cppFunctionName }}_{{ cbArg.name }}_asyncPromisePolling(uv_work_t* req, int status) {
  NanScope();

  {{ cppFunctionName }}_{{ cbArg.name|titleCase }}Baton* baton = static_cast<{{ cppFunctionName }}_{{ cbArg.name|titleCase }}Baton*>(req->data);
  Local<Object> promise = NanNew<Object>(baton->promise);
  NanCallback* isPendingFn = new NanCallback(promise->Get(NanNew("isPending")).As<Function>());
  Local<Value> argv[1]; // MSBUILD won't assign an array of length 0
  Local<Boolean> isPending = isPendingFn->Call(0, argv)->ToBoolean();

  if (isPending->Value()) {
    uv_queue_work(uv_default_loop(), &baton->req, {{ cppFunctionName }}_{{ cbArg.name }}_asyncWork, {{ cppFunctionName }}_{{ cbArg.name }}_asyncPromisePolling);
    return;
  }

  NanCallback* isFulfilledFn = new NanCallback(promise->Get(NanNew("isFulfilled")).As<Function>());
  Local<Boolean> isFulfilled = isFulfilledFn->Call(0, argv)->ToBoolean();

  if (isFulfilled->Value()) {
    NanCallback* resultFn = new NanCallback(promise->Get(NanNew("value")).As<Function>());
    Handle<Value> result = resultFn->Call(0, argv);
    {{ cbArg.returnType }} resultStatus;

    {% each cbArg|returnsInfo true false as _return %}
      if (result.IsEmpty() || result->IsNativeError()) {
        baton->result = {{ cbArg.returnError }};
      }
      else if (!result->IsNull() && !result->IsUndefined()) {
        {{ _return.cppClassName }}* wrapper = ObjectWrap::Unwrap<{{ _return.cppClassName }}>(result->ToObject());
        wrapper->selfFreeing = false;

        baton->{{ _return.name }} = wrapper->GetRefValue();
        baton->result = {{ cbArg.returnSuccess }};
      }
      else {
        baton->result = {{ cbArg.returnNoResults }};
      }
    {% endeach %}
    baton->done = true;
  }
  else {
    // promise was rejected
    baton->result = {{ cbArg.returnError }};
    baton->done = false;
  }
}
  {%endif%}
{%endeach%}
<|endoftext|>


<commit_before>/*
 * Graph2Benchmark.cpp
 *
 *  Created on: 05.02.2013
 *      Author: Christian Staudt (christian.staudt@kit.edu)
 */

#ifndef NOGTEST

#include "Graph2Benchmark.h"

namespace NetworKit {

Graph2Benchmark::Graph2Benchmark() {
	// TODO Auto-generated constructor stub

}

Graph2Benchmark::~Graph2Benchmark() {
	// TODO Auto-generated destructor stub
}

TEST_F(Graph2Benchmark, graphConstruction) {
	count n = 1e+7;;

	Aux::Timer run;
	INFO("[BEGIN] (n=" << n << ")");
	run.start();

	Graph G(n);

	run.stop();
	INFO("[DONE]" << run.elapsedTag());
}

TEST_F(Graph2Benchmark, nodeIteration) {
	count n = 1e+7;;
	Graph G(n);

	std::vector<node> nodes(n, 0);

	Aux::Timer run;
	INFO("[BEGIN] (n=" << n << ")");
	run.start();

	G.forNodes([&](node v){
		nodes[v] = v;
	});

	run.stop();
	INFO("[DONE]" << run.elapsedTag());

}

TEST_F(Graph2Benchmark, parallelNodeIteration) {
	count n = 1e+7;;
	Graph G(n);

	std::vector<node> nodes(n, 0);

	Aux::Timer run;
	INFO("[BEGIN] (n=" << n << ")");
	run.start();

	G.parallelForNodes([&](node v){
		nodes[v] = v;
	});

	run.stop();
	INFO("[DONE]" << run.elapsedTag());
}

TEST_F(Graph2Benchmark, nodePairIteration) {
	count n = 1e+4;;
	Graph G(n);

	Aux::Timer run;
	INFO("[BEGIN] (n=" << n << ")");
	run.start();

	count p = 0;
	G.forNodePairs([&](node u, node v){
		p += 1;
	});

	run.stop();
	INFO("[DONE]" << run.elapsedTag());

	EXPECT_EQ((n * (n-1)) / 2, p);
}

TEST_F(Graph2Benchmark, edgeInsertion) {

	count n = 1e+4;
	Graph G(n);

	Aux::Timer run;
	INFO("[BEGIN] (n=" << n << ")");
	run.start();

	G.forNodePairs([&](node u, node v){
		G.addEdge(u, v);
	});

	run.stop();
	INFO("[DONE]" << run.elapsedTag());

}

TEST_F(Graph2Benchmark, edgeRemoval) {
	count n = 1e+4;
	Graph G(n);

	// insert edges
	G.forNodePairs([&](node u, node v){
		G.addEdge(u, v);
	});

	Aux::Timer run;
	INFO("[BEGIN] (n=" << n << ")");
	run.start();

	G.forNodePairs([&](node u, node v){
		G.removeEdge(u, v);
	});

	run.stop();
	INFO("[DONE]" << run.elapsedTag());

}

TEST_F(Graph2Benchmark, edgeIteration) {
	count n = 1e+4;
	Graph G(n);

	// insert edges
	G.forNodePairs([&](node u, node v){
		G.addEdge(u, v);
	});

	Aux::Timer run;
	INFO("[BEGIN] (n=" << n << ")");
	run.start();

	G.forEdges([&](node u, node v){

	});

	run.stop();
	INFO("[DONE]" << run.elapsedTag());
}

TEST_F(Graph2Benchmark, parallelEdgeIteration) {
	count n = 1e+4;
	Graph G(n);

	// insert edges
	G.forNodePairs([&](node u, node v){
		G.addEdge(u, v);
	});

	Aux::Timer run;
	INFO("[BEGIN] (n=" << n << ")");
	run.start();

	count i = 0;
	G.parallelForEdges([&](node u, node v){
		i += 1;
	});

	EXPECT_TRUE(true) << "just iterate";

	run.stop();
	INFO("[DONE]" << run.elapsedTag());
}

TEST_F(Graph2Benchmark, parallelSumForNodes) {
	count n = 1e+7;
	Graph G(n);

	double sum = G.parallelSumForNodes([&](node v) {
		return 1;
	});

	EXPECT_EQ(n, sum) << "each node adds 1";

}

TEST_F(Graph2Benchmark, nodeInsertion) {
	count n = 1e+4;

	Graph G(0); // empty graph

	for (count i = 0; i < n; ++i) {
		node v = G.addNode();
	}

	EXPECT_TRUE(n, G.numberOfNodes()) << "n nodes should have been added";
}

TEST_F(Graph2Benchmark, nodeRemoval) {
	count n = 1e+4;

	Graph G(n); // empty graph

	for (node u = 0; u < n; ++u) {
		G.removeNode(u);
	}

	EXPECT_TRUE(0, G.numberOfNodes()) << "no nodes should be left";
}

} /* namespace NetworKit */

#endif /*NOGTEST */
<commit_msg>completed benchmarks<commit_after>/*
 * Graph2Benchmark.cpp
 *
 *  Created on: 05.02.2013
 *      Author: Christian Staudt (christian.staudt@kit.edu)
 */

#ifndef NOGTEST

#include "Graph2Benchmark.h"

namespace NetworKit {

Graph2Benchmark::Graph2Benchmark() {
	// TODO Auto-generated constructor stub

}

Graph2Benchmark::~Graph2Benchmark() {
	// TODO Auto-generated destructor stub
}

TEST_F(Graph2Benchmark, graphConstruction) {
	count n = 1e+7;;

	Aux::Timer run;
	INFO("[BEGIN] (n=" << n << ")");
	run.start();

	Graph G(n);

	run.stop();
	INFO("[DONE]" << run.elapsedTag());
}

TEST_F(Graph2Benchmark, nodeIteration) {
	count n = 1e+7;;
	Graph G(n);

	std::vector<node> nodes(n, 0);

	Aux::Timer run;
	INFO("[BEGIN] (n=" << n << ")");
	run.start();

	G.forNodes([&](node v){
		nodes[v] = v;
	});

	run.stop();
	INFO("[DONE]" << run.elapsedTag());

}

TEST_F(Graph2Benchmark, parallelNodeIteration) {
	count n = 1e+7;;
	Graph G(n);

	std::vector<node> nodes(n, 0);

	Aux::Timer run;
	INFO("[BEGIN] (n=" << n << ")");
	run.start();

	G.parallelForNodes([&](node v){
		nodes[v] = v;
	});

	run.stop();
	INFO("[DONE]" << run.elapsedTag());
}

TEST_F(Graph2Benchmark, nodePairIteration) {
	count n = 1e+4;;
	Graph G(n);

	Aux::Timer run;
	INFO("[BEGIN] (n=" << n << ")");
	run.start();

	count p = 0;
	G.forNodePairs([&](node u, node v){
		p += 1;
	});

	run.stop();
	INFO("[DONE]" << run.elapsedTag());

	EXPECT_EQ((n * (n-1)) / 2, p);
}

TEST_F(Graph2Benchmark, edgeInsertion) {

	count n = 1e+4;
	Graph G(n);

	Aux::Timer run;
	INFO("[BEGIN] (n=" << n << ")");
	run.start();

	G.forNodePairs([&](node u, node v){
		G.addEdge(u, v);
	});

	run.stop();
	INFO("[DONE]" << run.elapsedTag());

}

TEST_F(Graph2Benchmark, edgeRemoval) {
	count n = 1e+4;
	Graph G(n);

	// insert edges
	G.forNodePairs([&](node u, node v){
		G.addEdge(u, v);
	});

	Aux::Timer run;
	INFO("[BEGIN] (n=" << n << ")");
	run.start();

	G.forNodePairs([&](node u, node v){
		G.removeEdge(u, v);
	});

	run.stop();
	INFO("[DONE]" << run.elapsedTag());

}

TEST_F(Graph2Benchmark, edgeIteration) {
	count n = 1e+4;
	Graph G(n);

	// insert edges
	G.forNodePairs([&](node u, node v){
		G.addEdge(u, v);
	});

	Aux::Timer run;
	INFO("[BEGIN] (n=" << n << ")");
	run.start();

	G.forEdges([&](node u, node v){

	});

	run.stop();
	INFO("[DONE]" << run.elapsedTag());
}

TEST_F(Graph2Benchmark, parallelEdgeIteration) {
	count n = 1e+4;
	Graph G(n);

	// insert edges
	G.forNodePairs([&](node u, node v){
		G.addEdge(u, v);
	});

	Aux::Timer run;
	INFO("[BEGIN] (n=" << n << ")");
	run.start();

	count i = 0;
	G.parallelForEdges([&](node u, node v){
		i += 1;
	});

	EXPECT_TRUE(true) << "just iterate";

	run.stop();
	INFO("[DONE]" << run.elapsedTag());
}

TEST_F(Graph2Benchmark, parallelSumForNodes) {
	count n = 1e+7;
	Graph G(n);

	double sum = G.parallelSumForNodes([&](node v) {
		return 1;
	});

	EXPECT_EQ(n, sum) << "each node adds 1";

}

TEST_F(Graph2Benchmark, nodeInsertion) {
	count n = 1e+4;

	Graph G(0); // empty graph

	for (count i = 0; i < n; ++i) {
		node v = G.addNode();
	}

	EXPECT_EQ(n, G.numberOfNodes()) << "n nodes should have been added";
}

TEST_F(Graph2Benchmark, nodeRemoval) {
	count n = 1e+4;

	Graph G(n); // empty graph

	for (node u = 0; u < n; ++u) {
		G.removeNode(u);
	}

	EXPECT_EQ(0, G.numberOfNodes()) << "no nodes should be left";
}

} /* namespace NetworKit */

#endif /*NOGTEST */
<|endoftext|>


<commit_before>
#include "CommandParser.cpp"
#include "Configurations.h"
#include "Utils.cpp"

namespace L10ns {

inline void printDefaultHelp() {
    auto w = new TextWriter();
    w->addTab(2);
    w->addTab(10);
    w->writeLine("Usage: l10ns <command> [<options>]");
    w->newline();
    w->writeLine("Commands:");
    for (const auto& action : actions) {
        w->writeLine(*action.name + " " + *action.description);
    }
    w->print();
}

inline void printActionHelp(ActionKind action) {

}

inline void printCommandHelp(Command * command) {
    if (command->action == ActionKind::None) {
        printDefaultHelp();
    }
    else {
        printActionHelp(command->action);
    }
}

int init(int argc, char * argv[]) {
    auto command = parseCommandArguments(argc, argv);
    if (command->isRequestingVersion) {
        println("L10ns version ", VERSION, ".");
    }
    else if (command->isRequestingHelp) {
        printCommandHelp(command);
    }
    return 0;
}

} // L10ns
<commit_msg>Adds print default help<commit_after>
#include "CommandParser.cpp"
#include "Configurations.h"
#include "Utils.cpp"

namespace L10ns {

inline void printDefaultHelp() {
    auto w = new TextWriter();
    w->addTab(2);
    w->addTab(12);
    w->writeLine("Usage: l10ns [<options>] <command>");
    w->newline();
    w->writeLine("Commands:");
    w->newline();
    for (const auto& action : actions) {
        w->tab();
        w->write(*action.name);
        w->tab();
        w->writeLine(*action.description);
    }
    w->newline();
    w->writeLine("For more details: 'l10ns <command> --help'.");
    w->newline();
    w->clearTabs();
    w->addTab(2);
    w->addTab(17);
    w->writeLine("Options:");
    w->newline();
    for (const auto& flag : defaultFlags) {
        w->tab();
        if (flag.alias->length() != 0) {
            w->write(*flag.name + ", " + *flag.alias);
        }
        else {
            w->write(*flag.name);
        }
        w->tab();
        w->writeLine(*flag.description);
    }
    w->print();
}

inline void printActionHelp(ActionKind action) {

}

inline void printCommandHelp(Command * command) {
    if (command->action == ActionKind::None) {
        printDefaultHelp();
    }
    else {
        printActionHelp(command->action);
    }
}

int init(int argc, char * argv[]) {
    auto command = parseCommandArguments(argc, argv);
    if (command->isRequestingVersion) {
        println("L10ns version ", VERSION, ".");
    }
    else if (command->isRequestingHelp) {
        printCommandHelp(command);
    }
    return 0;
}

} // L10ns
<|endoftext|>


<commit_before>// Quadric-based mesh decimation

#include <geode/mesh/decimate.h>
#include <geode/python/wrap.h>
#include <geode/structure/Heap.h>
#include <geode/vector/SymmetricMatrix.h>
namespace geode {

typedef real T;
typedef Vector<T,3> TV;

namespace {
// Binary heap of potential collapses
struct Heap : public HeapBase<Heap>, public Noncopyable {
  typedef HeapBase<Heap> Base;
  Array<Tuple<VertexId,T,VertexId>> heap; // src,badness,dst
  Field<int,VertexId> inv_heap;

  Heap(const int nv)
    : inv_heap(nv,uninit) {
    inv_heap.flat.fill(-1);
  }

  int size() const {
    return heap.size();
  }

  bool first(const int i, const int j) const {
    return heap[i].y <= heap[j].y;
  }

  void swap(const int i, const int j) {
    std::swap(heap[i],heap[j]);
    inv_heap[heap[i].x] = i;
    inv_heap[heap[j].x] = j;
  }

  Vector<VertexId,2> pop() {
    const auto e = heap[0];
    inv_heap[e.x] = -1;
    const auto p = heap.pop();
    if (size()) {
      heap[0] = p;
      inv_heap[heap[0].x] = 0;
      Base::move_downward(0);
    }
    return vec(e.x,e.z);
  }

  void set(const VertexId v, const T q, const VertexId dst) {
    const auto entry = tuple(v,q,dst);
    int i = inv_heap[v];
    if (i < 0)
      i = heap.append(entry);
    else
      heap[i] = entry;
    Base::move_up_or_down(i);
  }

  void erase(const VertexId v) {
    int& i = inv_heap[v];
    if (i >= 0) {
      const auto p = heap.pop();
      if (i < size()) {
        heap[i] = p;
        inv_heap[p.x] = i;
        Base::move_up_or_down(i);
      }
      i = -1;
    }
  }
};
}

void decimate_inplace(MutableTriangleTopology& mesh, RawField<TV,VertexId> X,
                      const T distance, const T max_angle, const int min_vertices, const T boundary_distance) {
  if (mesh.n_vertices() <= min_vertices)
    return;
  const T area = sqr(distance);
  const T sign_sqr_min_cos = sign_sqr(max_angle > .99*pi ? -1 : cos(max_angle));

  // Finds the best edge to collapse v along.  Returns (q(e),dst(e)).
  const auto best_collapse = [&mesh,X](const VertexId v) {
    // The quadric around this version will be (x'Ax-b'x+c)/total
    T total = 0;
    SymmetricMatrix<T,3> A;
    TV b;
    T c = 0;
    for (const auto e : mesh.outgoing(v))
      if (!mesh.is_boundary(e)) {
        const auto f = mesh.face(e);
        const auto v = mesh.vertices(f);
        const auto p = X[v.x],
                   n = cross(X[v.y]-p,X[v.z]-p);
        const T w = magnitude(n);
        if (w) {
          total += w;
          // u = n/w
          // q(x) = w(u'(x-p))^2
          //      = w(u'x-u'p)^2
          //      = w(x'uu'x-2(pu'u)'x+(u'p)^2)
          //      = x'(nn'/w)x-2(pn'n/w)+(n'p)^2/w
          const T inv_w = 1/w,
                  pn = dot(p,n);
          A += scaled_outer_product(inv_w,n);
          b += inv_w*pn*n; // We'll multiply by 2 below
          c += inv_w*sqr(pn);
        }
      }
    // Normalize
    if (total) {
      const T inv_total = 1/total;
      A *= inv_total;
      b *= 2*inv_total;
      c *= inv_total;
    }

    // Find the best edge, ignoring normal constraints
    T min_q = inf;
    HalfedgeId min_e;
    for (const auto e : mesh.outgoing(v)) {
      const auto x = X[mesh.dst(e)];
      const T q = dot(x,A*x-b); // We'll add c below, specifically...
      if (min_q > q) {
        min_q = q;
        min_e = e;
      }
    }
    return tuple(min_q+c,mesh.dst(min_e)); // ...here
  };

  // Is it safe to collapse src(e) into dst(e)?
  const auto normal_safe = [&mesh,X,sign_sqr_min_cos](const HalfedgeId e) {
    if (sign_sqr_min_cos == -1) // If anything is allowed, there's nothing to do
      return true;
    const auto src = mesh.src(e),
               dst = mesh.dst(e);
    const auto xs = X[src],
               xd = X[dst];
    for (const auto ee : mesh.outgoing(src))
      if (e!=ee && !mesh.is_boundary(ee)) {
        const auto v2 = mesh.opposite(ee);
        if (v2 != dst) {
          const auto x1 = X[mesh.dst(ee)],
                     x2 = X[v2];
          const auto n0 = cross(x2-x1,xs-x1),
                     n1 = cross(x2-x1,xd-x1);
          if (sign_sqr(dot(n0,n1)) < sign_sqr_min_cos*sqr_magnitude(n0)*sqr_magnitude(n1))
            return false;
        }
      }
    return true;
  };

  // Initialize quadrics and heap
  Heap heap(mesh.n_vertices_);
  for (const auto v : mesh.vertices()) {
    const auto qe = best_collapse(v);
    if (qe.x <= area)
      heap.inv_heap[v] = heap.heap.append(tuple(v,qe.x,qe.y));
  }
  heap.make();

  // Update the quadric information for a vertex
  const auto update = [&heap,best_collapse,area](const VertexId v) {
    const auto qe = best_collapse(v);
    if (qe.x <= area)
      heap.set(v,qe.x,qe.y);
    else
      heap.erase(v);
  };

  // Repeatedly collapse the best vertex
  while (heap.size()) {
    const auto v = heap.pop();

    // Do these vertices still exist?
    if (mesh.valid(v.x) && mesh.valid(v.y)) {
      const auto e = mesh.halfedge(v.x,v.y);

      // Is the collapse invalid?
      if (e.valid() && mesh.is_collapse_safe(e)) {
        const auto vs = mesh.src(e),
                   vd = mesh.dst(e);
        const auto xs = X[vs],
                   xd = X[vd];

        // Are we moving a boundary vertex too far from its two boundary lines?
        {
          const auto b = mesh.halfedge(vs);
          if (mesh.is_boundary(b)) {
            const auto x0 = X[mesh.dst(b)],
                       x1 = X[mesh.src(mesh.prev(b))];
            if (   line_point_distance(simplex(xs,x0),xd) > boundary_distance
                || line_point_distance(simplex(xs,x1),xd) > boundary_distance)
              goto bad;
          }
        }

        // Do the normals change too much?
        if (sign_sqr_min_cos > -1)
          for (const auto ee : mesh.outgoing(vs))
            if (e!=ee && !mesh.is_boundary(ee)) {
              const auto v2 = mesh.opposite(ee);
              if (v2 != vd) {
                const auto x1 = X[mesh.dst(ee)],
                           x2 = X[v2];
                const auto n0 = cross(x2-x1,xs-x1),
                           n1 = cross(x2-x1,xd-x1);
                if (sign_sqr(dot(n0,n1)) < sign_sqr_min_cos*sqr_magnitude(n0)*sqr_magnitude(n1))
                  goto bad;
              }
            }

        // Collapse vs onto vd, then update the heap
        mesh.unsafe_collapse(e);
        if (mesh.n_vertices() <= min_vertices)
          break;
        update(vd);
        for (const auto e : mesh.outgoing(vd))
          update(mesh.dst(e));
      }
    }
    bad:;
  }
}

Tuple<Ref<const TriangleTopology>,Field<const TV,VertexId>>
decimate(const TriangleTopology& mesh, RawField<const TV,VertexId> X,
         const T distance, const T max_angle, const int min_vertices, const T boundary_distance) {
  const auto rmesh = mesh.mutate();
  const auto rX = X.copy();
  decimate_inplace(rmesh,rX,distance,max_angle,min_vertices,boundary_distance);
  return Tuple<Ref<const TriangleTopology>,Field<const TV,VertexId>>(rmesh,rX);
}

}
using namespace geode;

void wrap_decimate() {
  GEODE_FUNCTION(decimate)
  GEODE_FUNCTION(decimate_inplace)
}
<commit_msg>pull quadrics out to separate class<commit_after>// Quadric-based mesh decimation

#include <geode/mesh/decimate.h>
#include <geode/python/wrap.h>
#include <geode/structure/Heap.h>
#include <geode/mesh/quadric.h>

namespace geode {

typedef real T;
typedef Vector<T,3> TV;

namespace {
// Binary heap of potential collapses
struct Heap : public HeapBase<Heap>, public Noncopyable {
  typedef HeapBase<Heap> Base;
  Array<Tuple<VertexId,T,VertexId>> heap; // src,badness,dst
  Field<int,VertexId> inv_heap;

  Heap(const int nv)
    : inv_heap(nv,uninit) {
    inv_heap.flat.fill(-1);
  }

  int size() const {
    return heap.size();
  }

  bool first(const int i, const int j) const {
    return heap[i].y <= heap[j].y;
  }

  void swap(const int i, const int j) {
    std::swap(heap[i],heap[j]);
    inv_heap[heap[i].x] = i;
    inv_heap[heap[j].x] = j;
  }

  Vector<VertexId,2> pop() {
    const auto e = heap[0];
    inv_heap[e.x] = -1;
    const auto p = heap.pop();
    if (size()) {
      heap[0] = p;
      inv_heap[heap[0].x] = 0;
      Base::move_downward(0);
    }
    return vec(e.x,e.z);
  }

  void set(const VertexId v, const T q, const VertexId dst) {
    const auto entry = tuple(v,q,dst);
    int i = inv_heap[v];
    if (i < 0)
      i = heap.append(entry);
    else
      heap[i] = entry;
    Base::move_up_or_down(i);
  }

  void erase(const VertexId v) {
    int& i = inv_heap[v];
    if (i >= 0) {
      const auto p = heap.pop();
      if (i < size()) {
        heap[i] = p;
        inv_heap[p.x] = i;
        Base::move_up_or_down(i);
      }
      i = -1;
    }
  }
};
}

void decimate_inplace(MutableTriangleTopology& mesh, RawField<TV,VertexId> X,
                      const T distance, const T max_angle, const int min_vertices, const T boundary_distance) {
  if (mesh.n_vertices() <= min_vertices)
    return;
  const T area = sqr(distance);
  const T sign_sqr_min_cos = sign_sqr(max_angle > .99*pi ? -1 : cos(max_angle));

  // Finds the best edge to collapse v along.  Returns (q(e),dst(e)).
  const auto best_collapse = [&mesh,X](const VertexId v) {
    Quadric q = compute_quadric(mesh,X,v);

    // Find the best edge, ignoring normal constraints
    T min_q = inf;
    HalfedgeId min_e;
    for (const auto e : mesh.outgoing(v)) {
      const T qx = q(X[mesh.dst(e)]);
      if (min_q > qx) {
        min_q = qx;
        min_e = e;
      }
    }
    return tuple(min_q,mesh.dst(min_e));
  };

  // Initialize quadrics and heap
  Heap heap(mesh.n_vertices_);
  for (const auto v : mesh.vertices()) {
    const auto qe = best_collapse(v);
    if (qe.x <= area)
      heap.inv_heap[v] = heap.heap.append(tuple(v,qe.x,qe.y));
  }
  heap.make();

  // Update the quadric information for a vertex
  const auto update = [&heap,best_collapse,area](const VertexId v) {
    const auto qe = best_collapse(v);
    if (qe.x <= area)
      heap.set(v,qe.x,qe.y);
    else
      heap.erase(v);
  };

  // Repeatedly collapse the best vertex
  while (heap.size()) {
    const auto v = heap.pop();

    // Do these vertices still exist?
    if (mesh.valid(v.x) && mesh.valid(v.y)) {
      const auto e = mesh.halfedge(v.x,v.y);

      // Is the collapse invalid?
      if (e.valid() && mesh.is_collapse_safe(e)) {
        const auto vs = mesh.src(e),
                   vd = mesh.dst(e);
        const auto xs = X[vs],
                   xd = X[vd];

        // Are we moving a boundary vertex too far from its two boundary lines?
        {
          const auto b = mesh.halfedge(vs);
          if (mesh.is_boundary(b)) {
            const auto x0 = X[mesh.dst(b)],
                       x1 = X[mesh.src(mesh.prev(b))];
            if (   line_point_distance(simplex(xs,x0),xd) > boundary_distance
                || line_point_distance(simplex(xs,x1),xd) > boundary_distance)
              goto bad;
          }
        }

        // Do the normals change too much?
        if (sign_sqr_min_cos > -1)
          for (const auto ee : mesh.outgoing(vs))
            if (e!=ee && !mesh.is_boundary(ee)) {
              const auto v2 = mesh.opposite(ee);
              if (v2 != vd) {
                const auto x1 = X[mesh.dst(ee)],
                           x2 = X[v2];
                const auto n0 = cross(x2-x1,xs-x1),
                           n1 = cross(x2-x1,xd-x1);
                if (sign_sqr(dot(n0,n1)) < sign_sqr_min_cos*sqr_magnitude(n0)*sqr_magnitude(n1))
                  goto bad;
              }
            }

        // Collapse vs onto vd, then update the heap
        mesh.unsafe_collapse(e);
        if (mesh.n_vertices() <= min_vertices)
          break;
        update(vd);
        for (const auto e : mesh.outgoing(vd))
          update(mesh.dst(e));
      }
    }
    bad:;
  }
}

Tuple<Ref<const TriangleTopology>,Field<const TV,VertexId>>
decimate(const TriangleTopology& mesh, RawField<const TV,VertexId> X,
         const T distance, const T max_angle, const int min_vertices, const T boundary_distance) {
  const auto rmesh = mesh.mutate();
  const auto rX = X.copy();
  decimate_inplace(rmesh,rX,distance,max_angle,min_vertices,boundary_distance);
  return Tuple<Ref<const TriangleTopology>,Field<const TV,VertexId>>(rmesh,rX);
}

}
using namespace geode;

void wrap_decimate() {
  GEODE_FUNCTION(decimate)
  GEODE_FUNCTION(decimate_inplace)
}
<|endoftext|>


<commit_before>//=====================================================================//
/*!	@file
	@brief	デジタル・マイク制御 (R5F100ECA) 40ピン @n
			ROM: 32K, RAM: @n
			P15: green LED @n
			P16: red LED @n
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2017 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RL78/blob/master/LICENSE
*/
//=====================================================================//
#include "common/renesas.hpp"
#include "common/port_utils.hpp"
#include "common/fifo.hpp"
#include "common/uart_io.hpp"
#include "common/adc_io.hpp"
#include "common/format.hpp"
#include "common/iica_io.hpp"
#include "common/itimer.hpp"
#include "common/flash_io.hpp"
#include "common/command.hpp"

#include "sw.hpp"

namespace {

	typedef device::itimer<uint8_t> ITM;
	ITM		itm_;

	// UART1 の定義（SAU2、SAU3）
	typedef utils::fifo<uint8_t, 64> BUFFER;
	typedef device::uart_io<device::SAU00, device::SAU01, BUFFER, BUFFER> UART0;
	typedef device::uart_io<device::SAU02, device::SAU03, BUFFER, BUFFER> UART1;
	UART0	uart0_;
//	UART1	uart1_;

	typedef device::iica_io<device::IICA0> IICA;
	IICA 	iica_;

	// 最終チャネル番号＋１を設定
	typedef device::adc_io<1, utils::null_task> ADC;
	ADC 	adc_;

	typedef device::flash_io FLASH;
	FLASH	flash_;

//	utils::command<64> command_;

	// MIC 切り替え、入力定義
	typedef device::PORT<device::port_no::P12, device::bitpos::B2> MIC_SW1;
	typedef device::PORT<device::port_no::P12, device::bitpos::B1> MIC_SW2;
	utils::sw2<MIC_SW1, MIC_SW2> sw2_;

	// CH 設定、入力定義
	typedef device::PORT<device::port_no::P2,  device::bitpos::B1> CH_SW1;
	typedef device::PORT<device::port_no::P2,  device::bitpos::B0> CH_SW2;
	typedef device::PORT<device::port_no::P0,  device::bitpos::B1> CH_SW3;
	typedef device::PORT<device::port_no::P0,  device::bitpos::B0> CH_SW4;
	typedef device::PORT<device::port_no::P12, device::bitpos::B0> CH_SW5;
	utils::sw5<CH_SW1, CH_SW2, CH_SW3, CH_SW4, CH_SW5> sw5_;

	// Volume +/-
	typedef device::PORT<device::port_no::P3,  device::bitpos::B1> VOL_UP;
	typedef device::PORT<device::port_no::P7,  device::bitpos::B3> VOL_DN;
	utils::sw2<VOL_UP, VOL_DN> vol_;
}

extern "C" {

	void sci_putch(char ch)
	{
		uart0_.putch(ch);
	}

	void sci_puts(const char* str)
	{
		uart0_.puts(str);
	}

	char sci_getch(void)
	{
		return uart0_.getch();
	}

	uint16_t sci_length()
	{
		return uart0_.recv_length();
	}

	INTERRUPT_FUNC void UART0_TX_intr(void)
	{
		uart0_.send_task();
	}

	INTERRUPT_FUNC void UART0_RX_intr(void)
	{
		uart0_.recv_task();
	}

	INTERRUPT_FUNC void UART0_ER_intr(void)
	{
		uart0_.error_task();
	}

	INTERRUPT_FUNC void ADC_intr(void)
	{
		adc_.task();
	}

	INTERRUPT_FUNC void ITM_intr(void)
	{
		itm_.task();
	}
};

int main(int argc, char* argv[])
{
	using namespace device;

//	utils::port::pullup_all();  ///< 安全の為、全ての入力をプルアップ

	// itimer の開始
	{
		uint8_t intr_level = 1;
		itm_.start(60, intr_level);
	}

	// UART0 の開始
	{
		uint8_t intr_level = 1;
		uart0_.start(19200, intr_level);
	}

	// IICA(I2C) の開始
	{
		uint8_t intr_level = 0;
//		if(!iica_.start(IICA::speed::fast, intr_level)) {
		if(!iica_.start(IICA::speed::standard, intr_level)) {
			utils::format("IICA start error (%d)\n") % static_cast<uint32_t>(iica_.get_last_error());
		}
	}

	// A/D の開始
	{
		device::PM2.B0 = 1;
		uint8_t intr_level = 1;  // 割り込み設定
		adc_.start(ADC::REFP::VDD, ADC::REFM::VSS, intr_level);
	}

	// data flash の開始
	{
	}

	ADPC = 0x01; // A/D input All digital port

	PM2.B3 = 0;  // POWER CTRL (OUTPUT)
	P2.B3  = 1;  // Active high (ON)

	PM1.B5 = 0;  // LED G output
	PM1.B6 = 0;  // LED R output

	sw2_.start();
	PMC12 = 0b11111110;  // setup P12_0: digital port
	sw5_.start();

	vol_.start();

///	utils::format("Start Digital MIC\n");

	uint8_t cnt = 0;
	uint8_t vol = 0;
	while(1) {
		itm_.sync();

		vol_.service();
		if(vol_.positive() & 1) {
			if(vol < 8) {
				++vol;
			}
		}
		if(vol_.positive() & 2) {
			if(vol > 0) {
				--vol;
			}
		}

		if(uart0_.recv_length() > 0) {
			char ch = uart0_.getch();

			if(ch == 'C') {  // CH-SW (0 to 31)
				auto n = sw5_.get();
				uart0_.putch((n / 10) + '0');
				uart0_.putch((n % 10) + '0');
				uart0_.putch('\n');
			} else if(ch == 'M') {  // MIC-SW (0 to 3)
				auto n = sw2_.get();
				uart0_.putch((n % 10) + '0');
				uart0_.putch('\n');
			} else if(ch == 'F') {  // 混信フラグ (0 to 1)
				uart0_.putch('0');
				uart0_.putch('\n');
			} else if(ch == 'V') {  // ボリューム値
				uart0_.putch('0' + vol);
				uart0_.putch('\n');
			}
		}

		if(cnt >= 20) {
			cnt = 0;
		}
		if(cnt < 10) {
			P1.B5 = 1;
			P1.B6 = 0;
		} else {
			P1.B5 = 0;
			P1.B6 = 1;
		}
		++cnt;
	}
}
<commit_msg>update<commit_after>//=====================================================================//
/*!	@file
	@brief	デジタル・マイク制御 (R5F100ECA) 40ピン @n
			ROM: 32K, RAM: @n
			P15: green LED @n
			P16: red LED @n
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2017 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RL78/blob/master/LICENSE
*/
//=====================================================================//
#include "common/renesas.hpp"
#include "common/port_utils.hpp"
#include "common/fifo.hpp"
#include "common/uart_io.hpp"
#include "common/adc_io.hpp"
#include "common/format.hpp"
#include "common/iica_io.hpp"
#include "common/itimer.hpp"
#include "common/flash_io.hpp"
#include "common/command.hpp"

#include "sw.hpp"
#include "serial.hpp"

namespace {

	static const uint16_t VERSION = 15;

	typedef device::itimer<uint8_t> ITM;
	ITM		itm_;

	// UART1 の定義（SAU2、SAU3）
	typedef utils::fifo<uint8_t, 64> BUFFER;
	typedef device::uart_io<device::SAU00, device::SAU01, BUFFER, BUFFER> UART0;
	typedef device::uart_io<device::SAU02, device::SAU03, BUFFER, BUFFER> UART1;
	UART0	uart0_;
	UART1	uart1_;

	typedef device::iica_io<device::IICA0> IICA;
	IICA 	iica_;

	// 最終チャネル番号＋１を設定
	typedef device::adc_io<1, utils::null_task> ADC;
	ADC 	adc_;

	typedef device::flash_io FLASH;
	FLASH	flash_;

	// MIC 切り替え、入力定義
	typedef device::PORT<device::port_no::P12, device::bitpos::B2> MIC_SW1;
	typedef device::PORT<device::port_no::P12, device::bitpos::B1> MIC_SW2;
	typedef utils::sw2<MIC_SW1, MIC_SW2> SW2;
	SW2		sw2_;

	// CH 設定、入力定義
	typedef device::PORT<device::port_no::P2,  device::bitpos::B1> CH_SW1;
	typedef device::PORT<device::port_no::P2,  device::bitpos::B6> CH_SW2;  // P20/AIN0 --> P26
	typedef device::PORT<device::port_no::P2,  device::bitpos::B5> CH_SW3;
	typedef device::PORT<device::port_no::P2,  device::bitpos::B4> CH_SW4;
	typedef device::PORT<device::port_no::P12, device::bitpos::B0> CH_SW5;
	typedef utils::sw5<CH_SW1, CH_SW2, CH_SW3, CH_SW4, CH_SW5> SW5;
	SW5		sw5_;

	// Volume +/-
	typedef device::PORT<device::port_no::P3,  device::bitpos::B1> VOL_UP;
	typedef device::PORT<device::port_no::P7,  device::bitpos::B3> VOL_DN;
	utils::sw2<VOL_UP, VOL_DN> vol_;

	utils::command<64> command_;

	typedef dmic::serial<UART0, SW5, SW2> SERIAL;
	SERIAL	serial_(uart0_, sw5_, sw2_);
}

extern "C" {

	void sci_putch(char ch)
	{
		uart1_.putch(ch);
	}

	void sci_puts(const char* str)
	{
		uart1_.puts(str);
	}

	char sci_getch(void)
	{
		return uart1_.getch();
	}

	uint16_t sci_length()
	{
		return uart1_.recv_length();
	}

	INTERRUPT_FUNC void UART0_TX_intr(void)
	{
		uart0_.send_task();
	}

	INTERRUPT_FUNC void UART0_RX_intr(void)
	{
		uart0_.recv_task();
	}

	INTERRUPT_FUNC void UART0_ER_intr(void)
	{
		uart0_.error_task();
	}

	INTERRUPT_FUNC void UART1_TX_intr(void)
	{
		uart1_.send_task();
	}

	INTERRUPT_FUNC void UART1_RX_intr(void)
	{
		uart1_.recv_task();
	}

	INTERRUPT_FUNC void UART1_ER_intr(void)
	{
		uart1_.error_task();
	}

	INTERRUPT_FUNC void ADC_intr(void)
	{
		adc_.task();
	}

	INTERRUPT_FUNC void ITM_intr(void)
	{
		itm_.task();
	}
};

int main(int argc, char* argv[])
{
	using namespace device;

//	utils::port::pullup_all();  ///< 安全の為、全ての入力をプルアップ

	// itimer の開始
	{
		uint8_t intr_level = 2;
		itm_.start(60, intr_level);
	}

	// UART1 の開始
	{
		uint8_t intr_level = 1;
		// ４０ピン版、セカンドポート選択
		bool sec = true;
		uart1_.start(115200, intr_level, sec);
	}

	ADPC = 0x01; // A/D input All digital port

//	PM2.B3 = 0;  // POWER CTRL (OUTPUT)
//	P2.B3  = 1;  // Active high (ON)

	// IICA(I2C) の開始
	{
		uint8_t intr_level = 0;
///		if(!iica_.start(IICA::speed::fast, intr_level)) {
		if(!iica_.start(IICA::speed::standard, intr_level)) {
			utils::format("IICA start error (%d)\n") % static_cast<uint32_t>(iica_.get_last_error());
		}
	}

	// A/D の開始
	{
		device::PM2.B0 = 1;
		uint8_t intr_level = 1;  // 割り込み設定
		adc_.start(ADC::REFP::VDD, ADC::REFM::VSS, intr_level);
	}

	// data flash の開始
	{
	}

	PM1.B5 = 0;  // LED G output
	PM1.B6 = 0;  // LED R output

	vol_.start();

	serial_.start();

	utils::format("Start Digital MIC Version: %d.%02d\n") % (VERSION / 100) % (VERSION % 100);

	command_.set_prompt("# ");

	uint8_t cnt = 0;
	while(1) {
		itm_.sync();

		// コマンド入力と、コマンド解析
		if(command_.service()) {
			auto n = command_.get_words();
			if(command_.cmp_word(0, "sw2")) {
				utils::format("SW2: %02b\n") % static_cast<uint16_t>(sw2_.get());
			} else if(command_.cmp_word(0, "sw5")) {
				utils::format("SW5: %05b\n") % static_cast<uint16_t>(sw5_.get());
			} else if(command_.cmp_word(0, "vol")) {
				utils::format("volume: %d\n") % serial_.get_volume();
			} else if(command_.cmp_word(0, "help") || command_.cmp_word(0, "?")) {
				utils::format("sw2   list SW2 value\n");
				utils::format("sw5   list SW5 value\n");
				utils::format("vol   list VOL value\n");
			} else {
				const char* p = command_.get_command();
				if(p[0]) {
					utils::format("command error: '%s'\n") % p;
				}
			}
		}

		vol_.service();

		bool volp = false;
		if(vol_.positive() & 1) {
			volp = true;
		}
		bool volm = false;
		if(vol_.positive() & 2) {
			volm = true;
		}
		serial_.service(volp, volm);

		if(volp) {
			utils::format("V+: %d\n") % serial_.get_volume();
		}
		if(volm) {
			utils::format("V-: %d\n") % serial_.get_volume();
		}

		if(cnt >= 20) {
			cnt = 0;
		}
		if(cnt < 10) {
			P1.B5 = 1;
			P1.B6 = 0;
		} else {
			P1.B5 = 0;
			P1.B6 = 1;
		}
		++cnt;
	}
}
<|endoftext|>