<commit_before>#include "MoCapSimulator.h"

#include "Logging.h"
#undef   LOG_CLASS
#define  LOG_CLASS "MoCapSimulator"

#include <algorithm>
#include <iterator>
#include <string>

#include "math.h"

const float _frameRate = 60;

struct sRigidBodyMovementParams
{
	char* szName;
	int   axis;
	float radius;
	float posOffset;
	float rotOffset;
	float speed;
};

const sRigidBodyMovementParams RIGID_BODY_PARAMS[] =
{	{ "Walk_1m",  1,   -1,  1.5, -25, 1.0f /  15 }, // negative radius to make Z-axis face inwards, looking down towards origin
	{ "Walk_2m",  1,   -2,  1.5, -20, 1.0f /  20 }, // "
	{ "Walk_3m",  1,   -3,  1.5, -15, 1.0f / -25 }, // "
	{ "Walk_4m",  1,   -4,  1.5, -10, 1.0f / -30 }, // "
	{ "Walk_5m",  1,   -5,  1.5,  -7, 1.0f /  40 }, // "
	{ "Walk_10m", 1,  -10,  1.5,  -5, 1.0f /  50 }, // "
	{ "Oculus",   1,   -3,  1.5, -15, 1.0f /  30 },
	{ "RotX_pos", 0,  0.5,  1.0,   0, 1.0f /  10 },
	{ "RotX_neg", 0, -0.5, -1.0,   0, 1.0f / -10 },
	{ "RotY_pos", 1,  0.5,  1.0,   0, 1.0f /  10 },
	{ "RotY_neg", 1, -0.5, -1.0,   0, 1.0f / -10 },
	{ "RotZ_pos", 2,  0.5,  1.0,   0, 1.0f /  10 },
	{ "RotZ_neg", 2, -0.5, -1.0,   0, 1.0f / -10 },
};

const int MARKER_COUNT     = 4;
const int RIGID_BODY_COUNT = sizeof(RIGID_BODY_PARAMS) / sizeof(RIGID_BODY_PARAMS[0]);
const int SKELETON_COUNT   = 0;

MoCapSimulator::MoCapSimulator() :
	initialised(false)
{
}

bool MoCapSimulator::initialise()
{
	if (!initialised)
	{
		fTime = 0;
		iFrame = 0;

		arrPos.resize(RIGID_BODY_COUNT);
		arrRot.resize(RIGID_BODY_COUNT);
		arrTrackingLostCounter.resize(RIGID_BODY_COUNT);
		for (int i = 0; i < RIGID_BODY_COUNT; i++)
		{
			arrTrackingLostCounter[i] = 0;
		}
		trackingUnreliable = false;

		LOG_INFO("Initialised");

		initialised = true;
	}
	return initialised;
}

bool MoCapSimulator::isActive()
{
	return initialised;
}

float MoCapSimulator::getUpdateRate()
{
	return _frameRate;
}

bool MoCapSimulator::update()
{
	iFrame += 1;
	fTime  += (1.0f / _frameRate);

	for (int b = 0; b < RIGID_BODY_COUNT; b++)
	{
		// calculate new positions/rotations
		float t    = fTime * RIGID_BODY_PARAMS[b].speed;
		float r    = RIGID_BODY_PARAMS[b].radius;
		float oPos = RIGID_BODY_PARAMS[b].posOffset;
		float oRot = RIGID_BODY_PARAMS[b].rotOffset;
		switch (RIGID_BODY_PARAMS[b].axis)
		{
			case 0:
			{
				arrPos[b].set(oPos, r * cos(t), r * sin(t));   // zero degrees = Y+ up
				arrRot[b].fromAxisAngle(1, 0, 0, t);
				break;
			}
			case 1:
			{
				arrPos[b].set(r * -sin(t), oPos, r * -cos(t)); // zero degrees = Z- forwards
				arrRot[b].fromAxisAngle(0, 1, 0, t);
				// apply pitch
				Quaternion rotX(1, 0, 0, oRot * (float) (M_PI / 180));
				arrRot[b] = arrRot[b].mult(rotX);
				break;
			}
			case 2:
			{
				arrPos[b].set(r * -sin(t), r * cos(t), oPos);  // zero degrees = Y+ upwards
				arrRot[b].fromAxisAngle(0, 0, 1, t);
				break;
			}
		}

		if (trackingUnreliable)
		{
			if (rand() < RAND_MAX / 1000)
			{
				arrTrackingLostCounter[b] = rand() * 100 / RAND_MAX;
			}
		}
	}

	/*
	for (int s = 0; s < SKELETON_COUNT; s++)
	{

	}
	*/

	signalNewFrame();

	return true;
}

bool MoCapSimulator::getSceneDescription(MoCapData& refData)
{
	LOG_INFO("Requesting scene description")

	int descrIdx = 0;
	for (int b = 0; b < RIGID_BODY_COUNT; b++)
	{
		// create markerset description and frame
		sMarkerSetDescription* pMarkerDesc = new sMarkerSetDescription();
		sMarkerSetData&        msData      = refData.frame.MocapData[b];

		// name of marker set
		strcpy_s(pMarkerDesc->szName, sizeof(pMarkerDesc->szName), RIGID_BODY_PARAMS[b].szName);
		strcpy_s(msData.szName,       sizeof(msData.szName),       pMarkerDesc->szName);

		// number of markers
		pMarkerDesc->nMarkers = MARKER_COUNT;
		msData.nMarkers       = MARKER_COUNT;

		// names of markers
		pMarkerDesc->szMarkerNames = new char*[MARKER_COUNT];
		msData.Markers             = new MarkerData[MARKER_COUNT];
		for (int m = 0; m < MARKER_COUNT; m++)
		{
			char czMarkerName[10];
			sprintf_s(czMarkerName, sizeof(czMarkerName), "%02d", m + 1);
			pMarkerDesc->szMarkerNames[m] = _strdup(czMarkerName);
		}

		// add to description list
		refData.description.arrDataDescriptions[descrIdx].type = Descriptor_MarkerSet;
		refData.description.arrDataDescriptions[descrIdx].Data.MarkerSetDescription = pMarkerDesc;
		descrIdx++;

		sRigidBodyDescription* pBodyDesc = new sRigidBodyDescription();
		// fill in description structure
		pBodyDesc->ID       = b; // needs to be equal to array index
		pBodyDesc->parentID = -1;
		pBodyDesc->offsetx  = 0;
		pBodyDesc->offsety  = 0;
		pBodyDesc->offsetz  = 0;
		strcpy_s(pBodyDesc->szName, sizeof(pBodyDesc->szName), pMarkerDesc->szName);

		refData.description.arrDataDescriptions[descrIdx].type = Descriptor_RigidBody;
		refData.description.arrDataDescriptions[descrIdx].Data.RigidBodyDescription = pBodyDesc;
		descrIdx++;
	}

	for (int s = 0; s < SKELETON_COUNT; s++)
	{
		sSkeletonDescription* pSkeleton = new sSkeletonDescription();
		// fill in description structure
		pSkeleton->nRigidBodies = 2;
		//strcpy_s(pSkeleton->szName, ...);

		// pre-fill in frame structure for marker sets
		sSkeletonData& skData = refData.frame.Skeletons[s];
//todo

		refData.description.arrDataDescriptions[descrIdx].type = Descriptor_Skeleton;
		refData.description.arrDataDescriptions[descrIdx].Data.SkeletonDescription = pSkeleton;
		descrIdx++;
	}

	refData.description.nDataDescriptions = descrIdx;

	// pre-fill in frame data
	refData.frame.nMarkerSets  = RIGID_BODY_COUNT;
	refData.frame.nRigidBodies = RIGID_BODY_COUNT;
	refData.frame.nSkeletons   = SKELETON_COUNT;

	refData.frame.nOtherMarkers = 0;
	refData.frame.OtherMarkers  = NULL;

	refData.frame.nLabeledMarkers = 0;

	refData.frame.nForcePlates = 0;

	refData.frame.fLatency = 0.01f; // simulate 10ms
	refData.frame.Timecode = 0;
	refData.frame.TimecodeSubframe = 0;

	return true;
}

bool MoCapSimulator::getFrameData(MoCapData& refData)
{
	refData.frame.iFrame = iFrame;

	for (int b = 0; b < RIGID_BODY_COUNT; b++)
	{
		// simulate tracking loss
		bool trackingLost = false;
		if (arrTrackingLostCounter[b] > 0)
		{
			trackingLost = true;
			arrTrackingLostCounter[b]--;
		}

		// update marker data
		sMarkerSetData& msData = refData.frame.MocapData[b];
		for (int m = 0; m < msData.nMarkers; m++)
		{
			msData.Markers[m][0] = arrPos[b].x + (rand() * 0.1f / RAND_MAX - 0.05f);
			msData.Markers[m][1] = arrPos[b].y + (rand() * 0.1f / RAND_MAX - 0.05f);
			msData.Markers[m][2] = arrPos[b].z + (rand() * 0.1f / RAND_MAX - 0.05f);
		}

		// update rigid body data
		sRigidBodyData& rbData = refData.frame.RigidBodies[b];
		rbData.ID = b;
		rbData.x  = trackingLost ? 0 : arrPos[b].x;
		rbData.y  = trackingLost ? 0 : arrPos[b].y;
		rbData.z  = trackingLost ? 0 : arrPos[b].z;
		rbData.qx = trackingLost ? 0 : arrRot[b].x;
		rbData.qy = trackingLost ? 0 : arrRot[b].y;
		rbData.qz = trackingLost ? 0 : arrRot[b].z;
		rbData.qw = trackingLost ? 0 : arrRot[b].w;

		rbData.nMarkers  = 0;
		rbData.MeanError = 0;
		rbData.params    = trackingLost ? 0x00 : 0x01; // tracking OK
	}

	return true;
}

bool MoCapSimulator::processCommand(const std::string& strCommand)
{
	bool processed = false;

	// convert commandto lowercase
	std::string strCmdLowerCase;
	std::transform(strCommand.begin(), strCommand.end(), std::back_inserter(strCmdLowerCase), ::tolower);

	if (strCmdLowerCase == "lossy" )
	{
		trackingUnreliable = true;
		LOG_INFO("Tracking unreliable/lossy");
		processed = true;
	}
	else if (strCmdLowerCase == "lossless")
	{
		trackingUnreliable = false;
		LOG_INFO("Tracking reliable/lossless");
		processed = true;
	}

	return processed;
}

bool MoCapSimulator::deinitialise()
{
	if (initialised)
	{
		// nothing much to do here

		LOG_INFO("Deinitialised");
		initialised = false;
	}
	return !initialised;
}

MoCapSimulator::~MoCapSimulator()
{
	deinitialise();
}

<commit_msg>Changed simulator commands<commit_after>#include "MoCapSimulator.h"

#include "Logging.h"
#undef   LOG_CLASS
#define  LOG_CLASS "MoCapSimulator"

#include <algorithm>
#include <iterator>
#include <string>

#include "math.h"

const float _frameRate = 60;

struct sRigidBodyMovementParams
{
	char* szName;
	int   axis;
	float radius;
	float posOffset;
	float rotOffset;
	float speed;
};

const sRigidBodyMovementParams RIGID_BODY_PARAMS[] =
{	{ "Walk_1m",  1,   -1,  1.5, -25, 1.0f /  15 }, // negative radius to make Z-axis face inwards, looking down towards origin
	{ "Walk_2m",  1,   -2,  1.5, -20, 1.0f /  20 }, // "
	{ "Walk_3m",  1,   -3,  1.5, -15, 1.0f / -25 }, // "
	{ "Walk_4m",  1,   -4,  1.5, -10, 1.0f / -30 }, // "
	{ "Walk_5m",  1,   -5,  1.5,  -7, 1.0f /  40 }, // "
	{ "Walk_10m", 1,  -10,  1.5,  -5, 1.0f /  50 }, // "
	{ "Oculus",   1,   -3,  1.5, -15, 1.0f /  30 },
	{ "RotX_pos", 0,  0.5,  1.0,   0, 1.0f /  10 },
	{ "RotX_neg", 0, -0.5, -1.0,   0, 1.0f / -10 },
	{ "RotY_pos", 1,  0.5,  1.0,   0, 1.0f /  10 },
	{ "RotY_neg", 1, -0.5, -1.0,   0, 1.0f / -10 },
	{ "RotZ_pos", 2,  0.5,  1.0,   0, 1.0f /  10 },
	{ "RotZ_neg", 2, -0.5, -1.0,   0, 1.0f / -10 },
};

const int MARKER_COUNT     = 4;
const int RIGID_BODY_COUNT = sizeof(RIGID_BODY_PARAMS) / sizeof(RIGID_BODY_PARAMS[0]);
const int SKELETON_COUNT   = 0;

