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

#include "miner.h"

#include "amount.h"
#include "chain.h"
#include "chainparams.h"
#include "coins.h"
#include "config.h"
#include "consensus/consensus.h"
#include "consensus/merkle.h"
#include "consensus/validation.h"
#include "hash.h"
#include "net.h"
#include "policy/policy.h"
#include "pow.h"
#include "primitives/transaction.h"
#include "script/standard.h"
#include "timedata.h"
#include "txmempool.h"
#include "base58.h"
#include "util.h"
#include "utilmoneystr.h"
#include "validation.h"
#include "validationinterface.h"
#include "ethash/internal.h"

#include <algorithm>
#include <queue>
#include <utility>

#include <boost/thread.hpp>
#include <boost/tuple/tuple.hpp>

#include "wallet/wallet.h"

using namespace std;

static const int MAX_COINBASE_SCRIPTSIG_SIZE = 100;

//////////////////////////////////////////////////////////////////////////////
//
// BitcoinMiner
//

//
// Unconfirmed transactions in the memory pool often depend on other
// transactions in the memory pool. When we select transactions from the
// pool, we select by highest priority or fee rate, so we might consider
// transactions that depend on transactions that aren't yet in the block.

uint64_t nLastBlockTx = 0;
uint64_t nLastBlockSize = 0;

class ScoreCompare {
public:
    ScoreCompare() {}

    bool operator()(const CTxMemPool::txiter a, const CTxMemPool::txiter b) {
        // Convert to less than.
        return CompareTxMemPoolEntryByScore()(*b, *a);
    }
};

int64_t UpdateTime(CBlockHeader *pblock, const Config &config,
                   const CBlockIndex *pindexPrev) {
    int64_t nOldTime = pblock->nTime;
    int64_t nNewTime =
        std::max(pindexPrev->GetMedianTimePast() + 1, GetAdjustedTime());

    if (nOldTime < nNewTime) {
        pblock->nTime = nNewTime;
    }

    const Consensus::Params &consensusParams =
        config.GetChainParams().GetConsensus();

    // Updating time can change work required on testnet:
    if (consensusParams.fPowAllowMinDifficultyBlocks) {
        pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, config);
    }

    return nNewTime - nOldTime;
}

static uint64_t ComputeMaxGeneratedBlockSize(const Config &config,
                                             const CBlockIndex *pindexPrev) {
    // Block resource limits
    // If -blockmaxsize is not given, limit to DEFAULT_MAX_GENERATED_BLOCK_SIZE
    // If only one is given, only restrict the specified resource.
    // If both are given, restrict both.
    uint64_t nMaxGeneratedBlockSize = DEFAULT_MAX_GENERATED_BLOCK_SIZE;
    if (IsArgSet("-blockmaxsize")) {
        nMaxGeneratedBlockSize =
            GetArg("-blockmaxsize", DEFAULT_MAX_GENERATED_BLOCK_SIZE);
    }

    // Limit size to between 1K and MaxBlockSize-1K for sanity:
    nMaxGeneratedBlockSize =
        std::max(uint64_t(1000), std::min(config.GetMaxBlockSize() - 1000,
                                          nMaxGeneratedBlockSize));

    return nMaxGeneratedBlockSize;
}

BlockAssembler::BlockAssembler(const Config &_config,
                               const CChainParams &_chainparams)
    : chainparams(_chainparams), config(&_config) {
    if (IsArgSet("-blockmintxfee")) {
        CAmount n(0);
        ParseMoney(GetArg("-blockmintxfee", ""), n);
        blockMinFeeRate = CFeeRate(n);
    } else {
        blockMinFeeRate = CFeeRate(DEFAULT_BLOCK_MIN_TX_FEE);
    }

    LOCK(cs_main);
    nMaxGeneratedBlockSize =
        ComputeMaxGeneratedBlockSize(*config, chainActive.Tip());
}

void BlockAssembler::resetBlock() {
    inBlock.clear();

    // Reserve space for coinbase tx.
    nBlockSize = 1000;
    nBlockSigOps = 100;

    // These counters do not include coinbase tx.
    nBlockTx = 0;
    nFees = CAmount(0);
    nInterest = CAmount(0);

    lastFewTxs = 0;
    blockFinished = false;
}

static const std::vector<uint8_t>
getExcessiveBlockSizeSig(const Config &config) {
    std::string cbmsg = "/EB" + getSubVersionEB(config.GetMaxBlockSize()) + "/";
    const char *cbcstr = cbmsg.c_str();
    std::vector<uint8_t> vec(cbcstr, cbcstr + cbmsg.size());
    return vec;
}

std::unique_ptr<CBlockTemplate>
BlockAssembler::CreateNewBlock(const CScript &scriptPubKeyIn) {
    int64_t nTimeStart = GetTimeMicros();

    resetBlock();

    pblocktemplate.reset(new CBlockTemplate());
    if (!pblocktemplate.get()) {
        return nullptr;
    }

    // Pointer for convenience.
    pblock = &pblocktemplate->block;

    // Add dummy coinbase tx as first transaction.
    pblock->vtx.emplace_back();
    // updated at end
    pblocktemplate->vTxFees.push_back(CAmount(-1));
    // updated at end
    pblocktemplate->vTxSigOpsCount.push_back(-1);

    LOCK2(cs_main, mempool.cs);
    CBlockIndex *pindexPrev = chainActive.Tip();
    nHeight = pindexPrev->nHeight + 1;

    pblock->nVersion =
        ComputeBlockVersion(pindexPrev, chainparams.GetConsensus());
    // -regtest only: allow overriding block.nVersion with
    // -blockversion=N to test forking scenarios
    if (chainparams.MineBlocksOnDemand()) {
        pblock->nVersion = GetArg("-blockversion", pblock->nVersion);
    }

    pblock->nTime = GetAdjustedTime();
    pblock->nBlockHeight = chainActive.Height() + 1;
    nMaxGeneratedBlockSize = ComputeMaxGeneratedBlockSize(*config, pindexPrev);

    nLockTimeCutoff = pblock->GetBlockTime();

    addPriorityTxs();
    int nPackagesSelected = 0;
    int nDescendantsUpdated = 0;
    addPackageTxs(nPackagesSelected, nDescendantsUpdated);

    int64_t nTime1 = GetTimeMicros();

    nLastBlockTx = nBlockTx;
    nLastBlockSize = nBlockSize;

    // Create coinbase transaction.
    CMutableTransaction coinbaseTx;
    coinbaseTx.nFlags = TX_FLAGS_COINBASE;
    coinbaseTx.vin.resize(1);
    coinbaseTx.vin[0].prevout.SetNull();
    coinbaseTx.vout.resize(1);
    coinbaseTx.vout[0].SetNull();
    coinbaseTx.vout[0].scriptPubKey = scriptPubKeyIn;
    coinbaseTx.vout[0].nValue = nFees + GetBlockSubsidy(nHeight, chainparams.GetConsensus());
    coinbaseTx.vout[0].nLockTime = COINBASE_MATURITY;
    coinbaseTx.vin[0].prevout.n = nHeight;
    coinbaseTx.vin[0].prevout.nValue = coinbaseTx.vout[0].nValue;
    coinbaseTx.vin[0].scriptSig = CScript() << OP_0;
    pblock->vtx[0] = MakeTransactionRef(coinbaseTx);
    //inherit parameters from pindexPrev
    pblock->nChainInterest = pindexPrev->nChainInterest + nInterest;
    pblocktemplate->vTxFees[0] = -1 * nFees;

    uint64_t nSerializeSize =
        GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION);

    LogPrintf("CreateNewBlock(): total size: %u txs: %u fees: %ld sigops %d\n",
              nSerializeSize, nBlockTx, nFees, nBlockSigOps);

    // Fill in header.
    pblock->hashPrevBlock = pindexPrev->GetBlockHash();
    UpdateTime(pblock, *config, pindexPrev);
    pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, *config);
    pblock->nNonce = 0;

    pblocktemplate->vTxSigOpsCount[0] =
        GetSigOpCountWithoutP2SH(*pblock->vtx[0]);

    CValidationState state;
    if (!TestBlockValidity(*config, state, *pblock, pindexPrev, false, false)) {
        throw std::runtime_error(strprintf("%s: TestBlockValidity failed: %s",
                                           __func__,
                                           FormatStateMessage(state)));
    }
    int64_t nTime2 = GetTimeMicros();

    LogPrintf("CreateNewBlock: %s\n", pblock->ToString());
    LogPrint("bench", "CreateNewBlock() packages: %.2fms (%d packages, %d "
                      "updated descendants), validity: %.2fms (total %.2fms)\n",
             0.001 * (nTime1 - nTimeStart), nPackagesSelected,
             nDescendantsUpdated, 0.001 * (nTime2 - nTime1),
             0.001 * (nTime2 - nTimeStart));

    return std::move(pblocktemplate);
}

bool BlockAssembler::isStillDependent(CTxMemPool::txiter iter) {
    for (CTxMemPool::txiter parent : mempool.GetMemPoolParents(iter)) {
        if (!inBlock.count(parent)) {
            return true;
        }
    }
    return false;
}

void BlockAssembler::onlyUnconfirmed(CTxMemPool::setEntries &testSet) {
    for (CTxMemPool::setEntries::iterator iit = testSet.begin();
         iit != testSet.end();) {
        // Only test txs not already in the block.
        if (inBlock.count(*iit)) {
            testSet.erase(iit++);
        } else {
            iit++;
        }
    }
}

bool BlockAssembler::TestPackage(uint64_t packageSize, int64_t packageSigOps) {
    auto blockSizeWithPackage = nBlockSize + packageSize;
    if (blockSizeWithPackage >= nMaxGeneratedBlockSize) {
        return false;
    }
    if (nBlockSigOps + packageSigOps >=
        GetMaxBlockSigOpsCount(blockSizeWithPackage)) {
        return false;
    }
    return true;
}

// Perform transaction-level checks before adding to block:
// - transaction finality (locktime)
// - serialized size (in case -blockmaxsize is in use)
bool BlockAssembler::TestPackageTransactions(
    const CTxMemPool::setEntries &package) {
    uint64_t nPotentialBlockSize = nBlockSize;
    for (const CTxMemPool::txiter it : package) {
        CValidationState state;
        if (!ContextualCheckTransaction(*config, it->GetTx(), state, nHeight,
                                        nLockTimeCutoff)) {
            return false;
        }

        uint64_t nTxSize =
            ::GetSerializeSize(it->GetTx(), SER_NETWORK, PROTOCOL_VERSION);
        if (nPotentialBlockSize + nTxSize >= nMaxGeneratedBlockSize) {
            return false;
        }

        nPotentialBlockSize += nTxSize;
    }

    return true;
}

bool BlockAssembler::TestForBlock(CTxMemPool::txiter it) {
    auto blockSizeWithTx =
        nBlockSize +
        ::GetSerializeSize(it->GetTx(), SER_NETWORK, PROTOCOL_VERSION);
    if (blockSizeWithTx >= nMaxGeneratedBlockSize) {
        if (nBlockSize > nMaxGeneratedBlockSize - 100 || lastFewTxs > 50) {
            blockFinished = true;
            return false;
        }
        if (nBlockSize > nMaxGeneratedBlockSize - 1000) {
            lastFewTxs++;
        }
        return false;
    }

    auto maxBlockSigOps = GetMaxBlockSigOpsCount(blockSizeWithTx);
    if (nBlockSigOps + it->GetSigOpCount() >= maxBlockSigOps) {
        // If the block has room for no more sig ops then flag that the block is
        // finished.
        // TODO: We should consider adding another transaction that isn't very
        // dense in sigops instead of bailing out so easily.
        if (nBlockSigOps > maxBlockSigOps - 2) {
            blockFinished = true;
            return false;
        }
        // Otherwise attempt to find another tx with fewer sigops to put in the
        // block.
        return false;
    }

    // Must check that lock times are still valid. This can be removed once MTP
    // is always enforced as long as reorgs keep the mempool consistent.
    CValidationState state;
    if (!ContextualCheckTransaction(*config, it->GetTx(), state, nHeight,
                                    nLockTimeCutoff)) {
        return false;
    }

    return true;
}

void BlockAssembler::AddToBlock(CTxMemPool::txiter iter) {
    pblock->vtx.emplace_back(iter->GetSharedTx());
    pblocktemplate->vTxFees.push_back(iter->GetFee());
    pblocktemplate->vTxSigOpsCount.push_back(iter->GetSigOpCount());
    nBlockSize += iter->GetTxSize();
    ++nBlockTx;
    nBlockSigOps += iter->GetSigOpCount();
    nFees += iter->GetFee();
    nInterest += iter->GetInterest();
    inBlock.insert(iter);

    bool fPrintPriority = GetBoolArg("-printpriority", DEFAULT_PRINTPRIORITY);
    if (fPrintPriority) {
        double dPriority = iter->GetPriority(nHeight);
        CAmount dummy;
        mempool.ApplyDeltas(iter->GetTx().GetId(), dPriority, dummy);
        LogPrintf(
            "priority %.1f fee %s txid %s\n", dPriority,
            CFeeRate(iter->GetModifiedFee(), iter->GetTxSize()).ToString(),
            iter->GetTx().GetId().ToString());
    }
}

