text:
#include <event2/buffer.h>
#include <event2/keyvalq_struct.h>
#include <univalue.h>
#include <thread>
#include <stdio.h>
#include <boost/algorithm/string.hpp>

#include "baseimpl.hpp"

#include "config/chainparams.h"
#include "chaincontrol/coins.h"
#include "config/consensus.h"

#include "rpc/client.h"
#include "rpc/protocol.h"

#include "utils/utilstrencodings.h"
#include "utils/net/events.h"
#include "utils/base58.h"
#include "utils/util.h"
#include "utils/utilmoneystr.h"

#include "sbtccore/clientversion.h"
#include "sbtccore/core_io.h"
#include "sbtccore/transaction/policy.h"

#include "wallet/keystore.h"
#include "wallet/rbf.h"
#include "transaction/transaction.h"
#include "script/script.h"
#include "script/sign.h"

#define  COMMAND_ARG_SEP '`'

static bool fCreateBlank = false;
static std::map<std::string, UniValue> registers;
static const int CONTINUE_EXECUTION = -1;

static void RegisterSetJson(const std::string &key, const std::string &rawJson)
{
    UniValue val;
    if (!val.read(rawJson))
    {
        std::string strErr = "Cannot parse JSON for key " + key;
        throw std::runtime_error(strErr);
    }

    registers[key] = val;
}

static void RegisterSet(const std::string &strInput)
{
    // separate NAME:VALUE in string
    size_t pos = strInput.find(':');
    if ((pos == std::string::npos) ||
        (pos == 0) ||
        (pos == (strInput.size() - 1)))
        throw std::runtime_error("Register input requires NAME:VALUE");

    std::string key = strInput.substr(0, pos);
    std::string valStr = strInput.substr(pos + 1, std::string::npos);

    RegisterSetJson(key, valStr);
}

static void RegisterLoad(const std::string &strInput)
{
    // separate NAME:FILENAME in string
    size_t pos = strInput.find(':');
    if ((pos == std::string::npos) ||
        (pos == 0) ||
        (pos == (strInput.size() - 1)))
        throw std::runtime_error("Register load requires NAME:FILENAME");

    std::string key = strInput.substr(0, pos);
    std::string filename = strInput.substr(pos + 1, std::string::npos);

    FILE *f = fopen(filename.c_str(), "r");
    if (!f)
    {
        std::string strErr = "Cannot open file " + filename;
        throw std::runtime_error(strErr);
    }

    // load file chunks into one big buffer
    std::string valStr;
    while ((!feof(f)) && (!ferror(f)))
    {
        char buf[4096];
        int bread = fread(buf, 1, sizeof(buf), f);
        if (bread <= 0)
            break;

        valStr.insert(valStr.size(), buf, bread);
    }

    int error = ferror(f);
    fclose(f);

    if (error)
    {
        std::string strErr = "Error reading file " + filename;
        throw std::runtime_error(strErr);
    }

    // evaluate as JSON buffer register
    RegisterSetJson(key, valStr);
}

static CAmount ExtractAndValidateValue(const std::string &strValue)
{
    CAmount value;
    if (!ParseMoney(strValue, value))
        throw std::runtime_error("invalid TX output value");
    return value;
}

static void MutateTxVersion(CMutableTransaction &tx, const std::string &cmdVal)
{
    int64_t newVersion = atoi64(cmdVal);
    if (newVersion < 1 || newVersion > CTransaction::MAX_STANDARD_VERSION)
        throw std::runtime_error("Invalid TX version requested");

    tx.nVersion = (int)newVersion;
}

static void MutateTxLocktime(CMutableTransaction &tx, const std::string &cmdVal)
{
    int64_t newLocktime = atoi64(cmdVal);
    if (newLocktime < 0LL || newLocktime > 0xffffffffLL)
        throw std::runtime_error("Invalid TX locktime requested");

    tx.nLockTime = (unsigned int)newLocktime;
}

static void MutateTxRBFOptIn(CMutableTransaction &tx, const std::string &strInIdx)
{
    // parse requested index
    int inIdx = atoi(strInIdx);
    if (inIdx < 0 || inIdx >= (int)tx.vin.size())
    {
        throw std::runtime_error("Invalid TX input index '" + strInIdx + "'");
    }

    // set the nSequence to MAX_INT - 2 (= RBF opt in flag)
    int cnt = 0;
    for (CTxIn &txin : tx.vin)
    {
        if (strInIdx == "" || cnt == inIdx)
        {
            if (txin.nSequence > MAX_BIP125_RBF_SEQUENCE)
            {
                txin.nSequence = MAX_BIP125_RBF_SEQUENCE;
            }
        }
        ++cnt;
    }
}

static void MutateTxAddInput(CMutableTransaction &tx, const std::string &strInput)
{
    std::vector<std::string> vStrInputParts;
    boost::split(vStrInputParts, strInput, boost::is_any_of(":"));

    // separate TXID:VOUT in string
    if (vStrInputParts.size() < 2)
        throw std::runtime_error("TX input missing separator");

    // extract and validate TXID
    std::string strTxid = vStrInputParts[0];
    if ((strTxid.size() != 64) || !IsHex(strTxid))
        throw std::runtime_error("invalid TX input txid");
    uint256 txid(uint256S(strTxid));

    static const unsigned int minTxOutSz = 9;
    static const unsigned int maxVout = MAX_BLOCK_WEIGHT / (WITNESS_SCALE_FACTOR * minTxOutSz);

    // extract and validate vout
    std::string strVout = vStrInputParts[1];
    int vout = atoi(strVout);
    if ((vout < 0) || (vout > (int)maxVout))
        throw std::runtime_error("invalid TX input vout");

    // extract the optional sequence number
    uint32_t nSequenceIn = std::numeric_limits<unsigned int>::max();
    if (vStrInputParts.size() > 2)
        nSequenceIn = std::stoul(vStrInputParts[2]);

    // append to transaction input list
    CTxIn txin(txid, vout, CScript(), nSequenceIn);
    tx.vin.push_back(txin);
}

static void MutateTxAddOutAddr(CMutableTransaction &tx, const std::string &strInput)
{
    // Separate into VALUE:ADDRESS
    std::vector<std::string> vStrInputParts;
    boost::split(vStrInputParts, strInput, boost::is_any_of(":"));

    if (vStrInputParts.size() != 2)
        throw std::runtime_error("TX output missing or too many separators");

    // Extract and validate VALUE
    CAmount value = ExtractAndValidateValue(vStrInputParts[0]);

    // extract and validate ADDRESS
    std::string strAddr = vStrInputParts[1];
    CBitcoinAddress addr(strAddr);
    if (!addr.IsValid())
        throw std::runtime_error("invalid TX output address");
    // build standard output script via GetScriptForDestination()
    CScript scriptPubKey = GetScriptForDestination(addr.Get());

    // construct TxOut, append to transaction output list
    CTxOut txout(value, scriptPubKey);
    tx.vout.push_back(txout);
}

static void MutateTxAddOutPubKey(CMutableTransaction &tx, const std::string &strInput)
{
    // Separate into VALUE:PUBKEY[:FLAGS]
    std::vector<std::string> vStrInputParts;
    boost::split(vStrInputParts, strInput, boost::is_any_of(":"));

    if (vStrInputParts.size() < 2 || vStrInputParts.size() > 3)
        throw std::runtime_error("TX output missing or too many separators");

    // Extract and validate VALUE
    CAmount value = ExtractAndValidateValue(vStrInputParts[0]);

    // Extract and validate PUBKEY
    CPubKey pubkey(ParseHex(vStrInputParts[1]));
    if (!pubkey.IsFullyValid())
        throw std::runtime_error("invalid TX output pubkey");
    CScript scriptPubKey = GetScriptForRawPubKey(pubkey);

    // Extract and validate FLAGS
    bool bSegWit = false;
    bool bScriptHash = false;
    if (vStrInputParts.size() == 3)
    {
        std::string flags = vStrInputParts[2];
        bSegWit = (flags.find("W") != std::string::npos);
        bScriptHash = (flags.find("S") != std::string::npos);
    }

    if (bSegWit)
    {
        if (!pubkey.IsCompressed())
        {
            throw std::runtime_error("Uncompressed pubkeys are not useable for SegWit outputs");
        }
        // Call GetScriptForWitness() to build a P2WSH scriptPubKey
        scriptPubKey = GetScriptForWitness(scriptPubKey);
    }
    if (bScriptHash)
    {
        // Get the address for the redeem script, then call
        // GetScriptForDestination() to construct a P2SH scriptPubKey.
        CBitcoinAddress redeemScriptAddr(scriptPubKey);
        scriptPubKey = GetScriptForDestination(redeemScriptAddr.Get());
    }

    // construct TxOut, append to transaction output list
    CTxOut txout(value, scriptPubKey);
    tx.vout.push_back(txout);
}

