<commit_before>
#include "Globals.h"

#include "../BoundingBox.h"
#include "../Chunk.h"
#include "Floater.h"
#include "Player.h"
#include "../ClientHandle.h"

///////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cFloaterEntityCollisionCallback
class cFloaterEntityCollisionCallback :
	public cEntityCallback
{
public:
	cFloaterEntityCollisionCallback(cFloater * a_Floater, const Vector3d & a_Pos, const Vector3d & a_NextPos) :
		m_Floater(a_Floater),
		m_Pos(a_Pos),
		m_NextPos(a_NextPos),
		m_MinCoeff(1),
		m_HitEntity(NULL)
	{
	}
	virtual bool Item(cEntity * a_Entity) override
	{
		if (!a_Entity->IsMob())  // Floaters can only pull mobs not other entities.
		{
			return false;
		}

		cBoundingBox EntBox(a_Entity->GetPosition(), a_Entity->GetWidth() / 2, a_Entity->GetHeight());

		double LineCoeff;
		char Face;
		EntBox.Expand(m_Floater->GetWidth() / 2, m_Floater->GetHeight() / 2, m_Floater->GetWidth() / 2);
		if (!EntBox.CalcLineIntersection(m_Pos, m_NextPos, LineCoeff, Face))
		{
			// No intersection whatsoever
			return false;
		}

		if (LineCoeff < m_MinCoeff)
		{
			// The entity is closer than anything we've stored so far, replace it as the potential victim
			m_MinCoeff = LineCoeff;
			m_HitEntity = a_Entity;
		}

		// Don't break the enumeration, we want all the entities
		return false;
	}

	/// Returns the nearest entity that was hit, after the enumeration has been completed
	cEntity * GetHitEntity(void) const { return m_HitEntity; }

	/// Returns true if the callback has encountered a true hit
	bool HasHit(void) const { return (m_MinCoeff < 1); }

protected:
	cFloater * m_Floater;
	const Vector3d & m_Pos;
	const Vector3d & m_NextPos;
	double m_MinCoeff;  // The coefficient of the nearest hit on the Pos line

	// Although it's bad(tm) to store entity ptrs from a callback, we can afford it here, because the entire callback
	// is processed inside the tick thread, so the entities won't be removed in between the calls and the final processing
	cEntity * m_HitEntity;  // The nearest hit entity
} ;

///////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cFloaterCheckEntityExist
class cFloaterCheckEntityExist :
	public cEntityCallback
{
public:
	cFloaterCheckEntityExist(void) :
		m_EntityExists(false)
	{
	}

	bool Item(cEntity * a_Entity) override
	{
		m_EntityExists = true;
		return false;
	}

	bool DoesExist(void) const { return m_EntityExists; }
protected:
	bool m_EntityExists;
} ;

cFloater::cFloater(double a_X, double a_Y, double a_Z, Vector3d a_Speed, int a_PlayerID, int a_CountDownTime) :
	cEntity(etFloater, a_X, a_Y, a_Z, 0.2, 0.2),
	m_PickupCountDown(0),
	m_PlayerID(a_PlayerID),
	m_CanPickupItem(false),
	m_CountDownTime(a_CountDownTime),
	m_AttachedMobID(-1)
{
	SetSpeed(a_Speed);
}

void cFloater::SpawnOn(cClientHandle & a_Client)
{
	a_Client.SendSpawnObject(*this, 90, m_PlayerID, 0, 0);
}

void cFloater::Tick(float a_Dt, cChunk & a_Chunk)
{
	HandlePhysics(a_Dt, a_Chunk);
	if (IsBlockWater(m_World->GetBlock((int) GetPosX(), (int) GetPosY(), (int) GetPosZ())) && m_World->GetBlockMeta((int) GetPosX(), (int) GetPosY(), (int) GetPosZ()) == 0)
	{
		if (!m_CanPickupItem && m_AttachedMobID == -1) // Check if you can't already pickup a fish and if the floater isn't attached to a mob.
		{
			if (m_CountDownTime <= 0)
			{
				m_World->BroadcastSoundEffect("random.splash", (int) floor(GetPosX() * 8), (int) floor(GetPosY() * 8), (int) floor(GetPosZ() * 8), 1, 1);
				SetPosY(GetPosY() - 1);
				m_CanPickupItem = true;
				m_PickupCountDown = 20;
				m_CountDownTime = 100 + m_World->GetTickRandomNumber(800);
				LOGD("Floater %i can be picked up", GetUniqueID());
			}
			else if (m_CountDownTime == 20) // Calculate the position where the particles should spawn and start producing them.
			{
				LOGD("Started producing particles for floater %i", GetUniqueID());
				m_ParticlePos.Set(GetPosX() + (-4 + m_World->GetTickRandomNumber(8)), GetPosY(), GetPosZ() + (-4 + m_World->GetTickRandomNumber(8)));
				m_World->BroadcastParticleEffect("splash", (float) m_ParticlePos.x, (float) m_ParticlePos.y, (float) m_ParticlePos.z, 0, 0, 0, 0, 15);
			}
			else if (m_CountDownTime < 20)
			{
				m_ParticlePos = (m_ParticlePos + (GetPosition() - m_ParticlePos) / 6);
				m_World->BroadcastParticleEffect("splash", (float) m_ParticlePos.x, (float) m_ParticlePos.y, (float) m_ParticlePos.z, 0, 0, 0, 0, 15);
			}

			m_CountDownTime--;
			if (m_World->GetHeight((int) GetPosX(), (int) GetPosZ()) == (int) GetPosY())
			{
				if (m_World->IsWeatherWet() && m_World->GetTickRandomNumber(3) == 0) // 25% chance of an extra countdown when being rained on.
				{
					m_CountDownTime--;
				}
			}
			else // if the floater is underground it has a 50% chance of not decreasing the countdown.
			{
				if (m_World->GetTickRandomNumber(1) == 0)
				{
					m_CountDownTime++;
				}
			}
		}
		SetSpeedY(0.7);
	}

	if (CanPickup())  // Make sure the floater "loses its fish"
	{
		m_PickupCountDown--;
		if (m_PickupCountDown == 0)
		{
			m_CanPickupItem = false;
			LOGD("The fish is gone. Floater %i can not pick an item up.", GetUniqueID());
		}
	}

	if (GetSpeed().Length() > 4 && m_AttachedMobID == -1)
	{
		cFloaterEntityCollisionCallback Callback(this, GetPosition(), GetPosition() + GetSpeed() / 20);

		a_Chunk.ForEachEntity(Callback);
		if (Callback.HasHit())
		{
			AttachTo(Callback.GetHitEntity());
			Callback.GetHitEntity()->TakeDamage(*this); // TODO: the player attacked the mob not the floater.
			m_AttachedMobID = Callback.GetHitEntity()->GetUniqueID();
		}
	}

	cFloaterCheckEntityExist EntityCallback;
	m_World->DoWithEntityByID(m_PlayerID, EntityCallback);
	if (!EntityCallback.DoesExist()) // The owner doesn't exist anymore. Destroy the floater entity.
	{
		Destroy(true);
	}

	if (m_AttachedMobID != -1)
	{
		m_World->DoWithEntityByID(m_AttachedMobID, EntityCallback); // The mob the floater was attached to doesn't exist anymore.
		if (!EntityCallback.DoesExist())
		{
			m_AttachedMobID = -1;
		}
	}

	SetSpeedX(GetSpeedX() * 0.95);
	SetSpeedZ(GetSpeedZ() * 0.95);

	BroadcastMovementUpdate();
}<commit_msg>Fixed Parentheses.<commit_after>
#include "Globals.h"

#include "../BoundingBox.h"
#include "../Chunk.h"
#include "Floater.h"
#include "Player.h"
#include "../ClientHandle.h"

///////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cFloaterEntityCollisionCallback
class cFloaterEntityCollisionCallback :
	public cEntityCallback
{
public:
	cFloaterEntityCollisionCallback(cFloater * a_Floater, const Vector3d & a_Pos, const Vector3d & a_NextPos) :
		m_Floater(a_Floater),
		m_Pos(a_Pos),
		m_NextPos(a_NextPos),
		m_MinCoeff(1),
		m_HitEntity(NULL)
	{
	}
	virtual bool Item(cEntity * a_Entity) override
	{
		if (!a_Entity->IsMob())  // Floaters can only pull mobs not other entities.
		{
			return false;
		}

		cBoundingBox EntBox(a_Entity->GetPosition(), a_Entity->GetWidth() / 2, a_Entity->GetHeight());

		double LineCoeff;
		char Face;
		EntBox.Expand(m_Floater->GetWidth() / 2, m_Floater->GetHeight() / 2, m_Floater->GetWidth() / 2);
		if (!EntBox.CalcLineIntersection(m_Pos, m_NextPos, LineCoeff, Face))
		{
			// No intersection whatsoever
			return false;
		}

		if (LineCoeff < m_MinCoeff)
		{
			// The entity is closer than anything we've stored so far, replace it as the potential victim
			m_MinCoeff = LineCoeff;
			m_HitEntity = a_Entity;
		}

		// Don't break the enumeration, we want all the entities
		return false;
	}

	/// Returns the nearest entity that was hit, after the enumeration has been completed
	cEntity * GetHitEntity(void) const { return m_HitEntity; }

	/// Returns true if the callback has encountered a true hit
	bool HasHit(void) const { return (m_MinCoeff < 1); }

protected:
	cFloater * m_Floater;
	const Vector3d & m_Pos;
	const Vector3d & m_NextPos;
	double m_MinCoeff;  // The coefficient of the nearest hit on the Pos line

	// Although it's bad(tm) to store entity ptrs from a callback, we can afford it here, because the entire callback
	// is processed inside the tick thread, so the entities won't be removed in between the calls and the final processing
	cEntity * m_HitEntity;  // The nearest hit entity
} ;

///////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cFloaterCheckEntityExist
class cFloaterCheckEntityExist :
	public cEntityCallback
{
public:
	cFloaterCheckEntityExist(void) :
		m_EntityExists(false)
	{
	}

	bool Item(cEntity * a_Entity) override
	{
		m_EntityExists = true;
		return false;
	}

	bool DoesExist(void) const { return m_EntityExists; }
protected:
	bool m_EntityExists;
} ;

cFloater::cFloater(double a_X, double a_Y, double a_Z, Vector3d a_Speed, int a_PlayerID, int a_CountDownTime) :
	cEntity(etFloater, a_X, a_Y, a_Z, 0.2, 0.2),
	m_PickupCountDown(0),
	m_PlayerID(a_PlayerID),
	m_CanPickupItem(false),
	m_CountDownTime(a_CountDownTime),
	m_AttachedMobID(-1)
{
	SetSpeed(a_Speed);
}

void cFloater::SpawnOn(cClientHandle & a_Client)
{
	a_Client.SendSpawnObject(*this, 90, m_PlayerID, 0, 0);
}