int BlockAssembler::UpdatePackagesForAdded(
    const CTxMemPool::setEntries &alreadyAdded,
    indexed_modified_transaction_set &mapModifiedTx) {
    int nDescendantsUpdated = 0;
    for (const CTxMemPool::txiter it : alreadyAdded) {
        CTxMemPool::setEntries descendants;
        mempool.CalculateDescendants(it, descendants);
        // Insert all descendants (not yet in block) into the modified set.
        for (CTxMemPool::txiter desc : descendants) {
            if (alreadyAdded.count(desc)) {
                continue;
            }
            ++nDescendantsUpdated;
            modtxiter mit = mapModifiedTx.find(desc);
            if (mit == mapModifiedTx.end()) {
                CTxMemPoolModifiedEntry modEntry(desc);
                modEntry.nSizeWithAncestors -= it->GetTxSize();
                modEntry.nModFeesWithAncestors -= it->GetModifiedFee();
                modEntry.nSigOpCountWithAncestors -= it->GetSigOpCount();
                mapModifiedTx.insert(modEntry);
            } else {
                mapModifiedTx.modify(mit, update_for_parent_inclusion(it));
            }
        }
    }
    return nDescendantsUpdated;
}

// Skip entries in mapTx that are already in a block or are present in
// mapModifiedTx (which implies that the mapTx ancestor state is stale due to
// ancestor inclusion in the block). Also skip transactions that we've already
// failed to add. This can happen if we consider a transaction in mapModifiedTx
// and it fails: we can then potentially consider it again while walking mapTx.
// It's currently guaranteed to fail again, but as a belt-and-suspenders check
// we put it in failedTx and avoid re-evaluation, since the re-evaluation would
// be using cached size/sigops/fee values that are not actually correct.
bool BlockAssembler::SkipMapTxEntry(
    CTxMemPool::txiter it, indexed_modified_transaction_set &mapModifiedTx,
    CTxMemPool::setEntries &failedTx) {
    assert(it != mempool.mapTx.end());
    if (mapModifiedTx.count(it) || inBlock.count(it) || failedTx.count(it)) {
        return true;
    }
    return false;
}

void BlockAssembler::SortForBlock(
    const CTxMemPool::setEntries &package, CTxMemPool::txiter entry,
    std::vector<CTxMemPool::txiter> &sortedEntries) {
    // Sort package by ancestor count. If a transaction A depends on transaction
    // B, then A's ancestor count must be greater than B's. So this is
    // sufficient to validly order the transactions for block inclusion.
    sortedEntries.clear();
    sortedEntries.insert(sortedEntries.begin(), package.begin(), package.end());
    std::sort(sortedEntries.begin(), sortedEntries.end(),
              CompareTxIterByAncestorCount());
}

// This transaction selection algorithm orders the mempool based on feerate of a
// transaction including all unconfirmed ancestors. Since we don't remove
// transactions from the mempool as we select them for block inclusion, we need
// an alternate method of updating the feerate of a transaction with its
// not-yet-selected ancestors as we go. This is accomplished by walking the
// in-mempool descendants of selected transactions and storing a temporary
// modified state in mapModifiedTxs. Each time through the loop, we compare the
// best transaction in mapModifiedTxs with the next transaction in the mempool
// to decide what transaction package to work on next.
void BlockAssembler::addPackageTxs(int &nPackagesSelected,
                                   int &nDescendantsUpdated) {
    // mapModifiedTx will store sorted packages after they are modified because
    // some of their txs are already in the block.
    indexed_modified_transaction_set mapModifiedTx;
    // Keep track of entries that failed inclusion, to avoid duplicate work.
    CTxMemPool::setEntries failedTx;

    // Start by adding all descendants of previously added txs to mapModifiedTx
    // and modifying them for their already included ancestors.
    UpdatePackagesForAdded(inBlock, mapModifiedTx);

    CTxMemPool::indexed_transaction_set::index<ancestor_score>::type::iterator
        mi = mempool.mapTx.get<ancestor_score>().begin();
    CTxMemPool::txiter iter;

    // Limit the number of attempts to add transactions to the block when it is
    // close to full; this is just a simple heuristic to finish quickly if the
    // mempool has a lot of entries.
    const int64_t MAX_CONSECUTIVE_FAILURES = 1000;
    int64_t nConsecutiveFailed = 0;

    while (mi != mempool.mapTx.get<ancestor_score>().end() ||
           !mapModifiedTx.empty()) {
        // First try to find a new transaction in mapTx to evaluate.
        if (mi != mempool.mapTx.get<ancestor_score>().end() &&
            SkipMapTxEntry(mempool.mapTx.project<0>(mi), mapModifiedTx,
                           failedTx)) {
            ++mi;
            continue;
        }

        // Now that mi is not stale, determine which transaction to evaluate:
        // the next entry from mapTx, or the best from mapModifiedTx?
        bool fUsingModified = false;

        modtxscoreiter modit = mapModifiedTx.get<ancestor_score>().begin();
        if (mi == mempool.mapTx.get<ancestor_score>().end()) {
            // We're out of entries in mapTx; use the entry from mapModifiedTx
            iter = modit->iter;
            fUsingModified = true;
        } else {
            // Try to compare the mapTx entry to the mapModifiedTx entry.
            iter = mempool.mapTx.project<0>(mi);
            if (modit != mapModifiedTx.get<ancestor_score>().end() &&
                CompareModifiedEntry()(*modit, CTxMemPoolModifiedEntry(iter))) {
                // The best entry in mapModifiedTx has higher score than the one
                // from mapTx. Switch which transaction (package) to consider
                iter = modit->iter;
                fUsingModified = true;
            } else {
                // Either no entry in mapModifiedTx, or it's worse than mapTx.
                // Increment mi for the next loop iteration.
                ++mi;
            }
        }

        // We skip mapTx entries that are inBlock, and mapModifiedTx shouldn't
        // contain anything that is inBlock.
        assert(!inBlock.count(iter));

        uint64_t packageSize = iter->GetSizeWithAncestors();
        CAmount packageFees = iter->GetModFeesWithAncestors();
        int64_t packageSigOps = iter->GetSigOpCountWithAncestors();
        if (fUsingModified) {
            packageSize = modit->nSizeWithAncestors;
            packageFees = modit->nModFeesWithAncestors;
            packageSigOps = modit->nSigOpCountWithAncestors;
        }

        if (packageFees < blockMinFeeRate.GetFee(packageSize)) {
            // Everything else we might consider has a lower fee rate
            return;
        }

        if (!TestPackage(packageSize, packageSigOps)) {
            if (fUsingModified) {
                // Since we always look at the best entry in mapModifiedTx, we
                // must erase failed entries so that we can consider the next
                // best entry on the next loop iteration
                mapModifiedTx.get<ancestor_score>().erase(modit);
                failedTx.insert(iter);
            }

            ++nConsecutiveFailed;

            if (nConsecutiveFailed > MAX_CONSECUTIVE_FAILURES &&
                nBlockSize > nMaxGeneratedBlockSize - 1000) {
                // Give up if we're close to full and haven't succeeded in a
                // while.
                break;
            }
            continue;
        }

        CTxMemPool::setEntries ancestors;
        uint64_t nNoLimit = std::numeric_limits<uint64_t>::max();
        std::string dummy;
        mempool.CalculateMemPoolAncestors(*iter, ancestors, nNoLimit, nNoLimit,
                                          nNoLimit, nNoLimit, dummy, false);

        onlyUnconfirmed(ancestors);
        ancestors.insert(iter);

        // Test if all tx's are Final.
        if (!TestPackageTransactions(ancestors)) {
            if (fUsingModified) {
                mapModifiedTx.get<ancestor_score>().erase(modit);
                failedTx.insert(iter);
            }
            continue;
        }

        // This transaction will make it in; reset the failed counter.
        nConsecutiveFailed = 0;

        // Package can be added. Sort the entries in a valid order.
        std::vector<CTxMemPool::txiter> sortedEntries;
        SortForBlock(ancestors, iter, sortedEntries);

        for (size_t i = 0; i < sortedEntries.size(); ++i) {
            AddToBlock(sortedEntries[i]);
            // Erase from the modified set, if present
            mapModifiedTx.erase(sortedEntries[i]);
        }

        ++nPackagesSelected;

        // Update transactions that depend on each of these
        nDescendantsUpdated += UpdatePackagesForAdded(ancestors, mapModifiedTx);
    }
}

void BlockAssembler::addPriorityTxs() {
    // How much of the block should be dedicated to high-priority transactions,
    // included regardless of the fees they pay.
    if (config->GetBlockPriorityPercentage() == 0) {
        return;
    }

    uint64_t nBlockPrioritySize =
        nMaxGeneratedBlockSize * config->GetBlockPriorityPercentage() / 100;

    // This vector will be sorted into a priority queue:
    std::vector<TxCoinAgePriority> vecPriority;
    TxCoinAgePriorityCompare pricomparer;
    std::map<CTxMemPool::txiter, double, CTxMemPool::CompareIteratorByHash>
        waitPriMap;
    typedef std::map<CTxMemPool::txiter, double,
                     CTxMemPool::CompareIteratorByHash>::iterator waitPriIter;
    double actualPriority = -1;

    vecPriority.reserve(mempool.mapTx.size());
    for (CTxMemPool::indexed_transaction_set::iterator mi =
             mempool.mapTx.begin();
         mi != mempool.mapTx.end(); ++mi) {
        double dPriority = mi->GetPriority(nHeight);
        CAmount dummy;
        mempool.ApplyDeltas(mi->GetTx().GetId(), dPriority, dummy);
        vecPriority.push_back(TxCoinAgePriority(dPriority, mi));
    }
    std::make_heap(vecPriority.begin(), vecPriority.end(), pricomparer);

    CTxMemPool::txiter iter;

    // Add a tx from priority queue to fill the part of block reserved to
    // priority transactions.
    while (!vecPriority.empty() && !blockFinished) {
        iter = vecPriority.front().second;
        actualPriority = vecPriority.front().first;
        std::pop_heap(vecPriority.begin(), vecPriority.end(), pricomparer);
        vecPriority.pop_back();

        // If tx already in block, skip.
        if (inBlock.count(iter)) {
            // Shouldn't happen for priority txs.
            assert(false);
            continue;
        }

        // If tx is dependent on other mempool txs which haven't yet been
        // included then put it in the waitSet.
        if (isStillDependent(iter)) {
            waitPriMap.insert(std::make_pair(iter, actualPriority));
            continue;
        }

        // If this tx fits in the block add it, otherwise keep looping.
        if (TestForBlock(iter)) {
            AddToBlock(iter);

            // If now that this txs is added we've surpassed our desired
            // priority size or have dropped below the AllowFreeThreshold, then
            // we're done adding priority txs.
            if (nBlockSize >= nBlockPrioritySize ||
                !AllowFree(actualPriority)) {
                break;
            }

            // This tx was successfully added, so add transactions that depend
            // on this one to the priority queue to try again.
            for (CTxMemPool::txiter child : mempool.GetMemPoolChildren(iter)) {
                waitPriIter wpiter = waitPriMap.find(child);
                if (wpiter != waitPriMap.end()) {
                    vecPriority.push_back(
                        TxCoinAgePriority(wpiter->second, child));
                    std::push_heap(vecPriority.begin(), vecPriority.end(),
                                   pricomparer);
                    waitPriMap.erase(wpiter);
                }
            }
        }
    }
}

void IncrementExtraNonce(const Config &config, CBlock *pblock,
                         const CBlockIndex *pindexPrev,
                         unsigned int &nExtraNonce) {
    // Update nExtraNonce
    static uint256 hashPrevBlock;
    if (hashPrevBlock != pblock->hashPrevBlock) {
        nExtraNonce = 0;
        hashPrevBlock = pblock->hashPrevBlock;
    }
    ++nExtraNonce;
    // Height first in coinbase required for block.version=2
//    unsigned int nHeight = pindexPrev->nHeight + 1;
//    CMutableTransaction txCoinbase(*pblock->vtx[0]);
//    txCoinbase.vin[0].scriptSig =
//        (CScript() << nHeight << CScriptNum(nExtraNonce)
//                   << getExcessiveBlockSizeSig(config)) +
//        COINBASE_FLAGS;
//    assert(txCoinbase.vin[0].scriptSig.size() <= MAX_COINBASE_SCRIPTSIG_SIZE);

//    pblock->vtx[0] = MakeTransactionRef(std::move(txCoinbase));
    pblock->hashMerkleRoot = BlockMerkleRoot(*pblock);
}

CCriticalSection cs_miner;

MineWorker::MineWorker(const Config &_config):config(&_config)
{
    //GetMainSignals().ScriptForMining(coinbaseScript);
    scriptPubKey = CScript();

    fGenerate           = false;
    fPoolMiningFinished = true;

    nThreads      = -1;
    dHashesPerSec = 0.0;

    currentTemplate = NULL;
    minerThreads    = NULL;
    workDispatcher  = NULL;
    dagGenerator    = NULL;

    mapEpochLight.clear();
    mapEpochLight.clear();
    listWork.clear();
}

MineWorker::~MineWorker()
{
    if (currentTemplate){
        delete currentTemplate;
        currentTemplate = NULL;
    }

    DestroyEthashFull();
    DestroyEthashLight();
}

/*
void MineWorker::SetMinerAddress(CBitcoinAddress address)
{
    scriptPubKey = GetScriptForDestination(address.Get());
}

CBitcoinAddress MineWorker::GetMinerAddress()
{
    CTxDestination dest;
    ExtractDestination(scriptPubKey, dest);

    return CBitcoinAddress(dest);
}
*/

int MineWorker::GetThreads()
{
    return nThreads;
}

