<commit_before>// Copyright (c) 2017 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 "consensus/validation.h"
#include "wallet/feebumper.h"
#include "wallet/wallet.h"
#include "policy/policy.h"
#include "policy/rbf.h"
#include "validation.h" //for mempool access
#include "txmempool.h"
#include "utilmoneystr.h"
#include "util.h"
#include "net.h"

// Calculate the size of the transaction assuming all signatures are max size
// Use DummySignatureCreator, which inserts 72 byte signatures everywhere.
// TODO: re-use this in CWallet::CreateTransaction (right now
// CreateTransaction uses the constructed dummy-signed tx to do a priority
// calculation, but we should be able to refactor after priority is removed).
// NOTE: this requires that all inputs must be in mapWallet (eg the tx should
// be IsAllFromMe).
int64_t CalculateMaximumSignedTxSize(const CWallet *pWallet, const CTransaction &tx)
{
    CMutableTransaction txNew(tx);
    std::vector<std::pair<const CWalletTx *, unsigned int>> vCoins;
    // Look up the inputs.  We should have already checked that this transaction
    // IsAllFromMe(ISMINE_SPENDABLE), so every input should already be in our
    // wallet, with a valid index into the vout array.
    for (auto& input : tx.vin) {
        const auto mi = pWallet->mapWallet.find(input.prevout.hash);
        assert(mi != pWallet->mapWallet.end() && input.prevout.n < mi->second.tx->vout.size());
        vCoins.emplace_back(std::make_pair(&(mi->second), input.prevout.n));
    }
    if (!pWallet->DummySignTx(txNew, vCoins)) {
        // This should never happen, because IsAllFromMe(ISMINE_SPENDABLE)
        // implies that we can sign for every input.
        return -1;
    }
    return GetVirtualTransactionSize(txNew);
}

CFeeBumper::CFeeBumper(const CWallet *pWallet, const uint256 txidIn, int newConfirmTarget, bool specifiedConfirmTarget, CAmount totalFee, bool newTxReplaceable)
    :
    txid(txidIn),
    nOldFee(0),
    nNewFee(0)
{
    vErrors.clear();
    bumpedTxid.SetNull();
    AssertLockHeld(pWallet->cs_wallet);
    if (!pWallet->mapWallet.count(txid)) {
        vErrors.push_back("Invalid or non-wallet transaction id");
        currentResult = BumpFeeResult::INVALID_ADDRESS_OR_KEY;
        return;
    }
    auto it = pWallet->mapWallet.find(txid);
    const CWalletTx& wtx = it->second;

    if (pWallet->HasWalletSpend(txid)) {
        vErrors.push_back("Transaction has descendants in the wallet");
        currentResult = BumpFeeResult::INVALID_PARAMETER;
        return;
    }

    {
        LOCK(mempool.cs);
        auto it_mp = mempool.mapTx.find(txid);
        if (it_mp != mempool.mapTx.end() && it_mp->GetCountWithDescendants() > 1) {
            vErrors.push_back("Transaction has descendants in the mempool");
            currentResult = BumpFeeResult::INVALID_PARAMETER;
            return;
        }
    }

    if (wtx.GetDepthInMainChain() != 0) {
        vErrors.push_back("Transaction has been mined, or is conflicted with a mined transaction");
        currentResult = BumpFeeResult::WALLET_ERROR;
        return;
    }

    if (!SignalsOptInRBF(wtx)) {
        vErrors.push_back("Transaction is not BIP 125 replaceable");
        currentResult = BumpFeeResult::WALLET_ERROR;
        return;
    }

    if (wtx.mapValue.count("replaced_by_txid")) {
        vErrors.push_back(strprintf("Cannot bump transaction %s which was already bumped by transaction %s", txid.ToString(), wtx.mapValue.at("replaced_by_txid")));
        currentResult = BumpFeeResult::WALLET_ERROR;
        return;
    }

    // check that original tx consists entirely of our inputs
    // if not, we can't bump the fee, because the wallet has no way of knowing the value of the other inputs (thus the fee)
    if (!pWallet->IsAllFromMe(wtx, ISMINE_SPENDABLE)) {
        vErrors.push_back("Transaction contains inputs that don't belong to this wallet");
        currentResult = BumpFeeResult::WALLET_ERROR;
        return;
    }

    // figure out which output was change
    // if there was no change output or multiple change outputs, fail
    int nOutput = -1;
    for (size_t i = 0; i < wtx.tx->vout.size(); ++i) {
        if (pWallet->IsChange(wtx.tx->vout[i])) {
            if (nOutput != -1) {
                vErrors.push_back("Transaction has multiple change outputs");
                currentResult = BumpFeeResult::WALLET_ERROR;
                return;
            }
            nOutput = i;
        }
    }
    if (nOutput == -1) {
        vErrors.push_back("Transaction does not have a change output");
        currentResult = BumpFeeResult::WALLET_ERROR;
        return;
    }

    // Calculate the expected size of the new transaction.
    int64_t txSize = GetVirtualTransactionSize(*(wtx.tx));
    const int64_t maxNewTxSize = CalculateMaximumSignedTxSize(pWallet, *wtx.tx);
    if (maxNewTxSize < 0) {
        vErrors.push_back("Transaction contains inputs that cannot be signed");
        currentResult = BumpFeeResult::INVALID_ADDRESS_OR_KEY;
        return;
    }

    // calculate the old fee and fee-rate
    nOldFee = wtx.GetDebit(ISMINE_SPENDABLE) - wtx.tx->GetValueOut();
    CFeeRate nOldFeeRate(nOldFee, txSize);
    CFeeRate nNewFeeRate;
    // The wallet uses a conservative WALLET_INCREMENTAL_RELAY_FEE value to
    // future proof against changes to network wide policy for incremental relay
    // fee that our node may not be aware of.
    CFeeRate walletIncrementalRelayFee = CFeeRate(WALLET_INCREMENTAL_RELAY_FEE);
    if (::incrementalRelayFee > walletIncrementalRelayFee) {
        walletIncrementalRelayFee = ::incrementalRelayFee;
    }

    if (totalFee > 0) {
        CAmount minTotalFee = nOldFeeRate.GetFee(maxNewTxSize) + ::incrementalRelayFee.GetFee(maxNewTxSize);
        if (totalFee < minTotalFee) {
            vErrors.push_back(strprintf("Insufficient totalFee, must be at least %s (oldFee %s + incrementalFee %s)",
                                                                FormatMoney(minTotalFee), FormatMoney(nOldFeeRate.GetFee(maxNewTxSize)), FormatMoney(::incrementalRelayFee.GetFee(maxNewTxSize))));
            currentResult = BumpFeeResult::INVALID_PARAMETER;
            return;
        }
        CAmount requiredFee = pWallet->GetRequiredFee(maxNewTxSize);
        if (totalFee < requiredFee) {
            vErrors.push_back(strprintf("Insufficient totalFee (cannot be less than required fee %s)",
                                                                FormatMoney(requiredFee)));
            currentResult = BumpFeeResult::INVALID_PARAMETER;
            return;
        }
        nNewFee = totalFee;
        nNewFeeRate = CFeeRate(totalFee, maxNewTxSize);
    } else {
        // if user specified a confirm target then don't consider any global payTxFee
        if (specifiedConfirmTarget) {
            nNewFee = pWallet->GetMinimumFee(maxNewTxSize, newConfirmTarget, mempool, CAmount(0));
        }
        // otherwise use the regular wallet logic to select payTxFee or default confirm target
        else {
            nNewFee = pWallet->GetMinimumFee(maxNewTxSize, newConfirmTarget, mempool);
        }

        nNewFeeRate = CFeeRate(nNewFee, maxNewTxSize);

        // New fee rate must be at least old rate + minimum incremental relay rate
        // walletIncrementalRelayFee.GetFeePerK() should be exact, because it's initialized
        // in that unit (fee per kb).
        // However, nOldFeeRate is a calculated value from the tx fee/size, so
        // add 1 satoshi to the result, because it may have been rounded down.
        if (nNewFeeRate.GetFeePerK() < nOldFeeRate.GetFeePerK() + 1 + walletIncrementalRelayFee.GetFeePerK()) {
            nNewFeeRate = CFeeRate(nOldFeeRate.GetFeePerK() + 1 + walletIncrementalRelayFee.GetFeePerK());
            nNewFee = nNewFeeRate.GetFee(maxNewTxSize);
        }
    }

    // Check that in all cases the new fee doesn't violate maxTxFee
     if (nNewFee > maxTxFee) {
         vErrors.push_back(strprintf("Specified or calculated fee %s is too high (cannot be higher than maxTxFee %s)",
                               FormatMoney(nNewFee), FormatMoney(maxTxFee)));
         currentResult = BumpFeeResult::WALLET_ERROR;
         return;
     }

    // check that fee rate is higher than mempool's minimum fee
    // (no point in bumping fee if we know that the new tx won't be accepted to the mempool)
    // This may occur if the user set TotalFee or paytxfee too low, if fallbackfee is too low, or, perhaps,
    // in a rare situation where the mempool minimum fee increased significantly since the fee estimation just a
    // moment earlier. In this case, we report an error to the user, who may use totalFee to make an adjustment.
    CFeeRate minMempoolFeeRate = mempool.GetMinFee(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000);
    if (nNewFeeRate.GetFeePerK() < minMempoolFeeRate.GetFeePerK()) {
        vErrors.push_back(strprintf("New fee rate (%s) is less than the minimum fee rate (%s) to get into the mempool. totalFee value should to be at least %s or settxfee value should be at least %s to add transaction.", FormatMoney(nNewFeeRate.GetFeePerK()), FormatMoney(minMempoolFeeRate.GetFeePerK()), FormatMoney(minMempoolFeeRate.GetFee(maxNewTxSize)), FormatMoney(minMempoolFeeRate.GetFeePerK())));
        currentResult = BumpFeeResult::WALLET_ERROR;
        return;
    }

    // Now modify the output to increase the fee.
    // If the output is not large enough to pay the fee, fail.
    CAmount nDelta = nNewFee - nOldFee;
    assert(nDelta > 0);
    mtx =  *wtx.tx;
    CTxOut* poutput = &(mtx.vout[nOutput]);
    if (poutput->nValue < nDelta) {
        vErrors.push_back("Change output is too small to bump the fee");
        currentResult = BumpFeeResult::WALLET_ERROR;
        return;
    }

    // If the output would become dust, discard it (converting the dust to fee)
    poutput->nValue -= nDelta;
    if (poutput->nValue <= poutput->GetDustThreshold(::dustRelayFee)) {
        LogPrint(BCLog::RPC, "Bumping fee and discarding dust output\n");
        nNewFee += poutput->nValue;
        mtx.vout.erase(mtx.vout.begin() + nOutput);
    }

    // Mark new tx not replaceable, if requested.
    if (!newTxReplaceable) {
        for (auto& input : mtx.vin) {
            if (input.nSequence < 0xfffffffe) input.nSequence = 0xfffffffe;
        }
    }

    currentResult = BumpFeeResult::OK;
}

