text:
/*
    Copyright (c) 2002-2011 Tampere University.

    This file is part of TTA-Based Codesign Environment (TCE).

    Permission is hereby granted, free of charge, to any person obtaining a
    copy of this software and associated documentation files (the "Software"),
    to deal in the Software without restriction, including without limitation
    the rights to use, copy, modify, merge, publish, distribute, sublicense,
    and/or sell copies of the Software, and to permit persons to whom the
    Software is furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included in
    all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
    DEALINGS IN THE SOFTWARE.
 */
/**
 * @file ControlFlowGraph.hh
 *
 * Declaration of prototype control flow graph of TTA program
 * representation.
 *
 * @author Andrea Cilio 2005 (cilio-no.spam-cs.tut.fi)
 * @author Vladimir Guzma 2006 (vladimir.guzma-no.spam-tut.fi)
 * @note rating: red
 */

#ifndef TTA_CONTROL_FLOW_GRAPH_HH
#define TTA_CONTROL_FLOW_GRAPH_HH

#include <map>
#include <vector>

#include "CompilerWarnings.hh"
IGNORE_CLANG_WARNING("-Wunused-local-typedef")
IGNORE_COMPILER_WARNING("-Wunused-parameter")
#include <boost/graph/reverse_graph.hpp>
#include <boost/graph/depth_first_search.hpp>
POP_COMPILER_DIAGS
POP_CLANG_DIAGS

namespace llvm {
    class MCSymbol;
    class MachineInstr;
}

#include "Exception.hh"
#include "BoostGraph.hh"
#include "BasicBlockNode.hh"
#include "ControlFlowEdge.hh"
#include "Address.hh"
#include "NullAddress.hh"
#include "hash_map.hh"
#include "ProgramOperation.hh"

namespace TTAProgram {
    class Program;
    class Procedure;
    class Instruction;
    class Move;
    class InstructionReferenceManager;
    class POMRelocBookkeeper;
    class Address;
    class NullAddress;
    class Immediate;
    class Terminal;
}

namespace TTAMachine {
    class Machine;
}

namespace llvm {
    class MachineFunction;
    class MachineBasicBlock;
    class MCInstrDesc;
    class MCInstrInfo;
}

using boost::reverse_graph;

class InterPassData;
class DataDependenceGraph;
class CFGStatistics;

/**
 * Control Flow Graph.
 *
 * The basic blocks are initially in the original program order when traversed
 * with nodeCount()/node().
 */
class ControlFlowGraph : public BoostGraph<BasicBlockNode, ControlFlowEdge> {
public:
    ControlFlowGraph(
        const TCEString name,
        TTAProgram::Program* program = NULL);
    ControlFlowGraph(
        const TTAProgram::Procedure& procedure,
        InterPassData& passData);
    ControlFlowGraph(const TTAProgram::Procedure& procedure);
    virtual ~ControlFlowGraph();

    TCEString procedureName() const;
    int alignment() const;
    TTAProgram::Program* program() const;

    BasicBlockNode& entryNode() const;
    BasicBlockNode& exitNode() const;
    BasicBlockNode& firstNormalNode() const;

    TCEString printStatistics();
    const CFGStatistics& statistics();
    friend class ControlDependenceGraph;
    friend class ProgramDependenceGraph;

    void copyToProcedure(
        TTAProgram::Procedure& proc,
        TTAProgram::InstructionReferenceManager* irm = NULL);

    void copyToLLVMMachineFunction(
        llvm::MachineFunction& mf,
        TTAProgram::InstructionReferenceManager* irm = NULL);

    void updateReferencesFromProcToCfg();
    void convertBBRefsToInstRefs();

    ControlFlowEdge* incomingFTEdge(const BasicBlockNode& bbn) const;
    EdgeSet incomingJumpEdges(const BasicBlockNode& bbn) const;
    bool hasIncomingExternalJumps(const BasicBlockNode& bbn) const;

    void deleteNodeAndRefs(BasicBlockNode& node);

    TTAProgram::InstructionReferenceManager& instructionReferenceManager();
    void setInstructionReferenceManager(
        TTAProgram::InstructionReferenceManager& irm) {
        irm_ = &irm;
    }

    BasicBlockNode* jumpSuccessor(BasicBlockNode& bbn);
    BasicBlockNode* fallThruSuccessor(const BasicBlockNode& bbn) const;
    BasicBlockNode* fallThroughPredecessor(const BasicBlockNode& bbn) const;

    void addExitFromSinkNodes(BasicBlockNode* exitNode);
    void detectBackEdges();

    void reverseGuardOnOutEdges(const BasicBlockNode& bbn);
    void optimizeBBOrdering(
        bool removeDeadCode,
        TTAProgram::InstructionReferenceManager& irm,
        DataDependenceGraph* ddg);
    llvm::MachineBasicBlock& getMBB(
        llvm::MachineFunction& mf,
        const TTAProgram::BasicBlock& bb) const;

    void splitBasicBlocksWithCallsAndRefs();

    bool isSingleBBLoop(const BasicBlockNode& node) const;
    bool hasMultipleUnconditionalSuccessors(const BasicBlockNode& node) const;

    void addExit(NodeSet& retSourceNodes);

    void sanitize();

    TTAProgram::Immediate* findLimmWrite(
        TTAProgram::Move& move, BasicBlockNode& bb, int moveIndex);

    TTAProgram::Terminal* findJumpAddress(
        BasicBlockNode& src, ControlFlowEdge& e);

    BasicBlockNode* splitBB(BasicBlockNode& n, int remainingSize);

    bool hasFallThruPredecessor(const BasicBlockNode& bbn);

    int findRelJumpDistance(
        const BasicBlockNode &src,
        const TTAProgram::Terminal& jumpAddr,
        const TTAMachine::Machine& mach) const;

    bool allScheduledInBetween(
        const BasicBlockNode& src, const BasicBlockNode& dst) const;

private:
    // For temporary storage
    typedef hash_map<InstructionAddress, const TTAProgram::Instruction*>
        InstructionAddressMap;
    typedef std::vector<InstructionAddress> InstructionAddressVector;
    // Type of reversed underlying graph, needed for control dependence
    // analysis
    typedef reverse_graph<ControlFlowGraph::Graph> ReversedGraph;
    typedef BoostGraph<BasicBlockNode, ControlFlowEdge>::NodeDescriptor
        NodeDescriptor;
    typedef std::pair<InstructionAddress, ControlFlowEdge::CFGEdgePredicate>
    ReturnSource;
    typedef std::set<ReturnSource> ReturnSourceSet;
    /// DFS visitor which when finding back edge marks such edge as
    /// back edge
    class DFSBackEdgeVisitor : public boost::default_dfs_visitor    {
    public:
        DFSBackEdgeVisitor(){}
        template < typename EdgeDescriptor, typename Graph >
        void back_edge(EdgeDescriptor e, const Graph & g)const {
            g[e]->setBackEdge();
        }
    };

    void buildFrom(const TTAProgram::Procedure& procedure);
    void createBBEdges(
        const TTAProgram::Procedure& procedure,
        InstructionAddressMap& leaders,
        InstructionAddressMap& dataCodeRellocations);

    ReversedGraph& reversedGraph() const;

    bool hasInstructionAnotherJump(
        const TTAProgram::Instruction& ins,
        int moveIndex);
    void computeLeadersFromRefManager(
        InstructionAddressMap& leaders,
        const TTAProgram::Procedure& procedure);
    bool computeLeadersFromJumpSuccessors(
        InstructionAddressMap& leaders,
        const TTAProgram::Procedure& procedure);
    void computeLeadersFromRelocations(
        InstructionAddressMap& leaderSet,
        InstructionAddressMap& dataCodeRellocations,
        const TTAProgram::Procedure& procedure);

    void createAllBlocks(
        InstructionAddressMap& leaders,
        const TTAProgram::Procedure& procedure);
    BasicBlockNode& createBlock(
        TTAProgram::Instruction& leader,
        const TTAProgram::Instruction& endBlock);
    ControlFlowEdge& createControlFlowEdge(
        const TTAProgram::Instruction& iTail,
        const TTAProgram::Instruction& iHead,
        ControlFlowEdge::CFGEdgePredicate edgePredicate =
            ControlFlowEdge::CFLOW_EDGE_NORMAL,
        ControlFlowEdge::CFGEdgeType edgeType =
            ControlFlowEdge::CFLOW_EDGE_JUMP);

    void directJump(
        InstructionAddressMap& leaders,
        const InstructionAddress& leaderAddr,
        int insIndex,
        int moveIndex,
        const TTAProgram::Instruction& instructionTarget,
        const TTAProgram::Procedure& procedure);
    void indirectJump(
        InstructionAddressMap& leaders,
        const InstructionAddress& leaderAddr,
        InstructionAddressMap& dataCodeRellocations,
        int insIndex,
        int moveIndex,
        const TTAProgram::Procedure& procedure);
    void createJumps(
        InstructionAddressMap& leaders,
        const InstructionAddress& leaderAddr,
        InstructionAddressMap& dataCodeRellocations,
        const TTAProgram::Procedure& procedure,
        int insIndex,
        int moveIndex);
    unsigned int findNextIndex(
        const TTAProgram::Procedure& proc,
        int jumpInsIndex, int jumpMoveIndex);

    void addExit();
    void addEntryExitEdge();
    void removeEntryExitEdge();

    NodeSet findReachableNodes();
    NodeSet findUnreachableNodes(const NodeSet& reachableNodes);

    BasicBlockNode* splitBasicBlockAtIndex(BasicBlockNode& bbn, int index);

    void removeUnreachableNodes(
        const NodeSet& unreachableNodes, DataDependenceGraph* ddg);
    void mergeNodes(
        BasicBlockNode& node1,
        BasicBlockNode& node2,
        DataDependenceGraph* ddg,
        const ControlFlowEdge& connectingEdge);

    bool jumpToBBN(
        const TTAProgram::Terminal& jumpAddr, const BasicBlockNode& bbn) const;

    enum RemovedJumpData {
        JUMP_NOT_REMOVED = 0, /// nothing removed
        JUMP_REMOVED, /// jump removed, other things remain in BB
        LAST_ELEMENT_REMOVED /// last jump removed, no immeds in BB.
    };