static void MutateTxAddOutMultiSig(CMutableTransaction &tx, const std::string &strInput)
{
    // Separate into VALUE:REQUIRED:NUMKEYS:PUBKEY1:PUBKEY2:....[:FLAGS]
    std::vector<std::string> vStrInputParts;
    boost::split(vStrInputParts, strInput, boost::is_any_of(":"));

    // Check that there are enough parameters
    if (vStrInputParts.size() < 3)
        throw std::runtime_error("Not enough multisig parameters");

    // Extract and validate VALUE
    CAmount value = ExtractAndValidateValue(vStrInputParts[0]);

    // Extract REQUIRED
    uint32_t required = stoul(vStrInputParts[1]);

    // Extract NUMKEYS
    uint32_t numkeys = stoul(vStrInputParts[2]);

    // Validate there are the correct number of pubkeys
    if (vStrInputParts.size() < numkeys + 3)
        throw std::runtime_error("incorrect number of multisig pubkeys");

    if (required < 1 || required > 20 || numkeys < 1 || numkeys > 20 || numkeys < required)
        throw std::runtime_error("multisig parameter mismatch. Required " \
 + std::to_string(required) + " of " + std::to_string(numkeys) + "signatures.");

    // extract and validate PUBKEYs
    std::vector<CPubKey> pubkeys;
    for (int pos = 1; pos <= int(numkeys); pos++)
    {
        CPubKey pubkey(ParseHex(vStrInputParts[pos + 2]));
        if (!pubkey.IsFullyValid())
            throw std::runtime_error("invalid TX output pubkey");
        pubkeys.push_back(pubkey);
    }

    // Extract FLAGS
    bool bSegWit = false;
    bool bScriptHash = false;
    if (vStrInputParts.size() == numkeys + 4)
    {
        std::string flags = vStrInputParts.back();
        bSegWit = (flags.find("W") != std::string::npos);
        bScriptHash = (flags.find("S") != std::string::npos);
    } else if (vStrInputParts.size() > numkeys + 4)
    {
        // Validate that there were no more parameters passed
        throw std::runtime_error("Too many parameters");
    }

    CScript scriptPubKey = GetScriptForMultisig(required, pubkeys);

    if (bSegWit)
    {
        for (CPubKey &pubkey : pubkeys)
        {
            if (!pubkey.IsCompressed())
            {
                throw std::runtime_error("Uncompressed pubkeys are not useable for SegWit outputs");
            }
        }
        // Call GetScriptForWitness() to build a P2WSH scriptPubKey
        scriptPubKey = GetScriptForWitness(scriptPubKey);
    }
    if (bScriptHash)
    {
        // Get the address for the redeem script, then call
        // GetScriptForDestination() to construct a P2SH scriptPubKey.
        CBitcoinAddress addr(scriptPubKey);
        scriptPubKey = GetScriptForDestination(addr.Get());
    }

    // construct TxOut, append to transaction output list
    CTxOut txout(value, scriptPubKey);
    tx.vout.push_back(txout);
}

static void MutateTxAddOutData(CMutableTransaction &tx, const std::string &strInput)
{
    CAmount value = 0;

    // separate [VALUE:]DATA in string
    size_t pos = strInput.find(':');

    if (pos == 0)
        throw std::runtime_error("TX output value not specified");

    if (pos != std::string::npos)
    {
        // Extract and validate VALUE
        value = ExtractAndValidateValue(strInput.substr(0, pos));
    }

    // extract and validate DATA
    std::string strData = strInput.substr(pos + 1, std::string::npos);

    if (!IsHex(strData))
        throw std::runtime_error("invalid TX output data");

    std::vector<unsigned char> data = ParseHex(strData);

    CTxOut txout(value, CScript() << OP_RETURN << data);
    tx.vout.push_back(txout);
}

static void MutateTxAddOutScript(CMutableTransaction &tx, const std::string &strInput)
{
    // separate VALUE:SCRIPT[:FLAGS]
    std::vector<std::string> vStrInputParts;
    boost::split(vStrInputParts, strInput, boost::is_any_of(":"));
    if (vStrInputParts.size() < 2)
        throw std::runtime_error("TX output missing separator");

    // Extract and validate VALUE
    CAmount value = ExtractAndValidateValue(vStrInputParts[0]);

    // extract and validate script
    std::string strScript = vStrInputParts[1];
    CScript scriptPubKey = ParseScript(strScript);

    // Extract FLAGS
    bool bSegWit = false;
    bool bScriptHash = false;
    if (vStrInputParts.size() == 3)
    {
        std::string flags = vStrInputParts.back();
        bSegWit = (flags.find("W") != std::string::npos);
        bScriptHash = (flags.find("S") != std::string::npos);
    }

    if (bSegWit)
    {
        scriptPubKey = GetScriptForWitness(scriptPubKey);
    }
    if (bScriptHash)
    {
        CBitcoinAddress addr(scriptPubKey);
        scriptPubKey = GetScriptForDestination(addr.Get());
    }

    // construct TxOut, append to transaction output list
    CTxOut txout(value, scriptPubKey);
    tx.vout.push_back(txout);
}

static void MutateTxDelInput(CMutableTransaction &tx, const std::string &strInIdx)
{
    // parse requested deletion index
    int inIdx = atoi(strInIdx);
    if (inIdx < 0 || inIdx >= (int)tx.vin.size())
    {
        std::string strErr = "Invalid TX input index '" + strInIdx + "'";
        throw std::runtime_error(strErr.c_str());
    }

    // delete input from transaction
    tx.vin.erase(tx.vin.begin() + inIdx);
}

static void MutateTxDelOutput(CMutableTransaction &tx, const std::string &strOutIdx)
{
    // parse requested deletion index
    int outIdx = atoi(strOutIdx);
    if (outIdx < 0 || outIdx >= (int)tx.vout.size())
    {
        std::string strErr = "Invalid TX output index '" + strOutIdx + "'";
        throw std::runtime_error(strErr.c_str());
    }

    // delete output from transaction
    tx.vout.erase(tx.vout.begin() + outIdx);
}

static const unsigned int N_SIGHASH_OPTS = 12;
static const struct
{
    const char *flagStr;
    int flags;
} sighashOptions[N_SIGHASH_OPTS] = {
        {"ALL",                           SIGHASH_ALL},
        {"NONE",                          SIGHASH_NONE},
        {"SINGLE",                        SIGHASH_SINGLE},
        {"ALL|ANYONECANPAY",              SIGHASH_ALL | SIGHASH_ANYONECANPAY},
        {"NONE|ANYONECANPAY",             SIGHASH_NONE | SIGHASH_ANYONECANPAY},
        {"SINGLE|ANYONECANPAY",           SIGHASH_SINGLE | SIGHASH_ANYONECANPAY},
        {"ALL|SBTC_FORK",                 SIGHASH_ALL | SIGHASH_SBTC_FORK},
        {"NONE|SBTC_FORK",                SIGHASH_NONE | SIGHASH_SBTC_FORK},
        {"SINGLE|SBTC_FORK",              SIGHASH_SINGLE | SIGHASH_SBTC_FORK},
        {"ALL|SBTC_FORK|ANYONECANPAY",    SIGHASH_ALL | SIGHASH_SBTC_FORK | SIGHASH_ANYONECANPAY},
        {"NONE|SBTC_FORK|ANYONECANPAY",   SIGHASH_NONE | SIGHASH_SBTC_FORK | SIGHASH_ANYONECANPAY},
        {"SINGLE|SBTC_FORK|ANYONECANPAY", SIGHASH_SINGLE | SIGHASH_SBTC_FORK | SIGHASH_ANYONECANPAY},
};

static bool findSighashFlags(int &flags, const std::string &flagStr)
{
    flags = 0;

    for (unsigned int i = 0; i < N_SIGHASH_OPTS; i++)
    {
        if (flagStr == sighashOptions[i].flagStr)
        {
            flags = sighashOptions[i].flags;
            return true;
        }
    }

    return false;
}

static CAmount AmountFromValue(const UniValue &value)
{
    if (!value.isNum() && !value.isStr())
        throw std::runtime_error("Amount is not a number or string");
    CAmount amount;
    if (!ParseFixedPoint(value.getValStr(), 8, &amount))
        throw std::runtime_error("Invalid amount");
    if (!MoneyRange(amount))
        throw std::runtime_error("Amount out of range");
    return amount;
}

