<commit_before>
#include <utility>    // std::move
#include <string>     // std::string
#include <iostream>   // std::ostream
#include <shark.hpp>

using namespace std;
using namespace shark;

class tester {
	ostream& out;
	string current;
	long fails;
	long tests;
	long curfails;
	long curchecks;

public:
	tester(ostream& out): out(out), fails(0), tests(0) { }
	~tester() { }
	void begin_test(std::string&& name);
	void end_test();
	void add_result(test_result r);
};

void tester::begin_test(std::string&& name) {
	current = move(name);
	curfails = 0;
	curchecks = 0;
	if(world().procid == 0)
		out << "Begin test " << current << endl;
	world().sync();
}

void tester::end_test() {
	world().sync();
	bool fail = curfails > 0;
	tests++;
	if(fail) fails++;
	if(world().procid == 0) {
		out << "End test " << current << ": ";
		if(!fail)
			out << "Success (" << curchecks << " checks)" << endl;
		else
			out << "FAILED (" << curfails << " of " << curchecks << " checks failed)" << endl;
	}
}

void tester::add_result(test_result r) {
	curchecks += r.checks;
	curfails += r.fails;
}

using namespace shark::ndim;

template<int ndim, typename S>
class suite1 {

	const Domain<ndim>& dom;
	const S src;

public:
	suite1(const Domain<ndim>& dom, const S& src): dom(dom), src(src) { }
	~suite1() { }
	void test_basic(tester& t);
	void test_ghost(tester& t);
	void test_ghost_corner(tester& t);
	void test_ghost_periodic(tester& t);
	void run(tester& t) {
		test_basic(t);
		test_ghost(t);
		test_ghost_corner(t);
		test_ghost_periodic(t);
	}
};

template<int ndim, typename S>
suite1<ndim,S> make_suite1(const Domain<ndim>& dom, const S& src) {
	return suite1<ndim,S>(dom, src);
}

template<int ndim, typename S>
void suite1<ndim,S>::test_basic(tester& t) {
	t.begin_test("test_basic");
	{
		GlobalArray<ndim,double> ga(dom);
		ga = src;
		t.add_result(check(ga == src));
	}
	t.end_test();
}

template<int ndim, typename S>
void suite1<ndim,S>::test_ghost(tester& t) {
	t.begin_test("test_ghost");
	coords<ndim> gw;
	for(int d = 0; d < ndim; d++)
		gw[d] = 2;
	coords_range<ndim> inner = dom.total();
	for(int d = 0; d < ndim; d++) {
		inner.lower[d] += gw[d];
		inner.upper[d] -= gw[d];
	}
	{
		GlobalArray<ndim,double> ga(dom, gw);
		ga = src;
		ga.update();
		t.add_result(check(inner, ga == src));
		for(int d = 0; d < ndim; d++) {
			coords<ndim> sd = {{}}, su = {{}};
			sd[d] = -1;
			su[d] = 1;
			t.add_result(check(inner,
				shift(ga,sd) == shift(src,sd) &&
				shift(ga,su) == shift(src,su) &&
				shift(ga,sd+sd) == shift(src,sd+sd) &&
				shift(ga,su+su) == shift(src,su+su)));
		}
	}
	t.end_test();
}

template<int ndim, typename S>
void suite1<ndim,S>::test_ghost_corner(tester& t) {
	t.begin_test("test_ghost_corner");
	coords<ndim> gw;
	for(int d = 0; d < ndim; d++)
		gw[d] = 2;
	coords_range<ndim> inner = dom.total();
	for(int d = 0; d < ndim; d++) {
		inner.lower[d] += gw[d];
		inner.upper[d] -= gw[d];
	}
	{
		GlobalArray<ndim,double> ga(dom, gw, true);
		ga = src;
		ga.update();
		t.add_result(check(inner, ga == src));
		t.add_result(check(inner, shift(ga,gw) == shift(src,gw) && shift(ga,-gw) == shift(src,-gw)));
	}
	t.end_test();
}

template<int ndim, typename S>
void suite1<ndim,S>::test_ghost_periodic(tester& t) {
	t.begin_test("test_ghost_periodic");
	coords<ndim> gw;
	for(int d = 0; d < ndim; d++)
		gw[d] = 2;
	typename GlobalArray<ndim,double>::bounds bd;
	for(int d = 0; d < ndim; d++)
		bd[d] = Boundary<ndim,double>::periodic();
	{
		GlobalArray<ndim,double> ga(dom, gw, false, bd);
		ga = src;
		ga.update();
		t.add_result(check(dom.total(), ga == src));
		for(int d = 0; d < ndim; d++) {
			coords<ndim> sd = {{}}, su = {{}};
			sd[d] = -1;
			su[d] = 1;
			t.add_result(check(dom.total(),
				shift(ga,sd) == shift(src,sd,dom.total()) &&
				shift(ga,su) == shift(src,su,dom.total()) &&
				shift(ga,sd+sd) == shift(src,sd+sd,dom.total()) &&
				shift(ga,su+su) == shift(src,su+su,dom.total())));
		}
	}
	t.end_test();
}

int main(int argc, char* argv[]) {
	Init(&argc, &argv);
	SetupThreads();
	tester t(cerr);
	{
		coords<3> n = {{100,100,100}};
		Domain<3> dom(world(), n);
		auto f = sin(coord_val<0>(dom, 2*M_PI)) * cos(coord_val<1>(dom, 2*M_PI));
		make_suite1(dom, f).run(t);
	}
	Finalize();
}
<commit_msg>Move test<commit_after>
#include <utility>    // std::move
#include <string>     // std::string
#include <iostream>   // std::ostream
#include <shark.hpp>

using namespace std;
using namespace shark;

class tester {
	ostream& out;
	string current;
	long fails;
	long tests;
	long curfails;
	long curchecks;

public:
	tester(ostream& out): out(out), fails(0), tests(0) { }
	~tester() { }
	void begin_test(std::string&& name);
	void end_test();
	void add_result(test_result r);
};

void tester::begin_test(std::string&& name) {
	current = move(name);
	curfails = 0;
	curchecks = 0;
	if(world().procid == 0)
		out << "Begin test " << current << endl;
	world().sync();
}

void tester::end_test() {
	world().sync();
	bool fail = curfails > 0;
	tests++;
	if(fail) fails++;
	if(world().procid == 0) {
		out << "End test " << current << ": ";
		if(!fail)
			out << "Success (" << curchecks << " checks)" << endl;
		else
			out << "FAILED (" << curfails << " of " << curchecks << " checks failed)" << endl;
	}
}

void tester::add_result(test_result r) {
	curchecks += r.checks;
	curfails += r.fails;
}

using namespace shark::ndim;

template<int ndim, typename S>
class suite1 {

	const Domain<ndim>& dom;
	const S src;

public:
	suite1(const Domain<ndim>& dom, const S& src): dom(dom), src(src) { }
	~suite1() { }
	void test_basic(tester& t);
	void test_move(tester& t);
	void test_ghost(tester& t);
	void test_ghost_corner(tester& t);
	void test_ghost_periodic(tester& t);
	void run(tester& t) {
		test_basic(t);
		test_move(t);
		test_ghost(t);
		test_ghost_corner(t);
		test_ghost_periodic(t);
	}
};

template<int ndim, typename S>
suite1<ndim,S> make_suite1(const Domain<ndim>& dom, const S& src) {
	return suite1<ndim,S>(dom, src);
}

template<int ndim, typename S>
void suite1<ndim,S>::test_basic(tester& t) {
	t.begin_test("test_basic");
	{
		GlobalArray<ndim,double> ga(dom);
		ga = src;
		t.add_result(check(ga == src));
	}
	t.end_test();
}

template<int ndim, typename S>
void suite1<ndim,S>::test_move(tester& t) {
	t.begin_test("test_move");
	{
		GlobalArray<ndim,double> ga(dom);
		ga = constant(dom, 0.0);
		{
			GlobalArray<ndim,double> tmp(dom);
			tmp = src;
			ga = std::move(tmp);
		}
		t.add_result(check(ga == src));
	}
	t.end_test();
}

template<int ndim, typename S>
void suite1<ndim,S>::test_ghost(tester& t) {
	t.begin_test("test_ghost");
	coords<ndim> gw;
	for(int d = 0; d < ndim; d++)
		gw[d] = 2;
	coords_range<ndim> inner = dom.total();
	for(int d = 0; d < ndim; d++) {
		inner.lower[d] += gw[d];
		inner.upper[d] -= gw[d];
	}
	{
		GlobalArray<ndim,double> ga(dom, gw);
		ga = src;
		ga.update();
		t.add_result(check(inner, ga == src));
		for(int d = 0; d < ndim; d++) {
			coords<ndim> sd = {{}}, su = {{}};
			sd[d] = -1;
			su[d] = 1;
			t.add_result(check(inner,
				shift(ga,sd) == shift(src,sd) &&
				shift(ga,su) == shift(src,su) &&
				shift(ga,sd+sd) == shift(src,sd+sd) &&
				shift(ga,su+su) == shift(src,su+su)));
		}
	}
	t.end_test();
}

template<int ndim, typename S>
void suite1<ndim,S>::test_ghost_corner(tester& t) {
	t.begin_test("test_ghost_corner");
	coords<ndim> gw;
	for(int d = 0; d < ndim; d++)
		gw[d] = 2;
	coords_range<ndim> inner = dom.total();
	for(int d = 0; d < ndim; d++) {
		inner.lower[d] += gw[d];
		inner.upper[d] -= gw[d];
	}
	{
		GlobalArray<ndim,double> ga(dom, gw, true);
		ga = src;
		ga.update();
		t.add_result(check(inner, ga == src));
		t.add_result(check(inner, shift(ga,gw) == shift(src,gw) && shift(ga,-gw) == shift(src,-gw)));
	}
	t.end_test();
}

template<int ndim, typename S>
void suite1<ndim,S>::test_ghost_periodic(tester& t) {
	t.begin_test("test_ghost_periodic");
	coords<ndim> gw;
	for(int d = 0; d < ndim; d++)
		gw[d] = 2;
	typename GlobalArray<ndim,double>::bounds bd;
	for(int d = 0; d < ndim; d++)
		bd[d] = Boundary<ndim,double>::periodic();
	{
		GlobalArray<ndim,double> ga(dom, gw, false, bd);
		ga = src;
		ga.update();
		t.add_result(check(dom.total(), ga == src));
		for(int d = 0; d < ndim; d++) {
			coords<ndim> sd = {{}}, su = {{}};
			sd[d] = -1;
			su[d] = 1;
			t.add_result(check(dom.total(),
				shift(ga,sd) == shift(src,sd,dom.total()) &&
				shift(ga,su) == shift(src,su,dom.total()) &&
				shift(ga,sd+sd) == shift(src,sd+sd,dom.total()) &&
				shift(ga,su+su) == shift(src,su+su,dom.total())));
		}
	}
	t.end_test();
}

int main(int argc, char* argv[]) {
	Init(&argc, &argv);
	SetupThreads();
	tester t(cerr);
	{
		coords<3> n = {{100,100,100}};
		Domain<3> dom(world(), n);
		auto f = sin(coord_val<0>(dom, 2*M_PI)) * cos(coord_val<1>(dom, 2*M_PI));
		make_suite1(dom, f).run(t);
	}
	Finalize();
}
<|endoftext|>


<commit_before>// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "shell/in_process_native_runner.h"

#include "base/bind.h"
#include "base/callback_helpers.h"
#include "base/location.h"
#include "base/message_loop/message_loop_proxy.h"
#include "base/threading/platform_thread.h"
#include "shell/native_application_support.h"

namespace mojo {
namespace shell {

InProcessNativeRunner::InProcessNativeRunner(Context* context)
    : cleanup_(NativeApplicationCleanup::DONT_DELETE), app_library_(nullptr) {
}

InProcessNativeRunner::~InProcessNativeRunner() {
  // It is important to let the thread exit before unloading the DSO (when
  // app_library_ is destructed), because the library may have registered
  // thread-local data and destructors to run on thread termination.
  if (thread_) {
    DCHECK(thread_->HasBeenStarted());
    DCHECK(!thread_->HasBeenJoined());
    thread_->Join();
  }
}

void InProcessNativeRunner::Start(
    const base::FilePath& app_path,
    NativeApplicationCleanup cleanup,
    InterfaceRequest<Application> application_request,
    const base::Closure& app_completed_callback) {
  app_path_ = app_path;
  cleanup_ = cleanup;

  DCHECK(!application_request_.is_pending());
  application_request_ = application_request.Pass();

  DCHECK(app_completed_callback_runner_.is_null());
  app_completed_callback_runner_ =
      base::Bind(&base::TaskRunner::PostTask, base::MessageLoopProxy::current(),
                 FROM_HERE, app_completed_callback);

  DCHECK(!thread_);
  thread_.reset(new base::DelegateSimpleThread(this, "app_thread"));
  thread_->Start();
}

void InProcessNativeRunner::Run() {
  DVLOG(2) << "Loading/running Mojo app in process from library: "
           << app_path_.value()
           << " thread id=" << base::PlatformThread::CurrentId();

  // TODO(vtl): ScopedNativeLibrary doesn't have a .get() method!
  base::NativeLibrary app_library = LoadNativeApplication(app_path_, cleanup_);
  app_library_.Reset(app_library);
  RunNativeApplication(app_library, application_request_.Pass());
  app_completed_callback_runner_.Run();
  app_completed_callback_runner_.Reset();
}

scoped_ptr<NativeRunner> InProcessNativeRunnerFactory::Create(
    const Options& options) {
  return make_scoped_ptr(new InProcessNativeRunner(context_));
}

}  // namespace shell
}  // namespace mojo
<commit_msg>Give in process native runner-created threads useful names<commit_after>// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "shell/in_process_native_runner.h"

