<commit_before>// Copyright (c) 2012-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <bloom.h>

#include <hash.h>
#include <primitives/transaction.h>
#include <random.h>
#include <script/script.h>
#include <script/standard.h>
#include <span.h>
#include <streams.h>

#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <limits>
#include <vector>

static constexpr double LN2SQUARED = 0.4804530139182014246671025263266649717305529515945455;
static constexpr double LN2 = 0.6931471805599453094172321214581765680755001343602552;

CBloomFilter::CBloomFilter(const unsigned int nElements, const double nFPRate, const unsigned int nTweakIn, unsigned char nFlagsIn) :
    /**
     * The ideal size for a bloom filter with a given number of elements and false positive rate is:
     * - nElements * log(fp rate) / ln(2)^2
     * We ignore filter parameters which will create a bloom filter larger than the protocol limits
     */
    vData(std::min((unsigned int)(-1  / LN2SQUARED * nElements * log(nFPRate)), MAX_BLOOM_FILTER_SIZE * 8) / 8),
    /**
     * The ideal number of hash functions is filter size * ln(2) / number of elements
     * Again, we ignore filter parameters which will create a bloom filter with more hash functions than the protocol limits
     * See https://en.wikipedia.org/wiki/Bloom_filter for an explanation of these formulas
     */
    nHashFuncs(std::min((unsigned int)(vData.size() * 8 / nElements * LN2), MAX_HASH_FUNCS)),
    nTweak(nTweakIn),
    nFlags(nFlagsIn)
{
}

inline unsigned int CBloomFilter::Hash(unsigned int nHashNum, Span<const unsigned char> vDataToHash) const
{
    // 0xFBA4C795 chosen as it guarantees a reasonable bit difference between nHashNum values.
    return MurmurHash3(nHashNum * 0xFBA4C795 + nTweak, vDataToHash) % (vData.size() * 8);
}

void CBloomFilter::insert(Span<const unsigned char> vKey)
{
    if (vData.empty()) // Avoid divide-by-zero (CVE-2013-5700)
        return;
    for (unsigned int i = 0; i < nHashFuncs; i++)
    {
        unsigned int nIndex = Hash(i, vKey);
        // Sets bit nIndex of vData
        vData[nIndex >> 3] |= (1 << (7 & nIndex));
    }
}

void CBloomFilter::insert(const COutPoint& outpoint)
{
    CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
    stream << outpoint;
    insert(stream);
}

bool CBloomFilter::contains(Span<const unsigned char> vKey) const
{
    if (vData.empty()) // Avoid divide-by-zero (CVE-2013-5700)
        return true;
    for (unsigned int i = 0; i < nHashFuncs; i++)
    {
        unsigned int nIndex = Hash(i, vKey);
        // Checks bit nIndex of vData
        if (!(vData[nIndex >> 3] & (1 << (7 & nIndex))))
            return false;
    }
    return true;
}

bool CBloomFilter::contains(const COutPoint& outpoint) const
{
    CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
    stream << outpoint;
    return contains(MakeUCharSpan(stream));
}

bool CBloomFilter::IsWithinSizeConstraints() const
{
    return vData.size() <= MAX_BLOOM_FILTER_SIZE && nHashFuncs <= MAX_HASH_FUNCS;
}

bool CBloomFilter::IsRelevantAndUpdate(const CTransaction& tx)
{
    bool fFound = false;
    // Match if the filter contains the hash of tx
    //  for finding tx when they appear in a block
    if (vData.empty()) // zero-size = "match-all" filter
        return true;
    const uint256& hash = tx.GetHash();
    if (contains(hash))
        fFound = true;

    for (unsigned int i = 0; i < tx.vout.size(); i++)
    {
        const CTxOut& txout = tx.vout[i];
        // Match if the filter contains any arbitrary script data element in any scriptPubKey in tx
        // If this matches, also add the specific output that was matched.
        // This means clients don't have to update the filter themselves when a new relevant tx
        // is discovered in order to find spending transactions, which avoids round-tripping and race conditions.
        CScript::const_iterator pc = txout.scriptPubKey.begin();
        std::vector<unsigned char> data;
        while (pc < txout.scriptPubKey.end())
        {
            opcodetype opcode;
            if (!txout.scriptPubKey.GetOp(pc, opcode, data))
                break;
            if (data.size() != 0 && contains(data))
            {
                fFound = true;
                if ((nFlags & BLOOM_UPDATE_MASK) == BLOOM_UPDATE_ALL)
                    insert(COutPoint(hash, i));
                else if ((nFlags & BLOOM_UPDATE_MASK) == BLOOM_UPDATE_P2PUBKEY_ONLY)
                {
                    std::vector<std::vector<unsigned char> > vSolutions;
                    TxoutType type = Solver(txout.scriptPubKey, vSolutions);
                    if (type == TxoutType::PUBKEY || type == TxoutType::MULTISIG) {
                        insert(COutPoint(hash, i));
                    }
                }
                break;
            }
        }
    }

    if (fFound)
        return true;

    for (const CTxIn& txin : tx.vin)
    {
        // Match if the filter contains an outpoint tx spends
        if (contains(txin.prevout))
            return true;

        // Match if the filter contains any arbitrary script data element in any scriptSig in tx
        CScript::const_iterator pc = txin.scriptSig.begin();
        std::vector<unsigned char> data;
        while (pc < txin.scriptSig.end())
        {
            opcodetype opcode;
            if (!txin.scriptSig.GetOp(pc, opcode, data))
                break;
            if (data.size() != 0 && contains(data))
                return true;
        }
    }

    return false;
}

CRollingBloomFilter::CRollingBloomFilter(const unsigned int nElements, const double fpRate)
{
    double logFpRate = log(fpRate);
    /* The optimal number of hash functions is log(fpRate) / log(0.5), but
     * restrict it to the range 1-50. */
    nHashFuncs = std::max(1, std::min((int)round(logFpRate / log(0.5)), 50));
    /* In this rolling bloom filter, we'll store between 2 and 3 generations of nElements / 2 entries. */
    nEntriesPerGeneration = (nElements + 1) / 2;
    uint32_t nMaxElements = nEntriesPerGeneration * 3;
    /* The maximum fpRate = pow(1.0 - exp(-nHashFuncs * nMaxElements / nFilterBits), nHashFuncs)
     * =>          pow(fpRate, 1.0 / nHashFuncs) = 1.0 - exp(-nHashFuncs * nMaxElements / nFilterBits)
     * =>          1.0 - pow(fpRate, 1.0 / nHashFuncs) = exp(-nHashFuncs * nMaxElements / nFilterBits)
     * =>          log(1.0 - pow(fpRate, 1.0 / nHashFuncs)) = -nHashFuncs * nMaxElements / nFilterBits
     * =>          nFilterBits = -nHashFuncs * nMaxElements / log(1.0 - pow(fpRate, 1.0 / nHashFuncs))
     * =>          nFilterBits = -nHashFuncs * nMaxElements / log(1.0 - exp(logFpRate / nHashFuncs))
     */
    uint32_t nFilterBits = (uint32_t)ceil(-1.0 * nHashFuncs * nMaxElements / log(1.0 - exp(logFpRate / nHashFuncs)));
    data.clear();
    /* For each data element we need to store 2 bits. If both bits are 0, the
     * bit is treated as unset. If the bits are (01), (10), or (11), the bit is
     * treated as set in generation 1, 2, or 3 respectively.
     * These bits are stored in separate integers: position P corresponds to bit
     * (P & 63) of the integers data[(P >> 6) * 2] and data[(P >> 6) * 2 + 1]. */
    data.resize(((nFilterBits + 63) / 64) << 1);
    reset();
}

/* Similar to CBloomFilter::Hash */
static inline uint32_t RollingBloomHash(unsigned int nHashNum, uint32_t nTweak, Span<const unsigned char> vDataToHash)
{
    return MurmurHash3(nHashNum * 0xFBA4C795 + nTweak, vDataToHash);
}

// A replacement for x % n. This assumes that x and n are 32bit integers, and x is a uniformly random distributed 32bit value
// which should be the case for a good hash.
// See https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/
static inline uint32_t FastMod(uint32_t x, size_t n) {
    return ((uint64_t)x * (uint64_t)n) >> 32;
}

void CRollingBloomFilter::insert(Span<const unsigned char> vKey)
{
    if (nEntriesThisGeneration == nEntriesPerGeneration) {
        nEntriesThisGeneration = 0;
        nGeneration++;
        if (nGeneration == 4) {
            nGeneration = 1;
        }
        uint64_t nGenerationMask1 = 0 - (uint64_t)(nGeneration & 1);
        uint64_t nGenerationMask2 = 0 - (uint64_t)(nGeneration >> 1);
        /* Wipe old entries that used this generation number. */
        for (uint32_t p = 0; p < data.size(); p += 2) {
            uint64_t p1 = data[p], p2 = data[p + 1];
            uint64_t mask = (p1 ^ nGenerationMask1) | (p2 ^ nGenerationMask2);
            data[p] = p1 & mask;
            data[p + 1] = p2 & mask;
        }
    }
    nEntriesThisGeneration++;

    for (int n = 0; n < nHashFuncs; n++) {
        uint32_t h = RollingBloomHash(n, nTweak, vKey);
        int bit = h & 0x3F;
        /* FastMod works with the upper bits of h, so it is safe to ignore that the lower bits of h are already used for bit. */
        uint32_t pos = FastMod(h, data.size());
        /* The lowest bit of pos is ignored, and set to zero for the first bit, and to one for the second. */
        data[pos & ~1] = (data[pos & ~1] & ~(((uint64_t)1) << bit)) | ((uint64_t)(nGeneration & 1)) << bit;
        data[pos | 1] = (data[pos | 1] & ~(((uint64_t)1) << bit)) | ((uint64_t)(nGeneration >> 1)) << bit;
    }
}

bool CRollingBloomFilter::contains(Span<const unsigned char> vKey) const
{
    for (int n = 0; n < nHashFuncs; n++) {
        uint32_t h = RollingBloomHash(n, nTweak, vKey);
        int bit = h & 0x3F;
        uint32_t pos = FastMod(h, data.size());
        /* If the relevant bit is not set in either data[pos & ~1] or data[pos | 1], the filter does not contain vKey */
        if (!(((data[pos & ~1] | data[pos | 1]) >> bit) & 1)) {
            return false;
        }
    }
    return true;
}

void CRollingBloomFilter::reset()
{
    nTweak = GetRand(std::numeric_limits<unsigned int>::max());
    nEntriesThisGeneration = 0;
    nGeneration = 1;
    std::fill(data.begin(), data.end(), 0);
}
<commit_msg>refactor: Remove unused MakeUCharSpan<commit_after>// Copyright (c) 2012-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <bloom.h>

#include <hash.h>
#include <primitives/transaction.h>
#include <random.h>
#include <script/script.h>
#include <script/standard.h>
#include <span.h>
#include <streams.h>

#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <limits>
#include <vector>

static constexpr double LN2SQUARED = 0.4804530139182014246671025263266649717305529515945455;
static constexpr double LN2 = 0.6931471805599453094172321214581765680755001343602552;

CBloomFilter::CBloomFilter(const unsigned int nElements, const double nFPRate, const unsigned int nTweakIn, unsigned char nFlagsIn) :
    /**
     * The ideal size for a bloom filter with a given number of elements and false positive rate is:
     * - nElements * log(fp rate) / ln(2)^2
     * We ignore filter parameters which will create a bloom filter larger than the protocol limits
     */
    vData(std::min((unsigned int)(-1  / LN2SQUARED * nElements * log(nFPRate)), MAX_BLOOM_FILTER_SIZE * 8) / 8),
    /**
     * The ideal number of hash functions is filter size * ln(2) / number of elements
     * Again, we ignore filter parameters which will create a bloom filter with more hash functions than the protocol limits
     * See https://en.wikipedia.org/wiki/Bloom_filter for an explanation of these formulas
     */
    nHashFuncs(std::min((unsigned int)(vData.size() * 8 / nElements * LN2), MAX_HASH_FUNCS)),
    nTweak(nTweakIn),
    nFlags(nFlagsIn)
{
}

inline unsigned int CBloomFilter::Hash(unsigned int nHashNum, Span<const unsigned char> vDataToHash) const
{
    // 0xFBA4C795 chosen as it guarantees a reasonable bit difference between nHashNum values.
    return MurmurHash3(nHashNum * 0xFBA4C795 + nTweak, vDataToHash) % (vData.size() * 8);
}

