<commit_before>/**
 * @file consensushash.cpp
 *
 * This file contains the function to generate consensus hashes.
 */

#include "omnicore/consensushash.h"
#include "omnicore/dex.h"
#include "omnicore/mdex.h"
#include "omnicore/log.h"
#include "omnicore/omnicore.h"
#include "omnicore/sp.h"

#include <stdint.h>
#include <string>

#include <openssl/sha.h>

namespace mastercore
{
// Generates a consensus string for hashing based on a tally object
std::string GenerateConsensusString(const CMPTally& tallyObj, const std::string& address, const uint32_t propertyId)
{
    int64_t balance = tallyObj.getMoney(propertyId, BALANCE);
    int64_t sellOfferReserve = tallyObj.getMoney(propertyId, SELLOFFER_RESERVE);
    int64_t acceptReserve = tallyObj.getMoney(propertyId, ACCEPT_RESERVE);
    int64_t metaDExReserve = tallyObj.getMoney(propertyId, METADEX_RESERVE);

    // return a blank string if all balances are empty
    if (!balance && !sellOfferReserve && !acceptReserve && !metaDExReserve) return "";

    return strprintf("%s|%d|%d|%d|%d|%d",
            address, propertyId, balance, sellOfferReserve, acceptReserve, metaDExReserve);
}

// Generates a consensus string for hashing based on a DEx sell offer object
std::string GenerateConsensusString(const CMPOffer& offerObj, const std::string& address, const uint32_t propertyId)
{
    return strprintf("%s|%s|%d|%d|%d|%d|%d",
            offerObj.getHash().GetHex(), address, propertyId, offerObj.getOfferAmountOriginal(),
            offerObj.getBTCDesiredOriginal(), offerObj.getMinFee(), offerObj.getBlockTimeLimit());
}

// Generates a consensus string for hashing based on a DEx accept object
std::string GenerateConsensusString(const CMPAccept& acceptObj, const std::string& address)
{
    return strprintf("%s|%s|%d|%d|%d",
            acceptObj.getHash().GetHex(), address, acceptObj.getAcceptAmount(), acceptObj.getAcceptAmountRemaining(),
            acceptObj.getAcceptBlock());
}

// Generates a consensus string for hashing based on a MetaDEx object
std::string GenerateConsensusString(const CMPMetaDEx& tradeObj)
{
    return strprintf("%s|%s|%d|%d|%d|%d|%d",
            tradeObj.getHash().GetHex(), tradeObj.getAddr(), tradeObj.getProperty(), tradeObj.getAmountForSale(),
            tradeObj.getDesProperty(), tradeObj.getAmountDesired(), tradeObj.getAmountRemaining());
}

// Generates a consensus string for hashing based on a crowdsale object
std::string GenerateConsensusString(const CMPCrowd& crowdObj)
{
    return strprintf("%d|%d|%d|%d|%d",
            crowdObj.getPropertyId(), crowdObj.getCurrDes(), crowdObj.getDeadline(), crowdObj.getUserCreated(),
            crowdObj.getIssuerCreated());
}

// Generates a consensus string for hashing based on a property issuer
std::string GenerateConsensusString(const uint32_t propertyId, const std::string& address)
{
    return strprintf("%d|%s", propertyId, address);
}

/**
 * Obtains a hash of the active state to use for consensus verification and checkpointing.
 *
 * For increased flexibility, so other implementations like OmniWallet and OmniChest can
 * also apply this methodology without necessarily using the same exact data types (which
 * would be needed to hash the data bytes directly), create a string in the following
 * format for each entry to use for hashing:
 *
 * ---STAGE 1 - BALANCES---
 * Format specifiers & placeholders:
 *   "%s|%d|%d|%d|%d|%d" - "address|propertyid|balance|selloffer_reserve|accept_reserve|metadex_reserve"
 *
 * Note: empty balance records and the pending tally are ignored. Addresses are sorted based
 * on lexicographical order, and balance records are sorted by the property identifiers.
 *
 * ---STAGE 2 - DEX SELL OFFERS---
 * Format specifiers & placeholders:
 *   "%s|%s|%d|%d|%d|%d|%d" - "txid|address|propertyid|offeramount|btcdesired|minfee|timelimit"
 *
 * Note: ordered ascending by txid.
 *
 * ---STAGE 3 - DEX ACCEPTS---
 * Format specifiers & placeholders:
 *   "%s|%s|%d|%d|%d" - "matchedselloffertxid|buyer|acceptamount|acceptamountremaining|acceptblock"
 *
 * Note: ordered ascending by matchedselloffertxid followed by buyer.
 *
 * ---STAGE 4 - METADEX TRADES---
 * Format specifiers & placeholders:
 *   "%s|%s|%d|%d|%d|%d|%d" - "txid|address|propertyidforsale|amountforsale|propertyiddesired|amountdesired|amountremaining"
 *
 * Note: ordered ascending by txid.
 *
 * ---STAGE 5 - CROWDSALES---
 * Format specifiers & placeholders:
 *   "%d|%d|%d|%d|%d" - "propertyid|propertyiddesired|deadline|usertokens|issuertokens"
 *
 * Note: ordered by property ID.
 *
 * ---STAGE 6 - PROPERTIES---
 * Format specifiers & placeholders:
 *   "%d|%s" - "propertyid|issueraddress"
 *
 * Note: ordered by property ID.
 *
 * The byte order is important, and we assume:
 *   SHA256("abc") = "ad1500f261ff10b49c7a1796a36103b02322ae5dde404141eacf018fbf1678ba"
 *
 */
uint256 GetConsensusHash()
{
    // allocate and init a SHA256_CTX
    SHA256_CTX shaCtx;
    SHA256_Init(&shaCtx);

    LOCK(cs_tally);

    if (msc_debug_consensus_hash) PrintToLog("Beginning generation of current consensus hash...\n");

    // Balances - loop through the tally map, updating the sha context with the data from each balance and tally type
    // Placeholders:  "address|propertyid|balance|selloffer_reserve|accept_reserve|metadex_reserve"
    for (std::map<string, CMPTally>::iterator my_it = mp_tally_map.begin(); my_it != mp_tally_map.end(); ++my_it) {
        const std::string& address = my_it->first;
        CMPTally& tally = my_it->second;
        tally.init();
        uint32_t propertyId = 0;
        while (0 != (propertyId = (tally.next()))) {
            std::string dataStr = GenerateConsensusString(tally, address, propertyId);
            if (dataStr.empty()) continue; // skip empty balances
            if (msc_debug_consensus_hash) PrintToLog("Adding balance data to consensus hash: %s\n", dataStr);
            SHA256_Update(&shaCtx, dataStr.c_str(), dataStr.length());
        }
    }

    // DEx sell offers - loop through the DEx and add each sell offer to the consensus hash (ordered by txid)
    // Placeholders: "txid|address|propertyid|offeramount|btcdesired|minfee|timelimit"
    std::vector<std::pair<uint256, std::string> > vecDExOffers;
    for (OfferMap::iterator it = my_offers.begin(); it != my_offers.end(); ++it) {
        const CMPOffer& selloffer = it->second;
        const std::string& sellCombo = it->first;
        uint32_t propertyId = selloffer.getProperty();
        std::string seller = sellCombo.substr(0, sellCombo.size() - 2);
        std::string dataStr = GenerateConsensusString(selloffer, seller, propertyId);
        vecDExOffers.push_back(std::make_pair(selloffer.getHash(), dataStr));
    }
    std::sort (vecDExOffers.begin(), vecDExOffers.end());
    for (std::vector<std::pair<uint256, std::string> >::iterator it = vecDExOffers.begin(); it != vecDExOffers.end(); ++it) {
        std::string dataStr = (*it).second;
        if (msc_debug_consensus_hash) PrintToLog("Adding DEx offer data to consensus hash: %s\n", dataStr);
        SHA256_Update(&shaCtx, dataStr.c_str(), dataStr.length());
    }

    // DEx accepts - loop through the accepts map and add each accept to the consensus hash (ordered by matchedtxid then buyer)
    // Placeholders: "matchedselloffertxid|buyer|acceptamount|acceptamountremaining|acceptblock"
    std::vector<std::pair<std::string, std::string> > vecAccepts;
    for (AcceptMap::const_iterator it = my_accepts.begin(); it != my_accepts.end(); ++it) {
        const CMPAccept& accept = it->second;
        const std::string& acceptCombo = it->first;
        std::string buyer = acceptCombo.substr((acceptCombo.find("+") + 1), (acceptCombo.size()-(acceptCombo.find("+") + 1)));
        std::string dataStr = GenerateConsensusString(accept, buyer);
        std::string sortKey = strprintf("%s-%s", accept.getHash().GetHex(), buyer);
        vecAccepts.push_back(std::make_pair(sortKey, dataStr));
    }
    std::sort (vecAccepts.begin(), vecAccepts.end());
    for (std::vector<std::pair<std::string, std::string> >::iterator it = vecAccepts.begin(); it != vecAccepts.end(); ++it) {
        std::string dataStr = (*it).second;
        if (msc_debug_consensus_hash) PrintToLog("Adding DEx accept to consensus hash: %s\n", dataStr);
        SHA256_Update(&shaCtx, dataStr.c_str(), dataStr.length());
    }

    // MetaDEx trades - loop through the MetaDEx maps and add each open trade to the consensus hash (ordered by txid)
    // Placeholders: "txid|address|propertyidforsale|amountforsale|propertyiddesired|amountdesired|amountremaining"
    std::vector<std::pair<uint256, std::string> > vecMetaDExTrades;
    for (md_PropertiesMap::const_iterator my_it = metadex.begin(); my_it != metadex.end(); ++my_it) {
        const md_PricesMap& prices = my_it->second;
        for (md_PricesMap::const_iterator it = prices.begin(); it != prices.end(); ++it) {
            const md_Set& indexes = it->second;
            for (md_Set::const_iterator it = indexes.begin(); it != indexes.end(); ++it) {
                const CMPMetaDEx& obj = *it;
                std::string dataStr = GenerateConsensusString(obj);
                vecMetaDExTrades.push_back(std::make_pair(obj.getHash(), dataStr));
            }
        }
    }
    std::sort (vecMetaDExTrades.begin(), vecMetaDExTrades.end());
    for (std::vector<std::pair<uint256, std::string> >::iterator it = vecMetaDExTrades.begin(); it != vecMetaDExTrades.end(); ++it) {
        std::string dataStr = (*it).second;
        if (msc_debug_consensus_hash) PrintToLog("Adding MetaDEx trade data to consensus hash: %s\n", dataStr);
        SHA256_Update(&shaCtx, dataStr.c_str(), dataStr.length());
    }

    // Crowdsales - loop through open crowdsales and add to the consensus hash (ordered by property ID)
    // Note: the variables of the crowdsale (amount, bonus etc) are not part of the crowdsale map and not included here to
    // avoid additionalal loading of SP entries from the database
    // Placeholders: "propertyid|propertyiddesired|deadline|usertokens|issuertokens"
    std::vector<std::pair<uint32_t, std::string> > vecCrowds;
    for (CrowdMap::const_iterator it = my_crowds.begin(); it != my_crowds.end(); ++it) {
        const CMPCrowd& crowd = it->second;
        uint32_t propertyId = crowd.getPropertyId();
        std::string dataStr = GenerateConsensusString(crowd);
        vecCrowds.push_back(std::make_pair(propertyId, dataStr));
    }
    std::sort (vecCrowds.begin(), vecCrowds.end());
    for (std::vector<std::pair<uint32_t, std::string> >::iterator it = vecCrowds.begin(); it != vecCrowds.end(); ++it) {
        std::string dataStr = (*it).second;
        if (msc_debug_consensus_hash) PrintToLog("Adding Crowdsale entry to consensus hash: %s\n", dataStr);
        SHA256_Update(&shaCtx, dataStr.c_str(), dataStr.length());
    }

    // Properties - loop through each property and store the issuer (to capture state changes via change issuer transactions)
    // Note: we are loading every SP from the DB to check the issuer, if using consensus_hash_every_block debug option this
    //       will slow things down dramatically.  Not an issue to do it once every 10,000 blocks for checkpoint verification.
    // Placeholders: "propertyid|issueraddress"
    for (uint8_t ecosystem = 1; ecosystem <= 2; ecosystem++) {
        uint32_t startPropertyId = (ecosystem == 1) ? 1 : TEST_ECO_PROPERTY_1;
        for (uint32_t propertyId = startPropertyId; propertyId < _my_sps->peekNextSPID(ecosystem); propertyId++) {
            CMPSPInfo::Entry sp;
            {
                LOCK(cs_tally);
                if (!_my_sps->getSP(propertyId, sp)) {
                    PrintToLog("Error loading property ID %d for consensus hashing, hash should not be trusted!\n");
                    continue;
                }
            }
            std::string dataStr = GenerateConsensusString(propertyId, sp.issuer);
            if (msc_debug_consensus_hash) PrintToLog("Adding property to consensus hash: %s\n", dataStr);
            SHA256_Update(&shaCtx, dataStr.c_str(), dataStr.length());
        }
    }

    // extract the final result and return the hash
    uint256 consensusHash;
    SHA256_Final((unsigned char*)&consensusHash, &shaCtx);
    if (msc_debug_consensus_hash) PrintToLog("Finished generation of consensus hash.  Result: %s\n", consensusHash.GetHex());

    return consensusHash;
}

} // namespace mastercore
<commit_msg>Remove second tally lock (thanks @dexX7)<commit_after>/**
 * @file consensushash.cpp
 *
 * This file contains the function to generate consensus hashes.
 */

