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

#include "main.h"
#include "utiltime.h"
#include "bitcoinrpc.h"
#include "wallet.h"
#include "txmempool.h"
#include "txdb-leveldb.h"

using namespace std;

extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry);
extern enum Checkpoints::CPMode CheckpointsMode;

double GetDifficulty(const CBlockIndex* blockindex)
{
    // Floating point number that is a multiple of the minimum difficulty,
    // minimum difficulty = 1.0.
    if (blockindex == NULL)
    {
        if (pindexBest == NULL)
            return 1.0;
        else
            blockindex = GetLastBlockIndex(pindexBest, false);
    }

    int nShift = (blockindex->nBits >> 24) & 0xff;

    double dDiff =
        (double)0x0000ffff / (double)(blockindex->nBits & 0x00ffffff);

    while (nShift < 29)
    {
        dDiff *= 256.0;
        nShift++;
    }
    while (nShift > 29)
    {
        dDiff /= 256.0;
        nShift--;
    }

    return dDiff;
}

double GetPoWMHashPS()
{
    if (pindexBest->nHeight >= LAST_POW_BLOCK)
        return 0;

    int nPoWInterval = 72;
    int64_t nTargetSpacingWorkMin = 30, nTargetSpacingWork = 30;

    CBlockIndex* pindex = pindexGenesisBlock;
    CBlockIndex* pindexPrevWork = pindexGenesisBlock;

    while (pindex)
    {
        if (pindex->IsProofOfWork())
        {
            int64_t nActualSpacingWork = pindex->GetBlockTime() - pindexPrevWork->GetBlockTime();
            nTargetSpacingWork = ((nPoWInterval - 1) * nTargetSpacingWork + nActualSpacingWork + nActualSpacingWork) / (nPoWInterval + 1);
            nTargetSpacingWork = max(nTargetSpacingWork, nTargetSpacingWorkMin);
            pindexPrevWork = pindex;
        }

        pindex = pindex->pnext;
    }

    return GetDifficulty() * 4294.967296 / nTargetSpacingWork;
}

double GetPoSKernelPS()
{
    int nPoSInterval = 72;
    double dStakeKernelsTriedAvg = 0;
    int nStakesHandled = 0, nStakesTime = 0;

    CBlockIndex* pindex = pindexBest;;
    CBlockIndex* pindexPrevStake = NULL;

    while (pindex && nStakesHandled < nPoSInterval)
    {
        if (pindex->IsProofOfStake())
        {
            dStakeKernelsTriedAvg += GetDifficulty(pindex) * 4294967296.0;
            nStakesTime += pindexPrevStake ? (pindexPrevStake->nTime - pindex->nTime) : 0;
            pindexPrevStake = pindex;
            nStakesHandled++;
        }

        pindex = pindex->pprev;
    }

    return nStakesTime ? dStakeKernelsTriedAvg / nStakesTime : 0;
}

UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool fPrintTransactionDetail)
{
    UniValue result(UniValue::VOBJ);
    result.push_back(Pair("hash", block.GetHash().GetHex()));
    CMerkleTx txGen(block.vtx[0]);
    txGen.SetMerkleBranch(&block);
    result.push_back(Pair("confirmations", (int)txGen.GetDepthInMainChain()));
    result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION)));
    result.push_back(Pair("height", blockindex->nHeight));
    result.push_back(Pair("version", block.nVersion));
    result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex()));
    result.push_back(Pair("mint", ValueFromAmount(blockindex->nMint)));
    result.push_back(Pair("time", (int64_t)block.GetBlockTime()));
    result.push_back(Pair("nonce", (uint64_t)block.nNonce));
    result.push_back(Pair("bits", HexBits(block.nBits)));
    result.push_back(Pair("difficulty", GetDifficulty(blockindex)));
    result.push_back(Pair("blocktrust", leftTrim(blockindex->GetBlockTrust().GetHex(), '0')));
    result.push_back(Pair("chaintrust", leftTrim(blockindex->nChainTrust.GetHex(), '0')));
    if (blockindex->pprev)
        result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex()));
    if (blockindex->pnext)
        result.push_back(Pair("nextblockhash", blockindex->pnext->GetBlockHash().GetHex()));

    result.push_back(Pair("flags", strprintf("%s%s", blockindex->IsProofOfStake()? "proof-of-stake" : "proof-of-work", blockindex->GeneratedStakeModifier()? " stake-modifier": "")));
    result.push_back(Pair("proofhash", blockindex->hashProof.GetHex()));
    result.push_back(Pair("entropybit", (int)blockindex->GetStakeEntropyBit()));
    result.push_back(Pair("modifier", strprintf("%016" PRIx64, blockindex->nStakeModifier)));
    result.push_back(Pair("modifierchecksum", strprintf("%08x", blockindex->nStakeModifierChecksum)));
    UniValue txinfo(UniValue::VARR);
    BOOST_FOREACH (const CTransaction& tx, block.vtx)
    {
        if (fPrintTransactionDetail)
        {
            UniValue entry(UniValue::VOBJ);

            entry.push_back(Pair("txid", tx.GetHash().GetHex()));
            TxToJSON(tx, 0, entry);

            txinfo.push_back(entry);
        }
        else
            txinfo.push_back(tx.GetHash().GetHex());
    }

    result.push_back(Pair("tx", txinfo));

    if (block.IsProofOfStake())
        result.push_back(Pair("signature", HexStr(block.vchBlockSig.begin(), block.vchBlockSig.end())));

    return result;
}

UniValue getbestblockhash(const UniValue& params, bool fHelp)
{
    if (fHelp || params.size() != 0)
        throw runtime_error(
            "getbestblockhash\n"
            "Returns the hash of the best block in the longest block chain.");

    return hashBestChain.GetHex();
}

UniValue getblockcount(const UniValue& params, bool fHelp)
{
    if (fHelp || params.size() != 0)
        throw runtime_error(
            "getblockcount\n"
            "Returns the number of blocks in the longest block chain.");

    return nBestHeight;
}

UniValue getdifficulty(const UniValue& params, bool fHelp)
{
    if (fHelp || params.size() != 0)
        throw runtime_error(
            "getdifficulty\n"
            "Returns the difficulty as a multiple of the minimum difficulty.");

    UniValue obj(UniValue::VOBJ);
    obj.push_back(Pair("proof-of-work",        GetDifficulty()));
    obj.push_back(Pair("proof-of-stake",       GetDifficulty(GetLastBlockIndex(pindexBest, true))));
    obj.push_back(Pair("search-interval",      (int)nLastCoinStakeSearchInterval));
    return obj;
}

UniValue settxfee(const UniValue& params, bool fHelp)
{
    if (fHelp || params.size() < 1 || params.size() > 1 || AmountFromValue(params[0]) < MIN_TX_FEE)
        throw runtime_error(
            "settxfee <amount>\n"
            "<amount> is a real and is rounded to the nearest 0.01");

    nTransactionFee = AmountFromValue(params[0]);
    nTransactionFee = (nTransactionFee / CENT) * CENT;  // round to cent

    return true;
}

UniValue getrawmempool(const UniValue& params, bool fHelp)
{
    if (fHelp || params.size() != 0)
        throw runtime_error(
            "getrawmempool\n"
            "Returns all transaction ids in memory pool.");

    vector<uint256> vtxid;
    mempool.queryHashes(vtxid);

    UniValue a(UniValue::VARR);
    BOOST_FOREACH(const uint256& hash, vtxid)
        a.push_back(hash.ToString());

    return a;
}

UniValue getblockhash(const UniValue& params, bool fHelp)
{
    if (fHelp || params.size() != 1)
        throw runtime_error(
            "getblockhash <index>\n"
            "Returns hash of block in best-block-chain at <index>.");

    int nHeight = params[0].get_int();
    if (nHeight < 0 || nHeight > nBestHeight)
        throw runtime_error("Block number out of range.");

    CBlockIndex* pblockindex = FindBlockByHeight(nHeight);
    return pblockindex->phashBlock->GetHex();
}

UniValue getblock(const UniValue& params, bool fHelp)
{
    if (fHelp || params.size() < 1 || params.size() > 2)
        throw runtime_error(
            "getblock <hash> [txinfo]\n"
            "txinfo optional to print more detailed tx info\n"
            "Returns details of a block with given block-hash.");

    std::string strHash = params[0].get_str();
    uint256 hash(strHash);

    if (mapBlockIndex.count(hash) == 0)
        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");

    CBlock block;
    CBlockIndex* pblockindex = mapBlockIndex[hash];
    block.ReadFromDisk(pblockindex, true);

    return blockToJSON(block, pblockindex, params.size() > 1 ? params[1].get_bool() : false);
}

UniValue getblockbynumber(const UniValue& params, bool fHelp)
{
    if (fHelp || params.size() < 1 || params.size() > 2)
        throw runtime_error(
            "getblockbynumber <number> [txinfo]\n"
            "txinfo optional to print more detailed tx info\n"
            "Returns details of a block with given block-number.");

    int nHeight = params[0].get_int();
    if (nHeight < 0 || nHeight > nBestHeight)
        throw runtime_error("Block number out of range.");

    CBlock block;
    CBlockIndex* pblockindex = mapBlockIndex[hashBestChain];
    while (pblockindex->nHeight > nHeight)
        pblockindex = pblockindex->pprev;

    uint256 hash = *pblockindex->phashBlock;

    pblockindex = mapBlockIndex[hash];
    block.ReadFromDisk(pblockindex, true);

    return blockToJSON(block, pblockindex, params.size() > 1 ? params[1].get_bool() : false);
}

// ppcoin: get information of sync-checkpoint
UniValue getcheckpoint(const UniValue& params, bool fHelp)
{
    if (fHelp || params.size() != 0)
        throw runtime_error(
            "getcheckpoint\n"
            "Show info of synchronized checkpoint.\n");

    UniValue result(UniValue::VOBJ);
    CBlockIndex* pindexCheckpoint;

    result.push_back(Pair("synccheckpoint", Checkpoints::hashSyncCheckpoint.ToString().c_str()));
    pindexCheckpoint = mapBlockIndex[Checkpoints::hashSyncCheckpoint];
    result.push_back(Pair("height", pindexCheckpoint->nHeight));
    result.push_back(Pair("timestamp", DateTimeStrFormat(pindexCheckpoint->GetBlockTime()).c_str()));

    // Check that the block satisfies synchronized checkpoint
    if (CheckpointsMode == Checkpoints::STRICT)
        result.push_back(Pair("policy", "strict"));

    if (CheckpointsMode == Checkpoints::ADVISORY)
        result.push_back(Pair("policy", "advisory"));

    if (CheckpointsMode == Checkpoints::PERMISSIVE)
        result.push_back(Pair("policy", "permissive"));

    if (mapArgs.count("-checkpointkey"))
        result.push_back(Pair("checkpointmaster", true));

    return result;
}

UniValue getblockversionstats(const UniValue& params, bool fHelp) {
    if (fHelp || params.size() != 2)
        throw runtime_error(
                "getblockversionstats <version #> <blocks to count>\n"
                        "Return how many of the last n blocks have the version # specified\n");

    int nVersion = params[0].get_int();
    int nBlocks = params[1].get_int();

    int nTotal = 0;
    CBlockIndex* pindex = FindBlockByHeight(nBestHeight - nBlocks + 1);
    while (true) {
        if (pindex->nVersion == nVersion)
            ++nTotal;

        if (pindex->pnext)
            pindex = pindex->pnext;
        else
            break;
    }

    UniValue results(UniValue::VOBJ);
    results.push_back(Pair("total_with_version", nTotal));

    double dPercent = 0;
    if (nBlocks)
        dPercent = static_cast<double>(nTotal) / static_cast<double>(nBlocks) * 100;
    results.push_back(Pair("percent", dPercent));

    return results;
}

