<commit_before>/***********************************************************************************************************************
*                                                                                *
* SPLASH build system v0.2                                                                                *
*                                                                                *
* Copyright (c) 2016-2017 Andrew D. Zonenberg                                                                          *
* All rights reserved.                                                                                *
*                                                                                *
* Redistribution and use in Object and binary forms, with or without modification, are permitted provided that the     *
* following conditions are met:                                                                                *
*                                                                                *
*    * Redistributions of Object 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 author nor the names of any contributors may be used to endorse or promote products     *
*      derived from this software without specific prior written permission.                                           *
*                                                                                *
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS "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 AUTHORS BE HELD 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.                                                                                *
*                                                                                *
***********************************************************************************************************************/

#include "splashcore.h"

using namespace std;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Construction / destruction

HDLNetlistNode::HDLNetlistNode(
	BuildGraph* graph,
	string arch,
	string /*config*/,
	string name,
	string /*scriptpath*/,
	string path,
	string toolchain,
	string board,
	set<BuildFlag> flags,
	set<BuildGraphNode*> sources)
	: BuildGraphNode(graph, BuildFlag::COMPILE_TIME, toolchain, arch, name, path, flags)
	, m_board(board)
{
	/*
	LogDebug("[%6.3f] Creating HDLNetlistNode %s\nfor arch %s, toolchain %s, board %s\n",
		g_scheduler->GetDT(), path.c_str(), arch.c_str(), toolchain.c_str(),
		GetBasenameOfFileWithoutExt(board).c_str() );
	LogIndenter li;
	*/

	//Add an automatic dependency for the source files
	for(auto src : sources)
	{
		auto f = src->GetFilePath();
		m_dependencies.emplace(f);
		m_sources.emplace(f);
	}
}

HDLNetlistNode::~HDLNetlistNode()
{
}

bool HDLNetlistNode::ScanDependencies(string fname)
{
	//Read the source code for this file
	auto wc = m_graph->GetWorkingCopy();
	if(!wc->HasFile(fname))
	{
		SetInvalidInput(string("ERROR: Couldn't find source file ") + fname + " for dependency scan\n");
		return false;
	}
	string hash = wc->GetFileHash(fname);
	string source = g_cache->ReadCachedFile(hash);

	//Split the source file by lines
	vector<string> lines;
	ParseLines(source, lines);

	//Do very minimal parsing of the lines to look for dependencies
	for(auto line : lines)
	{
		//Eat spaces
		while(!line.empty() && isspace(line[0]))
			line = line.substr(1);

		//TODO: Parse multiline comments

		string cpath;

		//Look for preprocessor commands
		if(line[0] == '`')
		{
			//TODO: Implement `if etc
			//For now, skip anything but include statements
			if(line.find("`include") != 0)
				continue;

			//Look up the filename
			size_t start = line.find("\"");
			size_t end = line.find("\"", start+1);
			if( (start == string::npos) || (end == string::npos) )
			{
				SetInvalidInput("ERROR: Malformed `include line\n");
				return false;
			}
			string fpath = line.substr(start+1, end-(start+1));

			//Canonicalize based on our working directory
			cpath = GetDirOfFile(fname) + "/" + fpath;
			if(!CanonicalizePathThatMightNotExist(cpath))
			{
				SetInvalidInput(string("ERROR: Couldn't canonicalize include file ") + cpath + "\n");
				return false;
			}

			//LogDebug("Found include statement: %s (%s)\n", fpath.c_str(), cpath.c_str());
		}

		//Look for system tasks
		//FIXME: Doesn't process full HDL elaboration, will fail horribly if the filename is passed as a
		//parameter to the module!
		if(line[0] == '$')
		{
			//For now, skip anything but $readmem
			if(line.find("$readmem") != 0)
				continue;

			//Look up the filename
			size_t start = line.find("\"");
			size_t end = line.find("\"", start+1);
			if( (start == string::npos) || (end == string::npos) )
			{
				LogWarning("Couldn't parse $readmem argument (probably not hard coded): %s\n", line.c_str());
				continue;
			}
			string fpath = line.substr(start+1, end-(start+1));

			//Canonicalize based on our working directory
			cpath = GetDirOfFile(fname) + "/" + fpath;
			if(!CanonicalizePathThatMightNotExist(cpath))
			{
				SetInvalidInput(string("ERROR: Couldn't canonicalize $readmem file ") + cpath + "\n");
				return false;
			}

			//LogDebug("Found readmem: %s (%s)\n", fpath.c_str(), cpath.c_str());
		}

		//Skip if we didn't find anything
		if(cpath.empty())
			continue;

		//See if it exists
		if(!wc->HasFile(cpath))
		{
			SetInvalidInput(string("ERROR: Include file ") + cpath + " doesn't exist\n");
			return false;
		}

		//Add a source file node for it (if we don't have one already)
		auto h = wc->GetFileHash(cpath);
		if(!m_graph->HasNodeWithHash(h))
			m_graph->AddNode(new SourceFileNode(m_graph, cpath, h));

		//Pull it in
		m_dependencies.emplace(cpath);
	}

	return true;
}

void HDLNetlistNode::DoFinalize()
{
	auto wc = m_graph->GetWorkingCopy();

	//Run the dependency scanner once all nodes have been created
	for(auto f : m_sources)
	{
		//Run the dependency scanner on this file to see what other stuff we need to pull in.
		//For now, do not support recursive includes (i.e. we only scan this source file).
		//If the scanner fails, immediately return and stay failed with our temporary hash
		if(!ScanDependencies(f))
			return;
	}

	//Calculate our hash.
	//Dependencies and flags are obvious
	//NOTE: This needs to happen *even if our dependency scan failed* so that we can identify the scan errors
	string hashin;
	for(auto d : m_dependencies)
		hashin += wc->GetFileHash(d);
	for(auto f : m_flags)
		hashin += sha256(f);

	//Need to hash both the toolchain AND the triplet since some toolchains can target multiple triplets
	//Also hash board since pinout etc depend on that
	hashin += g_nodeManager->GetToolchainHash(m_arch, m_toolchain);
	hashin += sha256(m_arch);
	hashin += sha256(m_board);

	//Do not hash the output file name.
	//Having multiple files with identical inputs merged into a single node is *desirable*.

	//Done, calculate final hash
	m_hash = sha256(hashin);
}
<commit_msg>HDLNetlistNode: now specify current project as include dir so we can resolve constgen headers<commit_after>/***********************************************************************************************************************
*                                                                                *
* SPLASH build system v0.2                                                                                *
*                                                                                *
* Copyright (c) 2016-2017 Andrew D. Zonenberg                                                                          *
* All rights reserved.                                                                                *
*                                                                                *
* Redistribution and use in Object and binary forms, with or without modification, are permitted provided that the     *
* following conditions are met:                                                                                *
*                                                                                *
*    * Redistributions of Object 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 author nor the names of any contributors may be used to endorse or promote products     *
*      derived from this software without specific prior written permission.                                           *
*                                                                                *
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS "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 AUTHORS BE HELD 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.                                                                                *
*                                                                                *
***********************************************************************************************************************/

#include "splashcore.h"

using namespace std;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Construction / destruction

HDLNetlistNode::HDLNetlistNode(
	BuildGraph* graph,
	string arch,
	string /*config*/,
	string name,
	string scriptpath,
	string path,
	string toolchain,
	string board,
	set<BuildFlag> flags,
	set<BuildGraphNode*> sources)
	: BuildGraphNode(graph, BuildFlag::COMPILE_TIME, toolchain, arch, name, path, flags)
	, m_board(board)
{
	/*
	LogDebug("[%6.3f] Creating HDLNetlistNode %s\nfor arch %s, toolchain %s, board %s\n",
		g_scheduler->GetDT(), path.c_str(), arch.c_str(), toolchain.c_str(),
		GetBasenameOfFileWithoutExt(board).c_str() );
	LogIndenter li;
	*/

	//Include files in our working directory automatically
	string incdir = GetDirOfFile(scriptpath);
	m_flags.emplace(BuildFlag(string("library/__incdir/") + incdir));

	//Add an automatic dependency for the source files
	for(auto src : sources)
	{
		auto f = src->GetFilePath();
		m_dependencies.emplace(f);
		m_sources.emplace(f);
	}
}

HDLNetlistNode::~HDLNetlistNode()
{
}

bool HDLNetlistNode::ScanDependencies(string fname)
{
	//Read the source code for this file
	auto wc = m_graph->GetWorkingCopy();
	if(!wc->HasFile(fname))
	{
		SetInvalidInput(string("ERROR: Couldn't find source file ") + fname + " for dependency scan\n");
		return false;
	}
	string hash = wc->GetFileHash(fname);
	string source = g_cache->ReadCachedFile(hash);

	//Split the source file by lines
	vector<string> lines;
	ParseLines(source, lines);

	//Do very minimal parsing of the lines to look for dependencies
	for(auto line : lines)
	{
		//Eat spaces
		while(!line.empty() && isspace(line[0]))
			line = line.substr(1);

		//TODO: Parse multiline comments

		string cpath;

		//Look for preprocessor commands
		if(line[0] == '`')
		{
			//TODO: Implement `if etc
			//For now, skip anything but include statements
			if(line.find("`include") != 0)
				continue;

			//Look up the filename
			size_t start = line.find("\"");
			size_t end = line.find("\"", start+1);
			if( (start == string::npos) || (end == string::npos) )
			{
				SetInvalidInput("ERROR: Malformed `include line\n");
				return false;
			}
			string fpath = line.substr(start+1, end-(start+1));

			//Canonicalize based on our working directory and the original directory
			string cpath_guess1 = GetDirOfFile(m_path) + "/" + fpath;
			string cpath_guess2 = GetDirOfFile(fname) + "/" + fpath;

			if(CanonicalizePathThatMightNotExist(cpath_guess1) && cpath_guess1 != "" && wc->HasFile(cpath_guess1))
			{
				cpath = cpath_guess1;
				//LogDebug("Resolved include statement via project dir: %s (%s)\n", fpath.c_str(), cpath.c_str());
			}

			else if(CanonicalizePathThatMightNotExist(cpath_guess2) && cpath_guess2 != "" && wc->HasFile(cpath_guess2))
			{
				cpath = cpath_guess2;
				//LogDebug("Resolved include statement via source file dir: %s (%s)\n", fpath.c_str(), cpath.c_str());
			}
		}

		//Look for system tasks
		//FIXME: Doesn't process full HDL elaboration, will fail horribly if the filename is passed as a
		//parameter to the module!
		if(line[0] == '$')
		{
			//For now, skip anything but $readmem
			if(line.find("$readmem") != 0)
				continue;

			//Look up the filename
			size_t start = line.find("\"");
			size_t end = line.find("\"", start+1);
			if( (start == string::npos) || (end == string::npos) )
			{
				LogWarning("Couldn't parse $readmem argument (probably not hard coded): %s\n", line.c_str());
				continue;
			}
			string fpath = line.substr(start+1, end-(start+1));

			//Canonicalize based on our working directory
			cpath = GetDirOfFile(fname) + "/" + fpath;
			if(!CanonicalizePathThatMightNotExist(cpath))
			{
				SetInvalidInput(string("ERROR: Couldn't canonicalize $readmem file ") + cpath + "\n");
				return false;
			}

			//LogDebug("Found readmem: %s (%s)\n", fpath.c_str(), cpath.c_str());
		}

		//Skip if we didn't find anything
		if(cpath.empty())
			continue;

		//See if it exists
		if(!wc->HasFile(cpath))
		{
			SetInvalidInput(string("ERROR: Include file ") + cpath + " doesn't exist\n");
			return false;
		}

		//Add a source file node for it (if we don't have one already)
		auto h = wc->GetFileHash(cpath);
		if(!m_graph->HasNodeWithHash(h))
			m_graph->AddNode(new SourceFileNode(m_graph, cpath, h));

		//Pull it in
		m_dependencies.emplace(cpath);
	}

	return true;
}

void HDLNetlistNode::DoFinalize()
{
	auto wc = m_graph->GetWorkingCopy();

	//Run the dependency scanner once all nodes have been created
	for(auto f : m_sources)
	{
		//Run the dependency scanner on this file to see what other stuff we need to pull in.
		//For now, do not support recursive includes (i.e. we only scan this source file).
		//If the scanner fails, immediately return and stay failed with our temporary hash
		if(!ScanDependencies(f))
			return;
	}

	//Calculate our hash.
	//Dependencies and flags are obvious
	//NOTE: This needs to happen *even if our dependency scan failed* so that we can identify the scan errors
	string hashin;
	for(auto d : m_dependencies)
		hashin += wc->GetFileHash(d);
	for(auto f : m_flags)
		hashin += sha256(f);

	//Need to hash both the toolchain AND the triplet since some toolchains can target multiple triplets
	//Also hash board since pinout etc depend on that
	hashin += g_nodeManager->GetToolchainHash(m_arch, m_toolchain);
	hashin += sha256(m_arch);
	hashin += sha256(m_board);

	//Do not hash the output file name.
	//Having multiple files with identical inputs merged into a single node is *desirable*.

	//Done, calculate final hash
	m_hash = sha256(hashin);
}
<|endoftext|>