#include "omnicore/consensushash.h"
#include "omnicore/dex.h"
#include "omnicore/mdex.h"
#include "omnicore/log.h"
#include "omnicore/omnicore.h"
#include "omnicore/sp.h"

#include <stdint.h>
#include <string>

#include <openssl/sha.h>

namespace mastercore
{
// Generates a consensus string for hashing based on a tally object
std::string GenerateConsensusString(const CMPTally& tallyObj, const std::string& address, const uint32_t propertyId)
{
    int64_t balance = tallyObj.getMoney(propertyId, BALANCE);
    int64_t sellOfferReserve = tallyObj.getMoney(propertyId, SELLOFFER_RESERVE);
    int64_t acceptReserve = tallyObj.getMoney(propertyId, ACCEPT_RESERVE);
    int64_t metaDExReserve = tallyObj.getMoney(propertyId, METADEX_RESERVE);

    // return a blank string if all balances are empty
    if (!balance && !sellOfferReserve && !acceptReserve && !metaDExReserve) return "";

    return strprintf("%s|%d|%d|%d|%d|%d",
            address, propertyId, balance, sellOfferReserve, acceptReserve, metaDExReserve);
}

// Generates a consensus string for hashing based on a DEx sell offer object
std::string GenerateConsensusString(const CMPOffer& offerObj, const std::string& address, const uint32_t propertyId)
{
    return strprintf("%s|%s|%d|%d|%d|%d|%d",
            offerObj.getHash().GetHex(), address, propertyId, offerObj.getOfferAmountOriginal(),
            offerObj.getBTCDesiredOriginal(), offerObj.getMinFee(), offerObj.getBlockTimeLimit());
}

// Generates a consensus string for hashing based on a DEx accept object
std::string GenerateConsensusString(const CMPAccept& acceptObj, const std::string& address)
{
    return strprintf("%s|%s|%d|%d|%d",
            acceptObj.getHash().GetHex(), address, acceptObj.getAcceptAmount(), acceptObj.getAcceptAmountRemaining(),
            acceptObj.getAcceptBlock());
}

// Generates a consensus string for hashing based on a MetaDEx object
std::string GenerateConsensusString(const CMPMetaDEx& tradeObj)
{
    return strprintf("%s|%s|%d|%d|%d|%d|%d",
            tradeObj.getHash().GetHex(), tradeObj.getAddr(), tradeObj.getProperty(), tradeObj.getAmountForSale(),
            tradeObj.getDesProperty(), tradeObj.getAmountDesired(), tradeObj.getAmountRemaining());
}

// Generates a consensus string for hashing based on a crowdsale object
std::string GenerateConsensusString(const CMPCrowd& crowdObj)
{
    return strprintf("%d|%d|%d|%d|%d",
            crowdObj.getPropertyId(), crowdObj.getCurrDes(), crowdObj.getDeadline(), crowdObj.getUserCreated(),
            crowdObj.getIssuerCreated());
}

// Generates a consensus string for hashing based on a property issuer
std::string GenerateConsensusString(const uint32_t propertyId, const std::string& address)
{
    return strprintf("%d|%s", propertyId, address);
}

/**
 * Obtains a hash of the active state to use for consensus verification and checkpointing.
 *
 * For increased flexibility, so other implementations like OmniWallet and OmniChest can
 * also apply this methodology without necessarily using the same exact data types (which
 * would be needed to hash the data bytes directly), create a string in the following
 * format for each entry to use for hashing:
 *
 * ---STAGE 1 - BALANCES---
 * Format specifiers & placeholders:
 *   "%s|%d|%d|%d|%d|%d" - "address|propertyid|balance|selloffer_reserve|accept_reserve|metadex_reserve"
 *
 * Note: empty balance records and the pending tally are ignored. Addresses are sorted based
 * on lexicographical order, and balance records are sorted by the property identifiers.
 *
 * ---STAGE 2 - DEX SELL OFFERS---
 * Format specifiers & placeholders:
 *   "%s|%s|%d|%d|%d|%d|%d" - "txid|address|propertyid|offeramount|btcdesired|minfee|timelimit"
 *
 * Note: ordered ascending by txid.
 *
 * ---STAGE 3 - DEX ACCEPTS---
 * Format specifiers & placeholders:
 *   "%s|%s|%d|%d|%d" - "matchedselloffertxid|buyer|acceptamount|acceptamountremaining|acceptblock"
 *
 * Note: ordered ascending by matchedselloffertxid followed by buyer.
 *
 * ---STAGE 4 - METADEX TRADES---
 * Format specifiers & placeholders:
 *   "%s|%s|%d|%d|%d|%d|%d" - "txid|address|propertyidforsale|amountforsale|propertyiddesired|amountdesired|amountremaining"
 *
 * Note: ordered ascending by txid.
 *
 * ---STAGE 5 - CROWDSALES---
 * Format specifiers & placeholders:
 *   "%d|%d|%d|%d|%d" - "propertyid|propertyiddesired|deadline|usertokens|issuertokens"
 *
 * Note: ordered by property ID.
 *
 * ---STAGE 6 - PROPERTIES---
 * Format specifiers & placeholders:
 *   "%d|%s" - "propertyid|issueraddress"
 *
 * Note: ordered by property ID.
 *
 * The byte order is important, and we assume:
 *   SHA256("abc") = "ad1500f261ff10b49c7a1796a36103b02322ae5dde404141eacf018fbf1678ba"
 *
 */
uint256 GetConsensusHash()
{
    // allocate and init a SHA256_CTX
    SHA256_CTX shaCtx;
    SHA256_Init(&shaCtx);

    LOCK(cs_tally);

    if (msc_debug_consensus_hash) PrintToLog("Beginning generation of current consensus hash...\n");

    // Balances - loop through the tally map, updating the sha context with the data from each balance and tally type
    // Placeholders:  "address|propertyid|balance|selloffer_reserve|accept_reserve|metadex_reserve"
    for (std::map<string, CMPTally>::iterator my_it = mp_tally_map.begin(); my_it != mp_tally_map.end(); ++my_it) {
        const std::string& address = my_it->first;
        CMPTally& tally = my_it->second;
        tally.init();
        uint32_t propertyId = 0;
        while (0 != (propertyId = (tally.next()))) {
            std::string dataStr = GenerateConsensusString(tally, address, propertyId);
            if (dataStr.empty()) continue; // skip empty balances
            if (msc_debug_consensus_hash) PrintToLog("Adding balance data to consensus hash: %s\n", dataStr);
            SHA256_Update(&shaCtx, dataStr.c_str(), dataStr.length());
        }
    }

    // DEx sell offers - loop through the DEx and add each sell offer to the consensus hash (ordered by txid)
    // Placeholders: "txid|address|propertyid|offeramount|btcdesired|minfee|timelimit"
    std::vector<std::pair<uint256, std::string> > vecDExOffers;
    for (OfferMap::iterator it = my_offers.begin(); it != my_offers.end(); ++it) {
        const CMPOffer& selloffer = it->second;
        const std::string& sellCombo = it->first;
        uint32_t propertyId = selloffer.getProperty();
        std::string seller = sellCombo.substr(0, sellCombo.size() - 2);
        std::string dataStr = GenerateConsensusString(selloffer, seller, propertyId);
        vecDExOffers.push_back(std::make_pair(selloffer.getHash(), dataStr));
    }
    std::sort (vecDExOffers.begin(), vecDExOffers.end());
    for (std::vector<std::pair<uint256, std::string> >::iterator it = vecDExOffers.begin(); it != vecDExOffers.end(); ++it) {
        std::string dataStr = (*it).second;
        if (msc_debug_consensus_hash) PrintToLog("Adding DEx offer data to consensus hash: %s\n", dataStr);
        SHA256_Update(&shaCtx, dataStr.c_str(), dataStr.length());
    }

    // DEx accepts - loop through the accepts map and add each accept to the consensus hash (ordered by matchedtxid then buyer)
    // Placeholders: "matchedselloffertxid|buyer|acceptamount|acceptamountremaining|acceptblock"
    std::vector<std::pair<std::string, std::string> > vecAccepts;
    for (AcceptMap::const_iterator it = my_accepts.begin(); it != my_accepts.end(); ++it) {
        const CMPAccept& accept = it->second;
        const std::string& acceptCombo = it->first;
        std::string buyer = acceptCombo.substr((acceptCombo.find("+") + 1), (acceptCombo.size()-(acceptCombo.find("+") + 1)));
        std::string dataStr = GenerateConsensusString(accept, buyer);
        std::string sortKey = strprintf("%s-%s", accept.getHash().GetHex(), buyer);
        vecAccepts.push_back(std::make_pair(sortKey, dataStr));
    }
    std::sort (vecAccepts.begin(), vecAccepts.end());
    for (std::vector<std::pair<std::string, std::string> >::iterator it = vecAccepts.begin(); it != vecAccepts.end(); ++it) {
        std::string dataStr = (*it).second;
        if (msc_debug_consensus_hash) PrintToLog("Adding DEx accept to consensus hash: %s\n", dataStr);
        SHA256_Update(&shaCtx, dataStr.c_str(), dataStr.length());
    }

    // MetaDEx trades - loop through the MetaDEx maps and add each open trade to the consensus hash (ordered by txid)
    // Placeholders: "txid|address|propertyidforsale|amountforsale|propertyiddesired|amountdesired|amountremaining"
    std::vector<std::pair<uint256, std::string> > vecMetaDExTrades;
    for (md_PropertiesMap::const_iterator my_it = metadex.begin(); my_it != metadex.end(); ++my_it) {
        const md_PricesMap& prices = my_it->second;
        for (md_PricesMap::const_iterator it = prices.begin(); it != prices.end(); ++it) {
            const md_Set& indexes = it->second;
            for (md_Set::const_iterator it = indexes.begin(); it != indexes.end(); ++it) {
                const CMPMetaDEx& obj = *it;
                std::string dataStr = GenerateConsensusString(obj);
                vecMetaDExTrades.push_back(std::make_pair(obj.getHash(), dataStr));
            }
        }
    }
    std::sort (vecMetaDExTrades.begin(), vecMetaDExTrades.end());
    for (std::vector<std::pair<uint256, std::string> >::iterator it = vecMetaDExTrades.begin(); it != vecMetaDExTrades.end(); ++it) {
        std::string dataStr = (*it).second;
        if (msc_debug_consensus_hash) PrintToLog("Adding MetaDEx trade data to consensus hash: %s\n", dataStr);
        SHA256_Update(&shaCtx, dataStr.c_str(), dataStr.length());
    }

    // Crowdsales - loop through open crowdsales and add to the consensus hash (ordered by property ID)
    // Note: the variables of the crowdsale (amount, bonus etc) are not part of the crowdsale map and not included here to
    // avoid additionalal loading of SP entries from the database
    // Placeholders: "propertyid|propertyiddesired|deadline|usertokens|issuertokens"
    std::vector<std::pair<uint32_t, std::string> > vecCrowds;
    for (CrowdMap::const_iterator it = my_crowds.begin(); it != my_crowds.end(); ++it) {
        const CMPCrowd& crowd = it->second;
        uint32_t propertyId = crowd.getPropertyId();
        std::string dataStr = GenerateConsensusString(crowd);
        vecCrowds.push_back(std::make_pair(propertyId, dataStr));
    }
    std::sort (vecCrowds.begin(), vecCrowds.end());
    for (std::vector<std::pair<uint32_t, std::string> >::iterator it = vecCrowds.begin(); it != vecCrowds.end(); ++it) {
        std::string dataStr = (*it).second;
        if (msc_debug_consensus_hash) PrintToLog("Adding Crowdsale entry to consensus hash: %s\n", dataStr);
        SHA256_Update(&shaCtx, dataStr.c_str(), dataStr.length());
    }

    // Properties - loop through each property and store the issuer (to capture state changes via change issuer transactions)
    // Note: we are loading every SP from the DB to check the issuer, if using consensus_hash_every_block debug option this
    //       will slow things down dramatically.  Not an issue to do it once every 10,000 blocks for checkpoint verification.
    // Placeholders: "propertyid|issueraddress"
    for (uint8_t ecosystem = 1; ecosystem <= 2; ecosystem++) {
        uint32_t startPropertyId = (ecosystem == 1) ? 1 : TEST_ECO_PROPERTY_1;
        for (uint32_t propertyId = startPropertyId; propertyId < _my_sps->peekNextSPID(ecosystem); propertyId++) {
            CMPSPInfo::Entry sp;
            if (!_my_sps->getSP(propertyId, sp)) {
                PrintToLog("Error loading property ID %d for consensus hashing, hash should not be trusted!\n");
                continue;
            }
            std::string dataStr = GenerateConsensusString(propertyId, sp.issuer);
            if (msc_debug_consensus_hash) PrintToLog("Adding property to consensus hash: %s\n", dataStr);
            SHA256_Update(&shaCtx, dataStr.c_str(), dataStr.length());
        }
    }

    // extract the final result and return the hash
    uint256 consensusHash;
    SHA256_Final((unsigned char*)&consensusHash, &shaCtx);
    if (msc_debug_consensus_hash) PrintToLog("Finished generation of consensus hash.  Result: %s\n", consensusHash.GetHex());

    return consensusHash;
}

} // namespace mastercore
<|endoftext|>


