<commit_before>////////////////////////////////////////////////////////////
//
// DAGON - An Adventure Game Engine
// Copyright (c) 2012 Senscape s.r.l.
// All rights reserved.
//
// NOTICE: Senscape permits you to use, modify, and
// distribute this file in accordance with the terms of the
// license agreement accompanying it.
//
////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////

#include "DGConfig.h"
#include "DGFont.h"
#include "DGLog.h"

#include <algorithm>
#include <limits>

////////////////////////////////////////////////////////////
// Implementation - Constructor
////////////////////////////////////////////////////////////

DGFont::DGFont() {
    config = &DGConfig::getInstance();
    log = &DGLog::getInstance();

    _isLoaded = false;

    this->setType(DGObjectFont);
}

////////////////////////////////////////////////////////////
// Implementation - Destructor
////////////////////////////////////////////////////////////

DGFont::~DGFont() {
    // Nothing to do here
}

////////////////////////////////////////////////////////////
// Implementation
////////////////////////////////////////////////////////////

void DGFont::clear() {
    if (_isLoaded) {
        glDeleteTextures(128, _textures);
        free(_textures);
        FT_Done_Face(_face);
    }
}

bool DGFont::isLoaded() {
    return _isLoaded;
}

#ifndef _MSC_VER
#	define c99_vsnprintf vsnprintf
#else
/* Microsoft CRT vsnprintf() does not conform to C99.
 * Credit goes to http://stackoverflow.com/a/8712996
 */
static int c99_vsnprintf(
	char *buf,
	size_t size,
	const char *format,
	va_list ap
) {
	int count = (buf != NULL && size > 0) ?
		_vsnprintf_s(buf, size, _TRUNCATE, format, ap) :
		-1;
	if (count < 0)
		count = _vscprintf(format, ap);
	return count;
}
#endif

template <size_t Size>
static inline int vsnprintf_truncate(
	char (&buf)[Size],
	const char *format,
	va_list ap
) {
	using namespace std;
	return min<int>(
			c99_vsnprintf(buf, Size, format, ap),
			Size > 0 ? min<size_t>(Size - 1, numeric_limits<int>::max()) : 0);
}

void DGFont::print(int x, int y, const char* text, ...) {
    if (!_isLoaded)
        return;

	char line[DGMaxFeedLength];
	int length;
	va_list	ap;

	if (text == NULL) {
		*line = 0;
		length = 0;
	} else {
		va_start(ap, text);
		length = vsnprintf_truncate(line, text, ap);
		va_end(ap);
	}

	glPushAttrib(GL_CURRENT_BIT | GL_ENABLE_BIT | GL_TRANSFORM_BIT);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    glPushMatrix();
    glTranslatef(x, y, 0);

    for (const char* c = line; length > 0; c++, length--) {
        int ch = *c;

        GLfloat texCoords[] = {	0, 0,
            0, _glyph[ch].y,
            _glyph[ch].x, _glyph[ch].y,
            _glyph[ch].x, 0 };

        GLshort coords[] = { 0, 0,
            0, _glyph[ch].rows,
            _glyph[ch].width, _glyph[ch].rows,
            _glyph[ch].width, 0 };

        glBindTexture(GL_TEXTURE_2D, _textures[ch]);

        glTranslatef((GLfloat)_glyph[ch].left, 0, 0);

        glPushMatrix();
        glTranslatef(0, -(GLfloat)_glyph[ch].top + _height, 0);

        glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
        glVertexPointer(2, GL_SHORT, 0, coords);
        glDrawArrays(GL_TRIANGLE_FAN, 0, 4);

        glPopMatrix();
        glTranslatef((GLfloat)(_glyph[ch].advance >> 6), 0, 0);
    }

    glPopMatrix();

	glPopAttrib();
}

// FIXME: This is a repeated method from DGRenderManager - it would be best to avoid this
void DGFont::setColor(int color) {
    uint32_t aux = color;

	uint8_t b = (aux & 0x000000ff);
	uint8_t g = (aux & 0x0000ff00) >> 8;
	uint8_t r = (aux & 0x00ff0000) >> 16;
	uint8_t a = (aux & 0xff000000) >> 24;

	glColor4f((float)(r / 255.0f), (float)(g / 255.0f), (float)(b / 255.0f), (float)(a / 255.f));
}

void DGFont::setDefault(unsigned int heightOfFont) {
    _height = (float)heightOfFont;

	// WARNING: That 49052 size may not be exact... Careful!
	if (FT_New_Memory_Face(*_library, DGDefFontBinary, 49052, 0, &_face)) {
        log->error(DGModFont, "%s", DGMsg260004);
        return;
    }

    _loadFont();

    _isLoaded = true;
}

void DGFont::setLibrary(FT_Library* library) {
    _library = library;
}

void DGFont::setResource(const char* fromFileName, unsigned int heightOfFont) {
    _height = (float)heightOfFont;

    if (FT_New_Face(*_library, config->path(DGPathRes, fromFileName, DGObjectFont), 0, &_face)) {
        log->error(DGModFont, "%s: %s", DGMsg260003, fromFileName);
        return;
    }

    _loadFont();

    _isLoaded = true;
}

////////////////////////////////////////////////////////////
// Implementation - Private methods
////////////////////////////////////////////////////////////

void DGFont::_loadFont() {
    unsigned char ch;

    FT_Set_Char_Size(_face, _height << 6, _height << 6, 96, 96);

    _textures = (GLuint*)malloc(128 * sizeof(GLuint));
	glGenTextures(128, _textures);

	for (ch = 0; ch < 128; ch++) {
		int width, height;
		float x, y;

        FT_Bitmap bitmap;
        FT_BitmapGlyph bitmapGlyph;
		FT_Glyph glyph;
		GLubyte* expandedData;

		if (FT_Load_Glyph(_face, FT_Get_Char_Index(_face, ch), FT_LOAD_DEFAULT)) {
			log->error(DGModFont, "%s: %c", DGMsg260005, ch);
            return;
        }

		if (FT_Get_Glyph(_face->glyph, &glyph)) {
			log->error(DGModFont, "%s: %c", DGMsg260006, ch);
            return;
        }

        // Test code to define a stroke
        /*FT_Stroker stroker = NULL;
        FT_Stroker_New(*_library, &stroker);
        FT_Stroker_Set(stroker, 32,
                       FT_STROKER_LINECAP_BUTT,
                       FT_STROKER_LINEJOIN_MITER,
                       0);
        FT_Glyph_Stroke(&glyph, stroker, 1);
		FT_Stroker_Done(stroker);*/

		FT_Glyph_To_Bitmap(&glyph, ft_render_mode_normal, 0, 1);
		bitmapGlyph = (FT_BitmapGlyph)glyph;

		bitmap = bitmapGlyph->bitmap;

		width = _next(bitmap.width);
		height = _next(bitmap.rows);

		expandedData = (GLubyte*)malloc(2 * width * height); // FIXME: Is there a sizeof() missing here?

		for (int j = 0; j < height; j++) {
			for (int i = 0; i < width; i++) {
				expandedData[2 * (i + j * width)] = expandedData[2 * (i + j * width) + 1] =
				(i >= bitmap.width || j >= bitmap.rows) ?
				0 : bitmap.buffer[i + bitmap.width * j];
			}
		}

		x = (float)bitmap.width / (float)width;
		y = (float)bitmap.rows / (float)height;

		_glyph[ch].x = x;
		_glyph[ch].y = y;
		_glyph[ch].width = bitmap.width;
		_glyph[ch].rows = bitmap.rows;
		_glyph[ch].left = bitmapGlyph->left;
		_glyph[ch].top = bitmapGlyph->top;
		_glyph[ch].advance = _face->glyph->advance.x;

		glBindTexture(GL_TEXTURE_2D, _textures[ch]);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_LINEAR);

		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height,
					 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, expandedData);

		free(expandedData);
	}
}

int DGFont::_next(int a) {
    int rval = 1;
    while (rval < a) rval <<= 1;
    return rval;
}
<commit_msg>Now using vsnprintf() from C++11 to parse strings.<commit_after>////////////////////////////////////////////////////////////
//
// DAGON - An Adventure Game Engine
// Copyright (c) 2012 Senscape s.r.l.
// All rights reserved.
//
// NOTICE: Senscape permits you to use, modify, and
// distribute this file in accordance with the terms of the
// license agreement accompanying it.
//
////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////

#include "DGConfig.h"
#include "DGFont.h"
#include "DGLog.h"

////////////////////////////////////////////////////////////
// Implementation - Constructor
////////////////////////////////////////////////////////////

DGFont::DGFont() {
    config = &DGConfig::getInstance();
    log = &DGLog::getInstance();

    _isLoaded = false;

    this->setType(DGObjectFont);
}

////////////////////////////////////////////////////////////
// Implementation - Destructor
////////////////////////////////////////////////////////////

DGFont::~DGFont() {
    // Nothing to do here
}

////////////////////////////////////////////////////////////
// Implementation
////////////////////////////////////////////////////////////

void DGFont::clear() {
    if (_isLoaded) {
        glDeleteTextures(128, _textures);
        free(_textures);
        FT_Done_Face(_face);
    }
}

bool DGFont::isLoaded() {
    return _isLoaded;
}

void DGFont::print(int x, int y, const char* text, ...) {
    if (!_isLoaded)
        return;

	char line[DGMaxFeedLength];
	int length;
	va_list	ap;

	if (text == NULL) {
		*line = 0;
		length = 0;
	} else {
		va_start(ap, text);
		// TODO: Test if vsnprintf() works as expected on VS 2012,
        // otherwise use fix from main branch
        length = vsnprintf(line, DGMaxFeedLength, text, ap);
		va_end(ap);
	}

	glPushAttrib(GL_CURRENT_BIT | GL_ENABLE_BIT | GL_TRANSFORM_BIT);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    glPushMatrix();
    glTranslatef(x, y, 0);

    for (const char* c = line; length > 0; c++, length--) {
        int ch = *c;

        GLfloat texCoords[] = {	0, 0,
            0, _glyph[ch].y,
            _glyph[ch].x, _glyph[ch].y,
            _glyph[ch].x, 0 };

        GLshort coords[] = { 0, 0,
            0, _glyph[ch].rows,
            _glyph[ch].width, _glyph[ch].rows,
            _glyph[ch].width, 0 };

        glBindTexture(GL_TEXTURE_2D, _textures[ch]);

        glTranslatef((GLfloat)_glyph[ch].left, 0, 0);

        glPushMatrix();
        glTranslatef(0, -(GLfloat)_glyph[ch].top + _height, 0);

        glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
        glVertexPointer(2, GL_SHORT, 0, coords);
        glDrawArrays(GL_TRIANGLE_FAN, 0, 4);

        glPopMatrix();
        glTranslatef((GLfloat)(_glyph[ch].advance >> 6), 0, 0);
    }

    glPopMatrix();

	glPopAttrib();
}

// FIXME: This is a repeated method from DGRenderManager - it would be best to avoid this
void DGFont::setColor(int color) {
    uint32_t aux = color;

	uint8_t b = (aux & 0x000000ff);
	uint8_t g = (aux & 0x0000ff00) >> 8;
	uint8_t r = (aux & 0x00ff0000) >> 16;
	uint8_t a = (aux & 0xff000000) >> 24;

	glColor4f((float)(r / 255.0f), (float)(g / 255.0f), (float)(b / 255.0f), (float)(a / 255.f));
}

void DGFont::setDefault(unsigned int heightOfFont) {
    _height = (float)heightOfFont;

	// WARNING: That 49052 size may not be exact... Careful!
	if (FT_New_Memory_Face(*_library, DGDefFontBinary, 49052, 0, &_face)) {
        log->error(DGModFont, "%s", DGMsg260004);
        return;
    }

    _loadFont();

    _isLoaded = true;
}

void DGFont::setLibrary(FT_Library* library) {
    _library = library;
}

void DGFont::setResource(const char* fromFileName, unsigned int heightOfFont) {
    _height = (float)heightOfFont;

    if (FT_New_Face(*_library, config->path(DGPathRes, fromFileName, DGObjectFont), 0, &_face)) {
        log->error(DGModFont, "%s: %s", DGMsg260003, fromFileName);
        return;
    }

    _loadFont();

    _isLoaded = true;
}

