<commit_before>#include "con_thread.hpp"

#include <unordered_map>

#include <cstdint>
#include <cstdio>
#include <cstddef>

#include <errno.h>
#include <sys/epoll.h>
#include <sys/types.h>
#include <unistd.h>

#include <boost/coroutine/all.hpp>

#include "io_utils.hpp"

using namespace std;
namespace co = boost::coroutines;

enum connection_co_status
{
	STATUS_ERROR = -1,
	STATUS_DONE = 0,
	STATUS_WAIT_READ,
	STATUS_WAIT_WRITE
};

template <typename YieldType>
static io_status read_n_co(YieldType& yield, int fd, void *buf, std::size_t count, std::size_t& count_out)
{
	io_status result;
	while((result = read_n(fd, buf, count, count_out)) == IO_AGAIN && count_out == 0)
	{
		yield(STATUS_WAIT_READ);
	}
	return result;
}

template <typename YieldType>
static io_status write_n_co(YieldType& yield, int fd, const void *buf, std::size_t count, std::size_t& count_out)
{
	io_status result;
	while((result = write_n(fd, buf, count, count_out)) == IO_AGAIN && count_out == 0)
	{
		yield(STATUS_WAIT_WRITE);
	}
	return result;
}

void echo_connection_co_func(co::symmetric_coroutine<connection_co_status>::yield_type& yield)
{
	auto read_yielder =
	[
}

void con_thread_func(int epoll_fd, const std::atomic_bool& run)
{
	struct con_state
	{
		std::array<char, 512> data;
		std::size_t size;
		bool writable;

		con_state(): size(0), writable(false) {}
	};
	std::unordered_map<int, con_state> con_data;

	char buffer[256];

	int con_sock;
	while(run.load())
	{
		struct epoll_event events[8];
		int num = epoll_wait(epoll_fd, events, 8, 50);
		for(int i = 0; i < num; ++i)
		{
			fprintf(stderr, "Handling input\n");
			int fd = events[i].data.fd;
			uint32_t ev = events[i].events;
			if(ev & EPOLLRDHUP || ev & EPOLLHUP || ev & EPOLLERR)
			{
				fprintf(stderr, "Closed\n");
				close(fd);
				con_data.erase(fd);
				continue; // Go to next fd
			}

			con_state& s = con_data[fd];

			if(ev & EPOLLOUT)
			{
				fprintf(stderr, "EPOLLOUT\n");
				size_t written = 0;
				if(s.size > 0)
				{
					io_result result = write_n(fd, &s.data[0], s.size, written);
					if(result == IO_FAIL)
					{
						fprintf(stderr, "Closed\n");
						close(fd);
						con_data.erase(fd);
						continue;
					}

					if(written < s.size && written > 0)
					{
						std::copy(s.data.begin() + written, s.data.begin() + s.size, s.data.begin());
						s.size -= written;
					}
					else if(written == s.size)
					{
						s.size = 0;
					}

					if(result == IO_SUCCESS)
					{
						s.writable = true;
					}
					else
					{
						s.writable = false;
					}
				}
				else
				{
					s.writable = true;
				}
			}

			if(ev & EPOLLIN)
			{
				fprintf(stderr, "EPOLLIN\n");
				io_result read_result = IO_SUCCESS, write_result = IO_SUCCESS;
				while(s.writable)
				{
					size_t count = 0;
					read_result = read_n(fd, buffer, sizeof(buffer), count);
				    if(read_result == IO_FAIL)
						break;

					if(count > 0)
					{
						size_t written = 0;
						write_result = write_n(fd, buffer, count, written);
						if(write_result == IO_FAIL)
							break;

						if(write_result == IO_AGAIN)
						{
							std::copy(buffer + written, buffer + count, s.data.begin());
							s.size = count - written;
							s.writable = false;
						}
					}
					if(read_result == IO_AGAIN)
						break;
				}
				if(read_result == IO_FAIL || write_result == IO_FAIL)
				{
					fprintf(stderr, "Closed\n");
					close(fd);
					con_data.erase(fd);
					continue;
				}
				if(read_result == IO_SUCCESS)
				{
				    if(s.size < s.data.size())
					{
						size_t count = 0;
						read_result = read_n(fd, &s.data[0], s.data.size() - s.size, count);
						if(read_result == IO_FAIL)
						{
							close(fd);
							con_data.erase(fd);
							continue;
						}

						s.size += count;
					}
				    // Just discard any more bytes once fd buffer is full
					while(read_result == IO_SUCCESS)
					{
						size_t count = 0;
						read_result = read_n(fd, buffer, sizeof(buffer), count);
					}
					if(read_result == IO_FAIL)
					{
						fprintf(stderr, "Closed\n");
						close(fd);
						con_data.erase(fd);
						continue;
					}
				}
			}

		    // struct epoll_event new_event;
		    // new_event.events = EPOLL_EVENTS;
			// new_event.data.fd = fd;
			// epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &new_event);
		}
	}
}
<commit_msg>Coroutines<commit_after>#include "con_thread.hpp"

#include <unordered_map>

#include <cstdint>
#include <cstdio>
#include <cstddef>

#include <errno.h>
#include <sys/epoll.h>
#include <sys/types.h>
#include <unistd.h>

#include <boost/coroutine/all.hpp>

#include "io_utils.hpp"

using namespace std;
namespace co = boost::coroutines;

enum connection_co_status
{
	STATUS_ERROR = -1,
	STATUS_DONE = 0,
	STATUS_WAIT_READ,
	STATUS_WAIT_WRITE
};

template <typename YieldType>
static io_status read_n_co(YieldType& yield, int fd, void *buf, std::size_t count, std::size_t& count_out)
{
	io_status result;
	while((result = read_n(fd, buf, count, count_out)) == IO_AGAIN && count_out == 0)
	{
		yield(STATUS_WAIT_READ);
	}
	return result;
}

template <typename YieldType>
static io_status write_n_co(YieldType& yield, int fd, const void *buf, std::size_t count, std::size_t& count_out)
{
	io_status result;
	while((result = write_n(fd, buf, count, count_out)) == IO_AGAIN && count_out == 0)
	{
		yield(STATUS_WAIT_WRITE);
	}
	return result;
}

using connection_coroutine = co::symmetric_coroutine<void>;
using poller_coroutine = co::symmetric_coroutine<connection_co_status>;

struct connection_data
{
	int fd;
	connection_co_status status;
};

static void connection_co_func(connection_coroutine::yield_type& yield, poller_coroutine& poller, connection_data& data)
{
	auto yielder = bind(yield, ref(poller), placeholders::_1);

	char buffer[256];
	io_status result;
	while(true)
	{
		size_t count;
		result = read_n_co(yielder, data.fd, buffer, sizeof(buffer), count);
		if(result == IO_FAIL)
			break;
		result = write_n_co(yielder, data.fd, buffer, sizeof(buffer), count);
		if(result == IO_FAIL)
			break;
	}

	yield(poller, STATUS_DONE);
}

struct connection
{
	connection_coroutine co;
	connection_data data;
}

static void poller_co_func(poller_coroutine::yield_type& yield, poller_coroutine& this_co, int epoll_fd, atomic_bool& should_run)
{
	map<int, connection> cons;
	while(should_run.load())
	{
		struct epoll_event events[8];
		int num_events = epoll_wait(epoll_fd, events, 8, 50);
		for(int i = 0; i < num_events; ++i)
		{
			int fd = events[i].data.fd;
		    uint32_t event_mask = events[i].events;
			auto it = cons.find(fd);
			if(it == cons.end())
			{
				it = cons.emplace(fd, connection{});
				it->second.co = bind(connection_co_func, placeholders::_1, ref(this_co), ref(it->second));
				it->second.data = {fd, STATUS_WAIT_READ};
			}

			connection_co_status status = it->second.data.status;
			if((status == STATUS_WAIT_READ && (event_mask & EPOLLIN)) || (status == STATUS_WAIT_WRITE && (event_mask & EPOLLOUT)))
			{
				yield(it->second.co);
				status = yield.get();
			}

			if(status == STATUS_DONE || status == STATUS_FAIL)
			{
				goto end_con;
			}

			continue;

		end_con:
			close(fd);
			cons.erase(it);
		}
	}
}

void con_thread_func(int epoll_fd, const std::atomic_bool& run)
{
	struct con_state
	{
		std::array<char, 512> data;
		std::size_t size;
		bool writable;

		con_state(): size(0), writable(false) {}
	};
	std::unordered_map<int, con_state> con_data;

	char buffer[256];

	int con_sock;
	while(run.load())
	{
		struct epoll_event events[8];
		int num = epoll_wait(epoll_fd, events, 8, 50);
		for(int i = 0; i < num; ++i)
		{
			fprintf(stderr, "Handling input\n");
			int fd = events[i].data.fd;
			uint32_t ev = events[i].events;
			if(ev & EPOLLRDHUP || ev & EPOLLHUP || ev & EPOLLERR)
			{
				fprintf(stderr, "Closed\n");
				close(fd);
				con_data.erase(fd);
				continue; // Go to next fd
			}

			con_state& s = con_data[fd];

			if(ev & EPOLLOUT)
			{
				fprintf(stderr, "EPOLLOUT\n");
				size_t written = 0;
				if(s.size > 0)
				{
					io_result result = write_n(fd, &s.data[0], s.size, written);
					if(result == IO_FAIL)
					{
						fprintf(stderr, "Closed\n");
						close(fd);
						con_data.erase(fd);
						continue;
					}

					if(written < s.size && written > 0)
					{
						std::copy(s.data.begin() + written, s.data.begin() + s.size, s.data.begin());
						s.size -= written;
					}
					else if(written == s.size)
					{
						s.size = 0;
					}

					if(result == IO_SUCCESS)
					{
						s.writable = true;
					}
					else
					{
						s.writable = false;
					}
				}
				else
				{
					s.writable = true;
				}
			}

			if(ev & EPOLLIN)
			{
				fprintf(stderr, "EPOLLIN\n");
				io_result read_result = IO_SUCCESS, write_result = IO_SUCCESS;
				while(s.writable)
				{
					size_t count = 0;
					read_result = read_n(fd, buffer, sizeof(buffer), count);
				    if(read_result == IO_FAIL)
						break;

					if(count > 0)
					{
						size_t written = 0;
						write_result = write_n(fd, buffer, count, written);
						if(write_result == IO_FAIL)
							break;

						if(write_result == IO_AGAIN)
						{
							std::copy(buffer + written, buffer + count, s.data.begin());
							s.size = count - written;
							s.writable = false;
						}
					}
					if(read_result == IO_AGAIN)
						break;
				}
				if(read_result == IO_FAIL || write_result == IO_FAIL)
				{
					fprintf(stderr, "Closed\n");
					close(fd);
					con_data.erase(fd);
					continue;
				}
				if(read_result == IO_SUCCESS)
				{
				    if(s.size < s.data.size())
					{
						size_t count = 0;
						read_result = read_n(fd, &s.data[0], s.data.size() - s.size, count);
						if(read_result == IO_FAIL)
						{
							close(fd);
							con_data.erase(fd);
							continue;
						}

						s.size += count;
					}
				    // Just discard any more bytes once fd buffer is full
					while(read_result == IO_SUCCESS)
					{
						size_t count = 0;
						read_result = read_n(fd, buffer, sizeof(buffer), count);
					}
					if(read_result == IO_FAIL)
					{
						fprintf(stderr, "Closed\n");
						close(fd);
						con_data.erase(fd);
						continue;
					}
				}
			}

		    // struct epoll_event new_event;
		    // new_event.events = EPOLL_EVENTS;
			// new_event.data.fd = fd;
			// epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &new_event);
		}
	}
}
<|endoftext|>


<commit_before>// LuaWindow.cpp

// Implements the cLuaWindow class representing a virtual window that plugins may create and open for the player

#include "Globals.h"
#include "LuaWindow.h"
#include "../Entities/Player.h"
#include "../UI/SlotArea.h"
#include "PluginLua.h"
#include "lua/src/lauxlib.h"  // Needed for LUA_REFNIL
#include "../Root.h"
#include "../ClientHandle.h"

////////////////////////////////////////////////////////////////////////////////
// cLuaWindow:

cLuaWindow::cLuaWindow(cLuaState & a_LuaState, cWindow::WindowType a_WindowType, int a_SlotsX, int a_SlotsY, const AString & a_Title) :
	Super(a_WindowType, a_Title),
	m_Contents(a_SlotsX, a_SlotsY),
	m_LuaState(a_LuaState.QueryCanonLuaState())
{
	ASSERT(m_LuaState != nullptr);  // We must have a valid Lua state; this assert fails only if there was no Canon Lua state

	m_Contents.AddListener(*this);
	m_SlotAreas.push_back(new cSlotAreaItemGrid(m_Contents, *this));

	// If appropriate, add an Armor slot area:
	switch (a_WindowType)
	{
		case cWindow::wtInventory:
		case cWindow::wtWorkbench:
		{
			m_SlotAreas.push_back(new cSlotAreaArmor(*this));
			break;
		}
		default:
		{
			break;
		}
	}
	m_SlotAreas.push_back(new cSlotAreaInventory(*this));
	m_SlotAreas.push_back(new cSlotAreaHotBar(*this));
}

cLuaWindow::~cLuaWindow()
{
	m_Contents.RemoveListener(*this);

	// Close open lua window from players, to avoid dangling pointers
	cRoot::Get()->ForEachPlayer([this](cPlayer & a_Player)
		{
			if (a_Player.GetWindow() == this)
			{
				a_Player.CloseWindow(false);
			}
			return false;
		}
	);

	// Must delete slot areas now, because they are referencing this->m_Contents and would try to access it in cWindow's
	// destructor, when the member is already gone.
	for (cSlotAreas::iterator itr = m_SlotAreas.begin(), end = m_SlotAreas.end(); itr != end; ++itr)
	{
		delete *itr;
	}
	m_SlotAreas.clear();

	ASSERT(m_OpenedBy.empty());
}

void cLuaWindow::SetOnClicked(cLuaState::cCallbackPtr && a_OnClicked)
{
	// Only one Lua state can be a cLuaWindow object callback:
	ASSERT(a_OnClicked->IsSameLuaState(*m_LuaState));

	// Store the new reference, releasing the old one if appropriate:
	m_OnClicked = std::move(a_OnClicked);
}

void cLuaWindow::SetOnClosing(cLuaState::cCallbackPtr && a_OnClosing)
{
	// Only one Lua state can be a cLuaWindow object callback:
	ASSERT(a_OnClosing->IsSameLuaState(*m_LuaState));

	// Store the new reference, releasing the old one if appropriate:
	m_OnClosing = std::move(a_OnClosing);
}

void cLuaWindow::SetOnSlotChanged(cLuaState::cCallbackPtr && a_OnSlotChanged)
{
	// Only one Lua state can be a cLuaWindow object callback:
	ASSERT(a_OnSlotChanged->IsSameLuaState(*m_LuaState));

	// Store the new reference, releasing the old one if appropriate:
	m_OnSlotChanged = std::move(a_OnSlotChanged);
}

void cLuaWindow::OpenedByPlayer(cPlayer & a_Player)
{
	// If the first player is opening the window, create a Lua Reference to the window object so that Lua will not GC it until the last player closes the window:
	if (m_PlayerCount == 0)
	{
		m_LuaRef.CreateFromObject(*m_LuaState, this);
	}

	++m_PlayerCount;
	Super::OpenedByPlayer(a_Player);
}

bool cLuaWindow::ClosedByPlayer(cPlayer & a_Player, bool a_CanRefuse)
{
	// First notify the plugin through the registered callback:
	if (m_OnClosing != nullptr)
	{
		bool res;
		if (
			m_OnClosing->Call(this, &a_Player, a_CanRefuse, cLuaState::Return, res) &&  // The callback succeeded
			res                                                                         // The callback says not to close the window
		)
		{
			// The callback disagrees (the higher levels check the CanRefuse flag compliance)
			return false;
		}
	}

	// If the last player has closed the window, release the Lua reference, so that Lua may GC the object:
	--m_PlayerCount;
	if (m_PlayerCount == 0)
	{
		m_LuaRef.UnRef();
	}

	return Super::ClosedByPlayer(a_Player, a_CanRefuse);
}

void cLuaWindow::Destroy(void)
{
	Super::Destroy();

	// Lua will take care of this object, it will garbage-collect it, so we must not delete it!
	m_IsDestroyed = false;
}

void cLuaWindow::DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply)
{
	cSlotAreas Areas;
	for (auto && Area : m_SlotAreas)
	{
		if (Area != a_ClickedArea)
		{
			Areas.push_back(Area);
		}
	}

	Super::DistributeStackToAreas(a_ItemStack, a_Player, Areas, a_ShouldApply, false);
}

