<commit_before>/// (c) Koheron

#include "base.hpp"

Base::Base(Klib::DevMem& dev_mem_)
: dev_mem(dev_mem_),
  xadc(dev_mem_),
  gpio(dev_mem_)
{
    dac_wfm_size = 0;
    status = CLOSED;
}

Base::~Base()
{
    Close();
}

# define MAP_SIZE 4096

int Base::Open(uint32_t dac_wfm_size_)
{
    // Reopening
    if(status == OPENED && dac_wfm_size_ != dac_wfm_size) {
        Close();
    }

    if(status == CLOSED) {
        dac_wfm_size = dac_wfm_size_;

        // Initializes memory maps
        config_map = dev_mem.AddMemoryMap(CONFIG_ADDR, MAP_SIZE);

        if(static_cast<int>(config_map) < 0) {
            status = FAILED;
            return -1;
        }

        status_map = dev_mem.AddMemoryMap(STATUS_ADDR, MAP_SIZE);

        if(static_cast<int>(status_map) < 0) {
            status = FAILED;
            return -1;
        }

        dac_map = dev_mem.AddMemoryMap(DAC_ADDR, dac_wfm_size*MAP_SIZE/1024);

        if(static_cast<int>(dac_map) < 0) {
            status = FAILED;
            return -1;
        }

        // Open core drivers
        xadc.Open();
        gpio.Open();

        status = OPENED;
        reset();
    }

    return 0;
}

void Base::Close()
{
    if(status == OPENED) {
        reset();

        dev_mem.RmMemoryMap(config_map);
        dev_mem.RmMemoryMap(status_map);
        dev_mem.RmMemoryMap(dac_map);

        xadc.Close();
        gpio.Close();

        status = CLOSED;
    }
}

void Base::reset()
{
    assert(status == OPENED);

    // XADC
    xadc.set_channel(LASER_POWER_CHANNEL, LASER_CURRENT_CHANNEL);
    xadc.enable_averaging();
    xadc.set_averaging(256);

    // GPIO
    gpio.set_as_output(7, 2);

    // Config
    //Klib::ClearBit(dev_mem.GetBaseAddr(config_map) + ADDR_OFF, 0);
    Klib::ClearBit(dev_mem.GetBaseAddr(config_map) + ADDR_OFF, 1);
    Klib::SetBit(dev_mem.GetBaseAddr(config_map) + ADDR_OFF, 0);

    stop_laser();
    set_laser_current(0.0);
}

uint32_t Base::get_laser_current()
{
    return xadc.read(LASER_CURRENT_CHANNEL);
}

uint32_t Base::get_laser_power()
{
    return xadc.read(LASER_POWER_CHANNEL);
}

std::tuple<uint32_t, uint32_t> Base::get_monitoring()
{
    return std::make_tuple(get_laser_current(), get_laser_power());
}

void Base::start_laser()
{
    gpio.clear_bit(7, 2); // Laser enable on pin DIO7_P
}

void Base::stop_laser()
{
    gpio.set_bit(7, 2); // Laser enable on pin DIO7_P
}

#define GAIN_LT1789 (1+200/10)
#define PWM_MAX_VOLTAGE 1.8
#define PWM_MAX_VALUE 1024
#define MILLIAMPS_TO_AMPS 0.001
#define CURRENT_TO_VOLTAGE(current) \
    (current * MILLIAMPS_TO_AMPS * PWM_MAX_VALUE * GAIN_LT1789 / PWM_MAX_VOLTAGE)

void Base::set_laser_current(float current)
{
    float current_;
    current > MAX_LASER_CURRENT ? current_ = MAX_LASER_CURRENT : current_ = current;
    uint32_t voltage = (uint32_t) CURRENT_TO_VOLTAGE(current_);
    Klib::WriteReg32(dev_mem.GetBaseAddr(config_map) + PWM3_OFF, voltage);
}

void Base::set_dac_buffer(const uint32_t *data, uint32_t len)
{
    for (uint32_t i=0; i<len; i++)
        Klib::WriteReg32(dev_mem.GetBaseAddr(dac_map)+sizeof(uint32_t)*i, data[i]);
}

uint32_t Base::get_bitstream_id()
{
    return Klib::ReadReg32(dev_mem.GetBaseAddr(config_map) + BITSTREAM_ID_OFF);
}

void Base::set_led(uint32_t value)
{
    Klib::WriteReg32(dev_mem.GetBaseAddr(config_map) + LEDS_OFF, value);
}

void Base::reset_acquisition()
{
    Klib::ClearBit(dev_mem.GetBaseAddr(config_map) + ADDR_OFF, 1);
    Klib::SetBit(dev_mem.GetBaseAddr(config_map) + ADDR_OFF, 1);
}
<commit_msg>update middleware<commit_after>/// (c) Koheron

#include "base.hpp"

Base::Base(Klib::DevMem& dev_mem_)
: dev_mem(dev_mem_),
  xadc(dev_mem_),
  gpio(dev_mem_)
{
    dac_wfm_size = 0;
    status = CLOSED;
}

Base::~Base()
{
    Close();
}

# define MAP_SIZE 4096

# define LASER_ENABLE_PIN 4

int Base::Open(uint32_t dac_wfm_size_)
{
    // Reopening
    if(status == OPENED && dac_wfm_size_ != dac_wfm_size) {
        Close();
    }

    if(status == CLOSED) {
        dac_wfm_size = dac_wfm_size_;

        // Initializes memory maps
        config_map = dev_mem.AddMemoryMap(CONFIG_ADDR, MAP_SIZE);

        if(static_cast<int>(config_map) < 0) {
            status = FAILED;
            return -1;
        }

        status_map = dev_mem.AddMemoryMap(STATUS_ADDR, MAP_SIZE);

        if(static_cast<int>(status_map) < 0) {
            status = FAILED;
            return -1;
        }

        dac_map = dev_mem.AddMemoryMap(DAC_ADDR, dac_wfm_size*MAP_SIZE/1024);

        if(static_cast<int>(dac_map) < 0) {
            status = FAILED;
            return -1;
        }

        // Open core drivers
        xadc.Open();
        gpio.Open();

        status = OPENED;
        reset();
    }

    return 0;
}

void Base::Close()
{
    if(status == OPENED) {
        reset();

        dev_mem.RmMemoryMap(config_map);
        dev_mem.RmMemoryMap(status_map);
        dev_mem.RmMemoryMap(dac_map);

        xadc.Close();
        gpio.Close();

        status = CLOSED;
    }
}

void Base::reset()
{
    assert(status == OPENED);

    // XADC
    xadc.set_channel(LASER_POWER_CHANNEL, LASER_CURRENT_CHANNEL);
    xadc.enable_averaging();
    xadc.set_averaging(256);

    // GPIO
    gpio.set_as_output(LASER_ENABLE_PIN, 2);

    // Config
    //Klib::ClearBit(dev_mem.GetBaseAddr(config_map) + ADDR_OFF, 0);
    Klib::ClearBit(dev_mem.GetBaseAddr(config_map) + ADDR_OFF, 1);
    Klib::SetBit(dev_mem.GetBaseAddr(config_map) + ADDR_OFF, 0);

    stop_laser();
    set_laser_current(0.0);
}

uint32_t Base::get_laser_current()
{
    return xadc.read(LASER_CURRENT_CHANNEL);
}

uint32_t Base::get_laser_power()
{
    return xadc.read(LASER_POWER_CHANNEL);
}

std::tuple<uint32_t, uint32_t> Base::get_monitoring()
{
    return std::make_tuple(get_laser_current(), get_laser_power());
}

void Base::start_laser()
{
    gpio.clear_bit(LASER_ENABLE_PIN, 2); // Laser enable on pin DIO7_P
}

void Base::stop_laser()
{
    gpio.set_bit(LASER_ENABLE_PIN, 2); // Laser enable on pin DIO7_P
}

#define GAIN_LT1789 (1+200/10)
#define PWM_MAX_VOLTAGE 1.8
#define PWM_MAX_VALUE 1024
#define MILLIAMPS_TO_AMPS 0.001
#define CURRENT_TO_VOLTAGE(current) \
    (current * MILLIAMPS_TO_AMPS * PWM_MAX_VALUE * GAIN_LT1789 / PWM_MAX_VOLTAGE)

void Base::set_laser_current(float current)
{
    float current_;
    current > MAX_LASER_CURRENT ? current_ = MAX_LASER_CURRENT : current_ = current;
    uint32_t voltage = (uint32_t) CURRENT_TO_VOLTAGE(current_);
    Klib::WriteReg32(dev_mem.GetBaseAddr(config_map) + PWM3_OFF, voltage);
}

void Base::set_dac_buffer(const uint32_t *data, uint32_t len)
{
    for (uint32_t i=0; i<len; i++)
        Klib::WriteReg32(dev_mem.GetBaseAddr(dac_map)+sizeof(uint32_t)*i, data[i]);
}

uint32_t Base::get_bitstream_id()
{
    return Klib::ReadReg32(dev_mem.GetBaseAddr(config_map) + BITSTREAM_ID_OFF);
}

void Base::set_led(uint32_t value)
{
    Klib::WriteReg32(dev_mem.GetBaseAddr(config_map) + LEDS_OFF, value);
}

void Base::reset_acquisition()
{
    Klib::ClearBit(dev_mem.GetBaseAddr(config_map) + ADDR_OFF, 1);
    Klib::SetBit(dev_mem.GetBaseAddr(config_map) + ADDR_OFF, 1);
}
<|endoftext|>


<commit_before>//
// Copyright (c) 2008-2014 the Urho3D project.
//
// 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 "Precompiled.h"
#include "Log.h"
#include "LuaFunction.h"
#include "LuaScript.h"
#include "LuaScriptInstance.h"
#include "VectorBuffer.h"

extern "C"
{
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
}
#include "tolua++.h"
#include "ToluaUtils.h"

#include "DebugNew.h"

namespace Urho3D
{

LuaFunction::LuaFunction(lua_State* luaState, int functionRef) :
    luaState_(luaState),
    functionRef_(functionRef)
{
}

LuaFunction::~LuaFunction()
{
    if (functionRef_ != LUA_REFNIL)
        luaL_unref(luaState_, LUA_REGISTRYINDEX, functionRef_);
}

bool LuaFunction::IsValid() const
{
    return functionRef_ != LUA_REFNIL;
}

bool LuaFunction::BeginCall()
{
    if (!IsValid())
        return false;

    stackTop_ = lua_gettop(luaState_);
    numArguments_ = 0;
    lua_rawgeti(luaState_, LUA_REGISTRYINDEX, functionRef_);

    return true;
}

bool LuaFunction::BeginCall(const LuaScriptInstance* instance)
{
    if (!IsValid())
        return false;

    stackTop_ = lua_gettop(luaState_);
    numArguments_ = 1;
    lua_rawgeti(luaState_, LUA_REGISTRYINDEX, functionRef_);
    lua_rawgeti(luaState_, LUA_REGISTRYINDEX, instance->GetScriptObjectRef());

    return true;
}

bool LuaFunction::EndCall(int numReturns)
{
    if (lua_pcall(luaState_, numArguments_, numReturns, 0) != 0)
    {
        const char* message = lua_tostring(luaState_, -1);
        LOGERROR("Execute Lua function failed: " + String(message));
        lua_settop(luaState_, stackTop_);
        return false;
    }

    return true;
}

void LuaFunction::PushInt(int value)
{
    ++numArguments_;

    lua_pushinteger(luaState_, value);
}

void LuaFunction::PushBool(bool value)
{
    ++numArguments_;

    lua_pushboolean(luaState_, value);
}

void LuaFunction::PushFloat(float value)
{
    ++numArguments_;

    lua_pushnumber(luaState_, value);
}

void LuaFunction::PushString(const String& string)
{
    ++numArguments_;

    tolua_pushurho3dstring(luaState_, string);
}

void LuaFunction::PushUserType(void* userType, const char* typeName)
{
    ++numArguments_;

    tolua_pushusertype(luaState_, userType, typeName);
}

bool LuaFunction::PushVariant(const Variant& variant)
{
    switch (variant.GetType())
    {
    case VAR_INT:
        PushInt(variant.GetInt());
        return true;

    case VAR_BOOL:
        PushBool(variant.GetBool());
        return true;

    case VAR_FLOAT:
        PushFloat(variant.GetFloat());
        return true;

    case VAR_VECTOR2:
        PushUserType(variant.GetVector2(), "Vector2");
        return true;

    case VAR_VECTOR3:
        PushUserType(variant.GetVector3(), "Vector3");
        return true;

    case VAR_VECTOR4:
        PushUserType(variant.GetVector4(), "Vector4");
        return true;

    case VAR_QUATERNION:
        PushUserType(variant.GetQuaternion(), "Quaternion");
        return true;

    case VAR_COLOR:
        PushUserType(variant.GetQuaternion(), "Color");
        return true;

    case VAR_STRING:
        PushString(variant.GetString());
        return true;

    case VAR_BUFFER:
        {
            VectorBuffer buffer(variant.GetBuffer());
            PushUserType(buffer, "VectorBuffer");
        }
        return true;

    case VAR_RESOURCEREF:
        PushUserType(variant.GetResourceRef(), "ResourceRef");
        return true;

    case VAR_INTRECT:
        PushUserType(variant.GetIntRect(), "IntRect");
        return true;

    case VAR_INTVECTOR2:
        PushUserType(variant.GetIntVector2(), "IntVector2");
        return true;
    }

    return false;
}

bool LuaFunction::PushLuaTable(const String& tableName)
{
    ++numArguments_;

    lua_getglobal(luaState_, tableName.CString());
    if (!lua_istable(luaState_, -1))
    {
        LOGERROR("Could not find lua table " + tableName);
        return false;
    }
    return true;
}

}
<commit_msg>Minor fixed.<commit_after>//
// Copyright (c) 2008-2014 the Urho3D project.
//
// 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 "Precompiled.h"
#include "Log.h"
#include "LuaFunction.h"
#include "LuaScript.h"
#include "LuaScriptInstance.h"
#include "VectorBuffer.h"