<commit_before>// Copyright (c) 2015 Pierre Moulon.

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#ifndef OPENMVG_SFM_REPORT_HPP
#define OPENMVG_SFM_REPORT_HPP

#include "third_party/stlplus3/filesystemSimplified/file_system.hpp"
#include "third_party/htmlDoc/htmlDoc.hpp"
#include "third_party/histogram/histogram.hpp"
#include "third_party/vectorGraphics/svgDrawer.hpp"

namespace openMVG {
namespace sfm {

static bool Generate_SfM_Report
(
  const SfM_Data & sfm_data,
  const std::string & htmlFilename
)
{
  // Compute mean,max,median residual values per View
  IndexT residualCount = 0;
  Hash_Map< IndexT, std::vector<double> > residuals_per_view;
  for (Landmarks::const_iterator iterTracks = sfm_data.GetLandmarks().begin();
    iterTracks != sfm_data.GetLandmarks().end();
    ++iterTracks
  )
  {
    const Observations & obs = iterTracks->second.obs;
    for (Observations::const_iterator itObs = obs.begin();
      itObs != obs.end(); ++itObs)
    {
      const View * view = sfm_data.GetViews().at(itObs->first).get();
      const geometry::Pose3 pose = sfm_data.GetPoseOrDie(view);
      const cameras::IntrinsicBase * intrinsic = sfm_data.GetIntrinsics().at(view->id_intrinsic).get();
      // Use absolute values
      const Vec2 residual = intrinsic->residual(pose, iterTracks->second.X, itObs->second.x).array().abs();
      residuals_per_view[itObs->first].push_back(residual(0));
      residuals_per_view[itObs->first].push_back(residual(1));
      ++residualCount;
    }
  }
  using namespace htmlDocument;
  // extract directory from htmlFilename
  const std::string sTableBegin = "
",
    sTableEnd = "
",
    sRowBegin= "
", sRowEnd = "
",
    sColBegin = "", sColEnd = "	",
    sNewLine = "
", sFullLine = "
";

  htmlDocument::htmlDocumentStream htmlDocStream("SFM report.");
  htmlDocStream.pushInfo(
  htmlDocument::htmlMarkup("h1", std::string("SFM report.")));
  htmlDocStream.pushInfo(sFullLine);

  htmlDocStream.pushInfo( "Dataset info:" + sNewLine );

  std::ostringstream os;
  os << " #views: " << sfm_data.GetViews().size() << sNewLine
  << " #poses: " << sfm_data.GetPoses().size() << sNewLine
  << " #intrinsics: " << sfm_data.GetIntrinsics().size() << sNewLine
  << " #tracks: " << sfm_data.GetLandmarks().size() << sNewLine
  << " #residuals: " << residualCount << sNewLine;

  htmlDocStream.pushInfo( os.str() );
  htmlDocStream.pushInfo( sFullLine );

  htmlDocStream.pushInfo( sTableBegin);
  os.str("");
  os << sRowBegin
    << sColBegin + "IdView" + sColEnd
    << sColBegin + "Basename" + sColEnd
    << sColBegin + "#Observations" + sColEnd
    << sColBegin + "Residuals min" + sColEnd
    << sColBegin + "Residuals median" + sColEnd
    << sColBegin + "Residuals mean" + sColEnd
    << sColBegin + "Residuals max" + sColEnd
    << sRowEnd;
  htmlDocStream.pushInfo( os.str() );

  for (Views::const_iterator iterV = sfm_data.GetViews().begin();
    iterV != sfm_data.GetViews().end();
    ++iterV)
  {
    const View * v = iterV->second.get();
    const IndexT id_view = v->id_view;

    os.str("");
    os << sRowBegin
      << sColBegin << id_view << sColEnd
      << sColBegin + stlplus::basename_part(v->s_Img_path) + sColEnd;

    // IdView | basename | #Observations | residuals min | residual median | residual max
    if (sfm_data.IsPoseAndIntrinsicDefined(v))
    {
      const std::vector<double> & residuals = residuals_per_view.at(id_view);
      if (!residuals.empty())
      {
        double min, max, mean, median;
        minMaxMeanMedian(residuals.begin(), residuals.end(), min, max, mean, median);
        os << sColBegin << residuals.size()/2 << sColEnd // #observations
          << sColBegin << min << sColEnd
          << sColBegin << median << sColEnd
          << sColBegin << mean << sColEnd
          << sColBegin << max <<sColEnd;
      }
    }
    os << sRowEnd;
    htmlDocStream.pushInfo( os.str() );
  }
  htmlDocStream.pushInfo( sTableEnd );
  htmlDocStream.pushInfo( sFullLine );

  // combine all residual values into one vector
  // export the SVG histogram
  {
    IndexT residualCount = 0;
    for (Hash_Map< IndexT, std::vector<double> >::const_iterator
      it = residuals_per_view.begin();
      it != residuals_per_view.end();
      ++it)
    {
      residualCount += it->second.size();
    }
    // Concat per view residual values into one vector
    std::vector<double> residuals(residualCount);
    residualCount = 0;
    for (Hash_Map< IndexT, std::vector<double> >::const_iterator
      it = residuals_per_view.begin();
      it != residuals_per_view.end();
      ++it)
    {
      std::copy(it->second.begin(),
        it->second.begin()+it->second.size(),
        residuals.begin()+residualCount);
      residualCount += it->second.size();
    }
    if (!residuals.empty())
    {
      // RMSE computation
      const Eigen::Map<Eigen::RowVectorXd> residuals_mapping(&residuals[0], residuals.size());
      const double RMSE = std::sqrt(residuals_mapping.squaredNorm() / (double)residuals.size());
      os.str("");
      os << sFullLine << "SfM Scene RMSE: " << RMSE << sFullLine;
      htmlDocStream.pushInfo(os.str());

      const double maxRange = *max_element(residuals.begin(), residuals.end());
      Histogram<double> histo(0.0, maxRange, 100);
      histo.Add(residuals.begin(), residuals.end());

      svg::svgHisto svg_Histo;
      svg_Histo.draw(histo.GetHist(), std::pair<float,float>(0.f, maxRange),
        stlplus::create_filespec(stlplus::folder_part(htmlFilename), "residuals_histogram", "svg"),
        600, 200);

      os.str("");
      os << sNewLine<< "Residuals histogram" << sNewLine;
      os << "<img src=\""
        << "residuals_histogram.svg"
        << "\" height=\"300\" width =\"800\">\n";
      htmlDocStream.pushInfo(os.str());
    }
  }

  std::ofstream htmlFileStream(htmlFilename.c_str());
  htmlFileStream << htmlDocStream.getDoc();
  const bool bOk = !htmlFileStream.bad();
  return bOk;
}

} // namespace sfm
} // namespace openMVG

#endif // OPENMVG_SFM_REPORT_HPP
<commit_msg>minor fix in html report file.<commit_after>// Copyright (c) 2015 Pierre Moulon.

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#ifndef OPENMVG_SFM_REPORT_HPP
#define OPENMVG_SFM_REPORT_HPP

#include "third_party/stlplus3/filesystemSimplified/file_system.hpp"
#include "third_party/htmlDoc/htmlDoc.hpp"
#include "third_party/histogram/histogram.hpp"
#include "third_party/vectorGraphics/svgDrawer.hpp"

namespace openMVG {
namespace sfm {

static bool Generate_SfM_Report
(
  const SfM_Data & sfm_data,
  const std::string & htmlFilename
)
{
  // Compute mean,max,median residual values per View
  IndexT residualCount = 0;
  Hash_Map< IndexT, std::vector<double> > residuals_per_view;
  for (Landmarks::const_iterator iterTracks = sfm_data.GetLandmarks().begin();
    iterTracks != sfm_data.GetLandmarks().end();
    ++iterTracks
  )
  {
    const Observations & obs = iterTracks->second.obs;
    for (Observations::const_iterator itObs = obs.begin();
      itObs != obs.end(); ++itObs)
    {
      const View * view = sfm_data.GetViews().at(itObs->first).get();
      const geometry::Pose3 pose = sfm_data.GetPoseOrDie(view);
      const cameras::IntrinsicBase * intrinsic = sfm_data.GetIntrinsics().at(view->id_intrinsic).get();
      // Use absolute values
      const Vec2 residual = intrinsic->residual(pose, iterTracks->second.X, itObs->second.x).array().abs();
      residuals_per_view[itObs->first].push_back(residual(0));
      residuals_per_view[itObs->first].push_back(residual(1));
      ++residualCount;
    }
  }
  using namespace htmlDocument;
  // extract directory from htmlFilename
  const std::string sTableBegin = "
",
    sTableEnd = "
",
    sRowBegin= "
", sRowEnd = "
",
    sColBegin = "", sColEnd = "	",
    sNewLine = "
", sFullLine = "
";

  htmlDocument::htmlDocumentStream htmlDocStream("SFM report.");
  htmlDocStream.pushInfo(
  htmlDocument::htmlMarkup("h1", std::string("SFM report.")));
  htmlDocStream.pushInfo(sFullLine);

  htmlDocStream.pushInfo( "Dataset info:" + sNewLine );

  std::ostringstream os;
  os << " #views: " << sfm_data.GetViews().size() << sNewLine
  << " #poses: " << sfm_data.GetPoses().size() << sNewLine
  << " #intrinsics: " << sfm_data.GetIntrinsics().size() << sNewLine
  << " #tracks: " << sfm_data.GetLandmarks().size() << sNewLine
  << " #residuals: " << residualCount << sNewLine;

  htmlDocStream.pushInfo( os.str() );
  htmlDocStream.pushInfo( sFullLine );

  htmlDocStream.pushInfo( sTableBegin);
  os.str("");
  os << sRowBegin
    << sColBegin + "IdView" + sColEnd
    << sColBegin + "Basename" + sColEnd
    << sColBegin + "#Observations" + sColEnd
    << sColBegin + "Residuals min" + sColEnd
    << sColBegin + "Residuals median" + sColEnd
    << sColBegin + "Residuals mean" + sColEnd
    << sColBegin + "Residuals max" + sColEnd
    << sRowEnd;
  htmlDocStream.pushInfo( os.str() );

  for (Views::const_iterator iterV = sfm_data.GetViews().begin();
    iterV != sfm_data.GetViews().end();
    ++iterV)
  {
    const View * v = iterV->second.get();
    const IndexT id_view = v->id_view;

    os.str("");
    os << sRowBegin
      << sColBegin << id_view << sColEnd
      << sColBegin + stlplus::basename_part(v->s_Img_path) + sColEnd;

    // IdView | basename | #Observations | residuals min | residual median | residual max
    if (sfm_data.IsPoseAndIntrinsicDefined(v))
    {
      if( residuals_per_view.find(id_view) != residuals_per_view.end() )
      {
        const std::vector<double> & residuals = residuals_per_view.at(id_view);
        if (!residuals.empty())
        {
          double min, max, mean, median;
          minMaxMeanMedian(residuals.begin(), residuals.end(), min, max, mean, median);
          os << sColBegin << residuals.size()/2 << sColEnd // #observations
            << sColBegin << min << sColEnd
            << sColBegin << median << sColEnd
            << sColBegin << mean << sColEnd
            << sColBegin << max <<sColEnd;
        }
      }
    }
    os << sRowEnd;
    htmlDocStream.pushInfo( os.str() );
  }
  htmlDocStream.pushInfo( sTableEnd );
  htmlDocStream.pushInfo( sFullLine );

  // combine all residual values into one vector
  // export the SVG histogram
  {
    IndexT residualCount = 0;
    for (Hash_Map< IndexT, std::vector<double> >::const_iterator
      it = residuals_per_view.begin();
      it != residuals_per_view.end();
      ++it)
    {
      residualCount += it->second.size();
    }
    // Concat per view residual values into one vector
    std::vector<double> residuals(residualCount);
    residualCount = 0;
    for (Hash_Map< IndexT, std::vector<double> >::const_iterator
      it = residuals_per_view.begin();
      it != residuals_per_view.end();
      ++it)
    {
      std::copy(it->second.begin(),
        it->second.begin()+it->second.size(),
        residuals.begin()+residualCount);
      residualCount += it->second.size();
    }
    if (!residuals.empty())
    {
      // RMSE computation
      const Eigen::Map<Eigen::RowVectorXd> residuals_mapping(&residuals[0], residuals.size());
      const double RMSE = std::sqrt(residuals_mapping.squaredNorm() / (double)residuals.size());
      os.str("");
      os << sFullLine << "SfM Scene RMSE: " << RMSE << sFullLine;
      htmlDocStream.pushInfo(os.str());

      const double maxRange = *max_element(residuals.begin(), residuals.end());
      Histogram<double> histo(0.0, maxRange, 100);
      histo.Add(residuals.begin(), residuals.end());

      svg::svgHisto svg_Histo;
      svg_Histo.draw(histo.GetHist(), std::pair<float,float>(0.f, maxRange),
        stlplus::create_filespec(stlplus::folder_part(htmlFilename), "residuals_histogram", "svg"),
        600, 200);

      os.str("");
      os << sNewLine<< "Residuals histogram" << sNewLine;
      os << "<img src=\""
        << "residuals_histogram.svg"
        << "\" height=\"300\" width =\"800\">\n";
      htmlDocStream.pushInfo(os.str());
    }
  }

  std::ofstream htmlFileStream(htmlFilename.c_str());
  htmlFileStream << htmlDocStream.getDoc();
  const bool bOk = !htmlFileStream.bad();
  return bOk;
}

} // namespace sfm
} // namespace openMVG