void cLuaWindow::OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum)
{
	if (a_ItemGrid != &m_Contents)
	{
		ASSERT(!"Invalid ItemGrid in callback");
		return;
	}

	// If an OnSlotChanged callback has been registered, call it:
	if (m_OnSlotChanged != nullptr)
	{
		m_OnSlotChanged->Call(this, a_SlotNum);
	}
}

void cLuaWindow::Clicked(cPlayer & a_Player, int a_WindowID, short a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem)
{
	if (m_OnClicked != nullptr)
	{
		// Plugin can stop a click
		if (m_OnClicked->Call(this, &a_Player, a_SlotNum, a_ClickAction, a_ClickedItem))
		{
			// Tell the client the actual state of the window
			a_Player.GetClientHandle()->SendInventorySlot(-1, -1, a_Player.GetDraggingItem());
			BroadcastWholeWindow();
			return;
		}
	}

	cWindow::Clicked(a_Player, a_WindowID, a_SlotNum, a_ClickAction, a_ClickedItem);
}

<commit_msg>Respect return value of cLuaWindow's OnClicked handler (#4322)<commit_after>// LuaWindow.cpp

// Implements the cLuaWindow class representing a virtual window that plugins may create and open for the player

#include "Globals.h"
#include "LuaWindow.h"
#include "../Entities/Player.h"
#include "../UI/SlotArea.h"
#include "PluginLua.h"
#include "lua/src/lauxlib.h"  // Needed for LUA_REFNIL
#include "../Root.h"
#include "../ClientHandle.h"

////////////////////////////////////////////////////////////////////////////////
// cLuaWindow:

cLuaWindow::cLuaWindow(cLuaState & a_LuaState, cWindow::WindowType a_WindowType, int a_SlotsX, int a_SlotsY, const AString & a_Title) :
	Super(a_WindowType, a_Title),
	m_Contents(a_SlotsX, a_SlotsY),
	m_LuaState(a_LuaState.QueryCanonLuaState())
{
	ASSERT(m_LuaState != nullptr);  // We must have a valid Lua state; this assert fails only if there was no Canon Lua state

	m_Contents.AddListener(*this);
	m_SlotAreas.push_back(new cSlotAreaItemGrid(m_Contents, *this));

	// If appropriate, add an Armor slot area:
	switch (a_WindowType)
	{
		case cWindow::wtInventory:
		case cWindow::wtWorkbench:
		{
			m_SlotAreas.push_back(new cSlotAreaArmor(*this));
			break;
		}
		default:
		{
			break;
		}
	}
	m_SlotAreas.push_back(new cSlotAreaInventory(*this));
	m_SlotAreas.push_back(new cSlotAreaHotBar(*this));
}

