<commit_before>#ifndef _BACKUP_H_
#define _BACKUP_H_

#include "cmdline.hpp"

class Backup
{
public:
	Backup();
	Backup(const string &filename);
	bool execute(const vector<string> &lhs, const vector<string &rhs);
	//virtual bool isValid() = 0;
};

#endif
<commit_msg>added backup<commit_after>#ifndef _BACKUP_H_
#define _BACKUP_H_

#include "cmdline.hpp"

class Backup
{
public:
	Backup();
	Backup(const string &filename);
	bool execute(const vector<string> &lhs, const vector<string> &rhs);
	//virtual bool isValid() = 0;
};

#endif
<|endoftext|>


<commit_before>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2019 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <banman.h>

#include <netaddress.h>
#include <node/ui_interface.h>
#include <util/system.h>
#include <util/time.h>
#include <util/translation.h>

BanMan::BanMan(fs::path ban_file, CClientUIInterface* client_interface, int64_t default_ban_time)
    : m_client_interface(client_interface), m_ban_db(std::move(ban_file)), m_default_ban_time(default_ban_time)
{
    if (m_client_interface) m_client_interface->InitMessage(_("Loading banlist...").translated);

    int64_t n_start = GetTimeMillis();
    m_is_dirty = false;
    banmap_t banmap;
    if (m_ban_db.Read(banmap)) {
        SetBanned(banmap);        // thread save setter
        SetBannedSetDirty(false); // no need to write down, just read data
        SweepBanned();            // sweep out unused entries

        LogPrint(BCLog::NET, "Loaded %d banned node ips/subnets from banlist.dat  %dms\n",
            banmap.size(), GetTimeMillis() - n_start);
    } else {
        LogPrintf("Invalid or missing banlist.dat; recreating\n");
        SetBannedSetDirty(true); // force write
        DumpBanlist();
    }
}

BanMan::~BanMan()
{
    DumpBanlist();
}

void BanMan::DumpBanlist()
{
    SweepBanned(); // clean unused entries (if bantime has expired)

    if (!BannedSetIsDirty()) return;

    int64_t n_start = GetTimeMillis();

    banmap_t banmap;
    GetBanned(banmap);
    if (m_ban_db.Write(banmap)) {
        SetBannedSetDirty(false);
    }

    LogPrint(BCLog::NET, "Flushed %d banned node ips/subnets to banlist.dat  %dms\n",
        banmap.size(), GetTimeMillis() - n_start);
}

void BanMan::ClearBanned()
{
    {
        LOCK(m_cs_banned);
        m_banned.clear();
        m_is_dirty = true;
    }
    DumpBanlist(); //store banlist to disk
    if (m_client_interface) m_client_interface->BannedListChanged();
}

bool BanMan::IsDiscouraged(const CNetAddr& net_addr)
{
    LOCK(m_cs_banned);
    return m_discouraged.contains(net_addr.GetAddrBytes());
}

bool BanMan::IsBanned(const CNetAddr& net_addr)
{
    auto current_time = GetTime();
    LOCK(m_cs_banned);
    for (const auto& it : m_banned) {
        CSubNet sub_net = it.first;
        CBanEntry ban_entry = it.second;

        if (current_time < ban_entry.nBanUntil && sub_net.Match(net_addr)) {
            return true;
        }
    }
    return false;
}

bool BanMan::IsBanned(const CSubNet& sub_net)
{
    auto current_time = GetTime();
    LOCK(m_cs_banned);
    banmap_t::iterator i = m_banned.find(sub_net);
    if (i != m_banned.end()) {
        CBanEntry ban_entry = (*i).second;
        if (current_time < ban_entry.nBanUntil) {
            return true;
        }
    }
    return false;
}

void BanMan::Ban(const CNetAddr& net_addr, int64_t ban_time_offset, bool since_unix_epoch)
{
    CSubNet sub_net(net_addr);
    Ban(sub_net, ban_time_offset, since_unix_epoch);
}

void BanMan::Discourage(const CNetAddr& net_addr)
{
    LOCK(m_cs_banned);
    m_discouraged.insert(net_addr.GetAddrBytes());
}

void BanMan::Ban(const CSubNet& sub_net, int64_t ban_time_offset, bool since_unix_epoch)
{
    CBanEntry ban_entry(GetTime());

    int64_t normalized_ban_time_offset = ban_time_offset;
    bool normalized_since_unix_epoch = since_unix_epoch;
    if (ban_time_offset <= 0) {
        normalized_ban_time_offset = m_default_ban_time;
        normalized_since_unix_epoch = false;
    }
    ban_entry.nBanUntil = (normalized_since_unix_epoch ? 0 : GetTime()) + normalized_ban_time_offset;

    {
        LOCK(m_cs_banned);
        if (m_banned[sub_net].nBanUntil < ban_entry.nBanUntil) {
            m_banned[sub_net] = ban_entry;
            m_is_dirty = true;
        } else
            return;
    }
    if (m_client_interface) m_client_interface->BannedListChanged();

    //store banlist to disk immediately
    DumpBanlist();
}

bool BanMan::Unban(const CNetAddr& net_addr)
{
    CSubNet sub_net(net_addr);
    return Unban(sub_net);
}

bool BanMan::Unban(const CSubNet& sub_net)
{
    {
        LOCK(m_cs_banned);
        if (m_banned.erase(sub_net) == 0) return false;
        m_is_dirty = true;
    }
    if (m_client_interface) m_client_interface->BannedListChanged();
    DumpBanlist(); //store banlist to disk immediately
    return true;
}

void BanMan::GetBanned(banmap_t& banmap)
{
    LOCK(m_cs_banned);
    // Sweep the banlist so expired bans are not returned
    SweepBanned();
    banmap = m_banned; //create a thread safe copy
}

void BanMan::SetBanned(const banmap_t& banmap)
{
    LOCK(m_cs_banned);
    m_banned = banmap;
    m_is_dirty = true;
}

void BanMan::SweepBanned()
{
    int64_t now = GetTime();
    bool notify_ui = false;
    {
        LOCK(m_cs_banned);
        banmap_t::iterator it = m_banned.begin();
        while (it != m_banned.end()) {
            CSubNet sub_net = (*it).first;
            CBanEntry ban_entry = (*it).second;
            if (now > ban_entry.nBanUntil) {
                m_banned.erase(it++);
                m_is_dirty = true;
                notify_ui = true;
                LogPrint(BCLog::NET, "%s: Removed banned node ip/subnet from banlist.dat: %s\n", __func__, sub_net.ToString());
            } else
                ++it;
        }
    }
    // update UI
    if (notify_ui && m_client_interface) {
        m_client_interface->BannedListChanged();
    }
}

bool BanMan::BannedSetIsDirty()
{
    LOCK(m_cs_banned);
    return m_is_dirty;
}

void BanMan::SetBannedSetDirty(bool dirty)
{
    LOCK(m_cs_banned); //reuse m_banned lock for the m_is_dirty flag
    m_is_dirty = dirty;
}
<commit_msg>banlist: log post-swept banlist size at startup<commit_after>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2019 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <banman.h>

#include <netaddress.h>
#include <node/ui_interface.h>
#include <util/system.h>
#include <util/time.h>
#include <util/translation.h>

BanMan::BanMan(fs::path ban_file, CClientUIInterface* client_interface, int64_t default_ban_time)
    : m_client_interface(client_interface), m_ban_db(std::move(ban_file)), m_default_ban_time(default_ban_time)
{
    if (m_client_interface) m_client_interface->InitMessage(_("Loading banlist...").translated);

    int64_t n_start = GetTimeMillis();
    m_is_dirty = false;
    banmap_t banmap;
    if (m_ban_db.Read(banmap)) {
        SetBanned(banmap);        // thread save setter
        SetBannedSetDirty(false); // no need to write down, just read data
        SweepBanned();            // sweep out unused entries

        LogPrint(BCLog::NET, "Loaded %d banned node ips/subnets from banlist.dat  %dms\n",
            m_banned.size(), GetTimeMillis() - n_start);
    } else {
        LogPrintf("Invalid or missing banlist.dat; recreating\n");
        SetBannedSetDirty(true); // force write
        DumpBanlist();
    }
}

BanMan::~BanMan()
{
    DumpBanlist();
}

void BanMan::DumpBanlist()
{
    SweepBanned(); // clean unused entries (if bantime has expired)

    if (!BannedSetIsDirty()) return;

    int64_t n_start = GetTimeMillis();

    banmap_t banmap;
    GetBanned(banmap);
    if (m_ban_db.Write(banmap)) {
        SetBannedSetDirty(false);
    }

    LogPrint(BCLog::NET, "Flushed %d banned node ips/subnets to banlist.dat  %dms\n",
        banmap.size(), GetTimeMillis() - n_start);
}

void BanMan::ClearBanned()
{
    {
        LOCK(m_cs_banned);
        m_banned.clear();
        m_is_dirty = true;
    }
    DumpBanlist(); //store banlist to disk
    if (m_client_interface) m_client_interface->BannedListChanged();
}

bool BanMan::IsDiscouraged(const CNetAddr& net_addr)
{
    LOCK(m_cs_banned);
    return m_discouraged.contains(net_addr.GetAddrBytes());
}

bool BanMan::IsBanned(const CNetAddr& net_addr)
{
    auto current_time = GetTime();
    LOCK(m_cs_banned);
    for (const auto& it : m_banned) {
        CSubNet sub_net = it.first;
        CBanEntry ban_entry = it.second;

        if (current_time < ban_entry.nBanUntil && sub_net.Match(net_addr)) {
            return true;
        }
    }
    return false;
}

bool BanMan::IsBanned(const CSubNet& sub_net)
{
    auto current_time = GetTime();
    LOCK(m_cs_banned);
    banmap_t::iterator i = m_banned.find(sub_net);
    if (i != m_banned.end()) {
        CBanEntry ban_entry = (*i).second;
        if (current_time < ban_entry.nBanUntil) {
            return true;
        }
    }
    return false;
}

void BanMan::Ban(const CNetAddr& net_addr, int64_t ban_time_offset, bool since_unix_epoch)
{
    CSubNet sub_net(net_addr);
    Ban(sub_net, ban_time_offset, since_unix_epoch);
}

void BanMan::Discourage(const CNetAddr& net_addr)
{
    LOCK(m_cs_banned);
    m_discouraged.insert(net_addr.GetAddrBytes());
}

void BanMan::Ban(const CSubNet& sub_net, int64_t ban_time_offset, bool since_unix_epoch)
{
    CBanEntry ban_entry(GetTime());

    int64_t normalized_ban_time_offset = ban_time_offset;
    bool normalized_since_unix_epoch = since_unix_epoch;
    if (ban_time_offset <= 0) {
        normalized_ban_time_offset = m_default_ban_time;
        normalized_since_unix_epoch = false;
    }
    ban_entry.nBanUntil = (normalized_since_unix_epoch ? 0 : GetTime()) + normalized_ban_time_offset;

    {
        LOCK(m_cs_banned);
        if (m_banned[sub_net].nBanUntil < ban_entry.nBanUntil) {
            m_banned[sub_net] = ban_entry;
            m_is_dirty = true;
        } else
            return;
    }
    if (m_client_interface) m_client_interface->BannedListChanged();

    //store banlist to disk immediately
    DumpBanlist();
}

bool BanMan::Unban(const CNetAddr& net_addr)
{
    CSubNet sub_net(net_addr);
    return Unban(sub_net);
}

bool BanMan::Unban(const CSubNet& sub_net)
{
    {
        LOCK(m_cs_banned);
        if (m_banned.erase(sub_net) == 0) return false;
        m_is_dirty = true;
    }
    if (m_client_interface) m_client_interface->BannedListChanged();
    DumpBanlist(); //store banlist to disk immediately
    return true;
}

void BanMan::GetBanned(banmap_t& banmap)
{
    LOCK(m_cs_banned);
    // Sweep the banlist so expired bans are not returned
    SweepBanned();
    banmap = m_banned; //create a thread safe copy
}

void BanMan::SetBanned(const banmap_t& banmap)
{
    LOCK(m_cs_banned);
    m_banned = banmap;
    m_is_dirty = true;
}

void BanMan::SweepBanned()
{
    int64_t now = GetTime();
    bool notify_ui = false;
    {
        LOCK(m_cs_banned);
        banmap_t::iterator it = m_banned.begin();
        while (it != m_banned.end()) {
            CSubNet sub_net = (*it).first;
            CBanEntry ban_entry = (*it).second;
            if (now > ban_entry.nBanUntil) {
                m_banned.erase(it++);
                m_is_dirty = true;
                notify_ui = true;
                LogPrint(BCLog::NET, "%s: Removed banned node ip/subnet from banlist.dat: %s\n", __func__, sub_net.ToString());
            } else
                ++it;
        }
    }
    // update UI
    if (notify_ui && m_client_interface) {
        m_client_interface->BannedListChanged();
    }
}