<commit_before>#include "platform_interface.h"
#include "ocornut-imgui/imgui.h"
#include "renderer/renderer.h"

#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <mmsystem.h>

namespace PlatformInterface
{

	struct PlatformData
	{
		PlatformData()
		{
			for (int i = 0; i < Lumix::lengthOf(m_key_map); ++i)
			{
				m_key_map[i] = -1;
				m_system_key_map[i] = -1;
			}

			m_key_map[(int)Keys::ALT] = VK_MENU;
			m_key_map[(int)Keys::CONTROL] = VK_CONTROL;
			m_key_map[(int)Keys::SHIFT] = VK_SHIFT;
			m_key_map[(int)Keys::TAB] = VK_TAB;
			m_key_map[(int)Keys::LEFT] = VK_LEFT;
			m_key_map[(int)Keys::RIGHT] = VK_RIGHT;
			m_key_map[(int)Keys::UP] = VK_UP;
			m_key_map[(int)Keys::DOWN] = VK_DOWN;
			m_key_map[(int)Keys::PAGE_UP] = VK_PRIOR;
			m_key_map[(int)Keys::PAGE_DOWN] = VK_NEXT;
			m_key_map[(int)Keys::HOME] = VK_HOME;
			m_key_map[(int)Keys::END] = VK_END;
			m_key_map[(int)Keys::DEL] = VK_DELETE;
			m_key_map[(int)Keys::BACKSPACE] = VK_BACK;
			m_key_map[(int)Keys::ENTER] = VK_RETURN;
			m_key_map[(int)Keys::ESCAPE] = VK_ESCAPE;

			for (int i = 0; i < Lumix::lengthOf(m_key_map); ++i)
			{
				if (m_key_map[i] != -1) m_system_key_map[m_key_map[i]] = i;
			}
		}

		HWND m_hwnd;
		bool m_is_mouse_tracked;
		SystemEventHandler* m_handler;
		int m_key_map[512];
		int m_system_key_map[512];
	};

	static PlatformData g_platform_data;

	static int getSystemKey(int key)
	{
		if (g_platform_data.m_key_map[key] != -1)
		{
			return g_platform_data.m_key_map[key];
		}
		else
		{
			return key;
		}
	}

	static int getKeyFromSystem(int key)
	{
		if (g_platform_data.m_system_key_map[key] != -1)
		{
			return g_platform_data.m_system_key_map[key];
		}
		else
		{
			return key;
		}
	}

	static void trackMouse()
	{
		TRACKMOUSEEVENT track_event;
		track_event.cbSize = sizeof(TRACKMOUSEEVENT);
		track_event.dwFlags = TME_LEAVE;
		track_event.hwndTrack = g_platform_data.m_hwnd;
		g_platform_data.m_is_mouse_tracked = TrackMouseEvent(&track_event) == TRUE;
	}

	void getCurrentDirectory(char* buffer, int buffer_size)
	{
		GetCurrentDirectory(buffer_size, buffer);
	}

	void shutdown()
	{
		HINSTANCE hInst = GetModuleHandle(NULL);
		UnregisterClassA("lmxa", hInst);
	}

	void moveWindow(int x, int y, int w, int h)
	{
		MoveWindow(g_platform_data.m_hwnd, x, y, w, h, FALSE);
	}

	bool isMaximized()
	{
		WINDOWPLACEMENT wndpl;
		wndpl.length = sizeof(wndpl);
		if (GetWindowPlacement(g_platform_data.m_hwnd, &wndpl))
		{
			return wndpl.showCmd == SW_MAXIMIZE;
		}
		return false;
	}

	void maximizeWindow()
	{
		ShowWindow(g_platform_data.m_hwnd, SW_MAXIMIZE);
	}

	bool isForegroundWindow()
	{
		return GetForegroundWindow() == g_platform_data.m_hwnd;
	}

	void clipCursor(float min_x, float min_y, float max_x, float max_y)
	{
		POINT min;
		POINT max;
		min.x = LONG(min_x);
		min.y = LONG(min_y);
		max.x = LONG(max_x);
		max.y = LONG(max_y);
		ClientToScreen(g_platform_data.m_hwnd, &min);
		ClientToScreen(g_platform_data.m_hwnd, &max);
		RECT rect;
		rect.left = min.x;
		rect.right = max.x;
		rect.top = min.y;
		rect.bottom = max.y;
		ClipCursor(&rect);
	}

	void showCursor(bool show)
	{
		ShowCursor(show);
	}

	void unclipCursor()
	{
		ClipCursor(NULL);
	}

	int getWindowX()
	{
		RECT rect;
		GetClientRect(g_platform_data.m_hwnd, &rect);
		return int(rect.left);
	}

	int getWindowY()
	{
		RECT rect;
		GetClientRect(g_platform_data.m_hwnd, &rect);
		return int(rect.top);
	}

	int getWindowWidth()
	{
		RECT rect;
		GetClientRect(g_platform_data.m_hwnd, &rect);
		return int(rect.right - rect.left);
	}

	int getWindowHeight()
	{
		RECT rect;
		GetClientRect(g_platform_data.m_hwnd, &rect);
		return int(rect.bottom - rect.top);
	}

	void handleRawInput(LPARAM lParam)
	{
		UINT dwSize;
		char data[sizeof(RAWINPUT) * 10];

		GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, &dwSize, sizeof(RAWINPUTHEADER));
		if (dwSize > sizeof(data)) return;

		if (GetRawInputData((HRAWINPUT)lParam, RID_INPUT, data, &dwSize, sizeof(RAWINPUTHEADER)) !=
			dwSize) return;

		RAWINPUT* raw = (RAWINPUT*)data;
		if (raw->header.dwType == RIM_TYPEMOUSE &&
			raw->data.mouse.usFlags == MOUSE_MOVE_RELATIVE)
		{
			POINT p;
			GetCursorPos(&p);
			ScreenToClient(g_platform_data.m_hwnd, &p);

			g_platform_data.m_handler->onMouseMove(
				int(p.x), int(p.y), int(raw->data.mouse.lLastX), int(raw->data.mouse.lLastY));
		}
	}

	static LRESULT WINAPI msgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
	{
		if (!g_platform_data.m_handler) return DefWindowProc(hWnd, msg, wParam, lParam);

		int x = LOWORD(lParam);
		int y = HIWORD(lParam);

		switch (msg)
		{
			case WM_LBUTTONUP:
				g_platform_data.m_handler->onMouseButtonUp(SystemEventHandler::MouseButton::LEFT);
				break;
			case WM_LBUTTONDOWN:
				g_platform_data.m_handler->onMouseButtonDown(SystemEventHandler::MouseButton::LEFT);
				break;
			case WM_RBUTTONDOWN:
				g_platform_data.m_handler->onMouseButtonDown(SystemEventHandler::MouseButton::RIGHT);
				break;
			case WM_RBUTTONUP:
				g_platform_data.m_handler->onMouseButtonUp(SystemEventHandler::MouseButton::RIGHT);
				break;
			case WM_MBUTTONUP:
				g_platform_data.m_handler->onMouseButtonUp(SystemEventHandler::MouseButton::MIDDLE);
				break;
			case WM_MBUTTONDOWN:
				g_platform_data.m_handler->onMouseButtonDown(SystemEventHandler::MouseButton::MIDDLE);
				break;
			case WM_MOUSEWHEEL:
				g_platform_data.m_handler->onMouseWheel(GET_WHEEL_DELTA_WPARAM(wParam));
				break;
			case WM_INPUT: handleRawInput(lParam); break;
			case WM_MOUSEMOVE:
			{
				if (!g_platform_data.m_is_mouse_tracked) trackMouse();
			}
			break;
			case WM_ERASEBKGND: return 1;
			case WM_MOVE:
			case WM_SIZE:
			{
				RECT rect;
				GetClientRect(g_platform_data.m_hwnd, &rect);
				g_platform_data.m_handler->onWindowTransformed(
					rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top);
			}
			break;
			case WM_CLOSE: PostQuitMessage(0); break;
			case WM_MOUSELEAVE:
			{
				g_platform_data.m_is_mouse_tracked = false;
				g_platform_data.m_handler->onMouseLeftWindow();
			}
			break;
			case WM_KEYUP:
			case WM_SYSKEYUP: g_platform_data.m_handler->onKeyUp(getKeyFromSystem(wParam)); break;
			case WM_KEYDOWN:
			case WM_SYSKEYDOWN: g_platform_data.m_handler->onKeyDown(getKeyFromSystem(wParam)); break;
			case WM_CHAR: g_platform_data.m_handler->onChar(getKeyFromSystem(wParam)); break;
		}

		return DefWindowProc(hWnd, msg, wParam, lParam);
	}

	void getKeyName(int key, char* out, int max_size)
	{
		int virtualKey = getSystemKey(key);
		unsigned int scanCode = MapVirtualKey(virtualKey, MAPVK_VK_TO_VSC);

		// because MapVirtualKey strips the extended bit for some keys
		switch (virtualKey)
		{
		case VK_LEFT:
		case VK_UP:
		case VK_RIGHT:
		case VK_DOWN: // arrow keys
		case VK_PRIOR:
		case VK_NEXT: // page up and page down
		case VK_END:
		case VK_HOME:
		case VK_INSERT:
		case VK_DELETE:
		case VK_DIVIDE: // numpad slash
		case VK_NUMLOCK:
		{
			scanCode |= 0x100; // set extended bit
			break;
		}
		}

		GetKeyNameText(scanCode << 16, out, max_size);
	}

	bool processSystemEvents()
	{
		bool want_quit = false;
		MSG msg;
		while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);

			if (msg.message == WM_QUIT)
			{
				want_quit = true;
			}
		}
		return !want_quit;
	}

	void setSystemEventHandler(SystemEventHandler* handler)
	{
		g_platform_data.m_handler = handler;
	}

	void createWindow(SystemEventHandler* handler)
	{
		g_platform_data.m_handler = handler;

		HINSTANCE hInst = GetModuleHandle(NULL);
		WNDCLASSEX wnd;
		memset(&wnd, 0, sizeof(wnd));
		wnd.cbSize = sizeof(wnd);
		wnd.style = CS_HREDRAW | CS_VREDRAW;
		wnd.lpfnWndProc = msgProc;
		wnd.hInstance = hInst;
		wnd.hIcon = LoadIcon(NULL, IDI_APPLICATION);
		wnd.hCursor = LoadCursor(NULL, IDC_ARROW);
		wnd.lpszClassName = "lmxa";
		wnd.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
		auto x = RegisterClassExA(&wnd);
		g_platform_data.m_hwnd = CreateWindowA(
			"lmxa", "lmxa", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 0, 0, 800, 600, NULL, NULL, hInst, 0);
		SetWindowTextA(g_platform_data.m_hwnd, "Lumix Studio");

		RAWINPUTDEVICE Rid;
		Rid.usUsagePage = 0x01;
		Rid.usUsage = 0x02;
		Rid.dwFlags = 0;
		Rid.hwndTarget = 0;
		RegisterRawInputDevices(&Rid, 1, sizeof(Rid));

		timeBeginPeriod(1);
		trackMouse();

		Lumix::Renderer::setInitData(g_platform_data.m_hwnd);
		ImGui::GetIO().ImeWindowHandle = g_platform_data.m_hwnd;
	}

	void setWindowTitle(const char* title)
	{
		SetWindowTextA(g_platform_data.m_hwnd, title);
	}

	bool isPressed(int key)
	{
		return (GetKeyState(getSystemKey(key)) & 0x8000) != 0;
	}

	void setCursor(Cursor cursor)
	{
		switch (cursor)
		{
			case Cursor::NONE:
				SetCursor(NULL);
				break;
			default:
				SetCursor(LoadCursor(NULL, IDC_ARROW));
				break;
		}

	}

} // namespace PlatformInterface

INT WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, INT)
{
	int studioMain();
	return studioMain();
}
<commit_msg>ImGui : it is possible to enter decimal mark in DragFloat - closes #603<commit_after>#include "platform_interface.h"
#include "ocornut-imgui/imgui.h"
#include "renderer/renderer.h"

#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <mmsystem.h>

namespace PlatformInterface
{

	struct PlatformData
	{
		PlatformData()
		{
			for (int i = 0; i < Lumix::lengthOf(m_key_map); ++i)
			{
				m_key_map[i] = -1;
				m_system_key_map[i] = -1;
			}

			m_key_map[(int)Keys::ALT] = VK_MENU;
			m_key_map[(int)Keys::CONTROL] = VK_CONTROL;
			m_key_map[(int)Keys::SHIFT] = VK_SHIFT;
			m_key_map[(int)Keys::TAB] = VK_TAB;
			m_key_map[(int)Keys::LEFT] = VK_LEFT;
			m_key_map[(int)Keys::RIGHT] = VK_RIGHT;
			m_key_map[(int)Keys::UP] = VK_UP;
			m_key_map[(int)Keys::DOWN] = VK_DOWN;
			m_key_map[(int)Keys::PAGE_UP] = VK_PRIOR;
			m_key_map[(int)Keys::PAGE_DOWN] = VK_NEXT;
			m_key_map[(int)Keys::HOME] = VK_HOME;
			m_key_map[(int)Keys::END] = VK_END;
			m_key_map[(int)Keys::DEL] = VK_DELETE;
			m_key_map[(int)Keys::BACKSPACE] = VK_BACK;
			m_key_map[(int)Keys::ENTER] = VK_RETURN;
			m_key_map[(int)Keys::ESCAPE] = VK_ESCAPE;

			for (int i = 0; i < Lumix::lengthOf(m_key_map); ++i)
			{
				if (m_key_map[i] != -1) m_system_key_map[m_key_map[i]] = i;
			}
		}