void CBloomFilter::insert(Span<const unsigned char> vKey)
{
    if (vData.empty()) // Avoid divide-by-zero (CVE-2013-5700)
        return;
    for (unsigned int i = 0; i < nHashFuncs; i++)
    {
        unsigned int nIndex = Hash(i, vKey);
        // Sets bit nIndex of vData
        vData[nIndex >> 3] |= (1 << (7 & nIndex));
    }
}

void CBloomFilter::insert(const COutPoint& outpoint)
{
    CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
    stream << outpoint;
    insert(stream);
}

bool CBloomFilter::contains(Span<const unsigned char> vKey) const
{
    if (vData.empty()) // Avoid divide-by-zero (CVE-2013-5700)
        return true;
    for (unsigned int i = 0; i < nHashFuncs; i++)
    {
        unsigned int nIndex = Hash(i, vKey);
        // Checks bit nIndex of vData
        if (!(vData[nIndex >> 3] & (1 << (7 & nIndex))))
            return false;
    }
    return true;
}

bool CBloomFilter::contains(const COutPoint& outpoint) const
{
    CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
    stream << outpoint;
    return contains(stream);
}

bool CBloomFilter::IsWithinSizeConstraints() const
{
    return vData.size() <= MAX_BLOOM_FILTER_SIZE && nHashFuncs <= MAX_HASH_FUNCS;
}

bool CBloomFilter::IsRelevantAndUpdate(const CTransaction& tx)
{
    bool fFound = false;
    // Match if the filter contains the hash of tx
    //  for finding tx when they appear in a block
    if (vData.empty()) // zero-size = "match-all" filter
        return true;
    const uint256& hash = tx.GetHash();
    if (contains(hash))
        fFound = true;

    for (unsigned int i = 0; i < tx.vout.size(); i++)
    {
        const CTxOut& txout = tx.vout[i];
        // Match if the filter contains any arbitrary script data element in any scriptPubKey in tx
        // If this matches, also add the specific output that was matched.
        // This means clients don't have to update the filter themselves when a new relevant tx
        // is discovered in order to find spending transactions, which avoids round-tripping and race conditions.
        CScript::const_iterator pc = txout.scriptPubKey.begin();
        std::vector<unsigned char> data;
        while (pc < txout.scriptPubKey.end())
        {
            opcodetype opcode;
            if (!txout.scriptPubKey.GetOp(pc, opcode, data))
                break;
            if (data.size() != 0 && contains(data))
            {
                fFound = true;
                if ((nFlags & BLOOM_UPDATE_MASK) == BLOOM_UPDATE_ALL)
                    insert(COutPoint(hash, i));
                else if ((nFlags & BLOOM_UPDATE_MASK) == BLOOM_UPDATE_P2PUBKEY_ONLY)
                {
                    std::vector<std::vector<unsigned char> > vSolutions;
                    TxoutType type = Solver(txout.scriptPubKey, vSolutions);
                    if (type == TxoutType::PUBKEY || type == TxoutType::MULTISIG) {
                        insert(COutPoint(hash, i));
                    }
                }
                break;
            }
        }
    }

    if (fFound)
        return true;

    for (const CTxIn& txin : tx.vin)
    {
        // Match if the filter contains an outpoint tx spends
        if (contains(txin.prevout))
            return true;

        // Match if the filter contains any arbitrary script data element in any scriptSig in tx
        CScript::const_iterator pc = txin.scriptSig.begin();
        std::vector<unsigned char> data;
        while (pc < txin.scriptSig.end())
        {
            opcodetype opcode;
            if (!txin.scriptSig.GetOp(pc, opcode, data))
                break;
            if (data.size() != 0 && contains(data))
                return true;
        }
    }

    return false;
}

CRollingBloomFilter::CRollingBloomFilter(const unsigned int nElements, const double fpRate)
{
    double logFpRate = log(fpRate);
    /* The optimal number of hash functions is log(fpRate) / log(0.5), but
     * restrict it to the range 1-50. */
    nHashFuncs = std::max(1, std::min((int)round(logFpRate / log(0.5)), 50));
    /* In this rolling bloom filter, we'll store between 2 and 3 generations of nElements / 2 entries. */
    nEntriesPerGeneration = (nElements + 1) / 2;
    uint32_t nMaxElements = nEntriesPerGeneration * 3;
    /* The maximum fpRate = pow(1.0 - exp(-nHashFuncs * nMaxElements / nFilterBits), nHashFuncs)
     * =>          pow(fpRate, 1.0 / nHashFuncs) = 1.0 - exp(-nHashFuncs * nMaxElements / nFilterBits)
     * =>          1.0 - pow(fpRate, 1.0 / nHashFuncs) = exp(-nHashFuncs * nMaxElements / nFilterBits)
     * =>          log(1.0 - pow(fpRate, 1.0 / nHashFuncs)) = -nHashFuncs * nMaxElements / nFilterBits
     * =>          nFilterBits = -nHashFuncs * nMaxElements / log(1.0 - pow(fpRate, 1.0 / nHashFuncs))
     * =>          nFilterBits = -nHashFuncs * nMaxElements / log(1.0 - exp(logFpRate / nHashFuncs))
     */
    uint32_t nFilterBits = (uint32_t)ceil(-1.0 * nHashFuncs * nMaxElements / log(1.0 - exp(logFpRate / nHashFuncs)));
    data.clear();
    /* For each data element we need to store 2 bits. If both bits are 0, the
     * bit is treated as unset. If the bits are (01), (10), or (11), the bit is
     * treated as set in generation 1, 2, or 3 respectively.
     * These bits are stored in separate integers: position P corresponds to bit
     * (P & 63) of the integers data[(P >> 6) * 2] and data[(P >> 6) * 2 + 1]. */
    data.resize(((nFilterBits + 63) / 64) << 1);
    reset();
}

/* Similar to CBloomFilter::Hash */
static inline uint32_t RollingBloomHash(unsigned int nHashNum, uint32_t nTweak, Span<const unsigned char> vDataToHash)
{
    return MurmurHash3(nHashNum * 0xFBA4C795 + nTweak, vDataToHash);
}

// A replacement for x % n. This assumes that x and n are 32bit integers, and x is a uniformly random distributed 32bit value
// which should be the case for a good hash.
// See https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/
static inline uint32_t FastMod(uint32_t x, size_t n) {
    return ((uint64_t)x * (uint64_t)n) >> 32;
}

void CRollingBloomFilter::insert(Span<const unsigned char> vKey)
{
    if (nEntriesThisGeneration == nEntriesPerGeneration) {
        nEntriesThisGeneration = 0;
        nGeneration++;
        if (nGeneration == 4) {
            nGeneration = 1;
        }
        uint64_t nGenerationMask1 = 0 - (uint64_t)(nGeneration & 1);
        uint64_t nGenerationMask2 = 0 - (uint64_t)(nGeneration >> 1);
        /* Wipe old entries that used this generation number. */
        for (uint32_t p = 0; p < data.size(); p += 2) {
            uint64_t p1 = data[p], p2 = data[p + 1];
            uint64_t mask = (p1 ^ nGenerationMask1) | (p2 ^ nGenerationMask2);
            data[p] = p1 & mask;
            data[p + 1] = p2 & mask;
        }
    }
    nEntriesThisGeneration++;

    for (int n = 0; n < nHashFuncs; n++) {
        uint32_t h = RollingBloomHash(n, nTweak, vKey);
        int bit = h & 0x3F;
        /* FastMod works with the upper bits of h, so it is safe to ignore that the lower bits of h are already used for bit. */
        uint32_t pos = FastMod(h, data.size());
        /* The lowest bit of pos is ignored, and set to zero for the first bit, and to one for the second. */
        data[pos & ~1] = (data[pos & ~1] & ~(((uint64_t)1) << bit)) | ((uint64_t)(nGeneration & 1)) << bit;
        data[pos | 1] = (data[pos | 1] & ~(((uint64_t)1) << bit)) | ((uint64_t)(nGeneration >> 1)) << bit;
    }
}

bool CRollingBloomFilter::contains(Span<const unsigned char> vKey) const
{
    for (int n = 0; n < nHashFuncs; n++) {
        uint32_t h = RollingBloomHash(n, nTweak, vKey);
        int bit = h & 0x3F;
        uint32_t pos = FastMod(h, data.size());
        /* If the relevant bit is not set in either data[pos & ~1] or data[pos | 1], the filter does not contain vKey */
        if (!(((data[pos & ~1] | data[pos | 1]) >> bit) & 1)) {
            return false;
        }
    }
    return true;
}

void CRollingBloomFilter::reset()
{
    nTweak = GetRand(std::numeric_limits<unsigned int>::max());
    nEntriesThisGeneration = 0;
    nGeneration = 1;
    std::fill(data.begin(), data.end(), 0);
}
<|endoftext|>


<commit_before>// Copyright 2015 Mitchell Kember. Subject to the MIT License.

#include "sentence.hpp"

#include <algorithm>
#include <cassert>

// =============================================================================
//            Logical
// =============================================================================

std::ostream& operator<<(std::ostream& stream, const Sentence& s) {
	return s.print(stream);
}

// =============================================================================
//            Logical
// =============================================================================

Sentence* Logical::clone() const {
	return new Logical(_type, _a->clone(), _b->clone());
}

Sentence::Value Logical::value() const {
	Value va = _a->value();
	Value vb = _b->value();
	if (va == MU || vb == MU) {
		return MU;
	}
	switch(_type) {
	case AND:
		return static_cast<Value>(va && vb);
	case OR:
		return static_cast<Value>(va || vb);
	case IMPLIES:
		return static_cast<Value>(!va || vb);
	case IFF:
		return static_cast<Value>(va == vb);
	}
}

void Logical::negate() {
	switch (_type) {
	case AND:
		_type = OR;
		_a->negate();
		_b->negate();
		break;
	case OR:
		_type = AND;
		_a->negate();
		_b->negate();
		break;
	case IMPLIES:
		_type = AND;
		_b->negate();
		break;
	case IFF:
		expandIff();
		negate();
		break;
	}
}

std::ostream& Logical::print(std::ostream& s) const {
	s << '(';
	switch (_type) {
	case AND: s << "and"; break;
	case OR: s << "or"; break;
	case IMPLIES: s << "=>"; break;
	case IFF: s << "iff"; break;
	}
	s << ' ';
	_a->print(s);
	s << ' ';
	_b->print(s);
	return s << ')';
}

void Logical::converse() {
	assert(_type == IMPLIES);
	std::swap(_a, _b);
}

void Logical::contrapositive() {
	converse();
	_a->negate();
	_b->negate();
}

void Logical::expandIff() {
	assert(_type == IFF);
	_type = AND;
	Logical* fwd = new Logical(IMPLIES, _a, _b);
	Logical* bwd = new Logical(IMPLIES, _a->clone(), _b->clone());
	_a = fwd;
	_b = bwd;
}

int Logical::getType(const std::string& s) {
	if (s == "and") return AND;
	if (s == "or") return OR;
	if (s == "=>") return IMPLIES;
	if (s == "iff") return IFF;
	return -1;
}

// =============================================================================
//            Relation
// =============================================================================

Sentence* Relation::clone() const {
	return new Relation(_type, _a->clone(), _b->clone());
}

Sentence::Value Relation::value() const {
	return Sentence::MU;
}

void Relation::negate() {
	switch (_type) {
	case EQ: _type = NEQ; break;
	case NEQ: _type = EQ; break;
	case LT: _type = GTE; break;
	case GT: _type = LTE; break;
	case LTE: _type = GT; break;
	case GTE: _type = LT; break;
	case IN: _type = NOTIN; break;
	case NOTIN: _type = IN; break;
	case SUBSET:
		expandSubset();
		negate();
		break;
	}
}

std::ostream& Relation::print(std::ostream& s) const {
	s << '(';
	switch (_type) {
	case EQ: s << '='; break;
	case NEQ: s << "!="; break;
	case LT: s << '<'; break;
	case GT: s << '>'; break;
	case LTE: s << "<="; break;
	case GTE: s << ">="; break;
	case IN: s << "in"; break;
	case NOTIN: s << "notin"; break;
	case SUBSET: s << "subset"; break;
	}
	s << ' ';
	_a->print(s);
	s << ' ';
	_b->print(s);
	return s << ')';
}

Sentence* Relation::expandSubset() {
	assert(_type == SUBSET);
	Symbol* var = new Symbol('x');
	return new Quantified(
		Quantified::FORALL,
		var,
		dynamic_cast<Set*>(_a->clone()),
		new Relation(Relation::IN, var->cloneSelf(), _b->clone())
	);
}

int Relation::getType(const std::string& s) {
	if (s == "=") return EQ;
	if (s == "!=") return NEQ;
	if (s == "<") return LT;
	if (s == ">") return GT;
	if (s == "<=") return LTE;
	if (s == ">=") return GTE;
	if (s == "in") return IN;
	if (s == "notin") return NOTIN;
	if (s == "subset") return SUBSET;
	return -1;
}

