<commit_before>#include <stdio.h>
#include "PimAction.h"
#include "PimSprite.h"
#include "PimAssert.h"

// Upon implementing the various Action subclasses, I noticed that most of the
// code in the update-methods were structurally identical. The following macros
// may seem large, inuntuitive and nasty (and frankly they are), but the amount
// of duplicated code avoided by this method is in my opinion a worthy tradeoff.

//
//	ACTION_UPDATE_RELATIVE:
//		Update macro for [verb]ToActions
//
//	PARAMETERS:
//		_PARENT_TYPE:	The type of the parent; Sprite, GameNode, etc.
//		_MEMBER:		The member variable to change; position, scale, etc
//		_UPDATE_SET:	Must be of type _MEMBER. Look at any usage for reference.
//		_FINAL_SET:		Must be of type _MEMBER. Set the final value of _MEMBER.
#define ACTION_UPDATE_STATIC(_PARENT_TYPE,_MEMBER,_UPDATE_SET,_FINAL_SET)	\
timer -= dt;																\
if (timer > 0.f )													\
{																			\
	((_PARENT_TYPE*)GetParent())->_MEMBER = _UPDATE_SET;					\
}																			\
else																		\
{																			\
	((_PARENT_TYPE*)GetParent())->_MEMBER = _FINAL_SET;						\
	Cleanup();																\
}

//
//	ACTION_UPDATE_RELATIVE:
//		Update macro for [verb]ByActions
//
//	PARAMETERS:
//		_PARENT_TYPE:	The type of the parent; Sprite, GameNode, etc.
//		_MEMBER:		The member variable to change; position, scale, color, etc.
//						Note that the _MEMBER-type ABSOLUTELY MUST override the "+=" operator.
//		_UPDATE_VAR:	Must be of type _MEMBER. Only pass the variable, it's multiplied by
//						'dt' and '(1.f/dur)' in the macro.
#define ACTION_UPDATE_RELATIVE(_PARENT_TYPE,_MEMBER,_UPDATE_VAR)			\
bool ovride = false;														\
if (timer > 0.f && timer - dt <= 0.f)										\
{																			\
	float tmp = timer;														\
	timer -= dt;															\
	dt = tmp;																\
	ovride = true;															\
}																			\
else																		\
{																			\
	timer -= dt;															\
}																			\
if (timer > 0.f || ovride)													\
{																			\
	((_PARENT_TYPE*)GetParent())->_MEMBER += _UPDATE_VAR *dt*(1.f/dur);		\
	if (ovride) /* override means we're done */								\
	{																		\
		Cleanup();															\
	}																		\
}																			\
else																		\
{																			\
	Cleanup();																\
}

namespace Pim {
	/*
	=====================
	BaseAction::BaseAction
	=====================
	*/
	BaseAction::BaseAction(float duration) {
		done					= false;
		inQueue					= false;
		notifyOnCompletion		= false;
		queue					= NULL;
		notificationCallback	= NULL;
		dur						= duration;
		timer					= duration;
		initialDur				= duration;
	}

	/*
	=====================
	BaseAction::Cleanup
	=====================
	*/
	void BaseAction::Cleanup() {
		if (notifyOnCompletion) {
			notificationCallback->OnActionCompleted(this);
		}

		if (inQueue) {
			done = true;
			UnlistenFrame();

			queue->ActivateNext();
		} else {
			GetParent()->RemoveChild(this);
		}
	}

	/*
	=====================
	Action::Action
	=====================
	*/
	void Action::Activate() {
		PimAssert(GetParent() != NULL, "Action is orphan");
		ListenFrame();

		if (!notificationCallback) {
			notificationCallback = GetParent();
		}
	}

	/*
	=====================
	MoveToAction::MoveToAction
	=====================
	*/
	MoveToAction::MoveToAction(Vec2 destination, float duration)
		: Action(duration) {
		dest = destination;
	}

	/*
	=====================
	MoveToAction::Activate
	=====================
	*/
	void MoveToAction::Activate() {
		Action::Activate();
		start = GetParent()->position;
	}

	/*
	=====================
	MoveToAction::Update
	=====================
	*/
	void MoveToAction::Update(float dt) {
		ACTION_UPDATE_STATIC(
			GameNode,
			position,
			Vec2(
				dest.x + (start.x-dest.x) * (timer/dur),
				dest.y + (start.y-dest.y) * (timer/dur)
			),
			dest
		);
	}

	/*
	=====================
	MoveByAction::MoveByAction
	=====================
	*/
	MoveByAction::MoveByAction(Vec2 relative, float duration)
		: Action(duration) {
		rel		= relative;
	}

	/*
	=====================
	MoveByAction::Activate
	=====================
	*/
	void MoveByAction::Activate() {
		Action::Activate();
	}

	/*
	=====================
	MoveByAction::Update
	=====================
	*/
	void MoveByAction::Update(float dt) {
		ACTION_UPDATE_RELATIVE(GameNode, position, rel);
	}

	/*
	=====================
	RotateByAction::RotateByAction
	=====================
	*/
	RotateByAction::RotateByAction(float angle, float duration)
		: Action(duration) {
		total		= angle;
		dir			= angle / abs(angle);
	}

	/*
	=====================
	RotateByAction::Activate
	=====================
	*/
	void RotateByAction::Activate() {
		Action::Activate();
		remainding = total;
	}

	/*
	=====================
	RotateByAction::Update
	=====================
	*/
	void RotateByAction::Update(float dt) {
		ACTION_UPDATE_RELATIVE(GameNode, rotation, total);
	}

	/*
	=====================
	DelayAction::DelayAction
	=====================
	*/
	DelayAction::DelayAction(float duration)
		: Action(duration) {
	}

	/*
	=====================
	DelayAction::Activate
	=====================
	*/
	void DelayAction::Activate() {
		Action::Activate();
	}

	/*
	=====================
	DelayAction::Update
	=====================
	*/
	void DelayAction::Update(float dt) {
		timer -= dt;

		if (timer <= 0.f) {
			Cleanup();
		}
	}

	/*
	=====================
	SpriteAction::Activate
	=====================
	*/
	void SpriteAction::Activate() {
		PimAssert(GetParent() != NULL, "Action is orphan");
		PimAssert(dynamic_cast<Sprite*>(GetParent()) != NULL,
				  "Cannot add a Sprite-action to a non-sprite node!");

		ListenFrame();

		if (!notificationCallback) {
			notificationCallback = GetParent();
		}
	}

	/*
	=====================
	TintAction::TintAction
	=====================
	*/
	TintAction::TintAction(Color fadeTo, float duration)
		: SpriteAction(duration) {
		dest	= fadeTo;
	}

	/*
	=====================
	TintAction::Activate
	=====================
	*/
	void TintAction::Activate() {
		SpriteAction::Activate();
		source = ((Sprite*)GetParent())->color;
	}

	/*
	=====================
	TintAction::Update
	=====================
	*/
	void TintAction::Update(float dt) {
		ACTION_UPDATE_STATIC(
			Sprite,
			color,
			Color(
				dest.r + (source.r-dest.r) * (timer/dur),
				dest.g + (source.g-dest.g) * (timer/dur),
				dest.b + (source.b-dest.b) * (timer/dur),
				dest.a + (source.a-dest.a) * (timer/dur)
			),
			dest
		);
	}

	/*
	=====================
	ScaleToAction::ScaleToAction
	=====================
	*/
	ScaleToAction::ScaleToAction(Vec2 factor, float duration)
		: SpriteAction(duration) {
		dest = factor;
	}

	/*
	=====================
	ScaleToAction::Activate
	=====================
	*/
	void ScaleToAction::Activate() {
		SpriteAction::Activate();
		source = ((Sprite*)GetParent())->scale;
	}

	/*
	=====================
	ScaleToAction::Update
	=====================
	*/
	void ScaleToAction::Update(float dt) {
		ACTION_UPDATE_STATIC(
			Sprite,
			scale,
			Vec2(
				dest.x + (source.x-dest.x) * (timer/dur),
				dest.y + (source.y-dest.y) * (timer/dur)
			),
			dest
		);
	}

	/*
	=====================
	ScaleByAction::ScaleByAction
	=====================
	*/
	ScaleByAction::ScaleByAction(Vec2 factor, float duration)
		: SpriteAction(duration) {
		remainding = factor;
	}

	/*
	=====================
	ScaleByAction::Activate
	=====================
	*/
	void ScaleByAction::Activate() {
		SpriteAction::Activate();
	}

	/*
	=====================
	ScaleByAction::Update
	=====================
	*/
	void ScaleByAction::Update(float dt) {
		ACTION_UPDATE_RELATIVE(Sprite, scale, remainding);
	}

	/*
	=====================
	ActionQueue::ActionQueue
	=====================
	*/
	ActionQueue::ActionQueue(int numAct, BaseAction *act1, ...)
		: Action(0.f) {
		PimAssert(numAct != 0, "No actions / invalid num provided to ActionQueue");
		PimAssert(numAct < 32, "ActionQueues does not support more than 32 actions");

		curAct = NULL;

		actions.push_back(act1);
		act1->inQueue = true;
		act1->queue = this;

		va_list	argp;
		va_start(argp, act1);

		for (int i=1; i<numAct; i++) {
			actions.push_back(va_arg(argp, BaseAction*));
			actions[i]->inQueue = true;
			actions[i]->queue = this;
		}

		va_end(argp);
	}

	/*
	=====================
	ActionQueue::~ActionQueue
	=====================
	*/
	ActionQueue::~ActionQueue() {
		// Delete unplayed actions
		for (unsigned i=0; i<actions.size(); i++) {
			delete actions[i];
		}

		actions.clear();
	}

	/*
	=====================
	ActionQueue::Activate
	=====================
	*/
	void ActionQueue::Activate() {
		PimAssert(GetParent() != NULL, "Action is orphan");

		ListenFrame();
		ActivateNext();
	}

	/*
	=====================
	ActionQueue::Update
	=====================
	*/
	void ActionQueue::Update(float dt) {
		if (done) {
			GetParent()->RemoveChild(this);
		}
	}

	/*
	=====================
	ActionQueue::ActivateNext
	=====================
	*/
	void ActionQueue::ActivateNext() {
		if (actions.size() != 0) {
			float excess = 0.f;

			if (curAct) {
				excess = curAct->timer;

				if (parent) {
					parent->RemoveChild(curAct);
				}
			}

			curAct = actions[0];
			actions.pop_front();

			curAct->dur += excess;
			curAct->timer += excess;

			if (parent) {
				parent->AddChild(curAct);
				curAct->Activate();
			}
		} else {
			curAct = NULL;
			done = true;
		}
	}

	/*
	=====================
	ActionQueueRepeat::ActionQueueRepeat
	=====================
	*/
	ActionQueueRepeat::ActionQueueRepeat(unsigned int repNum, int numAct, BaseAction *act1, ...) {
		// Code duplication from ActionQueue::ActionQueue(...).
		// Variable arguments proved difficult to pass on.
		PimAssert(numAct != 0, "No actions / invalid num provided to ActionQueue");
		PimAssert(numAct < 32, "ActionQueues does not support more than 32 actions");

		curAct = NULL;

		actions.push_back(act1);
		act1->inQueue = true;
		act1->queue = this;

		va_list	argp;
		va_start(argp, act1);

		for (int i=1; i<numAct; i++) {
			actions.push_back(va_arg(argp, BaseAction*));
			actions[i]->inQueue = true;
			actions[i]->queue = this;
		}

		va_end(argp);

		// Custom init
		actionIdx		= -1;		// gets incremented in activateNext()
		remaindingLoops = repNum;
		infinite		= false;
	}

	/*
	=====================
	ActionQueueRepeat::~ActionQueueRepeat
	=====================
	*/
	ActionQueueRepeat::~ActionQueueRepeat() {
		if (curAct) {
			// Everything in the actions-deque is deleted in ActionQueue's
			// destructor - to avoid the ActionQueue AND the parent of curAct
			// attempting to delete it, it's removed from the actions-deque.
			for (unsigned i=0; i<actions.size(); i++) {
				if (actions[i] == curAct) {
					actions.erase(actions.begin() + i);

					if (parent) {
						parent->RemoveChild(curAct);
					}
				}
			}
		}
	}

	/*
	=====================
	ActionQueueRepeat::ActivateNext
	=====================
	*/
	void ActionQueueRepeat::ActivateNext() {
		if (willDelete) return;

		// Update the action counters
		if (unsigned(++actionIdx) >= actions.size()) {
			actionIdx = 0;

			if (!infinite) {
				remaindingLoops--;
			}
		}

		if (infinite || remaindingLoops > 0) {
			float excess = 0.f;

			if (curAct) {
				excess = curAct->timer;

				// The action is not deleted.
				if (parent) {
					GetParent()->RemoveChild(curAct, false);
				}

				curAct->UnlistenFrame();
			}

			// Prepare the next action
			curAct = actions[actionIdx];

			curAct->timer	= curAct->initialDur + excess;
			curAct->dur		= curAct->initialDur + excess;
			curAct->done	= false;

			// Run the next action
			if (parent) {
				GetParent()->AddChild(curAct);
				curAct->Activate();
			}

			curAct->Update(-excess);
		} else {
			done = true;
		}
	}
}<commit_msg>Added conditional detachment from parent in BaseAction::Cleanup<commit_after>#include <stdio.h>
#include "PimAction.h"
#include "PimSprite.h"
#include "PimAssert.h"