void MineWorker::SetThreads(int threadCount)
{
    nThreads = threadCount;
}

void MineWorker::RunWorker()
{
    CleanWork();
    PlatopiaMinerPoolStart();

    if (dagGenerator != NULL) {
        dagGenerator->interrupt();

        delete dagGenerator; dagGenerator = NULL;
    }

    if (workDispatcher != NULL) {
        workDispatcher->interrupt();

        delete workDispatcher; workDispatcher = NULL;
    }

    if (fGenerate) {
        dagGenerator = new boost::thread(boost::bind(&(MineWorker::dagGeneratorWork), this));
    }

    if (fGenerate) {
        workDispatcher = new boost::thread(boost::bind(&(MineWorker::dispatchWork), this));
    }

}

void MineWorker::StopWorker()
{
    PlatoPiaMinerPoolStop();
    CleanWork();
}

void MineWorker::PlatopiaMinerPoolStart(uint64_t nMaxTries)
{
    LogPrintf("PlatoPiaMinerPoolStart \n");

    fGenerate = true;
    if (nThreads < 0) {
        // In regtest threads defaults to 1
        if (Params().DefaultMinerThreads())
            nThreads = Params().DefaultMinerThreads();
        else
            nThreads = boost::thread::hardware_concurrency();
    }

    if (minerThreads != NULL) {
        minerThreads->interrupt_all();
        fPoolMiningFinished=true;

        delete minerThreads; minerThreads = NULL;
    }

    if (nThreads == 0 || !fGenerate) {
        fGenerate = false;
        LogPrintf("nThreads: %d\tfGenerate: %s\n", nThreads, fGenerate ? "true":"false");
        return;
    }
    dHashesPerSec = 0.0;

    LogPrintf("PlatopiaMinerPoolStart threads %d\n", nThreads);

    minerThreads = new boost::thread_group();
    for (int i = 0; i < nThreads; i++) {
        minerThreads->create_thread(boost::bind(&(MineWorker::doWork), this, nMaxTries));
    }

    return;
}

void MineWorker::dagGeneratorWork(MineWorker *worker)
{
    RenameThread("dagGeneratorWork");

    while (worker->fGenerate) {
        if (worker->GetEthashFull(chainActive.Height()) == NULL) worker->AppendEthashFull(chainActive.Height());

        if (chainActive.Height() % ETHASH_EPOCH_LENGTH > 20000) {
            worker->AppendEthashFull(chainActive.Height() + ETHASH_EPOCH_LENGTH);
        }

        MilliSleep(10 * 1000);
    }
}

void MineWorker::PlatoPiaMinerPoolStop()
{
    LogPrintf("PlatopiaMinerPoolStop\n");
    if (minerThreads != NULL) {
        minerThreads->interrupt_all();
        fPoolMiningFinished = true;
        delete minerThreads; minerThreads = NULL;
        dHashesPerSec = 0;
    }

    fGenerate = false;
}

bool MineWorker::AppendEthashFull(uint32_t nBlockHeight)
{
    if (mapEpochFull.find(nBlockHeight/ ETHASH_EPOCH_LENGTH) != mapEpochFull.end()) {
        return true;
    }

    {
        LOCK(cs_ethash);
        ethash_light_t plight = GetEthashLight(nBlockHeight);
        ethash_full_t  pfull  = ethash_full_new(plight, dagCallbackShim);

        int64_t nEpochs = nBlockHeight / ETHASH_EPOCH_LENGTH;
        mapEpochFull.insert(make_pair(nEpochs, pfull));
    }

    return true;
}

ethash_full_t MineWorker::GetEthashFull(uint32_t nBlockHeight) const
{
    if (mapEpochFull.find(nBlockHeight/ ETHASH_EPOCH_LENGTH) != mapEpochFull.end()) {
        return mapEpochFull.at(nBlockHeight / ETHASH_EPOCH_LENGTH);
    }

    return NULL;
}

bool MineWorker::EraseEthashFull(uint32_t nBlockHeight)
{
    if (mapEpochFull.find(nBlockHeight/ ETHASH_EPOCH_LENGTH) == mapEpochFull.end()) return true;

    ethash_full_t pfull = mapEpochFull.at(nBlockHeight / ETHASH_EPOCH_LENGTH);
    ethash_full_delete(pfull);
    mapEpochFull.erase(nBlockHeight / ETHASH_EPOCH_LENGTH);

    return true;
}

void MineWorker::DestroyEthashFull()
{
    for(std::map<int64_t, ethash_full_t>::iterator it = mapEpochFull.begin(); it != mapEpochFull.end(); it++) {
        ethash_full_t pfull = it->second;
        ethash_full_delete(pfull);
    }

    mapEpochFull.clear();
}

bool MineWorker::AppendEthashLight(uint32_t nBlockHeight)
{
    if (mapEpochLight.find(nBlockHeight/ ETHASH_EPOCH_LENGTH) != mapEpochLight.end()) {
        return true;
    }

    {
        LOCK(cs_ethash);
        ethash_light_t plight  = ethash_light_new(nBlockHeight);
        int64_t        nEpochs = nBlockHeight / ETHASH_EPOCH_LENGTH;
        mapEpochLight.insert(make_pair(nEpochs, plight));
    }

    return true;
}

ethash_light_t MineWorker::GetEthashLight(uint32_t nBlockHeight)
{
    if (mapEpochLight.find(nBlockHeight/ ETHASH_EPOCH_LENGTH) != mapEpochLight.end()) {
        return mapEpochLight.at(nBlockHeight / ETHASH_EPOCH_LENGTH);
    }

    AppendEthashLight(nBlockHeight);
    return mapEpochLight.at(nBlockHeight / ETHASH_EPOCH_LENGTH);
}

bool MineWorker::EraseEthashLight(uint32_t nBlockHeight)
{
    if (mapEpochLight.find(nBlockHeight/ ETHASH_EPOCH_LENGTH) == mapEpochLight.end()) return true;

    ethash_light_t plight = mapEpochLight.at(nBlockHeight / ETHASH_EPOCH_LENGTH);
    ethash_light_delete(plight);
    mapEpochLight.erase(nBlockHeight / ETHASH_EPOCH_LENGTH);

    return true;
}

void MineWorker::DestroyEthashLight()
{
    for(std::map<int64_t, ethash_light_t>::iterator it = mapEpochLight.begin(); it != mapEpochLight.end(); it++) {
        ethash_light_t plight = it->second;
        ethash_light_delete(plight);
    }

    mapEpochLight.clear();
}

void MineWorker::dispatchSingleWork(MineWorker *worker, std::shared_ptr<CReserveScript> coinbaseScript,
                                       int nBlocks, bool keepScript, vector<uint256> *vHashes)
{
    RenameThread("dispatchSingleWork");

    SetThreadPriority(THREAD_PRIORITY_LOWEST);
    LogPrintf("dispatchSingleWork: blocks: %d\n", nBlocks);
    while (worker->fGenerate && nBlocks) {
        worker->CleanWork();
        Work work = worker->GenNewWork(coinbaseScript->reserveScript);
        //Work work = worker->GenNewWork(worker->scriptPubKey);
        auto pwork = worker->AddWork(work.block, work.boundary);

        while (worker->fGenerate && nBlocks) {
            if (pwork->done) {
                SetThreadPriority(THREAD_PRIORITY_NORMAL);

                if (worker->ProcessBlockFound(worker->config, &(pwork->block), *pwalletMain)) {
                    vHashes->push_back(pwork->block.GetHash());
                    worker->RemoveWork(pwork->blockEthash);
                    nBlocks--;

                    if (keepScript) {
                        coinbaseScript->KeepScript();
                    }
                }
                SetThreadPriority(THREAD_PRIORITY_LOWEST);
                break;
            }
            static int64_t nLogTime;
            if (GetTime() - nLogTime > 1 * 30) {
                nLogTime = GetTime();
                LogPrintf("hashmeter %6.3f khash/s\n", worker->GetHashRate()/1000.0);
            }

            MilliSleep(1000);
        }
    }
}

void MineWorker::dispatchWork(MineWorker *worker)
{
    RenameThread("dispatchWork");

    SetThreadPriority(THREAD_PRIORITY_LOWEST);

    while (worker->fGenerate) {
        Work work = worker->GenNewWork(worker->scriptPubKey);
        auto pwork = worker->AddWork(work.block, work.boundary);

        while (worker->fGenerate) {
            if(chainActive.Height() >= pwork->block.nBlockHeight)
            {
                pwork->deprecated = true;
                while(pwork->miningThreads != 0)
                {
                    MilliSleep(1000);
                }

                worker->RemoveWork(pwork->blockEthash);
                break;
            }
            else
            {
                if (pwork->done)
                {
                    SetThreadPriority(THREAD_PRIORITY_NORMAL);
                    worker->ProcessBlockFound(worker->config, &(pwork->block), *pwalletMain);
                    while(pwork->miningThreads != 0)
                    {
                        MilliSleep(1000);
                    }

                    worker->RemoveWork(pwork->blockEthash);
                    SetThreadPriority(THREAD_PRIORITY_LOWEST);
                    break;
                }

                static int64_t nLogTime;
                if (GetTime() - nLogTime > 1 * 30) {
                    nLogTime = GetTime();
                    LogPrintf("hashmeter %6.3f khash/s\n", worker->GetHashRate()/1000.0);
                }
            }

            MilliSleep(1000);
        }
    }

}

void MineWorker::doWork(MineWorker *worker, uint64_t nMaxTries)
{
    RenameThread("doWork");

    while (worker->fGenerate) {
        auto work = worker->GetWork();
        if (work == NULL || work->done || work->deprecated) {
            MilliSleep(1000);
            continue;
        }

        {
            LOCK(cs_miner);
            work->miningThreads++;
        }

        uint32_t nBlockHeight = work->block.nBlockHeight;
        ethash_h256_t blockEthash = work->blockEthash;
        ethash_h256_t boundary    = work->boundary;
        LogPrintf("Work on: %s\n", ethash_h256_encode(blockEthash));

        ethash_h256_t mixHash = {0};
        uint64_t nNonce = 0;
        SetThreadPriority(THREAD_PRIORITY_LOWEST);
        if(worker->MinePlatopia(&(work->done), &(work->deprecated), blockEthash, nBlockHeight, boundary, &mixHash, &nNonce, nMaxTries))
        {
            work->block.nNonce  = nNonce;
            work->block.hashMix = mixHash;
            work->done = true;
        }
        {
            LOCK(cs_miner);
            work->miningThreads--;
        }
        SetThreadPriority(THREAD_PRIORITY_LOWEST);
        if (!worker->fGenerate)
        {
            break;
        }
    }

}

inline bool MineWorker::MinePlatopia(bool *fDone, bool *deprecated, ethash_h256_t blockEthash, uint64_t nBlockHeight, ethash_h256_t boundary, ethash_h256_t *mixHashOut, uint64_t *nonceOut, uint64_t nMaxTries)
{

    ethash_full_t pfull = GetEthashFull(nBlockHeight);
    while (pfull == NULL) {
        if (!fGenerate) return false;
        pfull = GetEthashFull(nBlockHeight);
        MilliSleep(1000);
    }
    uint64_t nNonce = GetRand(0xffffffffffffffff);

    uint64_t nTryCount      = 0;
    uint64_t nHashCount     = 0;
    int64_t  nHPSTimerStart = 0;

    while(fGenerate && !*fDone && !*deprecated) {
        ethash_return_value_t ret = ethash_full_compute(pfull, blockEthash, nNonce);
        if (ethash_quick_check_difficulty( &blockEthash, nNonce, &(ret.mix_hash), &boundary )) {
            // Found a solution
            SetThreadPriority(THREAD_PRIORITY_NORMAL);
            LogPrintf("PlatopiaMiner:\n");
            LogPrintf("proof-of-work found  \n");
            LogPrintf("   Ethash: %s\n", ethash_h256_encode(blockEthash));
            LogPrintf("   Target: %s\n", ethash_h256_encode(boundary));
            LogPrintf("   Nonce: %llu\n", nNonce);
            LogPrintf("   MixHash: %s\n", ethash_h256_encode(ret.mix_hash));
            *mixHashOut = ret.mix_hash;
            *nonceOut = nNonce;
            // In regression test mode, stop mining after a block is found.
            return true;
        }

        nHashCount += 1;
        nNonce     += 1;

        if(nMaxTries != 0) {
            nTryCount  += 1;

            if(nTryCount > nMaxTries) {
                break;
            }
        }

        if (GetTimeMillis() - nHPSTimerStart > 4000) {
            static CCriticalSection cs;
            {
                LOCK(cs);
                dHashesPerSec = (double)(1000.0 * nHashCount / (GetTimeMillis() - nHPSTimerStart));
            }
            nHPSTimerStart = GetTimeMillis();
            nHashCount = 0;
        }
    }

    return false;
}

double MineWorker::GetHashRate() const
{
    if (nThreads <= 1) return dHashesPerSec;
    return dHashesPerSec * nThreads;
}

void MineWorker::SetHashRate(double dRate)
{
    dHashesPerSec = dRate;

    static int64_t nLogTime;
    if (GetTime() - nLogTime > 1 * 30) {
        nLogTime = GetTime();
        LogPrintf("hashmeter %6.3f khash/s\n", GetHashRate()/1000.0);
    }
}