// =============================================================================
//            Quantified
// =============================================================================

Quantified::Quantified(Type t, Symbol* var, Set* domain, Sentence* body)
	: _type(t), _var(var) {
	_body = new Logical(
		Logical::IMPLIES,
		new Relation(Relation::IN, var->clone(), domain),
		body
	);
}

Sentence* Quantified::clone() const {
	return new Quantified(_type, _var->cloneSelf(), _body->clone());
}

Sentence::Value Quantified::value() const {
	return Sentence::MU;
}

void Quantified::negate() {
	_type = static_cast<Type>(!_type);
	_body->negate();
}

std::ostream& Quantified::print(std::ostream& s) const {
	s << '(';
	switch (_type) {
	case FORALL: s << "forall"; break;
	case EXISTS: s << "exists"; break;
	}
	s << ' ';
	_var->print(s);
	s << ' ';
	_body->print(s);
	return s << ')';
}

int Quantified::getType(const std::string& s) {
	if (s == "forall") return FORALL;
	if (s == "exists") return EXISTS;
	return -1;
}
<commit_msg>Fix quantified constructor (use AND for exists)<commit_after>// Copyright 2015 Mitchell Kember. Subject to the MIT License.

#include "sentence.hpp"

#include <algorithm>
#include <cassert>

// =============================================================================
//            Logical
// =============================================================================

std::ostream& operator<<(std::ostream& stream, const Sentence& s) {
	return s.print(stream);
}

// =============================================================================
//            Logical
// =============================================================================

Sentence* Logical::clone() const {
	return new Logical(_type, _a->clone(), _b->clone());
}

Sentence::Value Logical::value() const {
	Value va = _a->value();
	Value vb = _b->value();
	if (va == MU || vb == MU) {
		return MU;
	}
	switch(_type) {
	case AND:
		return static_cast<Value>(va && vb);
	case OR:
		return static_cast<Value>(va || vb);
	case IMPLIES:
		return static_cast<Value>(!va || vb);
	case IFF:
		return static_cast<Value>(va == vb);
	}
}

void Logical::negate() {
	switch (_type) {
	case AND:
		_type = OR;
		_a->negate();
		_b->negate();
		break;
	case OR:
		_type = AND;
		_a->negate();
		_b->negate();
		break;
	case IMPLIES:
		_type = AND;
		_b->negate();
		break;
	case IFF:
		expandIff();
		negate();
		break;
	}
}

std::ostream& Logical::print(std::ostream& s) const {
	s << '(';
	switch (_type) {
	case AND: s << "and"; break;
	case OR: s << "or"; break;
	case IMPLIES: s << "=>"; break;
	case IFF: s << "iff"; break;
	}
	s << ' ';
	_a->print(s);
	s << ' ';
	_b->print(s);
	return s << ')';
}

void Logical::converse() {
	assert(_type == IMPLIES);
	std::swap(_a, _b);
}

void Logical::contrapositive() {
	converse();
	_a->negate();
	_b->negate();
}

void Logical::expandIff() {
	assert(_type == IFF);
	_type = AND;
	Logical* fwd = new Logical(IMPLIES, _a, _b);
	Logical* bwd = new Logical(IMPLIES, _a->clone(), _b->clone());
	_a = fwd;
	_b = bwd;
}

int Logical::getType(const std::string& s) {
	if (s == "and") return AND;
	if (s == "or") return OR;
	if (s == "=>") return IMPLIES;
	if (s == "iff") return IFF;
	return -1;
}

// =============================================================================
//            Relation
// =============================================================================

Sentence* Relation::clone() const {
	return new Relation(_type, _a->clone(), _b->clone());
}

Sentence::Value Relation::value() const {
	return Sentence::MU;
}

void Relation::negate() {
	switch (_type) {
	case EQ: _type = NEQ; break;
	case NEQ: _type = EQ; break;
	case LT: _type = GTE; break;
	case GT: _type = LTE; break;
	case LTE: _type = GT; break;
	case GTE: _type = LT; break;
	case IN: _type = NOTIN; break;
	case NOTIN: _type = IN; break;
	case SUBSET:
		expandSubset();
		negate();
		break;
	}
}

std::ostream& Relation::print(std::ostream& s) const {
	s << '(';
	switch (_type) {
	case EQ: s << '='; break;
	case NEQ: s << "!="; break;
	case LT: s << '<'; break;
	case GT: s << '>'; break;
	case LTE: s << "<="; break;
	case GTE: s << ">="; break;
	case IN: s << "in"; break;
	case NOTIN: s << "notin"; break;
	case SUBSET: s << "subset"; break;
	}
	s << ' ';
	_a->print(s);
	s << ' ';
	_b->print(s);
	return s << ')';
}

Sentence* Relation::expandSubset() {
	assert(_type == SUBSET);
	Symbol* var = new Symbol('x');
	return new Quantified(
		Quantified::FORALL,
		var,
		dynamic_cast<Set*>(_a->clone()),
		new Relation(Relation::IN, var->cloneSelf(), _b->clone())
	);
}

int Relation::getType(const std::string& s) {
	if (s == "=") return EQ;
	if (s == "!=") return NEQ;
	if (s == "<") return LT;
	if (s == ">") return GT;
	if (s == "<=") return LTE;
	if (s == ">=") return GTE;
	if (s == "in") return IN;
	if (s == "notin") return NOTIN;
	if (s == "subset") return SUBSET;
	return -1;
}

// =============================================================================
//            Quantified
// =============================================================================

Quantified::Quantified(Type t, Symbol* var, Set* domain, Sentence* body)
	: _type(t), _var(var) {
	_body = new Logical(
		(_type == FORALL) ? Logical::IMPLIES : Logical::AND,
		new Relation(Relation::IN, var->clone(), domain),
		body
	);
}

Sentence* Quantified::clone() const {
	return new Quantified(_type, _var->cloneSelf(), _body->clone());
}

Sentence::Value Quantified::value() const {
	return Sentence::MU;
}

void Quantified::negate() {
	_type = static_cast<Type>(!_type);
	_body->negate();
}

std::ostream& Quantified::print(std::ostream& s) const {
	s << '(';
	switch (_type) {
	case FORALL: s << "forall"; break;
	case EXISTS: s << "exists"; break;
	}
	s << ' ';
	_var->print(s);
	s << ' ';
	_body->print(s);
	return s << ')';
}

int Quantified::getType(const std::string& s) {
	if (s == "forall") return FORALL;
	if (s == "exists") return EXISTS;
	return -1;
}
<|endoftext|>


<commit_before>#include "buffer.hh"

#include "buffer_manager.hh"
#include "window.hh"
#include "assert.hh"
#include "utils.hh"
#include "hooks_manager.hh"
#include "context.hh"

#include <algorithm>

namespace Kakoune
{

template<typename T>
T clamp(T min, T max, T val)
{
    if (val < min)
        return min;
    if (val > max)
        return max;
    return val;
}

Buffer::Buffer(const std::string& name, Type type,
               const String& initial_content)
    : m_name(name), m_type(type),
      m_history(1), m_history_cursor(m_history.begin()),
      m_last_save_undo_index(0)
{
    BufferManager::instance().register_buffer(this);
    if (not initial_content.empty())
        apply_modification(Modification::make_insert(begin(), initial_content));

    if (type == Type::NewFile)
        GlobalHooksManager::instance().run_hook("BufCreate", name, Context(*this));
    else if (type == Type::File)
        GlobalHooksManager::instance().run_hook("BufOpen", name, Context(*this));
}

Buffer::~Buffer()
{
    m_windows.clear();
    assert(m_modification_listeners.empty());
}

BufferIterator Buffer::iterator_at(const BufferCoord& line_and_column) const
{
    if (m_lines.empty())
        return begin();

    BufferCoord clamped = clamp(line_and_column);
    return BufferIterator(*this, m_lines[clamped.line] + clamped.column);
}

BufferCoord Buffer::line_and_column_at(const BufferIterator& iterator) const
{
    BufferCoord result;
    if (not m_lines.empty())
    {
        result.line = line_at(iterator);
        result.column = iterator.m_position - m_lines[result.line];
    }
    return result;
}

BufferPos Buffer::line_at(const BufferIterator& iterator) const
{
    auto it = std::upper_bound(m_lines.begin(), m_lines.end(),
                               iterator.m_position);
    return it - m_lines.begin() - 1;
}

BufferSize Buffer::line_length(BufferPos line) const
{
    assert(not m_lines.empty());
    BufferPos end = (line < m_lines.size() - 1) ?
                    m_lines[line + 1] : m_content.size();
    return end - m_lines[line];
}

BufferCoord Buffer::clamp(const BufferCoord& line_and_column) const
{
    if (m_lines.empty())
        return BufferCoord();

    BufferCoord result(line_and_column.line, line_and_column.column);
    result.line = Kakoune::clamp<int>(0, m_lines.size() - 1, result.line);
    int max_col = std::max(0, line_length(result.line)-2);
    result.column = Kakoune::clamp<int>(0, max_col, result.column);
    return result;
}

BufferIterator Buffer::iterator_at_line_begin(const BufferIterator& iterator) const
{
    return BufferIterator(*this, m_lines[line_at(iterator)]);
}

BufferIterator Buffer::iterator_at_line_end(const BufferIterator& iterator) const
{
    BufferPos line = line_at(iterator) + 1;
    return line < m_lines.size() ? BufferIterator(*this, m_lines[line]) : end();
}

BufferIterator Buffer::begin() const
{
    return BufferIterator(*this, 0);
}

BufferIterator Buffer::end() const
{
    return BufferIterator(*this, length());
}

BufferSize Buffer::length() const
{
    return m_content.size();
}

BufferSize Buffer::line_count() const
{
    return m_lines.size();
}

String Buffer::string(const BufferIterator& begin, const BufferIterator& end) const
{
    return m_content.substr(begin.m_position, end - begin);
}

BufferChar Buffer::at(BufferPos position) const
{
    return m_content[position];
}

void Buffer::begin_undo_group()
{
    assert(m_current_undo_group.empty());
    m_history.erase(m_history_cursor, m_history.end());

    if (m_history.size() < m_last_save_undo_index)
        m_last_save_undo_index = -1;

    m_history_cursor = m_history.end();
}

void Buffer::end_undo_group()
{
    m_history.push_back(m_current_undo_group);
    m_history_cursor = m_history.end();

    m_current_undo_group.clear();
}

Modification Modification::inverse() const
{
    Type inverse_type;
    switch (type)
    {
    case Insert: inverse_type = Erase;  break;
    case Erase:  inverse_type = Insert; break;
    default: assert(false);
    }
    return Modification(inverse_type, position, content);
}

bool Buffer::undo()
{
    if (m_history_cursor == m_history.begin())
        return false;

    --m_history_cursor;

    for (const Modification& modification : reversed(*m_history_cursor))
        apply_modification(modification.inverse());
}

bool Buffer::redo()
{
    if (m_history_cursor == m_history.end())
        return false;

    for (const Modification& modification : *m_history_cursor)
        apply_modification(modification);

    ++m_history_cursor;
}

void Buffer::update_lines(const Modification& modification)
{
    size_t length = modification.content.length();
    const BufferPos pos = modification.position.m_position;
    const BufferPos endpos = pos + length;

    // find the first line beginning after modification position
    auto line_it = std::upper_bound(m_lines.begin(), m_lines.end(), pos);

    if (modification.type == Modification::Insert)
    {
        // all following lines advanced by length
        for (auto it = line_it; it != m_lines.end(); ++it)
            *it += length;

        std::vector<BufferPos> new_lines;
        // if we inserted at the end of the buffer, we may have created a new
        // line without inserting a '\n'
        if (endpos == m_content.size() and
            (pos == 0 or m_content[pos-1] == '\n'))
            new_lines.push_back(pos);

        // every \n inserted that was not the last buffer character created a
        // new line
        for (BufferPos i = pos; i < endpos and i + 1 < m_content.size(); ++i)
        {
            if (m_content[i] == '\n')
                new_lines.push_back(i + 1);
        }
        m_lines.insert(line_it, new_lines.begin(), new_lines.end());
    }
    else if (modification.type == Modification::Erase)
    {
        // find the first line beginning after endpos
        auto end = std::upper_bound(line_it, m_lines.end(), endpos);

        // all the lines until the end moved back by length
        for (auto it = end; it != m_lines.end(); ++it)
        {
            *it -= length;
            assert(m_content[(*it)-1] == '\n');
        }

        // if we erased from the beginning of a line until the end of
        // the buffer, that line also needs to be erased
        if (pos == m_content.size() and *(line_it-1) == pos)
            --line_it;
        m_lines.erase(line_it, end);
    }
    else
        assert(false);
}

void Buffer::apply_modification(const Modification& modification)
{
    switch (modification.type)
    {
    case Modification::Insert:
        m_content.insert(modification.position.m_position,
                         modification.content);
        break;
    case Modification::Erase:
    {
        size_t size = modification.content.size();
        assert(string(modification.position, modification.position + size)
               == modification.content);
        m_content.erase(modification.position.m_position, size);
        break;
    }
    default:
        assert(false);
    }
    update_lines(modification);
    for (auto listener : m_modification_listeners)
        listener->on_modification(modification);
}

void Buffer::modify(Modification&& modification)
{
    if (modification.content.empty())
        return;

    apply_modification(modification);
    m_current_undo_group.push_back(std::move(modification));
}

Window* Buffer::get_or_create_window()
{
    if (m_windows.empty())
        m_windows.push_front(std::unique_ptr<Window>(new Window(*this)));

    return m_windows.front().get();
}

void Buffer::delete_window(Window* window)
{
    assert(&window->buffer() == this);
    auto window_it = std::find(m_windows.begin(), m_windows.end(), window);
    assert(window_it != m_windows.end());
    m_windows.erase(window_it);
}

bool Buffer::is_modified() const
{
    size_t history_cursor_index = m_history_cursor - m_history.begin();
    return m_last_save_undo_index != history_cursor_index
           or not m_current_undo_group.empty();
}

void Buffer::notify_saved()
{
    size_t history_cursor_index = m_history_cursor - m_history.begin();
    m_last_save_undo_index = history_cursor_index;
}

void Buffer::register_modification_listener(ModificationListener* listener)
{
    assert(listener);
    assert(not contains(m_modification_listeners, listener));
    m_modification_listeners.push_back(listener);
}

void Buffer::unregister_modification_listener(ModificationListener* listener)
{
    assert(listener);
    auto it = std::find(m_modification_listeners.begin(),
                        m_modification_listeners.end(),
                        listener);
    assert(it != m_modification_listeners.end());
    m_modification_listeners.erase(it);
}

}
<commit_msg>buffer style fix<commit_after>#include "buffer.hh"