// Upon implementing the various Action subclasses, I noticed that most of the
// code in the update-methods were structurally identical. The following macros
// may seem large, inuntuitive and nasty (and frankly they are), but the amount
// of duplicated code avoided by this method is in my opinion a worthy tradeoff.

//
//	ACTION_UPDATE_RELATIVE:
//		Update macro for [verb]ToActions
//
//	PARAMETERS:
//		_PARENT_TYPE:	The type of the parent; Sprite, GameNode, etc.
//		_MEMBER:		The member variable to change; position, scale, etc
//		_UPDATE_SET:	Must be of type _MEMBER. Look at any usage for reference.
//		_FINAL_SET:		Must be of type _MEMBER. Set the final value of _MEMBER.
#define ACTION_UPDATE_STATIC(_PARENT_TYPE,_MEMBER,_UPDATE_SET,_FINAL_SET)	\
timer -= dt;																\
if (timer > 0.f )													\
{																			\
	((_PARENT_TYPE*)GetParent())->_MEMBER = _UPDATE_SET;					\
}																			\
else																		\
{																			\
	((_PARENT_TYPE*)GetParent())->_MEMBER = _FINAL_SET;						\
	Cleanup();																\
}

//
//	ACTION_UPDATE_RELATIVE:
//		Update macro for [verb]ByActions
//
//	PARAMETERS:
//		_PARENT_TYPE:	The type of the parent; Sprite, GameNode, etc.
//		_MEMBER:		The member variable to change; position, scale, color, etc.
//						Note that the _MEMBER-type ABSOLUTELY MUST override the "+=" operator.
//		_UPDATE_VAR:	Must be of type _MEMBER. Only pass the variable, it's multiplied by
//						'dt' and '(1.f/dur)' in the macro.
#define ACTION_UPDATE_RELATIVE(_PARENT_TYPE,_MEMBER,_UPDATE_VAR)			\
bool ovride = false;														\
if (timer > 0.f && timer - dt <= 0.f)										\
{																			\
	float tmp = timer;														\
	timer -= dt;															\
	dt = tmp;																\
	ovride = true;															\
}																			\
else																		\
{																			\
	timer -= dt;															\
}																			\
if (timer > 0.f || ovride)													\
{																			\
	((_PARENT_TYPE*)GetParent())->_MEMBER += _UPDATE_VAR *dt*(1.f/dur);		\
	if (ovride) /* override means we're done */								\
	{																		\
		Cleanup();															\
	}																		\
}																			\
else																		\
{																			\
	Cleanup();																\
}

namespace Pim {
	/*
	=====================
	BaseAction::BaseAction
	=====================
	*/
	BaseAction::BaseAction(float duration) {
		done					= false;
		inQueue					= false;
		notifyOnCompletion		= false;
		queue					= NULL;
		notificationCallback	= NULL;
		dur						= duration;
		timer					= duration;
		initialDur				= duration;
	}

	/*
	=====================
	BaseAction::Cleanup
	=====================
	*/
	void BaseAction::Cleanup() {
		if (notifyOnCompletion) {
			notificationCallback->OnActionCompleted(this);
		}

		if (inQueue) {
			done = true;
			UnlistenFrame();

			queue->ActivateNext();
		} else {
			if (GetParent()) {
				GetParent()->RemoveChild(this);
			}
		}
	}

	/*
	=====================
	Action::Action
	=====================
	*/
	void Action::Activate() {
		PimAssert(GetParent() != NULL, "Action is orphan");
		ListenFrame();

		if (!notificationCallback) {
			notificationCallback = GetParent();
		}
	}

	/*
	=====================
	MoveToAction::MoveToAction
	=====================
	*/
	MoveToAction::MoveToAction(Vec2 destination, float duration)
		: Action(duration) {
		dest = destination;
	}

	/*
	=====================
	MoveToAction::Activate
	=====================
	*/
	void MoveToAction::Activate() {
		Action::Activate();
		start = GetParent()->position;
	}

	/*
	=====================
	MoveToAction::Update
	=====================
	*/
	void MoveToAction::Update(float dt) {
		ACTION_UPDATE_STATIC(
			GameNode,
			position,
			Vec2(
				dest.x + (start.x-dest.x) * (timer/dur),
				dest.y + (start.y-dest.y) * (timer/dur)
			),
			dest
		);
	}

	/*
	=====================
	MoveByAction::MoveByAction
	=====================
	*/
	MoveByAction::MoveByAction(Vec2 relative, float duration)
		: Action(duration) {
		rel		= relative;
	}

	/*
	=====================
	MoveByAction::Activate
	=====================
	*/
	void MoveByAction::Activate() {
		Action::Activate();
	}

	/*
	=====================
	MoveByAction::Update
	=====================
	*/
	void MoveByAction::Update(float dt) {
		ACTION_UPDATE_RELATIVE(GameNode, position, rel);
	}

	/*
	=====================
	RotateByAction::RotateByAction
	=====================
	*/
	RotateByAction::RotateByAction(float angle, float duration)
		: Action(duration) {
		total		= angle;
		dir			= angle / abs(angle);
	}

	/*
	=====================
	RotateByAction::Activate
	=====================
	*/
	void RotateByAction::Activate() {
		Action::Activate();
		remainding = total;
	}

	/*
	=====================
	RotateByAction::Update
	=====================
	*/
	void RotateByAction::Update(float dt) {
		ACTION_UPDATE_RELATIVE(GameNode, rotation, total);
	}

	/*
	=====================
	DelayAction::DelayAction
	=====================
	*/
	DelayAction::DelayAction(float duration)
		: Action(duration) {
	}

	/*
	=====================
	DelayAction::Activate
	=====================
	*/
	void DelayAction::Activate() {
		Action::Activate();
	}

	/*
	=====================
	DelayAction::Update
	=====================
	*/
	void DelayAction::Update(float dt) {
		timer -= dt;

		if (timer <= 0.f) {
			Cleanup();
		}
	}

	/*
	=====================
	SpriteAction::Activate
	=====================
	*/
	void SpriteAction::Activate() {
		PimAssert(GetParent() != NULL, "Action is orphan");
		PimAssert(dynamic_cast<Sprite*>(GetParent()) != NULL,
				  "Cannot add a Sprite-action to a non-sprite node!");

		ListenFrame();

		if (!notificationCallback) {
			notificationCallback = GetParent();
		}
	}

	/*
	=====================
	TintAction::TintAction
	=====================
	*/
	TintAction::TintAction(Color fadeTo, float duration)
		: SpriteAction(duration) {
		dest	= fadeTo;
	}

	/*
	=====================
	TintAction::Activate
	=====================
	*/
	void TintAction::Activate() {
		SpriteAction::Activate();
		source = ((Sprite*)GetParent())->color;
	}

	/*
	=====================
	TintAction::Update
	=====================
	*/
	void TintAction::Update(float dt) {
		ACTION_UPDATE_STATIC(
			Sprite,
			color,
			Color(
				dest.r + (source.r-dest.r) * (timer/dur),
				dest.g + (source.g-dest.g) * (timer/dur),
				dest.b + (source.b-dest.b) * (timer/dur),
				dest.a + (source.a-dest.a) * (timer/dur)
			),
			dest
		);
	}

	/*
	=====================
	ScaleToAction::ScaleToAction
	=====================
	*/
	ScaleToAction::ScaleToAction(Vec2 factor, float duration)
		: SpriteAction(duration) {
		dest = factor;
	}

	/*
	=====================
	ScaleToAction::Activate
	=====================
	*/
	void ScaleToAction::Activate() {
		SpriteAction::Activate();
		source = ((Sprite*)GetParent())->scale;
	}

	/*
	=====================
	ScaleToAction::Update
	=====================
	*/
	void ScaleToAction::Update(float dt) {
		ACTION_UPDATE_STATIC(
			Sprite,
			scale,
			Vec2(
				dest.x + (source.x-dest.x) * (timer/dur),
				dest.y + (source.y-dest.y) * (timer/dur)
			),
			dest
		);
	}

	/*
	=====================
	ScaleByAction::ScaleByAction
	=====================
	*/
	ScaleByAction::ScaleByAction(Vec2 factor, float duration)
		: SpriteAction(duration) {
		remainding = factor;
	}

	/*
	=====================
	ScaleByAction::Activate
	=====================
	*/
	void ScaleByAction::Activate() {
		SpriteAction::Activate();
	}

	/*
	=====================
	ScaleByAction::Update
	=====================
	*/
	void ScaleByAction::Update(float dt) {
		ACTION_UPDATE_RELATIVE(Sprite, scale, remainding);
	}

	/*
	=====================
	ActionQueue::ActionQueue
	=====================
	*/
	ActionQueue::ActionQueue(int numAct, BaseAction *act1, ...)
		: Action(0.f) {
		PimAssert(numAct != 0, "No actions / invalid num provided to ActionQueue");
		PimAssert(numAct < 32, "ActionQueues does not support more than 32 actions");

		curAct = NULL;

		actions.push_back(act1);
		act1->inQueue = true;
		act1->queue = this;

		va_list	argp;
		va_start(argp, act1);

		for (int i=1; i<numAct; i++) {
			actions.push_back(va_arg(argp, BaseAction*));
			actions[i]->inQueue = true;
			actions[i]->queue = this;
		}

		va_end(argp);
	}

	/*
	=====================
	ActionQueue::~ActionQueue
	=====================
	*/
	ActionQueue::~ActionQueue() {
		// Delete unplayed actions
		for (unsigned i=0; i<actions.size(); i++) {
			delete actions[i];
		}

		actions.clear();
	}

	/*
	=====================
	ActionQueue::Activate
	=====================
	*/
	void ActionQueue::Activate() {
		PimAssert(GetParent() != NULL, "Action is orphan");

		ListenFrame();
		ActivateNext();
	}

	/*
	=====================
	ActionQueue::Update
	=====================
	*/
	void ActionQueue::Update(float dt) {
		if (done) {
			GetParent()->RemoveChild(this);
		}
	}

	/*
	=====================
	ActionQueue::ActivateNext
	=====================
	*/
	void ActionQueue::ActivateNext() {
		if (actions.size() != 0) {
			float excess = 0.f;

			if (curAct) {
				excess = curAct->timer;

				if (parent) {
					parent->RemoveChild(curAct);
				}
			}

			curAct = actions[0];
			actions.pop_front();

			curAct->dur += excess;
			curAct->timer += excess;

			if (parent) {
				parent->AddChild(curAct);
				curAct->Activate();
			}
		} else {
			curAct = NULL;
			done = true;
		}
	}

	/*
	=====================
	ActionQueueRepeat::ActionQueueRepeat
	=====================
	*/
	ActionQueueRepeat::ActionQueueRepeat(unsigned int repNum, int numAct, BaseAction *act1, ...) {
		// Code duplication from ActionQueue::ActionQueue(...).
		// Variable arguments proved difficult to pass on.
		PimAssert(numAct != 0, "No actions / invalid num provided to ActionQueue");
		PimAssert(numAct < 32, "ActionQueues does not support more than 32 actions");

		curAct = NULL;

		actions.push_back(act1);
		act1->inQueue = true;
		act1->queue = this;

		va_list	argp;
		va_start(argp, act1);

		for (int i=1; i<numAct; i++) {
			actions.push_back(va_arg(argp, BaseAction*));
			actions[i]->inQueue = true;
			actions[i]->queue = this;
		}

		va_end(argp);

		// Custom init
		actionIdx		= -1;		// gets incremented in activateNext()
		remaindingLoops = repNum;
		infinite		= false;
	}

	/*
	=====================
	ActionQueueRepeat::~ActionQueueRepeat
	=====================
	*/
	ActionQueueRepeat::~ActionQueueRepeat() {
		if (curAct) {
			// Everything in the actions-deque is deleted in ActionQueue's
			// destructor - to avoid the ActionQueue AND the parent of curAct
			// attempting to delete it, it's removed from the actions-deque.
			for (unsigned i=0; i<actions.size(); i++) {
				if (actions[i] == curAct) {
					actions.erase(actions.begin() + i);

					if (parent) {
						parent->RemoveChild(curAct);
					}
				}
			}
		}
	}

