<commit_before>/*
    This file is part of Magnum.

    Copyright © 2010, 2011, 2012, 2013, 2014, 2015
              Vladimír Vondruš <mosra@centrum.cz>

    Permission is hereby granted, free of charge, to any person obtaining a
    copy of this software and associated documentation files (the "Software"),
    to deal in the Software without restriction, including without limitation
    the rights to use, copy, modify, merge, publish, distribute, sublicense,
    and/or sell copies of the Software, and to permit persons to whom the
    Software is furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included
    in all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
    DEALINGS IN THE SOFTWARE.
*/

#include "Context.h"

#include <alc.h>
#include <Corrade/Utility/Assert.h>
#include <Corrade/Utility/Debug.h>

#include "Magnum/Magnum.h"

namespace Magnum { namespace Audio {

Context* Context::_current = nullptr;

Context::Context() {
    CORRADE_ASSERT(!_current, "Audio::Context: context already created", );

    /* Open default device */
    const ALCchar* const defaultDevice = alcGetString(nullptr, ALC_DEFAULT_DEVICE_SPECIFIER);
    _device = alcOpenDevice(defaultDevice);
    if(!_device) {
        Error() << "Audio::Context: cannot open sound device" << defaultDevice;
        std::exit(1);
    }

    _context = alcCreateContext(_device, nullptr);
    if(!_context) {
        Error() << "Audio::Context: cannot create context:" << alcGetError(_device);
        std::exit(1);
    }

    alcMakeContextCurrent(_context);
    _current = this;
}

Context::~Context() {
    CORRADE_INTERNAL_ASSERT(_current == this);

    alcDestroyContext(_context);
    alcCloseDevice(_device);
}

}}
<commit_msg>Audio: Print additional info on Context creation<commit_after>/*
    This file is part of Magnum.

    Copyright © 2010, 2011, 2012, 2013, 2014, 2015
              Vladimír Vondruš <mosra@centrum.cz>

    Permission is hereby granted, free of charge, to any person obtaining a
    copy of this software and associated documentation files (the "Software"),
    to deal in the Software without restriction, including without limitation
    the rights to use, copy, modify, merge, publish, distribute, sublicense,
    and/or sell copies of the Software, and to permit persons to whom the
    Software is furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included
    in all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
    DEALINGS IN THE SOFTWARE.
*/

#include "Context.h"

#include <alc.h>
#include <Corrade/Utility/Assert.h>
#include <Corrade/Utility/Debug.h>

#include "Magnum/Magnum.h"

namespace Magnum { namespace Audio {

Context* Context::_current = nullptr;

Context::Context() {
    CORRADE_ASSERT(!_current, "Audio::Context: context already created", );

    /* Open default device */
    const ALCchar* const defaultDevice = alcGetString(nullptr, ALC_DEFAULT_DEVICE_SPECIFIER);
    _device = alcOpenDevice(defaultDevice);
    if(!_device) {
        Error() << "Audio::Context: cannot open sound device" << defaultDevice;
        std::exit(1);
    }

    _context = alcCreateContext(_device, nullptr);
    if(!_context) {
        Error() << "Audio::Context: cannot create context:" << alcGetError(_device);
        std::exit(1);
    }

    alcMakeContextCurrent(_context);
    _current = this;

    /* Print some info */
    Debug() << "Audio Renderer:" << rendererString() << "by" << vendorString();
    Debug() << "OpenAL version:" << versionString();
}

Context::~Context() {
    CORRADE_INTERNAL_ASSERT(_current == this);

    alcDestroyContext(_context);
    alcCloseDevice(_device);
}

}}
<|endoftext|>


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

#include "visual_server.h"
#include "audio_server.h"
#include "physics_server.h"
#include "physics_2d_server.h"
#include "spatial_sound_server.h"
#include "spatial_sound_2d_server.h"

void register_server_types() {

	Globals::get_singleton()->add_singleton( Globals::Singleton("VisualServer",VisualServer::get_singleton()) );
	Globals::get_singleton()->add_singleton( Globals::Singleton("VS",VisualServer::get_singleton()) );
	Globals::get_singleton()->add_singleton( Globals::Singleton("AudioServer",AudioServer::get_singleton()) );
	Globals::get_singleton()->add_singleton( Globals::Singleton("AS",AudioServer::get_singleton()) );
	Globals::get_singleton()->add_singleton( Globals::Singleton("PhysicsServer",PhysicsServer::get_singleton()) );
	Globals::get_singleton()->add_singleton( Globals::Singleton("PS",PhysicsServer::get_singleton()) );
	Globals::get_singleton()->add_singleton( Globals::Singleton("Physics2DServer",Physics2DServer::get_singleton()) );
	Globals::get_singleton()->add_singleton( Globals::Singleton("PS2D",Physics2DServer::get_singleton()) );
	Globals::get_singleton()->add_singleton( Globals::Singleton("SpatialSoundServer",SpatialSound2DServer::get_singleton()) );
	Globals::get_singleton()->add_singleton( Globals::Singleton("SS",SpatialSound2DServer::get_singleton()) );
	Globals::get_singleton()->add_singleton( Globals::Singleton("SpatialSound2DServer",SpatialSound2DServer::get_singleton()) );
	Globals::get_singleton()->add_singleton( Globals::Singleton("SS2D",SpatialSound2DServer::get_singleton()) );

	ObjectTypeDB::register_virtual_type<Physics2DDirectBodyState>();
	ObjectTypeDB::register_virtual_type<Physics2DDirectSpaceState>();
	ObjectTypeDB::register_virtual_type<Physics2DShapeQueryResult>();
	ObjectTypeDB::register_virtual_type<Physics2DTestMotionResult>();
	ObjectTypeDB::register_type<Physics2DShapeQueryParameters>();

	ObjectTypeDB::register_type<PhysicsShapeQueryParameters>();
	ObjectTypeDB::register_virtual_type<PhysicsDirectBodyState>();
	ObjectTypeDB::register_virtual_type<PhysicsDirectSpaceState>();
	ObjectTypeDB::register_virtual_type<PhysicsShapeQueryResult>();

}

void unregister_server_types(){

}
<commit_msg>fix register Physics2DTestMotionResult<commit_after>/*************************************************************************/
/*  register_server_types.cpp                                            */
/*************************************************************************/
/*                       This file is part of:                           */
/*                           GODOT ENGINE                                */
/*                    http://www.godotengine.org                         */
/*************************************************************************/
/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur.                 */
/*                                                                       */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the       */
/* "Software"), to deal in the Software without restriction, including   */
/* without limitation the rights to use, copy, modify, merge, publish,   */
/* distribute, sublicense, and/or sell copies of the Software, and to    */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions:                                             */
/*                                                                       */
/* The above copyright notice and this permission notice shall be        */
/* included in all copies or substantial portions of the Software.       */
/*                                                                       */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
/*************************************************************************/
#include "register_server_types.h"
#include "globals.h"

#include "visual_server.h"
#include "audio_server.h"
#include "physics_server.h"
#include "physics_2d_server.h"
#include "spatial_sound_server.h"
#include "spatial_sound_2d_server.h"

void register_server_types() {

	Globals::get_singleton()->add_singleton( Globals::Singleton("VisualServer",VisualServer::get_singleton()) );
	Globals::get_singleton()->add_singleton( Globals::Singleton("VS",VisualServer::get_singleton()) );
	Globals::get_singleton()->add_singleton( Globals::Singleton("AudioServer",AudioServer::get_singleton()) );
	Globals::get_singleton()->add_singleton( Globals::Singleton("AS",AudioServer::get_singleton()) );
	Globals::get_singleton()->add_singleton( Globals::Singleton("PhysicsServer",PhysicsServer::get_singleton()) );
	Globals::get_singleton()->add_singleton( Globals::Singleton("PS",PhysicsServer::get_singleton()) );
	Globals::get_singleton()->add_singleton( Globals::Singleton("Physics2DServer",Physics2DServer::get_singleton()) );
	Globals::get_singleton()->add_singleton( Globals::Singleton("PS2D",Physics2DServer::get_singleton()) );
	Globals::get_singleton()->add_singleton( Globals::Singleton("SpatialSoundServer",SpatialSound2DServer::get_singleton()) );
	Globals::get_singleton()->add_singleton( Globals::Singleton("SS",SpatialSound2DServer::get_singleton()) );
	Globals::get_singleton()->add_singleton( Globals::Singleton("SpatialSound2DServer",SpatialSound2DServer::get_singleton()) );
	Globals::get_singleton()->add_singleton( Globals::Singleton("SS2D",SpatialSound2DServer::get_singleton()) );

	ObjectTypeDB::register_virtual_type<Physics2DDirectBodyState>();
	ObjectTypeDB::register_virtual_type<Physics2DDirectSpaceState>();
	ObjectTypeDB::register_virtual_type<Physics2DShapeQueryResult>();
	ObjectTypeDB::register_type<Physics2DTestMotionResult>();
	ObjectTypeDB::register_type<Physics2DShapeQueryParameters>();

	ObjectTypeDB::register_type<PhysicsShapeQueryParameters>();
	ObjectTypeDB::register_virtual_type<PhysicsDirectBodyState>();
	ObjectTypeDB::register_virtual_type<PhysicsDirectSpaceState>();
	ObjectTypeDB::register_virtual_type<PhysicsShapeQueryResult>();

}

void unregister_server_types(){

}
<|endoftext|>


<commit_before>// Copyright (c) 2017-2018 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 <key_io.h>
#include <keystore.h>
#include <rpc/protocol.h>
#include <rpc/util.h>
#include <tinyformat.h>
#include <util/strencodings.h>

InitInterfaces* g_rpc_interfaces = nullptr;

// Converts a hex string to a public key if possible
CPubKey HexToPubKey(const std::string& hex_in)
{
    if (!IsHex(hex_in)) {
        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid public key: " + hex_in);
    }
    CPubKey vchPubKey(ParseHex(hex_in));
    if (!vchPubKey.IsFullyValid()) {
        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid public key: " + hex_in);
    }
    return vchPubKey;
}

// Retrieves a public key for an address from the given CKeyStore
CPubKey AddrToPubKey(CKeyStore* const keystore, const std::string& addr_in)
{
    CTxDestination dest = DecodeDestination(addr_in);
    if (!IsValidDestination(dest)) {
        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address: " + addr_in);
    }
    CKeyID key = GetKeyForDestination(*keystore, dest);
    if (key.IsNull()) {
        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("%s does not refer to a key", addr_in));
    }
    CPubKey vchPubKey;
    if (!keystore->GetPubKey(key, vchPubKey)) {
        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("no full public key for address %s", addr_in));
    }
    if (!vchPubKey.IsFullyValid()) {
       throw JSONRPCError(RPC_INTERNAL_ERROR, "Wallet contains an invalid public key");
    }
    return vchPubKey;
}

// Creates a multisig redeemscript from a given list of public keys and number required.
CScript CreateMultisigRedeemscript(const int required, const std::vector<CPubKey>& pubkeys)
{
    // Gather public keys
    if (required < 1) {
        throw JSONRPCError(RPC_INVALID_PARAMETER, "a multisignature address must require at least one key to redeem");
    }
    if ((int)pubkeys.size() < required) {
        throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("not enough keys supplied (got %u keys, but need at least %d to redeem)", pubkeys.size(), required));
    }
    if (pubkeys.size() > 16) {
        throw JSONRPCError(RPC_INVALID_PARAMETER, "Number of keys involved in the multisignature address creation > 16\nReduce the number");
    }

    CScript result = GetScriptForMultisig(required, pubkeys);

    if (result.size() > MAX_SCRIPT_ELEMENT_SIZE) {
        throw JSONRPCError(RPC_INVALID_PARAMETER, (strprintf("redeemScript exceeds size limit: %d > %d", result.size(), MAX_SCRIPT_ELEMENT_SIZE)));
    }

    return result;
}