bool BanMan::BannedSetIsDirty()
{
    LOCK(m_cs_banned);
    return m_is_dirty;
}

void BanMan::SetBannedSetDirty(bool dirty)
{
    LOCK(m_cs_banned); //reuse m_banned lock for the m_is_dirty flag
    m_is_dirty = dirty;
}
<|endoftext|>


<commit_before>/*
 base64.cpp and base64.h

 Copyright (C) 2004-2008 René Nyffenegger

 This source code is provided 'as-is', without any express or implied
 warranty. In no event will the author be held liable for any damages
 arising from the use of this software.

 Permission is granted to anyone to use this software for any purpose,
 including commercial applications, and to alter it and redistribute it
 freely, subject to the following restrictions:

 1. The origin of this source code must not be misrepresented; you must not
 claim that you wrote the original source code. If you use this source code
 in a product, an acknowledgment in the product documentation would be
 appreciated but is not required.

 2. Altered source versions must be plainly marked as such, and must not be
 misrepresented as being the original source code.

 3. This notice may not be removed or altered from any source distribution.

 René Nyffenegger rene.nyffenegger@adp-gmbh.ch

 */

#include "base64.hpp"
#include <iostream>

static const std::string base64_chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";

static inline bool is_base64(unsigned char c) {
	return (isalnum(c) || (c == '+') || (c == '/'));
}

std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len) {
	std::string ret;
	int i = 0;
	int j = 0;
	unsigned char char_array_3[3];
	unsigned char char_array_4[4];

	while (in_len--) {
		char_array_3[i++] = *(bytes_to_encode++);
		if (i == 3) {
			char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
			char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
			char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
			char_array_4[3] = char_array_3[2] & 0x3f;

			for(i = 0; (i <4) ; i++)
				ret += base64_chars[char_array_4[i]];
			i = 0;
		}
	}

	if (i)
	{
		for(j = i; j < 3; j++)
			char_array_3[j] = '\0';

		char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
		char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
		char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
		char_array_4[3] = char_array_3[2] & 0x3f;

		for (j = 0; (j < i + 1); j++)
			ret += base64_chars[char_array_4[j]];

		while((i++ < 3))
			ret += '=';

	}

	return ret;

}

std::string base64_decode(std::string const& encoded_string) {
	int in_len = encoded_string.size();
	int i = 0;
	int j = 0;
	int in_ = 0;
	unsigned char char_array_4[4], char_array_3[3];
	std::string ret;

	while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {
		char_array_4[i++] = encoded_string[in_]; in_++;
		if (i ==4) {
			for (i = 0; i <4; i++)
				char_array_4[i] = base64_chars.find(char_array_4[i]);

			char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
			char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
			char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];

			for (i = 0; (i < 3); i++)
				ret += char_array_3[i];
			i = 0;
		}
	}

	if (i) {
		for (j = i; j <4; j++)
			char_array_4[j] = 0;

		for (j = 0; j <4; j++)
			char_array_4[j] = base64_chars.find(char_array_4[j]);

		char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
		char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
		char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];

		for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
	}

	return ret;
}
<commit_msg>use strfnd not std::string::find char * is much lighter than std::string<commit_after>/*
 base64.cpp and base64.h

 Copyright (C) 2004-2008 René Nyffenegger

 This source code is provided 'as-is', without any express or implied
 warranty. In no event will the author be held liable for any damages
 arising from the use of this software.

 Permission is granted to anyone to use this software for any purpose,
 including commercial applications, and to alter it and redistribute it
 freely, subject to the following restrictions:

 1. The origin of this source code must not be misrepresented; you must not
 claim that you wrote the original source code. If you use this source code
 in a product, an acknowledgment in the product documentation would be
 appreciated but is not required.

 2. Altered source versions must be plainly marked as such, and must not be
 misrepresented as being the original source code.

 3. This notice may not be removed or altered from any source distribution.

 René Nyffenegger rene.nyffenegger@adp-gmbh.ch

 */

#include "base64.hpp"
#include <iostream>

static const char * const base64_chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";

static inline bool is_base64(unsigned char c) {
	return (isalnum(c) || (c == '+') || (c == '/'));
}

std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len) {
	std::string ret;
	int i = 0;
	int j = 0;
	unsigned char char_array_3[3];
	unsigned char char_array_4[4];

	while (in_len--) {
		char_array_3[i++] = *(bytes_to_encode++);
		if (i == 3) {
			char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
			char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
			char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
			char_array_4[3] = char_array_3[2] & 0x3f;

			for(i = 0; (i <4) ; i++)
				ret += base64_chars[char_array_4[i]];
			i = 0;
		}
	}

	if (i)
	{
		for(j = i; j < 3; j++)
			char_array_3[j] = '\0';

		char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
		char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
		char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
		char_array_4[3] = char_array_3[2] & 0x3f;

		for (j = 0; (j < i + 1); j++)
			ret += base64_chars[char_array_4[j]];

		while((i++ < 3))
			ret += '=';

	}

	return ret;

}

inline int strfnd(const char *str, char ch)
{
  return static_cast<int>(strchr(str, ch) - str);
}

std::string base64_decode(std::string const& encoded_string) {
	int in_len = encoded_string.size();
	int i = 0;
	int j = 0;
	int in_ = 0;
	unsigned char char_array_4[4], char_array_3[3];
	std::string ret;

	while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {
		char_array_4[i++] = encoded_string[in_]; in_++;
		if (i ==4) {
			for (i = 0; i <4; i++) {
				char_array_4[i] = strfnd(base64_chars, char_array_4[i]);
			}

			char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
			char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
			char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];

			for (i = 0; (i < 3); i++)
				ret += char_array_3[i];
			i = 0;
		}
	}

	if (i) {
		for (j = i; j <4; j++)
			char_array_4[j] = 0;

		for (j = 0; j <4; j++)
			char_array_4[j] = strfnd(base64_chars, char_array_4[j]);

		char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
		char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
		char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];

		for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
	}

	return ret;
}
<|endoftext|>


<commit_before>#ifndef _clause_hpp_INCLUDED
#define _clause_hpp_INCLUDED

#include <cstdlib>

namespace CaDiCaL {

// The 'Clause' data structure is very important. There are usually many
// clauses and accessing them is a hot-spot.  Thus we use three common
// optimizations to reduce their memory foot print and improve cache usage.
//
// (1) The most important optimization is to 'embed' the actual literals in
// the clause.  This requires a variadic size structure and thus strictly is
// not 'C' conformant, but supported by all compilers we used.  The
// alternative is to store the actual literals somewhere else, which
// not only needs more memory but more importantly also requires another
// memory access and thus is so costly that even for CaDiCaL we want to use
// this optimizations.
//
// (2) The boolean flags only need one bit each and thus there is enough
// space left to merge them with a 'glue' bit field (which is less accessed
// than 'size').  This saves 4 bytes and also keeps the header without
// 'resolved' nicely in 8 bytes.  We currently use 28 bits and actually
// since we do not want to mess with 'unsigned' versus 'signed' issues just
// use 27 out of them.  If more boolean flags are needed this number has to
// be adapted accordingly.
//
// (3) Since original clauses and clauses which are kept anyhow do not need
// the activity counter 'resolved', we can omit these 8 bytes for these.
// Clauses which have a 'resolved' field are called 'extended'.  The other
// clauses are actually allocated with 8 bytes less and accessing 'resolved'
// for them is not allowed.
//
// With these three optimizations a binary original clause only needs 16
// bytes instead of 40 bytes without embedding and 32 bytes with embedding
// the literals.  The last two optimizations reduce memory usage of very
// large formulas slightly but are otherwise not that important.
//
// If you want to add few additional boolean flags add them after the
// sequence of already existing ones.  This makes sure that these bits and
// the following 'glue' field are put into a 4 byte word. Of course you need
// to adapt 'LD_MAX_GLUE' accordingly.  Adding one flag reduces it by one.
//
// Similarly if you want to add more data to extended clauses put these
// fields after 'resolved' and before the flags section.  Then adapt the
// 'EXTENDED_OFFSET' accordingly.  You might need to consider padding though
// on some architectures, since misaligned pointer access might happen.
// For instance if you want to add a 4 byte 'int data' field, then you
// should also add a 'int padding' field, just to enforce that the
// 'resolved' field is always 8 byte aligned.  Here we assume that 'new'
// returns 8 bytes aligned memory, which on those systems which care about
// alignment is true for for sure.
//
// Additional fields needed for all clauses are savely put between 'glue'
// and 'size' without the need to change anything else.  In general these
// optimizations are local to 'clause.[hc]pp' and otherwise can be ignored
// except that you should for instance never access 'resolved' of a clauses
// which is not extended.  This can be checked with for instance 'valgrind'
// but is also guarded by making the actual '_resolved' field private and
// checking this contract in the 'resolved ()' accessor functions.

#define LD_MAX_GLUE     28      // 32 - 4 boolean flags
#define EXTENDED_OFFSET  8      // sizeof (resolved)

#define MAX_GLUE ((1<<(LD_MAX_GLUE-1))-1)

class Clause {

  long _resolved;        // time stamp when resolved last time

public:

  unsigned extended:1;  // 'resolved' field only valid this is true
  unsigned redundant:1; // aka 'learned' so not 'irredundant' (original)
  unsigned garbage:1;   // can be garbage collected unless it is a 'reason'
  unsigned reason:1;    // reason / antecedent clause can not be collected

  // This is the 'glue' = 'glucose level' = 'LBD' of a redundant clause.
  // We actually only use 'CLAUSE_LD_MAX_GLUE-1' bits since the field is
  // 'signed' to avoid surprises due to 'unsigned' versus 'sign' semantics.
  // Also note that 'C' does not explicitly define 'signedness' of 'int' bit
  // fields and thus we explicitly have to use 'signed' here (on an IBM main
  // frame or on Sparc 'int a:1' might be 'unsigned').
  //
  signed int glue : LD_MAX_GLUE;

  int size;             // actual size of 'literals' (at least 2)
  int literals[2];      // of variadic 'size' (not 2) in general

  static size_t bytes (int size) {
    return sizeof (Clause) + (size -2 ) * sizeof (int);
  }

  long & resolved () { assert (extended); return _resolved; }
  const long & resolved () const { assert (extended); return _resolved; }
};

struct resolved_earlier {
  bool operator () (const Clause * a, const Clause * b) {
    assert (a->extended), assert (b->extended);
    return a->resolved () < b->resolved ();
  }
};

};

#endif
<commit_msg>explained clause memory optimizations<commit_after>#ifndef _clause_hpp_INCLUDED
#define _clause_hpp_INCLUDED

#include <cstdlib>

namespace CaDiCaL {

// The 'Clause' data structure is very important. There are usually many
// clauses and accessing them is a hot-spot.  Thus we use three common
// optimizations to reduce their memory foot print and improve cache usage.
//
// (1) The most important optimization is to 'embed' the actual literals in
// the clause.  This requires a variadic size structure and thus strictly is
// not 'C' conformant, but supported by all compilers we used.  The
// alternative is to store the actual literals somewhere else, which
// not only needs more memory but more importantly also requires another
// memory access and thus is so costly that even for CaDiCaL we want to use
// this optimizations.
//
// (2) The boolean flags only need one bit each and thus there is enough
// space left to merge them with a 'glue' bit field (which is less accessed
// than 'size').  This saves 4 bytes and also keeps the header without
// 'resolved' nicely in 8 bytes.  We currently use 28 bits and actually
// since we do not want to mess with 'unsigned' versus 'signed' issues just
// use 27 out of them.  If more boolean flags are needed this number has to
// be adapted accordingly.
//
// (3) Original clauses and clauses with small glue or size are kept anyhow and o
// not need the activity counter 'resolved'.  Thus we can omit these 8 bytes for
// these clauses.  Redundant clauses of long size and with large glue have a
// 'resolved' field and are called 'extended'.  The non extended clauses need 8
// bytes less and accessing 'resolved' for them is not allowed.
//
// With these three optimizations a binary original clause only needs 16
// bytes instead of 40 bytes without embedding and 32 bytes with embedding
// the literals.  The last two optimizations reduce memory usage of very
// large formulas slightly but are otherwise not that important.
//
// If you want to add few additional boolean flags add them after the
// sequence of already existing ones.  This makes sure that these bits and
// the following 'glue' field are put into a 4 byte word by the compiler. Of course
// you need to adapt 'LD_MAX_GLUE' accordingly.  Adding one flag reduces it by one.
//
// Similarly if you want to add more data to extended clauses put these
// fields after 'resolved' and before the flags section.  Then adapt the
// 'EXTENDED_OFFSET' accordingly.  You might need to consider padding though
// on some architectures, since misaligned pointer access might happen.
// For instance if you want to add a 4 byte 'int data' field, then you
// should also add a 'int padding' field, just to enforce that the
// 'resolved' field is always 8 byte aligned.  Here we assume that 'new'
// returns 8 bytes aligned memory, which on those systems which care about
// alignment is true for sure.
//
// Additional fields needed for all clauses are savely put between 'glue'
// and 'size' without the need to change anything else.  In general these
// optimizations are local to 'clause.[hc]pp' and otherwise can be ignored
// except that you should for instance never access 'resolved' of a clauses
// which is not extended.  This can be checked with for instance 'valgrind'
// but is also guarded by making the actual '_resolved' field private and
// checking this contract in the 'resolved ()' accessor functions.

#define LD_MAX_GLUE     28      // 32 - 4 boolean flags
#define EXTENDED_OFFSET  8      // sizeof (resolved)

#define MAX_GLUE ((1<<(LD_MAX_GLUE-1))-1)

class Clause {