cLuaWindow::~cLuaWindow()
{
	m_Contents.RemoveListener(*this);

	// Close open lua window from players, to avoid dangling pointers
	cRoot::Get()->ForEachPlayer([this](cPlayer & a_Player)
		{
			if (a_Player.GetWindow() == this)
			{
				a_Player.CloseWindow(false);
			}
			return false;
		}
	);

	// Must delete slot areas now, because they are referencing this->m_Contents and would try to access it in cWindow's
	// destructor, when the member is already gone.
	for (cSlotAreas::iterator itr = m_SlotAreas.begin(), end = m_SlotAreas.end(); itr != end; ++itr)
	{
		delete *itr;
	}
	m_SlotAreas.clear();

	ASSERT(m_OpenedBy.empty());
}

void cLuaWindow::SetOnClicked(cLuaState::cCallbackPtr && a_OnClicked)
{
	// Only one Lua state can be a cLuaWindow object callback:
	ASSERT(a_OnClicked->IsSameLuaState(*m_LuaState));

	// Store the new reference, releasing the old one if appropriate:
	m_OnClicked = std::move(a_OnClicked);
}

void cLuaWindow::SetOnClosing(cLuaState::cCallbackPtr && a_OnClosing)
{
	// Only one Lua state can be a cLuaWindow object callback:
	ASSERT(a_OnClosing->IsSameLuaState(*m_LuaState));

	// Store the new reference, releasing the old one if appropriate:
	m_OnClosing = std::move(a_OnClosing);
}

void cLuaWindow::SetOnSlotChanged(cLuaState::cCallbackPtr && a_OnSlotChanged)
{
	// Only one Lua state can be a cLuaWindow object callback:
	ASSERT(a_OnSlotChanged->IsSameLuaState(*m_LuaState));

	// Store the new reference, releasing the old one if appropriate:
	m_OnSlotChanged = std::move(a_OnSlotChanged);
}

void cLuaWindow::OpenedByPlayer(cPlayer & a_Player)
{
	// If the first player is opening the window, create a Lua Reference to the window object so that Lua will not GC it until the last player closes the window:
	if (m_PlayerCount == 0)
	{
		m_LuaRef.CreateFromObject(*m_LuaState, this);
	}

	++m_PlayerCount;
	Super::OpenedByPlayer(a_Player);
}

bool cLuaWindow::ClosedByPlayer(cPlayer & a_Player, bool a_CanRefuse)
{
	// First notify the plugin through the registered callback:
	if (m_OnClosing != nullptr)
	{
		bool res;
		if (
			m_OnClosing->Call(this, &a_Player, a_CanRefuse, cLuaState::Return, res) &&  // The callback succeeded
			res                                                                         // The callback says not to close the window
		)
		{
			// The callback disagrees (the higher levels check the CanRefuse flag compliance)
			return false;
		}
	}

	// If the last player has closed the window, release the Lua reference, so that Lua may GC the object:
	--m_PlayerCount;
	if (m_PlayerCount == 0)
	{
		m_LuaRef.UnRef();
	}

	return Super::ClosedByPlayer(a_Player, a_CanRefuse);
}

void cLuaWindow::Destroy(void)
{
	Super::Destroy();

	// Lua will take care of this object, it will garbage-collect it, so we must not delete it!
	m_IsDestroyed = false;
}

void cLuaWindow::DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply)
{
	cSlotAreas Areas;
	for (auto && Area : m_SlotAreas)
	{
		if (Area != a_ClickedArea)
		{
			Areas.push_back(Area);
		}
	}

	Super::DistributeStackToAreas(a_ItemStack, a_Player, Areas, a_ShouldApply, false);
}

void cLuaWindow::OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum)
{
	if (a_ItemGrid != &m_Contents)
	{
		ASSERT(!"Invalid ItemGrid in callback");
		return;
	}

	// If an OnSlotChanged callback has been registered, call it:
	if (m_OnSlotChanged != nullptr)
	{
		m_OnSlotChanged->Call(this, a_SlotNum);
	}
}

void cLuaWindow::Clicked(cPlayer & a_Player, int a_WindowID, short a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem)
{
	if (m_OnClicked != nullptr)
	{
		// Plugin can stop a click
		bool res;
		if (m_OnClicked->Call(this, &a_Player, a_SlotNum, a_ClickAction, a_ClickedItem, cLuaState::Return, res) && res)
		{
			// Tell the client the actual state of the window
			a_Player.GetClientHandle()->SendInventorySlot(-1, -1, a_Player.GetDraggingItem());
			BroadcastWholeWindow();
			return;
		}
	}

	cWindow::Clicked(a_Player, a_WindowID, a_SlotNum, a_ClickAction, a_ClickedItem);
}

<|endoftext|>


<commit_before><commit_msg>Fix special case registers to be per-thread. Remove RMOR.<commit_after><|endoftext|>


<commit_before>#include "MainForm.moc"

#include "../assemble.h"
#include <tbb/task_scheduler_init.h>

MainForm::MainForm(QGraphicsScene* img, nbt* bf, QWidget* parent_)
                 : QGraphicsView(img, parent_), scene_(), bf_(bf), scale_(1),
                   images() {
  connect(this, SIGNAL(scaleSig()), this, SLOT(scale()));
  connect(this, SIGNAL(renderNewImage()), this, SLOT(populateSceneItem()));
  connect(this, SIGNAL(saveToFileSignal()), this, SLOT(saveToFile()));
  setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
}

class ApplyFooQT {
  mutable MainForm* mainform_;
  int i_;
  mutable tbb::atomic<size_t>* index_;
 public:
  void operator()( const tbb::blocked_range<std::vector<int>::iterator>& r ) const {
    for(std::vector<int>::iterator j=r.begin(); j!=r.end(); ++j) {
      bool result = false;
      std::pair<int, int> bp = projectCoords(std::make_pair(*j, i_),
                                        (4 - mainform_->bf_->set().rotate) % 4);
      Image<uint8_t> image = mainform_->bf_->getImage(bp.first, bp.second, &result);
      if (!result) {
        continue;
      }
      *index_ += 1;
      mainform_->images.push(MainForm::image_coords(image, QPoint(bp.first,
                                                                  bp.second)));
      mainform_->renderNewImageEmitter();
    }
  }
  ApplyFooQT(MainForm* mainform, int i, tbb::atomic<size_t>* index)
          : mainform_(mainform), i_(i), index_(index) {}
  /* just for the compiler */
  ApplyFooQT(const ApplyFooQT& rhs)
          : mainform_(rhs.mainform_), i_(rhs.i_), index_(rhs.index_) {}
 private:
  ApplyFooQT& operator=(const ApplyFoo&);
};

void MainForm::populateScene() {
  std::pair<int, int> min_norm, max_norm;
  calculateMinMaxPoint(min_norm, max_norm, *bf_);
  size_t range = static_cast<size_t>(max_norm.second - min_norm.second + 1);
  boost::progress_display show_progress(range);
  std::list<std::vector<int> > tiles(range);
  size_t tiles_nr = fillTiles(tiles, *bf_, min_norm, max_norm, show_progress);
  tbb::atomic<size_t> progress_index, mem_index;
  progress_index = 0;
  mem_index = 0;
  show_progress.restart(tiles_nr);
  std::list<std::vector<int> >::iterator it = tiles.begin();
  tbb::task_scheduler_init init;
  for (int i = min_norm.second; i <= max_norm.second; ++i) {
    tbb::parallel_for(tbb::blocked_range<std::vector<int>::iterator>
                                                       (it->begin(), it->end()),
                      ApplyFooQT(this, i, &progress_index));
    mem_index += progress_index;
    if (mem_index > 10000) {
      mem_index = 0;
      bf_->clearCache();
    }
    ++it;
    show_progress += progress_index;
    progress_index = 0;
  }
  bf_->clearCache();
  emit saveToFileSignal();
}

void MainForm::renderNewImageEmitter() {
  emit renderNewImage();
}

void MainForm::saveToFile() {
  QImage image(scene()->sceneRect().toRect().size(), QImage::Format_ARGB32);
  image.fill(0);
  QPainter painter(&image);
  scene()->render(&painter, painter.viewport(), scene()->sceneRect());
  image.save("image.png");
  fprintf(stderr, "image saved!\n");
  // throw std::runtime_error("image saved!");
}

void MainForm::populateSceneItem() {
  MainForm::image_coords img_coor;
  if (images.pop_if_present(img_coor)) {
    QImage img(&(img_coor.first.data[0]),
               img_coor.first.cols,
               img_coor.first.rows,
               QImage::Format_ARGB32);
    QGraphicsPixmapItem* pi = scene()->addPixmap(QPixmap::fromImage(img));
    pi->setFlag(QGraphicsItem::ItemIsMovable, false);
    pi->setFlag(QGraphicsItem::ItemIsSelectable, false);
    std::pair<int, int> p = projectCoords(
                                       std::make_pair(16 * img_coor.second.x(),
                                                      16 * img_coor.second.y()),
                                       bf_->set().rotate);
    if (bf_->set().isometric) {
      p = std::make_pair(2 * p.first - 2 * p.second, p.first + p.second);
    }
    pi->setPos(p.first, p.second);
    pi->setZValue(p.second);
  } else {
    throw std::runtime_error("must not happen in populateSceneItem()!");
  }
}

void MainForm::scale() {
  if (scale_ <= 0) {
    setTransform(QTransform().scale(1.0 / pow(2.0, abs(scale_ - 1)),
                                    1.0 / pow(2.0, abs(scale_ - 1))));
  } else {
    setTransform(QTransform().scale(scale_, scale_));
  }
}