class DescribeAddressVisitor : public boost::static_visitor<UniValue>
{
public:
    explicit DescribeAddressVisitor() {}

    UniValue operator()(const CNoDestination& dest) const
    {
        return UniValue(UniValue::VOBJ);
    }

    UniValue operator()(const CKeyID& keyID) const
    {
        UniValue obj(UniValue::VOBJ);
        obj.pushKV("isscript", false);
        obj.pushKV("iswitness", false);
        return obj;
    }

    UniValue operator()(const CScriptID& scriptID) const
    {
        UniValue obj(UniValue::VOBJ);
        obj.pushKV("isscript", true);
        obj.pushKV("iswitness", false);
        return obj;
    }

    UniValue operator()(const WitnessV0KeyHash& id) const
    {
        UniValue obj(UniValue::VOBJ);
        obj.pushKV("isscript", false);
        obj.pushKV("iswitness", true);
        obj.pushKV("witness_version", 0);
        obj.pushKV("witness_program", HexStr(id.begin(), id.end()));
        return obj;
    }

    UniValue operator()(const WitnessV0ScriptHash& id) const
    {
        UniValue obj(UniValue::VOBJ);
        obj.pushKV("isscript", true);
        obj.pushKV("iswitness", true);
        obj.pushKV("witness_version", 0);
        obj.pushKV("witness_program", HexStr(id.begin(), id.end()));
        return obj;
    }

    UniValue operator()(const WitnessUnknown& id) const
    {
        UniValue obj(UniValue::VOBJ);
        obj.pushKV("iswitness", true);
        obj.pushKV("witness_version", (int)id.version);
        obj.pushKV("witness_program", HexStr(id.program, id.program + id.length));
        return obj;
    }
};

UniValue DescribeAddress(const CTxDestination& dest)
{
    return boost::apply_visitor(DescribeAddressVisitor(), dest);
}

struct Section {
    Section(const std::string& left, const std::string& right)
        : m_left{left}, m_right{right} {}
    const std::string m_left;
    const std::string m_right;
};

struct Sections {
    std::vector<Section> m_sections;
    size_t m_max_pad{0};

    void PushSection(const Section& s)
    {
        m_max_pad = std::max(m_max_pad, s.m_left.size());
        m_sections.push_back(s);
    }

    enum class OuterType {
        ARR,
        OBJ,
        NAMED_ARG, // Only set on first recursion
    };

    void Push(const RPCArg& arg, const size_t current_indent = 5, const OuterType outer_type = OuterType::NAMED_ARG)
    {
        const auto indent = std::string(current_indent, ' ');
        const auto indent_next = std::string(current_indent + 2, ' ');
        switch (arg.m_type) {
        case RPCArg::Type::STR_HEX:
        case RPCArg::Type::STR:
        case RPCArg::Type::NUM:
        case RPCArg::Type::AMOUNT:
        case RPCArg::Type::BOOL: {
            if (outer_type == OuterType::NAMED_ARG) return; // Nothing more to do for non-recursive types on first recursion
            auto left = indent;
            if (arg.m_type_str.size() != 0 && outer_type == OuterType::OBJ) {
                left += "\"" + arg.m_name + "\": " + arg.m_type_str.at(0);
            } else {
                left += outer_type == OuterType::OBJ ? arg.ToStringObj(/* oneline */ false) : arg.ToString(/* oneline */ false);
            }
            left += ",";
            PushSection({left, arg.ToDescriptionString(/* implicitly_required */ outer_type == OuterType::ARR)});
            break;
        }
        case RPCArg::Type::OBJ:
        case RPCArg::Type::OBJ_USER_KEYS: {
            const auto right = outer_type == OuterType::NAMED_ARG ? "" : arg.ToDescriptionString(/* implicitly_required */ outer_type == OuterType::ARR);
            PushSection({indent + "{", right});
            for (const auto& arg_inner : arg.m_inner) {
                Push(arg_inner, current_indent + 2, OuterType::OBJ);
            }
            if (arg.m_type != RPCArg::Type::OBJ) {
                PushSection({indent_next + "...", ""});
            }
            PushSection({indent + "}" + (outer_type != OuterType::NAMED_ARG ? "," : ""), ""});
            break;
        }
        case RPCArg::Type::ARR: {
            auto left = indent;
            left += outer_type == OuterType::OBJ ? "\"" + arg.m_name + "\": " : "";
            left += "[";
            const auto right = outer_type == OuterType::NAMED_ARG ? "" : arg.ToDescriptionString(/* implicitly_required */ outer_type == OuterType::ARR);
            PushSection({left, right});
            for (const auto& arg_inner : arg.m_inner) {
                Push(arg_inner, current_indent + 2, OuterType::ARR);
            }
            PushSection({indent_next + "...", ""});
            PushSection({indent + "]" + (outer_type != OuterType::NAMED_ARG ? "," : ""), ""});
            break;
        }

            // no default case, so the compiler can warn about missing cases
        }
    }

    std::string ToString() const
    {
        std::string ret;
        const size_t pad = m_max_pad + 4;
        for (const auto& s : m_sections) {
            if (s.m_right.empty()) {
                ret += s.m_left;
                ret += "\n";
                continue;
            }

            std::string left = s.m_left;
            left.resize(pad, ' ');
            ret += left;

            // Properly pad after newlines
            std::string right;
            size_t begin = 0;
            size_t new_line_pos = s.m_right.find_first_of('\n');
            while (true) {
                right += s.m_right.substr(begin, new_line_pos - begin);
                if (new_line_pos == std::string::npos) {
                    break; //No new line
                }
                right += "\n" + std::string(pad, ' ');
                begin = s.m_right.find_first_not_of(' ', new_line_pos + 1);
                if (begin == std::string::npos) {
                    break; // Empty line
                }
                new_line_pos = s.m_right.find_first_of('\n', begin + 1);
            }
            ret += right;
            ret += "\n";
        }
        return ret;
    }
};

RPCHelpMan::RPCHelpMan(const std::string& name, const std::string& description, const std::vector<RPCArg>& args)
    : m_name{name}, m_description{description}, m_args{args}
{
    std::set<std::string> named_args;
    for (const auto& arg : m_args) {
        // Should have unique named arguments
        assert(named_args.insert(arg.m_name).second);
    }
}

std::string RPCHelpMan::ToString() const
{
    std::string ret;

    // Oneline summary
    ret += m_name;
    bool is_optional{false};
    for (const auto& arg : m_args) {
        ret += " ";
        if (arg.m_optional) {
            if (!is_optional) ret += "( ";
            is_optional = true;
        } else {
            // Currently we still support unnamed arguments, so any argument following an optional argument must also be optional
            // If support for positional arguments is deprecated in the future, remove this line
            assert(!is_optional);
        }
        ret += arg.ToString(/* oneline */ true);
    }
    if (is_optional) ret += " )";
    ret += "\n";

    // Description
    ret += m_description;

    // Arguments
    Sections sections;
    for (size_t i{0}; i < m_args.size(); ++i) {
        const auto& arg = m_args.at(i);

        if (i == 0) ret += "\nArguments:\n";

        // Push named argument name and description
        const auto str_wrapper = (arg.m_type == RPCArg::Type::STR || arg.m_type == RPCArg::Type::STR_HEX) ? "\"" : "";
        sections.m_sections.emplace_back(std::to_string(i + 1) + ". " + str_wrapper + arg.m_name + str_wrapper, arg.ToDescriptionString());
        sections.m_max_pad = std::max(sections.m_max_pad, sections.m_sections.back().m_left.size());

        // Recursively push nested args
        sections.Push(arg);
    }
    ret += sections.ToString();

    return ret;
}

std::string RPCArg::ToDescriptionString(const bool implicitly_required) const
{
    std::string ret;
    ret += "(";
    if (m_type_str.size() != 0) {
        ret += m_type_str.at(1);
    } else {
        switch (m_type) {
        case Type::STR_HEX:
        case Type::STR: {
            ret += "string";
            break;
        }
        case Type::NUM: {
            ret += "numeric";
            break;
        }
        case Type::AMOUNT: {
            ret += "numeric or string";
            break;
        }
        case Type::BOOL: {
            ret += "boolean";
            break;
        }
        case Type::OBJ:
        case Type::OBJ_USER_KEYS: {
            ret += "json object";
            break;
        }
        case Type::ARR: {
            ret += "json array";
            break;
        }

            // no default case, so the compiler can warn about missing cases
        }
    }
    if (!implicitly_required) {
        ret += ", ";
        if (m_optional) {
            ret += "optional";
            if (!m_default_value.empty()) {
                ret += ", default=" + m_default_value;
            } else {
                // TODO enable this assert, when all optional parameters have their default value documented
                //assert(false);
            }
        } else {
            ret += "required";
            assert(m_default_value.empty()); // Default value is ignored, and must not be present
        }
    }
    ret += ")";
    ret += m_description.empty() ? "" : " " + m_description;
    return ret;
}

std::string RPCArg::ToStringObj(const bool oneline) const
{
    std::string res;
    res += "\"";
    res += m_name;
    if (oneline) {
        res += "\":";
    } else {
        res += "\": ";
    }
    switch (m_type) {
    case Type::STR:
        return res + "\"str\"";
    case Type::STR_HEX:
        return res + "\"hex\"";
    case Type::NUM:
        return res + "n";
    case Type::AMOUNT:
        return res + "amount";
    case Type::BOOL:
        return res + "bool";
    case Type::ARR:
        res += "[";
        for (const auto& i : m_inner) {
            res += i.ToString(oneline) + ",";
        }
        return res + "...]";
    case Type::OBJ:
    case Type::OBJ_USER_KEYS:
        // Currently unused, so avoid writing dead code
        assert(false);

        // no default case, so the compiler can warn about missing cases
    }
    assert(false);
}

std::string RPCArg::ToString(const bool oneline) const
{
    if (oneline && !m_oneline_description.empty()) return m_oneline_description;

    switch (m_type) {
    case Type::STR_HEX:
    case Type::STR: {
        return "\"" + m_name + "\"";
    }
    case Type::NUM:
    case Type::AMOUNT:
    case Type::BOOL: {
        return m_name;
    }
    case Type::OBJ:
    case Type::OBJ_USER_KEYS: {
        std::string res;
        for (size_t i = 0; i < m_inner.size();) {
            res += m_inner[i].ToStringObj(oneline);
            if (++i < m_inner.size()) res += ",";
        }
        if (m_type == Type::OBJ) {
            return "{" + res + "}";
        } else {
            return "{" + res + ",...}";
        }
    }
    case Type::ARR: {
        std::string res;
        for (const auto& i : m_inner) {
            res += i.ToString(oneline) + ",";
        }
        return "[" + res + "...]";
    }

        // no default case, so the compiler can warn about missing cases
    }
    assert(false);
}
<commit_msg>RPCHelpMan: Support required arguments after optional ones<commit_after>// Copyright (c) 2017-2018 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 <key_io.h>
#include <keystore.h>
#include <rpc/protocol.h>
#include <rpc/util.h>
#include <tinyformat.h>
#include <util/strencodings.h>

InitInterfaces* g_rpc_interfaces = nullptr;

// Converts a hex string to a public key if possible
CPubKey HexToPubKey(const std::string& hex_in)
{
    if (!IsHex(hex_in)) {
        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid public key: " + hex_in);
    }
    CPubKey vchPubKey(ParseHex(hex_in));
    if (!vchPubKey.IsFullyValid()) {
        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid public key: " + hex_in);
    }
    return vchPubKey;
}