#include "base/bind.h"
#include "base/callback_helpers.h"
#include "base/location.h"
#include "base/message_loop/message_loop_proxy.h"
#include "base/threading/platform_thread.h"
#include "shell/native_application_support.h"

namespace mojo {
namespace shell {

InProcessNativeRunner::InProcessNativeRunner(Context* context)
    : cleanup_(NativeApplicationCleanup::DONT_DELETE), app_library_(nullptr) {
}

InProcessNativeRunner::~InProcessNativeRunner() {
  // It is important to let the thread exit before unloading the DSO (when
  // app_library_ is destructed), because the library may have registered
  // thread-local data and destructors to run on thread termination.
  if (thread_) {
    DCHECK(thread_->HasBeenStarted());
    DCHECK(!thread_->HasBeenJoined());
    thread_->Join();
  }
}

void InProcessNativeRunner::Start(
    const base::FilePath& app_path,
    NativeApplicationCleanup cleanup,
    InterfaceRequest<Application> application_request,
    const base::Closure& app_completed_callback) {
  app_path_ = app_path;
  cleanup_ = cleanup;

  DCHECK(!application_request_.is_pending());
  application_request_ = application_request.Pass();

  DCHECK(app_completed_callback_runner_.is_null());
  app_completed_callback_runner_ =
      base::Bind(&base::TaskRunner::PostTask, base::MessageLoopProxy::current(),
                 FROM_HERE, app_completed_callback);

  DCHECK(!thread_);
  std::string thread_name = "app_thread_" + app_path_.BaseName().AsUTF8Unsafe();
  thread_.reset(new base::DelegateSimpleThread(this, thread_name));
  thread_->Start();
}

void InProcessNativeRunner::Run() {
  DVLOG(2) << "Loading/running Mojo app in process from library: "
           << app_path_.value()
           << " thread id=" << base::PlatformThread::CurrentId();

  // TODO(vtl): ScopedNativeLibrary doesn't have a .get() method!
  base::NativeLibrary app_library = LoadNativeApplication(app_path_, cleanup_);
  app_library_.Reset(app_library);
  RunNativeApplication(app_library, application_request_.Pass());
  app_completed_callback_runner_.Run();
  app_completed_callback_runner_.Reset();
}

scoped_ptr<NativeRunner> InProcessNativeRunnerFactory::Create(
    const Options& options) {
  return make_scoped_ptr(new InProcessNativeRunner(context_));
}

}  // namespace shell
}  // namespace mojo
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: sb.hxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-07 21:01:48 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _SB_HXX
#define _SB_HXX

#ifndef _SBERRORS_HXX
 #include "sberrors.hxx"
#endif

#include <sbdef.hxx>
#include <sbmeth.hxx>
#include <sbmod.hxx>
#include <sbprop.hxx>
#include <sbstar.hxx>

#endif
<commit_msg>INTEGRATION: CWS vgbugs07 (1.2.206); FILE MERGED 2007/06/04 13:22:13 vg 1.2.206.1: #i76605# Remove -I .../inc/module hack introduced by hedaburemove01<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: sb.hxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: hr $ $Date: 2007-06-27 14:10:46 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _SB_HXX
#define _SB_HXX

#ifndef _SBERRORS_HXX
 #include <basic/sberrors.hxx>
#endif

#include <basic/sbdef.hxx>
#include <basic/sbmeth.hxx>
#include <basic/sbmod.hxx>
#include <basic/sbprop.hxx>
#include <basic/sbstar.hxx>

#endif
<|endoftext|>


<commit_before>#include <nan.h>
#include <fstream>
#include "hive.h"

using namespace v8;

static uv_key_t isolate_cache_key;
static uv_key_t context_cache_key;
static uv_once_t key_guard;

static std::ifstream f("node_modules/babel-core/browser.js");
static std::string babel(
    (std::istreambuf_iterator<char>(f)), std::istreambuf_iterator<char>());

static void create_keys() {
  (void) uv_key_create(&isolate_cache_key);
  (void) uv_key_create(&context_cache_key);
}

static Persistent<Context>* get_context(Isolate* isolate) {
  Persistent<Context>* context =
    (Persistent<Context> *) uv_key_get(&context_cache_key);

  if (context == NULL) {
    Local<Context> ctx = Context::New(isolate);
    context = new Persistent<Context>(isolate, ctx);

    Context::Scope context_scope(ctx);
    Local<Script> script = Script::Compile(
        String::NewFromUtf8(isolate, babel.c_str()));

    (void) script->Run();
    uv_key_set(&context_cache_key, context);
  }

  return context;
}

class HiveWorker : public NanAsyncWorker {
 public:
  HiveWorker(NanCallback* callback, std::string path, char* buf, size_t len)
    : NanAsyncWorker(callback), path(path), buf(buf), len(len) {}
  ~HiveWorker() {}

  // Executed inside the worker-thread.
  void Execute () {
    (void) uv_once(&key_guard, create_keys);

    Isolate* isolate = (Isolate *)uv_key_get(&isolate_cache_key);
    if (isolate == NULL) {
      isolate = Isolate::New();
      uv_key_set(&isolate_cache_key, isolate);
    }

    Locker locker(isolate);
    Isolate::Scope isolate_scope(isolate);
    HandleScope handle_scope(isolate);

    Persistent<Context>* context = get_context(isolate);
    Context::Scope context_scope(Local<Context>::New(isolate, *context));

    Local<String> source = String::NewFromUtf8(
        isolate, buf, String::kNormalString, len);

    Local<Script> script = Script::Compile(source);
    Local<Value> result = script->Run();

    res = result->IntegerValue();
    v8::Unlocker unlocker(isolate);
  }

  // Executed when the async work is complete, inside the main thread.
  void HandleOKCallback () {
    NanScope();

    Local<Value> argv[] = {
        NanNull(),
        NanNew<Number>(res)
    };

    callback->Call(2, argv);
  }

 private:
  std::string path;
  char* buf;
  size_t len;
  int64_t res;
};

NAN_METHOD(Take) {
  NanScope();

  if (args.Length() != 3) {
    NanThrowTypeError("Expected three arguments.");
    NanReturnUndefined();
  }

  if (!args[0]->IsString() || !args[2]->IsFunction()) {
    NanThrowTypeError("Received arguments of the wrong type.");
    NanReturnUndefined();
  }

  String::Utf8Value p(args[0]->ToString());
  std::string path(*p);

  char* buf = node::Buffer::Data(args[1]);
  size_t len = node::Buffer::Length(args[1]);
  NanCallback *callback = new NanCallback(args[2].As<Function>());

  NanAsyncQueueWorker(new HiveWorker(callback, path, buf, len));
  NanReturnUndefined();
}
<commit_msg>Refactor isolate creation; comments; use NAN where possible<commit_after>#include <nan.h>
#include <fstream>
#include "hive.h"

using namespace v8;

static uv_key_t isolate_cache_key;
static uv_key_t context_cache_key;
static uv_once_t key_guard;

static std::ifstream f("node_modules/babel-core/browser.js");
static std::string babel(
    (std::istreambuf_iterator<char>(f)), std::istreambuf_iterator<char>());

// Initialize libuv thread-local cache keys.
static void create_keys() {
  (void) uv_key_create(&isolate_cache_key);
  (void) uv_key_create(&context_cache_key);
}

// Returns an Isolate* from the thread-local cache, if it exists.
// Otherwise, creates and caches a new Isolate* before returning.
static Isolate* get_isolate() {
  Isolate* isolate = (Isolate *) uv_key_get(&isolate_cache_key);
  if (isolate == NULL) {
    isolate = Isolate::New();
    uv_key_set(&isolate_cache_key, isolate);
  }
  return isolate;
}

// Returns a Persistent<Context>* from the thread-local cache, if it exists.
// Otherwise, creates a new Persistent<Context>* in the given isolate, and
// evaluates the Babel bootstrap script to prepare the context for file
// transformation.
static Persistent<Context>* get_context(Isolate* isolate) {
  Persistent<Context>* context =
    (Persistent<Context> *) uv_key_get(&context_cache_key);

  if (context == NULL) {
    Local<Context> ctx = Context::New(isolate);
    context = new Persistent<Context>(isolate, ctx);

    Context::Scope context_scope(ctx);
    Local<Script> script = Script::Compile(
        String::NewFromUtf8(isolate, babel.c_str()));

    (void) script->Run();
    uv_key_set(&context_cache_key, context);
  }

  return context;
}

// Transforms the given file contents in a new v8 isolate on Node's default
// libuv thread pool, returning the result of the transformation on the main
// event loop.
class HiveWorker : public NanAsyncWorker {
 public:
  HiveWorker(NanCallback* callback, std::string path, char* buf, size_t len)
    : NanAsyncWorker(callback), path(path), buf(buf), len(len) {}
  ~HiveWorker() {}

  // Executed inside the worker-thread.
  void Execute () {
    (void) uv_once(&key_guard, create_keys);
    Isolate* isolate = get_isolate();
    Isolate::Scope isolate_scope(isolate);

    NanLocker();
    NanScope();

    Persistent<Context>* context = get_context(isolate);
    Context::Scope context_scope(Local<Context>::New(isolate, *context));

    Local<String> source = String::NewFromUtf8(
        isolate, buf, String::kNormalString, len);

    Local<Script> script = Script::Compile(source);
    Local<Value> result = script->Run();

    res = result->IntegerValue();
    NanUnlocker();
  }

  // Executed when the async work is complete, inside the main thread.
  void HandleOKCallback () {
    NanScope();

    Local<Value> argv[] = {
        NanNull(),
        NanNew<Number>(res)
    };

    callback->Call(2, argv);
  }

 private:
  std::string path;
  char* buf;
  size_t len;
  int64_t res;
};

NAN_METHOD(Take) {
  NanScope();

  if (args.Length() != 3) {
    NanThrowTypeError("Expected three arguments.");
    NanReturnUndefined();
  }

  if (!args[0]->IsString() || !args[2]->IsFunction()) {
    NanThrowTypeError("Received arguments of the wrong type.");
    NanReturnUndefined();
  }

  String::Utf8Value p(args[0]->ToString());
  std::string path(*p);

  char* buf = node::Buffer::Data(args[1]);
  size_t len = node::Buffer::Length(args[1]);
  NanCallback *callback = new NanCallback(args[2].As<Function>());

  NanAsyncQueueWorker(new HiveWorker(callback, path, buf, len));
  NanReturnUndefined();
}
<|endoftext|>


<commit_before>/* * * * * * * * * * * * *\
|*             ╔═╗ v0.4  *|
|* ╔═╦═╦═══╦═══╣ ╚═╦═╦═╗ *|
|* ║ ╔═╣ '╔╬═╗╚╣ ║ ║  '║ *|
|* ╚═╝ ╚═══╩═══╩═╩═╣ ╔═╝ *|
|* * * * * * * * * ╚═╝ * *|
|* Manipulation tool for *|
|*    ESRI Shapefiles    *|
|* * * * * * * * * * * * *|
|* http://www.npolar.no/ *|
\* * * * * * * * * * * * */

#include "polygon.hpp"
#include <algorithm>
#include <new>

namespace reshp
{
    polygon::intersection::intersection(reshp::polygon::ring* ring, reshp::polygon::ring* intersector_ring) :
        ring(ring),
        segment(NULL),
        segment_index(-1),
        intersector(intersector_ring)
    {
    }

    polygon::intersection::intersector::intersector(reshp::polygon::ring* ring) :
        ring(ring),
        segment(NULL),
        segment_index(-1)
    {
    }

    polygon::ring::ring() :
        type(polygon::ring::outer)
    {
    }

    void polygon::ring::calculate_aabb()
    {
        aabb.initialize(); // Initialize AABB with min/max extremes

        for(unsigned i = 0; i < segments.size(); ++i)
        {
            aabb.min.x = std::min(aabb.min.x, segments[i].start.x);
            aabb.min.y = std::min(aabb.min.y, segments[i].start.y);
            aabb.min.z = std::min(aabb.min.z, segments[i].start.z);

            aabb.max.x = std::max(aabb.max.x, segments[i].start.x);
            aabb.max.y = std::max(aabb.max.y, segments[i].start.y);
            aabb.max.z = std::max(aabb.max.z, segments[i].start.z);
        }
    }