Work MineWorker::GenNewWork(const CScript &scriptPubKeyIn)
{
    unique_ptr<CBlockTemplate> pblocktemplate(BlockAssembler((*config), Params()).CreateNewBlock(scriptPubKeyIn));

    if (!pblocktemplate.get()) throw error("CreateBlock Failed\n");

    CBlock *pblock = &pblocktemplate->block;

    unsigned int nExtraNonce = 0;
    {
        LOCK(cs_main);
        IncrementExtraNonce(*config, pblock, chainActive.Tip(), nExtraNonce);
    }

    arith_uint256 hashTarget  = arith_uint256().SetCompact(pblock->nBits);
    ethash_h256_t boundary    = hashTarget.ToEthashH256();
    ethash_h256_t blockEthash = CBlockHeaderBase(*pblock).GetEthash();

    return {*pblock, blockEthash, boundary, false, 0, false};
}

std::shared_ptr<Work>
MineWorker::AddWork(CBlock &block, ethash_h256_t boundary)
{
    ethash_h256_t blockEthash = CBlockHeaderBase(block).GetEthash();
    for (auto it = listWork.begin(); it != listWork.end(); it++) {
        if (EthashEquals((*it)->blockEthash, blockEthash) && EthashEquals(boundary, (*it)->boundary)) {
            return *it;
        }
    }

    LogPrintf("Add a new work %s\n", ethash_h256_encode(blockEthash));
    std::shared_ptr<Work> newWork(new Work{block, blockEthash, boundary, false, 0, false});
    listWork.push_back(newWork);
    return listWork.back();
}

std::shared_ptr<Work> MineWorker::GetWork() const
{
    for (auto it : listWork) {
        if (it->done) continue;

        return it;
    }

    LogPrintf("GetWork no work\n");
    return NULL;
}

std::shared_ptr<Work> MineWorker::GetWork(ethash_h256_t &blockEthash) const
{
    for (auto it : listWork) {
        if (EthashEquals(it->blockEthash, blockEthash)) return it;
    }

    return NULL;
}

void MineWorker::UpdateWork(ethash_h256_t &blockEthash, uint64_t &nonce, ethash_h256_t &hashMix)
{
    for (auto it : listWork) {
        if (EthashEquals(it->blockEthash, blockEthash)) {
            it->block.nNonce  = nonce;
            it->block.hashMix = hashMix;
        }
    }
}

void MineWorker::RemoveWork(const ethash_h256_t &blockEthash)
{
    LogPrintf("RemoveWork: %s\n", ethash_h256_encode_big(blockEthash));
    listWork.remove_if(([&, blockEthash](std::shared_ptr<Work> work){ return EthashEquals(work->blockEthash, blockEthash ); }));
}

void MineWorker::RemoveWork(uint32_t nBlockHeight)
{
    LogPrintf("RemoveWork: %u\n", nBlockHeight);
    listWork.remove_if(([&, nBlockHeight](std::shared_ptr<Work> work){ return work->block.nBlockHeight == nBlockHeight ; }));
}

void MineWorker::SetWorkDone(ethash_h256_t &blockEthash)
{
    for (auto it : listWork) {
        if (EthashEquals(it->blockEthash, blockEthash)) {
            it->done = true;
        }
    }
}

void MineWorker::ShowWorkList() const
{
    int i = 0;
    for (auto it : listWork) {
        LogPrintf("Work Index:%d, BlockEthash: %s, Height: %ld, Done: %s\n", i++, ethash_h256_encode_big(it->blockEthash), it->block.nBlockHeight, it->done ? "true":"false");
    }
}

void MineWorker::CleanWork()
{
    listWork.clear();
}

bool MineWorker::ProcessBlockFound(const Config *config, const CBlock* pblock, CWallet& wallet)
{

    LogPrintf("%s\n", pblock->ToString());
    LogPrintf("generated %s\n", FormatMoney(pblock->vtx[0]->GetValueOut()));

    // Found a solution
    {
        LOCK(cs_main);
        if (pblock->hashPrevBlock != chainActive.Tip()->GetBlockHash())
            return error("PlatopiaMiner : generated block is stale");
    }

    // Track how many getdata requests this block gets
    {
        LOCK(wallet.cs_wallet);
        wallet.mapRequestCount[pblock->GetHash()] = 0;
    }

    // Process this block the same as if we had received it from another node
    bool fNewBlock = false;
    std::shared_ptr<const CBlock> shared_pblock = std::make_shared<const CBlock>(*pblock);
    if (!ProcessNewBlock(*config, shared_pblock, true, &fNewBlock))
        return error("Platopia Miner : ProcessNewBlock, block not accepted");

    uint256 blockhash = pblock->GetHash();
    LogPrintf("NotifyBlockMined block hash %s", blockhash.ToString());
    //uiInterface.NotifyBlockMined(blockhash);

    return true;
}

vector<uint256> MineWorker::MineBlocks(std::shared_ptr<CReserveScript> coinbaseScript,
                                       int nGenerate, uint64_t nMaxTries, bool keepScript)
{
    CleanWork();
    PlatopiaMinerPoolStart(nMaxTries);

    if (dagGenerator != NULL) {
        dagGenerator->interrupt();

        delete dagGenerator; dagGenerator = NULL;
    }

    if (fGenerate) {
        dagGenerator = new boost::thread(boost::bind(&(MineWorker::dagGeneratorWork), this));
    }

    vector<uint256> blockHashes;
    if (workDispatcher != NULL) {
        workDispatcher->interrupt();

        delete workDispatcher; workDispatcher = NULL;
    }

    if (fGenerate) {
        workDispatcher = new boost::thread(boost::bind(&(MineWorker::dispatchSingleWork), this, coinbaseScript, nGenerate, keepScript, &blockHashes));
        //workDispatcher = new boost::thread(boost::bind(&(MineWorker::dispatchSingleWork), this, nBlocks, &blockHashes));
    }

    if (workDispatcher) {
        workDispatcher->join();
    }

    PlatoPiaMinerPoolStop();
    return blockHashes;
}

std::shared_ptr<Work> MineWorker::GetLastNewWork(std::shared_ptr<CReserveScript> coinbaseScript, bool keepScript, bool prune)
{
/*
    txnouttype outType = TX_NONSTANDARD;
    if(!IsStandard(scriptPubKey, outType))
    {
        string sAddress = pwalletMain->GetAddress();
        CBitcoinAddress address(sAddress);
        SetMinerAddress(address);
    }
*/

    auto pwork = GetWork();
    if (!pwork) {
        Work work = GenNewWork(scriptPubKey);
        LogPrintf("Gen NewWork NULL\n");
        pwork = AddWork(work.block, work.boundary);
    }

    if(prune)
    {
        while(pwork->block.nBlockHeight <= chainActive.Height())
        {
            RemoveWork(pwork->block.nBlockHeight);
            pwork = GetWork();
            if (!pwork) {
                Work work = GenNewWork(scriptPubKey);
                LogPrintf("Gen NewWork Height\n");
                pwork = AddWork(work.block, work.boundary);
            }
        }
    }

    ShowWorkList();
    return pwork;
}

bool MineWorker::SubmitWork(ethash_h256_t blockEthash, uint64_t nNonce, ethash_h256_t mixHash)
{
    SetWorkDone(blockEthash);
    UpdateWork(blockEthash, nNonce, mixHash);
    auto pwork = GetWork(blockEthash);
    if (pwork == NULL) {
        LogPrintf("no such Work %s\n", ethash_h256_encode(blockEthash));
        return false;
    }

    if (ProcessBlockFound(config, &(pwork->block), *pwalletMain)) {
        return true;
    }

    RemoveWork(pwork->blockEthash);
    return false;
}


text:
#ifndef COMMANDSERVER_HPP_
#define COMMANDSERVER_HPP_

#include "Thread.hpp"
#include "Network/TCPServer.hpp"

#include "CommandInterpreter.hpp"

#include <boost/foreach.hpp>

namespace Core {

class CommandServer : public Common::Thread {
public:

	CommandServer() {
		m_server.setServiceHook(boost::bind(&CommandServer::service, this, _1, _2, _3, _4));
		m_server.setCompletionHook(boost::bind(&CommandServer::completion, this, _1, _2));
	}

	void stop() {
		m_server.stop();
	}

	void addInformer(Informer * informer) {
		m_interpreter.addInformer(informer);
	}

	void printCommands() {
		m_interpreter.printCommands();
	}

protected:
	void run() {
		m_server.start();
	}

	int service(const unsigned char * msg, int /* msg_size */, unsigned char * reply, int reply_limit) {
		std::string rep = m_interpreter.execute((char*)msg+2);

		// empty reply is possible!
		int rep_size = (int)rep.size() < reply_limit - 3 ? rep.size() + 3 : reply_limit;
		reply[0] = rep_size / 256;
		reply[1] = rep_size % 256;

		strncpy((char*)reply+2, rep.c_str(), reply_limit-2);
		reply[reply_limit-1] = 0;

		return rep_size;
	}

	int completion(const unsigned char * msg, int msg_size) {
		return msg_size > 1 ? msg[0] * 256 + msg[1] : 2;
	}

private:
	Common::TCPServer m_server;

	CommandInterpreter m_interpreter;
};

}

#endif /* COMMANDSERVER_HPP_ */

ext: hpp

max_stars_repo_name: mlaszko/DisCODe

max_issues_repo_name: mlaszko/DisCODe

max_forks_repo_name: mlaszko/DisCODe


text:
/*
 * Copyright 2015-2019 Autoware Foundation. All rights reserved.
 *
 * 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.
 */

#include <arpa/inet.h>
#include <netinet/in.h>

#include <thread>

#include <boost/thread.hpp>

#include <ros/ros.h>
#include <ros/console.h>

#include <geometry_msgs/PoseStamped.h>
#include <tf/transform_datatypes.h>

#include <tablet_socket_msgs/mode_info.h>

#include <udon_socket/udon.hpp>