// Retrieves a public key for an address from the given CKeyStore
CPubKey AddrToPubKey(CKeyStore* const keystore, const std::string& addr_in)
{
    CTxDestination dest = DecodeDestination(addr_in);
    if (!IsValidDestination(dest)) {
        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address: " + addr_in);
    }
    CKeyID key = GetKeyForDestination(*keystore, dest);
    if (key.IsNull()) {
        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("%s does not refer to a key", addr_in));
    }
    CPubKey vchPubKey;
    if (!keystore->GetPubKey(key, vchPubKey)) {
        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("no full public key for address %s", addr_in));
    }
    if (!vchPubKey.IsFullyValid()) {
       throw JSONRPCError(RPC_INTERNAL_ERROR, "Wallet contains an invalid public key");
    }
    return vchPubKey;
}

// Creates a multisig redeemscript from a given list of public keys and number required.
CScript CreateMultisigRedeemscript(const int required, const std::vector<CPubKey>& pubkeys)
{
    // Gather public keys
    if (required < 1) {
        throw JSONRPCError(RPC_INVALID_PARAMETER, "a multisignature address must require at least one key to redeem");
    }
    if ((int)pubkeys.size() < required) {
        throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("not enough keys supplied (got %u keys, but need at least %d to redeem)", pubkeys.size(), required));
    }
    if (pubkeys.size() > 16) {
        throw JSONRPCError(RPC_INVALID_PARAMETER, "Number of keys involved in the multisignature address creation > 16\nReduce the number");
    }

    CScript result = GetScriptForMultisig(required, pubkeys);

    if (result.size() > MAX_SCRIPT_ELEMENT_SIZE) {
        throw JSONRPCError(RPC_INVALID_PARAMETER, (strprintf("redeemScript exceeds size limit: %d > %d", result.size(), MAX_SCRIPT_ELEMENT_SIZE)));
    }

    return result;
}

class DescribeAddressVisitor : public boost::static_visitor<UniValue>
{
public:
    explicit DescribeAddressVisitor() {}

    UniValue operator()(const CNoDestination& dest) const
    {
        return UniValue(UniValue::VOBJ);
    }

    UniValue operator()(const CKeyID& keyID) const
    {
        UniValue obj(UniValue::VOBJ);
        obj.pushKV("isscript", false);
        obj.pushKV("iswitness", false);
        return obj;
    }

    UniValue operator()(const CScriptID& scriptID) const
    {
        UniValue obj(UniValue::VOBJ);
        obj.pushKV("isscript", true);
        obj.pushKV("iswitness", false);
        return obj;
    }

    UniValue operator()(const WitnessV0KeyHash& id) const
    {
        UniValue obj(UniValue::VOBJ);
        obj.pushKV("isscript", false);
        obj.pushKV("iswitness", true);
        obj.pushKV("witness_version", 0);
        obj.pushKV("witness_program", HexStr(id.begin(), id.end()));
        return obj;
    }

    UniValue operator()(const WitnessV0ScriptHash& id) const
    {
        UniValue obj(UniValue::VOBJ);
        obj.pushKV("isscript", true);
        obj.pushKV("iswitness", true);
        obj.pushKV("witness_version", 0);
        obj.pushKV("witness_program", HexStr(id.begin(), id.end()));
        return obj;
    }

    UniValue operator()(const WitnessUnknown& id) const
    {
        UniValue obj(UniValue::VOBJ);
        obj.pushKV("iswitness", true);
        obj.pushKV("witness_version", (int)id.version);
        obj.pushKV("witness_program", HexStr(id.program, id.program + id.length));
        return obj;
    }
};

UniValue DescribeAddress(const CTxDestination& dest)
{
    return boost::apply_visitor(DescribeAddressVisitor(), dest);
}

struct Section {
    Section(const std::string& left, const std::string& right)
        : m_left{left}, m_right{right} {}
    const std::string m_left;
    const std::string m_right;
};

struct Sections {
    std::vector<Section> m_sections;
    size_t m_max_pad{0};

    void PushSection(const Section& s)
    {
        m_max_pad = std::max(m_max_pad, s.m_left.size());
        m_sections.push_back(s);
    }

    enum class OuterType {
        ARR,
        OBJ,
        NAMED_ARG, // Only set on first recursion
    };

    void Push(const RPCArg& arg, const size_t current_indent = 5, const OuterType outer_type = OuterType::NAMED_ARG)
    {
        const auto indent = std::string(current_indent, ' ');
        const auto indent_next = std::string(current_indent + 2, ' ');
        switch (arg.m_type) {
        case RPCArg::Type::STR_HEX:
        case RPCArg::Type::STR:
        case RPCArg::Type::NUM:
        case RPCArg::Type::AMOUNT:
        case RPCArg::Type::BOOL: {
            if (outer_type == OuterType::NAMED_ARG) return; // Nothing more to do for non-recursive types on first recursion
            auto left = indent;
            if (arg.m_type_str.size() != 0 && outer_type == OuterType::OBJ) {
                left += "\"" + arg.m_name + "\": " + arg.m_type_str.at(0);
            } else {
                left += outer_type == OuterType::OBJ ? arg.ToStringObj(/* oneline */ false) : arg.ToString(/* oneline */ false);
            }
            left += ",";
            PushSection({left, arg.ToDescriptionString(/* implicitly_required */ outer_type == OuterType::ARR)});
            break;
        }
        case RPCArg::Type::OBJ:
        case RPCArg::Type::OBJ_USER_KEYS: {
            const auto right = outer_type == OuterType::NAMED_ARG ? "" : arg.ToDescriptionString(/* implicitly_required */ outer_type == OuterType::ARR);
            PushSection({indent + "{", right});
            for (const auto& arg_inner : arg.m_inner) {
                Push(arg_inner, current_indent + 2, OuterType::OBJ);
            }
            if (arg.m_type != RPCArg::Type::OBJ) {
                PushSection({indent_next + "...", ""});
            }
            PushSection({indent + "}" + (outer_type != OuterType::NAMED_ARG ? "," : ""), ""});
            break;
        }
        case RPCArg::Type::ARR: {
            auto left = indent;
            left += outer_type == OuterType::OBJ ? "\"" + arg.m_name + "\": " : "";
            left += "[";
            const auto right = outer_type == OuterType::NAMED_ARG ? "" : arg.ToDescriptionString(/* implicitly_required */ outer_type == OuterType::ARR);
            PushSection({left, right});
            for (const auto& arg_inner : arg.m_inner) {
                Push(arg_inner, current_indent + 2, OuterType::ARR);
            }
            PushSection({indent_next + "...", ""});
            PushSection({indent + "]" + (outer_type != OuterType::NAMED_ARG ? "," : ""), ""});
            break;
        }

            // no default case, so the compiler can warn about missing cases
        }
    }

    std::string ToString() const
    {
        std::string ret;
        const size_t pad = m_max_pad + 4;
        for (const auto& s : m_sections) {
            if (s.m_right.empty()) {
                ret += s.m_left;
                ret += "\n";
                continue;
            }

            std::string left = s.m_left;
            left.resize(pad, ' ');
            ret += left;

            // Properly pad after newlines
            std::string right;
            size_t begin = 0;
            size_t new_line_pos = s.m_right.find_first_of('\n');
            while (true) {
                right += s.m_right.substr(begin, new_line_pos - begin);
                if (new_line_pos == std::string::npos) {
                    break; //No new line
                }
                right += "\n" + std::string(pad, ' ');
                begin = s.m_right.find_first_not_of(' ', new_line_pos + 1);
                if (begin == std::string::npos) {
                    break; // Empty line
                }
                new_line_pos = s.m_right.find_first_of('\n', begin + 1);
            }
            ret += right;
            ret += "\n";
        }
        return ret;
    }
};

RPCHelpMan::RPCHelpMan(const std::string& name, const std::string& description, const std::vector<RPCArg>& args)
    : m_name{name}, m_description{description}, m_args{args}
{
    std::set<std::string> named_args;
    for (const auto& arg : m_args) {
        // Should have unique named arguments
        assert(named_args.insert(arg.m_name).second);
    }
}

std::string RPCHelpMan::ToString() const
{
    std::string ret;

    // Oneline summary
    ret += m_name;
    bool was_optional{false};
    for (const auto& arg : m_args) {
        ret += " ";
        if (arg.m_optional) {
            if (!was_optional) ret += "( ";
            was_optional = true;
        } else {
            if (was_optional) ret += ") ";
            was_optional = false;
        }
        ret += arg.ToString(/* oneline */ true);
    }
    if (was_optional) ret += " )";
    ret += "\n";

    // Description
    ret += m_description;

    // Arguments
    Sections sections;
    for (size_t i{0}; i < m_args.size(); ++i) {
        const auto& arg = m_args.at(i);

        if (i == 0) ret += "\nArguments:\n";

        // Push named argument name and description
        sections.m_sections.emplace_back(std::to_string(i + 1) + ". " + arg.m_name, arg.ToDescriptionString());
        sections.m_max_pad = std::max(sections.m_max_pad, sections.m_sections.back().m_left.size());

        // Recursively push nested args
        sections.Push(arg);
    }
    ret += sections.ToString();

    return ret;
}

std::string RPCArg::ToDescriptionString(const bool implicitly_required) const
{
    std::string ret;
    ret += "(";
    if (m_type_str.size() != 0) {
        ret += m_type_str.at(1);
    } else {
        switch (m_type) {
        case Type::STR_HEX:
        case Type::STR: {
            ret += "string";
            break;
        }
        case Type::NUM: {
            ret += "numeric";
            break;
        }
        case Type::AMOUNT: {
            ret += "numeric or string";
            break;
        }
        case Type::BOOL: {
            ret += "boolean";
            break;
        }
        case Type::OBJ:
        case Type::OBJ_USER_KEYS: {
            ret += "json object";
            break;
        }
        case Type::ARR: {
            ret += "json array";
            break;
        }

            // no default case, so the compiler can warn about missing cases
        }
    }
    if (!implicitly_required) {
        ret += ", ";
        if (m_optional) {
            ret += "optional";
            if (!m_default_value.empty()) {
                ret += ", default=" + m_default_value;
            } else {
                // TODO enable this assert, when all optional parameters have their default value documented
                //assert(false);
            }
        } else {
            ret += "required";
            assert(m_default_value.empty()); // Default value is ignored, and must not be present
        }
    }
    ret += ")";
    ret += m_description.empty() ? "" : " " + m_description;
    return ret;
}

std::string RPCArg::ToStringObj(const bool oneline) const
{
    std::string res;
    res += "\"";
    res += m_name;
    if (oneline) {
        res += "\":";
    } else {
        res += "\": ";
    }
    switch (m_type) {
    case Type::STR:
        return res + "\"str\"";
    case Type::STR_HEX:
        return res + "\"hex\"";
    case Type::NUM:
        return res + "n";
    case Type::AMOUNT:
        return res + "amount";
    case Type::BOOL:
        return res + "bool";
    case Type::ARR:
        res += "[";
        for (const auto& i : m_inner) {
            res += i.ToString(oneline) + ",";
        }
        return res + "...]";
    case Type::OBJ:
    case Type::OBJ_USER_KEYS:
        // Currently unused, so avoid writing dead code
        assert(false);

        // no default case, so the compiler can warn about missing cases
    }
    assert(false);
}