  long _resolved;        // time stamp when resolved last time

public:

  unsigned extended:1;  // 'resolved' field only valid this is true
  unsigned redundant:1; // aka 'learned' so not 'irredundant' (original)
  unsigned garbage:1;   // can be garbage collected unless it is a 'reason'
  unsigned reason:1;    // reason / antecedent clause can not be collected

  // This is the 'glue' = 'glucose level' = 'LBD' of a redundant clause.
  // We actually only use 'CLAUSE_LD_MAX_GLUE-1' bits since the field is
  // 'signed' to avoid surprises due to 'unsigned' versus 'sign' semantics.
  // Also note that 'C' does not explicitly define 'signedness' of 'int' bit
  // fields and thus we explicitly have to use 'signed' here (on an IBM main
  // frame or on Sparc 'int a:1' might be 'unsigned').
  //
  signed int glue : LD_MAX_GLUE;

  int size;             // actual size of 'literals' (at least 2)
  int literals[2];      // of variadic 'size' (not 2) in general

  static size_t bytes (int size) {
    return sizeof (Clause) + (size -2 ) * sizeof (int);
  }

  long & resolved () { assert (extended); return _resolved; }
  const long & resolved () const { assert (extended); return _resolved; }
};

struct resolved_earlier {
  bool operator () (const Clause * a, const Clause * b) {
    assert (a->extended), assert (b->extended);
    return a->resolved () < b->resolved ();
  }
};

};

#endif
<|endoftext|>


<commit_before>#include "client.hpp"

#include "MemcachedAsyncProgressWorker.hpp"
#include "Job/SetJob.hpp"
#include "Job/GetJob.hpp"
#include "Job/TouchJob.hpp"
#include "Job/IncrementJob.hpp"
#include "Job/DecrementJob.hpp"
#include "Job/PrependJob.hpp"
#include "Job/AppendJob.hpp"
#include "Job/DeleteJob.hpp"
#include "Job/ExistJob.hpp"
#include "Job/ReplaceJob.hpp"
#include "Job/CasJob.hpp"
#include "Job/MGetJob.hpp"
#include "Job/FetchResultJob.hpp"
#include "Job/MGetAndFetchAllJob.hpp"

using namespace MemcachedNative;

using v8::Local;
using v8::Value;
using v8::Exception;
using v8::Object;

using Nan::AsyncProgressWorker;
using Nan::Callback;

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

Client::Client(const char* config_string)
	: isRunning(false)
{
	this->client = memcached(config_string, strlen(config_string));
}

Client::~Client() { }

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

	// Prepare constructor template
	v8::Local<v8::FunctionTemplate> tpl = Nan::New<v8::FunctionTemplate>(New);
	tpl->SetClassName(Nan::New("Client").ToLocalChecked());
	tpl->InstanceTemplate()->SetInternalFieldCount(1);

	// Prototype
	Nan::SetPrototypeMethod(tpl, "start", Start);
	Nan::SetPrototypeMethod(tpl, "set", Set);
	Nan::SetPrototypeMethod(tpl, "get", Get);
	Nan::SetPrototypeMethod(tpl, "stop", Stop);
	Nan::SetPrototypeMethod(tpl, "touch", Touch);
	Nan::SetPrototypeMethod(tpl, "increment", Increment);
	Nan::SetPrototypeMethod(tpl, "decrement", Decrement);
	Nan::SetPrototypeMethod(tpl, "append", Append);
	Nan::SetPrototypeMethod(tpl, "prepend", Prepend);
	Nan::SetPrototypeMethod(tpl, "delete", Delete);
	Nan::SetPrototypeMethod(tpl, "exist", Exist);
	Nan::SetPrototypeMethod(tpl, "replace", Replace);
	Nan::SetPrototypeMethod(tpl, "cas", Cas);
	Nan::SetPrototypeMethod(tpl, "mget", MGet);
	Nan::SetPrototypeMethod(tpl, "fetch_result", FetchResult);
	Nan::SetPrototypeMethod(tpl, "mget_and_fetch_all", MGetAndFetchAll);

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

void Client::New(const Nan::FunctionCallbackInfo<v8::Value>& info) {
	if (info.IsConstructCall()) {
		v8::String::Utf8Value param1(info[0]->ToString());
		std::string from = std::string(*param1);

		const char* conf = info[0]->IsUndefined() ? "--SERVER=localhost" : from.c_str();

		Client* obj = new Client(conf);
		obj->Wrap(info.This());
		info.GetReturnValue().Set(info.This());
	} else {
		const int argc = 1;
		v8::Local<v8::Value> argv[argc] = { info[0] };
		v8::Local<v8::Function> cons = Nan::New<v8::Function>(constructor);
		info.GetReturnValue().Set(cons->NewInstance(argc, argv));
	}
}