MoCapSimulator::MoCapSimulator() :
	initialised(false)
{
}

bool MoCapSimulator::initialise()
{
	if (!initialised)
	{
		fTime = 0;
		iFrame = 0;

		arrPos.resize(RIGID_BODY_COUNT);
		arrRot.resize(RIGID_BODY_COUNT);
		arrTrackingLostCounter.resize(RIGID_BODY_COUNT);
		for (int i = 0; i < RIGID_BODY_COUNT; i++)
		{
			arrTrackingLostCounter[i] = 0;
		}
		trackingUnreliable = false;

		LOG_INFO("Initialised");

		initialised = true;
	}
	return initialised;
}

bool MoCapSimulator::isActive()
{
	return initialised;
}

float MoCapSimulator::getUpdateRate()
{
	return _frameRate;
}

bool MoCapSimulator::update()
{
	iFrame += 1;
	fTime  += (1.0f / _frameRate);

	for (int b = 0; b < RIGID_BODY_COUNT; b++)
	{
		// calculate new positions/rotations
		float t    = fTime * RIGID_BODY_PARAMS[b].speed;
		float r    = RIGID_BODY_PARAMS[b].radius;
		float oPos = RIGID_BODY_PARAMS[b].posOffset;
		float oRot = RIGID_BODY_PARAMS[b].rotOffset;
		switch (RIGID_BODY_PARAMS[b].axis)
		{
			case 0:
			{
				arrPos[b].set(oPos, r * cos(t), r * sin(t));   // zero degrees = Y+ up
				arrRot[b].fromAxisAngle(1, 0, 0, t);
				break;
			}
			case 1:
			{
				arrPos[b].set(r * -sin(t), oPos, r * -cos(t)); // zero degrees = Z- forwards
				arrRot[b].fromAxisAngle(0, 1, 0, t);
				// apply pitch
				Quaternion rotX(1, 0, 0, oRot * (float) (M_PI / 180));
				arrRot[b] = arrRot[b].mult(rotX);
				break;
			}
			case 2:
			{
				arrPos[b].set(r * -sin(t), r * cos(t), oPos);  // zero degrees = Y+ upwards
				arrRot[b].fromAxisAngle(0, 0, 1, t);
				break;
			}
		}

		if (trackingUnreliable)
		{
			if (rand() < RAND_MAX / 1000)
			{
				arrTrackingLostCounter[b] = rand() * 100 / RAND_MAX;
			}
		}
	}

	/*
	for (int s = 0; s < SKELETON_COUNT; s++)
	{

	}
	*/

	signalNewFrame();

	return true;
}

bool MoCapSimulator::getSceneDescription(MoCapData& refData)
{
	LOG_INFO("Requesting scene description")

	int descrIdx = 0;
	for (int b = 0; b < RIGID_BODY_COUNT; b++)
	{
		// create markerset description and frame
		sMarkerSetDescription* pMarkerDesc = new sMarkerSetDescription();
		sMarkerSetData&        msData      = refData.frame.MocapData[b];

		// name of marker set
		strcpy_s(pMarkerDesc->szName, sizeof(pMarkerDesc->szName), RIGID_BODY_PARAMS[b].szName);
		strcpy_s(msData.szName,       sizeof(msData.szName),       pMarkerDesc->szName);

		// number of markers
		pMarkerDesc->nMarkers = MARKER_COUNT;
		msData.nMarkers       = MARKER_COUNT;

		// names of markers
		pMarkerDesc->szMarkerNames = new char*[MARKER_COUNT];
		msData.Markers             = new MarkerData[MARKER_COUNT];
		for (int m = 0; m < MARKER_COUNT; m++)
		{
			char czMarkerName[10];
			sprintf_s(czMarkerName, sizeof(czMarkerName), "%02d", m + 1);
			pMarkerDesc->szMarkerNames[m] = _strdup(czMarkerName);
		}

		// add to description list
		refData.description.arrDataDescriptions[descrIdx].type = Descriptor_MarkerSet;
		refData.description.arrDataDescriptions[descrIdx].Data.MarkerSetDescription = pMarkerDesc;
		descrIdx++;

		sRigidBodyDescription* pBodyDesc = new sRigidBodyDescription();
		// fill in description structure
		pBodyDesc->ID       = b; // needs to be equal to array index
		pBodyDesc->parentID = -1;
		pBodyDesc->offsetx  = 0;
		pBodyDesc->offsety  = 0;
		pBodyDesc->offsetz  = 0;
		strcpy_s(pBodyDesc->szName, sizeof(pBodyDesc->szName), pMarkerDesc->szName);

		refData.description.arrDataDescriptions[descrIdx].type = Descriptor_RigidBody;
		refData.description.arrDataDescriptions[descrIdx].Data.RigidBodyDescription = pBodyDesc;
		descrIdx++;
	}

	for (int s = 0; s < SKELETON_COUNT; s++)
	{
		sSkeletonDescription* pSkeleton = new sSkeletonDescription();
		// fill in description structure
		pSkeleton->nRigidBodies = 2;
		//strcpy_s(pSkeleton->szName, ...);

		// pre-fill in frame structure for marker sets
		sSkeletonData& skData = refData.frame.Skeletons[s];
//todo

		refData.description.arrDataDescriptions[descrIdx].type = Descriptor_Skeleton;
		refData.description.arrDataDescriptions[descrIdx].Data.SkeletonDescription = pSkeleton;
		descrIdx++;
	}

	refData.description.nDataDescriptions = descrIdx;

	// pre-fill in frame data
	refData.frame.nMarkerSets  = RIGID_BODY_COUNT;
	refData.frame.nRigidBodies = RIGID_BODY_COUNT;
	refData.frame.nSkeletons   = SKELETON_COUNT;

	refData.frame.nOtherMarkers = 0;
	refData.frame.OtherMarkers  = NULL;

	refData.frame.nLabeledMarkers = 0;

	refData.frame.nForcePlates = 0;

	refData.frame.fLatency = 0.01f; // simulate 10ms
	refData.frame.Timecode = 0;
	refData.frame.TimecodeSubframe = 0;

	return true;
}

bool MoCapSimulator::getFrameData(MoCapData& refData)
{
	refData.frame.iFrame = iFrame;

	for (int b = 0; b < RIGID_BODY_COUNT; b++)
	{
		// simulate tracking loss
		bool trackingLost = false;
		if (arrTrackingLostCounter[b] > 0)
		{
			trackingLost = true;
			arrTrackingLostCounter[b]--;
		}

		// update marker data
		sMarkerSetData& msData = refData.frame.MocapData[b];
		for (int m = 0; m < msData.nMarkers; m++)
		{
			msData.Markers[m][0] = arrPos[b].x + (rand() * 0.1f / RAND_MAX - 0.05f);
			msData.Markers[m][1] = arrPos[b].y + (rand() * 0.1f / RAND_MAX - 0.05f);
			msData.Markers[m][2] = arrPos[b].z + (rand() * 0.1f / RAND_MAX - 0.05f);
		}

		// update rigid body data
		sRigidBodyData& rbData = refData.frame.RigidBodies[b];
		rbData.ID = b;
		rbData.x  = trackingLost ? 0 : arrPos[b].x;
		rbData.y  = trackingLost ? 0 : arrPos[b].y;
		rbData.z  = trackingLost ? 0 : arrPos[b].z;
		rbData.qx = trackingLost ? 0 : arrRot[b].x;
		rbData.qy = trackingLost ? 0 : arrRot[b].y;
		rbData.qz = trackingLost ? 0 : arrRot[b].z;
		rbData.qw = trackingLost ? 0 : arrRot[b].w;

		rbData.nMarkers  = 0;
		rbData.MeanError = 0;
		rbData.params    = trackingLost ? 0x00 : 0x01; // tracking OK
	}

	return true;
}

bool MoCapSimulator::processCommand(const std::string& strCommand)
{
	bool processed = false;

	// convert commandto lowercase
	std::string strCmdLowerCase;
	std::transform(strCommand.begin(), strCommand.end(), std::back_inserter(strCmdLowerCase), ::tolower);

	if (strCmdLowerCase == "enabletrackingloss" )
	{
		trackingUnreliable = true;
		LOG_INFO("Tracking loss enabled");
		processed = true;
	}
	else if (strCmdLowerCase == "disabletrackingloss")
	{
		trackingUnreliable = false;
		LOG_INFO("Tracking loss disabled");
		processed = true;
	}

	return processed;
}

bool MoCapSimulator::deinitialise()
{
	if (initialised)
	{
		// nothing much to do here

		LOG_INFO("Deinitialised");
		initialised = false;
	}
	return !initialised;
}

MoCapSimulator::~MoCapSimulator()
{
	deinitialise();
}

<|endoftext|>


<commit_before>#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <kernel/libc.h>
#include <kernel/icxxabi.h>

#include <sys/stat.h>

#include <fcntl.h>
#include <dirent.h>

#include <kernel/assert.h>

#include <kernel/tty.h>
#include <kernel/heap.h>
#include <kernel/video.h>
#include <kernel/context.h>
#include <kernel/vga_context.h>
#include <kernel/window.h>
#include <kernel/list.h>
#include <kernel/desktop.h>
#include <kernel/ramdisk.h>
#include <kernel/fs/tar.h>
#include <kernel/fs/vfs.h>
#include <kernel/fs/initrd.h>

#include <kernel/devmanager.h>

#define _GRAPHICS 0

#include <arch/i386/idt.h>
#include <arch/i386/gdt.h>
#include <arch/i386/paging.h>
#include <arch/i386/serial.h>
#include <arch/i386/mouse.h>
#include <arch/i386/keyboard.h>

#include <arch/i386/multiboot.h>

#include <arch/i386/keyboard.h>

multiboot_info_t *mboot_info;
extern "C"
void kearly (multiboot_info_t *_mboot_info) {
	mboot_info = _mboot_info;
	init_kheap (*(uint32_t *)(mboot_info->mods_addr + 4));
}

extern "C"
void kmain (void) {
	init_gdt ();
	puts ("GDT initialized");
	init_idt ();
	puts ("IDT initialized");
	init_paging ();
	puts ("Paging initialized");

	const char *serial_test = "Hello Serial World!\n\r";
	Driver::COM1.Write (serial_test, strlen (serial_test), 0);
	puts ("Serial initialized");

	init_keyboard ();
	printf ("Keyboard initialized\n");
	init_mouse ();
	printf ("Mouse initialized\n");
	asm volatile ("sti");

	puts ("\nWelcome to ChronOS, well, the kernel to be more specific.");

	DeviceManager::devman->ListDevices ();

	/*auto *ramdisk = new Driver::Ramdisk (4, "initrd", (void *) *(uint32_t *)(mboot_info->mods_addr));
	auto *tar = FileSystem::Tar::Parse (ramdisk);*/

	auto *initrd = new FileSystem::Initrd ("/");
	VFS::InitVFS (initrd);

	mkdir ("/boot", 0777);
	mkdir ("/dev", 0777);

	struct stat bootst;
	struct stat devst;

	stat ("/boot", &bootst);
	stat ("/dev", &devst);

	assert (S_ISDIR (bootst.st_mode));
	assert (S_ISDIR (devst.st_mode));

	/*int file = open ("/greet.txt", O_RDONLY);

	if (file == -1)
		puts ("Could not open /greet.txt");
	else
		printf ("/greet.txt open in fd: %d\n", file);

	struct stat st;
	stat ("/", &st);
	assert (S_ISDIR(st.st_mode));
	stat ("/greet.txt", &st);
	assert (S_ISREG(st.st_mode));

	assert (false);*/

	/*DIR *root = opendir ("/");
	struct dirent *et = readdir (root);
	printf ("First file name: %s\n", et->name);*/

#if _GRAPHICS == 1
	Desktop *desktop = new Desktop (new VGAContext (3, "vga"));
	desktop->CreateWindow (10, 10, 80, 50);
	desktop->CreateWindow (100, 50, 50, 60);
	desktop->CreateWindow (200, 100, 50, 50);

	while (true) {
		desktop->update_mouse (mouse_x, mouse_y, mouse_left);
	}

#endif

	__cxa_finalize (0);

	for (;;) asm ("hlt");
}
<commit_msg>Fixed a quick thing.<commit_after>#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <kernel/libc.h>
#include <kernel/icxxabi.h>

#include <sys/stat.h>

#include <fcntl.h>
#include <dirent.h>

#include <kernel/assert.h>