#include "buffer_manager.hh"
#include "window.hh"
#include "assert.hh"
#include "utils.hh"
#include "hooks_manager.hh"
#include "context.hh"

#include <algorithm>

namespace Kakoune
{

template<typename T>
T clamp(T min, T max, T val)
{
    if (val < min)
        return min;
    if (val > max)
        return max;
    return val;
}

Buffer::Buffer(const std::string& name, Type type,
               const String& initial_content)
    : m_name(name), m_type(type),
      m_history(1), m_history_cursor(m_history.begin()),
      m_last_save_undo_index(0)
{
    BufferManager::instance().register_buffer(this);
    if (not initial_content.empty())
        apply_modification(Modification::make_insert(begin(), initial_content));

    if (type == Type::NewFile)
        GlobalHooksManager::instance().run_hook("BufCreate", name, Context(*this));
    else if (type == Type::File)
        GlobalHooksManager::instance().run_hook("BufOpen", name, Context(*this));
}

Buffer::~Buffer()
{
    m_windows.clear();
    assert(m_modification_listeners.empty());
}

BufferIterator Buffer::iterator_at(const BufferCoord& line_and_column) const
{
    if (m_lines.empty())
        return begin();

    BufferCoord clamped = clamp(line_and_column);
    return BufferIterator(*this, m_lines[clamped.line] + clamped.column);
}

BufferCoord Buffer::line_and_column_at(const BufferIterator& iterator) const
{
    BufferCoord result;
    if (not m_lines.empty())
    {
        result.line = line_at(iterator);
        result.column = iterator.m_position - m_lines[result.line];
    }
    return result;
}

BufferPos Buffer::line_at(const BufferIterator& iterator) const
{
    auto it = std::upper_bound(m_lines.begin(), m_lines.end(),
                               iterator.m_position);
    return it - m_lines.begin() - 1;
}

BufferSize Buffer::line_length(BufferPos line) const
{
    assert(not m_lines.empty());
    BufferPos end = (line < m_lines.size() - 1) ?
                    m_lines[line + 1] : length();
    return end - m_lines[line];
}

BufferCoord Buffer::clamp(const BufferCoord& line_and_column) const
{
    if (m_lines.empty())
        return BufferCoord();

    BufferCoord result(line_and_column.line, line_and_column.column);
    result.line = Kakoune::clamp<int>(0, m_lines.size() - 1, result.line);
    int max_col = std::max(0, line_length(result.line)-2);
    result.column = Kakoune::clamp<int>(0, max_col, result.column);
    return result;
}

BufferIterator Buffer::iterator_at_line_begin(const BufferIterator& iterator) const
{
    return BufferIterator(*this, m_lines[line_at(iterator)]);
}

BufferIterator Buffer::iterator_at_line_end(const BufferIterator& iterator) const
{
    BufferPos line = line_at(iterator) + 1;
    return line < m_lines.size() ? BufferIterator(*this, m_lines[line]) : end();
}

BufferIterator Buffer::begin() const
{
    return BufferIterator(*this, 0);
}

BufferIterator Buffer::end() const
{
    return BufferIterator(*this, length());
}

BufferSize Buffer::length() const
{
    return m_content.size();
}

BufferSize Buffer::line_count() const
{
    return m_lines.size();
}

String Buffer::string(const BufferIterator& begin, const BufferIterator& end) const
{
    return m_content.substr(begin.m_position, end - begin);
}

BufferChar Buffer::at(BufferPos position) const
{
    return m_content[position];
}

void Buffer::begin_undo_group()
{
    assert(m_current_undo_group.empty());
    m_history.erase(m_history_cursor, m_history.end());

    if (m_history.size() < m_last_save_undo_index)
        m_last_save_undo_index = -1;

    m_history_cursor = m_history.end();
}

void Buffer::end_undo_group()
{
    m_history.push_back(m_current_undo_group);
    m_history_cursor = m_history.end();

    m_current_undo_group.clear();
}

Modification Modification::inverse() const
{
    Type inverse_type;
    switch (type)
    {
    case Insert: inverse_type = Erase;  break;
    case Erase:  inverse_type = Insert; break;
    default: assert(false);
    }
    return Modification(inverse_type, position, content);
}

bool Buffer::undo()
{
    if (m_history_cursor == m_history.begin())
        return false;

    --m_history_cursor;

    for (const Modification& modification : reversed(*m_history_cursor))
        apply_modification(modification.inverse());
}

bool Buffer::redo()
{
    if (m_history_cursor == m_history.end())
        return false;

    for (const Modification& modification : *m_history_cursor)
        apply_modification(modification);

    ++m_history_cursor;
}

void Buffer::update_lines(const Modification& modification)
{
    size_t length = modification.content.length();
    const BufferPos pos = modification.position.m_position;
    const BufferPos endpos = pos + length;

    // find the first line beginning after modification position
    auto line_it = std::upper_bound(m_lines.begin(), m_lines.end(), pos);

    if (modification.type == Modification::Insert)
    {
        // all following lines advanced by length
        for (auto it = line_it; it != m_lines.end(); ++it)
            *it += length;

        std::vector<BufferPos> new_lines;
        // if we inserted at the end of the buffer, we may have created a new
        // line without inserting a '\n'
        if (endpos == m_content.size() and
            (pos == 0 or m_content[pos-1] == '\n'))
            new_lines.push_back(pos);

        // every \n inserted that was not the last buffer character created a
        // new line
        for (BufferPos i = pos; i < endpos and i + 1 < m_content.size(); ++i)
        {
            if (m_content[i] == '\n')
                new_lines.push_back(i + 1);
        }
        m_lines.insert(line_it, new_lines.begin(), new_lines.end());
    }
    else if (modification.type == Modification::Erase)
    {
        // find the first line beginning after endpos
        auto end = std::upper_bound(line_it, m_lines.end(), endpos);

        // all the lines until the end moved back by length
        for (auto it = end; it != m_lines.end(); ++it)
        {
            *it -= length;
            assert(m_content[(*it)-1] == '\n');
        }

        // if we erased from the beginning of a line until the end of
        // the buffer, that line also needs to be erased
        if (pos == m_content.size() and *(line_it-1) == pos)
            --line_it;
        m_lines.erase(line_it, end);
    }
    else
        assert(false);
}

void Buffer::apply_modification(const Modification& modification)
{
    switch (modification.type)
    {
    case Modification::Insert:
        m_content.insert(modification.position.m_position,
                         modification.content);
        break;
    case Modification::Erase:
    {
        size_t size = modification.content.size();
        assert(string(modification.position, modification.position + size)
               == modification.content);
        m_content.erase(modification.position.m_position, size);
        break;
    }
    default:
        assert(false);
    }
    update_lines(modification);
    for (auto listener : m_modification_listeners)
        listener->on_modification(modification);
}

void Buffer::modify(Modification&& modification)
{
    if (modification.content.empty())
        return;

    apply_modification(modification);
    m_current_undo_group.push_back(std::move(modification));
}

Window* Buffer::get_or_create_window()
{
    if (m_windows.empty())
        m_windows.push_front(std::unique_ptr<Window>(new Window(*this)));

    return m_windows.front().get();
}

void Buffer::delete_window(Window* window)
{
    assert(&window->buffer() == this);
    auto window_it = std::find(m_windows.begin(), m_windows.end(), window);
    assert(window_it != m_windows.end());
    m_windows.erase(window_it);
}

bool Buffer::is_modified() const
{
    size_t history_cursor_index = m_history_cursor - m_history.begin();
    return m_last_save_undo_index != history_cursor_index
           or not m_current_undo_group.empty();
}

void Buffer::notify_saved()
{
    size_t history_cursor_index = m_history_cursor - m_history.begin();
    m_last_save_undo_index = history_cursor_index;
}

void Buffer::register_modification_listener(ModificationListener* listener)
{
    assert(listener);
    assert(not contains(m_modification_listeners, listener));
    m_modification_listeners.push_back(listener);
}

void Buffer::unregister_modification_listener(ModificationListener* listener)
{
    assert(listener);
    auto it = std::find(m_modification_listeners.begin(),
                        m_modification_listeners.end(),
                        listener);
    assert(it != m_modification_listeners.end());
    m_modification_listeners.erase(it);
}

}
<|endoftext|>


<commit_before>//==================================================
// Copyright (c) 2015 Deividas Kazlauskas
//
// See the file license.txt for copying permission.
//==================================================

/*
 * =====================================================================================
 *
 *       Filename:  Range.hpp
 *
 *    Description:  Range class
 *
 *        Version:  1.0
 *        Created:  07/30/2014 06:01:51 PM
 *       Compiler:  gcc
 *
 *         Author:  David Kazlauskas (dk), david@templatious.org
 *
 * =====================================================================================
 */

#ifndef RANGE_KFIVLD23
#define RANGE_KFIVLD23

#include <utility>

#include <templatious/util/IteratorTagExtractor.hpp>
#include <templatious/CollectionAdapter.hpp>
#include <templatious/proxy/Picker.hpp>

namespace templatious {

TEMPLATIOUS_BOILERPLATE_EXCEPTION( RangeBeginMoreThanEndException,
    "Range beginning cannot be greater than end.");

template <class T, template <class> class StoragePolicy>
struct Range {

    template <class I>
    struct PIterator;

    typedef typename adapters::CollectionAdapter<T> Ad;
    typedef PIterator<typename Ad::Iterator> Iterator;
    typedef PIterator<typename Ad::ConstIterator> ConstIterator;
    typedef detail::IsProxy<T> ProxUtil;
    typedef typename ProxUtil::ICollection ICollection;
    typedef Range<T,StoragePolicy> ThisRange;

    static const bool proxy_inside = ProxUtil::val;
    static const bool random_access_iterator = ProxUtil::random_access_iterator;
    static const bool floating_iterator = Ad::floating_iterator;

    static_assert(Ad::is_valid,"Adapter is invalid.");

    typedef typename StoragePolicy<T>::Container Ref;

    template <class V>
    friend struct detail::IsProxy;

#ifndef TEMPLATIOUS_TESTING
private:
#endif

    Ref _c;
    Iterator _b;
    Iterator _e;
    bool _cleared;

    void assertUncleared() const {
        if (_cleared) {
            throw detail::ProxyClearedUsageException();
        }
    }

    void tagCleared() {
        _cleared = true;
    }

#ifndef TEMPLATIOUS_TESTING
public:
#endif

    template <class V>
    Range(V&& v,const Iterator& b,const Iterator& e) :
        _c(std::forward<V>(v)), _b(b), _e(e), _cleared(false)
    { }