UniValue invalidateblock(const UniValue& params, bool fHelp) {
    if (fHelp || params.size() != 1)
        throw runtime_error(
                "invalidateblock <block #>\n"
                        "Reorganize chain back to the block # specified\n");

    int nHeight = params[0].get_int();

    if (nHeight == 0) {
        UniValue result(UniValue::VOBJ);
        result.push_back(Pair("IsInitialBlockDownload", IsInitialBlockDownload()));
        return result;
    }

    if (pindexBest->nHeight < nHeight) {
        throw runtime_error("Specified block number is in the future.");
    }

    CBlockIndex* pindexTarget = NULL;

    for (CBlockIndex* pindex = pindexBest; pindex && pindex->pprev; pindex = pindex->pprev)
    {
        if (fDebug) LogPrintf("invalidateblock : *** processing block %d\n", pindex->nHeight);

        // if (fRequestShutdown || pindex->nHeight < nBestHeight-nCheckDepth)
        //     break;

        CBlock block;
        if (!block.ReadFromDisk(pindex))
            throw runtime_error("block.ReadFromDisk failed");

        if (pindex->nHeight == nHeight) {
            pindexTarget = pindex;
            break;
        } else if (pindex->nHeight < nHeight) {
            break;
        }
    }

    if (pindexTarget == NULL) {
        throw runtime_error("Block not found");
    }

    if (fDebug) LogPrintf("invalidateblock : *** stopped on block %d\n", pindexTarget->nHeight);

    // Reorg back to the fork
    LogPrintf("invalidateblock : *** moving best chain pointer back to block %d\n", pindexTarget->nHeight);
    CBlock block;
    if (!block.ReadFromDisk(pindexTarget))
        throw runtime_error("block.ReadFromDisk failed");

    if (fDebug) LogPrintf("invalidateblock : *** calling SetBestChain...\n");

    CTxDB txdb;
    block.SetBestChain(txdb, pindexTarget);

    return true;
}

UniValue reconsiderblock(const UniValue& params, bool fHelp)
{
    // NTRN TODO - implement this function
    throw runtime_error("Not implemented yet\n");
}
<commit_msg>Remove test code<commit_after>// Copyright (c) 2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Copyright (c) 2017 The Neutron developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "main.h"
#include "utiltime.h"
#include "bitcoinrpc.h"
#include "wallet.h"
#include "txmempool.h"
#include "txdb-leveldb.h"

using namespace std;

extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry);
extern enum Checkpoints::CPMode CheckpointsMode;

double GetDifficulty(const CBlockIndex* blockindex)
{
    // Floating point number that is a multiple of the minimum difficulty,
    // minimum difficulty = 1.0.
    if (blockindex == NULL)
    {
        if (pindexBest == NULL)
            return 1.0;
        else
            blockindex = GetLastBlockIndex(pindexBest, false);
    }

    int nShift = (blockindex->nBits >> 24) & 0xff;

    double dDiff =
        (double)0x0000ffff / (double)(blockindex->nBits & 0x00ffffff);

    while (nShift < 29)
    {
        dDiff *= 256.0;
        nShift++;
    }
    while (nShift > 29)
    {
        dDiff /= 256.0;
        nShift--;
    }

    return dDiff;
}

double GetPoWMHashPS()
{
    if (pindexBest->nHeight >= LAST_POW_BLOCK)
        return 0;

    int nPoWInterval = 72;
    int64_t nTargetSpacingWorkMin = 30, nTargetSpacingWork = 30;

    CBlockIndex* pindex = pindexGenesisBlock;
    CBlockIndex* pindexPrevWork = pindexGenesisBlock;

    while (pindex)
    {
        if (pindex->IsProofOfWork())
        {
            int64_t nActualSpacingWork = pindex->GetBlockTime() - pindexPrevWork->GetBlockTime();
            nTargetSpacingWork = ((nPoWInterval - 1) * nTargetSpacingWork + nActualSpacingWork + nActualSpacingWork) / (nPoWInterval + 1);
            nTargetSpacingWork = max(nTargetSpacingWork, nTargetSpacingWorkMin);
            pindexPrevWork = pindex;
        }

        pindex = pindex->pnext;
    }

    return GetDifficulty() * 4294.967296 / nTargetSpacingWork;
}

double GetPoSKernelPS()
{
    int nPoSInterval = 72;
    double dStakeKernelsTriedAvg = 0;
    int nStakesHandled = 0, nStakesTime = 0;

    CBlockIndex* pindex = pindexBest;;
    CBlockIndex* pindexPrevStake = NULL;

    while (pindex && nStakesHandled < nPoSInterval)
    {
        if (pindex->IsProofOfStake())
        {
            dStakeKernelsTriedAvg += GetDifficulty(pindex) * 4294967296.0;
            nStakesTime += pindexPrevStake ? (pindexPrevStake->nTime - pindex->nTime) : 0;
            pindexPrevStake = pindex;
            nStakesHandled++;
        }

        pindex = pindex->pprev;
    }

    return nStakesTime ? dStakeKernelsTriedAvg / nStakesTime : 0;
}

UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool fPrintTransactionDetail)
{
    UniValue result(UniValue::VOBJ);
    result.push_back(Pair("hash", block.GetHash().GetHex()));
    CMerkleTx txGen(block.vtx[0]);
    txGen.SetMerkleBranch(&block);
    result.push_back(Pair("confirmations", (int)txGen.GetDepthInMainChain()));
    result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION)));
    result.push_back(Pair("height", blockindex->nHeight));
    result.push_back(Pair("version", block.nVersion));
    result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex()));
    result.push_back(Pair("mint", ValueFromAmount(blockindex->nMint)));
    result.push_back(Pair("time", (int64_t)block.GetBlockTime()));
    result.push_back(Pair("nonce", (uint64_t)block.nNonce));
    result.push_back(Pair("bits", HexBits(block.nBits)));
    result.push_back(Pair("difficulty", GetDifficulty(blockindex)));
    result.push_back(Pair("blocktrust", leftTrim(blockindex->GetBlockTrust().GetHex(), '0')));
    result.push_back(Pair("chaintrust", leftTrim(blockindex->nChainTrust.GetHex(), '0')));
    if (blockindex->pprev)
        result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex()));
    if (blockindex->pnext)
        result.push_back(Pair("nextblockhash", blockindex->pnext->GetBlockHash().GetHex()));

    result.push_back(Pair("flags", strprintf("%s%s", blockindex->IsProofOfStake()? "proof-of-stake" : "proof-of-work", blockindex->GeneratedStakeModifier()? " stake-modifier": "")));
    result.push_back(Pair("proofhash", blockindex->hashProof.GetHex()));
    result.push_back(Pair("entropybit", (int)blockindex->GetStakeEntropyBit()));
    result.push_back(Pair("modifier", strprintf("%016" PRIx64, blockindex->nStakeModifier)));
    result.push_back(Pair("modifierchecksum", strprintf("%08x", blockindex->nStakeModifierChecksum)));
    UniValue txinfo(UniValue::VARR);
    BOOST_FOREACH (const CTransaction& tx, block.vtx)
    {
        if (fPrintTransactionDetail)
        {
            UniValue entry(UniValue::VOBJ);

            entry.push_back(Pair("txid", tx.GetHash().GetHex()));
            TxToJSON(tx, 0, entry);

            txinfo.push_back(entry);
        }
        else
            txinfo.push_back(tx.GetHash().GetHex());
    }

    result.push_back(Pair("tx", txinfo));

    if (block.IsProofOfStake())
        result.push_back(Pair("signature", HexStr(block.vchBlockSig.begin(), block.vchBlockSig.end())));

    return result;
}

UniValue getbestblockhash(const UniValue& params, bool fHelp)
{
    if (fHelp || params.size() != 0)
        throw runtime_error(
            "getbestblockhash\n"
            "Returns the hash of the best block in the longest block chain.");

    return hashBestChain.GetHex();
}

UniValue getblockcount(const UniValue& params, bool fHelp)
{
    if (fHelp || params.size() != 0)
        throw runtime_error(
            "getblockcount\n"
            "Returns the number of blocks in the longest block chain.");

    return nBestHeight;
}

UniValue getdifficulty(const UniValue& params, bool fHelp)
{
    if (fHelp || params.size() != 0)
        throw runtime_error(
            "getdifficulty\n"
            "Returns the difficulty as a multiple of the minimum difficulty.");

    UniValue obj(UniValue::VOBJ);
    obj.push_back(Pair("proof-of-work",        GetDifficulty()));
    obj.push_back(Pair("proof-of-stake",       GetDifficulty(GetLastBlockIndex(pindexBest, true))));
    obj.push_back(Pair("search-interval",      (int)nLastCoinStakeSearchInterval));
    return obj;
}

UniValue settxfee(const UniValue& params, bool fHelp)
{
    if (fHelp || params.size() < 1 || params.size() > 1 || AmountFromValue(params[0]) < MIN_TX_FEE)
        throw runtime_error(
            "settxfee <amount>\n"
            "<amount> is a real and is rounded to the nearest 0.01");

    nTransactionFee = AmountFromValue(params[0]);
    nTransactionFee = (nTransactionFee / CENT) * CENT;  // round to cent

    return true;
}

UniValue getrawmempool(const UniValue& params, bool fHelp)
{
    if (fHelp || params.size() != 0)
        throw runtime_error(
            "getrawmempool\n"
            "Returns all transaction ids in memory pool.");

    vector<uint256> vtxid;
    mempool.queryHashes(vtxid);

    UniValue a(UniValue::VARR);
    BOOST_FOREACH(const uint256& hash, vtxid)
        a.push_back(hash.ToString());

    return a;
}

UniValue getblockhash(const UniValue& params, bool fHelp)
{
    if (fHelp || params.size() != 1)
        throw runtime_error(
            "getblockhash <index>\n"
            "Returns hash of block in best-block-chain at <index>.");

    int nHeight = params[0].get_int();
    if (nHeight < 0 || nHeight > nBestHeight)
        throw runtime_error("Block number out of range.");

    CBlockIndex* pblockindex = FindBlockByHeight(nHeight);
    return pblockindex->phashBlock->GetHex();
}

UniValue getblock(const UniValue& params, bool fHelp)
{
    if (fHelp || params.size() < 1 || params.size() > 2)
        throw runtime_error(
            "getblock <hash> [txinfo]\n"
            "txinfo optional to print more detailed tx info\n"
            "Returns details of a block with given block-hash.");

    std::string strHash = params[0].get_str();
    uint256 hash(strHash);

    if (mapBlockIndex.count(hash) == 0)
        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");

    CBlock block;
    CBlockIndex* pblockindex = mapBlockIndex[hash];
    block.ReadFromDisk(pblockindex, true);

    return blockToJSON(block, pblockindex, params.size() > 1 ? params[1].get_bool() : false);
}