		HWND m_hwnd;
		bool m_is_mouse_tracked;
		SystemEventHandler* m_handler;
		int m_key_map[512];
		int m_system_key_map[512];
	};

	static PlatformData g_platform_data;

	static int getSystemKey(int key)
	{
		if (g_platform_data.m_key_map[key] != -1)
		{
			return g_platform_data.m_key_map[key];
		}
		else
		{
			return key;
		}
	}

	static int getKeyFromSystem(int key)
	{
		if (g_platform_data.m_system_key_map[key] != -1)
		{
			return g_platform_data.m_system_key_map[key];
		}
		else
		{
			return key;
		}
	}

	static void trackMouse()
	{
		TRACKMOUSEEVENT track_event;
		track_event.cbSize = sizeof(TRACKMOUSEEVENT);
		track_event.dwFlags = TME_LEAVE;
		track_event.hwndTrack = g_platform_data.m_hwnd;
		g_platform_data.m_is_mouse_tracked = TrackMouseEvent(&track_event) == TRUE;
	}

	void getCurrentDirectory(char* buffer, int buffer_size)
	{
		GetCurrentDirectory(buffer_size, buffer);
	}

	void shutdown()
	{
		HINSTANCE hInst = GetModuleHandle(NULL);
		UnregisterClassA("lmxa", hInst);
	}

	void moveWindow(int x, int y, int w, int h)
	{
		MoveWindow(g_platform_data.m_hwnd, x, y, w, h, FALSE);
	}

	bool isMaximized()
	{
		WINDOWPLACEMENT wndpl;
		wndpl.length = sizeof(wndpl);
		if (GetWindowPlacement(g_platform_data.m_hwnd, &wndpl))
		{
			return wndpl.showCmd == SW_MAXIMIZE;
		}
		return false;
	}

	void maximizeWindow()
	{
		ShowWindow(g_platform_data.m_hwnd, SW_MAXIMIZE);
	}

	bool isForegroundWindow()
	{
		return GetForegroundWindow() == g_platform_data.m_hwnd;
	}

	void clipCursor(float min_x, float min_y, float max_x, float max_y)
	{
		POINT min;
		POINT max;
		min.x = LONG(min_x);
		min.y = LONG(min_y);
		max.x = LONG(max_x);
		max.y = LONG(max_y);
		ClientToScreen(g_platform_data.m_hwnd, &min);
		ClientToScreen(g_platform_data.m_hwnd, &max);
		RECT rect;
		rect.left = min.x;
		rect.right = max.x;
		rect.top = min.y;
		rect.bottom = max.y;
		ClipCursor(&rect);
	}

	void showCursor(bool show)
	{
		ShowCursor(show);
	}

	void unclipCursor()
	{
		ClipCursor(NULL);
	}

	int getWindowX()
	{
		RECT rect;
		GetClientRect(g_platform_data.m_hwnd, &rect);
		return int(rect.left);
	}

	int getWindowY()
	{
		RECT rect;
		GetClientRect(g_platform_data.m_hwnd, &rect);
		return int(rect.top);
	}

	int getWindowWidth()
	{
		RECT rect;
		GetClientRect(g_platform_data.m_hwnd, &rect);
		return int(rect.right - rect.left);
	}

	int getWindowHeight()
	{
		RECT rect;
		GetClientRect(g_platform_data.m_hwnd, &rect);
		return int(rect.bottom - rect.top);
	}

	void handleRawInput(LPARAM lParam)
	{
		UINT dwSize;
		char data[sizeof(RAWINPUT) * 10];

		GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, &dwSize, sizeof(RAWINPUTHEADER));
		if (dwSize > sizeof(data)) return;

		if (GetRawInputData((HRAWINPUT)lParam, RID_INPUT, data, &dwSize, sizeof(RAWINPUTHEADER)) !=
			dwSize) return;

		RAWINPUT* raw = (RAWINPUT*)data;
		if (raw->header.dwType == RIM_TYPEMOUSE &&
			raw->data.mouse.usFlags == MOUSE_MOVE_RELATIVE)
		{
			POINT p;
			GetCursorPos(&p);
			ScreenToClient(g_platform_data.m_hwnd, &p);

			g_platform_data.m_handler->onMouseMove(
				int(p.x), int(p.y), int(raw->data.mouse.lLastX), int(raw->data.mouse.lLastY));
		}
	}

	static LRESULT WINAPI msgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
	{
		if (!g_platform_data.m_handler) return DefWindowProc(hWnd, msg, wParam, lParam);

		int x = LOWORD(lParam);
		int y = HIWORD(lParam);

		switch (msg)
		{
			case WM_LBUTTONUP:
				g_platform_data.m_handler->onMouseButtonUp(SystemEventHandler::MouseButton::LEFT);
				break;
			case WM_LBUTTONDOWN:
				g_platform_data.m_handler->onMouseButtonDown(SystemEventHandler::MouseButton::LEFT);
				break;
			case WM_RBUTTONDOWN:
				g_platform_data.m_handler->onMouseButtonDown(SystemEventHandler::MouseButton::RIGHT);
				break;
			case WM_RBUTTONUP:
				g_platform_data.m_handler->onMouseButtonUp(SystemEventHandler::MouseButton::RIGHT);
				break;
			case WM_MBUTTONUP:
				g_platform_data.m_handler->onMouseButtonUp(SystemEventHandler::MouseButton::MIDDLE);
				break;
			case WM_MBUTTONDOWN:
				g_platform_data.m_handler->onMouseButtonDown(SystemEventHandler::MouseButton::MIDDLE);
				break;
			case WM_MOUSEWHEEL:
				g_platform_data.m_handler->onMouseWheel(GET_WHEEL_DELTA_WPARAM(wParam));
				break;
			case WM_INPUT: handleRawInput(lParam); break;
			case WM_MOUSEMOVE:
			{
				if (!g_platform_data.m_is_mouse_tracked) trackMouse();
			}
			break;
			case WM_ERASEBKGND: return 1;
			case WM_MOVE:
			case WM_SIZE:
			{
				RECT rect;
				GetClientRect(g_platform_data.m_hwnd, &rect);
				g_platform_data.m_handler->onWindowTransformed(
					rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top);
			}
			break;
			case WM_CLOSE: PostQuitMessage(0); break;
			case WM_MOUSELEAVE:
			{
				g_platform_data.m_is_mouse_tracked = false;
				g_platform_data.m_handler->onMouseLeftWindow();
			}
			break;
			case WM_KEYUP:
			case WM_SYSKEYUP: g_platform_data.m_handler->onKeyUp(getKeyFromSystem(wParam)); break;
			case WM_KEYDOWN:
			case WM_SYSKEYDOWN: g_platform_data.m_handler->onKeyDown(getKeyFromSystem(wParam)); break;
			case WM_CHAR: g_platform_data.m_handler->onChar(wParam); break;
		}

		return DefWindowProc(hWnd, msg, wParam, lParam);
	}

	void getKeyName(int key, char* out, int max_size)
	{
		int virtualKey = getSystemKey(key);
		unsigned int scanCode = MapVirtualKey(virtualKey, MAPVK_VK_TO_VSC);

		// because MapVirtualKey strips the extended bit for some keys
		switch (virtualKey)
		{
		case VK_LEFT:
		case VK_UP:
		case VK_RIGHT:
		case VK_DOWN: // arrow keys
		case VK_PRIOR:
		case VK_NEXT: // page up and page down
		case VK_END:
		case VK_HOME:
		case VK_INSERT:
		case VK_DELETE:
		case VK_DIVIDE: // numpad slash
		case VK_NUMLOCK:
		{
			scanCode |= 0x100; // set extended bit
			break;
		}
		}

		GetKeyNameText(scanCode << 16, out, max_size);
	}

	bool processSystemEvents()
	{
		bool want_quit = false;
		MSG msg;
		while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);

			if (msg.message == WM_QUIT)
			{
				want_quit = true;
			}
		}
		return !want_quit;
	}

	void setSystemEventHandler(SystemEventHandler* handler)
	{
		g_platform_data.m_handler = handler;
	}

	void createWindow(SystemEventHandler* handler)
	{
		g_platform_data.m_handler = handler;

		HINSTANCE hInst = GetModuleHandle(NULL);
		WNDCLASSEX wnd;
		memset(&wnd, 0, sizeof(wnd));
		wnd.cbSize = sizeof(wnd);
		wnd.style = CS_HREDRAW | CS_VREDRAW;
		wnd.lpfnWndProc = msgProc;
		wnd.hInstance = hInst;
		wnd.hIcon = LoadIcon(NULL, IDI_APPLICATION);
		wnd.hCursor = LoadCursor(NULL, IDC_ARROW);
		wnd.lpszClassName = "lmxa";
		wnd.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
		auto x = RegisterClassExA(&wnd);
		g_platform_data.m_hwnd = CreateWindowA(
			"lmxa", "lmxa", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 0, 0, 800, 600, NULL, NULL, hInst, 0);
		SetWindowTextA(g_platform_data.m_hwnd, "Lumix Studio");

		RAWINPUTDEVICE Rid;
		Rid.usUsagePage = 0x01;
		Rid.usUsage = 0x02;
		Rid.dwFlags = 0;
		Rid.hwndTarget = 0;
		RegisterRawInputDevices(&Rid, 1, sizeof(Rid));

		timeBeginPeriod(1);
		trackMouse();

		Lumix::Renderer::setInitData(g_platform_data.m_hwnd);
		ImGui::GetIO().ImeWindowHandle = g_platform_data.m_hwnd;
	}

	void setWindowTitle(const char* title)
	{
		SetWindowTextA(g_platform_data.m_hwnd, title);
	}

	bool isPressed(int key)
	{
		return (GetKeyState(getSystemKey(key)) & 0x8000) != 0;
	}

	void setCursor(Cursor cursor)
	{
		switch (cursor)
		{
			case Cursor::NONE:
				SetCursor(NULL);
				break;
			default:
				SetCursor(LoadCursor(NULL, IDC_ARROW));
				break;
		}

	}

} // namespace PlatformInterface

INT WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, INT)
{
	int studioMain();
	return studioMain();
}
<|endoftext|>


<commit_before>
#include <GameData.h>
#include <File.h>
#include <DatCat.h>
#include <ExdData.h>
#include <ExdCat.h>
#include <Exd.h>
#include <iostream>
#include <cctype>
#include <set>
#include <src/servers/Server_Common/Exd/ExdData.h>
#include <src/servers/Server_Common/Logging/Logger.h>
#include <boost/range/algorithm/remove_if.hpp>
#include <boost/algorithm/string/classification.hpp>

#include <fstream>

Core::Logger g_log;
Core::Data::ExdData g_exdData;

//const std::string datLocation( "/opt/sapphire_3_15_0/bin/sqpack" );
const std::string datLocation( "C:\\Data\\Games\\Final Fantasy XIV\\SquareEnix\\FINAL FANTASY XIV - A Realm Reborn\\game\\sqpack\\ffxiv" );

std::string generateEnum( const std::string& exd, int8_t nameIndex, const std::string& type, bool useLang = true )
{

   xiv::dat::GameData data( datLocation );
   xiv::exd::ExdData eData( data );

   std::map< std::string, uint32_t> nameMap;

   std::string result = "\n   ///////////////////////////////////////////////////////////\n";
   result += "   //" + exd + ".exd\n";
   result += "   enum class " + exd + " : " + type + "\n";
   result += "   {\n";
   auto lang = useLang ? xiv::exd::Language::en : xiv::exd::Language::none;
   auto access = g_exdData.setupDatAccess( exd, lang );
   auto rows = access.get_rows();

   for( auto row : rows )
   {
      auto& fields = row.second;
      uint32_t id = row.first;
      auto test = boost::get< std::string >( &fields.at( nameIndex ) );
      if( !test )
         continue;
      auto str = *test;
      str.erase( boost::remove_if( str, boost::is_any_of(",_-':!(){} \x02\x1f\x01\x03") ), str.end() );
      if( str.empty() )
         continue;
      str[0] = std::toupper( str[0] );

      auto it = nameMap.find( str );
      if( it != nameMap.end() )
      {
         nameMap[str]++;
         str = str + std::to_string( nameMap[str] );
      }
      else
      {
         nameMap[str] = 0;
      }

      result += "      " + str + " = " + std::to_string( id  ) + ",\n";

   }

   /*
   result +=
           "      bool operator==( const " + exd + "& t, const " + type + "& g ) { return static_cast< " + type + " >( t ) == g; }\n"
           "      bool operator==( const " + type + "& g, const " + exd + "& t ) { return static_cast< " + type + " >( t ) == g; }\n";
   */

   result += "   };\n";

   return result;

}