#include <kernel/tty.h>
#include <kernel/heap.h>
#include <kernel/video.h>
#include <kernel/context.h>
#include <kernel/vga_context.h>
#include <kernel/window.h>
#include <kernel/list.h>
#include <kernel/desktop.h>
#include <kernel/ramdisk.h>
#include <kernel/fs/tar.h>
#include <kernel/fs/vfs.h>
#include <kernel/fs/initrd.h>

#include <kernel/devmanager.h>

#define _GRAPHICS 0

#include <arch/i386/idt.h>
#include <arch/i386/gdt.h>
#include <arch/i386/paging.h>
#include <arch/i386/serial.h>
#include <arch/i386/mouse.h>
#include <arch/i386/keyboard.h>

#include <arch/i386/multiboot.h>

#include <arch/i386/keyboard.h>

multiboot_info_t *mboot_info;
extern "C"
void kearly (multiboot_info_t *_mboot_info) {
	mboot_info = _mboot_info;
	init_kheap (*(uint32_t *)(mboot_info->mods_addr + 4));
}

extern "C"
void kmain (void) {
	init_gdt ();
	puts ("GDT initialized");
	init_idt ();
	puts ("IDT initialized");
	init_paging ();
	puts ("Paging initialized");

	const char *serial_test = "Hello Serial World!\n\r";
	Driver::COM1.Write (serial_test, strlen (serial_test), 0);
	puts ("Serial initialized");

	init_keyboard ();
	printf ("Keyboard initialized\n");
	init_mouse ();
	printf ("Mouse initialized\n");
	asm volatile ("sti");

	puts ("\nWelcome to ChronOS, well, the kernel to be more specific.");

	DeviceManager::devman->ListDevices ();

	/*auto *ramdisk = new Driver::Ramdisk (4, "initrd", (void *) *(uint32_t *)(mboot_info->mods_addr));
	auto *tar = FileSystem::Tar::Parse (ramdisk);*/

	auto *initrd = new FileSystem::Initrd ("/");
	VFS::InitVFS (initrd);

	mkdir ("/boot", 0777);
	mkdir ("/dev", 0777);

	struct stat bootst;
	struct stat devst;

	stat ("/boot", &bootst);
	stat ("/dev", &devst);

	assert (S_ISDIR (bootst.st_mode));
	assert (S_ISDIR (devst.st_mode));

	/*int file = open ("/greet.txt", O_RDONLY);

	if (file == -1)
		puts ("Could not open /greet.txt");
	else
		printf ("/greet.txt open in fd: %d\n", file);

	struct stat st;
	stat ("/", &st);
	assert (S_ISDIR(st.st_mode));
	stat ("/greet.txt", &st);
	assert (S_ISREG(st.st_mode));

	assert (false);*/

	/*DIR *root = opendir ("/");
	struct dirent *et = readdir (root);
	printf ("First file name: %s\n", et->name);*/

#if _GRAPHICS == 1
	Desktop *desktop = new Desktop (new VGAContext ("vga"));
	desktop->CreateWindow (10, 10, 80, 50);
	desktop->CreateWindow (100, 50, 50, 60);
	desktop->CreateWindow (200, 100, 50, 50);

	while (true) {
		desktop->update_mouse (mouse_x, mouse_y, mouse_left);
	}

#endif

	__cxa_finalize (0);

	for (;;) asm ("hlt");
}
<|endoftext|>


<commit_before>// Sample code to train the encoder-decoder model using small English-Japanese
// parallel corpora.
//
// Model detail:
//   Sutskever et al., 2014.
//   Sequence to Sequence Learning with Neural Networks.
//   https://arxiv.org/abs/1409.3215
//
// Corpora detail:
//   https://github.com/odashi/small_parallel_enja
//
// Usage:
//   Run 'download_data.sh' in the same directory before using this code.
// g++
//   -std=c++11
//   -I/path/to/primitiv/includes (typically -I../..)
//   -L/path/to/primitiv/libs     (typically -L../../build/primitiv)
//   encdec.cc -lprimitiv

#include <algorithm>
#include <fstream>
#include <iostream>
#include <random>
#include <string>
#include <utility>
#include <vector>

#include <primitiv/primitiv.h>
#include <primitiv/primitiv_cuda.h>

using primitiv::trainers::Adam;
namespace F = primitiv::node_ops;
namespace I = primitiv::initializers;
using namespace primitiv;
using namespace std;

namespace {

static const unsigned NUM_EMBED_UNITS = 512;
static const unsigned NUM_HIDDEN_UNITS = 512;
static const unsigned BATCH_SIZE = 64;
static const unsigned MAX_EPOCH = 100;
static const float DROPOUT_RATE = 0.5;

// Gathers the set of words from space-separated corpus.
unordered_map<string, unsigned> make_vocab(const string &filename) {
  ifstream ifs(filename);
  if (!ifs.is_open()) {
    cerr << "File could not be opened: " << filename << endl;
    exit(1);
  }
  unordered_map<string, unsigned> vocab;
  vocab.emplace(make_pair("<unk>", 0));
  string line, word;
  while (getline(ifs, line)) {
    line = "<s> " + line + " <s>";
    stringstream ss(line);
    while (getline(ss, word, ' ')) {
      if (vocab.find(word) == vocab.end()) {
        const unsigned id = vocab.size();
        vocab.emplace(make_pair(word, id));
      }
    }
  }
  return vocab;
}

// Generates word ID list using corpus and vocab.
vector<vector<unsigned>> load_corpus(
    const string &filename, const unordered_map<string, unsigned> &vocab) {
  ifstream ifs(filename);
  if (!ifs.is_open()) {
    cerr << "File could not be opened: " << filename << endl;
    exit(1);
  }
  vector<vector<unsigned>> corpus;
  string line, word;
  while (getline(ifs, line)) {
    line = "<s> " + line + " <s>";
    stringstream ss (line);
    vector<unsigned> sentence;
    while (getline(ss, word, ' ')) {
      const auto it = vocab.find(word);
      if (it != vocab.end()) sentence.emplace_back(it->second);
      else sentence.emplace_back(0);  // <unk>
    }
    corpus.emplace_back(move(sentence));
  }
  return corpus;
}

// Counts output labels in the corpus.
unsigned count_labels(const vector<vector<unsigned>> &corpus) {
  unsigned ret = 0;
  for (const auto &sent :corpus) ret += sent.size() - 1;
  return ret;
}

// Extracts a minibatch from loaded corpus
vector<vector<unsigned>> make_batch(
    const vector<vector<unsigned>> &corpus,
    const vector<unsigned> &sent_ids,
    unsigned eos_id) {
  const unsigned batch_size = sent_ids.size();
  unsigned max_len = 0;
  for (const unsigned sid : sent_ids) {
    max_len = std::max<unsigned>(max_len, corpus[sid].size());
  }
  vector<vector<unsigned>> batch(max_len, vector<unsigned>(batch_size, eos_id));
  for (unsigned i = 0; i < batch_size; ++i) {
    const auto &sent = corpus[sent_ids[i]];
    for (unsigned j = 0; j < sent.size(); ++j) {
      batch[j][i] = sent[j];
    }
  }
  return batch;
}

// Hand-written LSTM with input/forget/output gates and no peepholes.
// Formulation:
//   i = sigmoid(W_xi . x[t] + W_hi . h[t-1] + b_i)
//   f = sigmoid(W_xf . x[t] + W_hf . h[t-1] + b_f)
//   o = sigmoid(W_xo . x[t] + W_ho . h[t-1] + b_o)
//   j = tanh   (W_xj . x[t] + W_hj . h[t-1] + b_j)
//   c[t] = i * j + f * c[t-1]
//   h[t] = o * tanh(c[t])
class LSTM {
  public:
    LSTM(const string &name,
        unsigned in_size, unsigned out_size, Trainer &trainer)
      : out_size_(out_size)
      , pwxh_(name + "_wxh", {4 * out_size, in_size}, I::XavierUniform())
      , pwhh_(name + "_whh", {4 * out_size, out_size}, I::XavierUniform())
      , pbh_(name + "_bh", {4 * out_size}, I::Constant(0)) {
        trainer.add_parameter(pwxh_);
        trainer.add_parameter(pwhh_);
        trainer.add_parameter(pbh_);
      }

    // Initializes internal values.
    void init(const Node &init_c = Node()) {
      wxh_ = F::input(pwxh_);
      whh_ = F::input(pwhh_);
      bh_ = F::input(pbh_);
      if (!init_c.valid()) {
        h_ = c_ = F::zeros({out_size_});
      } else {
        c_ = init_c;
        h_ = F::tanh(c_);
      }
    }

    // Forward one step.
    Node forward(const Node &x) {
      const Node u = F::matmul(wxh_, x) + F::matmul(whh_, h_) + bh_;
      const Node i = F::sigmoid(F::slice(u, 0, 0, out_size_));
      const Node f = F::sigmoid(F::slice(u, 0, out_size_, 2 * out_size_));
      const Node o = F::sigmoid(F::slice(u, 0, 2 * out_size_, 3 * out_size_));
      const Node j = F::tanh(F::slice(u, 0, 3 * out_size_, 4 * out_size_));
      c_ = i * j + f * c_;
      h_ = o * F::tanh(c_);
      return h_;
    }

    // Retrieves current cell.
    Node get_cell() const { return c_; }

  private:
    unsigned out_size_;
    Parameter pwxh_, pwhh_, pbh_;
    Node wxh_, whh_, bh_, h_, c_;
};

// Encoder-decoder translation model.
class EncoderDecoder {
public:
  EncoderDecoder(unsigned src_vocab_size, unsigned trg_vocab_size,
      unsigned embed_size, unsigned hidden_size, Trainer &trainer)
    : psrc_lookup_(
        "src_lookup", {embed_size, src_vocab_size}, I::XavierUniform())
    , ptrg_lookup_(
        "trg_lookup", {embed_size, trg_vocab_size}, I::XavierUniform())
    , pwhy_("why", {trg_vocab_size, hidden_size}, I::XavierUniform())
    , pby_("by", {trg_vocab_size}, I::Constant(0))
    , src_lstm_("src_lstm", embed_size, hidden_size, trainer)
    , trg_lstm_("trg_lstm", embed_size, hidden_size, trainer) {
      trainer.add_parameter(psrc_lookup_);
      trainer.add_parameter(ptrg_lookup_);
      trainer.add_parameter(pwhy_);
      trainer.add_parameter(pby_);
    }

  // Forward function for training encoder-decoder. Both source and target data
  // should be arranged as:
  // src_tokens, trg_tokens = {
  //   {sent1_word1, sent2_word1, ..., sentN_word1},  // 1st token (<s>)
  //   {sent1_word2, sent2_word2, ..., sentN_word2},  // 2nd token (first word)
  //   ...,
  //   {sent1_wordM, sent2_wordM, ..., sentN_wordM},  // last token (<s>)
  // };
  Node forward_loss(
      const vector<vector<unsigned>> &src_tokens,
      const vector<vector<unsigned>> &trg_tokens,
      bool train) {
    Node src_lookup = F::input(psrc_lookup_);
    Node trg_lookup = F::input(ptrg_lookup_);
    Node why = F::input(pwhy_);
    Node by = F::input(pby_);

    // Reversed encoding (w/o first <s>)
    src_lstm_.init();
    for (unsigned i = src_tokens.size(); i > 1; --i) {
      Node x = F::pick(src_lookup, 1, src_tokens[i - 1]);
      x = F::dropout(x, DROPOUT_RATE, train);
      src_lstm_.forward(x);
    }

    // Decoding
    vector<Node> losses;
    trg_lstm_.init(src_lstm_.get_cell());
    for (unsigned i = 0; i < trg_tokens.size() - 1; ++i) {
      Node x = F::pick(trg_lookup, 1, trg_tokens[i]);
      x = F::dropout(x, DROPOUT_RATE, train);
      Node h = trg_lstm_.forward(x);
      h = F::dropout(h, DROPOUT_RATE, train);
      Node y = F::matmul(why, h) + by;
      losses.emplace_back(F::softmax_cross_entropy(y, 0, trg_tokens[i + 1]));
    }

    return F::batch::mean(F::sum(losses));
  }

private:
  Parameter psrc_lookup_, ptrg_lookup_, pwhy_, pby_;
  ::LSTM src_lstm_, trg_lstm_;
};

}  // namespace