UniValue getblockbynumber(const UniValue& params, bool fHelp)
{
    if (fHelp || params.size() < 1 || params.size() > 2)
        throw runtime_error(
            "getblockbynumber <number> [txinfo]\n"
            "txinfo optional to print more detailed tx info\n"
            "Returns details of a block with given block-number.");

    int nHeight = params[0].get_int();
    if (nHeight < 0 || nHeight > nBestHeight)
        throw runtime_error("Block number out of range.");

    CBlock block;
    CBlockIndex* pblockindex = mapBlockIndex[hashBestChain];
    while (pblockindex->nHeight > nHeight)
        pblockindex = pblockindex->pprev;

    uint256 hash = *pblockindex->phashBlock;

    pblockindex = mapBlockIndex[hash];
    block.ReadFromDisk(pblockindex, true);

    return blockToJSON(block, pblockindex, params.size() > 1 ? params[1].get_bool() : false);
}

// ppcoin: get information of sync-checkpoint
UniValue getcheckpoint(const UniValue& params, bool fHelp)
{
    if (fHelp || params.size() != 0)
        throw runtime_error(
            "getcheckpoint\n"
            "Show info of synchronized checkpoint.\n");

    UniValue result(UniValue::VOBJ);
    CBlockIndex* pindexCheckpoint;

    result.push_back(Pair("synccheckpoint", Checkpoints::hashSyncCheckpoint.ToString().c_str()));
    pindexCheckpoint = mapBlockIndex[Checkpoints::hashSyncCheckpoint];
    result.push_back(Pair("height", pindexCheckpoint->nHeight));
    result.push_back(Pair("timestamp", DateTimeStrFormat(pindexCheckpoint->GetBlockTime()).c_str()));

    // Check that the block satisfies synchronized checkpoint
    if (CheckpointsMode == Checkpoints::STRICT)
        result.push_back(Pair("policy", "strict"));

    if (CheckpointsMode == Checkpoints::ADVISORY)
        result.push_back(Pair("policy", "advisory"));

    if (CheckpointsMode == Checkpoints::PERMISSIVE)
        result.push_back(Pair("policy", "permissive"));

    if (mapArgs.count("-checkpointkey"))
        result.push_back(Pair("checkpointmaster", true));

    return result;
}

UniValue getblockversionstats(const UniValue& params, bool fHelp) {
    if (fHelp || params.size() != 2)
        throw runtime_error(
                "getblockversionstats <version #> <blocks to count>\n"
                        "Return how many of the last n blocks have the version # specified\n");

    int nVersion = params[0].get_int();
    int nBlocks = params[1].get_int();

    int nTotal = 0;
    CBlockIndex* pindex = FindBlockByHeight(nBestHeight - nBlocks + 1);
    while (true) {
        if (pindex->nVersion == nVersion)
            ++nTotal;

        if (pindex->pnext)
            pindex = pindex->pnext;
        else
            break;
    }

    UniValue results(UniValue::VOBJ);
    results.push_back(Pair("total_with_version", nTotal));

    double dPercent = 0;
    if (nBlocks)
        dPercent = static_cast<double>(nTotal) / static_cast<double>(nBlocks) * 100;
    results.push_back(Pair("percent", dPercent));

    return results;
}

UniValue invalidateblock(const UniValue& params, bool fHelp) {
    if (fHelp || params.size() != 1)
        throw runtime_error(
                "invalidateblock <block #>\n"
                        "Reorganize chain back to the block # specified\n");

    int nHeight = params[0].get_int();

    if (pindexBest->nHeight < nHeight) {
        throw runtime_error("Specified block number is in the future.");
    }

    CBlockIndex* pindexTarget = NULL;

    for (CBlockIndex* pindex = pindexBest; pindex && pindex->pprev; pindex = pindex->pprev)
    {
        if (fDebug) LogPrintf("invalidateblock : *** processing block %d\n", pindex->nHeight);

        // if (fRequestShutdown || pindex->nHeight < nBestHeight-nCheckDepth)
        //     break;

        CBlock block;
        if (!block.ReadFromDisk(pindex))
            throw runtime_error("block.ReadFromDisk failed");

        if (pindex->nHeight == nHeight) {
            pindexTarget = pindex;
            break;
        } else if (pindex->nHeight < nHeight) {
            break;
        }
    }

    if (pindexTarget == NULL) {
        throw runtime_error("Block not found");
    }

    if (fDebug) LogPrintf("invalidateblock : *** stopped on block %d\n", pindexTarget->nHeight);

    // Reorg back to the fork
    LogPrintf("invalidateblock : *** moving best chain pointer back to block %d\n", pindexTarget->nHeight);
    CBlock block;
    if (!block.ReadFromDisk(pindexTarget))
        throw runtime_error("block.ReadFromDisk failed");

    if (fDebug) LogPrintf("invalidateblock : *** calling SetBestChain...\n");

    CTxDB txdb;
    block.SetBestChain(txdb, pindexTarget);

    return true;
}

UniValue reconsiderblock(const UniValue& params, bool fHelp)
{
    // NTRN TODO - implement this function
    throw runtime_error("Not implemented yet\n");
}
<|endoftext|>


<commit_before>#include <Rcpp11>
#include <iostream>
#include <math.h>
#include <numeric>

using namespace Rcpp;
using namespace std;

double loglik(NumericVector eta, NumericVector y, NumericVector weights, Function linkinv, Function devfun)
{
    // Compute some values we need for the logLik computation:
    NumericVector mu = linkinv(eta);

    // Calculate the actual log likelihood:
    NumericVector dev_resids = devfun(y, mu, weights);
    double ll = sum(dev_resids);
    return(ll);
}

void gradCalc(NumericVector eta, NumericVector y, NumericVector weights, Function linkinv, NumericVector ldot)
{
    // Compute some values we need for the gradient computation:
    NumericVector mu = linkinv(eta);
    double sumw = sum(weights);

    // Calculate the actual log likelihood:
    ldot = weights * (mu-y) / sumw;
}

void rcppLinSolver(NumericMatrix X, NumericVector y, NumericVector w, NumericVector adaweights, int nrow, int ncol, int numGroup, NumericMatrix beta, Function linkinv, Function devfun, IntegerVector rangeGroupInd, IntegerVector groupLen, NumericVector lambda, int step, int innerIter, double thresh, NumericVector ldot, NumericVector nullBeta, double gamma, NumericVector eta, IntegerVector betaIsZero, int& groupChange, IntegerVector isActive, IntegerVector useGroup, int reset)
{
    NumericVector theta(ncol);
    int startInd = 0;
    double zeroCheck = 0;
    double check = 0;
    int count = 0;
    double diff = 1;
    double norm = 0;
    double uOp = 0;
    double Lnew = 0;
    double Lold = 0;
    double sqNormDelta = 0;
    double iProd = 0;
    NumericVector etaNew(nrow);
    NumericVector etaNull(nrow);
    NumericVector var(nrow);

    for(int i = 0; i < numGroup; i++)
    {
        if(useGroup[i] == 1)
        {
            startInd = rangeGroupInd[i];

            // Setting up null residuals calc to check if group is 0
            // Null residuals means the coefficients of group i are set to zero before computing residuals.
            for(int k = 0; k < nrow; k++)
            {
                etaNull[k] = eta[k];
                for(int j = startInd; j < rangeGroupInd[i] + groupLen[i]; j++)
                {
                    etaNull[k] = etaNull[k] - X[k + nrow * j] * beta[step*ncol + j];
                }
            }
            gradCalc(etaNull, y, w, linkinv, ldot);

            // Now compute the correlation of this group with the null residuals.
            NumericVector grad(groupLen[i]);
            for(int j = 0; j < groupLen[i]; j++)
            {
                grad[j] = 0;
                for(int k = 0; k < nrow; k++)
                {
                    grad[j] = grad[j] + X[k + nrow * (j + rangeGroupInd[i])] * ldot[k];
                }
            }
            zeroCheck = sum(pow(grad,2));

            // Is this group's correlation with the null residuals smaller than the threshold?
            // If so, set the coefficients of the group to zero.
            if(zeroCheck <= pow(adaweights[i],2)*pow(lambda[step],2)*groupLen[i])
            {
                if(betaIsZero[i] == 0)
                {
                    for(int k = 0; k < nrow; k++)
                    {
                        for(int j = rangeGroupInd[i]; j < rangeGroupInd[i] + groupLen[i]; j++)
                        {
                            eta[k] = eta[k] - X[k + nrow * j] * beta[step*ncol + j];
                        }
                    }
                }
                betaIsZero[i] = 1;
                for(int j = 0; j < groupLen[i]; j++)
                {
                    beta[step*ncol + j + rangeGroupInd[i]] = 0;
                }
            }
            else // The group's coefficients are nonzero
            {
                if(isActive[i] == 0)
                {
                    groupChange = 1;
                }
                isActive[i] = 1;

                // Hold the previous values of the coefficients
                for(int k = 0; k < ncol; k++)
                {
                    theta[k] = beta[step*ncol + k];
                }

                betaIsZero[i] = 0;
                NumericVector z(groupLen[i]);
                NumericVector U(groupLen[i]);
                NumericVector delta(groupLen[i]);
                NumericVector betaNew(ncol);

                count = 0;
                check = 100000;
                double t = 1;

                // Until convergence, iteratively recompute the group's coefficients:
                while(count <= innerIter && check > thresh)
                {
                    count++;

                    // Compute the working residuals (i.e. residuals at the current coefficient values)
                    gradCalc(eta, y, w, linkinv, ldot);

                    // Compute the group's correlation with the working residuals
                    for(int j = 0; j < groupLen[i]; j++)
                    {
                        grad[j] = 0;
                        for(int k = 0; k < nrow; k++)
                        {
                            grad[j] = grad[j] + X[k + nrow * (j + rangeGroupInd[i])] * ldot[k];
                        }
                    }

                    // Compute the log likelihood for the previous coefficient iteration
                    Lold = loglik(eta, y, w, linkinv, devfun);

                    // Back-tracking to optimize the step size for gradient descent:
                    diff = -1;
                    int optim_steps = 0;
                    while(diff < 0)
                    {
                        optim_steps++;

                        for(int j = 0; j < groupLen[i]; j++)
                        {
                            z[j] = beta[step*ncol + j + rangeGroupInd[i]] - t * grad[j];
                        }

                        norm = sum(pow(z, 2));
                        norm = sqrt(norm);

                        if(norm != 0){
                            uOp = (1 - adaweights[i]*lambda[step]*sqrt(double(groupLen[i]))*t/norm);   //Or not?
                        }
                        else{uOp = 0;}

                        if(uOp < 0)
                        {
                            uOp = 0;
                        }

                        for(int j = 0; j < groupLen[i]; j++)
                        {
                            U[j] = uOp*z[j];
                            delta[j] = U[j] - beta[step*ncol + j + rangeGroupInd[i]];
                        }

                        // Setting up betaNew and etaNew in direction of Grad for descent momentum
                        for(int k = 0; k < nrow; k++)
                        {
                            etaNew[k] = eta[k];
                            for(int j = 0; j < groupLen[i]; j++)
                            {
                                etaNew[k] = etaNew[k] + delta[j] * X[k + nrow*(rangeGroupInd[i] + j)];
                            }
                        }

                        // Compute log likelihood for the working coefficients
                        Lnew = loglik(etaNew, y, w, linkinv, devfun);

                        sqNormDelta = sum(pow(delta, 2));
                        iProd = sum(grad * delta);

                        // Check whether the working coefficients reduce the log likelihood
                        diff = Lold - Lnew + iProd + 0.5/t * sqNormDelta;

                        // Reduce the step size for the next iteration
                        t = t * gamma;
                    }
                    t = t / gamma;

                    check = 0;

                    for(int j = 0; j < groupLen[i]; j++)
                    {
                        // Check the difference between iterations of the coefficients
                        check = check + fabs(theta[j + rangeGroupInd[i]] - U[j]);

                        // Calculate the null etas (i.e. the etas when group i's coefficients are zero)
                        for(int k = 0; k < nrow; k++)
                        {
                            eta[k] = eta[k] - X[k + nrow * (j + rangeGroupInd[i])]*beta[step*ncol + j + rangeGroupInd[i]];
                        }

                        //Apply Nesterov acceleration to calculate the new coefficient values:
                        beta[step*ncol + j + rangeGroupInd[i]] = U[j] + count/(count+3) * (U[j] - theta[j + rangeGroupInd[i]]);
                        theta[j + rangeGroupInd[i]] = U[j];

                        // Compute the new values of eta after iterating group i's coefficients.
                        for(int k = 0; k < nrow; k++)
                        {
                            eta[k] = eta[k] + X[k + nrow * (j + rangeGroupInd[i])]*beta[step*ncol + j + rangeGroupInd[i]];
                        }
                    }
                }
            }
        }
    }
}