    template <class V>
    Range(V&& v,const Iterator& b) :
        _c(std::forward<V>(v)), _b(b),
        _e(_c.getRef()), _cleared(false) {}

    Range(ThisRange&& r) :
        _c(r._c.cpy()),
        _b(r._b),
        _e(r._e),
        _cleared(r._cleared)
    { }

    Iterator begin() {
        assertUncleared();
        return _b;
    }

    Iterator end() {
        assertUncleared();
        return _e;
    }

    ConstIterator cbegin() const {
        assertUncleared();
        return ConstIterator(
            ProxUtil::const_iter_cast(_b._i)
        );
    }

    ConstIterator cend() const {
        assertUncleared();
        return ConstIterator(
            ProxUtil::const_iter_cast(_e._i)
        );
    }

    Iterator iterAt(long n) {
        assertUncleared();
        if (!random_access_iterator) {
            Iterator res(_b);
            detail::naiveIterAdvance(res,_e,n);
            return res;
        } else {
            auto i = iterUnwrap(_b);
            auto e = iterUnwrap(_e);
            static const bool isNaiveAdvance =
                !util::IsRandomAccessIteratorTagged<decltype(i)>::value;
            typedef detail::AdvancePicker<isNaiveAdvance> A;
            long mul = ProxUtil::get_mul(_c.getRef());
            A::adv(i,e,mul * n);
            return Iterator(i);
        }
    }

    long size() const {
        if (!_cleared) {
            return -1;
        } else {
            return 0;
        }
    }

    template <class I>
    struct PIterator {
    private:
        I _i;

        template <class A1, template <class> class A2>
        friend struct Range;

        template <class V>
        friend struct detail::IsProxy;
    public:

        typedef PIterator<I> ThisIter;
        typedef decltype(*_i) IVal;

        PIterator(const I& i) : _i(i) {}

        PIterator& operator=(const PIterator& rhs) {
            _i = rhs._i;
            return *this;
        }

        ThisIter& operator++() {
            ++_i;
            return *this;
        }

        ThisIter& operator--() {
            --_i;
            return *this;
        }

        bool operator==(const ThisIter& rhs) const {
            return _i == rhs._i;
        }

        bool operator!=(const ThisIter& rhs) const {
            return !(*this == rhs);
        }

        IVal& operator*()
        {
            return *(this->_i);
        }

        const IVal& operator*() const
        {
            return *(this->_i);
        }

        auto operator->()
            -> decltype(&(this->_i))
        const {
            return &(this->_i);
        }

        auto getInternal()
            -> decltype(ProxUtil::iter_unwrap(_i))
        {
            return ProxUtil::iter_unwrap(_i);
        }

    };

    void clear() {
        detail::clearRoutine<floating_iterator>(*this);
        tagCleared();
        ProxUtil::tag_cleared(_c.getRef());
        _b = _e;
    }

    auto getInternal()
        -> decltype(ProxUtil::unwrap(_c.getRef()))
    {
        return ProxUtil::unwrap(_c.getRef());
    }

    long getMul() const {
        return ProxUtil::get_mul(_c.cgetRef());
    }

    template <class V>
    static auto iterUnwrap(V&& v)
        -> decltype(ProxUtil::iter_unwrap(
            std::forward<V>(v)))
    {
        return ProxUtil::iter_unwrap(
            std::forward<V>(v)
        );
    }
};

namespace detail {

template <class T, template <class> class StoragePolicy>
struct IsProxy< Range< T, StoragePolicy > > {
    typedef IsProxy<T> Internal;
    typedef Range<T,StoragePolicy> ThisCol;
    typedef typename ThisCol::ConstIterator ConstIterator;
    static const bool val = true;
    static const bool random_access_iterator =
        IsProxy< T >::random_access_iterator;

    typedef adapters::CollectionAdapter<T> Ad;
    typedef typename Ad::ThisCol ICollection;
    typedef typename
        adapters::CollectionAdapter<ICollection> IAdapter;

    template <class C>
    static auto unwrap(C&& c)
        -> decltype(c.getInternal())&
    {
        return c.getInternal();
    }

    template <class C>
    static auto iter_unwrap(C&& c)
        -> decltype(c.getInternal())&
    {
        return c.getInternal();
    }

    typedef long Dist;
    template <class U>
    static Dist get_mul(U&& u) {
        return u.getMul();
    }

    template <class U>
    static void tag_cleared(U& u) {
        u.tagCleared();
    }

    template <class Iter>
    static auto const_iter_cast(Iter&& i)
     -> decltype(
        ConstIterator(
            Internal::const_iter_cast(i._i)
        )
     )
    {
        return ConstIterator(
            Internal::const_iter_cast(i._i)
        );
    }
};

}

namespace adapters {

template <class T, template <class> class StoragePolicy>
struct CollectionAdapter< Range<T, StoragePolicy> > {

    static const bool is_valid = true;

    typedef Range<T, StoragePolicy> ThisCol;
    typedef const ThisCol ConstCol;
    typedef typename ThisCol::Iterator Iterator;
    typedef typename ThisCol::ConstIterator ConstIterator;
    typedef typename ThisCol::Ad::ValueType ValueType;
    typedef typename ThisCol::Ad::ConstValueType ConstValueType;

    static const bool floating_iterator = ThisCol::Ad::floating_iterator;

    template <class C>
    static Iterator begin(C&& c) {
        return c.begin();
    }

    template <class C>
    static Iterator end(C&& c) {
        return c.end();
    }

    static ConstIterator cbegin(ConstCol& c) {
        return c.cbegin();
    }

    static ConstIterator cend(ConstCol& c) {
        return c.cend();
    }

    template <class C>
    static Iterator iterAt(C&& c,long i) {
        return c.iterAt(i);
    }

    template <class C,class V>
    static void insertAt(C&& c,Iterator i,V&& v) {
        static_assert(templatious::util::DummyResolver<C,false>::val,
            "Range proxy class is uninsertable.");
    }

    template <class C>
    static void erase(C&& c, Iterator i) {
        static_assert(templatious::util::DummyResolver<C,false>::val,
            "Range proxy class is unerasable.");
    }

    template <class C>
    static void erase(C&& c, Iterator beg, Iterator end) {
        static_assert(templatious::util::DummyResolver<C,false>::val,
            "Range proxy class is unerasable.");
    }

    template <class C>
    static void clear(C&& c) {
        c.clear();
    }

    template <class C>
    static long size(C&& c) {
        return c.size();
    }

};

}
}

#endif /* end of include guard: RANGE_KFIVLD23 */
<commit_msg>alt ctor fix<commit_after>//==================================================
// Copyright (c) 2015 Deividas Kazlauskas
//
// See the file license.txt for copying permission.
//==================================================

/*
 * =====================================================================================
 *
 *       Filename:  Range.hpp
 *
 *    Description:  Range class
 *
 *        Version:  1.0
 *        Created:  07/30/2014 06:01:51 PM
 *       Compiler:  gcc
 *
 *         Author:  David Kazlauskas (dk), david@templatious.org
 *
 * =====================================================================================
 */

#ifndef RANGE_KFIVLD23
#define RANGE_KFIVLD23

#include <utility>

#include <templatious/util/IteratorTagExtractor.hpp>
#include <templatious/CollectionAdapter.hpp>
#include <templatious/proxy/Picker.hpp>

namespace templatious {

TEMPLATIOUS_BOILERPLATE_EXCEPTION( RangeBeginMoreThanEndException,
    "Range beginning cannot be greater than end.");

template <class T, template <class> class StoragePolicy>
struct Range {

    template <class I>
    struct PIterator;

    typedef typename adapters::CollectionAdapter<T> Ad;
    typedef PIterator<typename Ad::Iterator> Iterator;
    typedef PIterator<typename Ad::ConstIterator> ConstIterator;
    typedef detail::IsProxy<T> ProxUtil;
    typedef typename ProxUtil::ICollection ICollection;
    typedef Range<T,StoragePolicy> ThisRange;

    static const bool proxy_inside = ProxUtil::val;
    static const bool random_access_iterator = ProxUtil::random_access_iterator;
    static const bool floating_iterator = Ad::floating_iterator;

    static_assert(Ad::is_valid,"Adapter is invalid.");

    typedef typename StoragePolicy<T>::Container Ref;

    template <class V>
    friend struct detail::IsProxy;

#ifndef TEMPLATIOUS_TESTING
private:
#endif

    Ref _c;
    Iterator _b;
    Iterator _e;
    bool _cleared;

    void assertUncleared() const {
        if (_cleared) {
            throw detail::ProxyClearedUsageException();
        }
    }

    void tagCleared() {
        _cleared = true;
    }

#ifndef TEMPLATIOUS_TESTING
public:
#endif

    template <class V>
    Range(V&& v,const Iterator& b,const Iterator& e) :
        _c(std::forward<V>(v)), _b(b), _e(e), _cleared(false)
    { }

    template <class V>
    Range(V&& v,const Iterator& b) :
        _c(std::forward<V>(v)), _b(b),
        _e(Ad::end(_c.getRef())), _cleared(false) {}

    Range(ThisRange&& r) :
        _c(r._c.cpy()),
        _b(r._b),
        _e(r._e),
        _cleared(r._cleared)
    { }

    Iterator begin() {
        assertUncleared();
        return _b;
    }

    Iterator end() {
        assertUncleared();
        return _e;
    }

    ConstIterator cbegin() const {
        assertUncleared();
        return ConstIterator(
            ProxUtil::const_iter_cast(_b._i)
        );
    }

    ConstIterator cend() const {
        assertUncleared();
        return ConstIterator(
            ProxUtil::const_iter_cast(_e._i)
        );
    }

    Iterator iterAt(long n) {
        assertUncleared();
        if (!random_access_iterator) {
            Iterator res(_b);
            detail::naiveIterAdvance(res,_e,n);
            return res;
        } else {
            auto i = iterUnwrap(_b);
            auto e = iterUnwrap(_e);
            static const bool isNaiveAdvance =
                !util::IsRandomAccessIteratorTagged<decltype(i)>::value;
            typedef detail::AdvancePicker<isNaiveAdvance> A;
            long mul = ProxUtil::get_mul(_c.getRef());
            A::adv(i,e,mul * n);
            return Iterator(i);
        }
    }

    long size() const {
        if (!_cleared) {
            return -1;
        } else {
            return 0;
        }
    }

    template <class I>
    struct PIterator {
    private:
        I _i;

        template <class A1, template <class> class A2>
        friend struct Range;

        template <class V>
        friend struct detail::IsProxy;
    public:

        typedef PIterator<I> ThisIter;
        typedef decltype(*_i) IVal;

        PIterator(const I& i) : _i(i) {}

        PIterator& operator=(const PIterator& rhs) {
            _i = rhs._i;
            return *this;
        }

        ThisIter& operator++() {
            ++_i;
            return *this;
        }

        ThisIter& operator--() {
            --_i;
            return *this;
        }

        bool operator==(const ThisIter& rhs) const {
            return _i == rhs._i;
        }

        bool operator!=(const ThisIter& rhs) const {
            return !(*this == rhs);
        }

        IVal& operator*()
        {
            return *(this->_i);
        }

        const IVal& operator*() const
        {
            return *(this->_i);
        }

        auto operator->()
            -> decltype(&(this->_i))
        const {
            return &(this->_i);
        }

        auto getInternal()
            -> decltype(ProxUtil::iter_unwrap(_i))
        {
            return ProxUtil::iter_unwrap(_i);
        }

    };

    void clear() {
        detail::clearRoutine<floating_iterator>(*this);
        tagCleared();
        ProxUtil::tag_cleared(_c.getRef());
        _b = _e;
    }

    auto getInternal()
        -> decltype(ProxUtil::unwrap(_c.getRef()))
    {
        return ProxUtil::unwrap(_c.getRef());
    }

    long getMul() const {
        return ProxUtil::get_mul(_c.cgetRef());
    }

    template <class V>
    static auto iterUnwrap(V&& v)
        -> decltype(ProxUtil::iter_unwrap(
            std::forward<V>(v)))
    {
        return ProxUtil::iter_unwrap(
            std::forward<V>(v)
        );
    }
};

namespace detail {

template <class T, template <class> class StoragePolicy>
struct IsProxy< Range< T, StoragePolicy > > {
    typedef IsProxy<T> Internal;
    typedef Range<T,StoragePolicy> ThisCol;
    typedef typename ThisCol::ConstIterator ConstIterator;
    static const bool val = true;
    static const bool random_access_iterator =
        IsProxy< T >::random_access_iterator;