void cFloater::Tick(float a_Dt, cChunk & a_Chunk)
{
	HandlePhysics(a_Dt, a_Chunk);
	if (IsBlockWater(m_World->GetBlock((int) GetPosX(), (int) GetPosY(), (int) GetPosZ())) && m_World->GetBlockMeta((int) GetPosX(), (int) GetPosY(), (int) GetPosZ()) == 0)
	{
		if ((!m_CanPickupItem) && (m_AttachedMobID == -1)) // Check if you can't already pickup a fish and if the floater isn't attached to a mob.
		{
			if (m_CountDownTime <= 0)
			{
				m_World->BroadcastSoundEffect("random.splash", (int) floor(GetPosX() * 8), (int) floor(GetPosY() * 8), (int) floor(GetPosZ() * 8), 1, 1);
				SetPosY(GetPosY() - 1);
				m_CanPickupItem = true;
				m_PickupCountDown = 20;
				m_CountDownTime = 100 + m_World->GetTickRandomNumber(800);
				LOGD("Floater %i can be picked up", GetUniqueID());
			}
			else if (m_CountDownTime == 20) // Calculate the position where the particles should spawn and start producing them.
			{
				LOGD("Started producing particles for floater %i", GetUniqueID());
				m_ParticlePos.Set(GetPosX() + (-4 + m_World->GetTickRandomNumber(8)), GetPosY(), GetPosZ() + (-4 + m_World->GetTickRandomNumber(8)));
				m_World->BroadcastParticleEffect("splash", (float) m_ParticlePos.x, (float) m_ParticlePos.y, (float) m_ParticlePos.z, 0, 0, 0, 0, 15);
			}
			else if (m_CountDownTime < 20)
			{
				m_ParticlePos = (m_ParticlePos + (GetPosition() - m_ParticlePos) / 6);
				m_World->BroadcastParticleEffect("splash", (float) m_ParticlePos.x, (float) m_ParticlePos.y, (float) m_ParticlePos.z, 0, 0, 0, 0, 15);
			}

			m_CountDownTime--;
			if (m_World->GetHeight((int) GetPosX(), (int) GetPosZ()) == (int) GetPosY())
			{
				if (m_World->IsWeatherWet() && m_World->GetTickRandomNumber(3) == 0) // 25% chance of an extra countdown when being rained on.
				{
					m_CountDownTime--;
				}
			}
			else // if the floater is underground it has a 50% chance of not decreasing the countdown.
			{
				if (m_World->GetTickRandomNumber(1) == 0)
				{
					m_CountDownTime++;
				}
			}
		}
		SetSpeedY(0.7);
	}

	if (CanPickup())  // Make sure the floater "loses its fish"
	{
		m_PickupCountDown--;
		if (m_PickupCountDown == 0)
		{
			m_CanPickupItem = false;
			LOGD("The fish is gone. Floater %i can not pick an item up.", GetUniqueID());
		}
	}

	if ((GetSpeed().Length() > 4) && (m_AttachedMobID == -1))
	{
		cFloaterEntityCollisionCallback Callback(this, GetPosition(), GetPosition() + GetSpeed() / 20);

		a_Chunk.ForEachEntity(Callback);
		if (Callback.HasHit())
		{
			AttachTo(Callback.GetHitEntity());
			Callback.GetHitEntity()->TakeDamage(*this); // TODO: the player attacked the mob not the floater.
			m_AttachedMobID = Callback.GetHitEntity()->GetUniqueID();
		}
	}

	cFloaterCheckEntityExist EntityCallback;
	m_World->DoWithEntityByID(m_PlayerID, EntityCallback);
	if (!EntityCallback.DoesExist()) // The owner doesn't exist anymore. Destroy the floater entity.
	{
		Destroy(true);
	}

	if (m_AttachedMobID != -1)
	{
		m_World->DoWithEntityByID(m_AttachedMobID, EntityCallback); // The mob the floater was attached to doesn't exist anymore.
		if (!EntityCallback.DoesExist())
		{
			m_AttachedMobID = -1;
		}
	}

	SetSpeedX(GetSpeedX() * 0.95);
	SetSpeedZ(GetSpeedZ() * 0.95);

	BroadcastMovementUpdate();
}<|endoftext|>


<commit_before>/*	____________________________________________________________________________

	                 Scanner Component for the Micro A Compiler

	                                mscan.h

	                              Version 2007 - 2016

	                           James L. Richards
	                     Last Update: August 28, 2007
	                      	   Nelson A Castillo
	                     Last Update: January 31, 2016

	The routines in this unit are based on those provided in the book
	"Crafting A Compiler" by Charles N. Fischer and Richard J. LeBlanc, Jr.,
	Benjamin Cummings Publishing Co. (1991).

	See Section 2.2, pp. 25-29.
	____________________________________________________________________________
*/

#include <iostream>
#include <fstream>
#include <string>
#include <algorithm>
using namespace std;

extern ifstream sourceFile;
extern ofstream outFile, listFile;

#include "mscan.h"

// *******************
// **  Constructor  **
// *******************

Scanner::Scanner()
{
	tokenBuffer = "";
	lineBuffer = "";
	lineNumber = 0;
}

// ********************************
// **  Private Member Functions  **
// ********************************

void Scanner::BufferChar(char c)
{
	if (tokenBuffer.length() < ID_STRING_LEN){
		tokenBuffer += c;
	}
}

Token Scanner::CheckReserved()
{
	/* Convert the string to lower case */
	transform(tokenBuffer.begin(), tokenBuffer.end(), \
				tokenBuffer.begin(), ::tolower);
	/* Check the converted words */
	if ((tokenBuffer) == "bool") return BOOL_SYM;
	if ((tokenBuffer) == "break") return BREAK_SYM;
	if ((tokenBuffer) == "case") return CASE_SYM;
	if ((tokenBuffer) == "cheese") return CHEESE_SYM;
	if ((tokenBuffer) == "decs") return DECS_SYM;
	if ((tokenBuffer) == "do") return DO_SYM;
	if ((tokenBuffer) == "else") return ELSE_SYM;
	if ((tokenBuffer) == "end") return END_SYM;
	if ((tokenBuffer) == "false") return FALSE_SYM;
	if ((tokenBuffer) == "float") return FLOAT_SYM;
	if ((tokenBuffer) == "for") return FOR_SYM;
	if ((tokenBuffer) == "hiphip") return HIPHIP_SYM;
	if ((tokenBuffer) == "if") return IF_SYM;
	if ((tokenBuffer) == "int") return INT_SYM;
	if ((tokenBuffer) == "listen") return LISTEN_SYM;
	if ((tokenBuffer) == "otherwise") return OTHERWISE_SYM;
	if ((tokenBuffer) == "until") return UNTIL_SYM;
	if ((tokenBuffer) == "select") return SELECT_SYM;
	if ((tokenBuffer) == "shout") return SHOUT_SYM;
	if ((tokenBuffer) == "then") return THEN_SYM;
	if ((tokenBuffer) == "true") return TRUE_SYM;
	if ((tokenBuffer) == "while") return WHILE_SYM;

	return ID;
}

void Scanner::ClearBuffer()
{
	tokenBuffer = "";
}

void Scanner::LexicalError(char& c)
{
	cout << " *** Lexical Error: '" << c
		<< "' ignored at position " << int(lineBuffer.size())
		<< " on line #" << lineNumber + 1 << '.' << endl;
	listFile << " *** Lexical Error: '" << c
		<< "' ignored at position " << int(lineBuffer.size())
		<< " on line #" << lineNumber + 1 << '.' << endl;

	c = NextChar();
}
void Scanner::LexicalError(char& c, const string& errorExp)
{
	cout << " *** Lexical Error: '" << c
		<< "' ignored at position " << int(lineBuffer.size())
		<< " on line #" << lineNumber + 1 << '.' << '\n'
		<< errorExp << endl;
	listFile << " *** Lexical Error: '" << c
		<< "' ignored at position " << int(lineBuffer.size())
		<< " on line #" << lineNumber + 1 << '.' << '\n'
		<< errorExp << endl;

	c = NextChar();
}

char Scanner::NextChar()
{
	char c;

	sourceFile.get(c);
	if (c == '\n')
	{
		listFile.width(6);
		listFile << ++lineNumber << "  " << lineBuffer << endl;
		lineBuffer = "";
	} else{
		lineBuffer += c;
	}
	return c;
}

// *******************************
// **  Public Member Functions  **
// *******************************

Token Scanner::GetNextToken()
{
	char currentChar, c;

	ClearBuffer();
	currentChar = NextChar();
	while (!sourceFile.eof())
	{
		if (isspace(currentChar)) {
			/* do nothing */
			currentChar = NextChar();
		} else if (isalpha(currentChar)) {
			/* identifier */
			BufferChar(currentChar);
			c = sourceFile.peek();
			while (isalnum(c) || c == '_') {
				currentChar = NextChar();
				BufferChar(currentChar);
				c = sourceFile.peek();
			}
			return CheckReserved();
		} else if (isdigit(currentChar)) {
			/* integer or float literals */
			BufferChar(currentChar);
			c = sourceFile.peek();
			while (isdigit(c)) {
				currentChar = NextChar();
				BufferChar(currentChar);
				c = sourceFile.peek();
			}
			/* check if it is a float */
			if (c == '.') {
				currentChar = NextChar();
				c = sourceFile.peek();
				/* check for a digit after the '.' */
				if (!isdigit(c))
					LexicalError(currentChar, to_string(c) \
						+ " Boolean needs a digit" \
						" after the '.'");
				BufferChar(currentChar);
				while (isdigit(c)) {
					currentChar = NextChar();
					BufferChar(currentChar);
					c = sourceFile.peek();
				}
				/* check for power of 10 multipliers */
				if (c == 'e' || c == 'E') {
					currentChar = NextChar();
					c = sourceFile.peek();
					if (c != '+' && c!= '-') {
						LexicalError(currentChar, \
							to_string(c) + \
							" Boolean needs a "
							"'+'/'-' after 'E'");
					}
					BufferChar(currentChar);
					currentChar = NextChar();
					c = sourceFile.peek();
					if (!isdigit(c))
						LexicalError(currentChar, \
							to_string(c) + \
							" Boolean needs a " \
							"digit after '+'/'-'");
					BufferChar(currentChar);
					while (isdigit(c)) {
						currentChar = NextChar();
						BufferChar(currentChar);
						c = sourceFile.peek();
					}
				}
				return FLOAT_LIT;
			}
			return INT_LIT;
		} else if (currentChar == '"') {
			/* string literal */
			BufferChar(currentChar);
			c = sourceFile.peek();
			/* while not end of string */
			while (c != '"') {
				/* escape sequences */
				if (c == '\\') {
					/*
					 * Replace the '\' for a ':'
					 * which's SAM's escape char
					 */
					currentChar = NextChar();
					c = sourceFile.peek();
					currentChar = ':';
					if (c == '\\') {
						/* '\\' sequence */
						/* Just remove one '\' */
						currentChar = NextChar();
						BufferChar(currentChar);
						c = sourceFile.peek();
					} else if (c == '"') {
						/* '\"' sequence */
						/* replace '"' for ':' */
						BufferChar(currentChar);
						currentChar = NextChar();
						BufferChar(currentChar);
						c = sourceFile.peek();
					} else if (c == 'n') {
						/* \n sequence */
						/* replace for ascii '\n'(012)*/
						currentChar = NextChar();
						currentChar = '0';
						BufferChar(currentChar);
						currentChar = '1';
						BufferChar(currentChar);
						currentChar = '2';
						BufferChar(currentChar);
						c = sourceFile.peek();
					} else if (isdigit(c)) {
						/* '\ddd' sequence */
						int ind;
						for (ind = 0; ind < 3; ind++) {
							/* check for 3 digits */
							if (!isdigit(c))
								LexicalError(c, to_string(c) + "received. Expected three digits after \\.");
							currentChar = NextChar();
							BufferChar(currentChar);
							c = sourceFile.peek();
						}
					} else {
						LexicalError(currentChar, to_string(currentChar) + \
						" was followed by the wrong character -options are \\ or \".");
					}
				} else if (c == ':') {
					/*
					 * ':' is the escape char used
					 * by the SAM assembler. So it
					 * needs to be escaped.
					 */
					currentChar = NextChar();
					BufferChar(currentChar);
					BufferChar(currentChar);
					c = sourceFile.peek();
				} else {
					/* regular characters */
					currentChar = NextChar();
					BufferChar(currentChar);
					c = sourceFile.peek();
				}
			}
			/* buffer the final '"' */
			currentChar = NextChar();
			BufferChar(currentChar);
			return CHEESE_LIT;
		} else if (currentChar == '(') {
			BufferChar(currentChar);
			return LBANANA;
		} else if (currentChar == ')') {
			BufferChar(currentChar);
			return RBANANA;
		} else if (currentChar == '[') {
			BufferChar(currentChar);
			return LSTAPLE;
		} else if (currentChar == ']') {
			BufferChar(currentChar);
			return RSTAPLE;
		} else if (currentChar == '{') {
			BufferChar(currentChar);
			return LMUSTACHE;
		} else if (currentChar == '}') {
			BufferChar(currentChar);
			return RMUSTACHE;
		} else if (currentChar == ';') {
			BufferChar(currentChar);
			return SEMICOLON;
		} else if (currentChar == ':') {
			BufferChar(currentChar);
			return COLON;
		} else if (currentChar == ',') {
			BufferChar(currentChar);
			return COMMA;
		} else if (currentChar == '+') {
			BufferChar(currentChar);
			return PLUS_OP;
		} else if (currentChar == '*') {
			BufferChar(currentChar);
			return MULT_OP;
		} else if (currentChar == '/') {
			/* check if it is a multiline comment */
			if (sourceFile.peek() == ':') {
				do { /* skip comment */
					currentChar = NextChar();
					if (currentChar == ':') {
						currentChar = NextChar();
						if (currentChar == '/') {
							currentChar = NextChar();
							break;
						}
					}
				} while (!sourceFile.eof());
			} else {
				/* if it is a division operator */
				BufferChar(currentChar);
				return DIV_OP;
			}
		} else if (currentChar == '=') {
			BufferChar(currentChar);
			if (sourceFile.peek() == '=') {
				currentChar = NextChar();
				BufferChar(currentChar);
				return EQ_OP1;
			}
			currentChar = NextChar();
			return ASSIGN_OP;
		} else if (currentChar == '!') {
			BufferChar(currentChar);
			if (sourceFile.peek() == '!') {
				currentChar = NextChar();
				BufferChar(currentChar);
				return EQ_OP2;
			} else if (sourceFile.peek() == '=') {
				currentChar = NextChar();
				BufferChar(currentChar);
				return NE_OP;
			} else {
				LexicalError(currentChar, to_string(c) + \
						" The not operator is not" \
						" supported by MnC");
			}
			currentChar = NextChar();
		} else if (currentChar == '<') {
			BufferChar(currentChar);
			if (sourceFile.peek() == '=') {
				currentChar = NextChar();
				BufferChar(currentChar);
				return LE_OP;
			}
			currentChar = NextChar();
			return LT_OP;
		} else if (currentChar == '>') {
			BufferChar(currentChar);
			if (sourceFile.peek() == '=') {
				currentChar = NextChar();
				BufferChar(currentChar);
				return GE_OP;
			}
			currentChar = NextChar();
			return GT_OP;
		} else if (currentChar == '-') {
			/* check if it is a comment or a minus symbol */
			if (sourceFile.peek() == '-') { /* comment */
				do { /* skip comment */
					currentChar = NextChar();
				} while (currentChar != '\n');
			} else { /* minus operator */
				BufferChar(currentChar);
				currentChar = NextChar();
				return MINUS_OP;
			}

		} else {
			/* Unrecognized character */
			LexicalError(currentChar, to_string(c) + \
					" Unrecognized character");
		}
	} /* end while */

	return EOF_SYM;
}
<commit_msg>Use '//' instead of '--' for single line comments.<commit_after>/*	____________________________________________________________________________

	                 Scanner Component for the Micro A Compiler

	                                mscan.h

	                              Version 2007 - 2016

	                           James L. Richards
	                     Last Update: August 28, 2007
	                      	   Nelson A Castillo
	                     Last Update: January 31, 2016

	The routines in this unit are based on those provided in the book
	"Crafting A Compiler" by Charles N. Fischer and Richard J. LeBlanc, Jr.,
	Benjamin Cummings Publishing Co. (1991).

	See Section 2.2, pp. 25-29.
	____________________________________________________________________________
*/