static void MutateTxSign(CMutableTransaction &tx, const std::string &flagStr)
{
    int nHashType = SIGHASH_ALL | SIGHASH_SBTC_FORK;

    if (flagStr.size() > 0)
        if (!findSighashFlags(nHashType, flagStr))
            throw std::runtime_error("unknown sighash flag/sign option");

    std::vector<CTransaction> txVariants;
    txVariants.push_back(tx);

    // mergedTx will end up with all the signatures; it
    // starts as a clone of the raw tx:
    CMutableTransaction mergedTx(txVariants[0]);
    bool fComplete = true;
    CCoinsView viewDummy;
    CCoinsViewCache view(&viewDummy);

    if (!registers.count("privatekeys"))
        throw std::runtime_error("privatekeys register variable must be set.");
    CBasicKeyStore tempKeystore;
    UniValue keysObj = registers["privatekeys"];

    for (unsigned int kidx = 0; kidx < keysObj.size(); kidx++)
    {
        if (!keysObj[kidx].isStr())
            throw std::runtime_error("privatekey not a std::string");
        CBitcoinSecret vchSecret;
        bool fGood = vchSecret.SetString(keysObj[kidx].getValStr());
        if (!fGood)
            throw std::runtime_error("privatekey not valid");

        CKey key = vchSecret.GetKey();
        tempKeystore.AddKey(key);
    }

    // Add previous txouts given in the RPC call:
    if (!registers.count("prevtxs"))
        throw std::runtime_error("prevtxs register variable must be set.");
    UniValue prevtxsObj = registers["prevtxs"];
    {
        for (unsigned int previdx = 0; previdx < prevtxsObj.size(); previdx++)
        {
            UniValue prevOut = prevtxsObj[previdx];
            if (!prevOut.isObject())
                throw std::runtime_error("expected prevtxs internal object");

            std::map<std::string, UniValue::VType> types = {
                    {"txid",         UniValue::VSTR},
                    {"vout",         UniValue::VNUM},
                    {"scriptPubKey", UniValue::VSTR},
            };
            if (!prevOut.checkObject(types))
                throw std::runtime_error("prevtxs internal object typecheck fail");

            uint256 txid = ParseHashUV(prevOut["txid"], "txid");

            int nOut = atoi(prevOut["vout"].getValStr());
            if (nOut < 0)
                throw std::runtime_error("vout must be positive");

            COutPoint out(txid, nOut);
            std::vector<unsigned char> pkData(ParseHexUV(prevOut["scriptPubKey"], "scriptPubKey"));
            CScript scriptPubKey(pkData.begin(), pkData.end());

            {
                const Coin &coin = view.AccessCoin(out);
                if (!coin.IsSpent() && coin.out.scriptPubKey != scriptPubKey)
                {
                    std::string err("Previous output scriptPubKey mismatch:\n");
                    err = err + ScriptToAsmStr(coin.out.scriptPubKey) + "\nvs:\n" +
                          ScriptToAsmStr(scriptPubKey);
                    throw std::runtime_error(err);
                }
                Coin newcoin;
                newcoin.out.scriptPubKey = scriptPubKey;
                newcoin.out.nValue = 0;
                if (prevOut.exists("amount"))
                {
                    newcoin.out.nValue = AmountFromValue(prevOut["amount"]);
                }
                newcoin.nHeight = 1;
                view.AddCoin(out, std::move(newcoin), true);
            }

            // if redeemScript given and private keys given,
            // add redeemScript to the tempKeystore so it can be signed:
            if ((scriptPubKey.IsPayToScriptHash() || scriptPubKey.IsPayToWitnessScriptHash()) &&
                prevOut.exists("redeemScript"))
            {
                UniValue v = prevOut["redeemScript"];
                std::vector<unsigned char> rsData(ParseHexUV(v, "redeemScript"));
                CScript redeemScript(rsData.begin(), rsData.end());
                tempKeystore.AddCScript(redeemScript);
            }
        }
    }

    const CKeyStore &keystore = tempKeystore;

    bool fHashSingle = ((nHashType & ~(SIGHASH_ANYONECANPAY | SIGHASH_SBTC_FORK)) == SIGHASH_SINGLE);

    // Sign what we can:
    for (unsigned int i = 0; i < mergedTx.vin.size(); i++)
    {
        CTxIn &txin = mergedTx.vin[i];
        const Coin &coin = view.AccessCoin(txin.prevout);
        if (coin.IsSpent())
        {
            fComplete = false;
            continue;
        }
        const CScript &prevPubKey = coin.out.scriptPubKey;
        const CAmount &amount = coin.out.nValue;

        SignatureData sigdata;
        // Only sign SIGHASH_SINGLE if there's a corresponding output:
        if (!fHashSingle || (i < mergedTx.vout.size()))
            ProduceSignature(MutableTransactionSignatureCreator(&keystore, &mergedTx, i, amount, nHashType), prevPubKey,
                             sigdata);

        // ... and merge in other signatures:
        for (const CTransaction &txv : txVariants)
            sigdata = CombineSignatures(prevPubKey, MutableTransactionSignatureChecker(&mergedTx, i, amount), sigdata,
                                        DataFromTransaction(txv, i));
        UpdateTransaction(mergedTx, i, sigdata);

        if (!VerifyScript(txin.scriptSig, prevPubKey, &txin.scriptWitness, STANDARD_SCRIPT_VERIFY_FLAGS,
                          MutableTransactionSignatureChecker(&mergedTx, i, amount)))
            fComplete = false;
    }

    if (fComplete)
    {
        // do nothing... for now
        // perhaps store this for later optional JSON output
    }

    tx = mergedTx;
}

class Secp256k1Init
{
    ECCVerifyHandle globalVerifyHandle;

public:
    Secp256k1Init()
    {
        ECC_Start();
    }

    ~Secp256k1Init()
    {
        ECC_Stop();
    }
};

static void MutateTx(CMutableTransaction &tx, const std::string &command,
                     const std::string &commandVal)
{
    std::unique_ptr<Secp256k1Init> ecc;

    if (command == "nversion")
        MutateTxVersion(tx, commandVal);
    else if (command == "locktime")
        MutateTxLocktime(tx, commandVal);
    else if (command == "replaceable")
    {
        MutateTxRBFOptIn(tx, commandVal);
    } else if (command == "delin")
        MutateTxDelInput(tx, commandVal);
    else if (command == "in")
        MutateTxAddInput(tx, commandVal);

    else if (command == "delout")
        MutateTxDelOutput(tx, commandVal);
    else if (command == "outaddr")
        MutateTxAddOutAddr(tx, commandVal);
    else if (command == "outpubkey")
    {
        if (!ecc)
        {
            ecc.reset(new Secp256k1Init());
        }
        MutateTxAddOutPubKey(tx, commandVal);
    } else if (command == "outmultisig")
    {
        if (!ecc)
        {
            ecc.reset(new Secp256k1Init());
        }
        MutateTxAddOutMultiSig(tx, commandVal);
    } else if (command == "outscript")
        MutateTxAddOutScript(tx, commandVal);
    else if (command == "outdata")
        MutateTxAddOutData(tx, commandVal);

    else if (command == "sign")
    {
        if (!ecc)
        {
            ecc.reset(new Secp256k1Init());
        }
        MutateTxSign(tx, commandVal);
    } else if (command == "load")
        RegisterLoad(commandVal);

    else if (command == "set")
        RegisterSet(commandVal);

    else
        throw std::runtime_error("unknown command");
}

static void OutputTxJSON(const CTransaction &tx)
{
    UniValue entry(UniValue::VOBJ);
    TxToUniv(tx, uint256(), entry);

    std::string jsonOutput = entry.write(4);
    fprintf(stdout, "%s\n", jsonOutput.c_str());
}

static void OutputTxHash(const CTransaction &tx)
{
    std::string strHexHash = tx.GetHash().GetHex(); // the hex-encoded transaction hash (aka the transaction id)

    fprintf(stdout, "%s\n", strHexHash.c_str());
}

static void OutputTxHex(const CTransaction &tx)
{
    std::string strHex = EncodeHexTx(tx);

    fprintf(stdout, "%s\n", strHex.c_str());
}

static void OutputTx(const CTransaction &tx)
{
    if (Args().GetArg<bool>("-json", false))
        OutputTxJSON(tx);
    else if (Args().GetArg<bool>("-txid", false))
        OutputTxHash(tx);
    else
        OutputTxHex(tx);
}

std::string readStdin()
{
    char buf[4096];
    std::string ret;

    while (!feof(stdin))
    {
        size_t bread = fread(buf, 1, sizeof(buf), stdin);
        ret.append(buf, bread);
        if (bread < sizeof(buf))
            break;
    }

    if (ferror(stdin))
        throw std::runtime_error("error reading stdin");

    boost::algorithm::trim_right(ret);

    return ret;
}

void CApp::InitOptionMap()
{
    std::map<string, vector<option_item>> optionMap;

    vector<option_item> item = {
            {"help,h", "Print this message and exit."},
            {"create", "Create new, empty TX."},
            {"json",   "Select JSON output"},
            {"txid",   "Output only the hex-encoded transaction id of the resultant transaction."}
    };
    optionMap.emplace("Options:", item);

    item = {
            {"testnet", "Use the test chain"},
            {"regtest", "Enter regression test mode, which uses a special chain in which blocks can be solved instantly. "
                                                      "This is intended for regression testing tools and app_bpo development."}

    };
    optionMap.emplace("Chain selection options:", item);

    item = {
            {"delin=N",                                                         "Delete input N from TX"},
            {"delout=N",                                                        "Delete output N from TX"},
            {"in=TXID:VOUT(:SEQUENCE_NUMBER)",                                  "Add input to TX"},
            {"locktime=N",                                                      "Set TX lock time to N"},
            {"nversion=N",                                                      "Set TX version to N"},
            {"replaceable(=N)",                                                 "Set RBF opt-in sequence number for input N (if not provided, opt-in all available inputs)"},
            {"outaddr=VALUE:ADDRESS",                                           "Add address-based output to TX"},
            {"outpubkey=VALUE:PUBKEY[:FLAGS]",                                  _("Add pay-to-pubkey output to TX") +
                                                                                ". " +
                                                                                _("Optionally add the \"W\" flag to produce a pay-to-witness-pubkey-hash output") +
                                                                                ". " +
                                                                                _("Optionally add the \"S\" flag to wrap the output in a pay-to-script-hash.")},
            {"outdata=[VALUE:]DATA",                                            "Add data-based output to TX"},
            {"outscript=VALUE:SCRIPT[:FLAGS]",                                  _("Add raw script output to TX") +
                                                                                ". " +
                                                                                _("Optionally add the \"W\" flag to produce a pay-to-witness-script-hash output") +
                                                                                ". " +
                                                                                _("Optionally add the \"S\" flag to wrap the output in a pay-to-script-hash.")},
            {"outmultisig=VALUE:REQUIRED:PUBKEYS:PUBKEY1:PUBKEY2:....[:FLAGS]", _(
                    "Add Pay To n-of-m Multi-sig output to TX. n = REQUIRED, m = PUBKEYS") + ". " +
                                                                                _("Optionally add the \"W\" flag to produce a pay-to-witness-script-hash output") +
                                                                                ". " +
                                                                                _("Optionally add the \"S\" flag to wrap the output in a pay-to-script-hash.")},
            {"sign=SIGHASH-FLAGS",                                              _(
                    "Add zero or more signatures to transaction") + ". " +
                                                                                _("This command requires JSON registers:") +
                                                                                _("prevtxs=JSON object") + ", " +
                                                                                _("privatekeys=JSON object") + ". " +
                                                                                _("See signrawtransaction docs for format of sighash flags, JSON objects.")},
    };
    optionMap.emplace("Commands:", item);

    item = {
            {"load=NAME:FILENAME",   _("Load JSON file FILENAME into register NAME")},
            {"set=NAME:JSON-STRING", _("Set register NAME to given JSON-STRING")}
    };
    optionMap.emplace("Register Commands:", item);

    item = {
            {"hexsbtctx",        bpo::value<string>(), "Internal hex-encoded sbtc transaction"},
            {"commandargs",      bpo::value<string>(), "Internal Command arguments"}
    };
    optionMap.emplace("internal options(unavailable for command line):", item);

    std::string strHead =
            strprintf(_("%s sbtc-tx utility version"), _(PACKAGE_NAME)) + " " + FormatFullVersion() + "\n\n" +
            _("Usage:") + "\n" +
            "  bitcoin-tx [options] <hex-tx> [commands]  " + _("Update hex-encoded bitcoin transaction") + "\n" +
            "  bitcoin-tx [options] -create [commands]   " + _("Create hex-encoded bitcoin transaction") + "\n" +
            "\n";

    pArgs->SetOptionName(strHead);
    pArgs->SetOptionTable(optionMap);
}