int main() {
  // Loads vocab.
  const auto src_vocab = ::make_vocab("data/train.en");
  const auto trg_vocab = ::make_vocab("data/train.ja");
  cout << "#src_vocab: " << src_vocab.size() << endl;
  cout << "#trg_vocab: " << trg_vocab.size() << endl;
  const unsigned src_eos_id = src_vocab.at("<s>");
  const unsigned trg_eos_id = trg_vocab.at("<s>");

  // Loads all corpus.
  const auto train_src_corpus = ::load_corpus("data/train.en", src_vocab);
  const auto train_trg_corpus = ::load_corpus("data/train.ja", trg_vocab);
  const auto valid_src_corpus = ::load_corpus("data/dev.en", src_vocab);
  const auto valid_trg_corpus = ::load_corpus("data/dev.ja", trg_vocab);
  const unsigned num_train_sents = train_trg_corpus.size();
  const unsigned num_valid_sents = valid_trg_corpus.size();
  const unsigned num_train_labels = ::count_labels(train_trg_corpus);
  const unsigned num_valid_labels = ::count_labels(valid_trg_corpus);
  cout << "train: " << num_train_sents << " sentences, "
                    << num_train_labels << " labels" << endl;
  cout << "valid: " << num_valid_sents << " sentences, "
                    << num_valid_labels << " labels" << endl;

  // Uses GPU.
  CUDADevice dev(0);
  Device::set_default_device(dev);

  // Trainer.
  Adam trainer;
  trainer.set_weight_decay(1e-6);
  trainer.set_gradient_clipping(5);

  // Our translation model.
  ::EncoderDecoder encdec(
      src_vocab.size(), trg_vocab.size(),
      NUM_EMBED_UNITS, NUM_HIDDEN_UNITS, trainer);

  // Batch randomizer.
  random_device rd;
  mt19937 rng(rd());

  // Sentence IDs.
  vector<unsigned> train_ids(num_train_sents);
  vector<unsigned> valid_ids(num_valid_sents);
  iota(begin(train_ids), end(train_ids), 0);
  iota(begin(valid_ids), end(valid_ids), 0);

  // Train/valid loop.
  for (unsigned epoch = 0; epoch < MAX_EPOCH; ++epoch) {
    cout << "epoch " << (epoch + 1) << '/' << MAX_EPOCH << ':' << endl;
    // Shuffles train sentence IDs.
    shuffle(begin(train_ids), end(train_ids), rng);

    // Training.
    float train_loss = 0;
    for (unsigned ofs = 0; ofs < num_train_sents; ofs += BATCH_SIZE) {
      const vector<unsigned> batch_ids(
          begin(train_ids) + ofs,
          begin(train_ids) + std::min<unsigned>(
            ofs + BATCH_SIZE, num_train_sents));
      const auto src_batch = ::make_batch(
          train_src_corpus, batch_ids, src_eos_id);
      const auto trg_batch = ::make_batch(
          train_trg_corpus, batch_ids, trg_eos_id);
      trainer.reset_gradients();
      Graph g;
      Graph::set_default_graph(g);
      const auto loss = encdec.forward_loss(src_batch, trg_batch, true);
      train_loss += g.forward(loss).to_vector()[0] * batch_ids.size();
      g.backward(loss);
      trainer.update(1);
      cout << ofs << '\r' << flush;
    }
    const float train_ppl = std::exp(train_loss / num_train_labels);
    cout << "  train ppl = " << train_ppl << endl;

    // Validation.
    float valid_loss = 0;
    for (unsigned ofs = 0; ofs < num_valid_sents; ofs += BATCH_SIZE) {
      const vector<unsigned> batch_ids(
          begin(valid_ids) + ofs,
          begin(valid_ids) + std::min<unsigned>(
            ofs + BATCH_SIZE, num_valid_sents));
      const auto src_batch = ::make_batch(
          valid_src_corpus, batch_ids, src_eos_id);
      const auto trg_batch = ::make_batch(
          valid_trg_corpus, batch_ids, trg_eos_id);
      Graph g;
      Graph::set_default_graph(g);
      const auto loss = encdec.forward_loss(src_batch, trg_batch, false);
      valid_loss += g.forward(loss).to_vector()[0] * batch_ids.size();
      cout << ofs << '\r' << flush;
    }
    const float valid_ppl = std::exp(valid_loss / num_valid_labels);
    cout << "  valid ppl = " << valid_ppl << endl;
  }

  return 0;
}
<commit_msg>add frequency filter of vocabulary.<commit_after>// Sample code to train the encoder-decoder model using small English-Japanese
// parallel corpora.
//
// Model detail:
//   Sutskever et al., 2014.
//   Sequence to Sequence Learning with Neural Networks.
//   https://arxiv.org/abs/1409.3215
//
// Corpora detail:
//   https://github.com/odashi/small_parallel_enja
//
// Usage:
//   Run 'download_data.sh' in the same directory before using this code.
// g++
//   -std=c++11
//   -I/path/to/primitiv/includes (typically -I../..)
//   -L/path/to/primitiv/libs     (typically -L../../build/primitiv)
//   encdec.cc -lprimitiv

#include <algorithm>
#include <fstream>
#include <iostream>
#include <queue>
#include <random>
#include <sstream>
#include <string>
#include <utility>
#include <vector>

#include <primitiv/primitiv.h>
#include <primitiv/primitiv_cuda.h>

using primitiv::trainers::Adam;
namespace F = primitiv::node_ops;
namespace I = primitiv::initializers;
using namespace primitiv;
using namespace std;

namespace {

static const unsigned NUM_EMBED_UNITS = 512;
static const unsigned NUM_HIDDEN_UNITS = 512;
static const unsigned BATCH_SIZE = 64;
static const unsigned MAX_EPOCH = 100;
static const float DROPOUT_RATE = 0.5;

// Gathers the set of words from space-separated corpus.
unordered_map<string, unsigned> make_vocab(
    const string &filename, unsigned size) {
  if (size < 3) {
    cerr << "vocab size should be equal-to or grater-than 3." << endl;
    exit(1);
  }
  ifstream ifs(filename);
  if (!ifs.is_open()) {
    cerr << "File could not be opened: " << filename << endl;
    exit(1);
  }
  unordered_map<string, unsigned> freq;
  string line, word;
  while (getline(ifs, line)) {
    stringstream ss(line);
    while (getline(ss, word, ' ')) ++freq[word];
  }
  using freq_t = pair<string, unsigned>;
  auto cmp = [](const freq_t &a, const freq_t &b) {
    return a.second < b.second;
  };
  priority_queue<freq_t, vector<freq_t>, decltype(cmp)> q(cmp);
  for (const auto &x : freq) q.push(x);

  unordered_map<string, unsigned> vocab;
  vocab.insert(make_pair("<unk>", 0));
  vocab.insert(make_pair("<bos>", 1));
  vocab.insert(make_pair("<eos>", 2));
  for (unsigned i = 3; i < size; ++i) {
    vocab.insert(make_pair(q.top().first, i));
    q.pop();
  }

  return vocab;
}

// Generates word ID list using corpus and vocab.
vector<vector<unsigned>> load_corpus(
    const string &filename, const unordered_map<string, unsigned> &vocab) {
  ifstream ifs(filename);
  if (!ifs.is_open()) {
    cerr << "File could not be opened: " << filename << endl;
    exit(1);
  }
  vector<vector<unsigned>> corpus;
  string line, word;
  while (getline(ifs, line)) {
    line = "<bos> " + line + " <eos>";
    stringstream ss (line);
    vector<unsigned> sentence;
    while (getline(ss, word, ' ')) {
      const auto it = vocab.find(word);
      if (it != vocab.end()) sentence.emplace_back(it->second);
      else sentence.emplace_back(0);  // <unk>
    }
    corpus.emplace_back(move(sentence));
  }
  return corpus;
}

// Counts output labels in the corpus.
unsigned count_labels(const vector<vector<unsigned>> &corpus) {
  unsigned ret = 0;
  for (const auto &sent :corpus) ret += sent.size() - 1;  // w/o <bos>
  return ret;
}

// Extracts a minibatch from loaded corpus
vector<vector<unsigned>> make_batch(
    const vector<vector<unsigned>> &corpus,
    const vector<unsigned> &sent_ids,
    unsigned eos_id) {
  const unsigned batch_size = sent_ids.size();
  unsigned max_len = 0;
  for (const unsigned sid : sent_ids) {
    max_len = std::max<unsigned>(max_len, corpus[sid].size());
  }
  vector<vector<unsigned>> batch(max_len, vector<unsigned>(batch_size, eos_id));
  for (unsigned i = 0; i < batch_size; ++i) {
    const auto &sent = corpus[sent_ids[i]];
    for (unsigned j = 0; j < sent.size(); ++j) {
      batch[j][i] = sent[j];
    }
  }
  return batch;
}

// Hand-written LSTM with input/forget/output gates and no peepholes.
// Formulation:
//   i = sigmoid(W_xi . x[t] + W_hi . h[t-1] + b_i)
//   f = sigmoid(W_xf . x[t] + W_hf . h[t-1] + b_f)
//   o = sigmoid(W_xo . x[t] + W_ho . h[t-1] + b_o)
//   j = tanh   (W_xj . x[t] + W_hj . h[t-1] + b_j)
//   c[t] = i * j + f * c[t-1]
//   h[t] = o * tanh(c[t])
class LSTM {
  public:
    LSTM(const string &name,
        unsigned in_size, unsigned out_size, Trainer &trainer)
      : out_size_(out_size)
      , pwxh_(name + "_wxh", {4 * out_size, in_size}, I::XavierUniform())
      , pwhh_(name + "_whh", {4 * out_size, out_size}, I::XavierUniform())
      , pbh_(name + "_bh", {4 * out_size}, I::Constant(0)) {
        trainer.add_parameter(pwxh_);
        trainer.add_parameter(pwhh_);
        trainer.add_parameter(pbh_);
      }

    // Initializes internal values.
    void init(const Node &init_c = Node()) {
      wxh_ = F::input(pwxh_);
      whh_ = F::input(pwhh_);
      bh_ = F::input(pbh_);
      if (!init_c.valid()) {
        h_ = c_ = F::zeros({out_size_});
      } else {
        c_ = init_c;
        h_ = F::tanh(c_);
      }
    }

    // Forward one step.
    Node forward(const Node &x) {
      const Node u = F::matmul(wxh_, x) + F::matmul(whh_, h_) + bh_;
      const Node i = F::sigmoid(F::slice(u, 0, 0, out_size_));
      const Node f = F::sigmoid(F::slice(u, 0, out_size_, 2 * out_size_));
      const Node o = F::sigmoid(F::slice(u, 0, 2 * out_size_, 3 * out_size_));
      const Node j = F::tanh(F::slice(u, 0, 3 * out_size_, 4 * out_size_));
      c_ = i * j + f * c_;
      h_ = o * F::tanh(c_);
      return h_;
    }

    // Retrieves current cell.
    Node get_cell() const { return c_; }

  private:
    unsigned out_size_;
    Parameter pwxh_, pwhh_, pbh_;
    Node wxh_, whh_, bh_, h_, c_;
};

// Encoder-decoder translation model.
class EncoderDecoder {
public:
  EncoderDecoder(unsigned src_vocab_size, unsigned trg_vocab_size,
      unsigned embed_size, unsigned hidden_size, Trainer &trainer)
    : psrc_lookup_(
        "src_lookup", {embed_size, src_vocab_size}, I::XavierUniform())
    , ptrg_lookup_(
        "trg_lookup", {embed_size, trg_vocab_size}, I::XavierUniform())
    , pwhy_("why", {trg_vocab_size, hidden_size}, I::XavierUniform())
    , pby_("by", {trg_vocab_size}, I::Constant(0))
    , src_lstm_("src_lstm", embed_size, hidden_size, trainer)
    , trg_lstm_("trg_lstm", embed_size, hidden_size, trainer) {
      trainer.add_parameter(psrc_lookup_);
      trainer.add_parameter(ptrg_lookup_);
      trainer.add_parameter(pwhy_);
      trainer.add_parameter(pby_);
    }

  // Forward function for training encoder-decoder. Both source and target data
  // should be arranged as:
  // src_tokens, trg_tokens = {
  //   {sent1_word1, sent2_word1, ..., sentN_word1},  // 1st token (<bos>)
  //   {sent1_word2, sent2_word2, ..., sentN_word2},  // 2nd token (first word)
  //   ...,
  //   {sent1_wordM, sent2_wordM, ..., sentN_wordM},  // last token (<eos>)
  // };
  Node forward_loss(
      const vector<vector<unsigned>> &src_tokens,
      const vector<vector<unsigned>> &trg_tokens,
      bool train) {
    Node src_lookup = F::input(psrc_lookup_);
    Node trg_lookup = F::input(ptrg_lookup_);
    Node why = F::input(pwhy_);
    Node by = F::input(pby_);

    // Reversed encoding
    src_lstm_.init();
    for (unsigned i = src_tokens.size(); i > 0; --i) {
      Node x = F::pick(src_lookup, 1, src_tokens[i - 1]);
      x = F::dropout(x, DROPOUT_RATE, train);
      src_lstm_.forward(x);
    }

    // Decoding
    vector<Node> losses;
    trg_lstm_.init(src_lstm_.get_cell());
    for (unsigned i = 0; i < trg_tokens.size() - 1; ++i) {
      Node x = F::pick(trg_lookup, 1, trg_tokens[i]);
      x = F::dropout(x, DROPOUT_RATE, train);
      Node h = trg_lstm_.forward(x);
      h = F::dropout(h, DROPOUT_RATE, train);
      Node y = F::matmul(why, h) + by;
      losses.emplace_back(F::softmax_cross_entropy(y, 0, trg_tokens[i + 1]));
    }

    return F::batch::mean(F::sum(losses));
  }

private:
  Parameter psrc_lookup_, ptrg_lookup_, pwhy_, pby_;
  ::LSTM src_lstm_, trg_lstm_;
};

}  // namespace