int main()
{

   g_log.init();

   g_log.info( "Setting up EXD data" );
   if( !g_exdData.init( datLocation  ) )
   {
      g_log.fatal( "Error setting up EXD data " );
      return 1;
   }

   std::string result = "#ifndef _COMMON_GEN_H_\n#define _COMMON_GEN_H_\n";

   result += "\n#include <stdint.h>\n\n";

   result +=
   "/* This file has been automatically generated.\n   Changes will be lost upon regeneration.\n   To change the content edit tools/exd_common_gen */\n";

   result += "namespace Core {\n";
   result += "namespace Common {\n";
   result += generateEnum( "ActionCategory", 0, "uint8_t" );
   result += generateEnum( "BeastReputationRank", 1, "uint8_t" );
   result += generateEnum( "BeastTribe", 10, "uint8_t" );
   result += generateEnum( "ClassJob", 0, "uint8_t" );
   result += generateEnum( "ContentType", 0, "uint8_t" );
   result += generateEnum( "EmoteCategory", 0, "uint8_t" );
   result += generateEnum( "ExVersion", 0, "uint8_t" );
   result += generateEnum( "GrandCompany", 0, "uint8_t" );
   result += generateEnum( "GuardianDeity", 0, "uint8_t" );
   result += generateEnum( "ItemUICategory", 0, "uint8_t" );
   result += generateEnum( "ItemSearchCategory", 0, "uint8_t" );
   result += generateEnum( "OnlineStatus", 2, "uint8_t" );
   result += generateEnum( "Race", 1, "uint8_t" );
   result += generateEnum( "Tribe", 0, "uint8_t" );
   result += generateEnum( "Town", 0, "uint8_t" );
   result += generateEnum( "Weather", 1, "uint8_t" );
   result += "}\n";
   result += "}\n#endif\n";
   g_log.info( result );
   return 0;
}
<commit_msg>Fixed beast tribe string index<commit_after>
#include <GameData.h>
#include <File.h>
#include <DatCat.h>
#include <ExdData.h>
#include <ExdCat.h>
#include <Exd.h>
#include <iostream>
#include <cctype>
#include <set>
#include <src/servers/Server_Common/Exd/ExdData.h>
#include <src/servers/Server_Common/Logging/Logger.h>
#include <boost/range/algorithm/remove_if.hpp>
#include <boost/algorithm/string/classification.hpp>

#include <fstream>

Core::Logger g_log;
Core::Data::ExdData g_exdData;

//const std::string datLocation( "/opt/sapphire_3_15_0/bin/sqpack" );
const std::string datLocation( "C:\\Data\\Games\\Final Fantasy XIV\\SquareEnix\\FINAL FANTASY XIV - A Realm Reborn\\game\\sqpack\\ffxiv" );

std::string generateEnum( const std::string& exd, int8_t nameIndex, const std::string& type, bool useLang = true )
{

   xiv::dat::GameData data( datLocation );
   xiv::exd::ExdData eData( data );

   std::map< std::string, uint32_t> nameMap;

   std::string result = "\n   ///////////////////////////////////////////////////////////\n";
   result += "   //" + exd + ".exd\n";
   result += "   enum class " + exd + " : " + type + "\n";
   result += "   {\n";
   auto lang = useLang ? xiv::exd::Language::en : xiv::exd::Language::none;
   auto access = g_exdData.setupDatAccess( exd, lang );
   auto rows = access.get_rows();

   for( auto row : rows )
   {
      auto& fields = row.second;
      uint32_t id = row.first;
      auto test = boost::get< std::string >( &fields.at( nameIndex ) );
      if( !test )
         continue;
      auto str = *test;
      str.erase( boost::remove_if( str, boost::is_any_of(",_-':!(){} \x02\x1f\x01\x03") ), str.end() );
      if( str.empty() )
         continue;
      str[0] = std::toupper( str[0] );

      auto it = nameMap.find( str );
      if( it != nameMap.end() )
      {
         nameMap[str]++;
         str = str + std::to_string( nameMap[str] );
      }
      else
      {
         nameMap[str] = 0;
      }

      result += "      " + str + " = " + std::to_string( id  ) + ",\n";

   }

   /*
   result +=
           "      bool operator==( const " + exd + "& t, const " + type + "& g ) { return static_cast< " + type + " >( t ) == g; }\n"
           "      bool operator==( const " + type + "& g, const " + exd + "& t ) { return static_cast< " + type + " >( t ) == g; }\n";
   */

   result += "   };\n";

   return result;

}

int main()
{

   g_log.init();

   g_log.info( "Setting up EXD data" );
   if( !g_exdData.init( datLocation  ) )
   {
      g_log.fatal( "Error setting up EXD data " );
      return 1;
   }

   std::string result = "#ifndef _COMMON_GEN_H_\n#define _COMMON_GEN_H_\n";

   result += "\n#include <stdint.h>\n\n";

   result +=
   "/* This file has been automatically generated.\n   Changes will be lost upon regeneration.\n   To change the content edit tools/exd_common_gen */\n";

   result += "namespace Core {\n";
   result += "namespace Common {\n";
   result += generateEnum( "ActionCategory", 0, "uint8_t" );
   result += generateEnum( "BeastReputationRank", 1, "uint8_t" );
   result += generateEnum( "BeastTribe", 11, "uint8_t" );
   result += generateEnum( "ClassJob", 0, "uint8_t" );
   result += generateEnum( "ContentType", 0, "uint8_t" );
   result += generateEnum( "EmoteCategory", 0, "uint8_t" );
   result += generateEnum( "ExVersion", 0, "uint8_t" );
   result += generateEnum( "GrandCompany", 0, "uint8_t" );
   result += generateEnum( "GuardianDeity", 0, "uint8_t" );
   result += generateEnum( "ItemUICategory", 0, "uint8_t" );
   result += generateEnum( "ItemSearchCategory", 0, "uint8_t" );
   result += generateEnum( "OnlineStatus", 2, "uint8_t" );
   result += generateEnum( "Race", 1, "uint8_t" );
   result += generateEnum( "Tribe", 0, "uint8_t" );
   result += generateEnum( "Town", 0, "uint8_t" );
   result += generateEnum( "Weather", 1, "uint8_t" );
   result += "}\n";
   result += "}\n#endif\n";
   g_log.info( result );
   return 0;
}
<|endoftext|>


<commit_before>//===--- Local.cpp - Functions that perform local SIL transformations. ---===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===---------------------------------------------------------------------===//
#include "swift/SILPasses/Utils/Local.h"
#include "swift/SILAnalysis/Analysis.h"
#include "swift/SIL/CallGraph.h"
#include "swift/SIL/SILBuilder.h"
#include "swift/SIL/SILModule.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/IR/Intrinsics.h"
#include <deque>

using namespace swift;

bool
swift::isSideEffectFree(BuiltinFunctionRefInst *FR) {

  // First, check if we are dealing with a swift builtin.
  const BuiltinInfo &BInfo = FR->getBuiltinInfo();
  if (BInfo.ID != BuiltinValueKind::None) {
    return BInfo.isReadNone();
  }

  // Second, specialcase llvm intrinsic.
  const IntrinsicInfo & IInfo = FR->getIntrinsicInfo();
  if (IInfo.ID != llvm::Intrinsic::not_intrinsic) {
    return ( (IInfo.hasAttribute(llvm::Attribute::ReadNone) ||
              IInfo.hasAttribute(llvm::Attribute::ReadOnly)) &&
            IInfo.hasAttribute(llvm::Attribute::NoUnwind) );
  }

  llvm_unreachable("All cases are covered.");
}

bool swift::isReadNone(BuiltinFunctionRefInst *FR) {
  // First, check if we are dealing with a swift builtin.
  const BuiltinInfo &BInfo = FR->getBuiltinInfo();
  if (BInfo.ID != BuiltinValueKind::None)
    return BInfo.isReadNone();

  // Second, specialcase llvm intrinsic.
  const IntrinsicInfo & IInfo = FR->getIntrinsicInfo();
  if (IInfo.ID != llvm::Intrinsic::not_intrinsic)
    return IInfo.hasAttribute(llvm::Attribute::ReadNone) &&
      IInfo.hasAttribute(llvm::Attribute::NoUnwind);

  llvm_unreachable("All cases are covered.");
}

/// \brief Perform a fast local check to see if the instruction is dead.
///
/// This routine only examines the state of the instruction at hand.
bool
swift::isInstructionTriviallyDead(SILInstruction *I) {
  if (!I->use_empty() || isa<TermInst>(I))
    return false;

  // We know that some calls do not have side effects.
  if (const ApplyInst *AI = dyn_cast<ApplyInst>(I)) {
    if (BuiltinFunctionRefInst *FR =
        dyn_cast<BuiltinFunctionRefInst>(AI->getCallee().getDef())) {
      return isSideEffectFree(FR);
    }
  }

  // condfail instructions that obviously can't fail are dead.
  if (auto *CFI = dyn_cast<CondFailInst>(I))
    if (auto *ILI = dyn_cast<IntegerLiteralInst>(CFI->getOperand()))
      if (!ILI->getValue())
        return true;

  // mark_uninitialized is never dead.
  if (isa<MarkUninitializedInst>(I))
    return false;

  if (!I->mayHaveSideEffects())
    return true;

  return false;
}

/// \brief For each of the given instructions, if they are dead delete them
/// along with their dead operands.
///
/// \param IA The instruction to be deleted.
/// \param Force If Force is set, don't check if the top level instructions
///        are considered dead - delete them regardless.
bool
swift::recursivelyDeleteTriviallyDeadInstructions(ArrayRef<SILInstruction*> IA,
                                                  bool Force) {
  // Delete these instruction and others that become dead after it's deleted.
  llvm::SmallPtrSet<SILInstruction*, 8> DeadInsts;
  for (auto I : IA) {
    // If the instruction is not dead or force is false, there is nothing to do.
    if (Force || isInstructionTriviallyDead(I))
      DeadInsts.insert(I);
  }
  llvm::SmallPtrSet<SILInstruction*, 8> NextInsts;
  while (!DeadInsts.empty()) {
    for (auto I : DeadInsts) {
      // Check if any of the operands will become dead as well.
      MutableArrayRef<Operand> Ops = I->getAllOperands();
      for (Operand &Op : Ops) {
        SILValue OpVal = Op.get();
        if (!OpVal) continue;

        // Remove the reference from the instruction being deleted to this
        // operand.
        Op.drop();

        // If the operand is an instruction that is only used by the instruction
        // being deleted, delete it.
        if (SILInstruction *OpValInst = dyn_cast<SILInstruction>(OpVal))
          if (!DeadInsts.count(OpValInst) &&
             isInstructionTriviallyDead(OpValInst))
            NextInsts.insert(OpValInst);
      }
    }

    for (auto I : DeadInsts) {
      // This will remove this instruction and all its uses.
      I->eraseFromParent();
    }

    NextInsts.swap(DeadInsts);
    NextInsts.clear();
  }

  return true;
}

/// \brief If the given instruction is dead, delete it along with its dead
/// operands.
///
/// \param I The instruction to be deleted.
/// \param Force If Force is set, don't check if the top level instruction is
///        considered dead - delete it regardless.
/// \return Returns true if any instructions were deleted.
bool
swift::recursivelyDeleteTriviallyDeadInstructions(SILInstruction *I,
                                                       bool Force) {
  return recursivelyDeleteTriviallyDeadInstructions(
           ArrayRef<SILInstruction*>(I), Force);
}

void swift::eraseUsesOfInstruction(SILInstruction *Inst) {
  for (auto UI : Inst->getUses()) {
    auto *User = UI->getUser();

    // If the instruction itself has any uses, recursively zap them so that
    // nothing uses this instruction.
    eraseUsesOfInstruction(User);

    // Walk through the operand list and delete any random instructions that
    // will become trivially dead when this instruction is removed.

    for (auto &Op : User->getAllOperands()) {
      if (auto *OpI = dyn_cast<SILInstruction>(Op.get().getDef())) {
        // Don't recursively delete the pointer we're getting in.
        if (OpI != Inst) {
          Op.drop();
          recursivelyDeleteTriviallyDeadInstructions(OpI);
        }
      }
    }

    User->eraseFromParent();
  }
}

void swift::bottomUpCallGraphOrder(SILModule *M,
                                   std::vector<SILFunction*> &order) {
  CallGraphSorter<SILFunction*> sorter;
  for (auto &Caller : *M)
    for (auto &BB : Caller)
      for (auto &I : BB)
        if (FunctionRefInst *FRI = dyn_cast<FunctionRefInst>(&I)) {
          SILFunction *Callee = FRI->getReferencedFunction();
          sorter.addEdge(&Caller, Callee);
        }

  sorter.sort(order);
}