    typedef adapters::CollectionAdapter<T> Ad;
    typedef typename Ad::ThisCol ICollection;
    typedef typename
        adapters::CollectionAdapter<ICollection> IAdapter;

    template <class C>
    static auto unwrap(C&& c)
        -> decltype(c.getInternal())&
    {
        return c.getInternal();
    }

    template <class C>
    static auto iter_unwrap(C&& c)
        -> decltype(c.getInternal())&
    {
        return c.getInternal();
    }

    typedef long Dist;
    template <class U>
    static Dist get_mul(U&& u) {
        return u.getMul();
    }

    template <class U>
    static void tag_cleared(U& u) {
        u.tagCleared();
    }

    template <class Iter>
    static auto const_iter_cast(Iter&& i)
     -> decltype(
        ConstIterator(
            Internal::const_iter_cast(i._i)
        )
     )
    {
        return ConstIterator(
            Internal::const_iter_cast(i._i)
        );
    }
};

}

namespace adapters {

template <class T, template <class> class StoragePolicy>
struct CollectionAdapter< Range<T, StoragePolicy> > {

    static const bool is_valid = true;

    typedef Range<T, StoragePolicy> ThisCol;
    typedef const ThisCol ConstCol;
    typedef typename ThisCol::Iterator Iterator;
    typedef typename ThisCol::ConstIterator ConstIterator;
    typedef typename ThisCol::Ad::ValueType ValueType;
    typedef typename ThisCol::Ad::ConstValueType ConstValueType;

    static const bool floating_iterator = ThisCol::Ad::floating_iterator;

    template <class C>
    static Iterator begin(C&& c) {
        return c.begin();
    }

    template <class C>
    static Iterator end(C&& c) {
        return c.end();
    }

    static ConstIterator cbegin(ConstCol& c) {
        return c.cbegin();
    }

    static ConstIterator cend(ConstCol& c) {
        return c.cend();
    }

    template <class C>
    static Iterator iterAt(C&& c,long i) {
        return c.iterAt(i);
    }

    template <class C,class V>
    static void insertAt(C&& c,Iterator i,V&& v) {
        static_assert(templatious::util::DummyResolver<C,false>::val,
            "Range proxy class is uninsertable.");
    }

    template <class C>
    static void erase(C&& c, Iterator i) {
        static_assert(templatious::util::DummyResolver<C,false>::val,
            "Range proxy class is unerasable.");
    }

    template <class C>
    static void erase(C&& c, Iterator beg, Iterator end) {
        static_assert(templatious::util::DummyResolver<C,false>::val,
            "Range proxy class is unerasable.");
    }

    template <class C>
    static void clear(C&& c) {
        c.clear();
    }

    template <class C>
    static long size(C&& c) {
        return c.size();
    }

};

}
}

#endif /* end of include guard: RANGE_KFIVLD23 */
<|endoftext|>


<commit_before>#pragma once

#include <iostream>

#include "acmacs-draw/surface.hh"
#include "chart.hh"

// ----------------------------------------------------------------------

class Tree;
class TreeDraw;
class HzSections;

// ----------------------------------------------------------------------

class MarkAntigenSettings
{
 public:
    inline MarkAntigenSettings(bool aShow = true, std::string aName = std::string())
        : show(aShow), name(aName), label(aName), scale(15), aspect(1), rotation(0), outline_width(1), label_line_width(0.1),
          fill_color("red"), outline_color("white"),
          label_color("black"), label_line_color("transparent"), label_offset{-5, 2}, label_size(0.5) {}

    bool show;
    std::string name, label;
    double scale, aspect, rotation, outline_width, label_line_width;
    Color fill_color, outline_color, label_color, label_line_color;
    Size label_offset;
    double label_size;

}; // class MarkAntigenSettings

// ----------------------------------------------------------------------

class AntigenicMapsDrawSettings
{
 public:
    inline AntigenicMapsDrawSettings()
        : layout("labelled_grid"), width(500), columns(3), gap(20),
          border_width(1), grid_line_width(0.5),
          border_color("black"), grid_line_color("grey63"), background_color("white"), // 0xFFFFF8
          point_scale(1), serum_scale(5), reference_antigen_scale(5), test_antigen_scale(3), vaccine_antigen_scale(15), tracked_antigen_scale(5),
          serum_outline_width(0.5), reference_antigen_outline_width(0.5), test_antigen_outline_width(0.5), vaccine_antigen_outline_width(0.5),
          sequenced_antigen_outline_width(0.5), tracked_antigen_outline_width(0.5),
          serum_outline_color("grey88"), reference_antigen_outline_color("grey88"), test_antigen_outline_color("grey88"),
          test_antigen_fill_color("grey88"), vaccine_antigen_outline_color("white"), sequenced_antigen_outline_color("white"), sequenced_antigen_fill_color("grey63"),
          tracked_antigen_outline_color("white"), tracked_antigen_colored_by_clade(false), tracked_antigen_color("green3"),
          reassortant_rotation(0.5 /* M_PI / 6.0 */), egg_antigen_aspect(0.75),
          show_tracked_sera(true), serum_circle_color("grey50"), tracked_serum_outline_color("black"), serum_circle_thickness(0.1), tracked_serum_outline_width(0.1),
          map_title_color("black"), map_title_offset{0.3, 0.4}, map_title_size(11),
          mapped_antigens_section_line_color("black"), mapped_antigens_section_line_width(1),
          mark_antigens{{true, "VT 14-002966-VIR SIAT1 (2014-06-29)"}}
        {}
    ~AntigenicMapsDrawSettings();

    std::string layout;
    double width;
    size_t columns;
    double gap;
    Transformation transformation;
    Viewport viewport;

    double border_width, grid_line_width;
    Color border_color, grid_line_color, background_color;

    double point_scale;
    double serum_scale, reference_antigen_scale, test_antigen_scale, vaccine_antigen_scale, tracked_antigen_scale;
    double serum_outline_width, reference_antigen_outline_width, test_antigen_outline_width, vaccine_antigen_outline_width, sequenced_antigen_outline_width, tracked_antigen_outline_width;
    Color serum_outline_color, reference_antigen_outline_color, test_antigen_outline_color, test_antigen_fill_color, vaccine_antigen_outline_color, sequenced_antigen_outline_color, sequenced_antigen_fill_color, tracked_antigen_outline_color;
    bool tracked_antigen_colored_by_clade;
    Color tracked_antigen_color;
    double reassortant_rotation, egg_antigen_aspect;
    bool show_tracked_sera;
    Color serum_circle_color, tracked_serum_outline_color;
    double serum_circle_thickness, tracked_serum_outline_width;
    Color map_title_color;
    Size map_title_offset;      // offset of the top left corner of the text in letter W fraction
    double map_title_size;
    Color mapped_antigens_section_line_color;
    double mapped_antigens_section_line_width;

    std::vector<MarkAntigenSettings> mark_antigens;

}; // class AntigenicMapsDrawSettings

// ----------------------------------------------------------------------

class DrawPoint
{
 public:
    inline DrawPoint() = default;
    inline DrawPoint(const DrawPoint&) = default;
    inline DrawPoint(DrawPoint&&) = default;
    inline virtual ~DrawPoint() = default;
    inline DrawPoint& operator=(const DrawPoint&) = default;
    virtual void draw(Surface& aSurface, const Point& aPoint, const PointStyle& aStyle, const AntigenicMapsDrawSettings& aSettings) const = 0;
    virtual size_t level() const = 0;
    virtual inline double aspect(const Point&, const PointStyle& aStyle, const AntigenicMapsDrawSettings&) const { return aStyle.aspect; }
    virtual inline double rotation(const Point& aPoint, const PointStyle& aStyle, const AntigenicMapsDrawSettings& aSettings) const { return aPoint.attributes.reassortant ? aSettings.reassortant_rotation : aStyle.rotation; }
    virtual inline Color fill_color(const Point&, const PointStyle& aStyle, const AntigenicMapsDrawSettings&) const { return aStyle.fill_color; }
    virtual inline Color outline_color(const Point&, const PointStyle& aStyle, const AntigenicMapsDrawSettings&) const { return aStyle.outline_color; }
};

class DrawSerum : public DrawPoint
{
 public:
    virtual void draw(Surface& aSurface, const Point& aPoint, const PointStyle& aStyle, const AntigenicMapsDrawSettings& aSettings) const;
    virtual inline size_t level() const { return 1; }
    virtual inline Color outline_color(const Point&, const PointStyle&, const AntigenicMapsDrawSettings& aSettings) const { return aSettings.serum_outline_color; }
    virtual inline double outline_width(const Point&, const PointStyle&, const AntigenicMapsDrawSettings& aSettings) const { return aSettings.serum_outline_width; }
};

class DrawAntigen : public DrawPoint
{
 public:
    virtual inline double aspect(const Point& aPoint, const PointStyle& aStyle, const AntigenicMapsDrawSettings& aSettings) const { return aPoint.attributes.egg ? aSettings.egg_antigen_aspect : aStyle.aspect; }
};

class DrawReferenceAntigen : public DrawAntigen
{
 public:
    virtual void draw(Surface& aSurface, const Point& aPoint, const PointStyle& aStyle, const AntigenicMapsDrawSettings& aSettings) const;
    virtual inline size_t level() const { return 2; }
};

class DrawTestAntigen : public DrawAntigen
{
 public:
    virtual void draw(Surface& aSurface, const Point& aPoint, const PointStyle& aStyle, const AntigenicMapsDrawSettings& aSettings) const;
    virtual inline size_t level() const { return 3; }
};

class DrawSequencedAntigen : public DrawAntigen
{
 public:
    virtual void draw(Surface& aSurface, const Point& aPoint, const PointStyle& aStyle, const AntigenicMapsDrawSettings& aSettings) const;
    virtual inline size_t level() const { return 4; }
};

class DrawTrackedAntigen : public DrawAntigen
{
 public:
    inline DrawTrackedAntigen(Color aFillColor = "pink") : mColor(aFillColor) {}

    virtual void draw(Surface& aSurface, const Point& aPoint, const PointStyle& aStyle, const AntigenicMapsDrawSettings& aSettings) const;
    virtual inline size_t level() const { return 5; }
    inline void color(Color aColor) { mColor = aColor; }

 private:
    Color mColor;
};

class DrawTrackedSerum : public DrawSerum
{
 public:
    inline DrawTrackedSerum(Color aOutlineColor = 0, double aOutlineWidth = 1) : mOutlineColor(aOutlineColor), mOutlineWidth(aOutlineWidth) {}

    virtual void draw(Surface& aSurface, const Point& aPoint, const PointStyle& aStyle, const AntigenicMapsDrawSettings& aSettings) const;
    virtual inline size_t level() const { return 6; }
    virtual inline Color outline_color(const Point& /*aPoint*/, const PointStyle& /*aStyle*/, const AntigenicMapsDrawSettings& /*aSettings*/) const { return mOutlineColor; }
    virtual double outline_width(const Point& /*aPoint*/, const PointStyle& /*aStyle*/, const AntigenicMapsDrawSettings& /*aSettings*/) const { return mOutlineWidth; }

 private:
    Color mOutlineColor;
    double mOutlineWidth;
};

class DrawVaccineAntigen : public DrawAntigen
{
 public:
    virtual void draw(Surface& aSurface, const Point& aPoint, const PointStyle& aStyle, const AntigenicMapsDrawSettings& aSettings) const;
    virtual inline size_t level() const { return 9; }
};

class DrawMarkedAntigen : public DrawAntigen
{
 public:
    inline DrawMarkedAntigen(const MarkAntigenSettings& aData) : mData(aData) {}

    virtual void draw(Surface& aSurface, const Point& aPoint, const PointStyle& aStyle, const AntigenicMapsDrawSettings& aSettings) const;
    virtual inline size_t level() const { return 7; }

 private:
    MarkAntigenSettings mData;
};

// ----------------------------------------------------------------------

class AntigenicMapsDraw;
class HzSection;
class MappedAntigensDraw;

class AntigenicMapsLayout
{
 public:
    inline AntigenicMapsLayout(AntigenicMapsDraw& aAntigenicMapsDraw) : mAntigenicMapsDraw(aAntigenicMapsDraw) {}
    virtual ~AntigenicMapsLayout();

    virtual void prepare();
    virtual void draw() = 0;

 protected:
    AntigenicMapsDraw& mAntigenicMapsDraw;
    Viewport mMapViewport;

    std::vector<const DrawPoint*> mDrawPoints;
    std::map<size_t, size_t> mSequencedAntigens; // antigen_no to section_no