extern "C"
{
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
}
#include "tolua++.h"
#include "ToluaUtils.h"

#include "DebugNew.h"

namespace Urho3D
{

LuaFunction::LuaFunction(lua_State* luaState, int functionRef) :
    luaState_(luaState),
    functionRef_(functionRef)
{
}

LuaFunction::~LuaFunction()
{
    if (functionRef_ != LUA_REFNIL)
        luaL_unref(luaState_, LUA_REGISTRYINDEX, functionRef_);
}

bool LuaFunction::IsValid() const
{
    return functionRef_ != LUA_REFNIL;
}

bool LuaFunction::BeginCall()
{
    if (!IsValid())
        return false;

    stackTop_ = lua_gettop(luaState_);
    numArguments_ = 0;
    lua_rawgeti(luaState_, LUA_REGISTRYINDEX, functionRef_);

    return true;
}

bool LuaFunction::BeginCall(const LuaScriptInstance* instance)
{
    if (!IsValid())
        return false;

    stackTop_ = lua_gettop(luaState_);
    numArguments_ = 1;
    lua_rawgeti(luaState_, LUA_REGISTRYINDEX, functionRef_);
    lua_rawgeti(luaState_, LUA_REGISTRYINDEX, instance->GetScriptObjectRef());

    return true;
}

bool LuaFunction::EndCall(int numReturns)
{
    if (lua_pcall(luaState_, numArguments_, numReturns, 0) != 0)
    {
        const char* message = lua_tostring(luaState_, -1);
        LOGERROR("Execute Lua function failed: " + String(message));
        lua_settop(luaState_, stackTop_);
        return false;
    }

    return true;
}

void LuaFunction::PushInt(int value)
{
    ++numArguments_;

    lua_pushinteger(luaState_, value);
}

void LuaFunction::PushBool(bool value)
{
    ++numArguments_;

    lua_pushboolean(luaState_, value);
}

void LuaFunction::PushFloat(float value)
{
    ++numArguments_;

    lua_pushnumber(luaState_, value);
}

void LuaFunction::PushString(const String& string)
{
    ++numArguments_;

    tolua_pushurho3dstring(luaState_, string);
}

void LuaFunction::PushUserType(void* userType, const char* typeName)
{
    ++numArguments_;

    tolua_pushusertype(luaState_, userType, typeName);
}

bool LuaFunction::PushVariant(const Variant& variant)
{
    switch (variant.GetType())
    {
    case VAR_INT:
        PushInt(variant.GetInt());
        return true;

    case VAR_BOOL:
        PushBool(variant.GetBool());
        return true;

    case VAR_FLOAT:
        PushFloat(variant.GetFloat());
        return true;

    case VAR_VECTOR2:
        PushUserType(variant.GetVector2(), "Vector2");
        return true;

    case VAR_VECTOR3:
        PushUserType(variant.GetVector3(), "Vector3");
        return true;

    case VAR_VECTOR4:
        PushUserType(variant.GetVector4(), "Vector4");
        return true;

    case VAR_QUATERNION:
        PushUserType(variant.GetQuaternion(), "Quaternion");
        return true;

    case VAR_COLOR:
        PushUserType(variant.GetColor(), "Color");
        return true;

    case VAR_STRING:
        PushString(variant.GetString());
        return true;

    case VAR_BUFFER:
        {
            VectorBuffer buffer(variant.GetBuffer());
            PushUserType(buffer, "VectorBuffer");
        }
        return true;

    case VAR_RESOURCEREF:
        PushUserType(variant.GetResourceRef(), "ResourceRef");
        return true;

    case VAR_INTRECT:
        PushUserType(variant.GetIntRect(), "IntRect");
        return true;

    case VAR_INTVECTOR2:
        PushUserType(variant.GetIntVector2(), "IntVector2");
        return true;
    }

    return false;
}

bool LuaFunction::PushLuaTable(const String& tableName)
{
    ++numArguments_;

    lua_getglobal(luaState_, tableName.CString());
    if (!lua_istable(luaState_, -1))
    {
        LOGERROR("Could not find lua table " + tableName);
        return false;
    }
    return true;
}

}
<|endoftext|>