namespace {

struct Vehicle {
	std::int32_t mode;
	udon_socket::udon::Location location;
};

Vehicle vehicle;
boost::shared_mutex vehicle_mtx;

void cache_mode(const tablet_socket_msgs::mode_info& msg)
{
	boost::upgrade_lock<boost::shared_mutex> up_lock(vehicle_mtx);
	boost::upgrade_to_unique_lock<boost::shared_mutex> write_lock(up_lock);

	vehicle.mode = msg.mode;
}

void cache_pose(const geometry_msgs::PoseStamped& msg)
{
	boost::upgrade_lock<boost::shared_mutex> up_lock(vehicle_mtx);
	boost::upgrade_to_unique_lock<boost::shared_mutex> write_lock(up_lock);

	// msg's X-Y axis is reversed
	vehicle.location.x = msg.pose.position.y;
	vehicle.location.y = msg.pose.position.x;
	vehicle.location.z = msg.pose.position.z;
	vehicle.location.d = tf::getYaw(msg.pose.orientation);
	vehicle.location.d = (-1 * vehicle.location.d) + (M_PI / 2);
	vehicle.location.d = fmod(vehicle.location.d, (2 * M_PI));
	if (vehicle.location.d < 0)
		vehicle.location.d += (2 * M_PI);
}

void send_info(const sockaddr_in client_addr, int connect_fd, std::size_t bufsize, int period)
{
	std::uint8_t *buf;
	bool first;

	char astr[INET_ADDRSTRLEN];
	if (inet_ntop(AF_INET, &client_addr.sin_addr, astr, sizeof(astr)) == nullptr) {
		ROS_ERROR_STREAM("inet_ntop: " << std::strerror(errno));
		goto close_connect_fd;
	}

	buf = new std::uint8_t[bufsize];
	first = true;

	Vehicle curr, prev;
	while (true) {
		boost::shared_lock<boost::shared_mutex> read_lock(vehicle_mtx);
		curr = vehicle;
		read_lock.unlock();

		if (first) {
			ssize_t nbytes = udon_socket::udon::send_request(connect_fd);
			if (nbytes < 0) {
				ROS_ERROR_STREAM("udon_socket::udon::send_request: " << std::strerror(errno));
				goto delete_buf;
			}
			nbytes = recv(connect_fd, buf, bufsize, 0);
			if (nbytes < 0) {
				ROS_ERROR_STREAM("recv: " << std::strerror(errno));
				goto delete_buf;
			} else if (nbytes == 0) {
				ROS_INFO_STREAM("disconnect " << astr << ":" << ntohs(client_addr.sin_port));
				goto delete_buf;
			}

			nbytes = udon_socket::udon::send_mode(connect_fd, curr.mode);
			if (nbytes < 0) {
				ROS_ERROR_STREAM("udon_socket::udon::send_mode: " << std::strerror(errno));
				goto delete_buf;
			}
			nbytes = recv(connect_fd, buf, bufsize, 0);
			if (nbytes < 0) {
				ROS_ERROR_STREAM("recv: " << std::strerror(errno));
				goto delete_buf;
			} else if (nbytes == 0) {
				ROS_INFO_STREAM("disconnect " << astr << ":" << ntohs(client_addr.sin_port));
				goto delete_buf;
			}

			if (curr.mode == udon_socket::udon::MODE_AUTO) {
				nbytes = udon_socket::udon::send_location(connect_fd, curr.location);
				if (nbytes < 0) {
					ROS_ERROR_STREAM("udon_socket::udon::send_location: " << std::strerror(errno));
					goto delete_buf;
				}
				nbytes = recv(connect_fd, buf, bufsize, 0);
				if (nbytes < 0) {
					ROS_ERROR_STREAM("recv: " << std::strerror(errno));
					goto delete_buf;
				} else if (nbytes == 0) {
					ROS_INFO_STREAM("disconnect " << astr << ":" << ntohs(client_addr.sin_port));
					goto delete_buf;
				}
			}

			first = false;
		} else {
			if (curr.mode != prev.mode) {
				ssize_t nbytes = udon_socket::udon::send_mode(connect_fd, curr.mode);
				if (nbytes < 0) {
					ROS_ERROR_STREAM("udon_socket::udon::send_mode: " << std::strerror(errno));
					goto delete_buf;
				}
				nbytes = recv(connect_fd, buf, bufsize, 0);
				if (nbytes < 0) {
					ROS_ERROR_STREAM("recv: " << std::strerror(errno));
					goto delete_buf;
				} else if (nbytes == 0) {
					ROS_INFO_STREAM("disconnect " << astr << ":" << ntohs(client_addr.sin_port));
					goto delete_buf;
				}
			}

			if (curr.mode == udon_socket::udon::MODE_AUTO && curr.location != prev.location) {
				ssize_t nbytes = udon_socket::udon::send_location(connect_fd, curr.location);
				if (nbytes < 0) {
					ROS_ERROR_STREAM("udon_socket::udon::send_location: " << std::strerror(errno));
					goto delete_buf;
				}
				nbytes = recv(connect_fd, buf, bufsize, 0);
				if (nbytes < 0) {
					ROS_ERROR_STREAM("recv: " << std::strerror(errno));
					goto delete_buf;
				} else if (nbytes == 0) {
					ROS_INFO_STREAM("disconnect " << astr << ":" << ntohs(client_addr.sin_port));
					goto delete_buf;
				}
			}
		}

		prev = curr;

		std::this_thread::sleep_for(std::chrono::milliseconds(period));
	}

delete_buf:
	delete[] buf;
close_connect_fd:
	close(connect_fd);
}

void accept_sock(int backlog, std::size_t bufsize, int period, std::uint16_t port)
{
	int listen_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (listen_fd < 0) {
		ROS_ERROR_STREAM("socket: " << std::strerror(errno));
		return;
	}

	const int on = 1;
	if (setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
		ROS_ERROR_STREAM("setsockopt: " << std::strerror(errno));
		goto close_listen_fd;
	}

	sockaddr_in server_addr;
	std::memset(&server_addr, 0, sizeof(server_addr));
	server_addr.sin_family = AF_INET;
	server_addr.sin_port = htons(port);
	server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
	if (bind(listen_fd, reinterpret_cast<const sockaddr *>(&server_addr), sizeof(server_addr)) < 0) {
		ROS_ERROR_STREAM("bind: " << std::strerror(errno));
		goto close_listen_fd;
	}

	if (listen(listen_fd, backlog) < 0) {
		ROS_ERROR_STREAM("listen: " << std::strerror(errno));
		goto close_listen_fd;
	}

	char astr[INET_ADDRSTRLEN];
	if (inet_ntop(AF_INET, &server_addr.sin_addr, astr, sizeof(astr)) == nullptr) {
		ROS_ERROR_STREAM("inet_ntop: " << std::strerror(errno));
		goto close_listen_fd;
	}
	ROS_INFO_STREAM("listen " << astr << ":" << ntohs(server_addr.sin_port));

	int connect_fd;
	while (true) {
		sockaddr_in client_addr;
		socklen_t len = sizeof(client_addr);
		connect_fd = accept(listen_fd, reinterpret_cast<sockaddr *>(&client_addr), &len);
		if (connect_fd < 0) {
			ROS_ERROR_STREAM("accept: " << std::strerror(errno));
			goto close_listen_fd;
		}

		if (inet_ntop(AF_INET, &client_addr.sin_addr, astr, sizeof(astr)) == nullptr) {
			ROS_ERROR_STREAM("inet_ntop: " << std::strerror(errno));
			goto close_connect_fd;
		}
		ROS_INFO_STREAM("connect " << astr << ":" << ntohs(client_addr.sin_port));

		try {
			std::thread sender(send_info, client_addr, connect_fd, bufsize, period);
			sender.detach();
		} catch (std::exception &ex) {
			ROS_ERROR_STREAM("std::thread::thread: " << ex.what());
			goto close_connect_fd;
		}
	}

close_connect_fd:
	close(connect_fd);
close_listen_fd:
	close(listen_fd);
}

} // namespace

int main(int argc, char **argv)
{
	ros::init(argc, argv, "udon_sender");

	ros::NodeHandle n;

	int backlog;
	n.param<int>("/udon_sender/backlog", backlog, 128);
	int bufsize;
	n.param<int>("/udon_sender/bufsize", bufsize, 4096);
	int period;
	n.param<int>("/udon_sender/period", period, 200);
	int port;
	n.param<int>("/udon_sender/port", port, 5999);
	int sub_mode_queue_size;
	n.param<int>("/udon_sender/sub_mode_queue_size", sub_mode_queue_size, 1);
	int sub_pose_queue_size;
	n.param<int>("/udon_sender/sub_pose_queue_size", sub_pose_queue_size, 1);
	ROS_INFO_STREAM("backlog = " << backlog);
	ROS_INFO_STREAM("bufsize = " << bufsize);
	ROS_INFO_STREAM("period = " << period);
	ROS_INFO_STREAM("port = " << port);
	ROS_INFO_STREAM("sub_mode_queue_size = " << sub_mode_queue_size);
	ROS_INFO_STREAM("sub_pose_queue_size = " << sub_pose_queue_size);

	ros::Subscriber mode_sub = n.subscribe("/mode_info", sub_mode_queue_size, cache_mode);
	ros::Subscriber pose_sub = n.subscribe("/current_pose", sub_pose_queue_size, cache_pose);

	try {
		std::thread server(accept_sock, backlog, bufsize, period, port);
		server.detach();
	} catch (std::exception &ex) {
		ROS_ERROR_STREAM("std::thread::thread: " << ex.what());
		return EXIT_FAILURE;
	}

	ros::spin();

	return EXIT_SUCCESS;
}

ext: cpp


text:
#ifndef STAT_MAP_PHYLOGENETIC_HPP
#define STAT_MAP_PHYLOGENETIC_HPP

#include <numeric>
#include <boost/multi_array.hpp>
#include <sferes/stat/stat.hpp>
#include <glog/logging.h>
#include <boost/filesystem.hpp>

namespace sferes
{
  namespace stat
  {
    SFERES_STAT(MapImagePhylogeneticStat, ImageStat)
    {
    public:
      typedef boost::shared_ptr<Phen> phen_t;
      typedef boost::multi_array<phen_t, 2> array_t;
      typedef boost::array<float, 2> point_t;

      MapImagePhylogeneticStat() : _xs(0), _ys(0) {}
      template<typename E>
			void refresh(const E& ea)
			{
				_archive.clear();
				_xs = ea.archive().shape()[0];
				_ys = ea.archive().shape()[1];
				assert(_xs == Params::ea::res_x);
				assert(_ys == Params::ea::res_y);

				for (size_t i = 0; i < _xs; ++i)
				for (size_t j = 0; j < _ys; ++j)
				{
					phen_t p = ea.archive()[i][j];
					_archive.push_back(p);
				}

				// Report current generation every 10 generations
				// Print the current progress
				this->printProgress(ea.gen());

				// Print out every generation
				_write_archive(ea.archive(), ea.parents(), std::string("archive_"), ea, ea.gen());

			#ifdef MAP_WRITE_PARENTS
				_write_parents(ea.archive(), ea.parents(), std::string("parents_"), ea);
			#endif
			}

      const std::vector<phen_t>& getPopulation() const
			{
				return _archive;
			}

    	const std::vector<phen_t>& archive() const
    	{
    		return _archive;
    	}

      void show(std::ostream& os, size_t k)
			{
				std::cerr << "loading "<< k / _ys << "," << k % _ys << std::endl;
				if (_archive[k])
				{
					_archive[k]->develop();
					_archive[k]->show(os);
					_archive[k]->fit().set_mode(fit::mode::view);
					_archive[k]->fit().eval(*_archive[k]);
				}
				else
				std::cerr << "Warning, no point here" << std::endl;
			}

      template<class Archive>
        void serialize(Archive& ar, const unsigned int version)
			{
				ar & BOOST_SERIALIZATION_NVP(_archive);
				ar & BOOST_SERIALIZATION_NVP(_xs);
				ar & BOOST_SERIALIZATION_NVP(_ys);
			}

    protected:
      std::vector<phen_t> _archive;
      int _xs, _ys;

      template<typename EA>
      void _write_parents(const array_t& array,
			  const array_t& p_array,
			  const std::string& prefix,
			  const EA& ea) const
			{
				std::cout << "writing..." << prefix << ea.gen() << std::endl;
				std::string fname = ea.res_dir() + "/"
				+ prefix
				+ boost::lexical_cast<
				std::string>(ea.gen())
				+ std::string(".dat");
				std::ofstream ofs(fname.c_str());
				for (size_t i = 0; i < _xs; ++i)
				for (size_t j = 0; j < _ys; ++j)
				if (array[i][j] && p_array[i][j])
				{
					point_t p = _get_point(p_array[i][j]);
					size_t x = round(p[0] * _xs);
					size_t y = round(p[1] * _ys);
					ofs << i / (float) _xs
					<< " " << j / (float) _ys
					<< " " << p_array[i][j]->fit().value()
					<< " " << x / (float) _xs
					<< " " << y / (float) _ys
					<< " " << array[i][j]->fit().value()
					<< std::endl;
				}
			}

      template<typename EA>
      void _write_archive(const array_t& array,
      	const array_t& p_array,
			  const std::string& prefix,
			  const EA& ea,
			  const int gen) const
			{
				std::cout << "writing..." << prefix << ea.gen() << std::endl;
				std::string fname = ea.res_dir() + "/"
				+ prefix
				+ boost::lexical_cast<
				std::string>(ea.gen())
				+ std::string(".dat");

				std::ofstream ofs(fname.c_str());
				for (size_t i = 0; i < _xs; ++i)
				{
					for (size_t j = 0; j < _ys; ++j)
					{
						if (array[i][j])
						{
							float fitness = array[i][j]->fit().value(j);

							ofs
							<< " " << j		// This dimension is categorical (1-1000). No need to normalize to be [0, 1].
							<< " " << fitness;

							// CPPN genome info
							ofs
							<< " " << array[i][j]->gen().get_nb_neurons()
							<< " " << array[i][j]->gen().get_nb_connections();

							// Record the top-1 label and score
							ofs
							<< " " << array[i][j]->fit().label()
							<< " " << array[i][j]->fit().score();

//							if (Params::image::record_lineage)
//							{
								ofs << " " << array[i][j]->id();			// Record the id of this organism

								// Only print out the parent if this is a newly created organism
								if (array[i][j]->created_gen() == ea.gen())
								{
									ofs << " " << p_array[i][j]->id();		// Record the id of this organism's parent
								}
//							}

							ofs << std::endl;	// End of line

							// Always print the map in the first generation and last generation
							if (ea.gen() % Params::pop::dump_period == 0 || (ea.gen() <= 250 && (ea.gen() % 50 == 0)))
							{
								// Create the directory
								const std::string gen_dir = this->_make_gen_dir(ea.res_dir(), gen);

								// Print out images at the current generation
								std::string image_gen = boost::lexical_cast<std::string>(ea.gen());
								std::string category = boost::lexical_cast<std::string>(j);
								std::string image_fitness = boost::lexical_cast<std::string>(fitness);
								std::string image_file = gen_dir + "/map_" + image_gen + "_" + category + "_" + image_fitness;

								array[i][j]->log_best_image_fitness(image_file);
							}
						}
					}
				}
			}

    };
  }
}

#endif

max_stars_repo_name: Evolving-AI-Lab/innovation-engine

max_issues_repo_name: Evolving-AI-Lab/innovation-engine

max_forks_repo_name: Evolving-AI-Lab/innovation-engine


text:
#include "MatrixStack.h"

#include <cassert>
#include <stdio.h>
#include <vector>

#include <Eigen/Geometry>

using namespace std;
using namespace Eigen;

MatrixStack::MatrixStack() {
  mstack = make_shared<stack<Matrix4f>>();
  mstack->push(Matrix4f::Identity());
}

MatrixStack::~MatrixStack() {}

void MatrixStack::pushMatrix() {
  const Matrix4f &top = mstack->top();
  mstack->push(top);
  assert(mstack->size() < 100);
}

void MatrixStack::popMatrix() {
  assert(!mstack->empty());
  mstack->pop();
  // There should always be one matrix left.
  assert(!mstack->empty());
}

void MatrixStack::loadIdentity() {
  Matrix4f &top = mstack->top();
  top = Matrix4f::Identity();
}

void MatrixStack::translate(const Vector3f &t) {
  Matrix4f &top = mstack->top();
  Matrix4f E = Matrix4f::Identity();
  E(0, 3) = t(0);
  E(1, 3) = t(1);
  E(2, 3) = t(2);
  top *= E;
}

void MatrixStack::translate(float x, float y, float z) {
  translate(Vector3f(x, y, z));
}

void MatrixStack::scale(const Vector3f &s) {
  Matrix4f &top = mstack->top();
  Matrix4f E = Matrix4f::Identity();
  E(0, 0) = s(0);
  E(1, 1) = s(1);
  E(2, 2) = s(2);
  top *= E;
}

void MatrixStack::scale(float x, float y, float z) { scale(Vector3f(x, y, z)); }