void swift::replaceWithSpecializedFunction(ApplyInst *AI, SILFunction *NewF) {
  SILLocation Loc = AI->getLoc();
  ArrayRef<Substitution> Subst;

  SmallVector<SILValue, 4> Arguments;
  for (auto &Op : AI->getArgumentOperands()) {
    Arguments.push_back(Op.get());
  }

  SILBuilder Builder(AI);
  FunctionRefInst *FRI = Builder.createFunctionRef(Loc, NewF);

  ApplyInst *NAI =
      Builder.createApply(Loc, FRI, Arguments, AI->isTransparent());
  SILValue(AI, 0).replaceAllUsesWith(SILValue(NAI, 0));
  recursivelyDeleteTriviallyDeadInstructions(AI, true);
}

/// \brief Returns True if the operand or one of its users is captured.
static bool useCaptured(Operand *UI) {
  auto *User = UI->getUser();

  // These instructions do not cause the address to escape.
  if (isa<CopyAddrInst>(User) ||
      isa<LoadInst>(User) ||
      isa<ProtocolMethodInst>(User) ||
      (isa<StoreInst>(User) && UI->getOperandNumber() == 1) ||
      (isa<AssignInst>(User) && UI->getOperandNumber() == 1)) {
    return false;
  }

  if ((isa<AddressToPointerInst>(User) || isa<PointerToAddressInst>(User)) &&
      User->hasOneUse()) {
    return useCaptured(*User->use_begin());
  }

  return true;
}

bool
swift::canValueEscape(SILValue V, SmallVectorImpl<SILInstruction*> &Users) {
  for (auto UI : V.getUses()) {
    auto *User = UI->getUser();

    // These instructions do not cause the address to escape.
    if (!useCaptured(UI)) {
      Users.push_back(User);
      continue;
    }

    // These instructions only cause the value to escape if they are used in
    // a way that escapes.  Recursively check that the uses of the instruction
    // don't escape and collect all of the uses of the value.
    if (isa<StructElementAddrInst>(User) || isa<TupleElementAddrInst>(User) ||
        isa<ProjectExistentialInst>(User) || isa<OpenExistentialInst>(User) ||
        isa<MarkUninitializedInst>(User) || isa<AddressToPointerInst>(User) ||
        isa<PointerToAddressInst>(User)) {
      Users.push_back(User);
      if (canValueEscape(User, Users))
        return true;
      continue;
    }

    // apply and partial_apply instructions do not capture the pointer when
    // it is passed through inout arguments or for indirect returns.
    if (auto apply = dyn_cast<ApplyInst>(User)) {
      if (apply->getSubstCalleeType()
          ->getInterfaceParameters()[UI->getOperandNumber()-1].isIndirect())
        continue;
    }
    if (auto partialApply = dyn_cast<PartialApplyInst>(User)) {
      if (partialApply->getSubstCalleeType()
          ->getInterfaceParameters()[UI->getOperandNumber()-1].isIndirect())
        continue;
    }

    return true;
  }

  return false;
}
<commit_msg>Correctly index into the parameters for partial_apply.<commit_after>//===--- Local.cpp - Functions that perform local SIL transformations. ---===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===---------------------------------------------------------------------===//
#include "swift/SILPasses/Utils/Local.h"
#include "swift/SILAnalysis/Analysis.h"
#include "swift/SIL/CallGraph.h"
#include "swift/SIL/SILBuilder.h"
#include "swift/SIL/SILModule.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/IR/Intrinsics.h"
#include <deque>

using namespace swift;

bool
swift::isSideEffectFree(BuiltinFunctionRefInst *FR) {

  // First, check if we are dealing with a swift builtin.
  const BuiltinInfo &BInfo = FR->getBuiltinInfo();
  if (BInfo.ID != BuiltinValueKind::None) {
    return BInfo.isReadNone();
  }

  // Second, specialcase llvm intrinsic.
  const IntrinsicInfo & IInfo = FR->getIntrinsicInfo();
  if (IInfo.ID != llvm::Intrinsic::not_intrinsic) {
    return ( (IInfo.hasAttribute(llvm::Attribute::ReadNone) ||
              IInfo.hasAttribute(llvm::Attribute::ReadOnly)) &&
            IInfo.hasAttribute(llvm::Attribute::NoUnwind) );
  }

  llvm_unreachable("All cases are covered.");
}

bool swift::isReadNone(BuiltinFunctionRefInst *FR) {
  // First, check if we are dealing with a swift builtin.
  const BuiltinInfo &BInfo = FR->getBuiltinInfo();
  if (BInfo.ID != BuiltinValueKind::None)
    return BInfo.isReadNone();

  // Second, specialcase llvm intrinsic.
  const IntrinsicInfo & IInfo = FR->getIntrinsicInfo();
  if (IInfo.ID != llvm::Intrinsic::not_intrinsic)
    return IInfo.hasAttribute(llvm::Attribute::ReadNone) &&
      IInfo.hasAttribute(llvm::Attribute::NoUnwind);

  llvm_unreachable("All cases are covered.");
}

/// \brief Perform a fast local check to see if the instruction is dead.
///
/// This routine only examines the state of the instruction at hand.
bool
swift::isInstructionTriviallyDead(SILInstruction *I) {
  if (!I->use_empty() || isa<TermInst>(I))
    return false;

  // We know that some calls do not have side effects.
  if (const ApplyInst *AI = dyn_cast<ApplyInst>(I)) {
    if (BuiltinFunctionRefInst *FR =
        dyn_cast<BuiltinFunctionRefInst>(AI->getCallee().getDef())) {
      return isSideEffectFree(FR);
    }
  }

  // condfail instructions that obviously can't fail are dead.
  if (auto *CFI = dyn_cast<CondFailInst>(I))
    if (auto *ILI = dyn_cast<IntegerLiteralInst>(CFI->getOperand()))
      if (!ILI->getValue())
        return true;

  // mark_uninitialized is never dead.
  if (isa<MarkUninitializedInst>(I))
    return false;

  if (!I->mayHaveSideEffects())
    return true;

  return false;
}

/// \brief For each of the given instructions, if they are dead delete them
/// along with their dead operands.
///
/// \param IA The instruction to be deleted.
/// \param Force If Force is set, don't check if the top level instructions
///        are considered dead - delete them regardless.
bool
swift::recursivelyDeleteTriviallyDeadInstructions(ArrayRef<SILInstruction*> IA,
                                                  bool Force) {
  // Delete these instruction and others that become dead after it's deleted.
  llvm::SmallPtrSet<SILInstruction*, 8> DeadInsts;
  for (auto I : IA) {
    // If the instruction is not dead or force is false, there is nothing to do.
    if (Force || isInstructionTriviallyDead(I))
      DeadInsts.insert(I);
  }
  llvm::SmallPtrSet<SILInstruction*, 8> NextInsts;
  while (!DeadInsts.empty()) {
    for (auto I : DeadInsts) {
      // Check if any of the operands will become dead as well.
      MutableArrayRef<Operand> Ops = I->getAllOperands();
      for (Operand &Op : Ops) {
        SILValue OpVal = Op.get();
        if (!OpVal) continue;

        // Remove the reference from the instruction being deleted to this
        // operand.
        Op.drop();

        // If the operand is an instruction that is only used by the instruction
        // being deleted, delete it.
        if (SILInstruction *OpValInst = dyn_cast<SILInstruction>(OpVal))
          if (!DeadInsts.count(OpValInst) &&
             isInstructionTriviallyDead(OpValInst))
            NextInsts.insert(OpValInst);
      }
    }

    for (auto I : DeadInsts) {
      // This will remove this instruction and all its uses.
      I->eraseFromParent();
    }

    NextInsts.swap(DeadInsts);
    NextInsts.clear();
  }

  return true;
}

/// \brief If the given instruction is dead, delete it along with its dead
/// operands.
///
/// \param I The instruction to be deleted.
/// \param Force If Force is set, don't check if the top level instruction is
///        considered dead - delete it regardless.
/// \return Returns true if any instructions were deleted.
bool
swift::recursivelyDeleteTriviallyDeadInstructions(SILInstruction *I,
                                                       bool Force) {
  return recursivelyDeleteTriviallyDeadInstructions(
           ArrayRef<SILInstruction*>(I), Force);
}

void swift::eraseUsesOfInstruction(SILInstruction *Inst) {
  for (auto UI : Inst->getUses()) {
    auto *User = UI->getUser();

    // If the instruction itself has any uses, recursively zap them so that
    // nothing uses this instruction.
    eraseUsesOfInstruction(User);

    // Walk through the operand list and delete any random instructions that
    // will become trivially dead when this instruction is removed.

    for (auto &Op : User->getAllOperands()) {
      if (auto *OpI = dyn_cast<SILInstruction>(Op.get().getDef())) {
        // Don't recursively delete the pointer we're getting in.
        if (OpI != Inst) {
          Op.drop();
          recursivelyDeleteTriviallyDeadInstructions(OpI);
        }
      }
    }

    User->eraseFromParent();
  }
}

void swift::bottomUpCallGraphOrder(SILModule *M,
                                   std::vector<SILFunction*> &order) {
  CallGraphSorter<SILFunction*> sorter;
  for (auto &Caller : *M)
    for (auto &BB : Caller)
      for (auto &I : BB)
        if (FunctionRefInst *FRI = dyn_cast<FunctionRefInst>(&I)) {
          SILFunction *Callee = FRI->getReferencedFunction();
          sorter.addEdge(&Caller, Callee);
        }

  sorter.sort(order);
}

void swift::replaceWithSpecializedFunction(ApplyInst *AI, SILFunction *NewF) {
  SILLocation Loc = AI->getLoc();
  ArrayRef<Substitution> Subst;

  SmallVector<SILValue, 4> Arguments;
  for (auto &Op : AI->getArgumentOperands()) {
    Arguments.push_back(Op.get());
  }

  SILBuilder Builder(AI);
  FunctionRefInst *FRI = Builder.createFunctionRef(Loc, NewF);

  ApplyInst *NAI =
      Builder.createApply(Loc, FRI, Arguments, AI->isTransparent());
  SILValue(AI, 0).replaceAllUsesWith(SILValue(NAI, 0));
  recursivelyDeleteTriviallyDeadInstructions(AI, true);
}

/// \brief Returns True if the operand or one of its users is captured.
static bool useCaptured(Operand *UI) {
  auto *User = UI->getUser();

  // These instructions do not cause the address to escape.
  if (isa<CopyAddrInst>(User) ||
      isa<LoadInst>(User) ||
      isa<ProtocolMethodInst>(User) ||
      (isa<StoreInst>(User) && UI->getOperandNumber() == 1) ||
      (isa<AssignInst>(User) && UI->getOperandNumber() == 1)) {
    return false;
  }

  if ((isa<AddressToPointerInst>(User) || isa<PointerToAddressInst>(User)) &&
      User->hasOneUse()) {
    return useCaptured(*User->use_begin());
  }

  return true;
}

bool
swift::canValueEscape(SILValue V, SmallVectorImpl<SILInstruction*> &Users) {
  for (auto UI : V.getUses()) {
    auto *User = UI->getUser();

    // These instructions do not cause the address to escape.
    if (!useCaptured(UI)) {
      Users.push_back(User);
      continue;
    }

    // These instructions only cause the value to escape if they are used in
    // a way that escapes.  Recursively check that the uses of the instruction
    // don't escape and collect all of the uses of the value.
    if (isa<StructElementAddrInst>(User) || isa<TupleElementAddrInst>(User) ||
        isa<ProjectExistentialInst>(User) || isa<OpenExistentialInst>(User) ||
        isa<MarkUninitializedInst>(User) || isa<AddressToPointerInst>(User) ||
        isa<PointerToAddressInst>(User)) {
      Users.push_back(User);
      if (canValueEscape(User, Users))
        return true;
      continue;
    }

    // apply and partial_apply instructions do not capture the pointer when
    // it is passed through inout arguments or for indirect returns.
    if (auto apply = dyn_cast<ApplyInst>(User)) {
      if (apply->getSubstCalleeType()
          ->getInterfaceParameters()[UI->getOperandNumber()-1].isIndirect())
        continue;
    }
    if (auto partialApply = dyn_cast<PartialApplyInst>(User)) {
      auto args = partialApply->getArguments();
      auto params = partialApply->getSubstCalleeType()
        ->getInterfaceParameters();
      params = params.slice(params.size() - args.size(), args.size());
      if (params[UI->getOperandNumber()-1].isIndirect())
        continue;
    }

    return true;
  }

  return false;
}
<|endoftext|>


<commit_before>//Copyright (c) 2017 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.

#include "MinimumSpanningTree.h"

#include <iterator>
#include <algorithm>