<commit_before>/*
 * GameKeeper Framework
 *
 * Copyright (C) 2013 Karol Herbst <gamekeeper@karolherbst.de>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "webserverfixture.h"

#include <forward_list>
#include <future>

#include <gamekeeper/core/threadfactory.h>

#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/lexical_cast.hpp>

#include <Hypodermic/IContainer.h>

#include <mongoose.h>

GAMEKEEPER_NAMESPACE_START(test)

namespace algo = boost::algorithm;
namespace fs = boost::filesystem;
using boost::lexical_cast;
using gamekeeper::core::ThreadFactory;

static const fs::path fileServerRoot = WEBSERVERPATH;

WebServerFictureAspect::WebServerFictureAspect(std::shared_ptr<Hypodermic::IContainer> container)
{
	this->server = mg_create_server(nullptr, [](mg_connection * conn, mg_event event) -> int
	{
		if(event == MG_REQUEST)
		{
			std::vector<std::string> splittedPaths;
			std::string uri = std::string(&conn->uri[1]);
			algo::split(splittedPaths, uri, algo::is_any_of("/"), algo::token_compress_on);

			if(splittedPaths[0] == "files")
			{
				splittedPaths.erase(splittedPaths.begin());
				fs::path fileResource = fileServerRoot;
				for(std::string path : splittedPaths)
				{
					fileResource /= path;
				}
				if(fs::exists(fileResource))
				{
					fs::ifstream fs(fileResource);
					mg_send_status(conn, 200);

					if(fs.peek() != std::ifstream::traits_type::eof())
					{
						char buffer[8192];
						while(fs)
						{
							fs.read(buffer, 8192);
							mg_send_data(conn, buffer, fs.gcount());
						}
					}
					mg_send_data(conn, nullptr, 0);
					return MG_TRUE;
				}
				mg_send_status(conn, 404);
				return MG_TRUE;
			}
			else if(splittedPaths[0] == "bigfile")
			{
				if(splittedPaths.size() < 2)
				{
					mg_send_status(conn, 404);
					return MG_TRUE;
				}
				uint64_t size = lexical_cast<uint64_t>(splittedPaths[1]);
				mg_send_status(conn, 200);
				uint64_t chunks = (size / 1024);
				char buffer[1024];
				for(uint64_t i = 0; i < chunks; i++)
				{
					mg_send_data(conn, buffer, 1024);
				}
				uint16_t rest = size - chunks * 1024;
				if(rest != 0)
				{
					mg_send_data(conn, buffer, rest);
				}
				mg_send_data(conn, nullptr, 0);
				return MG_TRUE;
			}
			else if(splittedPaths[0] == "cookies")
			{
				if(splittedPaths.size() < 3)
				{
					mg_send_status(conn, 404);
					return MG_TRUE;
				}
				mg_send_status(conn, 200);
				mg_send_header(conn, "Set-Cookie", (splittedPaths[1] + '=' + splittedPaths[2]).c_str());
				mg_send_data(conn, "", 1);
				return MG_TRUE;
			}
			return MG_TRUE;
		}
		else if(event == MG_POLL)
		{
			return MG_FALSE;
		}
		return MG_TRUE;
	});
	mg_set_option(this->server, "listening_port", "8080");
	container->resolve<ThreadFactory>()->createThread("mongoose server thread",
		[this](ThreadFactory::ThreadFunction::argument_type interrupted) -> void
	{
		mg_server * copyServer = this->server;
		while(!interrupted)
		{
			mg_poll_server(copyServer, 1000);
		}
		mg_destroy_server(&this->server);
	});
}

GAMEKEEPER_NAMESPACE_END(test)
<commit_msg>test/webserverfixture: throw exception when setting port fails<commit_after>/*
 * GameKeeper Framework
 *
 * Copyright (C) 2013 Karol Herbst <gamekeeper@karolherbst.de>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "webserverfixture.h"

#include <forward_list>
#include <future>

#include <gamekeeper/core/exception.h>
#include <gamekeeper/core/threadfactory.h>

#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/lexical_cast.hpp>

#include <Hypodermic/IContainer.h>

#include <mongoose.h>

GAMEKEEPER_NAMESPACE_START(test)

namespace algo = boost::algorithm;
namespace fs = boost::filesystem;
using boost::lexical_cast;
using gamekeeper::core::ThreadFactory;

static const fs::path fileServerRoot = WEBSERVERPATH;

WebServerFictureAspect::WebServerFictureAspect(std::shared_ptr<Hypodermic::IContainer> container)
{
	this->server = mg_create_server(nullptr, [](mg_connection * conn, mg_event event) -> int
	{
		if(event == MG_REQUEST)
		{
			std::vector<std::string> splittedPaths;
			std::string uri = std::string(&conn->uri[1]);
			algo::split(splittedPaths, uri, algo::is_any_of("/"), algo::token_compress_on);

			if(splittedPaths[0] == "files")
			{
				splittedPaths.erase(splittedPaths.begin());
				fs::path fileResource = fileServerRoot;
				for(std::string path : splittedPaths)
				{
					fileResource /= path;
				}
				if(fs::exists(fileResource))
				{
					fs::ifstream fs(fileResource);
					mg_send_status(conn, 200);

					if(fs.peek() != std::ifstream::traits_type::eof())
					{
						char buffer[8192];
						while(fs)
						{
							fs.read(buffer, 8192);
							mg_send_data(conn, buffer, fs.gcount());
						}
					}
					mg_send_data(conn, nullptr, 0);
					return MG_TRUE;
				}
				mg_send_status(conn, 404);
				return MG_TRUE;
			}
			else if(splittedPaths[0] == "bigfile")
			{
				if(splittedPaths.size() < 2)
				{
					mg_send_status(conn, 404);
					return MG_TRUE;
				}
				uint64_t size = lexical_cast<uint64_t>(splittedPaths[1]);
				mg_send_status(conn, 200);
				uint64_t chunks = (size / 1024);
				char buffer[1024];
				for(uint64_t i = 0; i < chunks; i++)
				{
					mg_send_data(conn, buffer, 1024);
				}
				uint16_t rest = size - chunks * 1024;
				if(rest != 0)
				{
					mg_send_data(conn, buffer, rest);
				}
				mg_send_data(conn, nullptr, 0);
				return MG_TRUE;
			}
			else if(splittedPaths[0] == "cookies")
			{
				if(splittedPaths.size() < 3)
				{
					mg_send_status(conn, 404);
					return MG_TRUE;
				}
				mg_send_status(conn, 200);
				mg_send_header(conn, "Set-Cookie", (splittedPaths[1] + '=' + splittedPaths[2]).c_str());
				mg_send_data(conn, "", 1);
				return MG_TRUE;
			}
			return MG_TRUE;
		}
		else if(event == MG_POLL)
		{
			return MG_FALSE;
		}
		return MG_TRUE;
	});
	const char * msg = mg_set_option(this->server, "listening_port", "8080");
	if(msg != nullptr)
	{
		throw core::GameKeeperMessageException(std::string("couldn't setup embedded webserver: ") + msg);
	}
	container->resolve<ThreadFactory>()->createThread("mongoose server thread",
		[this](ThreadFactory::ThreadFunction::argument_type interrupted) -> void
	{
		mg_server * copyServer = this->server;
		while(!interrupted)
		{
			mg_poll_server(copyServer, 1000);
		}
		mg_destroy_server(&this->server);
	});
}

GAMEKEEPER_NAMESPACE_END(test)
<|endoftext|>


<commit_before>//------------------------------------------------------------------------------
// Copyright (c) 2016 John D. Haughton
//
// 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  "STB/ConsoleApp.h"

#include  "PLT/TerminalPaper.h"
#include  "PLT/TerminalStdio.h"

#include  "ZifVersion.h"
#include  "ZLauncher.h"
#include  "ZOptions.h"

class Zif : public STB::ConsoleApp
{
private:
   STB::Option<const char*>  opt_config{ 'c', "config",
                                         "Use alternate config file (default is \"zif.cfg\")",
                                         "zif.cfg"};

#ifdef TERMINAL_EMULATOR
   enum Display
   {
      DISP_KINDLE3,
      DISP_VGA,
      DISP_SVGA,
      DISP_XGA
   };

#ifdef PROJ_TARGET_Kindle3
   Display display = DISP_KINDLE3;
#else
   Display display = DISP_SVGA;
#endif

   STB::Option<bool>         opt_term{   't', "term",
                                         "Use the parent terminal (not the built in terminal)"};

   STB::Option<bool>         opt_k3{     'K', "k3",     "Kindle display 800x600"};
   STB::Option<bool>         opt_vga{    'V', "vga",    "VGA display    640x480"};
   STB::Option<bool>         opt_svga{   'S', "svga",   "SVGA display   800x600"};
   STB::Option<bool>         opt_xga{    'X', "xga",    "XGA display   1024x768"};
#endif

   ZOptions                  zoptions;

   const char*               filename{nullptr};

   int launch(PLT::Device& term)
   {
      ZLauncher  launcher(term, opt_config, zoptions);

      return filename ? launcher.run(filename)
                      : launcher.menu();
   }

   template <unsigned WIDTH, unsigned HEIGHT>
   int launchDisplay()
   {
      PLT::TerminalPaper<WIDTH,HEIGHT>  term(PROGRAM);
      return launch(term);
   }

   virtual int start() override
   {
      if (argc == 2)
      {
          filename = argv[1];
      }

#ifdef TERMINAL_EMULATOR
      if (opt_term)
#endif
      {
         // Use the parent terminal
         PLT::TerminalStdio  term(PROGRAM);
         return launch(term);
      }
#ifdef TERMINAL_EMULATOR
      else
      {
         // Use the built in terminal

              if (opt_k3)   display = DISP_KINDLE3;
         else if (opt_vga)  display = DISP_VGA;
         else if (opt_svga) display = DISP_SVGA;
         else if (opt_xga)  display = DISP_XGA;

         switch(display)
         {
         case DISP_KINDLE3: return launchDisplay< 600,800>();
         case DISP_VGA:     return launchDisplay< 640,480>();
         case DISP_SVGA:    return launchDisplay< 800,600>();
         case DISP_XGA:     return launchDisplay<1024,768>();
         }

         assert(!"Display selection bug");
         return 1;
      }
#endif
   }

public:
   Zif(int argc_, const char* argv_[])
      : ConsoleApp(argc_, argv_,
                   PROGRAM, AUTHOR, DESCRIPTION, VERSION, COPYRIGHT_YEAR, LICENSE,
                   "[Z-file]")
   {
      parseArgsAndStart();
   }
};

int main(int argc, const char *argv[])
{
#if defined(PROJ_TARGET_Emscripten)
    // TODO this is just a confidence test
    const char* local_argv[] = {"zif", "-v"};
    Zif(2, local_argv);
#else
    Zif(argc, argv);
#endif
}

<commit_msg>-K option description edit<commit_after>//------------------------------------------------------------------------------
// Copyright (c) 2016 John D. Haughton
//
// 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  "STB/ConsoleApp.h"

#include  "PLT/TerminalPaper.h"
#include  "PLT/TerminalStdio.h"

#include  "ZifVersion.h"
#include  "ZLauncher.h"
#include  "ZOptions.h"

class Zif : public STB::ConsoleApp
{
private:
   STB::Option<const char*>  opt_config{ 'c', "config",
                                         "Use alternate config file (default is \"zif.cfg\")",
                                         "zif.cfg"};

#ifdef TERMINAL_EMULATOR
   enum Display
   {
      DISP_KINDLE3,
      DISP_VGA,
      DISP_SVGA,
      DISP_XGA
   };

#ifdef PROJ_TARGET_Kindle3
   Display display = DISP_KINDLE3;
#else
   Display display = DISP_SVGA;
#endif

   STB::Option<bool>         opt_term{   't', "term",
                                         "Use the parent terminal (not the built in terminal)"};

   STB::Option<bool>         opt_k3{     'K', "k3",     "Kindle display 600x800"};
   STB::Option<bool>         opt_vga{    'V', "vga",    "VGA display    640x480"};
   STB::Option<bool>         opt_svga{   'S', "svga",   "SVGA display   800x600"};
   STB::Option<bool>         opt_xga{    'X', "xga",    "XGA display   1024x768"};
#endif

   ZOptions                  zoptions;

   const char*               filename{nullptr};

   int launch(PLT::Device& term)
   {
      ZLauncher  launcher(term, opt_config, zoptions);

      return filename ? launcher.run(filename)
                      : launcher.menu();
   }

   template <unsigned WIDTH, unsigned HEIGHT>
   int launchDisplay()
   {
      PLT::TerminalPaper<WIDTH,HEIGHT>  term(PROGRAM);
      return launch(term);
   }

   virtual int start() override
   {
      if (argc == 2)
      {
          filename = argv[1];
      }

#ifdef TERMINAL_EMULATOR
      if (opt_term)
#endif
      {
         // Use the parent terminal
         PLT::TerminalStdio  term(PROGRAM);
         return launch(term);
      }
#ifdef TERMINAL_EMULATOR
      else
      {
         // Use the built in terminal

              if (opt_k3)   display = DISP_KINDLE3;
         else if (opt_vga)  display = DISP_VGA;
         else if (opt_svga) display = DISP_SVGA;
         else if (opt_xga)  display = DISP_XGA;

         switch(display)
         {
         case DISP_KINDLE3: return launchDisplay< 600,800>();
         case DISP_VGA:     return launchDisplay< 640,480>();
         case DISP_SVGA:    return launchDisplay< 800,600>();
         case DISP_XGA:     return launchDisplay<1024,768>();
         }

         assert(!"Display selection bug");
         return 1;
      }
#endif
   }

public:
   Zif(int argc_, const char* argv_[])
      : ConsoleApp(argc_, argv_,
                   PROGRAM, AUTHOR, DESCRIPTION, VERSION, COPYRIGHT_YEAR, LICENSE,
                   "[Z-file]")
   {
      parseArgsAndStart();
   }
};

int main(int argc, const char *argv[])
{
#if defined(PROJ_TARGET_Emscripten)
    // TODO this is just a confidence test
    const char* local_argv[] = {"zif", "-v"};
    Zif(2, local_argv);
#else
    Zif(argc, argv);
#endif
}

<|endoftext|>


<commit_before>#include "catch.hpp"

#include <utility>
#include <type_traits>
#include <iterator>
#include <algorithm>

#include <member_iterator.hpp>

#include <forward_list>

TEST_CASE("member_iterator based on ForwardIterator", "[member_iterator]")
{
    struct mock
    {
        char c;
        int i;
    };

    std::forward_list<mock> mocklist{{'a', 1}, {'b', 2}, {'c', 3}};

    typedef helene::
        member_iterator<int, mock, std::forward_list<mock>::iterator, &mock::i>
            mocklist_iterator_type;

    mocklist_iterator_type beg_it = mocklist.begin();
    mocklist_iterator_type end_it = mocklist.end();

    ////////////////////////////////////////////////////////////////////////////
    // Iterator concept
    SECTION("construction")
    {
        auto elem = *beg_it;
        mocklist_iterator_type cop_it = beg_it;
        mocklist_iterator_type mov_it = std::move(beg_it);

        REQUIRE(*mov_it == elem);
        REQUIRE(cop_it == mov_it);
    }

    SECTION("assignment")
    {
        mocklist_iterator_type cop_it = beg_it;
        cop_it = end_it;

        REQUIRE(cop_it == end_it);
    }

    SECTION("move assignment")
    {
        mocklist_iterator_type an_it = beg_it;
        mocklist_iterator_type another_it = end_it;

        another_it = std::move(an_it);

        REQUIRE(another_it == beg_it);
        REQUIRE(*another_it == *beg_it);
    }

    SECTION("swappable")
    {
        using std::swap;

        mocklist_iterator_type beg_it2 = beg_it;
        mocklist_iterator_type end_it2 = end_it;

        swap(beg_it2, end_it2);

        REQUIRE(beg_it2 == end_it);
        REQUIRE(end_it2 == beg_it);
    }

    SECTION("traits")
    {
        std::iterator_traits<mocklist_iterator_type>::value_type i = 20;
        std::iterator_traits<mocklist_iterator_type>::difference_type j = -2;
        std::iterator_traits<mocklist_iterator_type>::reference k = i;
        std::iterator_traits<mocklist_iterator_type>::pointer l = &i;

        bool is_forward_iterator = std::is_same<
            std::iterator_traits<mocklist_iterator_type>::iterator_category,
            std::forward_iterator_tag>::value;

        REQUIRE(is_forward_iterator == true);
    }

    SECTION("dereference")
    {
        auto is_reference = std::is_same<decltype(*beg_it), int&>::value;

        REQUIRE(is_reference == true);
        REQUIRE(*beg_it == 1);
    }

    SECTION("preincrement")
    {
        auto ref_it = ++beg_it;

        bool is_iterator_reference =
            std::is_same<decltype(++beg_it), mocklist_iterator_type&>::value;

        REQUIRE(ref_it == beg_it);
        REQUIRE(*beg_it == 2);
        REQUIRE(is_iterator_reference == true);
    }

    SECTION("EqualityComparable")
    {
        bool equal = beg_it == end_it;

        REQUIRE(equal == false);
        REQUIRE(beg_it == mocklist.begin());
    }

    ////////////////////////////////////////////////////////////////////////////
    // InputIterator
    SECTION("!=")
    {
        bool not_equal = beg_it != mocklist.begin();

        REQUIRE(beg_it != end_it);
        REQUIRE(not_equal == false);
    }

    SECTION("postincrement")
    {
        bool is_conv_to_const_ref =
            std::is_convertible<decltype(beg_it++),
                                const mocklist_iterator_type&>::value;

        (void)beg_it++;

        REQUIRE(is_conv_to_const_ref == true);
        REQUIRE(*beg_it == 2);
    }

    SECTION("postincrement and dereference")
    {
        bool is_conv_to_value_type =
            std::is_convertible<decltype(*beg_it++), int>::value;

        auto val = *beg_it++;

        REQUIRE(is_conv_to_value_type == true);
        REQUIRE(val == 1);
        REQUIRE(*beg_it == 2);
    }

    ////////////////////////////////////////////////////////////////////////////
    // OutputIterator
    SECTION("assignment through iterator")
    {
        *beg_it = 10;

        REQUIRE(*beg_it == 10);
        REQUIRE(mocklist.front().i == 10);
        REQUIRE(mocklist.front().c == 'a');
    }

    ////////////////////////////////////////////////////////////////////////////
    // ForwardIterator
    SECTION("DefaultConstructible")
    {
        mocklist_iterator_type it;
        mocklist_iterator_type it2{};
        mocklist_iterator_type();
        mocklist_iterator_type{};
    }

    SECTION("multipass guarantee")
    {
        auto beg_it_copy = beg_it;
        ++beg_it;
        ++beg_it;

        auto val0 = *beg_it_copy++;
        auto val1 = *beg_it_copy++;
        auto val2 = *beg_it_copy;

        REQUIRE(val0 == 1);
        REQUIRE(val1 == 2);
        REQUIRE(val2 == 3);
    }

    ////////////////////////////////////////////////////////////////////////////
    // Test std algorithms
    SECTION("std::equal")
    {
        std::forward_list<mock> mocklist_copy = mocklist;

        mocklist_iterator_type beg_it_copy(mocklist_copy.begin());

        REQUIRE(std::equal(beg_it, end_it, beg_it_copy) == true);
    }

    SECTION("std::find")
    {
        auto found = std::find(beg_it, end_it, 2);

        REQUIRE(found != end_it);
    }

    SECTION("std::for_each")
    {
        int sum = 0;

        std::for_each(beg_it, end_it, [&sum](int i) { sum += i; });

        REQUIRE(sum == 6);
    }

    SECTION("std::search") // requires ForwardIterator
    {
        std::vector<int> subsequence;
        subsequence.push_back(2);
        subsequence.push_back(3);

        auto found =
            std::search(beg_it, end_it, subsequence.begin(), subsequence.end());

        REQUIRE(found != end_it);
    }

    SECTION("std::remove") // requires ForwardIterator
    {
        auto past_end = std::remove(beg_it, end_it, 2);
        auto native_iter = mocklist.begin();

        REQUIRE(*beg_it == 1);
        REQUIRE(native_iter->i == 1);
        REQUIRE(native_iter->c == 'a');

        SECTION("increment to second element")
        {
            ++beg_it;
            ++native_iter;

            REQUIRE(*beg_it == 3);
            REQUIRE(native_iter->i == 3);
            REQUIRE(native_iter->c == 'b');
        }
    }
}

TEST_CASE("member_iterator based on std::vector::iterator", "[member_iterator]")
{
    struct payload
    {
        int i;
        int
        get_i() const
        {
            return i;
        }

        bool
        operator==(const payload& other) const
        {
            return i == other.i;
        }
    };

    struct mock
    {
        double weight;
        payload value;
    };

    typedef helene::member_iterator<payload,
                                    mock,
                                    std::vector<mock>::iterator,
                                    &mock::value>
        mockveck_iterator_type;

    std::vector<mock> mockvec{{0.3, {1}}, {0.4, {2}}, {0.3, {3}}};

    mockveck_iterator_type beg_it(mockvec.begin());
    mockveck_iterator_type end_it(mockvec.end());

    SECTION("category should be random_access_iterator_tag")
    {
        bool is_rai = std::is_same<
            std::iterator_traits<mockveck_iterator_type>::iterator_category,
            std::random_access_iterator_tag>::value;

        REQUIRE(is_rai == true);
    }

    ////////////////////////////////////////////////////////////////////////////
    // BidirectionalIterator

    SECTION("predecrement")
    {
        --end_it;

        REQUIRE(end_it->i == 3);
        REQUIRE(end_it->get_i() == 3);
    }

    SECTION("postdecrement")
    {
        end_it--;

        REQUIRE(end_it->i == 3);
        REQUIRE(end_it->get_i() == 3);
    }

    SECTION("postdecrement and dereference statement")
    {
        ++beg_it;

        auto old = *beg_it--;
        REQUIRE(old.i == 2);
        REQUIRE(beg_it->i == 1);
    }

    ////////////////////////////////////////////////////////////////////////////
    // RandomAccesIterator

    SECTION("+=")
    {
        bool is_iter_ref =
            std::is_same<decltype(beg_it += 2), mockveck_iterator_type&>::value;

        beg_it += 2;

        REQUIRE(is_iter_ref == true);

        REQUIRE(beg_it->i == 3);
    }

    SECTION("adding number")
    {
        bool is_iter_type =
            std::is_same<decltype(beg_it + 2), mockveck_iterator_type>::value;
        bool is_iter_type2 =
            std::is_same<decltype(2 + beg_it), mockveck_iterator_type>::value;

        auto res1 = beg_it + 2;
        auto res2 = 2 + beg_it;

        REQUIRE(is_iter_type == true);
        REQUIRE(is_iter_type2 == true);

        REQUIRE(res1 == res2);
        REQUIRE(res1->i == 3);
        REQUIRE(res2->i == 3);
    }
}
<commit_msg>Add test for -=. 	modified:   tests/test_member_iterator2.cpp<commit_after>#include "catch.hpp"

#include <utility>
#include <type_traits>
#include <iterator>
#include <algorithm>

#include <member_iterator.hpp>

#include <forward_list>

TEST_CASE("member_iterator based on ForwardIterator", "[member_iterator]")
{
    struct mock
    {
        char c;
        int i;
    };

    std::forward_list<mock> mocklist{{'a', 1}, {'b', 2}, {'c', 3}};

    typedef helene::
        member_iterator<int, mock, std::forward_list<mock>::iterator, &mock::i>
            mocklist_iterator_type;

    mocklist_iterator_type beg_it = mocklist.begin();
    mocklist_iterator_type end_it = mocklist.end();

    ////////////////////////////////////////////////////////////////////////////
    // Iterator concept
    SECTION("construction")
    {
        auto elem = *beg_it;
        mocklist_iterator_type cop_it = beg_it;
        mocklist_iterator_type mov_it = std::move(beg_it);

        REQUIRE(*mov_it == elem);
        REQUIRE(cop_it == mov_it);
    }

    SECTION("assignment")
    {
        mocklist_iterator_type cop_it = beg_it;
        cop_it = end_it;

        REQUIRE(cop_it == end_it);
    }

    SECTION("move assignment")
    {
        mocklist_iterator_type an_it = beg_it;
        mocklist_iterator_type another_it = end_it;

        another_it = std::move(an_it);

        REQUIRE(another_it == beg_it);
        REQUIRE(*another_it == *beg_it);
    }

    SECTION("swappable")
    {
        using std::swap;

        mocklist_iterator_type beg_it2 = beg_it;
        mocklist_iterator_type end_it2 = end_it;

        swap(beg_it2, end_it2);

        REQUIRE(beg_it2 == end_it);
        REQUIRE(end_it2 == beg_it);
    }

    SECTION("traits")
    {
        std::iterator_traits<mocklist_iterator_type>::value_type i = 20;
        std::iterator_traits<mocklist_iterator_type>::difference_type j = -2;
        std::iterator_traits<mocklist_iterator_type>::reference k = i;
        std::iterator_traits<mocklist_iterator_type>::pointer l = &i;

        bool is_forward_iterator = std::is_same<
            std::iterator_traits<mocklist_iterator_type>::iterator_category,
            std::forward_iterator_tag>::value;

        REQUIRE(is_forward_iterator == true);
    }

    SECTION("dereference")
    {
        auto is_reference = std::is_same<decltype(*beg_it), int&>::value;

        REQUIRE(is_reference == true);
        REQUIRE(*beg_it == 1);
    }

    SECTION("preincrement")
    {
        auto ref_it = ++beg_it;

        bool is_iterator_reference =
            std::is_same<decltype(++beg_it), mocklist_iterator_type&>::value;

        REQUIRE(ref_it == beg_it);
        REQUIRE(*beg_it == 2);
        REQUIRE(is_iterator_reference == true);
    }

    SECTION("EqualityComparable")
    {
        bool equal = beg_it == end_it;

        REQUIRE(equal == false);
        REQUIRE(beg_it == mocklist.begin());
    }

    ////////////////////////////////////////////////////////////////////////////
    // InputIterator
    SECTION("!=")
    {
        bool not_equal = beg_it != mocklist.begin();

        REQUIRE(beg_it != end_it);
        REQUIRE(not_equal == false);
    }

    SECTION("postincrement")
    {
        bool is_conv_to_const_ref =
            std::is_convertible<decltype(beg_it++),
                                const mocklist_iterator_type&>::value;

        (void)beg_it++;

        REQUIRE(is_conv_to_const_ref == true);
        REQUIRE(*beg_it == 2);
    }

    SECTION("postincrement and dereference")
    {
        bool is_conv_to_value_type =
            std::is_convertible<decltype(*beg_it++), int>::value;

        auto val = *beg_it++;

        REQUIRE(is_conv_to_value_type == true);
        REQUIRE(val == 1);
        REQUIRE(*beg_it == 2);
    }

    ////////////////////////////////////////////////////////////////////////////
    // OutputIterator
    SECTION("assignment through iterator")
    {
        *beg_it = 10;

        REQUIRE(*beg_it == 10);
        REQUIRE(mocklist.front().i == 10);
        REQUIRE(mocklist.front().c == 'a');
    }

    ////////////////////////////////////////////////////////////////////////////
    // ForwardIterator
    SECTION("DefaultConstructible")
    {
        mocklist_iterator_type it;
        mocklist_iterator_type it2{};
        mocklist_iterator_type();
        mocklist_iterator_type{};
    }

    SECTION("multipass guarantee")
    {
        auto beg_it_copy = beg_it;
        ++beg_it;
        ++beg_it;

        auto val0 = *beg_it_copy++;
        auto val1 = *beg_it_copy++;
        auto val2 = *beg_it_copy;

        REQUIRE(val0 == 1);
        REQUIRE(val1 == 2);
        REQUIRE(val2 == 3);
    }

    ////////////////////////////////////////////////////////////////////////////
    // Test std algorithms
    SECTION("std::equal")
    {
        std::forward_list<mock> mocklist_copy = mocklist;

        mocklist_iterator_type beg_it_copy(mocklist_copy.begin());

        REQUIRE(std::equal(beg_it, end_it, beg_it_copy) == true);
    }

    SECTION("std::find")
    {
        auto found = std::find(beg_it, end_it, 2);

        REQUIRE(found != end_it);
    }

    SECTION("std::for_each")
    {
        int sum = 0;

        std::for_each(beg_it, end_it, [&sum](int i) { sum += i; });

        REQUIRE(sum == 6);
    }

    SECTION("std::search") // requires ForwardIterator
    {
        std::vector<int> subsequence;
        subsequence.push_back(2);
        subsequence.push_back(3);

        auto found =
            std::search(beg_it, end_it, subsequence.begin(), subsequence.end());

        REQUIRE(found != end_it);
    }

    SECTION("std::remove") // requires ForwardIterator
    {
        auto past_end = std::remove(beg_it, end_it, 2);
        auto native_iter = mocklist.begin();

        REQUIRE(*beg_it == 1);
        REQUIRE(native_iter->i == 1);
        REQUIRE(native_iter->c == 'a');

        SECTION("increment to second element")
        {
            ++beg_it;
            ++native_iter;

            REQUIRE(*beg_it == 3);
            REQUIRE(native_iter->i == 3);
            REQUIRE(native_iter->c == 'b');
        }
    }
}

TEST_CASE("member_iterator based on std::vector::iterator", "[member_iterator]")
{
    struct payload
    {
        int i;
        int
        get_i() const
        {
            return i;
        }

        bool
        operator==(const payload& other) const
        {
            return i == other.i;
        }
    };

    struct mock
    {
        double weight;
        payload value;
    };

    typedef helene::member_iterator<payload,
                                    mock,
                                    std::vector<mock>::iterator,
                                    &mock::value>
        mockveck_iterator_type;

    std::vector<mock> mockvec{{0.3, {1}}, {0.4, {2}}, {0.3, {3}}};

    mockveck_iterator_type beg_it(mockvec.begin());
    mockveck_iterator_type end_it(mockvec.end());

    SECTION("category should be random_access_iterator_tag")
    {
        bool is_rai = std::is_same<
            std::iterator_traits<mockveck_iterator_type>::iterator_category,
            std::random_access_iterator_tag>::value;

        REQUIRE(is_rai == true);
    }

    ////////////////////////////////////////////////////////////////////////////
    // BidirectionalIterator

    SECTION("predecrement")
    {
        --end_it;

        REQUIRE(end_it->i == 3);
        REQUIRE(end_it->get_i() == 3);
    }

    SECTION("postdecrement")
    {
        end_it--;

        REQUIRE(end_it->i == 3);
        REQUIRE(end_it->get_i() == 3);
    }

    SECTION("postdecrement and dereference statement")
    {
        ++beg_it;

        auto old = *beg_it--;
        REQUIRE(old.i == 2);
        REQUIRE(beg_it->i == 1);
    }

    ////////////////////////////////////////////////////////////////////////////
    // RandomAccesIterator

    SECTION("+=")
    {
        bool is_iter_ref =
            std::is_same<decltype(beg_it += 2), mockveck_iterator_type&>::value;

        beg_it += 2;

        REQUIRE(is_iter_ref == true);

        REQUIRE(beg_it->i == 3);
    }

    SECTION("adding number")
    {
        bool is_iter_type =
            std::is_same<decltype(beg_it + 2), mockveck_iterator_type>::value;
        bool is_iter_type2 =
            std::is_same<decltype(2 + beg_it), mockveck_iterator_type>::value;

        auto res1 = beg_it + 2;
        auto res2 = 2 + beg_it;

        REQUIRE(is_iter_type == true);
        REQUIRE(is_iter_type2 == true);

        REQUIRE(res1 == res2);
        REQUIRE(res1->i == 3);
        REQUIRE(res2->i == 3);
    }

    SECTION("-=")
    {
        bool is_iter_ref =
            std::is_same<decltype(end_it -= 2), mockveck_iterator_type&>::value;

        end_it -= 2;

        REQUIRE(is_iter_ref == true);
        REQUIRE(end_it->i == 2);
    }
}
<|endoftext|>


<commit_before>#include "SpriteBatch.h"
#include "../Objects/Object.h"
#include "../StarComponents.h"
#include "../Scenes/SceneManager.h"
#include "GraphicsManager.h"
#include "../Components/CameraComponent.h"
#include "../Objects/FreeCamera.h"
#include "../Scenes/BaseScene.h"
#include <algorithm>
#include "../Helpers/Math.h"
#include "ScaleSystem.h"

namespace star
{
	SpriteBatch * SpriteBatch::m_pSpriteBatch = nullptr;

	SpriteBatch::SpriteBatch(void):
		m_SpriteQueue(),
		m_TextQueue(),
		m_VertexBuffer(),
		m_UvCoordBuffer(),
		m_IsHUDBuffer(),
		m_ColorBuffer(),
		m_TextureSamplerID(0),
		m_ColorID(0),
		m_ScalingID(0),
		m_ViewInverseID(0),
		m_ProjectionID(0),
		m_ShaderPtr(nullptr)
	{

	}

	SpriteBatch::~SpriteBatch(void)
	{
		delete m_ShaderPtr;
	}

	SpriteBatch * SpriteBatch::GetInstance()
	{
		if(m_pSpriteBatch == nullptr)
		{
			m_pSpriteBatch = new SpriteBatch();
			m_pSpriteBatch->Initialize();
		}
		return m_pSpriteBatch;
	}

	void SpriteBatch::Initialize()
	{
		//Set Shader and shader variables
		tstring vShader(_T("Shaders/VertexPosColTexShader.vert")),
				fShader(_T("Shaders/VertexPosColTexShader.frag"));

		m_ShaderPtr = new Shader();
		if(!m_ShaderPtr->Init(vShader, fShader))
		{
			Logger::GetInstance()->
				Log(star::LogLevel::Info,
				_T("Initialization of Spritebatch Shader has Failed!"),
				STARENGINE_LOG_TAG);
		}

		m_VertexID = m_ShaderPtr->GetAttribLocation("position");
		m_UVID = m_ShaderPtr->GetAttribLocation("texCoord");
		m_IsHUDID = m_ShaderPtr->GetAttribLocation("isHUD");
		m_ColorID = m_ShaderPtr->GetAttribLocation("colorMultiplier");

		m_TextureSamplerID = m_ShaderPtr->GetUniformLocation("textureSampler");
		m_ScalingID = m_ShaderPtr->GetUniformLocation("scaleMatrix");
		m_ViewInverseID = m_ShaderPtr->GetUniformLocation("viewInverseMatrix");
		m_ProjectionID = m_ShaderPtr->GetUniformLocation("projectionMatrix");
	}

	void SpriteBatch::Flush()
	{
		Begin();
		DrawSprites();

		//Clear vertex, uv, color and isHud buffer
		m_VertexBuffer.clear();
		m_UvCoordBuffer.clear();
		m_IsHUDBuffer.clear();
		m_ColorBuffer.clear();

		DrawTextSprites();

		End();
	}

	void SpriteBatch::Begin()
	{
		m_ShaderPtr->Bind();

		//[TODO] Test android!
		glEnableVertexAttribArray(m_VertexID);
		glEnableVertexAttribArray(m_UVID);
		glEnableVertexAttribArray(m_IsHUDID);
		glEnableVertexAttribArray(m_ColorID);

		//Create Vertexbuffer
		CreateSpriteQuads();

		//Set uniforms
		glUniform1i(m_TextureSamplerID, 0);
		float scaleValue = ScaleSystem::GetInstance()->GetScale();
		mat4 scaleMat = Scale(scaleValue, scaleValue, 1.0f);
		glUniformMatrix4fv(m_ScalingID, 1, GL_FALSE, ToPointerValue(scaleMat));

		mat4 viewInverseMat = GraphicsManager::GetInstance()->GetViewInverseMatrix();
		glUniformMatrix4fv(m_ViewInverseID, 1, GL_FALSE, ToPointerValue(viewInverseMat));

		mat4 projectionMat = GraphicsManager::GetInstance()->GetProjectionMatrix();
		glUniformMatrix4fv(m_ProjectionID, 1, GL_FALSE, ToPointerValue(projectionMat));
	}

	void SpriteBatch::DrawSprites()
	{
		uint32 batchStart(0);
		uint32 batchSize(0);
		GLuint texture(0);
		for(const SpriteInfo& currentSprite : m_SpriteQueue)
		{
			//If != -> Flush
			if(texture != currentSprite.textureID)
			{
				FlushSprites(batchStart, batchSize, texture);

				batchStart += batchSize;
				batchSize = 0;

				texture = currentSprite.textureID;
			}
			++batchSize;
		}
		FlushSprites(batchStart, batchSize, texture);
	}

	void SpriteBatch::FlushSprites(uint32 start, uint32 size, uint32 texture)
	{
		if(size > 0)
		{
			//[TODO] Check if this can be optimized
			glBindTexture(GL_TEXTURE_2D, texture);

			//Set attributes and buffers
			glVertexAttribPointer(m_VertexID, 4, GL_FLOAT, 0, 0,
				reinterpret_cast<GLvoid*>(&m_VertexBuffer.at(0)));
			glVertexAttribPointer(m_UVID, 2, GL_FLOAT, 0, 0,
				reinterpret_cast<GLvoid*>(&m_UvCoordBuffer.at(0)));
			glVertexAttribPointer(m_IsHUDID, 1, GL_FLOAT, 0, 0,
				reinterpret_cast<GLvoid*>(&m_IsHUDBuffer.at(0)));
			glVertexAttribPointer(m_ColorID, 4, GL_FLOAT, 0, 0,
				reinterpret_cast<GLvoid*>(&m_ColorBuffer.at(0)));

			glDrawArrays(GL_TRIANGLES, start * 6, size * 6);
		}
	}

	void SpriteBatch::End()
	{
		//Unbind attributes and buffers
		glDisableVertexAttribArray(m_VertexID);
		glDisableVertexAttribArray(m_UVID);
		glDisableVertexAttribArray(m_IsHUDID);
		glDisableVertexAttribArray(m_ColorID);

		m_ShaderPtr->Unbind();

		m_SpriteQueue.clear();
		m_TextQueue.clear();

		m_VertexBuffer.clear();
		m_UvCoordBuffer.clear();
		m_IsHUDBuffer.clear();
		m_ColorBuffer.clear();
	}

	void SpriteBatch::DrawTextSprites()
	{
		CreateTextQuads();

		//FlushText once per TextComponent (same font)
		//Check per text how many characters -> Forloop drawing
		for(const TextInfo& text : m_TextQueue)
		{
			auto curFont = text.font;

			GLuint* textures = curFont.GetTextures();

			const tchar *start_line = text.text.c_str();
			for(int32 i = 0 ; start_line[i] != 0 ; ++i)
			{
				if(start_line[i] > FIRST_REAL_ASCII_CHAR)
				{
					glBindTexture(GL_TEXTURE_2D, textures[start_line[i]]);

					//Set attributes and buffers
					glVertexAttribPointer(m_VertexID, 4, GL_FLOAT, 0, 0,
						reinterpret_cast<GLvoid*>(&m_VertexBuffer.at(0)));
					glVertexAttribPointer(m_UVID, 2, GL_FLOAT, 0, 0,
						reinterpret_cast<GLvoid*>(&m_UvCoordBuffer.at(0)));
					glVertexAttribPointer(m_IsHUDID, 1, GL_FLOAT, 0, 0,
						reinterpret_cast<GLvoid*>(&m_IsHUDBuffer.at(0)));
					glVertexAttribPointer(m_ColorID, 4, GL_FLOAT, 0, 0,
						reinterpret_cast<GLvoid*>(&m_ColorBuffer.at(0)));
					glDrawArrays(GL_TRIANGLES, i * 6, 6);
				}
			}
		}
	}

	void SpriteBatch::CreateSpriteQuads()
	{
		//for every sprite that has to be drawn, push back all vertices
		//(VERTEX_AMOUNT per sprite) into the vertexbuffer and all uvcoords
		//(UV_AMOUNT per sprite) into the uvbuffer and the isHUD bool
		/*
		*  TL    TR
		*   0----1
		*   |   /|
		*   |  / |
		*   | /  |
		*   |/   |
		*   2----3
		*  BL    BR
		*/

		for(const SpriteInfo& sprite : m_SpriteQueue)
		{
			//Push back all vertices

			mat4 transformMat = Transpose(sprite.transformPtr->GetWorldMatrix());

			//[TODO] Add depth!
			//[TODO] Check if this can be changed :(

			vec4 TL = vec4(0, sprite.vertices.y, 0, 1);
			Mul(TL, transformMat, TL);

			vec4 TR = vec4(sprite.vertices.x, sprite.vertices.y, 0, 1);
			Mul(TR, transformMat, TR);

			vec4 BL = vec4(0, 0, 0, 1);
			Mul(BL, transformMat, BL);

			vec4 BR = vec4(sprite.vertices.x, 0, 0, 1);
			Mul(BR, transformMat, BR);

			//0
			m_VertexBuffer.push_back(TL);

			//1
			m_VertexBuffer.push_back(TR);

			//2
			m_VertexBuffer.push_back(BL);

			//1
			m_VertexBuffer.push_back(TR);

			//3
			m_VertexBuffer.push_back(BR);

			//2
			m_VertexBuffer.push_back(BL);

			//Push back all uv's

			//0
			m_UvCoordBuffer.push_back(sprite.uvCoords.x);
			m_UvCoordBuffer.push_back(sprite.uvCoords.y + sprite.uvCoords.w);

			//1
			m_UvCoordBuffer.push_back(sprite.uvCoords.x + sprite.uvCoords.z);
			m_UvCoordBuffer.push_back(sprite.uvCoords.y + sprite.uvCoords.w);

			//2
			m_UvCoordBuffer.push_back(sprite.uvCoords.x);
			m_UvCoordBuffer.push_back(sprite.uvCoords.y);

			//1
			m_UvCoordBuffer.push_back(sprite.uvCoords.x + sprite.uvCoords.z);
			m_UvCoordBuffer.push_back(sprite.uvCoords.y + sprite.uvCoords.w);

			//3
			m_UvCoordBuffer.push_back(sprite.uvCoords.x + sprite.uvCoords.z);
			m_UvCoordBuffer.push_back(sprite.uvCoords.y);

			//2
			m_UvCoordBuffer.push_back(sprite.uvCoords.x);
			m_UvCoordBuffer.push_back(sprite.uvCoords.y);

			//bool & color buffer
			for(uint32 i = 0; i < 6; ++i)
			{
				m_IsHUDBuffer.push_back(float32(sprite.bIsHud));
				//rgba
				m_ColorBuffer.push_back(sprite.colorMultiplier);
			}
		}
	}

	void SpriteBatch::CreateTextQuads()
	{
		//for every sprite that has to be drawn, push back all vertices
		//(VERTEX_AMOUNT per sprite) into the vertexbuffer and all uvcoords
		//(UV_AMOUNT per sprite) into the uvbuffer and the isHUD bool
		/*
		*  TL    TR
		*   0----1
		*   |   /|
		*   |  / |
		*   | /  |
		*   |/   |
		*   2----3
		*  BL    BR
		*/
		for(const TextInfo& text : m_TextQueue)
		{
			//Variables per textcomponent
			mat4 transformMat, offsetMatrix;
			const mat4& worldMat = text.transformPtr->GetWorldMatrix();
			int32 line_counter(0);
			int32 offsetX(text.horizontalTextOffset.at(line_counter));
			int32 offsetY(0);
			int32 fontHeight(text.font.GetMaxLetterHeight() + text.font.GetMinLetterHeight());
			for(auto it : text.text)
			{
				const CharacterInfo& charInfo = text.font.GetCharacterInfo(static_cast<suchar>(it));
				offsetMatrix = Translate
					(vec3(
						offsetX,
						offsetY + charInfo.letterDimensions.y + text.textHeight - fontHeight,
						0));
				offsetX += charInfo.letterDimensions.x;

				transformMat = Transpose(worldMat * offsetMatrix);

				vec4 TL = vec4(0, charInfo.vertexDimensions.y, 0, 1);
				Mul(TL, transformMat, TL);

				vec4 TR = vec4(charInfo.vertexDimensions.x, charInfo.vertexDimensions.y, 0, 1);
				Mul(TR, transformMat, TR);

				vec4 BL = vec4(0, 0, 0, 1);
				Mul(BL, transformMat, BL);

				vec4 BR = vec4(charInfo.vertexDimensions.x, 0, 0, 1);
				Mul(BR, transformMat, BR);

				//0
				m_VertexBuffer.push_back(TL);

				//1
				m_VertexBuffer.push_back(TR);

				//2
				m_VertexBuffer.push_back(BL);

				//1
				m_VertexBuffer.push_back(TR);

				//3
				m_VertexBuffer.push_back(BR);

				//2
				m_VertexBuffer.push_back(BL);

				//Push back all uv's

				//0
				m_UvCoordBuffer.push_back(0);
				m_UvCoordBuffer.push_back(0);

				//1
				m_UvCoordBuffer.push_back(charInfo.uvDimensions.x);
				m_UvCoordBuffer.push_back(0);

				//2
				m_UvCoordBuffer.push_back(0);
				m_UvCoordBuffer.push_back(charInfo.uvDimensions.y);

				//1
				m_UvCoordBuffer.push_back(charInfo.uvDimensions.x);
				m_UvCoordBuffer.push_back(0);

				//3
				m_UvCoordBuffer.push_back(charInfo.uvDimensions.x);
				m_UvCoordBuffer.push_back(charInfo.uvDimensions.y);

				//2
				m_UvCoordBuffer.push_back(0);
				m_UvCoordBuffer.push_back(charInfo.uvDimensions.y);

				//bool & color buffer
				for(uint32 i = 0; i < 6; ++i)
				{
					m_IsHUDBuffer.push_back(float32(text.bIsHud));
					//rgba
					m_ColorBuffer.push_back(text.colorMultiplier);
				}

				if(it == _T('\n'))
				{
					offsetY -= text.font.GetMaxLetterHeight() + text.verticalSpacing;
					++line_counter;
					offsetX = text.horizontalTextOffset.at(line_counter);
				}
			}
		}
	}

	void SpriteBatch::AddSpriteToQueue(const SpriteInfo& spriteInfo)
	{
		m_SpriteQueue.push_back(spriteInfo);
	}

	void SpriteBatch::AddTextToQueue(const TextInfo& text)
	{
		m_TextQueue.push_back(text);
	}
}
<commit_msg>Text rendering bug fix<commit_after>#include "SpriteBatch.h"
#include "../Objects/Object.h"
#include "../StarComponents.h"
#include "../Scenes/SceneManager.h"
#include "GraphicsManager.h"
#include "../Components/CameraComponent.h"
#include "../Objects/FreeCamera.h"
#include "../Scenes/BaseScene.h"
#include <algorithm>
#include "../Helpers/Math.h"
#include "ScaleSystem.h"