std::string RPCArg::ToString(const bool oneline) const
{
    if (oneline && !m_oneline_description.empty()) return m_oneline_description;

    switch (m_type) {
    case Type::STR_HEX:
    case Type::STR: {
        return "\"" + m_name + "\"";
    }
    case Type::NUM:
    case Type::AMOUNT:
    case Type::BOOL: {
        return m_name;
    }
    case Type::OBJ:
    case Type::OBJ_USER_KEYS: {
        std::string res;
        for (size_t i = 0; i < m_inner.size();) {
            res += m_inner[i].ToStringObj(oneline);
            if (++i < m_inner.size()) res += ",";
        }
        if (m_type == Type::OBJ) {
            return "{" + res + "}";
        } else {
            return "{" + res + ",...}";
        }
    }
    case Type::ARR: {
        std::string res;
        for (const auto& i : m_inner) {
            res += i.ToString(oneline) + ",";
        }
        return "[" + res + "...]";
    }

        // no default case, so the compiler can warn about missing cases
    }
    assert(false);
}
<|endoftext|>


<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/gfx/gtk_preserve_window.h"

#include <gdk/gdkwindow.h>
#include <gtk/gtk.h>
#include <gtk/gtkwidget.h>
#include <gtk/gtkfixed.h>

G_BEGIN_DECLS

#define GTK_PRESERVE_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
                                            GTK_TYPE_PRESERVE_WINDOW, \
                                            GtkPreserveWindowPrivate))

typedef struct _GtkPreserveWindowPrivate GtkPreserveWindowPrivate;

struct _GtkPreserveWindowPrivate {
  // If true, don't create/destroy windows on realize/unrealize.
  gboolean preserve_window;

  // Whether or not we delegate the resize of the GdkWindow
  // to someone else.
  gboolean delegate_resize;
};

G_DEFINE_TYPE(GtkPreserveWindow, gtk_preserve_window, GTK_TYPE_FIXED)

static void gtk_preserve_window_destroy(GtkObject* object);
static void gtk_preserve_window_realize(GtkWidget* widget);
static void gtk_preserve_window_unrealize(GtkWidget* widget);
static void gtk_preserve_window_size_allocate(GtkWidget* widget,
                                              GtkAllocation* allocation);

static void gtk_preserve_window_class_init(GtkPreserveWindowClass *klass) {
  GtkWidgetClass* widget_class = reinterpret_cast<GtkWidgetClass*>(klass);
  widget_class->realize = gtk_preserve_window_realize;
  widget_class->unrealize = gtk_preserve_window_unrealize;
  widget_class->size_allocate = gtk_preserve_window_size_allocate;

  GtkObjectClass* object_class = reinterpret_cast<GtkObjectClass*>(klass);
  object_class->destroy = gtk_preserve_window_destroy;

  GObjectClass* gobject_class = G_OBJECT_CLASS(klass);
  g_type_class_add_private(gobject_class, sizeof(GtkPreserveWindowPrivate));
}

static void gtk_preserve_window_init(GtkPreserveWindow* widget) {
  GtkPreserveWindowPrivate* priv = GTK_PRESERVE_WINDOW_GET_PRIVATE(widget);
  priv->preserve_window = FALSE;

  // These widgets always have their own window.
  gtk_fixed_set_has_window(GTK_FIXED(widget), TRUE);
}

GtkWidget* gtk_preserve_window_new() {
  return GTK_WIDGET(g_object_new(GTK_TYPE_PRESERVE_WINDOW, NULL));
}

static void gtk_preserve_window_destroy(GtkObject* object) {
  GtkWidget* widget = reinterpret_cast<GtkWidget*>(object);
  GtkPreserveWindowPrivate* priv = GTK_PRESERVE_WINDOW_GET_PRIVATE(widget);

  if (widget->window) {
    gdk_window_set_user_data(widget->window, NULL);
    // If the window is preserved, someone else must destroy it.
    if (!priv->preserve_window)
      gdk_window_destroy(widget->window);
    widget->window = NULL;
  }

  GTK_OBJECT_CLASS(gtk_preserve_window_parent_class)->destroy(object);
}

static void gtk_preserve_window_realize(GtkWidget* widget) {
  g_return_if_fail(GTK_IS_PRESERVE_WINDOW(widget));

  if (widget->window) {
    gdk_window_reparent(widget->window,
                        gtk_widget_get_parent_window(widget),
                        widget->allocation.x,
                        widget->allocation.y);
    widget->style = gtk_style_attach(widget->style, widget->window);
    gtk_style_set_background(widget->style, widget->window, GTK_STATE_NORMAL);

    gint event_mask = gtk_widget_get_events(widget);
    event_mask |= GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK;
    gdk_window_set_events(widget->window, (GdkEventMask) event_mask);
    gdk_window_set_user_data(widget->window, widget);

    // Deprecated as of GTK 2.22. Used for compatibility.
    // It should be: gtk_widget_set_realized(widget, TRUE)
    GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED);
  } else {
    GTK_WIDGET_CLASS(gtk_preserve_window_parent_class)->realize(widget);
  }
}

static void gtk_preserve_window_unrealize(GtkWidget* widget) {
  g_return_if_fail(GTK_IS_PRESERVE_WINDOW(widget));

  GtkPreserveWindowPrivate* priv = GTK_PRESERVE_WINDOW_GET_PRIVATE(widget);
  if (priv->preserve_window) {
    GtkWidgetClass* widget_class =
        GTK_WIDGET_CLASS(gtk_preserve_window_parent_class);
    GtkContainerClass* container_class =
        GTK_CONTAINER_CLASS(gtk_preserve_window_parent_class);

    // Deprecated as of GTK 2.22. Used for compatibility.
    // It should be: gtk_widget_get_mapped()
    if (GTK_WIDGET_MAPPED(widget)) {
      widget_class->unmap(widget);

      // Deprecated as of GTK 2.22. Used for compatibility.
      // It should be: gtk_widget_set_mapped(widget, FALSE)
      GTK_WIDGET_UNSET_FLAGS(widget, GTK_MAPPED);
    }

    // This is the behavior from GtkWidget, inherited by GtkFixed.
    // It is unclear why we should not call the potentially overridden
    // unrealize method (via the callback), but doing so causes errors.
    container_class->forall(
        GTK_CONTAINER(widget), FALSE,
        reinterpret_cast<GtkCallback>(gtk_widget_unrealize), NULL);

    gtk_style_detach(widget->style);
    gdk_window_reparent(widget->window, gdk_get_default_root_window(), 0, 0);
    gtk_selection_remove_all(widget);
    gdk_window_set_user_data(widget->window, NULL);

    // Deprecated as of GTK 2.22. Used for compatibility.
    // It should be: gtk_widget_set_realized(widget, FALSE)
    GTK_WIDGET_UNSET_FLAGS(widget, GTK_REALIZED);
  } else {
    GTK_WIDGET_CLASS(gtk_preserve_window_parent_class)->unrealize(widget);
  }
}

gboolean gtk_preserve_window_get_preserve(GtkPreserveWindow* window) {
  g_return_val_if_fail(GTK_IS_PRESERVE_WINDOW(window), FALSE);
  GtkPreserveWindowPrivate* priv = GTK_PRESERVE_WINDOW_GET_PRIVATE(window);

  return priv->preserve_window;
}

void gtk_preserve_window_set_preserve(GtkPreserveWindow* window,
                                      gboolean value) {
  g_return_if_fail(GTK_IS_PRESERVE_WINDOW(window));
  GtkPreserveWindowPrivate* priv = GTK_PRESERVE_WINDOW_GET_PRIVATE(window);
  priv->preserve_window = value;

  GtkWidget* widget = GTK_WIDGET(window);
  if (value && !widget->window) {
    GdkWindowAttr attributes;
    gint attributes_mask;

    // We may not know the width and height, so we rely on the fact
    // that a size-allocation will resize it later.
    attributes.width = 1;
    attributes.height = 1;

    attributes.window_type = GDK_WINDOW_CHILD;
    attributes.wclass = GDK_INPUT_OUTPUT;

    attributes.visual = gtk_widget_get_visual(widget);
    attributes.colormap = gtk_widget_get_colormap(widget);

    attributes_mask = GDK_WA_VISUAL | GDK_WA_COLORMAP;
    widget->window = gdk_window_new(
        gdk_get_default_root_window(), &attributes, attributes_mask);
  } else if (!value && widget->window && !GTK_WIDGET_REALIZED(widget)) {
    gdk_window_destroy(widget->window);
    widget->window = NULL;
  }
}

void gtk_preserve_window_size_allocate(GtkWidget* widget,
                                       GtkAllocation* allocation) {
  g_return_if_fail(GTK_IS_PRESERVE_WINDOW(widget));
  GtkPreserveWindowPrivate* priv = GTK_PRESERVE_WINDOW_GET_PRIVATE(widget);

  if (priv->delegate_resize) {
    // Just update the state. Someone else will gdk_window_resize the
    // associated GdkWindow.
    widget->allocation = *allocation;
  } else {
    GTK_WIDGET_CLASS(gtk_preserve_window_parent_class)->size_allocate(
        widget, allocation);
  }
}

void gtk_preserve_window_delegate_resize(GtkPreserveWindow* widget,
                                         gboolean delegate) {
  GtkPreserveWindowPrivate* priv = GTK_PRESERVE_WINDOW_GET_PRIVATE(widget);
  priv->delegate_resize = delegate;
}

G_END_DECLS
<commit_msg>To prevent damage to the back-buffer, it's only necessary to defer resize.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/gfx/gtk_preserve_window.h"

#include <gdk/gdkwindow.h>
#include <gtk/gtk.h>
#include <gtk/gtkwidget.h>
#include <gtk/gtkfixed.h>

G_BEGIN_DECLS

#define GTK_PRESERVE_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
                                            GTK_TYPE_PRESERVE_WINDOW, \
                                            GtkPreserveWindowPrivate))

typedef struct _GtkPreserveWindowPrivate GtkPreserveWindowPrivate;

struct _GtkPreserveWindowPrivate {
  // If true, don't create/destroy windows on realize/unrealize.
  gboolean preserve_window;

  // Whether or not we delegate the resize of the GdkWindow
  // to someone else.
  gboolean delegate_resize;
};

G_DEFINE_TYPE(GtkPreserveWindow, gtk_preserve_window, GTK_TYPE_FIXED)

static void gtk_preserve_window_destroy(GtkObject* object);
static void gtk_preserve_window_realize(GtkWidget* widget);
static void gtk_preserve_window_unrealize(GtkWidget* widget);
static void gtk_preserve_window_size_allocate(GtkWidget* widget,
                                              GtkAllocation* allocation);

static void gtk_preserve_window_class_init(GtkPreserveWindowClass *klass) {
  GtkWidgetClass* widget_class = reinterpret_cast<GtkWidgetClass*>(klass);
  widget_class->realize = gtk_preserve_window_realize;
  widget_class->unrealize = gtk_preserve_window_unrealize;
  widget_class->size_allocate = gtk_preserve_window_size_allocate;

  GtkObjectClass* object_class = reinterpret_cast<GtkObjectClass*>(klass);
  object_class->destroy = gtk_preserve_window_destroy;

  GObjectClass* gobject_class = G_OBJECT_CLASS(klass);
  g_type_class_add_private(gobject_class, sizeof(GtkPreserveWindowPrivate));
}

static void gtk_preserve_window_init(GtkPreserveWindow* widget) {
  GtkPreserveWindowPrivate* priv = GTK_PRESERVE_WINDOW_GET_PRIVATE(widget);
  priv->preserve_window = FALSE;

  // These widgets always have their own window.
  gtk_fixed_set_has_window(GTK_FIXED(widget), TRUE);
}

GtkWidget* gtk_preserve_window_new() {
  return GTK_WIDGET(g_object_new(GTK_TYPE_PRESERVE_WINDOW, NULL));
}