#endif // OPENMVG_SFM_REPORT_HPP
<|endoftext|>


<commit_before>// ***************************************************************************
//
//   Generated automatically by genwrapper.
//   Please DO NOT EDIT this file!
//
// ***************************************************************************

#include <osgIntrospection/ReflectionMacros>
#include <osgIntrospection/TypedMethodInfo>
#include <osgIntrospection/Attributes>

#include <osg/AlphaFunc>
#include <osg/CopyOp>
#include <osg/Shader>

BEGIN_ENUM_REFLECTOR(osg::Shader::Type)
	EnumLabel(osg::Shader::VERTEX);
	EnumLabel(osg::Shader::FRAGMENT);
	EnumLabel(osg::Shader::UNDEFINED);
END_REFLECTOR

BEGIN_ABSTRACT_OBJECT_REFLECTOR(osg::Shader)
	BaseType(osg::Object);
	ConstructorWithDefaults1(IN, osg::Shader::Type, type, osg::Shader::UNDEFINED);
	Constructor2(IN, osg::Shader::Type, type, IN, const std::string &, source);
	ConstructorWithDefaults2(IN, const osg::Shader &, rhs, , IN, const osg::CopyOp &, copyop, osg::CopyOp::SHALLOW_COPY);
	Method2(, META_Object, IN, osg, x, IN, osg::Shader, x);
	Method1(int, compare, IN, const osg::Shader &, rhs);
	Method1(bool, setType, IN, osg::Shader::Type, t);
	Method1(void, setShaderSource, IN, const std::string &, sourceText);
	Method1(bool, loadShaderSourceFromFile, IN, const std::string &, fileName);
	Method0(const std::string &, getShaderSource);
	Method0(osg::Shader::Type, getType);
	Method0(const char *, getTypename);
	Method0(void, dirtyShader);
	Method1(void, compileShader, IN, unsigned int, contextID);
	Method2(void, attachShader, IN, unsigned int, contextID, IN, GLuint, program);
	Method2(bool, getGlShaderInfoLog, IN, unsigned int, contextID, IN, std::string &, log);
	Method1(void, setName, IN, const std::string &, name);
	Method1(void, setName, IN, const char *, name);
	Method0(const std::string &, getName);
	Property(const std::string &, Name);
	Property(const std::string &, ShaderSource);
	PropertyWithReturnType(osg::Shader::Type, Type, bool);
	ReadOnlyProperty(const char *, Typename);
END_REFLECTOR

<commit_msg>Updated wrappers.<commit_after>// ***************************************************************************
//
//   Generated automatically by genwrapper.
//   Please DO NOT EDIT this file!
//
// ***************************************************************************

#include <osgIntrospection/ReflectionMacros>
#include <osgIntrospection/TypedMethodInfo>
#include <osgIntrospection/Attributes>

#include <osg/CopyOp>
#include <osg/Object>
#include <osg/Shader>

BEGIN_ENUM_REFLECTOR(osg::Shader::Type)
	EnumLabel(osg::Shader::VERTEX);
	EnumLabel(osg::Shader::FRAGMENT);
	EnumLabel(osg::Shader::UNDEFINED);
END_REFLECTOR

BEGIN_OBJECT_REFLECTOR(osg::Shader)
	BaseType(osg::Object);
	ConstructorWithDefaults1(IN, osg::Shader::Type, type, osg::Shader::UNDEFINED);
	Constructor2(IN, osg::Shader::Type, type, IN, const std::string &, source);
	ConstructorWithDefaults2(IN, const osg::Shader &, rhs, , IN, const osg::CopyOp &, copyop, osg::CopyOp::SHALLOW_COPY);
	Method0(osg::Object *, cloneType);
	Method1(osg::Object *, clone, IN, const osg::CopyOp &, copyop);
	Method1(bool, isSameKindAs, IN, const osg::Object *, obj);
	Method0(const char *, libraryName);
	Method0(const char *, className);
	Method1(int, compare, IN, const osg::Shader &, rhs);
	Method1(bool, setType, IN, osg::Shader::Type, t);
	Method1(void, setShaderSource, IN, const std::string &, sourceText);
	Method1(bool, loadShaderSourceFromFile, IN, const std::string &, fileName);
	Method0(const std::string &, getShaderSource);
	Method0(osg::Shader::Type, getType);
	Method0(const char *, getTypename);
	Method0(void, dirtyShader);
	Method1(void, compileShader, IN, unsigned int, contextID);
	Method2(void, attachShader, IN, unsigned int, contextID, IN, GLuint, program);
	Method2(bool, getGlShaderInfoLog, IN, unsigned int, contextID, IN, std::string &, log);
	Method1(void, setName, IN, const std::string &, name);
	Method1(void, setName, IN, const char *, name);
	Method0(const std::string &, getName);
	Property(const std::string &, Name);
	Property(const std::string &, ShaderSource);
	PropertyWithReturnType(osg::Shader::Type, Type, bool);
	ReadOnlyProperty(const char *, Typename);
END_REFLECTOR

<|endoftext|>


<commit_before>#include <iostream>
#include <stack>
#include <queue>
#include <cmath>

using std::stack;
using std::queue;

#include "operatorregistry.h"
#include "tokenizer.h"

double toNumber(string numberString)
{
	return std::stod(numberString);
}

double factorial(double n)
{
	return (n <= 1) ? 1 : n * factorial(n - 1);
}

void registerOperatorsIn(OperatorRegistry& operatorsRegistry)
{
	Operator plus("+", 2, 5, [](vector<double> args){return args[0] + args[1];});
	operatorsRegistry.registerOperator(plus);

	Operator minus("-", 2, 5, [](vector<double> args){return args[0] - args[1];});
	operatorsRegistry.registerOperator(minus);

	Operator mult("*", 2, 6, [](vector<double> args){return args[0] * args[1];});
	operatorsRegistry.registerOperator(mult);

	Operator division("/", 2, 6, [](vector<double> args){return args[0] / args[1];});
	operatorsRegistry.registerOperator(division);

	Operator fact("!", 1, 10, [](vector<double> args){return factorial(args[0]);});
	operatorsRegistry.registerOperator(fact);

	Operator power("^", 2, 11, [](vector<double> args){return pow(args[0], args[1]);});
	operatorsRegistry.registerOperator(power);
}

queue<Token> getReversedPolishNotationOf(string input, const OperatorRegistry& operatorsRegistry)
{
	Tokenizer tokenizer(input);
	bool expectOperator = false;
	bool expectNegativeNumber = false;

	queue<Token> reversedPolishNotation;
	stack<Token> operators;

	Token token;
	while(tokenizer.present())
	{
		token = tokenizer.get();
		// std::cout << "|" << token.value << "|" << std::endl;
		if(token.isNumber)
		{
			if(expectNegativeNumber)
			{
				token.value.insert(0, "-");
				reversedPolishNotation.push(token);
				expectNegativeNumber = false;
			}
			else
			{
				reversedPolishNotation.push(token);
			}
			expectOperator = true;
		}
		else
		{
			if(operatorsRegistry.hasOperatorFor(token.value))
			{
				if(!expectOperator && token.value == "-")
				{
					expectNegativeNumber = true;
					continue;
				}
				Operator operatr = operatorsRegistry.getOperatorFor(token.value);
				double priority = operatr.getPriority();
				while(!operators.empty() && operators.top().value != "(")
				{
					Operator topOperator = operatorsRegistry.getOperatorFor(operators.top().value);
					if(topOperator.getPriority() > priority)
					{
						reversedPolishNotation.push(operators.top());
						operators.pop();
					}
					else if(topOperator.getPriority() == priority && topOperator != operatr)
					{
						reversedPolishNotation.push(operators.top());
						operators.pop();
					}
					else
					{
						break;
					}
				}
				operators.push(token);
				expectOperator = false;
			}
			else // no operator
			{
				if(token.value == "(")
				{
					operators.push(token);
				}
				else if(token.value == ")")
				{
					while(!operators.empty() && operators.top().value != "(")
					{
						reversedPolishNotation.push(operators.top());
						operators.pop();
					}
					operators.pop(); //remove (
				}
				else
				{
					throw logic_error("Unrecognized symbol");
				}
			}
		}
	}

	while(!operators.empty())
	{
		reversedPolishNotation.push(operators.top());
		operators.pop();
	}
	return reversedPolishNotation;
}

double evaluateReversedPolishNotation(queue<Token>& reversedPolishNotation, const OperatorRegistry& operatorsRegistry)
{
	Token token;
	stack<double> numbers;
	while(!reversedPolishNotation.empty())
	{
		token = reversedPolishNotation.front();
		reversedPolishNotation.pop();
		if(operatorsRegistry.hasOperatorFor(token.value))
		{
			Operator operatr = operatorsRegistry.getOperatorFor(token.value);
			vector<double> operands;
			for (int i = 0; i < operatr.getArgumentsCount(); ++i)
			{
				if(numbers.empty())
				{
					throw logic_error("Not enough operands");
				}
				operands.insert(operands.begin(), numbers.top());
				numbers.pop();
			}
			numbers.push(operatr.evaluate(operands));
		}
		else
		{
			numbers.push(toNumber(token.value));
		}
	}

	if(numbers.size() != 1)
	{
		throw logic_error("Evaluaton error: More than one number in numbers stack at the end");
	}
	return numbers.top();
}

int main()
{
	string input;
	std::getline(std::cin, input);

	OperatorRegistry operatorsRegistry;
	registerOperatorsIn(operatorsRegistry);

	queue<Token> reversedPolishNotation = getReversedPolishNotationOf(input, operatorsRegistry);
	double value = evaluateReversedPolishNotation(reversedPolishNotation, operatorsRegistry);
	std::cout << value << std::endl;

	return 0;
}

<commit_msg>RPN factorial priority fixed<commit_after>#include <iostream>
#include <stack>
#include <queue>
#include <cmath>

using std::stack;
using std::queue;

#include "operatorregistry.h"
#include "tokenizer.h"

double toNumber(string numberString)
{
	return std::stod(numberString);
}

double factorial(double n)
{
	return (n <= 1) ? 1 : n * factorial(n - 1);
}

void registerOperatorsIn(OperatorRegistry& operatorsRegistry)
{
	Operator plus("+", 2, 5, [](vector<double> args){return args[0] + args[1];});
	operatorsRegistry.registerOperator(plus);

	Operator minus("-", 2, 5, [](vector<double> args){return args[0] - args[1];});
	operatorsRegistry.registerOperator(minus);

	Operator mult("*", 2, 6, [](vector<double> args){return args[0] * args[1];});
	operatorsRegistry.registerOperator(mult);

	Operator division("/", 2, 6, [](vector<double> args){return args[0] / args[1];});
	operatorsRegistry.registerOperator(division);

	Operator fact("!", 1, 11, [](vector<double> args){return factorial(args[0]);});
	operatorsRegistry.registerOperator(fact);

	Operator power("^", 2, 10, [](vector<double> args){return pow(args[0], args[1]);});
	operatorsRegistry.registerOperator(power);
}