namespace star
{
	SpriteBatch * SpriteBatch::m_pSpriteBatch = nullptr;

	SpriteBatch::SpriteBatch(void):
		m_SpriteQueue(),
		m_TextQueue(),
		m_VertexBuffer(),
		m_UvCoordBuffer(),
		m_IsHUDBuffer(),
		m_ColorBuffer(),
		m_TextureSamplerID(0),
		m_ColorID(0),
		m_ScalingID(0),
		m_ViewInverseID(0),
		m_ProjectionID(0),
		m_ShaderPtr(nullptr)
	{

	}

	SpriteBatch::~SpriteBatch(void)
	{
		delete m_ShaderPtr;
	}

	SpriteBatch * SpriteBatch::GetInstance()
	{
		if(m_pSpriteBatch == nullptr)
		{
			m_pSpriteBatch = new SpriteBatch();
			m_pSpriteBatch->Initialize();
		}
		return m_pSpriteBatch;
	}

	void SpriteBatch::Initialize()
	{
		//Set Shader and shader variables
		tstring vShader(_T("Shaders/VertexPosColTexShader.vert")),
				fShader(_T("Shaders/VertexPosColTexShader.frag"));

		m_ShaderPtr = new Shader();
		if(!m_ShaderPtr->Init(vShader, fShader))
		{
			Logger::GetInstance()->
				Log(star::LogLevel::Info,
				_T("Initialization of Spritebatch Shader has Failed!"),
				STARENGINE_LOG_TAG);
		}

		m_VertexID = m_ShaderPtr->GetAttribLocation("position");
		m_UVID = m_ShaderPtr->GetAttribLocation("texCoord");
		m_IsHUDID = m_ShaderPtr->GetAttribLocation("isHUD");
		m_ColorID = m_ShaderPtr->GetAttribLocation("colorMultiplier");

		m_TextureSamplerID = m_ShaderPtr->GetUniformLocation("textureSampler");
		m_ScalingID = m_ShaderPtr->GetUniformLocation("scaleMatrix");
		m_ViewInverseID = m_ShaderPtr->GetUniformLocation("viewInverseMatrix");
		m_ProjectionID = m_ShaderPtr->GetUniformLocation("projectionMatrix");
	}