////////////////////////////////////////////////////////////
// Implementation - Private methods
////////////////////////////////////////////////////////////

void DGFont::_loadFont() {
    unsigned char ch;

    FT_Set_Char_Size(_face, _height << 6, _height << 6, 96, 96);

    _textures = (GLuint*)malloc(128 * sizeof(GLuint));
	glGenTextures(128, _textures);

	for (ch = 0; ch < 128; ch++) {
		int width, height;
		float x, y;

        FT_Bitmap bitmap;
        FT_BitmapGlyph bitmapGlyph;
		FT_Glyph glyph;
		GLubyte* expandedData;

		if (FT_Load_Glyph(_face, FT_Get_Char_Index(_face, ch), FT_LOAD_DEFAULT)) {
			log->error(DGModFont, "%s: %c", DGMsg260005, ch);
            return;
        }

		if (FT_Get_Glyph(_face->glyph, &glyph)) {
			log->error(DGModFont, "%s: %c", DGMsg260006, ch);
            return;
        }

        // Test code to define a stroke
        /*FT_Stroker stroker = NULL;
        FT_Stroker_New(*_library, &stroker);
        FT_Stroker_Set(stroker, 32,
                       FT_STROKER_LINECAP_BUTT,
                       FT_STROKER_LINEJOIN_MITER,
                       0);
        FT_Glyph_Stroke(&glyph, stroker, 1);
		FT_Stroker_Done(stroker);*/

		FT_Glyph_To_Bitmap(&glyph, ft_render_mode_normal, 0, 1);
		bitmapGlyph = (FT_BitmapGlyph)glyph;

		bitmap = bitmapGlyph->bitmap;

		width = _next(bitmap.width);
		height = _next(bitmap.rows);

		expandedData = (GLubyte*)malloc(2 * width * height); // FIXME: Is there a sizeof() missing here?

		for (int j = 0; j < height; j++) {
			for (int i = 0; i < width; i++) {
				expandedData[2 * (i + j * width)] = expandedData[2 * (i + j * width) + 1] =
				(i >= bitmap.width || j >= bitmap.rows) ?
				0 : bitmap.buffer[i + bitmap.width * j];
			}
		}

		x = (float)bitmap.width / (float)width;
		y = (float)bitmap.rows / (float)height;

		_glyph[ch].x = x;
		_glyph[ch].y = y;
		_glyph[ch].width = bitmap.width;
		_glyph[ch].rows = bitmap.rows;
		_glyph[ch].left = bitmapGlyph->left;
		_glyph[ch].top = bitmapGlyph->top;
		_glyph[ch].advance = _face->glyph->advance.x;

		glBindTexture(GL_TEXTURE_2D, _textures[ch]);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_LINEAR);

		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height,
					 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, expandedData);

		free(expandedData);
	}
}

int DGFont::_next(int a) {
    int rval = 1;
    while (rval < a) rval <<= 1;
    return rval;
}
<|endoftext|>


<commit_before>#include "GameController.hpp"
#include "Game.hpp"
#include "../GameLogic/FourInALine/Game.hpp"
#include "../GameLogic/FourInALine/AAI.hpp"
#include "../Highscore/database.h"
#include "../../app/FourInALine.hpp"

#include <QDebug>
#include <QTimer>

namespace Game
{

/**
 * Creates a new game controller.
 *
 * @param parent Parent object.
 */
GameController::GameController(QObject *parent) :
    QObject(parent), moveRequested(false), artificialIntelligence(4)
{
	this->timeLimitTimer = new QTimer(this);
	this->timeLimitTimer->setInterval(1000);

	this->artificialIntelligenceTimer = new QTimer(this);
	this->artificialIntelligenceTimer->setInterval(100);

	this->connect(this->timeLimitTimer, &QTimer::timeout, this, &GameController::updateRemainingTime);
	this->connect(this->artificialIntelligenceTimer, &QTimer::timeout, this, &GameController::checkHintReady);
}

/**
 * Frees all used resources.
 */
GameController::~GameController()
{
	this->endGame();
}

/**
 * Starts a new game.
 *
 * @param game The game to start.
 */
void GameController::startGame(QSharedPointer<Game> game)
{
	this->game = game;
	this->moveRequested = false;

	qDebug() << "[" << this << "::startGame ] " << "Started new game.";
	qDebug() << "[" << this << "::startGame ] " << "Player 1:" << game->getFirstPlayer()->getName();
	qDebug() << "[" << this << "::startGame ] " << "Player 2:" << game->getSecondPlayer()->getName();

	this->connect(this->game->getFirstPlayer().data(), &::Game::Players::AbstractPlayer::moveReady, this,
	              &::Game::GameController::makeMove);
	this->connect(this->game->getSecondPlayer().data(), &::Game::Players::AbstractPlayer::moveReady, this,
	              &::Game::GameController::makeMove);

	emit this->gameStarted(game->getGameLogic()->getBoard()->getNumberOfColumns(),
	                       game->getGameLogic()->getBoard()->getNumberOfRows(),
	                       game->getFirstPlayer(),
	                       game->getSecondPlayer(),
	                       game->getGameLogic()->hasTimeLimit());

	// Replay moves already made in case this game was loaded from a savegame.

	auto replay = game->getGameLogic()->getReplay();
	for (unsigned int i = 0; i < replay.size(); ++i)
	{
		auto player = game->playerIdToPlayer(replay[i].first);
		auto movePosition = game->getGameLogic()->computeMovePosition(i);

		emit this->startPlayerTurn(player);
		emit this->setCell(movePosition.first, movePosition.second, player);
		emit this->endPlayerTurn();
	}

	this->requestNextMove();
}

/**
 * Ends the current game.
 */
void GameController::endGame()
{
	qDebug() << "[" << this << "::endGame ] " << "Ended game.";

	this->abortRequest();
	this->game.reset();

	emit this->gameEnded();
}

/**
 * Shows a hint for the next move a player could make.
 */
void GameController::showHint()
{
	qDebug() << "[" << this << "::showHint ] " << "Show hint";

	if (!this->artificialIntelligence.isComputing())
	{
		this->artificialIntelligence.computeNextMoveAsynchronously(*this->game->getGameLogic());
		this->artificialIntelligenceTimer->start();
	}
}

/**
 * Undoes the last move.
 */
void GameController::undoLastMove()
{
	qDebug() << "[" << this << "::undoLastMove ] " << "Undo last move";

	bool gameWasOverBefore = this->game->getGameLogic()->isOver();

	this->abortRequest();

	if (gameWasOverBefore)
	{
		auto winningCells = this->game->getGameLogic()->getBoard()->findWinningCells();

		for (auto it = winningCells.begin(); it != winningCells.end(); it++)
		{
			emit this->setCellHighlighted(it.getXPosition(), it.getYPosition(), false);
		}
	}

	auto nMoves = this->game->getGameLogic()->getNumberOfMoves();

	auto position = this->game->getGameLogic()->computeMovePosition(nMoves - 1);
	this->game->getGameLogic()->undoLastMove();

	emit this->removeCell(position.first, position.second);

	position = this->game->getGameLogic()->computeMovePosition(nMoves - 2);
	this->game->getGameLogic()->undoLastMove();

	emit this->removeCell(position.first, position.second);

	if (gameWasOverBefore)
	{
		emit this->gameNotOverAnymore();
	}

	this->requestNextMove();
}

/**
 * Makes a move at the given position.
 *
 * @param x X position of the column in which the token should be dropped.
 */
void GameController::makeMove(unsigned int x)
{
	qDebug() << "[" << this << "::makeMove ] " << "Player " << game->getCurrentPlayer()->getName()
	         << " made a move, token dropped in column " << x;

	auto currentPlayer = game->getCurrentPlayer();

	this->moveRequested = false;
	this->timeLimitTimer->stop();
	this->game->getGameLogic()->makeMove(x);

	auto moveNo = this->game->getGameLogic()->getNumberOfMoves() - 1;
	auto position = this->game->getGameLogic()->computeMovePosition(moveNo);

	emit this->setCell(position.first, position.second, currentPlayer);
	emit this->endPlayerTurn();

	if (!this->checkGameOver())
	{
		this->requestNextMove();
	}
}

/**
 * Decrements remaining seconds by one and makes a timeout move when the player's time is up.
 */
void GameController::updateRemainingTime()
{
	auto RANDOM_MOVE = ::GameLogic::FourInALine::Game::TimeoutAction::RANDOM_MOVE;

	this->remainingSeconds--;

	emit this->remainingTimeChanged(this->game->getGameLogic()->getTimeLimit(), this->remainingSeconds);

	if (0 == this->remainingSeconds)
	{
		qDebug() << "[" << this << "::updateRemainingTime ] " << "Player "
		         << game->getCurrentPlayer()->getName() << " timed out.";

		this->game->getGameLogic()->makeTimeoutMove();

		if (this->game->getGameLogic()->getTimeoutAction() == RANDOM_MOVE)
		{
			this->moveRequested = false;
			this->timeLimitTimer->stop();

			auto moveNo = this->game->getGameLogic()->getNumberOfMoves() - 1;
			auto position = this->game->getGameLogic()->computeMovePosition(moveNo);

			emit this->endPlayerTurn();
			emit this->setCell(position.first, position.second, this->game->getCurrentPlayer());
		}
		else
		{
			this->abortRequest();
		}

		// When the timeout action is RANDOM_MOVE, the game is probably not over after a timeout.

		if (!this->checkGameOver())
		{
			this->requestNextMove();
		}
	}
}

/**
 * Checks whether the game is over and if yes stops timer and emits gameOver().
 *
 * @return When it is over true, otherwise false.
 */
bool GameController::checkGameOver()
{
	QSharedPointer< ::GameLogic::FourInALine::Game> game = this->game->getGameLogic();

	if (game->isOver())
	{
		auto board = game->getBoard();
		auto winningCells = board->findWinningCells();

		qDebug() << "[" << this << "::checkGameOver ] " << "Game is over.";

		this->abortRequest();

		if (this->game->getGameLogic()->hasTimeLimit())
		{
			this->remainingSeconds = 0;
			this->timeLimitTimer->stop();
		}

		for (auto it = winningCells.begin(); it != winningCells.end(); it++)
		{
			emit this->setCellHighlighted(it.getXPosition(), it.getYPosition(), true);
		}
        emit this->gameOver(game->isDraw());
        if (this->game->isSavingHighscore())
        {
            Database* database = ::FourInALine::getInstance()->getDatabase();
            int result = 0;
            if (game->isDraw())
                result = 2;
            else if (this->game->getWinningPlayer() == this->game->getFirstPlayer())
                result = 1;
            database->insertHighscore(this->game->getFirstPlayer()->getName(), this->game->getSecondPlayer()->getName(), result);
        }
		return true;
	}

	return false;
}

/**
 * Aborts current request for the next move if there is one.
 */
void GameController::abortRequest()
{
	if (!this->moveRequested)
	{
		return;
	}

	qDebug() << "[" << this << "::abortRequest ] " << "Aborting request for next move by "
	         << game->getCurrentPlayer()->getName() << ".";

	if (this->game->getGameLogic()->hasTimeLimit())
	{
		this->remainingSeconds = 0;
		this->timeLimitTimer->stop();
	}

	emit this->endPlayerTurn();

	this->game->getCurrentPlayer()->abortMove();

	this->moveRequested = false;
}

/**
 * Requests next move from the current player and starts timer if there is a time limit.
 */
void GameController::requestNextMove()
{
	qDebug() << "[" << this << "::requestNextMove ] " << "Requesting next move from player "
	         << this->game->getCurrentPlayer()->getName() << ".";

	if (this->moveRequested)
	{
		qDebug() << "[" << this << "::requestNextMove ] " << "ERROR: There is already a move request.";

		this->abortRequest();
	}

	emit this->startPlayerTurn(this->game->getCurrentPlayer());

	this->game->getCurrentPlayer()->requestMove(this->game);
	this->moveRequested = true;

	if (this->game->getGameLogic()->hasTimeLimit())
	{
		this->remainingSeconds = this->game->getGameLogic()->getTimeLimit();
		this->timeLimitTimer->start();
	}
}

/**
 * Checks whether the AI has finished computing the hint and emits the according signal if so.
 */
void GameController::checkHintReady()
{
	if (this->artificialIntelligence.isNextMoveReady())
	{
		unsigned int nColumns = this->game->getGameLogic()->getBoard()->getNumberOfColumns();

		std::vector<int> columnScores(nColumns);
		for (unsigned int i = 0; i < nColumns; ++i)
		{
			columnScores[i] = -1;
		}

		unsigned int nextMove = this->artificialIntelligence.getNextMove();
		columnScores[nextMove] = 100;

		emit this->showColumnHints(columnScores);

		this->artificialIntelligenceTimer->stop();
	}
}

}
<commit_msg>Fixed bug that led to a crash when saving the highscores.<commit_after>#include "GameController.hpp"
#include "Game.hpp"
#include "../GameLogic/FourInALine/Game.hpp"
#include "../GameLogic/FourInALine/AAI.hpp"
#include "../Highscore/database.h"
#include "../../app/FourInALine.hpp"