	/*
	=====================
	ActionQueueRepeat::ActivateNext
	=====================
	*/
	void ActionQueueRepeat::ActivateNext() {
		if (willDelete) return;

		// Update the action counters
		if (unsigned(++actionIdx) >= actions.size()) {
			actionIdx = 0;

			if (!infinite) {
				remaindingLoops--;
			}
		}

		if (infinite || remaindingLoops > 0) {
			float excess = 0.f;

			if (curAct) {
				excess = curAct->timer;

				// The action is not deleted.
				if (parent) {
					GetParent()->RemoveChild(curAct, false);
				}

				curAct->UnlistenFrame();
			}

			// Prepare the next action
			curAct = actions[actionIdx];

			curAct->timer	= curAct->initialDur + excess;
			curAct->dur		= curAct->initialDur + excess;
			curAct->done	= false;

			// Run the next action
			if (parent) {
				GetParent()->AddChild(curAct);
				curAct->Activate();
			}

			curAct->Update(-excess);
		} else {
			done = true;
		}
	}
}<|endoftext|>


<commit_before>#include <iostream>
#include "structs.h"

using namespace std;

int main(void)
{
    // The default constructor for a struct just zeroes the values
    Vec3 v = Vec3();
    Vec3 vprime = Vec3();
    Vec2 w = Vec2();

    cout << "-----Pass by value test-----" << endl;
    cout << "Original 3 vector:" << endl;
    print_vec(v);
    vprime = set_vec(v, 1.0, 2.0, 3.0);
    cout << "Original 3 vector after modification:" << endl;
    print_vec(v);
    cout << "New 3 vector after modification:" << endl;
    print_vec(vprime);

    cout << "-----Pass by reference test-----" << endl;
    cout << "Original 2 vector:" << endl;
    print_vec(w);
    set_vec(w, 1.0, 2.0);
    cout << "Original 2 vector after modification:" << endl;
    print_vec(w);

    return 0;
}

Vec3 set_vec(Vec3 v, Component x, Component y, Component z)
{
    // Local value v is a copy of the original v
    v.x = x;
    v.y = y;
    v.z = z;
    return v;
}

void set_vec(Vec2 &wr, Component x, Component y)
{
    // Local reference wr refers directly to original memory location
    wr.x = x;
    wr.y = y;
}

void print_vec(const Vec3 v)
{
    cout << "3-Vector : [" << v.x << ", " << v.y << ", " << v.z << "]" << endl;
}

void print_vec(const Vec2 &wr)
{
    // Passing in a reference wr prevents unnecessary memory copying
    cout << "2Vector : [" << wr.x << ", " << wr.y << "]" << endl;
}

//TODO : Implement overloaded + operators
<commit_msg>structs.cc<commit_after>#include <iostream>
#include "structs.h"

using namespace std;

int main(void)
{
    // The default constructor for a struct just zeroes the values
    Vec3 v = Vec3();
    Vec3 vprime = Vec3();
    Vec2 w = Vec2();

    cout << "-----Pass by value test-----" << endl;
    cout << "Original 3 vector:" << endl;
    print_vec(v);
    vprime = set_vec(v, 1.0, 2.0, 3.0);
    cout << "Original 3 vector after modification:" << endl;
    print_vec(v);
    cout << "New 3 vector after modification:" << endl;
    print_vec(vprime);

    cout << "-----Pass by reference test-----" << endl;
    cout << "Original 2 vector:" << endl;
    print_vec(w);
    set_vec(w, 1.0, 2.0);
    cout << "Original 2 vector after modification:" << endl;
    print_vec(w);

    cout << "-----Operator+ Vec3 test-----" << endl;
    cout << "Original 3 vector:" << endl;
    print_vec(vprime);
    cout << "The sum of two vprimes is:" << endl;
    print_vec(vprime + vprime);

    cout << "-----Operator+ Vec2 test-----" << endl;
    cout << "Original 2 vector:" << endl;
    print_vec(w);
    cout << "The sum of two vprimes is:" << endl;
    print_vec(w + w);

    return 0;
}

Vec3 set_vec(Vec3 v, Component x, Component y, Component z)
{
    // Local value v is a copy of the original v
    v.x = x;
    v.y = y;
    v.z = z;
    return v;
}

void set_vec(Vec2 &wr, Component x, Component y)
{
    // Local reference wr refers directly to original memory location
    wr.x = x;
    wr.y = y;
}

void print_vec(const Vec3 v)
{
    cout << "3-Vector : [" << v.x << ", " << v.y << ", " << v.z << "]" << endl;
}

void print_vec(const Vec2 &wr)
{
    // Passing in a reference wr prevents unnecessary memory copying
    cout << "2Vector : [" << wr.x << ", " << wr.y << "]" << endl;
}

//TODO : Implement overloaded + operators
Vec3 operator+(const Vec3& a, const Vec3& b)
{
    Vec3 sum3;
    sum3.x = a.x + b.x;
    sum3.y = a.y + b.y;
    sum3.z = a.z + b.z;
    return sum3;
}

Vec2 operator+(const Vec2& c, const Vec2& d)
{
    Vec2 sum2;
    sum2.x = c.x + d.x;
    sum2.y = c.y + d.y;
    return sum2;
}
<|endoftext|>


<commit_before>// Copyright (c) 2014, German Neuroinformatics Node (G-Node)
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted under the terms of the BSD License. See
// LICENSE file in the root of the Project.

#include <boost/python.hpp>
#include <boost/optional.hpp>

#include <nix.hpp>
#include <accessors.hpp>
#include <transmorgify.hpp>
#include <iostream>

#include <PyEntity.hpp>

using namespace nix;
using namespace boost::python;

namespace nixpy {

// getter for Section

boost::optional<Section> getSectionById(const Section& section, const std::string& id) {
    Section sec = section.getSection(id);

    return sec ? boost::optional<Section>(sec) : boost::none;
}

boost::optional<Section> getSectionByPos(const Section& section, size_t index) {
    Section sec = section.getSection(index);

    return sec ? boost::optional<Section>(sec) : boost::none;
}

// Property

Property createProperty(Section& sec, const std::string& name, PyObject* obj) {
    extract<DataType> ext_type(obj);
    if (ext_type.check()) {
        return sec.createProperty(name, ext_type());
    }

    extract<Value&> ext_val(obj);
    if (ext_val.check()) {
        return sec.createProperty(name, ext_val());
    }

    extract<std::vector<Value>> ext_vec(obj);
    if (ext_vec.check()) {
        return sec.createProperty(name, ext_vec());
    }

    throw new std::runtime_error("Second parameter must be a Value, list of Value or DataType");
}

boost::optional<Property> getPropertyById(const Section& section, const std::string& id) {
    Property prop = section.getProperty(id);

    return prop ? boost::optional<Property>(prop) : boost::none;
}

boost::optional<Property> getPropertyByPos(const Section& section, size_t index) {
    Property prop = section.getProperty(index);

    return prop ? boost::optional<Property>(prop) : boost::none;
}

boost::optional<Property> getPropertyByName(const Section& section, const std::string& name) {
    Property prop = section.getProperty(name);

    return prop ? boost::optional<Property>(prop) : boost::none;
}

bool hasPropertyByName(const Section& section, const std::string& name) {
  return section.hasProperty(name);
}
// Repository

void setRepository(Section& sec, const boost::optional<std::string>& str) {
    if (str)
        sec.repository(*str);
    else
        sec.repository(boost::none);
}

// Mapping

void setMapping(Section& sec, const boost::optional<std::string>& str) {
    if (str)
        sec.mapping(*str);
    else
        sec.mapping(boost::none);
}

// Link

void setLink(Section& section, const boost::optional<Section>& link) {
    if (link && *link)
        section.link(*link);
    else
        section.link(boost::none);
}

boost::optional<Section> getLink(const Section& sec) {
    Section link = sec.link();
    return link ? boost::optional<Section>(link) : boost::none;
}

// Parent

boost::optional<Section> getParent(const Section& sec) {
    Section parent = sec.parent();
    return parent ? boost::optional<Section>(parent) : boost::none;
}

void PySection::do_export() {

    PyNamedEntity<base::ISection>::do_export("Section");
    class_<Section, bases<base::NamedEntity<base::ISection>>>("Section")
        // Properties
        .add_property("repository",
                      OPT_GETTER(std::string, Section, repository),
                      setRepository,
                      doc::section_repository)
        .add_property("mapping",
                      OPT_GETTER(std::string, Section, mapping),
                      setMapping,
                      doc::section_mapping)
        .add_property("link", getLink, setLink, doc::section_link)
        // Section
        .add_property("parent", getParent, doc::section_parent)
        .def("create_section", &Section::createSection,
             doc::section_create_section)
        .def("_section_count", &Section::sectionCount)
        .def("_get_section_by_id", &getSectionById)
        .def("_get_section_by_pos", &getSectionByPos)
        .def("_delete_section_by_id", REMOVER(std::string, nix::Section, deleteSection))
        // Property
        .def("_create_property", createProperty)
        .def("has_property_by_name", hasPropertyByName,
             doc::section_has_property_by_name)
        .def("get_property_by_name", getPropertyByName,
             doc::section_get_property_by_name)
        .def("_property_count", &Section::propertyCount)
        .def("_get_property_by_id", &getPropertyById)
        .def("_get_property_by_pos", &getPropertyByPos)
        .def("_delete_property_by_id", REMOVER(std::string, nix::Section, deleteProperty))
        .def("inherited_properties", &Section::inheritedProperties)
        // Other
        .def("__str__", &toStr<Section>)
        .def("__repr__", &toStr<Section>)
        ;

    to_python_converter<std::vector<Section>, vector_transmogrify<Section>>();
    to_python_converter<boost::optional<Section>, option_transmogrify<Section>>();
    option_transmogrify<Section>::register_from_python();
}

}
<commit_msg>createProperty accepts Python values, not nix::Value<commit_after>// Copyright (c) 2014, German Neuroinformatics Node (G-Node)
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted under the terms of the BSD License. See
// LICENSE file in the root of the Project.

#include <boost/python.hpp>
#include <boost/optional.hpp>

#include <nix.hpp>
#include <accessors.hpp>
#include <transmorgify.hpp>
#include <iostream>

#include <PyEntity.hpp>

using namespace nix;
using namespace boost::python;