	void SpriteBatch::Flush()
	{
		Begin();
		DrawSprites();

		//Clear vertex, uv, color and isHud buffer
		m_VertexBuffer.clear();
		m_UvCoordBuffer.clear();
		m_IsHUDBuffer.clear();
		m_ColorBuffer.clear();

		DrawTextSprites();

		End();
	}

	void SpriteBatch::Begin()
	{
		m_ShaderPtr->Bind();

		//[TODO] Test android!
		glEnableVertexAttribArray(m_VertexID);
		glEnableVertexAttribArray(m_UVID);
		glEnableVertexAttribArray(m_IsHUDID);
		glEnableVertexAttribArray(m_ColorID);

		//Create Vertexbuffer
		CreateSpriteQuads();

		//Set uniforms
		glUniform1i(m_TextureSamplerID, 0);
		float scaleValue = ScaleSystem::GetInstance()->GetScale();
		mat4 scaleMat = Scale(scaleValue, scaleValue, 1.0f);
		glUniformMatrix4fv(m_ScalingID, 1, GL_FALSE, ToPointerValue(scaleMat));

		mat4 viewInverseMat = GraphicsManager::GetInstance()->GetViewInverseMatrix();
		glUniformMatrix4fv(m_ViewInverseID, 1, GL_FALSE, ToPointerValue(viewInverseMat));

		mat4 projectionMat = GraphicsManager::GetInstance()->GetProjectionMatrix();
		glUniformMatrix4fv(m_ProjectionID, 1, GL_FALSE, ToPointerValue(projectionMat));
	}

