<commit_before>/*
 * Copyright 2011-2019 Branimir Karadzic. All rights reserved.
 * License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause
 */

#include "bgfx_p.h"

#if BGFX_CONFIG_RENDERER_OPENGLES
#	include "renderer_gl.h"

#	if BGFX_USE_HTML5

#include <emscripten/emscripten.h>
#include <emscripten/html5.h>

// from emscripten gl.c, because we're not going to go
// through egl
extern "C" void* emscripten_GetProcAddress(const char *name_);
extern "C" void* emscripten_webgl1_get_proc_address(const char *name_);
extern "C" void* emscripten_webgl2_get_proc_address(const char *name_);

namespace bgfx { namespace gl
{

#	define GL_IMPORT(_optional, _proto, _func, _import) _proto _func = NULL
#	include "glimports.h"

	static EmscriptenWebGLContextAttributes s_attrs;

	struct SwapChainGL
	{
		SwapChainGL(int _context, const char* _canvas)
			: m_context(_context)
		{
			BX_ALLOC(g_allocator, strlen(_canvas) + 1);
			strcpy(m_canvas, _canvas);

			makeCurrent();
			GL_CHECK(glClearColor(0.0f, 0.0f, 0.0f, 0.0f) );
			GL_CHECK(glClear(GL_COLOR_BUFFER_BIT) );
			swapBuffers();
			GL_CHECK(glClear(GL_COLOR_BUFFER_BIT) );
			swapBuffers();
		}

		~SwapChainGL()
		{
			emscripten_webgl_destroy_context(m_context);
			BX_FREE(g_allocator, m_canvas);
		}

		void makeCurrent()
		{
			emscripten_webgl_make_context_current(m_context);
		}

		void swapBuffers()
		{
			// There is no swapBuffers equivalent.  A swap happens whenever control is returned back
			// to the browser.
		}

		int m_context;
		char* m_canvas;
	};

	void GlContext::create(uint32_t _width, uint32_t _height)
	{
		// assert?
		if (m_primary != NULL)
			return;

		const char* canvas = (const char*) g_platformData.nwh; // if 0, Module.canvas is used

		m_primary = createSwapChain((void*)canvas);

		if (_width && _height)
			emscripten_set_canvas_element_size(canvas, (int)_width, (int)_height);

		makeCurrent(m_primary);
	}

	void GlContext::destroy()
	{
		if (m_primary)
		{
			if (m_current == m_primary)
				m_current = NULL;
			BX_DELETE(g_allocator, m_primary);
			m_primary = NULL;
		}
	}

	void GlContext::resize(uint32_t _width, uint32_t _height, uint32_t /* _flags */)
    {
		if (m_primary == NULL)
			return;

		emscripten_set_canvas_element_size(m_primary->m_canvas, (int) _width, (int) _height);
    }

	SwapChainGL* GlContext::createSwapChain(void* _nwh)
	{
		emscripten_webgl_init_context_attributes(&s_attrs);

		s_attrs.alpha = false;
		s_attrs.depth = true;
		s_attrs.stencil = true;
		s_attrs.enableExtensionsByDefault = true;

        // let emscripten figure out the best WebGL context to create
		// TODO this isn't necessarily the right thing, I don't think the code actually does the fallback like it should
		s_attrs.majorVersion = 0;
		s_attrs.majorVersion = 0;

		const char* canvas = (const char*) _nwh;

		int context = emscripten_webgl_create_context(canvas, &s_attrs);

		if (context <= 0)
		{
			BX_TRACE("Failed to create WebGL context.  (Canvas handle: '%s', error %d)", canvas, (int)context);
			return NULL;
		}

		int result = emscripten_webgl_make_context_current(context);
		if (EMSCRIPTEN_RESULT_SUCCESS != result)
		{
			BX_TRACE("emscripten_webgl_make_context_current failed (%d)", result);
			return NULL;
		}

		SwapChainGL* swapChain = BX_NEW(g_allocator, SwapChainGL)(context, canvas);

		import(1);

		return swapChain;
	}

	uint64_t GlContext::getCaps() const
	{
		return BGFX_CAPS_SWAP_CHAIN;
	}

	void GlContext::destroySwapChain(SwapChainGL* _swapChain)
	{
		BX_DELETE(g_allocator, _swapChain);
	}

	void GlContext::swap(SwapChainGL* /* _swapChain */)
	{
	}

	void GlContext::makeCurrent(SwapChainGL* _swapChain)
	{
		if (m_current != _swapChain)
		{
			m_current = _swapChain;

			if (NULL == _swapChain)
			{
				if (NULL != m_primary)
				{
					m_primary->makeCurrent();
				}
			}
			else
			{
				_swapChain->makeCurrent();
			}
		}
	}