queue<Token> getReversedPolishNotationOf(string input, const OperatorRegistry& operatorsRegistry)
{
	Tokenizer tokenizer(input);
	bool expectOperator = false;
	bool expectNegativeNumber = false;

	queue<Token> reversedPolishNotation;
	stack<Token> operators;

	Token token;
	while(tokenizer.present())
	{
		token = tokenizer.get();
		// std::cout << "|" << token.value << "|" << std::endl;
		if(token.isNumber)
		{
			if(expectNegativeNumber)
			{
				token.value.insert(0, "-");
				reversedPolishNotation.push(token);
				expectNegativeNumber = false;
			}
			else
			{
				reversedPolishNotation.push(token);
			}
			expectOperator = true;
		}
		else
		{
			if(operatorsRegistry.hasOperatorFor(token.value))
			{
				if(!expectOperator && token.value == "-")
				{
					expectNegativeNumber = true;
					continue;
				}
				Operator operatr = operatorsRegistry.getOperatorFor(token.value);
				double priority = operatr.getPriority();
				while(!operators.empty() && operators.top().value != "(")
				{
					Operator topOperator = operatorsRegistry.getOperatorFor(operators.top().value);
					if(topOperator.getPriority() > priority)
					{
						reversedPolishNotation.push(operators.top());
						operators.pop();
					}
					else if(topOperator.getPriority() == priority && topOperator != operatr)
					{
						reversedPolishNotation.push(operators.top());
						operators.pop();
					}
					else
					{
						break;
					}
				}
				operators.push(token);
				expectOperator = false;
			}
			else // no operator
			{
				if(token.value == "(")
				{
					operators.push(token);
				}
				else if(token.value == ")")
				{
					while(!operators.empty() && operators.top().value != "(")
					{
						reversedPolishNotation.push(operators.top());
						operators.pop();
					}
					operators.pop(); //remove (
				}
				else
				{
					throw logic_error("Unrecognized symbol");
				}
			}
		}
	}

	while(!operators.empty())
	{
		reversedPolishNotation.push(operators.top());
		operators.pop();
	}
	return reversedPolishNotation;
}

double evaluateReversedPolishNotation(queue<Token>& reversedPolishNotation, const OperatorRegistry& operatorsRegistry)
{
	Token token;
	stack<double> numbers;
	while(!reversedPolishNotation.empty())
	{
		token = reversedPolishNotation.front();
		reversedPolishNotation.pop();
		if(operatorsRegistry.hasOperatorFor(token.value))
		{
			Operator operatr = operatorsRegistry.getOperatorFor(token.value);
			vector<double> operands;
			for (int i = 0; i < operatr.getArgumentsCount(); ++i)
			{
				if(numbers.empty())
				{
					throw logic_error("Not enough operands");
				}
				operands.insert(operands.begin(), numbers.top());
				numbers.pop();
			}
			numbers.push(operatr.evaluate(operands));
		}
		else
		{
			numbers.push(toNumber(token.value));
		}
	}

	if(numbers.size() != 1)
	{
		throw logic_error("Evaluaton error: More than one number in numbers stack at the end");
	}
	return numbers.top();
}

int main()
{
	string input;
	std::getline(std::cin, input);

	OperatorRegistry operatorsRegistry;
	registerOperatorsIn(operatorsRegistry);

	queue<Token> reversedPolishNotation = getReversedPolishNotationOf(input, operatorsRegistry);
	double value = evaluateReversedPolishNotation(reversedPolishNotation, operatorsRegistry);
	std::cout << value << std::endl;

	return 0;
}

<|endoftext|>


<commit_before>//===- CorrelatedValuePropagation.cpp - Propagate CFG-derived info --------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the Correlated Value Propagation pass.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "correlated-value-propagation"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Function.h"
#include "llvm/Instructions.h"
#include "llvm/Pass.h"
#include "llvm/Analysis/LazyValueInfo.h"
#include "llvm/Support/CFG.h"
#include "llvm/Transforms/Utils/Local.h"
#include "llvm/ADT/Statistic.h"
using namespace llvm;

STATISTIC(NumPhis,      "Number of phis propagated");
STATISTIC(NumSelects,   "Number of selects propagated");
STATISTIC(NumMemAccess, "Number of memory access targets propagated");
STATISTIC(NumCmps,      "Number of comparisons propagated");

namespace {
  class CorrelatedValuePropagation : public FunctionPass {
    LazyValueInfo *LVI;

    bool processSelect(SelectInst *SI);
    bool processPHI(PHINode *P);
    bool processMemAccess(Instruction *I);
    bool processCmp(CmpInst *C);

  public:
    static char ID;
    CorrelatedValuePropagation(): FunctionPass(ID) { }

    bool runOnFunction(Function &F);

    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
      AU.addRequired<LazyValueInfo>();
    }
  };
}

char CorrelatedValuePropagation::ID = 0;
INITIALIZE_PASS(CorrelatedValuePropagation, "correlated-propagation",
                "Value Propagation", false, false);

// Public interface to the Value Propagation pass
Pass *llvm::createCorrelatedValuePropagationPass() {
  return new CorrelatedValuePropagation();
}

bool CorrelatedValuePropagation::processSelect(SelectInst *S) {
  if (S->getType()->isVectorTy()) return false;
  if (isa<Constant>(S->getOperand(0))) return false;

  Constant *C = LVI->getConstant(S->getOperand(0), S->getParent());
  if (!C) return false;

  ConstantInt *CI = dyn_cast<ConstantInt>(C);
  if (!CI) return false;

  S->replaceAllUsesWith(S->getOperand(CI->isOne() ? 1 : 2));
  S->eraseFromParent();

  ++NumSelects;

  return true;
}

bool CorrelatedValuePropagation::processPHI(PHINode *P) {
  bool Changed = false;

  BasicBlock *BB = P->getParent();
  for (unsigned i = 0, e = P->getNumIncomingValues(); i < e; ++i) {
    Value *Incoming = P->getIncomingValue(i);
    if (isa<Constant>(Incoming)) continue;

    Constant *C = LVI->getConstantOnEdge(P->getIncomingValue(i),
                                         P->getIncomingBlock(i),
                                         BB);
    if (!C) continue;

    P->setIncomingValue(i, C);
    Changed = true;
  }

  if (Value *ConstVal = P->hasConstantValue()) {
    P->replaceAllUsesWith(ConstVal);
    P->eraseFromParent();
    Changed = true;
  }

  ++NumPhis;

  return Changed;
}

bool CorrelatedValuePropagation::processMemAccess(Instruction *I) {
  Value *Pointer = 0;
  if (LoadInst *L = dyn_cast<LoadInst>(I))
    Pointer = L->getPointerOperand();
  else
    Pointer = cast<StoreInst>(I)->getPointerOperand();

  if (isa<Constant>(Pointer)) return false;

  Constant *C = LVI->getConstant(Pointer, I->getParent());
  if (!C) return false;

  ++NumMemAccess;
  I->replaceUsesOfWith(Pointer, C);
  return true;
}

/// processCmp - If the value of this comparison could be determined locally,
/// constant propagation would already have figured it out.  Instead, walk
/// the predecessors and statically evaluate the comparison based on information
/// available on that edge.  If a given static evaluation is true on ALL
/// incoming edges, then it's true universally and we can simplify the compare.
bool CorrelatedValuePropagation::processCmp(CmpInst *C) {
  Value *Op0 = C->getOperand(0);
  if (isa<Instruction>(Op0) &&
      cast<Instruction>(Op0)->getParent() == C->getParent())
    return false;

  Constant *Op1 = dyn_cast<Constant>(C->getOperand(1));
  if (!Op1) return false;

  pred_iterator PI = pred_begin(C->getParent()), PE = pred_end(C->getParent());
  if (PI == PE) return false;

  LazyValueInfo::Tristate Result = LVI->getPredicateOnEdge(C->getPredicate(),
                                    C->getOperand(0), Op1, *PI, C->getParent());
  if (Result == LazyValueInfo::Unknown) return false;

  ++PI;
  while (PI != PE) {
    LazyValueInfo::Tristate Res = LVI->getPredicateOnEdge(C->getPredicate(),
                                    C->getOperand(0), Op1, *PI, C->getParent());
    if (Res != Result) return false;
    ++PI;
  }

  ++NumCmps;

  if (Result == LazyValueInfo::True)
    C->replaceAllUsesWith(ConstantInt::getTrue(C->getContext()));
  else
    C->replaceAllUsesWith(ConstantInt::getFalse(C->getContext()));

  C->eraseFromParent();

  return true;
}

bool CorrelatedValuePropagation::runOnFunction(Function &F) {
  LVI = &getAnalysis<LazyValueInfo>();

  bool FnChanged = false;

  for (Function::iterator FI = F.begin(), FE = F.end(); FI != FE; ++FI) {
    bool BBChanged = false;
    for (BasicBlock::iterator BI = FI->begin(), BE = FI->end(); BI != BE; ) {
      Instruction *II = BI++;
      switch (II->getOpcode()) {
      case Instruction::Select:
        BBChanged |= processSelect(cast<SelectInst>(II));
        break;
      case Instruction::PHI:
        BBChanged |= processPHI(cast<PHINode>(II));
        break;
      case Instruction::ICmp:
      case Instruction::FCmp:
        BBChanged |= processCmp(cast<CmpInst>(II));
        break;
      case Instruction::Load:
      case Instruction::Store:
        BBChanged |= processMemAccess(II);
        break;
      }
    }

    // Propagating correlated values might leave cruft around.
    // Try to clean it up before we continue.
    if (BBChanged)
      SimplifyInstructionsInBlock(FI);

    FnChanged |= BBChanged;
  }

  return FnChanged;
}
<commit_msg>Use a depth-first iteratation in CorrelatedValuePropagation to avoid wasting time trying to optimize unreachable blocks.<commit_after>//===- CorrelatedValuePropagation.cpp - Propagate CFG-derived info --------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the Correlated Value Propagation pass.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "correlated-value-propagation"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Function.h"
#include "llvm/Instructions.h"
#include "llvm/Pass.h"
#include "llvm/Analysis/LazyValueInfo.h"
#include "llvm/Support/CFG.h"
#include "llvm/Transforms/Utils/Local.h"
#include "llvm/ADT/DepthFirstIterator.h"
#include "llvm/ADT/Statistic.h"
using namespace llvm;

STATISTIC(NumPhis,      "Number of phis propagated");
STATISTIC(NumSelects,   "Number of selects propagated");
STATISTIC(NumMemAccess, "Number of memory access targets propagated");
STATISTIC(NumCmps,      "Number of comparisons propagated");

namespace {
  class CorrelatedValuePropagation : public FunctionPass {
    LazyValueInfo *LVI;

    bool processSelect(SelectInst *SI);
    bool processPHI(PHINode *P);
    bool processMemAccess(Instruction *I);
    bool processCmp(CmpInst *C);

  public:
    static char ID;
    CorrelatedValuePropagation(): FunctionPass(ID) { }

    bool runOnFunction(Function &F);

    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
      AU.addRequired<LazyValueInfo>();
    }
  };
}

char CorrelatedValuePropagation::ID = 0;
INITIALIZE_PASS(CorrelatedValuePropagation, "correlated-propagation",
                "Value Propagation", false, false);

// Public interface to the Value Propagation pass
Pass *llvm::createCorrelatedValuePropagationPass() {
  return new CorrelatedValuePropagation();
}

bool CorrelatedValuePropagation::processSelect(SelectInst *S) {
  if (S->getType()->isVectorTy()) return false;
  if (isa<Constant>(S->getOperand(0))) return false;

  Constant *C = LVI->getConstant(S->getOperand(0), S->getParent());
  if (!C) return false;

  ConstantInt *CI = dyn_cast<ConstantInt>(C);
  if (!CI) return false;

  S->replaceAllUsesWith(S->getOperand(CI->isOne() ? 1 : 2));
  S->eraseFromParent();

  ++NumSelects;

  return true;
}

bool CorrelatedValuePropagation::processPHI(PHINode *P) {
  bool Changed = false;

  BasicBlock *BB = P->getParent();
  for (unsigned i = 0, e = P->getNumIncomingValues(); i < e; ++i) {
    Value *Incoming = P->getIncomingValue(i);
    if (isa<Constant>(Incoming)) continue;

    Constant *C = LVI->getConstantOnEdge(P->getIncomingValue(i),
                                         P->getIncomingBlock(i),
                                         BB);
    if (!C) continue;

    P->setIncomingValue(i, C);
    Changed = true;
  }

  if (Value *ConstVal = P->hasConstantValue()) {
    P->replaceAllUsesWith(ConstVal);
    P->eraseFromParent();
    Changed = true;
  }

  ++NumPhis;

  return Changed;
}