int main() {
  // Loads vocab.
  const auto src_vocab = ::make_vocab("data/train.en", 4000);
  const auto trg_vocab = ::make_vocab("data/train.ja", 5000);
  cout << "#src_vocab: " << src_vocab.size() << endl;
  cout << "#trg_vocab: " << trg_vocab.size() << endl;
  const unsigned src_eos_id = src_vocab.at("<eos>");
  const unsigned trg_eos_id = trg_vocab.at("<eos>");

  // Loads all corpus.
  const auto train_src_corpus = ::load_corpus("data/train.en", src_vocab);
  const auto train_trg_corpus = ::load_corpus("data/train.ja", trg_vocab);
  const auto valid_src_corpus = ::load_corpus("data/dev.en", src_vocab);
  const auto valid_trg_corpus = ::load_corpus("data/dev.ja", trg_vocab);
  const unsigned num_train_sents = train_trg_corpus.size();
  const unsigned num_valid_sents = valid_trg_corpus.size();
  const unsigned num_train_labels = ::count_labels(train_trg_corpus);
  const unsigned num_valid_labels = ::count_labels(valid_trg_corpus);
  cout << "train: " << num_train_sents << " sentences, "
                    << num_train_labels << " labels" << endl;
  cout << "valid: " << num_valid_sents << " sentences, "
                    << num_valid_labels << " labels" << endl;

  // Uses GPU.
  CUDADevice dev(0);
  Device::set_default_device(dev);

  // Trainer.
  Adam trainer;
  trainer.set_weight_decay(1e-6);
  trainer.set_gradient_clipping(5);

  // Our translation model.
  ::EncoderDecoder encdec(
      src_vocab.size(), trg_vocab.size(),
      NUM_EMBED_UNITS, NUM_HIDDEN_UNITS, trainer);

  // Batch randomizer.
  random_device rd;
  mt19937 rng(rd());

  // Sentence IDs.
  vector<unsigned> train_ids(num_train_sents);
  vector<unsigned> valid_ids(num_valid_sents);
  iota(begin(train_ids), end(train_ids), 0);
  iota(begin(valid_ids), end(valid_ids), 0);

  // Train/valid loop.
  for (unsigned epoch = 0; epoch < MAX_EPOCH; ++epoch) {
    cout << "epoch " << (epoch + 1) << '/' << MAX_EPOCH << ':' << endl;
    // Shuffles train sentence IDs.
    shuffle(begin(train_ids), end(train_ids), rng);

    // Training.
    float train_loss = 0;
    for (unsigned ofs = 0; ofs < num_train_sents; ofs += BATCH_SIZE) {
      const vector<unsigned> batch_ids(
          begin(train_ids) + ofs,
          begin(train_ids) + std::min<unsigned>(
            ofs + BATCH_SIZE, num_train_sents));
      const auto src_batch = ::make_batch(
          train_src_corpus, batch_ids, src_eos_id);
      const auto trg_batch = ::make_batch(
          train_trg_corpus, batch_ids, trg_eos_id);
      trainer.reset_gradients();
      Graph g;
      Graph::set_default_graph(g);
      const auto loss = encdec.forward_loss(src_batch, trg_batch, true);
      train_loss += g.forward(loss).to_vector()[0] * batch_ids.size();
      g.backward(loss);
      trainer.update(1);
      cout << ofs << '\r' << flush;
    }
    const float train_ppl = std::exp(train_loss / num_train_labels);
    cout << "  train ppl = " << train_ppl << endl;

    // Validation.
    float valid_loss = 0;
    for (unsigned ofs = 0; ofs < num_valid_sents; ofs += BATCH_SIZE) {
      const vector<unsigned> batch_ids(
          begin(valid_ids) + ofs,
          begin(valid_ids) + std::min<unsigned>(
            ofs + BATCH_SIZE, num_valid_sents));
      const auto src_batch = ::make_batch(
          valid_src_corpus, batch_ids, src_eos_id);
      const auto trg_batch = ::make_batch(
          valid_trg_corpus, batch_ids, trg_eos_id);
      Graph g;
      Graph::set_default_graph(g);
      const auto loss = encdec.forward_loss(src_batch, trg_batch, false);
      valid_loss += g.forward(loss).to_vector()[0] * batch_ids.size();
      cout << ofs << '\r' << flush;
    }
    const float valid_ppl = std::exp(valid_loss / num_valid_labels);
    cout << "  valid ppl = " << valid_ppl << endl;
  }

  return 0;
}
<|endoftext|>


<commit_before>/*********************************************************************************
 *
 * Inviwo - Interactive Visualization Workshop
 *
 * Copyright (c) 2013-2017 Inviwo Foundation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * 2. 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.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *********************************************************************************/

#include "textoverlaygl.h"
#include <modules/fontrendering/util/fontutils.h>

#include <inviwo/core/common/inviwoapplication.h>
#include <inviwo/core/datastructures/image/image.h>
#include <inviwo/core/util/filesystem.h>
#include <modules/opengl/inviwoopengl.h>
#include <modules/opengl/texture/textureutils.h>
#include <modules/opengl/openglutils.h>
#include <modules/opengl/shader/shaderutils.h>
#include <modules/opengl/image/imagegl.h>
#include <inviwo/core/util/assertion.h>

#include <cctype>
#include <locale>