static void gtk_preserve_window_destroy(GtkObject* object) {
  GtkWidget* widget = reinterpret_cast<GtkWidget*>(object);
  GtkPreserveWindowPrivate* priv = GTK_PRESERVE_WINDOW_GET_PRIVATE(widget);

  if (widget->window) {
    gdk_window_set_user_data(widget->window, NULL);
    // If the window is preserved, someone else must destroy it.
    if (!priv->preserve_window)
      gdk_window_destroy(widget->window);
    widget->window = NULL;
  }

  GTK_OBJECT_CLASS(gtk_preserve_window_parent_class)->destroy(object);
}

static void gtk_preserve_window_realize(GtkWidget* widget) {
  g_return_if_fail(GTK_IS_PRESERVE_WINDOW(widget));

  if (widget->window) {
    gdk_window_reparent(widget->window,
                        gtk_widget_get_parent_window(widget),
                        widget->allocation.x,
                        widget->allocation.y);
    widget->style = gtk_style_attach(widget->style, widget->window);
    gtk_style_set_background(widget->style, widget->window, GTK_STATE_NORMAL);

    gint event_mask = gtk_widget_get_events(widget);
    event_mask |= GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK;
    gdk_window_set_events(widget->window, (GdkEventMask) event_mask);
    gdk_window_set_user_data(widget->window, widget);

    // Deprecated as of GTK 2.22. Used for compatibility.
    // It should be: gtk_widget_set_realized(widget, TRUE)
    GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED);
  } else {
    GTK_WIDGET_CLASS(gtk_preserve_window_parent_class)->realize(widget);
  }
}

static void gtk_preserve_window_unrealize(GtkWidget* widget) {
  g_return_if_fail(GTK_IS_PRESERVE_WINDOW(widget));

  GtkPreserveWindowPrivate* priv = GTK_PRESERVE_WINDOW_GET_PRIVATE(widget);
  if (priv->preserve_window) {
    GtkWidgetClass* widget_class =
        GTK_WIDGET_CLASS(gtk_preserve_window_parent_class);
    GtkContainerClass* container_class =
        GTK_CONTAINER_CLASS(gtk_preserve_window_parent_class);

    // Deprecated as of GTK 2.22. Used for compatibility.
    // It should be: gtk_widget_get_mapped()
    if (GTK_WIDGET_MAPPED(widget)) {
      widget_class->unmap(widget);

      // Deprecated as of GTK 2.22. Used for compatibility.
      // It should be: gtk_widget_set_mapped(widget, FALSE)
      GTK_WIDGET_UNSET_FLAGS(widget, GTK_MAPPED);
    }

    // This is the behavior from GtkWidget, inherited by GtkFixed.
    // It is unclear why we should not call the potentially overridden
    // unrealize method (via the callback), but doing so causes errors.
    container_class->forall(
        GTK_CONTAINER(widget), FALSE,
        reinterpret_cast<GtkCallback>(gtk_widget_unrealize), NULL);

    gtk_style_detach(widget->style);
    gdk_window_reparent(widget->window, gdk_get_default_root_window(), 0, 0);
    gtk_selection_remove_all(widget);
    gdk_window_set_user_data(widget->window, NULL);

    // Deprecated as of GTK 2.22. Used for compatibility.
    // It should be: gtk_widget_set_realized(widget, FALSE)
    GTK_WIDGET_UNSET_FLAGS(widget, GTK_REALIZED);
  } else {
    GTK_WIDGET_CLASS(gtk_preserve_window_parent_class)->unrealize(widget);
  }
}

gboolean gtk_preserve_window_get_preserve(GtkPreserveWindow* window) {
  g_return_val_if_fail(GTK_IS_PRESERVE_WINDOW(window), FALSE);
  GtkPreserveWindowPrivate* priv = GTK_PRESERVE_WINDOW_GET_PRIVATE(window);

  return priv->preserve_window;
}

void gtk_preserve_window_set_preserve(GtkPreserveWindow* window,
                                      gboolean value) {
  g_return_if_fail(GTK_IS_PRESERVE_WINDOW(window));
  GtkPreserveWindowPrivate* priv = GTK_PRESERVE_WINDOW_GET_PRIVATE(window);
  priv->preserve_window = value;

  GtkWidget* widget = GTK_WIDGET(window);
  if (value && !widget->window) {
    GdkWindowAttr attributes;
    gint attributes_mask;

    // We may not know the width and height, so we rely on the fact
    // that a size-allocation will resize it later.
    attributes.width = 1;
    attributes.height = 1;

    attributes.window_type = GDK_WINDOW_CHILD;
    attributes.wclass = GDK_INPUT_OUTPUT;

    attributes.visual = gtk_widget_get_visual(widget);
    attributes.colormap = gtk_widget_get_colormap(widget);

    attributes_mask = GDK_WA_VISUAL | GDK_WA_COLORMAP;
    widget->window = gdk_window_new(
        gdk_get_default_root_window(), &attributes, attributes_mask);
  } else if (!value && widget->window && !GTK_WIDGET_REALIZED(widget)) {
    gdk_window_destroy(widget->window);
    widget->window = NULL;
  }
}

void gtk_preserve_window_size_allocate(GtkWidget* widget,
                                       GtkAllocation* allocation) {
  g_return_if_fail(GTK_IS_PRESERVE_WINDOW(widget));
  GtkPreserveWindowPrivate* priv = GTK_PRESERVE_WINDOW_GET_PRIVATE(widget);

  if (priv->delegate_resize) {
    widget->allocation = *allocation;
    // Only update the position. Someone else will call gdk_window_resize.
    if (GTK_WIDGET_REALIZED(widget)) {
      gdk_window_move(widget->window, allocation->x, allocation->y);
    }
  } else {
    GTK_WIDGET_CLASS(gtk_preserve_window_parent_class)->size_allocate(
        widget, allocation);
  }
}

void gtk_preserve_window_delegate_resize(GtkPreserveWindow* widget,
                                         gboolean delegate) {
  GtkPreserveWindowPrivate* priv = GTK_PRESERVE_WINDOW_GET_PRIVATE(widget);
  priv->delegate_resize = delegate;
}

G_END_DECLS
<|endoftext|>


<commit_before>/*=============================================================================
	Copyright (c) 2012-2014 Richard Otis

    Distributed under the Boost Software License, Version 1.0. (See accompanying
    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
=============================================================================*/

// subroutines for EZD global minimization
// Reference: Maria Emelianenko, Zi-Kui Liu, and Qiang Du.
// "A new algorithm for the automation of phase diagram calculation." Computational Materials Science 35.1 (2006): 61-74.

#include "libgibbs/include/libgibbs_pch.hpp"
#include "libgibbs/include/optimizer/utils/ezd_minimization.hpp"
#include "libgibbs/include/compositionset.hpp"
#include "libgibbs/include/constraint.hpp"
#include "libgibbs/include/models.hpp"
#include "libgibbs/include/optimizer/halton.hpp"
#include "libgibbs/include/optimizer/utils/ndsimplex.hpp"
#include "libgibbs/include/utils/cholesky.hpp"
#include <boost/bimap.hpp>
#include <boost/numeric/ublas/symmetric.hpp>
#include <boost/numeric/ublas/vector.hpp>
#include <boost/numeric/ublas/io.hpp>
#include <algorithm>
#include <string>
#include <map>

namespace Optimizer {

// TODO: Should this be a member function of GibbsOpt?
// The function calling LocateMinima definitely should be at least (needs access to all CompositionSets)
// LocateMinima finds all of the minima for a given phase's Gibbs energy
// In addition to allowing us to choose a better starting point, this will allow for automatic miscibility gap detection
void LocateMinima(
		CompositionSet const &phase,
		sublattice_set const &sublset,
		evalconditions const& conditions,
		const std::size_t depth // depth tracking for recursion
		) {
	constexpr const std::size_t grid_points_per_axis = 10; // TODO: make this user-configurable
	using namespace boost::numeric::ublas;
	typedef std::vector<double> PointType;

	const std::size_t k = 2;
	const std::size_t d = 2;
	boost::numeric::ublas::vector<double> vertices(k);
	for (auto i = 0; i < k; ++i) {
	  vertices(i) = 1.0 / (double)k;
	  vertices(i) /= (double)k;
	}
	auto colorscheme = color_schemes(k,d);
	for (auto i = colorscheme.begin(); i != colorscheme.end(); ++i) {
	  std::cout << "n = " << std::distance(colorscheme.begin(),i) << std::endl;
	  std::cout << *i << std::endl;
	  std::cout << prod(vertices,trans(*i)) << std::endl;
	}
	return;

	// EZD Global Minimization (Emelianenko et al., 2006)
	// For depth = 1: FIND CONCAVITY REGIONS
	if (depth == 1) {
		std::vector<PointType> points;
		std::vector<std::size_t> components_in_sublattice;

		// Get the first sublattice for this phase
		boost::multi_index::index<sublattice_set,phase_subl>::type::iterator ic0,ic1;
		int sublindex = 0;
		ic0 = boost::multi_index::get<phase_subl>(sublset).lower_bound(boost::make_tuple(phase.name(), sublindex));
		ic1 = boost::multi_index::get<phase_subl>(sublset).upper_bound(boost::make_tuple(phase.name(), sublindex));;

		// (1) Sample some points on the domain using NDSimplex
		// Because the grid is uniform, we can assume that each point is the center of an N-simplex

		// Determine number of components in each sublattice
		while (ic0 != ic1) {
			const std::size_t number_of_species = std::distance(ic0,ic1);
			if (number_of_species > 0) components_in_sublattice.push_back(number_of_species);
			// Next sublattice
			++sublindex;
			ic0 = boost::multi_index::get<phase_subl>(sublset).lower_bound(boost::make_tuple(phase.name(), sublindex));
			ic1 = boost::multi_index::get<phase_subl>(sublset).end();
		}

		points = NDSimplex::lattice_complex(components_in_sublattice, 20);

		for (auto pt : points) {
			std::cout << "(";
			for (auto i = pt.begin(); i != pt.end(); ++i) {
				std::cout << *i;
				if (std::distance(i,pt.end()) > 1) std::cout << ",";
			}
			std::cout << ")" << std::endl;
		}

		PointType minpoint (points[0].size());
		double gradient_magnitude = std::numeric_limits<double>::max();
		// (2) Calculate the Lagrangian Hessian for all sampled points
		for (auto pt : points) {
			if (pt.size() == 0) continue; // skip empty (invalid) points
			symmetric_matrix<double, lower> Hessian(zero_matrix<double>(pt.size(),pt.size()));
			try {
				Hessian = phase.evaluate_objective_hessian_matrix(conditions, phase.get_variable_map(), pt);
			}
			catch (boost::exception &e) {
				std::cout << boost::diagnostic_information(e);
				throw;
			}
			catch (std::exception &e) {
				std::cout << e.what();
				throw;
			}
			//std::cout << "Hessian: " << Hessian << std::endl;
			// NOTE: For this calculation we consider only the linear constraints for an isolated phase (e.g., site fraction balances)
			// (3) Save all points for which the Lagrangian Hessian is positive definite in the null space of the constraint gradient matrix
			//        NOTE: This is the projected Hessian method (Nocedal and Wright, 2006, ch. 12.4, p.349)
			//        But how do I choose the Lagrange multipliers for all the constraints? Can I calculate them?
			//        The answer is that, because the constraints are linear, there is no constraint contribution to the Hessian.
			//        That means that the Hessian of the Lagrangian is just the Hessian of the objective function.
			const std::size_t Zcolumns = pt.size() - phase.get_constraints().size();
			// Z is the constraint null space matrix = phase.get_constraint_null_space_matrix()
			//    (a) Set Hproj = transpose(Z)*(L'')*Z
			matrix<double> Hproj(pt.size(), Zcolumns);
			Hproj = prod(trans(phase.get_constraint_null_space_matrix()),
					matrix<double>(prod(Hessian,phase.get_constraint_null_space_matrix())));
			//std::cout << "Hproj: " << Hproj << std::endl;
			//    (b) Verify that all diagonal elements of Hproj are strictly positive; if not, remove this point from consideration
			//        NOTE: This is a necessary but not sufficient condition that a matrix be positive definite, and it's easy to check
			//        Reference: Carlen and Carvalho, 2007, p. 148, Eq. 5.12
			//    (c) Attempt a Cholesky factorization of Hproj; will only succeed if matrix is positive definite
			const bool is_positive_definite = cholesky_factorize(Hproj);
			//    (d) If it succeeds, save this point; else, remove it
			if (is_positive_definite) {
				std::cout << pt[0] << " ";
				double obj = phase.evaluate_objective(conditions, phase.get_variable_map(), &pt[0]);
				std::cout << obj << std::endl;
				std::vector<double> gradient = phase.evaluate_internal_objective_gradient(conditions, &pt[0]);
				double mag = 0;
				for (auto i = gradient.begin(); i != gradient.end(); ++i) {
					//std::cout << "gradient[" << std::distance(gradient.begin(),i) << "] = " << *i << std::endl;
					mag += pow(*i,2);
				}
				if (mag < gradient_magnitude) {
					gradient_magnitude = mag;
					minpoint = pt;
					std::cout << "new minpoint: ";
					for (auto i = minpoint.begin(); i != minpoint.end(); ++i) {
						std::cout << *i;
						if (std::distance(i,minpoint.end()) > 1) std::cout << ",";
					}
					std::cout << " gradient sq: " << gradient_magnitude << std::endl;
				}
			}
			else {

			}
			// (4) For each saved point, send to next depth
		}
	}
	// For depth > 1: FIND MINIMA
	else if (depth > 1) {
		// (1) Sample some points on the domain using NDGrid (probably separate function)
		// (2) Calculate the objective gradient (f') for all sampled points
		// Note: This can be done by making use of the first-order KKT conditions to estimate the Lagrange multipliers.
		// (3) Find the point (z) with the minimum magnitude of L'
		// (4) If that magnitude is less than some defined epsilon, or we've hit max_depth, return z as a minimum
		//     Else use N-cube assumption to define new domain around z and send to next depth (return minima from that)
	}
	else {
		// invalid depth; throw exception
	}
}

}
<commit_msg>Test code for calculating simplex subdivision from given vertices. Works for a simple case. Now all of this needs to get properly wrapped into objects.<commit_after>/*=============================================================================
	Copyright (c) 2012-2014 Richard Otis

    Distributed under the Boost Software License, Version 1.0. (See accompanying
    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
=============================================================================*/