bool CFeeBumper::commit(CWallet *pWallet)
{
    AssertLockHeld(pWallet->cs_wallet);
    vErrors.clear();
    if (txid.IsNull() || !pWallet->mapWallet.count(txid)) {
        vErrors.push_back("Invalid or non-wallet transaction id");
        currentResult = BumpFeeResult::MISC_ERROR;
    }
    CWalletTx& oldWtx = pWallet->mapWallet[txid];

    CWalletTx wtxBumped(pWallet, MakeTransactionRef(std::move(mtx)));
    // commit/broadcast the tx
    CReserveKey reservekey(pWallet);
    wtxBumped.mapValue = oldWtx.mapValue;
    wtxBumped.mapValue["replaces_txid"] = oldWtx.GetHash().ToString();
    wtxBumped.vOrderForm = oldWtx.vOrderForm;
    wtxBumped.strFromAccount = oldWtx.strFromAccount;
    wtxBumped.fTimeReceivedIsTxTime = true;
    wtxBumped.fFromMe = true;
    CValidationState state;
    if (!pWallet->CommitTransaction(wtxBumped, reservekey, g_connman.get(), state)) {
        // NOTE: CommitTransaction never returns false, so this should never happen.
        vErrors.push_back(strprintf("Error: The transaction was rejected! Reason given: %s", state.GetRejectReason()));
        return false;
    }

    bumpedTxid = wtxBumped.GetHash();
    if (state.IsInvalid()) {
        // This can happen if the mempool rejected the transaction.  Report
        // what happened in the "errors" response.
        vErrors.push_back(strprintf("Error: The transaction was rejected: %s", FormatStateMessage(state)));
    }

    // mark the original tx as bumped
    if (!pWallet->MarkReplaced(oldWtx.GetHash(), wtxBumped.GetHash())) {
        // TODO: see if JSON-RPC has a standard way of returning a response
        // along with an exception. It would be good to return information about
        // wtxBumped to the caller even if marking the original transaction
        // replaced does not succeed for some reason.
        vErrors.push_back("Error: Created new bumpfee transaction but could not mark the original transaction as replaced.");
    }
    return true;
}

<commit_msg>Directly abort execution in FeeBumper::commit if wallet or tx is not available<commit_after>// Copyright (c) 2017 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 "consensus/validation.h"
#include "wallet/feebumper.h"
#include "wallet/wallet.h"
#include "policy/policy.h"
#include "policy/rbf.h"
#include "validation.h" //for mempool access
#include "txmempool.h"
#include "utilmoneystr.h"
#include "util.h"
#include "net.h"

// Calculate the size of the transaction assuming all signatures are max size
// Use DummySignatureCreator, which inserts 72 byte signatures everywhere.
// TODO: re-use this in CWallet::CreateTransaction (right now
// CreateTransaction uses the constructed dummy-signed tx to do a priority
// calculation, but we should be able to refactor after priority is removed).
// NOTE: this requires that all inputs must be in mapWallet (eg the tx should
// be IsAllFromMe).
int64_t CalculateMaximumSignedTxSize(const CWallet *pWallet, const CTransaction &tx)
{
    CMutableTransaction txNew(tx);
    std::vector<std::pair<const CWalletTx *, unsigned int>> vCoins;
    // Look up the inputs.  We should have already checked that this transaction
    // IsAllFromMe(ISMINE_SPENDABLE), so every input should already be in our
    // wallet, with a valid index into the vout array.
    for (auto& input : tx.vin) {
        const auto mi = pWallet->mapWallet.find(input.prevout.hash);
        assert(mi != pWallet->mapWallet.end() && input.prevout.n < mi->second.tx->vout.size());
        vCoins.emplace_back(std::make_pair(&(mi->second), input.prevout.n));
    }
    if (!pWallet->DummySignTx(txNew, vCoins)) {
        // This should never happen, because IsAllFromMe(ISMINE_SPENDABLE)
        // implies that we can sign for every input.
        return -1;
    }
    return GetVirtualTransactionSize(txNew);
}

CFeeBumper::CFeeBumper(const CWallet *pWallet, const uint256 txidIn, int newConfirmTarget, bool specifiedConfirmTarget, CAmount totalFee, bool newTxReplaceable)
    :
    txid(txidIn),
    nOldFee(0),
    nNewFee(0)
{
    vErrors.clear();
    bumpedTxid.SetNull();
    AssertLockHeld(pWallet->cs_wallet);
    if (!pWallet->mapWallet.count(txid)) {
        vErrors.push_back("Invalid or non-wallet transaction id");
        currentResult = BumpFeeResult::INVALID_ADDRESS_OR_KEY;
        return;
    }
    auto it = pWallet->mapWallet.find(txid);
    const CWalletTx& wtx = it->second;

    if (pWallet->HasWalletSpend(txid)) {
        vErrors.push_back("Transaction has descendants in the wallet");
        currentResult = BumpFeeResult::INVALID_PARAMETER;
        return;
    }

    {
        LOCK(mempool.cs);
        auto it_mp = mempool.mapTx.find(txid);
        if (it_mp != mempool.mapTx.end() && it_mp->GetCountWithDescendants() > 1) {
            vErrors.push_back("Transaction has descendants in the mempool");
            currentResult = BumpFeeResult::INVALID_PARAMETER;
            return;
        }
    }

    if (wtx.GetDepthInMainChain() != 0) {
        vErrors.push_back("Transaction has been mined, or is conflicted with a mined transaction");
        currentResult = BumpFeeResult::WALLET_ERROR;
        return;
    }

    if (!SignalsOptInRBF(wtx)) {
        vErrors.push_back("Transaction is not BIP 125 replaceable");
        currentResult = BumpFeeResult::WALLET_ERROR;
        return;
    }

    if (wtx.mapValue.count("replaced_by_txid")) {
        vErrors.push_back(strprintf("Cannot bump transaction %s which was already bumped by transaction %s", txid.ToString(), wtx.mapValue.at("replaced_by_txid")));
        currentResult = BumpFeeResult::WALLET_ERROR;
        return;
    }

    // check that original tx consists entirely of our inputs
    // if not, we can't bump the fee, because the wallet has no way of knowing the value of the other inputs (thus the fee)
    if (!pWallet->IsAllFromMe(wtx, ISMINE_SPENDABLE)) {
        vErrors.push_back("Transaction contains inputs that don't belong to this wallet");
        currentResult = BumpFeeResult::WALLET_ERROR;
        return;
    }

    // figure out which output was change
    // if there was no change output or multiple change outputs, fail
    int nOutput = -1;
    for (size_t i = 0; i < wtx.tx->vout.size(); ++i) {
        if (pWallet->IsChange(wtx.tx->vout[i])) {
            if (nOutput != -1) {
                vErrors.push_back("Transaction has multiple change outputs");
                currentResult = BumpFeeResult::WALLET_ERROR;
                return;
            }
            nOutput = i;
        }
    }
    if (nOutput == -1) {
        vErrors.push_back("Transaction does not have a change output");
        currentResult = BumpFeeResult::WALLET_ERROR;
        return;
    }

    // Calculate the expected size of the new transaction.
    int64_t txSize = GetVirtualTransactionSize(*(wtx.tx));
    const int64_t maxNewTxSize = CalculateMaximumSignedTxSize(pWallet, *wtx.tx);
    if (maxNewTxSize < 0) {
        vErrors.push_back("Transaction contains inputs that cannot be signed");
        currentResult = BumpFeeResult::INVALID_ADDRESS_OR_KEY;
        return;
    }

    // calculate the old fee and fee-rate
    nOldFee = wtx.GetDebit(ISMINE_SPENDABLE) - wtx.tx->GetValueOut();
    CFeeRate nOldFeeRate(nOldFee, txSize);
    CFeeRate nNewFeeRate;
    // The wallet uses a conservative WALLET_INCREMENTAL_RELAY_FEE value to
    // future proof against changes to network wide policy for incremental relay
    // fee that our node may not be aware of.
    CFeeRate walletIncrementalRelayFee = CFeeRate(WALLET_INCREMENTAL_RELAY_FEE);
    if (::incrementalRelayFee > walletIncrementalRelayFee) {
        walletIncrementalRelayFee = ::incrementalRelayFee;
    }

    if (totalFee > 0) {
        CAmount minTotalFee = nOldFeeRate.GetFee(maxNewTxSize) + ::incrementalRelayFee.GetFee(maxNewTxSize);
        if (totalFee < minTotalFee) {
            vErrors.push_back(strprintf("Insufficient totalFee, must be at least %s (oldFee %s + incrementalFee %s)",
                                                                FormatMoney(minTotalFee), FormatMoney(nOldFeeRate.GetFee(maxNewTxSize)), FormatMoney(::incrementalRelayFee.GetFee(maxNewTxSize))));
            currentResult = BumpFeeResult::INVALID_PARAMETER;
            return;
        }
        CAmount requiredFee = pWallet->GetRequiredFee(maxNewTxSize);
        if (totalFee < requiredFee) {
            vErrors.push_back(strprintf("Insufficient totalFee (cannot be less than required fee %s)",
                                                                FormatMoney(requiredFee)));
            currentResult = BumpFeeResult::INVALID_PARAMETER;
            return;
        }
        nNewFee = totalFee;
        nNewFeeRate = CFeeRate(totalFee, maxNewTxSize);
    } else {
        // if user specified a confirm target then don't consider any global payTxFee
        if (specifiedConfirmTarget) {
            nNewFee = pWallet->GetMinimumFee(maxNewTxSize, newConfirmTarget, mempool, CAmount(0));
        }
        // otherwise use the regular wallet logic to select payTxFee or default confirm target
        else {
            nNewFee = pWallet->GetMinimumFee(maxNewTxSize, newConfirmTarget, mempool);
        }

        nNewFeeRate = CFeeRate(nNewFee, maxNewTxSize);

        // New fee rate must be at least old rate + minimum incremental relay rate
        // walletIncrementalRelayFee.GetFeePerK() should be exact, because it's initialized
        // in that unit (fee per kb).
        // However, nOldFeeRate is a calculated value from the tx fee/size, so
        // add 1 satoshi to the result, because it may have been rounded down.
        if (nNewFeeRate.GetFeePerK() < nOldFeeRate.GetFeePerK() + 1 + walletIncrementalRelayFee.GetFeePerK()) {
            nNewFeeRate = CFeeRate(nOldFeeRate.GetFeePerK() + 1 + walletIncrementalRelayFee.GetFeePerK());
            nNewFee = nNewFeeRate.GetFee(maxNewTxSize);
        }
    }

    // Check that in all cases the new fee doesn't violate maxTxFee
     if (nNewFee > maxTxFee) {
         vErrors.push_back(strprintf("Specified or calculated fee %s is too high (cannot be higher than maxTxFee %s)",
                               FormatMoney(nNewFee), FormatMoney(maxTxFee)));
         currentResult = BumpFeeResult::WALLET_ERROR;
         return;
     }

    // check that fee rate is higher than mempool's minimum fee
    // (no point in bumping fee if we know that the new tx won't be accepted to the mempool)
    // This may occur if the user set TotalFee or paytxfee too low, if fallbackfee is too low, or, perhaps,
    // in a rare situation where the mempool minimum fee increased significantly since the fee estimation just a
    // moment earlier. In this case, we report an error to the user, who may use totalFee to make an adjustment.
    CFeeRate minMempoolFeeRate = mempool.GetMinFee(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000);
    if (nNewFeeRate.GetFeePerK() < minMempoolFeeRate.GetFeePerK()) {
        vErrors.push_back(strprintf("New fee rate (%s) is less than the minimum fee rate (%s) to get into the mempool. totalFee value should to be at least %s or settxfee value should be at least %s to add transaction.", FormatMoney(nNewFeeRate.GetFeePerK()), FormatMoney(minMempoolFeeRate.GetFeePerK()), FormatMoney(minMempoolFeeRate.GetFee(maxNewTxSize)), FormatMoney(minMempoolFeeRate.GetFeePerK())));
        currentResult = BumpFeeResult::WALLET_ERROR;
        return;
    }

    // Now modify the output to increase the fee.
    // If the output is not large enough to pay the fee, fail.
    CAmount nDelta = nNewFee - nOldFee;
    assert(nDelta > 0);
    mtx =  *wtx.tx;
    CTxOut* poutput = &(mtx.vout[nOutput]);
    if (poutput->nValue < nDelta) {
        vErrors.push_back("Change output is too small to bump the fee");
        currentResult = BumpFeeResult::WALLET_ERROR;
        return;
    }

    // If the output would become dust, discard it (converting the dust to fee)
    poutput->nValue -= nDelta;
    if (poutput->nValue <= poutput->GetDustThreshold(::dustRelayFee)) {
        LogPrint(BCLog::RPC, "Bumping fee and discarding dust output\n");
        nNewFee += poutput->nValue;
        mtx.vout.erase(mtx.vout.begin() + nOutput);
    }

    // Mark new tx not replaceable, if requested.
    if (!newTxReplaceable) {
        for (auto& input : mtx.vin) {
            if (input.nSequence < 0xfffffffe) input.nSequence = 0xfffffffe;
        }
    }

    currentResult = BumpFeeResult::OK;
}