#include <iostream>
#include <fstream>
#include <string>
#include <algorithm>
using namespace std;

extern ifstream sourceFile;
extern ofstream outFile, listFile;

#include "mscan.h"

// *******************
// **  Constructor  **
// *******************

Scanner::Scanner()
{
	tokenBuffer = "";
	lineBuffer = "";
	lineNumber = 0;
}

// ********************************
// **  Private Member Functions  **
// ********************************

void Scanner::BufferChar(char c)
{
	if (tokenBuffer.length() < ID_STRING_LEN){
		tokenBuffer += c;
	}
}

Token Scanner::CheckReserved()
{
	/* Convert the string to lower case */
	transform(tokenBuffer.begin(), tokenBuffer.end(), \
				tokenBuffer.begin(), ::tolower);
	/* Check the converted words */
	if ((tokenBuffer) == "bool") return BOOL_SYM;
	if ((tokenBuffer) == "break") return BREAK_SYM;
	if ((tokenBuffer) == "case") return CASE_SYM;
	if ((tokenBuffer) == "cheese") return CHEESE_SYM;
	if ((tokenBuffer) == "decs") return DECS_SYM;
	if ((tokenBuffer) == "do") return DO_SYM;
	if ((tokenBuffer) == "else") return ELSE_SYM;
	if ((tokenBuffer) == "end") return END_SYM;
	if ((tokenBuffer) == "false") return FALSE_SYM;
	if ((tokenBuffer) == "float") return FLOAT_SYM;
	if ((tokenBuffer) == "for") return FOR_SYM;
	if ((tokenBuffer) == "hiphip") return HIPHIP_SYM;
	if ((tokenBuffer) == "if") return IF_SYM;
	if ((tokenBuffer) == "int") return INT_SYM;
	if ((tokenBuffer) == "listen") return LISTEN_SYM;
	if ((tokenBuffer) == "otherwise") return OTHERWISE_SYM;
	if ((tokenBuffer) == "until") return UNTIL_SYM;
	if ((tokenBuffer) == "select") return SELECT_SYM;
	if ((tokenBuffer) == "shout") return SHOUT_SYM;
	if ((tokenBuffer) == "then") return THEN_SYM;
	if ((tokenBuffer) == "true") return TRUE_SYM;
	if ((tokenBuffer) == "while") return WHILE_SYM;

	return ID;
}

void Scanner::ClearBuffer()
{
	tokenBuffer = "";
}

void Scanner::LexicalError(char& c)
{
	cout << " *** Lexical Error: '" << c
		<< "' ignored at position " << int(lineBuffer.size())
		<< " on line #" << lineNumber + 1 << '.' << endl;
	listFile << " *** Lexical Error: '" << c
		<< "' ignored at position " << int(lineBuffer.size())
		<< " on line #" << lineNumber + 1 << '.' << endl;

	c = NextChar();
}
void Scanner::LexicalError(char& c, const string& errorExp)
{
	cout << " *** Lexical Error: '" << c
		<< "' ignored at position " << int(lineBuffer.size())
		<< " on line #" << lineNumber + 1 << '.' << '\n'
		<< errorExp << endl;
	listFile << " *** Lexical Error: '" << c
		<< "' ignored at position " << int(lineBuffer.size())
		<< " on line #" << lineNumber + 1 << '.' << '\n'
		<< errorExp << endl;

	c = NextChar();
}

char Scanner::NextChar()
{
	char c;

	sourceFile.get(c);
	if (c == '\n')
	{
		listFile.width(6);
		listFile << ++lineNumber << "  " << lineBuffer << endl;
		lineBuffer = "";
	} else{
		lineBuffer += c;
	}
	return c;
}

// *******************************
// **  Public Member Functions  **
// *******************************

Token Scanner::GetNextToken()
{
	char currentChar, c;

	ClearBuffer();
	currentChar = NextChar();
	while (!sourceFile.eof())
	{
		if (isspace(currentChar)) {
			/* do nothing */
			currentChar = NextChar();
		} else if (isalpha(currentChar)) {
			/* identifier */
			BufferChar(currentChar);
			c = sourceFile.peek();
			while (isalnum(c) || c == '_') {
				currentChar = NextChar();
				BufferChar(currentChar);
				c = sourceFile.peek();
			}
			return CheckReserved();
		} else if (isdigit(currentChar)) {
			/* integer or float literals */
			BufferChar(currentChar);
			c = sourceFile.peek();
			while (isdigit(c)) {
				currentChar = NextChar();
				BufferChar(currentChar);
				c = sourceFile.peek();
			}
			/* check if it is a float */
			if (c == '.') {
				currentChar = NextChar();
				c = sourceFile.peek();
				/* check for a digit after the '.' */
				if (!isdigit(c))
					LexicalError(currentChar, to_string(c) \
						+ " Boolean needs a digit" \
						" after the '.'");
				BufferChar(currentChar);
				while (isdigit(c)) {
					currentChar = NextChar();
					BufferChar(currentChar);
					c = sourceFile.peek();
				}
				/* check for power of 10 multipliers */
				if (c == 'e' || c == 'E') {
					currentChar = NextChar();
					c = sourceFile.peek();
					if (c != '+' && c!= '-') {
						LexicalError(currentChar, \
							to_string(c) + \
							" Boolean needs a "
							"'+'/'-' after 'E'");
					}
					BufferChar(currentChar);
					currentChar = NextChar();
					c = sourceFile.peek();
					if (!isdigit(c))
						LexicalError(currentChar, \
							to_string(c) + \
							" Boolean needs a " \
							"digit after '+'/'-'");
					BufferChar(currentChar);
					while (isdigit(c)) {
						currentChar = NextChar();
						BufferChar(currentChar);
						c = sourceFile.peek();
					}
				}
				return FLOAT_LIT;
			}
			return INT_LIT;
		} else if (currentChar == '"') {
			/* string literal */
			BufferChar(currentChar);
			c = sourceFile.peek();
			/* while not end of string */
			while (c != '"') {
				/* escape sequences */
				if (c == '\\') {
					/*
					 * Replace the '\' for a ':'
					 * which's SAM's escape char
					 */
					currentChar = NextChar();
					c = sourceFile.peek();
					currentChar = ':';
					if (c == '\\') {
						/* '\\' sequence */
						/* Just remove one '\' */
						currentChar = NextChar();
						BufferChar(currentChar);
						c = sourceFile.peek();
					} else if (c == '"') {
						/* '\"' sequence */
						/* replace '"' for ':' */
						BufferChar(currentChar);
						currentChar = NextChar();
						BufferChar(currentChar);
						c = sourceFile.peek();
					} else if (c == 'n') {
						/* \n sequence */
						/* replace for ascii '\n'(012)*/
						currentChar = NextChar();
						currentChar = '0';
						BufferChar(currentChar);
						currentChar = '1';
						BufferChar(currentChar);
						currentChar = '2';
						BufferChar(currentChar);
						c = sourceFile.peek();
					} else if (isdigit(c)) {
						/* '\ddd' sequence */
						int ind;
						for (ind = 0; ind < 3; ind++) {
							/* check for 3 digits */
							if (!isdigit(c))
								LexicalError(c, to_string(c) + "received. Expected three digits after \\.");
							currentChar = NextChar();
							BufferChar(currentChar);
							c = sourceFile.peek();
						}
					} else {
						LexicalError(currentChar, to_string(currentChar) + \
						" was followed by the wrong character -options are \\ or \".");
					}
				} else if (c == ':') {
					/*
					 * ':' is the escape char used
					 * by the SAM assembler. So it
					 * needs to be escaped.
					 */
					currentChar = NextChar();
					BufferChar(currentChar);
					BufferChar(currentChar);
					c = sourceFile.peek();
				} else {
					/* regular characters */
					currentChar = NextChar();
					BufferChar(currentChar);
					c = sourceFile.peek();
				}
			}
			/* buffer the final '"' */
			currentChar = NextChar();
			BufferChar(currentChar);
			return CHEESE_LIT;
		} else if (currentChar == '(') {
			BufferChar(currentChar);
			return LBANANA;
		} else if (currentChar == ')') {
			BufferChar(currentChar);
			return RBANANA;
		} else if (currentChar == '[') {
			BufferChar(currentChar);
			return LSTAPLE;
		} else if (currentChar == ']') {
			BufferChar(currentChar);
			return RSTAPLE;
		} else if (currentChar == '{') {
			BufferChar(currentChar);
			return LMUSTACHE;
		} else if (currentChar == '}') {
			BufferChar(currentChar);
			return RMUSTACHE;
		} else if (currentChar == ';') {
			BufferChar(currentChar);
			return SEMICOLON;
		} else if (currentChar == ':') {
			BufferChar(currentChar);
			return COLON;
		} else if (currentChar == ',') {
			BufferChar(currentChar);
			return COMMA;
		} else if (currentChar == '+') {
			BufferChar(currentChar);
			return PLUS_OP;
		} else if (currentChar == '*') {
			BufferChar(currentChar);
			return MULT_OP;
		} else if (currentChar == '/') {
			/* check if it is a multiline comment */
			c = sourceFile.peek();
			if (c == ':') {
				do { /* skip comment */
					currentChar = NextChar();
					if (currentChar == ':') {
						currentChar = NextChar();
						if (currentChar == '/') {
							currentChar = NextChar();
							break;
						}
					}
				} while (!sourceFile.eof());
			} else if (c == '/') {
				/* single line commment */
				do { /* skip comment */
					currentChar = NextChar();
				} while (currentChar != '\n');
			} else {
				/* if it is a division operator */
				BufferChar(currentChar);
				return DIV_OP;
			}
		} else if (currentChar == '=') {
			BufferChar(currentChar);
			if (sourceFile.peek() == '=') {
				currentChar = NextChar();
				BufferChar(currentChar);
				return EQ_OP1;
			}
			currentChar = NextChar();
			return ASSIGN_OP;
		} else if (currentChar == '!') {
			BufferChar(currentChar);
			if (sourceFile.peek() == '!') {
				currentChar = NextChar();
				BufferChar(currentChar);
				return EQ_OP2;
			} else if (sourceFile.peek() == '=') {
				currentChar = NextChar();
				BufferChar(currentChar);
				return NE_OP;
			} else {
				LexicalError(currentChar, to_string(c) + \
						" The not operator is not" \
						" supported by MnC");
			}
			currentChar = NextChar();
		} else if (currentChar == '<') {
			BufferChar(currentChar);
			if (sourceFile.peek() == '=') {
				currentChar = NextChar();
				BufferChar(currentChar);
				return LE_OP;
			}
			currentChar = NextChar();
			return LT_OP;
		} else if (currentChar == '>') {
			BufferChar(currentChar);
			if (sourceFile.peek() == '=') {
				currentChar = NextChar();
				BufferChar(currentChar);
				return GE_OP;
			}
			currentChar = NextChar();
			return GT_OP;
		} else if (currentChar == '-') {
			/* minus operator */
			BufferChar(currentChar);
			currentChar = NextChar();
			return MINUS_OP;
		} else {
			/* Unrecognized character */
			LexicalError(currentChar, to_string(c) + \
					" Unrecognized character");
		}
	} /* end while */

	return EOF_SYM;
}
<|endoftext|>