    bool polygon::ring::contains(const reshp::point& point) const
    {
        bool inside = false;

        for(unsigned i = 0, j = segments.size() - 1; i < segments.size(); j = i++)
        {
            if(((segments[i].start.y > point.y) != (segments[j].start.y > point.y))
            && (point.x < (segments[j].start.x - segments[i].start.x) * (point.y - segments[i].start.y) / (segments[j].start.y - segments[i].start.y) + segments[i].start.x))
                inside = !inside;
        }

        return inside;
    }

    void polygon::ring::invert()
    {
        for(unsigned s = 0, c = segments.size(); s < c; ++s)
            if(s != (c - 1 -s))
                std::swap(segments[s], segments[c - 1 - s]);

        type = (type == inner ? outer : inner);
    }

    bool polygon::ring::inside(const reshp::polygon::ring& other) const
    {
        if(!aabb.inside(other.aabb))
            return false;

        for(unsigned i = 0; i < segments.size(); ++i)
            if(!other.contains(segments[i].start))
                return false;

        return true;
    }

    bool polygon::ring::intersects() const
    {
        for(unsigned i = 0, s = segments.size(); i < s - 2; ++i)
            for(unsigned j = i + 1; j < segments.size(); ++j)
                if(j - i > 1 && j < (s - 1) + i)
                    if(segments[i].intersects(segments[j]))
                        return true;

        return false;
    }

    bool polygon::ring::intersects(const reshp::polygon::ring& other, std::vector<reshp::polygon::intersection>* intersections) const
    {
        if(!aabb.intersects(other.aabb) && !other.aabb.intersects(aabb))
            return false;

        if(intersections)
            intersections->clear();

        reshp::polygon::ring* mutable_this = const_cast<reshp::polygon::ring*>(this);
        reshp::polygon::ring* mutable_other = const_cast<reshp::polygon::ring*>(&other);
        reshp::polygon::intersection intersection(mutable_this, mutable_other);

        for(unsigned tseg = 0; tseg < this->segments.size(); ++tseg)
        {
            intersection.segment = &mutable_this->segments[tseg];
            intersection.segment_index = tseg;

            for(unsigned oseg = 0; oseg < other.segments.size(); ++oseg)
            {
                intersection.intersector.segment = &mutable_other->segments[oseg];
                intersection.intersector.segment_index = oseg;

                if(intersection.segment->intersects(*intersection.intersector.segment, &intersection.point))
                {
                    if(!intersections)
                        return true;

                    intersections->push_back(intersection);
                }
            }
        }

        if(intersections && intersections->size())
            return true;

        return false;
    }

    polygon::polygon()
    {
    }

    polygon::polygon(const reshp::polygon& poly) :
        aabb(poly.aabb),
        rings(poly.rings)
    {
    }

    polygon::polygon(const reshp::shp::polygon& poly)
    {
        for(int32_t part = 0; part < poly.num_parts; ++part)
        {
            reshp::polygon::ring ring;
            int32_t first_index = poly.parts[part];
            reshp::point first(poly.points[first_index].x, poly.points[first_index].y);

            for(int32_t p = first_index + 1; p < poly.num_points; ++p)
            {
                reshp::segment segment(reshp::point(poly.points[p - 1].x, poly.points[p - 1].y),
                                       reshp::point(poly.points[p].x, poly.points[p].y));

                ring.segments.push_back(segment);

                if(segment.end == first)
                    break;
            }

            int sum = 0;

            for(unsigned s = 0; s < ring.segments.size(); ++s)
                sum += (ring.segments[s].end.x - ring.segments[s].start.x) * (ring.segments[s].end.y + ring.segments[s].start.y);

            // Clockwise: Outer, Counter-clockwise: Inner
            ring.type = (sum > 0 ? ring::outer : ring::inner);

            ring.calculate_aabb();
            rings.push_back(ring);
        }

        calculate_aabb();
    }

    void polygon::calculate_aabb()
    {
        aabb.initialize(); // Initialize AABB with min/max extremes

        for(unsigned i = 0; i < rings.size(); ++i)
        {
            rings[i].calculate_aabb();

            aabb.min.x = std::min(aabb.min.x, rings[i].aabb.min.x);
            aabb.min.y = std::min(aabb.min.y, rings[i].aabb.min.y);
            aabb.min.z = std::min(aabb.min.z, rings[i].aabb.min.z);

            aabb.max.x = std::max(aabb.max.x, rings[i].aabb.max.x);
            aabb.max.y = std::max(aabb.max.y, rings[i].aabb.max.y);
            aabb.max.z = std::max(aabb.max.z, rings[i].aabb.max.z);
        }
    }

    bool polygon::contains(const reshp::point& point) const
    {
        bool inside = false;

        // Return false if point is inside inner ring (hole)
        for(unsigned r = 0; r < rings.size(); ++r)
        {
            if(rings[r].contains(point))
            {
                if(rings[r].type == reshp::polygon::ring::inner)
                    return false;

                else if(!inside)
                    inside = true;
            }
        }

        return inside;
    }

    bool polygon::inside(const reshp::polygon& other) const
    {
        if(!aabb.inside(other.aabb))
            return false;

        for(unsigned tring = 0; tring < this->rings.size(); ++tring)
            for(unsigned oring = 0; oring < other.rings.size(); ++oring)
                if(!this->rings[tring].inside(other.rings[oring]))
                    return false;

        return true;
    }

    bool polygon::intersects() const
    {
        for(unsigned i = 0; i < rings.size(); ++i)
        {
            if(rings[i].intersects())
                return true;

            for(unsigned j = i + 1; j < rings.size(); ++j)
                if(rings[i].intersects(rings[j]))
                    return true;
        }

        return false;
    }

    bool polygon::intersects(const reshp::polygon& other, std::vector<reshp::polygon::intersection>* intersections) const
    {
        if(!aabb.intersects(other.aabb) && !other.aabb.intersects(aabb))
            return false;

        if(intersections)
            intersections->clear();

        for(unsigned tring = 0; tring < this->rings.size(); ++tring)
            for(unsigned oring = 0; oring < other.rings.size(); ++oring)
                if(this->rings[tring].intersects(other.rings[oring], intersections))
                    if(!intersections)
                        return true;

        if(intersections)
            return intersections->size();

        return false;
    }

    void polygon::operator>> (reshp::shp::polygon& poly) const
    {
        poly.box[0] = aabb.min.x;
        poly.box[1] = aabb.min.y;
        poly.box[2] = aabb.max.x;
        poly.box[3] = aabb.max.y;

        unsigned points = 0, parts = rings.size();

        for(unsigned p = 0; p < parts; ++p)
            points += rings[p].segments.size() + 1;

        if(poly.parts)
            delete poly.parts;

        if(poly.points)
            delete poly.points;

        if((poly.parts = new (std::nothrow) int32_t[parts]))
        {
            if((poly.points = new (std::nothrow) reshp::shp::point[points]))
            {
                for(unsigned r = 0; r < parts; ++r)
                {
                    poly.parts[poly.num_parts++] = poly.num_points;

                    for(unsigned s = 0; s < rings[r].segments.size(); ++s)
                        poly.points[poly.num_points++] = reshp::shp::point(rings[r].segments[s].start.x, rings[r].segments[s].start.y);

                    poly.points[poly.num_points++] = reshp::shp::point(rings[r].segments[0].start.x, rings[r].segments[0].start.y);
                }
            }
        }
    }
}
<commit_msg>Fixed error in polygon-ring invert function<commit_after>/* * * * * * * * * * * * *\
|*             ╔═╗ v0.4  *|
|* ╔═╦═╦═══╦═══╣ ╚═╦═╦═╗ *|
|* ║ ╔═╣ '╔╬═╗╚╣ ║ ║  '║ *|
|* ╚═╝ ╚═══╩═══╩═╩═╣ ╔═╝ *|
|* * * * * * * * * ╚═╝ * *|
|* Manipulation tool for *|
|*    ESRI Shapefiles    *|
|* * * * * * * * * * * * *|
|* http://www.npolar.no/ *|
\* * * * * * * * * * * * */

#include "polygon.hpp"
#include <algorithm>
#include <new>

namespace reshp
{
    polygon::intersection::intersection(reshp::polygon::ring* ring, reshp::polygon::ring* intersector_ring) :
        ring(ring),
        segment(NULL),
        segment_index(-1),
        intersector(intersector_ring)
    {
    }

    polygon::intersection::intersector::intersector(reshp::polygon::ring* ring) :
        ring(ring),
        segment(NULL),
        segment_index(-1)
    {
    }

    polygon::ring::ring() :
        type(polygon::ring::outer)
    {
    }

    void polygon::ring::calculate_aabb()
    {
        aabb.initialize(); // Initialize AABB with min/max extremes

        for(unsigned i = 0; i < segments.size(); ++i)
        {
            aabb.min.x = std::min(aabb.min.x, segments[i].start.x);
            aabb.min.y = std::min(aabb.min.y, segments[i].start.y);
            aabb.min.z = std::min(aabb.min.z, segments[i].start.z);

            aabb.max.x = std::max(aabb.max.x, segments[i].start.x);
            aabb.max.y = std::max(aabb.max.y, segments[i].start.y);
            aabb.max.z = std::max(aabb.max.z, segments[i].start.z);
        }
    }

    bool polygon::ring::contains(const reshp::point& point) const
    {
        bool inside = false;

        for(unsigned i = 0, j = segments.size() - 1; i < segments.size(); j = i++)
        {
            if(((segments[i].start.y > point.y) != (segments[j].start.y > point.y))
            && (point.x < (segments[j].start.x - segments[i].start.x) * (point.y - segments[i].start.y) / (segments[j].start.y - segments[i].start.y) + segments[i].start.x))
                inside = !inside;
        }

        return inside;
    }

    void polygon::ring::invert()
    {
        for(unsigned s = 0, c = segments.size(); s < c; ++s)
            std::swap(segments[s].start, segments[s].end);

        std::reverse(segments.begin(), segments.end());
        type = (type == inner ? outer : inner);
    }

    bool polygon::ring::inside(const reshp::polygon::ring& other) const
    {
        if(!aabb.inside(other.aabb))
            return false;

        for(unsigned i = 0; i < segments.size(); ++i)
            if(!other.contains(segments[i].start))
                return false;

        return true;
    }

    bool polygon::ring::intersects() const
    {
        for(unsigned i = 0, s = segments.size(); i < s - 2; ++i)
            for(unsigned j = i + 1; j < segments.size(); ++j)
                if(j - i > 1 && j < (s - 1) + i)
                    if(segments[i].intersects(segments[j]))
                        return true;

        return false;
    }

    bool polygon::ring::intersects(const reshp::polygon::ring& other, std::vector<reshp::polygon::intersection>* intersections) const
    {
        if(!aabb.intersects(other.aabb) && !other.aabb.intersects(aabb))
            return false;

        if(intersections)
            intersections->clear();

        reshp::polygon::ring* mutable_this = const_cast<reshp::polygon::ring*>(this);
        reshp::polygon::ring* mutable_other = const_cast<reshp::polygon::ring*>(&other);
        reshp::polygon::intersection intersection(mutable_this, mutable_other);

        for(unsigned tseg = 0; tseg < this->segments.size(); ++tseg)
        {
            intersection.segment = &mutable_this->segments[tseg];
            intersection.segment_index = tseg;

            for(unsigned oseg = 0; oseg < other.segments.size(); ++oseg)
            {
                intersection.intersector.segment = &mutable_other->segments[oseg];
                intersection.intersector.segment_index = oseg;

                if(intersection.segment->intersects(*intersection.intersector.segment, &intersection.point))
                {
                    if(!intersections)
                        return true;

                    intersections->push_back(intersection);
                }
            }
        }

        if(intersections && intersections->size())
            return true;

        return false;
    }

    polygon::polygon()
    {
    }

    polygon::polygon(const reshp::polygon& poly) :
        aabb(poly.aabb),
        rings(poly.rings)
    {
    }

    polygon::polygon(const reshp::shp::polygon& poly)
    {
        for(int32_t part = 0; part < poly.num_parts; ++part)
        {
            reshp::polygon::ring ring;
            int32_t first_index = poly.parts[part];
            reshp::point first(poly.points[first_index].x, poly.points[first_index].y);

            for(int32_t p = first_index + 1; p < poly.num_points; ++p)
            {
                reshp::segment segment(reshp::point(poly.points[p - 1].x, poly.points[p - 1].y),
                                       reshp::point(poly.points[p].x, poly.points[p].y));

                ring.segments.push_back(segment);

                if(segment.end == first)
                    break;
            }

            int sum = 0;

            for(unsigned s = 0; s < ring.segments.size(); ++s)
                sum += (ring.segments[s].end.x - ring.segments[s].start.x) * (ring.segments[s].end.y + ring.segments[s].start.y);

            // Clockwise: Outer, Counter-clockwise: Inner
            ring.type = (sum > 0 ? ring::outer : ring::inner);

            ring.calculate_aabb();
            rings.push_back(ring);
        }

        calculate_aabb();
    }