bool CFeeBumper::commit(CWallet *pWallet)
{
    AssertLockHeld(pWallet->cs_wallet);
    vErrors.clear();
    if (txid.IsNull() || !pWallet->mapWallet.count(txid)) {
        vErrors.push_back("Invalid or non-wallet transaction id");
        currentResult = BumpFeeResult::MISC_ERROR;
        return false;
    }
    CWalletTx& oldWtx = pWallet->mapWallet[txid];

    CWalletTx wtxBumped(pWallet, MakeTransactionRef(std::move(mtx)));
    // commit/broadcast the tx
    CReserveKey reservekey(pWallet);
    wtxBumped.mapValue = oldWtx.mapValue;
    wtxBumped.mapValue["replaces_txid"] = oldWtx.GetHash().ToString();
    wtxBumped.vOrderForm = oldWtx.vOrderForm;
    wtxBumped.strFromAccount = oldWtx.strFromAccount;
    wtxBumped.fTimeReceivedIsTxTime = true;
    wtxBumped.fFromMe = true;
    CValidationState state;
    if (!pWallet->CommitTransaction(wtxBumped, reservekey, g_connman.get(), state)) {
        // NOTE: CommitTransaction never returns false, so this should never happen.
        vErrors.push_back(strprintf("Error: The transaction was rejected! Reason given: %s", state.GetRejectReason()));
        return false;
    }

    bumpedTxid = wtxBumped.GetHash();
    if (state.IsInvalid()) {
        // This can happen if the mempool rejected the transaction.  Report
        // what happened in the "errors" response.
        vErrors.push_back(strprintf("Error: The transaction was rejected: %s", FormatStateMessage(state)));
    }

    // mark the original tx as bumped
    if (!pWallet->MarkReplaced(oldWtx.GetHash(), wtxBumped.GetHash())) {
        // TODO: see if JSON-RPC has a standard way of returning a response
        // along with an exception. It would be good to return information about
        // wtxBumped to the caller even if marking the original transaction
        // replaced does not succeed for some reason.
        vErrors.push_back("Error: Created new bumpfee transaction but could not mark the original transaction as replaced.");
    }
    return true;
}

<|endoftext|>


<commit_before>#include "codesearch.h"
#include "interface.h"
#include "debug.h"
#include "git_indexer.h"
#include "fs_indexer.h"
#include "interface-impl.h"

#include <json/json.h>

#include <gflags/gflags.h>

#include <re2/re2.h>
using re2::RE2;
using std::unique_ptr;

namespace {

json_object *to_json(const string &str) {
    return json_object_new_string(str.c_str());
}

json_object *to_json(const StringPiece &str) {
    return json_object_new_string_len(str.data(),
                                      str.size());
}

json_object *to_json(int i) {
    return json_object_new_int(i);
}

static json_object *to_json(const indexed_path &path) {
    json_object *out = json_object_new_object();
    json_object_object_add(out, "repo", to_json(path.tree->repo->name));
    json_object_object_add(out, "ref",  to_json(path.tree->revision));
    json_object_object_add(out, "path", to_json(path.path));
    return out;
}

json_object *to_json(const indexed_repo &repo) {
    json_object *out = json_object_new_object();
    json_object_object_add(out, "name", to_json(repo.name));
    if (repo.metadata)
        json_object_object_add(out, "metadata", json_object_get(repo.metadata));
    return out;
}

template <class T>
json_object *to_json(vector<T> vec) {
    json_object *out = json_object_new_array();
    for (auto it = vec.begin(); it != vec.end(); it++)
        json_object_array_add(out, to_json(*it));
    return out;
}

json_object *json_frame(const std::string op, json_object *body) {
    json_object *frame = json_object_new_object();
    json_object_object_add(frame, "opcode", to_json(op));
    json_object_object_add(frame, "body", body);
    return frame;
}

json_object *json_info(const code_searcher *cs) {
    json_object *obj = json_object_new_object();
    json_object_object_add(obj, "repos", to_json(cs->repos()));
    json_object_object_add(obj, "name", to_json(cs->name()));
    return obj;
}

long timeval_ms (struct timeval tv) {
    return tv.tv_sec * 1000 + tv.tv_usec / 1000;
}

struct repo_spec {
    string path;
    string name;
    vector<string> revisions;
    json_object *metadata;
};

json_object *get_with_type(json_object *parent, const char *key, json_type type) {
    json_object *val = json_object_object_get(parent, key);
    if (val == NULL || json_object_is_type(val, type)) {
        return val;
    }
    die("Error: '%s': expected %s, got %s", key,
        json_type_to_name(type),
        json_type_to_name(json_object_get_type(val)));
    return NULL;
}

repo_spec parse_repo_spec(json_object *js) {
    debug(kDebugUI, "Parsing: %s", json_object_to_json_string(js));
    if (!json_object_is_type(js, json_type_object)) {
        die("repository spec must be an object.");
    }

    repo_spec spec;
    json_object *prop;
    if ((prop = get_with_type(js, "path", json_type_string)))
        spec.path = json_object_get_string(prop);
    if ((prop = get_with_type(js, "name", json_type_string)))
        spec.name = json_object_get_string(prop);
    spec.metadata = json_object_get(get_with_type(js, "metadata", json_type_object));

    json_object *js_revs = get_with_type(js, "revisions", json_type_array);
    if (js_revs && json_object_is_type(js_revs, json_type_array)) {
        for (int i = 0; i < json_object_array_length(js_revs); ++i) {
            json_object *elt = json_object_array_get_idx(js_revs, i);
            if (!json_object_is_type(elt, json_type_string))
                die("repository: 'revisions' must be list of strings");
            spec.revisions.push_back(json_object_get_string(elt));
        }
    }

    return spec;
}

void extract_repo_specs(vector<repo_spec> &out, json_object *js) {
    switch(json_object_get_type(js)) {
    case json_type_object:
        debug(kDebugUI, "Parsing a single repo");
        out.push_back(parse_repo_spec(js));
        break;
    case json_type_array:
        debug(kDebugUI, "Parsing an array of repos...");
        for (int i = 0; i < json_object_array_length(js); ++i) {
            out.push_back(parse_repo_spec(json_object_array_get_idx(js, i)));
        }
        break;
    default:
        die("unrecognized type for repo spec: %s",
            json_object_to_json_string(js));
        exit(1);
    }
}

class json_interface : public codesearch_interface {
public:
    json_interface(FILE *in, FILE *out) : in_(in), out_(out) { }

    void write_frame(const std::string &opcode, json_object *body) {
        json_object *frame = json_frame(opcode, body);
        fprintf(out_, "%s\n", json_object_to_json_string(frame));
        json_object_put(frame);
    }

    virtual void print_match(const match_result *m) {
        json_object *obj = json_object_new_object();
        json_object *contexts = json_object_new_array();
        for (auto ctx = m->context.begin();
             ctx != m->context.end(); ++ctx) {
            json_object *jctx = json_object_new_object();
            json_object_object_add(jctx, "paths",  to_json(ctx->paths));
            json_object_object_add(jctx, "lno", to_json(ctx->lno));
            json_object_object_add(jctx, "context_before",
                                   to_json(ctx->context_before));
            json_object_object_add(jctx, "context_after",
                                   to_json(ctx->context_after));
            json_object_array_add(contexts, jctx);
        }
        json_object_object_add(obj, "contexts", contexts);
        json_object *bounds = json_object_new_array();
        json_object_array_add(bounds, to_json(m->matchleft));
        json_object_array_add(bounds, to_json(m->matchright));
        json_object_object_add(obj, "bounds", bounds);
        json_object_object_add(obj, "line", to_json(m->line));
        write_frame("match", obj);
    }

    virtual void print_error(const std::string &err) {
        write_frame("error", to_json(err));
    }

    virtual void print_prompt(const code_searcher *cs) {
        write_frame("ready", json_info(cs));
    }

    virtual bool getline(std::string &input) {
        return ::getline(input, in_);
    }

    bool extract_regex(json_object *js, const std::string &key,
                       const RE2::Options &opts, unique_ptr<RE2> *out) {
        out->reset(0);
        json_object *re_js = json_object_object_get(js, key.c_str());
        if (re_js == NULL)
            return true;

        if (json_object_get_type(re_js) != json_type_string) {
            print_error(std::string("Expected a JSON object: ") + key);
            return false;
        }
        unique_ptr<RE2> re(new RE2(json_object_get_string(re_js), opts));
        if (!re->ok()) {
            print_error(re->error());
            return false;
        }

        *out = std::move(re);
        return true;
    }

    virtual bool parse_query(const std::string &input,
                             query *out) {
        json_object *js = json_tokener_parse(input.c_str());
        if (is_error(js)) {
            print_error("Parse error: " +
                        string(json_tokener_errors[-(unsigned long)js]));
            return false;
        }
        if (json_object_get_type(js) != json_type_object) {
            print_error("Expected a JSON object");
            return false;
        }
        json_object *q = json_object_object_get(js, "body");
        if (q == NULL || json_object_get_type(q) != json_type_object) {
            print_error("Expected a JSON object");
            return false;
        }

        RE2::Options opts;
        default_re2_options(opts);

        json_object *fold_case = json_object_object_get(q, "fold_case");
        if (fold_case &&
            json_object_get_type(fold_case) == json_type_boolean &&
            json_object_get_boolean(fold_case))
            opts.set_case_sensitive(false);

        if (!extract_regex(q, "line", opts, &out->line_pat))
            return false;
        if (out->line_pat.get() == 0) {
            print_error("No regex specified!");
            return false;
        }

        opts.set_case_sensitive(true);

        if (!extract_regex(q, "file", opts, &out->file_pat) ||
            !extract_regex(q, "repo", opts, &out->tree_pat)) {
            return false;
        }

        json_object_put(js);

        return true;
    }