// [[Rcpp::export]]
int rcppLinNest(NumericMatrix X, NumericVector y, NumericVector w, NumericVector adaweights, Function linkinv, Function devfun, int nrow, int ncol, int numGroup, IntegerVector rangeGroupInd, IntegerVector groupLen, NumericVector lambda, NumericMatrix beta, int innerIter, int outerIter, double thresh, double outerThresh, NumericVector eta, double gamma, IntegerVector betaIsZero, int reset)
{
    NumericVector prob(nrow);
    NumericVector nullBeta(ncol);
    int n = nrow;
    int p = ncol;
    NumericVector ldot(n);
    IntegerVector isActive(numGroup);
    IntegerVector useGroup(numGroup);
    IntegerVector tempIsActive(numGroup);
    int nlam = lambda.size();

    for (int step=0; step<nlam; step++)
    {
        for(int i=0; i<numGroup; i++)
        {
            isActive[i] = 0;
            useGroup[i] = 1;
        }

        //Copy the most recent betas into position
        if (step>0)
        {
            int l = step - 1;

            for (int i=0; i<ncol; i++)
            {
                beta[step*ncol + i] = beta[l*ncol + i];
            }
        }

        // outer most loop creating response etc...
        int outermostCounter = 0;
        double outermostCheck = 100000;
        NumericVector outerOldBeta(p);
        int groupChange = 1;

        while(groupChange == 1)
        {
            groupChange = 0;

            rcppLinSolver(X, y, w, adaweights, nrow, ncol, numGroup, beta, linkinv, devfun, rangeGroupInd, groupLen, lambda, step, innerIter, thresh, ldot, nullBeta, gamma, eta, betaIsZero, groupChange, isActive, useGroup, reset);

            while(outermostCounter < outerIter && outermostCheck > outerThresh)
            {
                outermostCounter ++;
                for(int i=0; i<p; i++)
                {
                    outerOldBeta[i] = beta[step*ncol + i];
                }

                for(int i=0; i<numGroup; i++)
                {
                    tempIsActive[i] = isActive[i];
                }

                rcppLinSolver(X, y, w, adaweights, nrow, ncol, numGroup, beta, linkinv, devfun, rangeGroupInd, groupLen, lambda, step, innerIter, thresh, ldot, nullBeta, gamma, eta, betaIsZero, groupChange, isActive, tempIsActive, reset);

                outermostCheck = 0;
                for(int i=0; i<p; i++)
                {
                    outermostCheck = outermostCheck + fabs(outerOldBeta[i] - beta[step*ncol + i]);
                }
                outermostCheck = outermostCheck / abs(sum(outerOldBeta));
            }
        }
    }
    return 1;
}
<commit_msg>added some "delete"s in hopes to improving stability<commit_after>#include <Rcpp11>
#include <iostream>
#include <math.h>
#include <numeric>

using namespace Rcpp;
using namespace std;

double loglik(NumericVector eta, NumericVector y, NumericVector weights, Function linkinv, Function devfun)
{
    // Compute some values we need for the logLik computation:
    NumericVector mu = linkinv(eta);

    // Calculate the actual log likelihood:
    NumericVector dev_resids = devfun(y, mu, weights);
    double ll = sum(dev_resids);

    delete mu;
    delete dev_resids;

    return(ll);
}

void gradCalc(NumericVector eta, NumericVector y, NumericVector weights, Function linkinv, NumericVector ldot)
{
    // Compute some values we need for the gradient computation:
    NumericVector mu = linkinv(eta);
    double sumw = sum(weights);

    // Calculate the actual log likelihood:
    ldot = weights * (mu-y) / sumw;

    delete mu;
}

void rcppLinSolver(NumericMatrix X, NumericVector y, NumericVector w, NumericVector adaweights, int nrow, int ncol, int numGroup, NumericMatrix beta, Function linkinv, Function devfun, IntegerVector rangeGroupInd, IntegerVector groupLen, NumericVector lambda, int step, int innerIter, double thresh, NumericVector ldot, NumericVector nullBeta, double gamma, NumericVector eta, IntegerVector betaIsZero, int& groupChange, IntegerVector isActive, IntegerVector useGroup, int reset)
{
    NumericVector theta(ncol);
    int startInd = 0;
    double zeroCheck = 0;
    double check = 0;
    int count = 0;
    double diff = 1;
    double norm = 0;
    double uOp = 0;
    double Lnew = 0;
    double Lold = 0;
    double sqNormDelta = 0;
    double iProd = 0;
    NumericVector etaNew(nrow);
    NumericVector etaNull(nrow);
    NumericVector var(nrow);

    for(int i = 0; i < numGroup; i++)
    {
        if(useGroup[i] == 1)
        {
            startInd = rangeGroupInd[i];

            // Setting up null residuals calc to check if group is 0
            // Null residuals means the coefficients of group i are set to zero before computing residuals.
            for(int k = 0; k < nrow; k++)
            {
                etaNull[k] = eta[k];
                for(int j = startInd; j < rangeGroupInd[i] + groupLen[i]; j++)
                {
                    etaNull[k] = etaNull[k] - X[k + nrow * j] * beta[step*ncol + j];
                }
            }
            gradCalc(etaNull, y, w, linkinv, ldot);

            // Now compute the correlation of this group with the null residuals.
            NumericVector grad(groupLen[i]);
            for(int j = 0; j < groupLen[i]; j++)
            {
                grad[j] = 0;
                for(int k = 0; k < nrow; k++)
                {
                    grad[j] = grad[j] + X[k + nrow * (j + rangeGroupInd[i])] * ldot[k];
                }
            }
            zeroCheck = sum(pow(grad,2));

            // Is this group's correlation with the null residuals smaller than the threshold?
            // If so, set the coefficients of the group to zero.
            if(zeroCheck <= pow(adaweights[i],2)*pow(lambda[step],2)*groupLen[i])
            {
                if(betaIsZero[i] == 0)
                {
                    for(int k = 0; k < nrow; k++)
                    {
                        for(int j = rangeGroupInd[i]; j < rangeGroupInd[i] + groupLen[i]; j++)
                        {
                            eta[k] = eta[k] - X[k + nrow * j] * beta[step*ncol + j];
                        }
                    }
                }
                betaIsZero[i] = 1;
                for(int j = 0; j < groupLen[i]; j++)
                {
                    beta[step*ncol + j + rangeGroupInd[i]] = 0;
                }
            }
            else // The group's coefficients are nonzero
            {
                if(isActive[i] == 0)
                {
                    groupChange = 1;
                }
                isActive[i] = 1;

                // Hold the previous values of the coefficients
                for(int k = 0; k < ncol; k++)
                {
                    theta[k] = beta[step*ncol + k];
                }

                betaIsZero[i] = 0;
                NumericVector z(groupLen[i]);
                NumericVector U(groupLen[i]);
                NumericVector delta(groupLen[i]);
                NumericVector betaNew(ncol);

                count = 0;
                check = 100000;
                double t = 1;

                // Until convergence, iteratively recompute the group's coefficients:
                while(count <= innerIter && check > thresh)
                {
                    count++;

                    // Compute the working residuals (i.e. residuals at the current coefficient values)
                    gradCalc(eta, y, w, linkinv, ldot);

                    // Compute the group's correlation with the working residuals
                    for(int j = 0; j < groupLen[i]; j++)
                    {
                        grad[j] = 0;
                        for(int k = 0; k < nrow; k++)
                        {
                            grad[j] = grad[j] + X[k + nrow * (j + rangeGroupInd[i])] * ldot[k];
                        }
                    }

                    // Compute the log likelihood for the previous coefficient iteration
                    Lold = loglik(eta, y, w, linkinv, devfun);

                    // Back-tracking to optimize the step size for gradient descent:
                    diff = -1;
                    int optim_steps = 0;
                    while(diff < 0)
                    {
                        optim_steps++;

                        for(int j = 0; j < groupLen[i]; j++)
                        {
                            z[j] = beta[step*ncol + j + rangeGroupInd[i]] - t * grad[j];
                        }

                        norm = sum(pow(z, 2));
                        norm = sqrt(norm);

                        if(norm != 0){
                            uOp = (1 - adaweights[i]*lambda[step]*sqrt(double(groupLen[i]))*t/norm);   //Or not?
                        }
                        else{uOp = 0;}

                        if(uOp < 0)
                        {
                            uOp = 0;
                        }

                        for(int j = 0; j < groupLen[i]; j++)
                        {
                            U[j] = uOp*z[j];
                            delta[j] = U[j] - beta[step*ncol + j + rangeGroupInd[i]];
                        }

                        // Setting up betaNew and etaNew in direction of Grad for descent momentum
                        for(int k = 0; k < nrow; k++)
                        {
                            etaNew[k] = eta[k];
                            for(int j = 0; j < groupLen[i]; j++)
                            {
                                etaNew[k] = etaNew[k] + delta[j] * X[k + nrow*(rangeGroupInd[i] + j)];
                            }
                        }

                        // Compute log likelihood for the working coefficients
                        Lnew = loglik(etaNew, y, w, linkinv, devfun);

                        sqNormDelta = sum(pow(delta, 2));
                        iProd = sum(grad * delta);

                        // Check whether the working coefficients reduce the log likelihood
                        diff = Lold - Lnew + iProd + 0.5/t * sqNormDelta;

                        // Reduce the step size for the next iteration
                        t = t * gamma;
                    }
                    t = t / gamma;

                    check = 0;

                    for(int j = 0; j < groupLen[i]; j++)
                    {
                        // Check the difference between iterations of the coefficients
                        check = check + fabs(theta[j + rangeGroupInd[i]] - U[j]);

                        // Calculate the null etas (i.e. the etas when group i's coefficients are zero)
                        for(int k = 0; k < nrow; k++)
                        {
                            eta[k] = eta[k] - X[k + nrow * (j + rangeGroupInd[i])]*beta[step*ncol + j + rangeGroupInd[i]];
                        }

                        //Apply Nesterov acceleration to calculate the new coefficient values:
                        beta[step*ncol + j + rangeGroupInd[i]] = U[j] + count/(count+3) * (U[j] - theta[j + rangeGroupInd[i]]);
                        theta[j + rangeGroupInd[i]] = U[j];

                        // Compute the new values of eta after iterating group i's coefficients.
                        for(int k = 0; k < nrow; k++)
                        {
                            eta[k] = eta[k] + X[k + nrow * (j + rangeGroupInd[i])]*beta[step*ncol + j + rangeGroupInd[i]];
                        }
                    }
                }
                delete z;
                delete U;
                delete delta;
                delete betaNew;
            }
            delete grad;
        }
    }

    delete theta;
    delete etaNew;
    delete etaNull;
    delete var;
}