<commit_before>/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 QUICKSTEP_QUERY_EXECUTION_SHIFTBOSS_HPP_
#define QUICKSTEP_QUERY_EXECUTION_SHIFTBOSS_HPP_

#include <cstddef>
#include <cstdint>
#include <memory>
#include <unordered_map>

#include "catalog/CatalogDatabaseCache.hpp"
#include "catalog/CatalogTypedefs.hpp"
#include "query_execution/QueryContext.hpp"
#include "query_execution/QueryExecutionTypedefs.hpp"
#include "query_execution/WorkerDirectory.hpp"
#include "storage/Flags.hpp"
#include "storage/StorageConfig.h"  // For QUICKSTEP_HAVE_FILE_MANAGER_HDFS.
#include "threading/Thread.hpp"
#include "utility/Macros.hpp"

#include "glog/logging.h"

#include "tmb/address.h"
#include "tmb/id_typedefs.h"

namespace tmb { class MessageBus; };

namespace quickstep {

class StorageManager;

namespace serialization {
class CatalogDatabase;
class QueryContext;
}  // namespace serialization

/** \addtogroup QueryExecution
 *  @{
 */

/**
 * @brief The Shiftboss accepts workorder protos from shiftboss, and assigns
 *        the workorders to workers.
 **/
class Shiftboss : public Thread {
 public:
  /**
   * @brief Constructor.
   *
   * @param bus_global A pointer to the TMB for Foreman.
   * @param bus_local A pointer to the TMB for Workers.
   * @param storage_manager The StorageManager to use.
   * @param workers A pointer to the WorkerDirectory.
   * @param hdfs The HDFS connector via libhdfs3.
   * @param cpu_id The ID of the CPU to which the Shiftboss thread can be pinned.
   *
   * @note If cpu_id is not specified, Shiftboss thread can be possibly moved
   *       around on different CPUs by the OS.
  **/
  Shiftboss(tmb::MessageBus *bus_global,
            tmb::MessageBus *bus_local,
            StorageManager *storage_manager,
            WorkerDirectory *workers,
            void *hdfs,
            const int cpu_id = -1);

  ~Shiftboss() override {
  }

  /**
   * @brief Get the TMB client ID of Shiftboss thread.
   *
   * @return TMB client ID of shiftboss thread.
   **/
  inline tmb::client_id getBusClientID() const {
    return shiftboss_client_id_global_;
  }

  /**
   * @brief Get the Work Order processing capacity of all Workers managed by
   *        Shiftboss during a single round of WorkOrder dispatch.
   **/
  inline std::size_t getWorkOrderCapacity() const {
    DCHECK_NE(max_msgs_per_worker_, 0u);
    return max_msgs_per_worker_ * workers_->getNumWorkers();
  }

  /**
   * @brief Get the Worker to assign WorkOrders for execution. Block to wait if
   *        all Workers have reached their capacity for queued WorkOrders.
   **/
  // TODO(zuyu): To achieve non-blocking, we need a queue to cache received
  // normal Work Order protos from Foreman and the generated rebuild Work Orders.
  inline std::size_t getSchedulableWorker();

  /**
   * @brief Set the maximum number of messages that should be allocated to each
   *        worker during a single round of WorkOrder dispatch.
   *
   * @param max_msgs_per_worker Maximum number of messages.
   **/
  inline void setMaxMessagesPerWorker(const std::size_t max_msgs_per_worker) {
    max_msgs_per_worker_ = max_msgs_per_worker;
  }

 protected:
  /**
   * @brief The shiftboss receives workorders, and based on the response it
   *        assigns workorders to workers.
   *
   * @note  The workers who get the messages from the Shiftboss execute and
   *        subsequently delete the WorkOrder contained in the message.
   **/
  void run() override;

 private:
  void registerWithForeman();

  void processShiftbossRegistrationResponseMessage();

  /**
   * @brief Process the Shiftboss initiate message and ack back.
   *
   * @param query_id The given query id.
   * @param catalog_database_cache_proto The proto used to update
   *        CatalogDatabaseCache.
   * @param query_context_proto The QueryContext proto.
   **/
  void processQueryInitiateMessage(const std::size_t query_id,
                                   const serialization::CatalogDatabase &catalog_database_cache_proto,
                                   const serialization::QueryContext &query_context_proto);

  /**
   * @brief Process the RebuildWorkOrder initiate message and ack back.
   *
   * @param query_id The ID of the query to which this RebuildWorkOrder initiate
   *        message belongs.
   * @param op_index The index of the operator for rebuild work orders.
   * @param dest_index The InsertDestination index in QueryContext to rebuild.
   * @param rel_id The relation that needs to generate rebuild work orders.
   **/
  void processInitiateRebuildMessage(const std::size_t query_id,
                                     const std::size_t op_index,
                                     const QueryContext::insert_destination_id dest_index,
                                     const relation_id rel_id);

  tmb::MessageBus *bus_global_, *bus_local_;

  CatalogDatabaseCache database_cache_;
  StorageManager *storage_manager_;
  WorkerDirectory *workers_;

  // Not owned.
  void *hdfs_;

  // The ID of the CPU that the Shiftboss thread can optionally be pinned to.
  const int cpu_id_;

  tmb::client_id shiftboss_client_id_global_, shiftboss_client_id_local_, foreman_client_id_;

  // Unique per Shiftboss instance.
  std::uint64_t shiftboss_index_;

  // TMB recipients for all workers managed by this Shiftboss.
  tmb::Address worker_addresses_;

  // During a single round of WorkOrder dispatch, a Worker should be allocated
  // at most these many WorkOrders.
  std::size_t max_msgs_per_worker_;

  // The worker index for scheduling Work Order.
  std::size_t start_worker_index_;

  // QueryContexts per query.
  std::unordered_map<std::size_t, std::unique_ptr<QueryContext>> query_contexts_;

  DISALLOW_COPY_AND_ASSIGN(Shiftboss);
};

/** @} */

}  // namespace quickstep

#endif  // QUICKSTEP_QUERY_EXECUTION_SHIFTBOSS_HPP_
<commit_msg>Fixed a pedantic warning.<commit_after>/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 QUICKSTEP_QUERY_EXECUTION_SHIFTBOSS_HPP_
#define QUICKSTEP_QUERY_EXECUTION_SHIFTBOSS_HPP_

#include <cstddef>
#include <cstdint>
#include <memory>
#include <unordered_map>

#include "catalog/CatalogDatabaseCache.hpp"
#include "catalog/CatalogTypedefs.hpp"
#include "query_execution/QueryContext.hpp"
#include "query_execution/QueryExecutionTypedefs.hpp"
#include "query_execution/WorkerDirectory.hpp"
#include "storage/Flags.hpp"
#include "storage/StorageConfig.h"  // For QUICKSTEP_HAVE_FILE_MANAGER_HDFS.
#include "threading/Thread.hpp"
#include "utility/Macros.hpp"

#include "glog/logging.h"

#include "tmb/address.h"
#include "tmb/id_typedefs.h"

namespace tmb { class MessageBus; }

namespace quickstep {

class StorageManager;

namespace serialization {
class CatalogDatabase;
class QueryContext;
}  // namespace serialization

/** \addtogroup QueryExecution
 *  @{
 */

/**
 * @brief The Shiftboss accepts workorder protos from shiftboss, and assigns
 *        the workorders to workers.
 **/
class Shiftboss : public Thread {
 public:
  /**
   * @brief Constructor.
   *
   * @param bus_global A pointer to the TMB for Foreman.
   * @param bus_local A pointer to the TMB for Workers.
   * @param storage_manager The StorageManager to use.
   * @param workers A pointer to the WorkerDirectory.
   * @param hdfs The HDFS connector via libhdfs3.
   * @param cpu_id The ID of the CPU to which the Shiftboss thread can be pinned.
   *
   * @note If cpu_id is not specified, Shiftboss thread can be possibly moved
   *       around on different CPUs by the OS.
  **/
  Shiftboss(tmb::MessageBus *bus_global,
            tmb::MessageBus *bus_local,
            StorageManager *storage_manager,
            WorkerDirectory *workers,
            void *hdfs,
            const int cpu_id = -1);

  ~Shiftboss() override {
  }

  /**
   * @brief Get the TMB client ID of Shiftboss thread.
   *
   * @return TMB client ID of shiftboss thread.
   **/
  inline tmb::client_id getBusClientID() const {
    return shiftboss_client_id_global_;
  }

  /**
   * @brief Get the Work Order processing capacity of all Workers managed by
   *        Shiftboss during a single round of WorkOrder dispatch.
   **/
  inline std::size_t getWorkOrderCapacity() const {
    DCHECK_NE(max_msgs_per_worker_, 0u);
    return max_msgs_per_worker_ * workers_->getNumWorkers();
  }

  /**
   * @brief Get the Worker to assign WorkOrders for execution. Block to wait if
   *        all Workers have reached their capacity for queued WorkOrders.
   **/
  // TODO(zuyu): To achieve non-blocking, we need a queue to cache received
  // normal Work Order protos from Foreman and the generated rebuild Work Orders.
  inline std::size_t getSchedulableWorker();

  /**
   * @brief Set the maximum number of messages that should be allocated to each
   *        worker during a single round of WorkOrder dispatch.
   *
   * @param max_msgs_per_worker Maximum number of messages.
   **/
  inline void setMaxMessagesPerWorker(const std::size_t max_msgs_per_worker) {
    max_msgs_per_worker_ = max_msgs_per_worker;
  }

 protected:
  /**
   * @brief The shiftboss receives workorders, and based on the response it
   *        assigns workorders to workers.
   *
   * @note  The workers who get the messages from the Shiftboss execute and
   *        subsequently delete the WorkOrder contained in the message.
   **/
  void run() override;

 private:
  void registerWithForeman();

  void processShiftbossRegistrationResponseMessage();

  /**
   * @brief Process the Shiftboss initiate message and ack back.
   *
   * @param query_id The given query id.
   * @param catalog_database_cache_proto The proto used to update
   *        CatalogDatabaseCache.
   * @param query_context_proto The QueryContext proto.
   **/
  void processQueryInitiateMessage(const std::size_t query_id,
                                   const serialization::CatalogDatabase &catalog_database_cache_proto,
                                   const serialization::QueryContext &query_context_proto);

  /**
   * @brief Process the RebuildWorkOrder initiate message and ack back.
   *
   * @param query_id The ID of the query to which this RebuildWorkOrder initiate
   *        message belongs.
   * @param op_index The index of the operator for rebuild work orders.
   * @param dest_index The InsertDestination index in QueryContext to rebuild.
   * @param rel_id The relation that needs to generate rebuild work orders.
   **/
  void processInitiateRebuildMessage(const std::size_t query_id,
                                     const std::size_t op_index,
                                     const QueryContext::insert_destination_id dest_index,
                                     const relation_id rel_id);

  tmb::MessageBus *bus_global_, *bus_local_;

  CatalogDatabaseCache database_cache_;
  StorageManager *storage_manager_;
  WorkerDirectory *workers_;

  // Not owned.
  void *hdfs_;