void CApp::RelayoutArgs(int& argc, char**& argv)
{
    static std::list<std::string> _argx;
    static std::vector<const char*> _argv;

    _argv.emplace_back(argv[0]); // assert(argc >= 1)

    int i = 1;
    for (; i < argc && argv[i][0] == '-'; i++)
    {
        if (strlen(argv[i]) > 2 && argv[i][1] != '-')
        {
            _argx.emplace_back('-' + std::string(argv[i]));
            _argv.emplace_back(_argx.back().c_str());
        }
        else
        {
            _argv.emplace_back(argv[i]);
        }
    }

    for (auto opt : _argv)
    {
        if (strncmp(opt, "--create", 8) == 0)
        {
            fCreateBlank = true;
            break;
        }
    }

    if (i < argc)
    {
        if (!fCreateBlank)
        {
            _argx.emplace_back(std::string("--hexsbtctx=") + argv[i++]);
            _argv.emplace_back(_argx.back().c_str());
        }
    }

    if (i < argc)
    {
        std::string commandargs(argv[i++]);
        for (; i < argc; i++)
        {
            commandargs += COMMAND_ARG_SEP;
            commandargs += argv[i];
        }
        _argx.emplace_back(std::string("--commandargs=") + commandargs);
        _argv.emplace_back(_argx.back().c_str());
    }

    argc = (int)_argv.size();
    argv = (char**)&_argv[0];
}

bool CApp::Initialize(int argc, char **argv)
{
    SetupEnvironment();

    InitOptionMap();

    if (!pArgs->Init(argc, argv))
    {
        return false;
    }

    if (pArgs->IsArgSet("help") || pArgs->IsArgSet("usage"))
    {
        std::cout << pArgs->GetHelpMessage();
        return false;
    }

    try
    {
        pChainParams = CreateChainParams(ChainNameFromCommandLine());
    } catch(const std::exception& e)
    {
        fprintf(stderr, "Error: %s.\n", e.what());
        return false;
    }

    //InitializeLogging(pArgs->GetDataDir(false));
    return true;
}

bool CApp::Run()
{
    bool fUpdateTx = pArgs->IsArgSet("-hexsbtctx");

    if (fUpdateTx == fCreateBlank)
    {
        fprintf(stderr, "Error: Invalid command line arguments.\n");
        return false;
    }

    int nRet = 0;
    std::string strPrint;

    try
    {
        CMutableTransaction tx;
        if (fUpdateTx)
        {
            // param: hex-encoded bitcoin transaction
            std::string strHexTx = pArgs->GetArg<std::string>("-hexsbtctx", "");

            //if (strHexTx == "-")                 // "-" implies standard input
            //    strHexTx = readStdin();

            if (!DecodeHexTx(tx, strHexTx, true))
                throw std::runtime_error("invalid transaction encoding");
        }

        std::string strArgs = pArgs->GetArg<std::string>("-commandargs", "");
        std::vector<std::string> args = SplitString(strArgs, COMMAND_ARG_SEP);

        for (const auto& arg : args)
        {
            std::string key, value;
            size_t eqpos = arg.find('=');
            if (eqpos == std::string::npos)
                key = arg;
            else
            {
                key = arg.substr(0, eqpos);
                value = arg.substr(eqpos + 1);
            }

            MutateTx(tx, key, value);
        }

        OutputTx(tx);
    }
    catch (const boost::thread_interrupted &)
    {
        strPrint = "thread interrupted!";
        nRet = EXIT_FAILURE;
    }
    catch (const std::exception &e)
    {
        strPrint = std::string("error: ") + e.what();
        nRet = EXIT_FAILURE;
    }
    catch (...)
    {
        PrintExceptionContinue(nullptr, "CommandLineRawTx()");
        nRet = EXIT_FAILURE;
    }

    if (!strPrint.empty())
    {
        fprintf((nRet == EXIT_SUCCESS ? stdout : stderr), "%s\n", strPrint.c_str());
    }

    return nRet == EXIT_SUCCESS;
}


text:
// Concord
//
// Copyright (c) 2021 VMware, Inc. All Rights Reserved.
//
// This product is licensed to you under the Apache 2.0 license (the "License"). You may not use this product except in
// compliance with the Apache 2.0 License.
//
// This product may include a number of subcomponents with separate copyright notices and license terms. Your use of
// these subcomponents is subject to the terms and conditions of the subcomponent's license, as noted in the LICENSE
// file.

#include <memory>
#include <string>
#include <grpcpp/grpcpp.h>
#include <boost/program_options.hpp>
#include <yaml-cpp/yaml.h>

#include "client/clientservice/client_service.hpp"
#include "client/clientservice/configuration.hpp"
#include "client/concordclient/concord_client.hpp"
#include "Logger.hpp"
#include "Metrics.hpp"

using concord::client::clientservice::ClientService;
using concord::client::clientservice::configureSubscription;
using concord::client::clientservice::parseConfigFile;

using concord::client::concordclient::ConcordClient;
using concord::client::concordclient::ConcordClientConfig;

namespace po = boost::program_options;

po::variables_map parseCmdLine(int argc, char** argv) {
  po::options_description desc;
  // clang-format off
  desc.add_options()
    ("config", po::value<std::string>()->required(), "YAML configuration file for the RequestService")
    ("host", po::value<std::string>()->default_value("0.0.0.0"), "Clientservice gRPC service host")
    ("port", po::value<int>()->default_value(50505), "Clientservice gRPC service port")
    ("bft-batching", po::value<bool>()->default_value(false), "Enable batching requests before sending to replicas")
    ("tr-id", po::value<std::string>()->required(), "ID used to subscribe to replicas for data/hashes")
    ("tr-insecure", po::value<bool>()->default_value(false), "Testing only: Allow insecure connection with TRS on replicas")
    ("tr-tls-path", po::value<std::string>()->default_value(""), "Path to thin replica TLS certificates")
  ;
  // clang-format on
  po::variables_map opts;
  po::store(po::parse_command_line(argc, argv, desc), opts);
  po::notify(opts);

  return opts;
}

int main(int argc, char** argv) {
  // TODO: Use config file and watch thread for logger
  auto logger = logging::getLogger("concord.client.clientservice.main");

  auto opts = parseCmdLine(argc, argv);

  ConcordClientConfig config;
  try {
    auto yaml = YAML::LoadFile(opts["config"].as<std::string>());
    parseConfigFile(config, yaml);
    configureSubscription(
        config, opts["tr-id"].as<std::string>(), opts["tr-insecure"].as<bool>(), opts["tr-tls-path"].as<std::string>());
  } catch (std::exception& e) {
    LOG_ERROR(logger, "Failed to configure ConcordClient: " << e.what());
    return 1;
  }
  LOG_INFO(logger, "ConcordClient configured");

  auto concord_client = std::make_unique<ConcordClient>(config);
  auto metrics = std::make_shared<concordMetrics::Aggregator>();
  concord_client->setMetricsAggregator(metrics);
  ClientService service(std::move(concord_client));

  auto server_addr = opts["host"].as<std::string>() + ":" + std::to_string(opts["port"].as<int>());
  LOG_INFO(logger, "Starting clientservice at " << server_addr);
  service.start(server_addr);

  return 0;
}

ext: cpp

max_stars_repo_name: definitelyNotFBI/utt

max_issues_repo_name: definitelyNotFBI/utt

max_forks_repo_name: definitelyNotFBI/utt


text:
#include <boost/bind.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/asio/deadline_timer.hpp>
#include <chrono>

#include "TimerAction.h"
#include "Utility.h"
#include "Timer.h"
#include "ApplicationShortRun.h"

TimerAction::TimerAction()
{
}