    RemovedJumpData removeJumpToTarget(
        TTAProgram::CodeSnippet& cs,
        const TTAProgram::Instruction& target,
        int idx,
        DataDependenceGraph* ddg = NULL);

    const llvm::MCInstrDesc&
    findLLVMTargetInstrDesc(TCEString name, const llvm::MCInstrInfo& tii)
        const;

    void buildMBBFromBB(
        llvm::MachineBasicBlock& mbb,
        const TTAProgram::BasicBlock& bb) const;

    // Data saved from original procedure object
    TCEString procedureName_;
    TTAProgram::Program* program_;
    const TTAProgram::Procedure* procedure_;
    TTAProgram::Address startAddress_;
    TTAProgram::Address endAddress_;
    int alignment_;

    // Collection of all basic blocks of the control flow graph indexed by
    // the address of their start instruction (leader).
    hash_map<InstructionAddress, BasicBlockNode*> blocks_;

    // Mapping between original instructions and those in the cfg.
    typedef hash_map<TTAProgram::Instruction*,TTAProgram::Instruction*>
        InsMap;

    InsMap originalToCfgInstructions_;
    InsMap cfgToOriginalInstructions_;

    // all basic blocks which contain a return instruction.
    ReturnSourceSet returnSources_;

    // Optional interpass data to aid in the construction of the CFG.
    InterPassData* passData_;

    // IRM needs to be set explicitly if CFG is built and used without a
    // Program object.
    TTAProgram::InstructionReferenceManager* irm_;

    // Maps BasicBlockNode onto it's MachineBasicBlock equivalent
    mutable std::map<const TTAProgram::BasicBlock*, llvm::MachineBasicBlock*>
    bbMap_;

    /// For LLVM conversion: the dummy label instructions for SPU should be
    /// created for with the given MCSymbol as argument after building.
    mutable std::set<std::pair<ProgramOperationPtr, llvm::MCSymbol*> > tpos_;
    /// For LLVM conversion: mapping of created MachineInstructions to TCE
    /// ProgramOperations.
    mutable std::map<ProgramOperation*, llvm::MachineInstr*>
    programOperationToMIMap_;
};
#endif

ext: hh

max_stars_repo_name: kanishkan/tce

max_issues_repo_name: kanishkan/tce

max_forks_repo_name: kanishkan/tce


text:
/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2017 Sylko Olzscher
 *
 */

#include "test-crypto-001.h"
#include <iostream>
#include <boost/test/unit_test.hpp>
#include <crypto/hash/base64.h>

namespace cyng
{
    using namespace std::string_literals;

	bool test_crypto_001()
	{
		{
 			auto r0 = "grrrr shebangit!"s;
			auto r1 = crypto::base64_encode(r0);
			BOOST_CHECK_EQUAL(r1, "Z3JycnIgc2hlYmFuZ2l0IQ==");
			auto r2 = crypto::base64_decode(r1);
			BOOST_CHECK_EQUAL(r0, r2);
		}

		{
			auto r0 = "demo:demo"s;
			auto r1 = crypto::base64_encode(r0);
			BOOST_CHECK_EQUAL(r1, "ZGVtbzpkZW1v");
			auto r2 = crypto::base64_decode(r1);
			BOOST_CHECK_EQUAL(r0, r2);
		}

		return true;
	}

}

ext: cpp

max_stars_repo_name: BitStumbler/crypto

max_issues_repo_name: BitStumbler/crypto

max_forks_repo_name: BitStumbler/crypto


text:
#define BOOST_TEST_MODULE test_sequence

#include <boost/segmented_tree/seq.hpp>
#include <boost/test/unit_test.hpp>
#include <exception>
#include <limits>
#include "../common/iterator.hpp"
#include "../common/range.hpp"
#include "../common/single.hpp"

template <typename T, typename Alloc = std::allocator<T>>
using seq = boost::segmented_tree::seq<T, Alloc, TARGET_SIZE>;
using uint64_t = std::uint64_t;

template <typename T>
class tagged_allocator {
 private:
  unsigned tag_;

 public:
  using value_type = T;
  tagged_allocator(unsigned tag = 0) : tag_{tag} {}
  template <class U>
  tagged_allocator(tagged_allocator<U> const& other) : tag_{other.tag()} {}

  T* allocate(std::size_t n) {
    if (n <= std::numeric_limits<std::size_t>::max() / sizeof(T)) {
      if (auto ptr = std::malloc(n * sizeof(T))) return static_cast<T*>(ptr);
    }
    throw std::bad_alloc();
  }

  void deallocate(T* ptr, std::size_t) { std::free(ptr); }

  unsigned tag() const { return tag_; }
};

template <typename T, typename U>
inline bool operator==(const tagged_allocator<T>&, const tagged_allocator<U>&) {
  return true;
}

template <typename T, typename U>
inline bool operator!=(const tagged_allocator<T>& a,
                       const tagged_allocator<U>& b) {
  return !(a == b);
}

template <typename A, typename B>
void check_contents(A const& a, std::initializer_list<B> b) {
  BOOST_CHECK(a.size() == b.size());
  BOOST_CHECK(std::equal(a.begin(), a.end(), b.begin()));
}

template <typename A>
void check_contents(A const& a) {
  BOOST_CHECK(a.size() == 0);
  BOOST_CHECK(a.begin() == a.end());
}

BOOST_AUTO_TEST_CASE(test_construct_alloc) {
  tagged_allocator<uint64_t> alloc{12345};
  seq<uint64_t, tagged_allocator<uint64_t>> c1{alloc};
  check_contents(c1);
  BOOST_CHECK(c1.get_allocator().tag() == 12345);
}

BOOST_AUTO_TEST_CASE(test_construct_default) {
  seq<uint64_t> c1;
  check_contents(c1);
}

BOOST_AUTO_TEST_CASE(test_construct_count) {
  seq<uint64_t> c1(10, 3);
  check_contents(c1, {3, 3, 3, 3, 3, 3, 3, 3, 3, 3});
}

BOOST_AUTO_TEST_CASE(test_construct_range) {
  std::initializer_list<uint64_t> ilist{0, 1, 2, 3, 4};
  seq<uint64_t> c1{ilist.begin(), ilist.end()};
  check_contents(c1, ilist);
}

BOOST_AUTO_TEST_CASE(test_construct_copy) {
  std::initializer_list<uint64_t> ilist{0, 1, 2, 3, 4};
  seq<uint64_t> c1{ilist};
  seq<uint64_t> c2{c1};
  check_contents(c2, ilist);
}

BOOST_AUTO_TEST_CASE(test_construct_copy_alloc) {
  std::initializer_list<uint64_t> ilist{0, 1, 2, 3, 4};
  seq<uint64_t, tagged_allocator<uint64_t>> c1{ilist};
  tagged_allocator<uint64_t> alloc{12345};
  seq<uint64_t, tagged_allocator<uint64_t>> c2{c1, alloc};
  check_contents(c2, ilist);
  BOOST_CHECK(c2.get_allocator().tag() == 12345);
}

BOOST_AUTO_TEST_CASE(test_construct_move) {
  std::initializer_list<uint64_t> ilist{0, 1, 2, 3, 4};
  seq<uint64_t> c1{ilist};
  seq<uint64_t> c2{std::move(c1)};
  check_contents(c1);
  check_contents(c2, ilist);
}

BOOST_AUTO_TEST_CASE(test_construct_move_alloc) {
  std::initializer_list<uint64_t> ilist{0, 1, 2, 3, 4};
  seq<uint64_t, tagged_allocator<uint64_t>> c1{ilist};
  tagged_allocator<uint64_t> alloc{12345};
  seq<uint64_t, tagged_allocator<uint64_t>> c2{std::move(c1), alloc};
  check_contents(c1);
  check_contents(c2, ilist);
  BOOST_CHECK(c2.get_allocator().tag() == 12345);
}

BOOST_AUTO_TEST_CASE(test_construct_ilist) {
  std::initializer_list<uint64_t> ilist{0, 1, 2, 3, 4};
  seq<uint64_t> c1{ilist};
  check_contents(c1, ilist);
}

BOOST_AUTO_TEST_CASE(test_operator_assign) {
  std::initializer_list<uint64_t> ilist1{0, 1, 2, 3, 4};
  std::initializer_list<uint64_t> ilist2{5, 4, 3};
  seq<uint64_t> c1{ilist1};
  seq<uint64_t> c2{ilist2};
  seq<uint64_t> c3;
  c3 = c1;
  check_contents(c3, ilist1);
  c3 = c2;
  check_contents(c3, ilist2);
}

BOOST_AUTO_TEST_CASE(test_operator_move_assign) {
  std::initializer_list<uint64_t> ilist1{0, 1, 2, 3, 4};
  std::initializer_list<uint64_t> ilist2{5, 4, 3};
  seq<uint64_t> c1{ilist1};
  seq<uint64_t> c2{ilist2};
  seq<uint64_t> c3;
  c3 = std::move(c1);
  check_contents(c3, ilist1);
  check_contents(c1);
  c3 = std::move(c2);
  check_contents(c3, ilist2);
  check_contents(c2);
}

BOOST_AUTO_TEST_CASE(test_operator_assign_ilist) {
  std::initializer_list<uint64_t> ilist1{0, 1, 2, 3, 4};
  std::initializer_list<uint64_t> ilist2{5, 4, 3};
  seq<uint64_t> c1;
  c1 = ilist1;
  check_contents(c1, ilist1);
  c1 = ilist2;
  check_contents(c1, ilist2);
}

BOOST_AUTO_TEST_CASE(test_assign_count) {
  seq<uint64_t> c1{0, 1, 2, 3, 4};
  c1.assign(10, 0);
  check_contents(c1, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0});
  c1.assign(5, 1);
  check_contents(c1, {1, 1, 1, 1, 1});
}

BOOST_AUTO_TEST_CASE(test_assign_range) {
  std::initializer_list<uint64_t> ilist{0, 1, 2, 3, 4};
  seq<uint64_t> c1;
  c1.assign(ilist.begin(), ilist.end());
  check_contents(c1, ilist);
}

BOOST_AUTO_TEST_CASE(test_assign_ilist) {
  std::initializer_list<uint64_t> ilist{0, 1, 2, 3, 4};
  seq<uint64_t> c1;
  c1.assign(ilist);
  check_contents(c1, ilist);
}