// subroutines for EZD global minimization
// Reference: Maria Emelianenko, Zi-Kui Liu, and Qiang Du.
// "A new algorithm for the automation of phase diagram calculation." Computational Materials Science 35.1 (2006): 61-74.

#include "libgibbs/include/libgibbs_pch.hpp"
#include "libgibbs/include/optimizer/utils/ezd_minimization.hpp"
#include "libgibbs/include/compositionset.hpp"
#include "libgibbs/include/constraint.hpp"
#include "libgibbs/include/models.hpp"
#include "libgibbs/include/optimizer/halton.hpp"
#include "libgibbs/include/optimizer/utils/ndsimplex.hpp"
#include "libgibbs/include/utils/cholesky.hpp"
#include <boost/bimap.hpp>
#include <boost/numeric/ublas/symmetric.hpp>
#include <boost/numeric/ublas/vector.hpp>
#include <boost/numeric/ublas/io.hpp>
#include <algorithm>
#include <string>
#include <map>

namespace Optimizer {

// TODO: Should this be a member function of GibbsOpt?
// The function calling LocateMinima definitely should be at least (needs access to all CompositionSets)
// LocateMinima finds all of the minima for a given phase's Gibbs energy
// In addition to allowing us to choose a better starting point, this will allow for automatic miscibility gap detection
void LocateMinima(
		CompositionSet const &phase,
		sublattice_set const &sublset,
		evalconditions const& conditions,
		const std::size_t depth // depth tracking for recursion
		) {
	constexpr const std::size_t grid_points_per_axis = 10; // TODO: make this user-configurable
	using namespace boost::numeric::ublas;
	typedef std::vector<double> PointType;

	const std::size_t k = 2;
	const std::size_t d = 2;
	boost::numeric::ublas::matrix<double> vertex_coords(d,d+1);
	// test specifically for 2^2 subdivision of the 2-simplex (unit simplex)
	// NOTE: Will need to modify to handle automatic calculation of the dependent component
	vertex_coords(0,0) = 0;
	vertex_coords(1,0) = 0;
	vertex_coords(0,1) = 0;
	vertex_coords(1,1) = 1;
	vertex_coords(0,2) = 1;
	vertex_coords(1,2) = 0;
	const auto colorscheme = color_schemes(k,d);
	for (auto i = colorscheme.begin(); i != colorscheme.end(); ++i) {
	  std::cout << "n = " << std::distance(colorscheme.begin(),i) << std::endl;
	  boost::numeric::ublas::matrix<double> simplex_coords = zero_matrix<double>(d,d+1);
	  for (auto j = 0; j < d+1; ++j) {
	    std::cout << "j = " << j << std::endl;
	    matrix_column<matrix<double>> p (simplex_coords,j);
	    for (auto m = 0; m < k; ++m) {
	      std::cout << "m = " << m << std::endl;
	      const matrix_column<const matrix<double>> s(vertex_coords,(*i)(m,j));
	      p += (s / (double) k);
	    }
	  }
	  std::cout << *i << std::endl;
	  std::cout << simplex_coords << std::endl;
	}
	return;

	// EZD Global Minimization (Emelianenko et al., 2006)
	// For depth = 1: FIND CONCAVITY REGIONS
	if (depth == 1) {
		std::vector<PointType> points;
		std::vector<std::size_t> components_in_sublattice;

		// Get the first sublattice for this phase
		boost::multi_index::index<sublattice_set,phase_subl>::type::iterator ic0,ic1;
		int sublindex = 0;
		ic0 = boost::multi_index::get<phase_subl>(sublset).lower_bound(boost::make_tuple(phase.name(), sublindex));
		ic1 = boost::multi_index::get<phase_subl>(sublset).upper_bound(boost::make_tuple(phase.name(), sublindex));;

		// (1) Sample some points on the domain using NDSimplex
		// Because the grid is uniform, we can assume that each point is the center of an N-simplex

		// Determine number of components in each sublattice
		while (ic0 != ic1) {
			const std::size_t number_of_species = std::distance(ic0,ic1);
			if (number_of_species > 0) components_in_sublattice.push_back(number_of_species);
			// Next sublattice
			++sublindex;
			ic0 = boost::multi_index::get<phase_subl>(sublset).lower_bound(boost::make_tuple(phase.name(), sublindex));
			ic1 = boost::multi_index::get<phase_subl>(sublset).end();
		}

		points = NDSimplex::lattice_complex(components_in_sublattice, 20);

		for (auto pt : points) {
			std::cout << "(";
			for (auto i = pt.begin(); i != pt.end(); ++i) {
				std::cout << *i;
				if (std::distance(i,pt.end()) > 1) std::cout << ",";
			}
			std::cout << ")" << std::endl;
		}

		PointType minpoint (points[0].size());
		double gradient_magnitude = std::numeric_limits<double>::max();
		// (2) Calculate the Lagrangian Hessian for all sampled points
		for (auto pt : points) {
			if (pt.size() == 0) continue; // skip empty (invalid) points
			symmetric_matrix<double, lower> Hessian(zero_matrix<double>(pt.size(),pt.size()));
			try {
				Hessian = phase.evaluate_objective_hessian_matrix(conditions, phase.get_variable_map(), pt);
			}
			catch (boost::exception &e) {
				std::cout << boost::diagnostic_information(e);
				throw;
			}
			catch (std::exception &e) {
				std::cout << e.what();
				throw;
			}
			//std::cout << "Hessian: " << Hessian << std::endl;
			// NOTE: For this calculation we consider only the linear constraints for an isolated phase (e.g., site fraction balances)
			// (3) Save all points for which the Lagrangian Hessian is positive definite in the null space of the constraint gradient matrix
			//        NOTE: This is the projected Hessian method (Nocedal and Wright, 2006, ch. 12.4, p.349)
			//        But how do I choose the Lagrange multipliers for all the constraints? Can I calculate them?
			//        The answer is that, because the constraints are linear, there is no constraint contribution to the Hessian.
			//        That means that the Hessian of the Lagrangian is just the Hessian of the objective function.
			const std::size_t Zcolumns = pt.size() - phase.get_constraints().size();
			// Z is the constraint null space matrix = phase.get_constraint_null_space_matrix()
			//    (a) Set Hproj = transpose(Z)*(L'')*Z
			matrix<double> Hproj(pt.size(), Zcolumns);
			Hproj = prod(trans(phase.get_constraint_null_space_matrix()),
					matrix<double>(prod(Hessian,phase.get_constraint_null_space_matrix())));
			//std::cout << "Hproj: " << Hproj << std::endl;
			//    (b) Verify that all diagonal elements of Hproj are strictly positive; if not, remove this point from consideration
			//        NOTE: This is a necessary but not sufficient condition that a matrix be positive definite, and it's easy to check
			//        Reference: Carlen and Carvalho, 2007, p. 148, Eq. 5.12
			//    (c) Attempt a Cholesky factorization of Hproj; will only succeed if matrix is positive definite
			const bool is_positive_definite = cholesky_factorize(Hproj);
			//    (d) If it succeeds, save this point; else, remove it
			if (is_positive_definite) {
				std::cout << pt[0] << " ";
				double obj = phase.evaluate_objective(conditions, phase.get_variable_map(), &pt[0]);
				std::cout << obj << std::endl;
				std::vector<double> gradient = phase.evaluate_internal_objective_gradient(conditions, &pt[0]);
				double mag = 0;
				for (auto i = gradient.begin(); i != gradient.end(); ++i) {
					//std::cout << "gradient[" << std::distance(gradient.begin(),i) << "] = " << *i << std::endl;
					mag += pow(*i,2);
				}
				if (mag < gradient_magnitude) {
					gradient_magnitude = mag;
					minpoint = pt;
					std::cout << "new minpoint: ";
					for (auto i = minpoint.begin(); i != minpoint.end(); ++i) {
						std::cout << *i;
						if (std::distance(i,minpoint.end()) > 1) std::cout << ",";
					}
					std::cout << " gradient sq: " << gradient_magnitude << std::endl;
				}
			}
			else {

			}
			// (4) For each saved point, send to next depth
		}
	}
	// For depth > 1: FIND MINIMA
	else if (depth > 1) {
		// (1) Sample some points on the domain using NDGrid (probably separate function)
		// (2) Calculate the objective gradient (f') for all sampled points
		// Note: This can be done by making use of the first-order KKT conditions to estimate the Lagrange multipliers.
		// (3) Find the point (z) with the minimum magnitude of L'
		// (4) If that magnitude is less than some defined epsilon, or we've hit max_depth, return z as a minimum
		//     Else use N-cube assumption to define new domain around z and send to next depth (return minima from that)
	}
	else {
		// invalid depth; throw exception
	}
}

}
<|endoftext|>


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

#include "worker.hpp"