  // The ID of the CPU that the Shiftboss thread can optionally be pinned to.
  const int cpu_id_;

  tmb::client_id shiftboss_client_id_global_, shiftboss_client_id_local_, foreman_client_id_;

  // Unique per Shiftboss instance.
  std::uint64_t shiftboss_index_;

  // TMB recipients for all workers managed by this Shiftboss.
  tmb::Address worker_addresses_;

  // During a single round of WorkOrder dispatch, a Worker should be allocated
  // at most these many WorkOrders.
  std::size_t max_msgs_per_worker_;

  // The worker index for scheduling Work Order.
  std::size_t start_worker_index_;

  // QueryContexts per query.
  std::unordered_map<std::size_t, std::unique_ptr<QueryContext>> query_contexts_;

  DISALLOW_COPY_AND_ASSIGN(Shiftboss);
};

/** @} */

}  // namespace quickstep

#endif  // QUICKSTEP_QUERY_EXECUTION_SHIFTBOSS_HPP_
<|endoftext|>


<commit_before>#include "Header.h"

using namespace ATM;

//------------------------------------------------------------------------------//

Account::Account(){/* Initialize the Customer Data from the .txt file */}

//------------------------------------------------------------------------------//

//random comment
<commit_msg>Delete Account.cpp<commit_after><|endoftext|>


<commit_before>#include "../includes/FileWatcherLinux.h"

namespace NSFW {

  FileWatcherLinux::FileWatcherLinux(std::string path, std::queue<Event> &eventsQueue, bool &watchFiles)
    : mEventsQueue(eventsQueue), mInotify(0), mPath(path), mWatchFiles(watchFiles) {}
  FileWatcherLinux::~FileWatcherLinux() {}

  void FileWatcherLinux::addEvent(std::string action, inotify_event *inEvent) {
    Directory *parent = mWDtoDirNode[inEvent->wd];
    addEvent(action, parent->path + "/" + parent->name, new std::string(inEvent->name));
  }

  void FileWatcherLinux::addEvent(std::string action, std::string directory, std::string *file) {
    std::cout << action << ":" << directory << ":" << *file << std::endl;
    Event event;
    event.action = action;
    event.directory = directory;
    event.file = file;
    mEventsQueue.push(event);
  }

  Directory *FileWatcherLinux::buildDirTree(std::string path) {
    std::queue<Directory *> dirQueue;
    Directory *topRoot = new Directory;

    // create root of snapshot
    if (path[path.length() - 1] == '/') {
      path = path.substr(0, path.length() - 1);
    }

    size_t lastSlash = path.find_last_of("/");
    if (lastSlash != std::string::npos) {
      topRoot->name = path.substr(lastSlash + 1);
      topRoot->path = path.substr(0, lastSlash);
    } else {
      topRoot->name = "";
      topRoot->path = "/";
    }

    topRoot->watchDescriptor = -1;

    dirQueue.push(topRoot);
    bool checkRootOnExit = false;

    while (!dirQueue.empty()) {
      Directory *root = dirQueue.front();
      dirent ** directoryContents = NULL;
      std::string fullPath = root->path + "/" + root->name;
      int n = scandir(fullPath.c_str(), &directoryContents, NULL, alphasort);

      if (n < 0) {
        if (topRoot == root)
        {
          return NULL; // top directory no longer exists
        }
        else {
          checkRootOnExit = true;
          dirQueue.pop();
          continue;
        }
      }

      // find all the directories within this directory
      // this breaks the alphabetical sorting of directories
      for (int i = 0; i < n; ++i) {
        if (!strcmp(directoryContents[i]->d_name, ".") || !strcmp(directoryContents[i]->d_name, "..")) {
          continue; // skip navigation folder
        }

        // Certain *nix do not support dirent->d_type and may return DT_UNKOWN for every file returned in scandir
        // in order to make this work on all *nix, we need to stat the file to determine if it is a directory
        std::string filePath = root->path + "/" + root->name + "/" + directoryContents[i]->d_name;

        struct stat file;

        if (stat(filePath.c_str(), &file) < 0) {
          continue;
        }

        if (S_ISDIR(file.st_mode))
        {
          // create the directory struct for this directory and add a reference of this directory to its root
          Directory *dir = new Directory;
          dir->path = root->path + "/" + root->name;
          dir->name = directoryContents[i]->d_name;
          dir->watchDescriptor = -1;
          root->childDirectories[dir->name] = dir;
          dirQueue.push(dir);
        }
      }

      for (int i = 0; i < n; ++i) {
        delete directoryContents[i];
      }

      delete[] directoryContents;

      dirQueue.pop();
    }

    if (checkRootOnExit) {
      struct stat rootStat;
      if (!stat((topRoot->path + "/" + topRoot->name).c_str(), &rootStat) || !S_ISDIR(rootStat.st_mode)) {
        // delete tree as far as we can go
        destroyDirTree(topRoot);
        return NULL;
      }
    }

    return topRoot;
  }

  void FileWatcherLinux::destroyDirTree(Directory *tree) {
    if (tree == NULL) return;

    std::queue<Directory *> dirQueue;
    dirQueue.push(tree);

    while (!dirQueue.empty()) {
      Directory *root = dirQueue.front();

      // Add directories to the queue to continue listing events
      for (std::map<std::string, Directory *>::iterator dirIter = root->childDirectories.begin();
        dirIter != root->childDirectories.end(); ++dirIter)
      {
        dirQueue.push(dirIter->second);
      }

      dirQueue.pop();

      delete root;
    }
  }

  void FileWatcherLinux::destroyWatchTree(Directory *tree) {
    std::queue<Directory *> dirQueue;
    dirQueue.push(tree);

    if (fcntl(mInotify, F_GETFD) != -1 || errno != EBADF) {
      // need to pass errors back here so that the next call to poll
      // can clean up after this type of error
      return; // panic
    }

    while (!dirQueue.empty()) {
      Directory *root = dirQueue.front();

      inotify_rm_watch(mInotify, root->watchDescriptor);

      // Add directories to the queue to continue listing events
      for (std::map<std::string, Directory *>::iterator dirIter = root->childDirectories.begin();
        dirIter != root->childDirectories.end(); ++dirIter)
      {
        dirQueue.push(dirIter->second);
      }

      dirQueue.pop();

      delete root;
    }
  }

  std::string FileWatcherLinux::getPath() {
    return mPath;
  }

  void *FileWatcherLinux::mainLoop(void *params) {
    FileWatcherLinux *fwLinux = (FileWatcherLinux *)params;

    // build the directory tree before listening for events
    Directory *dirTree = fwLinux->buildDirTree(fwLinux->getPath());

    std::cout << "i finished building" << std::endl;

    // check that the directory can be watched before trying to watch it
    if (dirTree == NULL) {
      // throw error if the directory didn't exists
      return NULL;
    }

    std::cout << "start watching" << std::endl;

    fwLinux->setDirTree(dirTree);
    fwLinux->startWatchTree(dirTree);
    fwLinux->processEvents();

    return NULL;
  }

  void FileWatcherLinux::processEvents() {
    size_t count = sizeof(struct inotify_event) + NAME_MAX + 1;
    char *buffer = new char[1024*count];
    int watchDescriptor = -1;
    unsigned int bytesRead, position = 0, cookie = 0;
    Event lastMovedFromEvent;

    while(mWatchFiles && (bytesRead = read(mInotify, buffer, count)) > 0) {
      std::cout << "finish read" << std::endl;
      std::cout << position << std::endl << bytesRead << std::endl;
      inotify_event *inEvent;
      do {
        inEvent = (inotify_event *)(buffer + position);
        Event event;

        // if the event is not a moved to event and the cookie exists
        // we should reset the cookie and push the last moved from event
        if (cookie != 0 && inEvent->mask != IN_MOVED_TO) {
          cookie = 0;
          watchDescriptor = -1;
          mEventsQueue.push(lastMovedFromEvent);
        }
        std::cout << inEvent->mask << std::endl;
        bool isDir = inEvent->mask & IN_ISDIR;
        inEvent->mask = isDir ? inEvent->mask ^ IN_ISDIR : inEvent->mask;

        switch(inEvent->mask) {
          case IN_ATTRIB:
          case IN_MODIFY:
            std::cout << "changed" <<std::endl;
            addEvent("CHANGED", inEvent);
            break;
          case IN_CREATE:
          {
            std::cout << "created" <<std::endl;
            // check stats on the item CREATED
            // if it is a dir, create a watch for all of its directories
            if (isDir) {
              Directory *parent = mWDtoDirNode[inEvent->wd];
              std::string newPath = parent->path + "/" + parent->name + "/" + inEvent->name;

              // add the directory tree
              Directory *child = buildDirTree(newPath);

              if (child == NULL)
                break;

              parent->childDirectories[child->name] = child;
              startWatchTree(child);
            }

            addEvent("CREATED", inEvent);
            break;
          }
          case IN_DELETE:
            std::cout << "deleted" <<std::endl;

            if (isDir) {
              Directory *parent = mWDtoDirNode[inEvent->wd];
              Directory *child = parent->childDirectories[inEvent->name];
              parent->childDirectories.erase(child->name);
              destroyWatchTree(child);
              child = NULL;
            }

            addEvent("DELETED", inEvent);
            break;
          case IN_MOVED_FROM:
          std::cout << "moved from" <<std::endl;

            fd_set checkWD;
            FD_ZERO(&checkWD);
            FD_SET(mInotify, &checkWD);
            timeval timeout;
            timeout.tv_sec = 0;
            timeout.tv_usec = 250000;

            if (position + sizeof(struct inotify_event) + inEvent->len < bytesRead || select(mInotify+1, &checkWD, 0, 0, &timeout) > 0) {
              lastMovedFromEvent.action = "DELETED";
              lastMovedFromEvent.directory = mWDtoDirNode[inEvent->wd]->path;
              lastMovedFromEvent.file = new std::string(inEvent->name);
              cookie = inEvent->cookie;
              watchDescriptor = inEvent->wd;
            } else {
              addEvent("DELETED", inEvent);
            }
            break;
          case IN_MOVED_TO:
          std::cout << "moved to" <<std::endl;

            // check if this is a move event
            if (cookie != 0 && inEvent->cookie == cookie && inEvent->wd == watchDescriptor) {
              cookie = 0;
              watchDescriptor = -1;
              event.action = "RENAMED";
              event.directory = mWDtoDirNode[inEvent->wd]->path;
              event.file = new std::string[2];
              event.file[0] = *lastMovedFromEvent.file;
              event.file[1] = inEvent->name;
              delete lastMovedFromEvent.file;
              mEventsQueue.push(event);
              std::cout << "renamed" <<std::endl;
            } else {
              addEvent("CREATED", inEvent);
            }
            break;
        }
        std::cout << "finished one parse" << std::endl;
      } while ((position += sizeof(struct inotify_event) + inEvent->len) < bytesRead);
      std::cout << "finish parse events" << std::endl;
      std::cout << position << std::endl << bytesRead << std::endl;
      position = 0;
    }
  }

  bool FileWatcherLinux::start() {
    mInotify = inotify_init();
    if (mInotify < 0) {
      return false;
    }

    if (mWatchFiles && pthread_create(&mThread, 0, &FileWatcherLinux::mainLoop, (void *)this)) {
      return true;
    } else {
      return false;
    }
  }

  void FileWatcherLinux::startWatchTree(Directory *tree) {
    std::queue<Directory *> dirQueue;

    dirQueue.push(tree);

    while (!dirQueue.empty()) {
      Directory *root = dirQueue.front();

      root->watchDescriptor = inotify_add_watch(
        mInotify,
        (root->path + "/" + root->name).c_str(),
        IN_ATTRIB | IN_CREATE | IN_DELETE | IN_MODIFY | IN_MOVED_FROM | IN_MOVED_TO
      );

      if (root->watchDescriptor < 0) {
        // error
        return; // ?
      }

      mWDtoDirNode[root->watchDescriptor] = root;

      // find all the directories within this directory
      // this breaks the alphabetical sorting of directories
      for (std::map<std::string, Directory *>::iterator dirIter = root->childDirectories.begin();
        dirIter != root->childDirectories.end(); ++dirIter)
      {
        dirQueue.push(dirIter->second);
      }

      dirQueue.pop();
    }
  }

  void FileWatcherLinux::stop() {}