BOOST_AUTO_TEST_CASE(test_get_allocator) {
  tagged_allocator<uint64_t> alloc{12345};
  seq<uint64_t, tagged_allocator<uint64_t>> c1{alloc};
  BOOST_CHECK(c1.get_allocator().tag() == 12345);
}

template <typename T>
bool check_exception(T const&) {
  return true;
}

BOOST_AUTO_TEST_CASE(test_at) {
  seq<uint64_t> c1{0};
  BOOST_CHECK(c1.at(0) == 0);
  BOOST_CHECK_EXCEPTION(c1.at(1), std::out_of_range,
                        check_exception<std::out_of_range>);

  auto const& view = c1;
  BOOST_CHECK(view.at(0) == 0);
  BOOST_CHECK_EXCEPTION(view.at(1), std::out_of_range,
                        check_exception<std::out_of_range>);
}

BOOST_AUTO_TEST_CASE(test_operator_index) {
  seq<uint64_t> c1{0, 1};
  BOOST_CHECK(c1[0] == 0);
  BOOST_CHECK(c1[1] == 1);

  auto const& view = c1;
  BOOST_CHECK(view[0] == 0);
  BOOST_CHECK(view[1] == 1);
}

BOOST_AUTO_TEST_CASE(test_front) {
  seq<uint64_t> c1{0, 1};
  BOOST_CHECK(c1.front() == 0);

  auto const& view = c1;
  BOOST_CHECK(view.front() == 0);
}

BOOST_AUTO_TEST_CASE(test_back) {
  seq<uint64_t> c1{0, 1};
  BOOST_CHECK(c1.back() == 1);

  auto const& view = c1;
  BOOST_CHECK(view.back() == 1);
}

BOOST_AUTO_TEST_CASE(test_begin) {
  seq<uint64_t> c1{0, 1};
  BOOST_CHECK(*c1.begin() == 0);
  BOOST_CHECK(*c1.begin() == 0);

  auto const& view = c1;
  BOOST_CHECK(*view.begin() == 0);
  BOOST_CHECK(*view.begin() == 0);
}

BOOST_AUTO_TEST_CASE(test_end) {
  seq<uint64_t> c1{0, 1};
  BOOST_CHECK(*(c1.end() - 1) == 1);
  BOOST_CHECK(*(c1.end() - 1) == 1);

  auto const& view = c1;
  BOOST_CHECK(*(view.end() - 1) == 1);
  BOOST_CHECK(*(view.end() - 1) == 1);
}

BOOST_AUTO_TEST_CASE(test_rbegin) {
  seq<uint64_t> c1{0, 1};
  BOOST_CHECK(*c1.rbegin() == 1);
  BOOST_CHECK(*c1.rbegin() == 1);

  auto const& view = c1;
  BOOST_CHECK(*view.rbegin() == 1);
  BOOST_CHECK(*view.rbegin() == 1);
}

BOOST_AUTO_TEST_CASE(test_rend) {
  seq<uint64_t> c1{0, 1};
  BOOST_CHECK(*(c1.rend() - 1) == 0);
  BOOST_CHECK(*(c1.rend() - 1) == 0);

  auto const& view = c1;
  BOOST_CHECK(*(view.rend() - 1) == 0);
  BOOST_CHECK(*(view.rend() - 1) == 0);
}

BOOST_AUTO_TEST_CASE(test_penultimate) {
  seq<uint64_t> c1{0, 1};
  BOOST_CHECK(*c1.penultimate() == 1);
  BOOST_CHECK(*c1.cpenultimate() == 1);

  auto const& view = c1;
  BOOST_CHECK(*view.penultimate() == 1);
  BOOST_CHECK(*view.cpenultimate() == 1);
}

BOOST_AUTO_TEST_CASE(test_nth) {
  seq<uint64_t> c1{0, 1};
  BOOST_CHECK(*c1.nth(0) == 0);
  BOOST_CHECK(*c1.nth(1) == 1);

  auto const& view = c1;
  BOOST_CHECK(*view.nth(0) == 0);
  BOOST_CHECK(*view.nth(1) == 1);
}

BOOST_AUTO_TEST_CASE(test_index_of) {
  seq<uint64_t> c1{0, 1};
  BOOST_CHECK(c1.index_of(c1.nth(0)) == 0);
  BOOST_CHECK(c1.index_of(c1.nth(1)) == 1);
  BOOST_CHECK(c1.index_of(c1.nth(2)) == 2);

  auto const& view = c1;
  BOOST_CHECK(view.index_of(c1.nth(0)) == 0);
  BOOST_CHECK(view.index_of(c1.nth(1)) == 1);
  BOOST_CHECK(view.index_of(c1.nth(2)) == 2);
}

BOOST_AUTO_TEST_CASE(test_empty) {
  seq<uint64_t> c1;
  BOOST_CHECK(c1.empty() == true);
  seq<uint64_t> c2{0};
  BOOST_CHECK(c2.empty() == false);
}

BOOST_AUTO_TEST_CASE(test_size) {
  seq<uint64_t> c1;
  BOOST_CHECK(c1.size() == 0);
  seq<uint64_t> c2{0};
  BOOST_CHECK(c2.size() == 1);
  seq<uint64_t> c3{0, 1, 2, 3, 4};
  BOOST_CHECK(c3.size() == 5);
}

BOOST_AUTO_TEST_CASE(test_height) {
  seq<uint64_t> c1;
  BOOST_CHECK(c1.height() == 0);
  seq<uint64_t> c2{0};
  BOOST_CHECK(c2.height() == 1);
}

BOOST_AUTO_TEST_CASE(test_max_size) {
  seq<uint64_t> c1;
  BOOST_CHECK(c1.max_size() == std::numeric_limits<std::size_t>::max());
}

BOOST_AUTO_TEST_CASE(test_clear) {
  seq<uint64_t> c1{0, 1, 2, 3, 4};
  c1.clear();
  check_contents(c1);
}

BOOST_AUTO_TEST_CASE(test_insert_lvalue) {
  seq<uint64_t> c1{0, 1, 2, 4};
  c1.insert(c1.nth(3), 3);
  check_contents(c1, {0, 1, 2, 3, 4});

  seq<std::string> c2{"zero", "one", "two", "four"};
  c2.insert(c2.nth(3), "three");
  check_contents(c2, {"zero", "one", "two", "three", "four"});
}

BOOST_AUTO_TEST_CASE(test_insert_rvalue) {
  seq<std::string> c1{"zero", "one", "two", "four"};
  std::string s = "three";
  c1.insert(c1.nth(3), std::move(s));
  check_contents(c1, {"zero", "one", "two", "three", "four"});
}

BOOST_AUTO_TEST_CASE(test_insert_lvalue_count) {
  seq<uint64_t> c1{0, 1, 2, 4};
  c1.insert(c1.nth(3), 3, 3);
  check_contents(c1, {0, 1, 2, 3, 3, 3, 4});
}

BOOST_AUTO_TEST_CASE(test_insert_range) {
  seq<uint64_t> c1{0, 1, 2, 6};
  std::initializer_list<uint64_t> ilist{3, 4, 5};
  c1.insert(c1.nth(3), ilist.begin(), ilist.end());
  check_contents(c1, {0, 1, 2, 3, 4, 5, 6});
}

BOOST_AUTO_TEST_CASE(test_insert_ilist) {
  seq<uint64_t> c1{0, 1, 2, 6};
  std::initializer_list<uint64_t> ilist{3, 4, 5};
  c1.insert(c1.nth(3), ilist);
  check_contents(c1, {0, 1, 2, 3, 4, 5, 6});
}

BOOST_AUTO_TEST_CASE(test_emplace) {
  seq<uint64_t> c1{0, 1, 2, 4};
  c1.emplace(c1.nth(3));
  check_contents(c1, {0, 1, 2, 0, 4});

  seq<std::string> c2{"zero", "one", "two", "four"};
  c2.emplace(c2.nth(3), "three");
  check_contents(c2, {"zero", "one", "two", "three", "four"});
}

BOOST_AUTO_TEST_CASE(test_erase) {
  seq<uint64_t> c1{0, 1, 2, 3, 4};
  c1.erase(c1.nth(3));
  check_contents(c1, {0, 1, 2, 4});
  c1.erase(c1.nth(1));
  check_contents(c1, {0, 2, 4});
  c1.erase(c1.nth(2));
  check_contents(c1, {0, 2});
  c1.erase(c1.nth(0));
  check_contents(c1, {2});
  c1.erase(c1.nth(0));
  check_contents(c1);

  seq<std::string> c2{"zero", "one", "two", "three", "four"};
  c2.erase(c2.nth(3));
  check_contents(c2, {"zero", "one", "two", "four"});
  c2.erase(c2.nth(1));
  check_contents(c2, {"zero", "two", "four"});
  c2.erase(c2.nth(2));
  check_contents(c2, {"zero", "two"});
  c2.erase(c2.nth(0));
  check_contents(c2, {"two"});
  c2.erase(c2.nth(0));
  check_contents(c2);
}

BOOST_AUTO_TEST_CASE(test_erase_range) {
  seq<uint64_t> c1{0, 1, 2, 3, 4};
  c1.erase(c1.nth(1), c1.nth(4));
  check_contents(c1, {0, 4});
}

BOOST_AUTO_TEST_CASE(test_push_back_lvalue) {
  seq<uint64_t> c1;
  c1.push_back(0);
  c1.push_back(1);
  check_contents(c1, {0, 1});
}

BOOST_AUTO_TEST_CASE(test_push_back_rvalue) {
  seq<uint64_t> c1;
  uint64_t a1 = 0;
  uint64_t b1 = 1;
  c1.push_back(std::move(a1));
  c1.push_back(std::move(b1));
  check_contents(c1, {0, 1});

  seq<std::string> c2;
  std::string a2 = "zero";
  std::string b2 = "one";
  c2.push_back(std::move(a2));
  c2.push_back(std::move(b2));
  check_contents(c2, {"zero", "one"});
}

BOOST_AUTO_TEST_CASE(test_emplace_back) {
  seq<uint64_t> c1;
  c1.emplace_back();
  c1.emplace_back(1);
  check_contents(c1, {0, 1});

  seq<std::string> c2;
  c2.emplace_back();
  c2.emplace_back("one");
  check_contents(c2, {"", "one"});
}