namespace nixpy {

// getter for Section

boost::optional<Section> getSectionById(const Section& section, const std::string& id) {
    Section sec = section.getSection(id);

    return sec ? boost::optional<Section>(sec) : boost::none;
}

boost::optional<Section> getSectionByPos(const Section& section, size_t index) {
    Section sec = section.getSection(index);

    return sec ? boost::optional<Section>(sec) : boost::none;
}

// Property
Property createProperty(Section& sec, const std::string& name, list& valuelist) {
    std::vector<Value> nixvaluelist;
    for (int idx = 0; idx < len(valuelist); ++idx) {
        nixvaluelist.push_back(Value(object(valuelist[idx])));
    }
    return sec.createProperty(name, nixvaluelist);
}

Property createProperty(Section& sec, const std::string& name, PyObject* value) {

    Value nixvalue;

    if (PyBool_Check(value)) {
        bool conv = extract<bool>(value);
        nixvalue = Value(conv);
#if PY_MAJOR_VERSION >= 3
    } else if (PyLong_Check(value)) {
#else
    } else if (PyInt_Check(value)) {
#endif
        int64_t conv = extract<int64_t>(value);
        nixvalue = Value(conv);
    } else if (PyFloat_Check(value)) {
        double conv = extract<double>(value);
        nixvalue = Value(conv);
#if PY_MAJOR_VERSION >= 3
    } else if (PyUnicode_Check(value)) {
#else
    } else if (PyString_Check(value)) {
#endif
        std::string conv = extract<std::string>(value);
        nixvalue = Value(conv);
    } else {
        throw std::runtime_error("Wrong type");
    }

    return sec.createProperty(name, nixvalue);
}

Property (*createPropertyValue)(Section&, const std::string&, PyObject*) = createProperty;
Property (*createPropertyList)(Section&, const std::string&, boost::python::list&) = createProperty;

//Property createProperty(Section& sec, const std::string& name, PyObject* obj) {
//    extract<DataType> ext_type(obj);
//    if (ext_type.check()) {
//        return sec.createProperty(name, ext_type());
//    }
//
//    extract<Value&> ext_val(obj);
//    if (ext_val.check()) {
//        return sec.createProperty(name, ext_val());
//    }
//
//    extract<std::vector<Value>> ext_vec(obj);
//    if (ext_vec.check()) {
//        return sec.createProperty(name, ext_vec());
//    }
//
//    throw new std::runtime_error("Second parameter must be a Value, list of Value or DataType");
//}

boost::optional<Property> getPropertyById(const Section& section, const std::string& id) {
    Property prop = section.getProperty(id);

    return prop ? boost::optional<Property>(prop) : boost::none;
}

boost::optional<Property> getPropertyByPos(const Section& section, size_t index) {
    Property prop = section.getProperty(index);

    return prop ? boost::optional<Property>(prop) : boost::none;
}

boost::optional<Property> getPropertyByName(const Section& section, const std::string& name) {
    Property prop = section.getProperty(name);

    return prop ? boost::optional<Property>(prop) : boost::none;
}

bool hasPropertyByName(const Section& section, const std::string& name) {
  return section.hasProperty(name);
}
// Repository

void setRepository(Section& sec, const boost::optional<std::string>& str) {
    if (str)
        sec.repository(*str);
    else
        sec.repository(boost::none);
}

// Mapping

void setMapping(Section& sec, const boost::optional<std::string>& str) {
    if (str)
        sec.mapping(*str);
    else
        sec.mapping(boost::none);
}

// Link

void setLink(Section& section, const boost::optional<Section>& link) {
    if (link && *link)
        section.link(*link);
    else
        section.link(boost::none);
}

boost::optional<Section> getLink(const Section& sec) {
    Section link = sec.link();
    return link ? boost::optional<Section>(link) : boost::none;
}

// Parent

boost::optional<Section> getParent(const Section& sec) {
    Section parent = sec.parent();
    return parent ? boost::optional<Section>(parent) : boost::none;
}

void PySection::do_export() {

    PyNamedEntity<base::ISection>::do_export("Section");
    class_<Section, bases<base::NamedEntity<base::ISection>>>("Section")
        // Properties
        .add_property("repository",
                      OPT_GETTER(std::string, Section, repository),
                      setRepository,
                      doc::section_repository)
        .add_property("mapping",
                      OPT_GETTER(std::string, Section, mapping),
                      setMapping,
                      doc::section_mapping)
        .add_property("link", getLink, setLink, doc::section_link)
        // Section
        .add_property("parent", getParent, doc::section_parent)
        .def("create_section", &Section::createSection,
             doc::section_create_section)
        .def("_section_count", &Section::sectionCount)
        .def("_get_section_by_id", &getSectionById)
        .def("_get_section_by_pos", &getSectionByPos)
        .def("_delete_section_by_id", REMOVER(std::string, nix::Section, deleteSection))
        // Property
        .def("_create_property", createPropertyValue)
        .def("_create_property", createPropertyList)
        .def("has_property_by_name", hasPropertyByName,
             doc::section_has_property_by_name)
        .def("get_property_by_name", getPropertyByName,
             doc::section_get_property_by_name)
        .def("_property_count", &Section::propertyCount)
        .def("_get_property_by_id", &getPropertyById)
        .def("_get_property_by_pos", &getPropertyByPos)
        .def("_delete_property_by_id", REMOVER(std::string, nix::Section, deleteProperty))
        .def("inherited_properties", &Section::inheritedProperties)
        // Other
        .def("__str__", &toStr<Section>)
        .def("__repr__", &toStr<Section>)
        ;

    to_python_converter<std::vector<Section>, vector_transmogrify<Section>>();
    to_python_converter<boost::optional<Section>, option_transmogrify<Section>>();
    option_transmogrify<Section>::register_from_python();
}

}
<|endoftext|>


<commit_before>/*
 * This file is part of liblcf. Copyright (c) 2017 liblcf authors.
 * https://github.com/EasyRPG/liblcf - https://easyrpg.org
 *
 * liblcf is Free/Libre Open Source Software, released under the MIT License.
 * For the full copyright and license information, please view the COPYING
 * file that was distributed with this source code.
 */

#include <cstring>
#include <iostream>
#include <iomanip>
#include <type_traits>
#include "ldb_reader.h"
#include "lmt_reader.h"
#include "lmu_reader.h"
#include "lsd_reader.h"
#include "reader_struct.h"
#include "rpg_save.h"
#include "data.h"

// Read/Write Struct

template <class S>
void Struct<S>::MakeFieldMap() {
	if (!field_map.empty())
		return;
	for (int i = 0; fields[i] != NULL; i++)
		field_map[fields[i]->id] = fields[i];
}

template <class S>
void Struct<S>::MakeTagMap() {
	if (!tag_map.empty())
		return;
	for (int i = 0; fields[i] != NULL; i++)
		tag_map[fields[i]->name] = fields[i];
}

template <typename T>
struct StructDefault {
	static T make() {
		return T();
	}
};

template <>
struct StructDefault<RPG::Actor> {
	static RPG::Actor make() {
		auto actor = RPG::Actor();
		actor.Setup();
		return actor;
	}
};

template <class S>
void Struct<S>::ReadLcf(S& obj, LcfReader& stream) {
	MakeFieldMap();

	LcfReader::Chunk chunk_info;

	while (!stream.Eof()) {
		chunk_info.ID = stream.ReadInt();
		if (chunk_info.ID == 0)
			break;

		chunk_info.length = stream.ReadInt();
		if (chunk_info.length == 0)
			continue;

		typename field_map_type::const_iterator it = field_map.find(chunk_info.ID);
		if (it != field_map.end()) {
#ifdef LCF_DEBUG_TRACE
			printf("0x%02x (size: %d, pos: 0x%x): %s\n", chunk_info.ID, chunk_info.length, stream.Tell(), it->second->name);
#endif
			it->second->ReadLcf(obj, stream, chunk_info.length);
		}
		else
			stream.Skip(chunk_info);
	}
}

template<typename T>
typename std::enable_if<std::is_same<T, RPG::Save>::value ||
		std::is_same<T, RPG::Database>::value>::type
conditional_zero_writer(LcfWriter&) {
	// no-op
}

template<typename T>
typename std::enable_if<!std::is_same<T, RPG::Save>::value &&
		!std::is_same<T, RPG::Database>::value>::type
conditional_zero_writer(LcfWriter& stream) {
	stream.WriteInt(0);
}

template <class S>
void Struct<S>::WriteLcf(const S& obj, LcfWriter& stream) {
	const bool db_is2k3 = (Data::system.ldb_id == 2003);

	auto ref = StructDefault<S>::make();
	int last = -1;
	for (int i = 0; fields[i] != NULL; i++) {
		const Field<S>* field = fields[i];
		if (!db_is2k3 && field->is2k3) {
			continue;
		}
		if (field->id < last)
			std::cerr << "field order mismatch: " << field->id
					  << " after " << last
					  << " in struct " << name
					  << std::endl;
		if (field->IsDefault(obj, ref)) {
			continue;
		}
		stream.WriteInt(field->id);
		stream.WriteInt(field->LcfSize(obj, stream));
		field->WriteLcf(obj, stream);
	}
	// Writing a 0-byte after RPG::Database or RPG::Save breaks the parser in RPG_RT
	conditional_zero_writer<S>(stream);
}

template <class S>
int Struct<S>::LcfSize(const S& obj, LcfWriter& stream) {
	const bool db_is2k3 = (Data::system.ldb_id == 2003);
	int result = 0;
	auto ref = StructDefault<S>::make();
	for (int i = 0; fields[i] != NULL; i++) {
		const Field<S>* field = fields[i];
		if (!db_is2k3 && field->is2k3) {
			continue;
		}
		//printf("%s\n", field->name);
		if (field->IsDefault(obj, ref))
			continue;
		result += LcfReader::IntSize(field->id);
		int size = field->LcfSize(obj, stream);
		result += LcfReader::IntSize(size);
		result += size;
	}
	result += LcfReader::IntSize(0);
	return result;
}

template <class S>
void Struct<S>::WriteXml(const S& obj, XmlWriter& stream) {
	IDReader::WriteXmlTag(obj, name, stream);
	for (int i = 0; fields[i] != NULL; i++) {
		const Field<S>* field = fields[i];
		field->WriteXml(obj, stream);
	}
	stream.EndElement(name);
}

template <class S>
class StructXmlHandler : public XmlHandler {
public:
	StructXmlHandler(S& ref) : ref(ref), field(NULL) {
		Struct<S>::MakeTagMap();
	}

	void StartElement(XmlReader& stream, const char* name, const char** /* atts */) {
		field = Struct<S>::tag_map[name];
		field->BeginXml(ref, stream);
	}

	void EndElement(XmlReader& /* stream */, const char* /* name */) {
		field = NULL;
	}

	void CharacterData(XmlReader& /* stream */, const std::string& data) {
		if (field != NULL)
			field->ParseXml(ref, data);
	}
private:
	S& ref;
	const Field<S>* field;
};

template <class S>
class StructFieldXmlHandler : public XmlHandler {
public:
	StructFieldXmlHandler(S& ref) : ref(ref) {}

	void StartElement(XmlReader& stream, const char* name, const char** atts) {
		if (strcmp(name, Struct<S>::name) != 0)
			stream.Error("Expecting %s but got %s", Struct<S>::name, name);
		Struct<S>::IDReader::ReadIDXml(ref, atts);
		stream.SetHandler(new StructXmlHandler<S>(ref));
	}
private:
	S& ref;
};

template <class S>
void Struct<S>::BeginXml(S& obj, XmlReader& stream) {
	stream.SetHandler(new StructFieldXmlHandler<S>(obj));
}

// Read/Write std::vector<Struct>

template <class S>
void Struct<S>::ReadLcf(std::vector<S>& vec, LcfReader& stream) {
	int count = stream.ReadInt();
	vec.resize(count);
	for (int i = 0; i < count; i++) {
		IDReader::ReadID(vec[i], stream);
		TypeReader<S>::ReadLcf(vec[i], stream, 0);
	}
}

template <class S>
void Struct<S>::WriteLcf(const std::vector<S>& vec, LcfWriter& stream) {
	int count = vec.size();
	stream.WriteInt(count);
	for (int i = 0; i < count; i++) {
		IDReader::WriteID(vec[i], stream);
		TypeReader<S>::WriteLcf(vec[i], stream);
	}
}

template <class S>
int Struct<S>::LcfSize(const std::vector<S>& vec, LcfWriter& stream) {
	int result = 0;
	int count = vec.size();
	result += LcfReader::IntSize(count);
	for (int i = 0; i < count; i++) {
		result += IDReader::IDSize(vec[i]);
		result += TypeReader<S>::LcfSize(vec[i], stream);
	}
	return result;
}

template <class S>
void Struct<S>::WriteXml(const std::vector<S>& vec, XmlWriter& stream) {
	int count = vec.size();
	for (int i = 0; i < count; i++)
		TypeReader<S>::WriteXml(vec[i], stream);
}

template <class S>
class StructVectorXmlHandler : public XmlHandler {
public:
	StructVectorXmlHandler(std::vector<S>& ref) : ref(ref) {}

	void StartElement(XmlReader& stream, const char* name, const char** atts) {
		if (strcmp(name, Struct<S>::name) != 0)
			stream.Error("Expecting %s but got %s", Struct<S>::name, name);
		ref.resize(ref.size() + 1);
		S& obj = ref.back();
		Struct<S>::IDReader::ReadIDXml(obj, atts);
		stream.SetHandler(new StructXmlHandler<S>(obj));
	}
private:
	std::vector<S>& ref;
};

template <class S>
void Struct<S>::BeginXml(std::vector<S>& obj, XmlReader& stream) {
	stream.SetHandler(new StructVectorXmlHandler<S>(obj));
}

// Instantiate templates
#ifdef _MSC_VER
#pragma warning (disable : 4661)
#endif

template class Struct<RPG::Actor>;
template class Struct<RPG::Animation>;
template class Struct<RPG::AnimationCellData>;
template class Struct<RPG::AnimationFrame>;
template class Struct<RPG::AnimationTiming>;
template class Struct<RPG::Attribute>;
template class Struct<RPG::BattleCommand>;
template class Struct<RPG::BattleCommands>;
template class Struct<RPG::BattlerAnimation>;
template class Struct<RPG::BattlerAnimationData>;
template class Struct<RPG::BattlerAnimationExtension>;
template class Struct<RPG::Chipset>;
template class Struct<RPG::Class>;
template class Struct<RPG::CommonEvent>;
template class Struct<RPG::Database>;
template class Struct<RPG::Encounter>;
template class Struct<RPG::Enemy>;
template class Struct<RPG::EnemyAction>;
template class Struct<RPG::Event>;
template class Struct<RPG::EventPage>;
template class Struct<RPG::EventPageCondition>;
template class Struct<RPG::Item>;
template class Struct<RPG::ItemAnimation>;
template class Struct<RPG::Learning>;
template class Struct<RPG::Map>;
template class Struct<RPG::MapInfo>;
template class Struct<RPG::MoveRoute>;
template class Struct<RPG::Music>;
template class Struct<RPG::Save>;
template class Struct<RPG::SaveActor>;
template class Struct<RPG::SaveCommonEvent>;
template class Struct<RPG::SaveEventCommands>;
template class Struct<RPG::SaveEventData>;
template class Struct<RPG::SaveInventory>;
template class Struct<RPG::SaveMapEvent>;
template class Struct<RPG::SaveMapInfo>;
template class Struct<RPG::SavePartyLocation>;
template class Struct<RPG::SavePicture>;
template class Struct<RPG::SaveScreen>;
template class Struct<RPG::SaveSystem>;
template class Struct<RPG::SaveTarget>;
template class Struct<RPG::SaveTitle>;
template class Struct<RPG::SaveVehicleLocation>;
template class Struct<RPG::Skill>;
template class Struct<RPG::Sound>;
template class Struct<RPG::Start>;
template class Struct<RPG::State>;
template class Struct<RPG::Switch>;
template class Struct<RPG::System>;
template class Struct<RPG::Terms>;
template class Struct<RPG::Terrain>;
template class Struct<RPG::TestBattler>;
template class Struct<RPG::Troop>;
template class Struct<RPG::TroopMember>;
template class Struct<RPG::TroopPage>;
template class Struct<RPG::TroopPageCondition>;
template class Struct<RPG::Variable>;
<commit_msg>Detect corrupted chunks and reset the parser<commit_after>/*
 * This file is part of liblcf. Copyright (c) 2017 liblcf authors.
 * https://github.com/EasyRPG/liblcf - https://easyrpg.org
 *
 * liblcf is Free/Libre Open Source Software, released under the MIT License.
 * For the full copyright and license information, please view the COPYING
 * file that was distributed with this source code.
 */