namespace cura
{

MinimumSpanningTree::MinimumSpanningTree(std::unordered_set<Point> vertices) : adjacency_graph(prim(vertices))
{
    //Just copy over the fields.
}

auto MinimumSpanningTree::prim(std::unordered_set<Point> vertices) const -> AdjacencyGraph_t
{
    AdjacencyGraph_t result;
    if (vertices.empty())
    {
        return result; //No vertices, so we can't create edges either.
    }
    // If there's only one vertex, we can't go creating any edges so just add the point to the adjacency list with no
    // edges
    if (vertices.size() == 1)
    {
        // unordered_map::operator[]() will construct an empty vector in place for us when we try and access an element
        // that doesnt exist
        result[*vertices.begin()];
        return result;
    }
    result.reserve(vertices.size());
    std::vector<Point> vertices_list(vertices.begin(), vertices.end());

    std::unordered_map<const Point*, coord_t> smallest_distance;    //The shortest distance to the current tree.
    std::unordered_map<const Point*, const Point*> smallest_distance_to; //Which point the shortest distance goes towards.
    smallest_distance.reserve(vertices_list.size());
    smallest_distance_to.reserve(vertices_list.size());
    for (size_t vertex_index = 1; vertex_index < vertices_list.size(); vertex_index++)
    {
        const auto& vert = vertices_list[vertex_index];
        smallest_distance[&vert] = vSize2(vert - vertices_list[0]);
        smallest_distance_to[&vert] = &vertices_list[0];
    }

    while (result.size() < vertices_list.size()) //All of the vertices need to be in the tree at the end.
    {
        //Choose the closest vertex to connect to that is not yet in the tree.
        //This search is O(V) right now, which can be made down to O(log(V)). This reduces the overall time complexity from O(V*V) to O(V*log(E)).
        //However that requires an implementation of a heap that supports the decreaseKey operation, which is not in the std library.
        //TODO: Implement this?
        using MapValue = std::pair<const Point*, coord_t>;
        const auto closest = std::min_element(smallest_distance.begin(), smallest_distance.end(),
                                              [](const MapValue& a, const MapValue& b) {
                                                  return a.second < b.second;
                                              });

        //Add this point to the graph and remove it from the candidates.
        const Point* closest_point = closest->first;
        const Point other_end = *smallest_distance_to[closest_point];
        result[*closest_point].push_back({*closest_point, other_end});
        result[other_end].push_back({other_end, *closest_point});
        smallest_distance.erase(closest_point); //Remove it so we don't check for these points again.
        smallest_distance_to.erase(closest_point);

        //Update the distances of all points that are not in the graph.
        for (std::pair<const Point*, coord_t> point_and_distance : smallest_distance)
        {
            const coord_t new_distance = vSize2(*closest_point - *point_and_distance.first);
            const coord_t old_distance = point_and_distance.second;
            if (new_distance < old_distance) //New point is closer.
            {
                smallest_distance[point_and_distance.first] = new_distance;
                smallest_distance_to[point_and_distance.first] = closest_point;
            }
        }
    }

    return result;
}

std::vector<Point> MinimumSpanningTree::adjacentNodes(Point node) const
{
    std::vector<Point> result;
    AdjacencyGraph_t::const_iterator adjacency_entry = adjacency_graph.find(node);
    if (adjacency_entry != adjacency_graph.end())
    {
        const auto& edges = adjacency_entry->second;
        std::transform(edges.begin(), edges.end(), std::back_inserter(result),
                       [&node](const Edge& e) { return (e.start == node) ? e.end : e.start; });
    }
    return result;
}

std::vector<Point> MinimumSpanningTree::leaves() const
{
    std::vector<Point> result;
    for (std::pair<Point, std::vector<Edge>> node : adjacency_graph)
    {
        if (node.second.size() <= 1) //Leaves are nodes that have only one adjacent edge, or just the one node if the tree contains one node.
        {
            result.push_back(node.first);
        }
    }
    return result;
}

std::vector<Point> MinimumSpanningTree::vertices() const
{
    std::vector<Point> result;
    using MapValue = std::pair<Point, std::vector<Edge>>;
    std::transform(adjacency_graph.begin(), adjacency_graph.end(), std::back_inserter(result),
                   [](const MapValue& node) { return node.first; });
    return result;
}

}
<commit_msg>Add empty vector if key not in map yet<commit_after>//Copyright (c) 2017 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.

#include "MinimumSpanningTree.h"

#include <iterator>
#include <algorithm>

namespace cura
{

MinimumSpanningTree::MinimumSpanningTree(std::unordered_set<Point> vertices) : adjacency_graph(prim(vertices))
{
    //Just copy over the fields.
}

auto MinimumSpanningTree::prim(std::unordered_set<Point> vertices) const -> AdjacencyGraph_t
{
    AdjacencyGraph_t result;
    if (vertices.empty())
    {
        return result; //No vertices, so we can't create edges either.
    }
    // If there's only one vertex, we can't go creating any edges so just add the point to the adjacency list with no
    // edges
    if (vertices.size() == 1)
    {
        // unordered_map::operator[]() will construct an empty vector in place for us when we try and access an element
        // that doesnt exist
        result[*vertices.begin()];
        return result;
    }
    result.reserve(vertices.size());
    std::vector<Point> vertices_list(vertices.begin(), vertices.end());

    std::unordered_map<const Point*, coord_t> smallest_distance;    //The shortest distance to the current tree.
    std::unordered_map<const Point*, const Point*> smallest_distance_to; //Which point the shortest distance goes towards.
    smallest_distance.reserve(vertices_list.size());
    smallest_distance_to.reserve(vertices_list.size());
    for (size_t vertex_index = 1; vertex_index < vertices_list.size(); vertex_index++)
    {
        const auto& vert = vertices_list[vertex_index];
        smallest_distance[&vert] = vSize2(vert - vertices_list[0]);
        smallest_distance_to[&vert] = &vertices_list[0];
    }

    while (result.size() < vertices_list.size()) //All of the vertices need to be in the tree at the end.
    {
        //Choose the closest vertex to connect to that is not yet in the tree.
        //This search is O(V) right now, which can be made down to O(log(V)). This reduces the overall time complexity from O(V*V) to O(V*log(E)).
        //However that requires an implementation of a heap that supports the decreaseKey operation, which is not in the std library.
        //TODO: Implement this?
        using MapValue = std::pair<const Point*, coord_t>;
        const auto closest = std::min_element(smallest_distance.begin(), smallest_distance.end(),
                                              [](const MapValue& a, const MapValue& b) {
                                                  return a.second < b.second;
                                              });

        //Add this point to the graph and remove it from the candidates.
        const Point* closest_point = closest->first;
        const Point other_end = *smallest_distance_to[closest_point];
        if (result.find(*closest_point) == result.end())
        {
            result[*closest_point] = std::vector<Edge>();
        }
        result[*closest_point].push_back({*closest_point, other_end});
        if (result.find(other_end) == result.end())
        {
            result[other_end] = std::vector<Edge>();
        }
        result[other_end].push_back({other_end, *closest_point});
        smallest_distance.erase(closest_point); //Remove it so we don't check for these points again.
        smallest_distance_to.erase(closest_point);

        //Update the distances of all points that are not in the graph.
        for (std::pair<const Point*, coord_t> point_and_distance : smallest_distance)
        {
            const coord_t new_distance = vSize2(*closest_point - *point_and_distance.first);
            const coord_t old_distance = point_and_distance.second;
            if (new_distance < old_distance) //New point is closer.
            {
                smallest_distance[point_and_distance.first] = new_distance;
                smallest_distance_to[point_and_distance.first] = closest_point;
            }
        }
    }

    return result;
}

std::vector<Point> MinimumSpanningTree::adjacentNodes(Point node) const
{
    std::vector<Point> result;
    AdjacencyGraph_t::const_iterator adjacency_entry = adjacency_graph.find(node);
    if (adjacency_entry != adjacency_graph.end())
    {
        const auto& edges = adjacency_entry->second;
        std::transform(edges.begin(), edges.end(), std::back_inserter(result),
                       [&node](const Edge& e) { return (e.start == node) ? e.end : e.start; });
    }
    return result;
}

std::vector<Point> MinimumSpanningTree::leaves() const
{
    std::vector<Point> result;
    for (std::pair<Point, std::vector<Edge>> node : adjacency_graph)
    {
        if (node.second.size() <= 1) //Leaves are nodes that have only one adjacent edge, or just the one node if the tree contains one node.
        {
            result.push_back(node.first);
        }
    }
    return result;
}

std::vector<Point> MinimumSpanningTree::vertices() const
{
    std::vector<Point> result;
    using MapValue = std::pair<Point, std::vector<Edge>>;
    std::transform(adjacency_graph.begin(), adjacency_graph.end(), std::back_inserter(result),
                   [](const MapValue& node) { return node.first; });
    return result;
}

}
<|endoftext|>


<commit_before>#ifndef STAN_MATH_PRIM_FUN_REP_MATRIX_HPP
#define STAN_MATH_PRIM_FUN_REP_MATRIX_HPP

#include <stan/math/prim/meta.hpp>
#include <stan/math/prim/err.hpp>
#include <stan/math/prim/fun/Eigen.hpp>

namespace stan {
namespace math {

/**
 * Implementation of rep_matrix returning an Eigen matrix with scalar
 * type equal to the input scalar type.
 * @tparam Ret An Eigen type.
 * @tparam T A Scalar type.
 * @param x A Scalar whose values are propogated to all values in the return
 * matrix.
 * @param m Number or rows.
 * @param n Number of columns.
 */
template <typename Ret, typename T,
          require_eigen_matrix_dynamic_vt<is_stan_scalar, Ret>* = nullptr,
          require_stan_scalar_t<T>* = nullptr>
inline auto rep_matrix(const T& x, int m, int n) {
  check_nonnegative("rep_matrix", "rows", m);
  check_nonnegative("rep_matrix", "cols", n);
  return Ret::Constant(m, n, x);
}

/**
 * Default Implementation of rep_matrix returning an Eigen matrix with scalar
 * type equal to the input scalar type.
 * @tparam T A Scalar type.
 * @param x A Scalar whose values are propogated to all values in the return
 * matrix.
 * @param m Number or rows.
 * @param n Number of columns.
 */
template <typename T, require_stan_scalar_t<T>* = nullptr>
inline auto rep_matrix(const T& x, int m, int n) {
  return rep_matrix<Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>>(x, m, n);
}

/**
 * Implementation of rep_matrix returning an Eigen matrix from an Eigen
 * vector.
 * @tparam Vec An Eigen vector.
 * @param x An Eigen vector. For Row vectors the values are replacated rowwise.
 * and for column vectors the values are repliacated colwise.
 * @param n Number of rows or columns.
 */
template <typename Vec,
          require_eigen_vector_t<Vec>* = nullptr>
inline auto rep_matrix(const Vec& x, int n) {
  if (is_eigen_row_vector<Vec>::value) {
    check_nonnegative("rep_matrix", "rows", n);
    return x.replicate(n, 1);
  } else {
    check_nonnegative("rep_matrix", "cols", n);
    return x.replicate(1, n);
  }
}

}  // namespace math
}  // namespace stan

#endif
<commit_msg>[Jenkins] auto-formatting by clang-format version 6.0.0-1ubuntu2~16.04.1 (tags/RELEASE_600/final)<commit_after>#ifndef STAN_MATH_PRIM_FUN_REP_MATRIX_HPP
#define STAN_MATH_PRIM_FUN_REP_MATRIX_HPP

#include <stan/math/prim/meta.hpp>
#include <stan/math/prim/err.hpp>
#include <stan/math/prim/fun/Eigen.hpp>

namespace stan {
namespace math {

/**
 * Implementation of rep_matrix returning an Eigen matrix with scalar
 * type equal to the input scalar type.
 * @tparam Ret An Eigen type.
 * @tparam T A Scalar type.
 * @param x A Scalar whose values are propogated to all values in the return
 * matrix.
 * @param m Number or rows.
 * @param n Number of columns.
 */
template <typename Ret, typename T,
          require_eigen_matrix_dynamic_vt<is_stan_scalar, Ret>* = nullptr,
          require_stan_scalar_t<T>* = nullptr>
inline auto rep_matrix(const T& x, int m, int n) {
  check_nonnegative("rep_matrix", "rows", m);
  check_nonnegative("rep_matrix", "cols", n);
  return Ret::Constant(m, n, x);
}

/**
 * Default Implementation of rep_matrix returning an Eigen matrix with scalar
 * type equal to the input scalar type.
 * @tparam T A Scalar type.
 * @param x A Scalar whose values are propogated to all values in the return
 * matrix.
 * @param m Number or rows.
 * @param n Number of columns.
 */
template <typename T, require_stan_scalar_t<T>* = nullptr>
inline auto rep_matrix(const T& x, int m, int n) {
  return rep_matrix<Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>>(x, m, n);
}

/**
 * Implementation of rep_matrix returning an Eigen matrix from an Eigen
 * vector.
 * @tparam Vec An Eigen vector.
 * @param x An Eigen vector. For Row vectors the values are replacated rowwise.
 * and for column vectors the values are repliacated colwise.
 * @param n Number of rows or columns.
 */
template <typename Vec, require_eigen_vector_t<Vec>* = nullptr>
inline auto rep_matrix(const Vec& x, int n) {
  if (is_eigen_row_vector<Vec>::value) {
    check_nonnegative("rep_matrix", "rows", n);
    return x.replicate(n, 1);
  } else {
    check_nonnegative("rep_matrix", "cols", n);
    return x.replicate(1, n);
  }
}

}  // namespace math
}  // namespace stan