	void SpriteBatch::DrawSprites()
	{
		uint32 batchStart(0);
		uint32 batchSize(0);
		GLuint texture(0);
		for(const SpriteInfo& currentSprite : m_SpriteQueue)
		{
			//If != -> Flush
			if(texture != currentSprite.textureID)
			{
				FlushSprites(batchStart, batchSize, texture);

				batchStart += batchSize;
				batchSize = 0;

				texture = currentSprite.textureID;
			}
			++batchSize;
		}
		FlushSprites(batchStart, batchSize, texture);
	}

	void SpriteBatch::FlushSprites(uint32 start, uint32 size, uint32 texture)
	{
		if(size > 0)
		{
			//[TODO] Check if this can be optimized
			glBindTexture(GL_TEXTURE_2D, texture);

			//Set attributes and buffers
			glVertexAttribPointer(m_VertexID, 4, GL_FLOAT, 0, 0,
				reinterpret_cast<GLvoid*>(&m_VertexBuffer.at(0)));
			glVertexAttribPointer(m_UVID, 2, GL_FLOAT, 0, 0,
				reinterpret_cast<GLvoid*>(&m_UvCoordBuffer.at(0)));
			glVertexAttribPointer(m_IsHUDID, 1, GL_FLOAT, 0, 0,
				reinterpret_cast<GLvoid*>(&m_IsHUDBuffer.at(0)));
			glVertexAttribPointer(m_ColorID, 4, GL_FLOAT, 0, 0,
				reinterpret_cast<GLvoid*>(&m_ColorBuffer.at(0)));

			glDrawArrays(GL_TRIANGLES, start * 6, size * 6);
		}
	}

	void SpriteBatch::End()
	{
		//Unbind attributes and buffers
		glDisableVertexAttribArray(m_VertexID);
		glDisableVertexAttribArray(m_UVID);
		glDisableVertexAttribArray(m_IsHUDID);
		glDisableVertexAttribArray(m_ColorID);

		m_ShaderPtr->Unbind();

		m_SpriteQueue.clear();
		m_TextQueue.clear();

		m_VertexBuffer.clear();
		m_UvCoordBuffer.clear();
		m_IsHUDBuffer.clear();
		m_ColorBuffer.clear();
	}

	void SpriteBatch::DrawTextSprites()
	{
		CreateTextQuads();

		//FlushText once per TextComponent (same font)
		//Check per text how many characters -> Forloop drawing
		int32 startIndex(0);
		for(const TextInfo& text : m_TextQueue)
		{
			auto curFont = text.font;

			GLuint* textures = curFont.GetTextures();

			const tchar *start_line = text.text.c_str();
			for(int32 i = 0 ; start_line[i] != 0 ; ++i)
			{
				if(start_line[i] > FIRST_REAL_ASCII_CHAR)
				{
					glBindTexture(GL_TEXTURE_2D, textures[start_line[i]]);

					//Set attributes and buffers
					glVertexAttribPointer(m_VertexID, 4, GL_FLOAT, 0, 0,
						reinterpret_cast<GLvoid*>(&m_VertexBuffer.at(0)));
					glVertexAttribPointer(m_UVID, 2, GL_FLOAT, 0, 0,
						reinterpret_cast<GLvoid*>(&m_UvCoordBuffer.at(0)));
					glVertexAttribPointer(m_IsHUDID, 1, GL_FLOAT, 0, 0,
						reinterpret_cast<GLvoid*>(&m_IsHUDBuffer.at(0)));
					glVertexAttribPointer(m_ColorID, 4, GL_FLOAT, 0, 0,
						reinterpret_cast<GLvoid*>(&m_ColorBuffer.at(0)));
					glDrawArrays(GL_TRIANGLES, startIndex * 6, 6);
				}
				++startIndex;
			}
		}
	}

	void SpriteBatch::CreateSpriteQuads()
	{
		//for every sprite that has to be drawn, push back all vertices
		//(VERTEX_AMOUNT per sprite) into the vertexbuffer and all uvcoords
		//(UV_AMOUNT per sprite) into the uvbuffer and the isHUD bool
		/*
		*  TL    TR
		*   0----1
		*   |   /|
		*   |  / |
		*   | /  |
		*   |/   |
		*   2----3
		*  BL    BR
		*/

		for(const SpriteInfo& sprite : m_SpriteQueue)
		{
			//Push back all vertices

			mat4 transformMat = Transpose(sprite.transformPtr->GetWorldMatrix());

			//[TODO] Add depth!
			//[TODO] Check if this can be changed :(

			vec4 TL = vec4(0, sprite.vertices.y, 0, 1);
			Mul(TL, transformMat, TL);

			vec4 TR = vec4(sprite.vertices.x, sprite.vertices.y, 0, 1);
			Mul(TR, transformMat, TR);

			vec4 BL = vec4(0, 0, 0, 1);
			Mul(BL, transformMat, BL);

			vec4 BR = vec4(sprite.vertices.x, 0, 0, 1);
			Mul(BR, transformMat, BR);

			//0
			m_VertexBuffer.push_back(TL);

			//1
			m_VertexBuffer.push_back(TR);

			//2
			m_VertexBuffer.push_back(BL);

			//1
			m_VertexBuffer.push_back(TR);

			//3
			m_VertexBuffer.push_back(BR);

			//2
			m_VertexBuffer.push_back(BL);

			//Push back all uv's

			//0
			m_UvCoordBuffer.push_back(sprite.uvCoords.x);
			m_UvCoordBuffer.push_back(sprite.uvCoords.y + sprite.uvCoords.w);

			//1
			m_UvCoordBuffer.push_back(sprite.uvCoords.x + sprite.uvCoords.z);
			m_UvCoordBuffer.push_back(sprite.uvCoords.y + sprite.uvCoords.w);

			//2
			m_UvCoordBuffer.push_back(sprite.uvCoords.x);
			m_UvCoordBuffer.push_back(sprite.uvCoords.y);

			//1
			m_UvCoordBuffer.push_back(sprite.uvCoords.x + sprite.uvCoords.z);
			m_UvCoordBuffer.push_back(sprite.uvCoords.y + sprite.uvCoords.w);

			//3
			m_UvCoordBuffer.push_back(sprite.uvCoords.x + sprite.uvCoords.z);
			m_UvCoordBuffer.push_back(sprite.uvCoords.y);

			//2
			m_UvCoordBuffer.push_back(sprite.uvCoords.x);
			m_UvCoordBuffer.push_back(sprite.uvCoords.y);

			//bool & color buffer
			for(uint32 i = 0; i < 6; ++i)
			{
				m_IsHUDBuffer.push_back(float32(sprite.bIsHud));
				//rgba
				m_ColorBuffer.push_back(sprite.colorMultiplier);
			}
		}
	}