BOOST_AUTO_TEST_CASE(test_pop_back) {
  seq<uint64_t> c1{0, 1, 2, 3, 4};
  c1.pop_back();
  c1.pop_back();
  check_contents(c1, {0, 1, 2});
}

BOOST_AUTO_TEST_CASE(test_push_front_lvalue) {
  seq<uint64_t> c1;
  c1.push_front(1);
  c1.push_front(0);
  check_contents(c1, {0, 1});
}

BOOST_AUTO_TEST_CASE(test_push_front_rvalue) {
  seq<uint64_t> c1;
  uint64_t b1 = 1;
  uint64_t a1 = 0;
  c1.push_front(std::move(b1));
  c1.push_front(std::move(a1));
  check_contents(c1, {0, 1});

  seq<std::string> c2;
  std::string b2 = "one";
  std::string a2 = "zero";
  c2.push_front(std::move(b2));
  c2.push_front(std::move(a2));
  check_contents(c2, {"zero", "one"});
}

BOOST_AUTO_TEST_CASE(test_emplace_front) {
  seq<uint64_t> c1;
  c1.emplace_front(1);
  c1.emplace_front();
  check_contents(c1, {0, 1});

  seq<std::string> c2;
  c2.emplace_front("one");
  c2.emplace_front();
  check_contents(c2, {"", "one"});
}

BOOST_AUTO_TEST_CASE(test_pop_front) {
  seq<uint64_t> c1{0, 1, 2, 3, 4};
  c1.pop_front();
  c1.pop_front();
  check_contents(c1, {2, 3, 4});
}

BOOST_AUTO_TEST_CASE(test_resize_default) {
  seq<uint64_t> c1{0, 1, 2, 3, 4};
  c1.resize(10);
  check_contents(c1, {0, 1, 2, 3, 4, 0, 0, 0, 0, 0});
  c1.resize(5);
  check_contents(c1, {0, 1, 2, 3, 4});
}

BOOST_AUTO_TEST_CASE(test_resize_value) {
  seq<uint64_t> c1{0, 1, 2, 3, 4};
  c1.resize(10, 1);
  check_contents(c1, {0, 1, 2, 3, 4, 1, 1, 1, 1, 1});
  c1.resize(5, 1);
  check_contents(c1, {0, 1, 2, 3, 4});
}

BOOST_AUTO_TEST_CASE(test_swap_member) {
  std::initializer_list<uint64_t> a{0, 1, 2, 3, 4};
  std::initializer_list<uint64_t> b{4, 3, 2, 1, 0};
  seq<uint64_t> c1{a};
  seq<uint64_t> c2{b};
  c1.swap(c2);
  check_contents(c1, b);
  check_contents(c2, a);
}

BOOST_AUTO_TEST_CASE(test_swap_free) {
  std::initializer_list<uint64_t> a{0, 1, 2, 3, 4};
  std::initializer_list<uint64_t> b{4, 3, 2, 1, 0};
  seq<uint64_t> c1{a};
  seq<uint64_t> c2{b};
  swap(c1, c2);
  check_contents(c1, b);
  check_contents(c2, a);
}

BOOST_AUTO_TEST_CASE(test_splice_lvalue) {
  seq<uint64_t> c1{0, 1, 2, 3, 4};
  seq<uint64_t> c2{5, 6, 7, 8, 9};
  c1.splice(c1.nth(3), c2);
  check_contents(c1, {0, 1, 2, 5, 6, 7, 8, 9, 3, 4});
  check_contents(c2);

  seq<std::string> c3{"zero", "one", "two", "three", "four"};
  seq<std::string> c4{"five", "six", "seven", "eight", "nine"};
  c3.splice(c3.nth(3), c4);
  check_contents(c3, {"zero", "one", "two", "five", "six", "seven", "eight",
                      "nine", "three", "four"});
  check_contents(c4);
}

BOOST_AUTO_TEST_CASE(test_splice_rvalue) {
  seq<uint64_t> c1{0, 1, 2, 3, 4};
  seq<uint64_t> c2{5, 6, 7, 8, 9};
  c1.splice(c1.nth(3), std::move(c2));
  check_contents(c1, {0, 1, 2, 5, 6, 7, 8, 9, 3, 4});
  check_contents(c2);

  seq<std::string> c3{"zero", "one", "two", "three", "four"};
  seq<std::string> c4{"five", "six", "seven", "eight", "nine"};
  c3.splice(c3.nth(3), std::move(c4));
  check_contents(c3, {"zero", "one", "two", "five", "six", "seven", "eight",
                      "nine", "three", "four"});
  check_contents(c4);
}

BOOST_AUTO_TEST_CASE(test_splice_single_lvalue) {
  seq<uint64_t> c1{0, 1, 2, 3, 4};
  seq<uint64_t> c2{5, 6, 7, 8, 9};
  c1.splice(c1.nth(3), c2, c2.nth(3));
  check_contents(c1, {0, 1, 2, 8, 3, 4});
  check_contents(c2, {5, 6, 7, 9});

  seq<std::string> c3{"zero", "one", "two", "three", "four"};
  seq<std::string> c4{"five", "six", "seven", "eight", "nine"};
  c3.splice(c3.nth(3), c4, c4.nth(3));
  check_contents(c3, {"zero", "one", "two", "eight", "three", "four"});
  check_contents(c4, {"five", "six", "seven", "nine"});
}

BOOST_AUTO_TEST_CASE(test_splice_single_rvalue) {
  seq<uint64_t> c1{0, 1, 2, 3, 4};
  seq<uint64_t> c2{5, 6, 7, 8, 9};
  c1.splice(c1.nth(3), std::move(c2), c2.nth(3));
  check_contents(c1, {0, 1, 2, 8, 3, 4});
  check_contents(c2, {5, 6, 7, 9});

  seq<std::string> c3{"zero", "one", "two", "three", "four"};
  seq<std::string> c4{"five", "six", "seven", "eight", "nine"};
  c3.splice(c3.nth(3), std::move(c4), c4.nth(3));
  check_contents(c3, {"zero", "one", "two", "eight", "three", "four"});
  check_contents(c4, {"five", "six", "seven", "nine"});
}

BOOST_AUTO_TEST_CASE(test_splice_range_lvalue) {
  seq<uint64_t> c1{0, 1, 2, 3, 4};
  seq<uint64_t> c2{5, 6, 7, 8, 9};
  c1.splice(c1.nth(3), c2, c2.nth(1), c2.nth(4));
  check_contents(c1, {0, 1, 2, 6, 7, 8, 3, 4});
  check_contents(c2, {5, 9});

  seq<std::string> c3{"zero", "one", "two", "three", "four"};
  seq<std::string> c4{"five", "six", "seven", "eight", "nine"};
  c3.splice(c3.nth(3), c4, c4.nth(1), c4.nth(4));
  check_contents(
      c3, {"zero", "one", "two", "six", "seven", "eight", "three", "four"});
  check_contents(c4, {"five", "nine"});
}

BOOST_AUTO_TEST_CASE(test_splice_range_rvalue) {
  seq<uint64_t> c1{0, 1, 2, 3, 4};
  seq<uint64_t> c2{5, 6, 7, 8, 9};
  c1.splice(c1.nth(3), std::move(c2), c2.nth(1), c2.nth(4));
  check_contents(c1, {0, 1, 2, 6, 7, 8, 3, 4});
  check_contents(c2, {5, 9});

  seq<std::string> c3{"zero", "one", "two", "three", "four"};
  seq<std::string> c4{"five", "six", "seven", "eight", "nine"};
  c3.splice(c3.nth(3), std::move(c4), c4.nth(1), c4.nth(4));
  check_contents(
      c3, {"zero", "one", "two", "six", "seven", "eight", "three", "four"});
  check_contents(c4, {"five", "nine"});
}

BOOST_AUTO_TEST_CASE(test_splice_merge_lvalue) {
  seq<uint64_t> c1{0, 1, 2, 10, 20, 21, 30};
  seq<uint64_t> c2{1, 3, 4, 5, 22, 29, 31};
  c1.merge(c2);
  check_contents(c1, {0, 1, 1, 2, 3, 4, 5, 10, 20, 21, 22, 29, 30, 31});
  check_contents(c2);
}

BOOST_AUTO_TEST_CASE(test_splice_merge_rvalue) {
  seq<uint64_t> c1{0, 1, 2, 10, 20, 21, 30};
  seq<uint64_t> c2{1, 3, 4, 5, 22, 29, 31};
  c1.merge(std::move(c2));
  check_contents(c1, {0, 1, 1, 2, 3, 4, 5, 10, 20, 21, 22, 29, 30, 31});
  check_contents(c2);
}

BOOST_AUTO_TEST_CASE(test_remove) {
  seq<uint64_t> c1{0, 1, 2, 3, 4, 4, 3, 2, 1, 0};
  c1.remove(2);
  check_contents(c1, {0, 1, 3, 4, 4, 3, 1, 0});
}

BOOST_AUTO_TEST_CASE(test_remove_if) {
  seq<uint64_t> c1{0, 1, 2, 3, 4, 4, 3, 2, 1, 0};
  c1.remove_if([](uint64_t data) { return data >= 2; });
  check_contents(c1, {0, 1, 1, 0});
}

BOOST_AUTO_TEST_CASE(test_reverse) {
  seq<uint64_t> c1{0, 1, 2, 3, 4};
  c1.reverse();
  check_contents(c1, {4, 3, 2, 1, 0});
}

BOOST_AUTO_TEST_CASE(test_unique) {
  seq<uint64_t> c1{0, 1, 1, 2, 2, 2, 3, 4};
  c1.unique();
  check_contents(c1, {0, 1, 2, 3, 4});
}

BOOST_AUTO_TEST_CASE(test_sort) {
  seq<uint64_t> c1{3, 0, 4, 1, 2};
  c1.sort();
  check_contents(c1, {0, 1, 2, 3, 4});
}

BOOST_AUTO_TEST_CASE(test_sort_predicate) {
  seq<uint64_t> c1{3, 0, 4, 1, 2};
  c1.sort([](uint64_t a, uint64_t b) { return a > b; });
  check_contents(c1, {4, 3, 2, 1, 0});
}