    virtual void print_stats(timeval elapsed, const match_stats *stats) {
        json_object *obj = json_object_new_object();
        json_object_object_add(obj, "re2_time", json_object_new_int
                               (timeval_ms(stats->re2_time)));
        json_object_object_add(obj, "git_time", json_object_new_int
                               (timeval_ms(stats->git_time)));
        json_object_object_add(obj, "sort_time", json_object_new_int
                               (timeval_ms(stats->sort_time)));
        json_object_object_add(obj, "index_time", json_object_new_int
                               (timeval_ms(stats->index_time)));
        json_object_object_add(obj, "analyze_time", json_object_new_int
                               (timeval_ms(stats->analyze_time)));
        switch(stats->why) {
        case kExitNone: break;
        case kExitMatchLimit:
            json_object_object_add(obj, "why", json_object_new_string("limit"));
            break;
        case kExitTimeout:
            json_object_object_add(obj, "why", json_object_new_string("timeout"));
            break;
        }
        write_frame("done", obj);
    }

    virtual void build_index(code_searcher *cs, const vector<std::string> &argv) {
        if (argv.size() != 2) {
            print_error("Usage: " + argv[0] + " --json [OPTIONS] config.json");
            exit(1);
        }
        json_object *obj = json_object_from_file(const_cast<char*>(argv[1].c_str()));
        if (is_error(obj)) {
            print_error(string("Error parsing `") + argv[1] + string("': ") +
                        string(json_tokener_errors[-(unsigned long)obj]));
            exit(1);
        }

        json_object *name = json_object_object_get(obj, "name");
        if (json_object_is_type(name, json_type_string))
            cs->set_name(json_object_get_string(name));

        string path;
        json_object *js_paths = json_object_object_get(obj, "fs_paths");
        if (js_paths && json_object_is_type(js_paths, json_type_array)) {
            for (int i = 0; i < json_object_array_length(js_paths); ++i) {
                json_object *elt = json_object_array_get_idx(js_paths, i);
                if (json_object_is_type(elt, json_type_string)) {
                    path = json_object_get_string(elt);
                    debug(kDebugUI, "Walking `%s'...\n",
                        path.c_str());
                    fs_indexer indexer(cs, path);
                    indexer.walk(path);
                    debug(kDebugUI, "done\n");
                }
            }
        }

        vector<repo_spec> repos;
        json_object *repo_spec = json_object_object_get(obj, "repositories");
        if (repo_spec) {
            extract_repo_specs(repos, repo_spec);
            json_object_put(obj);

            for (auto it = repos.begin(); it != repos.end(); ++it) {
                debug(kDebugUI, "Walking name=%s, path=%s",
                      it->name.c_str(), it->path.c_str());
                git_indexer indexer(cs, it->path, it->name, it->metadata);
                for (auto rev = it->revisions.begin();
                     rev != it->revisions.end(); ++rev) {
                    debug(kDebugUI, "  walking %s..", rev->c_str());
                    indexer.walk(*rev);
                }
            }
        }
    }

    virtual void info(const char *msg, ...) {}
    virtual ~json_interface() {}

protected:
    FILE *in_, *out_;
};

};

codesearch_interface *make_json_interface(FILE *in, FILE *out) {
    return new json_interface(in, out);
}
<commit_msg>Implement a compat version of json_type_to_name.<commit_after>#include "codesearch.h"
#include "interface.h"
#include "debug.h"
#include "git_indexer.h"
#include "fs_indexer.h"
#include "interface-impl.h"

#include <json/json.h>

#include <gflags/gflags.h>

#include <re2/re2.h>
using re2::RE2;
using std::unique_ptr;

namespace {

json_object *to_json(const string &str) {
    return json_object_new_string(str.c_str());
}

json_object *to_json(const StringPiece &str) {
    return json_object_new_string_len(str.data(),
                                      str.size());
}

json_object *to_json(int i) {
    return json_object_new_int(i);
}

static json_object *to_json(const indexed_path &path) {
    json_object *out = json_object_new_object();
    json_object_object_add(out, "repo", to_json(path.tree->repo->name));
    json_object_object_add(out, "ref",  to_json(path.tree->revision));
    json_object_object_add(out, "path", to_json(path.path));
    return out;
}

json_object *to_json(const indexed_repo &repo) {
    json_object *out = json_object_new_object();
    json_object_object_add(out, "name", to_json(repo.name));
    if (repo.metadata)
        json_object_object_add(out, "metadata", json_object_get(repo.metadata));
    return out;
}

template <class T>
json_object *to_json(vector<T> vec) {
    json_object *out = json_object_new_array();
    for (auto it = vec.begin(); it != vec.end(); it++)
        json_object_array_add(out, to_json(*it));
    return out;
}

json_object *json_frame(const std::string op, json_object *body) {
    json_object *frame = json_object_new_object();
    json_object_object_add(frame, "opcode", to_json(op));
    json_object_object_add(frame, "body", body);
    return frame;
}

json_object *json_info(const code_searcher *cs) {
    json_object *obj = json_object_new_object();
    json_object_object_add(obj, "repos", to_json(cs->repos()));
    json_object_object_add(obj, "name", to_json(cs->name()));
    return obj;
}

long timeval_ms (struct timeval tv) {
    return tv.tv_sec * 1000 + tv.tv_usec / 1000;
}

struct repo_spec {
    string path;
    string name;
    vector<string> revisions;
    json_object *metadata;
};

// Reimplement this for compatibility with old libjson
const char *compat_json_type_to_name(enum json_type o_type) {
    switch (o_type) {
    case json_type_null:
        return "null";
    case json_type_boolean:
        return "boolean";
    case json_type_double:
        return "double";
    case json_type_int:
        return "int";
    case json_type_object:
        return "object";
    case json_type_array:
        return "array";
    case json_type_string:
        return "string";
    default:
        return "<unknown>";
    }
}

json_object *get_with_type(json_object *parent, const char *key, json_type type) {
    json_object *val = json_object_object_get(parent, key);
    if (val == NULL || json_object_is_type(val, type)) {
        return val;
    }
    die("Error: '%s': expected %s, got %s", key,
        compat_json_type_to_name(type),
        compat_json_type_to_name(json_object_get_type(val)));
    return NULL;
}

repo_spec parse_repo_spec(json_object *js) {
    debug(kDebugUI, "Parsing: %s", json_object_to_json_string(js));
    if (!json_object_is_type(js, json_type_object)) {
        die("repository spec must be an object.");
    }

    repo_spec spec;
    json_object *prop;
    if ((prop = get_with_type(js, "path", json_type_string)))
        spec.path = json_object_get_string(prop);
    if ((prop = get_with_type(js, "name", json_type_string)))
        spec.name = json_object_get_string(prop);
    spec.metadata = json_object_get(get_with_type(js, "metadata", json_type_object));

    json_object *js_revs = get_with_type(js, "revisions", json_type_array);
    if (js_revs && json_object_is_type(js_revs, json_type_array)) {
        for (int i = 0; i < json_object_array_length(js_revs); ++i) {
            json_object *elt = json_object_array_get_idx(js_revs, i);
            if (!json_object_is_type(elt, json_type_string))
                die("repository: 'revisions' must be list of strings");
            spec.revisions.push_back(json_object_get_string(elt));
        }
    }

    return spec;
}

void extract_repo_specs(vector<repo_spec> &out, json_object *js) {
    switch(json_object_get_type(js)) {
    case json_type_object:
        debug(kDebugUI, "Parsing a single repo");
        out.push_back(parse_repo_spec(js));
        break;
    case json_type_array:
        debug(kDebugUI, "Parsing an array of repos...");
        for (int i = 0; i < json_object_array_length(js); ++i) {
            out.push_back(parse_repo_spec(json_object_array_get_idx(js, i)));
        }
        break;
    default:
        die("unrecognized type for repo spec: %s",
            json_object_to_json_string(js));
        exit(1);
    }
}

class json_interface : public codesearch_interface {
public:
    json_interface(FILE *in, FILE *out) : in_(in), out_(out) { }

    void write_frame(const std::string &opcode, json_object *body) {
        json_object *frame = json_frame(opcode, body);
        fprintf(out_, "%s\n", json_object_to_json_string(frame));
        json_object_put(frame);
    }

    virtual void print_match(const match_result *m) {
        json_object *obj = json_object_new_object();
        json_object *contexts = json_object_new_array();
        for (auto ctx = m->context.begin();
             ctx != m->context.end(); ++ctx) {
            json_object *jctx = json_object_new_object();
            json_object_object_add(jctx, "paths",  to_json(ctx->paths));
            json_object_object_add(jctx, "lno", to_json(ctx->lno));
            json_object_object_add(jctx, "context_before",
                                   to_json(ctx->context_before));
            json_object_object_add(jctx, "context_after",
                                   to_json(ctx->context_after));
            json_object_array_add(contexts, jctx);
        }
        json_object_object_add(obj, "contexts", contexts);
        json_object *bounds = json_object_new_array();
        json_object_array_add(bounds, to_json(m->matchleft));
        json_object_array_add(bounds, to_json(m->matchright));
        json_object_object_add(obj, "bounds", bounds);
        json_object_object_add(obj, "line", to_json(m->line));
        write_frame("match", obj);
    }

    virtual void print_error(const std::string &err) {
        write_frame("error", to_json(err));
    }

    virtual void print_prompt(const code_searcher *cs) {
        write_frame("ready", json_info(cs));
    }

    virtual bool getline(std::string &input) {
        return ::getline(input, in_);
    }

    bool extract_regex(json_object *js, const std::string &key,
                       const RE2::Options &opts, unique_ptr<RE2> *out) {
        out->reset(0);
        json_object *re_js = json_object_object_get(js, key.c_str());
        if (re_js == NULL)
            return true;

        if (json_object_get_type(re_js) != json_type_string) {
            print_error(std::string("Expected a JSON object: ") + key);
            return false;
        }
        unique_ptr<RE2> re(new RE2(json_object_get_string(re_js), opts));
        if (!re->ok()) {
            print_error(re->error());
            return false;
        }

        *out = std::move(re);
        return true;
    }

    virtual bool parse_query(const std::string &input,
                             query *out) {
        json_object *js = json_tokener_parse(input.c_str());
        if (is_error(js)) {
            print_error("Parse error: " +
                        string(json_tokener_errors[-(unsigned long)js]));
            return false;
        }
        if (json_object_get_type(js) != json_type_object) {
            print_error("Expected a JSON object");
            return false;
        }
        json_object *q = json_object_object_get(js, "body");
        if (q == NULL || json_object_get_type(q) != json_type_object) {
            print_error("Expected a JSON object");
            return false;
        }

        RE2::Options opts;
        default_re2_options(opts);

        json_object *fold_case = json_object_object_get(q, "fold_case");
        if (fold_case &&
            json_object_get_type(fold_case) == json_type_boolean &&
            json_object_get_boolean(fold_case))
            opts.set_case_sensitive(false);

        if (!extract_regex(q, "line", opts, &out->line_pat))
            return false;
        if (out->line_pat.get() == 0) {
            print_error("No regex specified!");
            return false;
        }

        opts.set_case_sensitive(true);

        if (!extract_regex(q, "file", opts, &out->file_pat) ||
            !extract_regex(q, "repo", opts, &out->tree_pat)) {
            return false;
        }

        json_object_put(js);

        return true;
    }