    void polygon::calculate_aabb()
    {
        aabb.initialize(); // Initialize AABB with min/max extremes

        for(unsigned i = 0; i < rings.size(); ++i)
        {
            rings[i].calculate_aabb();

            aabb.min.x = std::min(aabb.min.x, rings[i].aabb.min.x);
            aabb.min.y = std::min(aabb.min.y, rings[i].aabb.min.y);
            aabb.min.z = std::min(aabb.min.z, rings[i].aabb.min.z);

            aabb.max.x = std::max(aabb.max.x, rings[i].aabb.max.x);
            aabb.max.y = std::max(aabb.max.y, rings[i].aabb.max.y);
            aabb.max.z = std::max(aabb.max.z, rings[i].aabb.max.z);
        }
    }

    bool polygon::contains(const reshp::point& point) const
    {
        bool inside = false;

        // Return false if point is inside inner ring (hole)
        for(unsigned r = 0; r < rings.size(); ++r)
        {
            if(rings[r].contains(point))
            {
                if(rings[r].type == reshp::polygon::ring::inner)
                    return false;

                else if(!inside)
                    inside = true;
            }
        }

        return inside;
    }

    bool polygon::inside(const reshp::polygon& other) const
    {
        if(!aabb.inside(other.aabb))
            return false;

        for(unsigned tring = 0; tring < this->rings.size(); ++tring)
            for(unsigned oring = 0; oring < other.rings.size(); ++oring)
                if(!this->rings[tring].inside(other.rings[oring]))
                    return false;

        return true;
    }

    bool polygon::intersects() const
    {
        for(unsigned i = 0; i < rings.size(); ++i)
        {
            if(rings[i].intersects())
                return true;

            for(unsigned j = i + 1; j < rings.size(); ++j)
                if(rings[i].intersects(rings[j]))
                    return true;
        }

        return false;
    }

    bool polygon::intersects(const reshp::polygon& other, std::vector<reshp::polygon::intersection>* intersections) const
    {
        if(!aabb.intersects(other.aabb) && !other.aabb.intersects(aabb))
            return false;

        if(intersections)
            intersections->clear();

        for(unsigned tring = 0; tring < this->rings.size(); ++tring)
            for(unsigned oring = 0; oring < other.rings.size(); ++oring)
                if(this->rings[tring].intersects(other.rings[oring], intersections))
                    if(!intersections)
                        return true;

        if(intersections)
            return intersections->size();

        return false;
    }