#include <cstring>
#include <iostream>
#include <iomanip>
#include <type_traits>
#include "ldb_reader.h"
#include "lmt_reader.h"
#include "lmu_reader.h"
#include "lsd_reader.h"
#include "reader_struct.h"
#include "rpg_save.h"
#include "data.h"

// Read/Write Struct

template <class S>
void Struct<S>::MakeFieldMap() {
	if (!field_map.empty())
		return;
	for (int i = 0; fields[i] != NULL; i++)
		field_map[fields[i]->id] = fields[i];
}

template <class S>
void Struct<S>::MakeTagMap() {
	if (!tag_map.empty())
		return;
	for (int i = 0; fields[i] != NULL; i++)
		tag_map[fields[i]->name] = fields[i];
}

template <typename T>
struct StructDefault {
	static T make() {
		return T();
	}
};

template <>
struct StructDefault<RPG::Actor> {
	static RPG::Actor make() {
		auto actor = RPG::Actor();
		actor.Setup();
		return actor;
	}
};

template <class S>
void Struct<S>::ReadLcf(S& obj, LcfReader& stream) {
	MakeFieldMap();

	LcfReader::Chunk chunk_info;

	while (!stream.Eof()) {
		chunk_info.ID = stream.ReadInt();
		if (chunk_info.ID == 0)
			break;

		chunk_info.length = stream.ReadInt();
		if (chunk_info.length == 0)
			continue;

		typename field_map_type::const_iterator it = field_map.find(chunk_info.ID);
		if (it != field_map.end()) {
#ifdef LCF_DEBUG_TRACE
			printf("0x%02x (size: %d, pos: 0x%x): %s\n", chunk_info.ID, chunk_info.length, stream.Tell(), it->second->name);
#endif
			const auto off = stream.Tell();
			it->second->ReadLcf(obj, stream, chunk_info.length);
			const auto bytes_read = stream.Tell() - off;
			if (bytes_read != chunk_info.length) {
				fprintf(stderr, "Warning: Corrupted Chunk 0x%02x (size: %d, pos: 0x%x): %s : Read %d bytes! Reseting...\n",
						chunk_info.ID, chunk_info.length, off, it->second->name, bytes_read);
				stream.Seek(off + chunk_info.length);
			}
		}
		else {
			stream.Skip(chunk_info);
		}
	}
}

template<typename T>
typename std::enable_if<std::is_same<T, RPG::Save>::value ||
		std::is_same<T, RPG::Database>::value>::type
conditional_zero_writer(LcfWriter&) {
	// no-op
}

template<typename T>
typename std::enable_if<!std::is_same<T, RPG::Save>::value &&
		!std::is_same<T, RPG::Database>::value>::type
conditional_zero_writer(LcfWriter& stream) {
	stream.WriteInt(0);
}

template <class S>
void Struct<S>::WriteLcf(const S& obj, LcfWriter& stream) {
	const bool db_is2k3 = (Data::system.ldb_id == 2003);

	auto ref = StructDefault<S>::make();
	int last = -1;
	for (int i = 0; fields[i] != NULL; i++) {
		const Field<S>* field = fields[i];
		if (!db_is2k3 && field->is2k3) {
			continue;
		}
		if (field->id < last)
			std::cerr << "field order mismatch: " << field->id
					  << " after " << last
					  << " in struct " << name
					  << std::endl;
		if (field->IsDefault(obj, ref)) {
			continue;
		}
		stream.WriteInt(field->id);
		stream.WriteInt(field->LcfSize(obj, stream));
		field->WriteLcf(obj, stream);
	}
	// Writing a 0-byte after RPG::Database or RPG::Save breaks the parser in RPG_RT
	conditional_zero_writer<S>(stream);
}

template <class S>
int Struct<S>::LcfSize(const S& obj, LcfWriter& stream) {
	const bool db_is2k3 = (Data::system.ldb_id == 2003);
	int result = 0;
	auto ref = StructDefault<S>::make();
	for (int i = 0; fields[i] != NULL; i++) {
		const Field<S>* field = fields[i];
		if (!db_is2k3 && field->is2k3) {
			continue;
		}
		//printf("%s\n", field->name);
		if (field->IsDefault(obj, ref))
			continue;
		result += LcfReader::IntSize(field->id);
		int size = field->LcfSize(obj, stream);
		result += LcfReader::IntSize(size);
		result += size;
	}
	result += LcfReader::IntSize(0);
	return result;
}

template <class S>
void Struct<S>::WriteXml(const S& obj, XmlWriter& stream) {
	IDReader::WriteXmlTag(obj, name, stream);
	for (int i = 0; fields[i] != NULL; i++) {
		const Field<S>* field = fields[i];
		field->WriteXml(obj, stream);
	}
	stream.EndElement(name);
}

template <class S>
class StructXmlHandler : public XmlHandler {
public:
	StructXmlHandler(S& ref) : ref(ref), field(NULL) {
		Struct<S>::MakeTagMap();
	}

	void StartElement(XmlReader& stream, const char* name, const char** /* atts */) {
		field = Struct<S>::tag_map[name];
		field->BeginXml(ref, stream);
	}

	void EndElement(XmlReader& /* stream */, const char* /* name */) {
		field = NULL;
	}

	void CharacterData(XmlReader& /* stream */, const std::string& data) {
		if (field != NULL)
			field->ParseXml(ref, data);
	}
private:
	S& ref;
	const Field<S>* field;
};

template <class S>
class StructFieldXmlHandler : public XmlHandler {
public:
	StructFieldXmlHandler(S& ref) : ref(ref) {}

	void StartElement(XmlReader& stream, const char* name, const char** atts) {
		if (strcmp(name, Struct<S>::name) != 0)
			stream.Error("Expecting %s but got %s", Struct<S>::name, name);
		Struct<S>::IDReader::ReadIDXml(ref, atts);
		stream.SetHandler(new StructXmlHandler<S>(ref));
	}
private:
	S& ref;
};

template <class S>
void Struct<S>::BeginXml(S& obj, XmlReader& stream) {
	stream.SetHandler(new StructFieldXmlHandler<S>(obj));
}

// Read/Write std::vector<Struct>

template <class S>
void Struct<S>::ReadLcf(std::vector<S>& vec, LcfReader& stream) {
	int count = stream.ReadInt();
	vec.resize(count);
	for (int i = 0; i < count; i++) {
		IDReader::ReadID(vec[i], stream);
		TypeReader<S>::ReadLcf(vec[i], stream, 0);
	}
}

template <class S>
void Struct<S>::WriteLcf(const std::vector<S>& vec, LcfWriter& stream) {
	int count = vec.size();
	stream.WriteInt(count);
	for (int i = 0; i < count; i++) {
		IDReader::WriteID(vec[i], stream);
		TypeReader<S>::WriteLcf(vec[i], stream);
	}
}

template <class S>
int Struct<S>::LcfSize(const std::vector<S>& vec, LcfWriter& stream) {
	int result = 0;
	int count = vec.size();
	result += LcfReader::IntSize(count);
	for (int i = 0; i < count; i++) {
		result += IDReader::IDSize(vec[i]);
		result += TypeReader<S>::LcfSize(vec[i], stream);
	}
	return result;
}

template <class S>
void Struct<S>::WriteXml(const std::vector<S>& vec, XmlWriter& stream) {
	int count = vec.size();
	for (int i = 0; i < count; i++)
		TypeReader<S>::WriteXml(vec[i], stream);
}

template <class S>
class StructVectorXmlHandler : public XmlHandler {
public:
	StructVectorXmlHandler(std::vector<S>& ref) : ref(ref) {}

	void StartElement(XmlReader& stream, const char* name, const char** atts) {
		if (strcmp(name, Struct<S>::name) != 0)
			stream.Error("Expecting %s but got %s", Struct<S>::name, name);
		ref.resize(ref.size() + 1);
		S& obj = ref.back();
		Struct<S>::IDReader::ReadIDXml(obj, atts);
		stream.SetHandler(new StructXmlHandler<S>(obj));
	}
private:
	std::vector<S>& ref;
};

template <class S>
void Struct<S>::BeginXml(std::vector<S>& obj, XmlReader& stream) {
	stream.SetHandler(new StructVectorXmlHandler<S>(obj));
}

// Instantiate templates
#ifdef _MSC_VER
#pragma warning (disable : 4661)
#endif

template class Struct<RPG::Actor>;
template class Struct<RPG::Animation>;
template class Struct<RPG::AnimationCellData>;
template class Struct<RPG::AnimationFrame>;
template class Struct<RPG::AnimationTiming>;
template class Struct<RPG::Attribute>;
template class Struct<RPG::BattleCommand>;
template class Struct<RPG::BattleCommands>;
template class Struct<RPG::BattlerAnimation>;
template class Struct<RPG::BattlerAnimationData>;
template class Struct<RPG::BattlerAnimationExtension>;
template class Struct<RPG::Chipset>;
template class Struct<RPG::Class>;
template class Struct<RPG::CommonEvent>;
template class Struct<RPG::Database>;
template class Struct<RPG::Encounter>;
template class Struct<RPG::Enemy>;
template class Struct<RPG::EnemyAction>;
template class Struct<RPG::Event>;
template class Struct<RPG::EventPage>;
template class Struct<RPG::EventPageCondition>;
template class Struct<RPG::Item>;
template class Struct<RPG::ItemAnimation>;
template class Struct<RPG::Learning>;
template class Struct<RPG::Map>;
template class Struct<RPG::MapInfo>;
template class Struct<RPG::MoveRoute>;
template class Struct<RPG::Music>;
template class Struct<RPG::Save>;
template class Struct<RPG::SaveActor>;
template class Struct<RPG::SaveCommonEvent>;
template class Struct<RPG::SaveEventCommands>;
template class Struct<RPG::SaveEventData>;
template class Struct<RPG::SaveInventory>;
template class Struct<RPG::SaveMapEvent>;
template class Struct<RPG::SaveMapInfo>;
template class Struct<RPG::SavePartyLocation>;
template class Struct<RPG::SavePicture>;
template class Struct<RPG::SaveScreen>;
template class Struct<RPG::SaveSystem>;
template class Struct<RPG::SaveTarget>;
template class Struct<RPG::SaveTitle>;
template class Struct<RPG::SaveVehicleLocation>;
template class Struct<RPG::Skill>;
template class Struct<RPG::Sound>;
template class Struct<RPG::Start>;
template class Struct<RPG::State>;
template class Struct<RPG::Switch>;
template class Struct<RPG::System>;
template class Struct<RPG::Terms>;
template class Struct<RPG::Terrain>;
template class Struct<RPG::TestBattler>;
template class Struct<RPG::Troop>;
template class Struct<RPG::TroopMember>;
template class Struct<RPG::TroopPage>;
template class Struct<RPG::TroopPageCondition>;
template class Struct<RPG::Variable>;
<|endoftext|>


<commit_before>/*************************************************************************
 *
 * Copyright 2016 Realm Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * 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.
 *
 **************************************************************************/

#ifndef REALM_UNICODE_HPP
#define REALM_UNICODE_HPP

#include <locale>
#include <cstdint>
#include <string>

#include <realm/util/safe_int_ops.hpp>
#include <realm/string_data.hpp>
#include <realm/util/features.h>
#include <realm/utilities.hpp>