// [[Rcpp::export]]
int rcppLinNest(NumericMatrix X, NumericVector y, NumericVector w, NumericVector adaweights, Function linkinv, Function devfun, int nrow, int ncol, int numGroup, IntegerVector rangeGroupInd, IntegerVector groupLen, NumericVector lambda, NumericMatrix beta, int innerIter, int outerIter, double thresh, double outerThresh, NumericVector eta, double gamma, IntegerVector betaIsZero, int reset)
{
    NumericVector prob(nrow);
    NumericVector nullBeta(ncol);
    int n = nrow;
    int p = ncol;
    NumericVector ldot(n);
    IntegerVector isActive(numGroup);
    IntegerVector useGroup(numGroup);
    IntegerVector tempIsActive(numGroup);
    int nlam = lambda.size();

    for (int step=0; step<nlam; step++)
    {
        for(int i=0; i<numGroup; i++)
        {
            isActive[i] = 0;
            useGroup[i] = 1;
        }

        //Copy the most recent betas into position
        if (step>0)
        {
            int l = step - 1;

            for (int i=0; i<ncol; i++)
            {
                beta[step*ncol + i] = beta[l*ncol + i];
            }
        }

        // outer most loop creating response etc...
        int outermostCounter = 0;
        double outermostCheck = 100000;
        NumericVector outerOldBeta(p);
        int groupChange = 1;

        while(groupChange == 1)
        {
            groupChange = 0;

            rcppLinSolver(X, y, w, adaweights, nrow, ncol, numGroup, beta, linkinv, devfun, rangeGroupInd, groupLen, lambda, step, innerIter, thresh, ldot, nullBeta, gamma, eta, betaIsZero, groupChange, isActive, useGroup, reset);

            while(outermostCounter < outerIter && outermostCheck > outerThresh)
            {
                outermostCounter ++;
                for(int i=0; i<p; i++)
                {
                    outerOldBeta[i] = beta[step*ncol + i];
                }

                for(int i=0; i<numGroup; i++)
                {
                    tempIsActive[i] = isActive[i];
                }

                rcppLinSolver(X, y, w, adaweights, nrow, ncol, numGroup, beta, linkinv, devfun, rangeGroupInd, groupLen, lambda, step, innerIter, thresh, ldot, nullBeta, gamma, eta, betaIsZero, groupChange, isActive, tempIsActive, reset);

                outermostCheck = 0;
                for(int i=0; i<p; i++)
                {
                    outermostCheck = outermostCheck + fabs(outerOldBeta[i] - beta[step*ncol + i]);
                }
                outermostCheck = outermostCheck / abs(sum(outerOldBeta));
            }
        }
        delete outerOldBeta;
    }

    delete prob;
    delete nullBeta;
    delete ldot;
    delete isActive;
    delete useGroup;
    delete tempIsActive;

    return 1;
}
<|endoftext|>


<commit_before>#ifndef _C4_RYML_DEF_HPP_
#define _C4_RYML_DEF_HPP_

#include "./span.hpp"

namespace c4 {
namespace yml {

#define _c4this  (static_cast< Writer      * >(this))
#define _c4cthis (static_cast< Writer const* >(this))

template< class Writer >
span Emitter< Writer >::emit(NodeRef const& n, bool error_on_excess)
{
    this->_visit(n);
    span result = _c4this->_get(error_on_excess);
    return result;
}

template< class Writer >
size_t Emitter< Writer >::tell() const
{
    return _c4cthis->m_pos;
}

template< class Writer >
void Emitter< Writer >::seek(size_t p)
{
    _c4this->m_pos = p;
}

template< class Writer >
size_t Emitter< Writer >::_visit(NodeRef const& n, size_t ilevel)
{
    if(n.is_stream())
    {
        ;
    }
    _do_visit(n, ilevel);
    if(n.is_stream())
    {
        _write(cspan("...\n", 4));
    }
    return _c4this->m_pos;
}

/** @todo this function is too complex. break it down into manageable pieces */
template< class Writer >
void Emitter< Writer >::_do_visit(NodeRef const& n, size_t ilevel, bool indent)
{
    RepC ind{' ', 2 * size_t(indent) * ilevel};

    if(n.is_doc())
    {
        _write(cspan("---\n", 4));
    }
    else if(n.is_keyval())
    {
        C4_ASSERT(n.has_parent());
        if( ! n.has_anchor())
        {
            _write(ind, n.keysc(), cspan(": ", 2), n.valsc(), '\n');
        }
        else
        {
            _write(ind, n.keysc(), cspan(": ", 2), AnchorScalar(n), '\n');
        }
    }
    else if(n.is_val())
    {
        C4_ASSERT(n.has_parent());
        if( ! n.has_anchor())
        {
            _write(ind, cspan(": ", 2), n.valsc(), '\n');
        }
        else
        {
            _write(ind, cspan(": ", 2), AnchorScalar(n), '\n');
        }
    }
    else if(n.is_container() && ! n.is_root())
    {
        C4_ASSERT(n.parent_is_map() || n.parent_is_seq());
        C4_ASSERT(n.is_map() || n.is_seq());

        if(n.parent_is_seq())
        {
            C4_ASSERT( ! n.has_key());
            _write(ind, cspan("- ", 2));
            if(n.has_val_tag())
            {
                _write(n.val_tag(), ' ');
            }
        }
        else if(n.parent_is_map())
        {
            C4_ASSERT(n.has_key());
            _write(ind, n.keysc(), ':');
            if(n.has_val_tag())
            {
                _write(' ', n.val_tag());
            }
        }
        else
        {
            C4_ERROR("tree error");
        }
        if(n.has_anchor())
        {
            _write(' ', '&', n.anchor());
        }

        if(n.has_children())
        {
            if(n.is_seq())
            {
                if(n.parent_is_map())
                {
                    _write('\n');
                    indent = true;
                }
                else
                {
                    // do not indent the first child, as it will be written on the same line
                    indent = false;
                }
            }
            else if(n.is_map())
            {
                if(n.parent_is_seq())
                {
                    // do not indent the first child, as it will be written on the same line
                    indent = false;
                }
                else
                {
                    _write('\n');
                    indent = true;
                }
            }
            else
            {
                C4_ERROR("invalid node");
            }
        }
        else
        {
            if(n.parent_is_map())
            {
                _write(' ');
            }

            if(n.is_seq())
            {
                _write(cspan("[]\n", 3));
            }
            else if(n.is_map())
            {
                _write(cspan("{}\n", 3));
            }
        }
    }
    else if(n.is_container() && n.is_root())
    {
        if( ! n.has_children())
        {
            if(n.is_seq())
            {
                _write(cspan("[]\n", 3));
            }
            else if(n.is_map())
            {
                _write(cspan("{}\n", 3));
            }
        }
    }

    size_t next_level = ilevel + 1;
    if(n.is_stream() || n.is_doc() || n.is_root())
    {
        next_level = ilevel; // do not indent at top level
    }

    for(auto ch : n.children())
    {
        _do_visit(ch, next_level, indent);
        indent = true;
    }
}

template< class Writer >
void Emitter< Writer >::_write_one(AnchorScalar const& sc)
{
    if( ! sc.tag.empty())
    {
        _c4this->_do_write(sc.tag);
        _c4this->_do_write(' ');
    }
    if( ! sc.anchor.empty())
    {
        _c4this->_do_write('&');
        _c4this->_do_write(sc.anchor);
        _c4this->_do_write(' ');
    }

    _write_scalar(sc.scalar);
}

template< class Writer >
void Emitter< Writer >::_write_one(NodeScalar const& sc)
{
    if( ! sc.tag.empty())
    {
        _c4this->_do_write(sc.tag);
        _c4this->_do_write(' ');
    }

    _write_scalar(sc.scalar);
}

template< class Writer >
void Emitter< Writer >::_write_scalar(cspan const& s)
{
    const bool no_dquotes = s.first_of( '"') == npos;
    const bool no_squotes = s.first_of('\'') == npos;
    const bool no_newline = s.first_of('\n') == npos;

    if(no_dquotes && no_squotes && no_newline)
    {
        if( ! s.empty())
        {
            _c4this->_do_write(s);
        }
        else
        {
            _c4this->_do_write("''");
        }
    }
    else
    {
        if(no_squotes && !no_dquotes)
        {
            _c4this->_do_write('\'');
            _c4this->_do_write(s);
            _c4this->_do_write('\'');
        }
        else if(no_dquotes && !no_squotes)
        {
            _c4this->_do_write('"');
            _c4this->_do_write(s);
            _c4this->_do_write('"');
        }
        else
        {
            size_t pos = 0;
            _c4this->_do_write('\'');
            for(size_t i = 0; i < s.len; ++i)
            {
                if(s[i] == '\'' || s[i] == '\n')
                {
                    cspan sub = s.subspan(pos, i-pos);
                    pos = i;
                    _c4this->_do_write(sub);
                    _c4this->_do_write(s[i]); // write the character twice
                }
            }
            if(pos < s.len)
            {
                cspan sub = s.subspan(pos);
                _c4this->_do_write(sub);
            }
            _c4this->_do_write('\'');
        }
    }
}

#undef _c4this
#undef _c4cthis

} // namespace yml
} // namespace c4

#endif /* _C4_RYML_DEF_HPP_ */
<commit_msg>woops<commit_after>#ifndef _C4_RYML_DEF_HPP_
#define _C4_RYML_DEF_HPP_

#include "./span.hpp"