    virtual void print_stats(timeval elapsed, const match_stats *stats) {
        json_object *obj = json_object_new_object();
        json_object_object_add(obj, "re2_time", json_object_new_int
                               (timeval_ms(stats->re2_time)));
        json_object_object_add(obj, "git_time", json_object_new_int
                               (timeval_ms(stats->git_time)));
        json_object_object_add(obj, "sort_time", json_object_new_int
                               (timeval_ms(stats->sort_time)));
        json_object_object_add(obj, "index_time", json_object_new_int
                               (timeval_ms(stats->index_time)));
        json_object_object_add(obj, "analyze_time", json_object_new_int
                               (timeval_ms(stats->analyze_time)));
        switch(stats->why) {
        case kExitNone: break;
        case kExitMatchLimit:
            json_object_object_add(obj, "why", json_object_new_string("limit"));
            break;
        case kExitTimeout:
            json_object_object_add(obj, "why", json_object_new_string("timeout"));
            break;
        }
        write_frame("done", obj);
    }

    virtual void build_index(code_searcher *cs, const vector<std::string> &argv) {
        if (argv.size() != 2) {
            print_error("Usage: " + argv[0] + " --json [OPTIONS] config.json");
            exit(1);
        }
        json_object *obj = json_object_from_file(const_cast<char*>(argv[1].c_str()));
        if (is_error(obj)) {
            print_error(string("Error parsing `") + argv[1] + string("': ") +
                        string(json_tokener_errors[-(unsigned long)obj]));
            exit(1);
        }

        json_object *name = json_object_object_get(obj, "name");
        if (json_object_is_type(name, json_type_string))
            cs->set_name(json_object_get_string(name));

        string path;
        json_object *js_paths = json_object_object_get(obj, "fs_paths");
        if (js_paths && json_object_is_type(js_paths, json_type_array)) {
            for (int i = 0; i < json_object_array_length(js_paths); ++i) {
                json_object *elt = json_object_array_get_idx(js_paths, i);
                if (json_object_is_type(elt, json_type_string)) {
                    path = json_object_get_string(elt);
                    debug(kDebugUI, "Walking `%s'...\n",
                        path.c_str());
                    fs_indexer indexer(cs, path);
                    indexer.walk(path);
                    debug(kDebugUI, "done\n");
                }
            }
        }

        vector<repo_spec> repos;
        json_object *repo_spec = json_object_object_get(obj, "repositories");
        if (repo_spec) {
            extract_repo_specs(repos, repo_spec);
            json_object_put(obj);

            for (auto it = repos.begin(); it != repos.end(); ++it) {
                debug(kDebugUI, "Walking name=%s, path=%s",
                      it->name.c_str(), it->path.c_str());
                git_indexer indexer(cs, it->path, it->name, it->metadata);
                for (auto rev = it->revisions.begin();
                     rev != it->revisions.end(); ++rev) {
                    debug(kDebugUI, "  walking %s..", rev->c_str());
                    indexer.walk(*rev);
                }
            }
        }
    }

    virtual void info(const char *msg, ...) {}
    virtual ~json_interface() {}

protected:
    FILE *in_, *out_;
};

};

codesearch_interface *make_json_interface(FILE *in, FILE *out) {
    return new json_interface(in, out);
}
<|endoftext|>


<commit_before>/**
 * @file AquilaFft.cpp
 *
 * A custom implementation of FFT radix-2 algorithm.
 *
 * This file is part of the Aquila DSP library.
 * Aquila is free software, licensed under the MIT/X11 License. A copy of
 * the license is provided with the library in the LICENSE file.
 *
 * @package Aquila
 * @version 3.0.0-dev
 * @author Zbigniew Siciarz
 * @date 2007-2010
 * @license http://www.opensource.org/licenses/mit-license.php MIT
 * @since 3.0.0
 */

#include "AquilaFft.h"
#include <algorithm>
#include <cmath>

namespace Aquila
{
    /**
     * Complex unit.
     */
    const ComplexType AquilaFft::j(0, 1);

    /**
     * Applies the transformation to the signal.
     *
     * @param x input signal
     * @param spectrum output specturm
     */
    void AquilaFft::fft(double x[], ComplexType spectrum[])
    {
        // bit-reversing the samples - a requirement of radix-2
        // instead of reversing in place, put the samples to result array
        unsigned int a = 1, b = 0, c = 0;
        std::copy(x, x + N, spectrum);
        for (b = 1; b < N; ++b)
        {
            if (b < a)
            {
                spectrum[a - 1] = x[b - 1];
                spectrum[b - 1] = x[a - 1];
            }
            c = N / 2;
            while (c < a)
            {
                a -= c;
                c /= 2;
            }
            a += c;
        }

        // FFT calculation using "butterflies"
        // code ported from Matlab, based on book by Tomasz P. Zieliski

        // FFT stages count
        unsigned int numStages = static_cast<unsigned int>(
                std::log(double(N)) / LN_2);

        // L = 2^k - DFT block length and offset
        // M = 2^(k-1) - butterflies per block, butterfly width
        // p - butterfly index
        // q - block index
        // r - index of sample in butterfly
        // Wi - starting value of Fourier base coefficient
        unsigned int L = 0, M = 0, p = 0, q = 0, r = 0;
        ComplexType Wi(0, 0), Temp(0, 0);

        ComplexType** Wi_cache = getCachedFftWi(numStages);

        // iterate over the stages
        for (unsigned int k = 1; k <= numStages; ++k)
        {
            L = 1 << k;
            M = 1 << (k - 1);
            Wi = Wi_cache[k][0];

            // iterate over butterflies
            for (p = 1; p <= M; ++p)
            {
                // iterate over blocks
                for (q = p; q <= N; q += L)
                {
                    r = q + M;
                    Temp = spectrum[r - 1] * Wi;
                    spectrum[r - 1] = spectrum[q - 1] - Temp;
                    spectrum[q - 1] = spectrum[q - 1] + Temp;
                }
                Wi = Wi_cache[k][p];
            }
        }
    }

    /**
     * Returns a table of Wi (twiddle factors) stored in cache.
     *
     * @param numStages the FFT stages count
     * @return pointer to an array of pointers to arrays of complex numbers
     */
    ComplexType** AquilaFft::getCachedFftWi(unsigned int numStages)
    {
        fftWiCacheKeyType key = numStages;
        // cache hit, return immediately
        if (fftWiCache.find(key) != fftWiCache.end())
        {
            return fftWiCache[key];
        }

        // nothing in cache, calculate twiddle factors
        ComplexType** Wi = new ComplexType*[numStages+1];
        for (unsigned int k = 1; k <= numStages; ++k)
        {
            // L = 2^k - DFT block length and offset
            // M = 2^(k-1) - butterflies per block, butterfly width
            // W - Fourier base multiplying factor
            unsigned int L = 1 << k;
            unsigned int M = 1 << (k-1);
            ComplexType W = exp((-j) * 2.0 * M_PI / double(L));
            Wi[k] = new ComplexType[M+1];
            Wi[k][0] = ComplexType(1.0);
            for (unsigned int p = 1; p <= M; ++p)
            {
                Wi[k][p] = Wi[k][p-1] * W;
            }
        }

        // store in cache and return
        fftWiCache[key] = Wi;

        return Wi;
    }

    /**
     * Clears the twiddle factor cache.
     */
    void AquilaFft::clearFftWiCache()
    {
        fftWiCacheType::const_iterator it;
        for (it = fftWiCache.begin(); it != fftWiCache.end(); it++)
        {
            ComplexType** c = it->second;
            unsigned int numStages = it->first;
            for (unsigned int i = 1; i <= numStages; ++i)
            {
                delete [] c[i];
            }

            delete [] c;
        }
    }
}
<commit_msg>Fixed encoding of the Polish name.<commit_after>/**
 * @file AquilaFft.cpp
 *
 * A custom implementation of FFT radix-2 algorithm.
 *
 * This file is part of the Aquila DSP library.
 * Aquila is free software, licensed under the MIT/X11 License. A copy of
 * the license is provided with the library in the LICENSE file.
 *
 * @package Aquila
 * @version 3.0.0-dev
 * @author Zbigniew Siciarz
 * @date 2007-2010
 * @license http://www.opensource.org/licenses/mit-license.php MIT
 * @since 3.0.0
 */

#include "AquilaFft.h"
#include <algorithm>
#include <cmath>

namespace Aquila
{
    /**
     * Complex unit.
     */
    const ComplexType AquilaFft::j(0, 1);

    /**
     * Applies the transformation to the signal.
     *
     * @param x input signal
     * @param spectrum output specturm
     */
    void AquilaFft::fft(double x[], ComplexType spectrum[])
    {
        // bit-reversing the samples - a requirement of radix-2
        // instead of reversing in place, put the samples to result array
        unsigned int a = 1, b = 0, c = 0;
        std::copy(x, x + N, spectrum);
        for (b = 1; b < N; ++b)
        {
            if (b < a)
            {
                spectrum[a - 1] = x[b - 1];
                spectrum[b - 1] = x[a - 1];
            }
            c = N / 2;
            while (c < a)
            {
                a -= c;
                c /= 2;
            }
            a += c;
        }

        // FFT calculation using "butterflies"
        // code ported from Matlab, based on book by Tomasz P. Zieliński

        // FFT stages count
        unsigned int numStages = static_cast<unsigned int>(
                std::log(double(N)) / LN_2);

        // L = 2^k - DFT block length and offset
        // M = 2^(k-1) - butterflies per block, butterfly width
        // p - butterfly index
        // q - block index
        // r - index of sample in butterfly
        // Wi - starting value of Fourier base coefficient
        unsigned int L = 0, M = 0, p = 0, q = 0, r = 0;
        ComplexType Wi(0, 0), Temp(0, 0);

        ComplexType** Wi_cache = getCachedFftWi(numStages);

        // iterate over the stages
        for (unsigned int k = 1; k <= numStages; ++k)
        {
            L = 1 << k;
            M = 1 << (k - 1);
            Wi = Wi_cache[k][0];

            // iterate over butterflies
            for (p = 1; p <= M; ++p)
            {
                // iterate over blocks
                for (q = p; q <= N; q += L)
                {
                    r = q + M;
                    Temp = spectrum[r - 1] * Wi;
                    spectrum[r - 1] = spectrum[q - 1] - Temp;
                    spectrum[q - 1] = spectrum[q - 1] + Temp;
                }
                Wi = Wi_cache[k][p];
            }
        }
    }