template <typename Container, typename T>
void test_iterator(Container const& container, std::vector<T> const& data) {
  BOOST_CHECK(accumulate_forward(data) == accumulate_forward(container));

  BOOST_CHECK(accumulate_forward_by(data, 1) ==
              accumulate_forward_by(container, 1));

  BOOST_CHECK(accumulate_forward_by(data, 10) ==
              accumulate_forward_by(container, 10));

  BOOST_CHECK(accumulate_forward_by(data, 100) ==
              accumulate_forward_by(container, 100));

  BOOST_CHECK(accumulate_forward_by(data, 1000) ==
              accumulate_forward_by(container, 1000));

  BOOST_CHECK(accumulate_forward_by(data, 10000) ==
              accumulate_forward_by(container, 10000));

  BOOST_CHECK(accumulate_backward(data) == accumulate_backward(container));

  BOOST_CHECK(accumulate_backward_by(data, 1) ==
              accumulate_backward_by(container, 1));

  BOOST_CHECK(accumulate_backward_by(data, 10) ==
              accumulate_backward_by(container, 10));

  BOOST_CHECK(accumulate_backward_by(data, 100) ==
              accumulate_backward_by(container, 100));

  BOOST_CHECK(accumulate_backward_by(data, 1000) ==
              accumulate_backward_by(container, 1000));

  BOOST_CHECK(accumulate_backward_by(data, 10000) ==
              accumulate_backward_by(container, 10000));
}

template <typename T>
void test_single(std::size_t count, std::uint32_t seed,
                 std::uint64_t checksum) {
  auto data = make_insertion_data_single<T>(count, seed);
  seq<T> container;
  insert_single(container, data);
  std::vector<T> inserted{container.begin(), container.end()};
  BOOST_CHECK(checksum == make_checksum_unsigned(inserted));
  test_iterator(container, inserted);
  erase_single(container, data);
  BOOST_CHECK(container.size() == std::size_t{1});
  BOOST_CHECK(container[0] == data.ordered[0]);
}

BOOST_AUTO_TEST_CASE(test_random_single) {
  test_single<uint64_t>(32ULL, 2397254571ULL, 4723602420748635361ULL);
  test_single<uint64_t>(992ULL, 463092544ULL, 12966777589746855639ULL);
  test_single<uint64_t>(30752ULL, 430452927ULL, 751509891372566603ULL);
  test_single<uint64_t>(953312ULL, 3109453262ULL, 10176667110359292238ULL);
}

template <typename T>
void test_range(std::size_t count, std::size_t size, std::uint32_t seed,
                std::uint64_t checksum) {
  auto data = make_insertion_data_range<T>(count, size, seed);
  seq<T> container;
  insert_range(container, data);
  std::vector<T> inserted{container.begin(), container.end()};
  BOOST_CHECK(checksum == make_checksum_unsigned(inserted));
  test_iterator(container, inserted);
  erase_range(container, data);
  BOOST_CHECK(std::size_t{1} == container.size());
  BOOST_CHECK(data.ordered[0] == container[0]);
}

BOOST_AUTO_TEST_CASE(test_random_range) {
  test_range<uint64_t>(1ULL, 953312ULL, 235951511ULL, 7803621008785366632ULL);
  test_range<uint64_t>(31ULL, 30752ULL, 1082972474ULL, 11846815057285548515ULL);
  test_range<uint64_t>(961ULL, 992ULL, 5659033ULL, 14482810490810820797ULL);
  test_range<uint64_t>(29791ULL, 32ULL, 3727649439ULL, 10804193997107502541ULL);
}

struct retry_exception {};

template <typename T>
class throwing_allocator {
 private:
  random_engine engine_;

 public:
  using value_type = T;

  throwing_allocator() = default;
  template <class U>
  throwing_allocator(const throwing_allocator<U>&) {}

  T* allocate(std::size_t n) {
    if (engine_() % 8 == 0) throw retry_exception{};
    if (n <= std::numeric_limits<std::size_t>::max() / sizeof(T)) {
      if (auto ptr = std::malloc(n * sizeof(T))) return static_cast<T*>(ptr);
    }
    throw std::bad_alloc();
  }

  void deallocate(T* ptr, std::size_t) { std::free(ptr); }

  template <typename U, typename... Args>
  void construct(U* p, Args&&... args) {
    if (engine_() % 8 == 0) throw retry_exception{};
    new (p) U(std::forward<Args>(args)...);
  }

  template <typename U, typename... Args>
  void construct(U* p, T&& value) {
    new (p) U(std::move(value));
  }
};

template <typename T, typename U>
inline bool operator==(const throwing_allocator<T>&,
                       const throwing_allocator<U>&) {
  return true;
}

template <typename T, typename U>
inline bool operator!=(const throwing_allocator<T>& a,
                       const throwing_allocator<U>& b) {
  return !(a == b);
}

template <typename Container, typename T>
void insert_single_retry(Container& container, insertion_data<T> const& data) {
  auto count = data.indexes.size();
  reserve(container, count);
  for (std::size_t i = 0; i != count; ++i) {
    while (true) {
      try {
        container.insert(nth(container, data.indexes[i]), data.ordered[i]);
        break;
      } catch (retry_exception const&) {
      }
    }
  }
}

template <typename T>
void test_single_retry(std::size_t count, std::uint32_t seed,
                       std::uint64_t checksum) {
  auto data = make_insertion_data_single<T>(count, seed);
  seq<T, throwing_allocator<T>> container;
  insert_single_retry(container, data);
  std::vector<T> inserted{container.begin(), container.end()};
  BOOST_CHECK(checksum == make_checksum_unsigned(inserted));
  test_iterator(container, inserted);
  erase_single(container, data);
  BOOST_CHECK(container.size() == std::size_t{1});
  BOOST_CHECK(container[0] == data.ordered[0]);
}

BOOST_AUTO_TEST_CASE(test_random_single_retry) {
  test_single_retry<uint64_t>(32ULL, 2397254571ULL, 4723602420748635361ULL);
  test_single_retry<uint64_t>(992ULL, 463092544ULL, 12966777589746855639ULL);
  test_single_retry<uint64_t>(30752ULL, 430452927ULL, 751509891372566603ULL);
  test_single_retry<uint64_t>(953312ULL, 3109453262ULL,
                              10176667110359292238ULL);
}

BOOST_AUTO_TEST_CASE(test_traits) {
  auto x = boost::segmented_tree::detail::is_alloc_move_construct_default<
      int, throwing_allocator<int>>::value;
  auto y = boost::segmented_tree::detail::is_alloc_move_construct_default<
      int, tagged_allocator<int>>::value;
  BOOST_CHECK(x == false);
  BOOST_CHECK(y == true);
}