void MatrixStack::scale(float s) { scale(Vector3f(s, s, s)); }

void MatrixStack::rotate(float angle, const Vector3f &axis) {
  Matrix4f &top = mstack->top();
  Matrix4f E = Matrix4f::Identity();
  E.block<3, 3>(0, 0) =
      AngleAxisf(angle * M_PI / 180.0f, axis.normalized()).toRotationMatrix();
  top *= E;
}

void MatrixStack::rotate(float angle, float x, float y, float z) {
  rotate(angle, Vector3f(x, y, z));
}

void MatrixStack::multMatrix(const Matrix4f &matrix) {
  Matrix4f &top = mstack->top();
  top *= matrix;
}

void MatrixStack::ortho(float left, float right, float bottom, float top,
                        float zNear, float zFar) {
  assert(left != right);
  assert(bottom != top);
  assert(zFar != zNear);
  // Sets the top of the stack
  Matrix4f &M = mstack->top();
  M = Matrix4f::Zero();
  M(0, 0) = 2.0f / (right - left);
  M(1, 1) = 2.0f / (top - bottom);
  M(2, 2) = -2.0f / (zFar - zNear);
  M(0, 3) = -(right + left) / (right - left);
  M(1, 3) = -(top + bottom) / (top - bottom);
  M(2, 3) = -(zFar + zNear) / (zFar - zNear);
  M(3, 3) = 1.0f;
}

void MatrixStack::ortho2D(float left, float right, float bottom, float top) {
  ortho(left, right, bottom, top, -1.0, 1.0);
}

void MatrixStack::perspective(float fovy, float aspect, float zNear,
                              float zFar) {
  assert(fovy != 0.0f);
  assert(aspect != 0.0f);
  assert(zFar != zNear);
  // Sets the top of the stack
  Matrix4f &M = mstack->top();
  M = Matrix4f::Zero();
  float tanHalfFovy = tan(0.5f * fovy * M_PI / 180.0f);
  M(0, 0) = 1.0f / (aspect * tanHalfFovy);
  M(1, 1) = 1.0f / (tanHalfFovy);
  M(2, 2) = -(zFar + zNear) / (zFar - zNear);
  M(2, 3) = -(2.0f * zFar * zNear) / (zFar - zNear);
  M(3, 2) = -1.0f;
}

void MatrixStack::frustum(float left, float right, float bottom, float top,
                          float nearval, float farval) {
  // http://cgit.freedesktop.org/mesa/mesa/tree/src/mesa/math/m_matrix.c
  float x, y, a, b, c, d;
  x = (2.0f * nearval) / (right - left);
  y = (2.0f * nearval) / (top - bottom);
  a = (right + left) / (right - left);
  b = (top + bottom) / (top - bottom);
  c = -(farval + nearval) / (farval - nearval);
  d = -(2.0f * farval * nearval) / (farval - nearval);

  // Sets the top of the stack
  Matrix4f &M = mstack->top();
  M(0, 0) = x;
  M(0, 1) = 0.0f;
  M(0, 2) = a;
  M(0, 3) = 0.0f;
  M(1, 0) = 0.0f;
  M(1, 1) = y;
  M(1, 2) = b;
  M(1, 3) = 0.0f;
  M(2, 0) = 0.0f;
  M(2, 1) = 0.0f;
  M(2, 2) = c;
  M(2, 3) = d;
  M(3, 0) = 0.0f;
  M(3, 1) = 0.0f;
  M(3, 2) = -1.0f;
  M(3, 3) = 0.0f;
}

void MatrixStack::lookAt(const Vector3f &eye, const Vector3f &center,
                         const Vector3f &up) {
  // http://cgit.freedesktop.org/mesa/mesa/tree/src/glu/mesa/glu.c?h=mesa_3_2_dev
  Vector3f x, y, z;
  z = (eye - center).normalized();
  y = up;
  x = y.cross(z);
  y = z.cross(x);
  x.normalize();
  y.normalize();
  Matrix4f M = Matrix4f::Identity();
  M.block<1, 3>(0, 0) = x;
  M.block<1, 3>(1, 0) = y;
  M.block<1, 3>(2, 0) = z;
  multMatrix(M);
  translate(-eye);
}

void MatrixStack::lookAt(float ex, float ey, float ez, float tx, float ty,
                         float tz, float ux, float uy, float uz) {
  lookAt(Vector3f(ex, ey, ez), Vector3f(tx, ty, tz), Vector3f(ux, uy, uz));
}

const Matrix4f &MatrixStack::topMatrix() const { return mstack->top(); }

void MatrixStack::print(const Matrix4f &mat, const char *name) const {
  if (name) {
    printf("%s = [\n", name);
  }
  for (int i = 0; i < 4; ++i) {
    for (int j = 0; j < 4; ++j) {
      printf("%- 5.2f ", mat(i, j));
    }
    printf("\n");
  }
  if (name) {
    printf("];");
  }
  printf("\n");
}

void MatrixStack::print(const char *name) const { print(mstack->top(), name); }

// void MatrixStack::printStack() const
// {
// 	// Copy everything to a non-const stack
// 	auto tempStack = mstack;
// 	while(!tempStack.empty()) {
// 		Matrix4f &top = tempStack.top();
// 		print(top);
// 		tempStack.pop();
// 	}
// }

// #include <iostream>
// int main(int argc, char **argv)
// {
// 	MatrixStack M;
// 	M.frustum(-1, 1, -2, 2, 0.1, 10.0);
// 	std::cout << M.topMatrix() << std::endl;
// }


text:
#include "wave/optimization/ceres/odom_linear/point_to_line_interpolated_transform.hpp"
#include <Eigen/QR>

namespace wave {

SE3PointToLine::SE3PointToLine(const double *const p, const double *const pA, const double *const pB, const double *const scal, const Mat3 &CovZ, bool calculate_weight)
        : pt(p), ptA(pA), ptB(pB), scale(scal) {
    Eigen::Matrix<double, 3, 12> JP_T;
    Eigen::Matrix<double, 3, 3> Jres_P;

    JP_T << this->pt[0], 0, 0, this->pt[1], 0, 0, this->pt[2], 0, 0, 1, 0, 0, //
            0, this->pt[0], 0, 0, this->pt[1], 0, 0, this->pt[2], 0, 0, 1, 0, //
            0, 0, this->pt[0], 0, 0, this->pt[1], 0, 0, this->pt[2], 0, 0, 1;

    this->diff[0] = this->ptB[0] - this->ptA[0];
    this->diff[1] = this->ptB[1] - this->ptA[1];
    this->diff[2] = this->ptB[2] - this->ptA[2];
    this->bottom = diff[0] * diff[0] + diff[1] * diff[1] + diff[2] * diff[2];

    if (this->bottom < 1e-10) {
        // The points defining the line are too close to each other
        throw std::out_of_range("Points defining line are too close!");
    }

    Jres_P(0,0) = 1 - (diff[0] * diff[0] / bottom);
    Jres_P(0,1) = -(diff[0] * diff[1] / bottom);
    Jres_P(0,2) = -(diff[0] * diff[2] / bottom);
    Jres_P(1,0) = -(diff[1] * diff[0] / bottom);
    Jres_P(1,1) = 1 - (diff[1] * diff[1] / bottom);
    Jres_P(1,2) = -(diff[1] * diff[2] / bottom);
    Jres_P(2,0) = -(diff[2] * diff[0] / bottom);
    Jres_P(2,1) = -(diff[2] * diff[1] / bottom);
    Jres_P(2,2) = 1 -(diff[2] * diff[2] / bottom);

    Eigen::Vector3d unitdiff;
    double invlength = 1.0/sqrt(this->bottom);
    if(this->diff[2] > 0) {
        unitdiff[0] = this->diff[0] * invlength;
        unitdiff[1] = this->diff[1] * invlength;
        unitdiff[2] = this->diff[2] * invlength;
    } else {
        unitdiff[0] = -this->diff[0] * invlength;
        unitdiff[1] = -this->diff[1] * invlength;
        unitdiff[2] = -this->diff[2] * invlength;
    }

    Eigen::Vector3d unitz;
    unitz << 0, 0, 1;

    auto v = unitdiff.cross(unitz);
    auto s = v.norm();
    auto c = unitz.dot(unitdiff);
    Mat3 skew;
    Transformation<>::skewSymmetric3(v, skew);
    this->rotation = Eigen::Matrix3d::Identity() + skew + skew*skew*((1-c)/(s*s));

    this->Jres_T = this->rotation * Jres_P * JP_T;

    if(calculate_weight) {
        auto rotated = (this->rotation * Jres_P * CovZ * Jres_P.transpose() * this->rotation.transpose());
        this->weight_matrix = rotated.block<2,2>(0,0).inverse().sqrt();
    } else {
        this->weight_matrix.setIdentity();
    }
}

bool SE3PointToLine::Evaluate(double const *const *parameters, double *residuals, double **jacobians) const {
    Eigen::Map<const Mat34> Tmap(parameters[0], 3, 4);
    Transformation<Eigen::Map<const Mat34>> Tk(Tmap);

    Transformation<Eigen::Matrix<double, 3, 4>> interpolated;

    Eigen::Map<const Vec3> PT(pt, 3, 1);
    auto twist = Tk.logMap();
    interpolated.setFromExpMap(*(this->scale) * twist);
    Vec3 POINT = interpolated.transform(PT);
    double point[3];
    Eigen::Map<Vec3>(point, 3, 1) = POINT;

    double p_A[3] = {point[0] - this->ptA[0], point[1] - this->ptA[1], point[2] - this->ptA[2]};

    double scaling = ceres::DotProduct(p_A, diff);
    // point on line closest to point
    double p_Tl[3] = {this->ptA[0] + (scaling / bottom) * diff[0],
                      this->ptA[1] + (scaling / bottom) * diff[1],
                      this->ptA[2] + (scaling / bottom) * diff[2]};

    double residual_o[3];
    residual_o[0] = point[0] - p_Tl[0];
    residual_o[1] = point[1] - p_Tl[1];
    residual_o[2] = point[2] - p_Tl[2];
    Eigen::Map<Vec3> res(residual_o, 3, 1);
    Eigen::Vector2d reduced = (this->rotation * res).block<2,1>(0,0);
    reduced = this->weight_matrix * reduced;
    Eigen::Map<Eigen::Vector2d>(residuals, 2, 1) = reduced;

    if (jacobians != NULL) {
        // Have to apply the "lift" jacobian to the Interpolation Jacobian because
        // of Ceres local parameterization
        Transformation<>::Jinterpolated(twist, *(this->scale), this->J_int);
        interpolated.J_lift(this->J_lift);
        Tk.J_lift(this->J_lift_full);

        this->J_lift_full_pinv = (this->J_lift_full.transpose() * this->J_lift_full).inverse() * this->J_lift_full.transpose();

        this->Jr_T = this->Jres_T * this->J_lift * this->J_int * this->J_lift_full_pinv;
        this->Jr_T_reduced = this->weight_matrix * this->Jr_T.block<2,12>(0,0);

        Eigen::Map<Eigen::Matrix<double, 2, 12, Eigen::RowMajor>>(jacobians[0], 2, 12) = this->Jr_T_reduced;
    }

    return true;
}

}  // namespace wave

max_stars_repo_name: Jebediah/libwave

max_issues_repo_name: Jebediah/libwave

max_forks_repo_name: Jebediah/libwave


text:
#include "cxxopts.hpp"

#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>

#include "benchmark_config.hpp"
#include "cli_config_parser.hpp"
#include "server/server.hpp"
#include "tpcc/tpcc_table_generator.hpp"
#include "tpcds/tpcds_table_generator.hpp"
#include "tpch/tpch_table_generator.hpp"

namespace {

void generate_benchmark_data(std::string argument_string) {
  // Remove unnecessary white spaces
  boost::trim_if(argument_string, boost::is_any_of(":"));

  // Remove dashes and convert to lower case to unify different writings of benchmarks ("TPC-H", "tpch", or "tpc-h")
  boost::replace_all(argument_string, "-", "");
  boost::to_lower(argument_string);

  auto benchmark_data_config = std::vector<std::string>{};
  // Split benchmark name and sizing factor
  boost::split(benchmark_data_config, argument_string, boost::is_any_of(":"), boost::token_compress_on);
  Assert(benchmark_data_config.size() == 2,
         "Malformed input for benchmark data generation. Expecting a benchmark name and a sizing factor.");

  const auto benchmark_name = benchmark_data_config[0];
  const auto sizing_factor = boost::lexical_cast<float, std::string>(benchmark_data_config[1]);

  Assert(benchmark_name == "tpch" || benchmark_name == "tpcds" || benchmark_name == "tpcc",
         "Benchmark data generation is only supported for TPC-C, TPC-DS, and TPC-H.");

  auto config = std::make_shared<opossum::BenchmarkConfig>(opossum::BenchmarkConfig::get_default_config());
  config->cache_binary_tables = true;
  if (benchmark_name == "tpcc") {
    config->cache_binary_tables = false;  // Not yet supported for TPC-C
    opossum::TPCCTableGenerator{static_cast<uint32_t>(sizing_factor), config}.generate_and_store();
  } else if (benchmark_name == "tpcds") {
    opossum::TPCDSTableGenerator{static_cast<uint32_t>(sizing_factor), config}.generate_and_store();
  } else if (benchmark_name == "tpch") {
    opossum::TPCHTableGenerator{sizing_factor, config}.generate_and_store();
  } else {
    Fail("Unexpected benchmark name passed in parameter 'benchmark_data'.");
  }
}

}  // namespace

