<commit_before>// Copyright 2015-2019 Elviss Strazdins. All rights reserved.

#if defined(__APPLE__)
#  include <TargetConditionals.h>
#endif
#include <stdexcept>
#include "Window.hpp"
#include "Engine.hpp"
#include "events/EventDispatcher.hpp"
#include "graphics/Renderer.hpp"

#if TARGET_OS_IOS
#  include "ios/NativeWindowIOS.hpp"
#elif TARGET_OS_TV
#  include "tvos/NativeWindowTVOS.hpp"
#elif TARGET_OS_MAC
#  include "macos/NativeWindowMacOS.hpp"
#elif defined(__ANDROID__)
#  include "android/NativeWindowAndroid.hpp"
#elif defined(__linux__)
#  include "linux/NativeWindowLinux.hpp"
#elif defined(_WIN32)
#  include "windows/NativeWindowWin.hpp"
#elif defined(__EMSCRIPTEN__)
#  include "emscripten/NativeWindowEm.hpp"
#endif

namespace ouzel
{
    Window::Window(Engine& initEngine,
                   const Size2U& newSize,
                   uint32_t flags,
                   const std::string& newTitle,
                   graphics::Driver graphicsDriver):
        engine(initEngine),
#if TARGET_OS_IOS
        nativeWindow(new NativeWindowIOS(std::bind(&Window::eventCallback, this, std::placeholders::_1),
                                         newTitle,
                                         graphicsDriver,
                                         flags & HIGH_DPI)),
#elif TARGET_OS_TV
        nativeWindow(new NativeWindowTVOS(std::bind(&Window::eventCallback, this, std::placeholders::_1),
                                          newTitle,
                                          graphicsDriver,
                                          flags & HIGH_DPI)),
#elif TARGET_OS_MAC
        nativeWindow(new NativeWindowMacOS(std::bind(&Window::eventCallback, this, std::placeholders::_1),
                                           newSize,
                                           flags & RESIZABLE,
                                           flags & FULLSCREEN,
                                           flags & EXCLUSIVE_FULLSCREEN,
                                           newTitle,
                                           graphicsDriver,
                                           flags & HIGH_DPI)),
#elif defined(__ANDROID__)
        nativeWindow(new NativeWindowAndroid(std::bind(&Window::eventCallback, this, std::placeholders::_1), newTitle)),
#elif defined(__linux__)
        nativeWindow(new NativeWindowLinux(std::bind(&Window::eventCallback, this, std::placeholders::_1),
                                           newSize,
                                           flags & RESIZABLE,
                                           flags & FULLSCREEN,
                                           flags & EXCLUSIVE_FULLSCREEN,
                                           newTitle,
                                           graphicsDriver,
                                           flags & DEPTH)),
#elif defined(_WIN32)
        nativeWindow(new NativeWindowWin(std::bind(&Window::eventCallback, this, std::placeholders::_1),
                                         newSize,
                                         flags & RESIZABLE,
                                         flags & FULLSCREEN,
                                         flags & EXCLUSIVE_FULLSCREEN,
                                         newTitle,
                                         flags & HIGH_DPI)),
#elif defined(__EMSCRIPTEN__)
        nativeWindow(new NativeWindowEm(std::bind(&Window::eventCallback, this, std::placeholders::_1),
                                        newSize,
                                        flags & FULLSCREEN,
                                        newTitle,
                                        flags & HIGH_DPI)),
#else
        nativeWindow(new NativeWindow(std::bind(&Window::eventCallback, this, std::placeholders::_1),
                                      newSize,
                                      flags & RESIZABLE,
                                      flags & FULLSCREEN,
                                      flags & EXCLUSIVE_FULLSCREEN,
                                      newTitle,
                                      flags & HIGH_DPI)),
#endif
        size(nativeWindow->getSize()),
        resolution(nativeWindow->getResolution()),
        resizable(flags & RESIZABLE),
        fullscreen(flags & FULLSCREEN),
        exclusiveFullscreen(flags & EXCLUSIVE_FULLSCREEN),
        highDpi(flags & HIGH_DPI),
        title(newTitle)
    {
        (void)newSize;
        (void)graphicsDriver;
    }

    void Window::update()
    {
        NativeWindow::Event event;

        for (;;)
        {
            std::unique_lock<std::mutex> lock(eventQueueMutex);
            if (eventQueue.empty()) break;
            event = std::move(eventQueue.front());
            eventQueue.pop();
            lock.unlock();

            handleEvent(event);
        }
    }

    void Window::eventCallback(const NativeWindow::Event& event)
    {
        if (event.type == NativeWindow::Event::Type::FOCUS_CHANGE)
        {
            if (event.focus)
                engine.resume();
            else
                engine.pause();
        }
        else
        {
            std::unique_lock<std::mutex> lock(eventQueueMutex);
            eventQueue.push(event);
        }
    }

    void Window::handleEvent(const NativeWindow::Event& event)
    {
        switch (event.type)
        {
            case NativeWindow::Event::Type::SIZE_CHANGE:
            {
                size = event.size;

                std::unique_ptr<WindowEvent> sizeChangeEvent(new WindowEvent());
                sizeChangeEvent->type = Event::Type::WINDOW_SIZE_CHANGE;
                sizeChangeEvent->window = this;
                sizeChangeEvent->size = event.size;
                engine.getEventDispatcher().dispatchEvent(std::move(sizeChangeEvent));
                break;
            }
            case NativeWindow::Event::Type::RESOLUTION_CHANGE:
            {
                resolution = event.resolution;

                engine.getRenderer()->setSize(resolution);

                std::unique_ptr<WindowEvent> resolutionChangeEvent(new WindowEvent());
                resolutionChangeEvent->type = Event::Type::RESOLUTION_CHANGE;
                resolutionChangeEvent->window = this;
                resolutionChangeEvent->size = event.size;
                engine.getEventDispatcher().dispatchEvent(std::move(resolutionChangeEvent));
                engine.getRenderer()->setSize(event.size);
                break;
            }
            case NativeWindow::Event::Type::FULLSCREEN_CHANGE:
            {
                fullscreen = event.fullscreen;

                std::unique_ptr<WindowEvent> fullscreenChangeEvent(new WindowEvent());
                fullscreenChangeEvent->type = Event::Type::FULLSCREEN_CHANGE;
                fullscreenChangeEvent->window = this;
                fullscreenChangeEvent->fullscreen = event.fullscreen;
                engine.getEventDispatcher().dispatchEvent(std::move(fullscreenChangeEvent));
                break;
            }
            case NativeWindow::Event::Type::SCREEN_CHANGE:
            {
                displayId = event.displayId;

                std::unique_ptr<WindowEvent> screenChangeEvent(new WindowEvent());
                screenChangeEvent->type = Event::Type::SCREEN_CHANGE;
                screenChangeEvent->window = this;
                screenChangeEvent->screenId = event.displayId;
                engine.getEventDispatcher().dispatchEvent(std::move(screenChangeEvent));
                break;
            }
            case NativeWindow::Event::Type::CLOSE:
                engine.exit();
                break;

            case NativeWindow::Event::Type::SHOW:
                visible = true;
                break;
            case NativeWindow::Event::Type::HIDE:
                visible = false;
                break;
            case NativeWindow::Event::Type::MINIMIZE:
                minimized = true;
                break;
            case NativeWindow::Event::Type::MAXIMIZE:
                break;
            case NativeWindow::Event::Type::RESTORE:
                minimized = false;
                break;
            default:
                throw std::runtime_error("Unhandled event");
        }
    }

    void Window::close()
    {
        NativeWindow::Command command(NativeWindow::Command::Type::CLOSE);
        nativeWindow->addCommand(command);
    }

    void Window::setSize(const Size2U& newSize)
    {
        if (size != newSize)
        {
            size = newSize;

            NativeWindow::Command command(NativeWindow::Command::Type::CHANGE_SIZE);
            command.size = newSize;
            nativeWindow->addCommand(command);

            std::unique_ptr<WindowEvent> event(new WindowEvent());
            event->type = Event::Type::WINDOW_SIZE_CHANGE;
            event->window = this;
            event->size = size;
            event->title = title;
            event->fullscreen = fullscreen;
            engine.getEventDispatcher().dispatchEvent(std::move(event));
        }
    }

    void Window::setFullscreen(bool newFullscreen)
    {
        if (fullscreen != newFullscreen)
        {
            fullscreen = newFullscreen;

            NativeWindow::Command command(NativeWindow::Command::Type::CHANGE_FULLSCREEN);
            command.fullscreen = newFullscreen;
            nativeWindow->addCommand(command);

            std::unique_ptr<WindowEvent> event(new WindowEvent());
            event->type = Event::Type::FULLSCREEN_CHANGE;
            event->window = this;
            event->size = size;
            event->title = title;
            event->fullscreen = fullscreen;
            engine.getEventDispatcher().dispatchEvent(std::move(event));
        }
    }

    void Window::setTitle(const std::string& newTitle)
    {
        if (title != newTitle)
        {
            title = newTitle;

            NativeWindow::Command command(NativeWindow::Command::Type::SET_TITLE);
            command.title = newTitle;
            nativeWindow->addCommand(command);

            std::unique_ptr<WindowEvent> event(new WindowEvent());
            event->type = Event::Type::WINDOW_TITLE_CHANGE;
            event->window = this;
            event->size = size;
            event->title = title;
            event->fullscreen = fullscreen;
            engine.getEventDispatcher().dispatchEvent(std::move(event));
        }
    }

    void Window::bringToFront()
    {
        NativeWindow::Command command(NativeWindow::Command::Type::BRING_TO_FRONT);
        nativeWindow->addCommand(command);
    }

    void Window::show()
    {
        NativeWindow::Command command(NativeWindow::Command::Type::SHOW);
        nativeWindow->addCommand(command);
    }

    void Window::hide()
    {
        NativeWindow::Command command(NativeWindow::Command::Type::HIDE);
        nativeWindow->addCommand(command);
    }

    void Window::minimize()
    {
        NativeWindow::Command command(NativeWindow::Command::Type::MINIMIZE);
        nativeWindow->addCommand(command);
    }

    void Window::maximize()
    {
        NativeWindow::Command command(NativeWindow::Command::Type::MAXIMIZE);
        nativeWindow->addCommand(command);
    }

    void Window::restore()
    {
        NativeWindow::Command command(NativeWindow::Command::Type::RESTORE);
        nativeWindow->addCommand(command);
    }
}
<commit_msg>Fix the resolution change event<commit_after>// Copyright 2015-2019 Elviss Strazdins. All rights reserved.

#if defined(__APPLE__)
#  include <TargetConditionals.h>
#endif
#include <stdexcept>
#include "Window.hpp"
#include "Engine.hpp"
#include "events/EventDispatcher.hpp"
#include "graphics/Renderer.hpp"

#if TARGET_OS_IOS
#  include "ios/NativeWindowIOS.hpp"
#elif TARGET_OS_TV
#  include "tvos/NativeWindowTVOS.hpp"
#elif TARGET_OS_MAC
#  include "macos/NativeWindowMacOS.hpp"
#elif defined(__ANDROID__)
#  include "android/NativeWindowAndroid.hpp"
#elif defined(__linux__)
#  include "linux/NativeWindowLinux.hpp"
#elif defined(_WIN32)
#  include "windows/NativeWindowWin.hpp"
#elif defined(__EMSCRIPTEN__)
#  include "emscripten/NativeWindowEm.hpp"
#endif