#endif
<|endoftext|>


<commit_before>#ifndef STAN_MATH_REV_FUN_LOG_SOFTMAX_HPP
#define STAN_MATH_REV_FUN_LOG_SOFTMAX_HPP

#include <stan/math/rev/core.hpp>
#include <stan/math/rev/core/typedefs.hpp>
#include <stan/math/prim/meta.hpp>
#include <stan/math/prim/err.hpp>
#include <stan/math/prim/fun/Eigen.hpp>
#include <stan/math/prim/fun/log_softmax.hpp>
#include <stan/math/prim/fun/softmax.hpp>
#include <stan/math/prim/fun/to_ref.hpp>
#include <stan/math/prim/fun/typedefs.hpp>
#include <cmath>
#include <vector>

namespace stan {
namespace math {

namespace internal {

class log_softmax_elt_vari : public vari {
 private:
  vari** alpha_;
  const double* softmax_alpha_;
  const int size_;  // array sizes
  const int idx_;   // in in softmax output

 public:
  log_softmax_elt_vari(double val, vari** alpha, const double* softmax_alpha,
                       int size, int idx)
      : vari(val),
        alpha_(alpha),
        softmax_alpha_(softmax_alpha),
        size_(size),
        idx_(idx) {}
  void chain() {
    for (int m = 0; m < size_; ++m) {
      if (m == idx_) {
        alpha_[m]->adj_ += adj_ * (1 - softmax_alpha_[m]);
      } else {
        alpha_[m]->adj_ -= adj_ * softmax_alpha_[m];
      }
    }
  }
};
}  // namespace internal

/**
 * Return the log softmax of the specified vector
 *
 * @tparam T type of input
 * @param x input
 * @return softmax of the input
 * @throw std::domain_error if the input size is 0
 */
template <typename T, require_eigen_st<is_var, T>* = nullptr>
auto log_softmax(const T& x) {
  const int a_size = x.size();

  check_nonzero_size("log_softmax", "x", x);

  const auto& x_ref = to_ref(x);

  vari** x_vi_array
      = ChainableStack::instance_->memalloc_.alloc_array<vari*>(a_size);
  Eigen::Map<vector_vi>(x_vi_array, a_size) = x_ref.vi();

  vector_d x_d = x_ref.val();

  // fold logic of math::softmax() and math::log_softmax()
  // to save computations

  vector_d diff = (x_d.array() - x_d.maxCoeff());
  vector_d softmax_x_d = diff.array().exp();
  double sum = softmax_x_d.sum();
  vector_d log_softmax_x_d = diff.array() - std::log(sum);

  // end fold
  double* softmax_x_d_array
      = ChainableStack::instance_->memalloc_.alloc_array<double>(a_size);
  Eigen::Map<vector_d>(softmax_x_d_array, a_size)
      = softmax_x_d.array() / sum;

  vector_v log_softmax_x(a_size);
  for (int k = 0; k < a_size; ++k) {
    log_softmax_x(k) = var(new internal::log_softmax_elt_vari(
        log_softmax_x_d[k], x_vi_array, softmax_x_d_array, a_size,
        k));
  }
  return log_softmax_x;
}

/**
 * Return the log softmax of the specified vector
 *
 * @tparam T type of input
 * @param x input
 * @return softmax of the input
 * @throw std::domain_error if the input size is 0
 */
template <typename T, require_var_matrix_t<T>* = nullptr>
inline auto log_softmax(const T& x) {
  check_nonzero_size("log_softmax", "x", x);

  const auto& theta = (x.val().array() - x.val().maxCoeff()).eval();

  return make_callback_var(
      (theta.array() - log(theta.exp().sum())).matrix(),
      [x](const auto& res) mutable {
        x.adj().noalias()
            += res.adj() - (res.adj().sum() * res.val().array().exp()).matrix();
      });
}

/**
 * Return the log softmax of the specified `std::vector` or
 * `std::vector` of containers.
 *
 * @tparam T type of input
 * @param x input
 * @return softmax of the input
 * @throw std::domain_error if the input size is 0
 */
template <typename T, require_std_vector_st<is_var, T>* = nullptr>
inline auto log_softmax(const T& x) {
  return apply_vector_unary<T>::apply(
      x, [](const auto& alpha) { return log_softmax(alpha); });
}

}  // namespace math
}  // namespace stan
#endif
<commit_msg>[Jenkins] auto-formatting by clang-format version 6.0.0-1ubuntu2~16.04.1 (tags/RELEASE_600/final)<commit_after>#ifndef STAN_MATH_REV_FUN_LOG_SOFTMAX_HPP
#define STAN_MATH_REV_FUN_LOG_SOFTMAX_HPP

#include <stan/math/rev/core.hpp>
#include <stan/math/rev/core/typedefs.hpp>
#include <stan/math/prim/meta.hpp>
#include <stan/math/prim/err.hpp>
#include <stan/math/prim/fun/Eigen.hpp>
#include <stan/math/prim/fun/log_softmax.hpp>
#include <stan/math/prim/fun/softmax.hpp>
#include <stan/math/prim/fun/to_ref.hpp>
#include <stan/math/prim/fun/typedefs.hpp>
#include <cmath>
#include <vector>

namespace stan {
namespace math {

namespace internal {

class log_softmax_elt_vari : public vari {
 private:
  vari** alpha_;
  const double* softmax_alpha_;
  const int size_;  // array sizes
  const int idx_;   // in in softmax output

 public:
  log_softmax_elt_vari(double val, vari** alpha, const double* softmax_alpha,
                       int size, int idx)
      : vari(val),
        alpha_(alpha),
        softmax_alpha_(softmax_alpha),
        size_(size),
        idx_(idx) {}
  void chain() {
    for (int m = 0; m < size_; ++m) {
      if (m == idx_) {
        alpha_[m]->adj_ += adj_ * (1 - softmax_alpha_[m]);
      } else {
        alpha_[m]->adj_ -= adj_ * softmax_alpha_[m];
      }
    }
  }
};
}  // namespace internal

/**
 * Return the log softmax of the specified vector
 *
 * @tparam T type of input
 * @param x input
 * @return softmax of the input
 * @throw std::domain_error if the input size is 0
 */
template <typename T, require_eigen_st<is_var, T>* = nullptr>
auto log_softmax(const T& x) {
  const int a_size = x.size();

  check_nonzero_size("log_softmax", "x", x);

  const auto& x_ref = to_ref(x);

  vari** x_vi_array
      = ChainableStack::instance_->memalloc_.alloc_array<vari*>(a_size);
  Eigen::Map<vector_vi>(x_vi_array, a_size) = x_ref.vi();

  vector_d x_d = x_ref.val();

  // fold logic of math::softmax() and math::log_softmax()
  // to save computations

  vector_d diff = (x_d.array() - x_d.maxCoeff());
  vector_d softmax_x_d = diff.array().exp();
  double sum = softmax_x_d.sum();
  vector_d log_softmax_x_d = diff.array() - std::log(sum);

  // end fold
  double* softmax_x_d_array
      = ChainableStack::instance_->memalloc_.alloc_array<double>(a_size);
  Eigen::Map<vector_d>(softmax_x_d_array, a_size) = softmax_x_d.array() / sum;

  vector_v log_softmax_x(a_size);
  for (int k = 0; k < a_size; ++k) {
    log_softmax_x(k) = var(new internal::log_softmax_elt_vari(
        log_softmax_x_d[k], x_vi_array, softmax_x_d_array, a_size, k));
  }
  return log_softmax_x;
}

/**
 * Return the log softmax of the specified vector
 *
 * @tparam T type of input
 * @param x input
 * @return softmax of the input
 * @throw std::domain_error if the input size is 0
 */
template <typename T, require_var_matrix_t<T>* = nullptr>
inline auto log_softmax(const T& x) {
  check_nonzero_size("log_softmax", "x", x);

  const auto& theta = (x.val().array() - x.val().maxCoeff()).eval();

  return make_callback_var(
      (theta.array() - log(theta.exp().sum())).matrix(),
      [x](const auto& res) mutable {
        x.adj().noalias()
            += res.adj() - (res.adj().sum() * res.val().array().exp()).matrix();
      });
}

/**
 * Return the log softmax of the specified `std::vector` or
 * `std::vector` of containers.
 *
 * @tparam T type of input
 * @param x input
 * @return softmax of the input
 * @throw std::domain_error if the input size is 0
 */
template <typename T, require_std_vector_st<is_var, T>* = nullptr>
inline auto log_softmax(const T& x) {
  return apply_vector_unary<T>::apply(
      x, [](const auto& alpha) { return log_softmax(alpha); });
}

}  // namespace math
}  // namespace stan
#endif
<|endoftext|>


<commit_before>#include <rtt/os/main.h>

#include <boost/program_options.hpp>
#include <iostream>

#include <rtt/typekit/RealTimeTypekit.hpp>
<% deployer.rtt_transports.each do |transport_name| %>
#include <rtt/transports/<%= transport_name %>/TransportPlugin.hpp>
<% end %>

<% if component.typekit || !component.used_typekits.empty? %>#include <rtt/types/TypekitPlugin.hpp><% end %>
<% if typekit = component.typekit %>
#include "typekit/Plugin.hpp"
<% deployer.transports.each do |transport_name| %>
#include "typekit/transports/<%= transport_name %>/TransportPlugin.hpp"
<% end %>
<% end %>
<% deployer.used_typekits.each do |tk| %>
    <% next if tk.virtual? %>
#include <<%= tk.name %>/typekit/Plugin.hpp>
    <% deployer.transports.each do |transport_name| %>
#include <<%= tk.name %>/transports/<%= transport_name %>/TransportPlugin.hpp>
    <% end %>
<% end %>

<% task_activities = deployer.task_activities.
        sort_by(&:name) %>

<% task_activities.each do |task| %>
#include <<%= task.context.header_file %>>
<% end %>
<% if deployer.corba_enabled? %>
#include <rtt/transports/corba/ApplicationServer.hpp>
#include <rtt/transports/corba/TaskContextServer.hpp>
#include <signal.h>
<% end %>

<% require 'set'
    activity_headers = task_activities.
        map { |t| t.activity_type.header }.
        compact.
        to_set %>
<% activity_headers.to_a.sort.each do |header| %>
#include <<%= header %>>
<% end %>

<% if deployer.browse %>
#include <ocl/TaskBrowser.hpp>
<% end %>

#include <rtt/Logger.hpp>
#include <rtt/base/ActivityInterface.hpp>

namespace po = boost::program_options;

class Deinitializer
{
    friend Deinitializer& operator << (Deinitializer&, RTT::base::ActivityInterface&);

    std::vector<RTT::base::ActivityInterface*> m_activities;

public:
    ~Deinitializer()
    {
        for (std::vector<RTT::base::ActivityInterface*>::const_iterator it = m_activities.begin();
                it != m_activities.end(); ++it)
        {
            (*it)->stop();
        }
    }
};

Deinitializer& operator << (Deinitializer& deinit, RTT::base::ActivityInterface& activity)
{
    deinit.m_activities.push_back(&activity);
    return deinit;
}

<% if deployer.corba_enabled? %>
void sigint_quit_orb(int)
{
    RTT::corba::TaskContextServer::ShutdownOrb(false);
}
<% end %>