void MainForm::mousePressEvent(QMouseEvent* mevent) {
  switch (mevent->button()) {
    case Qt::LeftButton:
      ++scale_;
      emit scaleSig();
      break;
    case Qt::MidButton:
      break;
    case Qt::RightButton:
      --scale_;
      emit scaleSig();
      break;
    default:
      break;
  }
  return;
}

void MainForm::mouseDoubleClickEvent(QMouseEvent* mevent) {
  mousePressEvent(mevent);
  return;
}
<commit_msg>fix bug with older Qt, where 0,0 was in scene rect<commit_after>#include "MainForm.moc"

#include "../assemble.h"
#include <tbb/task_scheduler_init.h>

MainForm::MainForm(QGraphicsScene* img, nbt* bf, QWidget* parent_)
                 : QGraphicsView(img, parent_), scene_(), bf_(bf), scale_(1),
                   images() {
  connect(this, SIGNAL(scaleSig()), this, SLOT(scale()));
  connect(this, SIGNAL(renderNewImage()), this, SLOT(populateSceneItem()));
  connect(this, SIGNAL(saveToFileSignal()), this, SLOT(saveToFile()));
  setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
}

class ApplyFooQT {
  mutable MainForm* mainform_;
  int i_;
  mutable tbb::atomic<size_t>* index_;
 public:
  void operator()( const tbb::blocked_range<std::vector<int>::iterator>& r ) const {
    for(std::vector<int>::iterator j=r.begin(); j!=r.end(); ++j) {
      bool result = false;
      std::pair<int, int> bp = projectCoords(std::make_pair(*j, i_),
                                        (4 - mainform_->bf_->set().rotate) % 4);
      Image<uint8_t> image = mainform_->bf_->getImage(bp.first, bp.second, &result);
      if (!result) {
        continue;
      }
      *index_ += 1;
      mainform_->images.push(MainForm::image_coords(image, QPoint(bp.first,
                                                                  bp.second)));
      mainform_->renderNewImageEmitter();
    }
  }
  ApplyFooQT(MainForm* mainform, int i, tbb::atomic<size_t>* index)
          : mainform_(mainform), i_(i), index_(index) {}
  /* just for the compiler */
  ApplyFooQT(const ApplyFooQT& rhs)
          : mainform_(rhs.mainform_), i_(rhs.i_), index_(rhs.index_) {}
 private:
  ApplyFooQT& operator=(const ApplyFoo&);
};

void MainForm::populateScene() {
  std::pair<int, int> min_norm, max_norm;
  calculateMinMaxPoint(min_norm, max_norm, *bf_);
  size_t range = static_cast<size_t>(max_norm.second - min_norm.second + 1);
  boost::progress_display show_progress(range);
  std::list<std::vector<int> > tiles(range);
  size_t tiles_nr = fillTiles(tiles, *bf_, min_norm, max_norm, show_progress);
  tbb::atomic<size_t> progress_index, mem_index;
  progress_index = 0;
  mem_index = 0;
  show_progress.restart(tiles_nr);
  std::list<std::vector<int> >::iterator it = tiles.begin();
  tbb::task_scheduler_init init;
  for (int i = min_norm.second; i <= max_norm.second; ++i) {
    tbb::parallel_for(tbb::blocked_range<std::vector<int>::iterator>
                                                       (it->begin(), it->end()),
                      ApplyFooQT(this, i, &progress_index));
    mem_index += progress_index;
    if (mem_index > 10000) {
      mem_index = 0;
      bf_->clearCache();
    }
    ++it;
    show_progress += progress_index;
    progress_index = 0;
  }
  bf_->clearCache();
  emit saveToFileSignal();
}

void MainForm::renderNewImageEmitter() {
  emit renderNewImage();
}

void MainForm::saveToFile() {
  QImage image(scene()->sceneRect().toRect().size(), QImage::Format_ARGB32);
  image.fill(0);
  QPainter painter(&image);
  scene()->render(&painter, painter.viewport(), scene()->sceneRect());
  image.save("image.png");
  fprintf(stderr, "image saved!\n");
  // throw std::runtime_error("image saved!");
}

void MainForm::populateSceneItem() {
  MainForm::image_coords img_coor;
  if (images.pop_if_present(img_coor)) {
    QImage img(&(img_coor.first.data[0]),
               img_coor.first.cols,
               img_coor.first.rows,
               QImage::Format_ARGB32);
    std::pair<int, int> p = projectCoords(
                                       std::make_pair(16 * img_coor.second.x(),
                                                      16 * img_coor.second.y()),
                                       bf_->set().rotate);
    if (bf_->set().isometric) {
      p = std::make_pair(2 * p.first - 2 * p.second, p.first + p.second);
    }
    QGraphicsPixmapItem* pi = new QGraphicsPixmapItem(QPixmap::fromImage(img));
    pi->setPos(p.first, p.second);
    pi->setZValue(p.second);
    pi->setFlag(QGraphicsItem::ItemIsMovable, false);
    pi->setFlag(QGraphicsItem::ItemIsSelectable, false);
    scene()->addItem(pi);
  } else {
    throw std::runtime_error("must not happen in populateSceneItem()!");
  }
}

void MainForm::scale() {
  if (scale_ <= 0) {
    setTransform(QTransform().scale(1.0 / pow(2.0, abs(scale_ - 1)),
                                    1.0 / pow(2.0, abs(scale_ - 1))));
  } else {
    setTransform(QTransform().scale(scale_, scale_));
  }
}

void MainForm::mousePressEvent(QMouseEvent* mevent) {
  switch (mevent->button()) {
    case Qt::LeftButton:
      ++scale_;
      emit scaleSig();
      break;
    case Qt::MidButton:
      break;
    case Qt::RightButton:
      --scale_;
      emit scaleSig();
      break;
    default:
      break;
  }
  return;
}

void MainForm::mouseDoubleClickEvent(QMouseEvent* mevent) {
  mousePressEvent(mevent);
  return;
}
<|endoftext|>


<commit_before>/**
 * @file Dcm.hpp
 *
 * A direction cosine matrix class.
 * All rotations and axis systems follow the right-hand rule.
 *
 * This library uses the convention that premultiplying a three dimensional
 * vector represented in coordinate system 1 will apply a rotation from coordinate system
 * 1 to coordinate system 2 to the vector.
 * Likewise, a matrix instance of this class also represents a coordinate transformation
 * from frame 2 to frame 1.
 *
 * @author James Goppert <james.goppert@gmail.com>
 */

#pragma once

#include "math.hpp"

namespace matrix
{

template<typename Type>
class Quaternion;

template<typename Type>
class Euler;

template<typename Type>
class AxisAngle;

/**
 * Direction cosine matrix class
 *
 * The rotation between two coordinate frames is
 * described by this class.
 */
template<typename Type>
class Dcm : public Matrix<Type, 3, 3>
{
public:
    virtual ~Dcm() {};

    typedef Matrix<Type, 3, 1> Vector3;

    /**
     * Standard constructor
     *
     * Initializes to identity
     */
    Dcm() : Matrix<Type, 3, 3>()
    {
        (*this) = eye<Type, 3>();
    }

    /**
     * Constructor from array
     *
     * @param _data pointer to array
     */
    Dcm(const Type *data_) : Matrix<Type, 3, 3>(data_)
    {
    }

    /**
     * Copy constructor
     *
     * @param other Matrix33 to set dcm to
     */
    Dcm(const Matrix<Type, 3, 3> &other) : Matrix<Type, 3, 3>(other)
    {
    }

    /**
     * Constructor from quaternion
     *
     * Instance is initialized from quaternion representing
     * coordinate transformation from frame 2 to frame 1.
     *
     * @param q quaternion to set dcm to
     */
    Dcm(const Quaternion<Type> &q)
    {
        Dcm &dcm = *this;
        Type a = q(0);
        Type b = q(1);
        Type c = q(2);
        Type d = q(3);
        Type aSq = a * a;
        Type bSq = b * b;
        Type cSq = c * c;
        Type dSq = d * d;
        dcm(0, 0) = aSq + bSq - cSq - dSq;
        dcm(0, 1) = 2 * (b * c - a * d);
        dcm(0, 2) = 2 * (a * c + b * d);
        dcm(1, 0) = 2 * (b * c + a * d);
        dcm(1, 1) = aSq - bSq + cSq - dSq;
        dcm(1, 2) = 2 * (c * d - a * b);
        dcm(2, 0) = 2 * (b * d - a * c);
        dcm(2, 1) = 2 * (a * b + c * d);
        dcm(2, 2) = aSq - bSq - cSq + dSq;
    }

    /**
     * Constructor from euler angles
     *
     * This sets the transformation matrix from frame 2 to frame 1 where the rotation
     * from frame 1 to frame 2 is described by a 3-2-1 intrinsic Tait-Bryan rotation sequence.
     *
     *
     * @param euler euler angle instance
     */
    Dcm(const Euler<Type> &euler)
    {
        Dcm &dcm = *this;
        Type cosPhi = Type(cos(euler.phi()));
        Type sinPhi = Type(sin(euler.phi()));
        Type cosThe = Type(cos(euler.theta()));
        Type sinThe = Type(sin(euler.theta()));
        Type cosPsi = Type(cos(euler.psi()));
        Type sinPsi = Type(sin(euler.psi()));

        dcm(0, 0) = cosThe * cosPsi;
        dcm(0, 1) = -cosPhi * sinPsi + sinPhi * sinThe * cosPsi;
        dcm(0, 2) = sinPhi * sinPsi + cosPhi * sinThe * cosPsi;

        dcm(1, 0) = cosThe * sinPsi;
        dcm(1, 1) = cosPhi * cosPsi + sinPhi * sinThe * sinPsi;
        dcm(1, 2) = -sinPhi * cosPsi + cosPhi * sinThe * sinPsi;

        dcm(2, 0) = -sinThe;
        dcm(2, 1) = sinPhi * cosThe;
        dcm(2, 2) = cosPhi * cosThe;
    }