    /**
     * Returns a table of Wi (twiddle factors) stored in cache.
     *
     * @param numStages the FFT stages count
     * @return pointer to an array of pointers to arrays of complex numbers
     */
    ComplexType** AquilaFft::getCachedFftWi(unsigned int numStages)
    {
        fftWiCacheKeyType key = numStages;
        // cache hit, return immediately
        if (fftWiCache.find(key) != fftWiCache.end())
        {
            return fftWiCache[key];
        }

        // nothing in cache, calculate twiddle factors
        ComplexType** Wi = new ComplexType*[numStages+1];
        for (unsigned int k = 1; k <= numStages; ++k)
        {
            // L = 2^k - DFT block length and offset
            // M = 2^(k-1) - butterflies per block, butterfly width
            // W - Fourier base multiplying factor
            unsigned int L = 1 << k;
            unsigned int M = 1 << (k-1);
            ComplexType W = exp((-j) * 2.0 * M_PI / double(L));
            Wi[k] = new ComplexType[M+1];
            Wi[k][0] = ComplexType(1.0);
            for (unsigned int p = 1; p <= M; ++p)
            {
                Wi[k][p] = Wi[k][p-1] * W;
            }
        }

        // store in cache and return
        fftWiCache[key] = Wi;

        return Wi;
    }

    /**
     * Clears the twiddle factor cache.
     */
    void AquilaFft::clearFftWiCache()
    {
        fftWiCacheType::const_iterator it;
        for (it = fftWiCache.begin(); it != fftWiCache.end(); it++)
        {
            ComplexType** c = it->second;
            unsigned int numStages = it->first;
            for (unsigned int i = 1; i <= numStages; ++i)
            {
                delete [] c[i];
            }

            delete [] c;
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 AUV-IITK
#include <ros/ros.h>
#include <std_msgs/Float32.h>
#include <std_msgs/Float64.h>
#include <task_commons/buoyAction.h>
#include <task_commons/lineAction.h>
#include <task_commons/buoyActionFeedback.h>
#include <task_commons/lineActionFeedback.h>
#include <task_commons/buoyActionResult.h>
#include <task_commons/lineActionResult.h>
#include <motion_commons/ForwardAction.h>
#include <motion_commons/UpwardAction.h>
#include <motion_commons/UpwardActionFeedback.h>
#include <motion_commons/ForwardActionFeedback.h>
#include <motion_commons/UpwardActionResult.h>
#include <motion_commons/ForwardActionResult.h>
#include <actionlib/client/simple_action_client.h>
#include <actionlib/client/terminal_state.h>

typedef actionlib::SimpleActionClient<task_commons::buoyAction> ClientBuoy;
typedef actionlib::SimpleActionClient<task_commons::lineAction> ClientLine;
typedef actionlib::SimpleActionClient<motion_commons::UpwardAction> ClientUpward;
typedef actionlib::SimpleActionClient<motion_commons::ForwardAction> ClientForward;

ClientBuoy *ptrClientBuoy;
ClientLine *ptrClientLine;
ClientUpward *ptrClientUpward;
ClientForward *ptrClientForward;
task_commons::buoyGoal goalBuoy;
task_commons::lineGoal goalLine;
motion_commons::UpwardGoal goalUpward;
motion_commons::ForwardGoal goalForward;

ros::Publisher pub_upward;
ros::Publisher pub_forward;

bool successBuoy = false;
bool successLine = false;
bool successUpward = false;
bool successDownward = false;

float present_depth;

void spinThreadBuoy()
{
  ClientBuoy &temp = *ptrClientBuoy;
  temp.waitForResult();
  successBuoy = (*(temp.getResult())).MotionCompleted;
  if (successBuoy)
  {
    ROS_INFO("%s: motion buoy successful", ros::this_node::getName().c_str());
  }
  else
    ROS_INFO("%s: motion buoy unsuccessful", ros::this_node::getName().c_str());
}

void spinThreadLine()
{
  ClientLine &temp = *ptrClientLine;
  temp.waitForResult();
  successLine = (*(temp.getResult())).MotionCompleted;
  if (successLine)
  {
    ROS_INFO("%s: motion line successful", ros::this_node::getName().c_str());
  }
  else
    ROS_INFO("%s: motion line unsuccessful", ros::this_node::getName().c_str());
}

void spinThreadUpwardPressure()
{
  ClientUpward &temp = *ptrClientUpward;
  temp.waitForResult();
  successUpward = (*(temp.getResult())).Result;
  if (successUpward)
  {
    ROS_INFO("%s Bot is at desired height.", ros::this_node::getName().c_str());
  }
  else
  {
    ROS_INFO("%s Bot is not at desired height, something went wrong", ros::this_node::getName().c_str());
  }
}

void spinThreadDownwardPressure()
{
  ClientUpward &temp = *ptrClientUpward;
  temp.waitForResult();
  successDownward = (*(temp.getResult())).Result;
  if (successDownward)
  {
    ROS_INFO("%s Bot is at desired height.", ros::this_node::getName().c_str());
  }
  else
  {
    ROS_INFO("%s Bot is not at desired height, something went wrong", ros::this_node::getName().c_str());
  }
}
// never ever put the argument of the callback function anything other then the specified
void buoyCB(task_commons::buoyActionFeedback msg)
{
  ROS_INFO("%s: x_coord = %f, y_coord = %f, distance = %f",
    ros::this_node::getName().c_str(), msg.feedback.x_coord, msg.feedback.y_coord, msg.feedback.distance);
}

void lineCB(task_commons::lineActionFeedback msg)
{
  ROS_INFO("%s: feedback recieved Angle Remaining = %f, x_coord = %f, y_coord = %f",
    ros::this_node::getName().c_str(), msg.feedback.AngleRemaining, msg.feedback.x_coord, msg.feedback.y_coord);
}

void pressureCB(std_msgs::Float64 pressure_sensor_data)
{
  present_depth = pressure_sensor_data.data;
  if (successBuoy)
    pub_upward.publish(pressure_sensor_data);
}

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

  ros::NodeHandle nh;
  // here buoy_server is the name of the node of the actionserver.
  ros::Subscriber sub_buoy = nh.subscribe<task_commons::buoyActionFeedback>("/buoy_server/feedback",
    1000, &buoyCB);
  ros::Subscriber sub_line = nh.subscribe<task_commons::lineActionFeedback>("/line_server/feedback",
    1000, &lineCB);
  ros::Subscriber sub_upward = nh.subscribe<std_msgs::Float64>("/varun/sensors/pressure_sensor/depth",
    1000, &pressureCB);
  pub_upward = nh.advertise<std_msgs::Float64>("/varun/motion/z_distance", 1000);
  pub_forward = nh.advertise<std_msgs::Float64>("/varun/motion/x_distance", 1000);

  ClientBuoy buoyClient("buoy_server");
  ptrClientBuoy = &buoyClient;
  ClientLine lineClient("line_server");
  ptrClientLine = &lineClient;
  ClientUpward upwardClient("upward");
  ptrClientUpward = &upwardClient;
  ClientForward forwardClient("forward");
  ptrClientForward = &forwardClient;

  ROS_INFO("Waiting for action server to start.");
  lineClient.waitForServer();
  buoyClient.waitForServer();
  upwardClient.waitForServer();
  forwardClient.waitForServer();

  goalLine.order = true;
  ROS_INFO("Action server started, sending goal to line.");

  ClientLine &canLine = *ptrClientLine;
  // send goal
  canLine.sendGoal(goalLine);
  boost::thread spin_thread_line(&spinThreadLine);

  while (!successLine)
  {
    ros::spinOnce();
  }

  goalBuoy.order = true;
  ROS_INFO("Action server started, sending goal to buoy.");

  ClientBuoy &canBuoy = *ptrClientBuoy;
  // send goal
  canBuoy.sendGoal(goalBuoy);
  boost::thread spin_thread_buoy(&spinThreadBuoy);

  while (!successBuoy)
  {
    ros::spinOnce();
  }

  goalUpward.Goal = present_depth + 10;
  goalUpward.loop = 10;
  ROS_INFO("Action server started, sending goal to upward.");

  ClientUpward &canUpward = *ptrClientUpward;
  // send goal
  canUpward.sendGoal(goalUpward);
  boost::thread spin_thread_upward(&spinThreadUpwardPressure);

  while (!successUpward)
  {
    ros::spinOnce();
  }

  goalForward.Goal = 0;
  goalForward.loop = 10;
  ROS_INFO("Action server started, sending goal to forward.");

  ClientForward &canForward = *ptrClientForward;
  // send goal
  canForward.sendGoal(goalForward);

  std_msgs::Float64 mock_forward;
  mock_forward.data = 250;
  pub_forward.publish(mock_forward);

  sleep(3);

  canForward.cancelGoal();

  goalUpward.Goal = present_depth - 13;
  goalUpward.loop = 10;
  ROS_INFO("Sending goal to upward.");

  ClientUpward &canDownward = *ptrClientUpward;
  // send goal
  canDownward.sendGoal(goalUpward);
  boost::thread spin_thread_downward(&spinThreadDownwardPressure);

  while (!successDownward)
  {
    ros::spinOnce();
  }

  ros::spin();
  return 0;
}
<commit_msg>added line2 task<commit_after>// Copyright 2016 AUV-IITK
#include <ros/ros.h>
#include <std_msgs/Float32.h>
#include <std_msgs/Float64.h>
#include <task_commons/buoyAction.h>
#include <task_commons/lineAction.h>
#include <task_commons/buoyActionFeedback.h>
#include <task_commons/lineActionFeedback.h>
#include <task_commons/buoyActionResult.h>
#include <task_commons/lineActionResult.h>
#include <motion_commons/ForwardAction.h>
#include <motion_commons/UpwardAction.h>
#include <motion_commons/UpwardActionFeedback.h>
#include <motion_commons/ForwardActionFeedback.h>
#include <motion_commons/UpwardActionResult.h>
#include <motion_commons/ForwardActionResult.h>
#include <actionlib/client/simple_action_client.h>
#include <actionlib/client/terminal_state.h>

typedef actionlib::SimpleActionClient<task_commons::buoyAction> ClientBuoy;
typedef actionlib::SimpleActionClient<task_commons::lineAction> ClientLine;
typedef actionlib::SimpleActionClient<motion_commons::UpwardAction> ClientUpward;
typedef actionlib::SimpleActionClient<motion_commons::ForwardAction> ClientForward;

ClientBuoy *ptrClientBuoy;
ClientLine *ptrClientLine;
ClientUpward *ptrClientUpward;
ClientForward *ptrClientForward;
task_commons::buoyGoal goalBuoy;
task_commons::lineGoal goalLine;
motion_commons::UpwardGoal goalUpward;
motion_commons::ForwardGoal goalForward;

ros::Publisher pub_upward;
ros::Publisher pub_forward;

bool successBuoy = false;
bool successLine = false;
bool successUpward = false;
bool successDownward = false;

float present_depth;

void spinThreadBuoy()
{
  ClientBuoy &temp = *ptrClientBuoy;
  temp.waitForResult();
  successBuoy = (*(temp.getResult())).MotionCompleted;
  if (successBuoy)
  {
    ROS_INFO("%s: motion buoy successful", ros::this_node::getName().c_str());
  }
  else
    ROS_INFO("%s: motion buoy unsuccessful", ros::this_node::getName().c_str());
}

void spinThreadLine()
{
  ClientLine &temp = *ptrClientLine;
  temp.waitForResult();
  successLine = (*(temp.getResult())).MotionCompleted;
  if (successLine)
  {
    ROS_INFO("%s: motion line successful", ros::this_node::getName().c_str());
  }
  else
    ROS_INFO("%s: motion line unsuccessful", ros::this_node::getName().c_str());
}

void spinThreadUpwardPressure()
{
  ClientUpward &temp = *ptrClientUpward;
  temp.waitForResult();
  successUpward = (*(temp.getResult())).Result;
  if (successUpward)
  {
    ROS_INFO("%s Bot is at desired height.", ros::this_node::getName().c_str());
  }
  else
  {
    ROS_INFO("%s Bot is not at desired height, something went wrong", ros::this_node::getName().c_str());
  }
}

void spinThreadDownwardPressure()
{
  ClientUpward &temp = *ptrClientUpward;
  temp.waitForResult();
  successDownward = (*(temp.getResult())).Result;
  if (successDownward)
  {
    ROS_INFO("%s Bot is at desired height.", ros::this_node::getName().c_str());
  }
  else
  {
    ROS_INFO("%s Bot is not at desired height, something went wrong", ros::this_node::getName().c_str());
  }
}
// never ever put the argument of the callback function anything other then the specified
void buoyCB(task_commons::buoyActionFeedback msg)
{
  ROS_INFO("%s: x_coord = %f, y_coord = %f, distance = %f",
    ros::this_node::getName().c_str(), msg.feedback.x_coord, msg.feedback.y_coord, msg.feedback.distance);
}

void lineCB(task_commons::lineActionFeedback msg)
{
  ROS_INFO("%s: feedback recieved Angle Remaining = %f, x_coord = %f, y_coord = %f",
    ros::this_node::getName().c_str(), msg.feedback.AngleRemaining, msg.feedback.x_coord, msg.feedback.y_coord);
}

void pressureCB(std_msgs::Float64 pressure_sensor_data)
{
  present_depth = pressure_sensor_data.data;
  if (successBuoy)
    pub_upward.publish(pressure_sensor_data);
}

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

  ros::NodeHandle nh;
  // here buoy_server is the name of the node of the actionserver.
  ros::Subscriber sub_buoy = nh.subscribe<task_commons::buoyActionFeedback>("/buoy_server/feedback",
    1000, &buoyCB);
  ros::Subscriber sub_line = nh.subscribe<task_commons::lineActionFeedback>("/line_server/feedback",
    1000, &lineCB);
  ros::Subscriber sub_upward = nh.subscribe<std_msgs::Float64>("/varun/sensors/pressure_sensor/depth",
    1000, &pressureCB);
  pub_upward = nh.advertise<std_msgs::Float64>("/varun/motion/z_distance", 1000);
  pub_forward = nh.advertise<std_msgs::Float64>("/varun/motion/x_distance", 1000);

  ClientBuoy buoyClient("buoy_server");
  ptrClientBuoy = &buoyClient;
  ClientLine lineClient("line_server");
  ptrClientLine = &lineClient;
  ClientUpward upwardClient("upward");
  ptrClientUpward = &upwardClient;
  ClientForward forwardClient("forward");
  ptrClientForward = &forwardClient;

  ROS_INFO("Waiting for action server to start.");
  lineClient.waitForServer();
  buoyClient.waitForServer();
  upwardClient.waitForServer();
  forwardClient.waitForServer();

  goalLine.order = true;
  ROS_INFO("Action server started, sending goal to line.");

  ClientLine &canLine = *ptrClientLine;
  // send goal
  canLine.sendGoal(goalLine);
  boost::thread spin_thread_line(&spinThreadLine);

  while (!successLine)
  {
    ros::spinOnce();
  }

  goalBuoy.order = true;
  ROS_INFO("Action server started, sending goal to buoy.");

  ClientBuoy &canBuoy = *ptrClientBuoy;
  // send goal
  canBuoy.sendGoal(goalBuoy);
  boost::thread spin_thread_buoy(&spinThreadBuoy);

  while (!successBuoy)
  {
    ros::spinOnce();
  }

  goalUpward.Goal = present_depth + 10;     // add param
  goalUpward.loop = 10;
  ROS_INFO("Action server started, sending goal to upward.");

  ClientUpward &canUpward = *ptrClientUpward;
  // send goal
  canUpward.sendGoal(goalUpward);
  boost::thread spin_thread_upward(&spinThreadUpwardPressure);

  while (!successUpward)
  {
    ros::spinOnce();
  }

  goalForward.Goal = 0;
  goalForward.loop = 10;
  ROS_INFO("Action server started, sending goal to forward.");

  ClientForward &canForward = *ptrClientForward;
  // send goal
  canForward.sendGoal(goalForward);

  std_msgs::Float64 mock_forward;
  mock_forward.data = 250;
  pub_forward.publish(mock_forward);

  sleep(5);                   // add param

  canForward.cancelGoal();

  goalUpward.Goal = present_depth - 11;         // add param
  goalUpward.loop = 10;
  ROS_INFO("Sending goal to upward.");

  ClientUpward &canDownward = *ptrClientUpward;
  // send goal
  canDownward.sendGoal(goalUpward);
  boost::thread spin_thread_downward(&spinThreadDownwardPressure);

  while (!successDownward)
  {
    ros::spinOnce();
  }

  successLine = false;
  goalLine.order = true;
  ROS_INFO("Sending goal to line.");

  // send goal
  canLine.sendGoal(goalLine);
  boost::thread spin_thread_line2(&spinThreadLine);

  while (!successLine)
  {
    ros::spinOnce();
  }
  ros::spin();
  return 0;
}
<|endoftext|>


<commit_before>// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include <vespa/vespalib/testkit/testapp.h>
#include <vespa/searchcorespi/plugin/factoryloader.h>
#include <vespa/vespalib/util/exceptions.h>

using namespace searchcorespi;

namespace {
TEST("require that plugins can be loaded.") {
    FactoryLoader fl;
    IIndexManagerFactory::UP f = fl.create("searchcorespi_tplugin");
    ASSERT_TRUE(f.get());
}

TEST("require that non-existent plugin causes failure") {
    FactoryLoader fl;
    EXPECT_EXCEPTION(fl.create("no-such-plugin"),
                     vespalib::IllegalArgumentException,
                     "cannot open shared object file");
}

TEST("require that missing factory function causes failure") {
    FactoryLoader fl;
    EXPECT_EXCEPTION(fl.create("searchcorespi_illegal-plugin"),
                     vespalib::IllegalArgumentException,
                     "Failed locating symbol 'createIndexManagerFactory'");
}
}  // namespace

TEST_MAIN() { TEST_RUN_ALL(); }
<commit_msg>Failure to load shared library gives a different error message on darwin.<commit_after>// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include <vespa/vespalib/testkit/testapp.h>
#include <vespa/searchcorespi/plugin/factoryloader.h>
#include <vespa/vespalib/util/exceptions.h>

using namespace searchcorespi;

namespace {
TEST("require that plugins can be loaded.") {
    FactoryLoader fl;
    IIndexManagerFactory::UP f = fl.create("searchcorespi_tplugin");
    ASSERT_TRUE(f.get());
}

TEST("require that non-existent plugin causes failure") {
    FactoryLoader fl;
#ifdef __APPLE__
    EXPECT_EXCEPTION(fl.create("no-such-plugin"),
                     vespalib::IllegalArgumentException,
                     "image not found");
#else
    EXPECT_EXCEPTION(fl.create("no-such-plugin"),
                     vespalib::IllegalArgumentException,
                     "cannot open shared object file");
#endif
}

TEST("require that missing factory function causes failure") {
    FactoryLoader fl;
    EXPECT_EXCEPTION(fl.create("searchcorespi_illegal-plugin"),
                     vespalib::IllegalArgumentException,
                     "Failed locating symbol 'createIndexManagerFactory'");
}
}  // namespace

TEST_MAIN() { TEST_RUN_ALL(); }
<|endoftext|>


<commit_before>/*
 * Copyright 2014 Cloudius Systems
 */

#ifndef UTILS_DATA_INPUT_HH_
#define UTILS_DATA_INPUT_HH_

#include "bytes.hh"
#include "net/byteorder.hh"

class data_input {
public:
    data_input(const bytes_view& v)
            : _view(v) {
    }
    data_input(bytes_view&& v)
            : _view(std::move(v)) {
    }
    data_input(const bytes& b)
            : data_input(bytes_view(b)) {
    }
    data_input(const bytes& b, size_t off, size_t n = bytes::npos)
            : data_input(
                    bytes_view(b.c_str() + off, std::min(b.size() - off, n))) {
        if (off > b.size()) {
            throw std::out_of_range("Offset out of range");
        }
    }
    data_input(data_input&&) = default;
    data_input(const data_input&) = default;