text:
{{header}}
{{#includes}}
#include <{{.}}>
{{/includes}}
{{#sources}}
#include <{{.}}>
{{/sources}}
#include <boost/python.hpp>
{{postinclude}}
{{#module.bindings}}
void {{.}}();
{{/module.bindings}}

BOOST_PYTHON_MODULE({{module.name}})
{
    {{precontent}}

    ::boost::python::docstring_options options(true, true, false);

{{#module.namespaces}}{{#name}}
    ::boost::python::scope(){{!
        }}{{#scope}}{{#name}}.attr("{{name}}"){{/name}}{{/scope}}.attr("{{name}}") = {{!
        }}::boost::python::object(::boost::python::handle<>({{!
              }}::boost::python::borrowed(::PyImport_AddModule({{!
                  }}"{{module.name}}{{#scope}}{{#name}}.{{name}}{{/name}}{{/scope}}.{{name}}"))));
{{/name}}{{/module.namespaces}}

{{#module.bindings}}
    {{.}}();
{{/module.bindings}}

    {{postcontent}}
}
{{footer}}


text:
// Copyright Abel Sinkovics (abel@sinkovics.hu) 2010.
// Distributed under the Boost Software License, Version 1.0.
//    (See accompanying file LICENSE_1_0.txt or copy at
//          http://www.boost.org/LICENSE_1_0.txt)

#include <mpllibs/metamonad/do_.hpp>
#include <mpllibs/metamonad/tmp_tag.hpp>
#include <mpllibs/metamonad/tmp_value.hpp>
#include <mpllibs/metamonad/returns.hpp>
#include <mpllibs/metamonad/lazy_metafunction.hpp>
#include <mpllibs/metamonad/metafunction.hpp>
#include <mpllibs/metamonad/eval_let.hpp>
#include <mpllibs/metamonad/let.hpp>
#include <mpllibs/metamonad/lambda_c.hpp>
#include <mpllibs/metamonad/name.hpp>
#include <mpllibs/metamonad/either.hpp>
#include <mpllibs/metamonad/lazy.hpp>
#include <mpllibs/metamonad/apply.hpp>
#include <mpllibs/metamonad/syntax.hpp>
#include <mpllibs/boost.hpp>

#include <boost/test/unit_test.hpp>

#include <boost/mpl/equal_to.hpp>
#include <boost/mpl/tag.hpp>
#include <boost/mpl/assert.hpp>

#include <boost/type_traits.hpp>

#include "common.hpp"

using boost::mpl::minus;

using mpllibs::metamonad::tmp_tag;
using mpllibs::metamonad::tmp_value;
using mpllibs::metamonad::returns;
using mpllibs::metamonad::lazy;
using mpllibs::metamonad::right;

/*
 * WrapperMonad
 */
namespace
{
  struct wrapper_tag : tmp_tag<wrapper_tag> {};

  typedef wrapper_tag wrapper_monad;

  MPLLIBS_METAFUNCTION(wrapped, (T)) ((tmp_value<wrapped<T>, wrapper_tag>));

  template <class T>
  struct unwrap;

  template <class T>
  struct unwrap<wrapped<T> > : returns<T> {};
}

namespace mpllibs
{
  namespace metamonad
  {
    namespace v1
    {
      template <>
      struct monad<wrapper_tag>
      {
        typedef lambda_c<t, wrapped<t> > return_;
        typedef lambda_c<a, f, apply<f, a> > bind;
      };
    }
  }
}

namespace MPLLIBS_BOOST_NAMESPACE
{
  namespace mpl
  {
    template <>
    struct equal_to_impl<wrapper_tag, wrapper_tag>
    {
      MPLLIBS_LAZY_METAFUNCTION(apply, (A)(B))
      ((lazy<equal_to<unwrap<A>, unwrap<B> > >));
    };
  }
}

namespace
{
  MPLLIBS_LAZY_METAFUNCTION(eval_to_right, (T)) ((right<T>));
}

BOOST_AUTO_TEST_CASE(test_do2)
{
  using mpllibs::metamonad::do_;
  using mpllibs::metamonad::let;
  using mpllibs::metamonad::eval_let;
  using mpllibs::metamonad::syntax;
  using mpllibs::metamonad::set;
  using mpllibs::metamonad::do_return;

  using boost::is_same;

  using boost::mpl::equal_to;

  typedef boost::mpl::tag<int13>::type int_tag;
  typedef mpllibs::metamonad::either_tag<int_tag, int_tag> either;

  // test_contents_of_return_is_substituted
  BOOST_MPL_ASSERT((
    equal_to<
      right<right<int13> >,
      do_<either,
        syntax<do_return<do_return<int13> > >
      >::type
    >
  ));

  // test_nested_do_with_different_monads
  BOOST_MPL_ASSERT((
    equal_to<
      right<wrapped<int13> >,
      do_<either,
        syntax<
          eval_to_right<
            do_<wrapper_monad,
              syntax<do_return<int13> >
            >
          >
        >
      >::type
    >
  ));

  // test_set_in_let
  BOOST_MPL_ASSERT((
    equal_to<
      right<int13>,
      eval_let<
        x, syntax<int11>,
        syntax<
          do_<either,
            syntax<set<x, do_return<int13> > >,
            syntax<do_return<x> >
          >
        >
      >::type
    >
  ));

  // test_argument_of_set_and_do_in_let
  BOOST_MPL_ASSERT((
    equal_to<
      right<int11>,
      eval_let<
        x, syntax<int11>,
        syntax<
          do_<either,
            syntax<set<x, do_return<int13> > >,
            syntax<do_return<int11> >
          >
        >
      >::type
    >
  ));

  // test_na_arguments_of_do
  BOOST_MPL_ASSERT((
    is_same<
      syntax<do_<either, syntax<do_return<int11> > > >,
      let<
        x, syntax<int11>,
        syntax<do_<either, syntax<do_return<int11> > > >
      >::type
    >
  ));
}


text:
// Copyright Marjan Drndarevski 2019
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.md
//  or copy at http://boost.org/LICENSE_1_0.txt)

#ifndef __STRUCTURE_HPP__
#define __STRUCTURE_HPP__

#include <any>

#include <boost/hana/adapt_struct.hpp>
#include <boost/hana/find.hpp>

#include <ambi/array.hpp>
#include <ambi/config.hpp>
#include <ambi/static_for.hpp>

namespace hana = boost::hana;

AMBI_NAMESPACE_BEGIN
    template<typename T>
    struct Structure {
        public:
            typedef T struct_type;

            Structure() : wrapped_struct{std::make_shared<T>()} {}

            template<typename...Args>
            Structure(Args... args);

            template<typename R, typename NAME>
            typename std::remove_pointer_t<R> getattr() const;

            template<std::size_t I, typename R,
                     std::enable_if_t<
                         std::is_fundamental_v<R>, R
                     > v = 0>
            void setattr(const R& value);

            template<std::size_t I, typename R,
                     std::enable_if_t<
                         std::is_pointer_v<R>, R
                     > p = nullptr>
            void setattr(const std::vector<std::remove_pointer_t<R>>& value);

            operator T() const noexcept
            {
                return *wrapped_struct;
            }

            operator T*() const noexcept
            {
                return wrapped_struct.get();
            }

        private:
            template<std::size_t I>
            auto& get_member() const;

            inline std::any& take_ownership(
                const std::size_t key, const std::any& object
            )
            {
                std::map<std::size_t, std::any>::iterator it = owned.find(key);
                if (it != owned.end()) {
                    it->second = object;
                } else {
                    owned.insert(std::make_pair(key, object));
                }
                return owned.at(key);
            }

        private:
            std::map<std::size_t, std::any> owned;
            std::shared_ptr<T> wrapped_struct;
    };

    template<typename T>
    template<typename... Args>
    Structure<T>::Structure(Args... args)
    {
        using Tuple = std::tuple<Args...>;

        wrapped_struct = std::make_shared<T>();
        constexpr std::size_t n = sizeof...(Args);
        auto arguments = Tuple(args...);

        // *wrapped_struct = {args...} creates dangling pointer if an
        // argument of type std::vector<T> is outlived in python.
        // Must call setattr() on all arguments to take ownership of the
        // vectors
        for_<n>([&] (auto i) {
            constexpr auto member_index = i.value;
            using RType = typename std::tuple_element_t<member_index, Tuple>;

            const auto& member = std::get<member_index>(arguments);

            if constexpr (std::is_fundamental_v<RType>) {
                this->template setattr<member_index>(member);
            } else {
                this->template
                    setattr<member_index, typename RType::value_type*>(member);
            }
        });
    }

    template<typename T>
    template<typename R, typename NAME>
    typename std::remove_pointer_t<R> Structure<T>::getattr() const
    {
        if constexpr (std::is_pointer_v<R>) {
            R member = *hana::find(*wrapped_struct, NAME{});
            if (member != nullptr) {
                return *member;
            }

            return {};
        } else {
            return *hana::find(*wrapped_struct, NAME{});
        }
    }

    template<typename T>
    template<std::size_t I>
    auto& Structure<T>::get_member() const
    {
        constexpr auto accessors = hana::accessors<T>();
        auto member = hana::second(accessors[hana::size_c<I>]);
        return member(*wrapped_struct);
    }

    template<typename T>
    template<std::size_t I, typename R,
             std::enable_if_t<std::is_fundamental_v<R>, R>>
    void Structure<T>::setattr(const R& value)
    {
        auto& member = get_member<I>();
        member = value;
    }

    template<typename T>
    template<std::size_t I, typename R,
             std::enable_if_t<std::is_pointer_v<R>, R>>
    void Structure<T>::setattr(
        const std::vector<std::remove_pointer_t<R>>& value
    )
    {
        auto& member = get_member<I>();

        using RType = std::vector<std::remove_pointer_t<R>>;

        const auto& v = std::any_cast<const RType&>(
            take_ownership(I, std::move(value))
        );

        member = const_cast<R>(v.data());
    }

#define STRUCT_MEMBER(struct_, name, type, index)                \
    constexpr auto name##_string = BOOST_HANA_STRING(#name);     \
    struct_.add_property(                                        \
        name##_string.c_str(),                                   \
        &Structure<decltype(struct_)::wrapped_type::struct_type> \
            ::getattr<type, decltype(name##_string)>,            \
        &Structure<decltype(struct_)::wrapped_type::struct_type> \
            ::setattr<index, type>                               \
    )                                                            \

AMBI_NAMESPACE_END

#endif

ext: hpp

max_stars_repo_name: mardsix/ambi

max_issues_repo_name: mardsix/ambi

max_forks_repo_name: mardsix/ambi


text:
// Copyright 2004-5 Trustees of Indiana University

// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

//
// read_graphviz_spirit.hpp -
//   Initialize a model of the BGL's MutableGraph concept and an associated
//  collection of property maps using a graph expressed in the GraphViz
// DOT Language.
//
//   Based on the grammar found at:
//   http://www.graphviz.org/cvs/doc/info/lang.html
//
//   See documentation for this code at:
//     http://www.boost.org/libs/graph/doc/read-graphviz.html
//

// Author: Ronald Garcia
//

#ifndef BOOST_READ_GRAPHVIZ_SPIRIT_HPP
#define BOOST_READ_GRAPHVIZ_SPIRIT_HPP

// Phoenix/Spirit set these limits to 3, but I need more.
#define PHOENIX_LIMIT 6
#define BOOST_SPIRIT_CLOSURE_LIMIT 6

#include <boost/spirit/iterator/multi_pass.hpp>
#include <boost/spirit/core.hpp>
#include <boost/spirit/utility/confix.hpp>
#include <boost/spirit/utility/distinct.hpp>
#include <boost/spirit/utility/lists.hpp>
#include <boost/spirit/utility/escape_char.hpp>
#include <boost/spirit/attribute.hpp>
#include <boost/spirit/dynamic.hpp>
#include <boost/spirit/actor.hpp>
#include <boost/spirit/phoenix.hpp>
#include <boost/spirit/phoenix/binders.hpp>
#include <boost/ref.hpp>
#include <boost/function/function2.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/dynamic_property_map.hpp>
#include <boost/graph/graph_traits.hpp>
#include <boost/detail/workaround.hpp>
#include <algorithm>
#include <exception> // for std::exception
#include <string>
#include <vector>
#include <set>
#include <utility>
#include <map>
#include <boost/graph/graphviz.hpp>

namespace phoenix {
// Workaround:  std::map::operator[] uses a different return type than all
// other standard containers.  Phoenix doesn't account for that.
template <typename TK, typename T0, typename T1>
struct binary_operator<index_op, std::map<TK,T0>, T1>
{
    typedef typename std::map<TK,T0>::mapped_type& result_type;
    static result_type eval(std::map<TK,T0>& container, T1 const& index)
    { return container[index]; }
};
} // namespace phoenix

namespace boost {
namespace detail {
namespace graph {

/////////////////////////////////////////////////////////////////////////////
// Application-specific type definitions
/////////////////////////////////////////////////////////////////////////////

typedef std::set<edge_t> edges_t;
typedef std::set<node_t> nodes_t;
typedef std::set<id_t> ids_t;
typedef std::map<edge_t,ids_t> edge_map_t;
typedef std::map<node_t,ids_t> node_map_t;
typedef std::map<id_t,id_t> props_t;
typedef std::map<id_t,props_t> subgraph_props_t;
typedef boost::function2<void, id_t const&, id_t const&> actor_t;
typedef std::vector<edge_t> edge_stack_t;
typedef std::map<id_t,nodes_t> subgraph_nodes_t;
typedef std::map<id_t,edges_t> subgraph_edges_t;

/////////////////////////////////////////////////////////////////////////////
// Stack frames used by semantic actions
/////////////////////////////////////////////////////////////////////////////
struct id_closure : boost::spirit::closure<id_closure, node_t> {
  member1 name;
};

struct node_id_closure : boost::spirit::closure<node_id_closure, node_t> {
  member1 name;
};

struct attr_list_closure : boost::spirit::closure<attr_list_closure, actor_t> {
  member1 prop_actor;
};

struct property_closure : boost::spirit::closure<property_closure, id_t, id_t> {
  member1 key;
  member2 value;
};

struct data_stmt_closure : boost::spirit::closure<data_stmt_closure,
                           nodes_t,nodes_t,edge_stack_t,bool,node_t> {
  member1 sources;
  member2 dests;
  member3 edge_stack;
  member4 saw_node;
  member5 active_node;
};

struct subgraph_closure : boost::spirit::closure<subgraph_closure,
                          nodes_t, edges_t, node_t> {
  member1 nodes;
  member2 edges;
  member3 name;
};

/////////////////////////////////////////////////////////////////////////////
// Grammar and Actions for the DOT Language
/////////////////////////////////////////////////////////////////////////////

// Grammar for a dot file.
struct dot_grammar : public boost::spirit::grammar<dot_grammar> {
  mutate_graph& graph_;
  explicit dot_grammar(mutate_graph& graph) : graph_(graph) { }

  template <class ScannerT>
  struct definition {

    definition(dot_grammar const& self) : self(self), subgraph_depth(0),
    keyword_p("0-9a-zA-Z_") {
      using namespace boost::spirit;
      using namespace phoenix;

      // RG - Future Work
      // - Handle multi-line strings using \ line continuation
      // - Make keywords case insensitive
      ID
          = ( lexeme_d[((alpha_p | ch_p('_')) >> *(alnum_p | ch_p('_')))]
            | real_p
            | confix_p('"', *c_escape_ch_p, '"')
            | comment_nest_p('<', '>')
            )[ID.name = construct_<std::string>(arg1,arg2)]
          ;

      a_list
          = list_p( ID[(a_list.key = arg1),
                       (a_list.value = "true")
                      ]
                    >> !( ch_p('=')
                          >> ID[a_list.value = arg1])
                          [phoenix::bind(&definition::call_prop_actor)
                          (var(*this),a_list.key,a_list.value)],ch_p(','));

      attr_list = +(ch_p('[') >> !a_list >> ch_p(']'));

      // RG - disregard port id's for now.
      port_location
          = (ch_p(':') >> ID)
          | (ch_p(':') >> ch_p('(') >> ID >> ch_p(',') >> ID >> ch_p(')'))
          ;

      port_angle = ch_p('@') >> ID;

      port
          = port_location >> (!port_angle)
          | port_angle >> (!port_location);

      node_id
          = ( ID[node_id.name = arg1] >> (!port) )
             [phoenix::bind(&definition::memoize_node)(var(*this))];

      attr_stmt
          = (as_lower_d[keyword_p("graph")]
             >> attr_list(actor_t(phoenix::bind(&definition::default_graph_prop)
                                     (var(*this),arg1,arg2))))
          | (as_lower_d[keyword_p("node")]
             >> attr_list(actor_t(phoenix::bind(&definition::default_node_prop)
                                     (var(*this),arg1,arg2))))
          | (as_lower_d[keyword_p("edge")]
             >> attr_list(actor_t(phoenix::bind(&definition::default_edge_prop)
                                     (var(*this),arg1,arg2))))
          ;

      // edge_head is set depending on the graph type (directed/undirected)
      edgeop = ch_p('-') >> ch_p(boost::ref(edge_head));

      edgeRHS
          =  +(    edgeop[(data_stmt.sources = data_stmt.dests),
                          (data_stmt.dests = construct_<nodes_t>())]
                   >> ( subgraph[data_stmt.dests = arg1]
                      | node_id[phoenix::bind(&definition::insert_node)
                                (var(*this),data_stmt.dests,arg1)]
                      )
                   [phoenix::bind(&definition::activate_edge)
                    (var(*this),data_stmt.sources,data_stmt.dests,
                     var(edges), var(default_edge_props))]
              );

      // To avoid backtracking, edge, node, and subgraph statements are
      // processed as one nonterminal.
      data_stmt
          = ( subgraph[(data_stmt.dests = arg1),// will get moved in rhs
                       (data_stmt.saw_node = false)]
            | node_id[(phoenix::bind(&definition::insert_node)
                       (var(*this),data_stmt.dests,arg1)),
                      (data_stmt.saw_node = true),
#ifdef BOOST_GRAPH_DEBUG
                      (std::cout << val("AcTive Node: ") << arg1 << "\n"),
#endif // BOOST_GRAPH_DEBUG
                      (data_stmt.active_node = arg1)]
            ) >> if_p(edgeRHS)[
                     !attr_list(
                       actor_t(phoenix::bind(&definition::edge_prop)
                               (var(*this),arg1,arg2)))
                  ].else_p[
                     if_p(data_stmt.saw_node)[
                         !attr_list(
                           actor_t(phoenix::bind(&definition::node_prop)
                                   (var(*this),arg1,arg2)))
                     ] // otherwise it's a subgraph, nothing more to do.
                  ];

      stmt
          = (ID >> ch_p('=') >> ID) // Graph property -- ignore.
          | attr_stmt
          | data_stmt
          ;

      stmt_list = *( stmt >> !ch_p(';') );

      subgraph
          = !(  as_lower_d[keyword_p("subgraph")]
                >> (!ID[(subgraph.name = arg1),
                        (subgraph.nodes = (var(subgraph_nodes))[arg1]),
                        (subgraph.edges = (var(subgraph_edges))[arg1])])
                )
          >> ch_p('{')[++var(subgraph_depth)]
          >> stmt_list
          >> ch_p('}')[--var(subgraph_depth)]
                      [(var(subgraph_nodes))[subgraph.name] = subgraph.nodes]
                      [(var(subgraph_edges))[subgraph.name] = subgraph.edges]

          | as_lower_d[keyword_p("subgraph")]
                >> ID[(subgraph.nodes = (var(subgraph_nodes))[arg1]),
                      (subgraph.edges = (var(subgraph_edges))[arg1])]
          ;

      the_grammar
          = (!as_lower_d[keyword_p("strict")])
            >>  ( as_lower_d[keyword_p("graph")][
                   (var(edge_head) = '-'),
                   (phoenix::bind(&definition::check_undirected)(var(*this)))]
                | as_lower_d[keyword_p("digraph")][
                   (var(edge_head) = '>'),
                   (phoenix::bind(&definition::check_directed)(var(*this)))]
                )
            >> (!ID) >> ch_p('{') >> stmt_list >> ch_p('}');

    } // definition()

    typedef boost::spirit::rule<ScannerT> rule_t;

    rule_t const& start() const { return the_grammar; }

    //
    // Semantic actions
    //

    void check_undirected() {
      if(self.graph_.is_directed())
        throw boost::undirected_graph_error();
    }

    void check_directed() {
      if(!self.graph_.is_directed())
        throw boost::directed_graph_error();
    }

    void memoize_node() {
      id_t const& node = node_id.name();
      props_t& node_props = default_node_props;

      if(nodes.find(node) == nodes.end()) {
        nodes.insert(node);
        self.graph_.do_add_vertex(node);

        node_map.insert(std::make_pair(node,ids_t()));

#ifdef BOOST_GRAPH_DEBUG
        std::cout << "Add new node " << node << std::endl;
#endif // BOOST_GRAPH_DEBUG
        // Set the default properties for this edge
        // RG: Here I  would actually set the properties
        for(props_t::iterator i = node_props.begin();
            i != node_props.end(); ++i) {
          set_node_property(node,i->first,i->second);
        }
        if(subgraph_depth > 0) {
          subgraph.nodes().insert(node);
          // Set the subgraph's default properties as well
          props_t& props = subgraph_node_props[subgraph.name()];
          for(props_t::iterator i = props.begin(); i != props.end(); ++i) {
            set_node_property(node,i->first,i->second);
          }
        }
      } else {
#ifdef BOOST_GRAPH_DEBUG
        std::cout << "See node " << node << std::endl;
#endif // BOOST_GRAPH_DEBUG
      }
    }

    void activate_edge(nodes_t& sources, nodes_t& dests, edges_t& edges,
                       props_t& edge_props) {
      edge_stack_t& edge_stack = data_stmt.edge_stack();
      for(nodes_t::iterator i = sources.begin(); i != sources.end(); ++i) {
        for(nodes_t::iterator j = dests.begin(); j != dests.end(); ++j) {
          // Create the edge and and push onto the edge stack.
#ifdef BOOST_GRAPH_DEBUG
          std::cout << "Edge " << *i << " to " << *j << std::endl;
#endif // BOOST_GRAPH_DEBUG

          edge_t edge = edge_t::new_edge();
          edge_stack.push_back(edge);
          edges.insert(edge);
          edge_map.insert(std::make_pair(edge,ids_t()));

          // Add the real edge.
          self.graph_.do_add_edge(edge, *i, *j);

          // Set the default properties for this edge
          for(props_t::iterator k = edge_props.begin();
              k != edge_props.end(); ++k) {
            set_edge_property(edge,k->first,k->second);
          }
          if(subgraph_depth > 0) {
            subgraph.edges().insert(edge);
            // Set the subgraph's default properties as well
            props_t& props = subgraph_edge_props[subgraph.name()];
            for(props_t::iterator k = props.begin(); k != props.end(); ++k) {
              set_edge_property(edge,k->first,k->second);
            }
          }
        }
      }
    }

    // node_prop - Assign the property for the current active node.
    void node_prop(id_t const& key, id_t const& value) {
      node_t& active_object = data_stmt.active_node();
      set_node_property(active_object, key, value);
    }

    // edge_prop - Assign the property for the current active edges.
    void edge_prop(id_t const& key, id_t const& value) {
      edge_stack_t const& active_edges_ = data_stmt.edge_stack();
      for (edge_stack_t::const_iterator i = active_edges_.begin();
           i != active_edges_.end(); ++i) {
        set_edge_property(*i,key,value);
      }
    }

    // default_graph_prop - Just ignore graph properties.
    void default_graph_prop(id_t const&, id_t const&) { }

    // default_node_prop - declare default properties for any future new nodes
    void default_node_prop(id_t const& key, id_t const& value) {
      nodes_t& nodes_ =
        subgraph_depth == 0 ? nodes : subgraph.nodes();
      props_t& node_props_ =
        subgraph_depth == 0 ?
        default_node_props :
        subgraph_node_props[subgraph.name()];

      // add this to the selected list of default node properties.
      node_props_[key] = value;
      // for each node, set its property to default-constructed value
      //   if it hasn't been set already.
      // set the dynamic property map value
      for(nodes_t::iterator i = nodes_.begin(); i != nodes_.end(); ++i)
        if(node_map[*i].find(key) == node_map[*i].end()) {
          set_node_property(*i,key,id_t());
        }
    }

    // default_edge_prop - declare default properties for any future new edges
   void default_edge_prop(id_t const& key, id_t const& value) {
      edges_t& edges_ =
        subgraph_depth == 0 ? edges : subgraph.edges();
      props_t& edge_props_ =
        subgraph_depth == 0 ?
        default_edge_props :
        subgraph_edge_props[subgraph.name()];

      // add this to the list of default edge properties.
      edge_props_[key] = value;
      // for each edge, set its property to be empty string
      // set the dynamic property map value
      for(edges_t::iterator i = edges_.begin(); i != edges_.end(); ++i)
        if(edge_map[*i].find(key) == edge_map[*i].end())
          set_edge_property(*i,key,id_t());
    }

    // helper function
    void insert_node(nodes_t& nodes, id_t const& name) {
      nodes.insert(name);
    }

    void call_prop_actor(std::string const& lhs, std::string const& rhs) {
      actor_t& actor = attr_list.prop_actor();
      // If first and last characters of the rhs are double-quotes,
      // remove them.
      if (!rhs.empty() && rhs[0] == '"' && rhs[rhs.size() - 1] == '"')
        actor(lhs, rhs.substr(1, rhs.size()-2));
      else
        actor(lhs,rhs);
    }

    void set_node_property(node_t const& node, id_t const& key,
                           id_t const& value) {

      // Add the property key to the "set" table to avoid default overwrite
      node_map[node].insert(key);
      // Set the user's property map
      self.graph_.set_node_property(key, node, value);
#ifdef BOOST_GRAPH_DEBUG
      // Tell the world
      std::cout << node << ": " << key << " = " << value << std::endl;
#endif // BOOST_GRAPH_DEBUG
    }

    void set_edge_property(edge_t const& edge, id_t const& key,
                           id_t const& value) {

      // Add the property key to the "set" table to avoid default overwrite
      edge_map[edge].insert(key);
      // Set the user's property map
      self.graph_.set_edge_property(key, edge, value);
#ifdef BOOST_GRAPH_DEBUG
      // Tell the world
      std::cout << "(" << edge.first << "," << edge.second << "): "
                << key << " = " << value << std::endl;
#endif // BOOST_GRAPH_DEBUG
    }

    // Variables explicitly initialized
    dot_grammar const& self;
    // if subgraph_depth > 0, then we're processing a subgraph.
    int subgraph_depth;

    // Keywords;
    const boost::spirit::distinct_parser<> keyword_p;
    //
    // rules that make up the grammar
    //
    boost::spirit::rule<ScannerT,id_closure::context_t> ID;
    boost::spirit::rule<ScannerT,property_closure::context_t> a_list;
    boost::spirit::rule<ScannerT,attr_list_closure::context_t> attr_list;
    rule_t port_location;
    rule_t port_angle;
    rule_t port;
    boost::spirit::rule<ScannerT,node_id_closure::context_t> node_id;
    rule_t attr_stmt;
    boost::spirit::rule<ScannerT,data_stmt_closure::context_t> data_stmt;
    boost::spirit::rule<ScannerT,subgraph_closure::context_t> subgraph;
    rule_t edgeop;
    rule_t edgeRHS;
    rule_t stmt;
    rule_t stmt_list;
    rule_t the_grammar;

    // The grammar uses edge_head to dynamically set the syntax for edges
    // directed graphs: edge_head = '>', and so edgeop = "->"
    // undirected graphs: edge_head = '-', and so edgeop = "--"
    char edge_head;

    //
    // Support data structures
    //

    nodes_t nodes;  // list of node names seen
    edges_t edges;  // list of edges seen
    node_map_t node_map; // remember the properties set for each node
    edge_map_t edge_map; // remember the properties set for each edge

    subgraph_nodes_t subgraph_nodes;   // per-subgraph lists of nodes
    subgraph_edges_t subgraph_edges;   // per-subgraph lists of edges

    props_t default_node_props;  // global default node properties
    props_t default_edge_props;  // global default edge properties
    subgraph_props_t subgraph_node_props;  // per-subgraph default node properties
    subgraph_props_t subgraph_edge_props;  // per-subgraph default edge properties
  }; // struct definition
}; // struct dot_grammar

//
// dot_skipper - GraphViz whitespace and comment skipper
//
struct dot_skipper : public boost::spirit::grammar<dot_skipper>
{
    dot_skipper() {}

    template <typename ScannerT>
    struct definition
    {
        definition(dot_skipper const& /*self*/)  {
          using namespace boost::spirit;
          using namespace phoenix;
          // comment forms
          skip = space_p
               | comment_p("//")
               | comment_p("#")
#if BOOST_WORKAROUND(BOOST_MSVC, <= 1400)
               | confix_p(str_p("/*") ,*anychar_p, str_p("*/"))
#else
               | confix_p("/*" ,*anychar_p, "*/")
#endif
               ;

#ifdef BOOST_SPIRIT_DEBUG
               BOOST_SPIRIT_DEBUG_RULE(skip);
#endif
        }

      boost::spirit::rule<ScannerT>  skip;
      boost::spirit::rule<ScannerT> const&
      start() const { return skip; }
    }; // definition
}; // dot_skipper

} // namespace graph
} // namespace detail

template <typename MultiPassIterator, typename MutableGraph>
bool read_graphviz(MultiPassIterator begin, MultiPassIterator end,
                   MutableGraph& graph, dynamic_properties& dp,
                   std::string const& node_id = "node_id") {
  using namespace boost;
  using namespace boost::spirit;

  typedef MultiPassIterator iterator_t;
  typedef skip_parser_iteration_policy< boost::detail::graph::dot_skipper>
    iter_policy_t;
  typedef scanner_policies<iter_policy_t> scanner_policies_t;
  typedef scanner<iterator_t, scanner_policies_t> scanner_t;

  ::boost::detail::graph::mutate_graph_impl<MutableGraph>
      m_graph(graph, dp, node_id);

  ::boost::detail::graph::dot_grammar p(m_graph);
  ::boost::detail::graph::dot_skipper skip_p;

  iter_policy_t iter_policy(skip_p);
  scanner_policies_t policies(iter_policy);

  scanner_t scan(begin, end, policies);

  return p.parse(scan);
}

} // namespace boost

#endif // BOOST_READ_GRAPHVIZ_SPIRIT_HPP

max_stars_repo_name: dstrigl/mcotf

max_issues_repo_name: dstrigl/mcotf

max_forks_repo_name: dstrigl/mcotf


text:
// https://qiita.com/benikabocha/items/5ec6b471de0d10aaf2df

// cppからpythonへEigenの配列を参照渡しするサンプル

/*
#include <pybind11/embed.h>

#include <pybind11/eval.h>
#include <pybind11/pybind11.h>
//#include <pybind11/numpy.h>
//#include <pybind11/eigen.h>

//#include <Eigen/Dense>

#include <pybind11/stl.h>
#include <pybind11/stl_bind.h>
PYBIND11_MAKE_OPAQUE(std::vector<int>);

#include <iostream>

namespace py = pybind11;

int main(int argc, char** argv) {
	wchar_t* program = Py_DecodeLocale(argv[0], nullptr);
	if (program == nullptr) {
		fprintf(stderr, "Fatal error: cannot decode argv[0]\n");
		exit(1);
	}

	Py_SetProgramName(program);
	Py_Initialize();
//	py::scoped_interpreter guard{};

	try {
		auto global = py::dict(py::module::import("__main__").attr("__dict__"));
		auto local = py::dict();
		// ここにコードを記述していく
		py::exec(
					"import numpy as np\n"
					"arr = np.array([1,2,])\n"
					"print(arr)\n",
					global);
		py::exec(
					"def tes(a):\n"
					"	print(1)\n",
					global);
		auto func_tes = global["tes"];
		std::vector<int> a;
		a.push_back(1);
		a.push_back(3);
//		func_tes(py::cast(&a));

	} catch (py::error_already_set& e) {
		std::cout << "Python error.\n" << e.what() << "\n";
	}

	Py_Finalize();
	PyMem_RawFree(program);

	return 0;
}

*/

// https://pybind11.readthedocs.io/en/stable/advanced/embedding.html
// https://github.com/pybind/pybind11/issues/1508

#include <pybind11/embed.h> // everything needed for embedding
#include <pybind11/pybind11.h>
#include <pybind11/stl_bind.h>

#include <iostream>
namespace py = pybind11;

PYBIND11_MAKE_OPAQUE(std::vector<int>);

PYBIND11_EMBEDDED_MODULE(_cc11binds, m) {
	m.doc() = "C++ type bindings created by py11bind";
	py::bind_vector<std::vector<int>>(m, "IntVector", py::module_local(false));
}

int main() {
	py::scoped_interpreter guard{}; // start the interpreter and keep it alive

	py::print("Hello, World!"); // use the Python API

	py::exec(R"(
        kwargs = dict(name="World", number=42)
        message = "Hello, {name}! The answer is {number}".format(**kwargs)
        print(message)
    )");
	py::exec(R"(
			 import numpy as np
			 arr = np.array([1,2])
			 print(arr)
			 )");
	py::module m;
	py::module::import("_cc11binds");
	m = py::module::import("stl");
	auto addFunc = m.attr("add");

	std::vector<int> v;
	v.push_back(3);
	v.push_back(6);

	std::cout << "before" << std::endl;
	for(auto &&val:v){
		std::cout << val << std::endl;
	}

	addFunc(&v);

	std::cout << "after" << std::endl;
	for(auto &&val:v){
		std::cout << val << std::endl;
	}

}