namespace realm {

enum string_compare_method_t {
    STRING_COMPARE_CORE,
    STRING_COMPARE_CPP11,
    STRING_COMPARE_CALLBACK,
    STRING_COMPARE_CORE_SIMILAR
};

extern StringCompareCallback string_compare_callback;
extern string_compare_method_t string_compare_method;

// Description for set_string_compare_method():
//
// Short summary: iOS language binding: call
//     set_string_compare_method() for fast but slightly inaccurate sort in some countries, or
//     set_string_compare_method(2, callbackptr) for slow but precise sort (see callbackptr below)
//
// Different countries ('locales') have different sorting order for strings and letters. Because there unfortunatly
// doesn't exist any unified standardized way to compare strings in C++ on multiple platforms, we need this method.
//
// It determins how sorting a TableView by a String column must take place. The 'method' argument can be:
//
// 0: Fast core-only compare (no OS/framework calls). LIMITATIONS: Works only upto 'Latin Extended 2' (unicodes
// 0...591). Also, sorting order is according to 'en_US' so it may be slightly inaccurate for some countries.
// 'callback' argument is ignored.
//
// Return value: Always 'true'
//
// 1: Native C++11 method if core is compiled as C++11. Gives precise sorting according
// to user's current locale. LIMITATIONS: Currently works only on Windows and on Linux with clang. Does NOT work on
// iOS (due to only 'C' locale being available in CoreFoundation, which puts 'Z' before 'a'). Unknown if works on
// Windows Phone / Android. Furthermore it does NOT work on Linux with gcc 4.7 or 4.8 (lack of c++11 feature that
// can convert utf8->wstring without calls to setlocale()).
//
// Return value: 'true' if supported, otherwise 'false' (if so, then previous setting, if any, is preserved).
//
// 2: Callback method. Language binding / C++ user must provide a utf-8 callback method of prototype:
// bool callback(const char* string1, const char* string2) where 'callback' must return bool(string1 < string2).
//
// Return value: Always 'true'
//
// Default is method = 0 if the function is never called
//
// NOT THREAD SAFE! Call once during initialization or make sure it's not called simultaneously with different
// arguments. The setting is remembered per-process; it does NOT need to be called prior to each sort
bool set_string_compare_method(string_compare_method_t method, StringCompareCallback callback);

// Return size in bytes of utf8 character. No error checking
size_t sequence_length(char lead);

// Limitations for case insensitive string search
// Case insensitive search (equal, begins_with, ends_with and contains)
// only works for unicodes 0...0x7f which is the same as the 0...127
// ASCII character set (letters a-z and A-Z).

// In does *not* work for the 0...255 ANSI character set that contains
// characters from many European countries like Germany, France, Denmark,
// etc.

// It also does not work for characters from non-western countries like
// Japan, Russia, Arabia, etc.

// If there exists characters outside the ASCII range either in the text
// to be searched for, or in the Realm string column which is searched
// in, then the compare yields a random result such that the row may or
// may not be included in the result set.

// Return bool(string1 < string2)
bool utf8_compare(StringData string1, StringData string2);

// Return unicode value of character.
uint32_t utf8value(const char* character);

inline bool equal_sequence(const char*& begin, const char* end, const char* begin2);

// FIXME: The current approach to case insensitive comparison requires
// that case mappings can be done in a way that does not change he
// number of bytes used to encode the individual Unicode
// character. This is not generally the case, so, as far as I can see,
// this approach has no future.
//
// FIXME: The current approach to case insensitive comparison relies
// on checking each "haystack" character against the corresponding
// character in both a lower cased and an upper cased version of the
// "needle". While this leads to efficient comparison, it ignores the
// fact that "case folding" is the only correct approach to case
// insensitive comparison in a locale agnostic Unicode
// environment.
//
// See
//   http://www.w3.org/International/wiki/Case_folding
//   http://userguide.icu-project.org/transforms/casemappings#TOC-Case-Folding.
//
// The ideal API would probably be something like this:
//
//   case_fold:        utf_8 -> case_folded
//   equal_case_fold:  (needle_case_folded, single_haystack_entry_utf_8) -> found
//   search_case_fold: (needle_case_folded, huge_haystack_string_utf_8) -> found_at_position
//
// The case folded form would probably be using UTF-32 or UTF-16.

/// If successful, returns a string of the same size as \a source.
/// Returns none if invalid UTF-8 encoding was encountered.
util::Optional<std::string> case_map(StringData source, bool upper);

enum IgnoreErrorsTag { IgnoreErrors };
std::string case_map(StringData source, bool upper, IgnoreErrorsTag);

/// Assumes that the sizes of \a needle_upper and \a needle_lower are
/// identical to the size of \a haystack. Returns false if the needle
/// is different from the haystack.
bool equal_case_fold(StringData haystack, const char* needle_upper, const char* needle_lower);

/// Assumes that the sizes of \a needle_upper and \a needle_lower are
/// both equal to \a needle_size. Returns haystack.size() if the
/// needle was not found.
size_t search_case_fold(StringData haystack, const char* needle_upper, const char* needle_lower, size_t needle_size);

/// Assumes that the sizes of \a needle_upper and \a needle_lower are
/// both equal to \a needle_size. Returns false if the
/// needle was not found.
bool contains_ins(StringData haystack, const char* needle_upper, const char* needle_lower, size_t needle_size, const std::array<uint8_t, 256> &charmap);

/// Case insensitive wildcard matching ('?' for single char, '*' for zero or more chars)
bool string_like_ins(StringData text, StringData pattern) noexcept;
bool string_like_ins(StringData text, StringData upper, StringData lower) noexcept;

} // namespace realm

#endif // REALM_UNICODE_HPP
<commit_msg>add like to the list of case insensitive limited predicates<commit_after>/*************************************************************************
 *
 * Copyright 2016 Realm Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * 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.
 *
 **************************************************************************/

#ifndef REALM_UNICODE_HPP
#define REALM_UNICODE_HPP

#include <locale>
#include <cstdint>
#include <string>

#include <realm/util/safe_int_ops.hpp>
#include <realm/string_data.hpp>
#include <realm/util/features.h>
#include <realm/utilities.hpp>

namespace realm {

enum string_compare_method_t {
    STRING_COMPARE_CORE,
    STRING_COMPARE_CPP11,
    STRING_COMPARE_CALLBACK,
    STRING_COMPARE_CORE_SIMILAR
};

extern StringCompareCallback string_compare_callback;
extern string_compare_method_t string_compare_method;

// Description for set_string_compare_method():
//
// Short summary: iOS language binding: call
//     set_string_compare_method() for fast but slightly inaccurate sort in some countries, or
//     set_string_compare_method(2, callbackptr) for slow but precise sort (see callbackptr below)
//
// Different countries ('locales') have different sorting order for strings and letters. Because there unfortunatly
// doesn't exist any unified standardized way to compare strings in C++ on multiple platforms, we need this method.
//
// It determins how sorting a TableView by a String column must take place. The 'method' argument can be:
//
// 0: Fast core-only compare (no OS/framework calls). LIMITATIONS: Works only upto 'Latin Extended 2' (unicodes
// 0...591). Also, sorting order is according to 'en_US' so it may be slightly inaccurate for some countries.
// 'callback' argument is ignored.
//
// Return value: Always 'true'
//
// 1: Native C++11 method if core is compiled as C++11. Gives precise sorting according
// to user's current locale. LIMITATIONS: Currently works only on Windows and on Linux with clang. Does NOT work on
// iOS (due to only 'C' locale being available in CoreFoundation, which puts 'Z' before 'a'). Unknown if works on
// Windows Phone / Android. Furthermore it does NOT work on Linux with gcc 4.7 or 4.8 (lack of c++11 feature that
// can convert utf8->wstring without calls to setlocale()).
//
// Return value: 'true' if supported, otherwise 'false' (if so, then previous setting, if any, is preserved).
//
// 2: Callback method. Language binding / C++ user must provide a utf-8 callback method of prototype:
// bool callback(const char* string1, const char* string2) where 'callback' must return bool(string1 < string2).
//
// Return value: Always 'true'
//
// Default is method = 0 if the function is never called
//
// NOT THREAD SAFE! Call once during initialization or make sure it's not called simultaneously with different
// arguments. The setting is remembered per-process; it does NOT need to be called prior to each sort
bool set_string_compare_method(string_compare_method_t method, StringCompareCallback callback);

// Return size in bytes of utf8 character. No error checking
size_t sequence_length(char lead);

// Limitations for case insensitive string search
// Case insensitive search (equal, begins_with, ends_with, like and contains)
// only works for unicodes 0...0x7f which is the same as the 0...127
// ASCII character set (letters a-z and A-Z).

// In does *not* work for the 0...255 ANSI character set that contains
// characters from many European countries like Germany, France, Denmark,
// etc.

// It also does not work for characters from non-western countries like
// Japan, Russia, Arabia, etc.

// If there exists characters outside the ASCII range either in the text
// to be searched for, or in the Realm string column which is searched
// in, then the compare yields a random result such that the row may or
// may not be included in the result set.

// Return bool(string1 < string2)
bool utf8_compare(StringData string1, StringData string2);

// Return unicode value of character.
uint32_t utf8value(const char* character);

inline bool equal_sequence(const char*& begin, const char* end, const char* begin2);

// FIXME: The current approach to case insensitive comparison requires
// that case mappings can be done in a way that does not change he
// number of bytes used to encode the individual Unicode
// character. This is not generally the case, so, as far as I can see,
// this approach has no future.
//
// FIXME: The current approach to case insensitive comparison relies
// on checking each "haystack" character against the corresponding
// character in both a lower cased and an upper cased version of the
// "needle". While this leads to efficient comparison, it ignores the
// fact that "case folding" is the only correct approach to case
// insensitive comparison in a locale agnostic Unicode
// environment.
//
// See
//   http://www.w3.org/International/wiki/Case_folding
//   http://userguide.icu-project.org/transforms/casemappings#TOC-Case-Folding.
//
// The ideal API would probably be something like this:
//
//   case_fold:        utf_8 -> case_folded
//   equal_case_fold:  (needle_case_folded, single_haystack_entry_utf_8) -> found
//   search_case_fold: (needle_case_folded, huge_haystack_string_utf_8) -> found_at_position
//
// The case folded form would probably be using UTF-32 or UTF-16.

/// If successful, returns a string of the same size as \a source.
/// Returns none if invalid UTF-8 encoding was encountered.
util::Optional<std::string> case_map(StringData source, bool upper);

enum IgnoreErrorsTag { IgnoreErrors };
std::string case_map(StringData source, bool upper, IgnoreErrorsTag);

/// Assumes that the sizes of \a needle_upper and \a needle_lower are
/// identical to the size of \a haystack. Returns false if the needle
/// is different from the haystack.
bool equal_case_fold(StringData haystack, const char* needle_upper, const char* needle_lower);

/// Assumes that the sizes of \a needle_upper and \a needle_lower are
/// both equal to \a needle_size. Returns haystack.size() if the
/// needle was not found.
size_t search_case_fold(StringData haystack, const char* needle_upper, const char* needle_lower, size_t needle_size);

/// Assumes that the sizes of \a needle_upper and \a needle_lower are
/// both equal to \a needle_size. Returns false if the
/// needle was not found.
bool contains_ins(StringData haystack, const char* needle_upper, const char* needle_lower, size_t needle_size, const std::array<uint8_t, 256> &charmap);

/// Case insensitive wildcard matching ('?' for single char, '*' for zero or more chars)
bool string_like_ins(StringData text, StringData pattern) noexcept;
bool string_like_ins(StringData text, StringData upper, StringData lower) noexcept;

} // namespace realm

#endif // REALM_UNICODE_HPP
<|endoftext|>


<commit_before>// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
/*
 * Ceph - scalable distributed file system
 *
 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
 *
 * This is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 2.1, as published by the Free Software
 * Foundation.  See file COPYING.
 *
 */

#include "RAID4PG.h"
#include "OSD.h"

#include "common/Logger.h"

#include "messages/MOSDOp.h"
#include "messages/MOSDOpReply.h"

#include "messages/MOSDPGNotify.h"
#include "messages/MOSDPGRemove.h"

#include "config.h"

#define  dout(l)    if (l<=g_conf.debug || l<=g_conf.debug_osd) *_dout << dbeginl << g_clock.now() << " osd" << osd->get_nodeid() << " " << (osd->osdmap ? osd->osdmap->get_epoch():0) << " " << *this << " "

#include <errno.h>
#include <sys/stat.h>

bool RAID4PG::preprocess_op(MOSDOp *op, utime_t now)
{
  return false;
}

void RAID4PG::do_op(MOSDOp *op)
{

}

void RAID4PG::do_op_reply(MOSDOpReply *reply)
{

}

// -----------------
// pg changes

bool RAID4PG::same_for_read_since(epoch_t e)
{
  return e >= info.history.same_since;   // whole pg set same
}

bool RAID4PG::same_for_modify_since(epoch_t e)
{
  return e >= info.history.same_since;   // whole pg set same
}

bool RAID4PG::same_for_rep_modify_since(epoch_t e)
{
  return e >= info.history.same_since;   // whole pg set same
}

// -----------------
// RECOVERY