	void GlContext::import(int webGLVersion)
	{
		BX_TRACE("Import:");
#		define GL_EXTENSION(_optional, _proto, _func, _import)                                                                                \
			{                                                                                \
				if (NULL == _func)                                                                                \
				{                                                                                \
					_func = (_proto)emscripten_webgl1_get_proc_address(#_import);                                                                                \
					if (!_func && webGLVersion >= 2)                                                                                \
					    _func = (_proto)emscripten_webgl2_get_proc_address(#_import);                                                                            \
					BX_TRACE("\t%p " #_func " (" #_import ")", _func);                                                                                \
					BGFX_FATAL(_optional || NULL != _func, Fatal::UnableToInitialize, "Failed to create WebGL/OpenGLES context. GetProcAddress(\"%s\")", #_import); \
				}                                                                                \
			}

#	include "glimports.h"
	}

} /* namespace gl */ } // namespace bgfx

#	endif // BGFX_USE_EGL
#endif // (BGFX_CONFIG_RENDERER_OPENGLES || BGFX_CONFIG_RENDERER_OPENGL)
<commit_msg>missing assignment to m_canvas on alloc<commit_after>/*
 * Copyright 2011-2019 Branimir Karadzic. All rights reserved.
 * License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause
 */

#include "bgfx_p.h"

#if BGFX_CONFIG_RENDERER_OPENGLES
#	include "renderer_gl.h"

#	if BGFX_USE_HTML5

#include <emscripten/emscripten.h>
#include <emscripten/html5.h>

// from emscripten gl.c, because we're not going to go
// through egl
extern "C" void* emscripten_GetProcAddress(const char *name_);
extern "C" void* emscripten_webgl1_get_proc_address(const char *name_);
extern "C" void* emscripten_webgl2_get_proc_address(const char *name_);

namespace bgfx { namespace gl
{

#	define GL_IMPORT(_optional, _proto, _func, _import) _proto _func = NULL
#	include "glimports.h"

	static EmscriptenWebGLContextAttributes s_attrs;

	struct SwapChainGL
	{
		SwapChainGL(int _context, const char* _canvas)
			: m_context(_context)
		{
			m_canvas = (char*)BX_ALLOC(g_allocator, strlen(_canvas) + 1);
			strcpy(m_canvas, _canvas);

			makeCurrent();
			GL_CHECK(glClearColor(0.0f, 0.0f, 0.0f, 0.0f) );
			GL_CHECK(glClear(GL_COLOR_BUFFER_BIT) );
			swapBuffers();
			GL_CHECK(glClear(GL_COLOR_BUFFER_BIT) );
			swapBuffers();
		}

		~SwapChainGL()
		{
			emscripten_webgl_destroy_context(m_context);
			BX_FREE(g_allocator, m_canvas);
		}

		void makeCurrent()
		{
			emscripten_webgl_make_context_current(m_context);
		}

		void swapBuffers()
		{
			// There is no swapBuffers equivalent.  A swap happens whenever control is returned back
			// to the browser.
		}

		int m_context;
		char* m_canvas;
	};

	void GlContext::create(uint32_t _width, uint32_t _height)
	{
		// assert?
		if (m_primary != NULL)
			return;

		const char* canvas = (const char*) g_platformData.nwh; // if 0, Module.canvas is used

		m_primary = createSwapChain((void*)canvas);

		if (_width && _height)
			emscripten_set_canvas_element_size(canvas, (int)_width, (int)_height);

		makeCurrent(m_primary);
	}

	void GlContext::destroy()
	{
		if (m_primary)
		{
			if (m_current == m_primary)
				m_current = NULL;
			BX_DELETE(g_allocator, m_primary);
			m_primary = NULL;
		}
	}

	void GlContext::resize(uint32_t _width, uint32_t _height, uint32_t /* _flags */)
    {
		if (m_primary == NULL)
			return;

		emscripten_set_canvas_element_size(m_primary->m_canvas, (int) _width, (int) _height);
    }

	SwapChainGL* GlContext::createSwapChain(void* _nwh)
	{
		emscripten_webgl_init_context_attributes(&s_attrs);

		s_attrs.alpha = false;
		s_attrs.depth = true;
		s_attrs.stencil = true;
		s_attrs.enableExtensionsByDefault = true;

        // let emscripten figure out the best WebGL context to create
		// TODO this isn't necessarily the right thing, I don't think the code actually does the fallback like it should
		s_attrs.majorVersion = 0;
		s_attrs.majorVersion = 0;

		const char* canvas = (const char*) _nwh;

		int context = emscripten_webgl_create_context(canvas, &s_attrs);

		if (context <= 0)
		{
			BX_TRACE("Failed to create WebGL context.  (Canvas handle: '%s', error %d)", canvas, (int)context);
			return NULL;
		}

		int result = emscripten_webgl_make_context_current(context);
		if (EMSCRIPTEN_RESULT_SUCCESS != result)
		{
			BX_TRACE("emscripten_webgl_make_context_current failed (%d)", result);
			return NULL;
		}

		SwapChainGL* swapChain = BX_NEW(g_allocator, SwapChainGL)(context, canvas);

		import(1);

		return swapChain;
	}

	uint64_t GlContext::getCaps() const
	{
		return BGFX_CAPS_SWAP_CHAIN;
	}

	void GlContext::destroySwapChain(SwapChainGL* _swapChain)
	{
		BX_DELETE(g_allocator, _swapChain);
	}

	void GlContext::swap(SwapChainGL* /* _swapChain */)
	{
	}

	void GlContext::makeCurrent(SwapChainGL* _swapChain)
	{
		if (m_current != _swapChain)
		{
			m_current = _swapChain;

			if (NULL == _swapChain)
			{
				if (NULL != m_primary)
				{
					m_primary->makeCurrent();
				}
			}
			else
			{
				_swapChain->makeCurrent();
			}
		}
	}

	void GlContext::import(int webGLVersion)
	{
		BX_TRACE("Import:");
#		define GL_EXTENSION(_optional, _proto, _func, _import)                                                                                \
			{                                                                                \
				if (NULL == _func)                                                                                \
				{                                                                                \
					_func = (_proto)emscripten_webgl1_get_proc_address(#_import);                                                                                \
					if (!_func && webGLVersion >= 2)                                                                                \
					    _func = (_proto)emscripten_webgl2_get_proc_address(#_import);                                                                            \
					BX_TRACE("\t%p " #_func " (" #_import ")", _func);                                                                                \
					BGFX_FATAL(_optional || NULL != _func, Fatal::UnableToInitialize, "Failed to create WebGL/OpenGLES context. GetProcAddress(\"%s\")", #_import); \
				}                                                                                \
			}

#	include "glimports.h"
	}

} /* namespace gl */ } // namespace bgfx

#	endif // BGFX_USE_EGL
#endif // (BGFX_CONFIG_RENDERER_OPENGLES || BGFX_CONFIG_RENDERER_OPENGL)
<|endoftext|>


<commit_before>#include "stdafx.h"
#include <boost/lexical_cast.hpp>
#include "operation.h"
#include "operations/post_operation.h"
#include "operations/put_operation.h"
#include "operations/erase_operation.h"
#include "internal_transaction.h"
#include "internal_datastore.h"

namespace You {
namespace DataStore {
namespace Internal {

const std::wstring DataStore::FILE_PATH = std::wstring(L"data.xml");

DataStore& DataStore::get() {
	static DataStore store;
	return store;
}

You::DataStore::Transaction DataStore::begin() {
	You::DataStore::Transaction result;
	transactionStack.push(std::weak_ptr<Internal::Transaction>(result));

	return result;
}

void DataStore::onTransactionCommit(Transaction& transaction) {
	pugi::xml_document temp;
	temp.reset(document);
	for (auto iter = transaction.operationsQueue.begin();
		iter != transaction.operationsQueue.end();
		++iter) {
		if (!iter->run(temp)) {
			// TODO(digawp): this is not necessarily the best thing to do.
			return transaction.rollback();
		}
	}
	document.reset(temp);
}

void DataStore::onTransactionRollback(Transaction& transaction) {
	transaction.operationsQueue.clear();
}

bool DataStore::post(TaskId rawId, const SerializedTask& sTask) {
	std::unique_ptr<Internal::IOperation> operation =
		std::make_unique<Internal::PostOperation>(rawId, sTask);

	if (!transactionStack.empty()) {
		if (auto transaction = transactionStack.top().lock()) {
			transaction->push(std::move(operation));
			return true;
		}
	}

	return operation->run(document);
}

bool DataStore::put(TaskId rawId, const SerializedTask& sTask) {
	std::unique_ptr<Internal::IOperation> operation =
		std::make_unique<Internal::PutOperation>(rawId, sTask);

	if (!transactionStack.empty()) {
		if (auto transaction = transactionStack.top().lock()) {
			transaction->push(std::move(operation));
			return true;
		}
	}

	return operation->run(document);
}

bool DataStore::erase(TaskId rawId) {
	std::unique_ptr<Internal::IOperation> operation =
		std::make_unique<Internal::EraseOperation>(rawId);
	if (!transactionStack.empty()) {
		if (auto transaction = transactionStack.top().lock()) {
			transaction->push(std::move(operation));
			return true;
		}
	}

	return operation->run(document);
}

SerializedTask DataStore::getTask(TaskId rawId) {
	std::wstring taskId = boost::lexical_cast<std::wstring>(rawId);
	pugi::xml_node toGet =
		document.find_child_by_attribute(L"id", taskId.c_str());

	return SerializationOperation::deserialize(toGet);
}

std::vector<SerializedTask> DataStore::getAllTask() {
	loadData();
	std::vector<SerializedTask> allTask;
	for (auto i = document.begin(); i != document.end(); ++i) {
		pugi::xml_node test = *i;
		// FOR SOME REASON IT IS A PCDATA
		if (test.type() == pugi::xml_node_type::node_pcdata) {
			throw "Fffff";
		}
		allTask.push_back(SerializationOperation::deserialize(*i));
	}
	return allTask;
}

bool DataStore::saveData() {
	bool status = document.save_file(FILE_PATH.c_str());
	return status;
}

void DataStore::loadData() {
	bool isInitialized =
		document.first_child().type() != pugi::xml_node_type::node_null;
	if (!isInitialized) {
		pugi::xml_parse_result status = document.load_file(FILE_PATH.c_str());

		// Not sure if the if block below is necessary
		if (status == pugi::xml_parse_status::status_file_not_found) {
			document.reset();
		}
	}
}

}  // namespace Internal
}  // namespace DataStore
}  // namespace You
<commit_msg>Remove unnecessary codes in getAllTask<commit_after>#include "stdafx.h"
#include <boost/lexical_cast.hpp>
#include "operation.h"
#include "operations/post_operation.h"
#include "operations/put_operation.h"
#include "operations/erase_operation.h"
#include "internal_transaction.h"
#include "internal_datastore.h"

namespace You {
namespace DataStore {
namespace Internal {

const std::wstring DataStore::FILE_PATH = std::wstring(L"data.xml");

DataStore& DataStore::get() {
	static DataStore store;
	return store;
}

You::DataStore::Transaction DataStore::begin() {
	You::DataStore::Transaction result;
	transactionStack.push(std::weak_ptr<Internal::Transaction>(result));

	return result;
}

void DataStore::onTransactionCommit(Transaction& transaction) {
	pugi::xml_document temp;
	temp.reset(document);
	for (auto iter = transaction.operationsQueue.begin();
		iter != transaction.operationsQueue.end();
		++iter) {
		if (!iter->run(temp)) {
			// TODO(digawp): this is not necessarily the best thing to do.
			return transaction.rollback();
		}
	}
	document.reset(temp);
}

void DataStore::onTransactionRollback(Transaction& transaction) {
	transaction.operationsQueue.clear();
}

bool DataStore::post(TaskId rawId, const SerializedTask& sTask) {
	std::unique_ptr<Internal::IOperation> operation =
		std::make_unique<Internal::PostOperation>(rawId, sTask);

	if (!transactionStack.empty()) {
		if (auto transaction = transactionStack.top().lock()) {
			transaction->push(std::move(operation));
			return true;
		}
	}

	return operation->run(document);
}

bool DataStore::put(TaskId rawId, const SerializedTask& sTask) {
	std::unique_ptr<Internal::IOperation> operation =
		std::make_unique<Internal::PutOperation>(rawId, sTask);

	if (!transactionStack.empty()) {
		if (auto transaction = transactionStack.top().lock()) {
			transaction->push(std::move(operation));
			return true;
		}
	}

	return operation->run(document);
}

bool DataStore::erase(TaskId rawId) {
	std::unique_ptr<Internal::IOperation> operation =
		std::make_unique<Internal::EraseOperation>(rawId);
	if (!transactionStack.empty()) {
		if (auto transaction = transactionStack.top().lock()) {
			transaction->push(std::move(operation));
			return true;
		}
	}

	return operation->run(document);
}

SerializedTask DataStore::getTask(TaskId rawId) {
	std::wstring taskId = boost::lexical_cast<std::wstring>(rawId);
	pugi::xml_node toGet =
		document.find_child_by_attribute(L"id", taskId.c_str());

	return SerializationOperation::deserialize(toGet);
}

std::vector<SerializedTask> DataStore::getAllTask() {
	loadData();
	std::vector<SerializedTask> allTask;
	for (auto i = document.begin(); i != document.end(); ++i) {
		allTask.push_back(SerializationOperation::deserialize(*i));
	}
	return allTask;
}

bool DataStore::saveData() {
	bool status = document.save_file(FILE_PATH.c_str());
	return status;
}

void DataStore::loadData() {
	bool isInitialized =
		document.first_child().type() != pugi::xml_node_type::node_null;
	if (!isInitialized) {
		pugi::xml_parse_result status = document.load_file(FILE_PATH.c_str());

		// Not sure if the if block below is necessary
		if (status == pugi::xml_parse_status::status_file_not_found) {
			document.reset();
		}
	}
}

}  // namespace Internal
}  // namespace DataStore
}  // namespace You
<|endoftext|>


<commit_before>//@author A0097630B
#include "stdafx.h"
#include "query_parser.h"

using Assert = Microsoft::VisualStudio::CppUnitTestFramework::Assert;

namespace You {
namespace NLP {
namespace UnitTests {

using You::NLP::EDIT_QUERY;

TEST_CLASS(EditQueryTests) {
public:
	TEST_METHOD(fieldsBinaryOr) {
		EDIT_QUERY::Fields lhs;
		EDIT_QUERY::Fields rhs;

		Assert::AreEqual(
			static_cast<size_t>(lhs) | static_cast<size_t>(rhs),
			static_cast<size_t>(lhs | rhs));
	}

	TEST_METHOD(fieldsBinaryAnd) {
		EDIT_QUERY::Fields lhs;
		EDIT_QUERY::Fields rhs;

		Assert::AreEqual(
			static_cast<size_t>(lhs) & static_cast<size_t>(rhs),
			static_cast<size_t>(lhs & rhs));
	}

	TEST_METHOD(convertsToStream) {
		{
			std::wostringstream stream;
			stream << DUMMY;
			Assert::AreEqual(
				std::wstring(L"Edit task #1 (Description => the lols)"),
				stream.str());
		}

		{  // NOLINT(whitespace/braces)
			EDIT_QUERY local = DUMMY;
			local.deadline = boost::posix_time::ptime(
				boost::gregorian::date(1970, boost::gregorian::Jan, 1),
				boost::posix_time::hours(0));

			std::wostringstream stream;
			stream << local;
			Assert::AreEqual(
				std::wstring(L"Edit task #1 (Description => the lols, "
					L"Deadline => 1970-Jan-01 00:00:00)"),
				stream.str());
		}

		{  // NOLINT(whitespace/braces)
			EDIT_QUERY local = DUMMY;
			local.priority = TaskPriority::HIGH;

			std::wostringstream stream;
			stream << local;
			Assert::AreEqual(
				std::wstring(L"Edit task #1 (Description => the lols, "
				L"Priority => 1)"),
				stream.str());
		}
	}

	TEST_METHOD(convertsToString) {
		Assert::AreEqual(
			std::wstring(L"Edit task #1 (Description => the lols)"),
			boost::lexical_cast<std::wstring>(DUMMY));
	}

	TEST_METHOD(comparesEquality) {
		EDIT_QUERY local = DUMMY;

		Assert::AreEqual(DUMMY, local);
	}

	TEST_METHOD(comparesInequality) {
		EDIT_QUERY local {
			DUMMY.taskID,
			DUMMY.description
		};

		Assert::AreEqual(DUMMY, local);

		EDIT_QUERY local2 = local;
		local2.taskID++;
		Assert::AreNotEqual(DUMMY, local2);

		local2 = local;
		local2.description = std::wstring(L"");
		Assert::AreNotEqual(DUMMY, local2);

		local2 = local;
		local2.deadline = boost::posix_time::ptime(
			boost::gregorian::date(1970, 1, 1),
			boost::posix_time::hours(1));
		Assert::AreNotEqual(local, local2);

		local2 = local;
		local2.priority = TaskPriority::HIGH;
		Assert::AreNotEqual(local, local2);

		local2 = local;
		local2.complete = true;
		Assert::AreNotEqual(local, local2);
	}

private:
	/// A dummy object.
	static const EDIT_QUERY DUMMY;
};

const EDIT_QUERY EditQueryTests::DUMMY {
	1,
	L"the lols"
};

}  // namespace UnitTests
}  // namespace NLP
}  // namespace You
<commit_msg>Fix warning.<commit_after>//@author A0097630B
#include "stdafx.h"
#include "query_parser.h"

using Assert = Microsoft::VisualStudio::CppUnitTestFramework::Assert;

namespace You {
namespace NLP {
namespace UnitTests {

using You::NLP::EDIT_QUERY;

TEST_CLASS(EditQueryTests) {
public:
	TEST_METHOD(fieldsBinaryOr) {
		TaskField lhs = TaskField::COMPLETE;
		TaskField rhs = TaskField::PRIORITY;

		Assert::AreEqual(
			static_cast<size_t>(lhs) | static_cast<size_t>(rhs),
			static_cast<size_t>(lhs | rhs));
	}

	TEST_METHOD(fieldsBinaryAnd) {
		TaskField lhs = TaskField::COMPLETE;
		TaskField rhs = TaskField::PRIORITY;

		Assert::AreEqual(
			static_cast<size_t>(lhs) & static_cast<size_t>(rhs),
			static_cast<size_t>(lhs & rhs));
	}

	TEST_METHOD(convertsToStream) {
		{
			std::wostringstream stream;
			stream << DUMMY;
			Assert::AreEqual(
				std::wstring(L"Edit task #1 (Description => the lols)"),
				stream.str());
		}

		{  // NOLINT(whitespace/braces)
			EDIT_QUERY local = DUMMY;
			local.deadline = boost::posix_time::ptime(
				boost::gregorian::date(1970, boost::gregorian::Jan, 1),
				boost::posix_time::hours(0));

			std::wostringstream stream;
			stream << local;
			Assert::AreEqual(
				std::wstring(L"Edit task #1 (Description => the lols, "
					L"Deadline => 1970-Jan-01 00:00:00)"),
				stream.str());
		}

		{  // NOLINT(whitespace/braces)
			EDIT_QUERY local = DUMMY;
			local.priority = TaskPriority::HIGH;

			std::wostringstream stream;
			stream << local;
			Assert::AreEqual(
				std::wstring(L"Edit task #1 (Description => the lols, "
				L"Priority => 1)"),
				stream.str());
		}
	}

	TEST_METHOD(convertsToString) {
		Assert::AreEqual(
			std::wstring(L"Edit task #1 (Description => the lols)"),
			boost::lexical_cast<std::wstring>(DUMMY));
	}

	TEST_METHOD(comparesEquality) {
		EDIT_QUERY local = DUMMY;

		Assert::AreEqual(DUMMY, local);
	}

	TEST_METHOD(comparesInequality) {
		EDIT_QUERY local {
			DUMMY.taskID,
			DUMMY.description
		};

		Assert::AreEqual(DUMMY, local);

		EDIT_QUERY local2 = local;
		local2.taskID++;
		Assert::AreNotEqual(DUMMY, local2);

		local2 = local;
		local2.description = std::wstring(L"");
		Assert::AreNotEqual(DUMMY, local2);

		local2 = local;
		local2.deadline = boost::posix_time::ptime(
			boost::gregorian::date(1970, 1, 1),
			boost::posix_time::hours(1));
		Assert::AreNotEqual(local, local2);

		local2 = local;
		local2.priority = TaskPriority::HIGH;
		Assert::AreNotEqual(local, local2);

		local2 = local;
		local2.complete = true;
		Assert::AreNotEqual(local, local2);
	}

private:
	/// A dummy object.
	static const EDIT_QUERY DUMMY;
};

const EDIT_QUERY EditQueryTests::DUMMY {
	1,
	L"the lols"
};

}  // namespace UnitTests
}  // namespace NLP
}  // namespace You
<|endoftext|>


<commit_before>#include "cssysdef.h"
#include "awstimer.h"
#include "awstxtbx.h"
#include "ivideo/graph2d.h"
#include "ivideo/graph3d.h"
#include "ivideo/fontserv.h"
#include "csutil/scfstr.h"
#include "iutil/evdefs.h"
#include "csutil/csctype.h"

#include <stdio.h>

const int awsTextBox::fsNormal = 0x0;
const int awsTextBox::fsBitmap = 0x1;

const int awsTextBox::signalChanged = 0x1;
const int awsTextBox::signalLostFocus = 0x2;
const int awsTextBox::signalEnterPressed = 0x3;
const int awsTextBox::signalTabPressed = 0x4;

static iAwsSink *textbox_sink = 0;

CS_IMPLEMENT_STATIC_VAR (GetTextBoxBlinkingCursorSlot, awsSlot,())

static awsSlot *textbox_slot = NULL;

static void BlinkCursor (void *, iAwsSource *source)
{
  iAwsComponent *comp = source->GetComponent ();

  //  Setting blink actually forces an inversion of blink's property, and if the textbox is the

  // focus then it will be Invalidated as well.
  comp->SetProperty ("Blink", 0);
}

awsTextBox::awsTextBox () :
  mouse_is_over(false),
  has_focus(false),
  should_mask(0),
  bkg(NULL),
  frame_style(0),
  alpha_level(92),
  text(NULL),
  disallow(NULL),
  maskchar(NULL),
  start(0),
  cursor(0),
  blink_timer(NULL),
  blink(true)
{
  textbox_slot = GetTextBoxBlinkingCursorSlot ();
}

awsTextBox::~awsTextBox ()
{
  if (blink_timer != 0)
  {
    textbox_slot->Disconnect (
        blink_timer,
        awsTimer::signalTick,
        textbox_sink,
        textbox_sink->GetTriggerID ("Blink"));
    delete blink_timer;
  }
}

const char *awsTextBox::Type ()
{
  return "Text Box";
}

bool awsTextBox::Setup (iAws *_wmgr, iAwsComponentNode *settings)
{
  if (!awsComponent::Setup (_wmgr, settings)) return false;

  // Setup blink event handling
  if (textbox_sink == 0)
  {
    textbox_sink = WindowManager ()->GetSinkMgr ()->CreateSink (NULL);
    textbox_sink->RegisterTrigger ("Blink", &BlinkCursor);
  }

  blink_timer = new awsTimer (WindowManager ()->GetObjectRegistry (), this);
  blink_timer->SetTimer (350);
  blink_timer->Start ();

  textbox_slot->Connect (
      blink_timer,
      awsTimer::signalTick,
      textbox_sink,
      textbox_sink->GetTriggerID ("Blink"));

  ////////////////
  iAwsPrefManager *pm = WindowManager ()->GetPrefMgr ();

  pm->LookupIntKey ("ButtonTextureAlpha", alpha_level); // global get
  pm->GetInt (settings, "Style", frame_style);
  pm->GetInt (settings, "Alpha", alpha_level);          // local overrides, if present.
  pm->GetInt (settings, "Masked", should_mask);
  pm->GetString (settings, "Text", text);
  pm->GetString (settings, "Disallow", disallow);
  pm->GetString (settings, "MaskChar", maskchar);

  if (text) {
      cursor = text->Length ();
      text = new scfString(*text);
  } else
    text = new scfString ();

  switch (frame_style)
  {
    case fsNormal:
      bkg = pm->GetTexture ("Texture");
      break;

    case fsBitmap:
      {
        iString *tn1 = NULL;

        pm->GetString (settings, "Bitmap", tn1);

        if (tn1) bkg = pm->GetTexture (tn1->GetData (), tn1->GetData ());
      }
      break;
  }

  return true;
}

bool awsTextBox::GetProperty (const char *name, void **parm)
{
  if (awsComponent::GetProperty (name, parm)) return true;

  if (strcmp ("Text", name) == 0)
  {
    char *st = NULL;

    if (text) st = text->GetData ();

    iString *s = new scfString (st);
    *parm = (void *)s;
    return true;
  }
  else if (strcmp ("Disallow", name) == 0)
  {
    char *st = NULL;

    if (disallow) st = disallow->GetData ();

    iString *s = new scfString (st);
    *parm = (void *)s;
    return true;
  }

  return false;
}

bool awsTextBox::SetProperty (const char *name, void *parm)
{
  if (awsComponent::SetProperty (name, parm)) return true;

  if (strcmp ("Blink", name) == 0)
  {
    blink = !blink;
    if (has_focus) Invalidate ();
    return true;
  }
  else if (strcmp ("Text", name) == 0)
  {
    iString *s = (iString *) (parm);

    if (s)
    {
      if (text) text->DecRef ();
      text = s;
      text->IncRef ();
      Invalidate ();
      start = 0;
      cursor = 0;
    }

    return true;
  }
  else if (strcmp ("Disallow", name) == 0)
  {
    iString *s = (iString *) (parm);

    if (s)
    {
      if (disallow) disallow->DecRef ();
      disallow = s;
      disallow->IncRef ();
    }

    return true;
  }

  return false;
}

void awsTextBox::OnDraw (csRect /*clip*/)
{
  iGraphics2D *g2d = WindowManager ()->G2D ();
  iGraphics3D *g3d = WindowManager ()->G3D ();

  int hi = WindowManager ()->GetPrefMgr ()->GetColor (AC_HIGHLIGHT);
  int hi2 = WindowManager ()->GetPrefMgr ()->GetColor (AC_HIGHLIGHT2);
  int lo = WindowManager ()->GetPrefMgr ()->GetColor (AC_SHADOW);
  int lo2 = WindowManager ()->GetPrefMgr ()->GetColor (AC_SHADOW2);
  int dfill = WindowManager ()->GetPrefMgr ()->GetColor (AC_DARKFILL);
  int black = WindowManager ()->GetPrefMgr ()->GetColor (AC_BLACK);

  switch (frame_style)
  {
    case fsNormal:
      g2d->DrawLine (
          Frame ().xmin + 0,
          Frame ().ymin + 0,
          Frame ().xmax - 1,
          Frame ().ymin + 0,
          lo2);
      g2d->DrawLine (
          Frame ().xmin + 0,
          Frame ().ymin + 0,
          Frame ().xmin + 0,
          Frame ().ymax - 1,
          lo2);
      g2d->DrawLine (
          Frame ().xmin + 1,
          Frame ().ymin + 1,
          Frame ().xmax - 0,
          Frame ().ymin + 1,
          lo);
      g2d->DrawLine (
          Frame ().xmin + 1,
          Frame ().ymin + 1,
          Frame ().xmin + 1,
          Frame ().ymax - 0,
          lo);
      g2d->DrawLine (
          Frame ().xmin + 1,
          Frame ().ymax - 0,
          Frame ().xmax - 0,
          Frame ().ymax - 0,
          hi);
      g2d->DrawLine (
          Frame ().xmax - 0,
          Frame ().ymin + 1,
          Frame ().xmax - 0,
          Frame ().ymax - 0,
          hi);

      g2d->DrawLine (
          Frame ().xmin + 2,
          Frame ().ymin + 2,
          Frame ().xmax - 1,
          Frame ().ymin + 2,
          black);
      g2d->DrawLine (
          Frame ().xmin + 2,
          Frame ().ymin + 2,
          Frame ().xmin + 2,
          Frame ().ymax - 1,
          black);
      g2d->DrawLine (
          Frame ().xmin + 2,
          Frame ().ymax - 1,
          Frame ().xmax - 1,
          Frame ().ymax - 1,
          hi2);
      g2d->DrawLine (
          Frame ().xmax - 1,
          Frame ().ymin + 2,
          Frame ().xmax - 1,
          Frame ().ymax - 1,
          hi2);

      g2d->DrawBox (
          Frame ().xmin + 3,
          Frame ().ymin + 3,
          Frame ().Width () - 3,
          Frame ().Height () - 3,
          dfill);

      if (bkg)
      {
        g3d->DrawPixmap (
            bkg,
            Frame ().xmin,
            Frame ().ymin,
            Frame ().Width () + 1,
            Frame ().Height () + 1,
            0,
            0,
            Frame ().Width () + 1,
            Frame ().Height () + 1,
            alpha_level);
      }
      break;

    case fsBitmap:
      if (bkg)
      {
        g3d->DrawPixmap (
            bkg,
            Frame ().xmin,
            Frame ().ymin,
            Frame ().Width (),
            Frame ().Height (),
            0,
            0,
            Frame ().Width (),
            Frame ().Height (),
            alpha_level);
      }
      break;
  }

  // Draw the caption, if there is one and the style permits it.
  if (text && text->Length ())
  {
    int tw, th, tx, ty, mcc;
    iString *saved = NULL;

    if (should_mask && maskchar)
    {
      saved = text->Clone ();

      unsigned int i;
      for (i = 0; i < text->Length (); ++i)
        text->SetAt (i, maskchar->GetAt (0));
    }

    // Get the maximum number of characters we can use
    mcc = WindowManager ()->GetPrefMgr ()->GetDefaultFont ()->GetLength (
        text->GetData () + start,
        Frame ().Width () - 10);

    if (mcc)
    {

      // Check to see if we're getting wierd.
      start = cursor - mcc;
      if (start < 0) start = 0;

      // Make the text the right length
      scfString tmp (text->GetData () + start);
      tmp.Truncate (mcc);

      // Get the size of the text
      WindowManager ()->GetPrefMgr ()->GetDefaultFont ()->
          GetDimensions (tmp.GetData (), tw, th);

      // Calculate the center
      tx = 4;
      ty = (Frame ().Height () >> 1) - (th >> 1);

      // Draw the text
      g2d->Write (
      WindowManager ()->GetPrefMgr ()->GetDefaultFont (),
      Frame ().xmin + tx,
      Frame ().ymin + ty,
      WindowManager ()->GetPrefMgr ()->GetColor (AC_TEXTFORE),
      -1,
      tmp.GetData ());

      if (should_mask && maskchar && saved)
      {
    text->Clear ();
    text->Append (saved);
    saved->Clear ();
    saved->DecRef ();
      }

    if (has_focus && blink)
    {
      g2d->DrawLine (
          Frame ().xmin + tx + tw + 1,
          Frame ().ymin + ty,
          Frame ().xmin + tx + tw + 1,
          Frame ().ymin + ty + th,
          WindowManager ()->GetPrefMgr ()->GetColor (AC_TEXTFORE));
    }
    }
  }
  else if (has_focus && blink)
  {
    g2d->DrawLine (
        Frame ().xmin + 5,
        Frame ().ymin + 5,
        Frame ().xmin + 5,
        Frame ().ymax - 5,
        WindowManager ()->GetPrefMgr ()->GetColor (AC_TEXTFORE));
  }
}

bool awsTextBox::OnMouseDown (int, int, int)
{
  /// This is needed to get keyboard focus for the mouse!
  return true;
}

bool awsTextBox::OnMouseExit ()
{
  mouse_is_over = false;
  Invalidate ();
  return true;
}

bool awsTextBox::OnMouseEnter ()
{
  mouse_is_over = true;
  Invalidate ();
  return true;
}

bool awsTextBox::OnKeypress (int key, int Char, int)
{
  switch (key)
  {
    case CSKEY_ENTER:
      Broadcast (signalEnterPressed);
      break;

    case CSKEY_TAB:
      Broadcast (signalTabPressed);
      break;

    case CSKEY_BACKSPACE:
      if (cursor > 0) cursor--;
      if (cursor - start < 5) start = cursor - 5;
      if (start < 0) start = 0;
      if (text && (text->Length () > 1))
        text->Truncate (text->Length () - 1);
      else
        text->Clear ();

      break;

    default:
      {
	if (!cs_isprint (Char))
	  break;

	if (disallow && (strchr (disallow->GetData (), Char) != 0))
	  break;

	char str[2];
	str[0] = (char)Char;
	str[1] = 0;

	printf ("Appending %c\n", Char);
	text->Append (str);
	cursor++;
	Broadcast (signalChanged);
      }
  }         // end switch
  Invalidate ();
  return true;
}

bool awsTextBox::OnLostFocus ()
{
  has_focus = false;
  Broadcast (signalLostFocus);
  Invalidate ();
  return true;
}

bool awsTextBox::OnGainFocus ()
{
  has_focus = true;
  Invalidate ();
  return true;
}

/************************************* Command Button Factory ****************/
awsTextBoxFactory::awsTextBoxFactory (iAws *wmgr) :
  awsComponentFactory(wmgr)
{
  Register ("Text Box");
  RegisterConstant ("tbfsNormal", awsTextBox::fsNormal);
  RegisterConstant ("tbfsBitmap", awsTextBox::fsBitmap);

  RegisterConstant ("signalTextBoxChanged", awsTextBox::signalChanged);
  RegisterConstant ("signalTextBoxLostFocus", awsTextBox::signalLostFocus);
  RegisterConstant ("signalEnterKeyPressed", awsTextBox::signalEnterPressed);
  RegisterConstant ("signalTabKeyPressed", awsTextBox::signalTabPressed);
}

awsTextBoxFactory::~awsTextBoxFactory ()
{
  // empty
}

iAwsComponent *awsTextBoxFactory::Create ()
{
  return new awsTextBox;
}
<commit_msg>removed debug code I left in awstextcomponent<commit_after>#include "cssysdef.h"
#include "awstimer.h"
#include "awstxtbx.h"
#include "ivideo/graph2d.h"
#include "ivideo/graph3d.h"
#include "ivideo/fontserv.h"
#include "csutil/scfstr.h"
#include "iutil/evdefs.h"
#include "csutil/csctype.h"

#include <stdio.h>

const int awsTextBox::fsNormal = 0x0;
const int awsTextBox::fsBitmap = 0x1;

const int awsTextBox::signalChanged = 0x1;
const int awsTextBox::signalLostFocus = 0x2;
const int awsTextBox::signalEnterPressed = 0x3;
const int awsTextBox::signalTabPressed = 0x4;

static iAwsSink *textbox_sink = 0;

CS_IMPLEMENT_STATIC_VAR (GetTextBoxBlinkingCursorSlot, awsSlot,())

static awsSlot *textbox_slot = NULL;

static void BlinkCursor (void *, iAwsSource *source)
{
  iAwsComponent *comp = source->GetComponent ();

  //  Setting blink actually forces an inversion of blink's property, and if the textbox is the

  // focus then it will be Invalidated as well.
  comp->SetProperty ("Blink", 0);
}

awsTextBox::awsTextBox () :
  mouse_is_over(false),
  has_focus(false),
  should_mask(0),
  bkg(NULL),
  frame_style(0),
  alpha_level(92),
  text(NULL),
  disallow(NULL),
  maskchar(NULL),
  start(0),
  cursor(0),
  blink_timer(NULL),
  blink(true)
{
  textbox_slot = GetTextBoxBlinkingCursorSlot ();
}

awsTextBox::~awsTextBox ()
{
  if (blink_timer != 0)
  {
    textbox_slot->Disconnect (
        blink_timer,
        awsTimer::signalTick,
        textbox_sink,
        textbox_sink->GetTriggerID ("Blink"));
    delete blink_timer;
  }
}

const char *awsTextBox::Type ()
{
  return "Text Box";
}

bool awsTextBox::Setup (iAws *_wmgr, iAwsComponentNode *settings)
{
  if (!awsComponent::Setup (_wmgr, settings)) return false;

  // Setup blink event handling
  if (textbox_sink == 0)
  {
    textbox_sink = WindowManager ()->GetSinkMgr ()->CreateSink (NULL);
    textbox_sink->RegisterTrigger ("Blink", &BlinkCursor);
  }

  blink_timer = new awsTimer (WindowManager ()->GetObjectRegistry (), this);
  blink_timer->SetTimer (350);
  blink_timer->Start ();

  textbox_slot->Connect (
      blink_timer,
      awsTimer::signalTick,
      textbox_sink,
      textbox_sink->GetTriggerID ("Blink"));

  ////////////////
  iAwsPrefManager *pm = WindowManager ()->GetPrefMgr ();

  pm->LookupIntKey ("ButtonTextureAlpha", alpha_level); // global get
  pm->GetInt (settings, "Style", frame_style);
  pm->GetInt (settings, "Alpha", alpha_level);          // local overrides, if present.
  pm->GetInt (settings, "Masked", should_mask);
  pm->GetString (settings, "Text", text);
  pm->GetString (settings, "Disallow", disallow);
  pm->GetString (settings, "MaskChar", maskchar);

  if (text) {
      cursor = text->Length ();
      text = new scfString(*text);
  } else
    text = new scfString ();

  switch (frame_style)
  {
    case fsNormal:
      bkg = pm->GetTexture ("Texture");
      break;

    case fsBitmap:
      {
        iString *tn1 = NULL;

        pm->GetString (settings, "Bitmap", tn1);

        if (tn1) bkg = pm->GetTexture (tn1->GetData (), tn1->GetData ());
      }
      break;
  }

  return true;
}

bool awsTextBox::GetProperty (const char *name, void **parm)
{
  if (awsComponent::GetProperty (name, parm)) return true;

  if (strcmp ("Text", name) == 0)
  {
    char *st = NULL;

    if (text) st = text->GetData ();

    iString *s = new scfString (st);
    *parm = (void *)s;
    return true;
  }
  else if (strcmp ("Disallow", name) == 0)
  {
    char *st = NULL;

    if (disallow) st = disallow->GetData ();

    iString *s = new scfString (st);
    *parm = (void *)s;
    return true;
  }

  return false;
}

bool awsTextBox::SetProperty (const char *name, void *parm)
{
  if (awsComponent::SetProperty (name, parm)) return true;

  if (strcmp ("Blink", name) == 0)
  {
    blink = !blink;
    if (has_focus) Invalidate ();
    return true;
  }
  else if (strcmp ("Text", name) == 0)
  {
    iString *s = (iString *) (parm);

    if (s)
    {
      if (text) text->DecRef ();
      text = s;
      text->IncRef ();
      Invalidate ();
      start = 0;
      cursor = 0;
    }

    return true;
  }
  else if (strcmp ("Disallow", name) == 0)
  {
    iString *s = (iString *) (parm);

    if (s)
    {
      if (disallow) disallow->DecRef ();
      disallow = s;
      disallow->IncRef ();
    }

    return true;
  }

  return false;
}

void awsTextBox::OnDraw (csRect /*clip*/)
{
  iGraphics2D *g2d = WindowManager ()->G2D ();
  iGraphics3D *g3d = WindowManager ()->G3D ();

  int hi = WindowManager ()->GetPrefMgr ()->GetColor (AC_HIGHLIGHT);
  int hi2 = WindowManager ()->GetPrefMgr ()->GetColor (AC_HIGHLIGHT2);
  int lo = WindowManager ()->GetPrefMgr ()->GetColor (AC_SHADOW);
  int lo2 = WindowManager ()->GetPrefMgr ()->GetColor (AC_SHADOW2);
  int dfill = WindowManager ()->GetPrefMgr ()->GetColor (AC_DARKFILL);
  int black = WindowManager ()->GetPrefMgr ()->GetColor (AC_BLACK);

  switch (frame_style)
  {
    case fsNormal:
      g2d->DrawLine (
          Frame ().xmin + 0,
          Frame ().ymin + 0,
          Frame ().xmax - 1,
          Frame ().ymin + 0,
          lo2);
      g2d->DrawLine (
          Frame ().xmin + 0,
          Frame ().ymin + 0,
          Frame ().xmin + 0,
          Frame ().ymax - 1,
          lo2);
      g2d->DrawLine (
          Frame ().xmin + 1,
          Frame ().ymin + 1,
          Frame ().xmax - 0,
          Frame ().ymin + 1,
          lo);
      g2d->DrawLine (
          Frame ().xmin + 1,
          Frame ().ymin + 1,
          Frame ().xmin + 1,
          Frame ().ymax - 0,
          lo);
      g2d->DrawLine (
          Frame ().xmin + 1,
          Frame ().ymax - 0,
          Frame ().xmax - 0,
          Frame ().ymax - 0,
          hi);
      g2d->DrawLine (
          Frame ().xmax - 0,
          Frame ().ymin + 1,
          Frame ().xmax - 0,
          Frame ().ymax - 0,
          hi);

      g2d->DrawLine (
          Frame ().xmin + 2,
          Frame ().ymin + 2,
          Frame ().xmax - 1,
          Frame ().ymin + 2,
          black);
      g2d->DrawLine (
          Frame ().xmin + 2,
          Frame ().ymin + 2,
          Frame ().xmin + 2,
          Frame ().ymax - 1,
          black);
      g2d->DrawLine (
          Frame ().xmin + 2,
          Frame ().ymax - 1,
          Frame ().xmax - 1,
          Frame ().ymax - 1,
          hi2);
      g2d->DrawLine (
          Frame ().xmax - 1,
          Frame ().ymin + 2,
          Frame ().xmax - 1,
          Frame ().ymax - 1,
          hi2);

      g2d->DrawBox (
          Frame ().xmin + 3,
          Frame ().ymin + 3,
          Frame ().Width () - 3,
          Frame ().Height () - 3,
          dfill);

      if (bkg)
      {
        g3d->DrawPixmap (
            bkg,
            Frame ().xmin,
            Frame ().ymin,
            Frame ().Width () + 1,
            Frame ().Height () + 1,
            0,
            0,
            Frame ().Width () + 1,
            Frame ().Height () + 1,
            alpha_level);
      }
      break;

    case fsBitmap:
      if (bkg)
      {
        g3d->DrawPixmap (
            bkg,
            Frame ().xmin,
            Frame ().ymin,
            Frame ().Width (),
            Frame ().Height (),
            0,
            0,
            Frame ().Width (),
            Frame ().Height (),
            alpha_level);
      }
      break;
  }

  // Draw the caption, if there is one and the style permits it.
  if (text && text->Length ())
  {
    int tw, th, tx, ty, mcc;
    iString *saved = NULL;

    if (should_mask && maskchar)
    {
      saved = text->Clone ();

      unsigned int i;
      for (i = 0; i < text->Length (); ++i)
        text->SetAt (i, maskchar->GetAt (0));
    }

    // Get the maximum number of characters we can use
    mcc = WindowManager ()->GetPrefMgr ()->GetDefaultFont ()->GetLength (
        text->GetData () + start,
        Frame ().Width () - 10);

    if (mcc)
    {

      // Check to see if we're getting wierd.
      start = cursor - mcc;
      if (start < 0) start = 0;

      // Make the text the right length
      scfString tmp (text->GetData () + start);
      tmp.Truncate (mcc);

      // Get the size of the text
      WindowManager ()->GetPrefMgr ()->GetDefaultFont ()->
          GetDimensions (tmp.GetData (), tw, th);

      // Calculate the center
      tx = 4;
      ty = (Frame ().Height () >> 1) - (th >> 1);

      // Draw the text
      g2d->Write (
      WindowManager ()->GetPrefMgr ()->GetDefaultFont (),
      Frame ().xmin + tx,
      Frame ().ymin + ty,
      WindowManager ()->GetPrefMgr ()->GetColor (AC_TEXTFORE),
      -1,
      tmp.GetData ());

      if (should_mask && maskchar && saved)
      {
    text->Clear ();
    text->Append (saved);
    saved->Clear ();
    saved->DecRef ();
      }

    if (has_focus && blink)
    {
      g2d->DrawLine (
          Frame ().xmin + tx + tw + 1,
          Frame ().ymin + ty,
          Frame ().xmin + tx + tw + 1,
          Frame ().ymin + ty + th,
          WindowManager ()->GetPrefMgr ()->GetColor (AC_TEXTFORE));
    }
    }
  }
  else if (has_focus && blink)
  {
    g2d->DrawLine (
        Frame ().xmin + 5,
        Frame ().ymin + 5,
        Frame ().xmin + 5,
        Frame ().ymax - 5,
        WindowManager ()->GetPrefMgr ()->GetColor (AC_TEXTFORE));
  }
}

bool awsTextBox::OnMouseDown (int, int, int)
{
  /// This is needed to get keyboard focus for the mouse!
  return true;
}

bool awsTextBox::OnMouseExit ()
{
  mouse_is_over = false;
  Invalidate ();
  return true;
}

bool awsTextBox::OnMouseEnter ()
{
  mouse_is_over = true;
  Invalidate ();
  return true;
}

bool awsTextBox::OnKeypress (int key, int Char, int)
{
  switch (key)
  {
    case CSKEY_ENTER:
      Broadcast (signalEnterPressed);
      break;

    case CSKEY_TAB:
      Broadcast (signalTabPressed);
      break;

    case CSKEY_BACKSPACE:
      if (cursor > 0) cursor--;
      if (cursor - start < 5) start = cursor - 5;
      if (start < 0) start = 0;
      if (text && (text->Length () > 1))
        text->Truncate (text->Length () - 1);
      else
        text->Clear ();

      break;

    default:
      {
	if (!cs_isprint (Char))
	  break;

	if (disallow && (strchr (disallow->GetData (), Char) != 0))
	  break;

	char str[2];
	str[0] = (char)Char;
	str[1] = 0;

	text->Append (str);
	cursor++;
	Broadcast (signalChanged);
      }
  }         // end switch
  Invalidate ();
  return true;
}

bool awsTextBox::OnLostFocus ()
{
  has_focus = false;
  Broadcast (signalLostFocus);
  Invalidate ();
  return true;
}

bool awsTextBox::OnGainFocus ()
{
  has_focus = true;
  Invalidate ();
  return true;
}

/************************************* Command Button Factory ****************/
awsTextBoxFactory::awsTextBoxFactory (iAws *wmgr) :
  awsComponentFactory(wmgr)
{
  Register ("Text Box");
  RegisterConstant ("tbfsNormal", awsTextBox::fsNormal);
  RegisterConstant ("tbfsBitmap", awsTextBox::fsBitmap);

  RegisterConstant ("signalTextBoxChanged", awsTextBox::signalChanged);
  RegisterConstant ("signalTextBoxLostFocus", awsTextBox::signalLostFocus);
  RegisterConstant ("signalEnterKeyPressed", awsTextBox::signalEnterPressed);
  RegisterConstant ("signalTabKeyPressed", awsTextBox::signalTabPressed);
}

awsTextBoxFactory::~awsTextBoxFactory ()
{
  // empty
}

iAwsComponent *awsTextBoxFactory::Create ()
{
  return new awsTextBox;
}
<|endoftext|>


<commit_before>#include <unistd.h>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <vector>
#include <ctime>
#include <string>
#include <climits>

#include "myers.h"

using namespace std;

int readFastaSequences(const char* path, vector< vector<unsigned char> >* seqs,
                       unsigned char* letterIdx, bool* inAlphabet, int &alphabetLength);

// For debugging
void printSeq(const vector<unsigned char> &seq) {
    for (int i = 0; i < seq.size(); i++)
        printf("%d ", seq[i]);
    printf("\n");
}

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

    //----------------------------- PARSE COMMAND LINE ------------------------//
    bool silent = false;
    char mode[16] = "SHW";
    int option;
    while ((option = getopt(argc, argv, "a:s")) >= 0) {
        switch (option) {
        case 'a': strcpy(mode, optarg); break;
        case 's': silent = true; break;
        }
    }
    if (optind + 2 != argc) {
        fprintf(stderr, "\n");
        fprintf(stderr, "Usage: aligner [options...] <queries.fasta> <target.fasta>\n");
        fprintf(stderr, "Options:\n");
        fprintf(stderr, "\t-s  If specified, there will be no score output (silent mode).\n");
        fprintf(stderr, "\t-a HW|NW|SHW  Alignment mode that will be used. [default: SHW]\n");
        return 1;
    }
    //-------------------------------------------------------------------------//

    int modeCode;
    if (!strcmp(mode, "SHW"))
        modeCode = MYERS_MODE_SHW;
    else if (!strcmp(mode, "HW"))
        modeCode = MYERS_MODE_HW;
    else if (!strcmp(mode, "NW"))
        modeCode = MYERS_MODE_NW;
    else {
        printf("Invalid mode!\n");
        return 1;
    }
    printf("Using mode %s\n", mode);

    // Alphabet information, will be constructed on fly while reading sequences
    unsigned char letterIdx[128]; //!< letterIdx[c] is index of letter c in alphabet
    bool inAlphabet[128]; // inAlphabet[c] is true if c is in alphabet
    for (int i = 0; i < 128; i++) {
        inAlphabet[i] = false;
    }
    int alphabetLength = 0;

    int readResult;
    // Read queries
    char* queriesFilepath = argv[optind];
    vector< vector<unsigned char> >* querySequences = new vector< vector<unsigned char> >();
    printf("Reading queries fasta file...\n");
    readResult = readFastaSequences(queriesFilepath, querySequences, letterIdx, inAlphabet, alphabetLength);
    if (readResult) {
        printf("Error: There is no file with name %s\n", queriesFilepath);
        return 1;
    }
    int numQueries = querySequences->size();

    // Read target
    char* targetFilepath = argv[optind+1];
    vector< vector<unsigned char> >* targetSequences = new vector< vector<unsigned char> >();
    printf("Reading target fasta file...\n");
    readResult = readFastaSequences(targetFilepath, targetSequences, letterIdx, inAlphabet, alphabetLength);
    if (readResult) {
        printf("Error: There is no file with name %s\n", targetFilepath);
        return 1;
    }
    unsigned char* target = (*targetSequences)[0].data();
    int targetLength = (*targetSequences)[0].size();

    printf("Alphabet: ");
    for (int c = 0; c < 128; c++)
        if (inAlphabet[c])
            printf("%c ", c);
    printf("\n");
    printf("Alphabet length: %d\n", alphabetLength);

    // ----------------------------- MAIN CALCULATION ----------------------------- //
    printf("\nSearching...\n");
    int* scores = new int[numQueries];
    int* pos    = new int[numQueries];
    clock_t start = clock();
    if (!silent)
        printf("Scores (score, position): \n");
    for (int i = 0; i < numQueries; i++) {
        myersCalcEditDistance((*querySequences)[i].data(), (*querySequences)[i].size(), target, targetLength,
                              alphabetLength, -1, modeCode, scores + i, pos + i);
        if (!silent)
            printf("(%d, %d) ", scores[i], pos[i]);
    }
    if (!silent)
        printf("\n");
    clock_t finish = clock();
    double cpuTime = ((double)(finish-start))/CLOCKS_PER_SEC;
    printf("\nCpu time of searching: %lf\n", cpuTime);
    // ---------------------------------------------------------------------------- //

    // Free allocated space
    delete querySequences;
    delete targetSequences;
    delete[] scores;
    delete[] pos;

    return 0;
}

/** Reads sequences from fasta file.
 * Function is passed current alphabet information and will update it if needed.
 * @param [in] path Path to fasta file containing sequences.
 * @param [out] seqs Sequences will be stored here, each sequence as vector of indexes from alphabet.
 * @param [inout] letterIdx  Array of length 128. letterIdx[c] is index of letter c in alphabet.
 * @param [inout] inAlphabet  Array of length 128. inAlphabet[c] is true if c is in alphabet.
 * @param [inout] alphabetLength
 * @return 0 if all ok, positive number otherwise.
 */
int readFastaSequences(const char* path, vector< vector<unsigned char> >* seqs,
                       unsigned char* letterIdx, bool* inAlphabet, int &alphabetLength) {
    seqs->clear();

    FILE* file = fopen(path, "r");
    if (file == 0)
        return 1;

    bool inHeader = false;
    bool inSequence = false;
    int buffSize = 4096;
    char buffer[buffSize];
    while (!feof(file)) {
        int read = fread(buffer, sizeof(char), buffSize, file);
        for (int i = 0; i < read; ++i) {
            char c = buffer[i];
            if (inHeader) { // I do nothing if in header
                if (c == '\n')
                    inHeader = false;
            } else {
                if (c == '>') {
                    inHeader = true;
                    inSequence = false;
                } else {
                    if (c == '\r' || c == '\n')
                        continue;
                    // If starting new sequence, initialize it.
                    if (inSequence == false) {
                        inSequence = true;
                        seqs->push_back(vector<unsigned char>());
                    }

                    if (!inAlphabet[c]) { // I construct alphabet on fly
                        inAlphabet[c] = true;
                        letterIdx[c] = alphabetLength;
                        alphabetLength++;
                    }
                    seqs->back().push_back(letterIdx[c]);
                }
            }
        }
    }

    fclose(file);
    return 0;
}
<commit_msg>#4 find best N scores but not working correctly yet<commit_after>#include <unistd.h>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <vector>
#include <ctime>
#include <string>
#include <climits>
#include <queue>

#include "myers.h"

using namespace std;

int readFastaSequences(const char* path, vector< vector<unsigned char> >* seqs,
                       unsigned char* letterIdx, bool* inAlphabet, int &alphabetLength);

// For debugging
void printSeq(const vector<unsigned char> &seq) {
    for (int i = 0; i < seq.size(); i++)
        printf("%d ", seq[i]);
    printf("\n");
}

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

    //----------------------------- PARSE COMMAND LINE ------------------------//
    // If true, there will be no output.
    bool silent = false;
    // Alignment mode.
    char mode[16] = "SHW";
    // How many best sequences (those with smallest score) do we want.
    // If 0, then we want them all.
    int numBestSeqs = 0;
    int option;
    while ((option = getopt(argc, argv, "a:n:s")) >= 0) { // : is not a delimiter but indicator of parameter
        switch (option) {
        case 'a': strcpy(mode, optarg); break;
        case 'n': numBestSeqs = atoi(optarg); break;
        case 's': silent = true; break;
        }
    }
    if (optind + 2 != argc) {
        fprintf(stderr, "\n");
        fprintf(stderr, "Usage: aligner [options...] <queries.fasta> <target.fasta>\n");
        fprintf(stderr, "Options:\n");
        fprintf(stderr, "\t-s  If specified, there will be no score output (silent mode).\n");
        fprintf(stderr, "\t-a HW|NW|SHW  Alignment mode that will be used. [default: SHW]\n");
        fprintf(stderr, "\t-n N  Score will be calculated only for N best sequences (best = with smallest score)."
                        "If N = 0 then all sequences will be calculated. "
                        "Specifying small N can make total calculation much faster. [default: 0]\n");
        return 1;
    }
    //-------------------------------------------------------------------------//

    int modeCode;
    if (!strcmp(mode, "SHW"))
        modeCode = MYERS_MODE_SHW;
    else if (!strcmp(mode, "HW"))
        modeCode = MYERS_MODE_HW;
    else if (!strcmp(mode, "NW"))
        modeCode = MYERS_MODE_NW;
    else {
        printf("Invalid mode!\n");
        return 1;
    }
    printf("Using mode %s\n", mode);

    // Alphabet information, will be constructed on fly while reading sequences
    unsigned char letterIdx[128]; //!< letterIdx[c] is index of letter c in alphabet
    bool inAlphabet[128]; // inAlphabet[c] is true if c is in alphabet
    for (int i = 0; i < 128; i++) {
        inAlphabet[i] = false;
    }
    int alphabetLength = 0;

    int readResult;
    // Read queries
    char* queriesFilepath = argv[optind];
    vector< vector<unsigned char> >* querySequences = new vector< vector<unsigned char> >();
    printf("Reading queries fasta file...\n");
    readResult = readFastaSequences(queriesFilepath, querySequences, letterIdx, inAlphabet, alphabetLength);
    if (readResult) {
        printf("Error: There is no file with name %s\n", queriesFilepath);
        return 1;
    }
    int numQueries = querySequences->size();

    // Read target
    char* targetFilepath = argv[optind+1];
    vector< vector<unsigned char> >* targetSequences = new vector< vector<unsigned char> >();
    printf("Reading target fasta file...\n");
    readResult = readFastaSequences(targetFilepath, targetSequences, letterIdx, inAlphabet, alphabetLength);
    if (readResult) {
        printf("Error: There is no file with name %s\n", targetFilepath);
        return 1;
    }
    unsigned char* target = (*targetSequences)[0].data();
    int targetLength = (*targetSequences)[0].size();

    printf("Alphabet: ");
    for (int c = 0; c < 128; c++)
        if (inAlphabet[c])
            printf("%c ", c);
    printf("\n");
    printf("Alphabet length: %d\n", alphabetLength);

    // ----------------------------- MAIN CALCULATION ----------------------------- //
    printf("\nSearching...\n");
    int* scores = new int[numQueries];
    int* pos    = new int[numQueries];
    priority_queue<int> bestScores; // Contains numBestSeqs best scores
    int k = -1;
    clock_t start = clock();

    printf("0/%d", numQueries);
    for (int i = 0; i < numQueries; i++) {
        // Calculate score
        myersCalcEditDistance((*querySequences)[i].data(), (*querySequences)[i].size(), target, targetLength,
                              alphabetLength, k, modeCode, scores + i, pos + i);

        // If we want only numBestSeqs best sequences, update best scores and adjust k to largest score.
        if (numBestSeqs > 0) {
            bestScores.push(scores[i]);
            if (bestScores.size() > numBestSeqs) {
                bestScores.pop();
                k = bestScores.top() - 1;
            }
        }

        printf("\r%d/%d", i+1, numQueries);
    }
    printf("\n");

    if (!silent) {
        printf("\nScores (score, position) \n");
        for (int i = 0; i < numQueries; i++)
            printf("%d: (%d, %d)\n", i, scores[i], pos[i]);
    }

    clock_t finish = clock();
    double cpuTime = ((double)(finish-start))/CLOCKS_PER_SEC;
    printf("\nCpu time of searching: %lf\n", cpuTime);
    // ---------------------------------------------------------------------------- //

    // Free allocated space
    delete querySequences;
    delete targetSequences;
    delete[] scores;
    delete[] pos;

    return 0;
}

/** Reads sequences from fasta file.
 * Function is passed current alphabet information and will update it if needed.
 * @param [in] path Path to fasta file containing sequences.
 * @param [out] seqs Sequences will be stored here, each sequence as vector of indexes from alphabet.
 * @param [inout] letterIdx  Array of length 128. letterIdx[c] is index of letter c in alphabet.
 * @param [inout] inAlphabet  Array of length 128. inAlphabet[c] is true if c is in alphabet.
 * @param [inout] alphabetLength
 * @return 0 if all ok, positive number otherwise.
 */
int readFastaSequences(const char* path, vector< vector<unsigned char> >* seqs,
                       unsigned char* letterIdx, bool* inAlphabet, int &alphabetLength) {
    seqs->clear();

    FILE* file = fopen(path, "r");
    if (file == 0)
        return 1;

    bool inHeader = false;
    bool inSequence = false;
    int buffSize = 4096;
    char buffer[buffSize];
    while (!feof(file)) {
        int read = fread(buffer, sizeof(char), buffSize, file);
        for (int i = 0; i < read; ++i) {
            char c = buffer[i];
            if (inHeader) { // I do nothing if in header
                if (c == '\n')
                    inHeader = false;
            } else {
                if (c == '>') {
                    inHeader = true;
                    inSequence = false;
                } else {
                    if (c == '\r' || c == '\n')
                        continue;
                    // If starting new sequence, initialize it.
                    if (inSequence == false) {
                        inSequence = true;
                        seqs->push_back(vector<unsigned char>());
                    }

                    if (!inAlphabet[c]) { // I construct alphabet on fly
                        inAlphabet[c] = true;
                        letterIdx[c] = alphabetLength;
                        alphabetLength++;
                    }
                    seqs->back().push_back(letterIdx[c]);
                }
            }
        }
    }

    fclose(file);
    return 0;
}
<|endoftext|>


<commit_before>#include "bytecode.h"

#include <assert.h>
#include <stdint.h>

class BytecodeException: public std::exception {};

static void put_uint16(std::vector<unsigned char> &obj, uint16_t x)
{
    obj.push_back(static_cast<unsigned char>(x >> 8) & 0xff);
    obj.push_back(static_cast<unsigned char>(x & 0xff));
}

static void put_uint32(std::vector<unsigned char> &obj, uint32_t x)
{
    obj.push_back(static_cast<unsigned char>(x >> 24) & 0xff);
    obj.push_back(static_cast<unsigned char>(x >> 16) & 0xff);
    obj.push_back(static_cast<unsigned char>(x >> 8) & 0xff);
    obj.push_back(static_cast<unsigned char>(x & 0xff));
}

static uint16_t get_uint16(const std::vector<unsigned char> &obj, size_t &i)
{
    if (i+2 > obj.size()) {
        throw BytecodeException();
    }
    uint16_t r = (obj[i] << 8) | obj[i+1];
    i += 2;
    return r;
}

static uint32_t get_uint32(const std::vector<unsigned char> &obj, size_t &i)
{
    if (i+4 > obj.size()) {
        throw BytecodeException();
    }
    uint32_t r = (obj[i] << 24) | (obj[i+1] << 16) | (obj[i+2] << 8) | obj[i+3];
    i += 4;
    return r;
}

static std::vector<std::string> getstrtable(const unsigned char *start, const unsigned char *end)
{
    std::vector<std::string> r;
    while (start != end) {
        size_t len = (start[0] << 24) | (start[1] << 16) | (start[2] << 8) | start[3];
        start += 4;
        r.push_back(std::string(reinterpret_cast<const char *>(start), len));
        start += len;
    }
    return r;
}

Bytecode::Bytecode()
  : obj(),
    source_path(),
    source_hash(),
    global_size(0),
    strtable(),
    export_types(),
    export_constants(),
    export_variables(),
    export_functions(),
    export_exceptions(),
    export_interfaces(),
    imports(),
    functions(),
    exceptions(),
    classes(),
    code()
{
}

bool Bytecode::load(const std::string &source_path, const std::vector<unsigned char> &bytes)
{
    this->source_path = source_path;
    obj = bytes;

    size_t i = 0;

    try {
        if (obj.size() < 32) {
            throw BytecodeException();
        }
        source_hash = std::string(&obj[i], &obj[i]+32);
        i += 32;

        global_size = get_uint16(obj, i);

        unsigned int strtablesize = get_uint32(obj, i);
        if (i+strtablesize > obj.size()) {
            throw BytecodeException();
        }
        strtable = getstrtable(&obj[i], &obj[i] + strtablesize);
        i += strtablesize;

        unsigned int typesize = get_uint16(obj, i);
        while (typesize > 0) {
            Type t;
            t.name = get_uint16(obj, i);
            t.descriptor = get_uint16(obj, i);
            export_types.push_back(t);
            typesize--;
        }

        unsigned int constantsize = get_uint16(obj, i);
        while (constantsize > 0) {
            Constant c;
            c.name = get_uint16(obj, i);
            c.type = get_uint16(obj, i);
            unsigned int size = get_uint16(obj, i);
            if (i+size > obj.size()) {
                throw BytecodeException();
            }
            c.value = Bytes(&obj[i], &obj[i+size]);
            i += size;
            export_constants.push_back(c);
            constantsize--;
        }

        unsigned int variablesize = get_uint16(obj, i);
        while (variablesize > 0) {
            Variable v;
            v.name = get_uint16(obj, i);
            v.type = get_uint16(obj, i);
            v.index = get_uint16(obj, i);
            export_variables.push_back(v);
            variablesize--;
        }

        unsigned int functionsize = get_uint16(obj, i);
        while (functionsize > 0) {
            Function f;
            f.name = get_uint16(obj, i);
            f.descriptor = get_uint16(obj, i);
            f.entry = get_uint16(obj, i);
            export_functions.push_back(f);
            functionsize--;
        }

        unsigned int exceptionexportsize = get_uint16(obj, i);
        while (exceptionexportsize > 0) {
            ExceptionExport e;
            e.name = get_uint16(obj, i);
            export_exceptions.push_back(e);
            exceptionexportsize--;
        }

        unsigned int interfaceexportsize = get_uint16(obj, i);
        while (interfaceexportsize > 0) {
            Interface iface;
            iface.name = get_uint16(obj, i);
            unsigned int methoddescriptorsize = get_uint16(obj, i);
            while (methoddescriptorsize > 0) {
                std::pair<unsigned int, unsigned int> m;
                m.first = get_uint16(obj, i);
                m.second = get_uint16(obj, i);
                iface.method_descriptors.push_back(m);
                methoddescriptorsize--;
            }
            export_interfaces.push_back(iface);
            interfaceexportsize--;
        }

        unsigned int importsize = get_uint16(obj, i);
        while (importsize > 0) {
            std::pair<unsigned int, std::string> imp;
            imp.first = get_uint16(obj, i);
            if (i+32 > obj.size()) {
                throw BytecodeException();
            }
            imp.second = std::string(&obj[i], &obj[i]+32);
            i += 32;
            imports.push_back(imp);
            importsize--;
        }

        /*unsigned int*/ functionsize = get_uint16(obj, i);
        while (functionsize > 0) {
            FunctionInfo f;
            f.name = get_uint16(obj, i);
            f.entry = get_uint16(obj, i);
            functions.push_back(f);
            functionsize--;
        }

        unsigned int exceptionsize = get_uint16(obj, i);
        while (exceptionsize > 0) {
            ExceptionInfo e;
            e.start = get_uint16(obj, i);
            e.end = get_uint16(obj, i);
            e.excid = get_uint16(obj, i);
            e.handler = get_uint16(obj, i);
            exceptions.push_back(e);
            exceptionsize--;
        }

        unsigned int classsize = get_uint16(obj, i);
        while (classsize > 0) {
            ClassInfo c;
            c.name = get_uint16(obj, i);
            unsigned int interfacecount = get_uint16(obj, i);
            while (interfacecount > 0) {
                std::vector<unsigned int> methods;
                unsigned int methodcount = get_uint16(obj, i);
                while (methodcount > 0) {
                    methods.push_back(get_uint16(obj, i));
                    methodcount--;
                }
                c.interfaces.push_back(methods);
                interfacecount--;
            }
            classes.push_back(c);
            classsize--;
        }

        code = Bytes(obj.begin() + i, obj.end());

    } catch (BytecodeException &) {
        return false;
    }

    return true;
}

Bytecode::Bytes Bytecode::getBytes() const
{
    std::vector<unsigned char> obj;

    assert(source_hash.length() == 32);
    for (int i = 0; i < 32; i++) {
        obj.push_back(source_hash[i]);
    }

    put_uint16(obj, static_cast<uint16_t>(global_size));

    std::vector<unsigned char> t;
    for (auto s: strtable) {
        put_uint32(t, static_cast<uint32_t>(s.length()));
        std::copy(s.begin(), s.end(), std::back_inserter(t));
    }
    put_uint32(obj, static_cast<uint32_t>(t.size()));
    std::copy(t.begin(), t.end(), std::back_inserter(obj));

    put_uint16(obj, static_cast<uint16_t>(export_types.size()));
    for (auto t: export_types) {
        put_uint16(obj, static_cast<uint16_t>(t.name));
        put_uint16(obj, static_cast<uint16_t>(t.descriptor));
    }

    put_uint16(obj, static_cast<uint16_t>(export_constants.size()));
    for (auto c: export_constants) {
        put_uint16(obj, static_cast<uint16_t>(c.name));
        put_uint16(obj, static_cast<uint16_t>(c.type));
        put_uint16(obj, static_cast<uint16_t>(c.value.size()));
        std::copy(c.value.begin(), c.value.end(), std::back_inserter(obj));
    }

    put_uint16(obj, static_cast<uint16_t>(export_variables.size()));
    for (auto v: export_variables) {
        put_uint16(obj, static_cast<uint16_t>(v.name));
        put_uint16(obj, static_cast<uint16_t>(v.type));
        put_uint16(obj, static_cast<uint16_t>(v.index));
    }

    put_uint16(obj, static_cast<uint16_t>(export_functions.size()));
    for (auto f: export_functions) {
        put_uint16(obj, static_cast<uint16_t>(f.name));
        put_uint16(obj, static_cast<uint16_t>(f.descriptor));
        put_uint16(obj, static_cast<uint16_t>(f.entry));
    }

    put_uint16(obj, static_cast<uint16_t>(export_exceptions.size()));
    for (auto e: export_exceptions) {
        put_uint16(obj, static_cast<uint16_t>(e.name));
    }

    put_uint16(obj, static_cast<uint16_t>(export_interfaces.size()));
    for (auto i: export_interfaces) {
        put_uint16(obj, static_cast<uint16_t>(i.name));
        put_uint16(obj, static_cast<uint16_t>(i.method_descriptors.size()));
        for (auto m: i.method_descriptors) {
            put_uint16(obj, static_cast<uint16_t>(m.first));
            put_uint16(obj, static_cast<uint16_t>(m.second));
        }
    }

    put_uint16(obj, static_cast<uint16_t>(imports.size()));
    for (auto i: imports) {
        put_uint16(obj, static_cast<uint16_t>(i.first));
        assert(i.second.length() == 32);
        for (int j = 0; j < 32; j++) {
            obj.push_back(i.second[j]);
        }
    }

    put_uint16(obj, static_cast<uint16_t>(functions.size()));
    for (auto f: functions) {
        put_uint16(obj, static_cast<uint16_t>(f.name));
        put_uint16(obj, static_cast<uint16_t>(f.entry));
    }

    put_uint16(obj, static_cast<uint16_t>(exceptions.size()));
    for (auto e: exceptions) {
        put_uint16(obj, static_cast<uint16_t>(e.start));
        put_uint16(obj, static_cast<uint16_t>(e.end));
        put_uint16(obj, static_cast<uint16_t>(e.excid));
        put_uint16(obj, static_cast<uint16_t>(e.handler));
    }

    put_uint16(obj, static_cast<uint16_t>(classes.size()));
    for (auto c: classes) {
        put_uint16(obj, static_cast<uint16_t>(c.name));
        put_uint16(obj, static_cast<uint16_t>(c.interfaces.size()));
        for (auto i: c.interfaces) {
            put_uint16(obj, static_cast<uint16_t>(i.size()));
            for (auto m: i) {
                put_uint16(obj, static_cast<uint16_t>(m));
            }
        }
    }

    std::copy(code.begin(), code.end(), std::back_inserter(obj));
    return obj;
}
<commit_msg>Use 32-bit offsets for function entry points in bytecode<commit_after>#include "bytecode.h"

#include <assert.h>
#include <stdint.h>

class BytecodeException: public std::exception {};

static void put_uint16(std::vector<unsigned char> &obj, uint16_t x)
{
    obj.push_back(static_cast<unsigned char>(x >> 8) & 0xff);
    obj.push_back(static_cast<unsigned char>(x & 0xff));
}

static void put_uint32(std::vector<unsigned char> &obj, uint32_t x)
{
    obj.push_back(static_cast<unsigned char>(x >> 24) & 0xff);
    obj.push_back(static_cast<unsigned char>(x >> 16) & 0xff);
    obj.push_back(static_cast<unsigned char>(x >> 8) & 0xff);
    obj.push_back(static_cast<unsigned char>(x & 0xff));
}

static uint16_t get_uint16(const std::vector<unsigned char> &obj, size_t &i)
{
    if (i+2 > obj.size()) {
        throw BytecodeException();
    }
    uint16_t r = (obj[i] << 8) | obj[i+1];
    i += 2;
    return r;
}

static uint32_t get_uint32(const std::vector<unsigned char> &obj, size_t &i)
{
    if (i+4 > obj.size()) {
        throw BytecodeException();
    }
    uint32_t r = (obj[i] << 24) | (obj[i+1] << 16) | (obj[i+2] << 8) | obj[i+3];
    i += 4;
    return r;
}

static std::vector<std::string> getstrtable(const unsigned char *start, const unsigned char *end)
{
    std::vector<std::string> r;
    while (start != end) {
        size_t len = (start[0] << 24) | (start[1] << 16) | (start[2] << 8) | start[3];
        start += 4;
        r.push_back(std::string(reinterpret_cast<const char *>(start), len));
        start += len;
    }
    return r;
}

Bytecode::Bytecode()
  : obj(),
    source_path(),
    source_hash(),
    global_size(0),
    strtable(),
    export_types(),
    export_constants(),
    export_variables(),
    export_functions(),
    export_exceptions(),
    export_interfaces(),
    imports(),
    functions(),
    exceptions(),
    classes(),
    code()
{
}

bool Bytecode::load(const std::string &source_path, const std::vector<unsigned char> &bytes)
{
    this->source_path = source_path;
    obj = bytes;

    size_t i = 0;

    try {
        if (obj.size() < 32) {
            throw BytecodeException();
        }
        source_hash = std::string(&obj[i], &obj[i]+32);
        i += 32;

        global_size = get_uint16(obj, i);

        unsigned int strtablesize = get_uint32(obj, i);
        if (i+strtablesize > obj.size()) {
            throw BytecodeException();
        }
        strtable = getstrtable(&obj[i], &obj[i] + strtablesize);
        i += strtablesize;

        unsigned int typesize = get_uint16(obj, i);
        while (typesize > 0) {
            Type t;
            t.name = get_uint16(obj, i);
            t.descriptor = get_uint16(obj, i);
            export_types.push_back(t);
            typesize--;
        }

        unsigned int constantsize = get_uint16(obj, i);
        while (constantsize > 0) {
            Constant c;
            c.name = get_uint16(obj, i);
            c.type = get_uint16(obj, i);
            unsigned int size = get_uint16(obj, i);
            if (i+size > obj.size()) {
                throw BytecodeException();
            }
            c.value = Bytes(&obj[i], &obj[i+size]);
            i += size;
            export_constants.push_back(c);
            constantsize--;
        }

        unsigned int variablesize = get_uint16(obj, i);
        while (variablesize > 0) {
            Variable v;
            v.name = get_uint16(obj, i);
            v.type = get_uint16(obj, i);
            v.index = get_uint16(obj, i);
            export_variables.push_back(v);
            variablesize--;
        }

        unsigned int functionsize = get_uint16(obj, i);
        while (functionsize > 0) {
            Function f;
            f.name = get_uint16(obj, i);
            f.descriptor = get_uint16(obj, i);
            f.entry = get_uint32(obj, i);
            export_functions.push_back(f);
            functionsize--;
        }

        unsigned int exceptionexportsize = get_uint16(obj, i);
        while (exceptionexportsize > 0) {
            ExceptionExport e;
            e.name = get_uint16(obj, i);
            export_exceptions.push_back(e);
            exceptionexportsize--;
        }

        unsigned int interfaceexportsize = get_uint16(obj, i);
        while (interfaceexportsize > 0) {
            Interface iface;
            iface.name = get_uint16(obj, i);
            unsigned int methoddescriptorsize = get_uint16(obj, i);
            while (methoddescriptorsize > 0) {
                std::pair<unsigned int, unsigned int> m;
                m.first = get_uint16(obj, i);
                m.second = get_uint16(obj, i);
                iface.method_descriptors.push_back(m);
                methoddescriptorsize--;
            }
            export_interfaces.push_back(iface);
            interfaceexportsize--;
        }

        unsigned int importsize = get_uint16(obj, i);
        while (importsize > 0) {
            std::pair<unsigned int, std::string> imp;
            imp.first = get_uint16(obj, i);
            if (i+32 > obj.size()) {
                throw BytecodeException();
            }
            imp.second = std::string(&obj[i], &obj[i]+32);
            i += 32;
            imports.push_back(imp);
            importsize--;
        }

        /*unsigned int*/ functionsize = get_uint16(obj, i);
        while (functionsize > 0) {
            FunctionInfo f;
            f.name = get_uint16(obj, i);
            f.entry = get_uint32(obj, i);
            functions.push_back(f);
            functionsize--;
        }

        unsigned int exceptionsize = get_uint16(obj, i);
        while (exceptionsize > 0) {
            ExceptionInfo e;
            e.start = get_uint16(obj, i);
            e.end = get_uint16(obj, i);
            e.excid = get_uint16(obj, i);
            e.handler = get_uint16(obj, i);
            exceptions.push_back(e);
            exceptionsize--;
        }

        unsigned int classsize = get_uint16(obj, i);
        while (classsize > 0) {
            ClassInfo c;
            c.name = get_uint16(obj, i);
            unsigned int interfacecount = get_uint16(obj, i);
            while (interfacecount > 0) {
                std::vector<unsigned int> methods;
                unsigned int methodcount = get_uint16(obj, i);
                while (methodcount > 0) {
                    methods.push_back(get_uint16(obj, i));
                    methodcount--;
                }
                c.interfaces.push_back(methods);
                interfacecount--;
            }
            classes.push_back(c);
            classsize--;
        }

        code = Bytes(obj.begin() + i, obj.end());

    } catch (BytecodeException &) {
        return false;
    }

    return true;
}

Bytecode::Bytes Bytecode::getBytes() const
{
    std::vector<unsigned char> obj;

    assert(source_hash.length() == 32);
    for (int i = 0; i < 32; i++) {
        obj.push_back(source_hash[i]);
    }

    put_uint16(obj, static_cast<uint16_t>(global_size));

    std::vector<unsigned char> t;
    for (auto s: strtable) {
        put_uint32(t, static_cast<uint32_t>(s.length()));
        std::copy(s.begin(), s.end(), std::back_inserter(t));
    }
    put_uint32(obj, static_cast<uint32_t>(t.size()));
    std::copy(t.begin(), t.end(), std::back_inserter(obj));

    put_uint16(obj, static_cast<uint16_t>(export_types.size()));
    for (auto t: export_types) {
        put_uint16(obj, static_cast<uint16_t>(t.name));
        put_uint16(obj, static_cast<uint16_t>(t.descriptor));
    }

    put_uint16(obj, static_cast<uint16_t>(export_constants.size()));
    for (auto c: export_constants) {
        put_uint16(obj, static_cast<uint16_t>(c.name));
        put_uint16(obj, static_cast<uint16_t>(c.type));
        put_uint16(obj, static_cast<uint16_t>(c.value.size()));
        std::copy(c.value.begin(), c.value.end(), std::back_inserter(obj));
    }

    put_uint16(obj, static_cast<uint16_t>(export_variables.size()));
    for (auto v: export_variables) {
        put_uint16(obj, static_cast<uint16_t>(v.name));
        put_uint16(obj, static_cast<uint16_t>(v.type));
        put_uint16(obj, static_cast<uint16_t>(v.index));
    }

    put_uint16(obj, static_cast<uint16_t>(export_functions.size()));
    for (auto f: export_functions) {
        put_uint16(obj, static_cast<uint16_t>(f.name));
        put_uint16(obj, static_cast<uint16_t>(f.descriptor));
        put_uint32(obj, static_cast<uint32_t>(f.entry));
    }

    put_uint16(obj, static_cast<uint16_t>(export_exceptions.size()));
    for (auto e: export_exceptions) {
        put_uint16(obj, static_cast<uint16_t>(e.name));
    }

    put_uint16(obj, static_cast<uint16_t>(export_interfaces.size()));
    for (auto i: export_interfaces) {
        put_uint16(obj, static_cast<uint16_t>(i.name));
        put_uint16(obj, static_cast<uint16_t>(i.method_descriptors.size()));
        for (auto m: i.method_descriptors) {
            put_uint16(obj, static_cast<uint16_t>(m.first));
            put_uint16(obj, static_cast<uint16_t>(m.second));
        }
    }

    put_uint16(obj, static_cast<uint16_t>(imports.size()));
    for (auto i: imports) {
        put_uint16(obj, static_cast<uint16_t>(i.first));
        assert(i.second.length() == 32);
        for (int j = 0; j < 32; j++) {
            obj.push_back(i.second[j]);
        }
    }

    put_uint16(obj, static_cast<uint16_t>(functions.size()));
    for (auto f: functions) {
        put_uint16(obj, static_cast<uint16_t>(f.name));
        put_uint32(obj, static_cast<uint32_t>(f.entry));
    }

    put_uint16(obj, static_cast<uint16_t>(exceptions.size()));
    for (auto e: exceptions) {
        put_uint16(obj, static_cast<uint16_t>(e.start));
        put_uint16(obj, static_cast<uint16_t>(e.end));
        put_uint16(obj, static_cast<uint16_t>(e.excid));
        put_uint16(obj, static_cast<uint16_t>(e.handler));
    }

    put_uint16(obj, static_cast<uint16_t>(classes.size()));
    for (auto c: classes) {
        put_uint16(obj, static_cast<uint16_t>(c.name));
        put_uint16(obj, static_cast<uint16_t>(c.interfaces.size()));
        for (auto i: c.interfaces) {
            put_uint16(obj, static_cast<uint16_t>(i.size()));
            for (auto m: i) {
                put_uint16(obj, static_cast<uint16_t>(m));
            }
        }
    }

    std::copy(code.begin(), code.end(), std::back_inserter(obj));
    return obj;
}
<|endoftext|>


<commit_before>#include <stdio.h>
#include <string>
#include <boost/python.hpp>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <string.h>
#include <math.h>
#include <vector>
#include <boost/random.hpp>
#include <boost/random/normal_distribution.hpp>

using namespace std;
using namespace boost;

template<typename T>
struct __attribute__((__packed__)) node {
  /*
   * We store a binary tree where each node has two things
   * - A vector associated with it
   * - Two children
   * All nodes occupy the same amount of memory
   * All nodes with n_descendants == 1 are leaf nodes.
   * A memory optimization is that for nodes with 2 <= n_descendants <= K,
   * we skip the vector. Instead we store a list of all descendants. K is
   * determined by the number of items that fits in the same space.
   * For nodes with n_descendants == 1 or > K, there is always a
   * corresponding vector.
   * Note that we can't really do sizeof(node<T>) because we cheat and allocate
   * more memory to be able to fit the vector outside
   */
  int n_descendants;
  int children[2]; // Will possibly store more than 2
  T v[0]; // Hack. We just allocate as much memory as we need and let this array overflow
};

template<typename T>
class AnnoyIndex {
  /*
   * We use random projection to build a forest of binary trees of all items.
   * Basically just split the hyperspace into two sides by a hyperplane,
   * then recursively split each of those subtrees etc.
   * We create a tree like this q times. The default q is determined automatically
   * in such a way that we at most use 2x as much memory as the vectors take.
   */
  int _f;
  size_t _s;
  int _n_items;
  mt19937 _rng;
  normal_distribution<T> _nd;
  variate_generator<mt19937&,
		    normal_distribution<T> > _var_nor;
  void* _nodes; // Could either be mmapped, or point to a memory buffer that we reallocate
  int _n_nodes;
  int _nodes_size;
  vector<int> _roots;
  int _K;
  bool _loaded;
public:
  AnnoyIndex(int f) : _rng(), _nd(), _var_nor(_rng, _nd) {
    _f = f;
    _s = sizeof(node<T>) + sizeof(T) * f; // Size of each node
    _n_items = 0;
    _n_nodes = 0;
    _nodes_size = 0;
    _nodes = NULL;
    _loaded = false;

    _K = (sizeof(T) * f + sizeof(int) * 2) / sizeof(int);
  }
  ~AnnoyIndex() {
    if (!_loaded && _nodes) {
      free(_nodes);
    }
  }

  void add_item(int item, const python::list& v) {
    _allocate_size(item+1);
    node<T>* n = _get(item);

    n->children[0] = 0;
    n->children[1] = 0;
    n->n_descendants = 1;

    for (int z = 0; z < _f; z++)
      n->v[z] = python::extract<T>(v[z]);

    if (item >= _n_items)
      _n_items = item + 1;
  }

  void build(int q) {
    _n_nodes = _n_items;
    while (1) {
      if (q == -1 && _n_nodes >= _n_items * 2)
	break;
      if (q != -1 && _roots.size() >= (size_t)q)
	break;
      printf("pass %zd...\n", _roots.size());

      vector<int> indices;
      for (int i = 0; i < _n_items; i++)
	indices.push_back(i);

      _roots.push_back(_make_tree(indices));
    }
    printf("has %d nodes\n", _n_nodes);
  }

  void save(const string& filename) {
    FILE *f = fopen(filename.c_str(), "w");

    fwrite(_nodes, _s, _n_nodes, f);

    fclose(f);

    free(_nodes);
    _n_items = 0;
    _n_nodes = 0;
    _nodes_size = 0;
    _nodes = NULL;
    _roots.clear();
    load(filename);
  }

  void load(const string& filename) {
    struct stat buf;
    stat(filename.c_str(), &buf);
    off_t size = buf.st_size;
    int fd = open(filename.c_str(), O_RDONLY, (mode_t)0400);
    _nodes = (node<T>*)mmap(0, size, PROT_READ, MAP_SHARED, fd, 0);

    int n = size / _s;

    // Find the nodes with the largest number of descendants. These are the roots
    int m = 0;
    for (int i = 0; i < n; i++) {
      if (_get(i)->n_descendants > m) {
	_roots.clear();
	m = _get(i)->n_descendants;
      }
      if (_get(i)->n_descendants == m) {
	_roots.push_back(i);
      }
    }
    _loaded = true;
    printf("found %lu roots with degree %d\n", _roots.size(), m);
  }

  inline T _cos(const T* x, const T* y) {
    T pp = 0, qq = 0, pq = 0;
    for (int z = 0; z < _f; z++) {
      pp += x[z] * x[z];
      qq += y[z] * y[z];
      pq += x[z] * y[z];
    }
    T ppqq = pp * qq;
    if (ppqq > 0) return pq / sqrt(ppqq);
    else return 0.0;
  }

  inline T cos(int i, int j) {
    const T* x = _get(i)->v;
    const T* y = _get(j)->v;
    return _cos(x, y);
  }

  python::list get_nns_by_item(int item, int n) {
    const node<T>* m = _get(item);
    return _get_all_nns(m->v, n);
  }
  python::list get_nns_by_vector(python::list v, int n) {
    vector<T> w(_f);
    for (int z = 0; z < _f; z++)
      w[z] = python::extract<T>(v[z]);
    return _get_all_nns(&w[0], n);
  }
private:
  void _allocate_size(int n) {
    if (n > _nodes_size) {
      int new_nodes_size = (_nodes_size + 1) * 2;
      if (n > new_nodes_size)
	new_nodes_size = n;
      _nodes = realloc(_nodes, _s * new_nodes_size);
      memset((char *)_nodes + (_nodes_size * _s)/sizeof(char), 0, (new_nodes_size - _nodes_size) * _s);
      _nodes_size = new_nodes_size;
    }
  }

  inline node<T>* _get(int i) {
    return (node<T>*)((char *)_nodes + (_s * i)/sizeof(char));
  }

  int _make_tree(const vector<int >& indices) {
    if (indices.size() == 1)
      return indices[0];

    _allocate_size(_n_nodes + 1);
    int item = _n_nodes++;
    node<T>* m = _get(item);
    m->n_descendants = indices.size();

    if (indices.size() <= (size_t)_K) {
      for (size_t i = 0; i < indices.size(); i++)
	m->children[i] = indices[i];
      return item;
    }

    vector<int> children_indices[2];
    for (int attempt = 0; attempt < 20; attempt ++) {
      /*
       * Create a random hyperplane.
       * If all points end up on the same time, we try again.
       * We could in principle *construct* a plane so that we split
       * all items evenly, but I think that could violate the guarantees
       * given by just picking a hyperplane at random
       */
      for (int z = 0; z < _f; z++)
	m->v[z] = _var_nor();

      children_indices[0].clear();
      children_indices[1].clear();

      for (size_t i = 0; i < indices.size(); i++) {
	int j = indices[i];
	node<T>* n = _get(j);
	if (!n) {
	  printf("node %d undef...\n", j);
	  continue;
	}
	T dot = 0;
	for (int z = 0; z < _f; z++) {
	  dot += m->v[z] * n->v[z];
	}
	while (dot == 0)
	  dot = _var_nor();
	children_indices[dot > 0].push_back(j);
      }

      if (children_indices[0].size() > 0 && children_indices[1].size() > 0) {
	break;
      }
    }

    while (children_indices[0].size() == 0 || children_indices[1].size() == 0) {
      // If we didn't find a hyperplane, just randomize sides as a last option
      if (indices.size() > 100000)
	printf("Failed splitting %lu items\n", indices.size());

      children_indices[0].clear();
      children_indices[1].clear();

      // Set the vector to 0.0
      for (int z = 0; z < _f; z++)
	m->v[z] = 0.0;

      for (size_t i = 0; i < indices.size(); i++) {
	int j = indices[i];
	// Just randomize...
	children_indices[_var_nor() > 0].push_back(j);
      }
    }

    int children_0 = _make_tree(children_indices[0]);
    int children_1 = _make_tree(children_indices[1]);

    // We need to fetch m again because it might have been reallocated
    m = _get(item);
    m->children[0] = children_0;
    m->children[1] = children_1;

    return item;
  }

  void _get_nns(const T* v, int i, vector<int>* result, int limit) {
    const node<T>* n = _get(i);

    if (n->n_descendants == 0) {
      // unknown item, nothing to do...
    } else if (n->n_descendants == 1) {
      result->push_back(i);
    } else if (n->n_descendants <= _K) {
      for (int j = 0; j < n->n_descendants; j++) {
	result->push_back(n->children[j]);
      }
    } else {
      T dot = 0;

      for (int z = 0; z < _f; z++)
	dot += v[z] * n->v[z];

      while (dot == 0) // Randomize side if the dot product is zero
	dot = _var_nor();

      _get_nns(v, n->children[dot > 0], result, limit);
      if (result->size() < (size_t)limit)
	_get_nns(v, n->children[dot < 0], result, limit);
    }
  }

  python::list _get_all_nns(const T* v, int n) {
    vector<pair<T, int> > nns_cos;

    for (size_t i = 0; i < _roots.size(); i++) {
      vector<int> nns;
      _get_nns(v, _roots[i], &nns, n);
      for (size_t j = 0; j < nns.size(); j++) {
	nns_cos.push_back(make_pair(_cos(v, _get(nns[j])->v), nns[j]));
      }
    }
    sort(nns_cos.begin(), nns_cos.end());
    int last = -1, length=0;
    python::list l;
    for (int i = (int)nns_cos.size() - 1; i >= 0 && length < n; i--) {
      if (nns_cos[i].second != last) {
	l.append(nns_cos[i].second);
	last = nns_cos[i].second;
	length++;
      }
    }
    return l;
  }
};

BOOST_PYTHON_MODULE(annoylib)
{
  python::class_<AnnoyIndex<float> >("AnnoyIndex", python::init<int>())
    .def("add_item",          &AnnoyIndex<float>::add_item)
    .def("build",             &AnnoyIndex<float>::build)
    .def("save",              &AnnoyIndex<float>::save)
    .def("load",              &AnnoyIndex<float>::load)
    .def("cos",               &AnnoyIndex<float>::cos)
    .def("get_nns_by_item",   &AnnoyIndex<float>::get_nns_by_item)
    .def("get_nns_by_vector", &AnnoyIndex<float>::get_nns_by_vector);
}
<commit_msg>write roots to the end of file, to make loading faster<commit_after>#include <stdio.h>
#include <string>
#include <boost/python.hpp>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <string.h>
#include <math.h>
#include <vector>
#include <boost/random.hpp>
#include <boost/random/normal_distribution.hpp>

using namespace std;
using namespace boost;

template<typename T>
struct __attribute__((__packed__)) node {
  /*
   * We store a binary tree where each node has two things
   * - A vector associated with it
   * - Two children
   * All nodes occupy the same amount of memory
   * All nodes with n_descendants == 1 are leaf nodes.
   * A memory optimization is that for nodes with 2 <= n_descendants <= K,
   * we skip the vector. Instead we store a list of all descendants. K is
   * determined by the number of items that fits in the same space.
   * For nodes with n_descendants == 1 or > K, there is always a
   * corresponding vector.
   * Note that we can't really do sizeof(node<T>) because we cheat and allocate
   * more memory to be able to fit the vector outside
   */
  int n_descendants;
  int children[2]; // Will possibly store more than 2
  T v[0]; // Hack. We just allocate as much memory as we need and let this array overflow
};

template<typename T>
class AnnoyIndex {
  /*
   * We use random projection to build a forest of binary trees of all items.
   * Basically just split the hyperspace into two sides by a hyperplane,
   * then recursively split each of those subtrees etc.
   * We create a tree like this q times. The default q is determined automatically
   * in such a way that we at most use 2x as much memory as the vectors take.
   */
  int _f;
  size_t _s;
  int _n_items;
  mt19937 _rng;
  normal_distribution<T> _nd;
  variate_generator<mt19937&,
		    normal_distribution<T> > _var_nor;
  void* _nodes; // Could either be mmapped, or point to a memory buffer that we reallocate
  int _n_nodes;
  int _nodes_size;
  vector<int> _roots;
  int _K;
  bool _loaded;
public:
  AnnoyIndex(int f) : _rng(), _nd(), _var_nor(_rng, _nd) {
    _f = f;
    _s = sizeof(node<T>) + sizeof(T) * f; // Size of each node
    _n_items = 0;
    _n_nodes = 0;
    _nodes_size = 0;
    _nodes = NULL;
    _loaded = false;

    _K = (sizeof(T) * f + sizeof(int) * 2) / sizeof(int);
  }
  ~AnnoyIndex() {
    if (!_loaded && _nodes) {
      free(_nodes);
    }
  }

  void add_item(int item, const python::list& v) {
    _allocate_size(item+1);
    node<T>* n = _get(item);

    n->children[0] = 0;
    n->children[1] = 0;
    n->n_descendants = 1;

    for (int z = 0; z < _f; z++)
      n->v[z] = python::extract<T>(v[z]);

    if (item >= _n_items)
      _n_items = item + 1;
  }

  void build(int q) {
    _n_nodes = _n_items;
    while (1) {
      if (q == -1 && _n_nodes >= _n_items * 2)
	break;
      if (q != -1 && _roots.size() >= (size_t)q)
	break;
      printf("pass %zd...\n", _roots.size());

      vector<int> indices;
      for (int i = 0; i < _n_items; i++)
	indices.push_back(i);

      _roots.push_back(_make_tree(indices));
    }
    // Also, copy the roots into the last segment of the array
    // This way we can load them faster without reading the whole file
    _allocate_size(_n_nodes + _roots.size());
    for (size_t i = 0; i < _roots.size(); i++)
      memcpy(_get(_n_nodes + i), _get(_roots[i]), _s);
    _n_nodes += _roots.size();

    printf("has %d nodes\n", _n_nodes);
  }

  void save(const string& filename) {
    FILE *f = fopen(filename.c_str(), "w");

    fwrite(_nodes, _s, _n_nodes, f);

    fclose(f);

    free(_nodes);
    _n_items = 0;
    _n_nodes = 0;
    _nodes_size = 0;
    _nodes = NULL;
    _roots.clear();
    load(filename);
  }

  void load(const string& filename) {
    struct stat buf;
    stat(filename.c_str(), &buf);
    off_t size = buf.st_size;
    int fd = open(filename.c_str(), O_RDONLY, (mode_t)0400);
    _nodes = (node<T>*)mmap(0, size, PROT_READ, MAP_SHARED, fd, 0);

    _n_nodes = size / _s;

    // Find the roots by scanning the end of the file and taking the nodes with most descendants
    int m = -1;
    for (int i = _n_nodes - 1; i >= 0; i--) {
      int k = _get(i)->n_descendants;
      if (m == -1 || k == m) {
	_roots.push_back(i);
	m = k;
      } else {
	break;
      }
    }
    _loaded = true;
    printf("found %lu roots with degree %d\n", _roots.size(), m);
  }

  inline T _cos(const T* x, const T* y) {
    T pp = 0, qq = 0, pq = 0;
    for (int z = 0; z < _f; z++) {
      pp += x[z] * x[z];
      qq += y[z] * y[z];
      pq += x[z] * y[z];
    }
    T ppqq = pp * qq;
    if (ppqq > 0) return pq / sqrt(ppqq);
    else return 0.0;
  }

  inline T cos(int i, int j) {
    const T* x = _get(i)->v;
    const T* y = _get(j)->v;
    return _cos(x, y);
  }

  python::list get_nns_by_item(int item, int n) {
    const node<T>* m = _get(item);
    return _get_all_nns(m->v, n);
  }
  python::list get_nns_by_vector(python::list v, int n) {
    vector<T> w(_f);
    for (int z = 0; z < _f; z++)
      w[z] = python::extract<T>(v[z]);
    return _get_all_nns(&w[0], n);
  }
private:
  void _allocate_size(int n) {
    if (n > _nodes_size) {
      int new_nodes_size = (_nodes_size + 1) * 2;
      if (n > new_nodes_size)
	new_nodes_size = n;
      _nodes = realloc(_nodes, _s * new_nodes_size);
      memset((char *)_nodes + (_nodes_size * _s)/sizeof(char), 0, (new_nodes_size - _nodes_size) * _s);
      _nodes_size = new_nodes_size;
    }
  }

  inline node<T>* _get(int i) {
    return (node<T>*)((char *)_nodes + (_s * i)/sizeof(char));
  }

  int _make_tree(const vector<int >& indices) {
    if (indices.size() == 1)
      return indices[0];

    _allocate_size(_n_nodes + 1);
    int item = _n_nodes++;
    node<T>* m = _get(item);
    m->n_descendants = indices.size();

    if (indices.size() <= (size_t)_K) {
      for (size_t i = 0; i < indices.size(); i++)
	m->children[i] = indices[i];
      return item;
    }

    vector<int> children_indices[2];
    for (int attempt = 0; attempt < 20; attempt ++) {
      /*
       * Create a random hyperplane.
       * If all points end up on the same time, we try again.
       * We could in principle *construct* a plane so that we split
       * all items evenly, but I think that could violate the guarantees
       * given by just picking a hyperplane at random
       */
      for (int z = 0; z < _f; z++)
	m->v[z] = _var_nor();

      children_indices[0].clear();
      children_indices[1].clear();

      for (size_t i = 0; i < indices.size(); i++) {
	int j = indices[i];
	node<T>* n = _get(j);
	if (!n) {
	  printf("node %d undef...\n", j);
	  continue;
	}
	T dot = 0;
	for (int z = 0; z < _f; z++) {
	  dot += m->v[z] * n->v[z];
	}
	while (dot == 0)
	  dot = _var_nor();
	children_indices[dot > 0].push_back(j);
      }

      if (children_indices[0].size() > 0 && children_indices[1].size() > 0) {
	break;
      }
    }

    while (children_indices[0].size() == 0 || children_indices[1].size() == 0) {
      // If we didn't find a hyperplane, just randomize sides as a last option
      if (indices.size() > 100000)
	printf("Failed splitting %lu items\n", indices.size());

      children_indices[0].clear();
      children_indices[1].clear();

      // Set the vector to 0.0
      for (int z = 0; z < _f; z++)
	m->v[z] = 0.0;

      for (size_t i = 0; i < indices.size(); i++) {
	int j = indices[i];
	// Just randomize...
	children_indices[_var_nor() > 0].push_back(j);
      }
    }

    int children_0 = _make_tree(children_indices[0]);
    int children_1 = _make_tree(children_indices[1]);

    // We need to fetch m again because it might have been reallocated
    m = _get(item);
    m->children[0] = children_0;
    m->children[1] = children_1;

    return item;
  }

  void _get_nns(const T* v, int i, vector<int>* result, int limit) {
    const node<T>* n = _get(i);

    if (n->n_descendants == 0) {
      // unknown item, nothing to do...
    } else if (n->n_descendants == 1) {
      result->push_back(i);
    } else if (n->n_descendants <= _K) {
      for (int j = 0; j < n->n_descendants; j++) {
	result->push_back(n->children[j]);
      }
    } else {
      T dot = 0;

      for (int z = 0; z < _f; z++)
	dot += v[z] * n->v[z];

      while (dot == 0) // Randomize side if the dot product is zero
	dot = _var_nor();

      _get_nns(v, n->children[dot > 0], result, limit);
      if (result->size() < (size_t)limit)
	_get_nns(v, n->children[dot < 0], result, limit);
    }
  }

  python::list _get_all_nns(const T* v, int n) {
    vector<pair<T, int> > nns_cos;

    for (size_t i = 0; i < _roots.size(); i++) {
      vector<int> nns;
      _get_nns(v, _roots[i], &nns, n);
      for (size_t j = 0; j < nns.size(); j++) {
	nns_cos.push_back(make_pair(_cos(v, _get(nns[j])->v), nns[j]));
      }
    }
    sort(nns_cos.begin(), nns_cos.end());
    int last = -1, length=0;
    python::list l;
    for (int i = (int)nns_cos.size() - 1; i >= 0 && length < n; i--) {
      if (nns_cos[i].second != last) {
	l.append(nns_cos[i].second);
	last = nns_cos[i].second;
	length++;
      }
    }
    return l;
  }
};

BOOST_PYTHON_MODULE(annoylib)
{
  python::class_<AnnoyIndex<float> >("AnnoyIndex", python::init<int>())
    .def("add_item",          &AnnoyIndex<float>::add_item)
    .def("build",             &AnnoyIndex<float>::build)
    .def("save",              &AnnoyIndex<float>::save)
    .def("load",              &AnnoyIndex<float>::load)
    .def("cos",               &AnnoyIndex<float>::cos)
    .def("get_nns_by_item",   &AnnoyIndex<float>::get_nns_by_item)
    .def("get_nns_by_vector", &AnnoyIndex<float>::get_nns_by_vector);
}
<|endoftext|>