    size_t avail() const {
        return _view.size();
    }
    bool has_next() const {
        return !_view.empty();
    }
    void ensure(size_t s) const {
        if (avail() < s) {
            throw std::out_of_range("Buffer underflow");
        }
    }
    template<typename T> T peek() const;
    template<typename T> T read();

    bytes_view read_view(size_t len) {
        bytes_view v(_view.begin(), len);
        _view.remove_prefix(len);
        return v;
    }

    template <typename SizeType>
    bytes_view read_view_to_blob() {
        auto len = read<SizeType>();
        return read_view(len);
    }
private:
    template<typename T> size_t ssize(const T &) const;
    template<typename T>
    inline std::enable_if_t<std::is_fundamental<T>::value, T> peek_primitive() const {
        ensure(sizeof(T));
        T t;
        std::copy_n(_view.begin(), sizeof(T), reinterpret_cast<char *>(&t));
        return net::ntoh(t);
    }

    bytes_view _view;
};

template<> inline sstring data_input::peek<sstring>() const {
    auto len = peek<uint16_t>();
    ensure(sizeof(uint16_t) + len);
    return sstring(reinterpret_cast<const char*>(_view.data()) + sizeof(uint16_t), len);
}
template<> inline size_t data_input::ssize<sstring>(const sstring & s) const {
    return sizeof(uint16_t) + s.size();
}
template<> inline bytes data_input::peek<bytes>() const {
    auto len = peek<uint32_t>();
    ensure(sizeof(uint32_t) + len);
    return bytes(_view.data() + sizeof(uint32_t), len);
}
template<> inline size_t data_input::ssize<bytes>(const bytes & s) const {
    return sizeof(uint32_t) + s.size();
}
template<> inline size_t data_input::ssize(const bool &) const {
    return sizeof(uint8_t);
}
template<> inline bool data_input::peek<bool>() const {
    return peek<uint8_t>() != 0;
}
template<typename T>
inline T data_input::peek() const {
    return peek_primitive<T>();
}
template<typename T> inline T data_input::read() {
    auto t = peek<T>();
    _view.remove_prefix(ssize(t));
    return std::move(t);
}
template<typename T> inline size_t data_input::ssize(const T &) const {
    return sizeof(T);
}

#endif /* UTILS_DATA_INPUT_HH_ */

<commit_msg>db: add data_input constructors & methods<commit_after>/*
 * Copyright 2014 Cloudius Systems
 */

#ifndef UTILS_DATA_INPUT_HH_
#define UTILS_DATA_INPUT_HH_

#include "bytes.hh"
#include "net/byteorder.hh"

class data_input {
public:
    data_input(const bytes_view& v)
            : _view(v) {
    }
    data_input(bytes_view&& v)
            : _view(std::move(v)) {
    }
    data_input(const bytes& b)
            : data_input(bytes_view(b)) {
    }
    data_input(const bytes& b, size_t off, size_t n = bytes::npos)
            : data_input(
                    bytes_view(b.c_str() + off, std::min(b.size() - off, n))) {
        if (off > b.size()) {
            throw std::out_of_range("Offset out of range");
        }
    }
    template<typename T>
    data_input(const std::experimental::basic_string_view<T>& view)
            : data_input(
                    bytes_view(reinterpret_cast<const int8_t *>(view.data()),
                            view.size() * sizeof(T))) {
    }
    template<typename T>
    data_input(const temporary_buffer<T>& buf)
            : data_input(
                    std::experimental::basic_string_view<T>(buf.get(), buf.size())) {
    }
    data_input(data_input&&) = default;
    data_input(const data_input&) = default;