  void FileWatcherLinux::setDirTree(Directory *tree) {
    mDirTree = tree;
  }

}
<commit_msg>removed debug statements<commit_after>#include "../includes/FileWatcherLinux.h"

namespace NSFW {

  FileWatcherLinux::FileWatcherLinux(std::string path, std::queue<Event> &eventsQueue, bool &watchFiles)
    : mEventsQueue(eventsQueue), mInotify(0), mPath(path), mWatchFiles(watchFiles) {}
  FileWatcherLinux::~FileWatcherLinux() {}

  void FileWatcherLinux::addEvent(std::string action, inotify_event *inEvent) {
    Directory *parent = mWDtoDirNode[inEvent->wd];
    addEvent(action, parent->path + "/" + parent->name, new std::string(inEvent->name));
  }

  void FileWatcherLinux::addEvent(std::string action, std::string directory, std::string *file) {
    Event event;
    event.action = action;
    event.directory = directory;
    event.file = file;
    mEventsQueue.push(event);
  }

  Directory *FileWatcherLinux::buildDirTree(std::string path) {
    std::queue<Directory *> dirQueue;
    Directory *topRoot = new Directory;

    // create root of snapshot
    if (path[path.length() - 1] == '/') {
      path = path.substr(0, path.length() - 1);
    }

    size_t lastSlash = path.find_last_of("/");
    if (lastSlash != std::string::npos) {
      topRoot->name = path.substr(lastSlash + 1);
      topRoot->path = path.substr(0, lastSlash);
    } else {
      topRoot->name = "";
      topRoot->path = "/";
    }

    topRoot->watchDescriptor = -1;

    dirQueue.push(topRoot);
    bool checkRootOnExit = false;

    while (!dirQueue.empty()) {
      Directory *root = dirQueue.front();
      dirent ** directoryContents = NULL;
      std::string fullPath = root->path + "/" + root->name;
      int n = scandir(fullPath.c_str(), &directoryContents, NULL, alphasort);

      if (n < 0) {
        if (topRoot == root)
        {
          return NULL; // top directory no longer exists
        }
        else {
          checkRootOnExit = true;
          dirQueue.pop();
          continue;
        }
      }

      // find all the directories within this directory
      // this breaks the alphabetical sorting of directories
      for (int i = 0; i < n; ++i) {
        if (!strcmp(directoryContents[i]->d_name, ".") || !strcmp(directoryContents[i]->d_name, "..")) {
          continue; // skip navigation folder
        }

        // Certain *nix do not support dirent->d_type and may return DT_UNKOWN for every file returned in scandir
        // in order to make this work on all *nix, we need to stat the file to determine if it is a directory
        std::string filePath = root->path + "/" + root->name + "/" + directoryContents[i]->d_name;

        struct stat file;

        if (stat(filePath.c_str(), &file) < 0) {
          continue;
        }

        if (S_ISDIR(file.st_mode))
        {
          // create the directory struct for this directory and add a reference of this directory to its root
          Directory *dir = new Directory;
          dir->path = root->path + "/" + root->name;
          dir->name = directoryContents[i]->d_name;
          dir->watchDescriptor = -1;
          root->childDirectories[dir->name] = dir;
          dirQueue.push(dir);
        }
      }

      for (int i = 0; i < n; ++i) {
        delete directoryContents[i];
      }

      delete[] directoryContents;

      dirQueue.pop();
    }

    if (checkRootOnExit) {
      struct stat rootStat;
      if (!stat((topRoot->path + "/" + topRoot->name).c_str(), &rootStat) || !S_ISDIR(rootStat.st_mode)) {
        // delete tree as far as we can go
        destroyDirTree(topRoot);
        return NULL;
      }
    }

    return topRoot;
  }

  void FileWatcherLinux::destroyDirTree(Directory *tree) {
    if (tree == NULL) return;

    std::queue<Directory *> dirQueue;
    dirQueue.push(tree);

    while (!dirQueue.empty()) {
      Directory *root = dirQueue.front();

      // Add directories to the queue to continue listing events
      for (std::map<std::string, Directory *>::iterator dirIter = root->childDirectories.begin();
        dirIter != root->childDirectories.end(); ++dirIter)
      {
        dirQueue.push(dirIter->second);
      }

      dirQueue.pop();

      delete root;
    }
  }

  void FileWatcherLinux::destroyWatchTree(Directory *tree) {
    std::queue<Directory *> dirQueue;
    dirQueue.push(tree);

    if (fcntl(mInotify, F_GETFD) != -1 || errno != EBADF) {
      // need to pass errors back here so that the next call to poll
      // can clean up after this type of error
      return; // panic
    }

    while (!dirQueue.empty()) {
      Directory *root = dirQueue.front();

      inotify_rm_watch(mInotify, root->watchDescriptor);

      // Add directories to the queue to continue listing events
      for (std::map<std::string, Directory *>::iterator dirIter = root->childDirectories.begin();
        dirIter != root->childDirectories.end(); ++dirIter)
      {
        dirQueue.push(dirIter->second);
      }

      dirQueue.pop();

      delete root;
    }
  }

  std::string FileWatcherLinux::getPath() {
    return mPath;
  }

  void *FileWatcherLinux::mainLoop(void *params) {
    FileWatcherLinux *fwLinux = (FileWatcherLinux *)params;

    // build the directory tree before listening for events
    Directory *dirTree = fwLinux->buildDirTree(fwLinux->getPath());

    // check that the directory can be watched before trying to watch it
    if (dirTree == NULL) {
      // throw error if the directory didn't exists
      return NULL;
    }

    fwLinux->setDirTree(dirTree);
    fwLinux->startWatchTree(dirTree);
    fwLinux->processEvents();

    return NULL;
  }

  void FileWatcherLinux::processEvents() {
    size_t count = sizeof(struct inotify_event) + NAME_MAX + 1;
    char *buffer = new char[1024*count];
    int watchDescriptor = -1;
    unsigned int bytesRead, position = 0, cookie = 0;
    Event lastMovedFromEvent;

    while(mWatchFiles && (bytesRead = read(mInotify, buffer, count)) > 0) {
      inotify_event *inEvent;
      do {
        inEvent = (inotify_event *)(buffer + position);
        Event event;

        // if the event is not a moved to event and the cookie exists
        // we should reset the cookie and push the last moved from event
        if (cookie != 0 && inEvent->mask != IN_MOVED_TO) {
          cookie = 0;
          watchDescriptor = -1;
          mEventsQueue.push(lastMovedFromEvent);
        }
        bool isDir = inEvent->mask & IN_ISDIR;
        inEvent->mask = isDir ? inEvent->mask ^ IN_ISDIR : inEvent->mask;

        switch(inEvent->mask) {
          case IN_ATTRIB:
          case IN_MODIFY:
            addEvent("CHANGED", inEvent);
            break;
          case IN_CREATE:
          {
            // check stats on the item CREATED
            // if it is a dir, create a watch for all of its directories
            if (isDir) {
              Directory *parent = mWDtoDirNode[inEvent->wd];
              std::string newPath = parent->path + "/" + parent->name + "/" + inEvent->name;

              // add the directory tree
              Directory *child = buildDirTree(newPath);

              if (child == NULL)
                break;

              parent->childDirectories[child->name] = child;
              startWatchTree(child);
            }

            addEvent("CREATED", inEvent);
            break;
          }
          case IN_DELETE:
            if (isDir) {
              Directory *parent = mWDtoDirNode[inEvent->wd];
              Directory *child = parent->childDirectories[inEvent->name];
              parent->childDirectories.erase(child->name);
              destroyWatchTree(child);
              child = NULL;
            }

            addEvent("DELETED", inEvent);
            break;
          case IN_MOVED_FROM:
            fd_set checkWD;
            FD_ZERO(&checkWD);
            FD_SET(mInotify, &checkWD);
            timeval timeout;
            timeout.tv_sec = 0;
            timeout.tv_usec = 250000;

            if (position + sizeof(struct inotify_event) + inEvent->len < bytesRead || select(mInotify+1, &checkWD, 0, 0, &timeout) > 0) {
              lastMovedFromEvent.action = "DELETED";
              lastMovedFromEvent.directory = mWDtoDirNode[inEvent->wd]->path;
              lastMovedFromEvent.file = new std::string(inEvent->name);
              cookie = inEvent->cookie;
              watchDescriptor = inEvent->wd;
            } else {
              addEvent("DELETED", inEvent);
            }
            break;
          case IN_MOVED_TO:
            // check if this is a move event
            if (cookie != 0 && inEvent->cookie == cookie && inEvent->wd == watchDescriptor) {
              cookie = 0;
              watchDescriptor = -1;
              event.action = "RENAMED";
              event.directory = mWDtoDirNode[inEvent->wd]->path;
              event.file = new std::string[2];
              event.file[0] = *lastMovedFromEvent.file;
              event.file[1] = inEvent->name;
              delete lastMovedFromEvent.file;
              mEventsQueue.push(event);
            } else {
              addEvent("CREATED", inEvent);
            }
            break;
        }
      } while ((position += sizeof(struct inotify_event) + inEvent->len) < bytesRead);
      position = 0;
    }
  }

  bool FileWatcherLinux::start() {
    mInotify = inotify_init();
    if (mInotify < 0) {
      return false;
    }

    if (mWatchFiles && pthread_create(&mThread, 0, &FileWatcherLinux::mainLoop, (void *)this)) {
      return true;
    } else {
      return false;
    }
  }

  void FileWatcherLinux::startWatchTree(Directory *tree) {
    std::queue<Directory *> dirQueue;

    dirQueue.push(tree);

    while (!dirQueue.empty()) {
      Directory *root = dirQueue.front();

      root->watchDescriptor = inotify_add_watch(
        mInotify,
        (root->path + "/" + root->name).c_str(),
        IN_ATTRIB | IN_CREATE | IN_DELETE | IN_MODIFY | IN_MOVED_FROM | IN_MOVED_TO
      );

      if (root->watchDescriptor < 0) {
        // error
        return; // ?
      }

      mWDtoDirNode[root->watchDescriptor] = root;

      // find all the directories within this directory
      // this breaks the alphabetical sorting of directories
      for (std::map<std::string, Directory *>::iterator dirIter = root->childDirectories.begin();
        dirIter != root->childDirectories.end(); ++dirIter)
      {
        dirQueue.push(dirIter->second);
      }

      dirQueue.pop();
    }
  }

  void FileWatcherLinux::stop() {}

  void FileWatcherLinux::setDirTree(Directory *tree) {
    mDirTree = tree;
  }

}
<|endoftext|>


<commit_before>#ifndef COMPONENTMANAGER_H
#define COMPONENTMANAGER_H

#include "components.hpp"
#include "animationcomponent.hpp"
#include "movecomponent.hpp"
#include "rendercomponent.hpp"
#include "inputcomponent.hpp"
#include "tilecomponent.hpp"
#include "sizecomponent.hpp"
#include "namecomponent.hpp"
#include "soundcomponent.hpp"
#include "healthcomponent.hpp"
#include "attackcomponent.hpp"
#include "commandcomponent.hpp"
#include "accelerationcomponent.hpp"
#include "birdcomponent.hpp"

typedef unsigned int ID;

class ComponentManager {
 public:
	Components<MoveComponent> moveComponents;
	Components<RenderComponent> renderComponents;
	Components<InputComponent> inputComponents;
	Components<TileComponent> tileComponents;
	Components<SizeComponent> sizeComponents;
    Components<NameComponent> nameComponents;
    Components<SoundComponent> soundComponents;
    Components<AnimationComponent> animationComponents;
    Components<HealthComponent> healthComponents;
    Components<AttackComponent> attackComponents;
    Components<CommandComponent> commandComponents;
    Components<AccelerationComponent> accelerationComponents;
    Components<BirdComponent> birdComponents;

    //Components<MoveComponent> moveComponentsDiff;
    //Components<RenderComponent> renderComponentsDiff;