bool CorrelatedValuePropagation::processMemAccess(Instruction *I) {
  Value *Pointer = 0;
  if (LoadInst *L = dyn_cast<LoadInst>(I))
    Pointer = L->getPointerOperand();
  else
    Pointer = cast<StoreInst>(I)->getPointerOperand();

  if (isa<Constant>(Pointer)) return false;

  Constant *C = LVI->getConstant(Pointer, I->getParent());
  if (!C) return false;

  ++NumMemAccess;
  I->replaceUsesOfWith(Pointer, C);
  return true;
}

/// processCmp - If the value of this comparison could be determined locally,
/// constant propagation would already have figured it out.  Instead, walk
/// the predecessors and statically evaluate the comparison based on information
/// available on that edge.  If a given static evaluation is true on ALL
/// incoming edges, then it's true universally and we can simplify the compare.
bool CorrelatedValuePropagation::processCmp(CmpInst *C) {
  Value *Op0 = C->getOperand(0);
  if (isa<Instruction>(Op0) &&
      cast<Instruction>(Op0)->getParent() == C->getParent())
    return false;

  Constant *Op1 = dyn_cast<Constant>(C->getOperand(1));
  if (!Op1) return false;

  pred_iterator PI = pred_begin(C->getParent()), PE = pred_end(C->getParent());
  if (PI == PE) return false;

  LazyValueInfo::Tristate Result = LVI->getPredicateOnEdge(C->getPredicate(),
                                    C->getOperand(0), Op1, *PI, C->getParent());
  if (Result == LazyValueInfo::Unknown) return false;

  ++PI;
  while (PI != PE) {
    LazyValueInfo::Tristate Res = LVI->getPredicateOnEdge(C->getPredicate(),
                                    C->getOperand(0), Op1, *PI, C->getParent());
    if (Res != Result) return false;
    ++PI;
  }

  ++NumCmps;

  if (Result == LazyValueInfo::True)
    C->replaceAllUsesWith(ConstantInt::getTrue(C->getContext()));
  else
    C->replaceAllUsesWith(ConstantInt::getFalse(C->getContext()));

  C->eraseFromParent();

  return true;
}

bool CorrelatedValuePropagation::runOnFunction(Function &F) {
  LVI = &getAnalysis<LazyValueInfo>();

  bool FnChanged = false;

  // Perform a depth-first walk of the CFG so that we don't waste time
  // optimizing unreachable blocks.
  for (df_iterator<BasicBlock*> FI = df_begin(&F.getEntryBlock()),
       FE = df_end(&F.getEntryBlock()); FI != FE; ++FI) {
    bool BBChanged = false;
    for (BasicBlock::iterator BI = FI->begin(), BE = FI->end(); BI != BE; ) {
      Instruction *II = BI++;
      switch (II->getOpcode()) {
      case Instruction::Select:
        BBChanged |= processSelect(cast<SelectInst>(II));
        break;
      case Instruction::PHI:
        BBChanged |= processPHI(cast<PHINode>(II));
        break;
      case Instruction::ICmp:
      case Instruction::FCmp:
        BBChanged |= processCmp(cast<CmpInst>(II));
        break;
      case Instruction::Load:
      case Instruction::Store:
        BBChanged |= processMemAccess(II);
        break;
      }
    }

    // Propagating correlated values might leave cruft around.
    // Try to clean it up before we continue.
    if (BBChanged)
      SimplifyInstructionsInBlock(*FI);

    FnChanged |= BBChanged;
  }

  return FnChanged;
}
<|endoftext|>


<commit_before>#include "data_uri.h"

#include <algorithm>
#include <iostream>
#include <string>

#include "base64.h"

using std::cout;
using std::endl;
using std::string;

size_t DataURI::Leanify(size_t size_leanified /*= 0*/) {
  uint8_t *p_read = fp_, *p_write = fp_ - size_leanified;

  while (p_read < fp_ + size_) {
    const string magic = "data:image/";
    uint8_t* data_magic = std::search(p_read, fp_ + size_, magic.begin(), magic.end());

    if (data_magic >= fp_ + size_) {
      memmove(p_write, p_read, fp_ + size_ - p_read);
      p_write += fp_ + size_ - p_read;
      break;
    }

    const string base64_sign = ";base64,";
    const size_t kMaxSearchGap = 64;
    uint8_t* search_end = data_magic + magic.size() + kMaxSearchGap + base64_sign.size();
    search_end = std::min(search_end, fp_ + size_);
    uint8_t* start =
        std::search(data_magic + magic.size(), search_end, base64_sign.begin(), base64_sign.end()) + base64_sign.size();

    memmove(p_write, p_read, start - p_read);
    p_write += start - p_read;
    p_read = start;

    if (p_read > search_end)
      continue;

    const string quote = "'\")";
    uint8_t* end = fp_ + size_;
    if (!single_mode_) {
      end = std::find_first_of(p_read, fp_ + size_, quote.begin(), quote.end());
      if (end >= fp_ + size_) {
        memmove(p_write, p_read, fp_ + size_ - p_read);
        p_write += fp_ + size_ - p_read;
        break;
      }
    }

    if (is_verbose) {
      cout << string(reinterpret_cast<char*>(data_magic), start + 8 - data_magic) << "... found at offset 0x"
           << std::hex << data_magic - fp_ << std::dec << endl;
    }
    size_t new_size = Base64(p_read, end - p_read).Leanify(p_read - p_write);
    p_write += new_size;
    p_read = end;
  }
  fp_ -= size_leanified;
  size_ = p_write - fp_;
  return size_;
}
<commit_msg>DataURI: don't print offset in single mode<commit_after>#include "data_uri.h"

#include <algorithm>
#include <iostream>
#include <string>

#include "base64.h"

using std::cout;
using std::endl;
using std::string;

size_t DataURI::Leanify(size_t size_leanified /*= 0*/) {
  uint8_t *p_read = fp_, *p_write = fp_ - size_leanified;

  while (p_read < fp_ + size_) {
    const string magic = "data:image/";
    uint8_t* data_magic = std::search(p_read, fp_ + size_, magic.begin(), magic.end());

    if (data_magic >= fp_ + size_) {
      memmove(p_write, p_read, fp_ + size_ - p_read);
      p_write += fp_ + size_ - p_read;
      break;
    }

    const string base64_sign = ";base64,";
    const size_t kMaxSearchGap = 64;
    uint8_t* search_end = data_magic + magic.size() + kMaxSearchGap + base64_sign.size();
    search_end = std::min(search_end, fp_ + size_);
    uint8_t* start =
        std::search(data_magic + magic.size(), search_end, base64_sign.begin(), base64_sign.end()) + base64_sign.size();

    memmove(p_write, p_read, start - p_read);
    p_write += start - p_read;
    p_read = start;

    if (p_read > search_end)
      continue;

    const string quote = "'\")";
    uint8_t* end = fp_ + size_;
    if (!single_mode_) {
      end = std::find_first_of(p_read, fp_ + size_, quote.begin(), quote.end());
      if (end >= fp_ + size_) {
        memmove(p_write, p_read, fp_ + size_ - p_read);
        p_write += fp_ + size_ - p_read;
        break;
      }
    }

    if (is_verbose) {
      cout << string(reinterpret_cast<char*>(data_magic), start + 8 - data_magic) << "... found";
      if (!single_mode_) {
        cout << " at offset 0x" << std::hex << data_magic - fp_ << std::dec;
      }
      cout << endl;
    }
    size_t new_size = Base64(p_read, end - p_read).Leanify(p_read - p_write);
    p_write += new_size;
    p_read = end;
  }
  fp_ -= size_leanified;
  size_ = p_write - fp_;
  return size_;
}
<|endoftext|>


<commit_before>#include "camera.hpp"

//constructors
Camera::Camera() :
_position{0.0},
_direction{1.0,0.0,0.0},
_aperture{40.0}
{}

Camera::Camera(glm::vec3 const& direction, float aperture) :
_direction{direction},
_aperture{aperture}
{}

Camera::Camera(std::string const& name, float aperture) :
_name{name},
_aperture{aperture}
{}

//destructors
Camera::~Camera()
{}

//get-methods

std::string const& Camera::name() const
{
	return _name;
}

glm::vec3 const& Camera::position() const
{
	return _position;
}

glm::vec3 const& Camera::direction() const
{
	return _direction;
}

//non-member functions

Ray Camera::getEyeRay(int x, int y, float &distance) const
{
	return Ray{glm::vec3{_position}, glm::vec3{x, y, distance}};
}

float Camera::getDistance(int width) const
{
	return (width/2)/tan(_aperture/2);
}

std::ostream& Camera::print(std::ostream& os) const
{
	os << "[Camera] " <<
 				"position: " << glm::to_string(_position) << "\n" <<
 				"direction: " << glm::to_string(_direction) << "\n";
	return os;
}

std::ostream& operator<<(std::ostream& os , Camera const& c)
{
	return c.print(os);
}<commit_msg>changed direction vector<commit_after>#include "camera.hpp"

//constructors
Camera::Camera() :
_position{0.0},
_direction{0.0,0.0,-1.0},
_aperture{40.0}
{}

Camera::Camera(glm::vec3 const& direction, float aperture) :
_direction{direction},
_aperture{aperture}
{}

Camera::Camera(std::string const& name, float aperture) :
_name{name},
_direction{0.0,0.0,-1.0},
_aperture{aperture}
{}

//destructors
Camera::~Camera()
{}

//get-methods

std::string const& Camera::name() const
{
	return _name;
}

glm::vec3 const& Camera::position() const
{
	return _position;
}

glm::vec3 const& Camera::direction() const
{
	return _direction;
}

//non-member functions

Ray Camera::getEyeRay(int x, int y, float &distance) const
{
	return Ray{glm::vec3{_position}, glm::vec3{x, y, distance}};
}

float Camera::getDistance(int width) const
{
	return (width/2)/tan(_aperture/2);
}

std::ostream& Camera::print(std::ostream& os) const
{
	os << "[Camera] " <<
 				"position: " << glm::to_string(_position) << "\n" <<
 				"direction: " << glm::to_string(_direction) << "\n";
	return os;
}

std::ostream& operator<<(std::ostream& os , Camera const& c)
{
	return c.print(os);
}<|endoftext|>


<commit_before>#include <curl/curl.h>
#include <boost/filesystem.hpp>
#include <boost/program_options.hpp>
#include <iomanip>
#include <iostream>

#include "accumulator.h"
#include "authenticate.h"
#include "json/json.h"
#include "logging/logging.h"
#include "treehub_server.h"

namespace po = boost::program_options;
using std::string;

// helper function to download data to a string
static size_t writeString(void *contents, size_t size, size_t nmemb, void *userp) {
  assert(userp);
  // append the writeback data to the provided string
  (static_cast<std::string *>(userp))->append(static_cast<char *>(contents), size * nmemb);

  // return size of written data
  return size * nmemb;
}

class CurlEasyWrapper {
 public:
  CurlEasyWrapper() { handler = curl_easy_init(); }
  ~CurlEasyWrapper() {
    if (handler != nullptr) {
      curl_easy_cleanup(handler);
    }
  }
  CURL *get() { return handler; }

 private:
  CURL *handler;
};