bool RAID4PG::is_missing_object(object_t oid)
{
  return false;
}

void RAID4PG::wait_for_missing_object(object_t oid, MOSDOp *op)
{
  //assert(0);
}

void RAID4PG::note_failed_osd(int o)
{
  dout(10) << "note_failed_osd osd" << o << dendl;
  //assert(0);
}

void RAID4PG::on_acker_change()
{
  dout(10) << "on_acker_change" << dendl;
  //assert(0);
}

void RAID4PG::on_role_change()
{
  dout(10) << "on_role_change" << dendl;
  //assert(0);
}

void RAID4PG::on_change()
{
  dout(10) << "on_change" << dendl;
  //assert(0);
}

// misc recovery crap

void RAID4PG::clean_up_local(ObjectStore::Transaction&)
{
}

void RAID4PG::cancel_recovery()
{
  //assert(0);
}

bool RAID4PG::do_recovery()
{
  //assert(0);
  return false;
}

void RAID4PG::purge_strays()
{
  //assert(0);
}

<commit_msg>some sample code for mapping logical object extent onto physical objects<commit_after>// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
/*
 * Ceph - scalable distributed file system
 *
 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
 *
 * This is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 2.1, as published by the Free Software
 * Foundation.  See file COPYING.
 *
 */

#include "RAID4PG.h"
#include "OSD.h"

#include "common/Logger.h"

#include "messages/MOSDOp.h"
#include "messages/MOSDOpReply.h"

#include "messages/MOSDPGNotify.h"
#include "messages/MOSDPGRemove.h"

#include "config.h"

#define  dout(l)    if (l<=g_conf.debug || l<=g_conf.debug_osd) *_dout << dbeginl << g_clock.now() << " osd" << osd->get_nodeid() << " " << (osd->osdmap ? osd->osdmap->get_epoch():0) << " " << *this << " "

#include <errno.h>
#include <sys/stat.h>

bool RAID4PG::preprocess_op(MOSDOp *op, utime_t now)
{
  return false;
}

void RAID4PG::do_op(MOSDOp *op)
{

  // a write will do something like
  object_t oid = op->get_oid();   // logical object
  pg_t pg = op->get_pg();
  ObjectLayout layout = op->get_layout();
  bufferlist data = op->get_data();
  off_t off = op->get_offset();
  off_t left = op->get_length();

  // map data onto pobjects
  int n = pg.size() - 1;  // n+1 raid4
  int rank = (off % layout.stripe_unit) % n;
  off_t off_in_bl = 0;
  while (left > 0) {
    pobject_t po(0, rank, oid);
    off_t off_in_po = off % layout.stripe_unit;
    off_t stripe_unit_end = off - off_in_po + layout.stripe_unit;
    off_t len_in_po = MAX(left, stripe_unit_end-off);
    bufferlist data_in_po;
    data_in_po.substr_of(data, off_in_bl, len_in_po);

    // next!
    off_in_bl += len_in_po;
    rank++;
    if (rank == n) rank = 0;
  }

}

void RAID4PG::do_op_reply(MOSDOpReply *reply)
{

}

// -----------------
// pg changes

bool RAID4PG::same_for_read_since(epoch_t e)
{
  return e >= info.history.same_since;   // whole pg set same
}

bool RAID4PG::same_for_modify_since(epoch_t e)
{
  return e >= info.history.same_since;   // whole pg set same
}

bool RAID4PG::same_for_rep_modify_since(epoch_t e)
{
  return e >= info.history.same_since;   // whole pg set same
}

// -----------------
// RECOVERY

bool RAID4PG::is_missing_object(object_t oid)
{
  return false;
}

void RAID4PG::wait_for_missing_object(object_t oid, MOSDOp *op)
{
  //assert(0);
}

void RAID4PG::note_failed_osd(int o)
{
  dout(10) << "note_failed_osd osd" << o << dendl;
  //assert(0);
}

void RAID4PG::on_acker_change()
{
  dout(10) << "on_acker_change" << dendl;
  //assert(0);
}

void RAID4PG::on_role_change()
{
  dout(10) << "on_role_change" << dendl;
  //assert(0);
}

void RAID4PG::on_change()
{
  dout(10) << "on_change" << dendl;
  //assert(0);
}

// misc recovery crap

void RAID4PG::clean_up_local(ObjectStore::Transaction&)
{
}

void RAID4PG::cancel_recovery()
{
  //assert(0);
}

bool RAID4PG::do_recovery()
{
  //assert(0);
  return false;
}

void RAID4PG::purge_strays()
{
  //assert(0);
}

<|endoftext|>


<commit_before>#include "webcam.hpp"

using namespace cv;
using namespace std;

int main (int argc, char** argv) {

 CvCapture* capture = 0;
 int width, height, fps;

 capture = cvCaptureFromCAM(0);

 if (!capture) {
  printf("No camera detected!");
  return -1;
 }

 ifstream configFile (".config");

 if (configFile.is_open()) {

  //probably want to support corrupted .config
  string line;
  getline(configFile, line);
  istringstream(line)>>width;
  getline(configFile, line);
  istringstream(line)>>height;
  cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, width);
  cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, height);

  configFile.close();

 } else {

  initResolutions();

  for (int i=36; i<150; i++) {
   cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, resolutions[i].width);
   cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, resolutions[i].height);
  }

  width = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH);
  height = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT);

  ofstream configFileOut(".config");
  configFileOut << width;
  configFileOut << "\n";
  configFileOut << height;
  configFileOut << "\n";
  configFileOut.close();
 }

 bool keepGoing = true;

// srand(890);//not interested in good randomness

 Mat image;
 while (keepGoing) {

  image = cvQueryFrame(capture);
  imshow("webcam", image);

// thresholds on dark regions
  Mat black, blurred;
  Mat channel[3];
  split(image, channel);
  equalizeHist(channel[0], channel[0]);
  equalizeHist(channel[1], channel[1]);
  equalizeHist(channel[2], channel[2]);
  merge(channel, 3, black);
  blur(black, blurred, Size(width/4.5,height/9));
  split(blurred, channel);
  black = (channel[0] + channel[1] + channel[2])/3.0;
  equalizeHist(black, black);
  bitwise_not(black,black);
  threshold(black, black, 210, 1, THRESH_BINARY);
//  imshow("black", black);

  add(black, Scalar(2), black);
  Mat fgd, bgd;
  grabCut(image, black, Rect(1,1), bgd, fgd, 5, GC_INIT_WITH_MASK);
  imshow("bgd1", bgd);
  imshow("fgd1", fgd);
  grabCut(image, black, Rect(1,1), bgd, fgd, 15, GC_INIT_WITH_MASK);
  imshow("bgd2", bgd);
  imshow("fgd2", fgd);
  grabCut(image, black, Rect(1,1), bgd, fgd, 25, GC_INIT_WITH_MASK);
  imshow("bgd3", bgd);
  imshow("fgd3", fgd);

/*
  split(image, channel);
  channel[0] = channel[0].mul(black);
  channel[1] = channel[1].mul(black);
  channel[2] = channel[2].mul(black);
  merge(channel, 3, image);
*/
//  imshow("yox", image);

//do some weird morphological closing thing
//  Mat channel[3];

/*
  Mat canny;
  Canny(image, canny, 0, 50);
  imshow("canny", canny);
*/

/*
  Mat fill = image.clone();
  Point seed(rand()%width, rand()%height);
  floodFill(fill, seed, Scalar(200,0,0), 0, Scalar(0,0,0), Scalar(25,25,25));
  imshow("fill", fill);
*/

  keepGoing = (waitKey(25)<0);

 }

 cvReleaseCapture(&capture);

 return 0;
}
<commit_msg>hacking<commit_after>#include "webcam.hpp"

using namespace cv;
using namespace std;

int main (int argc, char** argv) {

 CvCapture* capture = 0;
 int width, height, fps;

 capture = cvCaptureFromCAM(0);

 if (!capture) {
  printf("No camera detected!");
  return -1;
 }

 ifstream configFile (".config");

 if (configFile.is_open()) {

  //probably want to support corrupted .config
  string line;
  getline(configFile, line);
  istringstream(line)>>width;
  getline(configFile, line);
  istringstream(line)>>height;
  cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, width);
  cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, height);

  configFile.close();

 } else {

  initResolutions();

  for (int i=36; i<150; i++) {
   cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, resolutions[i].width);
   cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, resolutions[i].height);
  }

  width = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH);
  height = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT);

  ofstream configFileOut(".config");
  configFileOut << width;
  configFileOut << "\n";
  configFileOut << height;
  configFileOut << "\n";
  configFileOut.close();
 }

 bool keepGoing = true;

// srand(890);//not interested in good randomness

 Mat image;
 while (keepGoing) {

  image = cvQueryFrame(capture);
  imshow("webcam", image);

// thresholds on dark regions
  Mat black, blurred;
  Mat channel[3];
  split(image, channel);
  equalizeHist(channel[0], channel[0]);
  equalizeHist(channel[1], channel[1]);
  equalizeHist(channel[2], channel[2]);
  merge(channel, 3, black);
  blur(black, blurred, Size(width/4.5,height/9));
  split(blurred, channel);
  black = (channel[0] + channel[1] + channel[2])/3.0;
  equalizeHist(black, black);
  bitwise_not(black,black);
  threshold(black, black, 210, 1, THRESH_BINARY);
//  imshow("black", black);

  add(black, Scalar(2), black);
  Mat fgd, bgd;
  grabCut(image, black, Rect(1,1,1,1), bgd, fgd, 5, GC_INIT_WITH_MASK);
  imshow("bgd1", bgd);
  imshow("fgd1", fgd);
  grabCut(image, black, Rect(1,1,1,1), bgd, fgd, 15, GC_INIT_WITH_MASK);
  imshow("bgd2", bgd);
  imshow("fgd2", fgd);
  grabCut(image, black, Rect(1,1,1,1), bgd, fgd, 25, GC_INIT_WITH_MASK);
  imshow("bgd3", bgd);
  imshow("fgd3", fgd);

/*
  split(image, channel);
  channel[0] = channel[0].mul(black);
  channel[1] = channel[1].mul(black);
  channel[2] = channel[2].mul(black);
  merge(channel, 3, image);
*/
//  imshow("yox", image);

//do some weird morphological closing thing
//  Mat channel[3];

/*
  Mat canny;
  Canny(image, canny, 0, 50);
  imshow("canny", canny);
*/

/*
  Mat fill = image.clone();
  Point seed(rand()%width, rand()%height);
  floodFill(fill, seed, Scalar(200,0,0), 0, Scalar(0,0,0), Scalar(25,25,25));
  imshow("fill", fill);
*/

  keepGoing = (waitKey(25)<0);

 }

 cvReleaseCapture(&capture);

 return 0;
}
<|endoftext|>


<commit_before>#include "webcam.hpp"

using namespace cv;
using namespace std;

int main (int argc, char** argv) {

 CvCapture* capture = 0;
 int width, height, fps;

 capture = cvCaptureFromCAM(0);

 if (!capture) {
  printf("No camera detected!");
  return -1;
 }

 ifstream configFile (".config");

 if (configFile.is_open()) {

  //probably want to support corrupted .config
  string line;
  getline(configFile, line);
  istringstream(line)>>width;
  getline(configFile, line);
  istringstream(line)>>height;
  cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, width);
  cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, height);

  configFile.close();

 } else {

  initResolutions();

  for (int i=36; i<150; i++) {
   cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, resolutions[i].width);
   cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, resolutions[i].height);
  }

  width = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH);
  height = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT);

  ofstream configFileOut(".config");
  configFileOut << width;
  configFileOut << "\n";
  configFileOut << height;
  configFileOut << "\n";
  configFileOut.close();
 }

 bool keepGoing = true;

// srand(890);//not interested in good randomness

 Mat image;
 Mat channel[3];

 while (keepGoing) {

  image = cvQueryFrame(capture);
  //imshow("webcam", image);

// thresholds on dark regions

  Mat gray, blurred_gray, threshold_gray;
  cvtColor(image, gray, CV_BGR2GRAY);
  blur(gray, blurred_gray, Size(width/10,height/20));
  equalizeHist(blurred_gray, blurred_gray);
  bitwise_not(blurred_gray, blurred_gray);
  threshold(blurred_gray, threshold_gray, 210, 1, THRESH_BINARY);
  imshow("threshold", threshold_gray);

  Mat mask = threshold_gray.mul(blurred_gray);
  imshow("mask", mask);

  Moments lol = moments(mask, 1);
  circle(image, Point(lol.m10/lol.m00,lol.m01/lol.m00),20,Scalar(128),30);
  imshow("threshold", image);
  keepGoing = (waitKey(25)<0);

 }

 cvReleaseCapture(&capture);

 return 0;
}
<commit_msg>hacking<commit_after>#include "webcam.hpp"

using namespace cv;
using namespace std;