int ORO_main(int argc, char* argv[])
{
   po::options_description desc("Options");

   desc.add_options()
        ("help", "show all available options supported by this deployment")
   <% if needs_service_discovery_support? %>
        ("sd-domain", po::value<std::string>(), "set service discovery domain")
   <% end %>
   ;

   po::variables_map vm;
   po::store(po::parse_command_line(argc, argv, desc), vm);
   po::notify(vm);

   if(vm.count("help")) {
       std::cout << desc << std::endl;
       return 0;
   }

   <% if deployer.loglevel %>
   if ( log().getLogLevel() < Logger::<%= deployer.loglevel %> ) {
       log().setLogLevel( Logger::<%= deployer.loglevel %> );
   }
   <% end %>

   RTT::types::TypekitRepository::Import( new RTT::types::RealTimeTypekitPlugin );
   <% if deployer.transports.include?('corba') %>
   RTT::types::TypekitRepository::Import( new RTT::corba::CorbaLibPlugin );
   <% end %>
   <% if deployer.transports.include?('mqueue') %>
   RTT::types::TypekitRepository::Import( new RTT::mqueue::MQLibPlugin );
   <% end %>

   <% if component.typekit %>
   RTT::types::TypekitRepository::Import( new orogen_typekits::<%= component.name %>TypekitPlugin );
   <% deployer.transports.each do |transport_name| %>
   RTT::types::TypekitRepository::Import( new <%= typekit.transport_plugin_name(transport_name) %> );
   <% end %>
   <% end %>
   <% deployer.used_typekits.each do |tk| %>
   <% next if tk.virtual? %>
   RTT::types::TypekitRepository::Import( new orogen_typekits::<%= tk.name %>TypekitPlugin );
       <% deployer.transports.each do |transport_name| %>
   RTT::types::TypekitRepository::Import( new <%= Orocos::Generation::Typekit.transport_plugin_name(transport_name, tk.name) %> );
       <% end %>
   <% end %>

<% if deployer.corba_enabled? %>
    RTT::corba::ApplicationServer::InitOrb(argc, argv);
<% end %>

<% task_activities.each do |task| %>
    <%= task.context.class_name %> task_<%= task.name%>("<%= task.name %>", vm);
    <%= task.generate_activity_setup %>
    task_<%= task.name %>.setActivity(activity_<%= task.name %>);
    <% task.properties.sort_by { |prop| prop.name }.each do |prop|
        if prop.value %>
    dynamic_cast< RTT::Property<  <%= prop.interface_object.type.cxx_name %> >*>(
            task_<%= task.name %>.properties()->getProperty("<%= prop.name %>"))
        ->set(<%= prop.value.inspect %>);
        <% end %>
    <% end %>

    <% if deployer.corba_enabled? %>
    RTT::corba::TaskContextServer::Create( &task_<%= task.name%> );
    <% end %>
<% end %>

<% if !deployer.loggers.empty?
        deployer.loggers.sort_by { |filename, _| filename }.each do |filename, logger|
            logger.config.each do |type, reported_activity, args| %>
                task_<%= logger.task.name %>.connectPeers(&task_<%= reported_activity.name %>);
                task_<%= logger.task.name %>.report<%= type %>(<%= args.map { |v| "\"#{v}\"" }.join(", ") %>);
            <% end %>
        <% end %>
<% end %>

   Deinitializer deinit;

    // Start some activities
<% task_activities.each do |task| %>
    deinit << *activity_<%= task.name%>;

    <% if task.start?
        if task.context.needs_configuration? %>
    if (!task_<%= task.name %>.configure())
    {
        RTT::log(RTT::Error) << "cannot configure <%= task.name %>" << RTT::endlog();
        return -1;
    }
        <% end %>
    if (!task_<%= task.name %>.start())
    {
        RTT::log(RTT::Error) << "cannot start <%= task.name %>" << RTT::endlog();
        return -1;
    }
    <% end %>
<% end %>

<% deployer.peers.sort_by { |a, b| [a.name, b.name] }.each do |a, b| %>
    task_<%= a.name %>.connectPeers(&task_<%= b.name %>);
<% end %>

<% deployer.connections.
    sort_by { |src, dst, policy| [src.name, dst.name] }.
    each do |src, dst, policy|
        if src.kind_of?(TaskDeployment) %>
            task_<%= src.activity.name %>.connectPorts(&task_<%= dst.activity.name %>);
        <% else %>
        {
            <%= policy.to_code("policy") %>
            RTT::base::OutputPortInterface* src = dynamic_cast<RTT::base::OutputPortInterface*>(
                    task_<%= src.activity.name %>.ports()->getPort("<%= src.name %>"));
            RTT::base::InputPortInterface* dst = dynamic_cast<RTT::base::InputPortInterface*>(
                    task_<%= dst.activity.name %>.ports()->getPort("<%= dst.name %>"));
            src->createConnection(*dst, policy);
        }
        <% end %>
    <% end %>

<% if deployer.corba_enabled? %>
    struct sigaction sigint_handler;
    sigint_handler.sa_handler = &sigint_quit_orb;
    sigemptyset(&sigint_handler.sa_mask);
    sigint_handler.sa_flags     = 0;
    sigint_handler.sa_restorer  = 0;
    if (-1 == sigaction(SIGINT, &sigint_handler, 0))
    {
        std::cerr << "failed to install SIGINT handler" << std::endl;
        return 1;
    }
    sigset_t unblock_sigint;
    sigemptyset(&unblock_sigint);
    sigaddset(&unblock_sigint, SIGINT);
    if (-1 == sigprocmask(SIG_UNBLOCK, &unblock_sigint, NULL))
    {
        std::cerr << "failed to install SIGINT handler" << std::endl;
        return 1;
    }
    RTT::corba::TaskContextServer::RunOrb();
<% elsif deployer.browse %>
    OCL::TaskBrowser browser(& task_<%= deployer.browse.name %>);
    browser.loop();
<% end %>

    return 0;
}

<commit_msg>add prefix attribute to deployments<commit_after>#include <rtt/os/main.h>

#include <boost/program_options.hpp>
#include <iostream>

#include <rtt/typekit/RealTimeTypekit.hpp>
<% deployer.rtt_transports.each do |transport_name| %>
#include <rtt/transports/<%= transport_name %>/TransportPlugin.hpp>
<% end %>

<% if component.typekit || !component.used_typekits.empty? %>#include <rtt/types/TypekitPlugin.hpp><% end %>
<% if typekit = component.typekit %>
#include "typekit/Plugin.hpp"
<% deployer.transports.each do |transport_name| %>
#include "typekit/transports/<%= transport_name %>/TransportPlugin.hpp"
<% end %>
<% end %>
<% deployer.used_typekits.each do |tk| %>
    <% next if tk.virtual? %>
#include <<%= tk.name %>/typekit/Plugin.hpp>
    <% deployer.transports.each do |transport_name| %>
#include <<%= tk.name %>/transports/<%= transport_name %>/TransportPlugin.hpp>
    <% end %>
<% end %>

<% task_activities = deployer.task_activities.
        sort_by(&:name) %>

<% task_activities.each do |task| %>
#include <<%= task.context.header_file %>>
<% end %>
<% if deployer.corba_enabled? %>
#include <rtt/transports/corba/ApplicationServer.hpp>
#include <rtt/transports/corba/TaskContextServer.hpp>
#include <signal.h>
<% end %>

<% require 'set'
    activity_headers = task_activities.
        map { |t| t.activity_type.header }.
        compact.
        to_set %>
<% activity_headers.to_a.sort.each do |header| %>
#include <<%= header %>>
<% end %>

<% if deployer.browse %>
#include <ocl/TaskBrowser.hpp>
<% end %>

#include <rtt/Logger.hpp>
#include <rtt/base/ActivityInterface.hpp>

namespace po = boost::program_options;

class Deinitializer
{
    friend Deinitializer& operator << (Deinitializer&, RTT::base::ActivityInterface&);

    std::vector<RTT::base::ActivityInterface*> m_activities;

public:
    ~Deinitializer()
    {
        for (std::vector<RTT::base::ActivityInterface*>::const_iterator it = m_activities.begin();
                it != m_activities.end(); ++it)
        {
            (*it)->stop();
        }
    }
};

Deinitializer& operator << (Deinitializer& deinit, RTT::base::ActivityInterface& activity)
{
    deinit.m_activities.push_back(&activity);
    return deinit;
}

<% if deployer.corba_enabled? %>
void sigint_quit_orb(int)
{
    RTT::corba::TaskContextServer::ShutdownOrb(false);
}
<% end %>

int ORO_main(int argc, char* argv[])
{
   po::options_description desc("Options");

   desc.add_options()
        ("help", "show all available options supported by this deployment")
        ("prefix", po::value<std::string>(), "Sets a prefix for all TaskContext names")
   <% if needs_service_discovery_support? %>
        ("sd-domain", po::value<std::string>(), "set service discovery domain")
   <% end %>
   ;

   po::variables_map vm;
   po::store(po::parse_command_line(argc, argv, desc), vm);
   po::notify(vm);

   if(vm.count("help")) {
       std::cout << desc << std::endl;
       return 0;
   }

   <% if deployer.loglevel %>
   if ( log().getLogLevel() < Logger::<%= deployer.loglevel %> ) {
       log().setLogLevel( Logger::<%= deployer.loglevel %> );
   }
   <% end %>

   RTT::types::TypekitRepository::Import( new RTT::types::RealTimeTypekitPlugin );
   <% if deployer.transports.include?('corba') %>
   RTT::types::TypekitRepository::Import( new RTT::corba::CorbaLibPlugin );
   <% end %>
   <% if deployer.transports.include?('mqueue') %>
   RTT::types::TypekitRepository::Import( new RTT::mqueue::MQLibPlugin );
   <% end %>

   <% if component.typekit %>
   RTT::types::TypekitRepository::Import( new orogen_typekits::<%= component.name %>TypekitPlugin );
   <% deployer.transports.each do |transport_name| %>
   RTT::types::TypekitRepository::Import( new <%= typekit.transport_plugin_name(transport_name) %> );
   <% end %>
   <% end %>
   <% deployer.used_typekits.each do |tk| %>
   <% next if tk.virtual? %>
   RTT::types::TypekitRepository::Import( new orogen_typekits::<%= tk.name %>TypekitPlugin );
       <% deployer.transports.each do |transport_name| %>
   RTT::types::TypekitRepository::Import( new <%= Orocos::Generation::Typekit.transport_plugin_name(transport_name, tk.name) %> );
       <% end %>
   <% end %>

<% if deployer.corba_enabled? %>
    RTT::corba::ApplicationServer::InitOrb(argc, argv);
<% end %>

    std::string prefix = "";

    if( vm.count("prefix"))
        prefix = vm["prefix"].as<std::string>();

<% task_activities.each do |task| %>
    <%= task.context.class_name %> task_<%= task.name%>(prefix + "<%= task.name %>", vm);
    <%= task.generate_activity_setup %>
    task_<%= task.name %>.setActivity(activity_<%= task.name %>);
    <% task.properties.sort_by { |prop| prop.name }.each do |prop|
        if prop.value %>
    dynamic_cast< RTT::Property<  <%= prop.interface_object.type.cxx_name %> >*>(
            task_<%= task.name %>.properties()->getProperty("<%= prop.name %>"))
        ->set(<%= prop.value.inspect %>);
        <% end %>
    <% end %>

    <% if deployer.corba_enabled? %>
    RTT::corba::TaskContextServer::Create( &task_<%= task.name%> );
    <% end %>
<% end %>

<% if !deployer.loggers.empty?
        deployer.loggers.sort_by { |filename, _| filename }.each do |filename, logger|
            logger.config.each do |type, reported_activity, args| %>
                task_<%= logger.task.name %>.connectPeers(&task_<%= reported_activity.name %>);
                task_<%= logger.task.name %>.report<%= type %>(<%= args.map { |v| "\"#{v}\"" }.join(", ") %>);
            <% end %>
        <% end %>
<% end %>

   Deinitializer deinit;

    // Start some activities
<% task_activities.each do |task| %>
    deinit << *activity_<%= task.name%>;

    <% if task.start?
        if task.context.needs_configuration? %>
    if (!task_<%= task.name %>.configure())
    {
        RTT::log(RTT::Error) << "cannot configure <%= task.name %>" << RTT::endlog();
        return -1;
    }
        <% end %>
    if (!task_<%= task.name %>.start())
    {
        RTT::log(RTT::Error) << "cannot start <%= task.name %>" << RTT::endlog();
        return -1;
    }
    <% end %>
<% end %>

<% deployer.peers.sort_by { |a, b| [a.name, b.name] }.each do |a, b| %>
    task_<%= a.name %>.connectPeers(&task_<%= b.name %>);
<% end %>

<% deployer.connections.
    sort_by { |src, dst, policy| [src.name, dst.name] }.
    each do |src, dst, policy|
        if src.kind_of?(TaskDeployment) %>
            task_<%= src.activity.name %>.connectPorts(&task_<%= dst.activity.name %>);
        <% else %>
        {
            <%= policy.to_code("policy") %>
            RTT::base::OutputPortInterface* src = dynamic_cast<RTT::base::OutputPortInterface*>(
                    task_<%= src.activity.name %>.ports()->getPort("<%= src.name %>"));
            RTT::base::InputPortInterface* dst = dynamic_cast<RTT::base::InputPortInterface*>(
                    task_<%= dst.activity.name %>.ports()->getPort("<%= dst.name %>"));
            src->createConnection(*dst, policy);
        }
        <% end %>
    <% end %>

<% if deployer.corba_enabled? %>
    struct sigaction sigint_handler;
    sigint_handler.sa_handler = &sigint_quit_orb;
    sigemptyset(&sigint_handler.sa_mask);
    sigint_handler.sa_flags     = 0;
    sigint_handler.sa_restorer  = 0;
    if (-1 == sigaction(SIGINT, &sigint_handler, 0))
    {
        std::cerr << "failed to install SIGINT handler" << std::endl;
        return 1;
    }
    sigset_t unblock_sigint;
    sigemptyset(&unblock_sigint);
    sigaddset(&unblock_sigint, SIGINT);
    if (-1 == sigprocmask(SIG_UNBLOCK, &unblock_sigint, NULL))
    {
        std::cerr << "failed to install SIGINT handler" << std::endl;
        return 1;
    }
    RTT::corba::TaskContextServer::RunOrb();
<% elsif deployer.browse %>
    OCL::TaskBrowser browser(& task_<%= deployer.browse.name %>);
    browser.loop();
<% end %>

    return 0;
}

<|endoftext|>