	MoveComponent& createMoveComponent(const ID id) {
        return moveComponents[id] = MoveComponent();
    }
	RenderComponent& createRenderComponent(const ID id) {
        return renderComponents[id] = RenderComponent();
    }
	InputComponent& createInputComponent(const ID id) {
        return inputComponents[id] = InputComponent();
    }
	TileComponent& createTileComponent(const ID id) {
        return tileComponents[id] = TileComponent();
    }
    SizeComponent& createSizeComponent(const ID id) {
        return sizeComponents[id] = SizeComponent();
    }
    NameComponent& createNameComponent(const ID id) {
        return nameComponents[id] = NameComponent();
    }
    SoundComponent& createSoundComponent(const ID id) {
        return soundComponents[id] = SoundComponent();
    }
    AnimationComponent& createAnimationComponent(const ID id) {
        return animationComponents[id] = AnimationComponent();
    }
    HealthComponent& createHealthComponent(const ID id) {
        return healthComponents[id] = HealthComponent();
    }
    AttackComponent& createAttackComponent(const ID id) {
        return attackComponents[id] = AttackComponent();
    }
    CommandComponent& createCommandComponent(const ID id) {
        return commandComponents[id] = CommandComponent();
    }
    AccelerationComponent& createAccelerationComponent(const ID id) {
        return accelerationComponents[id] = AccelerationComponent();
    }
    BirdComponent& createBirdComponent(const ID id) {
        return birdComponents[id] = BirdComponent();
    }

    static constexpr uint sizePerEntity() {
        return
            sizeof(MoveComponent) +
            sizeof(RenderComponent) +
            sizeof(InputComponent) +
            sizeof(TileComponent) +
            sizeof(SizeComponent) +
            sizeof(NameComponent) +
            sizeof(SoundComponent) +
            sizeof(AnimationComponent) +
            sizeof(HealthComponent) +
            sizeof(AttackComponent) +
            sizeof(CommandComponent) +
            sizeof(AccelerationComponent);
    }

    void clearComponents(ID id);
};

#endif //COMPONENTMANAGER_H
<commit_msg>fixed bug where BirdComponent wasnt counted in sizePerEntity<commit_after>#ifndef COMPONENTMANAGER_H
#define COMPONENTMANAGER_H

#include "components.hpp"
#include "animationcomponent.hpp"
#include "movecomponent.hpp"
#include "rendercomponent.hpp"
#include "inputcomponent.hpp"
#include "tilecomponent.hpp"
#include "sizecomponent.hpp"
#include "namecomponent.hpp"
#include "soundcomponent.hpp"
#include "healthcomponent.hpp"
#include "attackcomponent.hpp"
#include "commandcomponent.hpp"
#include "accelerationcomponent.hpp"
#include "birdcomponent.hpp"

typedef unsigned int ID;

class ComponentManager {
 public:
	Components<MoveComponent> moveComponents;
	Components<RenderComponent> renderComponents;
	Components<InputComponent> inputComponents;
	Components<TileComponent> tileComponents;
	Components<SizeComponent> sizeComponents;
    Components<NameComponent> nameComponents;
    Components<SoundComponent> soundComponents;
    Components<AnimationComponent> animationComponents;
    Components<HealthComponent> healthComponents;
    Components<AttackComponent> attackComponents;
    Components<CommandComponent> commandComponents;
    Components<AccelerationComponent> accelerationComponents;
    Components<BirdComponent> birdComponents;

    //Components<MoveComponent> moveComponentsDiff;
    //Components<RenderComponent> renderComponentsDiff;

	MoveComponent& createMoveComponent(const ID id) {
        return moveComponents[id] = MoveComponent();
    }
	RenderComponent& createRenderComponent(const ID id) {
        return renderComponents[id] = RenderComponent();
    }
	InputComponent& createInputComponent(const ID id) {
        return inputComponents[id] = InputComponent();
    }
	TileComponent& createTileComponent(const ID id) {
        return tileComponents[id] = TileComponent();
    }
    SizeComponent& createSizeComponent(const ID id) {
        return sizeComponents[id] = SizeComponent();
    }
    NameComponent& createNameComponent(const ID id) {
        return nameComponents[id] = NameComponent();
    }
    SoundComponent& createSoundComponent(const ID id) {
        return soundComponents[id] = SoundComponent();
    }
    AnimationComponent& createAnimationComponent(const ID id) {
        return animationComponents[id] = AnimationComponent();
    }
    HealthComponent& createHealthComponent(const ID id) {
        return healthComponents[id] = HealthComponent();
    }
    AttackComponent& createAttackComponent(const ID id) {
        return attackComponents[id] = AttackComponent();
    }
    CommandComponent& createCommandComponent(const ID id) {
        return commandComponents[id] = CommandComponent();
    }
    AccelerationComponent& createAccelerationComponent(const ID id) {
        return accelerationComponents[id] = AccelerationComponent();
    }
    BirdComponent& createBirdComponent(const ID id) {
        return birdComponents[id] = BirdComponent();
    }

    static constexpr uint sizePerEntity() {
        return
            sizeof(MoveComponent) +
            sizeof(RenderComponent) +
            sizeof(InputComponent) +
            sizeof(TileComponent) +
            sizeof(SizeComponent) +
            sizeof(NameComponent) +
            sizeof(SoundComponent) +
            sizeof(AnimationComponent) +
            sizeof(HealthComponent) +
            sizeof(AttackComponent) +
            sizeof(CommandComponent) +
            sizeof(AccelerationComponent) +
            sizeof(BirdComponent);
    }

    void clearComponents(ID id);
};

#endif //COMPONENTMANAGER_H
<|endoftext|>


<commit_before>/*
 *    _aaaa,  _aa.  sa,  aaa              _aaaa,_  ac  .aa.   .aa.  .aa,  _a, sa
 *  .wWV!!!T  |Wm;  dQ[  $WF            _mWT!"?Y  ]QE  :Q#:   ]QW[  :WWk. ]Q[ dW
 * .jWf       :WW: .dQ[  dQ[           .mW(       )WE  :Q#:  .mSQh. :mWQa.]W[ dQ
 * |QW:       :Wm;  mQ[  dQ[           ]Qk        )Qmi_aQW:  <B:$Qc :WBWQ()W[ dQ
 * |W#:  .ww  ;WW;  dQ[  dQ[  .......  ]Qk        )QB?YYW#:  jf ]Qp.:mE)Qm]Q[ )W
 * +WQ;  :Wm  |Wm; .mQ[  dQ[ :qgggggga ]Qm.       ]WE  :Q# :=QasuQm;:Wk 3QQW[ )Y
 *  ]Wmi.:Wm  +$Q; .mW(  dQ[  !"!!"!!^ dQk,  ._   ]WE  :Q# :3D"!!$Qc.Wk -$WQ[
 *   "?????? ` "?!=m?!   ??'            -??????!  -?!  -?? -?'   "?"-?"  "??' "?
 *
 * Copyright (c) 2004 darkbits                              Js_./
 * Per Larsson a.k.a finalman                          _RqZ{a<^_aa
 * Olof Naessn a.k.a jansem/yakslem                _asww7!uY`>  )\a//
 *                                                 _Qhm`] _f "'c  1!5m
 * Visit: http://guichan.darkbits.org             )Qk<P ` _: :+' .'  "{[
 *                                               .)j(] .d_/ '-(  P .   S
 * License: (BSD)                                <Td/Z <fP"5(\"??"\a.  .L
 * Redistribution and use in source and          _dV>ws?a-?'      ._/L  #'
 * binary forms, with or without                 )4d[#7r, .   '     )d`)[
 * modification, are permitted provided         _Q-5'5W..j/?'   -?!\)cam'
 * that the following conditions are met:       j<<WP+k/);.        _W=j f
 * 1. Redistributions of source code must       .$%w\/]Q  . ."'  .  mj$
 *    retain the above copyright notice,        ]E.pYY(Q]>.   a     J@\
 *    this list of conditions and the           j(]1u<sE"L,. .   ./^ ]{a
 *    following disclaimer.                     4'_uomm\.  )L);-4     (3=
 * 2. Redistributions in binary form must        )_]X{Z('a_"a7'<a"a,  ]"[
 *    reproduce the above copyright notice,       #}<]m7`Za??4,P-"'7. ).m
 *    this list of conditions and the            ]d2e)Q(<Q(  ?94   b-  LQ/
 *    following disclaimer in the                <B!</]C)d_, '(<' .f. =C+m
 *    documentation and/or other materials      .Z!=J ]e []('-4f _ ) -.)m]'
 *    provided with the distribution.          .w[5]' _[ /.)_-"+?   _/ <W"
 * 3. Neither the name of darkbits nor the     :$we` _! + _/ .        j?
 *    names of its contributors may be used     =3)= _f  (_yQmWW$#(    "
 *    to endorse or promote products derived     -   W,  sQQQQmZQ#Wwa]..
 *    from this software without specific        (js, \[QQW$QWW#?!V"".
 *    prior written permission.                    ]y:.<\..          .
 *                                                 -]n w/ '         [.
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT       )/ )/           !
 * HOLDERS AND CONTRIBUTORS "AS IS" AND ANY         <  (; sac    ,    '
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING,               ]^ .-  %
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF            c <   r
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR            aga<  <La
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE          5%  )P'-3L
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR        _bQf` y`..)a
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,          ,J?4P'.P"_(\?d'.,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES               _Pa,)!f/<[]/  ?"
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT      _2-..:. .r+_,.. .
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,     ?a.<%"'  " -'.a_ _,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION)                     ^
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef GCN_GRAPHICS_HPP
#define GCN_GRAPHICS_HPP

#include "guichan/cliprectangle.hpp"
#include "guichan/color.hpp"
#include "guichan/image.hpp"

#include <stack>
#include <string>

namespace gcn
{
  class Font;

  /**
   * This is the graphics object used for drawing in the Gui-chan library.
   * It contains all vital member functions for drawing. The class is abstract
   * and should be overloaded, to create graphic drivers to specific platforms.
   * We have included graphic drivers for some common platforms, like the SDL
   * library and the Allegro library.
   *
   * In the graphics object you can set clip areas to limit drawing to certain
   * areas of the screen. Clip areas are put on a stack, which means that you
   * can push smaller and smaller clip areas onto the stack. All coordinates
   * will be relative to the topmost clip area. In most cases you won't have
   * to worry about the clip areas, unless you want to implement some really
   * complex widget. Pushing and poping of clip areas are handled automatically
   * by container widgets when their child widgets are drawn.
   *
   * IMPORTANT: Remember to pop each clip area that you pushed on the stack
   * after you are done with it.
   *
   * If you feel that the graphics object is to restrictive for your needs,
   * there is nothing stopping you from using your own code for drawing, for
   * example with a library like SDL. However, this might hurt the portability
   * of your application.
   *
   * If you implement a new graphics driver for a platform we don't support,
   * we would be very pleased to add it to Gui-chan.
   *
   * @see AllegroGraphics, OpenGLGraphics, SDLGraphics, Image
   */

  class Graphics
  {
  public:
    Graphics();

    virtual ~Graphics() { }

    /**
     * This function is called by the Gui class when Gui::draw() is
     * called. It is needed by some graphics objects to perform
     * preparations before they draw (for example, OpenGLGraphics).
     *
     * NOTE: You will never need to call this function yourself, the
     *       Gui object will do it for you.
     *
     * @see _endDraw, Gui::draw
     */
    virtual void _beginDraw() { }

    /**
     * This function is called by the Gui class when a Gui::draw() is
     * done. It should reset any state changes made by _beginDraw().
     *
     * NOTE: You will never need to call this function yourself, the
     *       Gui object will do it for you.
     *
     * @see _beginDraw, Gui::draw
     */
    virtual void _endDraw() { }

    /**
     * This function pushes a clip area onto the stack. The x and y
     * coordinates in the Rectangle will be relative to the last
     * pushed clip area. If the new area falls outside the current
     * clip area it will be clipped as necessary.
     *
     * @param area the clip area to be pushed onto the stack.
     * @return false if the the new area lays totally outside the
     *         current clip area. Note that an empty clip area
     *         will be pused in this case.
     * @see Rectangle
     */
    virtual bool pushClipArea(Rectangle area);

    /**
     * Removes the topmost clip area from the stack.
     *
     * @throws Exception if the stack is empty when calling this function.
     */
    virtual void popClipArea();

    /**
     * Draws a part of an image. Note that the width and height
     * arguments will not scale the image, but specifies the size
     * of the part to be drawn. If you want to draw the whole image
     * there is a simplified version of this function.
     *
     * EXAMPLE: drawImage(myImage, 10, 10, 20, 20, 40, 40);
     * will draw a rectangular piece of myImage starting at coordinate
     * (10, 10) in myImage, with width and height 40. The piece will be
     * drawn with it's top left corner at coordinate (20, 20).
     *
     * @param image the image to draw.
     * @param srcX source image x coordinate
     * @param srcY source image y coordinate
     * @param dstX destination x coordinate
     * @param dstY destination y coordinate
     * @param width the width of the piece
     * @param height the height of the piece
     * @see Image
     */
    virtual void drawImage(const Image* image, int srcX, int srcY,
                           int dstX, int dstY, int width,
                           int height) = 0;
    /**
     * This is a simplified version of the other drawImage. It will
     * draw a whole image at the coordinate you specify. It is equivalent
     * to calling:
     * drawImage(myImage, 0, 0, dstX, dstY, image->getWidth(), image->getHeight());
     *
     * @see drawImage
     */
    virtual void drawImage(const Image* image, int dstX, int dstY);

    /**
     * This function draws a single point (pixel).
     *
     * @param x the x coordinate
     * @param y the y coordinate
     */
    virtual void drawPoint(int x, int y) = 0;

    /**
     * This function draws a line.
     *
     * @param x1 the first x coordinate
     * @param y1 the first y coordinate
     * @param x2 the second x coordinate
     * @param y2 the second y coordinate
     */
    virtual void drawLine(int x1, int y1, int x2, int y2) = 0;

    /**
     * This function draws a simple, non-filled, rectangle with one pixel border.
     *
     * @param rectangle the rectangle to draw
     * @see Rectangle
     */
    virtual void drawRectangle(const Rectangle& rectangle) = 0;

    /**
     * This function draws a filled rectangle.
     *
     * @param rectangle the filled rectangle to draw
     * @see Rectangle
     */
    virtual void fillRectangle(const Rectangle& rectangle) = 0;

    /**
     * @see Color
     */
    virtual void setColor(const Color& color);
//     /**
//      *
//      */
//     void setHorizontalGradient(const Color& color1, const Color& color2){}
//     /**
//      *
//      */
//     void setVerticalGradient(const Color& color1, const Color& color2){}

    /**
     *
     */
    virtual void setFont(Font* font);

    /**
     *
     */
    virtual void drawText(const std::string& text, const int x, const int y);

//     /**
//      *
//      */
//     virtual void drawTextCenter(const std::string& text, const int x, const int y) = 0;

//     /**
//      *
//      */
//     void setBlender(const std::string blenderMode){}

  protected:
    std::stack<ClipRectangle> mClipStack;
    Color mColor;
    Font* mFont;

  }; // end graphics

} // end gcn