TimerAction::TimerAction(std::shared_ptr<ApplicationShortRun> app)
	:m_app(app)
{
	const static char fname[] = "TimerAction::TimerAction() ";
	LOG(INFO) << fname << "Entered." << std::endl;

	LOG(INFO) << "Current time <" << Utility::convertTime2Str(std::chrono::system_clock::now())
		<< ">, start time <" << Utility::convertTime2Str(app->getStartTime()) << "> App <" << app->getName() << ">." << std::endl;

	int firstSleepSec = 0;
	if (app->getStartTime() > std::chrono::system_clock::now())
	{
		firstSleepSec = std::chrono::duration_cast<std::chrono::seconds>(app->getStartTime() - std::chrono::system_clock::now()).count();
	}
	else
	{
		auto totalSec = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now() - app->getStartTime()).count();
		firstSleepSec = totalSec % app->getStartInterval();
	}

	m_timer = std::make_shared<boost::asio::deadline_timer>(TIMER.getIO(), boost::posix_time::seconds(firstSleepSec));
	m_timer->async_wait(boost::bind(&TimerAction::onTimeOut, this, boost::asio::placeholders::error));

	LOG(INFO) << "Timer will sleep <" << firstSleepSec << "> seconds for app <" << app->getName() <<
		">, next start time is <" << Utility::convertTime2Str(std::chrono::system_clock::now() + std::chrono::seconds(firstSleepSec))
		<< ">." << std::endl;
}

TimerAction::~TimerAction()
{
	const static char fname[] = "TimerAction::~TimerAction() ";
	LOG(INFO) << fname << "Entered." << std::endl;
}

void TimerAction::onTimeOut(const boost::system::error_code& ec)
{
	const static char fname[] = "TimerAction::onTimeOut() ";

	if (ec)
	{
		LOG(WARNING) << "TimerAction is canceled." << std::endl;
		delete this;
	}
	else
	{
		std::shared_ptr<ApplicationShortRun> app = m_app.lock();

		if (app != nullptr && app->isNormal())
		{
			LOG(INFO) << fname << "Timeout for app <" << app->getName() << ">." << std::endl;
			std::shared_ptr<Application> self = app;
			app->invokeNow(self);

			// Set next timer
			m_timer->expires_at(m_timer->expires_at() + boost::posix_time::seconds(app->getStartInterval()));
			m_timer->async_wait(boost::bind(&TimerAction::onTimeOut, this, boost::asio::placeholders::error));
		}
		else if (nullptr == app)
		{
			cancelTimer();
		}
	}
}

void TimerAction::cancelTimer()
{
	const static char fname[] = "TimerAction::cancelTimer() ";
	try
	{
		m_timer->cancel();
	}
	catch (...)
	{
		LOG(INFO) << fname << "Cancel timer failed" << std::endl;
	}
}

max_stars_repo_name: julyhurt/application-manager

max_issues_repo_name: julyhurt/application-manager

max_forks_repo_name: julyhurt/application-manager


text:
/**
 * Copyright Soramitsu Co., Ltd. All Rights Reserved.
 * SPDX-License-Identifier: Apache-2.0
 */

#include "ametsuchi/impl/proto_specific_query_executor.h"

#include <boost/variant.hpp>
#include "ametsuchi/specific_query_executor.hpp"
#include "backend/protobuf/queries/proto_query.hpp"
#include "backend/protobuf/query_responses/proto_query_response.hpp"
#include "validators/field_validator.hpp"
#include "validators/protobuf/proto_query_validator.hpp"
#include "validators/query_validator.hpp"
#include "validators/validators_common.hpp"

namespace {
  Iroha_ProtoQueryResponse serialize(iroha::protocol::QueryResponse response) {
    Iroha_ProtoQueryResponse result{};

    result.size = response.ByteSize();
    result.data = malloc(result.size);
    response.SerializeToArray(result.data, result.size);

    return result;
  }

  iroha::protocol::QueryResponse makeErrorResponse(int code,
                                                   std::string message) {
    iroha::protocol::QueryResponse result{};

    auto *error_response = result.mutable_error_response();
    error_response->set_error_code(code);
    error_response->set_message(std::move(message));

    return result;
  }
}  // namespace

Iroha_ProtoQueryResponse Iroha_ProtoSpecificQueryExecutorExecute(void *executor,
                                                                 void *data,
                                                                 int size) {
  iroha::protocol::Query protocol_query;
  if (!protocol_query.ParseFromArray(data, size)) {
    return serialize(makeErrorResponse(100, "Deserialization failed"));
  }

  if (auto maybe_error =
          shared_model::validation::ProtoQueryValidator().validate(
              protocol_query)) {
    return serialize(makeErrorResponse(200, maybe_error.value().toString()));
  }

  shared_model::proto::Query proto_query(protocol_query);

  if (auto maybe_error =
          shared_model::validation::QueryValidator<
              shared_model::validation::FieldValidator,
              shared_model::validation::QueryValidatorVisitor<
                  shared_model::validation::FieldValidator>>(
              std::make_shared<shared_model::validation::ValidatorsConfig>(0))
              .validate(proto_query)) {
    return serialize(makeErrorResponse(300, maybe_error.value().toString()));
  }

  auto response =
      reinterpret_cast<iroha::ametsuchi::SpecificQueryExecutor *>(executor)
          ->execute(proto_query);
  auto &proto_response =
      static_cast<shared_model::proto::QueryResponse *>(response.get())
          ->getTransport();

  return serialize(proto_response);
}

max_stars_repo_name: Revertron/iroha

max_issues_repo_name: Revertron/iroha

max_forks_repo_name: Revertron/iroha


text:
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>

#include <CGAL/Triangulation_2.h>
#include <CGAL/Projection_traits_xy_3.h>
#include <CGAL/boost/graph/graph_traits_Triangulation_2.h>
#include <CGAL/boost/graph/iterator.h>

#include <boost/graph/filtered_graph.hpp>

typedef CGAL::Exact_predicates_inexact_constructions_kernel       Epic;
typedef CGAL::Projection_traits_xy_3<Epic>                        K;
typedef K::Point_2                                                Point;

typedef CGAL::Triangulation_2<K>                                  Triangulation;

typedef boost::graph_traits<Triangulation>::vertex_descriptor     vertex_descriptor;
typedef boost::graph_traits<Triangulation>::vertex_iterator       vertex_iterator;
typedef boost::graph_traits<Triangulation>::halfedge_descriptor   halfedge_descriptor;
typedef boost::graph_traits<Triangulation>::halfedge_iterator     halfedge_iterator;
typedef boost::graph_traits<Triangulation>::edge_iterator         edge_iterator;
typedef boost::graph_traits<Triangulation>::edge_descriptor       edge_descriptor;
typedef boost::graph_traits<Triangulation>::face_descriptor       face_descriptor;
typedef boost::graph_traits<Triangulation>::face_iterator         face_iterator;

typedef std::map<vertex_descriptor, int>                          VertexIndexMap;
typedef boost::associative_property_map<VertexIndexMap>           VertexIdPropertyMap;

typedef boost::property_map<Triangulation, boost::vertex_point_t>::type Ppmap;

int main(int /*argc*/, char** /*argc*/)
{
  Triangulation tr;

  tr.insert(Point(0.1,0,1));
  tr.insert(Point(1,0,1));
  tr.insert(Point(0.2,0.2, 2));
  tr.insert(Point(0,1,2));
  tr.insert(Point(0,2,3));

  // Associate indices to the vertices
  VertexIndexMap vertex_id_map;
  VertexIdPropertyMap vertex_index_pmap(vertex_id_map);
  int index = 0;

  for(vertex_descriptor vd : vertices(tr))
    vertex_id_map[vd] = index++;
  std::cerr << index << " vertices" << std::endl;

  index = 0;
  for(halfedge_descriptor hd : halfedges(tr))
  {
    vertex_descriptor vd = source(hd, tr);
    CGAL_USE(vd);
    ++index;
  }
  std::cerr << index << " halfedges" << std::endl;

  index = 0;
  for(edge_descriptor ed : edges(tr))
  {
    vertex_descriptor vd = source(ed, tr);
    CGAL_USE(vd);
    ++index;
  }
  std::cerr << index << " edges" << std::endl;

  index = 0;
  for(face_descriptor fd : faces(tr))
  {
    halfedge_descriptor hd = halfedge(fd, tr);
    CGAL_USE(hd);
    ++index;
  }
  std::cerr << index << " faces" << std::endl;

  std::cerr << num_vertices(tr) << " " << num_halfedges(tr) << " " << num_edges(tr) << " " << num_faces(tr) << std::endl;

  std::cout << "vertices incident to the first vertex:" << std::endl;
  Ppmap ppmap = get(boost::vertex_point, tr);
  for(vertex_descriptor vd : vertices_around_target(*vertices(tr).first, tr))
    std::cout <<  ppmap[vd] << std::endl;

  ppmap[*(++vertices(tr).first)] = Point(78, 1, 2);
  std::cout << "changed point of vertex " << ppmap[*(++vertices(tr).first)] << std::endl;

  return EXIT_SUCCESS;
}

max_stars_repo_name: ffteja/cgal

max_issues_repo_name: ffteja/cgal

max_forks_repo_name: ffteja/cgal


text:
#define BOOST_TEST_MAIN
#include <boost/test/included/unit_test.hpp>

#include "cxxpznn1/core.hpp"

BOOST_AUTO_TEST_CASE(test_puzzle_001)
{
    unsigned int size = 4;
    cxxpznn1::Puzzle puzzle(size);

    cxxpznn1::Grid grid = puzzle.as_grid();

    int** g = new int*[size+2];
    for (int i = 0; i < size+2; i++)
    {
        g[i] = new int[size+2];
    }

    for (int i = 0; i < size+2; i++)
    {
        for (int j = 0; j < size+2; j++)
        {
            g[i][j] = -1;
        }
    }

    for (int i = 1; i <= size; i++)
    {
        for (int j = 1; j <= size; j++)
        {
            g[i][j] = size * (i-1) + j;
        }
    }

    g[size][size] = 0;

    cxxpznn1::Grid target(size+2, g);

    BOOST_CHECK(grid == target);
}