    DrawSerum mDrawSerum;
    DrawReferenceAntigen mDrawReferenceAntigen;
    DrawTestAntigen mDrawTestAntigen;
    DrawSequencedAntigen mDrawSequencedAntigen;
    DrawTrackedAntigen mDrawTrackedAntigen;
    std::vector<DrawTrackedAntigen> mDrawTrackedAntigensColoredByClade;
    DrawVaccineAntigen mDrawVaccineAntigen;
    std::vector<DrawMarkedAntigen> mDrawMarkedAntigens;
    std::vector<DrawTrackedSerum> mDrawTrackedSera;

    virtual void find_sequenced_antigens();
    virtual void draw_points_reset();
    virtual void draw_chart(Surface& aSurface, size_t aSectionIndex);
    virtual void mark_tracked_sera(size_t aSectionIndex);
    virtual void draw_map_title(Surface& aSurface, size_t aSectionIndex);
    virtual void mark_tracked_antigens(size_t aSectionIndex);
    virtual void mark_marked_antigens();

      // tracked_antigens_colored_by_clade
      // tracked_sera

}; // class AntigenicMapsLayout

// ----------------------------------------------------------------------

class AntigenicMapsDraw
{
 public:
    inline AntigenicMapsDraw(Surface& aSurface, Tree& aTree, Chart& aChart, HzSections& aHzSections, MappedAntigensDraw& aMappedAntigensDraw, AntigenicMapsDrawSettings& aSettings)
        : mSurface(aSurface), mTree(aTree), mChart(aChart), mHzSections(aHzSections), mMappedAntigensDraw(aMappedAntigensDraw), mSettings(aSettings) {}

    void init_settings();
    void prepare();
    void draw();

    inline Surface& surface() { return mSurface; }
    inline const Tree& tree() const { return mTree; }
    inline const Chart& chart() const { return mChart; }
    inline const HzSections& hz_sections() const { return mHzSections; }
    inline MappedAntigensDraw& mapped_antigens_draw() { return mMappedAntigensDraw; }
    inline const AntigenicMapsDrawSettings& settings() const { return mSettings; }

 private:
    Surface& mSurface;
    Tree& mTree;
    Chart& mChart;
    HzSections& mHzSections;
    MappedAntigensDraw& mMappedAntigensDraw;
    AntigenicMapsDrawSettings& mSettings;
    std::unique_ptr<AntigenicMapsLayout> mLayout;

}; // class AntigenicMapsDraw

// ----------------------------------------------------------------------

class LabelledGrid : public AntigenicMapsLayout
{
 public:
    inline LabelledGrid(AntigenicMapsDraw& aAntigenicMapsDraw) : AntigenicMapsLayout(aAntigenicMapsDraw) {}

    virtual void prepare();
    virtual void draw();

 protected:
    virtual void draw_chart(Surface& aSurface, size_t aSectionIndex);
    virtual void draw_mapped_antigens_section(size_t aSectionIndex);

}; // class LabelledGrid

// ----------------------------------------------------------------------
/// Local Variables:
/// eval: (if (fboundp 'eu-rename-buffer) (eu-rename-buffer))
/// End:
<commit_msg>porting to the new surface system (from acmacs-draw)<commit_after>#pragma once

#include <iostream>

#include "acmacs-draw/surface.hh"
#include "chart.hh"

// ----------------------------------------------------------------------

class Tree;
class TreeDraw;
class HzSections;

// ----------------------------------------------------------------------

class MarkAntigenSettings
{
 public:
    inline MarkAntigenSettings(bool aShow = true, std::string aName = std::string())
        : show(aShow), name(aName), label(aName), scale(15), aspect(1), rotation(0), outline_width(1), label_line_width(0.1),
          fill_color("red"), outline_color("white"),
          label_color("black"), label_line_color("transparent"), label_offset{-2, 2}, label_size(9) {}

    bool show;
    std::string name, label;
    double scale, aspect, rotation, outline_width, label_line_width;
    Color fill_color, outline_color, label_color, label_line_color;
    Size label_offset;
    double label_size;

}; // class MarkAntigenSettings

// ----------------------------------------------------------------------

class AntigenicMapsDrawSettings
{
 public:
    inline AntigenicMapsDrawSettings()
        : layout("labelled_grid"), width(500), columns(3), gap(20),
          border_width(1), grid_line_width(0.5),
          border_color("black"), grid_line_color("grey63"), background_color("white"), // 0xFFFFF8
          point_scale(1), serum_scale(5), reference_antigen_scale(5), test_antigen_scale(3), vaccine_antigen_scale(15), tracked_antigen_scale(5),
          serum_outline_width(0.5), reference_antigen_outline_width(0.5), test_antigen_outline_width(0.5), vaccine_antigen_outline_width(0.5),
          sequenced_antigen_outline_width(0.5), tracked_antigen_outline_width(0.5),
          serum_outline_color("grey88"), reference_antigen_outline_color("grey88"), test_antigen_outline_color("grey88"),
          test_antigen_fill_color("grey88"), vaccine_antigen_outline_color("white"), sequenced_antigen_outline_color("white"), sequenced_antigen_fill_color("grey63"),
          tracked_antigen_outline_color("white"), tracked_antigen_colored_by_clade(false), tracked_antigen_color("green3"),
          reassortant_rotation(0.5 /* M_PI / 6.0 */), egg_antigen_aspect(0.75),
          show_tracked_sera(true), serum_circle_color("grey50"), tracked_serum_outline_color("black"), serum_circle_thickness(0.1), tracked_serum_outline_width(0.1),
          map_title_color("black"), map_title_offset{0.3, 0.4}, map_title_size(11),
          mapped_antigens_section_line_color("black"), mapped_antigens_section_line_width(1),
          mark_antigens{{true, "VT 14-002966-VIR SIAT1 (2014-06-29)"}}
        {}
    ~AntigenicMapsDrawSettings();

    std::string layout;
    double width;
    size_t columns;
    double gap;
    Transformation transformation;
    Viewport viewport;

    double border_width, grid_line_width;
    Color border_color, grid_line_color, background_color;

    double point_scale;
    double serum_scale, reference_antigen_scale, test_antigen_scale, vaccine_antigen_scale, tracked_antigen_scale;
    double serum_outline_width, reference_antigen_outline_width, test_antigen_outline_width, vaccine_antigen_outline_width, sequenced_antigen_outline_width, tracked_antigen_outline_width;
    Color serum_outline_color, reference_antigen_outline_color, test_antigen_outline_color, test_antigen_fill_color, vaccine_antigen_outline_color, sequenced_antigen_outline_color, sequenced_antigen_fill_color, tracked_antigen_outline_color;
    bool tracked_antigen_colored_by_clade;
    Color tracked_antigen_color;
    double reassortant_rotation, egg_antigen_aspect;
    bool show_tracked_sera;
    Color serum_circle_color, tracked_serum_outline_color;
    double serum_circle_thickness, tracked_serum_outline_width;
    Color map_title_color;
    Size map_title_offset;      // offset of the top left corner of the text in letter W fraction
    double map_title_size;
    Color mapped_antigens_section_line_color;
    double mapped_antigens_section_line_width;

    std::vector<MarkAntigenSettings> mark_antigens;

}; // class AntigenicMapsDrawSettings

// ----------------------------------------------------------------------

class DrawPoint
{
 public:
    inline DrawPoint() = default;
    inline DrawPoint(const DrawPoint&) = default;
    inline DrawPoint(DrawPoint&&) = default;
    inline virtual ~DrawPoint() = default;
    inline DrawPoint& operator=(const DrawPoint&) = default;
    virtual void draw(Surface& aSurface, const Point& aPoint, const PointStyle& aStyle, const AntigenicMapsDrawSettings& aSettings) const = 0;
    virtual size_t level() const = 0;
    virtual inline double aspect(const Point&, const PointStyle& aStyle, const AntigenicMapsDrawSettings&) const { return aStyle.aspect; }
    virtual inline double rotation(const Point& aPoint, const PointStyle& aStyle, const AntigenicMapsDrawSettings& aSettings) const { return aPoint.attributes.reassortant ? aSettings.reassortant_rotation : aStyle.rotation; }
    virtual inline Color fill_color(const Point&, const PointStyle& aStyle, const AntigenicMapsDrawSettings&) const { return aStyle.fill_color; }
    virtual inline Color outline_color(const Point&, const PointStyle& aStyle, const AntigenicMapsDrawSettings&) const { return aStyle.outline_color; }
};

class DrawSerum : public DrawPoint
{
 public:
    virtual void draw(Surface& aSurface, const Point& aPoint, const PointStyle& aStyle, const AntigenicMapsDrawSettings& aSettings) const;
    virtual inline size_t level() const { return 1; }
    virtual inline Color outline_color(const Point&, const PointStyle&, const AntigenicMapsDrawSettings& aSettings) const { return aSettings.serum_outline_color; }
    virtual inline double outline_width(const Point&, const PointStyle&, const AntigenicMapsDrawSettings& aSettings) const { return aSettings.serum_outline_width; }
};

class DrawAntigen : public DrawPoint
{
 public:
    virtual inline double aspect(const Point& aPoint, const PointStyle& aStyle, const AntigenicMapsDrawSettings& aSettings) const { return aPoint.attributes.egg ? aSettings.egg_antigen_aspect : aStyle.aspect; }
};

class DrawReferenceAntigen : public DrawAntigen
{
 public:
    virtual void draw(Surface& aSurface, const Point& aPoint, const PointStyle& aStyle, const AntigenicMapsDrawSettings& aSettings) const;
    virtual inline size_t level() const { return 2; }
};

class DrawTestAntigen : public DrawAntigen
{
 public:
    virtual void draw(Surface& aSurface, const Point& aPoint, const PointStyle& aStyle, const AntigenicMapsDrawSettings& aSettings) const;
    virtual inline size_t level() const { return 3; }
};

class DrawSequencedAntigen : public DrawAntigen
{
 public:
    virtual void draw(Surface& aSurface, const Point& aPoint, const PointStyle& aStyle, const AntigenicMapsDrawSettings& aSettings) const;
    virtual inline size_t level() const { return 4; }
};

class DrawTrackedAntigen : public DrawAntigen
{
 public:
    inline DrawTrackedAntigen(Color aFillColor = "pink") : mColor(aFillColor) {}

    virtual void draw(Surface& aSurface, const Point& aPoint, const PointStyle& aStyle, const AntigenicMapsDrawSettings& aSettings) const;
    virtual inline size_t level() const { return 5; }
    inline void color(Color aColor) { mColor = aColor; }

 private:
    Color mColor;
};

class DrawTrackedSerum : public DrawSerum
{
 public:
    inline DrawTrackedSerum(Color aOutlineColor = 0, double aOutlineWidth = 1) : mOutlineColor(aOutlineColor), mOutlineWidth(aOutlineWidth) {}

    virtual void draw(Surface& aSurface, const Point& aPoint, const PointStyle& aStyle, const AntigenicMapsDrawSettings& aSettings) const;
    virtual inline size_t level() const { return 6; }
    virtual inline Color outline_color(const Point& /*aPoint*/, const PointStyle& /*aStyle*/, const AntigenicMapsDrawSettings& /*aSettings*/) const { return mOutlineColor; }
    virtual double outline_width(const Point& /*aPoint*/, const PointStyle& /*aStyle*/, const AntigenicMapsDrawSettings& /*aSettings*/) const { return mOutlineWidth; }

 private:
    Color mOutlineColor;
    double mOutlineWidth;
};

class DrawVaccineAntigen : public DrawAntigen
{
 public:
    virtual void draw(Surface& aSurface, const Point& aPoint, const PointStyle& aStyle, const AntigenicMapsDrawSettings& aSettings) const;
    virtual inline size_t level() const { return 9; }
};

class DrawMarkedAntigen : public DrawAntigen
{
 public:
    inline DrawMarkedAntigen(const MarkAntigenSettings& aData) : mData(aData) {}

    virtual void draw(Surface& aSurface, const Point& aPoint, const PointStyle& aStyle, const AntigenicMapsDrawSettings& aSettings) const;
    virtual inline size_t level() const { return 7; }

 private:
    MarkAntigenSettings mData;
};

// ----------------------------------------------------------------------

class AntigenicMapsDraw;
class HzSection;
class MappedAntigensDraw;

class AntigenicMapsLayout
{
 public:
    inline AntigenicMapsLayout(AntigenicMapsDraw& aAntigenicMapsDraw) : mAntigenicMapsDraw(aAntigenicMapsDraw) {}
    virtual ~AntigenicMapsLayout();

    virtual void prepare();
    virtual void draw() = 0;

 protected:
    AntigenicMapsDraw& mAntigenicMapsDraw;
    Viewport mMapViewport;

    std::vector<const DrawPoint*> mDrawPoints;
    std::map<size_t, size_t> mSequencedAntigens; // antigen_no to section_no