    void polygon::operator>> (reshp::shp::polygon& poly) const
    {
        poly.box[0] = aabb.min.x;
        poly.box[1] = aabb.min.y;
        poly.box[2] = aabb.max.x;
        poly.box[3] = aabb.max.y;

        unsigned points = 0, parts = rings.size();

        for(unsigned p = 0; p < parts; ++p)
            points += rings[p].segments.size() + 1;

        if(poly.parts)
            delete poly.parts;

        if(poly.points)
            delete poly.points;

        if((poly.parts = new (std::nothrow) int32_t[parts]))
        {
            if((poly.points = new (std::nothrow) reshp::shp::point[points]))
            {
                for(unsigned r = 0; r < parts; ++r)
                {
                    poly.parts[poly.num_parts++] = poly.num_points;

                    for(unsigned s = 0; s < rings[r].segments.size(); ++s)
                        poly.points[poly.num_points++] = reshp::shp::point(rings[r].segments[s].start.x, rings[r].segments[s].start.y);

                    poly.points[poly.num_points++] = reshp::shp::point(rings[r].segments[0].start.x, rings[r].segments[0].start.y);
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>//
// Copyright (C) 2006 SIPez LLC.
// Licensed to SIPfoundry under a Contributor Agreement.
//
// Copyright (C) 2004-2006 SIPfoundry Inc.
// Licensed by SIPfoundry under the LGPL license.
//
// Copyright (C) 2004-2006 Pingtel Corp.  All rights reserved.
// Licensed to SIPfoundry under a Contributor Agreement.
//
// $$
///////////////////////////////////////////////////////////////////////////////

// SYSTEM INCLUDES
#include <assert.h>

#ifdef __pingtel_on_posix__
#  ifdef __linux__
#     include <stdlib.h>
      typedef __int64_t __int64;
#  elif defined(sun)
#     include <sys/int_types.h>
      typedef int64_t __int64;
#  elif defined(__MACH__) /* OS X */
#     include <sys/types.h>
      typedef int64_t __int64;
#  else
#     error Unsupported POSIX OS.
#  endif
#endif

// APPLICATION INCLUDES

#include <os/OsMsg.h>
#include <os/OsMsgPool.h>

#include "mp/MpBuf.h"
#include "mp/MprToSpkr.h"
#include "mp/MpBufferMsg.h"
#include "mp/dsplib.h"
#include "mp/MpMediaTask.h"

#ifdef RTL_ENABLED
#   include <rtl_macro.h>
#endif

int iTrainingNoiseFlag = 0;
static int iComfortNoiseFlag = 1;
/*
int comfortNoise(int Flag) {
   int save = iComfortNoiseFlag;
   iComfortNoiseFlag = Flag;
   return (save);
}
*/

// EXTERNAL FUNCTIONS
// EXTERNAL VARIABLES
// CONSTANTS
// STATIC VARIABLE INITIALIZATIONS
TOSPEAKERHOOK MprToSpkr::s_fnToSpeakerHook = NULL ;

static const int DEF_INIT_VOL = 363188;
static const int DEF_VOL_STEP = 27500; // approx. 2dB

int MprToSpkr::slInitVol   = DEF_INIT_VOL;
int MprToSpkr::slVolStep   = DEF_VOL_STEP;

#ifdef DETECT_SPKR_OVERFLOW /* [ */
int MprToSpkr::smStatsReports = 0;
#endif /* DETECT_SPKR_OVERFLOW ] */

#ifdef REIMPLEMENT_CLARISIS_EQ /* [ */
int MprToSpkr::smClarisisHandsetSpeakerEq[EqFilterLen_ix] =  {
      0, 0, 0, 0, 0, 0,
      0, 0, 0, 0, 0, 0,
      0, 0, 0, 0, 0, 74,
      231, -6883, 32767, -6883, 231, 74
   };
#endif /* REIMPLEMENT_CLARISIS_EQ ] */

/* //////////////////////////// PUBLIC //////////////////////////////////// */

/* ============================ CREATORS ================================== */

// Constructor
MprToSpkr::MprToSpkr(const UtlString& rName,
                     OsMsgQ *pSpkQ,
                     OsMsgQ *pEchoQ)
:  MpAudioResource(rName, 1, 1, 0, 1)
,  mpSpkQ(pSpkQ)
,  mpEchoQ(pEchoQ)
,  mulNoiseLevel(1000L)
#ifdef DETECT_SPKR_OVERFLOW /* [ */
,  mOverflowsIn(0)
,  mUnderflowsIn(0)
,  mOverflowsOut(0)
,  mUnderflowsOut(0)
,  mTotalSamples(0)
,  mMaxIn(0)
,  mMinIn(0)
,  mMaxOut(0)
,  mMinOut(0)
#endif /* DETECT_SPKR_OVERFLOW ] */

#ifdef REIMPLEMENT_CLARISIS_EQ /* [ */
,  mpEqSave_ix(NULL)
,  mpCurEq_ix(NULL)
,  mLastSpkr_ix(0)
#endif /* REIMPLEMENT_CLARISIS_EQ ] */
{
   int i;

   init_CNG();

#ifdef REIMPLEMENT_CLARISIS_EQ /* [ */
   mpCurEq_ix = &MprToSpkr::smClarisisHandsetSpeakerEq[0];
   mLastSpkr_ix = CODEC_DISABLE_SPKR;

   mpEqSave_ix = new int[samplesPerFrame + EqFilterLen_ix - 1];
   memset(mpEqSave_ix, 0, (samplesPerFrame + EqFilterLen_ix - 1) * sizeof(int));
#endif /* REIMPLEMENT_CLARISIS_EQ ] */

   /*** Speaker volume control ***/
   /* Originally, it is set to control by the codec. It is moved to here for
      acoustic echo cancellation purpose */

   for (i = 0; i < (VOLUME_CONTROL_TABLE_SIZE); i++) {
      mlpVolTable[i] = 0;
   }

#ifdef DETECT_SPKR_OVERFLOW /* [ */
   mReport = smStatsReports;
#endif /* DETECT_SPKR_OVERFLOW ] */

}

// Destructor
MprToSpkr::~MprToSpkr()
{
#ifdef DETECT_SPKR_OVERFLOW /* [ */
   stats();
#endif /* DETECT_SPKR_OVERFLOW ] */
}

/* ============================ MANIPULATORS ============================== */

#ifdef DETECT_SPKR_OVERFLOW /* [ */
int MprToSpkr::spkrStats()
{
   return smStatsReports++; // trigger another report and reset
}
#endif /* DETECT_SPKR_OVERFLOW ] */

/* ============================ ACCESSORS ================================= */

/* ============================ INQUIRY =================================== */

/* //////////////////////////// PROTECTED ///////////////////////////////// */

/* //////////////////////////// PRIVATE /////////////////////////////////// */

#ifdef DETECT_SPKR_OVERFLOW /* [ */
void MprToSpkr::stats()
{
   if ((mOverflowsOut+mUnderflowsOut+mOverflowsIn+mUnderflowsIn) > 0) {
      osPrintf(
         "MprToSpkr(0x%X): volume control handled %d total samples\n"
         "  input under/overflows %d+%d, output %d+%d\n",
         (int) this, mTotalSamples,
         mUnderflowsIn, mOverflowsIn, mUnderflowsOut, mOverflowsOut);
   } else {
      osPrintf("MprToSpkr(0x%X): no under/overflows in %d samples\n",
         (int) this, mTotalSamples);
   }
/*
   osPrintf(" ranges: input(%d .. %d), output(%d .. %d)\n",
      mMinIn, mMaxIn, mMinOut, mMaxOut);
*/

   mMinIn = mMaxIn = mMinOut = mMaxOut = mOverflowsOut =
   mUnderflowsOut = mOverflowsIn = mUnderflowsIn = mTotalSamples = 0;
}
#endif /* DETECT_SPKR_OVERFLOW ] */

void MprToSpkr::initVolTable()
{

   __int64 tempGain;

   int i;

   mlpVolTable[0] = (int) (tempGain = MprToSpkr::slInitVol);
   mlpVolTable[1] = (int) tempGain;
   mlpVolTable[VOLUME_CONTROL_TABLE_SIZE-2] = 0;
   mlpVolTable[VOLUME_CONTROL_TABLE_SIZE-1] = 0;
   for (i = 2; i < (VOLUME_CONTROL_TABLE_SIZE-2); i++) {
      mlpVolTable[i] = (int) (tempGain = (tempGain * slVolStep)>>15);
   }

   osPrintf("MprToSpkr::gains:");
   for( i = 0; i < VOLUME_CONTROL_TABLE_SIZE; i++) {
      osPrintf("%c%d", ((7 == (i&7)) ? '\n' : ' '), mlpVolTable[i]);
   }
   osPrintf("\n");

}

#ifdef REIMPLEMENT_CLARISIS_EQ /* [ */
void MprToSpkr::SpeakerEqualization_ix(MpAudioSample* shpSamples, int iLength)
{

   int         ShiftGain_ix = 13;
   int         i;
   int         c;
   int         iSample;
   int*        ip = mpEqSave_ix;
   const int*  pCurCoeff;
   MpAudioSample*     sp = shpSamples;

   const int* pCoeffSet = &MprToSpkr::smClarisisHandsetSpeakerEq[0];

   for (c = 1; c < EqFilterLen_ix; c++) {  // copy last few down to beginning
      *ip = ip[iLength];
      ip++;
   }

   for (i = 0; i < iLength; i++) { // convert new set to 32 bits
      *ip++ = *sp++;
   }

   for (i = 0; i < iLength; i++) {
      iSample = 0;
      ip = &mpEqSave_ix[i];
      pCurCoeff = pCoeffSet;
      for (c = 0; c < EqFilterLen_ix; c++) {
         iSample += *pCurCoeff++ * *ip++;
      }

      // rescale, then down 3 dB for Handset, +3dB for Headset
      iSample = ((iSample >> 15) * 13300) >> ShiftGain_ix;
      if (iSample < MIN_SPKR_DtoA) iSample = MIN_SPKR_DtoA;
      if (iSample > MAX_SPKR_DtoA) iSample = MAX_SPKR_DtoA;
      shpSamples[i] = iSample;
   }
}
#endif /* REIMPLEMENT_CLARISIS_EQ ] */

UtlBoolean MprToSpkr::doProcessFrame(MpBufPtr inBufs[],
                                     MpBufPtr outBufs[],
                                     int inBufsSize,
                                     int outBufsSize,
                                     UtlBoolean isEnabled,
                                     int samplesPerFrame,
                                     int samplesPerSecond)
{
    MpBufferMsg*   pMsg;
    MpBufferMsg*   pFlush;
    OsMsgPool*     spkrPool;
    MpAudioBufPtr  out;
    MpAudioSample* shpSamples;
    int            iLength;

    // We have only one input
    if (inBufsSize != 1)
    {
        return FALSE;
    }

#ifdef DETECT_SPKR_OVERFLOW /* [ */
    if (mReport < smStatsReports)
    {
        mReport = smStatsReports;
        stats();
    }
#endif /* DETECT_SPKR_OVERFLOW ] */

    // Do processing if enabled and if data is available
    if (isEnabled && inBufs[0].isValid())
    {

        // Own input buffer
        out = inBufs[0];
        inBufs[0].release();

        shpSamples = out->getSamplesWritePtr();
        iLength = out->getSamplesNumber();

        /////////////////////////////////////////////////
        // samples ready for EQ processing //////////////
        /////////////////////////////////////////////////

#ifdef REIMPLEMENT_CLARISIS_EQ /* [ */
        SpeakerEqualization_ix(shpSamples, iLength);
#endif /* REIMPLEMENT_CLARISIS_EQ ] */

        if(iTrainingNoiseFlag > 0)
        {
            /* generate white noise to test the performance if AEC only.
             * This is for parameter tweaking only. The original speaker
             * signal will be dropped.
             */
            out->setSamplesNumber(samplesPerFrame);
            iLength = out->getSamplesNumber();
            white_noise_generator(shpSamples, iLength, iTrainingNoiseFlag);
        }
        else
        {
            if(out->getSpeechType() == MP_SPEECH_COMFORT_NOISE)
            {
                out->setSamplesNumber(samplesPerFrame);
                iLength = out->getSamplesNumber();
                if(iComfortNoiseFlag > 0)
                {
                    comfort_noise_generator(shpSamples, iLength, mulNoiseLevel);
                }
                else
                {
                    memset((char *)shpSamples, 0 , iLength*2);
                }
            }
            else
            {
                background_noise_level_estimation(mulNoiseLevel, shpSamples,
                                                  iLength);
            }
        }

        if (s_fnToSpeakerHook)
        {
            /*
            * Allow an external identity to consume speaker data.  Ideally,
            * this should probably become a different resource, but
            * abstracting a new CallFlowGraph is a lot of work.
            */

            s_fnToSpeakerHook(iLength, (short*)shpSamples) ;
        }

        // TODO:: I don't know why we set attenuation to 0 here. BTW, it used only in the MprEchoSuppress().
        out->setAttenDb(0);

        // Push data to the output, if connected.
        if (isOutputConnected(0))
        {
            outBufs[0] = out;
        }

#ifdef RTL_ENABLED
   RTL_EVENT("ToSpeaker queue", mpSpkQ->numMsgs());
#endif

        // Flush speaker queue if it is full.
        while (mpSpkQ && MAX_SPKR_BUFFERS < mpSpkQ->numMsgs())
        {
            if (mpSpkQ->receive((OsMsg*&) pFlush, OsTime::NO_WAIT_TIME) == OS_SUCCESS)
            {
                pFlush->releaseMsg();
                osPrintf( "pSpkQ drained. %d msgs in queue now\n"
                        , mpSpkQ->numMsgs());
            }
        }

        // Prepare msg to be sent to Media Task
        spkrPool = MpMediaTask::getMediaTask(0)->getBufferMsgPool();
        assert(NULL != spkrPool);
        pMsg = spkrPool ? (MpBufferMsg*) spkrPool->findFreeMsg() : NULL;
        if (NULL == pMsg)
        {
            pMsg = new MpBufferMsg(MpBufferMsg::AUD_PLAY);
        }

        pMsg->setMsgSubType(MpBufferMsg::AUD_PLAY);

        // Copy buffer to the message
        pMsg->setBuffer(out);

        // Send data to Media Task
        if (  mpSpkQ
           && (mpSpkQ->send(*pMsg, OsTime::NO_WAIT_TIME) == OS_SUCCESS))
        {
            // Post a copy of this message to the mpEchoQ so that it
            // can be used in AEC calculations.
            MpBufferMsg AECMsg(MpBufferMsg::ACK_EOSTREAM);

            // TODO: We should pre-allocate a bunch of messages for
            //       this purpose (see DmaMsgPool as an example).

            // Buffer is moved to the message. ob pointer is invalidated.
            AECMsg.ownBuffer(out) ;
            if (  mpEchoQ->numMsgs() >= mpEchoQ->maxMsgs()
               || mpEchoQ->send(AECMsg, OsTime::NO_WAIT_TIME) != OS_SUCCESS)
            {
//               osPrintf("pEchoQ->send() failed!\n");
            }
        }
        else
        {
            osPrintf("pSpkQ->send() failed!\n");
            if (pMsg->isMsgReusable())
            {
                pMsg->releaseMsg();
            }
        }

        if (!pMsg->isMsgReusable())
        {
            delete pMsg;
        }
    }
    else
    {
        // Push data to the output, if connected.
        if (isOutputConnected(0))
        {
            outBufs[0] = inBufs[0];
        }
    }

   return TRUE;
}

/* ============================ FUNCTIONS ================================= */
<commit_msg>Remove unused code from MprToSpkr.<commit_after>//
// Copyright (C) 2006 SIPez LLC.
// Licensed to SIPfoundry under a Contributor Agreement.
//
// Copyright (C) 2004-2006 SIPfoundry Inc.
// Licensed by SIPfoundry under the LGPL license.
//
// Copyright (C) 2004-2006 Pingtel Corp.  All rights reserved.
// Licensed to SIPfoundry under a Contributor Agreement.
//
// $$
///////////////////////////////////////////////////////////////////////////////

// SYSTEM INCLUDES
#include <assert.h>

#ifdef __pingtel_on_posix__
#  ifdef __linux__
#     include <stdlib.h>
      typedef __int64_t __int64;
#  elif defined(sun)
#     include <sys/int_types.h>
      typedef int64_t __int64;
#  elif defined(__MACH__) /* OS X */
#     include <sys/types.h>
      typedef int64_t __int64;
#  else
#     error Unsupported POSIX OS.
#  endif
#endif

// APPLICATION INCLUDES

#include <os/OsMsg.h>
#include <os/OsMsgPool.h>

#include "mp/MpBuf.h"
#include "mp/MprToSpkr.h"
#include "mp/MpBufferMsg.h"
#include "mp/dsplib.h"
#include "mp/MpMediaTask.h"

#ifdef RTL_ENABLED
#   include <rtl_macro.h>
#endif

int iTrainingNoiseFlag = 0;
static int iComfortNoiseFlag = 1;
/*
int comfortNoise(int Flag) {
   int save = iComfortNoiseFlag;
   iComfortNoiseFlag = Flag;
   return (save);
}
*/

// EXTERNAL FUNCTIONS
// EXTERNAL VARIABLES
// CONSTANTS
// STATIC VARIABLE INITIALIZATIONS
TOSPEAKERHOOK MprToSpkr::s_fnToSpeakerHook = NULL ;

static const int DEF_INIT_VOL = 363188;
static const int DEF_VOL_STEP = 27500; // approx. 2dB

int MprToSpkr::slInitVol   = DEF_INIT_VOL;
int MprToSpkr::slVolStep   = DEF_VOL_STEP;

#ifdef DETECT_SPKR_OVERFLOW /* [ */
int MprToSpkr::smStatsReports = 0;
#endif /* DETECT_SPKR_OVERFLOW ] */

#ifdef REIMPLEMENT_CLARISIS_EQ /* [ */
int MprToSpkr::smClarisisHandsetSpeakerEq[EqFilterLen_ix] =  {
      0, 0, 0, 0, 0, 0,
      0, 0, 0, 0, 0, 0,
      0, 0, 0, 0, 0, 74,
      231, -6883, 32767, -6883, 231, 74
   };
#endif /* REIMPLEMENT_CLARISIS_EQ ] */

/* //////////////////////////// PUBLIC //////////////////////////////////// */

/* ============================ CREATORS ================================== */

// Constructor
MprToSpkr::MprToSpkr(const UtlString& rName,
                     OsMsgQ *pSpkQ,
                     OsMsgQ *pEchoQ)
:  MpAudioResource(rName, 1, 1, 0, 1)
,  mpSpkQ(pSpkQ)
,  mpEchoQ(pEchoQ)
,  mulNoiseLevel(1000L)
#ifdef DETECT_SPKR_OVERFLOW /* [ */
,  mOverflowsIn(0)
,  mUnderflowsIn(0)
,  mOverflowsOut(0)
,  mUnderflowsOut(0)
,  mTotalSamples(0)
,  mMaxIn(0)
,  mMinIn(0)
,  mMaxOut(0)
,  mMinOut(0)
#endif /* DETECT_SPKR_OVERFLOW ] */

#ifdef REIMPLEMENT_CLARISIS_EQ /* [ */
,  mpEqSave_ix(NULL)
,  mpCurEq_ix(NULL)
,  mLastSpkr_ix(0)
#endif /* REIMPLEMENT_CLARISIS_EQ ] */
{
   int i;

   init_CNG();

#ifdef REIMPLEMENT_CLARISIS_EQ /* [ */
   mpCurEq_ix = &MprToSpkr::smClarisisHandsetSpeakerEq[0];
   mLastSpkr_ix = CODEC_DISABLE_SPKR;

   mpEqSave_ix = new int[samplesPerFrame + EqFilterLen_ix - 1];
   memset(mpEqSave_ix, 0, (samplesPerFrame + EqFilterLen_ix - 1) * sizeof(int));
#endif /* REIMPLEMENT_CLARISIS_EQ ] */

   /*** Speaker volume control ***/
   /* Originally, it is set to control by the codec. It is moved to here for
      acoustic echo cancellation purpose */

   for (i = 0; i < (VOLUME_CONTROL_TABLE_SIZE); i++) {
      mlpVolTable[i] = 0;
   }

#ifdef DETECT_SPKR_OVERFLOW /* [ */
   mReport = smStatsReports;
#endif /* DETECT_SPKR_OVERFLOW ] */

}

// Destructor
MprToSpkr::~MprToSpkr()
{
#ifdef DETECT_SPKR_OVERFLOW /* [ */
   stats();
#endif /* DETECT_SPKR_OVERFLOW ] */
}

/* ============================ MANIPULATORS ============================== */

#ifdef DETECT_SPKR_OVERFLOW /* [ */
int MprToSpkr::spkrStats()
{
   return smStatsReports++; // trigger another report and reset
}
#endif /* DETECT_SPKR_OVERFLOW ] */

/* ============================ ACCESSORS ================================= */

/* ============================ INQUIRY =================================== */

/* //////////////////////////// PROTECTED ///////////////////////////////// */

/* //////////////////////////// PRIVATE /////////////////////////////////// */

#ifdef DETECT_SPKR_OVERFLOW /* [ */
void MprToSpkr::stats()
{
   if ((mOverflowsOut+mUnderflowsOut+mOverflowsIn+mUnderflowsIn) > 0) {
      osPrintf(
         "MprToSpkr(0x%X): volume control handled %d total samples\n"
         "  input under/overflows %d+%d, output %d+%d\n",
         (int) this, mTotalSamples,
         mUnderflowsIn, mOverflowsIn, mUnderflowsOut, mOverflowsOut);
   } else {
      osPrintf("MprToSpkr(0x%X): no under/overflows in %d samples\n",
         (int) this, mTotalSamples);
   }
/*
   osPrintf(" ranges: input(%d .. %d), output(%d .. %d)\n",
      mMinIn, mMaxIn, mMinOut, mMaxOut);
*/

   mMinIn = mMaxIn = mMinOut = mMaxOut = mOverflowsOut =
   mUnderflowsOut = mOverflowsIn = mUnderflowsIn = mTotalSamples = 0;
}
#endif /* DETECT_SPKR_OVERFLOW ] */

void MprToSpkr::initVolTable()
{

   __int64 tempGain;

   int i;

   mlpVolTable[0] = (int) (tempGain = MprToSpkr::slInitVol);
   mlpVolTable[1] = (int) tempGain;
   mlpVolTable[VOLUME_CONTROL_TABLE_SIZE-2] = 0;
   mlpVolTable[VOLUME_CONTROL_TABLE_SIZE-1] = 0;
   for (i = 2; i < (VOLUME_CONTROL_TABLE_SIZE-2); i++) {
      mlpVolTable[i] = (int) (tempGain = (tempGain * slVolStep)>>15);
   }

   osPrintf("MprToSpkr::gains:");
   for( i = 0; i < VOLUME_CONTROL_TABLE_SIZE; i++) {
      osPrintf("%c%d", ((7 == (i&7)) ? '\n' : ' '), mlpVolTable[i]);
   }
   osPrintf("\n");

}

#ifdef REIMPLEMENT_CLARISIS_EQ /* [ */
void MprToSpkr::SpeakerEqualization_ix(MpAudioSample* shpSamples, int iLength)
{

   int         ShiftGain_ix = 13;
   int         i;
   int         c;
   int         iSample;
   int*        ip = mpEqSave_ix;
   const int*  pCurCoeff;
   MpAudioSample*     sp = shpSamples;

   const int* pCoeffSet = &MprToSpkr::smClarisisHandsetSpeakerEq[0];

   for (c = 1; c < EqFilterLen_ix; c++) {  // copy last few down to beginning
      *ip = ip[iLength];
      ip++;
   }

   for (i = 0; i < iLength; i++) { // convert new set to 32 bits
      *ip++ = *sp++;
   }

   for (i = 0; i < iLength; i++) {
      iSample = 0;
      ip = &mpEqSave_ix[i];
      pCurCoeff = pCoeffSet;
      for (c = 0; c < EqFilterLen_ix; c++) {
         iSample += *pCurCoeff++ * *ip++;
      }

      // rescale, then down 3 dB for Handset, +3dB for Headset
      iSample = ((iSample >> 15) * 13300) >> ShiftGain_ix;
      if (iSample < MIN_SPKR_DtoA) iSample = MIN_SPKR_DtoA;
      if (iSample > MAX_SPKR_DtoA) iSample = MAX_SPKR_DtoA;
      shpSamples[i] = iSample;
   }
}
#endif /* REIMPLEMENT_CLARISIS_EQ ] */

UtlBoolean MprToSpkr::doProcessFrame(MpBufPtr inBufs[],
                                     MpBufPtr outBufs[],
                                     int inBufsSize,
                                     int outBufsSize,
                                     UtlBoolean isEnabled,
                                     int samplesPerFrame,
                                     int samplesPerSecond)
{
    MpBufferMsg*   pMsg;
    MpBufferMsg*   pFlush;
    OsMsgPool*     spkrPool;
    MpAudioBufPtr  out;
    MpAudioSample* shpSamples;
    int            iLength;

    // We have only one input
    if (inBufsSize != 1)
    {
        return FALSE;
    }

#ifdef DETECT_SPKR_OVERFLOW /* [ */
    if (mReport < smStatsReports)
    {
        mReport = smStatsReports;
        stats();
    }
#endif /* DETECT_SPKR_OVERFLOW ] */

    // Do processing if enabled and if data is available
    if (isEnabled && inBufs[0].isValid())
    {

        // Own input buffer
        out = inBufs[0];
        inBufs[0].release();

        shpSamples = out->getSamplesWritePtr();
        iLength = out->getSamplesNumber();

        /////////////////////////////////////////////////
        // samples ready for EQ processing //////////////
        /////////////////////////////////////////////////

#ifdef REIMPLEMENT_CLARISIS_EQ /* [ */
        SpeakerEqualization_ix(shpSamples, iLength);
#endif /* REIMPLEMENT_CLARISIS_EQ ] */

        if(iTrainingNoiseFlag > 0)
        {
            /* generate white noise to test the performance if AEC only.
             * This is for parameter tweaking only. The original speaker
             * signal will be dropped.
             */
            out->setSamplesNumber(samplesPerFrame);
            iLength = out->getSamplesNumber();
            white_noise_generator(shpSamples, iLength, iTrainingNoiseFlag);
        }
        else
        {
            if(out->getSpeechType() == MP_SPEECH_COMFORT_NOISE)
            {
                out->setSamplesNumber(samplesPerFrame);
                iLength = out->getSamplesNumber();
                if(iComfortNoiseFlag > 0)
                {
                    comfort_noise_generator(shpSamples, iLength, mulNoiseLevel);
                }
                else
                {
                    memset((char *)shpSamples, 0 , iLength*2);
                }
            }
            else
            {
                background_noise_level_estimation(mulNoiseLevel, shpSamples,
                                                  iLength);
            }
        }

        if (s_fnToSpeakerHook)
        {
            /*
            * Allow an external identity to consume speaker data.  Ideally,
            * this should probably become a different resource, but
            * abstracting a new CallFlowGraph is a lot of work.
            */

            s_fnToSpeakerHook(iLength, (short*)shpSamples) ;
        }

        // Push data to the output, if connected.
        if (isOutputConnected(0))
        {
            outBufs[0] = out;
        }

#ifdef RTL_ENABLED
   RTL_EVENT("ToSpeaker queue", mpSpkQ->numMsgs());
#endif

        // Flush speaker queue if it is full.
        while (mpSpkQ && MAX_SPKR_BUFFERS < mpSpkQ->numMsgs())
        {
            if (mpSpkQ->receive((OsMsg*&) pFlush, OsTime::NO_WAIT_TIME) == OS_SUCCESS)
            {
                pFlush->releaseMsg();
                osPrintf( "pSpkQ drained. %d msgs in queue now\n"
                        , mpSpkQ->numMsgs());
            }
        }

        // Prepare msg to be sent to Media Task
        spkrPool = MpMediaTask::getMediaTask(0)->getBufferMsgPool();
        assert(NULL != spkrPool);
        pMsg = spkrPool ? (MpBufferMsg*) spkrPool->findFreeMsg() : NULL;
        if (NULL == pMsg)
        {
            pMsg = new MpBufferMsg(MpBufferMsg::AUD_PLAY);
        }

        pMsg->setMsgSubType(MpBufferMsg::AUD_PLAY);

        // Copy buffer to the message
        pMsg->setBuffer(out);

        // Send data to Media Task
        if (  mpSpkQ
           && (mpSpkQ->send(*pMsg, OsTime::NO_WAIT_TIME) == OS_SUCCESS))
        {
            // Post a copy of this message to the mpEchoQ so that it
            // can be used in AEC calculations.
            MpBufferMsg AECMsg(MpBufferMsg::ACK_EOSTREAM);

            // TODO: We should pre-allocate a bunch of messages for
            //       this purpose (see DmaMsgPool as an example).

            // Buffer is moved to the message. ob pointer is invalidated.
            AECMsg.ownBuffer(out) ;
            if (  mpEchoQ->numMsgs() >= mpEchoQ->maxMsgs()
               || mpEchoQ->send(AECMsg, OsTime::NO_WAIT_TIME) != OS_SUCCESS)
            {
//               osPrintf("pEchoQ->send() failed!\n");
            }
        }
        else
        {
            osPrintf("pSpkQ->send() failed!\n");
            if (pMsg->isMsgReusable())
            {
                pMsg->releaseMsg();
            }
        }

        if (!pMsg->isMsgReusable())
        {
            delete pMsg;
        }
    }
    else
    {
        // Push data to the output, if connected.
        if (isOutputConnected(0))
        {
            outBufs[0] = inBufs[0];
        }
    }

   return TRUE;
}

/* ============================ FUNCTIONS ================================= */
<|endoftext|>


<commit_before>/*
Copyright (c) 2017 InversePalindrome
Nihil - SoundProperties.hpp
InversePalindrome.com
*/

#pragma once

struct SoundProperties
{
	SoundProperties(float volume, float pitch, float attenuation, float minDistance) :
		volume(volume),
		pitch(pitch),
		attenuation(attenuation),
		minDistance(minDistance)
	{
	}

	float volume;
	float pitch;
	float attenuation;
	float minDistance;
};<commit_msg>Delete SoundProperties.hpp<commit_after><|endoftext|>


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

  Library:   CTK

  Copyright (c) Kitware Inc.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0.txt

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

=========================================================================*/

// Qt includes
#include <QDebug>

// CTK includes
#include "ctkErrorLogFDMessageHandler.h"
#include "ctkErrorLogFDMessageHandler_p.h"
#include "ctkUtils.h"

// STD includes
#include <cstdio>
#ifdef Q_OS_WIN32
# include <fcntl.h>  // For _O_TEXT
# include <io.h>     // For _pipe, _dup and _dup2
#else
# include <unistd.h> // For pipe, dup and dup2
#endif

// --------------------------------------------------------------------------
// ctkFDHandler methods
// See http://stackoverflow.com/questions/5419356/redirect-stdout-stderr-to-a-string
// and http://stackoverflow.com/questions/955962/how-to-buffer-stdout-in-memory-and-write-it-from-a-dedicated-thread

// --------------------------------------------------------------------------
ctkFDHandler::ctkFDHandler(ctkErrorLogFDMessageHandler* messageHandler,
                           ctkErrorLogLevel::LogLevel logLevel,
                           ctkErrorLogModel::TerminalOutput terminalOutput)
{
  this->MessageHandler = messageHandler;
  this->LogLevel = logLevel;
  this->TerminalOutput = terminalOutput;
  this->SavedFDNumber = 0;
  this->Enabled = false;
  this->Initialized = false;
  this->init();
}

// --------------------------------------------------------------------------
ctkFDHandler::~ctkFDHandler()
{
  if (this->Initialized)
    {
    this->RedirectionFile.close();
    delete this->RedirectionStream;
    }
}

// --------------------------------------------------------------------------
void ctkFDHandler::init()
{
#ifdef Q_OS_WIN32
  int status = _pipe(this->Pipe, 65536, _O_TEXT);
#else
  int status = pipe(this->Pipe);
#endif
  if (status != 0)
    {
    qCritical().nospace() << "ctkFDHandler - Failed to create pipe !";
    return;
    }
  this->RedirectionFile.open(this->Pipe[0], QIODevice::ReadOnly);
  this->RedirectionStream = new QTextStream(&this->RedirectionFile);
  this->Initialized = true;
}

// --------------------------------------------------------------------------
FILE* ctkFDHandler::terminalOutputFile()
{
  return this->TerminalOutput == ctkErrorLogModel::StandardOutput ? stdout : stderr;
}

// --------------------------------------------------------------------------
void ctkFDHandler::setEnabled(bool value)
{
  if (!this->Initialized)
    {
    return;
    }
  if (this->Enabled == value)
    {
    return;
    }

  if (value)
    {
    // Flush (stdout|stderr) so that any buffered messages are delivered
    fflush(this->terminalOutputFile());

    // Save position of current standard output
    fgetpos(this->terminalOutputFile(), &this->SavedFDPos);
#ifdef Q_OS_WIN32
    this->SavedFDNumber = _dup(_fileno(this->terminalOutputFile()));
    _dup2(this->Pipe[1], _fileno(this->terminalOutputFile()));
    _close(this->Pipe[1]);
#else
    this->SavedFDNumber = dup(fileno(this->terminalOutputFile()));
    dup2(this->Pipe[1], fileno(this->terminalOutputFile()));
    close(this->Pipe[1]);
#endif

    // Start polling thread
    this->Enabled = true;
    this->start();
    }
  else
    {
    // Flush stdout or stderr so that any buffered messages are delivered
    fflush(this->terminalOutputFile());

    // Flush current stream so that any buffered messages are delivered
    this->RedirectionFile.flush();

    // Stop polling thread
    {
      QMutexLocker locker(&this->EnableMutex);
      this->Enabled = false;
    }

    QString newline("\n");
#ifdef Q_OS_WIN32
    _write(fileno(this->terminalOutputFile()), qPrintable(newline), newline.size());
#else
    write(fileno(this->terminalOutputFile()), qPrintable(newline), newline.size());
#endif

    // Wait the polling thread graciously terminates
    this->wait();

    // Close files and restore standard output to stdout or stderr - which should be the terminal
#ifdef Q_OS_WIN32
    _dup2(this->SavedFDNumber, _fileno(this->terminalOutputFile()));
    _close(this->SavedFDNumber);
#else
    dup2(this->SavedFDNumber, fileno(this->terminalOutputFile()));
    close(this->SavedFDNumber);
#endif
    clearerr(this->terminalOutputFile());
    fsetpos(this->terminalOutputFile(), &this->SavedFDPos);

#ifdef Q_OS_WIN32
    this->SavedFDNumber = _fileno(this->terminalOutputFile());
#else
    this->SavedFDNumber = fileno(this->terminalOutputFile());
#endif
    }

  ctkErrorLogTerminalOutput * terminalOutput =
      this->MessageHandler->terminalOutput(this->TerminalOutput);
  if(terminalOutput)
    {
    terminalOutput->setFileDescriptor(this->SavedFDNumber);
    }
}

// --------------------------------------------------------------------------
bool ctkFDHandler::enabled()const
{
  QMutexLocker locker(&this->EnableMutex);
  return this->Enabled;
}

// --------------------------------------------------------------------------
void ctkFDHandler::run()
{
  while(true)
    {
    char c = '\0';
    QString line;
    while(c != '\n')
      {
#ifdef Q_OS_WIN32
      int res = _read(this->Pipe[0], &c, 1); // When used with pipe, read() is blocking
#else
      ssize_t res = read(this->Pipe[0], &c, 1); // When used with pipe, read() is blocking
#endif
      if (res == -1)
        {
        break;
        }
      if (c != '\n')
        {
        line += c;
        }
      }

    if (!this->enabled())
      {
      break;
      }

    Q_ASSERT(this->MessageHandler);
    this->MessageHandler->handleMessage(
      ctk::qtHandleToString(QThread::currentThreadId()),
      this->LogLevel,
      this->MessageHandler->handlerPrettyName(),
      line);
    }
}

// --------------------------------------------------------------------------
// ctkErrorLogFDMessageHandlerPrivate

// --------------------------------------------------------------------------
class ctkErrorLogFDMessageHandlerPrivate
{
public:
  ctkErrorLogFDMessageHandlerPrivate();
  ~ctkErrorLogFDMessageHandlerPrivate();

  ctkFDHandler * StdOutFDHandler;
  ctkFDHandler * StdErrFDHandler;
};

// --------------------------------------------------------------------------
// ctkErrorLogFDMessageHandlerPrivate methods

//------------------------------------------------------------------------------
ctkErrorLogFDMessageHandlerPrivate::ctkErrorLogFDMessageHandlerPrivate()
{
}

//------------------------------------------------------------------------------
ctkErrorLogFDMessageHandlerPrivate::~ctkErrorLogFDMessageHandlerPrivate()
{
  delete this->StdOutFDHandler;
  delete this->StdErrFDHandler;
}

//------------------------------------------------------------------------------
// ctkErrorLogFDMessageHandler methods

//------------------------------------------------------------------------------
QString ctkErrorLogFDMessageHandler::HandlerName = QLatin1String("FD");

// --------------------------------------------------------------------------
ctkErrorLogFDMessageHandler::ctkErrorLogFDMessageHandler() :
  Superclass(), d_ptr(new ctkErrorLogFDMessageHandlerPrivate())
{
  Q_D(ctkErrorLogFDMessageHandler);
  d->StdOutFDHandler = new ctkFDHandler(this, ctkErrorLogLevel::Info, ctkErrorLogModel::StandardOutput);
  d->StdErrFDHandler = new ctkFDHandler(this, ctkErrorLogLevel::Critical, ctkErrorLogModel::StandardError);
}

// --------------------------------------------------------------------------
ctkErrorLogFDMessageHandler::~ctkErrorLogFDMessageHandler()
{
}

// --------------------------------------------------------------------------
QString ctkErrorLogFDMessageHandler::handlerName()const
{
  return ctkErrorLogFDMessageHandler::HandlerName;
}

// --------------------------------------------------------------------------
void ctkErrorLogFDMessageHandler::setEnabledInternal(bool value)
{
  Q_D(ctkErrorLogFDMessageHandler);
  d->StdOutFDHandler->setEnabled(value);
  d->StdErrFDHandler->setEnabled(value);
}
<commit_msg>Fix ctkErrorLogFDMessageHandler compilation warning<commit_after>/*=========================================================================

  Library:   CTK

  Copyright (c) Kitware Inc.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0.txt

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

=========================================================================*/

// Qt includes
#include <QDebug>

// CTK includes
#include "ctkErrorLogFDMessageHandler.h"
#include "ctkErrorLogFDMessageHandler_p.h"
#include "ctkUtils.h"

// STD includes
#include <cstdio>
#ifdef Q_OS_WIN32
# include <fcntl.h>  // For _O_TEXT
# include <io.h>     // For _pipe, _dup and _dup2
#else
# include <unistd.h> // For pipe, dup and dup2
#endif

// --------------------------------------------------------------------------
// ctkFDHandler methods
// See http://stackoverflow.com/questions/5419356/redirect-stdout-stderr-to-a-string
// and http://stackoverflow.com/questions/955962/how-to-buffer-stdout-in-memory-and-write-it-from-a-dedicated-thread

// --------------------------------------------------------------------------
ctkFDHandler::ctkFDHandler(ctkErrorLogFDMessageHandler* messageHandler,
                           ctkErrorLogLevel::LogLevel logLevel,
                           ctkErrorLogModel::TerminalOutput terminalOutput)
{
  this->MessageHandler = messageHandler;
  this->LogLevel = logLevel;
  this->TerminalOutput = terminalOutput;
  this->SavedFDNumber = 0;
  this->Enabled = false;
  this->Initialized = false;
  this->init();
}

// --------------------------------------------------------------------------
ctkFDHandler::~ctkFDHandler()
{
  if (this->Initialized)
    {
    this->RedirectionFile.close();
    delete this->RedirectionStream;
    }
}

// --------------------------------------------------------------------------
void ctkFDHandler::init()
{
#ifdef Q_OS_WIN32
  int status = _pipe(this->Pipe, 65536, _O_TEXT);
#else
  int status = pipe(this->Pipe);
#endif
  if (status != 0)
    {
    qCritical().nospace() << "ctkFDHandler - Failed to create pipe !";
    return;
    }
  this->RedirectionFile.open(this->Pipe[0], QIODevice::ReadOnly);
  this->RedirectionStream = new QTextStream(&this->RedirectionFile);
  this->Initialized = true;
}

// --------------------------------------------------------------------------
FILE* ctkFDHandler::terminalOutputFile()
{
  return this->TerminalOutput == ctkErrorLogModel::StandardOutput ? stdout : stderr;
}

// --------------------------------------------------------------------------
void ctkFDHandler::setEnabled(bool value)
{
  if (!this->Initialized)
    {
    return;
    }
  if (this->Enabled == value)
    {
    return;
    }

  if (value)
    {
    // Flush (stdout|stderr) so that any buffered messages are delivered
    fflush(this->terminalOutputFile());

    // Save position of current standard output
    fgetpos(this->terminalOutputFile(), &this->SavedFDPos);
#ifdef Q_OS_WIN32
    this->SavedFDNumber = _dup(_fileno(this->terminalOutputFile()));
    _dup2(this->Pipe[1], _fileno(this->terminalOutputFile()));
    _close(this->Pipe[1]);
#else
    this->SavedFDNumber = dup(fileno(this->terminalOutputFile()));
    dup2(this->Pipe[1], fileno(this->terminalOutputFile()));
    close(this->Pipe[1]);
#endif

    // Start polling thread
    this->Enabled = true;
    this->start();
    }
  else
    {
    // Flush stdout or stderr so that any buffered messages are delivered
    fflush(this->terminalOutputFile());

    // Flush current stream so that any buffered messages are delivered
    this->RedirectionFile.flush();

    // Stop polling thread
    {
      QMutexLocker locker(&this->EnableMutex);
      this->Enabled = false;
    }

    QString newline("\n");
#ifdef Q_OS_WIN32
    _write(_fileno(this->terminalOutputFile()), qPrintable(newline), newline.size());
#else
    write(fileno(this->terminalOutputFile()), qPrintable(newline), newline.size());
#endif

    // Wait the polling thread graciously terminates
    this->wait();

    // Close files and restore standard output to stdout or stderr - which should be the terminal
#ifdef Q_OS_WIN32
    _dup2(this->SavedFDNumber, _fileno(this->terminalOutputFile()));
    _close(this->SavedFDNumber);
#else
    dup2(this->SavedFDNumber, fileno(this->terminalOutputFile()));
    close(this->SavedFDNumber);
#endif
    clearerr(this->terminalOutputFile());
    fsetpos(this->terminalOutputFile(), &this->SavedFDPos);

#ifdef Q_OS_WIN32
    this->SavedFDNumber = _fileno(this->terminalOutputFile());
#else
    this->SavedFDNumber = fileno(this->terminalOutputFile());
#endif
    }

  ctkErrorLogTerminalOutput * terminalOutput =
      this->MessageHandler->terminalOutput(this->TerminalOutput);
  if(terminalOutput)
    {
    terminalOutput->setFileDescriptor(this->SavedFDNumber);
    }
}

// --------------------------------------------------------------------------
bool ctkFDHandler::enabled()const
{
  QMutexLocker locker(&this->EnableMutex);
  return this->Enabled;
}

// --------------------------------------------------------------------------
void ctkFDHandler::run()
{
  while(true)
    {
    char c = '\0';
    QString line;
    while(c != '\n')
      {
#ifdef Q_OS_WIN32
      int res = _read(this->Pipe[0], &c, 1); // When used with pipe, read() is blocking
#else
      ssize_t res = read(this->Pipe[0], &c, 1); // When used with pipe, read() is blocking
#endif
      if (res == -1)
        {
        break;
        }
      if (c != '\n')
        {
        line += c;
        }
      }

    if (!this->enabled())
      {
      break;
      }

    Q_ASSERT(this->MessageHandler);
    this->MessageHandler->handleMessage(
      ctk::qtHandleToString(QThread::currentThreadId()),
      this->LogLevel,
      this->MessageHandler->handlerPrettyName(),
      line);
    }
}

// --------------------------------------------------------------------------
// ctkErrorLogFDMessageHandlerPrivate

// --------------------------------------------------------------------------
class ctkErrorLogFDMessageHandlerPrivate
{
public:
  ctkErrorLogFDMessageHandlerPrivate();
  ~ctkErrorLogFDMessageHandlerPrivate();

  ctkFDHandler * StdOutFDHandler;
  ctkFDHandler * StdErrFDHandler;
};

// --------------------------------------------------------------------------
// ctkErrorLogFDMessageHandlerPrivate methods

//------------------------------------------------------------------------------
ctkErrorLogFDMessageHandlerPrivate::ctkErrorLogFDMessageHandlerPrivate()
{
}

//------------------------------------------------------------------------------
ctkErrorLogFDMessageHandlerPrivate::~ctkErrorLogFDMessageHandlerPrivate()
{
  delete this->StdOutFDHandler;
  delete this->StdErrFDHandler;
}

//------------------------------------------------------------------------------
// ctkErrorLogFDMessageHandler methods

//------------------------------------------------------------------------------
QString ctkErrorLogFDMessageHandler::HandlerName = QLatin1String("FD");

// --------------------------------------------------------------------------
ctkErrorLogFDMessageHandler::ctkErrorLogFDMessageHandler() :
  Superclass(), d_ptr(new ctkErrorLogFDMessageHandlerPrivate())
{
  Q_D(ctkErrorLogFDMessageHandler);
  d->StdOutFDHandler = new ctkFDHandler(this, ctkErrorLogLevel::Info, ctkErrorLogModel::StandardOutput);
  d->StdErrFDHandler = new ctkFDHandler(this, ctkErrorLogLevel::Critical, ctkErrorLogModel::StandardError);
}

// --------------------------------------------------------------------------
ctkErrorLogFDMessageHandler::~ctkErrorLogFDMessageHandler()
{
}

// --------------------------------------------------------------------------
QString ctkErrorLogFDMessageHandler::handlerName()const
{
  return ctkErrorLogFDMessageHandler::HandlerName;
}

// --------------------------------------------------------------------------
void ctkErrorLogFDMessageHandler::setEnabledInternal(bool value)
{
  Q_D(ctkErrorLogFDMessageHandler);
  d->StdOutFDHandler->setEnabled(value);
  d->StdErrFDHandler->setEnabled(value);
}
<|endoftext|>


<commit_before>#include <algorithm>
#include <cstdio>
#include <limits>

#include "graphics.h"
#include "nesterovBase.h"
#include "nesterovPlace.h"
#include "placerBase.h"
#include "utility/Logger.h"

namespace gpl {

Graphics::Graphics(utl::Logger* logger,
                   std::shared_ptr<PlacerBase> pb,
                   InitialPlace* ip)
    : pb_(pb),
      nb_(),
      np_(nullptr),
      ip_(ip),
      selected_(nullptr),
      draw_bins_(false),
      logger_(logger)
{
  gui::Gui::get()->registerRenderer(this);
}

Graphics::Graphics(utl::Logger* logger,
                   NesterovPlace* np,
                   std::shared_ptr<PlacerBase> pb,
                   std::shared_ptr<NesterovBase> nb,
                   bool draw_bins)
    : pb_(pb),
      nb_(nb),
      np_(np),
      ip_(nullptr),
      selected_(nullptr),
      draw_bins_(draw_bins),
      logger_(logger)
{
  gui::Gui::get()->registerRenderer(this);
}

void Graphics::drawBounds(gui::Painter& painter)
{
  // draw core bounds
  auto& die = pb_->die();
  painter.setPen(gui::Painter::yellow, /* cosmetic */ true);
  painter.drawLine(die.coreLx(), die.coreLy(), die.coreUx(), die.coreLy());
  painter.drawLine(die.coreUx(), die.coreLy(), die.coreUx(), die.coreUy());
  painter.drawLine(die.coreUx(), die.coreUy(), die.coreLx(), die.coreUy());
  painter.drawLine(die.coreLx(), die.coreUy(), die.coreLx(), die.coreLy());
}

void Graphics::drawInitial(gui::Painter& painter)
{
  drawBounds(painter);

  painter.setPen(gui::Painter::white, /* cosmetic */ true);
  for (auto& inst : pb_->placeInsts()) {
    int lx = inst->lx();
    int ly = inst->ly();
    int ux = inst->ux();
    int uy = inst->uy();

    gui::Painter::Color color = gui::Painter::dark_blue;
    color.a = 180;
    painter.setBrush(color);
    painter.drawRect({lx, ly, ux, uy});
  }
}

void Graphics::drawNesterov(gui::Painter& painter)
{
  drawBounds(painter);
  if (draw_bins_) {
    // Draw the bins
    painter.setPen(gui::Painter::white, /* cosmetic */ true);
    for (auto& bin : nb_->bins()) {
      int color = bin->density() * 50 + 20;

      color = (color > 255) ? 255 : (color < 20) ? 20 : color;
      color = 255 - color;

      painter.setBrush({color, color, color, 180});
      painter.drawRect({bin->lx(), bin->ly(), bin->ux(), bin->uy()});
    }
  }

  // Draw the placeable objects
  painter.setPen(gui::Painter::white);
  for (auto* gCell : nb_->gCells()) {
    const int gcx = gCell->dCx();
    const int gcy = gCell->dCy();

    int xl = gcx - gCell->dx() / 2;
    int yl = gcy - gCell->dy() / 2;
    int xh = gcx + gCell->dx() / 2;
    int yh = gcy + gCell->dy() / 2;

    gui::Painter::Color color;
    if (gCell->isInstance()) {
      color = gui::Painter::dark_blue;
    } else if (gCell->isFiller()) {
      color = gui::Painter::dark_magenta;
    }
    if (gCell == selected_) {
      color = gui::Painter::yellow;
    }

    color.a = 180;
    painter.setBrush(color);
    painter.drawRect({xl, yl, xh, yh});
  }

  // Draw lines to neighbors
  if (selected_) {
    painter.setPen(gui::Painter::yellow, true);
    for (GPin* pin : selected_->gPins()) {
      GNet* net = pin->gNet();
      if (!net) {
        continue;
      }
      for (GPin* other_pin : net->gPins()) {
        GCell* neighbor = other_pin->gCell();
        if (neighbor == selected_) {
          continue;
        }
        painter.drawLine(
            pin->cx(), pin->cy(), other_pin->cx(), other_pin->cy());
      }
    }
  }

  // Draw force direction lines
  if (draw_bins_) {
    float efMax = 0;
    int max_len = std::numeric_limits<int>::max();
    for (auto& bin : nb_->bins()) {
      efMax
          = std::max(efMax, hypot(bin->electroForceX(), bin->electroForceY()));
      max_len = std::min({max_len, bin->dx(), bin->dy()});
    }

    for (auto& bin : nb_->bins()) {
      float fx = bin->electroForceX();
      float fy = bin->electroForceY();
      float f = hypot(fx, fy);
      float ratio = f / efMax;
      float dx = fx / f * max_len * ratio;
      float dy = fy / f * max_len * ratio;

      int cx = bin->cx();
      int cy = bin->cy();

      painter.setPen(gui::Painter::red, true);
      painter.drawLine(cx, cy, cx + dx, cy + dy);
    }
  }
}

void Graphics::drawObjects(gui::Painter& painter)
{
  if (nb_) {
    drawNesterov(painter);
  } else {
    drawInitial(painter);
  }
}

void Graphics::reportSelected()
{
  if (!selected_) {
    return;
  }
  auto instance = selected_->instance();
  logger_->report("Inst: {}", instance->dbInst()->getName());

  if (np_) {
    auto wlCoeffX = np_->getWireLengthCoefX();
    auto wlCoeffY = np_->getWireLengthCoefY();

    logger_->report("  Wire Length Gradient");
    for (auto& gPin : selected_->gPins()) {
      FloatPoint wlGrad
          = nb_->getWireLengthGradientPinWA(gPin, wlCoeffX, wlCoeffY);
      logger_->report("          ({:+.2e}, {:+.2e}) pin {}",
                      wlGrad.x,
                      wlGrad.y,
                      gPin->pin()->name());
    }

    FloatPoint wlGrad
        = nb_->getWireLengthGradientWA(selected_, wlCoeffX, wlCoeffY);
    logger_->report("  sum wl  ({: .2e}, {: .2e})", wlGrad.x, wlGrad.y);

    auto densityGrad = nb_->getDensityGradient(selected_);
    float densityPenalty = np_->getDensityPenalty();
    logger_->report("  density ({: .2e}, {: .2e}) (penalty: {})",
                    densityPenalty * densityGrad.x,
                    densityPenalty * densityGrad.y,
                    densityPenalty);
    logger_->report("  overall ({: .2e}, {: .2e})",
                    wlGrad.x + densityPenalty * densityGrad.x,
                    wlGrad.y + densityPenalty * densityGrad.y);
  }
}

void Graphics::cellPlot(bool pause)
{
  gui::Gui::get()->redraw();
  if (pause) {
    reportSelected();
    gui::Gui::get()->pause();
  }
}

gui::Selected Graphics::select(odb::dbTechLayer* layer, const odb::Point& point)
{
  selected_ = nullptr;

  if (layer || !nb_) {
    return gui::Selected();
  }

  for (GCell* cell : nb_->gCells()) {
    const int gcx = cell->dCx();
    const int gcy = cell->dCy();

    int xl = gcx - cell->dx() / 2;
    int yl = gcy - cell->dy() / 2;
    int xh = gcx + cell->dx() / 2;
    int yh = gcy + cell->dy() / 2;

    if (point.x() < xl || point.y() < yl || point.x() > xh || point.y() > yh) {
      continue;
    }

    selected_ = cell;
    if (cell->isInstance()) {
      reportSelected();
      return gui::Selected(cell->instance()->dbInst());
    }
  }
  return gui::Selected();
}

void Graphics::status(const std::string& message)
{
  gui::Gui::get()->status(message);
}

/* static */
bool Graphics::guiActive()
{
  return gui::Gui::get() != nullptr;
}

}  // namespace gpl
<commit_msg>gpl: change placeable objects to green for better visibility<commit_after>#include <algorithm>
#include <cstdio>
#include <limits>

#include "graphics.h"
#include "nesterovBase.h"
#include "nesterovPlace.h"
#include "placerBase.h"
#include "utility/Logger.h"

namespace gpl {

Graphics::Graphics(utl::Logger* logger,
                   std::shared_ptr<PlacerBase> pb,
                   InitialPlace* ip)
    : pb_(pb),
      nb_(),
      np_(nullptr),
      ip_(ip),
      selected_(nullptr),
      draw_bins_(false),
      logger_(logger)
{
  gui::Gui::get()->registerRenderer(this);
}

Graphics::Graphics(utl::Logger* logger,
                   NesterovPlace* np,
                   std::shared_ptr<PlacerBase> pb,
                   std::shared_ptr<NesterovBase> nb,
                   bool draw_bins)
    : pb_(pb),
      nb_(nb),
      np_(np),
      ip_(nullptr),
      selected_(nullptr),
      draw_bins_(draw_bins),
      logger_(logger)
{
  gui::Gui::get()->registerRenderer(this);
}

void Graphics::drawBounds(gui::Painter& painter)
{
  // draw core bounds
  auto& die = pb_->die();
  painter.setPen(gui::Painter::yellow, /* cosmetic */ true);
  painter.drawLine(die.coreLx(), die.coreLy(), die.coreUx(), die.coreLy());
  painter.drawLine(die.coreUx(), die.coreLy(), die.coreUx(), die.coreUy());
  painter.drawLine(die.coreUx(), die.coreUy(), die.coreLx(), die.coreUy());
  painter.drawLine(die.coreLx(), die.coreUy(), die.coreLx(), die.coreLy());
}

void Graphics::drawInitial(gui::Painter& painter)
{
  drawBounds(painter);

  painter.setPen(gui::Painter::white, /* cosmetic */ true);
  for (auto& inst : pb_->placeInsts()) {
    int lx = inst->lx();
    int ly = inst->ly();
    int ux = inst->ux();
    int uy = inst->uy();

    gui::Painter::Color color = gui::Painter::dark_green;
    color.a = 180;
    painter.setBrush(color);
    painter.drawRect({lx, ly, ux, uy});
  }
}

void Graphics::drawNesterov(gui::Painter& painter)
{
  drawBounds(painter);
  if (draw_bins_) {
    // Draw the bins
    painter.setPen(gui::Painter::white, /* cosmetic */ true);
    for (auto& bin : nb_->bins()) {
      int color = bin->density() * 50 + 20;

      color = (color > 255) ? 255 : (color < 20) ? 20 : color;
      color = 255 - color;

      painter.setBrush({color, color, color, 180});
      painter.drawRect({bin->lx(), bin->ly(), bin->ux(), bin->uy()});
    }
  }

  // Draw the placeable objects
  painter.setPen(gui::Painter::white);
  for (auto* gCell : nb_->gCells()) {
    const int gcx = gCell->dCx();
    const int gcy = gCell->dCy();

    int xl = gcx - gCell->dx() / 2;
    int yl = gcy - gCell->dy() / 2;
    int xh = gcx + gCell->dx() / 2;
    int yh = gcy + gCell->dy() / 2;

    gui::Painter::Color color;
    if (gCell->isInstance()) {
      color = gui::Painter::dark_green;
    } else if (gCell->isFiller()) {
      color = gui::Painter::dark_magenta;
    }
    if (gCell == selected_) {
      color = gui::Painter::yellow;
    }

    color.a = 180;
    painter.setBrush(color);
    painter.drawRect({xl, yl, xh, yh});
  }

  // Draw lines to neighbors
  if (selected_) {
    painter.setPen(gui::Painter::yellow, true);
    for (GPin* pin : selected_->gPins()) {
      GNet* net = pin->gNet();
      if (!net) {
        continue;
      }
      for (GPin* other_pin : net->gPins()) {
        GCell* neighbor = other_pin->gCell();
        if (neighbor == selected_) {
          continue;
        }
        painter.drawLine(
            pin->cx(), pin->cy(), other_pin->cx(), other_pin->cy());
      }
    }
  }

  // Draw force direction lines
  if (draw_bins_) {
    float efMax = 0;
    int max_len = std::numeric_limits<int>::max();
    for (auto& bin : nb_->bins()) {
      efMax
          = std::max(efMax, hypot(bin->electroForceX(), bin->electroForceY()));
      max_len = std::min({max_len, bin->dx(), bin->dy()});
    }

    for (auto& bin : nb_->bins()) {
      float fx = bin->electroForceX();
      float fy = bin->electroForceY();
      float f = hypot(fx, fy);
      float ratio = f / efMax;
      float dx = fx / f * max_len * ratio;
      float dy = fy / f * max_len * ratio;

      int cx = bin->cx();
      int cy = bin->cy();

      painter.setPen(gui::Painter::red, true);
      painter.drawLine(cx, cy, cx + dx, cy + dy);
    }
  }
}

void Graphics::drawObjects(gui::Painter& painter)
{
  if (nb_) {
    drawNesterov(painter);
  } else {
    drawInitial(painter);
  }
}

void Graphics::reportSelected()
{
  if (!selected_) {
    return;
  }
  auto instance = selected_->instance();
  logger_->report("Inst: {}", instance->dbInst()->getName());

  if (np_) {
    auto wlCoeffX = np_->getWireLengthCoefX();
    auto wlCoeffY = np_->getWireLengthCoefY();

    logger_->report("  Wire Length Gradient");
    for (auto& gPin : selected_->gPins()) {
      FloatPoint wlGrad
          = nb_->getWireLengthGradientPinWA(gPin, wlCoeffX, wlCoeffY);
      logger_->report("          ({:+.2e}, {:+.2e}) pin {}",
                      wlGrad.x,
                      wlGrad.y,
                      gPin->pin()->name());
    }

    FloatPoint wlGrad
        = nb_->getWireLengthGradientWA(selected_, wlCoeffX, wlCoeffY);
    logger_->report("  sum wl  ({: .2e}, {: .2e})", wlGrad.x, wlGrad.y);

    auto densityGrad = nb_->getDensityGradient(selected_);
    float densityPenalty = np_->getDensityPenalty();
    logger_->report("  density ({: .2e}, {: .2e}) (penalty: {})",
                    densityPenalty * densityGrad.x,
                    densityPenalty * densityGrad.y,
                    densityPenalty);
    logger_->report("  overall ({: .2e}, {: .2e})",
                    wlGrad.x + densityPenalty * densityGrad.x,
                    wlGrad.y + densityPenalty * densityGrad.y);
  }
}

void Graphics::cellPlot(bool pause)
{
  gui::Gui::get()->redraw();
  if (pause) {
    reportSelected();
    gui::Gui::get()->pause();
  }
}

gui::Selected Graphics::select(odb::dbTechLayer* layer, const odb::Point& point)
{
  selected_ = nullptr;

  if (layer || !nb_) {
    return gui::Selected();
  }

  for (GCell* cell : nb_->gCells()) {
    const int gcx = cell->dCx();
    const int gcy = cell->dCy();

    int xl = gcx - cell->dx() / 2;
    int yl = gcy - cell->dy() / 2;
    int xh = gcx + cell->dx() / 2;
    int yh = gcy + cell->dy() / 2;

    if (point.x() < xl || point.y() < yl || point.x() > xh || point.y() > yh) {
      continue;
    }

    selected_ = cell;
    if (cell->isInstance()) {
      reportSelected();
      return gui::Selected(cell->instance()->dbInst());
    }
  }
  return gui::Selected();
}

void Graphics::status(const std::string& message)
{
  gui::Gui::get()->status(message);
}

/* static */
bool Graphics::guiActive()
{
  return gui::Gui::get() != nullptr;
}

}  // namespace gpl
<|endoftext|>