    size_t avail() const {
        return _view.size();
    }
    bool has_next() const {
        return !_view.empty();
    }
    void ensure(size_t s) const {
        if (avail() < s) {
            throw std::out_of_range("Buffer underflow");
        }
    }
    template<typename T> T peek() const;
    template<typename T> T read();

    bytes_view read_view(size_t len) {
        bytes_view v(_view.begin(), len);
        _view.remove_prefix(len);
        return v;
    }

    template <typename SizeType>
    bytes_view read_view_to_blob() {
        auto len = read<SizeType>();
        return read_view(len);
    }

    void skip(size_t s) {
        ensure(s);
        _view.remove_prefix(s);
    }
private:
    template<typename T> size_t ssize(const T &) const;
    template<typename T>
    inline std::enable_if_t<std::is_fundamental<T>::value, T> peek_primitive() const {
        ensure(sizeof(T));
        T t;
        std::copy_n(_view.begin(), sizeof(T), reinterpret_cast<char *>(&t));
        return net::ntoh(t);
    }

    bytes_view _view;
};

template<> inline sstring data_input::peek<sstring>() const {
    auto len = peek<uint16_t>();
    ensure(sizeof(uint16_t) + len);
    return sstring(reinterpret_cast<const char*>(_view.data()) + sizeof(uint16_t), len);
}
template<> inline size_t data_input::ssize<sstring>(const sstring & s) const {
    return sizeof(uint16_t) + s.size();
}
template<> inline bytes data_input::peek<bytes>() const {
    auto len = peek<uint32_t>();
    ensure(sizeof(uint32_t) + len);
    return bytes(_view.data() + sizeof(uint32_t), len);
}
template<> inline size_t data_input::ssize<bytes>(const bytes & s) const {
    return sizeof(uint32_t) + s.size();
}
template<> inline size_t data_input::ssize(const bool &) const {
    return sizeof(uint8_t);
}
template<> inline bool data_input::peek<bool>() const {
    return peek<uint8_t>() != 0;
}
template<typename T>
inline T data_input::peek() const {
    return peek_primitive<T>();
}
template<typename T> inline T data_input::read() {
    auto t = peek<T>();
    _view.remove_prefix(ssize(t));
    return std::move(t);
}
template<typename T> inline size_t data_input::ssize(const T &) const {
    return sizeof(T);
}

#endif /* UTILS_DATA_INPUT_HH_ */

<|endoftext|>


<commit_before>#include "vizrenderthread.h"
#include "viz/vizwidget.h"

VizRenderThread::VizRenderThread(VizWidget *parent) :
    QThread(parent),
    vertexBuffer(QOpenGLBuffer::VertexBuffer),
    fftBuffer()
{
    this->parent = parent;
    playbackWidget = NULL;
    vertShader = "./shaders/basic.vert";
    fragShader = "./shaders/basic.frag";
    rendering = true;
    needsResize = false;
    frameCount = 0;
}

void VizRenderThread::resize(int w, int h)
{
    this->winWidth = w;
    this->winHeight = h;
    needsResize = true;
}

void VizRenderThread::run()
{
    parent->makeCurrent();
    initialize();
    rendering = true;
    while(rendering)
    {
        if(needsResize)
            glViewport(0, 0, (GLint)winWidth, (GLint)winHeight);

        // Clear the buffer with the current clearing color
        glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
        //Update the fft buffer
        updateFFT();
        updateShaders();
        // Draw stuff
        glDrawArrays(GL_QUADS, 0, 4);

        parent->swapBuffers();
        ++frameCount;
        msleep(16);
    }
    //Unload every thing for the next time the viz starts
    fftBuffer.release();
    vertexBuffer.release();
    shaderProgram.removeAllShaders();
    shaderProgram.release();
}

void VizRenderThread::updateShaders()
{
    shaderProgram.setUniformValue("winSize", winWidth, winHeight);
    shaderProgram.setUniformValue("time", frameCount);
    fftBuffer.write(0, &fftData, FFT_SIZE);
}

void VizRenderThread::updateFFT()
{
    if(playbackWidget != NULL)
        playbackWidget->getFFT(&fftData);
}

void VizRenderThread::stop()
{
    rendering = false;
}

void VizRenderThread::initialize()
{
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glEnable(GL_DEPTH_TEST);
    frameCount = 0;

    // Prepare a complete shader program...
    if ( !prepareShaders(vertShader, fragShader) )
        return;
    // Bind the shader program so that we can associate variables from
    // our application to the shaders
    if ( !shaderProgram.bind() )
    {
        qWarning() << "Could not bind shader program to context";
        return;
    }

    // Make the background quad and bind it to the vertex buffer
    GLfloat vertices[] = {-1, -1, 0, //bottom left corner
                          -1,  1, 0, //top left corner
                           1,  1, 0, //top right corner
                           1, -1, 0}; // bottom right corner

    vertexBuffer.create();
    vertexBuffer.setUsagePattern( QOpenGLBuffer::StaticDraw );
    if ( !vertexBuffer.bind() )
    {
        qWarning() << "Could not bind vertex buffer to the context";
        return;
    }
    vertexBuffer.allocate(vertices, 3 * 4 * sizeof( float ));
    shaderProgram.setAttributeBuffer("vertex", GL_FLOAT, 0, 3);
    shaderProgram.enableAttributeArray("vertex");

    // Setup the fft buffer
    fftBuffer.create();
    fftBuffer.bind(shaderProgram.programId(), "fftBlock");
    fftBuffer.allocate(FFT_SIZE);
}

bool VizRenderThread::prepareShaders(const QString &vertShaderPath, const QString &fragShaderPath)
{
    // First we load and compile the vertex shader...
    bool result = shaderProgram.addShaderFromSourceFile(QOpenGLShader::Vertex, vertShaderPath);
    if ( !result )
        qWarning() << shaderProgram.log();

    // ...now the fragment shader...
    result = shaderProgram.addShaderFromSourceFile(QOpenGLShader::Fragment, fragShaderPath);
    if ( !result )
        qWarning() << shaderProgram.log();

    // ...and finally we link them to resolve any references.
    result = shaderProgram.link();
    if ( !result )
        qWarning() << "Could not link shader program:" << shaderProgram.log();

    return result;
}
<commit_msg>Fixed stupid opengl warnings<commit_after>#include "vizrenderthread.h"
#include "viz/vizwidget.h"

VizRenderThread::VizRenderThread(VizWidget *parent) :
    QThread(parent),
    shaderProgram(this),
    vertexBuffer(QOpenGLBuffer::VertexBuffer),
    fftBuffer()
{
    this->parent = parent;
    playbackWidget = NULL;
    vertShader = "./shaders/basic.vert";
    fragShader = "./shaders/basic.frag";
    needsResize = false;
    frameCount = 0;
}

void VizRenderThread::resize(int w, int h)
{
    this->winWidth = w;
    this->winHeight = h;
    needsResize = true;
}

void VizRenderThread::run()
{
    initialize();
    rendering = true;
    while(rendering)
    {
        parent->makeCurrent();
        if(needsResize)
            glViewport(0, 0, (GLint)winWidth, (GLint)winHeight);

        // Clear the buffer with the current clearing color
        glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
        //Update the fft buffer
        updateFFT();
        updateShaders();
        // Draw stuff
        glDrawArrays(GL_QUADS, 0, 4);

        parent->swapBuffers();
        ++frameCount;
        msleep(16);
    }
    //Unload every thing for the next time the viz starts
    fftBuffer.release();
    vertexBuffer.release();
    shaderProgram.removeAllShaders();
    shaderProgram.release();
}

void VizRenderThread::updateShaders()
{
    shaderProgram.setUniformValue("winSize", winWidth, winHeight);
    shaderProgram.setUniformValue("time", frameCount);
    fftBuffer.write(0, &fftData, FFT_SIZE);
}

void VizRenderThread::updateFFT()
{
    if(playbackWidget != NULL)
        playbackWidget->getFFT(&fftData);
}

void VizRenderThread::stop()
{
    rendering = false;
}

void VizRenderThread::initialize()
{
    parent->makeCurrent();
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glEnable(GL_DEPTH_TEST);
    frameCount = 0;

    // Prepare a complete shader program...
    if ( !prepareShaders(vertShader, fragShader) )
        return;
    // Bind the shader program so that we can associate variables from
    // our application to the shaders
    if ( !shaderProgram.bind() )
    {
        qWarning() << "Could not bind shader program to context";
        return;
    }

    // Make the background quad and bind it to the vertex buffer
    GLfloat vertices[] = {-1, -1, 0, //bottom left corner
                          -1,  1, 0, //top left corner
                           1,  1, 0, //top right corner
                           1, -1, 0}; // bottom right corner

    vertexBuffer.create();
    vertexBuffer.setUsagePattern( QOpenGLBuffer::StaticDraw );
    if ( !vertexBuffer.bind() )
    {
        qWarning() << "Could not bind vertex buffer to the context";
        return;
    }
    vertexBuffer.allocate(vertices, 3 * 4 * sizeof( float ));
    shaderProgram.setAttributeBuffer("vertex", GL_FLOAT, 0, 3);
    shaderProgram.enableAttributeArray("vertex");

    // Setup the fft buffer
    fftBuffer.create();
    fftBuffer.bind(shaderProgram.programId(), "fftBlock");
    fftBuffer.allocate(FFT_SIZE);
}

bool VizRenderThread::prepareShaders(const QString &vertShaderPath, const QString &fragShaderPath)
{
    // First we load and compile the vertex shader...
    bool result = shaderProgram.addShaderFromSourceFile(QOpenGLShader::Vertex, vertShaderPath);
    if ( !result )
        qWarning() << shaderProgram.log();

    // ...now the fragment shader...
    result = shaderProgram.addShaderFromSourceFile(QOpenGLShader::Fragment, fragShaderPath);
    if ( !result )
        qWarning() << shaderProgram.log();

    // ...and finally we link them to resolve any references.
    result = shaderProgram.link();
    if ( !result )
        qWarning() << "Could not link shader program:" << shaderProgram.log();

    return result;
}
<|endoftext|>