namespace c4 {
namespace yml {

#define _c4this  (static_cast< Writer      * >(this))
#define _c4cthis (static_cast< Writer const* >(this))

template< class Writer >
span Emitter< Writer >::emit(NodeRef const& n, bool error_on_excess)
{
    this->_visit(n);
    span result = _c4this->_get(error_on_excess);
    return result;
}

template< class Writer >
size_t Emitter< Writer >::tell() const
{
    return _c4cthis->m_pos;
}

template< class Writer >
void Emitter< Writer >::seek(size_t p)
{
    _c4this->m_pos = p;
}

template< class Writer >
size_t Emitter< Writer >::_visit(NodeRef const& n, size_t ilevel)
{
    if(n.is_stream())
    {
        ;
    }
    _do_visit(n, ilevel);
    if(n.is_stream())
    {
        _write(cspan("...\n", 4));
    }
    return _c4this->m_pos;
}

/** @todo this function is too complex. break it down into manageable pieces */
template< class Writer >
void Emitter< Writer >::_do_visit(NodeRef const& n, size_t ilevel, bool indent)
{
    RepC ind{' ', 2 * size_t(indent) * ilevel};

    if(n.is_doc())
    {
        _write(cspan("---\n", 4));
    }
    else if(n.is_keyval())
    {
        C4_ASSERT(n.has_parent());
        if( ! n.has_anchor())
        {
            _write(ind, n.keysc(), cspan(": ", 2), n.valsc(), '\n');
        }
        else
        {
            _write(ind, n.keysc(), cspan(": ", 2), AnchorScalar(n), '\n');
        }
    }
    else if(n.is_val())
    {
        C4_ASSERT(n.has_parent());
        if( ! n.has_anchor())
        {
            _write(ind, cspan("- ", 2), n.valsc(), '\n');
        }
        else
        {
            _write(ind, cspan("- ", 2), AnchorScalar(n), '\n');
        }
    }
    else if(n.is_container() && ! n.is_root())
    {
        C4_ASSERT(n.parent_is_map() || n.parent_is_seq());
        C4_ASSERT(n.is_map() || n.is_seq());

        if(n.parent_is_seq())
        {
            C4_ASSERT( ! n.has_key());
            _write(ind, cspan("- ", 2));
            if(n.has_val_tag())
            {
                _write(n.val_tag(), ' ');
            }
        }
        else if(n.parent_is_map())
        {
            C4_ASSERT(n.has_key());
            _write(ind, n.keysc(), ':');
            if(n.has_val_tag())
            {
                _write(' ', n.val_tag());
            }
        }
        else
        {
            C4_ERROR("tree error");
        }
        if(n.has_anchor())
        {
            _write(' ', '&', n.anchor());
        }

        if(n.has_children())
        {
            if(n.is_seq())
            {
                if(n.parent_is_map())
                {
                    _write('\n');
                    indent = true;
                }
                else
                {
                    // do not indent the first child, as it will be written on the same line
                    indent = false;
                }
            }
            else if(n.is_map())
            {
                if(n.parent_is_seq())
                {
                    // do not indent the first child, as it will be written on the same line
                    indent = false;
                }
                else
                {
                    _write('\n');
                    indent = true;
                }
            }
            else
            {
                C4_ERROR("invalid node");
            }
        }
        else
        {
            if(n.parent_is_map())
            {
                _write(' ');
            }

            if(n.is_seq())
            {
                _write(cspan("[]\n", 3));
            }
            else if(n.is_map())
            {
                _write(cspan("{}\n", 3));
            }
        }
    }
    else if(n.is_container() && n.is_root())
    {
        if( ! n.has_children())
        {
            if(n.is_seq())
            {
                _write(cspan("[]\n", 3));
            }
            else if(n.is_map())
            {
                _write(cspan("{}\n", 3));
            }
        }
    }

    size_t next_level = ilevel + 1;
    if(n.is_stream() || n.is_doc() || n.is_root())
    {
        next_level = ilevel; // do not indent at top level
    }

    for(auto ch : n.children())
    {
        _do_visit(ch, next_level, indent);
        indent = true;
    }
}

template< class Writer >
void Emitter< Writer >::_write_one(AnchorScalar const& sc)
{
    if( ! sc.tag.empty())
    {
        _c4this->_do_write(sc.tag);
        _c4this->_do_write(' ');
    }
    if( ! sc.anchor.empty())
    {
        _c4this->_do_write('&');
        _c4this->_do_write(sc.anchor);
        _c4this->_do_write(' ');
    }

    _write_scalar(sc.scalar);
}

template< class Writer >
void Emitter< Writer >::_write_one(NodeScalar const& sc)
{
    if( ! sc.tag.empty())
    {
        _c4this->_do_write(sc.tag);
        _c4this->_do_write(' ');
    }

    _write_scalar(sc.scalar);
}

template< class Writer >
void Emitter< Writer >::_write_scalar(cspan const& s)
{
    const bool no_dquotes = s.first_of( '"') == npos;
    const bool no_squotes = s.first_of('\'') == npos;
    const bool no_newline = s.first_of('\n') == npos;

    if(no_dquotes && no_squotes && no_newline)
    {
        if( ! s.empty())
        {
            _c4this->_do_write(s);
        }
        else
        {
            _c4this->_do_write("''");
        }
    }
    else
    {
        if(no_squotes && !no_dquotes)
        {
            _c4this->_do_write('\'');
            _c4this->_do_write(s);
            _c4this->_do_write('\'');
        }
        else if(no_dquotes && !no_squotes)
        {
            _c4this->_do_write('"');
            _c4this->_do_write(s);
            _c4this->_do_write('"');
        }
        else
        {
            size_t pos = 0;
            _c4this->_do_write('\'');
            for(size_t i = 0; i < s.len; ++i)
            {
                if(s[i] == '\'' || s[i] == '\n')
                {
                    cspan sub = s.subspan(pos, i-pos);
                    pos = i;
                    _c4this->_do_write(sub);
                    _c4this->_do_write(s[i]); // write the character twice
                }
            }
            if(pos < s.len)
            {
                cspan sub = s.subspan(pos);
                _c4this->_do_write(sub);
            }
            _c4this->_do_write('\'');
        }
    }
}

#undef _c4this
#undef _c4cthis

} // namespace yml
} // namespace c4

#endif /* _C4_RYML_DEF_HPP_ */
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2017 ArangoDB GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
///     http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Manuel Baesler
////////////////////////////////////////////////////////////////////////////////

#include <date/date.h>
#include "Basics/datetime.h"
#include "Basics/StringUtils.h"
#include "Logger/Logger.h"

#include <boost/algorithm/string.hpp>

#include <regex>
#include <vector>

namespace {
std::regex const iso8601Regex(
                          "(\\+|\\-)?\\d+(\\-\\d{1,2}(\\-\\d{1,2})?)?" // YY[YY]-MM-DD
                          "("
                          "("
                          // Time is optional
                            "(\\ |T)" // T or blank separates date and time
                            "\\d\\d\\:\\d\\d" // time: hh:mm
                            "(\\:\\d\\d(\\.\\d{1,3})?)?" // Optional: :ss.mmms
                            "("
                              "z|Z|" // trailing Z or start of timezone
                              "(\\+|\\-)"
                              "\\d\\d\\:\\d\\d" // timezone hh:mm
                            ")?"
                          ")|"
                          "(z|Z)" // Z
                          ")?"
                          );

/* REGEX GROUPS
12:34:56.789-12:34
submatch 0: '12:34:56.789-12:34'
submatch 1: '12'
submatch 2: '34'
submatch 3: ':56.789'
submatch 4: '56'
submatch 5: '.789'
submatch 6: '789'
submatch 7: '-12:34'
submatch 8: '-'
submatch 9: '12'
submatch 10: '34'
*/

std::regex const timeRegex(
    "(\\d\\d)\\:(\\d\\d)(\\:(\\d\\d)(\\.(\\d{1,3}))?)?((\\+|\\-)(\\d\\d)\\:"
    "(\\d\\d))?");

/* REGEX GROUPS
P1Y2M3W4DT5H6M7.891S
  submatch 0: P1Y2M3W4DT5H6M7.891S
  submatch 1: 1Y
  submatch 2: 1
  submatch 3: 2M
  submatch 4: 2
  submatch 5: 3W
  submatch 6: 3
  submatch 7: 4D
  submatch 8: 4
  submatch 9: T5H6M7.891S
  submatch 10: 5H
  submatch 11: 5
  submatch 12: 6M
  submatch 13: 6
  submatch 14: 7.891S
  submatch 15: 7
  submatch 16: .891
  submatch 17: 891
*/
std::regex const durationRegex("P((\\d+)Y)?((\\d+)M)?((\\d+)W)?((\\d+)D)?(T((\\d+)H)?((\\d+)M)?((\\d+)(\\.(\\d{1,3}))?S)?)?");

} // namespace

bool arangodb::basics::parse_dateTime(
    std::string const& dateTimeIn,
    tp_sys_clock_ms& date_tp) {
  using namespace date;
  using namespace std::chrono;

  std::string dateTime = dateTimeIn;
  std::string strDate, strTime;

  boost::algorithm::trim(dateTime);

  if (!std::regex_match(dateTime, ::iso8601Regex)) {
    LOG_TOPIC(DEBUG, arangodb::Logger::FIXME)
        << "regex failed for datetime '" << dateTime << "'";
    return false;
  }

  strDate = dateTime;

  if (strDate.back() == 'Z' || strDate.back() == 'z') {
    strDate.pop_back();
  }

  LOG_TOPIC(DEBUG, arangodb::Logger::FIXME)
      << "parse datetime '" << strDate << "'";

  if (strDate.find("T") != std::string::npos ||
      strDate.find(" ") != std::string::npos) {  // split into ymd / time
    std::vector<std::string> strs;
    boost::split(strs, strDate, boost::is_any_of("T "));

    strDate = strs[0];
    strTime = strs[1];
  }  // if

  // parse date component
  int parsedYear, parsedMonth = 1, parsedDay = 1, numParsedComponents;

  numParsedComponents = sscanf(strDate.c_str(), "%d-%d-%d", &parsedYear,
                               &parsedMonth, &parsedDay);

  if (numParsedComponents == 0 || numParsedComponents == EOF) {
    LOG_TOPIC(DEBUG, arangodb::Logger::FIXME)
        << "sscanf parse failed with " << numParsedComponents;
    return false;
  }

  if (1 < numParsedComponents && (parsedMonth < 1 || 12 < parsedMonth)) {
    return false;
  }

  if (2 < numParsedComponents && (parsedDay < 1 || 31 < parsedDay)) {
    return false;
  }

  LOG_TOPIC(DEBUG, arangodb::Logger::FIXME)
      << "parsed YMD " << parsedYear << " " << parsedMonth << " " << parsedDay;

  date_tp = sys_days(year{parsedYear} / parsedMonth / parsedDay);

  // parse Time HH:MM:SS(.SSS)((+|-)HH:MM)
  if (1 < strTime.size()) {
    std::smatch time_parts;

    if (!std::regex_match(strTime, time_parts, ::timeRegex)) {
      LOG_TOPIC(DEBUG, arangodb::Logger::FIXME)
          << "regex failed for time " << strTime;
      return false;
    }

    // hour
    hours parsedHours{atoi(time_parts[1].str().c_str())};

    if (hours{23} < parsedHours) {
      return false;
    }
    date_tp += parsedHours;

    // minute
    minutes parsedMinutes{atoi(time_parts[2].str().c_str())};

    if (minutes{59} < parsedMinutes) {
      return false;
    }
    date_tp += parsedMinutes;

    // seconds
    seconds parsedSeconds{atoi(time_parts[4].str().c_str())};

    if (seconds{59} < parsedSeconds) {
      return false;
    }
    date_tp += parsedSeconds;

    // milliseconds .9 -> 900ms
    date_tp +=
        milliseconds{atoi((time_parts[6].str() + "00").substr(0, 3).c_str())};

    // time offset
    if (time_parts[8].str().size()) {
      hours parsedHours{atoi(time_parts[9].str().c_str())};  // hours

      if (hours{23} < parsedHours) {
        return false;
      }
      minutes offset = parsedHours;

      minutes parsedMinutes{atoi(time_parts[10].str().c_str())};  // minutes

      if (minutes{59} < parsedMinutes) {
        return false;
      }
      offset += parsedMinutes;

      if (time_parts[8].str() == "-") {
        offset *= -1;
      }
      date_tp -= offset;
    }
  }  // if

  return true;
}