BOOST_AUTO_TEST_CASE(test_puzzle_002)
{
    unsigned int size = 4;
    cxxpznn1::Puzzle puzzle(size);
    puzzle.move(cxxpznn1::Direction::V::Up);

    cxxpznn1::Grid grid = puzzle.as_grid();

    cxxpznn1::Grid target(size+2, cxxpznn1::Puzzle::create_initial_grid(size));

    BOOST_CHECK(grid == target);
}

BOOST_AUTO_TEST_CASE(test_puzzle_003)
{
    unsigned int size = 4;
    cxxpznn1::Puzzle puzzle(size);
    puzzle.move(cxxpznn1::Direction::V::Left);

    cxxpznn1::Grid grid = puzzle.as_grid();

    cxxpznn1::Grid target(size+2, cxxpznn1::Puzzle::create_initial_grid(size));

    BOOST_CHECK(grid == target);
}

BOOST_AUTO_TEST_CASE(test_puzzle_004)
{
    unsigned int size = 4;
    cxxpznn1::Puzzle puzzle(size);
    puzzle.move(cxxpznn1::Direction::V::Down);

    cxxpznn1::Grid grid = puzzle.as_grid();

    int** g = cxxpznn1::Puzzle::create_initial_grid(size);
    g[3][4] = 0;
    g[4][4] = 12;
    cxxpznn1::Grid target(size+2, g);

    BOOST_CHECK(grid == target);
}

BOOST_AUTO_TEST_CASE(test_puzzle_005)
{
    unsigned int size = 4;
    cxxpznn1::Puzzle puzzle(size);
    puzzle.move(cxxpznn1::Direction::V::Right);

    cxxpznn1::Grid grid = puzzle.as_grid();

    int** g = cxxpznn1::Puzzle::create_initial_grid(size);
    g[4][3] = 0;
    g[4][4] = 15;
    cxxpznn1::Grid target(size+2, g);

    BOOST_CHECK(grid == target);
}

BOOST_AUTO_TEST_CASE(test_puzzle_006)
{
    unsigned int size = 4;
    cxxpznn1::Puzzle puzzle(size);
    puzzle.move(cxxpznn1::Direction::V::Down);
    puzzle.move(cxxpznn1::Direction::V::Right);
    puzzle.move(cxxpznn1::Direction::V::Up);
    puzzle.move(cxxpznn1::Direction::V::Left);

    cxxpznn1::Grid grid = puzzle.as_grid();

    int** g = cxxpznn1::Puzzle::create_initial_grid(size);
    g[3][3] = 15;
    g[3][4] = 11;
    g[4][3] = 12;
    g[4][4] = 0;
    cxxpznn1::Grid target(size+2, g);

    BOOST_CHECK(grid == target);
}

BOOST_AUTO_TEST_CASE(test_puzzle_007)
{
    unsigned int size = 4;
    cxxpznn1::Puzzle puzzle(size);
    puzzle.move(cxxpznn1::Direction::V::Right);
    puzzle.move(cxxpznn1::Direction::V::Right);
    puzzle.move(cxxpznn1::Direction::V::Right);
    puzzle.move(cxxpznn1::Direction::V::Right);

    cxxpznn1::Grid grid = puzzle.as_grid();

    int** g = cxxpznn1::Puzzle::create_initial_grid(size);
    g[4][1] = 0;
    g[4][2] = 13;
    g[4][3] = 14;
    g[4][4] = 15;
    cxxpznn1::Grid target(size+2, g);

    BOOST_CHECK(grid == target);
}

BOOST_AUTO_TEST_CASE(test_puzzle_008)
{
    unsigned int size = 4;
    cxxpznn1::Puzzle puzzle(size);
    puzzle.move(cxxpznn1::Direction::V::Down);
    puzzle.move(cxxpznn1::Direction::V::Down);
    puzzle.move(cxxpznn1::Direction::V::Down);
    puzzle.move(cxxpznn1::Direction::V::Down);

    cxxpznn1::Grid grid = puzzle.as_grid();

    int** g = cxxpznn1::Puzzle::create_initial_grid(size);
    g[1][4] = 0;
    g[2][4] = 4;
    g[3][4] = 8;
    g[4][4] = 12;
    cxxpznn1::Grid target(size+2, g);

    BOOST_CHECK(grid == target);
}


text: #include <boost/thread/executors/work.hpp>

ext: hpp

max_stars_repo_name: miathedev/BoostForArduino

max_issues_repo_name: miathedev/BoostForArduino

max_forks_repo_name: miathedev/BoostForArduino


text:
/**
* Connected Vision - https://github.com/ConnectedVision
* MIT License
*/

// auto-generated header by CodeFromTemplate - Connected Vision - https://github.com/ConnectedVision
// CodeFromTemplate Version: 0.3 alpha
// stubs/Stub_generic_config_chain.cpp
// NEVER TOUCH this file!

#include <utility>

#include <rapidjson/document.h>
#include <rapidjson/prettywriter.h>
#include <rapidjson/stringbuffer.h>
#include <rapidjson/error/en.h>
#include <boost/make_shared.hpp>

#include "Stub_generic_config_chain.h"
#include "../Class_generic_config_chain.h"

// --> Do NOT EDIT <--
namespace ConnectedVision {

// --> Do NOT EDIT <--
/* copy constructors */
Stub_generic_config_chain::Stub_generic_config_chain(const Stub_generic_config_chain& other)
{
	// TODO: other.readLock
	// connections
	{
		const auto& n0 = other.connections;
		auto a0 = boost::make_shared<std::vector<boost::shared_ptr<Class_generic_config_chain_connections>>>( (n0->size()) );
		for (size_t i0 = 0; i0 < n0->size(); ++i0)
		{
			if ( n0->at(i0) )
				a0->at(i0) = boost::make_shared<Class_generic_config_chain_connections>( *n0->at(i0) );
		}
		connections = a0;
	}
	// config
	if ( other.config )
		config = boost::make_shared<std::string>(*other.config);
}

// --> Do NOT EDIT <--
/* copy assignment operator */
Stub_generic_config_chain& Stub_generic_config_chain::operator =(const Stub_generic_config_chain& other)
{
	Stub_generic_config_chain tmp(other); // re-use copy-constructor
	*this = std::move(tmp); // re-use move-assignment
	return *this;
}

// --> Do NOT EDIT <--
/* mopy assignment operator */
Stub_generic_config_chain& Stub_generic_config_chain::operator =(Stub_generic_config_chain&& other) noexcept
{
	// connections
    std::swap(connections, other.connections);
	// config
    std::swap(config, other.config);

	return *this;
}

// --> Do NOT EDIT <--
/* default constructors */
Stub_generic_config_chain::Stub_generic_config_chain()
{
	clear();
}

// --> Do NOT EDIT <--
Stub_generic_config_chain::Stub_generic_config_chain(const rapidjson::Value& value)
{
	clear();
	parseJson( value );
}

// --> Do NOT EDIT <--
Stub_generic_config_chain::Stub_generic_config_chain(const std::string& str)
{
	clear();
	parseJson( str );
}

// --> Do NOT EDIT <--
Stub_generic_config_chain::~Stub_generic_config_chain()
{
}

// --> Do NOT EDIT <--
void Stub_generic_config_chain::clear()
{
	this->connections.reset( new std::vector<boost::shared_ptr<Class_generic_config_chain_connections>> );
	this->config.reset( new std::string("") );
}

// --> Do NOT EDIT <--
void Stub_generic_config_chain::parseJson(const char *str)
{
	// ignore empty data
	if ( str[0] == 0 )
		return;

	// parse data
	rapidjson::Document document;
	if (document.Parse<0>(str).HasParseError())
	{
		std::string context;
		size_t off = document.GetErrorOffset();
		size_t i, line_start = 0, context_start = 0;
		int num_line = 1;
		for ( i = 0; (i < off) && str[i]; i++ )
		{
			if ( str[i] == '\n' )
			{ line_start = i+1; context_start = i+1; num_line++; }
			if ( str[i] == '{' || str[i] == '[' )
			{ context_start = i; }
		}
		for ( i = context_start; str[i]; i++ )
		{
			if ( str[i] == '\n' || str[i] == '\r' ) break;
			context += str[i];
			if ( str[i] == '}' || str[i] == ']' ) break;
		}
		throw ConnectedVision::runtime_error( std::string("parse error of JSON Object: ") + rapidjson::GetParseError_En(document.GetParseError()) + std::string(" at line ") + ConnectedVision::intToStr( num_line ) + ": " + context);
	}

	parseJson(document);
}

// --> Do NOT EDIT <--
void Stub_generic_config_chain::parseJson(const rapidjson::Value& value)
{
	clear();
	if ( !value.IsObject() )
		throw ConnectedVision::runtime_error( "no JSON Object");

	// connections
	if ((value.HasMember("connections")) && value["connections"].IsArray())
	{
		const rapidjson::Value& n0 = value["connections"];
		boost::shared_ptr<std::vector<boost::shared_ptr<Class_generic_config_chain_connections>>> a0( new std::vector<boost::shared_ptr<Class_generic_config_chain_connections>>(n0.Size()) );
		for (rapidjson::SizeType i0 = 0; i0 < n0.Size(); i0++)
		{
			a0->at(i0) = boost::shared_ptr<Class_generic_config_chain_connections>( new Class_generic_config_chain_connections( n0[i0] ) );
		}
		set_connections( a0 );
	}
	else
		throw ConnectedVision::runtime_error( "required member is missing: 'connections'");

	// config
	if ((value.HasMember("config")) && ( value["config"].IsObject() || value["config"].IsArray() || value["config"].IsInt64() || value["config"].IsNumber() || value["config"].IsBool() ))
	{
		set_config( boost::shared_ptr<std::string>( new std::string( ConnectedVision::jsonToStr(value["config"]) ) ) );
	}
	else
		throw ConnectedVision::runtime_error( "required member is missing: 'config'");

}

// --> Do NOT EDIT <--
std::string Stub_generic_config_chain::toJsonStr() const
{
	rapidjson::StringBuffer s;
	rapidjson::Document doc; doc.SetObject();
	this->toJson(doc, doc.GetAllocator());
	rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(s);
	doc.Accept(writer);
	return std::string(s.GetString());
}

// --> Do NOT EDIT <--
std::string Stub_generic_config_chain::toJson() const
{
	rapidjson::StringBuffer s;
	rapidjson::Document doc; doc.SetObject();
	this->toJson(doc, doc.GetAllocator());
	rapidjson::Writer<rapidjson::StringBuffer> writer(s);
	doc.Accept(writer);
	return std::string(s.GetString());
}

// --> Do NOT EDIT <--
rapidjson::Value& Stub_generic_config_chain::toJson(rapidjson::Value& node, rapidjson::Value::AllocatorType& allocator) const
{
	{ // connections
		rapidjson::Value n0; n0.SetArray();
		boost::shared_ptr<std::vector<boost::shared_ptr<Class_generic_config_chain_connections>>>&& a0 = get_connections(); // rvalue reference for const functions
		for (size_t i0 = 0; i0 < a0->size(); i0++)
		{
			// process array level 0
			// final dimension of array, add actual value
			if ( a0->at(i0) )	// ensure that we have no NULL pointer
			{
				n0.PushBack(a0->at(i0)->toJson( rapidjson::Value().SetObject(), allocator), allocator);
			}
		}
		node.AddMember("connections", n0, allocator);
	}
	{ // config
		rapidjson::Document doc(&allocator);
		doc.Parse<0>( get_config()->c_str() );
		node.AddMember("config", static_cast<rapidjson::Value&>(doc), allocator);
	}
	return node;
}

// --> Do NOT EDIT <--
boost::shared_ptr<std::vector<boost::shared_ptr<Class_generic_config_chain_connections>>> Stub_generic_config_chain::get_connections() const
{
	return( this->connections );
}

// --> Do NOT EDIT <--
const boost::shared_ptr<const std::vector<boost::shared_ptr<Class_generic_config_chain_connections>>> Stub_generic_config_chain::getconst_connections() const
{
	return( boost::static_pointer_cast<const std::vector<boost::shared_ptr<Class_generic_config_chain_connections>>>(this->connections) );
}

// --> Do NOT EDIT <--
void Stub_generic_config_chain::set_connections(boost::shared_ptr<std::vector<boost::shared_ptr<Class_generic_config_chain_connections>>> value)
{
	this->connections = value;
}

// --> Do NOT EDIT <--
boost::shared_ptr<Class_generic_config_chain_connections> Stub_generic_config_chain::get_connections(int index) const
{
	return( this->connections->at(index) );
}

// --> Do NOT EDIT <--
const boost::shared_ptr<Class_generic_config_chain_connections>& Stub_generic_config_chain::getconst_connections(int index) const
{
	return( this->connections->at(index) );
}

// --> Do NOT EDIT <--
void Stub_generic_config_chain::add_connections(boost::shared_ptr<Class_generic_config_chain_connections> value)
{
	this->connections->push_back(value);
}

// --> Do NOT EDIT <--
boost::shared_ptr<std::string> Stub_generic_config_chain::get_config() const
{
	return( this->config );
}

// --> Do NOT EDIT <--
const boost::shared_ptr<const std::string> Stub_generic_config_chain::getconst_config() const
{
	return( boost::static_pointer_cast<const std::string>(this->config) );
}

// --> Do NOT EDIT <--
void Stub_generic_config_chain::set_config(boost::shared_ptr<std::string> value)
{
	this->config = value;
}

} // namespace ConnectedVision