    /**
     * Constructor from axis angle
     *
     * This sets the transformation matrix from frame 2 to frame 1 where the rotation
     * from frame 1 to frame 2 is described by a 3-2-1 intrinsic Tait-Bryan rotation sequence.
     *
     *
     * @param euler euler angle instance
     */
    Dcm(const AxisAngle<Type> &aa)
    {
        Dcm &dcm = *this;
        dcm = Quaternion<Type>(aa);
    }

    Vector<Type, 3> vee() const      // inverse to Vector.hat() operation
    {
        const Dcm &A(*this);
        Vector<Type, 3> v;
        v(0) = -A(1, 2);
        v(1) =  A(0, 2);
        v(2) = -A(0, 1);
        return v;
    }

    void renormalize()
    {
        /* renormalize rows */
        for (int row = 0; row < 3; row++) {
            matrix::Vector3f rvec(this->_data[row]);
            this->setRow(row, rvec.normalized());
        }
    }
};

typedef Dcm<float> Dcmf;

} // namespace matrix

/* vim: set et fenc=utf-8 ff=unix sts=0 sw=4 ts=4 : */
<commit_msg>Changed Dcm to inherit from SquareMatrix because it is square and we can use the trace method<commit_after>/**
 * @file Dcm.hpp
 *
 * A direction cosine matrix class.
 * All rotations and axis systems follow the right-hand rule.
 *
 * This library uses the convention that premultiplying a three dimensional
 * vector represented in coordinate system 1 will apply a rotation from coordinate system
 * 1 to coordinate system 2 to the vector.
 * Likewise, a matrix instance of this class also represents a coordinate transformation
 * from frame 2 to frame 1.
 *
 * @author James Goppert <james.goppert@gmail.com>
 */

#pragma once

#include "math.hpp"

namespace matrix
{

template<typename Type>
class Quaternion;

template<typename Type>
class Euler;

template<typename Type>
class AxisAngle;

/**
 * Direction cosine matrix class
 *
 * The rotation between two coordinate frames is
 * described by this class.
 */
template<typename Type>
class Dcm : public SquareMatrix<Type, 3>
{
public:
    virtual ~Dcm() {};

    typedef Matrix<Type, 3, 1> Vector3;

    /**
     * Standard constructor
     *
     * Initializes to identity
     */
    Dcm() : SquareMatrix<Type, 3>()
    {
        (*this) = eye<Type, 3>();
    }

    /**
     * Constructor from array
     *
     * @param _data pointer to array
     */
    Dcm(const Type *data_) : SquareMatrix<Type, 3>(data_)
    {
    }

    /**
     * Copy constructor
     *
     * @param other Matrix33 to set dcm to
     */
    Dcm(const Matrix<Type, 3, 3> &other) : SquareMatrix<Type, 3>(other)
    {
    }

    /**
     * Constructor from quaternion
     *
     * Instance is initialized from quaternion representing
     * coordinate transformation from frame 2 to frame 1.
     *
     * @param q quaternion to set dcm to
     */
    Dcm(const Quaternion<Type> &q)
    {
        Dcm &dcm = *this;
        Type a = q(0);
        Type b = q(1);
        Type c = q(2);
        Type d = q(3);
        Type aSq = a * a;
        Type bSq = b * b;
        Type cSq = c * c;
        Type dSq = d * d;
        dcm(0, 0) = aSq + bSq - cSq - dSq;
        dcm(0, 1) = 2 * (b * c - a * d);
        dcm(0, 2) = 2 * (a * c + b * d);
        dcm(1, 0) = 2 * (b * c + a * d);
        dcm(1, 1) = aSq - bSq + cSq - dSq;
        dcm(1, 2) = 2 * (c * d - a * b);
        dcm(2, 0) = 2 * (b * d - a * c);
        dcm(2, 1) = 2 * (a * b + c * d);
        dcm(2, 2) = aSq - bSq - cSq + dSq;
    }

    /**
     * Constructor from euler angles
     *
     * This sets the transformation matrix from frame 2 to frame 1 where the rotation
     * from frame 1 to frame 2 is described by a 3-2-1 intrinsic Tait-Bryan rotation sequence.
     *
     *
     * @param euler euler angle instance
     */
    Dcm(const Euler<Type> &euler)
    {
        Dcm &dcm = *this;
        Type cosPhi = Type(cos(euler.phi()));
        Type sinPhi = Type(sin(euler.phi()));
        Type cosThe = Type(cos(euler.theta()));
        Type sinThe = Type(sin(euler.theta()));
        Type cosPsi = Type(cos(euler.psi()));
        Type sinPsi = Type(sin(euler.psi()));

        dcm(0, 0) = cosThe * cosPsi;
        dcm(0, 1) = -cosPhi * sinPsi + sinPhi * sinThe * cosPsi;
        dcm(0, 2) = sinPhi * sinPsi + cosPhi * sinThe * cosPsi;

        dcm(1, 0) = cosThe * sinPsi;
        dcm(1, 1) = cosPhi * cosPsi + sinPhi * sinThe * sinPsi;
        dcm(1, 2) = -sinPhi * cosPsi + cosPhi * sinThe * sinPsi;

        dcm(2, 0) = -sinThe;
        dcm(2, 1) = sinPhi * cosThe;
        dcm(2, 2) = cosPhi * cosThe;
    }

    /**
     * Constructor from axis angle
     *
     * This sets the transformation matrix from frame 2 to frame 1 where the rotation
     * from frame 1 to frame 2 is described by a 3-2-1 intrinsic Tait-Bryan rotation sequence.
     *
     *
     * @param euler euler angle instance
     */
    Dcm(const AxisAngle<Type> &aa)
    {
        Dcm &dcm = *this;
        dcm = Quaternion<Type>(aa);
    }

    Vector<Type, 3> vee() const      // inverse to Vector.hat() operation
    {
        const Dcm &A(*this);
        Vector<Type, 3> v;
        v(0) = -A(1, 2);
        v(1) =  A(0, 2);
        v(2) = -A(0, 1);
        return v;
    }

    void renormalize()
    {
        /* renormalize rows */
        for (int row = 0; row < 3; row++) {
            matrix::Vector3f rvec(this->_data[row]);
            this->setRow(row, rvec.normalized());
        }
    }
};

typedef Dcm<float> Dcmf;

} // namespace matrix

/* vim: set et fenc=utf-8 ff=unix sts=0 sw=4 ts=4 : */
<|endoftext|>


<commit_before>/***********************************************************************************************************************
 **
 ** Copyright (c) 2011, 2012 ETH Zurich
 ** All rights reserved.
 **
 ** Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
 ** following conditions are met:
 **
 **    * Redistributions of source code must retain the above copyright notice, this list of conditions and the
 **      following disclaimer.
 **    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
 **      following disclaimer in the documentation and/or other materials provided with the distribution.
 **    * Neither the name of the ETH Zurich nor the names of its contributors may be used to endorse or promote products
 **      derived from this software without specific prior written permission.
 **
 **
 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 ** INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 ** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 ** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 ** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 **
 **********************************************************************************************************************/

/*
 * ExpressionEditor.cpp
 *
 *  Created on: Jan 11, 2012
 *      Author: Dimitar Asenov
 */

#include "expression_editor/ExpressionEditor.h"

#include "expression_editor/parser/Token.h"
#include "expression_editor/parser/Parser.h"
#include "expression_editor/tree_builder/ExpressionTreeBuilder.h"

namespace Interaction {

Expression* ExpressionEditor::parse(const QString& expression_text)
{
	if (!expression_text.isNull()) setText(expression_text);

	return ExpressionTreeBuilder().build( Parser(ops_).parse( Token::tokenize(text_, ops_)) );
}

} /* namespace InteractionBase */
<commit_msg>Fix ExpressionEditor::parse to adjust the result for operator precedence<commit_after>/***********************************************************************************************************************
 **
 ** Copyright (c) 2011, 2012 ETH Zurich
 ** All rights reserved.
 **
 ** Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
 ** following conditions are met:
 **
 **    * Redistributions of source code must retain the above copyright notice, this list of conditions and the
 **      following disclaimer.
 **    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
 **      following disclaimer in the documentation and/or other materials provided with the distribution.
 **    * Neither the name of the ETH Zurich nor the names of its contributors may be used to endorse or promote products
 **      derived from this software without specific prior written permission.
 **
 **
 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 ** INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 ** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 ** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 ** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 **
 **********************************************************************************************************************/

/*
 * ExpressionEditor.cpp
 *
 *  Created on: Jan 11, 2012
 *      Author: Dimitar Asenov
 */

#include "expression_editor/ExpressionEditor.h"

#include "expression_editor/parser/Token.h"
#include "expression_editor/parser/Parser.h"
#include "expression_editor/tree_builder/ExpressionTreeBuilder.h"
#include "expression_editor/ExpressionTreeUtils.h"

namespace Interaction {

Expression* ExpressionEditor::parse(const QString& expression_text)
{
	if (!expression_text.isNull()) setText(expression_text);

	Expression* top = ExpressionTreeBuilder().build( Parser(ops_).parse( Token::tokenize(text_, ops_)) );
	ExpressionTreeUtils::fixTop(top);
	return top;
}

} /* namespace InteractionBase */
<|endoftext|>


<commit_before>#include <iostream>
#include <fstream>
#include <sstream>
#include <time.h>
#include <stdlib.h>
#include <vector>
#include <set>
#include <iomanip>
#include <algorithm>

using namespace std;