#include <QDebug>
#include <QTimer>

namespace Game
{

/**
 * Creates a new game controller.
 *
 * @param parent Parent object.
 */
GameController::GameController(QObject *parent) :
    QObject(parent), moveRequested(false), artificialIntelligence(4)
{
	this->timeLimitTimer = new QTimer(this);
	this->timeLimitTimer->setInterval(1000);

	this->artificialIntelligenceTimer = new QTimer(this);
	this->artificialIntelligenceTimer->setInterval(100);

	this->connect(this->timeLimitTimer, &QTimer::timeout, this, &GameController::updateRemainingTime);
	this->connect(this->artificialIntelligenceTimer, &QTimer::timeout, this, &GameController::checkHintReady);
}

/**
 * Frees all used resources.
 */
GameController::~GameController()
{
	this->endGame();
}

/**
 * Starts a new game.
 *
 * @param game The game to start.
 */
void GameController::startGame(QSharedPointer<Game> game)
{
	this->game = game;
	this->moveRequested = false;

	qDebug() << "[" << this << "::startGame ] " << "Started new game.";
	qDebug() << "[" << this << "::startGame ] " << "Player 1:" << game->getFirstPlayer()->getName();
	qDebug() << "[" << this << "::startGame ] " << "Player 2:" << game->getSecondPlayer()->getName();

	this->connect(this->game->getFirstPlayer().data(), &::Game::Players::AbstractPlayer::moveReady, this,
	              &::Game::GameController::makeMove);
	this->connect(this->game->getSecondPlayer().data(), &::Game::Players::AbstractPlayer::moveReady, this,
	              &::Game::GameController::makeMove);

	emit this->gameStarted(game->getGameLogic()->getBoard()->getNumberOfColumns(),
	                       game->getGameLogic()->getBoard()->getNumberOfRows(),
	                       game->getFirstPlayer(),
	                       game->getSecondPlayer(),
	                       game->getGameLogic()->hasTimeLimit());

	// Replay moves already made in case this game was loaded from a savegame.

	auto replay = game->getGameLogic()->getReplay();
	for (unsigned int i = 0; i < replay.size(); ++i)
	{
		auto player = game->playerIdToPlayer(replay[i].first);
		auto movePosition = game->getGameLogic()->computeMovePosition(i);

		emit this->startPlayerTurn(player);
		emit this->setCell(movePosition.first, movePosition.second, player);
		emit this->endPlayerTurn();
	}

	this->requestNextMove();
}

/**
 * Ends the current game.
 */
void GameController::endGame()
{
	qDebug() << "[" << this << "::endGame ] " << "Ended game.";

	this->abortRequest();
	this->game.reset();

	emit this->gameEnded();
}

/**
 * Shows a hint for the next move a player could make.
 */
void GameController::showHint()
{
	qDebug() << "[" << this << "::showHint ] " << "Show hint";

	if (!this->artificialIntelligence.isComputing())
	{
		this->artificialIntelligence.computeNextMoveAsynchronously(*this->game->getGameLogic());
		this->artificialIntelligenceTimer->start();
	}
}

/**
 * Undoes the last move.
 */
void GameController::undoLastMove()
{
	qDebug() << "[" << this << "::undoLastMove ] " << "Undo last move";

	bool gameWasOverBefore = this->game->getGameLogic()->isOver();

	this->abortRequest();

	if (gameWasOverBefore)
	{
		auto winningCells = this->game->getGameLogic()->getBoard()->findWinningCells();

		for (auto it = winningCells.begin(); it != winningCells.end(); it++)
		{
			emit this->setCellHighlighted(it.getXPosition(), it.getYPosition(), false);
		}
	}

	auto nMoves = this->game->getGameLogic()->getNumberOfMoves();

	auto position = this->game->getGameLogic()->computeMovePosition(nMoves - 1);
	this->game->getGameLogic()->undoLastMove();

	emit this->removeCell(position.first, position.second);

	position = this->game->getGameLogic()->computeMovePosition(nMoves - 2);
	this->game->getGameLogic()->undoLastMove();

	emit this->removeCell(position.first, position.second);

	if (gameWasOverBefore)
	{
		emit this->gameNotOverAnymore();
	}

	this->requestNextMove();
}

/**
 * Makes a move at the given position.
 *
 * @param x X position of the column in which the token should be dropped.
 */
void GameController::makeMove(unsigned int x)
{
	qDebug() << "[" << this << "::makeMove ] " << "Player " << game->getCurrentPlayer()->getName()
	         << " made a move, token dropped in column " << x;

	auto currentPlayer = game->getCurrentPlayer();

	this->moveRequested = false;
	this->timeLimitTimer->stop();
	this->game->getGameLogic()->makeMove(x);

	auto moveNo = this->game->getGameLogic()->getNumberOfMoves() - 1;
	auto position = this->game->getGameLogic()->computeMovePosition(moveNo);

	emit this->setCell(position.first, position.second, currentPlayer);
	emit this->endPlayerTurn();

	if (!this->checkGameOver())
	{
		this->requestNextMove();
	}
}

/**
 * Decrements remaining seconds by one and makes a timeout move when the player's time is up.
 */
void GameController::updateRemainingTime()
{
	auto RANDOM_MOVE = ::GameLogic::FourInALine::Game::TimeoutAction::RANDOM_MOVE;

	this->remainingSeconds--;

	emit this->remainingTimeChanged(this->game->getGameLogic()->getTimeLimit(), this->remainingSeconds);

	if (0 == this->remainingSeconds)
	{
		qDebug() << "[" << this << "::updateRemainingTime ] " << "Player "
		         << game->getCurrentPlayer()->getName() << " timed out.";

		this->game->getGameLogic()->makeTimeoutMove();

		if (this->game->getGameLogic()->getTimeoutAction() == RANDOM_MOVE)
		{
			this->moveRequested = false;
			this->timeLimitTimer->stop();

			auto moveNo = this->game->getGameLogic()->getNumberOfMoves() - 1;
			auto position = this->game->getGameLogic()->computeMovePosition(moveNo);

			emit this->endPlayerTurn();
			emit this->setCell(position.first, position.second, this->game->getCurrentPlayer());
		}
		else
		{
			this->abortRequest();
		}

		// When the timeout action is RANDOM_MOVE, the game is probably not over after a timeout.

		if (!this->checkGameOver())
		{
			this->requestNextMove();
		}
	}
}

/**
 * Checks whether the game is over and if yes stops timer and emits gameOver().
 *
 * @return When it is over true, otherwise false.
 */
bool GameController::checkGameOver()
{
	QSharedPointer< ::GameLogic::FourInALine::Game> game = this->game->getGameLogic();

	if (game->isOver())
	{
		auto board = game->getBoard();
		auto winningCells = board->findWinningCells();

		qDebug() << "[" << this << "::checkGameOver ] " << "Game is over.";

		this->abortRequest();

		if (this->game->getGameLogic()->hasTimeLimit())
		{
			this->remainingSeconds = 0;
			this->timeLimitTimer->stop();
		}

		for (auto it = winningCells.begin(); it != winningCells.end(); it++)
		{
			emit this->setCellHighlighted(it.getXPosition(), it.getYPosition(), true);
		}

        if (this->game->isSavingHighscore())
        {
            Database* database = ::FourInALine::getInstance()->getDatabase();
            int result = 0;
            if (game->isDraw())
                result = 2;
            else if (this->game->getWinningPlayer() == this->game->getFirstPlayer())
                result = 1;
            database->insertHighscore(this->game->getFirstPlayer()->getName(), this->game->getSecondPlayer()->getName(), result);
        }

		emit this->gameOver(game->isDraw());

		// this->game could be a new game after gameOver has been emitted!

		return true;
	}

	return false;
}

/**
 * Aborts current request for the next move if there is one.
 */
void GameController::abortRequest()
{
	if (!this->moveRequested)
	{
		return;
	}

	qDebug() << "[" << this << "::abortRequest ] " << "Aborting request for next move by "
	         << game->getCurrentPlayer()->getName() << ".";

	if (this->game->getGameLogic()->hasTimeLimit())
	{
		this->remainingSeconds = 0;
		this->timeLimitTimer->stop();
	}

	emit this->endPlayerTurn();

	this->game->getCurrentPlayer()->abortMove();

	this->moveRequested = false;
}

/**
 * Requests next move from the current player and starts timer if there is a time limit.
 */
void GameController::requestNextMove()
{
	qDebug() << "[" << this << "::requestNextMove ] " << "Requesting next move from player "
	         << this->game->getCurrentPlayer()->getName() << ".";

	if (this->moveRequested)
	{
		qDebug() << "[" << this << "::requestNextMove ] " << "ERROR: There is already a move request.";

		this->abortRequest();
	}

	emit this->startPlayerTurn(this->game->getCurrentPlayer());

	this->game->getCurrentPlayer()->requestMove(this->game);
	this->moveRequested = true;

	if (this->game->getGameLogic()->hasTimeLimit())
	{
		this->remainingSeconds = this->game->getGameLogic()->getTimeLimit();
		this->timeLimitTimer->start();
	}
}

/**
 * Checks whether the AI has finished computing the hint and emits the according signal if so.
 */
void GameController::checkHintReady()
{
	if (this->artificialIntelligence.isNextMoveReady())
	{
		unsigned int nColumns = this->game->getGameLogic()->getBoard()->getNumberOfColumns();

		std::vector<int> columnScores(nColumns);
		for (unsigned int i = 0; i < nColumns; ++i)
		{
			columnScores[i] = -1;
		}

		unsigned int nextMove = this->artificialIntelligence.getNextMove();
		columnScores[nextMove] = 100;

		emit this->showColumnHints(columnScores);

		this->artificialIntelligenceTimer->stop();
	}
}

}
<|endoftext|>


<commit_before>#include "Context.h"
#include "Timing.h"
using namespace esp;

static ESP_TLS_DECL ThreadContext* _thread_context = nullptr;
static ProfileContext* _context = nullptr;

void ThreadContext::Zone(const char *zoneName)
{
	ProfileEvent *ev = profileIntervalStack.Push();
	ev->eventType = EV_ZONE_INTERVAL;
	ev->timestamp = GetSystemTimestamp();
	ev->frameNumber = frameNumber;
	ev->eventNameRef = _context->MapStringToReference(zoneName);

}

void ThreadContext::End()
{

}

void ThreadContext::Sample(const char *probeName, const int32_t& value)
{

}

void ThreadContext::Sample(const char *probeName, const uint32_t& value)
{

}