namespace ouzel
{
    Window::Window(Engine& initEngine,
                   const Size2U& newSize,
                   uint32_t flags,
                   const std::string& newTitle,
                   graphics::Driver graphicsDriver):
        engine(initEngine),
#if TARGET_OS_IOS
        nativeWindow(new NativeWindowIOS(std::bind(&Window::eventCallback, this, std::placeholders::_1),
                                         newTitle,
                                         graphicsDriver,
                                         flags & HIGH_DPI)),
#elif TARGET_OS_TV
        nativeWindow(new NativeWindowTVOS(std::bind(&Window::eventCallback, this, std::placeholders::_1),
                                          newTitle,
                                          graphicsDriver,
                                          flags & HIGH_DPI)),
#elif TARGET_OS_MAC
        nativeWindow(new NativeWindowMacOS(std::bind(&Window::eventCallback, this, std::placeholders::_1),
                                           newSize,
                                           flags & RESIZABLE,
                                           flags & FULLSCREEN,
                                           flags & EXCLUSIVE_FULLSCREEN,
                                           newTitle,
                                           graphicsDriver,
                                           flags & HIGH_DPI)),
#elif defined(__ANDROID__)
        nativeWindow(new NativeWindowAndroid(std::bind(&Window::eventCallback, this, std::placeholders::_1), newTitle)),
#elif defined(__linux__)
        nativeWindow(new NativeWindowLinux(std::bind(&Window::eventCallback, this, std::placeholders::_1),
                                           newSize,
                                           flags & RESIZABLE,
                                           flags & FULLSCREEN,
                                           flags & EXCLUSIVE_FULLSCREEN,
                                           newTitle,
                                           graphicsDriver,
                                           flags & DEPTH)),
#elif defined(_WIN32)
        nativeWindow(new NativeWindowWin(std::bind(&Window::eventCallback, this, std::placeholders::_1),
                                         newSize,
                                         flags & RESIZABLE,
                                         flags & FULLSCREEN,
                                         flags & EXCLUSIVE_FULLSCREEN,
                                         newTitle,
                                         flags & HIGH_DPI)),
#elif defined(__EMSCRIPTEN__)
        nativeWindow(new NativeWindowEm(std::bind(&Window::eventCallback, this, std::placeholders::_1),
                                        newSize,
                                        flags & FULLSCREEN,
                                        newTitle,
                                        flags & HIGH_DPI)),
#else
        nativeWindow(new NativeWindow(std::bind(&Window::eventCallback, this, std::placeholders::_1),
                                      newSize,
                                      flags & RESIZABLE,
                                      flags & FULLSCREEN,
                                      flags & EXCLUSIVE_FULLSCREEN,
                                      newTitle,
                                      flags & HIGH_DPI)),
#endif
        size(nativeWindow->getSize()),
        resolution(nativeWindow->getResolution()),
        resizable(flags & RESIZABLE),
        fullscreen(flags & FULLSCREEN),
        exclusiveFullscreen(flags & EXCLUSIVE_FULLSCREEN),
        highDpi(flags & HIGH_DPI),
        title(newTitle)
    {
        (void)newSize;
        (void)graphicsDriver;
    }

    void Window::update()
    {
        NativeWindow::Event event;

        for (;;)
        {
            std::unique_lock<std::mutex> lock(eventQueueMutex);
            if (eventQueue.empty()) break;
            event = std::move(eventQueue.front());
            eventQueue.pop();
            lock.unlock();

            handleEvent(event);
        }
    }

    void Window::eventCallback(const NativeWindow::Event& event)
    {
        if (event.type == NativeWindow::Event::Type::FOCUS_CHANGE)
        {
            if (event.focus)
                engine.resume();
            else
                engine.pause();
        }
        else
        {
            std::unique_lock<std::mutex> lock(eventQueueMutex);
            eventQueue.push(event);
        }
    }

    void Window::handleEvent(const NativeWindow::Event& event)
    {
        switch (event.type)
        {
            case NativeWindow::Event::Type::SIZE_CHANGE:
            {
                size = event.size;

                std::unique_ptr<WindowEvent> sizeChangeEvent(new WindowEvent());
                sizeChangeEvent->type = Event::Type::WINDOW_SIZE_CHANGE;
                sizeChangeEvent->window = this;
                sizeChangeEvent->size = event.size;
                engine.getEventDispatcher().dispatchEvent(std::move(sizeChangeEvent));
                break;
            }
            case NativeWindow::Event::Type::RESOLUTION_CHANGE:
            {
                resolution = event.resolution;

                engine.getRenderer()->setSize(resolution);

                std::unique_ptr<WindowEvent> resolutionChangeEvent(new WindowEvent());
                resolutionChangeEvent->type = Event::Type::RESOLUTION_CHANGE;
                resolutionChangeEvent->window = this;
                resolutionChangeEvent->size = event.resolution;
                engine.getEventDispatcher().dispatchEvent(std::move(resolutionChangeEvent));
                break;
            }
            case NativeWindow::Event::Type::FULLSCREEN_CHANGE:
            {
                fullscreen = event.fullscreen;

                std::unique_ptr<WindowEvent> fullscreenChangeEvent(new WindowEvent());
                fullscreenChangeEvent->type = Event::Type::FULLSCREEN_CHANGE;
                fullscreenChangeEvent->window = this;
                fullscreenChangeEvent->fullscreen = event.fullscreen;
                engine.getEventDispatcher().dispatchEvent(std::move(fullscreenChangeEvent));
                break;
            }
            case NativeWindow::Event::Type::SCREEN_CHANGE:
            {
                displayId = event.displayId;

                std::unique_ptr<WindowEvent> screenChangeEvent(new WindowEvent());
                screenChangeEvent->type = Event::Type::SCREEN_CHANGE;
                screenChangeEvent->window = this;
                screenChangeEvent->screenId = event.displayId;
                engine.getEventDispatcher().dispatchEvent(std::move(screenChangeEvent));
                break;
            }
            case NativeWindow::Event::Type::CLOSE:
                engine.exit();
                break;

            case NativeWindow::Event::Type::SHOW:
                visible = true;
                break;
            case NativeWindow::Event::Type::HIDE:
                visible = false;
                break;
            case NativeWindow::Event::Type::MINIMIZE:
                minimized = true;
                break;
            case NativeWindow::Event::Type::MAXIMIZE:
                break;
            case NativeWindow::Event::Type::RESTORE:
                minimized = false;
                break;
            default:
                throw std::runtime_error("Unhandled event");
        }
    }

    void Window::close()
    {
        NativeWindow::Command command(NativeWindow::Command::Type::CLOSE);
        nativeWindow->addCommand(command);
    }

    void Window::setSize(const Size2U& newSize)
    {
        if (size != newSize)
        {
            size = newSize;

            NativeWindow::Command command(NativeWindow::Command::Type::CHANGE_SIZE);
            command.size = newSize;
            nativeWindow->addCommand(command);

            std::unique_ptr<WindowEvent> event(new WindowEvent());
            event->type = Event::Type::WINDOW_SIZE_CHANGE;
            event->window = this;
            event->size = size;
            event->title = title;
            event->fullscreen = fullscreen;
            engine.getEventDispatcher().dispatchEvent(std::move(event));
        }
    }

    void Window::setFullscreen(bool newFullscreen)
    {
        if (fullscreen != newFullscreen)
        {
            fullscreen = newFullscreen;

            NativeWindow::Command command(NativeWindow::Command::Type::CHANGE_FULLSCREEN);
            command.fullscreen = newFullscreen;
            nativeWindow->addCommand(command);

            std::unique_ptr<WindowEvent> event(new WindowEvent());
            event->type = Event::Type::FULLSCREEN_CHANGE;
            event->window = this;
            event->size = size;
            event->title = title;
            event->fullscreen = fullscreen;
            engine.getEventDispatcher().dispatchEvent(std::move(event));
        }
    }

    void Window::setTitle(const std::string& newTitle)
    {
        if (title != newTitle)
        {
            title = newTitle;

            NativeWindow::Command command(NativeWindow::Command::Type::SET_TITLE);
            command.title = newTitle;
            nativeWindow->addCommand(command);

            std::unique_ptr<WindowEvent> event(new WindowEvent());
            event->type = Event::Type::WINDOW_TITLE_CHANGE;
            event->window = this;
            event->size = size;
            event->title = title;
            event->fullscreen = fullscreen;
            engine.getEventDispatcher().dispatchEvent(std::move(event));
        }
    }

    void Window::bringToFront()
    {
        NativeWindow::Command command(NativeWindow::Command::Type::BRING_TO_FRONT);
        nativeWindow->addCommand(command);
    }

    void Window::show()
    {
        NativeWindow::Command command(NativeWindow::Command::Type::SHOW);
        nativeWindow->addCommand(command);
    }

    void Window::hide()
    {
        NativeWindow::Command command(NativeWindow::Command::Type::HIDE);
        nativeWindow->addCommand(command);
    }

    void Window::minimize()
    {
        NativeWindow::Command command(NativeWindow::Command::Type::MINIMIZE);
        nativeWindow->addCommand(command);
    }

    void Window::maximize()
    {
        NativeWindow::Command command(NativeWindow::Command::Type::MAXIMIZE);
        nativeWindow->addCommand(command);
    }

    void Window::restore()
    {
        NativeWindow::Command command(NativeWindow::Command::Type::RESTORE);
        nativeWindow->addCommand(command);
    }
}
<|endoftext|>


<commit_before>#include <iostream>
#include <fstream>
#include <random>
#include <cstdlib> //atoi
#include "grid.h"

#define die(msg) {std::cerr << msg << '\n'; return 1;}

int main(int argc, char** argv)
{
	if(argc < 3)
		die("Usage: " << argv[0] << " <seed> <input file> <output file>");

	unsigned seed = atoi(argv[1]);
	const char* input_file = argv[2];
	const char* output_file = argv[3];
	grid automata_transitions;
	grid automata_outputs;
	unsigned automata_state;
	std::mt19937 rng;

	rng.seed(seed);
	automata_transitions = generate_latin_square(256, rng);
	automata_outputs 	 = generate_latin_square(256, rng);
	automata_state = rng() % 256;

	const unsigned buffer_size = 8192;
	unsigned char* buffer = new unsigned char[buffer_size];

	std::ifstream fis(input_file, std::ios::binary);
	std::ofstream fos(output_file, std::ios::binary | std::ios::trunc);

	if(!fis.good())
		die("Couldn't open input file: " << input_file);

	if(!fos.good())
		die("Couldn't open output file: " << output_file);

	while(fis.good() && fos.good())
	{
		fis.read((char*)buffer, buffer_size);
		for(unsigned i=0; i<fis.gcount(); i++)
		{
			int c = buffer[i];

			//Do a reverse lookup
			for(unsigned y=0; y<256; y++)
			{
				if(automata_outputs(automata_state, y) == c)
				{
					fos << (char)y;
					automata_state = automata_transitions(automata_state, y);

					break;
				}
			}
		}
	}

	delete [] buffer;

	return 0;
}<commit_msg>Delatin now precomputes a reverse lookup table instead doing it per-character<commit_after>#include <iostream>
#include <fstream>
#include <random>
#include <cstdlib> //atoi
#include "grid.h"

#define die(msg) {std::cerr << msg << '\n'; return 1;}

int main(int argc, char** argv)
{
	if(argc < 3)
		die("Usage: " << argv[0] << " <seed> <input file> <output file>");

	unsigned seed = atoi(argv[1]);
	const char* input_file = argv[2];
	const char* output_file = argv[3];
	grid automata_transitions;
	grid automata_outputs;
	grid reverse_lookup_table;
	unsigned automata_state;
	std::mt19937 rng;

	rng.seed(seed);
	automata_transitions = generate_latin_square(256, rng);
	automata_outputs 	 = generate_latin_square(256, rng);
	automata_state = rng() % 256;

	reverse_lookup_table.resize(256, 256);
	for(unsigned x=0; x<256; x++)
	{
		for(unsigned y=0; y<256; y++)
			for(unsigned cy=0; cy<256; cy++)
				if(automata_outputs(x,cy) == y)
				{
					reverse_lookup_table(x,y) = cy;
					break;
				}
	}

	const unsigned buffer_size = 8192;
	unsigned char* buffer = new unsigned char[buffer_size];

	std::ifstream fis(input_file, std::ios::binary);
	std::ofstream fos(output_file, std::ios::binary | std::ios::trunc);

	if(!fis.good())
		die("Couldn't open input file: " << input_file);

	if(!fos.good())
		die("Couldn't open output file: " << output_file);

	while(fis.good() && fos.good())
	{
		fis.read((char*)buffer, buffer_size);
		for(unsigned i=0; i<fis.gcount(); i++)
		{
			int c = buffer[i];
			int d = reverse_lookup_table(automata_state, c);
			fos << (char)d;
			automata_state = automata_transitions(automata_state, d);
		}
	}

	delete [] buffer;

	return 0;
}<|endoftext|>


<commit_before>#include "LinearRegression.h"
#include <armadillo>
#include <assert.h>
#include <iostream>

using namespace arma;

LinearRegression::LinearRegression(mat &x, vec &y)
    : x{x}, y{y}, trained{false} {
  assert(x.n_rows == y.n_rows);

  // Create Bias Layer and append at the end of  x
  mat bias = ones<mat>(y.n_rows, 2);
  this->x.insert_cols(x.n_cols, bias);
}

LinearRegression::~LinearRegression() {}

void LinearRegression::AddData(mat &extraX, vec &extraY) {
  assert(extraX.n_rows == extraY.n_rows);
  assert(extraX.n_rows == this->x.n_rows);
  this->trained = false;
  this->x.insert_rows(this->x.n_rows, extraX);
  this->y.insert_rows(this->y.n_rows, extraY);
}

void LinearRegression::Train() {
  mat xtx = (this->x.t() * this->x);
  // Check if xtx is full-rank matrix
  if (rank(xtx) == y.n_rows) {
    this->w = inv(xtx) * this->x.t() * y;
    this->trained = true;
  } else {
    std::cerr << "you have to regularize your data set" << std::endl;
  }
}

uword LinearRegression::ExampleNumber() { return this->x.n_rows; }