int main(int argc, char **argv) {
  logger_init();

  string ref = "uninitialized";

  boost::filesystem::path credentials_path;
  string home_path = string(getenv("HOME"));
  string cacerts;

  int verbosity;
  po::options_description desc("garage-check command line options");
  // clang-format off
  desc.add_options()
    ("help", "print usage")
    ("verbose,v",accumulator<int>(&verbosity), "verbose logging (use twice for more information)")
    ("quiet,q", "quiet mode")
    ("ref,r", po::value<string>(&ref)->required(), "refhash to check")
    ("credentials,j", po::value<boost::filesystem::path>(&credentials_path)->required(), "credentials (json or zip containing json)")
    ("cacert", po::value<string>(&cacerts), "override path to CA root certificates, in the same format as curl --cacert");
  // clang-format on

  po::variables_map vm;

  try {
    po::store(po::parse_command_line(argc, reinterpret_cast<const char *const *>(argv), desc), vm);

    if (vm.count("help") != 0u) {
      LOG_INFO << desc;
      return EXIT_SUCCESS;
    }

    po::notify(vm);
  } catch (const po::error &o) {
    LOG_INFO << o.what();
    LOG_INFO << desc;
    return EXIT_FAILURE;
  }

  // Configure logging
  if (verbosity == 0) {
    // 'verbose' trumps 'quiet'
    if (static_cast<int>(vm.count("quiet")) != 0) {
      logger_set_threshold(boost::log::trivial::warning);
    } else {
      logger_set_threshold(boost::log::trivial::info);
    }
  } else if (verbosity == 1) {
    logger_set_threshold(boost::log::trivial::debug);
    LOG_DEBUG << "Debug level debugging enabled";
  } else if (verbosity > 1) {
    logger_set_threshold(boost::log::trivial::trace);
    LOG_TRACE << "Trace level debugging enabled";
  } else {
    assert(0);
  }

  TreehubServer treehub;
  if (cacerts != "") {
    if (boost::filesystem::exists(cacerts)) {
      treehub.ca_certs(cacerts);
    } else {
      LOG_FATAL << "--cacert path " << cacerts << " does not exist";
      return EXIT_FAILURE;
    }
  }

  if (authenticate(cacerts, ServerCredentials(credentials_path), treehub) != EXIT_SUCCESS) {
    LOG_FATAL << "Authentication failed";
    return EXIT_FAILURE;
  }

  // check if the ref is present on treehub
  CurlEasyWrapper curl;
  if (curl.get() == nullptr) {
    LOG_FATAL << "Error initializing curl";
    return EXIT_FAILURE;
  }
  curl_easy_setopt(curl.get(), CURLOPT_VERBOSE, get_curlopt_verbose());
  curl_easy_setopt(curl.get(), CURLOPT_NOBODY, 1L);  // HEAD

  treehub.InjectIntoCurl("objects/" + ref.substr(0, 2) + "/" + ref.substr(2) + ".commit", curl.get());

  CURLcode result = curl_easy_perform(curl.get());
  if (result != CURLE_OK) {
    LOG_FATAL << "Error connecting to treehub: " << result << ": " << curl_easy_strerror(result);
    return EXIT_FAILURE;
  }

  long http_code;  // NOLINT
  curl_easy_getinfo(curl.get(), CURLINFO_RESPONSE_CODE, &http_code);
  if (http_code == 404) {
    LOG_FATAL << "OSTree commit " << ref << " is missing in treehub";
    return EXIT_FAILURE;
  }
  if (http_code != 200) {
    LOG_FATAL << "Error " << http_code << " getting commit " << ref << " from treehub";
    return EXIT_FAILURE;
  }
  LOG_INFO << "OSTree commit " << ref << " is found on treehub";

  // check if the ref is present in targets.json
  curl_easy_setopt(curl.get(), CURLOPT_VERBOSE, get_curlopt_verbose());
  curl_easy_setopt(curl.get(), CURLOPT_HTTPGET, 1L);
  curl_easy_setopt(curl.get(), CURLOPT_NOBODY, 0L);
  treehub.InjectIntoCurl("/api/v1/user_repo/targets.json", curl.get(), true);

  std::string targets_str;
  curl_easy_setopt(curl.get(), CURLOPT_WRITEFUNCTION, writeString);
  curl_easy_setopt(curl.get(), CURLOPT_WRITEDATA, (void *)&targets_str);
  result = curl_easy_perform(curl.get());

  if (result != CURLE_OK) {
    LOG_FATAL << "Error connecting to TUF repo: " << result << ": " << curl_easy_strerror(result);
    return EXIT_FAILURE;
  }

  curl_easy_getinfo(curl.get(), CURLINFO_RESPONSE_CODE, &http_code);
  if (http_code != 200) {
    LOG_FATAL << "Error " << http_code << " getting targets.json from TUF repo: " << targets_str;
    return EXIT_FAILURE;
  }

  Json::Value targets_json = Utils::parseJSON(targets_str);
  Json::Value target_list = targets_json["signed"]["targets"];
  for (Json::ValueIterator t_it = target_list.begin(); t_it != target_list.end(); t_it++) {
    if ((*t_it)["hashes"]["sha256"].asString() == ref) {
      LOG_INFO << "OSTree package " << ref << " is found in targets.json";
      return EXIT_SUCCESS;
    }
  }
  LOG_INFO << "OSTree package " << ref << " was not found in targets.json";
  return EXIT_FAILURE;
}
// vim: set tabstop=2 shiftwidth=2 expandtab:
<commit_msg>Check targets expiry date in garage-check<commit_after>#include <curl/curl.h>
#include <boost/filesystem.hpp>
#include <boost/program_options.hpp>
#include <ctime>
#include <iomanip>
#include <iostream>

#include "accumulator.h"
#include "authenticate.h"
#include "json/json.h"
#include "logging/logging.h"
#include "treehub_server.h"
#include "uptane/tuf.h"

namespace po = boost::program_options;
using std::string;

// helper function to download data to a string
static size_t writeString(void *contents, size_t size, size_t nmemb, void *userp) {
  assert(userp);
  // append the writeback data to the provided string
  (static_cast<std::string *>(userp))->append(static_cast<char *>(contents), size * nmemb);

  // return size of written data
  return size * nmemb;
}

class CurlEasyWrapper {
 public:
  CurlEasyWrapper() { handler = curl_easy_init(); }
  ~CurlEasyWrapper() {
    if (handler != nullptr) {
      curl_easy_cleanup(handler);
    }
  }
  CURL *get() { return handler; }

 private:
  CURL *handler;
};

int main(int argc, char **argv) {
  logger_init();

  string ref = "uninitialized";

  boost::filesystem::path credentials_path;
  string home_path = string(getenv("HOME"));
  string cacerts;

  int verbosity;
  po::options_description desc("garage-check command line options");
  // clang-format off
  desc.add_options()
    ("help", "print usage")
    ("verbose,v",accumulator<int>(&verbosity), "verbose logging (use twice for more information)")
    ("quiet,q", "quiet mode")
    ("ref,r", po::value<string>(&ref)->required(), "refhash to check")
    ("credentials,j", po::value<boost::filesystem::path>(&credentials_path)->required(), "credentials (json or zip containing json)")
    ("cacert", po::value<string>(&cacerts), "override path to CA root certificates, in the same format as curl --cacert");
  // clang-format on

  po::variables_map vm;

  try {
    po::store(po::parse_command_line(argc, reinterpret_cast<const char *const *>(argv), desc), vm);

    if (vm.count("help") != 0u) {
      LOG_INFO << desc;
      return EXIT_SUCCESS;
    }

    po::notify(vm);
  } catch (const po::error &o) {
    LOG_INFO << o.what();
    LOG_INFO << desc;
    return EXIT_FAILURE;
  }

  // Configure logging
  if (verbosity == 0) {
    // 'verbose' trumps 'quiet'
    if (static_cast<int>(vm.count("quiet")) != 0) {
      logger_set_threshold(boost::log::trivial::warning);
    } else {
      logger_set_threshold(boost::log::trivial::info);
    }
  } else if (verbosity == 1) {
    logger_set_threshold(boost::log::trivial::debug);
    LOG_DEBUG << "Debug level debugging enabled";
  } else if (verbosity > 1) {
    logger_set_threshold(boost::log::trivial::trace);
    LOG_TRACE << "Trace level debugging enabled";
  } else {
    assert(0);
  }

  TreehubServer treehub;
  if (cacerts != "") {
    if (boost::filesystem::exists(cacerts)) {
      treehub.ca_certs(cacerts);
    } else {
      LOG_FATAL << "--cacert path " << cacerts << " does not exist";
      return EXIT_FAILURE;
    }
  }

  if (authenticate(cacerts, ServerCredentials(credentials_path), treehub) != EXIT_SUCCESS) {
    LOG_FATAL << "Authentication failed";
    return EXIT_FAILURE;
  }

  // check if the ref is present on treehub
  CurlEasyWrapper curl;
  if (curl.get() == nullptr) {
    LOG_FATAL << "Error initializing curl";
    return EXIT_FAILURE;
  }
  curl_easy_setopt(curl.get(), CURLOPT_VERBOSE, get_curlopt_verbose());
  curl_easy_setopt(curl.get(), CURLOPT_NOBODY, 1L);  // HEAD

  treehub.InjectIntoCurl("objects/" + ref.substr(0, 2) + "/" + ref.substr(2) + ".commit", curl.get());

  CURLcode result = curl_easy_perform(curl.get());
  if (result != CURLE_OK) {
    LOG_FATAL << "Error connecting to treehub: " << result << ": " << curl_easy_strerror(result);
    return EXIT_FAILURE;
  }

  long http_code;  // NOLINT
  curl_easy_getinfo(curl.get(), CURLINFO_RESPONSE_CODE, &http_code);
  if (http_code == 404) {
    LOG_FATAL << "OSTree commit " << ref << " is missing in treehub";
    return EXIT_FAILURE;
  }
  if (http_code != 200) {
    LOG_FATAL << "Error " << http_code << " getting commit " << ref << " from treehub";
    return EXIT_FAILURE;
  }
  LOG_INFO << "OSTree commit " << ref << " is found on treehub";

  // check if the ref is present in targets.json
  curl_easy_setopt(curl.get(), CURLOPT_VERBOSE, get_curlopt_verbose());
  curl_easy_setopt(curl.get(), CURLOPT_HTTPGET, 1L);
  curl_easy_setopt(curl.get(), CURLOPT_NOBODY, 0L);
  treehub.InjectIntoCurl("/api/v1/user_repo/targets.json", curl.get(), true);

  std::string targets_str;
  curl_easy_setopt(curl.get(), CURLOPT_WRITEFUNCTION, writeString);
  curl_easy_setopt(curl.get(), CURLOPT_WRITEDATA, (void *)&targets_str);
  result = curl_easy_perform(curl.get());

  if (result != CURLE_OK) {
    LOG_FATAL << "Error connecting to TUF repo: " << result << ": " << curl_easy_strerror(result);
    return EXIT_FAILURE;
  }

  curl_easy_getinfo(curl.get(), CURLINFO_RESPONSE_CODE, &http_code);
  if (http_code != 200) {
    LOG_FATAL << "Error " << http_code << " getting targets.json from TUF repo: " << targets_str;
    return EXIT_FAILURE;
  }

  Json::Value targets_json = Utils::parseJSON(targets_str);
  std::string expiry_time_str = targets_json["signed"]["expires"].asString();
  Uptane::TimeStamp timestamp(expiry_time_str);

  if (timestamp.IsExpiredAt(Uptane::TimeStamp::Now())) {
    LOG_FATAL << "targets.json has been expired.";
    return EXIT_FAILURE;
  }

  Json::Value target_list = targets_json["signed"]["targets"];
  for (Json::ValueIterator t_it = target_list.begin(); t_it != target_list.end(); t_it++) {
    if ((*t_it)["hashes"]["sha256"].asString() == ref) {
      LOG_INFO << "OSTree package " << ref << " is found in targets.json";
      return EXIT_SUCCESS;
    }
  }
  LOG_INFO << "OSTree package " << ref << " was not found in targets.json";
  return EXIT_FAILURE;
}
// vim: set tabstop=2 shiftwidth=2 expandtab:
<|endoftext|>


<commit_before>#ifndef scoped_H__
#define scoped_H__

namespace testbed
{

////////////////////////////////////////////////////////////////////////////////////////////////////
// scoped_ptr and scoped_linkage_ptr provide end-of-scope actions on arbitrary and external linkage
// pointers, respectively. In addition, scoped_ptr is resettable, while scoped_linkage_ptr comes at
// zero memory overhead.
////////////////////////////////////////////////////////////////////////////////////////////////////

class non_copyable
{
	non_copyable(const non_copyable&) {}
	non_copyable& operator =(const non_copyable&) { return *this; }

public:
	non_copyable() {}
};

template <
	typename T,
	template< typename F > class FTOR_T,
	T* PTR_T >
class scoped_linkage_ptr : non_copyable, FTOR_T< T >
{
public:
	scoped_linkage_ptr() {}

	~scoped_linkage_ptr()
	{
		FTOR_T< T >::operator()(PTR_T);
	}
};

template <
	typename T,
	template< typename F > class FTOR_T >
class scoped_ptr : non_copyable, FTOR_T< T >
{
	T* m;

public:
	scoped_ptr()
	: m(0)
	{}

	explicit scoped_ptr(T* arg)
	: m(arg)
	{}

	~scoped_ptr()
	{
		if (0 != m)
			FTOR_T< T >::operator()(m);
	}

	void reset()
	{
		m = 0;
	}

	void swap(scoped_ptr& oth)
	{
		T* const t = m;
		m = oth.m;
		oth.m = t;
	}

	T* operator ()() const
	{
		return m;
	}
};

template < typename T >
class scoped_functor
{
public:
	void operator()(T*);
};

typedef bool (deinit_resources_t)();

template <>
class scoped_functor< deinit_resources_t >
{
public:
	void operator()(deinit_resources_t* arg)
	{
		arg();
	}
};

template < typename T >
class generic_delete
{
public:

	void operator()(T* arg)
	{
		delete arg;
	}
};

template < typename T >
class generic_delete_arr
{
public:

	void operator()(T* arg)
	{
		delete [] arg;
	}
};

} // namespace testbed

#endif // scoped_H__
<commit_msg>update scoped in common to the latest version<commit_after>#ifndef scoped_H__
#define scoped_H__