void ThreadContext::Sample(const char *probeName, const float& value)
{

}
<commit_msg>Little bites. (I'm cooking supper.)<commit_after>#include "Context.h"
#include "Timing.h"
using namespace esp;

static ESP_TLS_DECL ThreadContext* _thread_context = nullptr;
static ProfileContext* _context = nullptr;

void ThreadContext::Zone(const char *zoneName)
{
	ProfileEvent *parentZone = profileIntervalStack.Peek();
	ProfileEvent *ev = profileIntervalStack.Push();
	ev->eventType = EV_ZONE_INTERVAL;
	ev->timestamp = GetSystemTimestamp();
	ev->frameNumber = frameNumber;
	ev->eventNameRef = _context->MapStringToReference(zoneName);
	if (parentZone){
		ev->parentEventRef = parentZone->id;
	}
}

void ThreadContext::End()
{

}

void ThreadContext::Sample(const char *probeName, const int32_t& value)
{

}

void ThreadContext::Sample(const char *probeName, const uint32_t& value)
{

}

void ThreadContext::Sample(const char *probeName, const float& value)
{

}
<|endoftext|>


<commit_before>//=======================================================================
// Copyright Baptiste Wicht 2011.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include "Context.hpp"

using std::map;
using std::string;
using std::endl;
using std::vector;
using std::unordered_set;
using std::unordered_map;

using namespace eddic;

vector<Context*> Context::contexts;

/*vector<OldContext*> OldContext::contexts;
unsigned int OldContext::currentVariable = 0;

OldContext::~OldContext() {
    map<string, Variable*>::const_iterator it = variables.begin();
    map<string, Variable*>::const_iterator end = variables.end();

    for ( ; it != end; ++it) {
        delete it->second;
    }
}

Variable* OldContext::find(const std::string& variable) {
    map<string, Variable*>::const_iterator it = variables.find(variable);

    if (it == variables.end()) {
        if (m_parent != NULL) {
            return m_parent->find(variable);
        }

        return NULL;
    }

    return it->second;
}

bool OldContext::exists(const std::string& variable) const {
    if (variables.find(variable) != variables.end()) {
        return true;
    }

    if (m_parent != NULL) {
        return m_parent->exists(variable);
    }

    return false;
}

unsigned int OldContext::index(const std::string& variable) const {
    map<string, Variable*>::const_iterator it = variables.find(variable);

    if (it == variables.end()) {
        if (m_parent != NULL) {
            return m_parent->index(variable);
        }

        return -1;
    }

    return it->second->index();
}

Variable* OldContext::create(const std::string& variable, Type type) {
    Variable* v = new Variable(variable, type, currentVariable++);

    variables[variable] = v;

    return v;
}

void OldContext::write(AssemblyFileWriter& writer) {
    map<string, Variable*>::const_iterator it = variables.begin();
    map<string, Variable*>::const_iterator end = variables.end();

    for ( ; it != end; ++it) {
        if (it->second->type() == INT) {
            writer.stream() << ".comm VI" << it->second->index() << ",4,4" << endl;
        } else if (it->second->type() == STRING) {
            writer.stream() << ".comm VS" << it->second->index() << ",8,4" << endl;
        }
    }
}

void OldContext::writeAll(AssemblyFileWriter& writer) {
    for (vector<OldContext*>::const_iterator it = contexts.begin(); it != contexts.end(); ++it) {
        (*it)->write(writer);
    }
}

void OldContext::cleanup(){
    for (vector<OldContext*>::const_iterator it = contexts.begin(); it != contexts.end(); ++it) {
        delete *it;
    }
}*/

Context::~Context() {
    StoredVariables::const_iterator it = m_stored.begin();
    StoredVariables::const_iterator end = m_stored.end();

    for ( ; it != end; ++it) {
        delete it->second;
    }
}

void Context::storeVariable(const std::string& name, Variable* variable){
    m_stored[name] = variable;
}

bool Context::exists(const std::string& variable) const {
    bool found = m_visibles.find(variable) != m_visibles.end();

    if(!found){
        if(m_parent){
            return m_parent->exists(variable);
        }
    }

    return found;
}

Variable* Context::getVariable(const std::string& variable) const {
    bool found = m_visibles.find(variable) != m_visibles.end();

    if(!found){
        if(m_parent){
            return getVariable(variable);
        }
    }

    return (*m_stored.find(variable)).second;
}

void Context::cleanup(){
    for (vector<Context*>::const_iterator it = contexts.begin(); it != contexts.end(); ++it) {
        delete *it;
    }
}

void FunctionContext::write(AssemblyFileWriter& writer){
    StoredVariables::const_iterator it = m_stored.begin();
    StoredVariables::const_iterator end = m_stored.end();

    int size = 0;

    for ( ; it != end; ++it) {
        if (it->second->type() == INT) {
            size += 4;
        } else if (it->second->type() == STRING) {
            size += 8;
        }
    }

    if(size > 0){
        writer.stream() << "subl $" << size << " , %edx" << std::endl;
    }
}

void FunctionContext::release(AssemblyFileWriter& writer){
    StoredVariables::const_iterator it = m_stored.begin();
    StoredVariables::const_iterator end = m_stored.end();

    int size = 0;

    for ( ; it != end; ++it) {
        if (it->second->type() == INT) {
            size += 4;
        } else if (it->second->type() == STRING) {
            size += 8;
        }
    }

    if(size > 0){
        writer.stream() << "addl $" << size << " , %edx" << std::endl;
    }
}

void GlobalContext::write(AssemblyFileWriter& writer){
    StoredVariables::const_iterator it = m_stored.begin();
    StoredVariables::const_iterator end = m_stored.end();

    for ( ; it != end; ++it) {
        if (it->second->type() == INT) {
            writer.stream() << ".comm VI" << it->second->position().name() << ",4,4" << endl;
        } else if (it->second->type() == STRING) {
            writer.stream() << ".comm VS" << it->second->position().name() << ",8,4" << endl;
        }
    }
}

Variable* GlobalContext::addVariable(const std::string& variable, Type type){
    Position position(GLOBAL, variable);

    Variable* v = new Variable(variable, type, position);

    m_visibles.insert(variable);

    storeVariable(variable, v);

    return v;
}

Variable* FunctionContext::newVariable(const std::string& variable, Type type){
    Position position(STACK, currentPosition);

    currentPosition += type == INT ? 4 : 8;

    return new Variable(variable, type, position);
}

Variable* FunctionContext::addVariable(const std::string& variable, Type type){
    Variable* v = newVariable(variable, type);

    m_visibles.insert(variable);

    storeVariable(variable, v);

    return v;
}

Variable* BlockContext::addVariable(const std::string& variable, Type type){
    Variable* v = m_functionContext->newVariable(variable, type);

    m_visibles.insert(variable);

    m_functionContext->storeVariable(variable, v);

    return v;
}

void Variable::moveToRegister(AssemblyFileWriter& writer, std::string reg){
    if(m_type == INT){
        if(m_position.isStack()){
            writer.stream() << "movl -" << m_position.offset() << "(ebp), " << reg << endl;
        } else if(m_position.isGlobal()){
            writer.stream() << "movl VI" << m_position.name() << ", " << reg << endl;
        }
   } else if (m_type == STRING){
       //TODO Should never be called
   }
}

void Variable::moveToRegister(AssemblyFileWriter& writer, std::string reg1, std::string reg2){
    if(m_type == INT){
       //TODO Should never be called
   } else if (m_type == STRING){
       if(m_position.isStack()){
           writer.stream() << "movl -" << m_position.offset() << "(ebp), " << reg1 << endl;
           writer.stream() << "movl -" << (m_position.offset() + 4) << "(ebp), " << reg2 << endl;
       } else {
           writer.stream() << "movl VS" << m_position.name() << ", " << reg1 << endl;
           writer.stream() << "movl VS" << m_position.name() << "+4, " << reg2 << endl;
       }
   }
}

void Variable::moveFromRegister(AssemblyFileWriter& writer, std::string reg){
    if(m_type == INT){
        if(m_position.isStack()){
            writer.stream() << "movl " << reg << ", -" << m_position.offset() << "(ebp)" << endl;
        } else if(m_position.isGlobal()){
            writer.stream() << "movl " << reg << ", VI" << m_position.name()  << endl;
        }
   } else if (m_type == STRING){
       //TODO Should never be called
   }
}

void Variable::moveFromRegister(AssemblyFileWriter& writer, std::string reg1, std::string reg2){
    if(m_type == INT){
       //TODO Should never be called
   } else if (m_type == STRING){
       if(m_position.isStack()){
           writer.stream() << "movl " << reg1 << ", -" << m_position.offset() << "(ebp)" << endl;
           writer.stream() << "movl " << reg2 << ", -" << (m_position.offset() + 4) << "(ebp)" << endl;
       } else {
           writer.stream() << "movl " << reg1 << ", VS" << m_position.name() << endl;
           writer.stream() << "movl " << reg2 << ", VS" << m_position.name() << "+4" << endl;
       }
   }
}

void Variable::pushToStack(AssemblyFileWriter& writer){
    switch (m_type) {
        case INT:
            if(m_position.isStack()){
                writer.stream() << "pushl -" << m_position.offset() << "(ebp)" << std::endl;
            } else if(m_position.isGlobal()){
                writer.stream() << "pushl VI" << m_position.name() << std::endl;
            }

            break;
        case STRING:
            if(m_position.isStack()){
                writer.stream() << "pushl -" << m_position.offset() << "(ebp)" << std::endl;
                writer.stream() << "pushl -" << (m_position.offset() + 4) << "(ebp)" << std::endl;
            } else if(m_position.isGlobal()){
                writer.stream() << "pushl VS" << m_index << endl;
                writer.stream() << "pushl VS" << m_index << "+4" << std::endl;
            }

            break;
    }
}

void Variable::popFromStack(AssemblyFileWriter& writer){
    switch (m_type) {
        case INT:
            writer.stream() << "movl (%esp), %eax" << endl;
            writer.stream() << "addl $4, %esp" << endl;

            moveFromRegister(writer, "%eax");

            break;
        case STRING:
            writer.stream() << "movl (%esp), %eax" << endl;
            writer.stream() << "movl 4(%esp), %ebx" << endl;
            writer.stream() << "addl $8, %esp" << endl;

            moveFromRegister(writer, "%eax", "%ebx");

            break;
    }
}
<commit_msg>Fix ASM output for variables in stack<commit_after>//=======================================================================
// Copyright Baptiste Wicht 2011.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include "Context.hpp"

using std::map;
using std::string;
using std::endl;
using std::vector;
using std::unordered_set;
using std::unordered_map;

using namespace eddic;

vector<Context*> Context::contexts;

/*vector<OldContext*> OldContext::contexts;
unsigned int OldContext::currentVariable = 0;

OldContext::~OldContext() {
    map<string, Variable*>::const_iterator it = variables.begin();
    map<string, Variable*>::const_iterator end = variables.end();

    for ( ; it != end; ++it) {
        delete it->second;
    }
}

Variable* OldContext::find(const std::string& variable) {
    map<string, Variable*>::const_iterator it = variables.find(variable);

    if (it == variables.end()) {
        if (m_parent != NULL) {
            return m_parent->find(variable);
        }

        return NULL;
    }

    return it->second;
}

bool OldContext::exists(const std::string& variable) const {
    if (variables.find(variable) != variables.end()) {
        return true;
    }

    if (m_parent != NULL) {
        return m_parent->exists(variable);
    }

    return false;
}

unsigned int OldContext::index(const std::string& variable) const {
    map<string, Variable*>::const_iterator it = variables.find(variable);

    if (it == variables.end()) {
        if (m_parent != NULL) {
            return m_parent->index(variable);
        }

        return -1;
    }

    return it->second->index();
}

Variable* OldContext::create(const std::string& variable, Type type) {
    Variable* v = new Variable(variable, type, currentVariable++);

    variables[variable] = v;

    return v;
}

void OldContext::write(AssemblyFileWriter& writer) {
    map<string, Variable*>::const_iterator it = variables.begin();
    map<string, Variable*>::const_iterator end = variables.end();

    for ( ; it != end; ++it) {
        if (it->second->type() == INT) {
            writer.stream() << ".comm VI" << it->second->index() << ",4,4" << endl;
        } else if (it->second->type() == STRING) {
            writer.stream() << ".comm VS" << it->second->index() << ",8,4" << endl;
        }
    }
}

void OldContext::writeAll(AssemblyFileWriter& writer) {
    for (vector<OldContext*>::const_iterator it = contexts.begin(); it != contexts.end(); ++it) {
        (*it)->write(writer);
    }
}

void OldContext::cleanup(){
    for (vector<OldContext*>::const_iterator it = contexts.begin(); it != contexts.end(); ++it) {
        delete *it;
    }
}*/

Context::~Context() {
    StoredVariables::const_iterator it = m_stored.begin();
    StoredVariables::const_iterator end = m_stored.end();

    for ( ; it != end; ++it) {
        delete it->second;
    }
}

void Context::storeVariable(const std::string& name, Variable* variable){
    m_stored[name] = variable;
}

bool Context::exists(const std::string& variable) const {
    bool found = m_visibles.find(variable) != m_visibles.end();

    if(!found){
        if(m_parent){
            return m_parent->exists(variable);
        }
    }

    return found;
}

Variable* Context::getVariable(const std::string& variable) const {
    bool found = m_visibles.find(variable) != m_visibles.end();

    if(!found){
        if(m_parent){
            return getVariable(variable);
        }
    }

    return (*m_stored.find(variable)).second;
}

void Context::cleanup(){
    for (vector<Context*>::const_iterator it = contexts.begin(); it != contexts.end(); ++it) {
        delete *it;
    }
}

void FunctionContext::write(AssemblyFileWriter& writer){
    StoredVariables::const_iterator it = m_stored.begin();
    StoredVariables::const_iterator end = m_stored.end();

    int size = 0;

    for ( ; it != end; ++it) {
        if (it->second->type() == INT) {
            size += 4;
        } else if (it->second->type() == STRING) {
            size += 8;
        }
    }

    if(size > 0){
        writer.stream() << "subl $" << size << " , %edx" << std::endl;
    }
}

void FunctionContext::release(AssemblyFileWriter& writer){
    StoredVariables::const_iterator it = m_stored.begin();
    StoredVariables::const_iterator end = m_stored.end();

    int size = 0;

    for ( ; it != end; ++it) {
        if (it->second->type() == INT) {
            size += 4;
        } else if (it->second->type() == STRING) {
            size += 8;
        }
    }

    if(size > 0){
        writer.stream() << "addl $" << size << " , %edx" << std::endl;
    }
}

void GlobalContext::write(AssemblyFileWriter& writer){
    StoredVariables::const_iterator it = m_stored.begin();
    StoredVariables::const_iterator end = m_stored.end();

    for ( ; it != end; ++it) {
        if (it->second->type() == INT) {
            writer.stream() << ".comm VI" << it->second->position().name() << ",4,4" << endl;
        } else if (it->second->type() == STRING) {
            writer.stream() << ".comm VS" << it->second->position().name() << ",8,4" << endl;
        }
    }
}

Variable* GlobalContext::addVariable(const std::string& variable, Type type){
    Position position(GLOBAL, variable);

    Variable* v = new Variable(variable, type, position);

    m_visibles.insert(variable);

    storeVariable(variable, v);

    return v;
}

Variable* FunctionContext::newVariable(const std::string& variable, Type type){
    Position position(STACK, currentPosition);

    currentPosition += type == INT ? 4 : 8;

    return new Variable(variable, type, position);
}

Variable* FunctionContext::addVariable(const std::string& variable, Type type){
    Variable* v = newVariable(variable, type);

    m_visibles.insert(variable);

    storeVariable(variable, v);

    return v;
}

Variable* BlockContext::addVariable(const std::string& variable, Type type){
    Variable* v = m_functionContext->newVariable(variable, type);

    m_visibles.insert(variable);

    m_functionContext->storeVariable(variable, v);

    return v;
}

void Variable::moveToRegister(AssemblyFileWriter& writer, std::string reg){
    if(m_type == INT){
        if(m_position.isStack()){
            writer.stream() << "movl -" << m_position.offset() << "(%ebp), " << reg << endl;
        } else if(m_position.isGlobal()){
            writer.stream() << "movl VI" << m_position.name() << ", " << reg << endl;
        }
   } else if (m_type == STRING){
       //TODO Should never be called
   }
}

void Variable::moveToRegister(AssemblyFileWriter& writer, std::string reg1, std::string reg2){
    if(m_type == INT){
       //TODO Should never be called
   } else if (m_type == STRING){
       if(m_position.isStack()){
           writer.stream() << "movl -" << m_position.offset() << "(%ebp), " << reg1 << endl;
           writer.stream() << "movl -" << (m_position.offset() + 4) << "(%ebp), " << reg2 << endl;
       } else {
           writer.stream() << "movl VS" << m_position.name() << ", " << reg1 << endl;
           writer.stream() << "movl VS" << m_position.name() << "+4, " << reg2 << endl;
       }
   }
}

void Variable::moveFromRegister(AssemblyFileWriter& writer, std::string reg){
    if(m_type == INT){
        if(m_position.isStack()){
            writer.stream() << "movl " << reg << ", -" << m_position.offset() << "(%ebp)" << endl;
        } else if(m_position.isGlobal()){
            writer.stream() << "movl " << reg << ", VI" << m_position.name()  << endl;
        }
   } else if (m_type == STRING){
       //TODO Should never be called
   }
}

void Variable::moveFromRegister(AssemblyFileWriter& writer, std::string reg1, std::string reg2){
    if(m_type == INT){
       //TODO Should never be called
   } else if (m_type == STRING){
       if(m_position.isStack()){
           writer.stream() << "movl " << reg1 << ", -" << m_position.offset() << "(%ebp)" << endl;
           writer.stream() << "movl " << reg2 << ", -" << (m_position.offset() + 4) << "(%ebp)" << endl;
       } else {
           writer.stream() << "movl " << reg1 << ", VS" << m_position.name() << endl;
           writer.stream() << "movl " << reg2 << ", VS" << m_position.name() << "+4" << endl;
       }
   }
}

void Variable::pushToStack(AssemblyFileWriter& writer){
    switch (m_type) {
        case INT:
            if(m_position.isStack()){
                writer.stream() << "pushl -" << m_position.offset() << "(%ebp)" << std::endl;
            } else if(m_position.isGlobal()){
                writer.stream() << "pushl VI" << m_position.name() << std::endl;
            }

            break;
        case STRING:
            if(m_position.isStack()){
                writer.stream() << "pushl -" << m_position.offset() << "(%ebp)" << std::endl;
                writer.stream() << "pushl -" << (m_position.offset() + 4) << "(%ebp)" << std::endl;
            } else if(m_position.isGlobal()){
                writer.stream() << "pushl VS" << m_index << endl;
                writer.stream() << "pushl VS" << m_index << "+4" << std::endl;
            }

            break;
    }
}

void Variable::popFromStack(AssemblyFileWriter& writer){
    switch (m_type) {
        case INT:
            writer.stream() << "movl (%esp), %eax" << endl;
            writer.stream() << "addl $4, %esp" << endl;

            moveFromRegister(writer, "%eax");

            break;
        case STRING:
            writer.stream() << "movl (%esp), %eax" << endl;
            writer.stream() << "movl 4(%esp), %ebx" << endl;
            writer.stream() << "addl $8, %esp" << endl;

            moveFromRegister(writer, "%eax", "%ebx");

            break;
    }
}
<|endoftext|>


<commit_before>//////////////////////////////////////////////////////////////////////////////
// NoLifeClient - Part of the NoLifeStory project                           //
// Copyright © 2013 Peter Atashian                                          //
//                                                                          //
// This program is free software: you can redistribute it and/or modify     //
// it under the terms of the GNU Affero General Public License as           //
// published by the Free Software Foundation, either version 3 of the       //
// License, or (at your option) any later version.                          //
//                                                                          //
// This program is distributed in the hope that it will be useful,          //
// but WITHOUT ANY WARRANTY; without even the implied warranty of           //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            //
// GNU Affero General Public License for more details.                      //
//                                                                          //
// You should have received a copy of the GNU Affero General Public License //
// along with this program.  If not, see <http://www.gnu.org/licenses/>.    //
//////////////////////////////////////////////////////////////////////////////

#include "layer.hpp"
#include "map.hpp"
#include <nx/nx.hpp>

namespace nl {
    std::array<layer, 8> layers;
    void layer::render() {
        for (uint8_t i = 0; i < 8; ++i) {
            //for (obj & o : layers[i].Objs) o.Render();
            for (tile & t : layers[i].tiles) t.render();
            //if (Player::Pos.layer == i) Player::Render();
        }
    }
    void layer::load() {
        for (uint8_t i = 0; i < 8; ++i) {
            layer & l = layers[i];
            node n = map::current[i];
            node tn = nx::map["Tile"][n["info"]["tS"] + ".img"];
            //l.Objs.clear();
            //for (node nn : n["obj"]) l.Objs.emplace_back(nn);
            //sort(l.Objs.begin(), l.Objs.end());
            l.tiles.clear();
            for (node nn : n["tile"]) l.tiles.emplace_back(nn, tn);
            std::sort(l.tiles.begin(), l.tiles.end(), [](tile const & a, tile const & b) {
                return a.z < b.z;
            });
        }
    }
}<commit_msg>client: #include <algorithm> in layer.cpp<commit_after>//////////////////////////////////////////////////////////////////////////////
// NoLifeClient - Part of the NoLifeStory project                           //
// Copyright © 2013 Peter Atashian                                          //
//                                                                          //
// This program is free software: you can redistribute it and/or modify     //
// it under the terms of the GNU Affero General Public License as           //
// published by the Free Software Foundation, either version 3 of the       //
// License, or (at your option) any later version.                          //
//                                                                          //
// This program is distributed in the hope that it will be useful,          //
// but WITHOUT ANY WARRANTY; without even the implied warranty of           //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            //
// GNU Affero General Public License for more details.                      //
//                                                                          //
// You should have received a copy of the GNU Affero General Public License //
// along with this program.  If not, see <http://www.gnu.org/licenses/>.    //
//////////////////////////////////////////////////////////////////////////////

#include "layer.hpp"
#include "map.hpp"
#include <nx/nx.hpp>
#include <algorithm>

namespace nl {
    std::array<layer, 8> layers;
    void layer::render() {
        for (uint8_t i = 0; i < 8; ++i) {
            //for (obj & o : layers[i].Objs) o.Render();
            for (tile & t : layers[i].tiles) t.render();
            //if (Player::Pos.layer == i) Player::Render();
        }
    }
    void layer::load() {
        for (uint8_t i = 0; i < 8; ++i) {
            layer & l = layers[i];
            node n = map::current[i];
            node tn = nx::map["Tile"][n["info"]["tS"] + ".img"];
            //l.Objs.clear();
            //for (node nn : n["obj"]) l.Objs.emplace_back(nn);
            //sort(l.Objs.begin(), l.Objs.end());
            l.tiles.clear();
            for (node nn : n["tile"]) l.tiles.emplace_back(nn, tn);
            std::sort(l.tiles.begin(), l.tiles.end(), [](tile const & a, tile const & b) {
                return a.z < b.z;
            });
        }
    }
}
<|endoftext|>


<commit_before>/**
* @file      Decoder.cpp
* @copyright (c) 2014 by Petr Zemek (s3rvac@gmail.com) and contributors
* @license   BSD, see the @c LICENSE file for more details
* @brief     Implementation of the Decoder class.
*/

#include "Decoder.h"

#include <cassert>
#include <regex>
#include <sstream>

#include "BInteger.h"
#include "BString.h"
#include "Utils.h"

namespace bencoding {

/**
* @brief Constructs a new exception with the given message.
*/
DecodingError::DecodingError(const std::string &what):
	std::runtime_error(what) {}

/**
* @brief Constructs a decoder.
*/
Decoder::Decoder() {}

/**
* @brief Creates a new decoder.
*/
std::unique_ptr<Decoder> Decoder::create() {
	return std::unique_ptr<Decoder>(new Decoder());
}

/**
* @brief Decodes the given bencoded data and returns them.
*/
std::unique_ptr<BItem> Decoder::decode(const std::string &data) {
	std::istringstream input(data);
	return decode(input);
}

/**
* @brief Reads all the data from the given @a input, decodes them and returns
*        them.
*/
std::unique_ptr<BItem> Decoder::decode(std::istream &input) {
	switch (input.peek()) {
		case 'i':
			return decodeInteger(input);
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
			return decodeString(input);
		default:
			throw DecodingError(std::string("unexpected character: '") +
				static_cast<char>(input.peek()) + "'");
	}

	assert(false && "should never happen");
	return std::unique_ptr<BItem>();
}

/**
* @brief Decodes an integer from @a input.
*
* @par Format
* @code
* i<integer encoded in base ten ASCII>e
* @endcode
*
* @par Example
* @code
* i3e represents the integer 3
* @endcode
*
* Moreover, only the significant digits should be used, one cannot pad the
* integer with zeroes, such as @c i04e (see the
* specification).
*/
std::unique_ptr<BInteger> Decoder::decodeInteger(std::istream &input) const {
	return decodeEncodedInteger(readEncodedInteger(input));
}

/**
* @brief Reads an encoded integer from @a input.
*/
std::string Decoder::readEncodedInteger(std::istream &input) const {
	// See the description of decodeInteger() for the format and example.
	std::string encodedInteger;
	bool encodedIntegerReadCorrectly = readUntil(input, encodedInteger, 'e');
	if (!encodedIntegerReadCorrectly) {
		throw DecodingError("error during the decoding of an integer near '" +
			encodedInteger + "'");
	}

	return encodedInteger;
}

/**
* @brief Decodes the given encoded integer.
*/
std::unique_ptr<BInteger> Decoder::decodeEncodedInteger(
		const std::string &encodedInteger) const {
	// See the description of decodeInteger() for the format and example.
	std::regex integerRegex("i([-+]?(0|[1-9][0-9]*))e");
	std::smatch match;
	bool valid = std::regex_match(encodedInteger, match, integerRegex);
	if (!valid) {
		throw DecodingError("encountered an encoded integer of invalid format: '" +
			encodedInteger + "'");
	}

	BInteger::ValueType integerValue;
	strToNum(match[1].str(), integerValue);
	return BInteger::create(integerValue);
}

/**
* @brief Decodes a string from @a input.
*
* @par Format
* @code
* <string length encoded in base ten ASCII>:<string data>
* @endcode
*
* @par Example
* @code
* 4:test represents the string "test"
* @endcode
*/
std::unique_ptr<BString> Decoder::decodeString(std::istream &input) const {
	std::string::size_type stringLength(readStringLength(input));
	readColon(input);
	std::string str(readStringOfGivenLength(input, stringLength));
	return BString::create(str);
}

/**
* @brief Reads the string length from @a input, validates it, and returns it.
*/
std::string::size_type Decoder::readStringLength(std::istream &input) const {
	std::string stringLengthInASCII;
	bool stringLengthInASCIIReadCorrectly = readUpTo(input, stringLengthInASCII, ':');
	if (!stringLengthInASCIIReadCorrectly) {
		throw DecodingError("error during the decoding of a string near '" +
			stringLengthInASCII + "'");
	}

	std::string::size_type stringLength;
	bool stringLengthIsValid = strToNum(stringLengthInASCII, stringLength);
	if (!stringLengthIsValid) {
		throw DecodingError("invalid string length: '" + stringLengthInASCII + "'");
	}

	return stringLength;
}

/**
* @brief Reads a colon from @a input and discards it.
*/
void Decoder::readColon(std::istream &input) const {
	int c = input.get();
	if (c != ':') {
		throw DecodingError("expected a colon (':'), got '" +
			std::to_string(static_cast<char>(c)) + "'");
	}
}

/**
* @brief Reads a string of the given @a length from @a input and returns it.
*/
std::string Decoder::readStringOfGivenLength(std::istream &input,
		std::string::size_type length) const {
	std::string str(length, char());
	input.read(&str[0], length);
	std::string::size_type numOfReadChars(input.gcount());
	if (numOfReadChars != length) {
		throw DecodingError("expected a string containing " + std::to_string(length) +
			" characters, but read only " + std::to_string(numOfReadChars) +
			" characters");
	}
	return str;
}

} // namespace bencoding
<commit_msg>Decoder: Enhance the formatting of the description of decode().<commit_after>/**
* @file      Decoder.cpp
* @copyright (c) 2014 by Petr Zemek (s3rvac@gmail.com) and contributors
* @license   BSD, see the @c LICENSE file for more details
* @brief     Implementation of the Decoder class.
*/

#include "Decoder.h"

#include <cassert>
#include <regex>
#include <sstream>

#include "BInteger.h"
#include "BString.h"
#include "Utils.h"

namespace bencoding {

/**
* @brief Constructs a new exception with the given message.
*/
DecodingError::DecodingError(const std::string &what):
	std::runtime_error(what) {}

/**
* @brief Constructs a decoder.
*/
Decoder::Decoder() {}

/**
* @brief Creates a new decoder.
*/
std::unique_ptr<Decoder> Decoder::create() {
	return std::unique_ptr<Decoder>(new Decoder());
}

/**
* @brief Decodes the given bencoded @a data and returns them.
*/
std::unique_ptr<BItem> Decoder::decode(const std::string &data) {
	std::istringstream input(data);
	return decode(input);
}

/**
* @brief Reads all the data from the given @a input, decodes them and returns
*        them.
*/
std::unique_ptr<BItem> Decoder::decode(std::istream &input) {
	switch (input.peek()) {
		case 'i':
			return decodeInteger(input);
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
			return decodeString(input);
		default:
			throw DecodingError(std::string("unexpected character: '") +
				static_cast<char>(input.peek()) + "'");
	}

	assert(false && "should never happen");
	return std::unique_ptr<BItem>();
}

/**
* @brief Decodes an integer from @a input.
*
* @par Format
* @code
* i<integer encoded in base ten ASCII>e
* @endcode
*
* @par Example
* @code
* i3e represents the integer 3
* @endcode
*
* Moreover, only the significant digits should be used, one cannot pad the
* integer with zeroes, such as @c i04e (see the
* specification).
*/
std::unique_ptr<BInteger> Decoder::decodeInteger(std::istream &input) const {
	return decodeEncodedInteger(readEncodedInteger(input));
}

/**
* @brief Reads an encoded integer from @a input.
*/
std::string Decoder::readEncodedInteger(std::istream &input) const {
	// See the description of decodeInteger() for the format and example.
	std::string encodedInteger;
	bool encodedIntegerReadCorrectly = readUntil(input, encodedInteger, 'e');
	if (!encodedIntegerReadCorrectly) {
		throw DecodingError("error during the decoding of an integer near '" +
			encodedInteger + "'");
	}

	return encodedInteger;
}

/**
* @brief Decodes the given encoded integer.
*/
std::unique_ptr<BInteger> Decoder::decodeEncodedInteger(
		const std::string &encodedInteger) const {
	// See the description of decodeInteger() for the format and example.
	std::regex integerRegex("i([-+]?(0|[1-9][0-9]*))e");
	std::smatch match;
	bool valid = std::regex_match(encodedInteger, match, integerRegex);
	if (!valid) {
		throw DecodingError("encountered an encoded integer of invalid format: '" +
			encodedInteger + "'");
	}

	BInteger::ValueType integerValue;
	strToNum(match[1].str(), integerValue);
	return BInteger::create(integerValue);
}

/**
* @brief Decodes a string from @a input.
*
* @par Format
* @code
* <string length encoded in base ten ASCII>:<string data>
* @endcode
*
* @par Example
* @code
* 4:test represents the string "test"
* @endcode
*/
std::unique_ptr<BString> Decoder::decodeString(std::istream &input) const {
	std::string::size_type stringLength(readStringLength(input));
	readColon(input);
	std::string str(readStringOfGivenLength(input, stringLength));
	return BString::create(str);
}

/**
* @brief Reads the string length from @a input, validates it, and returns it.
*/
std::string::size_type Decoder::readStringLength(std::istream &input) const {
	std::string stringLengthInASCII;
	bool stringLengthInASCIIReadCorrectly = readUpTo(input, stringLengthInASCII, ':');
	if (!stringLengthInASCIIReadCorrectly) {
		throw DecodingError("error during the decoding of a string near '" +
			stringLengthInASCII + "'");
	}

	std::string::size_type stringLength;
	bool stringLengthIsValid = strToNum(stringLengthInASCII, stringLength);
	if (!stringLengthIsValid) {
		throw DecodingError("invalid string length: '" + stringLengthInASCII + "'");
	}

	return stringLength;
}

/**
* @brief Reads a colon from @a input and discards it.
*/
void Decoder::readColon(std::istream &input) const {
	int c = input.get();
	if (c != ':') {
		throw DecodingError("expected a colon (':'), got '" +
			std::to_string(static_cast<char>(c)) + "'");
	}
}

/**
* @brief Reads a string of the given @a length from @a input and returns it.
*/
std::string Decoder::readStringOfGivenLength(std::istream &input,
		std::string::size_type length) const {
	std::string str(length, char());
	input.read(&str[0], length);
	std::string::size_type numOfReadChars(input.gcount());
	if (numOfReadChars != length) {
		throw DecodingError("expected a string containing " + std::to_string(length) +
			" characters, but read only " + std::to_string(numOfReadChars) +
			" characters");
	}
	return str;
}

} // namespace bencoding
<|endoftext|>


<commit_before>/* --
 * Copyright (C) 2013, George Makrydakis <irrequietus@gmail.com>
 *
 * This file is part of odreex.
 *
 * odreex is free software: you can redistribute it and/or modify it under the
 * terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 *
 * odreex is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * odreex. If not, see http://www.gnu.org/licenses/.
 *
 */

#ifndef _ODREEX_AMPLE_CHARSEQ_HH_
#define _ODREEX_AMPLE_CHARSEQ_HH_

#include <cstdint>
#include <type_traits>
#include <odreex/ppmpf/base.hh>

namespace odreex {
namespace ample {

/* NOTE: A prototypical template "metastring" implementation. Despite several
 * advances in C++11, it is still not possible for a series of reasons to deploy
 * strings as non type template parameters. Using the PPMPF_REPEAT macro family
 * from the odreex ppmpf framework, we can "add" this facility without the need
 * of a third party dependency. Null characters can be introduced in this
 * "metastring" called charseq from now on. In a few words this macro expands
 * as follows:
 *
 * Given : ample_charseq("hello, world")
 * Equals: charseq<'h', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd'>
 *
 * And this is a regular type that can be used as a type parameter wherever this
 * is applicable.
 */
template<char... Chars_C>
struct charseq {

    static char const value[sizeof...(Chars_C)];
    static std::size_t size = sizeof...(Chars_C);

    template<std::size_t Z>
    static constexpr uint16_t intfy_at(char const (&a)[Z], std::size_t N) {
        return static_cast<uint16_t>(Z - 1 > N ? a[N] : 256);
    }

    template<uint16_t... Int_N>
    struct intfy {
    private:
        template<typename, typename = intfy<>>
        struct impl;

        template<uint16_t X, uint16_t... A, uint16_t... B>
        struct impl<intfy<X, A...>, intfy<B...>>
            : std::conditional< (X == 256)
                              , impl< intfy<A...>, intfy<B...>>
                              , impl <intfy<A...>, intfy<B...,X>>>::type
        {};

        template<uint16_t... X>
        struct impl<intfy<>, intfy<X...>> {
            typedef charseq<static_cast<unsigned char>(X)...> type;
        };
    public:
        typedef typename impl<intfy<Int_N...>>::type type;
    };
};

template<char... X>
char const charseq<X...>::value[] = {
    X...
};

} /* ample */
} /* odreex */

/* NOTE: ample_charseq(x) where x is a quoted string is the function macro doing
 * the generation of the charsec<char...> equivalent type from the x string. The
 * ample_charseq_intfy_at is left as a macro to use during generation. The
 * PPMPF_HRMAX value is used for the time being as indicating the maximum string
 * "length" allowed, which right now defaults to 64.
 */
#define ample_charseq_intfy_at(n,x) \
        odreex::ample::charseq<>::intfy_at(x, n)

#define ample_charseq(x) \
    typename odreex::ample::charseq<>::intfy< \
        PPMPF_REPEATS(ample_charseq_intfy_at, PPMPF_COMMA, x) \
    >::type

#endif /* _ODREEX_AMPLE_CHARSEQ_HH_ */
<commit_msg>Added a missing const specifier to charseq internals.<commit_after>/* --
 * Copyright (C) 2013, George Makrydakis <irrequietus@gmail.com>
 *
 * This file is part of odreex.
 *
 * odreex is free software: you can redistribute it and/or modify it under the
 * terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 *
 * odreex is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * odreex. If not, see http://www.gnu.org/licenses/.
 *
 */

#ifndef _ODREEX_AMPLE_CHARSEQ_HH_
#define _ODREEX_AMPLE_CHARSEQ_HH_

#include <cstdint>
#include <type_traits>
#include <odreex/ppmpf/base.hh>

namespace odreex {
namespace ample {

/* NOTE: A prototypical template "metastring" implementation. Despite several
 * advances in C++11, it is still not possible for a series of reasons to deploy
 * strings as non type template parameters. Using the PPMPF_REPEAT macro family
 * from the odreex ppmpf framework, we can "add" this facility without the need
 * of a third party dependency. Null characters can be introduced in this
 * "metastring" called charseq from now on. In a few words this macro expands
 * as follows:
 *
 * Given : ample_charseq("hello, world")
 * Equals: charseq<'h', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd'>
 *
 * And this is a regular type that can be used as a type parameter wherever this
 * is applicable.
 */
template<char... Chars_C>
struct charseq {

    static char const value[sizeof...(Chars_C)];
    static std::size_t const size = sizeof...(Chars_C);

    template<std::size_t Z>
    static constexpr uint16_t intfy_at(char const (&a)[Z], std::size_t N) {
        return static_cast<uint16_t>(Z - 1 > N ? a[N] : 256);
    }

    template<uint16_t... Int_N>
    struct intfy {
    private:
        template<typename, typename = intfy<>>
        struct impl;

        template<uint16_t X, uint16_t... A, uint16_t... B>
        struct impl<intfy<X, A...>, intfy<B...>>
            : std::conditional< (X == 256)
                              , impl< intfy<A...>, intfy<B...>>
                              , impl <intfy<A...>, intfy<B...,X>>>::type
        {};

        template<uint16_t... X>
        struct impl<intfy<>, intfy<X...>> {
            typedef charseq<static_cast<unsigned char>(X)...> type;
        };
    public:
        typedef typename impl<intfy<Int_N...>>::type type;
    };
};

template<char... X>
char const charseq<X...>::value[] = {
    X...
};

} /* ample */
} /* odreex */

/* NOTE: ample_charseq(x) where x is a quoted string is the function macro doing
 * the generation of the charsec<char...> equivalent type from the x string. The
 * ample_charseq_intfy_at is left as a macro to use during generation. The
 * PPMPF_HRMAX value is used for the time being as indicating the maximum string
 * "length" allowed, which right now defaults to 64.
 */
#define ample_charseq_intfy_at(n,x) \
        odreex::ample::charseq<>::intfy_at(x, n)

#define ample_charseq(x) \
    typename odreex::ample::charseq<>::intfy< \
        PPMPF_REPEATS(ample_charseq_intfy_at, PPMPF_COMMA, x) \
    >::type

#endif /* _ODREEX_AMPLE_CHARSEQ_HH_ */
<|endoftext|>


<commit_before>#include "foo_musicbrainz.h"

static const GUID guid_cfg_short_date = { 0x18734618, 0x7920, 0x4d24, { 0x84, 0xa1, 0xb9, 0xd6, 0x6e, 0xd8, 0x25, 0xbc } };
cfg_bool cfg_short_date(guid_cfg_short_date, false);

static const GUID guid_cfg_no_feat = { 0x98f9ce46, 0xe0c5, 0x48f4, { 0xa6, 0x3e, 0x19, 0x34, 0x39, 0x64, 0x35, 0x55 } };
cfg_bool cfg_no_feat(guid_cfg_no_feat, false);

static const GUID guid_cfg_write_ids = { 0x8c8b61e0, 0x8eea, 0x4c34, { 0x9a, 0x51, 0x4d, 0xa9, 0x9c, 0xec, 0xcb, 0xbc } };
cfg_bool cfg_write_ids(guid_cfg_write_ids, true);

static const GUID guid_cfg_albumtype = { 0xd8fdb1d8, 0xde2, 0x4f1f, { 0x85, 0x5a, 0xc0, 0x5, 0x98, 0x60, 0x9b, 0xe9 } };
cfg_bool cfg_albumtype(guid_cfg_albumtype, true);

static const GUID guid_cfg_albumstatus = { 0x57a8dddd, 0xdf24, 0x4fd3, { 0xac, 0x95, 0x6f, 0x8, 0x3, 0x26, 0x41, 0x7c } };
cfg_bool cfg_albumstatus(guid_cfg_albumstatus, true);

static const GUID guid_cfg_albumtype_data = { 0x20968c09, 0xb0d4, 0x4059, { 0xb8, 0x92, 0xda, 0x76, 0xf8, 0xe6, 0x51, 0x4e } };
cfg_string cfg_albumtype_data(guid_cfg_albumtype_data, "MUSICBRAINZ_ALBUMTYPE");

static const GUID guid_cfg_albumstatus_data = { 0x77182aac, 0x1caa, 0x4793, { 0xb7, 0x15, 0xcc, 0xf8, 0x97, 0xba, 0x11, 0x1a } };
cfg_string cfg_albumstatus_data(guid_cfg_albumstatus_data, "MUSICBRAINZ_ALBUMSTATUS");

class CPreferencesDialog : public CDialogImpl<CPreferencesDialog>
{
public:
	enum { IDD = IDD_PREFERENCES };

	BEGIN_MSG_MAP(CPreferencesDialog)
		MSG_WM_INITDIALOG(OnInitDialog)
		COMMAND_HANDLER_EX(IDC_SHORT_DATE, BN_CLICKED, OnShortDate)
		COMMAND_HANDLER_EX(IDC_NO_FEAT, BN_CLICKED, OnNoFeat)
		COMMAND_HANDLER_EX(IDC_WRITE_IDS, BN_CLICKED, OnWriteIDs)
		COMMAND_HANDLER_EX(IDC_ALBUMTYPE, BN_CLICKED, OnAlbumType)
		COMMAND_HANDLER_EX(IDC_ALBUMSTATUS, BN_CLICKED, OnAlbumStatus)
		COMMAND_HANDLER_EX(IDC_ALBUMTYPE_DATA, EN_UPDATE, OnAlbumTypeUpdate)
		COMMAND_HANDLER_EX(IDC_ALBUMSTATUS_DATA, EN_UPDATE, OnAlbumStatusUpdate)
	END_MSG_MAP()

	void OnFinalMessage(HWND hwnd)
	{
		delete this;
	}

	BOOL OnInitDialog(CWindow wndFocus, LPARAM lInitParam)
	{
		CEdit cfg_edit_albumtype_data = GetDlgItem(IDC_ALBUMTYPE_DATA);
		CEdit cfg_edit_albumstatus_data = GetDlgItem(IDC_ALBUMSTATUS_DATA);
		((CButton)GetDlgItem(IDC_SHORT_DATE)).SetCheck(cfg_short_date.get_value());
		((CButton)GetDlgItem(IDC_NO_FEAT)).SetCheck(cfg_no_feat.get_value());
		((CButton)GetDlgItem(IDC_WRITE_IDS)).SetCheck(cfg_write_ids.get_value());
		((CButton)GetDlgItem(IDC_ALBUMTYPE)).SetCheck(cfg_albumtype.get_value());
		((CButton)GetDlgItem(IDC_ALBUMSTATUS)).SetCheck(cfg_albumstatus.get_value());
		uSetWindowText(cfg_edit_albumtype_data, cfg_albumtype_data);
		uSetWindowText(cfg_edit_albumstatus_data, cfg_albumstatus_data);
		if (cfg_albumtype.get_value()) cfg_edit_albumtype_data.EnableWindow(1);
		if (cfg_albumstatus.get_value()) cfg_edit_albumstatus_data.EnableWindow(1);
		return 0;
	}

	void OnShortDate(UINT uNotifyCode, int nID, CButton wndCtl)
	{
		cfg_short_date = (bool)wndCtl.GetCheck();
	}

	void OnNoFeat(UINT uNotifyCode, int nID, CButton wndCtl)
	{
		cfg_no_feat = (bool)wndCtl.GetCheck();
	}

	void OnWriteIDs(UINT uNotifyCode, int nID, CButton wndCtl)
	{
		cfg_write_ids = (bool)wndCtl.GetCheck();
	}

	void OnAlbumType(UINT uNotifyCode, int nID, CButton wndCtl)
	{
		cfg_albumtype = (bool)wndCtl.GetCheck();
		GetDlgItem(IDC_ALBUMTYPE_DATA).EnableWindow(cfg_albumtype.get_value());
	}

	void OnAlbumStatus(UINT uNotifyCode, int nID, CButton wndCtl)
	{
		cfg_albumstatus = (bool)wndCtl.GetCheck();
		GetDlgItem(IDC_ALBUMSTATUS_DATA).EnableWindow(cfg_albumstatus.get_value());
	}

	void OnAlbumTypeUpdate(UINT uNotifyCode, int nID, CWindow wndCtl)
	{
		uGetWindowText(wndCtl, cfg_albumtype_data);
	}

	void OnAlbumStatusUpdate(UINT uNotifyCode, int nID, CWindow wndCtl)
	{
		uGetWindowText(wndCtl, cfg_albumstatus_data);
	}
};

class foo_mb_preferences_page : public preferences_page_v2
{
public:
	HWND create(HWND parent)
	{
		CPreferencesDialog *PreferencesDialog = new CPreferencesDialog();
		PreferencesDialog->Create(parent);
		return PreferencesDialog->m_hWnd;
	}

	const char * get_name()
	{
		return "MusicBrainz Tagger";
	}

	GUID get_guid()
	{
		static const GUID guid_foo_mb_preferences_page = { 0x79179a37, 0x5942, 0x4fdf, { 0xbb, 0xb7, 0x93, 0xfd, 0x35, 0xfc, 0xfe, 0x97 } };
		return guid_foo_mb_preferences_page;
	}

	GUID get_parent_guid()
	{
		return preferences_page::guid_tagging;
	}

	bool reset_query()
	{
		return true;
	}

	void reset()
	{
		cfg_short_date = false;
		cfg_no_feat = false;
		cfg_write_ids = true;
		cfg_albumtype = true;
		cfg_albumstatus = true;
		cfg_albumtype_data = "MUSICBRAINZ_ALBUMTYPE";
		cfg_albumstatus_data = "MUSICBRAINZ_ALBUMSTATUS";
	}

	double get_sort_priority()
	{
		return 0;
	}
};

static preferences_page_factory_t<foo_mb_preferences_page> g_foo_mb_preferences_page_factory;
<commit_msg>Updated preferences page to use latest API<commit_after>#include "foo_musicbrainz.h"

static const GUID guid_cfg_short_date = { 0x18734618, 0x7920, 0x4d24, { 0x84, 0xa1, 0xb9, 0xd6, 0x6e, 0xd8, 0x25, 0xbc } };
cfg_bool cfg_short_date(guid_cfg_short_date, false);

static const GUID guid_cfg_no_feat = { 0x98f9ce46, 0xe0c5, 0x48f4, { 0xa6, 0x3e, 0x19, 0x34, 0x39, 0x64, 0x35, 0x55 } };
cfg_bool cfg_no_feat(guid_cfg_no_feat, false);

static const GUID guid_cfg_write_ids = { 0x8c8b61e0, 0x8eea, 0x4c34, { 0x9a, 0x51, 0x4d, 0xa9, 0x9c, 0xec, 0xcb, 0xbc } };
cfg_bool cfg_write_ids(guid_cfg_write_ids, true);

static const GUID guid_cfg_albumtype = { 0xd8fdb1d8, 0xde2, 0x4f1f, { 0x85, 0x5a, 0xc0, 0x5, 0x98, 0x60, 0x9b, 0xe9 } };
cfg_bool cfg_albumtype(guid_cfg_albumtype, true);

static const GUID guid_cfg_albumstatus = { 0x57a8dddd, 0xdf24, 0x4fd3, { 0xac, 0x95, 0x6f, 0x8, 0x3, 0x26, 0x41, 0x7c } };
cfg_bool cfg_albumstatus(guid_cfg_albumstatus, true);

static const GUID guid_cfg_albumtype_data = { 0x20968c09, 0xb0d4, 0x4059, { 0xb8, 0x92, 0xda, 0x76, 0xf8, 0xe6, 0x51, 0x4e } };
cfg_string cfg_albumtype_data(guid_cfg_albumtype_data, "MUSICBRAINZ_ALBUMTYPE");

static const GUID guid_cfg_albumstatus_data = { 0x77182aac, 0x1caa, 0x4793, { 0xb7, 0x15, 0xcc, 0xf8, 0x97, 0xba, 0x11, 0x1a } };
cfg_string cfg_albumstatus_data(guid_cfg_albumstatus_data, "MUSICBRAINZ_ALBUMSTATUS");

class PreferencesPageInstance : public CDialogImpl<PreferencesPageInstance>, public preferences_page_instance {
private:
	CButton short_date_checkbox;
	CButton no_feat_checkbox;
	CButton write_ids_checkbox;
	CButton write_albumtype_checkbox;
	CButton write_albumstatus_checkbox;
	CEdit albumtype;
	CEdit albumstatus;
	preferences_page_callback::ptr on_change_callback;

public:
	PreferencesPageInstance(preferences_page_callback::ptr callback) : on_change_callback(callback) {}

	enum { IDD = IDD_PREFERENCES };

	BEGIN_MSG_MAP(CPreferencesDialog)
		MSG_WM_INITDIALOG(OnInitDialog)
		COMMAND_HANDLER_EX(IDC_SHORT_DATE, BN_CLICKED, OnChanged)
		COMMAND_HANDLER_EX(IDC_NO_FEAT, BN_CLICKED, OnChanged)
		COMMAND_HANDLER_EX(IDC_WRITE_IDS, BN_CLICKED, OnChanged)
		COMMAND_HANDLER_EX(IDC_ALBUMTYPE, BN_CLICKED, OnAlbumType)
		COMMAND_HANDLER_EX(IDC_ALBUMSTATUS, BN_CLICKED, OnAlbumStatus)
		COMMAND_HANDLER_EX(IDC_ALBUMTYPE_DATA, EN_UPDATE, OnChanged)
		COMMAND_HANDLER_EX(IDC_ALBUMSTATUS_DATA, EN_UPDATE, OnChanged)
	END_MSG_MAP()

	BOOL OnInitDialog(CWindow wndFocus, LPARAM lInitParam) {
		short_date_checkbox = GetDlgItem(IDC_SHORT_DATE);
		no_feat_checkbox = GetDlgItem(IDC_NO_FEAT);
		write_ids_checkbox = GetDlgItem(IDC_WRITE_IDS);
		write_albumtype_checkbox = GetDlgItem(IDC_ALBUMTYPE);
		write_albumstatus_checkbox = GetDlgItem(IDC_ALBUMSTATUS);
		albumtype = GetDlgItem(IDC_ALBUMTYPE_DATA);
		albumstatus = GetDlgItem(IDC_ALBUMSTATUS_DATA);

		short_date_checkbox.SetCheck(cfg_short_date.get_value());
		no_feat_checkbox.SetCheck(cfg_no_feat.get_value());
		write_ids_checkbox.SetCheck(cfg_write_ids.get_value());
		write_albumtype_checkbox.SetCheck(cfg_albumtype.get_value());
		write_albumstatus_checkbox.SetCheck(cfg_albumstatus.get_value());
		uSetWindowText(albumtype, cfg_albumtype_data);
		uSetWindowText(albumstatus, cfg_albumstatus_data);
		if (cfg_albumtype.get_value()) albumtype.EnableWindow(true);
		if (cfg_albumstatus.get_value()) albumstatus.EnableWindow(true);

		return 0;
	}

	bool has_changed() {
		if ((bool)short_date_checkbox.GetCheck() != cfg_short_date.get_value()) return true;
		if ((bool)no_feat_checkbox.GetCheck() != cfg_no_feat.get_value()) return true;
		if ((bool)write_ids_checkbox.GetCheck() != cfg_write_ids.get_value()) return true;
		if ((bool)write_albumtype_checkbox.GetCheck() != cfg_albumtype.get_value()) return true;
		if ((bool)write_albumstatus_checkbox.GetCheck() != cfg_albumstatus.get_value()) return true;

		pfc::string8 temp;
		uGetWindowText(albumtype, temp);
		if (cfg_albumtype_data != temp) return true;
		uGetWindowText(albumstatus, temp);
		if (cfg_albumstatus_data != temp) return true;

		return false;
	}

	t_uint32 get_state() {
		t_uint32 state = preferences_state::resettable;
		if (has_changed()) state |= preferences_state::changed;
		return state;
	}

	void apply() {
		cfg_short_date = (bool)short_date_checkbox.GetCheck();
		cfg_no_feat = (bool)no_feat_checkbox.GetCheck();
		cfg_write_ids = (bool)write_ids_checkbox.GetCheck();
		cfg_albumtype = (bool)write_albumtype_checkbox.GetCheck();
		cfg_albumstatus = (bool)write_albumstatus_checkbox.GetCheck();
		uGetWindowText(albumtype, cfg_albumtype_data);
		uGetWindowText(albumstatus, cfg_albumstatus_data);
	}

	void on_change() {
		on_change_callback->on_state_changed();
	}

	void reset() {
		short_date_checkbox.SetCheck(false);
		no_feat_checkbox.SetCheck(false);
		write_ids_checkbox.SetCheck(true);
		write_albumtype_checkbox.SetCheck(true);
		write_albumstatus_checkbox.SetCheck(true);
		uSetWindowText(albumtype, "MUSICBRAINZ_ALBUMTYPE");
		uSetWindowText(albumstatus, "MUSICBRAINZ_ALBUMSTATUS");
		on_change();
	}

	void OnChanged(UINT, int, HWND) {
		on_change();
	}

	void OnAlbumType(UINT, int, CButton) {
		albumtype.EnableWindow((bool)write_albumtype_checkbox.GetCheck());
		on_change();
	}

	void OnAlbumStatus(UINT, int, CButton) {
		albumstatus.EnableWindow((bool)write_albumstatus_checkbox.GetCheck());
		on_change();
	}
};

class PreferencesPage : public preferences_page_impl<PreferencesPageInstance> {
public:
	const char * get_name() {
		return "MusicBrainz Tagger";
	}

	GUID get_guid() {
		static const GUID guid = { 0x79179a37, 0x5942, 0x4fdf, { 0xbb, 0xb7, 0x93, 0xfd, 0x35, 0xfc, 0xfe, 0x97 } };
		return guid;
	}

	GUID get_parent_guid() {
		return preferences_page::guid_tagging;
	}
};

preferences_page_factory_t<PreferencesPage> _;
<|endoftext|>


<commit_before>/*
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * StreamingClient.cpp
 * Implementation of Streaming Client
 * Copyright (C) 2005-2008 Simon Newton
 */

#include <ola/BaseTypes.h>
#include <ola/Closure.h>
#include <ola/DmxBuffer.h>
#include <ola/Logging.h>
#include <ola/StreamingClient.h>
#include "common/protocol/Ola.pb.h"
#include "common/rpc/StreamRpcChannel.h"

namespace ola {

using ola::rpc::StreamRpcChannel;
using ola::proto::OlaServerService_Stub;

StreamingClient::StreamingClient()
    : m_socket(NULL),
      m_closure(NULL),
      m_channel(NULL),
      m_stub(NULL) {
}

StreamingClient::~StreamingClient() {
  Stop();
}

/*
 * Setup the Streaming Client
 *
 * @returns true on success, false on failure
 */
bool StreamingClient::Setup() {
  if (!m_socket) {
    m_socket = TcpSocket::Connect("127.0.0.1", OLA_DEFAULT_PORT);
    if (!m_socket) {
      return false;
    }
  }

  m_socket->SetOnClose(
      NewSingleClosure(this, &StreamingClient::SocketClosed));

  m_channel = new StreamRpcChannel(NULL, m_socket);

  if (!m_channel) {
    delete m_socket;
    m_socket = NULL;
    return false;
  }

  m_stub = new OlaServerService_Stub(m_channel);

  if (!m_stub) {
    delete m_channel;
    delete m_socket;
    m_channel = NULL;
    m_socket = NULL;
    return false;
  }
  return true;
}

/*
 * Close the ola connection.
 * @return true on sucess, false on failure
 */
void StreamingClient::Stop() {
  if (m_stub)
    delete m_stub;

  if (m_channel)
    delete m_channel;

  if (m_socket)
    delete m_socket;

  m_stub = NULL;
  m_channel = NULL;
  m_socket = NULL;
}

/*
 * Send DMX to the remote OLA server
 */
bool StreamingClient::SendDmx(unsigned int universe,
                              const DmxBuffer &data) const {
  if (!m_stub || m_socket->CheckIfClosed())
    return false;

  ola::proto::DmxData request;
  request.set_universe(universe);
  request.set_data(data.Get());
  m_stub->StreamDmxData(NULL, &request, NULL, NULL);
  return true;
}

/*
 * Called when the socket is closed
 */
int StreamingClient::SocketClosed() {
  OLA_WARN << "The RPC socket has been closed, this is more than likely due"
    << "to a framing error, perhaps you're sending too fast?";
  if (m_closure)
    m_closure->Run();
  return 0;
}
}  // ola
<commit_msg> * fix the error message<commit_after>/*
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * StreamingClient.cpp
 * Implementation of Streaming Client
 * Copyright (C) 2005-2008 Simon Newton
 */

#include <ola/BaseTypes.h>
#include <ola/Closure.h>
#include <ola/DmxBuffer.h>
#include <ola/Logging.h>
#include <ola/StreamingClient.h>
#include "common/protocol/Ola.pb.h"
#include "common/rpc/StreamRpcChannel.h"

namespace ola {

using ola::rpc::StreamRpcChannel;
using ola::proto::OlaServerService_Stub;

StreamingClient::StreamingClient()
    : m_socket(NULL),
      m_closure(NULL),
      m_channel(NULL),
      m_stub(NULL) {
}

StreamingClient::~StreamingClient() {
  Stop();
}

/*
 * Setup the Streaming Client
 *
 * @returns true on success, false on failure
 */
bool StreamingClient::Setup() {
  if (!m_socket) {
    m_socket = TcpSocket::Connect("127.0.0.1", OLA_DEFAULT_PORT);
    if (!m_socket) {
      return false;
    }
  }

  m_socket->SetOnClose(
      NewSingleClosure(this, &StreamingClient::SocketClosed));

  m_channel = new StreamRpcChannel(NULL, m_socket);

  if (!m_channel) {
    delete m_socket;
    m_socket = NULL;
    return false;
  }

  m_stub = new OlaServerService_Stub(m_channel);

  if (!m_stub) {
    delete m_channel;
    delete m_socket;
    m_channel = NULL;
    m_socket = NULL;
    return false;
  }
  return true;
}

/*
 * Close the ola connection.
 * @return true on sucess, false on failure
 */
void StreamingClient::Stop() {
  if (m_stub)
    delete m_stub;

  if (m_channel)
    delete m_channel;

  if (m_socket)
    delete m_socket;

  m_stub = NULL;
  m_channel = NULL;
  m_socket = NULL;
}

/*
 * Send DMX to the remote OLA server
 */
bool StreamingClient::SendDmx(unsigned int universe,
                              const DmxBuffer &data) const {
  if (!m_stub || m_socket->CheckIfClosed())
    return false;

  ola::proto::DmxData request;
  request.set_universe(universe);
  request.set_data(data.Get());
  m_stub->StreamDmxData(NULL, &request, NULL, NULL);
  return true;
}

/*
 * Called when the socket is closed
 */
int StreamingClient::SocketClosed() {
  OLA_WARN << "The RPC socket has been closed, this is more than likely due"
    << " to a framing error, perhaps you're sending too fast?";
  if (m_closure)
    m_closure->Run();
  return 0;
}
}  // ola
<|endoftext|>