int main()
{
	//srand((unsigned)time(NULL));
	//int val = rand();
	//char Hex[33];
	//itoa(val, Hex, 16);
	//cout << "Random Decimal Byte:" << val;
	//cout << "\nEquivalent Hex Byte: " << Hex << endl;

	///////
	const int DNAs = 2;// 1048575;
	srand((unsigned)time(NULL));

	vector<string> dnas;
	set<string> uniqueDNAs;

	int ints[5] = { 0 };
	int currSize = 2;
	for (size_t row = 1; row <= DNAs; row++)
	{
		ostringstream oss;
		string currDNA;
		oss << hex << std::setw(5) << std::setfill('0') << row;

		currDNA = oss.str();
		bool is_in = uniqueDNAs.find(currDNA) != uniqueDNAs.end();
		if (is_in)
		{

		}
		else
		{
			uniqueDNAs.insert(currDNA);
			for (size_t col = 0; col < currSize; col++)
			{
				dnas.push_back(currDNA);
			}
		}

		currSize += 2;
	}

	dnas.push_back("fffff");

	std::random_shuffle(dnas.begin(), dnas.end());

	ofstream fileOutput("test1.txt");
	for (const auto& dna : dnas)
	{
		fileOutput << dna << endl;
	}

	//fileOutput << oss.str() << endl;

	return 0;
}<commit_msg>change in algorithm<commit_after>#include <iostream>
#include <fstream>
#include <sstream>
#include <time.h>
#include <stdlib.h>
#include <vector>
#include <set>
#include <iomanip>
#include <algorithm>

using namespace std;

int main()
{
	// srand((unsigned)time(NULL));

	const int DNAs = 1000;// 1048575;

	vector<string> dnas;
	set<string> uniqueDNAs;

	int currSize = 2;
	for (size_t row = 1; row <= DNAs; row++)
	{
		ostringstream oss;
		string currDNA;
		oss << hex << std::setw(5) << std::setfill('0') << row;

		currDNA = oss.str();

		uniqueDNAs.insert(currDNA);
		for (size_t col = 0; col < currSize; col++)
		{
			dnas.push_back(currDNA);
		}

		currSize += 2;
	}

	dnas.push_back("fffff");

	std::random_shuffle(dnas.begin(), dnas.end());

	ofstream fileOutput("test1.txt");
	for (const auto& dna : dnas)
	{
		fileOutput << dna;
	}

	return 0;
}<|endoftext|>


<commit_before>/*
 * Copyright (C) 2012 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "class_linker.h"
#include "interpreter/interpreter.h"
#include "invoke_arg_array_builder.h"
#include "mirror/art_method-inl.h"
#include "mirror/object-inl.h"
#include "object_utils.h"
#include "runtime.h"
#include "stack.h"

namespace art {

extern "C" void artInterpreterToCompiledCodeBridge(Thread* self, MethodHelper& mh,
                                                   const DexFile::CodeItem* code_item,
                                                   ShadowFrame* shadow_frame, JValue* result) {
  mirror::ArtMethod* method = shadow_frame->GetMethod();
  // Ensure static methods are initialized.
  if (method->IsStatic()) {
    mirror::Class* declaringClass = method->GetDeclaringClass();
    if (UNLIKELY(!declaringClass->IsInitializing())) {
      if (UNLIKELY(!Runtime::Current()->GetClassLinker()->EnsureInitialized(declaringClass,
                                                                            true, true))) {
        DCHECK(Thread::Current()->IsExceptionPending());
        return;
      }
      CHECK(declaringClass->IsInitializing());
    }
  }
  uint16_t arg_offset = (code_item == NULL) ? 0 : code_item->registers_size_ - code_item->ins_size_;
#if defined(ART_USE_PORTABLE_COMPILER)
  ArgArray arg_array(mh.GetShorty(), mh.GetShortyLength());
  arg_array.BuildArgArrayFromFrame(shadow_frame, arg_offset);
  method->Invoke(self, arg_array.GetArray(), arg_array.GetNumBytes(), result, mh.GetShorty()[0]);
#else
  method->Invoke(self, shadow_frame->GetVRegArgs(arg_offset),
                 (shadow_frame->NumberOfVRegs() - arg_offset) * sizeof(uint32_t),
                 result, mh.GetShorty()[0]);
#endif
}

}  // namespace art
<commit_msg>am 76f55230: Merge "Add missing push/pop shadow frame to artInterpreterToCompiledCodeBridge."<commit_after>/*
 * Copyright (C) 2012 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "class_linker.h"
#include "interpreter/interpreter.h"
#include "invoke_arg_array_builder.h"
#include "mirror/art_method-inl.h"
#include "mirror/object-inl.h"
#include "object_utils.h"
#include "runtime.h"
#include "stack.h"

namespace art {

extern "C" void artInterpreterToCompiledCodeBridge(Thread* self, MethodHelper& mh,
                                                   const DexFile::CodeItem* code_item,
                                                   ShadowFrame* shadow_frame, JValue* result) {
  mirror::ArtMethod* method = shadow_frame->GetMethod();
  // Ensure static methods are initialized.
  if (method->IsStatic()) {
    mirror::Class* declaringClass = method->GetDeclaringClass();
    if (UNLIKELY(!declaringClass->IsInitializing())) {
      self->PushShadowFrame(shadow_frame);
      if (UNLIKELY(!Runtime::Current()->GetClassLinker()->EnsureInitialized(declaringClass,
                                                                            true, true))) {
        self->PopShadowFrame();
        DCHECK(self->IsExceptionPending());
        return;
      }
      self->PopShadowFrame();
      CHECK(declaringClass->IsInitializing());
    }
  }
  uint16_t arg_offset = (code_item == NULL) ? 0 : code_item->registers_size_ - code_item->ins_size_;
#if defined(ART_USE_PORTABLE_COMPILER)
  ArgArray arg_array(mh.GetShorty(), mh.GetShortyLength());
  arg_array.BuildArgArrayFromFrame(shadow_frame, arg_offset);
  method->Invoke(self, arg_array.GetArray(), arg_array.GetNumBytes(), result, mh.GetShorty()[0]);
#else
  method->Invoke(self, shadow_frame->GetVRegArgs(arg_offset),
                 (shadow_frame->NumberOfVRegs() - arg_offset) * sizeof(uint32_t),
                 result, mh.GetShorty()[0]);
#endif
}

}  // namespace art
<|endoftext|>


<commit_before>/*
 * lambda.cpp
 *
 *  Created on: Jan 14, 2015
 *      Author: radoslav
 */

#include "lambda.h"
#include "strtok.h"
#include "identifier.h"
#include <cstring>

void Lambda::copy(const Lambda& other)
{
	signature = other.signature;
	body = other.body->clone();
}

void Lambda::destroy()
{
	delete body;
}

Lambda::Lambda(const char*& code): Value(VALUE_LAMBDA)
{
	if (!gotoToken(code, " \t\n\r") || *code != '\\')
	{
		type = VALUE_INVALID;
		return;
	}

	code++;

	if (!gotoToken(code, " \t\n\r") || *code != '(')
	{
		type = VALUE_INVALID;
		return;
	}

	code++;

	while (gotoToken(code, ", \t\n\r") && *code != ')')
		signature.push_back(Identifier(code));

	if (*code != ')')
		type = VALUE_INVALID;
	else
	{
		code++;
		body = Statement::createStatement(code);
	}
}

Lambda::Lambda(const Lambda& other): Value(other)
{
	copy(other);
}

Lambda& Lambda::operator=(const Lambda& other)
{
	if (&other != this)
	{
		destroy();
		Value::operator=(other);
		copy(other);
	}

	return *this;
}

Lambda::~Lambda()
{
	destroy();
}

<commit_msg>renamed method<commit_after>/*
 * lambda.cpp
 *
 *  Created on: Jan 14, 2015
 *      Author: radoslav
 */

#include "lambda.h"
#include "strtok.h"
#include "identifier.h"
#include <cstring>

void Lambda::copy(const Lambda& other)
{
	signature = other.signature;
	body = other.body->clone();
}

void Lambda::destroy()
{
	delete body;
}

Lambda::Lambda(const char*& code): Value(VALUE_LAMBDA)
{
	if (!gotoToken(code, " \t\n\r") || *code != '\\')
	{
		type = VALUE_INVALID;
		return;
	}

	code++;

	if (!gotoToken(code, " \t\n\r") || *code != '(')
	{
		type = VALUE_INVALID;
		return;
	}

	code++;

	while (gotoToken(code, ", \t\n\r") && *code != ')')
		signature.push_back(Identifier(code));

	if (*code != ')')
		type = VALUE_INVALID;
	else
	{
		code++;
		body = Statement::create(code);
	}
}

Lambda::Lambda(const Lambda& other): Value(other)
{
	copy(other);
}

Lambda& Lambda::operator=(const Lambda& other)
{
	if (&other != this)
	{
		destroy();
		Value::operator=(other);
		copy(other);
	}

	return *this;
}

Lambda::~Lambda()
{
	destroy();
}

<|endoftext|>


<commit_before>#include "bookmark.h"

/**
 * @brief Bookmark::Bookmark
 * @param frame_nbr Frame number associated with the bookmark.
 * @param frame Frame associated with the bookmark.
 * @param dir_path Path to the directory to store image in.
 * @param text Text description of the bookmark.
 */
Bookmark::Bookmark(int frame_nbr, QImage frame, QString dir_path, QString text) {
    this->frame_number = frame_nbr;
    this->frame = frame;
    this->dir_path = dir_path;
    this->description = text;
    // There's no file path yet, since the frame has not been exported
    this->file_path = QString();
}

/**
 * @brief Bookmark::Bookmark
 * Null initializing constructor.
 */
Bookmark::Bookmark() {
    frame_number = 0;
    frame = QImage();
    dir_path = QString();
    file_path = QString();
    description = QString();
}