void Client::Start(const Nan::FunctionCallbackInfo<v8::Value>& info) {
	Client* memClient = ObjectWrap::Unwrap<Client>(info.Holder());
	Callback* callback = new Callback(info[0].As<v8::Function>());

	memClient->isRunning = true;

	memClient->backgroundThread = new MemcachedAsyncProgressWorker(memClient, callback);
	Nan::AsyncQueueWorker(memClient->backgroundThread);

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

void Client::Set(const Nan::FunctionCallbackInfo<v8::Value>& info) {
	Client* memClient = ObjectWrap::Unwrap<Client>(info.Holder());

	v8::String::Utf8Value param0(info[0]->ToString());
	std::string param0String = std::string(*param0);
	char* memcached_key = (char*) malloc(param0String.length() * sizeof(char));
	strcpy(memcached_key, param0String.c_str());

	v8::String::Utf8Value param1(info[1]->ToString());
	std::string param1String = std::string(*param1);
	char* memcached_value = (char*) malloc(param1String.length() * sizeof(char));
	strcpy(memcached_value, param1String.c_str());

	time_t ttl = info[2]->NumberValue();

	Callback* callback = new Callback(info[3].As<v8::Function>());

	JobBase* job = new SetJob(memClient, callback, memcached_key, memcached_value, ttl);
	memClient->jobs.insert(job);

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

void Client::Get(const Nan::FunctionCallbackInfo<v8::Value>& info) {
	Client* memClient = ObjectWrap::Unwrap<Client>(info.Holder());

	v8::String::Utf8Value param0(info[0]->ToString());
	std::string param0String = std::string(*param0);
	char* memcached_key = (char*) malloc(param0String.length() * sizeof(char));
	strcpy(memcached_key, param0String.c_str());

	Callback* callback = new Callback(info[1].As<v8::Function>());

	JobBase* job = new GetJob(memClient, callback, memcached_key);
	memClient->jobs.insert(job);

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

void Client::Touch(const Nan::FunctionCallbackInfo<v8::Value>& info) {
	Client* memClient = ObjectWrap::Unwrap<Client>(info.Holder());

	v8::String::Utf8Value param0(info[0]->ToString());
	std::string param0String = std::string(*param0);
	char* memcached_key = (char*) malloc(param0String.length() * sizeof(char));
	strcpy(memcached_key, param0String.c_str());

	time_t ttl = info[1]->NumberValue();

	Callback* callback = new Callback(info[2].As<v8::Function>());

	JobBase* job = new TouchJob(memClient, callback, memcached_key, ttl);
	memClient->jobs.insert(job);

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

void Client::Increment(const Nan::FunctionCallbackInfo<v8::Value>& info) {
	Client* memClient = ObjectWrap::Unwrap<Client>(info.Holder());

	v8::String::Utf8Value param0(info[0]->ToString());
	std::string param0String = std::string(*param0);
	char* memcached_key = (char*) malloc(param0String.length() * sizeof(char));
	strcpy(memcached_key, param0String.c_str());

	uint32_t delta = info[1]->NumberValue();

	Callback* callback = new Callback(info[2].As<v8::Function>());

	JobBase* job = new IncrementJob(memClient, callback, memcached_key, delta);
	memClient->jobs.insert(job);

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

void Client::Decrement(const Nan::FunctionCallbackInfo<v8::Value>& info) {
	Client* memClient = ObjectWrap::Unwrap<Client>(info.Holder());

	v8::String::Utf8Value param0(info[0]->ToString());
	std::string param0String = std::string(*param0);
	char* memcached_key = (char*) malloc(param0String.length() * sizeof(char));
	strcpy(memcached_key, param0String.c_str());

	uint32_t delta = info[1]->NumberValue();

	Callback* callback = new Callback(info[2].As<v8::Function>());

	JobBase* job = new DecrementJob(memClient, callback, memcached_key, delta);
	memClient->jobs.insert(job);

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

void Client::Append(const Nan::FunctionCallbackInfo<v8::Value>& info) {
	Client* memClient = ObjectWrap::Unwrap<Client>(info.Holder());

	v8::String::Utf8Value param0(info[0]->ToString());
	std::string param0String = std::string(*param0);
	char* memcached_key = (char*) malloc(param0String.length() * sizeof(char));
	strcpy(memcached_key, param0String.c_str());

	v8::String::Utf8Value param1(info[1]->ToString());
	std::string param1String = std::string(*param1);
	char* memcached_value = (char*) malloc(param1String.length() * sizeof(char));
	strcpy(memcached_value, param1String.c_str());

	Callback* callback = new Callback(info[2].As<v8::Function>());

	JobBase* job = new AppendJob(memClient, callback, memcached_key, memcached_value);
	memClient->jobs.insert(job);

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

void Client::Prepend(const Nan::FunctionCallbackInfo<v8::Value>& info) {
	Client* memClient = ObjectWrap::Unwrap<Client>(info.Holder());

	v8::String::Utf8Value param0(info[0]->ToString());
	std::string param0String = std::string(*param0);
	char* memcached_key = (char*) malloc(param0String.length() * sizeof(char));
	strcpy(memcached_key, param0String.c_str());

	v8::String::Utf8Value param1(info[1]->ToString());
	std::string param1String = std::string(*param1);
	char* memcached_value = (char*) malloc(param1String.length() * sizeof(char));
	strcpy(memcached_value, param1String.c_str());

	Callback* callback = new Callback(info[2].As<v8::Function>());

	JobBase* job = new PrependJob(memClient, callback, memcached_key, memcached_value);
	memClient->jobs.insert(job);

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

void Client::Delete(const Nan::FunctionCallbackInfo<v8::Value>& info) {
	Client* memClient = ObjectWrap::Unwrap<Client>(info.Holder());

	v8::String::Utf8Value param0(info[0]->ToString());
	std::string param0String = std::string(*param0);
	char* memcached_key = (char*) malloc(param0String.length() * sizeof(char));
	strcpy(memcached_key, param0String.c_str());

	uint32_t expirationTime = info[1]->ToUint32()->Value();

	Callback* callback = new Callback(info[2].As<v8::Function>());

	JobBase* job = new DeleteJob(memClient, callback, memcached_key, expirationTime);
	memClient->jobs.insert(job);

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

void Client::Exist(const Nan::FunctionCallbackInfo<v8::Value>& info) {
	Client* memClient = ObjectWrap::Unwrap<Client>(info.Holder());

	v8::String::Utf8Value param0(info[0]->ToString());
	std::string param0String = std::string(*param0);
	char* memcached_key = (char*) malloc(param0String.length() * sizeof(char));
	strcpy(memcached_key, param0String.c_str());

	Callback* callback = new Callback(info[1].As<v8::Function>());

	JobBase* job = new ExistJob(memClient, callback, memcached_key);
	memClient->jobs.insert(job);

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

void Client::Replace(const Nan::FunctionCallbackInfo<v8::Value>& info) {
	Client* memClient = ObjectWrap::Unwrap<Client>(info.Holder());

	v8::String::Utf8Value param0(info[0]->ToString());
	std::string param0String = std::string(*param0);
	char* memcached_key = (char*) malloc(param0String.length() * sizeof(char));
	strcpy(memcached_key, param0String.c_str());

	v8::String::Utf8Value param1(info[1]->ToString());
	std::string param1String = std::string(*param1);
	char* memcached_value = (char*) malloc(param1String.length() * sizeof(char));
	strcpy(memcached_value, param1String.c_str());

	time_t ttl = info[2]->NumberValue();

	Callback* callback = new Callback(info[3].As<v8::Function>());

	JobBase* job = new ReplaceJob(memClient, callback, memcached_key, memcached_value, ttl);
	memClient->jobs.insert(job);

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

void Client::Cas(const Nan::FunctionCallbackInfo<v8::Value>& info) {
	Client* memClient = ObjectWrap::Unwrap<Client>(info.Holder());

	v8::String::Utf8Value param0(info[0]->ToString());
	std::string param0String = std::string(*param0);
	char* memcached_key = (char*) malloc(param0String.length() * sizeof(char));
	strcpy(memcached_key, param0String.c_str());

	v8::String::Utf8Value param1(info[1]->ToString());
	std::string param1String = std::string(*param1);
	char* memcached_value = (char*) malloc(param1String.length() * sizeof(char));
	strcpy(memcached_value, param1String.c_str());

	time_t ttl = info[2]->NumberValue();

	// String to uint64_t
	v8::String::Utf8Value param3(info[3]->ToString());
	std::string param3String = std::string(*param3);
	char* casString = (char*) malloc(param3String.length() * sizeof(char));
	strcpy(casString, param3String.c_str());
	uint64_t cas;
	sscanf(casString, "%" PRIu64, &cas);

	Callback* callback = new Callback(info[4].As<v8::Function>());

	JobBase* job = new CasJob(memClient, callback, memcached_key, memcached_value, ttl, cas);
	memClient->jobs.insert(job);

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

void Client::MGet(const Nan::FunctionCallbackInfo<v8::Value>& info) {
	Client* memClient = ObjectWrap::Unwrap<Client>(info.Holder());

	v8::Local<v8::Object> arr = info[0]->ToObject();
	size_t number_of_keys = arr->GetOwnPropertyNames()->Length();
	printf("%s %lu %s\n", "Array with", number_of_keys, "keys");
	char** keys = new char*[number_of_keys];
	for(size_t i = 0; i < number_of_keys; i++) {
		v8::String::Utf8Value param0(arr->Get(i)->ToString());
		std::string param0String = std::string(*param0);
		keys[i] = new char[param0String.length()];
		strcpy(keys[i], param0String.c_str());
	}

	Callback* callback = new Callback(info[1].As<v8::Function>());

	JobBase* job = new MGetJob(memClient, callback, keys, number_of_keys);
	memClient->jobs.insert(job);

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

void Client::FetchResult(const Nan::FunctionCallbackInfo<v8::Value>& info) {
	Client* memClient = ObjectWrap::Unwrap<Client>(info.Holder());

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

	JobBase* job = new FetchResultJob(memClient, callback);
	memClient->jobs.insert(job);

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

void Client::MGetAndFetchAll(const Nan::FunctionCallbackInfo<v8::Value>& info) {
	Client* memClient = ObjectWrap::Unwrap<Client>(info.Holder());

	v8::Local<v8::Object> arr = info[0]->ToObject();
	size_t number_of_keys = arr->GetOwnPropertyNames()->Length();
	printf("%s %lu %s\n", "Array with", number_of_keys, "keys");
	char** keys = new char*[number_of_keys];
	for(size_t i = 0; i < number_of_keys; i++) {
		v8::String::Utf8Value param0(arr->Get(i)->ToString());
		std::string param0String = std::string(*param0);
		keys[i] = new char[param0String.length()];
		strcpy(keys[i], param0String.c_str());
	}

	Callback* callback = new Callback(info[1].As<v8::Function>());

	JobBase* job = new MGetAndFetchAllJob(memClient, callback, keys, number_of_keys);
	memClient->jobs.insert(job);

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

void Client::Stop(const Nan::FunctionCallbackInfo<v8::Value>& info) {
	Client* memClient = ObjectWrap::Unwrap<Client>(info.Holder());

	memClient->backgroundThread->setCallback(new Callback(info[0].As<v8::Function>()));
	memClient->isRunning = false;
}
<commit_msg>Refactorize with getCharsFromParam<commit_after>#include "client.hpp"

#include "MemcachedAsyncProgressWorker.hpp"
#include "Job/SetJob.hpp"
#include "Job/GetJob.hpp"
#include "Job/TouchJob.hpp"
#include "Job/IncrementJob.hpp"
#include "Job/DecrementJob.hpp"
#include "Job/PrependJob.hpp"
#include "Job/AppendJob.hpp"
#include "Job/DeleteJob.hpp"
#include "Job/ExistJob.hpp"
#include "Job/ReplaceJob.hpp"
#include "Job/CasJob.hpp"
#include "Job/MGetJob.hpp"
#include "Job/FetchResultJob.hpp"
#include "Job/MGetAndFetchAllJob.hpp"

using namespace MemcachedNative;

using v8::Local;
using v8::Value;
using v8::Exception;
using v8::Object;

using Nan::AsyncProgressWorker;
using Nan::Callback;

char* getCharsFromParam(v8::Local<v8::String> param) {
	v8::String::Utf8Value param0(param);
	std::string param0String = std::string(*param0);
	char* value = new char[param0String.length()];
	strcpy(value, param0String.c_str());
	return value;
}

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

Client::Client(const char* config_string)
	: isRunning(false)
{
	this->client = memcached(config_string, strlen(config_string));
}

Client::~Client() { }

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

	// Prepare constructor template
	v8::Local<v8::FunctionTemplate> tpl = Nan::New<v8::FunctionTemplate>(New);
	tpl->SetClassName(Nan::New("Client").ToLocalChecked());
	tpl->InstanceTemplate()->SetInternalFieldCount(1);

	// Prototype
	Nan::SetPrototypeMethod(tpl, "start", Start);
	Nan::SetPrototypeMethod(tpl, "set", Set);
	Nan::SetPrototypeMethod(tpl, "get", Get);
	Nan::SetPrototypeMethod(tpl, "stop", Stop);
	Nan::SetPrototypeMethod(tpl, "touch", Touch);
	Nan::SetPrototypeMethod(tpl, "increment", Increment);
	Nan::SetPrototypeMethod(tpl, "decrement", Decrement);
	Nan::SetPrototypeMethod(tpl, "append", Append);
	Nan::SetPrototypeMethod(tpl, "prepend", Prepend);
	Nan::SetPrototypeMethod(tpl, "delete", Delete);
	Nan::SetPrototypeMethod(tpl, "exist", Exist);
	Nan::SetPrototypeMethod(tpl, "replace", Replace);
	Nan::SetPrototypeMethod(tpl, "cas", Cas);
	Nan::SetPrototypeMethod(tpl, "mget", MGet);
	Nan::SetPrototypeMethod(tpl, "fetch_result", FetchResult);
	Nan::SetPrototypeMethod(tpl, "mget_and_fetch_all", MGetAndFetchAll);

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

void Client::New(const Nan::FunctionCallbackInfo<v8::Value>& info) {
	if (info.IsConstructCall()) {
		v8::String::Utf8Value param1(info[0]->ToString());
		std::string from = std::string(*param1);

		const char* conf = info[0]->IsUndefined() ? "--SERVER=localhost" : from.c_str();

		Client* obj = new Client(conf);
		obj->Wrap(info.This());
		info.GetReturnValue().Set(info.This());
	} else {
		const int argc = 1;
		v8::Local<v8::Value> argv[argc] = { info[0] };
		v8::Local<v8::Function> cons = Nan::New<v8::Function>(constructor);
		info.GetReturnValue().Set(cons->NewInstance(argc, argv));
	}
}

void Client::Start(const Nan::FunctionCallbackInfo<v8::Value>& info) {
	Client* memClient = ObjectWrap::Unwrap<Client>(info.Holder());
	Callback* callback = new Callback(info[0].As<v8::Function>());

	memClient->isRunning = true;

	memClient->backgroundThread = new MemcachedAsyncProgressWorker(memClient, callback);
	Nan::AsyncQueueWorker(memClient->backgroundThread);

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

void Client::Set(const Nan::FunctionCallbackInfo<v8::Value>& info) {
	Client* memClient = ObjectWrap::Unwrap<Client>(info.Holder());

	char* memcached_key = getCharsFromParam(info[0]->ToString());
	char* memcached_value = getCharsFromParam(info[1]->ToString());

	time_t ttl = info[2]->NumberValue();

	Callback* callback = new Callback(info[3].As<v8::Function>());

	JobBase* job = new SetJob(memClient, callback, memcached_key, memcached_value, ttl);
	memClient->jobs.insert(job);

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

void Client::Get(const Nan::FunctionCallbackInfo<v8::Value>& info) {
	Client* memClient = ObjectWrap::Unwrap<Client>(info.Holder());

	char* memcached_key = getCharsFromParam(info[0]->ToString());

	Callback* callback = new Callback(info[1].As<v8::Function>());

	JobBase* job = new GetJob(memClient, callback, memcached_key);
	memClient->jobs.insert(job);

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

void Client::Touch(const Nan::FunctionCallbackInfo<v8::Value>& info) {
	Client* memClient = ObjectWrap::Unwrap<Client>(info.Holder());

	char* memcached_key = getCharsFromParam(info[0]->ToString());

	time_t ttl = info[1]->NumberValue();

	Callback* callback = new Callback(info[2].As<v8::Function>());

	JobBase* job = new TouchJob(memClient, callback, memcached_key, ttl);
	memClient->jobs.insert(job);

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

void Client::Increment(const Nan::FunctionCallbackInfo<v8::Value>& info) {
	Client* memClient = ObjectWrap::Unwrap<Client>(info.Holder());

	char* memcached_key = getCharsFromParam(info[0]->ToString());

	uint32_t delta = info[1]->NumberValue();

	Callback* callback = new Callback(info[2].As<v8::Function>());

	JobBase* job = new IncrementJob(memClient, callback, memcached_key, delta);
	memClient->jobs.insert(job);

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

void Client::Decrement(const Nan::FunctionCallbackInfo<v8::Value>& info) {
	Client* memClient = ObjectWrap::Unwrap<Client>(info.Holder());

	char* memcached_key = getCharsFromParam(info[0]->ToString());

	uint32_t delta = info[1]->NumberValue();

	Callback* callback = new Callback(info[2].As<v8::Function>());

	JobBase* job = new DecrementJob(memClient, callback, memcached_key, delta);
	memClient->jobs.insert(job);

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

void Client::Append(const Nan::FunctionCallbackInfo<v8::Value>& info) {
	Client* memClient = ObjectWrap::Unwrap<Client>(info.Holder());

	char* memcached_key = getCharsFromParam(info[0]->ToString());
	char* memcached_value = getCharsFromParam(info[1]->ToString());

	Callback* callback = new Callback(info[2].As<v8::Function>());

	JobBase* job = new AppendJob(memClient, callback, memcached_key, memcached_value);
	memClient->jobs.insert(job);

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

void Client::Prepend(const Nan::FunctionCallbackInfo<v8::Value>& info) {
	Client* memClient = ObjectWrap::Unwrap<Client>(info.Holder());

	char* memcached_key = getCharsFromParam(info[0]->ToString());
	char* memcached_value = getCharsFromParam(info[1]->ToString());

	Callback* callback = new Callback(info[2].As<v8::Function>());

	JobBase* job = new PrependJob(memClient, callback, memcached_key, memcached_value);
	memClient->jobs.insert(job);

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

void Client::Delete(const Nan::FunctionCallbackInfo<v8::Value>& info) {
	Client* memClient = ObjectWrap::Unwrap<Client>(info.Holder());

	char* memcached_key = getCharsFromParam(info[0]->ToString());

	uint32_t expirationTime = info[1]->ToUint32()->Value();

	Callback* callback = new Callback(info[2].As<v8::Function>());

	JobBase* job = new DeleteJob(memClient, callback, memcached_key, expirationTime);
	memClient->jobs.insert(job);

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

void Client::Exist(const Nan::FunctionCallbackInfo<v8::Value>& info) {
	Client* memClient = ObjectWrap::Unwrap<Client>(info.Holder());

	char* memcached_key = getCharsFromParam(info[0]->ToString());

	Callback* callback = new Callback(info[1].As<v8::Function>());

	JobBase* job = new ExistJob(memClient, callback, memcached_key);
	memClient->jobs.insert(job);

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

void Client::Replace(const Nan::FunctionCallbackInfo<v8::Value>& info) {
	Client* memClient = ObjectWrap::Unwrap<Client>(info.Holder());

	char* memcached_key = getCharsFromParam(info[0]->ToString());
	char* memcached_value = getCharsFromParam(info[1]->ToString());

	time_t ttl = info[2]->NumberValue();

	Callback* callback = new Callback(info[3].As<v8::Function>());

	JobBase* job = new ReplaceJob(memClient, callback, memcached_key, memcached_value, ttl);
	memClient->jobs.insert(job);

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

void Client::Cas(const Nan::FunctionCallbackInfo<v8::Value>& info) {
	Client* memClient = ObjectWrap::Unwrap<Client>(info.Holder());

	char* memcached_key = getCharsFromParam(info[0]->ToString());
	char* memcached_value = getCharsFromParam(info[1]->ToString());

	time_t ttl = info[2]->NumberValue();

	// String to uint64_t
	char* casString = getCharsFromParam(info[3]->ToString());
	uint64_t cas;
	sscanf(casString, "%" PRIu64, &cas);

	Callback* callback = new Callback(info[4].As<v8::Function>());

	JobBase* job = new CasJob(memClient, callback, memcached_key, memcached_value, ttl, cas);
	memClient->jobs.insert(job);

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

void Client::MGet(const Nan::FunctionCallbackInfo<v8::Value>& info) {
	Client* memClient = ObjectWrap::Unwrap<Client>(info.Holder());

	v8::Local<v8::Object> arr = info[0]->ToObject();
	size_t number_of_keys = arr->GetOwnPropertyNames()->Length();
	printf("%s %lu %s\n", "Array with", number_of_keys, "keys");
	char** keys = new char*[number_of_keys];
	for(size_t i = 0; i < number_of_keys; i++) {
		keys[i] = getCharsFromParam(arr->Get(i)->ToString());
	}

	Callback* callback = new Callback(info[1].As<v8::Function>());

	JobBase* job = new MGetJob(memClient, callback, keys, number_of_keys);
	memClient->jobs.insert(job);

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

void Client::FetchResult(const Nan::FunctionCallbackInfo<v8::Value>& info) {
	Client* memClient = ObjectWrap::Unwrap<Client>(info.Holder());

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

	JobBase* job = new FetchResultJob(memClient, callback);
	memClient->jobs.insert(job);

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

void Client::MGetAndFetchAll(const Nan::FunctionCallbackInfo<v8::Value>& info) {
	Client* memClient = ObjectWrap::Unwrap<Client>(info.Holder());

	v8::Local<v8::Object> arr = info[0]->ToObject();
	size_t number_of_keys = arr->GetOwnPropertyNames()->Length();
	printf("%s %lu %s\n", "Array with", number_of_keys, "keys");
	char** keys = new char*[number_of_keys];
	for(size_t i = 0; i < number_of_keys; i++) {
		keys[i] = getCharsFromParam(arr->Get(i)->ToString());
	}

	Callback* callback = new Callback(info[1].As<v8::Function>());

	JobBase* job = new MGetAndFetchAllJob(memClient, callback, keys, number_of_keys);
	memClient->jobs.insert(job);

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

void Client::Stop(const Nan::FunctionCallbackInfo<v8::Value>& info) {
	Client* memClient = ObjectWrap::Unwrap<Client>(info.Holder());

	memClient->backgroundThread->setCallback(new Callback(info[0].As<v8::Function>()));
	memClient->isRunning = false;
}
<|endoftext|>


<commit_before>#include <string.h>
#include <utils.h>
#include "command.h"
#include "../CmdHandler.h"
#include "../option.h"
#include "../strfmt.h"
#include "../stringparse.h"

/* full name of the command */
CMDNAME("xp");
/* description of the command */
CMDDESCR("query experience information");
/* command usage synopsis */
CMDUSAGE("$xp [-i|-r] NUM");
/* -r flag usage */
static const char *RUSAGE = "$xp -r START STOP";

#define MAX_XP 0xBEBC200

static int xptolvl(int x);
static int lvltoxp(int x);
static int xprange(char *out, struct command *c);

/* xp: query experience information */
int CmdHandler::xp(char *out, struct command *c)
{
	int inv, range, status;
	int64_t x;
	char num[RSN_BUF];

	int opt;
	static struct l_option long_opts[] = {
		{ "help", NO_ARG, 'h' },
		{ "inverse", NO_ARG, 'i' },
		{ "range", NO_ARG, 'r' },
		{ 0, 0, 0 }
	};

	inv = range = 0;
	status = EXIT_SUCCESS;
	opt_init();
	while ((opt = l_getopt_long(c->argc, c->argv, "ir", long_opts)) != EOF) {
		switch (opt) {
		case 'h':
			HELPMSG(out, CMDNAME, CMDUSAGE, CMDDESCR);
			return EXIT_SUCCESS;
		case 'i':
			inv = 1;
			break;
		case 'r':
			range = 1;
			break;
		case '?':
			_sprintf(out, MAX_MSG, "%s", l_opterr());
			return EXIT_FAILURE;
		default:
			return EXIT_FAILURE;
		}
	}

	if (range) {
		if (inv) {
			_sprintf(out, MAX_MSG, "%s: cannot use -i with -r",
					c->argv[0]);
			status = EXIT_FAILURE;
		} else {
			status = xprange(out, c);
		}
		return status;
	}

	if (l_optind != c->argc - 1) {
		USAGEMSG(out, CMDNAME, CMDUSAGE);
		return EXIT_FAILURE;
	}

	if (!parsenum(c->argv[l_optind], &x)) {
		_sprintf(out, MAX_MSG, "%s: invalid number: %s",
				c->argv[0], c->argv[l_optind]);
		return EXIT_FAILURE;
	}
	if (x < 0) {
		_sprintf(out, MAX_MSG, "%s: number cannot be "
				"negative", c->argv[0]);
		return EXIT_FAILURE;
	}

	if (inv) {
		if (x > MAX_XP) {
			_sprintf(out, MAX_MSG, "%s: xp cannot exceed 200m",
					c->argv[0]);
			status = EXIT_FAILURE;
		} else {
			fmtnum(num, RSN_BUF, c->argv[l_optind]);
			_sprintf(out, MAX_MSG, "[XP] %s xp: level %d",
					num, xptolvl(x));
		}
		return status;
	}

	if (x < 1 || x > 126) {
		_sprintf(out, MAX_MSG, "%s: level must be between 1-126",
				c->argv[0]);
		status = EXIT_FAILURE;
	} else {
		_sprintf(out, MAX_MSG, "%d", lvltoxp(x));
		fmtnum(num, RSN_BUF, out);
		_sprintf(out, MAX_MSG, "[XP] level %ld: ", x);
		strcat(out, num);
		strcat(out, " xp");
	}
	return status;
}

/* xptolvl: calculate the level at x xp */
static int xptolvl(int x)
{
	int n;

	n = 1;
	x *= 4;
	x += 1;
	while (x >= 0) {
		x -= floor(n + 300 * pow(2, n / 7.0));
		++n;
	}

	return n - 1;
}

/* lvltoxp: return xp required for level x */
static int lvltoxp(int x)
{
	int n, res;

	res = 0;
	for (n = 1; n < x; ++n)
		res += floor(n + 300 * pow(2, n / 7.0));
	res = floor(0.25 * res);

	return res;
}

/* xprange: calcuate the amount of xp between the levels in args */
static int xprange(char *out, struct command *c)
{
	int64_t x, y;
	char *a, *b;
	char num[RSN_BUF];

	if (l_optind == c->argc || l_optind < c->argc - 2) {
		USAGEMSG(out, CMDNAME, RUSAGE);
		return EXIT_FAILURE;
	}

	a = c->argv[l_optind];
	if (l_optind == c->argc - 1) {
		if (!(b = strchr(a, '-')) || !b[1]) {
			_sprintf(out, MAX_MSG, "%s: must provide two levels",
					c->argv[0]);
			return EXIT_FAILURE;
		}
		*b++ = '\0';
	} else {
		b = c->argv[l_optind + 1];
	}

	if (!parsenum(a, &x)) {
		_sprintf(out, MAX_MSG, "%s: invalid number: %s", c->argv[0], a);
		return EXIT_FAILURE;
	}
	if (x < 1 || x > 126) {
		_sprintf(out, MAX_MSG, "%s: level must be between 1-126",
				c->argv[0]);
		return EXIT_FAILURE;
	}
	if (!parsenum(b, &y)) {
		_sprintf(out, MAX_MSG, "%s: invalid number: %s", c->argv[0], b);
		return EXIT_FAILURE;
	}
	if (y < 1 || y > 126) {
		_sprintf(out, MAX_MSG, "%s: level must be between 1-126",
				c->argv[0]);
		return EXIT_FAILURE;
	}

	if (x > y) {
		_sprintf(out, MAX_MSG, "%s: invalid range", c->argv[0]);
		return EXIT_FAILURE;
	}

	x = lvltoxp(x);
	y = lvltoxp(y);

	_sprintf(out, MAX_MSG, "%ld", y - x);
	fmtnum(num, RSN_BUF, out);
	_sprintf(out, MAX_MSG, "[XP] level %s-%s: %s xp", a, b, num);
	return EXIT_SUCCESS;
}
<commit_msg>Change xp command to use parsenum_mult<commit_after>#include <string.h>
#include <utils.h>
#include "command.h"
#include "../CmdHandler.h"
#include "../option.h"
#include "../strfmt.h"
#include "../stringparse.h"

/* full name of the command */
CMDNAME("xp");
/* description of the command */
CMDDESCR("query experience information");
/* command usage synopsis */
CMDUSAGE("$xp [-i|-r] NUM");
/* -r flag usage */
static const char *RUSAGE = "$xp -r START STOP";

#define MAX_XP 0xBEBC200

static int xptolvl(int x);
static int lvltoxp(int x);
static int xprange(char *out, struct command *c);

/* xp: query experience information */
int CmdHandler::xp(char *out, struct command *c)
{
	int inv, range, status;
	int64_t x;
	char num[RSN_BUF];

	int opt;
	static struct l_option long_opts[] = {
		{ "help", NO_ARG, 'h' },
		{ "inverse", NO_ARG, 'i' },
		{ "range", NO_ARG, 'r' },
		{ 0, 0, 0 }
	};

	inv = range = 0;
	status = EXIT_SUCCESS;
	opt_init();
	while ((opt = l_getopt_long(c->argc, c->argv, "ir", long_opts)) != EOF) {
		switch (opt) {
		case 'h':
			HELPMSG(out, CMDNAME, CMDUSAGE, CMDDESCR);
			return EXIT_SUCCESS;
		case 'i':
			inv = 1;
			break;
		case 'r':
			range = 1;
			break;
		case '?':
			_sprintf(out, MAX_MSG, "%s", l_opterr());
			return EXIT_FAILURE;
		default:
			return EXIT_FAILURE;
		}
	}

	if (range) {
		if (inv) {
			_sprintf(out, MAX_MSG, "%s: cannot use -i with -r",
					c->argv[0]);
			status = EXIT_FAILURE;
		} else {
			status = xprange(out, c);
		}
		return status;
	}

	if (l_optind != c->argc - 1) {
		USAGEMSG(out, CMDNAME, CMDUSAGE);
		return EXIT_FAILURE;
	}

	if (!parsenum_mult(c->argv[l_optind], &x)) {
		_sprintf(out, MAX_MSG, "%s: invalid number: %s",
				c->argv[0], c->argv[l_optind]);
		return EXIT_FAILURE;
	}
	if (x < 0) {
		_sprintf(out, MAX_MSG, "%s: number cannot be "
				"negative", c->argv[0]);
		return EXIT_FAILURE;
	}

	if (inv) {
		if (x > MAX_XP) {
			_sprintf(out, MAX_MSG, "%s: xp cannot exceed 200m",
					c->argv[0]);
			status = EXIT_FAILURE;
		} else {
			_sprintf(out, MAX_MSG, "%ld", x);
			fmtnum(num, RSN_BUF, out);
			_sprintf(out, MAX_MSG, "[XP] %s xp: level %d",
					num, xptolvl(x));
		}
		return status;
	}

	if (x < 1 || x > 126) {
		_sprintf(out, MAX_MSG, "%s: level must be between 1-126",
				c->argv[0]);
		status = EXIT_FAILURE;
	} else {
		_sprintf(out, MAX_MSG, "%d", lvltoxp(x));
		fmtnum(num, RSN_BUF, out);
		_sprintf(out, MAX_MSG, "[XP] level %ld: ", x);
		strcat(out, num);
		strcat(out, " xp");
	}
	return status;
}

/* xptolvl: calculate the level at x xp */
static int xptolvl(int x)
{
	int n;

	n = 1;
	x *= 4;
	x += 1;
	while (x >= 0) {
		x -= floor(n + 300 * pow(2, n / 7.0));
		++n;
	}

	return n - 1;
}

/* lvltoxp: return xp required for level x */
static int lvltoxp(int x)
{
	int n, res;

	res = 0;
	for (n = 1; n < x; ++n)
		res += floor(n + 300 * pow(2, n / 7.0));
	res = floor(0.25 * res);

	return res;
}

/* xprange: calcuate the amount of xp between the levels in args */
static int xprange(char *out, struct command *c)
{
	int64_t x, y;
	char *a, *b;
	char num[RSN_BUF];

	if (l_optind == c->argc || l_optind < c->argc - 2) {
		USAGEMSG(out, CMDNAME, RUSAGE);
		return EXIT_FAILURE;
	}

	a = c->argv[l_optind];
	if (l_optind == c->argc - 1) {
		if (!(b = strchr(a, '-')) || !b[1]) {
			_sprintf(out, MAX_MSG, "%s: must provide two levels",
					c->argv[0]);
			return EXIT_FAILURE;
		}
		*b++ = '\0';
	} else {
		b = c->argv[l_optind + 1];
	}

	if (!parsenum(a, &x)) {
		_sprintf(out, MAX_MSG, "%s: invalid number: %s", c->argv[0], a);
		return EXIT_FAILURE;
	}
	if (x < 1 || x > 126) {
		_sprintf(out, MAX_MSG, "%s: level must be between 1-126",
				c->argv[0]);
		return EXIT_FAILURE;
	}
	if (!parsenum(b, &y)) {
		_sprintf(out, MAX_MSG, "%s: invalid number: %s", c->argv[0], b);
		return EXIT_FAILURE;
	}
	if (y < 1 || y > 126) {
		_sprintf(out, MAX_MSG, "%s: level must be between 1-126",
				c->argv[0]);
		return EXIT_FAILURE;
	}

	if (x > y) {
		_sprintf(out, MAX_MSG, "%s: invalid range", c->argv[0]);
		return EXIT_FAILURE;
	}

	x = lvltoxp(x);
	y = lvltoxp(y);

	_sprintf(out, MAX_MSG, "%ld", y - x);
	fmtnum(num, RSN_BUF, out);
	_sprintf(out, MAX_MSG, "[XP] level %s-%s: %s xp", a, b, num);
	return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>#pragma once
#include <string>
#include <map>
#include <sstream>
#include <fstream>
#include <functional>
#include <vector>
#define JSON_CLASS(name) class name : public cppson::Parsable<name>
#define FIELD(type, name) \
struct Init_ ## name \
{\
	Init_ ## name ## () \
	{ \
		meta[ #name ] = [](Type* t, cppson::JsonValue value) -> bool \
		{ \
			return value.parse(t->name); \
		}; \
	} \
};\
struct Meta_ ## name\
{\
	Meta_ ## name ## ()\
	{\
		static Init_ ## name init;\
	}\
};\
Meta_ ## name meta_ ## name;\
type name;

namespace cppson
{

class Single
{
public:
	template<typename R>
	R GetValue()
	{
		static_assert(false, "invalid call.");
	}

	template<>
	int GetValue<int>()
	{
		return atoi(str.c_str());
	}

	template<>
	bool GetValue<bool>()
	{
		if (str == "true" || str == "TRUE")
		{
			return true;
		}
		else
		{
			return false;
		}
	}

	template<>
	double GetValue<double>()
	{
		return atof(str.c_str());
	}

	template<>
	std::string GetValue<std::string>()
	{
		return str;
	}

	std::string& GetStr()
	{
		return str;
	}

private:
	std::string str;
};

class JsonValue
{
public:

	//if failed, return -1
	int init(std::vector<std::string>& tokens, int offset)
	{
		//object
		if (tokens[offset] == "{")
		{
			type = OBJECT;
			offset++;

			while (tokens[offset] != "}")
			{
				if (tokens[offset] == "\"")
				{
					std::string& key = tokens[offset + 1];

					if (tokens[offset + 2] != "\"" || tokens[offset + 3] != ":")
						return -1;

					offset = obj[key].init(tokens, offset + 4);

					if (offset == -1)
						return -1;
				}
				else if (tokens[offset] == ",")
				{
					offset++;
				}
				else
				{
					return -1;
				}
			}
			return offset + 1;
		}
		else if (tokens[offset] == "[")
		{
			type = ARRAY;
			offset++;
			while (tokens[offset] != "]")
			{
				if (tokens[offset] == ",")
				{
					offset++;
				}
				else
				{
					JsonValue value;
					offset = value.init(tokens, offset);
					if (offset == -1)
						return -1;

					arr.push_back(value);
				}
			}
			return offset + 1;
		}
		else
		{
			type = SINGLE;
			if (tokens[offset] == "\"")
			{
				single.GetStr() = tokens[offset + 1];
				return offset + 3;
			}
			else
			{
				single.GetStr() = tokens[offset];
				return offset + 1;
			}
		}
	}

	template<typename T>
	bool parse(T& val)
	{
		static_assert(std::is_base_of<Parsable<T>, T>::value, "T must be derived from Parsable<T>");

		if (type != OBJECT)
			return false;

		for (auto m : obj)
		{
			if (!T::GetMeta().at(m.first)(&val, m.second))
			{
				return false;
			}
		}

		return true;
	}

	template<typename T>
	bool parse(std::vector<T>& val)
	{
		static_assert(std::is_base_of<Parsable<T>, T>::value ||
					std::is_same<int, T>::value ||
					std::is_same<double, T>::value ||
					std::is_same<std::string, T>::value ||
					std::is_same<bool, T>::value, "T must be derived from Parsable<T>, or T must be int or double or std::string or bool.");

		if (type != ARRAY)
			return false;

		for (auto v : arr)
		{
			T p;

			if (v.parse(p))
				val.push_back(p);
			else
				return false;
		}

		return true;
	}

	template<>
	bool parse<int>(int& val)
	{
		if (type != SINGLE)
			return false;

		val = single.GetValue<int>();

		return true;
	}

	template<>
	bool parse<double>(double& val)
	{
		if (type != SINGLE)
			return false;

		val = single.GetValue<double>();

		return true;
	}

	template<>
	bool parse<bool>(bool& val)
	{
		if (type != SINGLE)
			return false;

		val = single.GetValue<bool>();

		return true;
	}

	template<>
	bool parse<std::string>(std::string& val)
	{
		if (type != SINGLE)
			return false;

		val = single.GetValue<std::string>();

		return true;
	}

private:
	enum Type
	{
		NONE,
		SINGLE,
		OBJECT,
		ARRAY
	};

	Type type;
	Single single;
	std::map<std::string, JsonValue> obj;
	std::vector<JsonValue> arr;
};

template<typename T>
class Parsable
{
public:
	using Type = T;

	bool ParseFromFile(const std::string& fileName)
	{
		std::ifstream file(fileName);

		if (!file.is_open())
			return false;

		std::string str((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());

		return ParseFromString(str);
	}

	bool ParseFromString(const std::string& str)
	{
		std::vector<std::string> tokens;
		std::string token;
		std::string space = " \t\r\n";
		std::string delim = ":{}[],";
		std::string number = "0123456789.";
		int state = 0;

		for (size_t i = 0; i < str.size(); i++)
		{
			switch (state)
			{
			case 0:
				//ignore space
				if (space.find(str[i]) != std::string::npos)
				{
					if (token.size() != 0)
					{
						tokens.push_back(token);
						token.clear();
					}

					continue;
				}
				//go string
				else if (str[i] == '"')
				{
					if (token.size() != 0)
						return false;

					tokens.push_back({ str[i] });
					state = 1;
				}
				//one char token
				else if (delim.find(str[i]) != std::string::npos)
				{
					if (token.size() != 0)
					{
						tokens.push_back(token);
						token.clear();
					}
					tokens.push_back({ str[i] });
				}
				//number
				else if (number.find(str[i]) != std::string::npos)
				{
					token.push_back({ str[i] });
				}
				//true or false
				else if (str.substr(i, 4) == "true")
				{
					if (token.size() != 0)
						return false;

					tokens.push_back(str.substr(i, 4));
				}
				else if (str.substr(i, 5) == "false")
				{
					if (token.size() != 0)
						return false;

					tokens.push_back(str.substr(i, 5));
				}
				else
				{
					return false;
				}
				break;
			case 1:
				if (str[i] == '"')
				{
					tokens.push_back(token);
					tokens.push_back({ str[i] });
					token.clear();
					state = 0;
				}
				else
				{
					token.push_back({ str[i] });
				}
				break;
			}
		}

		JsonValue value;

		if (value.init(tokens, 0) == -1)
			return false;

		Type& t = static_cast<Type&>(*this);

		value.parse(t);
		return true;
	}
	using Meta = std::map<std::string, std::function<bool(Type*, JsonValue)> >;

	static const Meta& GetMeta()
	{
		return meta;
	}

protected:

	static Meta meta;
};

template<typename T>
typename Parsable<T>::Meta Parsable<T>::meta;

}<commit_msg>add final<commit_after>#pragma once
#include <string>
#include <map>
#include <sstream>
#include <fstream>
#include <functional>
#include <vector>
#define JSON_CLASS(name) class name final : public cppson::Parsable<name>
#define FIELD(type, name) \
struct Init_ ## name \
{\
	Init_ ## name ## () \
	{ \
		meta[ #name ] = [](Type* t, cppson::JsonValue value) -> bool \
		{ \
			return value.parse(t->name); \
		}; \
	} \
};\
struct Meta_ ## name\
{\
	Meta_ ## name ## ()\
	{\
		static Init_ ## name init;\
	}\
};\
Meta_ ## name meta_ ## name;\
type name;

namespace cppson
{

class Single
{
public:
	template<typename R>
	R GetValue()
	{
		static_assert(false, "invalid call.");
	}

	template<>
	int GetValue<int>()
	{
		return atoi(str.c_str());
	}

	template<>
	bool GetValue<bool>()
	{
		if (str == "true" || str == "TRUE")
		{
			return true;
		}
		else
		{
			return false;
		}
	}

	template<>
	double GetValue<double>()
	{
		return atof(str.c_str());
	}

	template<>
	std::string GetValue<std::string>()
	{
		return str;
	}

	std::string& GetStr()
	{
		return str;
	}

private:
	std::string str;
};

class JsonValue
{
public:

	//if failed, return -1
	int init(std::vector<std::string>& tokens, int offset)
	{
		//object
		if (tokens[offset] == "{")
		{
			type = OBJECT;
			offset++;

			while (tokens[offset] != "}")
			{
				if (tokens[offset] == "\"")
				{
					std::string& key = tokens[offset + 1];

					if (tokens[offset + 2] != "\"" || tokens[offset + 3] != ":")
						return -1;

					offset = obj[key].init(tokens, offset + 4);

					if (offset == -1)
						return -1;
				}
				else if (tokens[offset] == ",")
				{
					offset++;
				}
				else
				{
					return -1;
				}
			}
			return offset + 1;
		}
		else if (tokens[offset] == "[")
		{
			type = ARRAY;
			offset++;
			while (tokens[offset] != "]")
			{
				if (tokens[offset] == ",")
				{
					offset++;
				}
				else
				{
					JsonValue value;
					offset = value.init(tokens, offset);
					if (offset == -1)
						return -1;

					arr.push_back(value);
				}
			}
			return offset + 1;
		}
		else
		{
			type = SINGLE;
			if (tokens[offset] == "\"")
			{
				single.GetStr() = tokens[offset + 1];
				return offset + 3;
			}
			else
			{
				single.GetStr() = tokens[offset];
				return offset + 1;
			}
		}
	}

	template<typename T>
	bool parse(T& val)
	{
		static_assert(std::is_base_of<Parsable<T>, T>::value, "T must be derived from Parsable<T>");

		if (type != OBJECT)
			return false;

		for (auto m : obj)
		{
			if (!T::GetMeta().at(m.first)(&val, m.second))
			{
				return false;
			}
		}

		return true;
	}

	template<typename T>
	bool parse(std::vector<T>& val)
	{
		static_assert(std::is_base_of<Parsable<T>, T>::value ||
					std::is_same<int, T>::value ||
					std::is_same<double, T>::value ||
					std::is_same<std::string, T>::value ||
					std::is_same<bool, T>::value, "T must be derived from Parsable<T>, or T must be int or double or std::string or bool.");

		if (type != ARRAY)
			return false;

		for (auto v : arr)
		{
			T p;

			if (v.parse(p))
				val.push_back(p);
			else
				return false;
		}

		return true;
	}

	template<>
	bool parse<int>(int& val)
	{
		if (type != SINGLE)
			return false;

		val = single.GetValue<int>();

		return true;
	}

	template<>
	bool parse<double>(double& val)
	{
		if (type != SINGLE)
			return false;

		val = single.GetValue<double>();

		return true;
	}

	template<>
	bool parse<bool>(bool& val)
	{
		if (type != SINGLE)
			return false;

		val = single.GetValue<bool>();

		return true;
	}

	template<>
	bool parse<std::string>(std::string& val)
	{
		if (type != SINGLE)
			return false;

		val = single.GetValue<std::string>();

		return true;
	}

private:
	enum Type
	{
		NONE,
		SINGLE,
		OBJECT,
		ARRAY
	};

	Type type;
	Single single;
	std::map<std::string, JsonValue> obj;
	std::vector<JsonValue> arr;
};

template<typename T>
class Parsable
{
public:
	using Type = T;

	bool ParseFromFile(const std::string& fileName)
	{
		std::ifstream file(fileName);

		if (!file.is_open())
			return false;

		std::string str((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());

		return ParseFromString(str);
	}

	bool ParseFromString(const std::string& str)
	{
		std::vector<std::string> tokens;
		std::string token;
		std::string space = " \t\r\n";
		std::string delim = ":{}[],";
		std::string number = "0123456789.";
		int state = 0;

		for (size_t i = 0; i < str.size(); i++)
		{
			switch (state)
			{
			case 0:
				//ignore space
				if (space.find(str[i]) != std::string::npos)
				{
					if (token.size() != 0)
					{
						tokens.push_back(token);
						token.clear();
					}

					continue;
				}
				//go string
				else if (str[i] == '"')
				{
					if (token.size() != 0)
						return false;

					tokens.push_back({ str[i] });
					state = 1;
				}
				//one char token
				else if (delim.find(str[i]) != std::string::npos)
				{
					if (token.size() != 0)
					{
						tokens.push_back(token);
						token.clear();
					}
					tokens.push_back({ str[i] });
				}
				//number
				else if (number.find(str[i]) != std::string::npos)
				{
					token.push_back({ str[i] });
				}
				//true or false
				else if (str.substr(i, 4) == "true")
				{
					if (token.size() != 0)
						return false;

					tokens.push_back(str.substr(i, 4));
				}
				else if (str.substr(i, 5) == "false")
				{
					if (token.size() != 0)
						return false;

					tokens.push_back(str.substr(i, 5));
				}
				else
				{
					return false;
				}
				break;
			case 1:
				if (str[i] == '"')
				{
					tokens.push_back(token);
					tokens.push_back({ str[i] });
					token.clear();
					state = 0;
				}
				else
				{
					token.push_back({ str[i] });
				}
				break;
			}
		}

		JsonValue value;

		if (value.init(tokens, 0) == -1)
			return false;

		Type& t = static_cast<Type&>(*this);

		value.parse(t);
		return true;
	}
	using Meta = std::map<std::string, std::function<bool(Type*, JsonValue)> >;

	static const Meta& GetMeta()
	{
		return meta;
	}

protected:

	static Meta meta;
};

template<typename T>
typename Parsable<T>::Meta Parsable<T>::meta;

}<|endoftext|>


<commit_before>#ifndef CURSOR_HPP
#define CURSOR_HPP

class Cursor
{
	sf::Vector2u size;
	sf::Vector2i pos;
	float outline_thickness;
	sf::RectangleShape cursor;
public:
	Cursor(const sf::Vector2u& sz, float thick, sf::Color fill, sf::Color outline);

	inline const sf::Vector2i& get_pos() const
	{
		return pos;
	}

	void set_pos(const sf::Vector2i& p);

	inline const sf::Vector2u& get_size() const
	{
		return size;
	}

	void set_size(const sf::Vector2u& sz);

	inline sf::Vector2f get_center() const
	{
		return ((sf::Vector2f)pos + sf::Vector2f(0.5, 0.5)) * (float)PPB;
	}

	inline void move(const sf::Vector2i& d)
	{
		set_pos(pos + d);
	}

	void set_zoom(float zoom);

	inline void draw_on(sf::RenderWindow& window) const
	{
		window.draw(cursor);
	}
};

#endif
<commit_msg>Update cursor includes<commit_after>#ifndef CURSOR_HPP
#define CURSOR_HPP

#include <SFML/Graphics.hpp>

#include "constants.hpp"

class Cursor
{
	sf::Vector2u size;
	sf::Vector2i pos;
	float outline_thickness;
	sf::RectangleShape cursor;
public:
	Cursor(const sf::Vector2u& sz, float thick, sf::Color fill, sf::Color outline);

	inline const sf::Vector2i& get_pos() const
	{
		return pos;
	}

	void set_pos(const sf::Vector2i& p);

	inline const sf::Vector2u& get_size() const
	{
		return size;
	}

	void set_size(const sf::Vector2u& sz);

	inline sf::Vector2f get_center() const
	{
		return ((sf::Vector2f)pos + sf::Vector2f(0.5, 0.5)) * (float)PPB;
	}

	inline void move(const sf::Vector2i& d)
	{
		set_pos(pos + d);
	}

	void set_zoom(float zoom);

	inline void draw_on(sf::RenderWindow& window) const
	{
		window.draw(cursor);
	}
};

#endif
<|endoftext|>


<commit_before>#include "engine.h"
#include "random.h"
#include "Updatable.h"
#include "collisionable.h"
#include "audio/source.h"
#include "io/keybinding.h"
#include "soundManager.h"
#include "windowManager.h"
#include "scriptInterface.h"
#include "multiplayer_server.h"

#include <thread>
#include <SDL.h>

#ifdef DEBUG
#include <typeinfo>
int DEBUG_PobjCount;
PObject* DEBUG_PobjListStart;
#endif

Engine* engine;

Engine::Engine()
{
    engine = this;

#ifdef WIN32
    // Setup crash reporter (Dr. MinGW) if available.
    exchndl = DynamicLibrary::open("exchndl.dll");

    if (exchndl)
    {
        auto pfnExcHndlInit = exchndl->getFunction<void(*)(void)>("ExcHndlInit");

        if (pfnExcHndlInit)
        {
            pfnExcHndlInit();
            LOG(INFO) << "Crash Reporter ON";
        }
        else
        {
            exchndl.reset();
        }
    }
#endif // WIN32

    SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "0");
    SDL_SetHint(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, "0");
#ifdef SDL_HINT_ANDROID_SEPARATE_MOUSE_AND_TOUCH
    SDL_SetHint(SDL_HINT_ANDROID_SEPARATE_MOUSE_AND_TOUCH, "1");
#elif defined(SDL_HINT_MOUSE_TOUCH_EVENTS)
    SDL_SetHint(SDL_HINT_MOUSE_TOUCH_EVENTS, "0");
    SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0");
#endif
    SDL_Init(SDL_INIT_EVERYTHING);
    SDL_ShowCursor(false);

    atexit(SDL_Quit);

    initRandom();
    CollisionManager::initialize();
    gameSpeed = 1.0f;
    running = true;
    elapsedTime = 0.0f;
    soundManager = new SoundManager();
}

Engine::~Engine()
{
    updatableList.clear();
    delete soundManager;
    soundManager = nullptr;
}

void Engine::registerObject(string name, P<PObject> obj)
{
    objectMap[name] = obj;
}

P<PObject> Engine::getObject(string name)
{
    if (!objectMap[name])
        return NULL;
    return objectMap[name];
}

void Engine::runMainLoop()
{
    if (Window::all_windows.size() == 0)
    {
        sp::SystemStopwatch frame_timer;
        while(running)
        {
            float delta = frame_timer.restart();
            if (delta > 0.5f)
                delta = 0.5f;
            if (delta < 0.001f)
                delta = 0.001f;
            delta *= gameSpeed;

            foreach(Updatable, u, updatableList)
                u->update(delta);
            elapsedTime += delta;
            CollisionManager::handleCollisions(delta);
            ScriptObject::clearDestroyedObjects();
            soundManager->updateTick();

            std::this_thread::sleep_for(std::chrono::duration<float>(1.f/60.f - delta));
        }
    }else{
        sp::audio::Source::startAudioSystem();
        sp::SystemStopwatch frame_timer;
#ifdef DEBUG
        sp::SystemTimer debug_output_timer;
        debug_output_timer.repeat(5);
#endif
        while(running)
        {
            // Handle events
            SDL_Event event;
            while (SDL_PollEvent(&event))
            {
                handleEvent(event);
            }

#ifdef DEBUG
            if (debug_output_timer.isExpired())
                LOG(DEBUG) << "Object count: " << DEBUG_PobjCount << " " << updatableList.size();
#endif

            float delta = frame_timer.restart();
            if (delta > 0.5f)
                delta = 0.5f;
            if (delta < 0.001f)
                delta = 0.001f;
            delta *= gameSpeed;
            EngineTiming engine_timing;

            sp::SystemStopwatch engine_timing_stopwatch;
            foreach(Updatable, u, updatableList) {
                u->update(delta);
            }
            elapsedTime += delta;
            engine_timing.update = engine_timing_stopwatch.restart();
            CollisionManager::handleCollisions(delta);
            engine_timing.collision = engine_timing_stopwatch.restart();
            ScriptObject::clearDestroyedObjects();
            soundManager->updateTick();

            // Clear the window
            for(auto window : Window::all_windows)
                window->render();
            engine_timing.render = engine_timing_stopwatch.restart();
            engine_timing.server_update = 0.0f;
            if (game_server)
                engine_timing.server_update = game_server->getUpdateTime();

            last_engine_timing = engine_timing;

            sp::io::Keybinding::allPostUpdate();
        }
        soundManager->stopMusic();
        sp::audio::Source::stopAudioSystem();
    }
}

void Engine::handleEvent(SDL_Event& event)
{
    if (event.type == SDL_QUIT)
        running = false;
#ifdef DEBUG
    if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_ESCAPE)
        running = false;
    if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_l)
    {
        int n = 0;
        printf("------------------------\n");
        std::unordered_map<string,int> totals;
        for(PObject* obj = DEBUG_PobjListStart; obj; obj = obj->DEBUG_PobjListNext)
        {
            printf("%c%4d: %4d: %s\n", obj->isDestroyed() ? '>' : ' ', n++, obj->getRefCount(), typeid(*obj).name());
            if (!obj->isDestroyed())
            {
                totals[typeid(*obj).name()]=totals[typeid(*obj).name()]+1;
            }
        }
        printf("--non-destroyed totals--\n");
        int grand_total=0;
        for (auto entry : totals)
        {
            printf("%4d %s\n", entry.second, entry.first.c_str());
            grand_total+=entry.second;
        }
        printf("%4d %s\n",grand_total,"All PObjects");
        printf("------------------------\n");
    }
#endif

    unsigned int window_id = 0;
    switch(event.type)
    {
    case SDL_KEYDOWN:
#ifdef __EMSCRIPTEN__
        if (!audio_started)
        {
            audio::AudioSource::startAudioSystem();
            audio_started = true;
        }
#endif
    case SDL_KEYUP:
        window_id = event.key.windowID;
        break;
    case SDL_MOUSEMOTION:
        window_id = event.motion.windowID;
        break;
    case SDL_MOUSEBUTTONDOWN:
#ifdef __EMSCRIPTEN__
        if (!audio_started)
        {
            audio::AudioSource::startAudioSystem();
            audio_started = true;
        }
#endif
    case SDL_MOUSEBUTTONUP:
        window_id = event.button.windowID;
        break;
    case SDL_MOUSEWHEEL:
        window_id = event.wheel.windowID;
        break;
    case SDL_WINDOWEVENT:
        window_id = event.window.windowID;
        break;
    case SDL_FINGERDOWN:
    case SDL_FINGERUP:
    case SDL_FINGERMOTION:
        window_id = event.tfinger.windowID;
        break;
    case SDL_TEXTEDITING:
        window_id = event.edit.windowID;
        break;
    case SDL_TEXTINPUT:
        window_id = event.text.windowID;
        break;
    }
    if (window_id != 0)
    {
        foreach(Window, window, Window::all_windows)
            if (window->window && SDL_GetWindowID(static_cast<SDL_Window*>(window->window)) == window_id)
                window->handleEvent(event);
    }
    sp::io::Keybinding::handleEvent(event);
}

void Engine::setGameSpeed(float speed)
{
    gameSpeed = speed;
}

float Engine::getGameSpeed()
{
    return gameSpeed;
}

float Engine::getElapsedTime()
{
    return elapsedTime;
}

Engine::EngineTiming Engine::getEngineTiming()
{
    return last_engine_timing;
}

void Engine::shutdown()
{
    running = false;
}
<commit_msg>Fix build on older SDL version<commit_after>#include "engine.h"
#include "random.h"
#include "Updatable.h"
#include "collisionable.h"
#include "audio/source.h"
#include "io/keybinding.h"
#include "soundManager.h"
#include "windowManager.h"
#include "scriptInterface.h"
#include "multiplayer_server.h"

#include <thread>
#include <SDL.h>

#ifdef DEBUG
#include <typeinfo>
int DEBUG_PobjCount;
PObject* DEBUG_PobjListStart;
#endif

Engine* engine;

Engine::Engine()
{
    engine = this;

#ifdef WIN32
    // Setup crash reporter (Dr. MinGW) if available.
    exchndl = DynamicLibrary::open("exchndl.dll");

    if (exchndl)
    {
        auto pfnExcHndlInit = exchndl->getFunction<void(*)(void)>("ExcHndlInit");

        if (pfnExcHndlInit)
        {
            pfnExcHndlInit();
            LOG(INFO) << "Crash Reporter ON";
        }
        else
        {
            exchndl.reset();
        }
    }
#endif // WIN32

    SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "0");
    SDL_SetHint(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, "0");
#ifdef SDL_HINT_ANDROID_SEPARATE_MOUSE_AND_TOUCH
    SDL_SetHint(SDL_HINT_ANDROID_SEPARATE_MOUSE_AND_TOUCH, "1");
#elif defined(SDL_HINT_MOUSE_TOUCH_EVENTS)
    SDL_SetHint(SDL_HINT_MOUSE_TOUCH_EVENTS, "0");
    SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0");
#endif
    SDL_Init(SDL_INIT_EVERYTHING);
    SDL_ShowCursor(false);

    atexit(SDL_Quit);

    initRandom();
    CollisionManager::initialize();
    gameSpeed = 1.0f;
    running = true;
    elapsedTime = 0.0f;
    soundManager = new SoundManager();
}

Engine::~Engine()
{
    updatableList.clear();
    delete soundManager;
    soundManager = nullptr;
}

void Engine::registerObject(string name, P<PObject> obj)
{
    objectMap[name] = obj;
}

P<PObject> Engine::getObject(string name)
{
    if (!objectMap[name])
        return NULL;
    return objectMap[name];
}

void Engine::runMainLoop()
{
    if (Window::all_windows.size() == 0)
    {
        sp::SystemStopwatch frame_timer;
        while(running)
        {
            float delta = frame_timer.restart();
            if (delta > 0.5f)
                delta = 0.5f;
            if (delta < 0.001f)
                delta = 0.001f;
            delta *= gameSpeed;

            foreach(Updatable, u, updatableList)
                u->update(delta);
            elapsedTime += delta;
            CollisionManager::handleCollisions(delta);
            ScriptObject::clearDestroyedObjects();
            soundManager->updateTick();

            std::this_thread::sleep_for(std::chrono::duration<float>(1.f/60.f - delta));
        }
    }else{
        sp::audio::Source::startAudioSystem();
        sp::SystemStopwatch frame_timer;
#ifdef DEBUG
        sp::SystemTimer debug_output_timer;
        debug_output_timer.repeat(5);
#endif
        while(running)
        {
            // Handle events
            SDL_Event event;
            while (SDL_PollEvent(&event))
            {
                handleEvent(event);
            }

#ifdef DEBUG
            if (debug_output_timer.isExpired())
                LOG(DEBUG) << "Object count: " << DEBUG_PobjCount << " " << updatableList.size();
#endif

            float delta = frame_timer.restart();
            if (delta > 0.5f)
                delta = 0.5f;
            if (delta < 0.001f)
                delta = 0.001f;
            delta *= gameSpeed;
            EngineTiming engine_timing;

            sp::SystemStopwatch engine_timing_stopwatch;
            foreach(Updatable, u, updatableList) {
                u->update(delta);
            }
            elapsedTime += delta;
            engine_timing.update = engine_timing_stopwatch.restart();
            CollisionManager::handleCollisions(delta);
            engine_timing.collision = engine_timing_stopwatch.restart();
            ScriptObject::clearDestroyedObjects();
            soundManager->updateTick();

            // Clear the window
            for(auto window : Window::all_windows)
                window->render();
            engine_timing.render = engine_timing_stopwatch.restart();
            engine_timing.server_update = 0.0f;
            if (game_server)
                engine_timing.server_update = game_server->getUpdateTime();

            last_engine_timing = engine_timing;

            sp::io::Keybinding::allPostUpdate();
        }
        soundManager->stopMusic();
        sp::audio::Source::stopAudioSystem();
    }
}

void Engine::handleEvent(SDL_Event& event)
{
    if (event.type == SDL_QUIT)
        running = false;
#ifdef DEBUG
    if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_ESCAPE)
        running = false;
    if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_l)
    {
        int n = 0;
        printf("------------------------\n");
        std::unordered_map<string,int> totals;
        for(PObject* obj = DEBUG_PobjListStart; obj; obj = obj->DEBUG_PobjListNext)
        {
            printf("%c%4d: %4d: %s\n", obj->isDestroyed() ? '>' : ' ', n++, obj->getRefCount(), typeid(*obj).name());
            if (!obj->isDestroyed())
            {
                totals[typeid(*obj).name()]=totals[typeid(*obj).name()]+1;
            }
        }
        printf("--non-destroyed totals--\n");
        int grand_total=0;
        for (auto entry : totals)
        {
            printf("%4d %s\n", entry.second, entry.first.c_str());
            grand_total+=entry.second;
        }
        printf("%4d %s\n",grand_total,"All PObjects");
        printf("------------------------\n");
    }
#endif

    unsigned int window_id = 0;
    switch(event.type)
    {
    case SDL_KEYDOWN:
#ifdef __EMSCRIPTEN__
        if (!audio_started)
        {
            audio::AudioSource::startAudioSystem();
            audio_started = true;
        }
#endif
    case SDL_KEYUP:
        window_id = event.key.windowID;
        break;
    case SDL_MOUSEMOTION:
        window_id = event.motion.windowID;
        break;
    case SDL_MOUSEBUTTONDOWN:
#ifdef __EMSCRIPTEN__
        if (!audio_started)
        {
            audio::AudioSource::startAudioSystem();
            audio_started = true;
        }
#endif
    case SDL_MOUSEBUTTONUP:
        window_id = event.button.windowID;
        break;
    case SDL_MOUSEWHEEL:
        window_id = event.wheel.windowID;
        break;
    case SDL_WINDOWEVENT:
        window_id = event.window.windowID;
        break;
    case SDL_FINGERDOWN:
    case SDL_FINGERUP:
    case SDL_FINGERMOTION:
#if SDL_PATCHLEVEL >= 12
        window_id = event.tfinger.windowID;
#else
        window_id = SDL_GetWindowID(SDL_GetMouseFocus());
#endif
        break;
    case SDL_TEXTEDITING:
        window_id = event.edit.windowID;
        break;
    case SDL_TEXTINPUT:
        window_id = event.text.windowID;
        break;
    }
    if (window_id != 0)
    {
        foreach(Window, window, Window::all_windows)
            if (window->window && SDL_GetWindowID(static_cast<SDL_Window*>(window->window)) == window_id)
                window->handleEvent(event);
    }
    sp::io::Keybinding::handleEvent(event);
}

void Engine::setGameSpeed(float speed)
{
    gameSpeed = speed;
}

float Engine::getGameSpeed()
{
    return gameSpeed;
}

float Engine::getElapsedTime()
{
    return elapsedTime;
}

Engine::EngineTiming Engine::getEngineTiming()
{
    return last_engine_timing;
}

void Engine::shutdown()
{
    running = false;
}
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- vim:set ts=4 sw=4 sts=4 noet: */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "gui/app.h"

#include <boost/process/search_path.hpp>

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-qual"
#include <wx/config.h>
#include <wx/filename.h>
#pragma GCC diagnostic pop

#include "gui/main-frame.h"
#include "gui/pref-page-general.h"
#include "utf8path.h"

namespace flint {
namespace gui {

bool App::OnInit()
{
	if (!wxApp::OnInit())
		return false;

	SetAppDisplayName("Flint");
	SetVendorDisplayName("Flint project");

	wxFileName fileName;
	fileName.AssignHomeDir();
	fileName.AppendDir(".flint");
	fileName.AppendDir("2");
	fileName.Mkdir(wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL); // make sure that it exists
	fileName.SetCwd();

	auto frame = new MainFrame;
	frame->CentreOnScreen();
	frame->Show();

	pref_editor_ = nullptr;

	return true;
}

int App::OnExit()
{
	// clean up working directory
	wxFileName fileName;
	fileName.AssignHomeDir();
	fileName.SetCwd(); // change directory at first
	fileName.AppendDir(".flint");
	fileName.AppendDir("2");
	fileName.Rmdir(wxPATH_RMDIR_RECURSIVE);

	return wxApp::OnExit();
}

boost::filesystem::path App::GetGnuplotExecutable() const
{
	boost::filesystem::path p(gnuplot_executable_.ToStdString());
	if (p.empty()) {
		// search executable from PATH
		p = boost::process::search_path("gnuplot");
	}
	return p;
}

void App::OnGnuplotExecutable(wxFileDirPickerEvent &event)
{
	gnuplot_executable_ = event.GetPath();
}

void App::ShowPreferencesEditor(wxWindow *parent)
{
	if (!pref_editor_) {
		pref_editor_ = new wxPreferencesEditor;
		pref_editor_->AddPage(new PrefPageGeneral(gnuplot_executable_));
	}
	pref_editor_->Show(parent);
}

}
}

wxIMPLEMENT_APP(flint::gui::App);
<commit_msg>Remember selected path of gnuplot executable for future session<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- vim:set ts=4 sw=4 sts=4 noet: */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "gui/app.h"

#include <boost/process/search_path.hpp>

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-qual"
#include <wx/config.h>
#include <wx/filename.h>
#include <wx/persist.h>
#pragma GCC diagnostic pop

#include "gui/main-frame.h"
#include "gui/pref-page-general.h"
#include "utf8path.h"

namespace flint {
namespace gui {

namespace {

class PersistentApp : public wxPersistentObject
{
public:
	PersistentApp(App *, wxString &gnuplot_executable);

	virtual void Save() const override;
	virtual bool Restore() override;
	virtual wxString GetKind() const override;
	virtual wxString GetName() const override;

private:
	wxString &gnuplot_executable_;
};

PersistentApp::PersistentApp(App *obj, wxString &gnuplot_executable)
	: wxPersistentObject(obj)
	, gnuplot_executable_(gnuplot_executable)
{
}

void PersistentApp::Save() const
{
	SaveValue("gnuplot_executable", gnuplot_executable_);
}

bool PersistentApp::Restore()
{
	return RestoreValue("gnuplot_executable", &gnuplot_executable_);
}

wxString PersistentApp::GetKind() const
{
	return "Preference";
}

wxString PersistentApp::GetName() const
{
	return "File";
}

}

bool App::OnInit()
{
	if (!wxApp::OnInit())
		return false;

	SetAppDisplayName("Flint");
	SetVendorDisplayName("Flint project");

	wxPersistenceManager::Get().RegisterAndRestore(this, new PersistentApp(this, gnuplot_executable_));

	wxFileName fileName;
	fileName.AssignHomeDir();
	fileName.AppendDir(".flint");
	fileName.AppendDir("2");
	fileName.Mkdir(wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL); // make sure that it exists
	fileName.SetCwd();

	auto frame = new MainFrame;
	frame->CentreOnScreen();
	frame->Show();

	pref_editor_ = nullptr;

	return true;
}

int App::OnExit()
{
	wxPersistenceManager::Get().SaveAndUnregister(this);

	// clean up working directory
	wxFileName fileName;
	fileName.AssignHomeDir();
	fileName.SetCwd(); // change directory at first
	fileName.AppendDir(".flint");
	fileName.AppendDir("2");
	fileName.Rmdir(wxPATH_RMDIR_RECURSIVE);

	return wxApp::OnExit();
}

boost::filesystem::path App::GetGnuplotExecutable() const
{
	boost::filesystem::path p(gnuplot_executable_.ToStdString());
	if (p.empty()) {
		// search executable from PATH
		p = boost::process::search_path("gnuplot");
	}
	return p;
}

void App::OnGnuplotExecutable(wxFileDirPickerEvent &event)
{
	gnuplot_executable_ = event.GetPath();
}

void App::ShowPreferencesEditor(wxWindow *parent)
{
	if (!pref_editor_) {
		pref_editor_ = new wxPreferencesEditor;
		pref_editor_->AddPage(new PrefPageGeneral(gnuplot_executable_));
	}
	pref_editor_->Show(parent);
}

}
}

wxIMPLEMENT_APP(flint::gui::App);
<|endoftext|>