    DrawSerum mDrawSerum;
    DrawReferenceAntigen mDrawReferenceAntigen;
    DrawTestAntigen mDrawTestAntigen;
    DrawSequencedAntigen mDrawSequencedAntigen;
    DrawTrackedAntigen mDrawTrackedAntigen;
    std::vector<DrawTrackedAntigen> mDrawTrackedAntigensColoredByClade;
    DrawVaccineAntigen mDrawVaccineAntigen;
    std::vector<DrawMarkedAntigen> mDrawMarkedAntigens;
    std::vector<DrawTrackedSerum> mDrawTrackedSera;

    virtual void find_sequenced_antigens();
    virtual void draw_points_reset();
    virtual void draw_chart(Surface& aSurface, size_t aSectionIndex);
    virtual void mark_tracked_sera(size_t aSectionIndex);
    virtual void draw_map_title(Surface& aSurface, size_t aSectionIndex);
    virtual void mark_tracked_antigens(size_t aSectionIndex);
    virtual void mark_marked_antigens();

      // tracked_antigens_colored_by_clade
      // tracked_sera

}; // class AntigenicMapsLayout

// ----------------------------------------------------------------------

class AntigenicMapsDraw
{
 public:
    inline AntigenicMapsDraw(Surface& aSurface, Tree& aTree, Chart& aChart, HzSections& aHzSections, MappedAntigensDraw& aMappedAntigensDraw, AntigenicMapsDrawSettings& aSettings)
        : mSurface(aSurface), mTree(aTree), mChart(aChart), mHzSections(aHzSections), mMappedAntigensDraw(aMappedAntigensDraw), mSettings(aSettings) {}

    void init_settings();
    void prepare();
    void draw();

    inline Surface& surface() { return mSurface; }
    inline const Tree& tree() const { return mTree; }
    inline const Chart& chart() const { return mChart; }
    inline const HzSections& hz_sections() const { return mHzSections; }
    inline MappedAntigensDraw& mapped_antigens_draw() { return mMappedAntigensDraw; }
    inline const AntigenicMapsDrawSettings& settings() const { return mSettings; }

 private:
    Surface& mSurface;
    Tree& mTree;
    Chart& mChart;
    HzSections& mHzSections;
    MappedAntigensDraw& mMappedAntigensDraw;
    AntigenicMapsDrawSettings& mSettings;
    std::unique_ptr<AntigenicMapsLayout> mLayout;

}; // class AntigenicMapsDraw

// ----------------------------------------------------------------------

class LabelledGrid : public AntigenicMapsLayout
{
 public:
    inline LabelledGrid(AntigenicMapsDraw& aAntigenicMapsDraw) : AntigenicMapsLayout(aAntigenicMapsDraw) {}

    virtual void prepare();
    virtual void draw();

 protected:
    virtual void draw_chart(Surface& aSurface, size_t aSectionIndex);
    virtual void draw_mapped_antigens_section(size_t aSectionIndex);

}; // class LabelledGrid

// ----------------------------------------------------------------------
/// Local Variables:
/// eval: (if (fboundp 'eu-rename-buffer) (eu-rename-buffer))
/// End:
<|endoftext|>


<commit_before>/*
   Copyright 2016 Mitchell Young

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

#include "xs_mesh.hpp"

#include <iostream>
#include <map>
#include <memory>
#include "util/blitz_typedefs.hpp"
#include "util/files.hpp"
#include "util/global_config.hpp"

namespace mocc {
XSMesh::XSMesh(const CoreMesh &mesh, MeshTreatment treatment): state_(0)
{

    LogFile << "Initializing XS Mesh... ";

    const MaterialLib &mat_lib = mesh.mat_lib();

    // Assume the same number of groups as the source material library
    ng_ = mat_lib.n_group();

    // Get energy group bounds
    eubounds_ = mat_lib.g_bounds();

    // Set up the XS mesh regions. This essentially boils down to generating a
    // map from material index to the flat source region indices that are filled
    // by the indexed material. After that, everything else should be quite
    // similar.
    std::map<int, VecI> fsr_map;

    int nreg = mesh.n_reg(treatment);

    if (treatment == MeshTreatment::TRUE) {
        int ireg = 0;
        for (const auto &pini : mesh) {
            const PinMesh &pm   = pini->mesh();
            const VecI &mat_ids = pini->mat_ids();
            int ixsreg          = 0;
            for (auto &mat_id : mat_ids) {
                for (size_t reg = 0; reg < pm.n_fsrs(ixsreg); reg++) {
                    fsr_map[mat_id].push_back(ireg);
                    ireg++;
                }
                ixsreg++;
            }
        }
    } else if (treatment == MeshTreatment::PLANE) {
        int ireg = 0;
        int iz   = 0;
        for (const auto &block : mesh.subplane()) {
            const Plane &plane = mesh.unique_plane(mesh.unique_plane_id(iz));
            for (const auto &lattice : plane) {
                for (const auto &pin : *lattice) {
                    const VecI &mat_ids = pin->mat_ids();
                    const PinMesh &pm = pin->mesh();
                    int ixsreg        = 0;
                    for (const auto &mat_id : mat_ids) {
                        for(unsigned reg=0; reg<pm.n_fsrs(ixsreg); ++reg ){
                            assert(ireg < nreg);
                            fsr_map[mat_id].push_back(ireg);
                            ireg++;
                        }
                        ixsreg++;
                    }
                }
            }
            iz += block;
        }
    } else {
        // Should be using the homogenized class. This would be nice to merge at
        // some point though
        return;
    }

    int n_xsreg = fsr_map.size();

    this->allocate_xs(n_xsreg, ng_);

    // The ids/keys in fsr_map correspond to the user-specified IDs in the
    // material library. We want to cast this into a contiguous, zero-based
    // index space for internal storage and saner indexing, hence the imat
    // counter.
    n_reg_expanded_ = 0;
    VecI mat_ids(n_xsreg);
    int imat = 0;
    for (const auto &mat_pair : fsr_map) {
        mat_ids[imat]   = mat_pair.first;
        const auto &mat = mat_lib[mat_pair.first];
        xstr_(imat, blitz::Range::all()) = mat.xstr();
        xsnf_(imat, blitz::Range::all()) = mat.xsnf();
        xsch_(imat, blitz::Range::all()) = mat.xsch();
        xsf_(imat, blitz::Range::all())  = mat.xsf();
        n_reg_expanded_ += mat_pair.second.size();

        imat++;
    }

    // Preallocate space for the regions. Saves on lots of copies for large
    // xsmeshes.
    regions_.reserve(fsr_map.size());
    imat = 0;
    for (auto &reg_pair : fsr_map) {
        const auto &mat = mat_lib[mat_ids[imat]];
        regions_.emplace_back(reg_pair.second, &xstr_(imat, 0), &xsnf_(imat, 0),
                              &xsch_(imat, 0), &xsf_(imat, 0), &xsrm_(imat, 0),
                              mat.xssc());
        imat++;
    }

    LogFile << "done." << std::endl;

    return;
}

std::ostream &operator<<(std::ostream &os, const XSMeshRegion &xsr)
{
    int ng = xsr.xsmacsc_.n_group();
    os << "Transport: " << std::endl;
    for (int ig = 0; ig < ng; ig++) {
        os << xsr.xsmactr_[ig];
    }
    os << std::endl;

    os << "nu-fission: " << std::endl;
    for (int ig = 0; ig < ng; ig++) {
        os << xsr.xsmacnf_[ig];
    }
    os << std::endl;

    os << "chi: " << std::endl;
    for (int ig = 0; ig < ng; ig++) {
        os << xsr.xsmacch_[ig];
    }
    os << std::endl;

    os << "removal: " << std::endl;
    for (int ig = 0; ig < ng; ig++) {
        os << xsr.xsmacrm_[ig];
    }
    os << std::endl;

    os << "Scattering matrix:" << std::endl;
    os << xsr.xsmacsc_ << std::endl;

    return os;
}
}
<commit_msg>Remove unused variable<commit_after>/*
   Copyright 2016 Mitchell Young

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

#include "xs_mesh.hpp"

#include <iostream>
#include <map>
#include <memory>
#include "util/blitz_typedefs.hpp"
#include "util/files.hpp"
#include "util/global_config.hpp"

namespace mocc {
XSMesh::XSMesh(const CoreMesh &mesh, MeshTreatment treatment): state_(0)
{

    LogFile << "Initializing XS Mesh... ";

    const MaterialLib &mat_lib = mesh.mat_lib();

    // Assume the same number of groups as the source material library
    ng_ = mat_lib.n_group();

    // Get energy group bounds
    eubounds_ = mat_lib.g_bounds();

    // Set up the XS mesh regions. This essentially boils down to generating a
    // map from material index to the flat source region indices that are filled
    // by the indexed material. After that, everything else should be quite
    // similar.
    std::map<int, VecI> fsr_map;

    if (treatment == MeshTreatment::TRUE) {
        int ireg = 0;
        for (const auto &pini : mesh) {
            const PinMesh &pm   = pini->mesh();
            const VecI &mat_ids = pini->mat_ids();
            int ixsreg          = 0;
            for (auto &mat_id : mat_ids) {
                for (size_t reg = 0; reg < pm.n_fsrs(ixsreg); reg++) {
                    fsr_map[mat_id].push_back(ireg);
                    ireg++;
                }
                ixsreg++;
            }
        }
    } else if (treatment == MeshTreatment::PLANE) {
        int ireg = 0;
        int iz   = 0;
        for (const auto &block : mesh.subplane()) {
            const Plane &plane = mesh.unique_plane(mesh.unique_plane_id(iz));
            for (const auto &lattice : plane) {
                for (const auto &pin : *lattice) {
                    const VecI &mat_ids = pin->mat_ids();
                    const PinMesh &pm = pin->mesh();
                    int ixsreg        = 0;
                    for (const auto &mat_id : mat_ids) {
                        for(unsigned reg=0; reg<pm.n_fsrs(ixsreg); ++reg ){
                            assert(ireg < nreg);
                            fsr_map[mat_id].push_back(ireg);
                            ireg++;
                        }
                        ixsreg++;
                    }
                }
            }
            iz += block;
        }
    } else {
        // Should be using the homogenized class. This would be nice to merge at
        // some point though
        return;
    }

    int n_xsreg = fsr_map.size();

    this->allocate_xs(n_xsreg, ng_);

    // The ids/keys in fsr_map correspond to the user-specified IDs in the
    // material library. We want to cast this into a contiguous, zero-based
    // index space for internal storage and saner indexing, hence the imat
    // counter.
    n_reg_expanded_ = 0;
    VecI mat_ids(n_xsreg);
    int imat = 0;
    for (const auto &mat_pair : fsr_map) {
        mat_ids[imat]   = mat_pair.first;
        const auto &mat = mat_lib[mat_pair.first];
        xstr_(imat, blitz::Range::all()) = mat.xstr();
        xsnf_(imat, blitz::Range::all()) = mat.xsnf();
        xsch_(imat, blitz::Range::all()) = mat.xsch();
        xsf_(imat, blitz::Range::all())  = mat.xsf();
        n_reg_expanded_ += mat_pair.second.size();

        imat++;
    }

    // Preallocate space for the regions. Saves on lots of copies for large
    // xsmeshes.
    regions_.reserve(fsr_map.size());
    imat = 0;
    for (auto &reg_pair : fsr_map) {
        const auto &mat = mat_lib[mat_ids[imat]];
        regions_.emplace_back(reg_pair.second, &xstr_(imat, 0), &xsnf_(imat, 0),
                              &xsch_(imat, 0), &xsf_(imat, 0), &xsrm_(imat, 0),
                              mat.xssc());
        imat++;
    }

    LogFile << "done." << std::endl;

    return;
}

std::ostream &operator<<(std::ostream &os, const XSMeshRegion &xsr)
{
    int ng = xsr.xsmacsc_.n_group();
    os << "Transport: " << std::endl;
    for (int ig = 0; ig < ng; ig++) {
        os << xsr.xsmactr_[ig];
    }
    os << std::endl;

    os << "nu-fission: " << std::endl;
    for (int ig = 0; ig < ng; ig++) {
        os << xsr.xsmacnf_[ig];
    }
    os << std::endl;

    os << "chi: " << std::endl;
    for (int ig = 0; ig < ng; ig++) {
        os << xsr.xsmacch_[ig];
    }
    os << std::endl;

    os << "removal: " << std::endl;
    for (int ig = 0; ig < ng; ig++) {
        os << xsr.xsmacrm_[ig];
    }
    os << std::endl;

    os << "Scattering matrix:" << std::endl;
    os << xsr.xsmacsc_ << std::endl;

    return os;
}
}
<|endoftext|>