/**
 * @brief Bookmark::get_frame_number
 * @return Returns the frame number that the bookmark points to.
 */
int Bookmark::get_frame_number() {
    return frame_number;
}

/**
 * @brief Bookmark::get_frame
 * @return Returns the frame of the bookmark.
 */
QImage Bookmark::get_frame() {
    return frame;
}

/**
 * @brief Bookmark::get_file_path
 * @return Returns the file_path of the exported bookmark.
 *         If bookmark is not exported yet, an empty string is returned
 */
QString Bookmark::get_file_path() {
    return file_path;
}

/**
 * @brief Bookmark::get_description
 * @return Returns the description associated with the bookmark.
 */
QString Bookmark::get_description() {
    return description;
}

/**
 * @brief Bookmark::read
 * @param json
 * Reads a bookmark from a Json object.
 */
void Bookmark::read(const QJsonObject& json){
    this->frame_number = json["frame"].toInt();
    this->dir_path = json["dir"].toString();
    this->file_path = json["path"].toString();
    this->description = json["note"].toString();
    frame.load(file_path);
}

/**
 * @brief Bookmark::write
 * @param json
 * Writes a bookmark to a Json object, and exports the frame.
 */
void Bookmark::write(QJsonObject& json){
    // Exports the frame and updates file_path.
    export_frame();

    json["frame"] = this->frame_number;
    json["dir"] = this->dir_path;
    json["path"] = this->file_path;
    json["note"] = this->description;
}

/**
 * @brief Bookmark::export_frame
 * Export the frame of the bookmark to a tiff-file in the project folder.
 */
void Bookmark::export_frame() {
    // Update file path in case there's already a file with this file name
    create_file_path();
    QImageWriter writer(file_path, "tiff");
    writer.write(frame);
}

/**
 * @brief Bookmark::create_file_path
 * Creates and updates the file path to export the bookmark frame to.
 */
void Bookmark::create_file_path() {

    // Append FRAMENR.tiff to the directory path
    QString path = QString(dir_path);
    path.append("/");
    path.append(QString::number(frame_number));
    path.append(".tiff");
-   int counter = 1;
 -  while (QFile::exists(path)) {
 -      // If file exists, try FRAMENR(X).tiff
 -      path = QString(dir_path);
 -      path.append("/");
 -      path.append(QString::number(frame_number));
 -      path.append("(");
 -      path.append(QString::number(counter));
 -      path.append(").tiff");
 -      counter++;
 -  }
    // Update file path variable
    file_path = path;
}

/**
 * @brief Bookmark::remove_exported_image
 * Removes the exported image, if there is one.
 */
void Bookmark::remove_exported_image() {
    // If the file path is empty, then the frame has not been exported so there's nothing to remove.
    if (!file_path.isEmpty()) {
        QFile file(file_path);
        file.remove();
    }
}
<commit_msg>Update bookmark.cpp<commit_after>#include "bookmark.h"

/**
 * @brief Bookmark::Bookmark
 * @param frame_nbr Frame number associated with the bookmark.
 * @param frame Frame associated with the bookmark.
 * @param dir_path Path to the directory to store image in.
 * @param text Text description of the bookmark.
 */
Bookmark::Bookmark(int frame_nbr, QImage frame, QString dir_path, QString text) {
    this->frame_number = frame_nbr;
    this->frame = frame;
    this->dir_path = dir_path;
    this->description = text;
    // There's no file path yet, since the frame has not been exported
    this->file_path = QString();
}

/**
 * @brief Bookmark::Bookmark
 * Null initializing constructor.
 */
Bookmark::Bookmark() {
    frame_number = 0;
    frame = QImage();
    dir_path = QString();
    file_path = QString();
    description = QString();
}

/**
 * @brief Bookmark::get_frame_number
 * @return Returns the frame number that the bookmark points to.
 */
int Bookmark::get_frame_number() {
    return frame_number;
}

/**
 * @brief Bookmark::get_frame
 * @return Returns the frame of the bookmark.
 */
QImage Bookmark::get_frame() {
    return frame;
}

/**
 * @brief Bookmark::get_file_path
 * @return Returns the file_path of the exported bookmark.
 *         If bookmark is not exported yet, an empty string is returned
 */
QString Bookmark::get_file_path() {
    return file_path;
}

/**
 * @brief Bookmark::get_description
 * @return Returns the description associated with the bookmark.
 */
QString Bookmark::get_description() {
    return description;
}

/**
 * @brief Bookmark::read
 * @param json
 * Reads a bookmark from a Json object.
 */
void Bookmark::read(const QJsonObject& json){
    this->frame_number = json["frame"].toInt();
    this->dir_path = json["dir"].toString();
    this->file_path = json["path"].toString();
    this->description = json["note"].toString();
    frame.load(file_path);
}

/**
 * @brief Bookmark::write
 * @param json
 * Writes a bookmark to a Json object, and exports the frame.
 */
void Bookmark::write(QJsonObject& json){
    // Exports the frame and updates file_path.
    export_frame();

    json["frame"] = this->frame_number;
    json["dir"] = this->dir_path;
    json["path"] = this->file_path;
    json["note"] = this->description;
}

/**
 * @brief Bookmark::export_frame
 * Export the frame of the bookmark to a tiff-file in the project folder.
 */
void Bookmark::export_frame() {
    // Update file path in case there's already a file with this file name
    create_file_path();
    QImageWriter writer(file_path, "tiff");
    writer.write(frame);
}

/**
 * @brief Bookmark::create_file_path
 * Creates and updates the file path to export the bookmark frame to.
 */
void Bookmark::create_file_path() {

    // Append FRAMENR.tiff to the directory path
    QString path = QString(dir_path);
    path.append("/");
    path.append(QString::number(frame_number));
    path.append(".tiff");
-
    int counter = 1;
 -  while (QFile::exists(path)) {
 -      // If file exists, try FRAMENR(X).tiff
 -      path = QString(dir_path);
 -      path.append("/");
 -      path.append(QString::number(frame_number));
 -      path.append("(");
 -      path.append(QString::number(counter));
 -      path.append(").tiff");
 -      counter++;
 -  }
    // Update file path variable
    file_path = path;
}

/**
 * @brief Bookmark::remove_exported_image
 * Removes the exported image, if there is one.
 */
void Bookmark::remove_exported_image() {
    // If the file path is empty, then the frame has not been exported so there's nothing to remove.
    if (!file_path.isEmpty()) {
        QFile file(file_path);
        file.remove();
    }
}
<|endoftext|>


<commit_before>/*
 * Rule.cc
 *
 * Copyright (C) 2015 Misgana Bayetta
 *
 * Author: Misgana Bayetta <misgana.bayetta@gmail.com> 2015
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Free Software Foundation and including the exceptions
 * at http://opencog.org/wiki/Licenses
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, write to:
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include <queue>

#include <boost/uuid/uuid_io.hpp>
#include <boost/uuid/uuid_generators.hpp>

#include <opencog/atomspace/AtomSpace.h>
#include <opencog/atoms/bind/BindLink.h>
#include <opencog/atoms/bind/DefineLink.h>

#include "Rule.h"

using namespace opencog;

Rule::Rule(Handle rule)
{
	if (!rule->isType(MEMBER_LINK, true))
		throw InvalidParamException(TRACE_INFO,
		                            "Rule '%s' is expected to be a MemberLink",
		                            rule->toString().c_str());

	Handle name_h = LinkCast(rule)->getOutgoingAtom(0),
		rbs_h = LinkCast(rule)->getOutgoingAtom(1);

	rule_handle_ = DefineLink::get_definition(name_h);
	name_ = NodeCast(name_h)->getName();
	category_ = NodeCast(rbs_h)->getName();
	weight_ = rule->getTruthValue()->getMean();
}

float Rule::get_weight()
{
	return weight_;
}

void Rule::set_category(const string& name)
{
	category_ = name;
}

string& Rule::get_category()
{
	return category_;
}

const string& Rule::get_category() const
{
	return category_;
}

void Rule::set_name(const string& name)
{
	name_ = name;
}

string& Rule::get_name()
{
	return name_;
}

const string& Rule::get_name() const
{
	return name_;
}

void Rule::set_handle(Handle h) throw (InvalidParamException)
{
	rule_handle_ = h;
}

Handle Rule::get_handle()
{
	return rule_handle_;
}

/**
 * Get the typed variable list of the Rule.
 *
 * @return the VariableList or the lone VariableNode
 */
Handle Rule::get_vardecl()
{
	return LinkCast(rule_handle_)->getOutgoingAtom(0);
}

/**
 * Get the implicant (input) of the rule defined in a BindLink.
 *
 * @return the Handle of the implicant
 */
Handle Rule::get_implicant()
{
	// if the rule's handle has not been set yet
	if (rule_handle_ == Handle::UNDEFINED)
		return Handle::UNDEFINED;

	return BindLinkCast(rule_handle_)->get_body();
}

/**
 * Get the set of members of the implicant which are
 * connected by a root logical link.
 *
 * @return HandleSeq of members of the implicant
 */
HandleSeq Rule::get_implicant_seq()
{
    Handle implicant= get_implicant();
    Type t = implicant->getType();
    HandleSeq hs;

    if (t == AND_LINK or t == OR_LINK)
        hs = LinkCast(implicant)->getOutgoingSet();
    else
        hs.push_back(implicant);

    return hs;
}
/**
 * Get the implicand (output) of the rule defined in a BindLink.
 *
 * @return the Handle of the implicand
 */
Handle Rule::get_implicand()
{
	// if the rule's handle has not been set yet
	if (rule_handle_ == Handle::UNDEFINED)
		return Handle::UNDEFINED;

	return BindLinkCast(rule_handle_)->get_implicand();
}