#include <chrono>
#include <random>
#include <set>
#include <stdexcept>
#include <json/value.h>
#include <json/reader.h>
#include <json/writer.h>
#include <tntdb/error.h>
#include <cyvdb/match_manager.hpp>
#include <cyvdb/player_manager.hpp>
#include <cyvmath/match.hpp>
#include <cyvmath/player.hpp>
#include <cyvmath/rule_set_create.hpp>
#include <cyvws/game_msg_action.hpp>
#include <cyvws/msg_type.hpp>
#include <cyvws/notification_type.hpp>
#include <cyvws/server_request_action.hpp>
#include "b64.hpp"
#include "client_data.hpp"
#include "match_data.hpp"

using namespace cyvmath;
using namespace cyvws;

using namespace std;
using namespace std::chrono;
using namespace websocketpp;

Worker::Worker(SharedServerData& data, send_func_type sendFunc)
	: m_data{data}
	, m_sendFunc{sendFunc}
	, m_thread{bind(&Worker::processMessages, this)}
{ }

Worker::~Worker()
{
	m_thread.join();
}

void Worker::send(connection_hdl hdl, const string& data)
{
	m_sendFunc(hdl, data, frame::opcode::text);
}

void Worker::send(connection_hdl hdl, const Json::Value& data)
{
	send(hdl, Json::FastWriter().write(data));
}

void Worker::sendCommErr(connection_hdl hdl, const string& errMsg)
{
	Json::Value data;
	data["msgType"] = "notification";
	data["notificationData"]["type"] = "commError";
	data["notificationData"]["errMsg"] = errMsg;

	send(hdl, data);
}

void Worker::processMessages()
{
	Json::Reader reader;

	while(m_data.running)
	{
		unique_lock<mutex> jobLock(m_data.jobMtx);

		while(m_data.running && m_data.jobQueue.empty())
			m_data.jobCond.wait(jobLock);

		if(!m_data.running)
			break;

		auto job = m_data.jobQueue.front();
		m_data.jobQueue.pop();

		jobLock.unlock();

		try
		{
			// Process job
			Json::Value recvdJson;
			if(!reader.parse(job.msg_ptr->get_payload(), recvdJson, false))
			{
				sendCommErr(job.conn_hdl, "Received message is no valid JSON");
				continue;
			}

			set<connection_hdl, owner_less<connection_hdl>> otherClients;

			shared_ptr<ClientData> clientData;

			unique_lock<mutex> matchDataLock(m_data.matchDataMtx, defer_lock); // don't lock yet
			unique_lock<mutex> clientDataLock(m_data.clientDataMtx);

			auto it1 = m_data.clientData.find(job.conn_hdl);
			if(it1 != m_data.clientData.end())
			{
				clientData = it1->second;
				clientDataLock.unlock();

				for(auto it2 : clientData->getMatchData().getClientDataSets())
					if(*it2 != *clientData)
						otherClients.insert(it2->getConnHdl());
			}
			else clientDataLock.unlock();

			switch(StrToMsgType(recvdJson["msgType"].asString()))
			{
				case MsgType::CHAT_MSG:
				case MsgType::CHAT_MSG_ACK:
				case MsgType::GAME_MSG:
				case MsgType::GAME_MSG_ACK:
				case MsgType::GAME_MSG_ERR:
				{
					// TODO: Does re-creating the Json string
					// from the Json::Value make sense or should
					// we just resend the original Json string?
					string json = Json::FastWriter().write(recvdJson);

					for(auto hdl : otherClients)
						send(hdl, json);

					break;
				}
				case MsgType::SERVER_REQUEST:
				{
					const auto& requestData = recvdJson["requestData"];
					const auto& param = requestData["param"];

					Json::Value reply;
					reply["msgType"] = MsgTypeToStr(MsgType::SERVER_REPLY);
					// cast to int and back to not allow any non-numeral data
					reply["msgID"] = recvdJson["msgID"].asInt();

					auto& replyData = reply["replyData"];
					replyData["success"] = true;

					// g++ warns about the default argument for the lambda with -pedantic,
					// maybe change how serverReply errors are sent to fix that?
					auto setError = [&replyData](const string& error, const string& errorDetails = {}) {
						replyData["success"] = false;
						replyData["error"] = error;
						replyData["errorDetails"] = errorDetails;
					};

					switch(StrToServerRequestAction(requestData["action"].asString()))
					{
						case ServerRequestAction::INIT_COMM:
						{
							// TODO: move to somewhere else (probably cyvws)
							constexpr unsigned short protocolVersionMajor = 1;

							const auto& versionStr = requestData["param"]["protocolVersion"].asString();

							if(versionStr.empty())
								sendCommErr(job.conn_hdl, "Expected non-empty string value as protocolVersion in initComm");
							else
							{
								if(stoi(versionStr.substr(0, versionStr.find('.'))) != protocolVersionMajor)
									setError("differingMajorProtVersion", "Expected major protocol version " + to_string(protocolVersionMajor));

								send(job.conn_hdl, reply);
							}
							break;
						}
						case ServerRequestAction::CREATE_GAME:
						{
							if(clientData)
								setError("This connection is already in use for a running match");
							else
							{
								auto ruleSet = StrToRuleSet(param["ruleSet"].asString());
								auto color   = StrToPlayersColor(param["color"].asString());
								auto random  = param["random"].asBool();
								auto _public = param["public"].asBool();

								auto matchID  = newMatchID();
								auto playerID = newPlayerID();

								auto newMatchData = make_shared<MatchData>(createMatch(ruleSet, matchID));
								auto newClientData = make_shared<ClientData>(
									createPlayer(newMatchData->getMatch(), color, playerID),
									job.conn_hdl, *newMatchData
								);

								newMatchData->getClientDataSets().insert(newClientData);

								clientDataLock.lock();
								auto tmp1 = m_data.clientData.emplace(job.conn_hdl, newClientData);
								clientDataLock.unlock();
								assert(tmp1.second);

								matchDataLock.lock();
								auto tmp2 = m_data.matchData.emplace(matchID, newMatchData);
								matchDataLock.unlock();
								assert(tmp2.second);

								replyData["matchID"]  = matchID;
								replyData["playerID"] = playerID;

								// TODO
								thread([=] {
									this_thread::sleep_for(milliseconds(50));

									auto match = createMatch(ruleSet, matchID, random, _public);
									auto player = createPlayer(*match, color, playerID);

									cyvdb::MatchManager().addMatch(move(match));
									cyvdb::PlayerManager().addPlayer(move(player));
								}).detach();
							}

							send(job.conn_hdl, reply);

							break;
						}
						case ServerRequestAction::JOIN_GAME:
						{
							matchDataLock.lock();

							auto matchIt = m_data.matchData.find(requestData["matchID"].asString());

							if(clientData)
								setError("This connection is already in use for a running match");
							else if(matchIt == m_data.matchData.end())
								setError("Game not found");
							else
							{
								auto matchData = matchIt->second;
								auto matchClients = matchData->getClientDataSets();

								if(matchClients.size() == 0)
									setError("You tried to join a game without an active player, this doesn't work yet");
								else if(matchClients.size() > 1)
									setError("This game already has two players");
								else
								{
									auto ruleSet  = matchData->getMatch().getRuleSet();
									auto color    = !(*matchClients.begin())->getPlayer().getColor();
									auto matchID  = requestData["matchID"].asString();
									auto playerID = newPlayerID();

									auto newClientData = make_shared<ClientData>(
										createPlayer(matchData->getMatch(), color, playerID),
										job.conn_hdl, *matchData
									);

									matchData->getClientDataSets().insert(newClientData);

									clientDataLock.lock();
									auto tmp = m_data.clientData.emplace(job.conn_hdl, newClientData);
									clientDataLock.unlock();
									assert(tmp.second);

									replyData["success"]  = true;
									replyData["color"]    = PlayersColorToStr(color);
									replyData["playerID"] = playerID;
									replyData["ruleSet"]  = RuleSetToStr(ruleSet);

									Json::Value notification;
									notification["msgType"] = "notification";

									auto& notificationData = notification["notificationData"];
									notificationData["type"] = NotificationTypeToStr(NotificationType::USER_JOINED);
									//notificationData["screenName"] =
									//notificationData["registered"] =
									//notificationData["role"] =

									auto&& msg = Json::FastWriter().write(notification);

									for(auto& clientIt : matchClients)
										send(clientIt->getConnHdl(), msg);

									send(job.conn_hdl, reply);

									thread([=] {
										this_thread::sleep_for(milliseconds(50));

										// TODO
										auto match = createMatch(ruleSet, matchID);
										cyvdb::PlayerManager().addPlayer(createPlayer(*match, color, playerID));
									}).detach();
								}
							}

							matchDataLock.unlock();

							break;
						}
						case ServerRequestAction::SUBSCR_GAME_LIST_UPDATES:
						{
							// ignore param["ruleSet"] for now
							for (const auto& list : param["lists"])
							{
								const auto& listName = list.asString();

								if (listName == "openRandomGames")
									m_data.randomGamesSubscribers.insert(job.conn_hdl);
								else if (listName == "runningPublicGames")
									m_data.publicGamesSubscribers.insert(job.conn_hdl);
								//else
									// send error message
							}
						}
						case ServerRequestAction::UNSUBSCR_GAME_LIST_UPDATES:
						{
							// ignore param["ruleSet"] for now
							for (const auto& list : param["lists"])
							{
								const auto& listName = list.asString();

								if (listName == "openRandomGames")
								{
									const auto& it = m_data.randomGamesSubscribers.find(job.conn_hdl);

									if(it != m_data.randomGamesSubscribers.end())
										m_data.randomGamesSubscribers.erase(job.conn_hdl);
								}
								else if (listName == "runningPublicGames")
								{
									const auto& it = m_data.publicGamesSubscribers.find(job.conn_hdl);

									if(it != m_data.publicGamesSubscribers.end())
										m_data.publicGamesSubscribers.erase(job.conn_hdl);
								}
								//else
								//{
								//	send error message
								//}
							}
							break;
						}
						default:
							sendCommErr(job.conn_hdl, "Unrecognized server request action");
					}

					break;
				}
				case MsgType::NOTIFICATION:
				case MsgType::SERVER_REPLY:
					sendCommErr(job.conn_hdl, "This msgType is not intended for client-to-server messages");
					break;
				case MsgType::UNDEFINED:
					sendCommErr(job.conn_hdl, "No valid msgType found");
					break;
				default:
					// MsgType enum value valid, implementation lacks support for some feature
					assert(0);
					break;
			}
		}
		catch(std::error_code& e)
		{
			cerr << "Caught a std::error_code\n-----\n" << e << '\n' << e.message() << endl;
		}
		catch(std::exception& e)
		{
			cerr << "Caught a std::exception: " << e.what() << endl;
		}
		catch(...)
		{
			cerr << "Caught an unrecognized error (not derived from either exception or error_code)" << endl;
		}
	}
}

string Worker::newMatchID()
{
	static ranlux24 int24Generator(system_clock::now().time_since_epoch().count());

	string res;
	unique_lock<mutex> matchDataLock(m_data.matchDataMtx);

	do
	{
		res = int24ToB64ID(int24Generator());
	}
	while(m_data.matchData.find(res) != m_data.matchData.end());

	matchDataLock.unlock();

	return res;
}

string Worker::newPlayerID()
{
	static ranlux48 int48Generator(system_clock::now().time_since_epoch().count());

	// TODO
	return int48ToB64ID(int48Generator());
}
<commit_msg>Some work on the serverRequest error reporting, fixed joinGame requests not getting replies<commit_after>/* Copyright 2014 Jonas Platte
 *
 * This file is part of Cyvasse Online.
 *
 * Cyvasse Online is free software: you can redistribute it and/or modify it under the
 * terms of the GNU Affero General Public License as published by the Free Software Foundation,
 * either version 3 of the License, or (at your option) any later version.
 *
 * Cyvasse Online is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License along with this program.
 * If not, see <http://www.gnu.org/licenses/>.
 */