namespace inviwo {

const ProcessorInfo TextOverlayGL::processorInfo_{
    "org.inviwo.TextOverlayGL",  // Class identifier
    "Text Overlay",              // Display name
    "Drawing",                   // Category
    CodeState::Stable,           // Code state
    Tags::GL,                    // Tags
};
const ProcessorInfo TextOverlayGL::getProcessorInfo() const {
    return processorInfo_;
}

TextOverlayGL::TextOverlayGL()
    : Processor()
    , inport_("inport")
    , outport_("outport")
    , enable_("enable","Enabled",true)
    , text_("Text", "Text", "Lorem ipsum etc.", InvalidationLevel::InvalidOutput,
            PropertySemantics::TextEditor)
    , color_("color_", "Color", vec4(1.0f), vec4(0.0f), vec4(1.0f), vec4(0.01f),
                  InvalidationLevel::InvalidOutput, PropertySemantics::Color)
    , fontFace_("fontFace", "Font Face")
    , fontSize_("fontSize", "Font size")
    , fontPos_("Position", "Position", vec2(0.0f), vec2(0.0f), vec2(1.0f), vec2(0.01f))
    , anchorPos_("Anchor", "Anchor", vec2(-1.0f), vec2(-1.0f), vec2(1.0f), vec2(0.01f))
    , addArgButton_("addArgBtn", "Add String Argument")
    , numArgs_(0u)
{
    addPort(inport_);
    addPort(outport_);
    addProperty(enable_);
    addProperty(text_);
    addProperty(color_);
    addProperty(fontFace_);
    addProperty(fontPos_);
    addProperty(anchorPos_);
    addProperty(fontSize_);
    addProperty(addArgButton_);

    addArgButton_.onChange([this]() {
        if (numArgs_ >= maxNumArgs_) {
            addArgButton_.setReadOnly(numArgs_ >= maxNumArgs_);
            return;
        }
        ++numArgs_;
        std::string num = std::to_string(numArgs_);
        auto property = new StringProperty(std::string("arg") + num, "Arg " + num);
        property->setSerializationMode(PropertySerializationMode::All);
        addProperty(property, true);
    });

    auto fonts = util::getAvailableFonts();

    for (auto font : fonts) {
        auto identifier = filesystem::getFileNameWithoutExtension(font.second);
        // use the file name w/o extension as identifier
        fontFace_.addOption(identifier, font.first, font.second);
    }
    fontFace_.setSelectedIdentifier("arial");
    fontFace_.setCurrentStateAsDefault();

    // set up different font sizes
    std::vector<int> fontSizes ={ 8, 10, 11, 12, 14, 16, 20, 24, 28, 36, 48, 60, 72, 96 };
    for (auto size : fontSizes) {
        std::string str = std::to_string(size);
        fontSize_.addOption(str, str, size);
    }
    fontSize_.setSelectedIndex(4);
    fontSize_.setCurrentStateAsDefault();
}

void TextOverlayGL::process() {
    if (!enable_.get()) {
        outport_.setData(inport_.getData());
        return;
    }

    if (fontFace_.isModified()) {
        textRenderer_.setFont(fontFace_.get());
    }

    // check whether a property was modified
    if (!cacheTexture_ ||
        util::any_of(getProperties(), [](const auto& p) { return p->isModified(); })) {
        updateCache();
    }

    // draw cached overlay on top of the input image
    utilgl::activateTargetAndCopySource(outport_, inport_, ImageType::ColorDepthPicking);
    utilgl::DepthFuncState depthFunc(GL_ALWAYS);
    utilgl::BlendModeState blending(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    // use integer position for best results
    vec2 size(cacheTexture_->getDimensions());
    vec2 shift = 0.5f * size * (anchorPos_.get() + vec2(1.0f, 1.0f));

    ivec2 pos(fontPos_.get() * vec2(outport_.getDimensions()));
    pos -= ivec2(shift);
    // render texture containing the text onto the current canvas
    textureRenderer_.render(cacheTexture_, pos, outport_.getDimensions());

    utilgl::deactivateCurrentTarget();
}

void TextOverlayGL::deserialize(Deserializer & d) {
    Processor::deserialize(d);
    // update the number of place markers properties using the total number of string properties in
    // this processor. Note that this number is one element larger.
    auto args = this->getPropertiesByType<StringProperty>(false);
    numArgs_ = args.size() - 1;

    // only maxNumArgs_ are supported, disable button if more exist
    addArgButton_.setReadOnly(numArgs_ > maxNumArgs_);
}

std::string TextOverlayGL::getString() const {
    std::string str = text_.get();
    // replace all occurrences of place markers with the corresponding args
    auto args = this->getPropertiesByType<StringProperty>(false);
    // remove default text string property
    util::erase_remove_if(args, [this](const auto& p) { return p == &text_; });
    ivwAssert(numArgs_ == args.size(),
              "TextOverlayGL: number arguments not matching internal count");

    // parse string for all "%" and try to extract the number following the percent sign
    bool printWarning = false;

    std::string matchStr("%");
    for (std::size_t offset = str.find(matchStr, 0u); offset != std::string::npos;
         offset = str.find(matchStr, offset)) {
        // extract number substring,
        // read 3 characters to ensure that the number only has at most 2 digits
        std::string numStr = str.substr(offset + 1, 3);
        if (std::isdigit(numStr[0])) {
            std::size_t numDigits = 0;
            // extract number and reduce it by one since the %args start with 1
            // std::stoul will not throw an invalid argument exception since we made sure, it is a
            // number (std::isdigit above)
            std::size_t argNum = std::stoul(numStr, &numDigits) - 1;
            if (argNum <= numArgs_) {
                // make textual replacement ("%" and number of digits)
                str.replace(offset, numDigits + 1, args[argNum]->get());
                offset += args[argNum]->get().size();
            } else {
                if (numDigits > 2) printWarning = true;
                offset += 1 + numDigits;
            }
        }
    }

    if (printWarning) {
        LogWarn("Input text contains more than the allowed " << maxNumArgs_ << " place markers.");
    }
    return str;
}

void TextOverlayGL::updateCache() {
    textRenderer_.setFontSize(fontSize_.getSelectedValue());
    std::string str(getString());

    size2_t labelSize(textRenderer_.computeTextSize(str));
    if (!cacheTexture_ ||
        (cacheTexture_->getDimensions() != labelSize)) {
        auto texture = std::make_shared<Texture2D>(labelSize, GL_RGBA, GL_RGBA,
                                                   GL_UNSIGNED_BYTE, GL_LINEAR);
        texture->initialize(nullptr);
        cacheTexture_ = texture;
    }
    textRenderer_.renderToTexture(cacheTexture_, str, color_.get());
}

}  // namespace
<commit_msg>FontRendering: Use util to create texture<commit_after>/*********************************************************************************
 *
 * Inviwo - Interactive Visualization Workshop
 *
 * Copyright (c) 2013-2017 Inviwo Foundation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * 2. 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.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *********************************************************************************/

#include "textoverlaygl.h"
#include <modules/fontrendering/util/fontutils.h>

#include <inviwo/core/common/inviwoapplication.h>
#include <inviwo/core/datastructures/image/image.h>
#include <inviwo/core/util/filesystem.h>
#include <modules/opengl/inviwoopengl.h>
#include <modules/opengl/texture/textureutils.h>
#include <modules/opengl/openglutils.h>
#include <modules/opengl/shader/shaderutils.h>
#include <modules/opengl/image/imagegl.h>
#include <inviwo/core/util/assertion.h>

#include <cctype>
#include <locale>

namespace inviwo {

const ProcessorInfo TextOverlayGL::processorInfo_{
    "org.inviwo.TextOverlayGL",  // Class identifier
    "Text Overlay",              // Display name
    "Drawing",                   // Category
    CodeState::Stable,           // Code state
    Tags::GL,                    // Tags
};
const ProcessorInfo TextOverlayGL::getProcessorInfo() const {
    return processorInfo_;
}

TextOverlayGL::TextOverlayGL()
    : Processor()
    , inport_("inport")
    , outport_("outport")
    , enable_("enable","Enabled",true)
    , text_("Text", "Text", "Lorem ipsum etc.", InvalidationLevel::InvalidOutput,
            PropertySemantics::TextEditor)
    , color_("color_", "Color", vec4(1.0f), vec4(0.0f), vec4(1.0f), vec4(0.01f),
                  InvalidationLevel::InvalidOutput, PropertySemantics::Color)
    , fontFace_("fontFace", "Font Face")
    , fontSize_("fontSize", "Font size")
    , fontPos_("Position", "Position", vec2(0.0f), vec2(0.0f), vec2(1.0f), vec2(0.01f))
    , anchorPos_("Anchor", "Anchor", vec2(-1.0f), vec2(-1.0f), vec2(1.0f), vec2(0.01f))
    , addArgButton_("addArgBtn", "Add String Argument")
    , numArgs_(0u)
{
    addPort(inport_);
    addPort(outport_);
    addProperty(enable_);
    addProperty(text_);
    addProperty(color_);
    addProperty(fontFace_);
    addProperty(fontPos_);
    addProperty(anchorPos_);
    addProperty(fontSize_);
    addProperty(addArgButton_);

    addArgButton_.onChange([this]() {
        if (numArgs_ >= maxNumArgs_) {
            addArgButton_.setReadOnly(numArgs_ >= maxNumArgs_);
            return;
        }
        ++numArgs_;
        std::string num = std::to_string(numArgs_);
        auto property = new StringProperty(std::string("arg") + num, "Arg " + num);
        property->setSerializationMode(PropertySerializationMode::All);
        addProperty(property, true);
    });

    auto fonts = util::getAvailableFonts();

    for (auto font : fonts) {
        auto identifier = filesystem::getFileNameWithoutExtension(font.second);
        // use the file name w/o extension as identifier
        fontFace_.addOption(identifier, font.first, font.second);
    }
    fontFace_.setSelectedIdentifier("arial");
    fontFace_.setCurrentStateAsDefault();

    // set up different font sizes
    std::vector<int> fontSizes ={ 8, 10, 11, 12, 14, 16, 20, 24, 28, 36, 48, 60, 72, 96 };
    for (auto size : fontSizes) {
        std::string str = std::to_string(size);
        fontSize_.addOption(str, str, size);
    }
    fontSize_.setSelectedIndex(4);
    fontSize_.setCurrentStateAsDefault();
}

void TextOverlayGL::process() {
    if (!enable_.get()) {
        outport_.setData(inport_.getData());
        return;
    }

    if (fontFace_.isModified()) {
        textRenderer_.setFont(fontFace_.get());
    }

    // check whether a property was modified
    if (!cacheTexture_ ||
        util::any_of(getProperties(), [](const auto& p) { return p->isModified(); })) {
        updateCache();
    }

    // draw cached overlay on top of the input image
    utilgl::activateTargetAndCopySource(outport_, inport_, ImageType::ColorDepthPicking);
    utilgl::DepthFuncState depthFunc(GL_ALWAYS);
    utilgl::BlendModeState blending(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    // use integer position for best results
    vec2 size(cacheTexture_->getDimensions());
    vec2 shift = 0.5f * size * (anchorPos_.get() + vec2(1.0f, 1.0f));

    ivec2 pos(fontPos_.get() * vec2(outport_.getDimensions()));
    pos -= ivec2(shift);
    // render texture containing the text onto the current canvas
    textureRenderer_.render(cacheTexture_, pos, outport_.getDimensions());

    utilgl::deactivateCurrentTarget();
}

void TextOverlayGL::deserialize(Deserializer & d) {
    Processor::deserialize(d);
    // update the number of place markers properties using the total number of string properties in
    // this processor. Note that this number is one element larger.
    auto args = this->getPropertiesByType<StringProperty>(false);
    numArgs_ = args.size() - 1;

    // only maxNumArgs_ are supported, disable button if more exist
    addArgButton_.setReadOnly(numArgs_ > maxNumArgs_);
}

std::string TextOverlayGL::getString() const {
    std::string str = text_.get();
    // replace all occurrences of place markers with the corresponding args
    auto args = this->getPropertiesByType<StringProperty>(false);
    // remove default text string property
    util::erase_remove_if(args, [this](const auto& p) { return p == &text_; });
    ivwAssert(numArgs_ == args.size(),
              "TextOverlayGL: number arguments not matching internal count");

    // parse string for all "%" and try to extract the number following the percent sign
    bool printWarning = false;

    std::string matchStr("%");
    for (std::size_t offset = str.find(matchStr, 0u); offset != std::string::npos;
         offset = str.find(matchStr, offset)) {
        // extract number substring,
        // read 3 characters to ensure that the number only has at most 2 digits
        std::string numStr = str.substr(offset + 1, 3);
        if (std::isdigit(numStr[0])) {
            std::size_t numDigits = 0;
            // extract number and reduce it by one since the %args start with 1
            // std::stoul will not throw an invalid argument exception since we made sure, it is a
            // number (std::isdigit above)
            std::size_t argNum = std::stoul(numStr, &numDigits) - 1;
            if (argNum <= numArgs_) {
                // make textual replacement ("%" and number of digits)
                str.replace(offset, numDigits + 1, args[argNum]->get());
                offset += args[argNum]->get().size();
            } else {
                if (numDigits > 2) printWarning = true;
                offset += 1 + numDigits;
            }
        }
    }

    if (printWarning) {
        LogWarn("Input text contains more than the allowed " << maxNumArgs_ << " place markers.");
    }
    return str;
}

void TextOverlayGL::updateCache() {
    textRenderer_.setFontSize(fontSize_.getSelectedValue());
    std::string str(getString());
    cacheTexture_ = util::createTextTexture(textRenderer_ , str , fontSize_.getSelectedValue() , color_.get() , cacheTexture_ );
}

}  // namespace
<|endoftext|>


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

#include "modules/planning/planner/rtk/rtk_replay_planner.h"

#include <fstream>
#include <utility>

#include "cyber/common/log.h"
#include "modules/common/util/string_tokenizer.h"
#include "modules/common/vehicle_state/vehicle_state_provider.h"
#include "modules/planning/common/planning_gflags.h"

namespace apollo {
namespace planning {

using apollo::common::ErrorCode;
using apollo::common::Status;
using apollo::common::TrajectoryPoint;
using apollo::common::VehicleStateProvider;

RTKReplayPlanner::RTKReplayPlanner() {
  ReadTrajectoryFile(FLAGS_rtk_trajectory_filename);
}

Status RTKReplayPlanner::Init(const PlanningConfig&) { return Status::OK(); }

Status RTKReplayPlanner::Plan(const TrajectoryPoint& planning_start_point,
                              Frame* frame) {
  auto status = Status::OK();
  bool has_plan = false;
  auto it = std::find_if(
      frame->mutable_reference_line_info()->begin(),
      frame->mutable_reference_line_info()->end(),
      [](const ReferenceLineInfo& ref) { return ref.IsChangeLanePath(); });
  if (it != frame->mutable_reference_line_info()->end()) {
    status = PlanOnReferenceLine(planning_start_point, frame, &(*it));
    has_plan = (it->IsDrivable() && it->IsChangeLanePath() &&
                it->TrajectoryLength() > FLAGS_change_lane_min_length);
    if (!has_plan) {
      AERROR << "Fail to plan for lane change.";
    }
  }

  if (!has_plan || !FLAGS_prioritize_change_lane) {
    for (auto& reference_line_info : *frame->mutable_reference_line_info()) {
      if (reference_line_info.IsChangeLanePath()) {
        continue;
      }
      status = PlanOnReferenceLine(planning_start_point, frame,
                                   &reference_line_info);
      if (status != Status::OK()) {
        AERROR << "planner failed to make a driving plan for: "
               << reference_line_info.Lanes().Id();
      }
    }
  }
  return status;
}

Status RTKReplayPlanner::PlanOnReferenceLine(
    const TrajectoryPoint& planning_init_point, Frame*,
    ReferenceLineInfo* reference_line_info) {
  if (complete_rtk_trajectory_.empty() || complete_rtk_trajectory_.size() < 2) {
    std::string msg(
        "RTKReplayPlanner doesn't have a recorded trajectory or "
        "the recorded trajectory doesn't have enough valid trajectory "
        "points.");
    AERROR << msg;
    return Status(ErrorCode::PLANNING_ERROR, msg);
  }

  std::uint32_t matched_index =
      QueryPositionMatchedPoint(planning_init_point, complete_rtk_trajectory_);

  std::uint32_t forward_buffer = FLAGS_rtk_trajectory_forward;
  // end_index is excluded.
  std::uint32_t end_index = std::min<std::uint32_t>(
      complete_rtk_trajectory_.size(), matched_index + forward_buffer);

  //  auto* trajectory_points = trajectory_pb->mutable_trajectory_point();
  std::vector<TrajectoryPoint> trajectory_points(
      complete_rtk_trajectory_.begin() + matched_index,
      complete_rtk_trajectory_.begin() + end_index);

  // reset relative time
  double zero_time = complete_rtk_trajectory_[matched_index].relative_time();
  for (auto& trajectory_point : trajectory_points) {
    trajectory_point.set_relative_time(trajectory_point.relative_time() -
                                       zero_time);
  }

  // check if the trajectory has enough points;
  // if not, append the last points multiple times and
  // adjust their corresponding time stamps.
  while (trajectory_points.size() <
         static_cast<std::size_t>(FLAGS_rtk_trajectory_forward)) {
    const auto& last_point = trajectory_points.rbegin();
    auto new_point = last_point;
    new_point->set_relative_time(new_point->relative_time() +
                                 FLAGS_rtk_trajectory_resolution);
    trajectory_points.push_back(*new_point);
  }
  reference_line_info->SetTrajectory(DiscretizedTrajectory(trajectory_points));
  return Status::OK();
}

void RTKReplayPlanner::ReadTrajectoryFile(const std::string& filename) {
  if (!complete_rtk_trajectory_.empty()) {
    complete_rtk_trajectory_.clear();
  }

  std::ifstream file_in(filename.c_str());
  if (!file_in.is_open()) {
    AERROR << "RTKReplayPlanner cannot open trajectory file: " << filename;
    return;
  }

  std::string line;
  // skip the header line.
  getline(file_in, line);

  while (true) {
    getline(file_in, line);
    if (line == "") {
      break;
    }

    auto tokens = apollo::common::util::StringTokenizer::Split(line, "\t ");
    if (tokens.size() < 11) {
      AERROR << "RTKReplayPlanner parse line failed; the data dimension does "
                "not match.";
      AERROR << line;
      continue;
    }

    TrajectoryPoint point;
    point.mutable_path_point()->set_x(std::stod(tokens[0]));
    point.mutable_path_point()->set_y(std::stod(tokens[1]));
    point.mutable_path_point()->set_z(std::stod(tokens[2]));

    point.set_v(std::stod(tokens[3]));
    point.set_a(std::stod(tokens[4]));

    point.mutable_path_point()->set_kappa(std::stod(tokens[5]));
    point.mutable_path_point()->set_dkappa(std::stod(tokens[6]));

    point.set_relative_time(std::stod(tokens[7]));

    point.mutable_path_point()->set_theta(std::stod(tokens[8]));

    point.mutable_path_point()->set_s(std::stod(tokens[10]));
    complete_rtk_trajectory_.push_back(std::move(point));
  }

  file_in.close();
}

std::uint32_t RTKReplayPlanner::QueryPositionMatchedPoint(
    const TrajectoryPoint& start_point,
    const std::vector<TrajectoryPoint>& trajectory) const {
  auto func_distance_square = [](const TrajectoryPoint& point, const double x,
                                 const double y) {
    double dx = point.path_point().x() - x;
    double dy = point.path_point().y() - y;
    return dx * dx + dy * dy;
  };
  double d_min =
      func_distance_square(trajectory.front(), start_point.path_point().x(),
                           start_point.path_point().y());
  std::uint32_t index_min = 0;
  for (std::uint32_t i = 1; i < trajectory.size(); ++i) {
    double d_temp =
        func_distance_square(trajectory[i], start_point.path_point().x(),
                             start_point.path_point().y());
    if (d_temp < d_min) {
      d_min = d_temp;
      index_min = i;
    }
  }
  return index_min;
}

}  // namespace planning
}  // namespace apollo
<commit_msg>planning: fix compile warning.<commit_after>/******************************************************************************
 * Copyright 2017 The Apollo Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *****************************************************************************/

#include "modules/planning/planner/rtk/rtk_replay_planner.h"

#include <fstream>
#include <utility>

#include "cyber/common/log.h"
#include "modules/common/util/string_tokenizer.h"
#include "modules/common/vehicle_state/vehicle_state_provider.h"
#include "modules/planning/common/planning_gflags.h"

namespace apollo {
namespace planning {

using apollo::common::ErrorCode;
using apollo::common::Status;
using apollo::common::TrajectoryPoint;
using apollo::common::VehicleStateProvider;

RTKReplayPlanner::RTKReplayPlanner() {
  ReadTrajectoryFile(FLAGS_rtk_trajectory_filename);
}

Status RTKReplayPlanner::Init(const PlanningConfig&) { return Status::OK(); }

Status RTKReplayPlanner::Plan(const TrajectoryPoint& planning_start_point,
                              Frame* frame) {
  auto status = Status::OK();
  bool has_plan = false;
  auto it = std::find_if(
      frame->mutable_reference_line_info()->begin(),
      frame->mutable_reference_line_info()->end(),
      [](const ReferenceLineInfo& ref) { return ref.IsChangeLanePath(); });
  if (it != frame->mutable_reference_line_info()->end()) {
    status = PlanOnReferenceLine(planning_start_point, frame, &(*it));
    has_plan = (it->IsDrivable() && it->IsChangeLanePath() &&
                it->TrajectoryLength() > FLAGS_change_lane_min_length);
    if (!has_plan) {
      AERROR << "Fail to plan for lane change.";
    }
  }

  if (!has_plan || !FLAGS_prioritize_change_lane) {
    for (auto& reference_line_info : *frame->mutable_reference_line_info()) {
      if (reference_line_info.IsChangeLanePath()) {
        continue;
      }
      status = PlanOnReferenceLine(planning_start_point, frame,
                                   &reference_line_info);
      if (status != Status::OK()) {
        AERROR << "planner failed to make a driving plan for: "
               << reference_line_info.Lanes().Id();
      }
    }
  }
  return status;
}

Status RTKReplayPlanner::PlanOnReferenceLine(
    const TrajectoryPoint& planning_init_point, Frame*,
    ReferenceLineInfo* reference_line_info) {
  if (complete_rtk_trajectory_.empty() || complete_rtk_trajectory_.size() < 2) {
    std::string msg(
        "RTKReplayPlanner doesn't have a recorded trajectory or "
        "the recorded trajectory doesn't have enough valid trajectory "
        "points.");
    AERROR << msg;
    return Status(ErrorCode::PLANNING_ERROR, msg);
  }

  std::uint32_t matched_index =
      QueryPositionMatchedPoint(planning_init_point, complete_rtk_trajectory_);

  std::uint32_t forward_buffer =
      static_cast<std::uint32_t>(FLAGS_rtk_trajectory_forward);
  // end_index is excluded.
  std::uint32_t end_index = std::min<std::uint32_t>(
      static_cast<std::uint32_t>(complete_rtk_trajectory_.size()),
      matched_index + forward_buffer);

  //  auto* trajectory_points = trajectory_pb->mutable_trajectory_point();
  std::vector<TrajectoryPoint> trajectory_points(
      complete_rtk_trajectory_.begin() + matched_index,
      complete_rtk_trajectory_.begin() + end_index);

  // reset relative time
  double zero_time = complete_rtk_trajectory_[matched_index].relative_time();
  for (auto& trajectory_point : trajectory_points) {
    trajectory_point.set_relative_time(trajectory_point.relative_time() -
                                       zero_time);
  }

  // check if the trajectory has enough points;
  // if not, append the last points multiple times and
  // adjust their corresponding time stamps.
  while (trajectory_points.size() <
         static_cast<std::size_t>(FLAGS_rtk_trajectory_forward)) {
    const auto& last_point = trajectory_points.rbegin();
    auto new_point = last_point;
    new_point->set_relative_time(new_point->relative_time() +
                                 FLAGS_rtk_trajectory_resolution);
    trajectory_points.push_back(*new_point);
  }
  reference_line_info->SetTrajectory(DiscretizedTrajectory(trajectory_points));
  return Status::OK();
}

void RTKReplayPlanner::ReadTrajectoryFile(const std::string& filename) {
  if (!complete_rtk_trajectory_.empty()) {
    complete_rtk_trajectory_.clear();
  }

  std::ifstream file_in(filename.c_str());
  if (!file_in.is_open()) {
    AERROR << "RTKReplayPlanner cannot open trajectory file: " << filename;
    return;
  }

  std::string line;
  // skip the header line.
  getline(file_in, line);

  while (true) {
    getline(file_in, line);
    if (line == "") {
      break;
    }

    auto tokens = apollo::common::util::StringTokenizer::Split(line, "\t ");
    if (tokens.size() < 11) {
      AERROR << "RTKReplayPlanner parse line failed; the data dimension does "
                "not match.";
      AERROR << line;
      continue;
    }

    TrajectoryPoint point;
    point.mutable_path_point()->set_x(std::stod(tokens[0]));
    point.mutable_path_point()->set_y(std::stod(tokens[1]));
    point.mutable_path_point()->set_z(std::stod(tokens[2]));

    point.set_v(std::stod(tokens[3]));
    point.set_a(std::stod(tokens[4]));

    point.mutable_path_point()->set_kappa(std::stod(tokens[5]));
    point.mutable_path_point()->set_dkappa(std::stod(tokens[6]));

    point.set_relative_time(std::stod(tokens[7]));

    point.mutable_path_point()->set_theta(std::stod(tokens[8]));

    point.mutable_path_point()->set_s(std::stod(tokens[10]));
    complete_rtk_trajectory_.push_back(std::move(point));
  }

  file_in.close();
}

std::uint32_t RTKReplayPlanner::QueryPositionMatchedPoint(
    const TrajectoryPoint& start_point,
    const std::vector<TrajectoryPoint>& trajectory) const {
  auto func_distance_square = [](const TrajectoryPoint& point, const double x,
                                 const double y) {
    double dx = point.path_point().x() - x;
    double dy = point.path_point().y() - y;
    return dx * dx + dy * dy;
  };
  double d_min =
      func_distance_square(trajectory.front(), start_point.path_point().x(),
                           start_point.path_point().y());
  std::uint32_t index_min = 0;
  for (std::uint32_t i = 1; i < trajectory.size(); ++i) {
    double d_temp =
        func_distance_square(trajectory[i], start_point.path_point().x(),
                             start_point.path_point().y());
    if (d_temp < d_min) {
      d_min = d_temp;
      index_min = i;
    }
  }
  return index_min;
}

}  // namespace planning
}  // namespace apollo
<|endoftext|>


<commit_before>/*

Copyright (c) 2003, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#ifndef TORRENT_HTTP_TRACKER_CONNECTION_HPP_INCLUDED
#define TORRENT_HTTP_TRACKER_CONNECTION_HPP_INCLUDED

#include <string>

#ifdef _MSC_VER
#pragma warning(push, 1)
#endif

#include <boost/shared_ptr.hpp>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#include "libtorrent/peer_id.hpp"
#include "libtorrent/tracker_manager.hpp"
#include "libtorrent/config.hpp"

namespace libtorrent
{

	class http_connection;
	class entry;
	class http_parser;
	class connection_queue;
	class session_settings;

	class TORRENT_EXPORT http_tracker_connection
		: public tracker_connection
	{
	friend class tracker_manager;
	public:

		http_tracker_connection(
			io_service& ios
			, connection_queue& cc
			, tracker_manager& man
			, tracker_request const& req
			, address bind_infc
			, boost::weak_ptr<request_callback> c
			, session_settings const& stn
			, proxy_settings const& ps
			, std::string const& password = "");

		void close();

	private:

		boost::intrusive_ptr<http_tracker_connection> self()
		{ return boost::intrusive_ptr<http_tracker_connection>(this); }

		void on_response(asio::error_code const& ec, http_parser const& parser
			, char const* data, int size);

		virtual void on_timeout() {}

		void parse(int status_code, const entry& e);
		bool extract_peer_info(const entry& e, peer_entry& ret);

		tracker_manager& m_man;
		boost::shared_ptr<http_connection> m_tracker_connection;
	};

}

#endif // TORRENT_HTTP_TRACKER_CONNECTION_HPP_INCLUDED

<commit_msg>silence msvc warning<commit_after>/*

Copyright (c) 2003, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#ifndef TORRENT_HTTP_TRACKER_CONNECTION_HPP_INCLUDED
#define TORRENT_HTTP_TRACKER_CONNECTION_HPP_INCLUDED

#include <string>

#ifdef _MSC_VER
#pragma warning(push, 1)
#endif

#include <boost/shared_ptr.hpp>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#include "libtorrent/peer_id.hpp"
#include "libtorrent/tracker_manager.hpp"
#include "libtorrent/config.hpp"

namespace libtorrent
{

	struct http_connection;
	class entry;
	class http_parser;
	class connection_queue;
	class session_settings;

	class TORRENT_EXPORT http_tracker_connection
		: public tracker_connection
	{
	friend class tracker_manager;
	public:

		http_tracker_connection(
			io_service& ios
			, connection_queue& cc
			, tracker_manager& man
			, tracker_request const& req
			, address bind_infc
			, boost::weak_ptr<request_callback> c
			, session_settings const& stn
			, proxy_settings const& ps
			, std::string const& password = "");

		void close();

	private:

		boost::intrusive_ptr<http_tracker_connection> self()
		{ return boost::intrusive_ptr<http_tracker_connection>(this); }

		void on_response(asio::error_code const& ec, http_parser const& parser
			, char const* data, int size);

		virtual void on_timeout() {}

		void parse(int status_code, const entry& e);
		bool extract_peer_info(const entry& e, peer_entry& ret);

		tracker_manager& m_man;
		boost::shared_ptr<http_connection> m_tracker_connection;
	};

}

#endif // TORRENT_HTTP_TRACKER_CONNECTION_HPP_INCLUDED

<|endoftext|>


<commit_before>#pragma once

#include "oqpi/platform.hpp"
#include "oqpi/error_handling.hpp"
#include "oqpi/synchronization/sync_common.hpp"

namespace oqpi {

    //----------------------------------------------------------------------------------------------
    // Forward declaration of this platform mutex implementation
    using mutex_impl = class win_mutex;

    //----------------------------------------------------------------------------------------------
    class win_mutex
    {
    protected:
        //------------------------------------------------------------------------------------------
        using native_handle_type = HANDLE;

    protected:
        //------------------------------------------------------------------------------------------
        win_mutex(const std::string &name, sync_object_creation_options creationOption, bool lockOnCreation)
            : handle_(nullptr)
        {
            if (creationOption == sync_object_creation_options::open_existing)
            {
                oqpi_check(!name.empty());
                handle_ = OpenMutexA(MUTEX_ALL_ACCESS, FALSE, name.c_str());
            }
            else
            {
                handle_ = CreateMutexA(nullptr, lockOnCreation, name.empty() ? nullptr : name.c_str());
                if ((handle_ != nullptr) && (creationOption == sync_object_creation_options::create_if_nonexistent) && (GetLastError() == ERROR_ALREADY_EXISTS))
                {
                    CloseHandle(handle_);
                    handle_ = nullptr;
                }
            }
        }

        //------------------------------------------------------------------------------------------
        ~win_mutex()
        {
            if (handle_)
            {
                CloseHandle(handle_);
                handle_ = nullptr;
            }
        }

        //------------------------------------------------------------------------------------------
        win_mutex(win_mutex &&other)
            : handle_(other.handle_)
        {
            other.handle_ = nullptr;
        }

        //------------------------------------------------------------------------------------------
        win_mutex& operator =(win_mutex &&rhs)
        {
            if (this != &rhs)
            {
                handle_ = rhs.handle_;
                rhs.handle_ = nullptr;
            }
            return (*this);
        }

    protected:
        //------------------------------------------------------------------------------------------
        // User interface
        native_handle_type getNativeHandle() const
        {
            return handle_;
        }

        //------------------------------------------------------------------------------------------
        bool isValid() const
        {
            return handle_ != nullptr;
        }

        //------------------------------------------------------------------------------------------
        bool lock()
        {
            return internalWait(INFINITE, TRUE);
        }

        //------------------------------------------------------------------------------------------
        bool tryLock()
        {
            return internalWait(0, TRUE);
        }

        //------------------------------------------------------------------------------------------
        template<typename _Rep, typename _Period>
        bool tryLockFor(const std::chrono::duration<_Rep, _Period>& relTime)
        {
            const auto dwMilliseconds = DWORD(std::chrono::duration_cast<std::chrono::milliseconds>(relTime).count());
            return internalWait(dwMilliseconds, TRUE);
        }

        //------------------------------------------------------------------------------------------
        void unlock()
        {
            oqpi_verify(ReleaseMutex(handle_) != FALSE);
        }

    private:
        //------------------------------------------------------------------------------------------
        bool internalWait(DWORD dwMilliseconds, BOOL bAlertable)
        {
            const auto result = WaitForSingleObjectEx(handle_, dwMilliseconds, bAlertable);
            if (oqpi_failed(result == WAIT_OBJECT_0 || result == WAIT_TIMEOUT))
            {
                oqpi_error("WaitForSingleObjectEx failed with error code 0x%x", GetLastError());
            }
            return (result == WAIT_OBJECT_0);
        }

    private:
        //------------------------------------------------------------------------------------------
        // Not copyable
        win_mutex(const win_mutex &)                = delete;
        win_mutex& operator =(const win_mutex &)    = delete;

    private:
        //------------------------------------------------------------------------------------------
        HANDLE  handle_;
    };

} /*oqpi*/
<commit_msg>Do not assert if a wait on mutex fails<commit_after>#pragma once

#include "oqpi/platform.hpp"
#include "oqpi/error_handling.hpp"
#include "oqpi/synchronization/sync_common.hpp"

namespace oqpi {