double LinearRegression::Predict(vec &x) {
  if (!this->trained) {
    std::cerr << "This model hasn't been trained" << std::endl;
    return 0.0;
  }
  return (this->w * x).eval()(0, 0);
}
<commit_msg>Fixed small bug<commit_after>#include "LinearRegression.h"
#include <armadillo>
#include <assert.h>
#include <iostream>

using namespace arma;

LinearRegression::LinearRegression(mat &x, vec &y)
    : x{x}, y{y}, trained{false} {
  assert(x.n_rows == y.n_rows);

  // Create Bias Layer and append at the end of  x
  mat bias = ones<mat>(y.n_rows, 2);
  this->x.insert_cols(x.n_cols, bias);
}

LinearRegression::~LinearRegression() {}

void LinearRegression::AddData(mat &extraX, vec &extraY) {
  assert(extraX.n_rows == extraY.n_rows);
  assert(extraX.n_rows == this->x.n_rows);
  this->trained = false;
  this->x.insert_rows(this->x.n_rows, extraX);
  this->y.insert_rows(this->y.n_rows, extraY);
}

void LinearRegression::Train() {
  mat xtx = (this->x.t() * this->x);
  // Check if xtx is full-rank matrix
  if (rank(xtx) == xtx.n_rows) {
    this->w = inv(xtx) * this->x.t() * y;
    this->trained = true;
  } else {
    std::cerr << "you have to regularize your data set" << std::endl;
  }
}

uword LinearRegression::ExampleNumber() { return this->x.n_rows; }

double LinearRegression::Predict(vec &x) {
  if (!this->trained) {
    std::cerr << "This model hasn't been trained" << std::endl;
    return 0.0;
  }
  return (this->w * x).eval()(0, 0);
}
<|endoftext|>


<commit_before>#include "Transition.hpp"

#include <string>

ppTransition::ppTransition(ppSwitch* sw, int priority, ppGenericSound* sourceSound, ppGenericSound* destSound){
	this->priority = priority;
	this->sourceSound = sourceSound;
	this->destSound = destSound;
	this->transitioning = false;
	this->transitionTrack = NULL;
	this->SetSourcePosition(ppTransitionSourcePosition::IMMEDIATE);
	this->SetSourceOffset(0);
	this->SetSourceDuration(5);
	this->SetSourceCurve(new ppLinearEasing());
	this->SetDestinationPosition(ppTransitionDestinationPosition::ENTRY_CUE);
	this->SetDestinationOffset(0);
	this->SetDestinationDuration(5);
	this->SetDestinationCurve(new ppLinearEasing());
}

ppTransition::~ppTransition(){}

void ppTransition::Trigger(ppGenericSound* actualSource, ppGenericSound* actualDest){
	if(this->transitioning){
		return;
	}
	this->actualSource = actualSource;
	this->actualDest = actualDest;

	this->triggerSync = false;
	this->transitioning = true;

	if(this->sourceSound){
		this->actualSource = this->sourceSound;
	}
	if(this->destSound){
		this->actualDest = this->destSound;
	}

	this->syncPoint = (Uint32)(this->GetSourceDuration()*1000);

	long minStartTime = this->GetSourceOffset()*1000;
	long destStartTime = this->GetDestinationOffset()*1000;
	if(destStartTime < minStartTime){
		minStartTime = destStartTime;
	}
	if(minStartTime < 0){
		this->syncPoint -= minStartTime;
	}
	this->triggerTime = SDL_GetTicks();
	if(this->sourcePosition == ppTransitionSourcePosition::NEXT_BAR){
		int bar = this->actualSource->GetCurrentBar(this->actualSource->GetCurrentTime()+this->GetSyncPoint());
		float difTime = this->actualSource->GetTimeForBar(bar+1) - this->GetSyncPoint() - this->actualSource->GetCurrentTime();
		this->triggerTime += (Uint32)(difTime*1000);
	}else if(this->sourcePosition == ppTransitionSourcePosition::NEXT_BEAT){
		int beat = this->actualSource->GetTotalBeat(this->actualSource->GetCurrentTime()+this->GetSyncPoint());
		float difTime = this->actualSource->GetTimeForBeat(beat+1) - this->GetSyncPoint() - this->actualSource->GetCurrentTime();
		this->triggerTime += (Uint32)(difTime*1000);
	}

	new ppTimeListener(this->actualSource, this);
	new ppTimeListener(this->actualDest, this);
}

void ppTransition::Update(){
	if(!this->transitioning || this->GetTransitionPosition() < 0){
		return;
	}
	ppGenericSound* source = this->sourceSound;
	ppEasing* sourceEasing = this->sourceEasing;
	ppGenericSound* dest = this->destSound;
	ppEasing* destEasing = this->destEasing;
	ppGenericSound* transition = this->transitionTrack;
	if(!source){
		source = this->actualSource;
	}
	// If its destination is to "any" track, use the target
	if(!dest){
		dest = this->actualDest;
	}
	long currentTime = this->GetTransitionPosition()*1000;

	long sourceStartTime = this->GetSourceOffset()*1000;
	long destStartTime = this->GetDestinationOffset()*1000;

	long minStartTime = sourceStartTime;
	if(destStartTime < minStartTime){
		minStartTime = destStartTime;
	}
	if(minStartTime < 0){
		sourceStartTime -= minStartTime;
		destStartTime -= minStartTime;
	}

	// Source time calculation
	long sourceEndTime = sourceStartTime+this->GetSourceDuration()*1000;

	// Transition time calculation
	long transitionEntryCue = 0;
	long transitionExitCue = 0;
	long transitionStartTime = 0;
	long transitionDuration = 0;
	long transitionEndTime = 0;
	if(transition){
		transitionEntryCue = transition->GetAudioFormat()->PositionToTime(transition->GetEntryCue())*1000;
		transitionExitCue = transition->GetAudioFormat()->PositionToTime(transition->GetNormalExitCue())*1000;
		transitionStartTime = this->syncPoint-transitionEntryCue;
		transitionDuration = transitionExitCue-transitionEntryCue;
		transitionEndTime = this->syncPoint+transitionDuration+((transition->GetTotalTime()*1000)-transitionExitCue);
		long destEntryCue = 0;
		if(dest){
			destEntryCue = dest->GetAudioFormat()->PositionToTime(dest->GetEntryCue())*1000;
		}
		destStartTime = this->syncPoint+transitionDuration-destEntryCue;
	}

	// Destination time calculation
	long destEndTime = destStartTime+this->GetDestinationDuration()*1000;

	if(transition && currentTime >= transitionStartTime && currentTime < transitionEndTime && !transition->IsPlaying()){
		transition->Play();
	}else if(transition && currentTime >= transitionEndTime && transition->IsPlaying()){
		transition->StopDecay(true);
	}

	if(source && currentTime >= sourceStartTime && currentTime < sourceEndTime && sourceEasing){
		if(!source->IsPlaying()){
			source->Play();
		}
		float v = sourceEasing->GetValue(sourceEndTime-currentTime, this->sourceDuration*1000, 0, 1);
		source->SetVolume(v);
	}else if(source && currentTime >= sourceEndTime && !sourceEasing){
		source->SetVolume(0);
	}
	if(dest && currentTime >= destStartTime && currentTime < destEndTime){
		if(!dest->IsPlaying()){
			if(this->destPosition == ppTransitionDestinationPosition::SAME_TIME){
				dest->Seek(source->GetCurrentTime());
			}
			dest->Play();
		}
		float v = 1;
		if(destEasing){
			v -= destEasing->GetValue(destEndTime-currentTime, this->destDuration*1000, 0, 1);
		}
		dest->SetVolume(v);
	}
	if(source && currentTime > sourceEndTime){
		source->StopDecay(true);
	}
	if(dest && currentTime > destEndTime){
		dest->SetVolume(1);
	}
	if(currentTime > this->syncPoint && !this->triggerSync){
		// TODO: Trigger seeking here
		this->triggerSync = true;
	}
	if(currentTime > sourceEndTime && currentTime > destEndTime && this->triggerSync){
		this->transitioning = false;
	}
}

bool ppTransition::IsTransitioning(){
	return this->transitioning;
}

bool ppTransition::IsSourceName(const char *name){
	return !this->GetSource() || this->GetSource()->GetName() == std::string(name);
}

bool ppTransition::IsDestinationName(const char *name){
	return !this->GetDestination() || this->GetDestination()->GetName() == std::string(name);
}

ppGenericSound* ppTransition::GetSource(){
	return this->sourceSound;
}

ppGenericSound* ppTransition::GetDestination(){
	return this->destSound;
}

ppGenericSound* ppTransition::GetActualSource(){
	return this->actualSource;
}

ppGenericSound* ppTransition::GetTransitionTrack(){
	return this->transitionTrack;
}

ppGenericSound* ppTransition::GetActualDestination(){
	return this->actualDest;
}

float ppTransition::GetTransitionPosition(){
	// Convert unsigned to float then subtract it
	return (SDL_GetTicks()/1000.0f)-(this->triggerTime/1000.0f);
}

float ppTransition::GetSyncPoint(){
	return this->syncPoint/1000.0f;
}

void ppTransition::SetSourcePosition(ppTransitionSourcePosition sourcePosition){
	this->sourcePosition = sourcePosition;
}

void ppTransition::SetDestinationPosition(ppTransitionDestinationPosition destPosition){
	this->destPosition = destPosition;
}

void ppTransition::SetTransitionTrack(ppGenericSound* transitionTrack){
	this->transitionTrack = transitionTrack;
}

int ppTransition::GetPriority(){
	return this->priority;
}

void ppTransition::SetSourceOffset(float offset){
	this->sourceOffset = offset;
}

void ppTransition::SetSourceDuration(float duration){
	this->sourceDuration = duration;
}

void ppTransition::SetSourceCurve(ppEasing* easing){
	this->sourceEasing = easing;
}

void ppTransition::SetDestinationOffset(float offset){
	this->destOffset = offset;
}

void ppTransition::SetDestinationDuration(float duration){
	this->destDuration = duration;
}

void ppTransition::SetDestinationCurve(ppEasing* easing){
	this->destEasing = easing;
}

ppTransitionSourcePosition ppTransition::GetSourcePosition(){
	return this->sourcePosition;
}

float ppTransition::GetSourceOffset(){
	return this->sourceOffset;
}

float ppTransition::GetSourceDuration(){
	return this->sourceDuration;
}

ppEasing* ppTransition::GetSourceCurve(){
	return this->sourceEasing;
}

ppTransitionDestinationPosition ppTransition::GetDestinationPosition(){
	return this->destPosition;
}

float ppTransition::GetDestinationOffset(){
	return this->destOffset;
}

float ppTransition::GetDestinationDuration(){
	return this->destDuration;
}

ppEasing* ppTransition::GetDestinationCurve(){
	return this->destEasing;
}
<commit_msg>Fix no easing transition timing<commit_after>#include "Transition.hpp"

#include <string>

ppTransition::ppTransition(ppSwitch* sw, int priority, ppGenericSound* sourceSound, ppGenericSound* destSound){
	this->priority = priority;
	this->sourceSound = sourceSound;
	this->destSound = destSound;
	this->transitioning = false;
	this->transitionTrack = NULL;
	this->SetSourcePosition(ppTransitionSourcePosition::IMMEDIATE);
	this->SetSourceOffset(0);
	this->SetSourceDuration(5);
	this->SetSourceCurve(new ppLinearEasing());
	this->SetDestinationPosition(ppTransitionDestinationPosition::ENTRY_CUE);
	this->SetDestinationOffset(0);
	this->SetDestinationDuration(5);
	this->SetDestinationCurve(new ppLinearEasing());
}

ppTransition::~ppTransition(){}

void ppTransition::Trigger(ppGenericSound* actualSource, ppGenericSound* actualDest){
	if(this->transitioning){
		return;
	}
	this->actualSource = actualSource;
	this->actualDest = actualDest;

	this->triggerSync = false;
	this->transitioning = true;

	if(this->sourceSound){
		this->actualSource = this->sourceSound;
	}
	if(this->destSound){
		this->actualDest = this->destSound;
	}

	this->syncPoint = 0;
	if(this->sourceEasing){
		this->syncPoint = (Uint32)(this->GetSourceDuration()*1000);
	}

	long minStartTime = this->GetSourceOffset()*1000;
	long destStartTime = this->GetDestinationOffset()*1000;
	if(destStartTime < minStartTime){
		minStartTime = destStartTime;
	}
	if(minStartTime < 0){
		this->syncPoint -= minStartTime;
	}
	this->triggerTime = SDL_GetTicks();
	if(this->sourcePosition == ppTransitionSourcePosition::NEXT_BAR){
		int bar = this->actualSource->GetCurrentBar(this->actualSource->GetCurrentTime()+this->GetSyncPoint());
		float difTime = this->actualSource->GetTimeForBar(bar+1) - this->GetSyncPoint() - this->actualSource->GetCurrentTime();
		this->triggerTime += (Uint32)(difTime*1000);
	}else if(this->sourcePosition == ppTransitionSourcePosition::NEXT_BEAT){
		int beat = this->actualSource->GetTotalBeat(this->actualSource->GetCurrentTime()+this->GetSyncPoint());
		float difTime = this->actualSource->GetTimeForBeat(beat+1) - this->GetSyncPoint() - this->actualSource->GetCurrentTime();
		this->triggerTime += (Uint32)(difTime*1000);
	}

	new ppTimeListener(this->actualSource, this);
	new ppTimeListener(this->actualDest, this);
}