#include "worker.hpp"

#include <chrono>
#include <random>
#include <set>
#include <stdexcept>
#include <json/value.h>
#include <json/reader.h>
#include <json/writer.h>
#include <tntdb/error.h>
#include <cyvdb/match_manager.hpp>
#include <cyvdb/player_manager.hpp>
#include <cyvmath/match.hpp>
#include <cyvmath/player.hpp>
#include <cyvmath/rule_set_create.hpp>
#include <cyvws/game_msg_action.hpp>
#include <cyvws/msg_type.hpp>
#include <cyvws/notification_type.hpp>
#include <cyvws/server_request_action.hpp>
#include "b64.hpp"
#include "client_data.hpp"
#include "match_data.hpp"

using namespace cyvmath;
using namespace cyvws;

using namespace std;
using namespace std::chrono;
using namespace websocketpp;

Worker::Worker(SharedServerData& data, send_func_type sendFunc)
	: m_data{data}
	, m_sendFunc{sendFunc}
	, m_thread{bind(&Worker::processMessages, this)}
{ }

Worker::~Worker()
{
	m_thread.join();
}

void Worker::send(connection_hdl hdl, const string& data)
{
	m_sendFunc(hdl, data, frame::opcode::text);
}

void Worker::send(connection_hdl hdl, const Json::Value& data)
{
	send(hdl, Json::FastWriter().write(data));
}

void Worker::sendCommErr(connection_hdl hdl, const string& errMsg)
{
	Json::Value data;
	data["msgType"] = "notification";
	data["notificationData"]["type"] = "commError";
	data["notificationData"]["errMsg"] = errMsg;

	send(hdl, data);
}

void Worker::processMessages()
{
	Json::Reader reader;

	while(m_data.running)
	{
		unique_lock<mutex> jobLock(m_data.jobMtx);

		while(m_data.running && m_data.jobQueue.empty())
			m_data.jobCond.wait(jobLock);

		if(!m_data.running)
			break;

		auto job = m_data.jobQueue.front();
		m_data.jobQueue.pop();

		jobLock.unlock();

		try
		{
			// Process job
			Json::Value recvdJson;
			if(!reader.parse(job.msg_ptr->get_payload(), recvdJson, false))
			{
				sendCommErr(job.conn_hdl, "Received message is no valid JSON");
				continue;
			}

			set<connection_hdl, owner_less<connection_hdl>> otherClients;

			shared_ptr<ClientData> clientData;

			unique_lock<mutex> matchDataLock(m_data.matchDataMtx, defer_lock); // don't lock yet
			unique_lock<mutex> clientDataLock(m_data.clientDataMtx);

			auto it1 = m_data.clientData.find(job.conn_hdl);
			if(it1 != m_data.clientData.end())
			{
				clientData = it1->second;
				clientDataLock.unlock();

				for(auto it2 : clientData->getMatchData().getClientDataSets())
					if(*it2 != *clientData)
						otherClients.insert(it2->getConnHdl());
			}
			else clientDataLock.unlock();

			switch(StrToMsgType(recvdJson["msgType"].asString()))
			{
				case MsgType::CHAT_MSG:
				case MsgType::CHAT_MSG_ACK:
				case MsgType::GAME_MSG:
				case MsgType::GAME_MSG_ACK:
				case MsgType::GAME_MSG_ERR:
				{
					// TODO: Does re-creating the Json string
					// from the Json::Value make sense or should
					// we just resend the original Json string?
					string json = Json::FastWriter().write(recvdJson);

					for(auto hdl : otherClients)
						send(hdl, json);

					break;
				}
				case MsgType::SERVER_REQUEST:
				{
					const auto& requestData = recvdJson["requestData"];
					const auto& param = requestData["param"];

					Json::Value reply;
					reply["msgType"] = MsgTypeToStr(MsgType::SERVER_REPLY);
					// cast to int and back to not allow any non-numeral data
					reply["msgID"] = recvdJson["msgID"].asInt();

					auto& replyData = reply["replyData"];
					replyData["success"] = true;

					// g++ warns about the default argument for the lambda with -pedantic,
					// maybe change how serverReply errors are sent to fix that?
					auto setError = [&replyData](const string& error, const string& errorDetails = {}) {
						replyData["success"] = false;
						replyData["error"] = error;

						if(!errorDetails.empty())
							replyData["errorDetails"] = errorDetails;
					};

					switch(StrToServerRequestAction(requestData["action"].asString()))
					{
						case ServerRequestAction::INIT_COMM:
						{
							// TODO: move to somewhere else (probably cyvws)
							constexpr unsigned short protocolVersionMajor = 1;

							const auto& versionStr = requestData["param"]["protocolVersion"].asString();

							if(versionStr.empty())
								sendCommErr(job.conn_hdl, "Expected non-empty string value as protocolVersion in initComm");
							else
							{
								if(stoi(versionStr.substr(0, versionStr.find('.'))) != protocolVersionMajor)
									setError("differingMajorProtVersion", "Expected major protocol version " + to_string(protocolVersionMajor));

								send(job.conn_hdl, reply);
							}
							break;
						}
						case ServerRequestAction::CREATE_GAME:
						{
							if(clientData)
								setError("connInUse");
							else
							{
								auto ruleSet = StrToRuleSet(param["ruleSet"].asString());
								auto color   = StrToPlayersColor(param["color"].asString());
								auto random  = param["random"].asBool();
								auto _public = param["public"].asBool();

								auto matchID  = newMatchID();
								auto playerID = newPlayerID();

								auto newMatchData = make_shared<MatchData>(createMatch(ruleSet, matchID));
								auto newClientData = make_shared<ClientData>(
									createPlayer(newMatchData->getMatch(), color, playerID),
									job.conn_hdl, *newMatchData
								);

								newMatchData->getClientDataSets().insert(newClientData);

								clientDataLock.lock();
								auto tmp1 = m_data.clientData.emplace(job.conn_hdl, newClientData);
								clientDataLock.unlock();
								assert(tmp1.second);

								matchDataLock.lock();
								auto tmp2 = m_data.matchData.emplace(matchID, newMatchData);
								matchDataLock.unlock();
								assert(tmp2.second);

								replyData["matchID"]  = matchID;
								replyData["playerID"] = playerID;

								// TODO
								thread([=] {
									this_thread::sleep_for(milliseconds(50));

									auto match = createMatch(ruleSet, matchID, random, _public);
									auto player = createPlayer(*match, color, playerID);

									cyvdb::MatchManager().addMatch(move(match));
									cyvdb::PlayerManager().addPlayer(move(player));
								}).detach();
							}

							send(job.conn_hdl, reply);

							break;
						}
						case ServerRequestAction::JOIN_GAME:
						{
							matchDataLock.lock();

							auto matchIt = m_data.matchData.find(requestData["matchID"].asString());

							if(clientData)
								setError("connInUse");
							else if(matchIt == m_data.matchData.end())
								setError("gameNotFound");
							else
							{
								auto matchData = matchIt->second;
								auto matchClients = matchData->getClientDataSets();

								if(matchClients.size() == 0)
									setError("gameEmpty");
								else if(matchClients.size() > 1)
									setError("gameFull");
								else
								{
									auto ruleSet  = matchData->getMatch().getRuleSet();
									auto color    = !(*matchClients.begin())->getPlayer().getColor();
									auto matchID  = requestData["matchID"].asString();
									auto playerID = newPlayerID();

									auto newClientData = make_shared<ClientData>(
										createPlayer(matchData->getMatch(), color, playerID),
										job.conn_hdl, *matchData
									);

									matchData->getClientDataSets().insert(newClientData);

									clientDataLock.lock();
									auto tmp = m_data.clientData.emplace(job.conn_hdl, newClientData);
									clientDataLock.unlock();
									assert(tmp.second);

									replyData["success"]  = true;
									replyData["color"]    = PlayersColorToStr(color);
									replyData["playerID"] = playerID;
									replyData["ruleSet"]  = RuleSetToStr(ruleSet);

									Json::Value notification;
									notification["msgType"] = "notification";

									auto& notificationData = notification["notificationData"];
									notificationData["type"] = NotificationTypeToStr(NotificationType::USER_JOINED);
									//notificationData["screenName"] =
									//notificationData["registered"] =
									//notificationData["role"] =

									auto&& msg = Json::FastWriter().write(notification);

									for(auto& clientIt : matchClients)
										send(clientIt->getConnHdl(), msg);

									send(job.conn_hdl, reply);

									thread([=] {
										this_thread::sleep_for(milliseconds(50));

										// TODO
										auto match = createMatch(ruleSet, matchID);
										cyvdb::PlayerManager().addPlayer(createPlayer(*match, color, playerID));
									}).detach();
								}
							}

							matchDataLock.unlock();

							send(job.conn_hdl, reply);

							break;
						}
						case ServerRequestAction::SUBSCR_GAME_LIST_UPDATES:
						{
							// ignore param["ruleSet"] for now
							for (const auto& list : param["lists"])
							{
								const auto& listName = list.asString();

								if (listName == "openRandomGames")
									m_data.randomGamesSubscribers.insert(job.conn_hdl);
								else if (listName == "runningPublicGames")
									m_data.publicGamesSubscribers.insert(job.conn_hdl);
								//else
									// send error message
							}
						}
						case ServerRequestAction::UNSUBSCR_GAME_LIST_UPDATES:
						{
							// ignore param["ruleSet"] for now
							for (const auto& list : param["lists"])
							{
								const auto& listName = list.asString();

								if (listName == "openRandomGames")
								{
									const auto& it = m_data.randomGamesSubscribers.find(job.conn_hdl);

									if(it != m_data.randomGamesSubscribers.end())
										m_data.randomGamesSubscribers.erase(job.conn_hdl);
								}
								else if (listName == "runningPublicGames")
								{
									const auto& it = m_data.publicGamesSubscribers.find(job.conn_hdl);

									if(it != m_data.publicGamesSubscribers.end())
										m_data.publicGamesSubscribers.erase(job.conn_hdl);
								}
								//else
								//{
								//	send error message
								//}
							}
							break;
						}
						default:
							sendCommErr(job.conn_hdl, "Unrecognized server request action");
					}

					break;
				}
				case MsgType::NOTIFICATION:
				case MsgType::SERVER_REPLY:
					sendCommErr(job.conn_hdl, "This msgType is not intended for client-to-server messages");
					break;
				case MsgType::UNDEFINED:
					sendCommErr(job.conn_hdl, "No valid msgType found");
					break;
				default:
					// MsgType enum value valid, implementation lacks support for some feature
					assert(0);
					break;
			}
		}
		catch(std::error_code& e)
		{
			cerr << "Caught a std::error_code\n-----\n" << e << '\n' << e.message() << endl;
		}
		catch(std::exception& e)
		{
			cerr << "Caught a std::exception: " << e.what() << endl;
		}
		catch(...)
		{
			cerr << "Caught an unrecognized error (not derived from either exception or error_code)" << endl;
		}
	}
}

string Worker::newMatchID()
{
	static ranlux24 int24Generator(system_clock::now().time_since_epoch().count());

	string res;
	unique_lock<mutex> matchDataLock(m_data.matchDataMtx);

	do
	{
		res = int24ToB64ID(int24Generator());
	}
	while(m_data.matchData.find(res) != m_data.matchData.end());

	matchDataLock.unlock();

	return res;
}

string Worker::newPlayerID()
{
	static ranlux48 int48Generator(system_clock::now().time_since_epoch().count());

	// TODO
	return int48ToB64ID(int48Generator());
}
<|endoftext|>