    //----------------------------------------------------------------------------------------------
    // Forward declaration of this platform mutex implementation
    using mutex_impl = class win_mutex;

    //----------------------------------------------------------------------------------------------
    class win_mutex
    {
    protected:
        //------------------------------------------------------------------------------------------
        using native_handle_type = HANDLE;

    protected:
        //------------------------------------------------------------------------------------------
        win_mutex(const std::string &name, sync_object_creation_options creationOption, bool lockOnCreation)
            : handle_(nullptr)
        {
            if (creationOption == sync_object_creation_options::open_existing)
            {
                oqpi_check(!name.empty());
                handle_ = OpenMutexA(MUTEX_ALL_ACCESS, FALSE, name.c_str());
            }
            else
            {
                handle_ = CreateMutexA(nullptr, lockOnCreation, name.empty() ? nullptr : name.c_str());
                if ((handle_ != nullptr) && (creationOption == sync_object_creation_options::create_if_nonexistent) && (GetLastError() == ERROR_ALREADY_EXISTS))
                {
                    CloseHandle(handle_);
                    handle_ = nullptr;
                }
            }
        }

        //------------------------------------------------------------------------------------------
        ~win_mutex()
        {
            if (handle_)
            {
                CloseHandle(handle_);
                handle_ = nullptr;
            }
        }