cxxopts::Options get_server_cli_options() {
  cxxopts::Options cli_options("./hyriseServer", "Starts Hyrise server in order to accept network requests.");

  // clang-format off
  cli_options.add_options()
    ("help", "Display this help and exit") // NOLINT
    ("address", "Specify the address to run on", cxxopts::value<std::string>()->default_value("0.0.0.0"))  // NOLINT
    ("p,port", "Specify the port number. 0 means randomly select an available one. If no port is specified, the the server will start on PostgreSQL's official port", cxxopts::value<uint16_t>()->default_value("5432"))  // NOLINT
    ("benchmark_data", "Optional for benchmarking purposes: specify the benchmark name and sizing factor to generate "
                       "at server start (e.g., \"TPC-C:5\", \"TPC-DS:5\", or \"TPC-H:10\"). Supported are TPC-C, "
                       "TPC-DS, and TPC-H. The sizing factor determines the scale factor in TPC-DS and TPC-H, and the "
                       "warehouse count in TPC-C.", cxxopts::value<std::string>()) // NOLINT
    ("execution_info", "Send execution information after statement execution", cxxopts::value<bool>()->default_value("false")) // NOLINT
    ;  // NOLINT
  // clang-format on

  return cli_options;
}

int main(int argc, char* argv[]) {
  auto cli_options = get_server_cli_options();
  const auto parsed_options = cli_options.parse(argc, argv);

  // Print help and exit
  if (parsed_options.count("help")) {
    std::cout << cli_options.help() << std::endl;
    return 0;
  }

  /**
    * The optional parameter `benchmark_data` allows users to generate benchmark data when starting the hyrise server.
    * This is not an ideal solution, but due to several users' requests and our goal to facilitate easy evaluation of
    * Hyrise, we decided to integrate the data generation into the server nonetheless.
    *
    * We do not plan on exposing other parameters, such as the encoding or the chunk size via this facility. You can
    * change the modify the config object as needed.
    */
  if (parsed_options.count("benchmark_data")) {
    generate_benchmark_data(parsed_options["benchmark_data"].as<std::string>());
  }

  const auto execution_info = parsed_options["execution_info"].as<bool>();
  const auto port = parsed_options["port"].as<uint16_t>();

  boost::system::error_code error;
  const auto address = boost::asio::ip::make_address(parsed_options["address"].as<std::string>(), error);

  Assert(!error, "Not a valid IPv4 address: " + parsed_options["address"].as<std::string>() + ", terminating...");

  auto server = opossum::Server{address, port, static_cast<opossum::SendExecutionInfo>(execution_info)};
  server.run();

  return 0;
}

max_stars_repo_name: mrks-test/hyrise

max_issues_repo_name: mrks-test/hyrise

max_forks_repo_name: mrks-test/hyrise


text:
// Copyright 2015-2020 Tier IV, Inc. All rights reserved.
//
// 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.

#include <boost/io/ios_state.hpp>
#include <openscenario_interpreter/syntax/boolean.hpp>

namespace openscenario_interpreter
{
inline namespace syntax
{
std::ostream & operator<<(std::ostream & os, const Boolean & datum)
{
  boost::io::ios_flags_saver saver{os};
  return os << std::boolalpha << datum.data;
}

std::istream & operator>>(std::istream & is, Boolean & datum)
{
  boost::io::ios_flags_saver saver{is};
  return is >> std::boolalpha >> datum.data;
}

const Element true_v = make<Boolean>(true);
const Element false_v = make<Boolean>(false);

const Element & asBoolean(bool value) { return value ? true_v : false_v; }
}  // namespace syntax
}  // namespace openscenario_interpreter


text:
//
// file HashedFingerprint.cc
// David Cosgrove
// AstraZeneca
// 29th January 2009
//

#include <fstream>
#include <iomanip>
#include <iostream>
#include <sstream>

#include <boost/lexical_cast.hpp>
#include <boost/regex.hpp>

#include "ByteSwapper.H"
#include "HashedFingerprint.H"

using namespace std;