	void SpriteBatch::CreateTextQuads()
	{
		//for every sprite that has to be drawn, push back all vertices
		//(VERTEX_AMOUNT per sprite) into the vertexbuffer and all uvcoords
		//(UV_AMOUNT per sprite) into the uvbuffer and the isHUD bool
		/*
		*  TL    TR
		*   0----1
		*   |   /|
		*   |  / |
		*   | /  |
		*   |/   |
		*   2----3
		*  BL    BR
		*/
		for(const TextInfo& text : m_TextQueue)
		{
			//Variables per textcomponent
			mat4 transformMat, offsetMatrix;
			const mat4& worldMat = text.transformPtr->GetWorldMatrix();
			int32 line_counter(0);
			int32 offsetX(text.horizontalTextOffset.at(line_counter));
			int32 offsetY(0);
			int32 fontHeight(text.font.GetMaxLetterHeight() + text.font.GetMinLetterHeight());
			for(auto it : text.text)
			{
				const CharacterInfo& charInfo = text.font.GetCharacterInfo(static_cast<suchar>(it));
				offsetMatrix = Translate
					(vec3(
						offsetX,
						offsetY + charInfo.letterDimensions.y + text.textHeight - fontHeight,
						0));
				offsetX += charInfo.letterDimensions.x;

				transformMat = Transpose(worldMat * offsetMatrix);

				vec4 TL = vec4(0, charInfo.vertexDimensions.y, 0, 1);
				Mul(TL, transformMat, TL);

				vec4 TR = vec4(charInfo.vertexDimensions.x, charInfo.vertexDimensions.y, 0, 1);
				Mul(TR, transformMat, TR);

				vec4 BL = vec4(0, 0, 0, 1);
				Mul(BL, transformMat, BL);

				vec4 BR = vec4(charInfo.vertexDimensions.x, 0, 0, 1);
				Mul(BR, transformMat, BR);

				//0
				m_VertexBuffer.push_back(TL);

				//1
				m_VertexBuffer.push_back(TR);

				//2
				m_VertexBuffer.push_back(BL);

				//1
				m_VertexBuffer.push_back(TR);

				//3
				m_VertexBuffer.push_back(BR);

				//2
				m_VertexBuffer.push_back(BL);

				//Push back all uv's

				//0
				m_UvCoordBuffer.push_back(0);
				m_UvCoordBuffer.push_back(0);

				//1
				m_UvCoordBuffer.push_back(charInfo.uvDimensions.x);
				m_UvCoordBuffer.push_back(0);

				//2
				m_UvCoordBuffer.push_back(0);
				m_UvCoordBuffer.push_back(charInfo.uvDimensions.y);

				//1
				m_UvCoordBuffer.push_back(charInfo.uvDimensions.x);
				m_UvCoordBuffer.push_back(0);

				//3
				m_UvCoordBuffer.push_back(charInfo.uvDimensions.x);
				m_UvCoordBuffer.push_back(charInfo.uvDimensions.y);

				//2
				m_UvCoordBuffer.push_back(0);
				m_UvCoordBuffer.push_back(charInfo.uvDimensions.y);

				//bool & color buffer
				for(uint32 i = 0; i < 6; ++i)
				{
					m_IsHUDBuffer.push_back(float32(text.bIsHud));
					//rgba
					m_ColorBuffer.push_back(text.colorMultiplier);
				}

				if(it == _T('\n'))
				{
					offsetY -= text.font.GetMaxLetterHeight() + text.verticalSpacing;
					++line_counter;
					offsetX = text.horizontalTextOffset.at(line_counter);
				}
			}
		}
	}

	void SpriteBatch::AddSpriteToQueue(const SpriteInfo& spriteInfo)
	{
		m_SpriteQueue.push_back(spriteInfo);
	}

	void SpriteBatch::AddTextToQueue(const TextInfo& text)
	{
		m_TextQueue.push_back(text);
	}
}
<|endoftext|>


<commit_before>/**
  * Touhou Community Reliant Automatic Patcher
  * Tasogare Frontier support plugin
  *
  * ----
  *
  * On-the-fly th175 pl patcher
  */

#include <thcrap.h>
#include "thcrap_tasofro.h"

static void copy_line(const char*& file_in, const char *file_in_end, char*& file_out)
{
	const char *search_end = std::find(file_in, file_in_end, '\n');
	if (search_end != file_in_end) search_end++;
	file_out = std::copy(file_in, search_end, file_out);
	file_in = search_end;
}

static void copy_text_line(const char*& file_in, const char *file_in_end, char*& file_out)
{
	const char *search_end = std::find(file_in + 1, file_in_end, '"');
	if (search_end != file_in_end) search_end++;
	file_out = std::copy(file_in, search_end, file_out);
	file_in = search_end;
	copy_line(file_in, file_in_end, file_out);
}

static void patch_text_line(const char*& file_in, const char *file_in_end, char*& file_out, const std::string& rep)
{
	bool ends_with_pause = false;
	// Skip original text in input
	file_in = std::find(file_in + 1, file_in_end, '"');

	// If the text ends with an @, add it at the end of our replacement text
	if (*(file_in - 1) == '@') {
		ends_with_pause = true;
	}
	if (file_in != file_in_end) {
		// Skip the " at the end
		file_in++;
	}

	*file_out = '"'; file_out++;

	for (char c : rep) {
		if (c == '"') {
			*file_out = '"'; file_out++;
		}
		*file_out = c; file_out++;
	}

	if (ends_with_pause) {
		*file_out = '@'; file_out++;
	}
	*file_out = '"'; file_out++;
	copy_line(file_in, file_in_end, file_out);
}

int patch_th175_pl(void *file_inout, size_t, size_t size_in, const char *, json_t *patch)
{
	if (!patch) {
		return 0;
	}

	auto file_in_storage = std::make_unique<char[]>(size_in);
	std::copy((char*)file_inout, ((char*)file_inout) + size_in, file_in_storage.get());

	const char *file_in = file_in_storage.get();
	const char *file_in_end = file_in + size_in;
	char *file_out = (char*)file_inout;

	unsigned int line_num = 1;
	while (file_in < file_in_end) {
		if (*file_in != '"') {
			copy_line(file_in, file_in_end, file_out);
			continue;
		}

		json_t *rep = json_object_numkey_get(patch, line_num);
		line_num++;
		rep = json_object_get(rep, "lines");
		if (!rep) {
			copy_text_line(file_in, file_in_end, file_out);
			continue;
		}

		std::string rep_string;
		json_t *value;
		json_flex_array_foreach_scoped(size_t, i, rep, value) {
			if (!rep_string.empty()) {
				rep_string += '\n';
			}
			rep_string += json_string_value(value);
		}
		patch_text_line(file_in, file_in_end, file_out, rep_string);
	}

#if 0
	std::filesystem::path dir = std::filesystem::absolute(fn);
	dir.remove_filename();
	std::filesystem::create_directories(dir);

	std::ofstream f(fn, std::ios::binary);
	f.write((char*)file_inout, size_out);
	f.close();
#endif

	return 1;
}
<commit_msg>th175: add stages name patching<commit_after>/**
  * Touhou Community Reliant Automatic Patcher
  * Tasogare Frontier support plugin
  *
  * ----
  *
  * On-the-fly th175 pl patcher
  */

#include <thcrap.h>
#include "thcrap_tasofro.h"

static const char *STAGE_NAME_COMMAND = u8",ステージ見出し,";

static void copy_line(const char*& file_in, const char *file_in_end, char*& file_out)
{
	const char *search_end = std::find(file_in, file_in_end, '\n');
	if (search_end != file_in_end) search_end++;
	file_out = std::copy(file_in, search_end, file_out);
	file_in = search_end;
}

static void copy_text_line(const char*& file_in, const char *file_in_end, char*& file_out)
{
	const char *search_end = std::find(file_in + 1, file_in_end, '"');
	if (search_end != file_in_end) search_end++;
	file_out = std::copy(file_in, search_end, file_out);
	file_in = search_end;
	copy_line(file_in, file_in_end, file_out);
}

static void patch_text_line(const char*& file_in, const char *file_in_end, char*& file_out, const std::string& rep)
{
	bool ends_with_pause = false;
	// Skip original text in input
	file_in = std::find(file_in + 1, file_in_end, '"');

	// If the text ends with an @, add it at the end of our replacement text
	if (*(file_in - 1) == '@') {
		ends_with_pause = true;
	}
	if (file_in != file_in_end) {
		// Skip the " at the end
		file_in++;
	}

	*file_out = '"'; file_out++;

	for (char c : rep) {
		if (c == '"') {
			*file_out = '"'; file_out++;
		}
		*file_out = c; file_out++;
	}

	if (ends_with_pause) {
		*file_out = '@'; file_out++;
	}
	*file_out = '"'; file_out++;
	copy_line(file_in, file_in_end, file_out);
}

static void patch_stage_name(const char*& file_in, const char *file_in_end, char*& file_out, json_t *rep_obj)
{
	if (!rep_obj) {
		copy_line(file_in, file_in_end, file_out);
		return;
	}

	json_t *value;
	std::string rep;
	json_flex_array_foreach_scoped(size_t, i, rep_obj, value) {
		if (!rep.empty()) {
			rep += "\n";
		}
		rep += json_string_value(value);
	}
	if (rep.empty()) {
		copy_line(file_in, file_in_end, file_out);
		return;
	}

	// Skip original text in input
	file_in = std::find(file_in, file_in_end, '\n');
	if (file_in != file_in_end) file_in++;

	strcpy(file_out, STAGE_NAME_COMMAND); file_out += strlen(STAGE_NAME_COMMAND);
	*file_out = '"'; file_out++;
	file_out = std::copy(rep.begin(), rep.end(), file_out);
	strcpy(file_out, "\"\r\n"); file_out += 3;
}

int patch_th175_pl(void *file_inout, size_t, size_t size_in, const char *, json_t *patch)
{
	if (!patch) {
		return 0;
	}

	auto file_in_storage = std::make_unique<char[]>(size_in);
	std::copy((char*)file_inout, ((char*)file_inout) + size_in, file_in_storage.get());

	const char *file_in = file_in_storage.get();
	const char *file_in_end = file_in + size_in;
	char *file_out = (char*)file_inout;

	unsigned int line_num = 1;
	while (file_in < file_in_end) {
		if (strncmp(file_in, STAGE_NAME_COMMAND, strlen(STAGE_NAME_COMMAND)) == 0) {
			patch_stage_name(file_in, file_in_end, file_out, json_object_get(patch, "stagename"));
			continue;
		}
		else if (*file_in != '"') {
			copy_line(file_in, file_in_end, file_out);
			continue;
		}

		json_t *rep = json_object_numkey_get(patch, line_num);
		line_num++;
		rep = json_object_get(rep, "lines");
		if (!rep) {
			copy_text_line(file_in, file_in_end, file_out);
			continue;
		}

		std::string rep_string;
		json_t *value;
		json_flex_array_foreach_scoped(size_t, i, rep, value) {
			if (!rep_string.empty()) {
				rep_string += '\n';
			}
			rep_string += json_string_value(value);
		}
		patch_text_line(file_in, file_in_end, file_out, rep_string);
	}

#if 0
	std::filesystem::path dir = std::filesystem::absolute(fn);
	dir.remove_filename();
	std::filesystem::create_directories(dir);

	std::ofstream f(fn, std::ios::binary);
	f.write((char*)file_inout, size_out);
	f.close();
#endif

	return 1;
}
<|endoftext|>


<commit_before>/* job.cpp
 * Copyright (C) 2003-2005 Tommi Maekitalo
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 */

#include "tnt/job.h"
#include "tnt/tcpjob.h"
#include "tnt/tntnet.h"
#include <tnt/httpreply.h>
#include <tnt/ssl.h>
#include <cxxtools/log.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <config.h>

log_define("tntnet.job")

namespace tnt
{
  unsigned Job::socket_read_timeout = 10;
  unsigned Job::socket_write_timeout = 10000;
  unsigned Job::keepalive_max = 1000;
  unsigned Job::socket_buffer_size = 16384;

  Job::~Job()
  { }

  unsigned Job::addRef()
  {
    cxxtools::MutexLock lock(mutex);
    return ++refs;
  }

  unsigned Job::release()
  {
    mutex.lock();
    if (--refs == 0)
    {
      mutex.unlock();
      delete this;
      return 0;
    }
    else
    {
      mutex.unlock();
      return refs;
    }
  }

  void Job::clear()
  {
    parser.reset();
    request.clear();
    touch();
  }