void ppTransition::Update(){
	if(!this->transitioning || this->GetTransitionPosition() < 0){
		return;
	}
	ppGenericSound* source = this->sourceSound;
	ppEasing* sourceEasing = this->sourceEasing;
	ppGenericSound* dest = this->destSound;
	ppEasing* destEasing = this->destEasing;
	ppGenericSound* transition = this->transitionTrack;
	if(!source){
		source = this->actualSource;
	}
	// If its destination is to "any" track, use the target
	if(!dest){
		dest = this->actualDest;
	}
	long currentTime = this->GetTransitionPosition()*1000;

	long sourceStartTime = this->GetSourceOffset()*1000;
	long destStartTime = this->GetDestinationOffset()*1000;

	long minStartTime = sourceStartTime;
	if(destStartTime < minStartTime){
		minStartTime = destStartTime;
	}
	if(minStartTime < 0){
		sourceStartTime -= minStartTime;
		destStartTime -= minStartTime;
	}

	// Source time calculation
	long sourceEndTime = sourceStartTime;
	if(this->sourceEasing){
		sourceEndTime += this->GetSourceDuration()*1000;
	}

	// Transition time calculation
	long transitionEntryCue = 0;
	long transitionExitCue = 0;
	long transitionStartTime = 0;
	long transitionDuration = 0;
	long transitionEndTime = 0;
	if(transition){
		transitionEntryCue = transition->GetAudioFormat()->PositionToTime(transition->GetEntryCue())*1000;
		transitionExitCue = transition->GetAudioFormat()->PositionToTime(transition->GetNormalExitCue())*1000;
		transitionStartTime = this->syncPoint-transitionEntryCue;
		transitionDuration = transitionExitCue-transitionEntryCue;
		transitionEndTime = this->syncPoint+transitionDuration+((transition->GetTotalTime()*1000)-transitionExitCue);
		long destEntryCue = 0;
		if(dest){
			destEntryCue = dest->GetAudioFormat()->PositionToTime(dest->GetEntryCue())*1000;
		}
		destStartTime = this->syncPoint+transitionDuration-destEntryCue;
	}

	// Destination time calculation
	long destEndTime = destStartTime+this->GetDestinationDuration()*1000;

	if(transition && currentTime >= transitionStartTime && currentTime < transitionEndTime && !transition->IsPlaying()){
		transition->Play();
	}else if(transition && currentTime >= transitionEndTime && transition->IsPlaying()){
		transition->StopDecay(true);
	}

	if(source && currentTime >= sourceStartTime && currentTime <= sourceEndTime && sourceEasing){
		if(!source->IsPlaying()){
			source->Play();
		}
		float v = sourceEasing->GetValue(sourceEndTime-currentTime, this->sourceDuration*1000, 0, 1);
		source->SetVolume(v);
	}else if(source && currentTime > sourceEndTime && !sourceEasing){
		source->SetVolume(0);
	}
	if(dest && currentTime >= destStartTime && currentTime <= destEndTime){
		if(!dest->IsPlaying()){
			if(this->destPosition == ppTransitionDestinationPosition::SAME_TIME){
				dest->Seek(source->GetCurrentTime());
			}
			dest->Play();
		}
		float v = 1;
		if(destEasing){
			v -= destEasing->GetValue(destEndTime-currentTime, this->destDuration*1000, 0, 1);
		}
		dest->SetVolume(v);
	}
	if(source && currentTime > sourceEndTime){
		source->StopDecay(true);
	}
	if(dest && currentTime > destEndTime){
		dest->SetVolume(1);
	}
	if(currentTime > this->syncPoint && !this->triggerSync){
		// TODO: Trigger seeking here
		this->triggerSync = true;
	}
	if(currentTime > sourceEndTime && currentTime > destEndTime && this->triggerSync){
		this->transitioning = false;
	}
}

bool ppTransition::IsTransitioning(){
	return this->transitioning;
}

bool ppTransition::IsSourceName(const char *name){
	return !this->GetSource() || this->GetSource()->GetName() == std::string(name);
}

bool ppTransition::IsDestinationName(const char *name){
	return !this->GetDestination() || this->GetDestination()->GetName() == std::string(name);
}

ppGenericSound* ppTransition::GetSource(){
	return this->sourceSound;
}

ppGenericSound* ppTransition::GetDestination(){
	return this->destSound;
}

ppGenericSound* ppTransition::GetActualSource(){
	return this->actualSource;
}

ppGenericSound* ppTransition::GetTransitionTrack(){
	return this->transitionTrack;
}

ppGenericSound* ppTransition::GetActualDestination(){
	return this->actualDest;
}

float ppTransition::GetTransitionPosition(){
	// Convert unsigned to float then subtract it
	return (SDL_GetTicks()/1000.0f)-(this->triggerTime/1000.0f);
}

float ppTransition::GetSyncPoint(){
	return this->syncPoint/1000.0f;
}

void ppTransition::SetSourcePosition(ppTransitionSourcePosition sourcePosition){
	this->sourcePosition = sourcePosition;
}

void ppTransition::SetDestinationPosition(ppTransitionDestinationPosition destPosition){
	this->destPosition = destPosition;
}

void ppTransition::SetTransitionTrack(ppGenericSound* transitionTrack){
	this->transitionTrack = transitionTrack;
}

int ppTransition::GetPriority(){
	return this->priority;
}

void ppTransition::SetSourceOffset(float offset){
	this->sourceOffset = offset;
}

void ppTransition::SetSourceDuration(float duration){
	this->sourceDuration = duration;
}

void ppTransition::SetSourceCurve(ppEasing* easing){
	this->sourceEasing = easing;
}

void ppTransition::SetDestinationOffset(float offset){
	this->destOffset = offset;
}

void ppTransition::SetDestinationDuration(float duration){
	this->destDuration = duration;
}

void ppTransition::SetDestinationCurve(ppEasing* easing){
	this->destEasing = easing;
}

ppTransitionSourcePosition ppTransition::GetSourcePosition(){
	return this->sourcePosition;
}

float ppTransition::GetSourceOffset(){
	return this->sourceOffset;
}

float ppTransition::GetSourceDuration(){
	return this->sourceDuration;
}

ppEasing* ppTransition::GetSourceCurve(){
	return this->sourceEasing;
}

ppTransitionDestinationPosition ppTransition::GetDestinationPosition(){
	return this->destPosition;
}

float ppTransition::GetDestinationOffset(){
	return this->destOffset;
}

float ppTransition::GetDestinationDuration(){
	return this->destDuration;
}

ppEasing* ppTransition::GetDestinationCurve(){
	return this->destEasing;
}
<|endoftext|>


<commit_before>#include "resources.h"

Resources::Resources()
{
    //connect(this, SIGNAL(resourcesChanged()), this, SLOT(checkResources()));
}

void Resources::distrubuteResources()
{
   money = wood = stone = food = 5000;
}

void Resources::outputResources()
{
    QTextStream console(stdout);
    console << "Food\t: "  << food  << "\n";
    console << "Wood\t: "  << wood  << "\n";
    console << "Money\t: " << money << "\n" ;
    console << "Stone\t: " << stone << "\n";
}

void Resources::updateFood(ll foodChange)
{
    food  += foodChange;
}

void Resources::updateWood(ll woodChange)
{
    wood  += woodChange;
}

void Resources::updateStone(ll stoneChange)
{
    stone += stoneChange;
}

void Resources::updateMoney(ll moneyChange)
{
    money += moneyChange;
}
/*
void Resources::updateResources(ll foodChange, ll woodChange, ll stoneChange, ll moneyChange)
{
    food  += foodChange;
    wood  += woodChange;
    stone += stoneChange;
    money += moneyChange;
    emit resourcesChanged();
}
*/
/*******************************
 *           TODO              *
 *******************************/
void Resources::checkResources()
{
    if(food  < 0 || wood < 0 || stone < 0 || money < 0) emit gameOver();

}

<commit_msg>Delete resources.cpp<commit_after><|endoftext|>


<commit_before>// InstModelTests.h
#include <gtest/gtest.h>

#include "InstModel.h"
#include "FacilityModel.h"
#include "Prototype.h"

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
//- - - - - - - Tests specific to the InstModel class itself- - - - - - -
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
class ConcreteInstModel : public InstModel {
 public:
  ConcreteInstModel() { };

  virtual ~ConcreteInstModel() {};

};

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
class DieModel : public FacilityModel {
 public:
  DieModel() {
    tickCount_ = 0;
    tockCount_ = 0;
    tickDie_ = false;
    tockDie_ = false;
  };

  virtual ~DieModel() {};

  // virtual Prototype* clone() {
  //   DieModel* clone = new DieModel();
  //   return dynamic_cast<Prototype*>(clone);
  // };

  virtual void receiveMessage(msg_ptr msg) { };

  virtual void handleTick(int time) {
    tickCount_++;
    totalTicks++;

    if (tickDie_) {
      delete this;
    }
  }

  virtual void handleTock(int time) {
    tockCount_++;
    totalTocks++;

    if (tockDie_) {
      delete this;
    }
  }

  int tickCount_;
  int tockCount_;

  bool tickDie_;
  bool tockDie_;

  static int totalTicks;
  static int totalTocks;
};

int DieModel::totalTicks = 0;
int DieModel::totalTocks = 0;

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
class InstModelClassTests : public ::testing::Test {
  protected:

    DieModel* child1_;
    DieModel* child2_;
    DieModel* child3_;
    DieModel* child4_;
    DieModel* child5_;

    TimeAgent* inst_;