namespace testbed {

////////////////////////////////////////////////////////////////////////////////////////////////////
// scoped_ptr and scoped_linkage_ptr provide end-of-scope actions on arbitrary and external linkage
// pointers, respectively. In addition, scoped_ptr is resettable, while scoped_linkage_ptr comes at
// zero memory overhead.
////////////////////////////////////////////////////////////////////////////////////////////////////

class non_copyable
{
	non_copyable(const non_copyable&) {}
	non_copyable& operator =(const non_copyable&) { return *this; }

public:
	non_copyable() {}
};

template <
	typename T,
	template< typename F > class FTOR_T,
	T* PTR_T >
class scoped_linkage_ptr : non_copyable, FTOR_T< T >
{
public:
	~scoped_linkage_ptr()
	{
		FTOR_T< T >::operator()(PTR_T);
	}
};

template <
	typename T,
	template< typename F > class FTOR_T >
class scoped_ptr : non_copyable, FTOR_T< T >
{
	T* m;

public:
	scoped_ptr()
	: m(0)
	{}

	explicit scoped_ptr(T* arg)
	: m(arg)
	{}

	~scoped_ptr()
	{
		if (0 != m)
			FTOR_T< T >::operator()(m);
	}

	void reset()
	{
		m = 0;
	}

	void swap(scoped_ptr& oth)
	{
		m = __atomic_exchange_n(&oth.m, m, __ATOMIC_RELAXED);
	}

	T* operator ()() const
	{
		return m;
	}
};

template < typename T >
class scoped_functor
{
public:
	void operator()(T*);
};

typedef bool (deinit_resources_t)();

template <>
class scoped_functor< deinit_resources_t >
{
public:
	void operator()(deinit_resources_t* arg)
	{
		arg();
	}
};

template < typename T >
class generic_delete
{
public:
	void operator()(T* arg)
	{
		delete arg;
	}
};

template < typename T >
class generic_delete_arr
{
public:
	void operator()(T* arg)
	{
		delete [] arg;
	}
};

} // namespace testbed

#endif // scoped_H__
<|endoftext|>


<commit_before>/* This file is part of Strigi Desktop Search
 *
 * Copyright (C) 2007 Jos van den Oever <jos@vandenoever.info>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */
#include "variant.h"

using namespace std;
using namespace Strigi;

class Strigi::VariantPrivate {
public:
    int32_t i_value;
    uint32_t u_value;
    string s_value;
    vector<string> as_value;
    vector<vector<string> > aas_value;
    Variant::Type vartype;
    bool valid;

    VariantPrivate() :i_value(0), u_value(0), vartype(Variant::b_val), valid(false) {}
    VariantPrivate(const Variant& v) { *this = v; }
    void operator=(const VariantPrivate& v);
    bool b() const;
    int32_t i() const;
    uint32_t u() const;
    string s() const;
    vector<string> as() const;
    vector<vector<string> > aas() const;

    static string itos(int32_t i);
};
Variant::Variant() :p(new VariantPrivate()) {}
Variant::Variant(bool v) :p(new VariantPrivate()) {
    *this=v;
}
Variant::Variant(int32_t v) :p(new VariantPrivate()) {
    *this=v;
}
Variant::Variant(uint32_t v) :p(new VariantPrivate()) {
    *this=v;
}
Variant::Variant(const char* v) :p(new VariantPrivate()) {
    *this=v;
}
Variant::Variant(const string& v) :p(new VariantPrivate()) {
    *this=v;
}
Variant::Variant(const vector<string>& v) :p(new VariantPrivate()) {
    *this=v;
}
Variant::Variant(const vector<vector<string> >& v) :p(new VariantPrivate()) {
    *this=v;
}
Variant::Variant(const Variant& v) :p(new VariantPrivate(*v.p)) {
}
Variant::~Variant() {
  delete p;
}

Variant::Type
Variant::type() const { return p->vartype; }
const Variant&
Variant::operator=(bool v) {
    p->valid = true;
    p->i_value = v;
    p->vartype = b_val;
    return *this;
}
const Variant&
Variant::operator=(int32_t v) {
    p->valid=true;
    p->i_value = v;
    p->u_value = v;
    p->vartype = i_val;
    return *this;
}
const Variant&
Variant::operator=(uint32_t v) {
    p->valid=true;
    p->i_value = v;
    p->u_value = v;
    p->vartype = u_val;
    return *this;
}
const Variant&
Variant::operator=(const char* v) {
    p->valid=true;
    p->s_value.assign(v);
    p->vartype = s_val;
    return *this;
}
const Variant&
Variant::operator=(const string& v) {
    p->valid=true;
    p->s_value.assign(v);
    p->vartype = s_val;
    return *this;
}
const Variant&
Variant::operator=(const vector<string>& v) {
    p->valid=true;
    p->as_value = v;
    p->vartype = as_val;
    return *this;
}
const Variant&
Variant::operator=(const vector<vector<string> >& v) {
    p->valid=true;
    p->aas_value = v;
    p->vartype = aas_val;
    return *this;
}
const Variant&
Variant::operator=(const Variant& v) {
    *p = *v.p;
    return v;
}
void
VariantPrivate::operator=(const VariantPrivate& v) {
    i_value = v.i_value;
    s_value = v.s_value;
    as_value = v.as_value;
    vartype = v.vartype;
    valid = v.valid;
}
bool
Variant::b() const {
    return p->b();
}
bool
VariantPrivate::b() const {
    switch (vartype) {
    case Variant::b_val:
    case Variant::i_val:
         return i_value;
    case Variant::s_val:
         return s_value == "1" || s_value == "true" || s_value == "True"
             || s_value == "TRUE";
    case Variant::as_val:
         return as_value.size();
    default:
         return false;
    }
}
int32_t
Variant::i() const {
    return p->i();
}
int32_t
VariantPrivate::i() const {
    switch (vartype) {
    case Variant::b_val:
    case Variant::i_val:
         return i_value;
    case Variant::s_val:
         return atoi(s_value.c_str());
    case Variant::as_val:
         return as_value.size();
    default:
         return -1;
    }
}
uint32_t
Variant::u() const {
    return p->u();
}
uint32_t
VariantPrivate::u() const {
    switch (vartype) {
    case Variant::b_val:
    case Variant::i_val:
    case Variant::u_val:
         return u_value;
    case Variant::s_val:
         return atoi(s_value.c_str());
    case Variant::as_val:
         return as_value.size();
    default:
         return -1;
    }
}
string
VariantPrivate::itos(int32_t i) {
    ostringstream o;
    o << i;
    return o.str();
}
string
Variant::s() const {
    return p->s();
}
string
VariantPrivate::s() const {
    switch (vartype) {
    case Variant::b_val:
         return i_value ?"true" :"false";
    case Variant::i_val:
         return itos(i_value);
    case Variant::s_val:
         return s_value;
    case Variant::as_val:
         return as_value.size() ?as_value[0] :"";
    default:
         return "";
    }
}
vector<string>
Variant::as() const {
    return p->as();
}
vector<string>
VariantPrivate::as() const {
    if (vartype == Variant::as_val) {
        return as_value;
    }
    vector<string> v;
    if (b()) {
        v.push_back(s());
    }
    return v;
}
vector<vector<string> >
Variant::aas() const {
    return p->aas();
}
vector<vector<string> >
VariantPrivate::aas() const {
    if (vartype == Variant::aas_val) {
        return aas_value;
    }
    vector<vector<string> > v;
    if (b()) {
        v.push_back(as());
    }
    return v;
}
bool
Variant::isValid() const {
    return p->valid;
}
<commit_msg>warning--<commit_after>/* This file is part of Strigi Desktop Search
 *
 * Copyright (C) 2007 Jos van den Oever <jos@vandenoever.info>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */
#include "variant.h"

using namespace std;
using namespace Strigi;

class Strigi::VariantPrivate {
public:
    int32_t i_value;
    uint32_t u_value;
    string s_value;
    vector<string> as_value;
    vector<vector<string> > aas_value;
    Variant::Type vartype;
    bool valid;

    VariantPrivate() :i_value(0), u_value(0), vartype(Variant::b_val), valid(false) {}
    VariantPrivate(const Variant& v) { *this = v; }
    void operator=(const VariantPrivate& v);
    bool b() const;
    int32_t i() const;
    uint32_t u() const;
    string s() const;
    vector<string> as() const;
    vector<vector<string> > aas() const;

    static string itos(int32_t i);
};
Variant::Variant() :p(new VariantPrivate()) {}
Variant::Variant(bool v) :p(new VariantPrivate()) {
    *this=v;
}
Variant::Variant(int32_t v) :p(new VariantPrivate()) {
    *this=v;
}
Variant::Variant(uint32_t v) :p(new VariantPrivate()) {
    *this=v;
}
Variant::Variant(const char* v) :p(new VariantPrivate()) {
    *this=v;
}
Variant::Variant(const string& v) :p(new VariantPrivate()) {
    *this=v;
}
Variant::Variant(const vector<string>& v) :p(new VariantPrivate()) {
    *this=v;
}
Variant::Variant(const vector<vector<string> >& v) :p(new VariantPrivate()) {
    *this=v;
}
Variant::Variant(const Variant& v) :p(new VariantPrivate(*v.p)) {
}
Variant::~Variant() {
  delete p;
}

Variant::Type
Variant::type() const { return p->vartype; }
const Variant&
Variant::operator=(bool v) {
    p->valid = true;
    p->i_value = v;
    p->vartype = b_val;
    return *this;
}
const Variant&
Variant::operator=(int32_t v) {
    p->valid=true;
    p->i_value = v;
    p->u_value = v;
    p->vartype = i_val;
    return *this;
}
const Variant&
Variant::operator=(uint32_t v) {
    p->valid=true;
    p->i_value = v;
    p->u_value = v;
    p->vartype = u_val;
    return *this;
}
const Variant&
Variant::operator=(const char* v) {
    p->valid=true;
    p->s_value.assign(v);
    p->vartype = s_val;
    return *this;
}
const Variant&
Variant::operator=(const string& v) {
    p->valid=true;
    p->s_value.assign(v);
    p->vartype = s_val;
    return *this;
}
const Variant&
Variant::operator=(const vector<string>& v) {
    p->valid=true;
    p->as_value = v;
    p->vartype = as_val;
    return *this;
}
const Variant&
Variant::operator=(const vector<vector<string> >& v) {
    p->valid=true;
    p->aas_value = v;
    p->vartype = aas_val;
    return *this;
}
const Variant&
Variant::operator=(const Variant& v) {
    *p = *v.p;
    return v;
}
void
VariantPrivate::operator=(const VariantPrivate& v) {
    i_value = v.i_value;
    s_value = v.s_value;
    as_value = v.as_value;
    vartype = v.vartype;
    valid = v.valid;
}
bool
Variant::b() const {
    return p->b();
}
bool
VariantPrivate::b() const {
    switch (vartype) {
    case Variant::b_val:
    case Variant::i_val:
         return i_value;
    case Variant::s_val:
         return s_value == "1" || s_value == "true" || s_value == "True"
             || s_value == "TRUE";
    case Variant::as_val:
         return as_value.size();
    default:
         return false;
    }
}
int32_t
Variant::i() const {
    return p->i();
}
int32_t
VariantPrivate::i() const {
    switch (vartype) {
    case Variant::b_val:
    case Variant::i_val:
         return i_value;
    case Variant::s_val:
         return atoi(s_value.c_str());
    case Variant::as_val:
         return as_value.size();
    default:
         return -1;
    }
}
uint32_t
Variant::u() const {
    return p->u();
}
uint32_t
VariantPrivate::u() const {
    switch (vartype) {
    case Variant::b_val:
    case Variant::i_val:
    case Variant::u_val:
         return u_value;
    case Variant::s_val:
         return atoi(s_value.c_str());
    case Variant::as_val:
         return as_value.size();
    default:
         return ~0U;
    }
}
string
VariantPrivate::itos(int32_t i) {
    ostringstream o;
    o << i;
    return o.str();
}
string
Variant::s() const {
    return p->s();
}
string
VariantPrivate::s() const {
    switch (vartype) {
    case Variant::b_val:
         return i_value ?"true" :"false";
    case Variant::i_val:
         return itos(i_value);
    case Variant::s_val:
         return s_value;
    case Variant::as_val:
         return as_value.size() ?as_value[0] :"";
    default:
         return "";
    }
}
vector<string>
Variant::as() const {
    return p->as();
}
vector<string>
VariantPrivate::as() const {
    if (vartype == Variant::as_val) {
        return as_value;
    }
    vector<string> v;
    if (b()) {
        v.push_back(s());
    }
    return v;
}
vector<vector<string> >
Variant::aas() const {
    return p->aas();
}
vector<vector<string> >
VariantPrivate::aas() const {
    if (vartype == Variant::aas_val) {
        return aas_value;
    }
    vector<vector<string> > v;
    if (b()) {
        v.push_back(as());
    }
    return v;
}
bool
Variant::isValid() const {
    return p->valid;
}
<|endoftext|>