bool arangodb::basics::regex_isoDuration(std::string const& isoDuration, std::smatch& durationParts) {
  if (isoDuration.length() <= 1) {
    return false;
  }

  if (!std::regex_match(isoDuration, durationParts, ::durationRegex)) {
    return false;
  }

  return true;
}
<commit_msg>remove sscanf calls from datetime functions (#5350)<commit_after>////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2017 ArangoDB GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
///     http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Manuel Baesler
////////////////////////////////////////////////////////////////////////////////

#include <date/date.h>
#include "Basics/datetime.h"
#include "Basics/NumberUtils.h"
#include "Logger/Logger.h"

#include <boost/algorithm/string.hpp>

#include <regex>
#include <vector>

namespace {
std::regex const iso8601Regex(
                          "(\\+|\\-)?\\d+(\\-\\d{1,2}(\\-\\d{1,2})?)?" // YY[YY]-MM-DD
                          "("
                          "("
                          // Time is optional
                            "(\\ |T)" // T or blank separates date and time
                            "\\d\\d\\:\\d\\d" // time: hh:mm
                            "(\\:\\d\\d(\\.\\d{1,3})?)?" // Optional: :ss.mmms
                            "("
                              "z|Z|" // trailing Z or start of timezone
                              "(\\+|\\-)"
                              "\\d\\d\\:\\d\\d" // timezone hh:mm
                            ")?"
                          ")|"
                          "(z|Z)" // Z
                          ")?"
                          );

/* REGEX GROUPS
12:34:56.789-12:34
submatch 0: '12:34:56.789-12:34'
submatch 1: '12'
submatch 2: '34'
submatch 3: ':56.789'
submatch 4: '56'
submatch 5: '.789'
submatch 6: '789'
submatch 7: '-12:34'
submatch 8: '-'
submatch 9: '12'
submatch 10: '34'
*/

std::regex const timeRegex(
    "(\\d\\d)\\:(\\d\\d)(\\:(\\d\\d)(\\.(\\d{1,3}))?)?((\\+|\\-)(\\d\\d)\\:"
    "(\\d\\d))?");

/* REGEX GROUPS
P1Y2M3W4DT5H6M7.891S
  submatch 0: P1Y2M3W4DT5H6M7.891S
  submatch 1: 1Y
  submatch 2: 1
  submatch 3: 2M
  submatch 4: 2
  submatch 5: 3W
  submatch 6: 3
  submatch 7: 4D
  submatch 8: 4
  submatch 9: T5H6M7.891S
  submatch 10: 5H
  submatch 11: 5
  submatch 12: 6M
  submatch 13: 6
  submatch 14: 7.891S
  submatch 15: 7
  submatch 16: .891
  submatch 17: 891
*/
std::regex const durationRegex("P((\\d+)Y)?((\\d+)M)?((\\d+)W)?((\\d+)D)?(T((\\d+)H)?((\\d+)M)?((\\d+)(\\.(\\d{1,3}))?S)?)?");

} // namespace

bool arangodb::basics::parse_dateTime(
    std::string const& dateTimeIn,
    tp_sys_clock_ms& date_tp) {
  using namespace date;
  using namespace std::chrono;

  std::string dateTime = dateTimeIn;
  std::string strDate, strTime;

  boost::algorithm::trim(dateTime);

  if (!std::regex_match(dateTime, ::iso8601Regex)) {
    LOG_TOPIC(DEBUG, arangodb::Logger::FIXME)
        << "regex failed for datetime '" << dateTime << "'";
    return false;
  }

  strDate = dateTime;

  if (strDate.back() == 'Z' || strDate.back() == 'z') {
    strDate.pop_back();
  }

  LOG_TOPIC(DEBUG, arangodb::Logger::FIXME)
      << "parse datetime '" << strDate << "'";

  if (strDate.find("T") != std::string::npos ||
      strDate.find(" ") != std::string::npos) {  // split into ymd / time
    std::vector<std::string> strs;
    boost::split(strs, strDate, boost::is_any_of("T "));

    strDate = strs[0];
    strTime = strs[1];
  }  // if

  // parse date component, moves pointer "p" forward
  // returns true if "p" pointed to a valid number, and false otherwise
  auto parseDateComponent = [](char const*& p, char const* e, int& result) -> bool {
    char const* s = p; // remember initial start
    while (p < e && *p >= '0' && *p <= '9') {
      ++p;
    }
    if (p == s) {
      // did not find any valid character
      return false;
    }
    result = NumberUtils::atoi_unchecked<int>(s, p);
    if (p < e && *p == '-') {
      ++p;
    }
    return true;
  };

  char const* p = strDate.data();
  char const* e = p + strDate.size();

  // month and day are optional, so they intentionally default to 1
  int parsedYear, parsedMonth = 1, parsedDay = 1;

  // at least year must be valid
  if (!parseDateComponent(p, e, parsedYear)) {
    return false;
  }

  parseDateComponent(p, e, parsedMonth);
  parseDateComponent(p, e, parsedDay);

  if (parsedMonth < 1 || parsedMonth > 12 || parsedDay < 1 || parsedDay > 31) {
    // definitely invalid
    return false;
  }

  LOG_TOPIC(DEBUG, arangodb::Logger::FIXME)
      << "parsed YMD " << parsedYear << " " << parsedMonth << " " << parsedDay;

  date_tp = sys_days(year{parsedYear} / parsedMonth / parsedDay);

  // parse Time HH:MM:SS(.SSS)((+|-)HH:MM)
  if (1 < strTime.size()) {
    std::smatch time_parts;

    if (!std::regex_match(strTime, time_parts, ::timeRegex)) {
      LOG_TOPIC(DEBUG, arangodb::Logger::FIXME)
          << "regex failed for time " << strTime;
      return false;
    }

    // hour
    hours parsedHours{atoi(time_parts[1].str().c_str())};

    if (hours{23} < parsedHours) {
      return false;
    }
    date_tp += parsedHours;

    // minute
    minutes parsedMinutes{atoi(time_parts[2].str().c_str())};

    if (minutes{59} < parsedMinutes) {
      return false;
    }
    date_tp += parsedMinutes;

    // seconds
    seconds parsedSeconds{atoi(time_parts[4].str().c_str())};

    if (seconds{59} < parsedSeconds) {
      return false;
    }
    date_tp += parsedSeconds;

    // milliseconds .9 -> 900ms
    date_tp +=
        milliseconds{atoi((time_parts[6].str() + "00").substr(0, 3).c_str())};

    // time offset
    if (time_parts[8].str().size()) {
      hours parsedHours{atoi(time_parts[9].str().c_str())};  // hours

      if (hours{23} < parsedHours) {
        return false;
      }
      minutes offset = parsedHours;

      minutes parsedMinutes{atoi(time_parts[10].str().c_str())};  // minutes

      if (minutes{59} < parsedMinutes) {
        return false;
      }
      offset += parsedMinutes;

      if (time_parts[8].str() == "-") {
        offset *= -1;
      }
      date_tp -= offset;
    }
  }  // if

  return true;
}

bool arangodb::basics::regex_isoDuration(std::string const& isoDuration, std::smatch& durationParts) {
  if (isoDuration.length() <= 1) {
    return false;
  }

  if (!std::regex_match(isoDuration, durationParts, ::durationRegex)) {
    return false;
  }

  return true;
}
<|endoftext|>


<commit_before>#include "cubeMap.h"
#include "ray.h"
#include "../ui/TraceUI.h"
extern TraceUI* traceUI;

glm::dvec3 CubeMap::getColor(ray r) const {
    /* Indexing:
     * tMap[0] = +x
     * tMap[1] = -x
     * tMap[2] = +y
     * tMap[3] = -y
     * tMap[4] = +z
     * tMap[5] = -z

    /* We can look at the colision of a ray r(t)=r.d, ignoring the P term. We then look at a simple 2x2x2 cube centered
     * at the origin. We know the face we collide with is the one with the smallest t term. By convention, all these
     * planes will have a, b, or c set to +-1 and d to 1 (creating normals that face outwards). The solution for t is
     * therefore: t = 1/dot(n, r.d) */

    double tVals[6];
    glm::dvec3 normals[6] = {glm::dvec3(1, 0, 0), glm::dvec3(-1, 0, 0), glm::dvec3(0, 1, 0), glm::dvec3(0, -1, 0),
                             glm::dvec3(0, 0, 1), glm::dvec3(0, 0, -1)};

    int minIdx = -1;
    double minT = 0;
    for(int i = 0; i < 6; i++) {
        double t = 1.0 / glm::dot(normals[i], r.d);

        if(minIdx == -1 || (t > 0 && t < minT)) {
            minIdx = i;
            minT = t;
        }
    }

    // Calculate the intersection point. We can simply project this onto the surface
    glm::dvec3 point = r.d*minT;

    // Project vector onto the respective plane
    glm::dvec3 proj = point - glm::dot(point, normals[minIdx])*normals[minIdx];
    glm::dvec2 twoDProj(0, 0);

    if(minIdx == 0 || minIdx == 1)
        twoDProj = glm::dvec2(proj.y, proj.z);
    if(minIdx == 2 || minIdx == 3)
        twoDProj = glm::dvec2(proj.x, proj.z);
    if(minIdx == 4 || minIdx == 5)
        twoDProj = glm::dvec2(proj.x, proj.y);

    return tMap[minIdx]->getPixelAt(twoDProj.x, twoDProj.y);
}<commit_msg>Added scaling bug<commit_after>#include <iostream>
#include "cubeMap.h"
#include "ray.h"
#include "../ui/TraceUI.h"
extern TraceUI* traceUI;

glm::dvec3 CubeMap::getColor(ray r) const {
    /* Indexing:
     * tMap[0] = +x
     * tMap[1] = -x
     * tMap[2] = +y
     * tMap[3] = -y
     * tMap[4] = +z
     * tMap[5] = -z

    /* We can look at the colision of a ray r(t)=r.d, ignoring the P term. We then look at a simple 2x2x2 cube centered
     * at the origin. We know the face we collide with is the one with the smallest t term. By convention, all these
     * planes will have a, b, or c set to +-1 and d to 1 (creating normals that face outwards). The solution for t is
     * therefore: t = 1/dot(n, r.d) */

    double tVals[6];
    glm::dvec3 normals[6] = {glm::dvec3(1, 0, 0), glm::dvec3(-1, 0, 0), glm::dvec3(0, 1, 0), glm::dvec3(0, -1, 0),
                             glm::dvec3(0, 0, 1), glm::dvec3(0, 0, -1)};

    int minIdx = -1;
    double minT = 0;
    for(int i = 0; i < 6; i++) {
        double t = 1.0 / glm::dot(normals[i], r.d);

        if(minIdx == -1 || (t > 0 && t < minT)) {
            minIdx = i;
            minT = t;
        }
    }

    // Calculate the intersection point. We can simply project this onto the surface
    glm::dvec3 point = r.d*minT;

    // Project vector onto the respective plane
    glm::dvec3 proj = point - glm::dot(point, normals[minIdx])*normals[minIdx];
    glm::dvec2 twoDProj(0, 0);

    if(minIdx == 0 || minIdx == 1)
        twoDProj = glm::dvec2(-proj.z, -proj.y);
    if(minIdx == 2 || minIdx == 3)
        twoDProj = glm::dvec2(proj.x, proj.z);
    if(minIdx == 4 || minIdx == 5)
        twoDProj = glm::dvec2(proj.x, proj.y);

    glm::dvec2 uvCoord = (twoDProj + glm::dvec2(1, 1)) / 2.0;
    int xCoord = (int)(tMap[minIdx]->getWidth()*uvCoord.x);
    int yCoord = (int)(tMap[minIdx]->getHeight()*uvCoord.y);

    return tMap[minIdx]->getPixelAt(xCoord, yCoord);
}<|endoftext|>


<commit_before>// Copyright (C) 2012-2014 Leap Motion, Inc. All rights reserved.
#include "stdafx.h"
#include "AutoPacketFactory.h"
#include "AutoPacketInternal.hpp"
#include "fast_pointer_cast.h"
#include "thread_specific_ptr.h"
#include <cmath>

AutoPacketFactory::AutoPacketFactory(void):
  ContextMember("AutoPacketFactory"),
  m_parent(GetContext()->GetParentContext()),
  m_packetCount(0),
  m_packetDurationSum(0),
  m_packetDurationSqSum(0)
{}

AutoPacketFactory::~AutoPacketFactory() {}

std::shared_ptr<AutoPacket> AutoPacketFactory::NewPacket(void) {
  if(ShouldStop())
    throw autowiring_error("Attempted to create a packet on an AutoPacketFactory that was already terminated");
  if(!IsRunning())
    throw autowiring_error("Cannot create a packet until the AutoPacketFactory is started");

  std::shared_ptr<AutoPacketInternal> retVal;
  {
    std::lock_guard<std::mutex> lk(m_lock);

    // New packet issued
    ++m_packetCount;

    // Create a new next packet
    retVal = m_nextPacket;
    m_nextPacket = retVal->SuccessorInternal();
  }

  retVal->Initialize();
  return retVal;
}

std::shared_ptr<AutoPacketInternal> AutoPacketFactory::ConstructPacket(void) {
  return std::make_shared<AutoPacketInternal>(*this, GetInternalOutstanding());
}

bool AutoPacketFactory::IsAutoPacketType(const std::type_info& dataType) {
  return
    dataType == typeid(AutoPacket) ||
    dataType == typeid(auto_arg<AutoPacket&>::id_type) ||
    dataType == typeid(auto_arg<const AutoPacket&>::id_type);
}

std::shared_ptr<void> AutoPacketFactory::GetInternalOutstanding(void) {
  auto retVal = m_outstandingInternal.lock();
  if (retVal)
    return retVal;

  std::shared_ptr<Object> outstanding = GetOutstanding();
  retVal = std::shared_ptr<void>(
    (void*)1,
    [this, outstanding] (void*) mutable {
      std::lock_guard<std::mutex> lk(m_lock);
      m_stateCondition.notify_all();

      // Weak pointer will prevent our lambda from being destroyed, so we manually reset
      // the outstanding counter in order to force it to be reset here
      outstanding.reset();
    }
  );
  m_outstandingInternal = retVal;
  return retVal;
}

bool AutoPacketFactory::OnStart(void) {
  // Initialize first packet
  m_nextPacket = ConstructPacket();

  // Wake us up. We're starting now
  m_stateCondition.notify_all();
  return true;
}

void AutoPacketFactory::OnStop(bool graceful) {
  // Queue of local variables to be destroyed when leaving scope
  t_autoFilterSet autoFilters;

  // Reset next packet, it will never be issued
  m_nextPacket.reset();

  // Lock destruction precedes local variables
  std::lock_guard<std::mutex> lk(m_lock);

  // Same story with the AutoFilters
  autoFilters.swap(m_autoFilters);

  // Now we can lock, update state, and notify any listeners
  m_stateCondition.notify_all();
}

void AutoPacketFactory::DoAdditionalWait(void) {
  std::unique_lock<std::mutex> lk(m_lock);
  m_stateCondition.wait(
    lk,
    [this]{
      return ShouldStop() && m_outstandingInternal.expired();
    }
  );
}

void AutoPacketFactory::Clear(void) {
  // Simple handoff to Stop is sufficient
  Stop(false);
}

void AutoPacketFactory::AddSubscriber(const AutoFilterDescriptor& rhs) {
  std::lock_guard<std::mutex> lk(m_lock);
  m_autoFilters.insert(rhs);
}

void AutoPacketFactory::RemoveSubscriber(const AutoFilterDescriptor& autoFilter) {
  // Trivial removal from the autofilter set:
  std::lock_guard<std::mutex> lk(m_lock);
  m_autoFilters.erase(autoFilter);
}

AutoFilterDescriptor AutoPacketFactory::GetTypeDescriptorUnsafe(const std::type_info* nodeType) {
  //ASSUME: type_info uniquely specifies descriptor
  for (auto& af : m_autoFilters)
    if (af.GetAutoFilterTypeInfo() == nodeType)
      return af;

  return AutoFilterDescriptor();
}

size_t AutoPacketFactory::GetOutstandingPacketCount(void) const {
  // Next packet is stored internally, don't count that packet
  return m_outstandingInternal.use_count() - 1;
}

void AutoPacketFactory::RecordPacketDuration(std::chrono::nanoseconds duration) {
  std::unique_lock<std::mutex> lk(m_lock);
  m_packetDurationSum += duration.count();
  m_packetDurationSqSum += duration.count() * duration.count();
}

double AutoPacketFactory::GetMeanPacketLifetime(void) {
  return m_packetDurationSum / m_packetCount;
}

double AutoPacketFactory::GetPacketLifetimeStandardDeviation(void) {
  double mean = m_packetDurationSum / m_packetCount;
  double variance = m_packetDurationSqSum / m_packetCount - mean * mean;
  return std::sqrt(variance >= 0.0 ? variance : 0.0 );
}

void AutoPacketFactory::ResetPacketStatistics(void) {
  std::unique_lock<std::mutex> lk(m_lock);
  m_packetCount = 0;
  m_packetDurationSum = 0.0;
  m_packetDurationSqSum = 0.0;
}

template class RegType<AutoPacketFactory>;
template struct SlotInformationStump<AutoPacketFactory, false>;
template const std::shared_ptr<AutoPacketFactory>& SharedPointerSlot::as<AutoPacketFactory>(void) const;
template std::shared_ptr<AutoPacketFactory> autowiring::fast_pointer_cast<AutoPacketFactory, Object>(const std::shared_ptr<Object>& Other);
<commit_msg>Fix merge error.<commit_after>// Copyright (C) 2012-2014 Leap Motion, Inc. All rights reserved.
#include "stdafx.h"
#include "AutoPacketFactory.h"
#include "AutoPacketInternal.hpp"
#include "fast_pointer_cast.h"
#include "thread_specific_ptr.h"
#include <cmath>

AutoPacketFactory::AutoPacketFactory(void):
  ContextMember("AutoPacketFactory"),
  m_packetCount(0),
  m_packetDurationSum(0),
  m_packetDurationSqSum(0)
{}

AutoPacketFactory::~AutoPacketFactory() {}

std::shared_ptr<AutoPacket> AutoPacketFactory::NewPacket(void) {
  if(ShouldStop())
    throw autowiring_error("Attempted to create a packet on an AutoPacketFactory that was already terminated");
  if(!IsRunning())
    throw autowiring_error("Cannot create a packet until the AutoPacketFactory is started");

  std::shared_ptr<AutoPacketInternal> retVal;
  {
    std::lock_guard<std::mutex> lk(m_lock);

    // New packet issued
    ++m_packetCount;

    // Create a new next packet
    retVal = m_nextPacket;
    m_nextPacket = retVal->SuccessorInternal();
  }

  retVal->Initialize();
  return retVal;
}

std::shared_ptr<AutoPacketInternal> AutoPacketFactory::ConstructPacket(void) {
  return std::make_shared<AutoPacketInternal>(*this, GetInternalOutstanding());
}

bool AutoPacketFactory::IsAutoPacketType(const std::type_info& dataType) {
  return
    dataType == typeid(AutoPacket) ||
    dataType == typeid(auto_arg<AutoPacket&>::id_type) ||
    dataType == typeid(auto_arg<const AutoPacket&>::id_type);
}

std::shared_ptr<void> AutoPacketFactory::GetInternalOutstanding(void) {
  auto retVal = m_outstandingInternal.lock();
  if (retVal)
    return retVal;

  std::shared_ptr<Object> outstanding = GetOutstanding();
  retVal = std::shared_ptr<void>(
    (void*)1,
    [this, outstanding] (void*) mutable {
      std::lock_guard<std::mutex> lk(m_lock);
      m_stateCondition.notify_all();

      // Weak pointer will prevent our lambda from being destroyed, so we manually reset
      // the outstanding counter in order to force it to be reset here
      outstanding.reset();
    }
  );
  m_outstandingInternal = retVal;
  return retVal;
}

bool AutoPacketFactory::OnStart(void) {
  // Initialize first packet
  m_nextPacket = ConstructPacket();

  // Wake us up. We're starting now
  m_stateCondition.notify_all();
  return true;
}

void AutoPacketFactory::OnStop(bool graceful) {
  // Queue of local variables to be destroyed when leaving scope
  t_autoFilterSet autoFilters;

  // Reset next packet, it will never be issued
  m_nextPacket.reset();

  // Lock destruction precedes local variables
  std::lock_guard<std::mutex> lk(m_lock);

  // Same story with the AutoFilters
  autoFilters.swap(m_autoFilters);

  // Now we can lock, update state, and notify any listeners
  m_stateCondition.notify_all();
}

void AutoPacketFactory::DoAdditionalWait(void) {
  std::unique_lock<std::mutex> lk(m_lock);
  m_stateCondition.wait(
    lk,
    [this]{
      return ShouldStop() && m_outstandingInternal.expired();
    }
  );
}

void AutoPacketFactory::Clear(void) {
  // Simple handoff to Stop is sufficient
  Stop(false);
}

void AutoPacketFactory::AddSubscriber(const AutoFilterDescriptor& rhs) {
  std::lock_guard<std::mutex> lk(m_lock);
  m_autoFilters.insert(rhs);
}

void AutoPacketFactory::RemoveSubscriber(const AutoFilterDescriptor& autoFilter) {
  // Trivial removal from the autofilter set:
  std::lock_guard<std::mutex> lk(m_lock);
  m_autoFilters.erase(autoFilter);
}

AutoFilterDescriptor AutoPacketFactory::GetTypeDescriptorUnsafe(const std::type_info* nodeType) {
  //ASSUME: type_info uniquely specifies descriptor
  for (auto& af : m_autoFilters)
    if (af.GetAutoFilterTypeInfo() == nodeType)
      return af;

  return AutoFilterDescriptor();
}

size_t AutoPacketFactory::GetOutstandingPacketCount(void) const {
  // Next packet is stored internally, don't count that packet
  return m_outstandingInternal.use_count() - 1;
}

void AutoPacketFactory::RecordPacketDuration(std::chrono::nanoseconds duration) {
  std::unique_lock<std::mutex> lk(m_lock);
  m_packetDurationSum += duration.count();
  m_packetDurationSqSum += duration.count() * duration.count();
}

double AutoPacketFactory::GetMeanPacketLifetime(void) {
  return m_packetDurationSum / m_packetCount;
}

double AutoPacketFactory::GetPacketLifetimeStandardDeviation(void) {
  double mean = m_packetDurationSum / m_packetCount;
  double variance = m_packetDurationSqSum / m_packetCount - mean * mean;
  return std::sqrt(variance >= 0.0 ? variance : 0.0 );
}

void AutoPacketFactory::ResetPacketStatistics(void) {
  std::unique_lock<std::mutex> lk(m_lock);
  m_packetCount = 0;
  m_packetDurationSum = 0.0;
  m_packetDurationSqSum = 0.0;
}

template class RegType<AutoPacketFactory>;
template struct SlotInformationStump<AutoPacketFactory, false>;
template const std::shared_ptr<AutoPacketFactory>& SharedPointerSlot::as<AutoPacketFactory>(void) const;
template std::shared_ptr<AutoPacketFactory> autowiring::fast_pointer_cast<AutoPacketFactory, Object>(const std::shared_ptr<Object>& Other);
<|endoftext|>