#endif // end GCN_GRAPHICS_HPP

/*
 * yakslem - "little cake on cake, but that's the fall"
 * finalman - "skall jag skriva det?"
 * yakslem - "ja, varfor inte?"
 */

<commit_msg>Change drawText so it uses Font::drawString<commit_after>/*
 *    _aaaa,  _aa.  sa,  aaa              _aaaa,_  ac  .aa.   .aa.  .aa,  _a, sa
 *  .wWV!!!T  |Wm;  dQ[  $WF            _mWT!"?Y  ]QE  :Q#:   ]QW[  :WWk. ]Q[ dW
 * .jWf       :WW: .dQ[  dQ[           .mW(       )WE  :Q#:  .mSQh. :mWQa.]W[ dQ
 * |QW:       :Wm;  mQ[  dQ[           ]Qk        )Qmi_aQW:  <B:$Qc :WBWQ()W[ dQ
 * |W#:  .ww  ;WW;  dQ[  dQ[  .......  ]Qk        )QB?YYW#:  jf ]Qp.:mE)Qm]Q[ )W
 * +WQ;  :Wm  |Wm; .mQ[  dQ[ :qgggggga ]Qm.       ]WE  :Q# :=QasuQm;:Wk 3QQW[ )Y
 *  ]Wmi.:Wm  +$Q; .mW(  dQ[  !"!!"!!^ dQk,  ._   ]WE  :Q# :3D"!!$Qc.Wk -$WQ[
 *   "?????? ` "?!=m?!   ??'            -??????!  -?!  -?? -?'   "?"-?"  "??' "?
 *
 * Copyright (c) 2004 darkbits                              Js_./
 * Per Larsson a.k.a finalman                          _RqZ{a<^_aa
 * Olof Naessn a.k.a jansem/yakslem                _asww7!uY`>  )\a//
 *                                                 _Qhm`] _f "'c  1!5m
 * Visit: http://guichan.darkbits.org             )Qk<P ` _: :+' .'  "{[
 *                                               .)j(] .d_/ '-(  P .   S
 * License: (BSD)                                <Td/Z <fP"5(\"??"\a.  .L
 * Redistribution and use in source and          _dV>ws?a-?'      ._/L  #'
 * binary forms, with or without                 )4d[#7r, .   '     )d`)[
 * modification, are permitted provided         _Q-5'5W..j/?'   -?!\)cam'
 * that the following conditions are met:       j<<WP+k/);.        _W=j f
 * 1. Redistributions of source code must       .$%w\/]Q  . ."'  .  mj$
 *    retain the above copyright notice,        ]E.pYY(Q]>.   a     J@\
 *    this list of conditions and the           j(]1u<sE"L,. .   ./^ ]{a
 *    following disclaimer.                     4'_uomm\.  )L);-4     (3=
 * 2. Redistributions in binary form must        )_]X{Z('a_"a7'<a"a,  ]"[
 *    reproduce the above copyright notice,       #}<]m7`Za??4,P-"'7. ).m
 *    this list of conditions and the            ]d2e)Q(<Q(  ?94   b-  LQ/
 *    following disclaimer in the                <B!</]C)d_, '(<' .f. =C+m
 *    documentation and/or other materials      .Z!=J ]e []('-4f _ ) -.)m]'
 *    provided with the distribution.          .w[5]' _[ /.)_-"+?   _/ <W"
 * 3. Neither the name of darkbits nor the     :$we` _! + _/ .        j?
 *    names of its contributors may be used     =3)= _f  (_yQmWW$#(    "
 *    to endorse or promote products derived     -   W,  sQQQQmZQ#Wwa]..
 *    from this software without specific        (js, \[QQW$QWW#?!V"".
 *    prior written permission.                    ]y:.<\..          .
 *                                                 -]n w/ '         [.
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT       )/ )/           !
 * HOLDERS AND CONTRIBUTORS "AS IS" AND ANY         <  (; sac    ,    '
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING,               ]^ .-  %
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF            c <   r
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR            aga<  <La
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE          5%  )P'-3L
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR        _bQf` y`..)a
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,          ,J?4P'.P"_(\?d'.,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES               _Pa,)!f/<[]/  ?"
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT      _2-..:. .r+_,.. .
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,     ?a.<%"'  " -'.a_ _,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION)                     ^
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef GCN_GRAPHICS_HPP
#define GCN_GRAPHICS_HPP

#include "guichan/cliprectangle.hpp"
#include "guichan/color.hpp"
#include "guichan/image.hpp"

#include <stack>
#include <string>

namespace gcn
{
  class Font;

  /**
   * This is the graphics object used for drawing in the Gui-chan library.
   * It contains all vital member functions for drawing. The class is abstract
   * and should be overloaded, to create graphic drivers to specific platforms.
   * We have included graphic drivers for some common platforms, like the SDL
   * library and the Allegro library.
   *
   * In the graphics object you can set clip areas to limit drawing to certain
   * areas of the screen. Clip areas are put on a stack, which means that you
   * can push smaller and smaller clip areas onto the stack. All coordinates
   * will be relative to the topmost clip area. In most cases you won't have
   * to worry about the clip areas, unless you want to implement some really
   * complex widget. Pushing and poping of clip areas are handled automatically
   * by container widgets when their child widgets are drawn.
   *
   * IMPORTANT: Remember to pop each clip area that you pushed on the stack
   * after you are done with it.
   *
   * If you feel that the graphics object is to restrictive for your needs,
   * there is nothing stopping you from using your own code for drawing, for
   * example with a library like SDL. However, this might hurt the portability
   * of your application.
   *
   * If you implement a new graphics driver for a platform we don't support,
   * we would be very pleased to add it to Gui-chan.
   *
   * @see AllegroGraphics, OpenGLGraphics, SDLGraphics, Image
   */

  class Graphics
  {
  public:
    Graphics();

    virtual ~Graphics() { }

    /**
     * This function is called by the Gui class when Gui::draw() is
     * called. It is needed by some graphics objects to perform
     * preparations before they draw (for example, OpenGLGraphics).
     *
     * NOTE: You will never need to call this function yourself, the
     *       Gui object will do it for you.
     *
     * @see _endDraw, Gui::draw
     */
    virtual void _beginDraw() { }

    /**
     * This function is called by the Gui class when a Gui::draw() is
     * done. It should reset any state changes made by _beginDraw().
     *
     * NOTE: You will never need to call this function yourself, the
     *       Gui object will do it for you.
     *
     * @see _beginDraw, Gui::draw
     */
    virtual void _endDraw() { }

    /**
     * This function pushes a clip area onto the stack. The x and y
     * coordinates in the Rectangle will be relative to the last
     * pushed clip area. If the new area falls outside the current
     * clip area it will be clipped as necessary.
     *
     * @param area the clip area to be pushed onto the stack.
     * @return false if the the new area lays totally outside the
     *         current clip area. Note that an empty clip area
     *         will be pused in this case.
     * @see Rectangle
     */
    virtual bool pushClipArea(Rectangle area);

    /**
     * Removes the topmost clip area from the stack.
     *
     * @throws Exception if the stack is empty when calling this function.
     */
    virtual void popClipArea();

    /**
     * Draws a part of an image. Note that the width and height
     * arguments will not scale the image, but specifies the size
     * of the part to be drawn. If you want to draw the whole image
     * there is a simplified version of this function.
     *
     * EXAMPLE: drawImage(myImage, 10, 10, 20, 20, 40, 40);
     * will draw a rectangular piece of myImage starting at coordinate
     * (10, 10) in myImage, with width and height 40. The piece will be
     * drawn with it's top left corner at coordinate (20, 20).
     *
     * @param image the image to draw.
     * @param srcX source image x coordinate
     * @param srcY source image y coordinate
     * @param dstX destination x coordinate
     * @param dstY destination y coordinate
     * @param width the width of the piece
     * @param height the height of the piece
     * @see Image
     */
    virtual void drawImage(const Image* image, int srcX, int srcY,
                           int dstX, int dstY, int width,
                           int height) = 0;
    /**
     * This is a simplified version of the other drawImage. It will
     * draw a whole image at the coordinate you specify. It is equivalent
     * to calling:
     * drawImage(myImage, 0, 0, dstX, dstY, image->getWidth(), image->getHeight());
     *
     * @see drawImage
     */
    virtual void drawImage(const Image* image, int dstX, int dstY);

    /**
     * This function draws a single point (pixel).
     *
     * @param x the x coordinate
     * @param y the y coordinate
     */
    virtual void drawPoint(int x, int y) = 0;

    /**
     * This function draws a line.
     *
     * @param x1 the first x coordinate
     * @param y1 the first y coordinate
     * @param x2 the second x coordinate
     * @param y2 the second y coordinate
     */
    virtual void drawLine(int x1, int y1, int x2, int y2) = 0;

    /**
     * This function draws a simple, non-filled, rectangle with one pixel border.
     *
     * @param rectangle the rectangle to draw
     * @see Rectangle
     */
    virtual void drawRectangle(const Rectangle& rectangle) = 0;

    /**
     * This function draws a filled rectangle.
     *
     * @param rectangle the filled rectangle to draw
     * @see Rectangle
     */
    virtual void fillRectangle(const Rectangle& rectangle) = 0;

    /**
     * @see Color
     */
    virtual void setColor(const Color& color);
//     /**
//      *
//      */
//     void setHorizontalGradient(const Color& color1, const Color& color2){}
//     /**
//      *
//      */
//     void setVerticalGradient(const Color& color1, const Color& color2){}

    /**
     *
     */
    virtual void setFont(Font* font);

    /**
     *
     */
    virtual void drawText(const std::string& text, int x, int y);

//     /**
//      *
//      */
//     virtual void drawTextCenter(const std::string& text, const int x, const int y) = 0;

//     /**
//      *
//      */
//     void setBlender(const std::string blenderMode){}

  protected:
    std::stack<ClipRectangle> mClipStack;
    Color mColor;
    Font* mFont;

  }; // end graphics

} // end gcn

#endif // end GCN_GRAPHICS_HPP

/*
 * yakslem - "little cake on cake, but that's the fall"
 * finalman - "skall jag skriva det?"
 * yakslem - "ja, varfor inte?"
 */

<|endoftext|>