int main (int argc, char** argv) {

 CvCapture* capture = 0;
 int width, height, fps;

 capture = cvCaptureFromCAM(0);

 if (!capture) {
  printf("No camera detected!");
  return -1;
 }

 ifstream configFile (".config");

 if (configFile.is_open()) {

  //probably want to support corrupted .config
  string line;
  getline(configFile, line);
  istringstream(line)>>width;
  getline(configFile, line);
  istringstream(line)>>height;
  cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, width);
  cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, height);

  configFile.close();

 } else {

  initResolutions();

  for (int i=36; i<150; i++) {
   cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, resolutions[i].width);
   cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, resolutions[i].height);
  }

  width = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH);
  height = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT);

  ofstream configFileOut(".config");
  configFileOut << width;
  configFileOut << "\n";
  configFileOut << height;
  configFileOut << "\n";
  configFileOut.close();
 }

 bool keepGoing = true;

// srand(890);//not interested in good randomness

 Mat image;
 Mat channel[3];

 while (keepGoing) {

  image = cvQueryFrame(capture);
  //imshow("webcam", image);

// thresholds on dark regions

  Mat gray, blurred_gray, threshold_gray;
  cvtColor(image, gray, CV_BGR2GRAY);
  blur(gray, blurred_gray, Size(width/10,height/20));
  equalizeHist(blurred_gray, blurred_gray);
  bitwise_not(blurred_gray, blurred_gray);
  threshold(blurred_gray, threshold_gray, 210, 1, THRESH_BINARY);
  imshow("threshold", threshold_gray);

  Mat mask = threshold_gray.mul(blurred_gray);
  imshow("mask", mask);

  Moments lol = moments(mask, 1);
  circle(image, Point(lol.m10/lol.m00,lol.m01/lol.m00),20,Scalar(128),30);
  imshow("leimage", image);
  keepGoing = (waitKey(25)<0);

 }

 cvReleaseCapture(&capture);

 return 0;
}
<|endoftext|>


<commit_before>
#include <boost/python.hpp>
using namespace boost::python;

class Point {
public:
	Point(float x = 0, float y = 0) {
		_x = x;
		_y = y;
	}

	float x() const {
		return _x;
	}
	void set_x(float x) {
		_x = x;
	}

	float y() const {
		return _y;
	}
	void set_y(float y) {
		_y = y;
	}

private:
	float _x, _y;
};

class Robot {
public:
	Point pos, vel;
	float angle, angle_vel;
};

BOOST_PYTHON_MODULE(robocup)
{
	class_<Point>("Point", init<float, float>())
		.add_property("x", &Point::x, &Point::set_x)
		.add_property("y", &Point::y, &Point::set_y)
	;

	class_<Robot>("Robot", init<>())
		.def_readwrite("pos", &Robot::pos)
		.def_readwrite("vel", &Robot::vel)
		.def_readwrite("angle", &Robot::angle)
		.def_readwrite("angle_vel", &Robot::angle_vel)
	;
}

<commit_msg>removed junk stuff from boost python wrapper<commit_after>
#include <boost/python.hpp>
using namespace boost::python;

BOOST_PYTHON_MODULE(robocup)
{
	class_<Point>("Point", init<float, float>())
		.add_property("x", &Point::x, &Point::set_x)
		.add_property("y", &Point::y, &Point::set_y)
	;

	class_<Robot>("Robot", init<>())
		.def_readwrite("pos", &Robot::pos)
		.def_readwrite("vel", &Robot::vel)
		.def_readwrite("angle", &Robot::angle)
		.def_readwrite("angle_vel", &Robot::angle_vel)
	;
}
<|endoftext|>


<commit_before>/*
Copyright 2015 Adam Grandquist

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.
 */
/**
 * @author Adam Grandquist
 * @copyright Apache
 */

#ifndef REQL_REQL_PROTOCOL_HPP_
#define REQL_REQL_PROTOCOL_HPP_

#include "./reql/handshake.hpp"
#include "./reql/query.hpp"
#include "./reql/socket.hpp"

#include <atomic>
#include <cstdint>
#include <sstream>
#include <string>
#include <thread>

namespace _ReQL {

template <class auth_e, class handshake_e, class socket_e>
class Protocol_t {
public:
  template <class addr_t, class auth_t, class func_t, class port_t>
  void connect(const addr_t &addr, const port_t &port, const auth_t &auth, func_t func) {
    p_sock.connect(addr, port);
    Handshake_t<auth_e, handshake_e>(p_sock, auth);
    std::thread([func, this] {
      size_t buff_size;
      std::ostringstream buffer;
      while (true) {
        while (buff_size < 12) {
          auto string = p_sock.read();
          buff_size += string.size();
          buffer << string;
        }
        auto string = buffer.str();
        buffer.clear();
        buffer << string.substr(12);
        auto token = get_token(string.c_str());
        auto size = get_size(string.c_str() + 8);
        while (buff_size < size) {
          auto string = p_sock.read();
          buff_size += string.size();
          buffer << string;
        }
        string = buffer.str();
        buffer.clear();
        buffer << string.substr(size);
        run(token, make_query(REQL_CONTINUE));
        func(string.substr(0, size), token);
      }
    }).detach();
  }

  void disconnect() {
    p_sock.disconnect();
  }

  bool connected() const {
    return p_sock.connected();
  }

  template <class query_t>
  auto run(query_t query) {
    auto token = p_next_token++;
    run(token, query);
    return token;
  }

  void stop(std::uint64_t token) {
    run(token, make_query(REQL_STOP));
  }

private:
  template <class query_t>
  void run(std::uint64_t token, query_t query) {
    std::ostringstream stream("\0\0\0\0\0\0\0\0\0\0\0\0", std::ios_base::ate);
    stream << std::boolalpha
           << std::setprecision(std::numeric_limits<double>::digits10 + 1)
           << query;

    auto wire_query = stream.str();
    auto size = wire_query.size();
    auto data = wire_query.data();

    make_token(data, token);
    make_size(data + 8, static_cast<std::uint32_t>(size - 12));

    p_sock.write(data, size);
  }

  static std::uint32_t get_size(const char *buf) {
    return (static_cast<std::uint32_t>(buf[0]) << 0) |
    (static_cast<std::uint32_t>(buf[1]) << 8) |
    (static_cast<std::uint32_t>(buf[2]) << 16) |
    (static_cast<std::uint32_t>(buf[3]) << 24);
  }

  static void make_size(char *buf, const std::uint32_t magic) {
    buf[0] = static_cast<char>((magic >> 0) & 0xFF);
    buf[1] = static_cast<char>((magic >> 8) & 0xFF);
    buf[2] = static_cast<char>((magic >> 16) & 0xFF);
    buf[3] = static_cast<char>((magic >> 24) & 0xFF);
  }

  static std::uint64_t get_token(const char *buf) {
    return (static_cast<std::uint64_t>(buf[0]) << 0) |
    (static_cast<std::uint64_t>(buf[1]) << 8) |
    (static_cast<std::uint64_t>(buf[2]) << 16) |
    (static_cast<std::uint64_t>(buf[3]) << 24) |
    (static_cast<std::uint64_t>(buf[4]) << 32) |
    (static_cast<std::uint64_t>(buf[5]) << 40) |
    (static_cast<std::uint64_t>(buf[6]) << 48) |
    (static_cast<std::uint64_t>(buf[7]) << 56);
  }

  static void make_token(char *buf, const std::uint64_t magic) {
    buf[0] = static_cast<char>((magic >> 0) & 0xFF);
    buf[1] = static_cast<char>((magic >> 8) & 0xFF);
    buf[2] = static_cast<char>((magic >> 16) & 0xFF);
    buf[3] = static_cast<char>((magic >> 24) & 0xFF);
    buf[4] = static_cast<char>((magic >> 32) & 0xFF);
    buf[5] = static_cast<char>((magic >> 40) & 0xFF);
    buf[6] = static_cast<char>((magic >> 48) & 0xFF);
    buf[7] = static_cast<char>((magic >> 56) & 0xFF);
  }

  std::atomic<std::uint64_t> p_next_token;
  Socket_t<socket_e> p_sock;
};

}  // namespace _ReQL

#endif  // REQL_REQL_PROTOCOL_HPP_
<commit_msg>Fix const cast needed.<commit_after>/*
Copyright 2015 Adam Grandquist

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.
 */
/**
 * @author Adam Grandquist
 * @copyright Apache
 */

#ifndef REQL_REQL_PROTOCOL_HPP_
#define REQL_REQL_PROTOCOL_HPP_

#include "./reql/handshake.hpp"
#include "./reql/query.hpp"
#include "./reql/socket.hpp"

#include <atomic>
#include <cstdint>
#include <sstream>
#include <string>
#include <thread>

namespace _ReQL {

template <class auth_e, class handshake_e, class socket_e>
class Protocol_t {
public:
  template <class addr_t, class auth_t, class func_t, class port_t>
  void connect(const addr_t &addr, const port_t &port, const auth_t &auth, func_t func) {
    p_sock.connect(addr, port);
    Handshake_t<auth_e, handshake_e>(p_sock, auth);
    std::thread([func, this] {
      size_t buff_size;
      std::ostringstream buffer;
      while (true) {
        while (buff_size < 12) {
          auto string = p_sock.read();
          buff_size += string.size();
          buffer << string;
        }
        auto string = buffer.str();
        buffer.clear();
        buffer << string.substr(12);
        auto token = get_token(string.c_str());
        auto size = get_size(string.c_str() + 8);
        while (buff_size < size) {
          auto string = p_sock.read();
          buff_size += string.size();
          buffer << string;
        }
        string = buffer.str();
        buffer.clear();
        buffer << string.substr(size);
        run(token, make_query(REQL_CONTINUE));
        func(string.substr(0, size), token);
      }
    }).detach();
  }

  void disconnect() {
    p_sock.disconnect();
  }

  bool connected() const {
    return p_sock.connected();
  }

  template <class query_t>
  auto run(query_t query) {
    auto token = p_next_token++;
    run(token, query);
    return token;
  }

  void stop(std::uint64_t token) {
    run(token, make_query(REQL_STOP));
  }

private:
  template <class query_t>
  void run(std::uint64_t token, query_t query) {
    std::ostringstream stream("\0\0\0\0\0\0\0\0\0\0\0\0", std::ios_base::ate);
    stream << std::boolalpha
           << std::setprecision(std::numeric_limits<double>::digits10 + 1)
           << query;

    auto wire_query = stream.str();
    auto size = wire_query.size();
    auto data = const_cast<char *>(wire_query.data());

    make_token(data, token);
    make_size(data + 8, static_cast<std::uint32_t>(size - 12));

    p_sock.write(data, size);
  }

  static std::uint32_t get_size(const char *buf) {
    return (static_cast<std::uint32_t>(buf[0]) << 0) |
    (static_cast<std::uint32_t>(buf[1]) << 8) |
    (static_cast<std::uint32_t>(buf[2]) << 16) |
    (static_cast<std::uint32_t>(buf[3]) << 24);
  }

  static void make_size(char *buf, const std::uint32_t magic) {
    buf[0] = static_cast<char>((magic >> 0) & 0xFF);
    buf[1] = static_cast<char>((magic >> 8) & 0xFF);
    buf[2] = static_cast<char>((magic >> 16) & 0xFF);
    buf[3] = static_cast<char>((magic >> 24) & 0xFF);
  }

  static std::uint64_t get_token(const char *buf) {
    return (static_cast<std::uint64_t>(buf[0]) << 0) |
    (static_cast<std::uint64_t>(buf[1]) << 8) |
    (static_cast<std::uint64_t>(buf[2]) << 16) |
    (static_cast<std::uint64_t>(buf[3]) << 24) |
    (static_cast<std::uint64_t>(buf[4]) << 32) |
    (static_cast<std::uint64_t>(buf[5]) << 40) |
    (static_cast<std::uint64_t>(buf[6]) << 48) |
    (static_cast<std::uint64_t>(buf[7]) << 56);
  }

  static void make_token(char *buf, const std::uint64_t magic) {
    buf[0] = static_cast<char>((magic >> 0) & 0xFF);
    buf[1] = static_cast<char>((magic >> 8) & 0xFF);
    buf[2] = static_cast<char>((magic >> 16) & 0xFF);
    buf[3] = static_cast<char>((magic >> 24) & 0xFF);
    buf[4] = static_cast<char>((magic >> 32) & 0xFF);
    buf[5] = static_cast<char>((magic >> 40) & 0xFF);
    buf[6] = static_cast<char>((magic >> 48) & 0xFF);
    buf[7] = static_cast<char>((magic >> 56) & 0xFF);
  }

  std::atomic<std::uint64_t> p_next_token;
  Socket_t<socket_e> p_sock;
};

}  // namespace _ReQL

#endif  // REQL_REQL_PROTOCOL_HPP_
<|endoftext|>