  int Job::msecToTimeout(time_t currentTime) const
  {
    return (lastAccessTime - currentTime + 1) * 1000
         + getKeepAliveTimeout()
         - getSocketReadTimeout();
  }

  unsigned Job::getKeepAliveTimeout()
  {
    return HttpReply::getKeepAliveTimeout();
  }

  ////////////////////////////////////////////////////////////////////////
  // Tcpjob
  //
  void Tcpjob::accept()
  {
    log_debug("accept");
    socket.accept(listener);

    struct sockaddr_storage s = socket.getSockAddr();
    struct sockaddr_storage sockaddr;
    memcpy(&sockaddr, &s, sizeof(sockaddr));

    char buffer[INET6_ADDRSTRLEN];
    log_debug("connection accepted from "
      << inet_ntop(AF_INET6, &(socket.getPeeraddr()), buffer, sizeof(buffer)));

    getRequest().setPeerAddr(socket.getPeeraddr());
    getRequest().setServerAddr(sockaddr);
    getRequest().setSsl(false);
    touch();
  }

  std::iostream& Tcpjob::getStream()
  {
    if (socket.cxxtools::net::Socket::bad())
    {
      accept();
      log_debug("connection accepted");
      if (!Tntnet::shouldStop())
        queue.put(new Tcpjob(getRequest().getApplication(), listener, queue));
      else
        log_info("tntnet stopping - no new job is generated");
    }
    return socket;
  }

  int Tcpjob::getFd() const
  {
    return socket.getFd();
  }

  void Tcpjob::setRead()
  {
    socket.setTimeout(getSocketReadTimeout());
  }

  void Tcpjob::setWrite()
  {
    socket.setTimeout(getSocketWriteTimeout());
  }

#ifdef USE_SSL
  ////////////////////////////////////////////////////////////////////////
  // SslTcpjob
  //
  void SslTcpjob::accept()
  {
    log_debug("accept (ssl)");
    socket.accept(listener);
    log_debug("connection accepted (ssl)");

    struct sockaddr_storage s = socket.getSockAddr();
    struct sockaddr_storage sockaddr;
    memcpy(&sockaddr, &s, sizeof(sockaddr));

    getRequest().setPeerAddr(socket.getPeeraddr());
    getRequest().setServerAddr(sockaddr);
    getRequest().setSsl(true);

    setRead();
    touch();
  }

  std::iostream& SslTcpjob::getStream()
  {
    if (socket.cxxtools::net::Socket::bad())
    {
      accept();
      log_debug("connection accepted");
      if (!Tntnet::shouldStop())
        queue.put(new SslTcpjob(getRequest().getApplication(), listener, queue));
      else
        log_info("tntnet stopping - no new ssl-job is generated");
    }
    return socket;
  }

  int SslTcpjob::getFd() const
  {
    return socket.getFd();
  }

  void SslTcpjob::setRead()
  {
    socket.setTimeout(getSocketReadTimeout());
  }

  void SslTcpjob::setWrite()
  {
    socket.setTimeout(getSocketWriteTimeout());
  }

#endif // USE_SSL

#ifdef USE_GNUTLS
  ////////////////////////////////////////////////////////////////////////
  // GnuTlsTcpjob
  //
  void GnuTlsTcpjob::accept()
  {
    log_debug("accept (ssl)");
    accept();
    log_debug("connection accepted (ssl)");

    struct sockaddr_storage s = socket.getSockAddr();
    struct sockaddr_storage sockaddr;
    memcpy(&sockaddr, &s, sizeof(sockaddr));

    getRequest().setPeerAddr(socket.getPeeraddr());
    getRequest().setServerAddr(sockaddr);
    getRequest().setSsl(true);

    setRead();
    touch();
  }

  std::iostream& GnuTlsTcpjob::getStream()
  {
    if (socket.cxxtools::net::Socket::bad())
    {
      accept();
      log_debug("connection accepted");
      if (!Tntnet::shouldStop())
        queue.put(new GnuTlsTcpjob(listener, queue));
      else
        log_info("tntnet stopping - no new ssl-job is generated");
    }
    return socket;
  }

  int GnuTlsTcpjob::getFd() const
  {
    return socket.getFd();
  }

  void GnuTlsTcpjob::setRead()
  {
    socket.setTimeout(getSocketReadTimeout());
  }

  void GnuTlsTcpjob::setWrite()
  {
    socket.setTimeout(getSocketWriteTimeout());
  }

#endif // USE_GNUTLS

  //////////////////////////////////////////////////////////////////////
  // Jobqueue
  //
  void Jobqueue::put(JobPtr j, bool force)
  {
    log_debug("Jobqueue::put");
    j->touch();

    cxxtools::MutexLock lock(mutex);

    if (!force && capacity > 0)
    {
      while (jobs.size() >= capacity)
      {
        log_warn("Jobqueue full");
        notFull.wait(lock);
      }
    }

    log_debug("jobs.push");
    jobs.push_back(j);

    if (waitThreads == 0)
    {
      log_info("no waiting threads left");
      noWaitThreads.signal();
    }

    notEmpty.signal();
  }

  Jobqueue::JobPtr Jobqueue::get()
  {
    cxxtools::MutexLock lock(mutex);

    // wait, until a job is available
    ++waitThreads;

    log_debug("wait for job (" << jobs.size() << " jobs available)");

    while (jobs.empty())
      notEmpty.wait(lock);

    --waitThreads;

    log_debug("Jobqueue: fetch job " << waitThreads << " waiting threads left; " << jobs.size() << " jobs in queue");

    // take next job (queue is locked)
    JobPtr j = jobs.front();
    jobs.pop_front();

    // if there are threads waiting, wake another
    if (!jobs.empty() && waitThreads > 0)
    {
      log_debug("signal another thread");
      notEmpty.signal();
    }
    notFull.signal();

    return j;
  }

}
<commit_msg>bugfix: add Tntnet-application parameter to GnuTlsListener<commit_after>/* job.cpp
 * Copyright (C) 2003-2005 Tommi Maekitalo
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 */

#include "tnt/job.h"
#include "tnt/tcpjob.h"
#include "tnt/tntnet.h"
#include <tnt/httpreply.h>
#include <tnt/ssl.h>
#include <cxxtools/log.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <config.h>

log_define("tntnet.job")

namespace tnt
{
  unsigned Job::socket_read_timeout = 10;
  unsigned Job::socket_write_timeout = 10000;
  unsigned Job::keepalive_max = 1000;
  unsigned Job::socket_buffer_size = 16384;

  Job::~Job()
  { }

  unsigned Job::addRef()
  {
    cxxtools::MutexLock lock(mutex);
    return ++refs;
  }

  unsigned Job::release()
  {
    mutex.lock();
    if (--refs == 0)
    {
      mutex.unlock();
      delete this;
      return 0;
    }
    else
    {
      mutex.unlock();
      return refs;
    }
  }

  void Job::clear()
  {
    parser.reset();
    request.clear();
    touch();
  }

  int Job::msecToTimeout(time_t currentTime) const
  {
    return (lastAccessTime - currentTime + 1) * 1000
         + getKeepAliveTimeout()
         - getSocketReadTimeout();
  }

  unsigned Job::getKeepAliveTimeout()
  {
    return HttpReply::getKeepAliveTimeout();
  }

  ////////////////////////////////////////////////////////////////////////
  // Tcpjob
  //
  void Tcpjob::accept()
  {
    log_debug("accept");
    socket.accept(listener);

    struct sockaddr_storage s = socket.getSockAddr();
    struct sockaddr_storage sockaddr;
    memcpy(&sockaddr, &s, sizeof(sockaddr));

    char buffer[INET6_ADDRSTRLEN];
    log_debug("connection accepted from "
      << inet_ntop(AF_INET6, &(socket.getPeeraddr()), buffer, sizeof(buffer)));

    getRequest().setPeerAddr(socket.getPeeraddr());
    getRequest().setServerAddr(sockaddr);
    getRequest().setSsl(false);
    touch();
  }

  std::iostream& Tcpjob::getStream()
  {
    if (socket.cxxtools::net::Socket::bad())
    {
      accept();
      log_debug("connection accepted");
      if (!Tntnet::shouldStop())
        queue.put(new Tcpjob(getRequest().getApplication(), listener, queue));
      else
        log_info("tntnet stopping - no new job is generated");
    }
    return socket;
  }

  int Tcpjob::getFd() const
  {
    return socket.getFd();
  }

  void Tcpjob::setRead()
  {
    socket.setTimeout(getSocketReadTimeout());
  }

  void Tcpjob::setWrite()
  {
    socket.setTimeout(getSocketWriteTimeout());
  }

#ifdef USE_SSL
  ////////////////////////////////////////////////////////////////////////
  // SslTcpjob
  //
  void SslTcpjob::accept()
  {
    log_debug("accept (ssl)");
    socket.accept(listener);
    log_debug("connection accepted (ssl)");

    struct sockaddr_storage s = socket.getSockAddr();
    struct sockaddr_storage sockaddr;
    memcpy(&sockaddr, &s, sizeof(sockaddr));

    getRequest().setPeerAddr(socket.getPeeraddr());
    getRequest().setServerAddr(sockaddr);
    getRequest().setSsl(true);

    setRead();
    touch();
  }

  std::iostream& SslTcpjob::getStream()
  {
    if (socket.cxxtools::net::Socket::bad())
    {
      accept();
      log_debug("connection accepted");
      if (!Tntnet::shouldStop())
        queue.put(new SslTcpjob(getRequest().getApplication(), listener, queue));
      else
        log_info("tntnet stopping - no new ssl-job is generated");
    }
    return socket;
  }

  int SslTcpjob::getFd() const
  {
    return socket.getFd();
  }

  void SslTcpjob::setRead()
  {
    socket.setTimeout(getSocketReadTimeout());
  }

  void SslTcpjob::setWrite()
  {
    socket.setTimeout(getSocketWriteTimeout());
  }

#endif // USE_SSL

#ifdef USE_GNUTLS
  ////////////////////////////////////////////////////////////////////////
  // GnuTlsTcpjob
  //
  void GnuTlsTcpjob::accept()
  {
    log_debug("accept (ssl)");
    accept();
    log_debug("connection accepted (ssl)");

    struct sockaddr_storage s = socket.getSockAddr();
    struct sockaddr_storage sockaddr;
    memcpy(&sockaddr, &s, sizeof(sockaddr));

    getRequest().setPeerAddr(socket.getPeeraddr());
    getRequest().setServerAddr(sockaddr);
    getRequest().setSsl(true);

    setRead();
    touch();
  }

  std::iostream& GnuTlsTcpjob::getStream()
  {
    if (socket.cxxtools::net::Socket::bad())
    {
      accept();
      log_debug("connection accepted");
      if (!Tntnet::shouldStop())
        queue.put(new GnuTlsTcpjob(getRequest().getApplication(), listener, queue));
      else
        log_info("tntnet stopping - no new ssl-job is generated");
    }
    return socket;
  }

  int GnuTlsTcpjob::getFd() const
  {
    return socket.getFd();
  }

  void GnuTlsTcpjob::setRead()
  {
    socket.setTimeout(getSocketReadTimeout());
  }

  void GnuTlsTcpjob::setWrite()
  {
    socket.setTimeout(getSocketWriteTimeout());
  }

#endif // USE_GNUTLS

  //////////////////////////////////////////////////////////////////////
  // Jobqueue
  //
  void Jobqueue::put(JobPtr j, bool force)
  {
    log_debug("Jobqueue::put");
    j->touch();

    cxxtools::MutexLock lock(mutex);

    if (!force && capacity > 0)
    {
      while (jobs.size() >= capacity)
      {
        log_warn("Jobqueue full");
        notFull.wait(lock);
      }
    }

    log_debug("jobs.push");
    jobs.push_back(j);

    if (waitThreads == 0)
    {
      log_info("no waiting threads left");
      noWaitThreads.signal();
    }

    notEmpty.signal();
  }

  Jobqueue::JobPtr Jobqueue::get()
  {
    cxxtools::MutexLock lock(mutex);

    // wait, until a job is available
    ++waitThreads;

    log_debug("wait for job (" << jobs.size() << " jobs available)");

    while (jobs.empty())
      notEmpty.wait(lock);

    --waitThreads;

    log_debug("Jobqueue: fetch job " << waitThreads << " waiting threads left; " << jobs.size() << " jobs in queue");

    // take next job (queue is locked)
    JobPtr j = jobs.front();
    jobs.pop_front();

    // if there are threads waiting, wake another
    if (!jobs.empty() && waitThreads > 0)
    {
      log_debug("signal another thread");
      notEmpty.signal();
    }
    notFull.signal();

    return j;
  }

}
<|endoftext|>