        //------------------------------------------------------------------------------------------
        win_mutex(win_mutex &&other)
            : handle_(other.handle_)
        {
            other.handle_ = nullptr;
        }

        //------------------------------------------------------------------------------------------
        win_mutex& operator =(win_mutex &&rhs)
        {
            if (this != &rhs)
            {
                handle_ = rhs.handle_;
                rhs.handle_ = nullptr;
            }
            return (*this);
        }

    protected:
        //------------------------------------------------------------------------------------------
        // User interface
        native_handle_type getNativeHandle() const
        {
            return handle_;
        }

        //------------------------------------------------------------------------------------------
        bool isValid() const
        {
            return handle_ != nullptr;
        }

        //------------------------------------------------------------------------------------------
        bool lock()
        {
            return internalWait(INFINITE, TRUE);
        }

        //------------------------------------------------------------------------------------------
        bool tryLock()
        {
            return internalWait(0, TRUE);
        }

        //------------------------------------------------------------------------------------------
        template<typename _Rep, typename _Period>
        bool tryLockFor(const std::chrono::duration<_Rep, _Period>& relTime)
        {
            const auto dwMilliseconds = DWORD(std::chrono::duration_cast<std::chrono::milliseconds>(relTime).count());
            return internalWait(dwMilliseconds, TRUE);
        }

        //------------------------------------------------------------------------------------------
        void unlock()
        {
            oqpi_verify(ReleaseMutex(handle_) != FALSE);
        }

    private:
        //------------------------------------------------------------------------------------------
        bool internalWait(DWORD dwMilliseconds, BOOL bAlertable)
        {
            const auto result = WaitForSingleObjectEx(handle_, dwMilliseconds, bAlertable);
            if (result == WAIT_FAILED)
            {
                oqpi_error("WaitForSingleObjectEx failed with error code 0x%x", GetLastError());
            }
            return (result == WAIT_OBJECT_0);
        }

    private:
        //------------------------------------------------------------------------------------------
        // Not copyable
        win_mutex(const win_mutex &)                = delete;
        win_mutex& operator =(const win_mutex &)    = delete;

    private:
        //------------------------------------------------------------------------------------------
        HANDLE  handle_;
    };

} /*oqpi*/
<|endoftext|>


<commit_before>#include "Expression.hpp"

#ifdef Expression_defined

Expression::Expression()
{
	IsLeft = false;
}

NumberExpression::NumberExpression(int number)
{
	Value = number;
}

double NumberExpression::Eval()
{
	return Value;
}

BinaryExpression::BinaryExpression(BinaryOperator Op, std::unique_ptr<Expression>&& First, std::unique_ptr<Expression>&& Second) :
	First(move(First)), Second(move(Second)), Op(Op)
{ }

double BinaryExpression::Eval()
{
	auto lhs = First->Eval();
	auto rhs = Second->Eval();
	switch (Op) {

	case BinaryOperator::Plus:
		return lhs + rhs;
	case BinaryOperator::Minus:
		return lhs - rhs;
	case BinaryOperator::Multiply:
		return lhs * rhs;
	case BinaryOperator::Divide:
		return lhs / rhs;
	default: throw Exception(nullptr, nullptr);
	}
}

Exception::Exception(std::string aStart, const wchar_t* aError)
{
	Start = aStart;
	Error = aError;
}

bool Is(std::stringstream& Stream, const char Text)
{
	auto Read = Stream.tellg();
	while (Stream.peek() == ' ')Stream.get();

	if (Stream.peek() == Text) {
		Stream.get();
		return true;
	}
	Stream.seekg(Read);
	return false;
}

std::unique_ptr<NumberExpression> GetNumber(std::stringstream& Stream)
{
	auto Result = 0;
	auto GotNumber = false;
	while (Stream.peek() == ' ')Stream.get();
	while (true) {
		auto c = Stream.peek();
		if ('0' <= c && c <= '9') {
			Result = Result * 10 + (c - '0');
			GotNumber = true;
			Stream.get();
		} else { break; }
	}
	if (GotNumber) {
		return std::make_unique<NumberExpression>(Result);
	}
	throw Exception(Stream.str(), L"此处需要表达式");
}

std::unique_ptr<Expression> GetTerm(std::stringstream& Stream)
{
	try {
		return GetNumber(Stream);
	} catch (Exception) {
		if (Is(Stream, '(')) {
			auto Result = GetExp(Stream);
			if (Is(Stream, ')')) {
				return Result;
			}
			throw Exception(Stream.str(), L"此处需要右括号");
		}
		throw;
	}
}

std::unique_ptr<Expression> GetFactor(std::stringstream& Stream)
{
	auto Result = GetTerm(Stream);
	while (true) {
		BinaryOperator Operator;
		if (Is(Stream, '*')) { Operator = BinaryOperator::Multiply; } else if (Is(Stream, '/')) { Operator = BinaryOperator::Divide; } else { break; }
		Result = std::make_unique<BinaryExpression>(Operator, move(Result), GetTerm(Stream));
	}
	return Result;
}

std::unique_ptr<Expression> GetExp(std::stringstream& Stream)
{
	auto Result = GetFactor(Stream);
	while (true) {
		BinaryOperator Operator;
		if (Is(Stream, '+')) { Operator = BinaryOperator::Plus; } else if (Is(Stream, '-')) { Operator = BinaryOperator::Minus; } else { break; }
		Result = std::make_unique<BinaryExpression>(Operator, move(Result), GetFactor(Stream));
	}
	return Result;
}

std::unique_ptr<Expression> GetExp(std::string Exp){
	std::stringstream ss(Exp);
	return GetExp(ss);
}

#endif<commit_msg>FIX unused case<commit_after>#include "Expression.hpp"

#ifdef Expression_defined

Expression::Expression()
{
	IsLeft = false;
}

NumberExpression::NumberExpression(int number)
{
	Value = number;
}

double NumberExpression::Eval()
{
	return Value;
}

BinaryExpression::BinaryExpression(BinaryOperator Op, std::unique_ptr<Expression>&& First, std::unique_ptr<Expression>&& Second) :
	First(move(First)), Second(move(Second)), Op(Op)
{ }

double BinaryExpression::Eval()
{
	auto lhs = First->Eval();
	auto rhs = Second->Eval();

	switch (Op) {
	case BinaryOperator::Plus:
		return lhs + rhs;
	case BinaryOperator::Minus:
		return lhs - rhs;
	case BinaryOperator::Multiply:
		return lhs * rhs;
	case BinaryOperator::Divide:
		return lhs / rhs;
	}
}

Exception::Exception(std::string aStart, const wchar_t* aError)
{
	Start = aStart;
	Error = aError;
}

bool Is(std::stringstream& Stream, const char Text)
{
	auto Read = Stream.tellg();
	while (Stream.peek() == ' ')Stream.get();

	if (Stream.peek() == Text) {
		Stream.get();
		return true;
	}
	Stream.seekg(Read);
	return false;
}

std::unique_ptr<NumberExpression> GetNumber(std::stringstream& Stream)
{
	auto Result = 0;
	auto GotNumber = false;
	while (Stream.peek() == ' ')Stream.get();
	while (true) {
		auto c = Stream.peek();
		if ('0' <= c && c <= '9') {
			Result = Result * 10 + (c - '0');
			GotNumber = true;
			Stream.get();
		} else { break; }
	}
	if (GotNumber) {
		return std::make_unique<NumberExpression>(Result);
	}
	throw Exception(Stream.str(), L"此处需要表达式");
}

std::unique_ptr<Expression> GetTerm(std::stringstream& Stream)
{
	try {
		return GetNumber(Stream);
	} catch (Exception) {
		if (Is(Stream, '(')) {
			auto Result = GetExp(Stream);
			if (Is(Stream, ')')) {
				return Result;
			}
			throw Exception(Stream.str(), L"此处需要右括号");
		}
		throw;
	}
}

std::unique_ptr<Expression> GetFactor(std::stringstream& Stream)
{
	auto Result = GetTerm(Stream);
	while (true) {
		BinaryOperator Operator;
		if (Is(Stream, '*')) { Operator = BinaryOperator::Multiply; } else if (Is(Stream, '/')) { Operator = BinaryOperator::Divide; } else { break; }
		Result = std::make_unique<BinaryExpression>(Operator, move(Result), GetTerm(Stream));
	}
	return Result;
}

std::unique_ptr<Expression> GetExp(std::stringstream& Stream)
{
	auto Result = GetFactor(Stream);
	while (true) {
		BinaryOperator Operator;
		if (Is(Stream, '+')) { Operator = BinaryOperator::Plus; } else if (Is(Stream, '-')) { Operator = BinaryOperator::Minus; } else { break; }
		Result = std::make_unique<BinaryExpression>(Operator, move(Result), GetFactor(Stream));
	}
	return Result;
}

std::unique_ptr<Expression> GetExp(std::string Exp){
	std::stringstream ss(Exp);
	return GetExp(ss);
}

#endif<|endoftext|>