    virtual void SetUp() {
      child1_ = new DieModel();
      child2_ = new DieModel();
      child3_ = new DieModel();
      child4_ = new DieModel();
      child5_ = new DieModel();

      inst_ = new ConcreteInstModel();
      child1_->enterSimulation(inst_);
      child2_->enterSimulation(inst_);
      child3_->enterSimulation(inst_);
      child4_->enterSimulation(inst_);
      child5_->enterSimulation(inst_);
    }
};

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TEST_F(InstModelClassTests, TickIter) {
  child2_->tickDie_ = true;

  ASSERT_NO_THROW(inst_->handleTick(0));
  EXPECT_EQ(DieModel::totalTicks, 5);
  EXPECT_EQ(child1_->tickCount_, 1);
  EXPECT_EQ(child3_->tickCount_, 1);
  EXPECT_EQ(child4_->tickCount_, 1);
  EXPECT_EQ(child5_->tickCount_, 1);

  child1_->tickDie_ = true;
  child3_->tickDie_ = true;

  ASSERT_NO_THROW(inst_->handleTick(0));
  EXPECT_EQ(DieModel::totalTicks, 9);
  EXPECT_EQ(child4_->tickCount_, 2);
  EXPECT_EQ(child5_->tickCount_, 2);
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TEST_F(InstModelClassTests, TockIter) {
  child2_->tockDie_ = true;

  ASSERT_NO_THROW(inst_->handleTock(0));
  EXPECT_EQ(DieModel::totalTocks, 5);
  EXPECT_EQ(child1_->tockCount_, 1);
  EXPECT_EQ(child3_->tockCount_, 1);
  EXPECT_EQ(child4_->tockCount_, 1);
  EXPECT_EQ(child5_->tockCount_, 1);

  child1_->tockDie_ = true;
  child3_->tockDie_ = true;

  ASSERT_NO_THROW(inst_->handleTock(0));
  EXPECT_EQ(DieModel::totalTocks, 9);
  EXPECT_EQ(child4_->tockCount_, 2);
  EXPECT_EQ(child5_->tockCount_, 2);
}

<commit_msg>added cloneModuleMembersFrom to the DieModel in the InstClassTests<commit_after>// InstModelTests.h
#include <gtest/gtest.h>

#include "InstModel.h"
#include "FacilityModel.h"
#include "Prototype.h"

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
//- - - - - - - Tests specific to the InstModel class itself- - - - - - -
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
class ConcreteInstModel : public InstModel {
 public:
  ConcreteInstModel() { };

  virtual ~ConcreteInstModel() {};

};

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
class DieModel : public FacilityModel {
 public:
  DieModel() {
    tickCount_ = 0;
    tockCount_ = 0;
    tickDie_ = false;
    tockDie_ = false;
  };

  virtual ~DieModel() {};

  // virtual Prototype* clone() {
  //   DieModel* clone = new DieModel();
  //   return dynamic_cast<Prototype*>(clone);
  // };

  virtual void receiveMessage(msg_ptr msg) { };
  virtual void cloneModuleMembersFrom(FacilityModel* source){};

  virtual void handleTick(int time) {
    tickCount_++;
    totalTicks++;

    if (tickDie_) {
      delete this;
    }
  }

  virtual void handleTock(int time) {
    tockCount_++;
    totalTocks++;

    if (tockDie_) {
      delete this;
    }
  }

  int tickCount_;
  int tockCount_;

  bool tickDie_;
  bool tockDie_;

  static int totalTicks;
  static int totalTocks;
};

int DieModel::totalTicks = 0;
int DieModel::totalTocks = 0;

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
class InstModelClassTests : public ::testing::Test {
  protected:

    DieModel* child1_;
    DieModel* child2_;
    DieModel* child3_;
    DieModel* child4_;
    DieModel* child5_;

    TimeAgent* inst_;

    virtual void SetUp() {
      child1_ = new DieModel();
      child2_ = new DieModel();
      child3_ = new DieModel();
      child4_ = new DieModel();
      child5_ = new DieModel();

      inst_ = new ConcreteInstModel();
      child1_->enterSimulation(inst_);
      child2_->enterSimulation(inst_);
      child3_->enterSimulation(inst_);
      child4_->enterSimulation(inst_);
      child5_->enterSimulation(inst_);
    }
};

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TEST_F(InstModelClassTests, TickIter) {
  child2_->tickDie_ = true;

  ASSERT_NO_THROW(inst_->handleTick(0));
  EXPECT_EQ(DieModel::totalTicks, 5);
  EXPECT_EQ(child1_->tickCount_, 1);
  EXPECT_EQ(child3_->tickCount_, 1);
  EXPECT_EQ(child4_->tickCount_, 1);
  EXPECT_EQ(child5_->tickCount_, 1);

  child1_->tickDie_ = true;
  child3_->tickDie_ = true;

  ASSERT_NO_THROW(inst_->handleTick(0));
  EXPECT_EQ(DieModel::totalTicks, 9);
  EXPECT_EQ(child4_->tickCount_, 2);
  EXPECT_EQ(child5_->tickCount_, 2);
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TEST_F(InstModelClassTests, TockIter) {
  child2_->tockDie_ = true;

  ASSERT_NO_THROW(inst_->handleTock(0));
  EXPECT_EQ(DieModel::totalTocks, 5);
  EXPECT_EQ(child1_->tockCount_, 1);
  EXPECT_EQ(child3_->tockCount_, 1);
  EXPECT_EQ(child4_->tockCount_, 1);
  EXPECT_EQ(child5_->tockCount_, 1);

  child1_->tockDie_ = true;
  child3_->tockDie_ = true;

  ASSERT_NO_THROW(inst_->handleTock(0));
  EXPECT_EQ(DieModel::totalTocks, 9);
  EXPECT_EQ(child4_->tockCount_, 2);
  EXPECT_EQ(child5_->tockCount_, 2);
}

<|endoftext|>


<commit_before>//
// Copyright (c) 2014 Toshiaki Takada
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

#include "project.hpp"
#include "cli.hpp"
#include "cli_builtins.hpp"

int
cli_builtins_debug_cli_set(Cli *cli, StringVector& vec)
{
  cli->set_debug(true);

  return 1;
}

int
cli_builtins_debug_cli_unset(Cli *cli, StringVector& vec)
{
  cli->set_debug(false);

  return 1;
}

int
cli_exit(Cli *cli, StringVector& vec)
{
  cli->exit();

  return 1;
}

int
cli_debug(Cli *cli, StringVector& vec)
{
  cout << "DEBUG" << endl;

  return 1;
}

int
cli_show_result(Cli *cli, StringVector& vec)
{
  cout << cli->result().str() << endl;

  return 1;
}

int
cli_write_result(Cli *cli, StringVector& vec)
{
  ofstream file;

  file.open("error.txt");
  file << cli->result().str() << endl;
  file.close();

  return 1;
}

void
cli_builtins_init(Cli *cli)
{
  cli->built_in_["debug-cli-set"] = cli_builtins_debug_cli_set;
  cli->built_in_["debug-cli-unset"] = cli_builtins_debug_cli_unset;
  cli->built_in_["cli-exit"] = cli_exit;
  cli->built_in_["cli-debug"] = cli_debug;
  cli->built_in_["show-result"] = cli_show_result;
  cli->built_in_["write-result"] = cli_write_result;
}

void
cli_mode_set(Cli *cli, string name)
{
  cli->mode_set(name);
}

void
cli_mode_up(Cli *cli, unsigned int up)
{
  cli->mode_up(up);
}
<commit_msg>Remove unused functions.<commit_after>//
// Copyright (c) 2014 Toshiaki Takada
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

#include "project.hpp"
#include "cli.hpp"
#include "cli_builtins.hpp"

int
cli_builtins_debug_cli_set(Cli *cli, StringVector& vec)
{
  cli->set_debug(true);

  return 1;
}

int
cli_builtins_debug_cli_unset(Cli *cli, StringVector& vec)
{
  cli->set_debug(false);

  return 1;
}

int
cli_exit(Cli *cli, StringVector& vec)
{
  cli->exit();

  return 1;
}

int
cli_debug(Cli *cli, StringVector& vec)
{
  cout << "DEBUG" << endl;

  return 1;
}

int
cli_show_result(Cli *cli, StringVector& vec)
{
  cout << cli->result().str() << endl;

  return 1;
}

int
cli_write_result(Cli *cli, StringVector& vec)
{
  ofstream file;

  file.open("error.txt");
  file << cli->result().str() << endl;
  file.close();

  return 1;
}

void
cli_builtins_init(Cli *cli)
{
  cli->built_in_["debug-cli-set"] = cli_builtins_debug_cli_set;
  cli->built_in_["debug-cli-unset"] = cli_builtins_debug_cli_unset;
  cli->built_in_["cli-exit"] = cli_exit;
  cli->built_in_["cli-debug"] = cli_debug;
  cli->built_in_["show-result"] = cli_show_result;
  cli->built_in_["write-result"] = cli_write_result;
}

<|endoftext|>


<commit_before>
#include <gloperate-text/FontLoader.h>

#include <fstream>
#include <sstream>
#include <string>
#include <functional>
#include <set>
#include <map>
#include <algorithm>

#include <glbinding/gl/enum.h>
#include <loggingzeug/logging.h>

#include <stringzeug/conversion.h>
#include <stringzeug/manipulation.h>

#include <iozeug/FilePath.h>

#include <gloperate/resources/RawFile.h>
#include <gloperate/resources/ResourceManager.h>

#include <gloperate-text/FontFace.h>

namespace gloperate_text
{

FontLoader::FontLoader(gloperate::ResourceManager & resourceManager)
: m_resourceManager(resourceManager)
{
}

bool FontLoader::canLoad(const std::string & ext) const
{
    return ext == ".txt";
}

std::vector<std::string> FontLoader::loadingTypes() const
{
    return { "Littera Text Font (*.txt)" };
}

std::string FontLoader::allLoadingTypes() const
{
    return "*.txt";
}

FontFace * FontLoader::load(const std::string & filename
    , const reflectionzeug::Variant &, const std::function<void(int, int)>) const
{
    auto in = std::ifstream(filename, std::ios::in | std::ios::binary);

    if (!in)
        return nullptr;

    auto fontFace = new FontFace();

    auto line = std::string();
    auto identifier = std::string();
    auto fontSize = 0.f;

    while (std::getline(in, line))
    {
        auto ss = std::stringstream();
        ss << line;

        if (!std::getline(ss, identifier, ' '))
        {
            assert(false);
            continue;
        }

        if      (identifier == "info")
        {
            handleInfo(ss, *fontFace, fontSize);
        }
        else if (identifier == "common")
        {
            handleCommon(ss, *fontFace, fontSize);
        }
        else if (identifier == "page")
        {
            handlePage(ss, *fontFace, filename);
        }
        else if (identifier == "char")
        {
            handleChar(ss, *fontFace);
        }
        else if (identifier == "kerning")
        {
            handleKerning(ss, *fontFace);
        }
    }

    if (fontFace->glyphTexture())
        return fontFace;

    delete fontFace;
    return nullptr;
}

void FontLoader::handleInfo(std::stringstream & stream, FontFace & fontFace, float & fontSize) const
{
    auto pairs = readKeyValuePairs(stream, { "size", "padding" });

    fontSize = stringzeug::fromString<float>(pairs.at("size"));

    auto values = stringzeug::split(pairs.at("padding"), ',');
    assert(values.size() == 4);

    auto padding = glm::vec4();
    padding[0] = stringzeug::fromString<float>(values[2]); // top
    padding[1] = stringzeug::fromString<float>(values[1]); // right
    padding[2] = stringzeug::fromString<float>(values[3]); // bottom
    padding[3] = stringzeug::fromString<float>(values[0]); // left

    fontFace.setGlyphTexturePadding(padding);
}

void FontLoader::handleCommon(std::stringstream & stream, FontFace & fontFace, const float fontSize) const
{
    auto pairs = readKeyValuePairs(stream, { "lineHeight", "base", "scaleW", "scaleH" });

    fontFace.setAscent(stringzeug::fromString<float>(pairs.at("base")));
    fontFace.setDescent(fontFace.ascent() - fontSize);

    assert(fontFace.size() > 0.f);
    fontFace.setLineHeight(stringzeug::fromString<float>(pairs.at("lineHeight")));

    fontFace.setGlyphTextureExtent({
        stringzeug::fromString<float>(pairs.at("scaleW")),
        stringzeug::fromString<float>(pairs.at("scaleH")) });
}

void FontLoader::handlePage(std::stringstream & stream, FontFace & fontFace, const std::string & filename) const
{
    auto pairs = readKeyValuePairs(stream, { "file" });

    const auto path = iozeug::FilePath(filename).directoryPath();
    const auto file = stringzeug::stripped(pairs.at("file"), { '"', '\r' });

    if (stringzeug::hasSuffix(file, ".raw"))
    {
        auto texture = new globjects::Texture(gl::GL_TEXTURE_2D);
        auto raw = gloperate::RawFile(path + "/" + file);

        if (!raw.isValid())
        {
            assert(false);
            return;
        }

        texture->image2D(0, gl::GL_R8, fontFace.glyphTextureExtent(), 0
            , gl::GL_RED, gl::GL_UNSIGNED_BYTE, raw.data());

        fontFace.setGlyphTexture(texture);
    }
    else
        fontFace.setGlyphTexture(m_resourceManager.load<globjects::Texture>(path + "/" + file));

    fontFace.glyphTexture()->setParameter(gl::GL_TEXTURE_MIN_FILTER, gl::GL_LINEAR);
    fontFace.glyphTexture()->setParameter(gl::GL_TEXTURE_MAG_FILTER, gl::GL_LINEAR);
    fontFace.glyphTexture()->setParameter(gl::GL_TEXTURE_WRAP_S, gl::GL_CLAMP_TO_EDGE);
    fontFace.glyphTexture()->setParameter(gl::GL_TEXTURE_WRAP_T, gl::GL_CLAMP_TO_EDGE);
}

void FontLoader::handleChar(std::stringstream & stream, FontFace & fontFace) const
{
    auto pairs = readKeyValuePairs(stream, { "id", "x", "y", "width", "height", "xoffset", "yoffset", "xadvance" });

    auto index = stringzeug::fromString<GlyphIndex>(pairs.at("id"));
    assert(index > 0);

    auto glyph = Glyph();

    glyph.setIndex(index);

    const auto extentScale = 1.f / glm::vec2(fontFace.glyphTextureExtent());
    const auto extent = glm::vec2(
        stringzeug::fromString<float>(pairs.at("width")),
        stringzeug::fromString<float>(pairs.at("height")));

    glyph.setSubTextureOrigin({
        stringzeug::fromString<float>(pairs.at("x")) * extentScale.x,
        1.f - (stringzeug::fromString<float>(pairs.at("y")) + extent.y) * extentScale.y});

    glyph.setExtent(extent);
    glyph.setSubTextureExtent(extent * extentScale);

    glyph.setBearing(fontFace.ascent(),
        stringzeug::fromString<float>(pairs.at("xoffset")),
        stringzeug::fromString<float>(pairs.at("yoffset")));

    glyph.setAdvance(stringzeug::fromString<float>(pairs.at("xadvance")));

    fontFace.addGlyph(glyph);
}

void FontLoader::handleKerning(std::stringstream & stream, FontFace & fontFace) const
{
    auto pairs = readKeyValuePairs(stream, { "first", "second", "amount" });

    auto first = stringzeug::fromString<GlyphIndex>(pairs.at("first"));
    assert(first > 0);

    auto second = stringzeug::fromString<GlyphIndex>(pairs.at("second"));
    assert(second > 0);

    auto kerning = stringzeug::fromString<float>(pairs.at("amount"));

    fontFace.setKerning(first, second, kerning);
}

FontLoader::StringPairs FontLoader::readKeyValuePairs(
    std::stringstream & stream
    , const std::initializer_list<const char *> & mandatoryKeys)
{
    auto key = std::string();
    auto value = std::string();

    auto pairs = StringPairs();

    while (stream)
    {
        if (!std::getline(stream, key, '='))
            continue;

        if (!std::getline(stream, value, ' '))
            continue;

        pairs.insert(std::pair<std::string, std::string>(key, value));
    }

    // check if all required keys are provided
    auto valid = true;
    for (const auto mandatoryKey : mandatoryKeys)
    {
        valid |= pairs.find(mandatoryKey) != pairs.cend();
    }

    if (!valid)
        return StringPairs();

    return pairs;
}

} // namespace gloperate_text
<commit_msg>Fix compilation for gcc 4.8/4.9<commit_after>
#include <gloperate-text/FontLoader.h>

#include <fstream>
#include <sstream>
#include <string>
#include <functional>
#include <set>
#include <map>
#include <algorithm>

#include <glbinding/gl/enum.h>
#include <loggingzeug/logging.h>

#include <stringzeug/conversion.h>
#include <stringzeug/manipulation.h>

#include <iozeug/FilePath.h>

#include <gloperate/resources/RawFile.h>
#include <gloperate/resources/ResourceManager.h>

#include <gloperate-text/FontFace.h>

namespace gloperate_text
{

FontLoader::FontLoader(gloperate::ResourceManager & resourceManager)
: m_resourceManager(resourceManager)
{
}

bool FontLoader::canLoad(const std::string & ext) const
{
    return ext == ".txt";
}

std::vector<std::string> FontLoader::loadingTypes() const
{
    return { "Littera Text Font (*.txt)" };
}

std::string FontLoader::allLoadingTypes() const
{
    return "*.txt";
}

FontFace * FontLoader::load(const std::string & filename
    , const reflectionzeug::Variant &, const std::function<void(int, int)>) const
{
    std::ifstream in(filename, std::ios::in | std::ios::binary);

    if (!in)
        return nullptr;

    auto fontFace = new FontFace();

    auto line = std::string();
    auto identifier = std::string();
    auto fontSize = 0.f;

    while (std::getline(in, line))
    {
        std::stringstream ss;
        ss << line;

        if (!std::getline(ss, identifier, ' '))
        {
            assert(false);
            continue;
        }

        if      (identifier == "info")
        {
            handleInfo(ss, *fontFace, fontSize);
        }
        else if (identifier == "common")
        {
            handleCommon(ss, *fontFace, fontSize);
        }
        else if (identifier == "page")
        {
            handlePage(ss, *fontFace, filename);
        }
        else if (identifier == "char")
        {
            handleChar(ss, *fontFace);
        }
        else if (identifier == "kerning")
        {
            handleKerning(ss, *fontFace);
        }
    }

    if (fontFace->glyphTexture())
        return fontFace;

    delete fontFace;
    return nullptr;
}

void FontLoader::handleInfo(std::stringstream & stream, FontFace & fontFace, float & fontSize) const
{
    auto pairs = readKeyValuePairs(stream, { "size", "padding" });

    fontSize = stringzeug::fromString<float>(pairs.at("size"));

    auto values = stringzeug::split(pairs.at("padding"), ',');
    assert(values.size() == 4);

    auto padding = glm::vec4();
    padding[0] = stringzeug::fromString<float>(values[2]); // top
    padding[1] = stringzeug::fromString<float>(values[1]); // right
    padding[2] = stringzeug::fromString<float>(values[3]); // bottom
    padding[3] = stringzeug::fromString<float>(values[0]); // left

    fontFace.setGlyphTexturePadding(padding);
}

void FontLoader::handleCommon(std::stringstream & stream, FontFace & fontFace, const float fontSize) const
{
    auto pairs = readKeyValuePairs(stream, { "lineHeight", "base", "scaleW", "scaleH" });

    fontFace.setAscent(stringzeug::fromString<float>(pairs.at("base")));
    fontFace.setDescent(fontFace.ascent() - fontSize);

    assert(fontFace.size() > 0.f);
    fontFace.setLineHeight(stringzeug::fromString<float>(pairs.at("lineHeight")));

    fontFace.setGlyphTextureExtent({
        stringzeug::fromString<float>(pairs.at("scaleW")),
        stringzeug::fromString<float>(pairs.at("scaleH")) });
}

void FontLoader::handlePage(std::stringstream & stream, FontFace & fontFace, const std::string & filename) const
{
    auto pairs = readKeyValuePairs(stream, { "file" });

    const auto path = iozeug::FilePath(filename).directoryPath();
    const auto file = stringzeug::stripped(pairs.at("file"), { '"', '\r' });

    if (stringzeug::hasSuffix(file, ".raw"))
    {
        auto texture = new globjects::Texture(gl::GL_TEXTURE_2D);
        auto raw = gloperate::RawFile(path + "/" + file);

        if (!raw.isValid())
        {
            assert(false);
            return;
        }

        texture->image2D(0, gl::GL_R8, fontFace.glyphTextureExtent(), 0
            , gl::GL_RED, gl::GL_UNSIGNED_BYTE, raw.data());

        fontFace.setGlyphTexture(texture);
    }
    else
        fontFace.setGlyphTexture(m_resourceManager.load<globjects::Texture>(path + "/" + file));

    fontFace.glyphTexture()->setParameter(gl::GL_TEXTURE_MIN_FILTER, gl::GL_LINEAR);
    fontFace.glyphTexture()->setParameter(gl::GL_TEXTURE_MAG_FILTER, gl::GL_LINEAR);
    fontFace.glyphTexture()->setParameter(gl::GL_TEXTURE_WRAP_S, gl::GL_CLAMP_TO_EDGE);
    fontFace.glyphTexture()->setParameter(gl::GL_TEXTURE_WRAP_T, gl::GL_CLAMP_TO_EDGE);
}

void FontLoader::handleChar(std::stringstream & stream, FontFace & fontFace) const
{
    auto pairs = readKeyValuePairs(stream, { "id", "x", "y", "width", "height", "xoffset", "yoffset", "xadvance" });

    auto index = stringzeug::fromString<GlyphIndex>(pairs.at("id"));
    assert(index > 0);

    auto glyph = Glyph();

    glyph.setIndex(index);

    const auto extentScale = 1.f / glm::vec2(fontFace.glyphTextureExtent());
    const auto extent = glm::vec2(
        stringzeug::fromString<float>(pairs.at("width")),
        stringzeug::fromString<float>(pairs.at("height")));

    glyph.setSubTextureOrigin({
        stringzeug::fromString<float>(pairs.at("x")) * extentScale.x,
        1.f - (stringzeug::fromString<float>(pairs.at("y")) + extent.y) * extentScale.y});

    glyph.setExtent(extent);
    glyph.setSubTextureExtent(extent * extentScale);

    glyph.setBearing(fontFace.ascent(),
        stringzeug::fromString<float>(pairs.at("xoffset")),
        stringzeug::fromString<float>(pairs.at("yoffset")));

    glyph.setAdvance(stringzeug::fromString<float>(pairs.at("xadvance")));

    fontFace.addGlyph(glyph);
}

void FontLoader::handleKerning(std::stringstream & stream, FontFace & fontFace) const
{
    auto pairs = readKeyValuePairs(stream, { "first", "second", "amount" });

    auto first = stringzeug::fromString<GlyphIndex>(pairs.at("first"));
    assert(first > 0);

    auto second = stringzeug::fromString<GlyphIndex>(pairs.at("second"));
    assert(second > 0);

    auto kerning = stringzeug::fromString<float>(pairs.at("amount"));

    fontFace.setKerning(first, second, kerning);
}

FontLoader::StringPairs FontLoader::readKeyValuePairs(
    std::stringstream & stream
    , const std::initializer_list<const char *> & mandatoryKeys)
{
    auto key = std::string();
    auto value = std::string();

    auto pairs = StringPairs();

    while (stream)
    {
        if (!std::getline(stream, key, '='))
            continue;

        if (!std::getline(stream, value, ' '))
            continue;

        pairs.insert(std::pair<std::string, std::string>(key, value));
    }

    // check if all required keys are provided
    auto valid = true;
    for (const auto mandatoryKey : mandatoryKeys)
    {
        valid |= pairs.find(mandatoryKey) != pairs.cend();
    }

    if (!valid)
        return StringPairs();

    return pairs;
}

} // namespace gloperate_text
<|endoftext|>


<commit_before>/*
 * node-rdkafka - Node.js wrapper for RdKafka C/C++ library
 *
 * Copyright (c) 2016 Blizzard Entertainment
 *
 * This software may be modified and distributed under the terms
 * of the MIT license.  See the LICENSE.txt file for details.
 */

#include <string>
#include <vector>

#include "src/producer.h"
#include "src/workers.h"

namespace NodeKafka {

/**
 * @brief Producer v8 wrapped object.
 *
 * Wraps the RdKafka::Producer object with compositional inheritence and
 * provides methods for interacting with it exposed to node.
 *
 * The base wrappable RdKafka::Handle deals with most of the wrapping but
 * we still need to declare its prototype.
 *
 * @sa RdKafka::Producer
 * @sa NodeKafka::Connection
 */

Producer::Producer(Conf* gconfig, Conf* tconfig):
  Connection(gconfig, tconfig),
  m_dr_cb(),
  m_partitioner_cb() {
    std::string errstr;

    m_gconfig->set("default_topic_conf", m_tconfig, errstr);
    m_gconfig->set("dr_cb", &m_dr_cb, errstr);
  }

Producer::~Producer() {
  Disconnect();
}

Nan::Persistent<v8::Function> Producer::constructor;

void Producer::Init(v8::Local<v8::Object> exports) {
  Nan::HandleScope scope;

  v8::Local<v8::FunctionTemplate> tpl = Nan::New<v8::FunctionTemplate>(New);
  tpl->SetClassName(Nan::New("Producer").ToLocalChecked());
  tpl->InstanceTemplate()->SetInternalFieldCount(1);

  /*
   * Lifecycle events inherited from NodeKafka::Connection
   *
   * @sa NodeKafka::Connection
   */

  Nan::SetPrototypeMethod(tpl, "onEvent", NodeOnEvent);

  /*
   * @brief Methods to do with establishing state
   */

  Nan::SetPrototypeMethod(tpl, "connect", NodeConnect);
  Nan::SetPrototypeMethod(tpl, "disconnect", NodeDisconnect);
  Nan::SetPrototypeMethod(tpl, "getMetadata", NodeGetMetadata);
  Nan::SetPrototypeMethod(tpl, "poll", NodePoll);

  /*
   * Lifecycle events specifically designated for RdKafka::Producer
   *
   * @sa RdKafka::Producer
   */

  Nan::SetPrototypeMethod(tpl, "onDeliveryReport", NodeOnDelivery);

  /*
   * @brief Methods exposed to do with message production
   */

  Nan::SetPrototypeMethod(tpl, "setPartitioner", NodeSetPartitioner);
  Nan::SetPrototypeMethod(tpl, "produce", NodeProduce);

    // connect. disconnect. resume. pause. get meta data
  constructor.Reset(tpl->GetFunction());

  exports->Set(Nan::New("Producer").ToLocalChecked(), tpl->GetFunction());
}

void Producer::New(const Nan::FunctionCallbackInfo<v8::Value>& info) {
  if (!info.IsConstructCall()) {
    return Nan::ThrowError("non-constructor invocation not supported");
  }

  if (info.Length() < 2) {
    return Nan::ThrowError("You must supply global and topic configuration");
  }

  if (!info[0]->IsObject()) {
    return Nan::ThrowError("Global configuration data must be specified");
  }

  if (!info[1]->IsObject()) {
    return Nan::ThrowError("Topic configuration must be specified");
  }

  std::string errstr;

  Conf* gconfig =
    Conf::create(RdKafka::Conf::CONF_GLOBAL, info[0]->ToObject(), errstr);

  if (!gconfig) {
    return Nan::ThrowError(errstr.c_str());
  }

  Conf* tconfig =
    Conf::create(RdKafka::Conf::CONF_TOPIC, info[1]->ToObject(), errstr);

  if (!tconfig) {
    // No longer need this since we aren't instantiating anything
    delete gconfig;
    return Nan::ThrowError(errstr.c_str());
  }

  Producer* producer = new Producer(gconfig, tconfig);

  // Wrap it
  producer->Wrap(info.This());

  // Then there is some weird initialization that happens
  // basically it sets the configuration data
  // we don't need to do that because we lazy load it

  info.GetReturnValue().Set(info.This());
}

v8::Local<v8::Object> Producer::NewInstance(v8::Local<v8::Value> arg) {
  Nan::EscapableHandleScope scope;

  const unsigned argc = 1;

  v8::Local<v8::Value> argv[argc] = { arg };
  v8::Local<v8::Function> cons = Nan::New<v8::Function>(constructor);
  v8::Local<v8::Object> instance =
    Nan::NewInstance(cons, argc, argv).ToLocalChecked();

  return scope.Escape(instance);
}

std::string Producer::Name() {
  if (!IsConnected()) {
    return std::string("");
  }
  return std::string(m_client->name());
}

Baton Producer::Connect() {
  if (IsConnected()) {
    return Baton(RdKafka::ERR_NO_ERROR);
  }

  std::string errstr;

  m_client = RdKafka::Producer::create(m_gconfig, errstr);

  if (!m_client) {
    // @todo implement errstr into this somehow
    return Baton(RdKafka::ERR__STATE);
  }

  return Baton(RdKafka::ERR_NO_ERROR);
}

void Producer::ActivateDispatchers() {
  m_event_cb.dispatcher.Activate();  // From connection
  m_dr_cb.dispatcher.Activate();
}

void Producer::DeactivateDispatchers() {
  m_event_cb.dispatcher.Deactivate();  // From connection
  m_dr_cb.dispatcher.Deactivate();
}

void Producer::Disconnect() {
  if (IsConnected()) {
    scoped_mutex_lock lock(m_connection_lock);
    // @todo look at hanging
    delete m_client;
    m_client = NULL;
  }
}

/**
 * [Producer::Produce description]
 * @param message - pointer to the message we are sending. This method will
 * create a copy of it, so you are still required to free it when done.
 * @param size - size of the message. We are copying the memory so we need
 * the size
 * @param topic - RdKafka::Topic* object to send the message to. Generally
 * created by NodeKafka::Topic::toRDKafkaTopic
 * @param partition - partition to send it to. Send in
 * RdKafka::Topic::PARTITION_UA to send to an unassigned topic
 * @param key - a string pointer for the key, or null if there is none.
 * @return - A baton object with error code set if it failed.
 */
Baton Producer::Produce(void* message, size_t size, RdKafka::Topic* topic,
  int32_t partition, std::string *key) {
  RdKafka::ErrorCode response_code;

  if (IsConnected()) {
    scoped_mutex_lock lock(m_connection_lock);
    if (IsConnected()) {
      RdKafka::Producer* producer = dynamic_cast<RdKafka::Producer*>(m_client);
      response_code = producer->produce(topic, partition,
            RdKafka::Producer::RK_MSG_COPY, message, size, key, NULL);

      Poll();
    } else {
      response_code = RdKafka::ERR__STATE;
    }
  } else {
    response_code = RdKafka::ERR__STATE;
  }

  // These topics actually link to the configuration
  // they are made from. It's so we can reuse topic configurations
  // That means if we delete it here and librd thinks its still linked,
  // producing to the same topic will try to reuse it and it will die.
  //
  // Honestly, we may need to make configuration a first class object
  // @todo(Conf needs to be a first class object that is passed around)
  // delete topic;

  if (response_code != RdKafka::ERR_NO_ERROR) {
    return Baton(response_code);
  }

  return Baton(RdKafka::ERR_NO_ERROR);
}

void Producer::Poll() {
  m_client->poll(0);
}

/* Node exposed methods */

/**
 * @brief Producer::NodeProduce - produce a message through a producer
 *
 * This is a synchronous method. You may ask, "why?". The answer is because
 * there is no true value doing this asynchronously. All it does is degrade
 * performance. This method does not block - all it does is add a message
 * to a queue. In the case where the queue is full, it will return an error
 * immediately. The only way this method blocks is when you provide it a
 * flag to do so, which we never do.
 *
 * Doing it asynchronously eats up the libuv threadpool for no reason and
 * increases execution time by a very small amount. It will take two ticks of
 * the event loop to execute at minimum - 1 for executing it and another for
 * calling back the callback.
 *
 * @sa RdKafka::Producer::produce
 */
NAN_METHOD(Producer::NodeProduce) {
  Nan::HandleScope scope;

  // Need to extract the message data here.
  if (info.Length() < 3 || !info[0]->IsObject()) {
    // Just throw an exception
    return Nan::ThrowError("Need to specify a topic, partition, and message");
  }

  // First parameter is a topic
  Topic* topic = ObjectWrap::Unwrap<Topic>(info[0].As<v8::Object>());

  // Second parameter is the partition
  int32_t partition;

  if (info[1]->IsNull() || info[1]->IsUndefined()) {
    partition = RdKafka::Topic::PARTITION_UA;
  } else {
    partition = Nan::To<int32_t>(info[1]).FromJust();
  }

  if (partition < 0) {
    partition = RdKafka::Topic::PARTITION_UA;
  }

  size_t message_buffer_length;
  void* message_buffer_data;

  if (info[2]->IsNull()) {
    // This is okay for whatever reason
    message_buffer_length = 0;
    message_buffer_data = NULL;
  } else if (!node::Buffer::HasInstance(info[2])) {
    return Nan::ThrowError("Message must be a buffer or null");
  } else {
    v8::Local<v8::Object> message_buffer_object = info[2]->ToObject();

    // v8 handles the garbage collection here so we need to make a copy of
    // the buffer or assign the buffer to a persistent handle.

    // I'm not sure which would be the more performant option. I assume
    // the persistent handle would be but for now we'll try this one
    // which should be more memory-efficient and allow v8 to dispose of the
    // buffer sooner

    message_buffer_length = node::Buffer::Length(message_buffer_object);
    message_buffer_data = node::Buffer::Data(message_buffer_object);
  }

  // Last we have to get the key
  std::string * key;

  if (info[3]->IsNull() || info[3]->IsUndefined()) {
    key = NULL;
  } else {
    v8::Local<v8::String> val = info[3]->ToString();
    // Get string pointer for this thing
    Nan::Utf8String keyUTF8(val);
    std::string keyString(*keyUTF8);

    // This will just go out of scope and we don't send it anywhere,
    // since it is copied there is no need to delete it
    key = &keyString;
  }

  Producer* producer = ObjectWrap::Unwrap<Producer>(info.This());

  Baton b = producer->Produce(message_buffer_data, message_buffer_length,
    topic->toRDKafkaTopic(), partition, key);

  // Let the JS library throw if we need to so the error can be more rich
  int error_code = static_cast<int>(b.err());

  info.GetReturnValue().Set(Nan::New<v8::Number>(error_code));
}

NAN_METHOD(Producer::NodeOnDelivery) {
  Nan::HandleScope scope;

  if (info.Length() < 1 || !info[0]->IsFunction()) {
    // Just throw an exception
    return Nan::ThrowError("Need to specify a callback");
  }

  Producer* producer = ObjectWrap::Unwrap<Producer>(info.This());
  v8::Local<v8::Function> cb = info[0].As<v8::Function>();

  producer->m_dr_cb.dispatcher.AddCallback(cb);
  info.GetReturnValue().Set(Nan::True());
}

NAN_METHOD(Producer::NodeSetPartitioner) {
  Nan::HandleScope scope;

  if (info.Length() < 1 || !info[0]->IsFunction()) {
    // Just throw an exception
    return Nan::ThrowError("Need to specify a callback");
  }

  Producer* producer = ObjectWrap::Unwrap<Producer>(info.This());
  v8::Local<v8::Function> cb = info[0].As<v8::Function>();
  producer->m_partitioner_cb.SetCallback(cb);
  info.GetReturnValue().Set(Nan::True());
}

NAN_METHOD(Producer::NodeConnect) {
  Nan::HandleScope scope;

  if (info.Length() < 1 || !info[0]->IsFunction()) {
    // Just throw an exception
    return Nan::ThrowError("Need to specify a callback");
  }

  // This needs to be offloaded to libuv
  v8::Local<v8::Function> cb = info[0].As<v8::Function>();
  Nan::Callback *callback = new Nan::Callback(cb);

  Producer* producer = ObjectWrap::Unwrap<Producer>(info.This());
  Nan::AsyncQueueWorker(new Workers::ProducerConnect(callback, producer));

  info.GetReturnValue().Set(Nan::Null());
}

NAN_METHOD(Producer::NodePoll) {
  Nan::HandleScope scope;

  Producer* producer = ObjectWrap::Unwrap<Producer>(info.This());

  if (!producer->IsConnected()) {
    Nan::ThrowError("Producer is disconnected");
  } else {
    producer->Poll();
    info.GetReturnValue().Set(Nan::True());
  }
}

#if RD_KAFKA_VERSION > 0x00090200
Baton Producer::Flush(int timeout_ms) {
  RdKafka::ErrorCode response_code;
  if (IsConnected()) {
    scoped_mutex_lock lock(m_connection_lock);
    if (IsConnected()) {
      RdKafka::Producer* producer = dynamic_cast<RdKafka::Producer*>(m_client);
      response_code = producer->flush(timeout_ms);
    } else {
      response_code = RdKafka::ERR__STATE;
    }
  } else {
    response_code = RdKafka::ERR__STATE;
  }

  return Baton(response_code);
}

NAN_METHOD(Producer::NodeFlush) {
  Nan::HandleScope scope;

  if (info.Length() < 1 || !info[0]->IsFunction()) {
    // Just throw an exception
    return Nan::ThrowError("Need to specify a callback");
  }

  int timeout_ms;

  if (info[0]->IsNull() || info[0]->IsUndefined()) {
    timeout_ms = 1000;
  } else {
    timeout_ms = Nan::To<int>(info[0]).FromJust();
  }

  Producer* producer = ObjectWrap::Unwrap<Producer>(info.This());

  if (!producer->IsConnected()) {
    Nan::ThrowError("Producer is disconnected");
  } else {
    Baton b = producer->Flush(timeout_ms);
    if (b.err() != RdKafka::ErrorCode::ERR_NO_ERROR) {
      return Nan::ThrowError(b.errstr().c_str());
    }
    info.GetReturnValue().Set(Nan::True());
  }
}
#endif

NAN_METHOD(Producer::NodeDisconnect) {
  Nan::HandleScope scope;

  if (info.Length() < 1 || !info[0]->IsFunction()) {
    // Just throw an exception
    return Nan::ThrowError("Need to specify a callback");
  }

  v8::Local<v8::Function> cb = info[0].As<v8::Function>();
  Nan::Callback *callback = new Nan::Callback(cb);

  Producer* producer = ObjectWrap::Unwrap<Producer>(info.This());
  Nan::AsyncQueueWorker(new Workers::ProducerDisconnect(callback, producer));

  info.GetReturnValue().Set(Nan::Null());
}

}  // namespace NodeKafka
<commit_msg>fix for key of zero length on Ubuntu 14 (#53)<commit_after>/*
 * node-rdkafka - Node.js wrapper for RdKafka C/C++ library
 *
 * Copyright (c) 2016 Blizzard Entertainment
 *
 * This software may be modified and distributed under the terms
 * of the MIT license.  See the LICENSE.txt file for details.
 */

#include <string>
#include <vector>

#include "src/producer.h"
#include "src/workers.h"

namespace NodeKafka {

/**
 * @brief Producer v8 wrapped object.
 *
 * Wraps the RdKafka::Producer object with compositional inheritence and
 * provides methods for interacting with it exposed to node.
 *
 * The base wrappable RdKafka::Handle deals with most of the wrapping but
 * we still need to declare its prototype.
 *
 * @sa RdKafka::Producer
 * @sa NodeKafka::Connection
 */

Producer::Producer(Conf* gconfig, Conf* tconfig):
  Connection(gconfig, tconfig),
  m_dr_cb(),
  m_partitioner_cb() {
    std::string errstr;

    m_gconfig->set("default_topic_conf", m_tconfig, errstr);
    m_gconfig->set("dr_cb", &m_dr_cb, errstr);
  }

Producer::~Producer() {
  Disconnect();
}

Nan::Persistent<v8::Function> Producer::constructor;

void Producer::Init(v8::Local<v8::Object> exports) {
  Nan::HandleScope scope;

  v8::Local<v8::FunctionTemplate> tpl = Nan::New<v8::FunctionTemplate>(New);
  tpl->SetClassName(Nan::New("Producer").ToLocalChecked());
  tpl->InstanceTemplate()->SetInternalFieldCount(1);

  /*
   * Lifecycle events inherited from NodeKafka::Connection
   *
   * @sa NodeKafka::Connection
   */

  Nan::SetPrototypeMethod(tpl, "onEvent", NodeOnEvent);

  /*
   * @brief Methods to do with establishing state
   */

  Nan::SetPrototypeMethod(tpl, "connect", NodeConnect);
  Nan::SetPrototypeMethod(tpl, "disconnect", NodeDisconnect);
  Nan::SetPrototypeMethod(tpl, "getMetadata", NodeGetMetadata);
  Nan::SetPrototypeMethod(tpl, "poll", NodePoll);

  /*
   * Lifecycle events specifically designated for RdKafka::Producer
   *
   * @sa RdKafka::Producer
   */

  Nan::SetPrototypeMethod(tpl, "onDeliveryReport", NodeOnDelivery);

  /*
   * @brief Methods exposed to do with message production
   */

  Nan::SetPrototypeMethod(tpl, "setPartitioner", NodeSetPartitioner);
  Nan::SetPrototypeMethod(tpl, "produce", NodeProduce);

    // connect. disconnect. resume. pause. get meta data
  constructor.Reset(tpl->GetFunction());

  exports->Set(Nan::New("Producer").ToLocalChecked(), tpl->GetFunction());
}

void Producer::New(const Nan::FunctionCallbackInfo<v8::Value>& info) {
  if (!info.IsConstructCall()) {
    return Nan::ThrowError("non-constructor invocation not supported");
  }

  if (info.Length() < 2) {
    return Nan::ThrowError("You must supply global and topic configuration");
  }

  if (!info[0]->IsObject()) {
    return Nan::ThrowError("Global configuration data must be specified");
  }

  if (!info[1]->IsObject()) {
    return Nan::ThrowError("Topic configuration must be specified");
  }

  std::string errstr;

  Conf* gconfig =
    Conf::create(RdKafka::Conf::CONF_GLOBAL, info[0]->ToObject(), errstr);

  if (!gconfig) {
    return Nan::ThrowError(errstr.c_str());
  }

  Conf* tconfig =
    Conf::create(RdKafka::Conf::CONF_TOPIC, info[1]->ToObject(), errstr);

  if (!tconfig) {
    // No longer need this since we aren't instantiating anything
    delete gconfig;
    return Nan::ThrowError(errstr.c_str());
  }

  Producer* producer = new Producer(gconfig, tconfig);

  // Wrap it
  producer->Wrap(info.This());

  // Then there is some weird initialization that happens
  // basically it sets the configuration data
  // we don't need to do that because we lazy load it

  info.GetReturnValue().Set(info.This());
}

v8::Local<v8::Object> Producer::NewInstance(v8::Local<v8::Value> arg) {
  Nan::EscapableHandleScope scope;

  const unsigned argc = 1;

  v8::Local<v8::Value> argv[argc] = { arg };
  v8::Local<v8::Function> cons = Nan::New<v8::Function>(constructor);
  v8::Local<v8::Object> instance =
    Nan::NewInstance(cons, argc, argv).ToLocalChecked();

  return scope.Escape(instance);
}

std::string Producer::Name() {
  if (!IsConnected()) {
    return std::string("");
  }
  return std::string(m_client->name());
}

Baton Producer::Connect() {
  if (IsConnected()) {
    return Baton(RdKafka::ERR_NO_ERROR);
  }

  std::string errstr;

  m_client = RdKafka::Producer::create(m_gconfig, errstr);

  if (!m_client) {
    // @todo implement errstr into this somehow
    return Baton(RdKafka::ERR__STATE);
  }

  return Baton(RdKafka::ERR_NO_ERROR);
}

void Producer::ActivateDispatchers() {
  m_event_cb.dispatcher.Activate();  // From connection
  m_dr_cb.dispatcher.Activate();
}

void Producer::DeactivateDispatchers() {
  m_event_cb.dispatcher.Deactivate();  // From connection
  m_dr_cb.dispatcher.Deactivate();
}

void Producer::Disconnect() {
  if (IsConnected()) {
    scoped_mutex_lock lock(m_connection_lock);
    // @todo look at hanging
    delete m_client;
    m_client = NULL;
  }
}

/**
 * [Producer::Produce description]
 * @param message - pointer to the message we are sending. This method will
 * create a copy of it, so you are still required to free it when done.
 * @param size - size of the message. We are copying the memory so we need
 * the size
 * @param topic - RdKafka::Topic* object to send the message to. Generally
 * created by NodeKafka::Topic::toRDKafkaTopic
 * @param partition - partition to send it to. Send in
 * RdKafka::Topic::PARTITION_UA to send to an unassigned topic
 * @param key - a string pointer for the key, or null if there is none.
 * @return - A baton object with error code set if it failed.
 */
Baton Producer::Produce(void* message, size_t size, RdKafka::Topic* topic,
  int32_t partition, std::string *key) {
  RdKafka::ErrorCode response_code;

  if (IsConnected()) {
    scoped_mutex_lock lock(m_connection_lock);
    if (IsConnected()) {
      RdKafka::Producer* producer = dynamic_cast<RdKafka::Producer*>(m_client);
      response_code = producer->produce(topic, partition,
            RdKafka::Producer::RK_MSG_COPY, message, size, key, NULL);

      Poll();
    } else {
      response_code = RdKafka::ERR__STATE;
    }
  } else {
    response_code = RdKafka::ERR__STATE;
  }

  // These topics actually link to the configuration
  // they are made from. It's so we can reuse topic configurations
  // That means if we delete it here and librd thinks its still linked,
  // producing to the same topic will try to reuse it and it will die.
  //
  // Honestly, we may need to make configuration a first class object
  // @todo(Conf needs to be a first class object that is passed around)
  // delete topic;

  if (response_code != RdKafka::ERR_NO_ERROR) {
    return Baton(response_code);
  }

  return Baton(RdKafka::ERR_NO_ERROR);
}

void Producer::Poll() {
  m_client->poll(0);
}

/* Node exposed methods */

/**
 * @brief Producer::NodeProduce - produce a message through a producer
 *
 * This is a synchronous method. You may ask, "why?". The answer is because
 * there is no true value doing this asynchronously. All it does is degrade
 * performance. This method does not block - all it does is add a message
 * to a queue. In the case where the queue is full, it will return an error
 * immediately. The only way this method blocks is when you provide it a
 * flag to do so, which we never do.
 *
 * Doing it asynchronously eats up the libuv threadpool for no reason and
 * increases execution time by a very small amount. It will take two ticks of
 * the event loop to execute at minimum - 1 for executing it and another for
 * calling back the callback.
 *
 * @sa RdKafka::Producer::produce
 */
NAN_METHOD(Producer::NodeProduce) {
  Nan::HandleScope scope;

  // Need to extract the message data here.
  if (info.Length() < 3 || !info[0]->IsObject()) {
    // Just throw an exception
    return Nan::ThrowError("Need to specify a topic, partition, and message");
  }

  // First parameter is a topic
  Topic* topic = ObjectWrap::Unwrap<Topic>(info[0].As<v8::Object>());

  // Second parameter is the partition
  int32_t partition;

  if (info[1]->IsNull() || info[1]->IsUndefined()) {
    partition = RdKafka::Topic::PARTITION_UA;
  } else {
    partition = Nan::To<int32_t>(info[1]).FromJust();
  }

  if (partition < 0) {
    partition = RdKafka::Topic::PARTITION_UA;
  }

  size_t message_buffer_length;
  void* message_buffer_data;

  if (info[2]->IsNull()) {
    // This is okay for whatever reason
    message_buffer_length = 0;
    message_buffer_data = NULL;
  } else if (!node::Buffer::HasInstance(info[2])) {
    return Nan::ThrowError("Message must be a buffer or null");
  } else {
    v8::Local<v8::Object> message_buffer_object = info[2]->ToObject();

    // v8 handles the garbage collection here so we need to make a copy of
    // the buffer or assign the buffer to a persistent handle.

    // I'm not sure which would be the more performant option. I assume
    // the persistent handle would be but for now we'll try this one
    // which should be more memory-efficient and allow v8 to dispose of the
    // buffer sooner

    message_buffer_length = node::Buffer::Length(message_buffer_object);
    message_buffer_data = node::Buffer::Data(message_buffer_object);
  }

  // Last we have to get the key
  std::string * key;

  if (info[3]->IsNull() || info[3]->IsUndefined()) {
    key = NULL;
  } else {
    v8::Local<v8::String> val = info[3]->ToString();
    // Get string pointer for this thing
    Nan::Utf8String keyUTF8(val);
    key = new std::string(*keyUTF8);
  }

  Producer* producer = ObjectWrap::Unwrap<Producer>(info.This());

  Baton b = producer->Produce(message_buffer_data, message_buffer_length,
    topic->toRDKafkaTopic(), partition, key);

  // we can delete the key as librdkafka will take a copy of the message
  if (key) {
    delete key;
  }

  // Let the JS library throw if we need to so the error can be more rich
  int error_code = static_cast<int>(b.err());

  info.GetReturnValue().Set(Nan::New<v8::Number>(error_code));
}

NAN_METHOD(Producer::NodeOnDelivery) {
  Nan::HandleScope scope;

  if (info.Length() < 1 || !info[0]->IsFunction()) {
    // Just throw an exception
    return Nan::ThrowError("Need to specify a callback");
  }

  Producer* producer = ObjectWrap::Unwrap<Producer>(info.This());
  v8::Local<v8::Function> cb = info[0].As<v8::Function>();

  producer->m_dr_cb.dispatcher.AddCallback(cb);
  info.GetReturnValue().Set(Nan::True());
}

NAN_METHOD(Producer::NodeSetPartitioner) {
  Nan::HandleScope scope;

  if (info.Length() < 1 || !info[0]->IsFunction()) {
    // Just throw an exception
    return Nan::ThrowError("Need to specify a callback");
  }

  Producer* producer = ObjectWrap::Unwrap<Producer>(info.This());
  v8::Local<v8::Function> cb = info[0].As<v8::Function>();
  producer->m_partitioner_cb.SetCallback(cb);
  info.GetReturnValue().Set(Nan::True());
}

NAN_METHOD(Producer::NodeConnect) {
  Nan::HandleScope scope;

  if (info.Length() < 1 || !info[0]->IsFunction()) {
    // Just throw an exception
    return Nan::ThrowError("Need to specify a callback");
  }

  // This needs to be offloaded to libuv
  v8::Local<v8::Function> cb = info[0].As<v8::Function>();
  Nan::Callback *callback = new Nan::Callback(cb);

  Producer* producer = ObjectWrap::Unwrap<Producer>(info.This());
  Nan::AsyncQueueWorker(new Workers::ProducerConnect(callback, producer));

  info.GetReturnValue().Set(Nan::Null());
}

NAN_METHOD(Producer::NodePoll) {
  Nan::HandleScope scope;

  Producer* producer = ObjectWrap::Unwrap<Producer>(info.This());

  if (!producer->IsConnected()) {
    Nan::ThrowError("Producer is disconnected");
  } else {
    producer->Poll();
    info.GetReturnValue().Set(Nan::True());
  }
}

#if RD_KAFKA_VERSION > 0x00090200
Baton Producer::Flush(int timeout_ms) {
  RdKafka::ErrorCode response_code;
  if (IsConnected()) {
    scoped_mutex_lock lock(m_connection_lock);
    if (IsConnected()) {
      RdKafka::Producer* producer = dynamic_cast<RdKafka::Producer*>(m_client);
      response_code = producer->flush(timeout_ms);
    } else {
      response_code = RdKafka::ERR__STATE;
    }
  } else {
    response_code = RdKafka::ERR__STATE;
  }

  return Baton(response_code);
}

NAN_METHOD(Producer::NodeFlush) {
  Nan::HandleScope scope;

  if (info.Length() < 1 || !info[0]->IsFunction()) {
    // Just throw an exception
    return Nan::ThrowError("Need to specify a callback");
  }

  int timeout_ms;

  if (info[0]->IsNull() || info[0]->IsUndefined()) {
    timeout_ms = 1000;
  } else {
    timeout_ms = Nan::To<int>(info[0]).FromJust();
  }

  Producer* producer = ObjectWrap::Unwrap<Producer>(info.This());

  if (!producer->IsConnected()) {
    Nan::ThrowError("Producer is disconnected");
  } else {
    Baton b = producer->Flush(timeout_ms);
    if (b.err() != RdKafka::ErrorCode::ERR_NO_ERROR) {
      return Nan::ThrowError(b.errstr().c_str());
    }
    info.GetReturnValue().Set(Nan::True());
  }
}
#endif

NAN_METHOD(Producer::NodeDisconnect) {
  Nan::HandleScope scope;

  if (info.Length() < 1 || !info[0]->IsFunction()) {
    // Just throw an exception
    return Nan::ThrowError("Need to specify a callback");
  }

  v8::Local<v8::Function> cb = info[0].As<v8::Function>();
  Nan::Callback *callback = new Nan::Callback(cb);

  Producer* producer = ObjectWrap::Unwrap<Producer>(info.This());
  Nan::AsyncQueueWorker(new Workers::ProducerDisconnect(callback, producer));

  info.GetReturnValue().Set(Nan::Null());
}

}  // namespace NodeKafka
<|endoftext|>