/**
 * Get the implicand (output) of the rule defined in a BindLink.
 *
 * This function does extra processing to find the real output over an
 * ExecutionOutputLink.  ie, skip to the ListLink under the ExLink.
 *
 * @return the HandleSeq of the implicand
 */
HandleSeq Rule::get_implicand_seq()
{
	// if the rule's handle has not been set yet
	if (rule_handle_ == Handle::UNDEFINED)
		return HandleSeq();

	Handle implicand = BindLinkCast(rule_handle_)->get_implicand();

	std::queue<Handle> pre_output;
	HandleSeq final_output;

	// skip the top level ListLink
	if (implicand->getType() == LIST_LINK)
	{
		for (Handle h : LinkCast(implicand)->getOutgoingSet())
			pre_output.push(h);
	}
	else
	{
		pre_output.push(implicand);
	}

	// check all output of ExecutionOutputLink
	while (not pre_output.empty())
	{
		Handle hfront = pre_output.front();
		pre_output.pop();

		if (hfront->getType() == EXECUTION_OUTPUT_LINK)
		{
			// get the ListLink containing the arguments of the ExecutionOutputLink
			Handle harg = LinkCast(hfront)->getOutgoingSet()[1];

			for (Handle h : LinkCast(harg)->getOutgoingSet())
				pre_output.push(h);

			continue;
		}

		// if not an ExecutionOutputLink, it is a final output
		final_output.push_back(hfront);
	}

	return final_output;
}

void Rule::set_weight(float p)
{
	weight_ = p;
}

/**
 * Create a new rule where all variables are renamed.
 *
 * @param as  pointer to the atomspace where the new BindLink will be added
 * @return    a new Rule object with its own new BindLink
 */
Rule Rule::gen_standardize_apart(AtomSpace* as)
{
	// clone the Rule
	Rule st_ver = *this;
	std::map<Handle, Handle> dict;

	Handle st_bindlink = standardize_helper(as, rule_handle_, dict);
	st_ver.set_handle(st_bindlink);

	return st_ver;
}

/**
 * Basic helper function to standardize apart the BindLink.
 *
 * @param as     pointer to an atomspace where new atoms are added
 * @param h      an input atom to standardize apart
 * @param dict   a mapping of old VariableNode and new VariableNode
 * @return       the new atom
 */
Handle Rule::standardize_helper(AtomSpace* as, const Handle h, std::map<Handle, Handle>& dict)
{
	if (LinkCast(h))
	{
		HandleSeq old_outgoing = LinkCast(h)->getOutgoingSet();
		HandleSeq new_outgoing;

		for (auto ho : old_outgoing)
			new_outgoing.push_back(standardize_helper(as, ho, dict));

		return as->add_atom(createLink(h->getType(), new_outgoing, h->getTruthValue()));
	}

	// normal node does not need to be changed
	if (h->getType() != VARIABLE_NODE)
		return h;

	// use existing mapping if the VariableNode is already mapped
	if (dict.count(h) == 1)
		return dict[h];

	std::string new_name = NodeCast(h)->getName() + "-standardize_apart-" + to_string(boost::uuids::random_generator()());

	Handle hcpy = as->add_atom(createNode(h->getType(), new_name, h->getTruthValue()));
	dict[h] = hcpy;

	return hcpy;
}
<commit_msg>Changed standardized-apart variable to always be the same<commit_after>/*
 * Rule.cc
 *
 * Copyright (C) 2015 Misgana Bayetta
 *
 * Author: Misgana Bayetta <misgana.bayetta@gmail.com> 2015
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Free Software Foundation and including the exceptions
 * at http://opencog.org/wiki/Licenses
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, write to:
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include <queue>

#include <boost/uuid/uuid_io.hpp>
#include <boost/uuid/uuid_generators.hpp>

#include <opencog/atomspace/AtomSpace.h>
#include <opencog/atoms/bind/BindLink.h>
#include <opencog/atoms/bind/DefineLink.h>

#include "Rule.h"

using namespace opencog;

Rule::Rule(Handle rule)
{
	if (!rule->isType(MEMBER_LINK, true))
		throw InvalidParamException(TRACE_INFO,
		                            "Rule '%s' is expected to be a MemberLink",
		                            rule->toString().c_str());

	Handle name_h = LinkCast(rule)->getOutgoingAtom(0),
		rbs_h = LinkCast(rule)->getOutgoingAtom(1);

	rule_handle_ = DefineLink::get_definition(name_h);
	name_ = NodeCast(name_h)->getName();
	category_ = NodeCast(rbs_h)->getName();
	weight_ = rule->getTruthValue()->getMean();
}

float Rule::get_weight()
{
	return weight_;
}

void Rule::set_category(const string& name)
{
	category_ = name;
}

string& Rule::get_category()
{
	return category_;
}

const string& Rule::get_category() const
{
	return category_;
}

void Rule::set_name(const string& name)
{
	name_ = name;
}

string& Rule::get_name()
{
	return name_;
}

const string& Rule::get_name() const
{
	return name_;
}

void Rule::set_handle(Handle h) throw (InvalidParamException)
{
	rule_handle_ = h;
}

Handle Rule::get_handle()
{
	return rule_handle_;
}

/**
 * Get the typed variable list of the Rule.
 *
 * @return the VariableList or the lone VariableNode
 */
Handle Rule::get_vardecl()
{
	return LinkCast(rule_handle_)->getOutgoingAtom(0);
}

/**
 * Get the implicant (input) of the rule defined in a BindLink.
 *
 * @return the Handle of the implicant
 */
Handle Rule::get_implicant()
{
	// if the rule's handle has not been set yet
	if (rule_handle_ == Handle::UNDEFINED)
		return Handle::UNDEFINED;

	return BindLinkCast(rule_handle_)->get_body();
}

/**
 * Get the set of members of the implicant which are
 * connected by a root logical link.
 *
 * @return HandleSeq of members of the implicant
 */
HandleSeq Rule::get_implicant_seq()
{
    Handle implicant= get_implicant();
    Type t = implicant->getType();
    HandleSeq hs;

    if (t == AND_LINK or t == OR_LINK)
        hs = LinkCast(implicant)->getOutgoingSet();
    else
        hs.push_back(implicant);

    return hs;
}
/**
 * Get the implicand (output) of the rule defined in a BindLink.
 *
 * @return the Handle of the implicand
 */
Handle Rule::get_implicand()
{
	// if the rule's handle has not been set yet
	if (rule_handle_ == Handle::UNDEFINED)
		return Handle::UNDEFINED;

	return BindLinkCast(rule_handle_)->get_implicand();
}

/**
 * Get the implicand (output) of the rule defined in a BindLink.
 *
 * This function does extra processing to find the real output over an
 * ExecutionOutputLink.  ie, skip to the ListLink under the ExLink.
 *
 * @return the HandleSeq of the implicand
 */
HandleSeq Rule::get_implicand_seq()
{
	// if the rule's handle has not been set yet
	if (rule_handle_ == Handle::UNDEFINED)
		return HandleSeq();

	Handle implicand = BindLinkCast(rule_handle_)->get_implicand();

	std::queue<Handle> pre_output;
	HandleSeq final_output;

	// skip the top level ListLink
	if (implicand->getType() == LIST_LINK)
	{
		for (Handle h : LinkCast(implicand)->getOutgoingSet())
			pre_output.push(h);
	}
	else
	{
		pre_output.push(implicand);
	}

	// check all output of ExecutionOutputLink
	while (not pre_output.empty())
	{
		Handle hfront = pre_output.front();
		pre_output.pop();

		if (hfront->getType() == EXECUTION_OUTPUT_LINK)
		{
			// get the ListLink containing the arguments of the ExecutionOutputLink
			Handle harg = LinkCast(hfront)->getOutgoingSet()[1];

			for (Handle h : LinkCast(harg)->getOutgoingSet())
				pre_output.push(h);

			continue;
		}

		// if not an ExecutionOutputLink, it is a final output
		final_output.push_back(hfront);
	}

	return final_output;
}

void Rule::set_weight(float p)
{
	weight_ = p;
}

/**
 * Create a new rule where all variables are renamed.
 *
 * @param as  pointer to the atomspace where the new BindLink will be added
 * @return    a new Rule object with its own new BindLink
 */
Rule Rule::gen_standardize_apart(AtomSpace* as)
{
	// clone the Rule
	Rule st_ver = *this;
	std::map<Handle, Handle> dict;

	Handle st_bindlink = standardize_helper(as, rule_handle_, dict);
	st_ver.set_handle(st_bindlink);

	return st_ver;
}

/**
 * Basic helper function to standardize apart the BindLink.
 *
 * @param as     pointer to an atomspace where new atoms are added
 * @param h      an input atom to standardize apart
 * @param dict   a mapping of old VariableNode and new VariableNode
 * @return       the new atom
 */
Handle Rule::standardize_helper(AtomSpace* as, const Handle h, std::map<Handle, Handle>& dict)
{
	if (LinkCast(h))
	{
		HandleSeq old_outgoing = LinkCast(h)->getOutgoingSet();
		HandleSeq new_outgoing;

		for (auto ho : old_outgoing)
			new_outgoing.push_back(standardize_helper(as, ho, dict));

		return as->add_atom(createLink(h->getType(), new_outgoing, h->getTruthValue()));
	}

	// normal node does not need to be changed
	if (h->getType() != VARIABLE_NODE)
		return h;

	// use existing mapping if the VariableNode is already mapped
	if (dict.count(h) == 1)
		return dict[h];

	std::stringstream ss;
	ss << NodeCast(h)->getName() << "-" << rule_handle_ << "-standardize_apart";

	Handle hcpy = as->add_atom(createNode(h->getType(), ss.str(), h->getTruthValue()));
	dict[h] = hcpy;

	return hcpy;
}
<|endoftext|>