max_stars_repo_name: ConnectedVision/ConnectedVision

max_issues_repo_name: ConnectedVision/ConnectedVision

max_forks_repo_name: ConnectedVision/ConnectedVision


text:
// Boost.Geometry (aka GGL, Generic Geometry Library)

// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.

// Use, modification and distribution is subject to 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)

#ifndef BOOST_GEOMETRY_EXTENSIONS_ALGORITHMS_DETAIL_OVERLAY_SPLIT_RINGS_HPP
#define BOOST_GEOMETRY_EXTENSIONS_ALGORITHMS_DETAIL_OVERLAY_SPLIT_RINGS_HPP

#define BOOST_GEOMETRY_CHECK_SPLIT_RINGS

#include <deque>
#include <string>

#include <boost/range.hpp>

#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/core/ring_type.hpp>
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/interior_rings.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/algorithms/intersects.hpp>
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_turns.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>

#if defined(BOOST_GEOMETRY_DEBUG_SPLIT_RINGS) || defined(BOOST_GEOMETRY_CHECK_SPLIT_RINGS)
#  include <boost/geometry/io/wkt/wkt.hpp>
#endif

namespace boost { namespace geometry
{

#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace split_rings
{

template <typename Range>
struct split_range
{
/*

   1             2
   +-------------+
   |      4     /
   |       |\  /
   |       | \/____ IP
   |       | /\
   |       |/  \
   |      3     \
   +-------------+
  0,6            5

  - we want to split the range at the IP into two rings
  - At the IP: we have segment_indices 2,4 (result of get_turns_in_sections)
  - We want to copy and remove vertices 3,4
  --> count=4-2
  --> copy [3,5) -> copy(begin()+id1+1, begin()+id1+count+1)
  --> erase: idem
  --> insert(begin()+id1+1)

  --> we use id1+1

  After that, we need to update all indices AFTER IP.
  We removed two vertices here (4-2), and added one (the IP)

*/
    static inline void apply(Range& range, Range& output
        , segment_identifier const& id1
        , segment_identifier const& id2
        , typename geometry::point_type<Range>::type const& point
        )
    {
        if (id1.ring_index == id2.ring_index
            && id1.multi_index == id2.multi_index)
        {
            int mn = (std::min)(id1.segment_index, id2.segment_index);
            mn++;

            typename boost::range_iterator<Range>::type first = range.begin();
            first += mn;

            typename boost::range_iterator<Range>::type last = first;
            last += geometry::math::abs(id2.segment_index - id1.segment_index);

            // Create splitted ring
            output.push_back(point);
            std::copy(first, last, std::back_inserter(output));
            output.push_back(point);

            // Remove the loop from the range
            range.erase(first, last);

            // Iterator is invalid because of erasure, construct again
            range.insert(range.begin() + mn, point);
        }
    }
};

/*template <typename Polygon>
struct split_polygon
{
    typedef typename geometry::ring_type<Polygon>::type ring_type;

    static inline void apply(Polygon& polygon, ring_type& splitted
        , segment_identifier const& id1
        , segment_identifier const& id2
        , typename geometry::point_type<Polygon>::type const& point
        )
    {
        if (id1.ring_index == id2.ring_index
            && id1.multi_index == id2.multi_index)
        {
            ring_type& ring = id1.ring_index < 0
                ? geometry::exterior_ring(polygon)
                : geometry::interior_rings(polygon)[id1.ring_index];

            split_range<ring_type>::apply(ring, splitted, id1, id2, point);
        }
    }
};*/

template <typename Tag, typename Geometry>
struct split
{};

template <typename Ring>
struct split<ring_tag, Ring> : split_range<Ring>
{};

//template <typename Polygon>
//struct split<polygon_tag, Polygon> : split_polygon<Polygon>
//{};

template <typename Tag, typename RingCollection, typename Geometry>
struct insert_rings
{};

template <typename RingCollection, typename Ring>
struct insert_rings<ring_tag, RingCollection, Ring>
{
    static inline void apply(RingCollection& ring_collection, Ring const& ring)
    {
#ifdef BOOST_GEOMETRY_DEBUG_SPLIT_RINGS
std::cout << geometry::wkt(ring)
        << " ; " << geometry::area(ring)
        << " " << ring.size()
        //<< " at " << geometry::wkt(first.point)
        << std::endl;
/*std::cout << "geometry "
    << " " << geometry::area(geometry)
    << std::endl;*/
#endif

        ring_collection.push_back(ring);
    }
};

template <typename RingCollection, typename Polygon>
struct insert_rings<polygon_tag, RingCollection, Polygon>
{
    static inline void apply(RingCollection& ring_collection, Polygon const& polygon)
    {
        ring_collection.push_back(exterior_ring(polygon));

        typename interior_return_type<Polygon const>::type rings
                    = interior_rings(polygon);

        typedef typename boost::range_const_iterator
            <
                typename interior_type<Polygon const>::type
            >::type ring_iterator;

        for (ring_iterator it = boost::begin(rings); it != boost::end(rings); ++it)
        {
#ifdef BOOST_GEOMETRY_DEBUG_SPLIT_RINGS
std::cout << geometry::wkt(*it)
        << " ; " << geometry::area(*it)
        << " " << it->size()
        //<< " at " << geometry::wkt(first.point)
        << std::endl;
/*std::cout << "geometry "
    << " " << geometry::area(geometry)
    << std::endl;*/
#endif

            ring_collection.push_back(*it);
        }
    }
};

/// Sorts vector of turns (results from get_turns)
template <typename Turn>
struct sorter
{
    inline bool operator()(Turn const& left, Turn const& right) const
    {
        if (left.count_between != right.count_between)
        {
            return left.count_between < right.count_between;
        }

        if (left.operations[0].seg_id.segment_index
                == right.operations[0].seg_id.segment_index)
        {
            return left.operations[0].distance < right.operations[0].distance;
        }
        return left.operations[0].seg_id.segment_index
                    < right.operations[0].seg_id.segment_index;
    }
};

/// Turn operation with additional distance field
template <typename P>
struct split_turn_operation : public detail::overlay::turn_operation
{
   inline split_turn_operation()
        : detail::overlay::turn_operation()
        , distance(geometry::return_distance_result<distance_type>(0))
    {}

    typedef typename default_distance_result<P, P>::type distance_type;
    distance_type distance; // distance-measurement from segment.first to IP
};

/// Turn information with distance fields, plus "count_between"  field
template <typename P>
struct split_turn_info : detail::overlay::turn_info
            <
                P, split_turn_operation<P>
            >
{
    //std::string history;
    int count_between; // counts number of segments between ring in intersection

    split_turn_info()
        : count_between(0)
    {}
};

/// Policy to calculate distance
struct split_calculate_distance_policy
{
    template <typename Point1, typename Point2, typename Info>
    static inline void apply(Info& info, Point1 const& p1, Point2 const& p2)
    {
        info.operations[0].distance
                    = geometry::distance(info.point, p1);
        info.operations[1].distance
                    = geometry::distance(info.point, p2);
    }

};

template <typename Range, typename RingCollection>
class range_split_rings
{
    typedef typename geometry::tag<Range>::type tag;
    typedef typename geometry::point_type<Range>::type point_type;

    typedef typename geometry::ring_type<Range>::type ring_type;

    typedef typename strategy_intersection
        <
            typename cs_tag<point_type>::type,
            point_type,
            point_type,
            point_type
        >::segment_intersection_strategy_type strategy;

#ifdef BOOST_GEOMETRY_DEBUG_SPLIT_RINGS
    template <typename Turns>
    static void report(Turns const& turns, std::string const& header)
    {
        if (turns.empty())
        {
            return;
        }
        std::cout << header << std::endl;
        BOOST_FOREACH(typename boost::range_value<Turns>::type const& turn, turns)
        {
            std::cout
                << "I at " << turn.operations[0].seg_id.segment_index
                << "/" << turn.operations[1].seg_id.segment_index
                << " (" << turn.count_between
                << ") " << turn.operations[0].distance
                << "/" << turn.operations[1].distance
                << " " << geometry::wkt(turn.point) << std::endl;
        }
    }
#endif

    template <typename Operation>
    static bool adapt(Operation& op, Operation const& first, Operation const& second)
    {
        if (first.seg_id.segment_index > second.seg_id.segment_index)
        {
            return adapt(op, second, first);
        }
        if (op.seg_id.segment_index > first.seg_id.segment_index
            || (op.seg_id.segment_index == first.seg_id.segment_index
                && op.distance > first.distance)
            )
        {
            if (op.seg_id.segment_index < second.seg_id.segment_index
                || (op.seg_id.segment_index == second.seg_id.segment_index
                    && op.distance < second.distance)
                )
            {
                // mark for deletion
                op.seg_id.segment_index = -1;
                return true;
            }
            else
            {
                op.seg_id.segment_index -= (second.seg_id.segment_index - first.seg_id.segment_index - 1);
            }
        }
        return false;
    }

    static void call(Range range, RingCollection& ring_collection)
    {
        typedef split_turn_info<point_type> turn_info;

        typedef std::deque<turn_info> turns_type;
        turns_type turns;

        detail::get_turns::no_interrupt_policy policy;
        geometry::get_turns
            <
                split_calculate_distance_policy
            >(range, turns, policy);

        //report(turns, "intersected");

        // Make operations[0].seg_id always the smallest, to sort properly
        // Also calculate the number of segments in between
        for (typename boost::range_iterator<turns_type>::type
            it = boost::begin(turns);
            it != boost::end(turns);
            ++it)
        {
            turn_info& turn = *it;
            if (turn.operations[0].seg_id.segment_index > turn.operations[1].seg_id.segment_index)
            {
                std::swap(turn.operations[0], turn.operations[1]);
            }
            // ...[1] > ...[0]
            // check count
            int const between1 = turn.operations[1].seg_id.segment_index
                - turn.operations[0].seg_id.segment_index;
            /*
            NOTE: if we would use between2 here, we have to adapt other code as well,
                    such as adaption of the indexes; splitting of the range, etc.
            int between2 = boost::size(range) + turn.operations[0].seg_id.segment_index
                    - turn.operations[1].seg_id.segment_index;
            turn.count_between = (std::min)(between1, between2);
            */

            turn.count_between = between1;
        }
        //report(turns, "swapped");

        std::sort(turns.begin(), turns.end(), sorter<turn_info>());
        //report(turns, "sorted");

        while(turns.size() > 0)
        {
            // Process first turn
            turn_info const& turn = turns.front();

            split_turn_operation<point_type> const& first_op = turn.operations[0];
            split_turn_operation<point_type> const& second_op = turn.operations[1];
            bool do_split = first_op.seg_id.segment_index >= 0
                    && second_op.seg_id.segment_index >= 0;

            if (do_split)
            {
#ifdef BOOST_GEOMETRY_CHECK_SPLIT_RINGS
                ring_type copy = range; // TEMP, for check
#endif
                ring_collection.resize(ring_collection.size() + 1);
                split<ring_tag, Range>::apply(range, ring_collection.back(),
                        turn.operations[0].seg_id, turn.operations[1].seg_id,
                        turn.point);

#ifdef BOOST_GEOMETRY_CHECK_SPLIT_RINGS
                {
                    std::deque<turn_info> splitted_turns;
                    geometry::get_turns
                        <
                            split_calculate_distance_policy
                        >(ring_collection.back(),
                            splitted_turns,
                            detail::get_turns::no_interrupt_policy());

                    if (splitted_turns.size() > 0)
                    {
                        std::cout << "TODO Still intersecting! " << splitted_turns.size() << std::endl;
                        //std::cout << "       " << geometry::wkt(copy) << std::endl;
                        //std::cout << "       " << geometry::wkt(splitted) << std::endl;
                        //report(splitted_turns, "NOT OK");
                        //std::cout << std::endl;
                    }
                }
#endif

            }

            turns.pop_front();

            if (do_split)
            {
                for (typename boost::range_iterator<turns_type>::type
                    rest = boost::begin(turns);
                    rest != boost::end(turns);
                    ++rest)
                {
                    //turn_info copy = turn;
                    if (adapt(rest->operations[0], first_op, second_op)
                        || adapt(rest->operations[1], first_op, second_op))
                    {
                        /**
                        std::cout << " ADAPTED "
                            << copy.operations[0].seg_id.segment_index << "/" << copy.operations[1].seg_id.segment_index
                            << " "
                            << geometry::wkt(copy.point) << std::endl;
                        **/
                    }
                }
            }
            while(turns.size() > 0
                && (turns.front().operations[0].seg_id.segment_index < 0
                    || turns.front().operations[1].seg_id.segment_index < 0))
            {
                turns.pop_front();
            }
        }

        // Add the (possibly untouched) input range
        insert_rings<ring_tag, RingCollection, Range>::apply(ring_collection, range);
    }

public :
    // Copy by value of range is intentional, copy is modified here
    static inline void apply(Range range, RingCollection& ring_collection)
    {
        call(range, ring_collection);
    }
};

template <typename Polygon, typename RingCollection>
struct polygon_split_rings
{
  typedef range_split_rings
        <
            typename ring_type<Polygon>::type,
            RingCollection
        > per_ring;

    static inline void apply(Polygon const& polygon, RingCollection& ring_collection)
    {
        per_ring::apply(exterior_ring(polygon), ring_collection);

        typedef typename boost::range_const_iterator
            <
                typename interior_type<Polygon const>::type
            >::type ring_iterator;

        for (ring_iterator it = boost::begin(interior_rings(polygon));
             it != boost::end(interior_rings(polygon));
             ++it)
        {
            per_ring::apply(*it, ring_collection);
        }
    }
};

}} // namespace detail::split_rings
#endif // DOXYGEN_NO_DETAIL

#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{

template
<
    typename GeometryTag,
    typename Geometry,
    typename RingCollection
>
struct split_rings
{};

template<typename Polygon, typename RingCollection>
struct split_rings<polygon_tag, Polygon, RingCollection>
    : detail::split_rings::polygon_split_rings<Polygon, RingCollection>
{};

template<typename Ring, typename RingCollection>
struct split_rings<ring_tag, Ring, RingCollection>
    : detail::split_rings::range_split_rings<Ring, RingCollection>
{};

} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH

template
<
    typename Geometry,
    typename RingCollection
>
inline void split_rings(Geometry const& geometry, RingCollection& out)
{
    concept::check<Geometry const>();
    concept::check<typename boost::range_value<RingCollection>::type>();

    dispatch::split_rings
    <
        typename tag<Geometry>::type,
        Geometry,
        RingCollection
    >::apply(geometry, out);
}

}} // namespace boost::geometry

#endif // BOOST_GEOMETRY_EXTENSIONS_ALGORITHMS_DETAIL_OVERLAY_SPLIT_RINGS_HPP

max_stars_repo_name: bowlofstew/omim

max_issues_repo_name: bowlofstew/omim

max_forks_repo_name: bowlofstew/omim


text: #include <boost/fusion/adapted/array/category_of_impl.hpp>