#if defined(__GNUC__) && defined(__SSSE3__)
#include "popcount_ssse3.cc"
#elif defined(__GNUC__) && defined(__SSE2__)
#include "popcount_ssse2.cc"
#endif
namespace DAC_FINGERPRINTS {

pHDC HashedFingerprint::dist_calc_ = &HashedFingerprint::tanimoto;
pHTDC HashedFingerprint::threshold_dist_calc_ = &HashedFingerprint::tanimoto;
unsigned int HashedFingerprint::num_ints_ = 0;

static const unsigned int BITS_PER_INT = 8 * sizeof( unsigned int );

// **************************************************************************
HashedFingerprint::HashedFingerprint() :
  FingerprintBase() , finger_bits_( 0 ) , num_bits_set_( 0 ) {

  make_zero_fp( num_ints_ * BITS_PER_INT );

}

// **************************************************************************
HashedFingerprint::HashedFingerprint( const string &name ) :
  FingerprintBase( name ) , finger_bits_( 0 ) , num_bits_set_( 0 ) {

  make_zero_fp( num_ints_ * BITS_PER_INT );

}

// **************************************************************************
// this one from the contents of a string built with get_string_rep.
HashedFingerprint::HashedFingerprint( const string &name ,
                                      const string &rep ) :
  FingerprintBase( name ) , finger_bits_( 0 ) , num_bits_set_( 0 ) {

  // 10 is the number of chars needed to write
  // numeric_limits<unsigned int>::max() in ascii. At least when I built
  // this in Dec 2014. If I wanted to be really sure, I'd work it out
  // at runtime and put it in a static variable, I guess
  unsigned int new_num_ints = rep.length() / 10;
  if( rep.length() % 10 ) {
    ++new_num_ints;
  }

  if( !num_ints_ ) {
    num_ints_ = new_num_ints;
  }

  if( new_num_ints != num_ints_ ) {
    throw HashedFingerprintLengthError( num_ints_ , new_num_ints );
  }

  finger_bits_ = new unsigned int[num_ints_];

  int next_bit = 0;
  for( int i = num_ints_ - 1 ; i >= 0 ; --i , next_bit += 10 ) {
    finger_bits_[i] = boost::lexical_cast<unsigned int>( rep.substr( next_bit , 10 ) );
  }

  count_bits();

}

// **************************************************************************
HashedFingerprint::HashedFingerprint( const string &name ,
                                      unsigned int *new_ints ) :
  FingerprintBase( name ) , finger_bits_( 0 ) , num_bits_set_( 0 ) {

  if( num_ints_ > 0 ) {
    finger_bits_ = new unsigned int[num_ints_];
    copy( new_ints , new_ints + num_ints_ , finger_bits_ );
  }

  count_bits();

}

// **************************************************************************
HashedFingerprint::HashedFingerprint( const HashedFingerprint &fp ) :
  FingerprintBase() , finger_bits_( 0 ) , num_bits_set_( 0 ) {

  copy_data( fp );

}

// **************************************************************************
HashedFingerprint::~HashedFingerprint() {

  delete [] finger_bits_;

}

// **************************************************************************
HashedFingerprint &HashedFingerprint::operator=( const HashedFingerprint &fp ) {

  if( &fp == this ) {
    return *this;
  }

  copy_data( fp );

  return *this;

}

// *******************************************************************************
// bitwise operators for combining fingerprints.
HashedFingerprint HashedFingerprint::operator&( const HashedFingerprint &rhs ) const {

  HashedFingerprint ret_val( "" );
  for( unsigned int i = 0 ; i < HashedFingerprint::num_ints() ; ++i ) {
    ret_val.finger_bits_[i] = finger_bits_[i] & rhs.finger_bits_[i];
  }
  ret_val.num_bits_set_ = 0; // to force a re-count if count_bits() is called

  return ret_val;

}

// *******************************************************************************
HashedFingerprint HashedFingerprint::operator|( const HashedFingerprint &rhs ) const {

  HashedFingerprint ret_val( "" );
  for( unsigned int i = 0 ; i < HashedFingerprint::num_ints() ; ++i ) {
    ret_val.finger_bits_[i] = finger_bits_[i] | rhs.finger_bits_[i];
  }
  ret_val.num_bits_set_ = 0; // to force a re-count if count_bits() is called

  return ret_val;

}

// *******************************************************************************
HashedFingerprint &HashedFingerprint::operator&=( const HashedFingerprint &rhs ) {

  for( unsigned int i = 0 ; i < num_ints_ ; ++i ) {
    finger_bits_[i] &= rhs.finger_bits_[i];
  }
  num_bits_set_ = 0; // to force a re-count if count_bits() is called

  return *this;

}

// *******************************************************************************
HashedFingerprint &HashedFingerprint::operator|=( const HashedFingerprint &rhs ) {

  for( unsigned int i = 0 ; i < num_ints_ ; ++i ) {
    finger_bits_[i] |= rhs.finger_bits_[i];
  }
  num_bits_set_ = 0; // to force a re-count if count_bits() is called

  return *this;

}

// *******************************************************************************
// work out how many chars are required to accommodate the number of
// bits requested.
unsigned int HashedFingerprint::calc_num_ints_req( int num_bits ) const {

  unsigned int nc = num_bits / BITS_PER_INT;
  if( num_bits % BITS_PER_INT ) {
    ++nc;
  }

  return nc;

}

// *******************************************************************************
// make empty fingerprint of the required size.
void HashedFingerprint::make_zero_fp( int num_bits ) {

  unsigned int new_num_ints = calc_num_ints_req( num_bits );

  if( num_ints_ && new_num_ints != num_ints_ ) {
    throw HashedFingerprintLengthError( num_ints_ , new_num_ints );
  }

  if( !num_ints_ ) {
    num_ints_ = new_num_ints;
  }

  if( num_ints_ ) {
    if( finger_bits_ && new_num_ints != num_ints_ ) {
      delete [] finger_bits_;
      finger_bits_ = 0;
    }
    if( !finger_bits_ ) {
      finger_bits_ = new unsigned int[num_ints_];
    }
    std::fill_n( finger_bits_ , num_ints_ , 0 );
  }

}

// **************************************************************************
double HashedFingerprint::tanimoto( const HashedFingerprint &f ) const {

  if( !num_bits_set_ && !f.num_bits_set_ ) {
    return 0.0; // otherwise, we'll get a NaN.
  }

  int num_in_common = num_bits_in_common( f );

  double dist = 1.0 - ( double( num_in_common ) /
                        double( num_bits_set_ + f.num_bits_set_ - num_in_common ));

  return dist;

}

// **************************************************************************
// If the distance is predicted to be above the threshold, return 1.0
double HashedFingerprint::tanimoto( const HashedFingerprint &f ,
                                    float threshold ) const {

  float min_dist;
  if( num_bits_set_ < f.num_bits_set_ ) {
    min_dist = 1.0 - float( num_bits_set_ ) / float( f.num_bits_set_ );
  } else {
    min_dist = 1.0 - float( f.num_bits_set_ ) / float( num_bits_set_ );
  }
  if( min_dist > threshold ) {
    return 1.0;
  } else {
    return tanimoto( f );
  }

}

// **************************************************************************
double HashedFingerprint::tversky( const HashedFingerprint &f ) const {

  int num_a_not_b , num_b_not_a;

  int num_in_common = num_bits_in_common( f , num_a_not_b , num_b_not_a );

  double dist = 1.0 - ( double( num_in_common ) /
                        ( tversky_alpha_ * double( num_a_not_b ) +
                          ( 1.0 - tversky_alpha_ ) * double( num_b_not_a )
                          + double( num_in_common ) ) );

  return dist;

}

// **************************************************************************
double HashedFingerprint::tversky( const HashedFingerprint &f ,
                                   float threshold __attribute__((unused)) ) const {

  // don't have a calculation for the threshold, so just return the normal
  // one
  return tversky( f );

}

// ***************************************************************************
int HashedFingerprint::num_bits_in_common( const HashedFingerprint &f ) const {

  static unsigned int *common_bits = 0;
  if( !common_bits ) {
    common_bits = new unsigned int[num_ints_];
  }

  const unsigned int *these = finger_bits_ , *those = f.finger_bits_;
  unsigned int *cb = common_bits;

  transform( these , these + num_ints_ , those , cb , std::bit_and<unsigned int>() );

  return count_bits_set( common_bits , num_ints_ );

}

// ***************************************************************************
int HashedFingerprint::num_bits_in_common( const HashedFingerprint &f ,
                                           int &num_in_a_not_b ,
                                           int &num_in_b_not_a ) const {

  static unsigned int *common_bits = 0 , *in_a_not_b = 0 , *in_b_not_a = 0;
  if( !common_bits ) {
    common_bits = new unsigned int[num_ints_];
    in_a_not_b = new unsigned int[num_ints_];
    in_b_not_a = new unsigned int[num_ints_];
  }

  num_in_a_not_b = num_in_b_not_a = 0;

  unsigned int *cb = common_bits , *anb = in_a_not_b , *bna = in_b_not_a;
  const unsigned int *these = finger_bits_ , *those = f.finger_bits_;
  for( unsigned int i = 0 ; i < num_ints_ ; ++i , ++cb , ++anb , ++bna , ++these , ++those ) {
    *cb = *these & *those;
    *anb = *these & ( ~ *those );
    *bna = *those & ( ~ *these );
  }

  num_in_a_not_b = count_bits_set( in_a_not_b , num_ints_ );
  num_in_b_not_a = count_bits_set( in_b_not_a , num_ints_ );
  return count_bits_set( common_bits , num_ints_ );

}

// ***************************************************************************
int HashedFingerprint::num_set_in_this_and_not_in_2( const HashedFingerprint &fp2 ) const {

  static unsigned int *in_this_not_2 = 0;
  if( !in_this_not_2 ) {
    in_this_not_2 = new unsigned int[num_ints_];
  }

  unsigned int *itn2 = in_this_not_2;
  const unsigned int *these = finger_bits_ , *those = fp2.finger_bits_;

  for( unsigned int i = 0 ; i < num_ints_ ; ++i , ++itn2 , ++these , ++those ) {
    *itn2 = *these & ( ~ *those );
  }

  return count_bits_set( in_this_not_2 , num_ints_ );

}

// **************************************************************************
string HashedFingerprint::get_string_rep() const {

  // 10 is the number of chars needed to write
  // numeric_limits<unsigned int>::max() in ascii. At least when I built
  // this in Dec 2014. If I wanted to be really sure, I'd work it out
  // at runtime and put it in a static variable, I guess
  ostringstream oss;
  oss << "__FP";
  for( int i = num_ints_ - 1 ; i >= 0 ; --i )
    oss << setfill( '0' ) << setw( 10 ) << finger_bits_[i];

  return oss.str();

}

// *************************************************************************
void HashedFingerprint::set_similarity_calc( SIMILARITY_CALC sc ) {

  switch( sc ) {
  case TANIMOTO :
    dist_calc_ = &HashedFingerprint::tanimoto;
    threshold_dist_calc_ = &HashedFingerprint::tanimoto;
    break;
  case TVERSKY :
    dist_calc_ = &HashedFingerprint::tversky;
    threshold_dist_calc_ = &HashedFingerprint::tversky;
    break;
  }

}

// **************************************************************************
// count the number of set bits in the fingerprint
int HashedFingerprint::count_bits() const {

  if( !num_bits_set_ ) {
    num_bits_set_ = count_bits_set( finger_bits_ , num_ints_ );
  }

  return num_bits_set_;

}

// **************************************************************************
// calculate the distance between this fingerprint and the one passed in
// using dist_calc_
double HashedFingerprint::calc_distance( const FingerprintBase &f ) const {

  return f.calc_distance( *this );

}

// **************************************************************************
// calculate the distance between this fingerprint and the one passed in
// using dist_calc_
double HashedFingerprint::calc_distance( const FingerprintBase &f ,
                                         float threshold ) const {

  return f.calc_distance( *this , threshold );

}

// **************************************************************************
// calculate the distance between this fingerprint and the one passed in
// using dist_calc_
double HashedFingerprint::calc_distance( const HashedFingerprint &f ) const {

  return (this->*dist_calc_)( f );

}

// **************************************************************************
// calculate the distance between this fingerprint and the one passed
// in using threshold_dist_calc_.  If the distance is predicted to be above
// the threshold, return 1.0
double HashedFingerprint::calc_distance( const HashedFingerprint &f ,
                                         float threshold ) const {

  return (this->*threshold_dist_calc_)( f , threshold );

}

// **************************************************************************
// calculate the distance between this fingerprint and the one passed in
// using dist_calc_
double HashedFingerprint::calc_distance( const NotHashedFingerprint &f __attribute__((unused)) ) const {

  throw IncompatibleFingerprintError( "calc_distance" );

}

// **************************************************************************
// calculate the distance between this fingerprint and the one passed
// in using threshold_dist_calc_.  If the distance is predicted to be above
// the threshold, return 1.0
double HashedFingerprint::calc_distance( const NotHashedFingerprint &f __attribute__((unused)) ,
                                         float threshold __attribute__((unused))  ) const {

  throw IncompatibleFingerprintError( "calc_distance" );

}

// **************************************************************************
bool HashedFingerprint::binary_read( gzFile fp , bool byte_swapping ) {

  int name_len;
  gzread( fp , &name_len , sizeof( int ) );
  if( gzeof( fp ) ) {
    return false;
  }
  if( byte_swapping ) DACLIB::byte_swapper<int>( name_len );

  finger_name_.resize( name_len , ' ' );
  gzread( fp , &finger_name_[0] , name_len );
  gzread( fp , reinterpret_cast<void *>( finger_bits_ ) , num_ints_ * sizeof( unsigned int ) );

  num_bits_set_ = 0; // to force a re-count
  count_bits();

  return true;

}

// **************************************************************************
// write to a previously initialised flush output file
void HashedFingerprint::binary_write( gzFile fp ) const {

  int name_len = finger_name_.length();
  gzwrite( fp , reinterpret_cast<void *>( &name_len ) , sizeof( int ) );
  gzwrite( fp , &finger_name_[0] , name_len );
  gzwrite( fp , reinterpret_cast<void *>( finger_bits_ ) , num_ints_ * sizeof( unsigned int ) );

}

// **************************************************************************
// write to a previously initialised flush output file
void HashedFingerprint::binary_write( FILE *fp ) const {

  int name_len = finger_name_.length();
  fwrite( reinterpret_cast<void *>( &name_len ) , sizeof( int ) , 1 , fp );
  fwrite( finger_name_.c_str() , 1 , name_len , fp );
  fwrite( reinterpret_cast<void *>( finger_bits_ ) , 1 , num_ints_ * sizeof( unsigned int ) , fp );

}

// **************************************************************************
// read an ascii representation
bool HashedFingerprint::ascii_read( gzFile fp , const string &sep ) {

  // in FingerprintBase
  string full_line = read_full_line( fp );
  if( gzeof( fp ) && full_line.empty() ) {
    return false;
  }

  string name , rest;
  // if sep is empty, split into 2 strings on space
  if( sep.empty() ) {
    size_t space_pos = full_line.find( ' ' );
    if( string::npos == space_pos ) {
      cerr << "Error reading fingerprint line : " << full_line << endl;
      exit( 1 );
    }
    name = full_line.substr( 0 , space_pos );
    rest = full_line.substr( space_pos + 1 );
  } else {
    // it's a bit more complicated. change sep to space, take out the 1st
    // string as name, stick the rest back together again and proceed
    // convert_sep_to_new_sep in FingerprintBase
    string new_fl = convert_sep_to_new_sep( full_line , sep , " " );
    size_t space_pos = new_fl.find( ' ' );
    if( string::npos == space_pos ) {
      cerr << "Error reading fingerprint line : " << full_line << endl;
      exit( 1 );
    }
    name = full_line.substr( 0 , space_pos );
    rest = convert_sep_to_new_sep( full_line.substr( space_pos + 1 ) , " " , "" );
  }

  // first time through, num_ints() should be zero, as we won't know at this
  // stage what we're dealing with.
  if( !num_ints() ) {
    try {
      make_zero_fp( rest.length() );
    } catch( HashedFingerprintLengthError &e ) {
      cerr << "Caught : " << e.what() << endl;
      exit( 1 );
    }
  }
  build_fp_from_bitstring( name , rest );

  return true;

}

// **************************************************************************
// write an ascii representation
void HashedFingerprint::ascii_write( gzFile fp , const string &sep ) const {

  static unsigned int *bit_masks = 0;
  if( !bit_masks ) {
    bit_masks = new unsigned int[BITS_PER_INT];
    int b = 1 << (BITS_PER_INT - 1);
    for( unsigned int i = 0 ; i < BITS_PER_INT ; ++i ) {
      bit_masks[i] = b;
      b >>= 1;
    }
  }

  gzprintf( fp , "%s" , finger_name_.c_str() );
  if( sep.empty() ) {
    gzprintf( fp , " " );
  }
  for( unsigned int i = 0 ; i < num_ints_ ; ++i ) {
    for( unsigned int j = 0 ; j < BITS_PER_INT ; ++j ) {
      if( finger_bits_[i] & bit_masks[j] ) {
        gzprintf( fp , "%s1" , sep.c_str() );
      } else {
        gzprintf( fp , "%s0" , sep.c_str() );
      }
    }
  }
  gzprintf( fp , "\n" );

}

// **************************************************************************
// write an ascii representation
void HashedFingerprint::ascii_write( FILE *fp , const string &sep ) const {

#ifdef NOTYET
  cout << "HashedFingerprint::ascii_write, num_ints_ = " << num_ints_ << endl;
#endif

  static unsigned int *bit_masks = 0;
  if( !bit_masks ) {
    bit_masks = new unsigned int[BITS_PER_INT];
    unsigned int b = 1 << (BITS_PER_INT - 1);
    for( unsigned int i = 0 ; i < BITS_PER_INT ; ++i ) {
      bit_masks[i] = b;
      b >>= 1;
    }
  }

  fprintf( fp , "%s" , finger_name_.c_str() );
  if( sep.empty() ) {
    fprintf( fp , " " );
  }
  for( unsigned int i = 0 ; i < num_ints_ ; ++i ) {
    for( unsigned int j = 0 ; j < BITS_PER_INT ; ++j ) {
      if( finger_bits_[i] & bit_masks[j] ) {
        fprintf( fp , "%s1" , sep.c_str() );
      } else {
        fprintf( fp , "%s0" , sep.c_str() );
      }
    }
  }
  fprintf( fp , "\n" );

}

// **************************************************************************
void HashedFingerprint::copy_data( const HashedFingerprint &fp ) {

  FingerprintBase::copy_data( fp );

  if( num_ints_ && !finger_bits_ ) {
    finger_bits_ = new unsigned int[num_ints_];
  }
  copy( fp.finger_bits_ , fp.finger_bits_ + num_ints_ , finger_bits_ );

  num_bits_set_ = fp.num_bits_set_;

}

// **************************************************************************
void HashedFingerprint::build_fp_from_bitstring( const string &name ,
                                                 const string &bitstring ) {

  finger_name_ = name;
  unsigned int new_num_ints = calc_num_ints_req( bitstring.length() );
  if( num_ints_ && new_num_ints != num_ints_ ) {
    throw HashedFingerprintLengthError( new_num_ints , num_ints_ );
  }
  // obviously the bit string is the 'wrong way round' wrt least significant
  // bit

  // make sure that there are an integral number of blocks of BITS_PER_INT
  static string spare_bits;
  if( spare_bits.empty() ) {
    for( unsigned int i = 0 ; i < BITS_PER_INT ; ++i ) {
      spare_bits += "0";
    }
  }
  // need to pad the bitstring to an unsigned int boundary
  int padding_needed = bitstring.length() % BITS_PER_INT;
  if( padding_needed ) {
    padding_needed = BITS_PER_INT - padding_needed;
  }
  string bits_to_use = padding_needed ?
        spare_bits.substr( 0 , padding_needed ) + bitstring : bitstring;
  num_bits_set_ = 0;

  static unsigned int *bit_masks = 0;
  if( !bit_masks ) {
    bit_masks = new unsigned int[BITS_PER_INT];
    unsigned int b = 1 << (BITS_PER_INT - 1);
    for( unsigned int i = 0 ; i < BITS_PER_INT ; ++i ) {
      bit_masks[i] = b;
      b >>= 1;
    }
  }

  for( unsigned int i = 0 , j = 0 ;
       i < num_ints_ ; ++i , j += BITS_PER_INT ) {
    string next_bits = bits_to_use.substr( j , BITS_PER_INT );
    finger_bits_[i] = 0;
    for( unsigned int l = BITS_PER_INT ; l > 0 ; --l ) {
      if( '1' == next_bits[l-1] ) {
        ++num_bits_set_;
        finger_bits_[i] |= bit_masks[l-1];
      }
    }

  }

}

// ****************************************************************************
int count_bits_set( unsigned int *bits , int num_ints ) {

#if defined(__GNUC__) && defined(__SSSE3__)
  return popcount_ssse3( bits , num_ints );
#elif defined(__GNUC__) && defined(__SSE2__)
  return popcount_ssse2( bits , num_ints );
#else
  return 0;
#endif

}

// ****************************************************************************
// thrown when the program tries to change num_chars_.
HashedFingerprintLengthError::HashedFingerprintLengthError( int new_len ,
                                                            int old_len ) {

  msg_ = string( "Changed fingerprint length from " ) +
      boost::lexical_cast<string>( old_len ) + string( " to " ) +
      boost::lexical_cast<string>( new_len ) + string( "." );

}

} // end of namespace DAC_FINGERPRINTS

ext: cc

max_stars_repo_name: OpenEye-Contrib/Flush

max_issues_repo_name: OpenEye-Contrib/Flush

max_forks_repo_name: OpenEye-Contrib/Flush


text:
/********************************************************************************
 * Copyright 2009 The Robotics Group, The Maersk Mc-Kinney Moller Institute,
 * Faculty of Engineering, University of Southern Denmark
 *
 * 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.
 ********************************************************************************/

#ifdef _MSC_VER
#include <boost/cstdint.hpp>
typedef boost::int8_t int8_t;
typedef boost::uint8_t uint8_t;
typedef boost::int16_t int16_t;
typedef boost::uint16_t uint16_t;
typedef boost::int32_t int32_t;
typedef boost::uint32_t uint32_t;
typedef boost::int64_t int64_t;
typedef boost::uint64_t uint64_t;

#else
#include <stdint.h>
#endif


text: #include <boost/regex/v4/c_regex_traits.hpp>

max_stars_repo_name: miathedev/BoostForArduino

max_issues_repo_name: miathedev/BoostForArduino

max_forks_repo_name: miathedev/BoostForArduino