text:
///////////////////////////////////////////////////////////////////////////////
/// \file matches.hpp
/// Contains definition of matches\<\> metafunction for determining if
/// a given expression matches a given pattern.
//
//  Copyright 2008 Eric Niebler. 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)

#ifndef BOOST_PROTO_MATCHES_HPP_EAN_11_03_2006
#define BOOST_PROTO_MATCHES_HPP_EAN_11_03_2006

#include <boost/config.hpp>
#include <boost/detail/workaround.hpp>
#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/arithmetic/dec.hpp>
#include <boost/preprocessor/arithmetic/sub.hpp>
#include <boost/preprocessor/iteration/iterate.hpp>
#include <boost/preprocessor/facilities/intercept.hpp>
#include <boost/preprocessor/punctuation/comma_if.hpp>
#include <boost/preprocessor/repetition/enum.hpp>
#include <boost/preprocessor/repetition/enum_params.hpp>
#include <boost/preprocessor/repetition/enum_shifted.hpp>
#include <boost/preprocessor/repetition/enum_binary_params.hpp>
#include <boost/preprocessor/repetition/enum_shifted_params.hpp>
#include <boost/preprocessor/repetition/enum_trailing_params.hpp>
#include <boost/preprocessor/repetition/enum_params_with_a_default.hpp>
#include <boost/preprocessor/repetition/repeat.hpp>
#include <boost/config.hpp>
#include <boost/mpl/logical.hpp>
#include <boost/mpl/eval_if.hpp>
#include <boost/proto/detail/template_arity.hpp>
#include <boost/utility/enable_if.hpp>
#if BOOST_WORKAROUND(BOOST_MSVC, == 1310)
#include <boost/type_traits/is_array.hpp>
#endif
#include <boost/type_traits/is_const.hpp>
#include <boost/type_traits/is_convertible.hpp>
#include <boost/type_traits/is_reference.hpp>
#include <boost/type_traits/is_pointer.hpp>
#include <boost/proto/proto_fwd.hpp>
#include <boost/proto/traits.hpp>
#include <boost/proto/transform/when.hpp>
#include <boost/proto/transform/impl.hpp>

#if defined(_MSC_VER) && (_MSC_VER >= 1020)
# pragma warning(push)
# pragma warning(disable:4305) // 'specialization' : truncation from 'const int' to 'bool'
#endif

#define BOOST_PROTO_LOGICAL_typename_G  BOOST_PP_ENUM_PARAMS(BOOST_PROTO_MAX_LOGICAL_ARITY, typename G)
#define BOOST_PROTO_LOGICAL_G           BOOST_PP_ENUM_PARAMS(BOOST_PROTO_MAX_LOGICAL_ARITY, G)

namespace boost { namespace proto
{

    namespace detail
    {
        template<typename Expr, typename BasicExpr, typename Grammar>
        struct matches_;

        template<bool B, typename Pred>
        struct and_2;

        template<typename And, typename Expr, typename State, typename Data>
        struct _and_impl;

        template<typename T, typename U>
        struct array_matches
          : mpl::false_
        {};

        template<typename T, std::size_t M>
        struct array_matches<T[M], T *>
          : mpl::true_
        {};

        template<typename T, std::size_t M>
        struct array_matches<T[M], T const *>
          : mpl::true_
        {};

        template<typename T, std::size_t M>
        struct array_matches<T[M], T[proto::N]>
          : mpl::true_
        {};

        template<typename T, typename U
            BOOST_PROTO_TEMPLATE_ARITY_PARAM(long Arity = detail::template_arity<U>::value)
        >
        struct lambda_matches
          : mpl::false_
        {};

        template<typename T>
        struct lambda_matches<T, proto::_ BOOST_PROTO_TEMPLATE_ARITY_PARAM(-1)>
          : mpl::true_
        {};

        template<typename T>
        struct lambda_matches<T, T BOOST_PROTO_TEMPLATE_ARITY_PARAM(-1)>
          : mpl::true_
        {};

        template<typename T, std::size_t M, typename U>
        struct lambda_matches<T[M], U BOOST_PROTO_TEMPLATE_ARITY_PARAM(-1)>
          : array_matches<T[M], U>
        {};

        template<typename T, std::size_t M>
        struct lambda_matches<T[M], _ BOOST_PROTO_TEMPLATE_ARITY_PARAM(-1)>
          : mpl::true_
        {};

        template<typename T, std::size_t M>
        struct lambda_matches<T[M], T[M] BOOST_PROTO_TEMPLATE_ARITY_PARAM(-1)>
          : mpl::true_
        {};

        template<template<typename> class T, typename Expr0, typename Grammar0>
        struct lambda_matches<T<Expr0>, T<Grammar0> BOOST_PROTO_TEMPLATE_ARITY_PARAM(1) >
          : lambda_matches<Expr0, Grammar0>
        {};

        // vararg_matches_impl
        template<typename Args1, typename Back, long From, long To>
        struct vararg_matches_impl;

        // vararg_matches
        template<typename Expr, typename Args1, typename Args2, typename Back, bool Can, bool Zero, typename Void = void>
        struct vararg_matches
          : mpl::false_
        {};

        template<typename Expr, typename Args1, typename Args2, typename Back>
        struct vararg_matches<Expr, Args1, Args2, Back, true, true, typename Back::proto_is_vararg_>
          : matches_<
                Expr
              , proto::basic_expr<ignore, Args1, Args1::arity>
              , proto::basic_expr<ignore, Args2, Args1::arity>
            >
        {};

        template<typename Expr, typename Args1, typename Args2, typename Back>
        struct vararg_matches<Expr, Args1, Args2, Back, true, false, typename Back::proto_is_vararg_>
          : and_2<
                matches_<
                    Expr
                  , proto::basic_expr<ignore, Args1, Args2::arity>
                  , proto::basic_expr<ignore, Args2, Args2::arity>
                >::value
              , vararg_matches_impl<Args1, typename Back::proto_grammar, Args2::arity + 1, Args1::arity>
            >
        {};

        // How terminal_matches<> handles references and cv-qualifiers.
        // The cv and ref matter *only* if the grammar has a top-level ref.
        //
        // Expr       |   Grammar    |  Matches?
        // -------------------------------------
        // T              T             yes
        // T &            T             yes
        // T const &      T             yes
        // T              T &           no
        // T &            T &           yes
        // T const &      T &           no
        // T              T const &     no
        // T &            T const &     no
        // T const &      T const &     yes

        template<typename T, typename U>
        struct is_cv_ref_compatible
          : mpl::true_
        {};

        template<typename T, typename U>
        struct is_cv_ref_compatible<T, U &>
          : mpl::false_
        {};

        template<typename T, typename U>
        struct is_cv_ref_compatible<T &, U &>
          : mpl::bool_<is_const<T>::value == is_const<U>::value>
        {};

    #if BOOST_WORKAROUND(BOOST_MSVC, == 1310)
        // MSVC-7.1 has lots of problems with array types that have been
        // deduced. Partially specializing terminal_matches<> on array types
        // doesn't seem to work.
        template<
            typename T
          , typename U
          , bool B = is_array<BOOST_PROTO_UNCVREF(T)>::value
        >
        struct terminal_array_matches
          : mpl::false_
        {};

        template<typename T, typename U, std::size_t M>
        struct terminal_array_matches<T, U(&)[M], true>
          : is_convertible<T, U(&)[M]>
        {};

        template<typename T, typename U>
        struct terminal_array_matches<T, U(&)[proto::N], true>
          : is_convertible<T, U *>
        {};

        template<typename T, typename U>
        struct terminal_array_matches<T, U *, true>
          : is_convertible<T, U *>
        {};

        // terminal_matches
        template<typename T, typename U>
        struct terminal_matches
          : mpl::or_<
                mpl::and_<
                    is_cv_ref_compatible<T, U>
                  , lambda_matches<
                        BOOST_PROTO_UNCVREF(T)
                      , BOOST_PROTO_UNCVREF(U)
                    >
                >
              , terminal_array_matches<T, U>
            >
        {};
    #else
        // terminal_matches
        template<typename T, typename U>
        struct terminal_matches
          : mpl::and_<
                is_cv_ref_compatible<T, U>
              , lambda_matches<
                    BOOST_PROTO_UNCVREF(T)
                  , BOOST_PROTO_UNCVREF(U)
                >
            >
        {};

        template<typename T, std::size_t M>
        struct terminal_matches<T(&)[M], T(&)[proto::N]>
          : mpl::true_
        {};

        template<typename T, std::size_t M>
        struct terminal_matches<T(&)[M], T *>
          : mpl::true_
        {};

        // Avoid ambiguity errors on MSVC
        #if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1500))
        template<typename T, std::size_t M>
        struct terminal_matches<T const (&)[M], T const[M]>
          : mpl::true_
        {};
        #endif
    #endif

        template<typename T>
        struct terminal_matches<T, T>
          : mpl::true_
        {};

        template<typename T>
        struct terminal_matches<T &, T>
          : mpl::true_
        {};

        template<typename T>
        struct terminal_matches<T const &, T>
          : mpl::true_
        {};

        template<typename T>
        struct terminal_matches<T, proto::_>
          : mpl::true_
        {};

        template<typename T>
        struct terminal_matches<T, exact<T> >
          : mpl::true_
        {};

        template<typename T, typename U>
        struct terminal_matches<T, proto::convertible_to<U> >
          : is_convertible<T, U>
        {};

        // matches_
        template<typename Expr, typename BasicExpr, typename Grammar>
        struct matches_
          : mpl::false_
        {};

        template<typename Expr, typename BasicExpr>
        struct matches_< Expr, BasicExpr, proto::_ >
          : mpl::true_
        {};

        template<typename Expr, typename Tag, typename Args1, long N1, typename Args2, long N2>
        struct matches_< Expr, proto::basic_expr<Tag, Args1, N1>, proto::basic_expr<Tag, Args2, N2> >
          : vararg_matches< Expr, Args1, Args2, typename Args2::back_, (N1+2 > N2), (N2 > N1) >
        {};

        template<typename Expr, typename Tag, typename Args1, long N1, typename Args2, long N2>
        struct matches_< Expr, proto::basic_expr<Tag, Args1, N1>, proto::basic_expr<proto::_, Args2, N2> >
          : vararg_matches< Expr, Args1, Args2, typename Args2::back_, (N1+2 > N2), (N2 > N1) >
        {};

        template<typename Expr, typename Tag, typename Args1, typename Args2>
        struct matches_< Expr, proto::basic_expr<Tag, Args1, 0>, proto::basic_expr<Tag, Args2, 0> >
          : terminal_matches<typename Args1::child0, typename Args2::child0>
        {};

        template<typename Expr, typename Tag, typename Args1, typename Args2, long N2>
        struct matches_< Expr, proto::basic_expr<Tag, Args1, 0>, proto::basic_expr<proto::_, Args2, N2> >
          : mpl::false_
        {};

        template<typename Expr, typename Tag, typename Args1, typename Args2>
        struct matches_< Expr, proto::basic_expr<Tag, Args1, 0>, proto::basic_expr<proto::_, Args2, 0> >
          : terminal_matches<typename Args1::child0, typename Args2::child0>
        {};

        template<typename Expr, typename Tag, typename Args1, typename Args2>
        struct matches_< Expr, proto::basic_expr<Tag, Args1, 1>, proto::basic_expr<Tag, Args2, 1> >
          : matches_<
                typename detail::expr_traits<typename Args1::child0>::value_type::proto_derived_expr
              , typename detail::expr_traits<typename Args1::child0>::value_type::proto_grammar
              , typename Args2::child0::proto_grammar
            >
        {};

        template<typename Expr, typename Tag, typename Args1, typename Args2>
        struct matches_< Expr, proto::basic_expr<Tag, Args1, 1>, proto::basic_expr<proto::_, Args2, 1> >
          : matches_<
                typename detail::expr_traits<typename Args1::child0>::value_type::proto_derived_expr
              , typename detail::expr_traits<typename Args1::child0>::value_type::proto_grammar
              , typename Args2::child0::proto_grammar
            >
        {};

        #include <boost/proto/detail/and_n.hpp>
        #include <boost/proto/detail/or_n.hpp>
        #include <boost/proto/detail/matches_.hpp>
        #include <boost/proto/detail/vararg_matches_impl.hpp>
        #include <boost/proto/detail/lambda_matches.hpp>

        // handle proto::if_
        template<typename Expr, typename Tag, typename Args, long Arity, typename If, typename Then, typename Else>
        struct matches_<Expr, proto::basic_expr<Tag, Args, Arity>, proto::if_<If, Then, Else> >
          : mpl::eval_if_c<
                remove_reference<
                    typename when<_, If>::template impl<Expr, int, int>::result_type
                >::type::value
              , matches_<Expr, proto::basic_expr<Tag, Args, Arity>, typename Then::proto_grammar>
              , matches_<Expr, proto::basic_expr<Tag, Args, Arity>, typename Else::proto_grammar>
            >::type
        {
            typedef
                typename mpl::if_c<
                    remove_reference<
                        typename when<_, If>::template impl<Expr, int, int>::result_type
                    >::type::value
                  , Then
                  , Else
                >::type
            which;
        };

        // handle degenerate cases of proto::or_
        template<typename Expr, typename BasicExpr>
        struct matches_<Expr, BasicExpr, or_<> >
          : mpl::false_
        {
            typedef not_<_> which;
        };

        template<typename Expr, typename BasicExpr, typename G0>
        struct matches_<Expr, BasicExpr, or_<G0> >
          : matches_<Expr, BasicExpr, typename G0::proto_grammar>
        {
            typedef G0 which;
        };

        // handle degenerate cases of proto::and_
        template<typename Expr, typename BasicExpr>
        struct matches_<Expr, BasicExpr, and_<> >
          : mpl::true_
        {};

        template<typename Expr, typename BasicExpr, typename G0>
        struct matches_<Expr, BasicExpr, and_<G0> >
          : matches_<Expr, BasicExpr, typename G0::proto_grammar>
        {};

        // handle proto::not_
        template<typename Expr, typename BasicExpr, typename Grammar>
        struct matches_<Expr, BasicExpr, not_<Grammar> >
          : mpl::not_<matches_<Expr, BasicExpr, typename Grammar::proto_grammar> >
        {};

        // handle proto::switch_
        template<typename Expr, typename Tag, typename Args, long Arity, typename Cases, typename Transform>
        struct matches_<Expr, proto::basic_expr<Tag, Args, Arity>, switch_<Cases, Transform> >
          : matches_<
                Expr
              , proto::basic_expr<Tag, Args, Arity>
              , typename Cases::template case_<
                    typename when<_,Transform>::template impl<Expr,int,int>::result_type
                >::proto_grammar
            >
        {
            typedef
                typename Cases::template case_<
                    typename when<_, Transform>::template impl<Expr, int, int>::result_type
                >
            which;
        };

        // handle proto::switch_ with the default Transform for specially for better compile times
        template<typename Expr, typename Tag, typename Args, long Arity, typename Cases>
        struct matches_<Expr, proto::basic_expr<Tag, Args, Arity>, switch_<Cases> >
          : matches_<
                Expr
              , proto::basic_expr<Tag, Args, Arity>
              , typename Cases::template case_<Tag>::proto_grammar
            >
        {
            typedef typename Cases::template case_<Tag> which;
        };
    }

    /// \brief A Boolean metafunction that evaluates whether a given
    /// expression type matches a grammar.
    ///
    /// <tt>matches\<Expr,Grammar\></tt> inherits (indirectly) from
    /// \c mpl::true_ if <tt>Expr::proto_grammar</tt> matches
    /// <tt>Grammar::proto_grammar</tt>, and from \c mpl::false_
    /// otherwise.
    ///
    /// Non-terminal expressions are matched against a grammar
    /// according to the following rules:
    ///
    /// \li The wildcard pattern, \c _, matches any expression.
    /// \li An expression <tt>expr\<AT, listN\<A0,A1,...An\> \></tt>
    ///     matches a grammar <tt>expr\<BT, listN\<B0,B1,...Bn\> \></tt>
    ///     if \c BT is \c _ or \c AT, and if \c Ax matches \c Bx for
    ///     each \c x in <tt>[0,n)</tt>.
    /// \li An expression <tt>expr\<AT, listN\<A0,...An,U0,...Um\> \></tt>
    ///     matches a grammar <tt>expr\<BT, listM\<B0,...Bn,vararg\<V\> \> \></tt>
    ///     if \c BT is \c _ or \c AT, and if \c Ax matches \c Bx
    ///     for each \c x in <tt>[0,n)</tt> and if \c Ux matches \c V
    ///     for each \c x in <tt>[0,m)</tt>.
    /// \li An expression \c E matches <tt>or_\<B0,B1,...Bn\></tt> if \c E
    ///     matches some \c Bx for \c x in <tt>[0,n)</tt>.
    /// \li An expression \c E matches <tt>and_\<B0,B1,...Bn\></tt> if \c E
    ///     matches all \c Bx for \c x in <tt>[0,n)</tt>.
    /// \li An expression \c E matches <tt>if_\<T,U,V\></tt> if
    ///     <tt>boost::result_of\<when\<_,T\>(E,int,int)\>::type::value</tt>
    ///     is \c true and \c E matches \c U; or, if
    ///     <tt>boost::result_of\<when\<_,T\>(E,int,int)\>::type::value</tt>
    ///     is \c false and \c E matches \c V. (Note: \c U defaults to \c _
    ///     and \c V defaults to \c not_\<_\>.)
    /// \li An expression \c E matches <tt>not_\<T\></tt> if \c E does
    ///     not match \c T.
    /// \li An expression \c E matches <tt>switch_\<C,T\></tt> if
    ///     \c E matches <tt>C::case_\<boost::result_of\<T(E)\>::type\></tt>.
    ///     (Note: T defaults to <tt>tag_of\<_\>()</tt>.)
    ///
    /// A terminal expression <tt>expr\<AT,term\<A\> \></tt> matches
    /// a grammar <tt>expr\<BT,term\<B\> \></tt> if \c BT is \c AT or
    /// \c proto::_ and if one of the following is true:
    ///
    /// \li \c B is the wildcard pattern, \c _
    /// \li \c A is \c B
    /// \li \c A is <tt>B &</tt>
    /// \li \c A is <tt>B const &</tt>
    /// \li \c B is <tt>exact\<A\></tt>
    /// \li \c B is <tt>convertible_to\<X\></tt> and
    ///     <tt>is_convertible\<A,X\>::value</tt> is \c true.
    /// \li \c A is <tt>X[M]</tt> or <tt>X(&)[M]</tt> and
    ///     \c B is <tt>X[proto::N]</tt>.
    /// \li \c A is <tt>X(&)[M]</tt> and \c B is <tt>X(&)[proto::N]</tt>.
    /// \li \c A is <tt>X[M]</tt> or <tt>X(&)[M]</tt> and
    ///     \c B is <tt>X*</tt>.
    /// \li \c B lambda-matches \c A (see below).
    ///
    /// A type \c B lambda-matches \c A if one of the following is true:
    ///
    /// \li \c B is \c A
    /// \li \c B is the wildcard pattern, \c _
    /// \li \c B is <tt>T\<B0,B1,...Bn\></tt> and \c A is
    ///     <tt>T\<A0,A1,...An\></tt> and for each \c x in
    ///     <tt>[0,n)</tt>, \c Ax and \c Bx are types
    ///     such that \c Ax lambda-matches \c Bx
    template<typename Expr, typename Grammar>
    struct matches
      : detail::matches_<
            typename Expr::proto_derived_expr
          , typename Expr::proto_grammar
          , typename Grammar::proto_grammar
        >
    {};

    /// INTERNAL ONLY
    ///
    template<typename Expr, typename Grammar>
    struct matches<Expr &, Grammar>
      : detail::matches_<
            typename Expr::proto_derived_expr
          , typename Expr::proto_grammar
          , typename Grammar::proto_grammar
        >
    {};

    /// \brief A wildcard grammar element that matches any expression,
    /// and a transform that returns the current expression unchanged.
    ///
    /// The wildcard type, \c _, is a grammar element such that
    /// <tt>matches\<E,_\>::value</tt> is \c true for any expression
    /// type \c E.
    ///
    /// The wildcard can also be used as a stand-in for a template
    /// argument when matching terminals. For instance, the following
    /// is a grammar that will match any <tt>std::complex\<\></tt>
    /// terminal:
    ///
    /// \code
    /// BOOST_MPL_ASSERT((
    ///     matches<
    ///         terminal<std::complex<double> >::type
    ///       , terminal<std::complex< _ > >
    ///     >
    /// ));
    /// \endcode
    ///
    /// When used as a transform, \c _ returns the current expression
    /// unchanged. For instance, in the following, \c _ is used with
    /// the \c fold\<\> transform to fold the children of a node:
    ///
    /// \code
    /// struct CountChildren
    ///   : or_<
    ///         // Terminals have no children
    ///         when<terminal<_>, mpl::int_<0>()>
    ///         // Use fold<> to count the children of non-terminals
    ///       , otherwise<
    ///             fold<
    ///                 _ // <-- fold the current expression
    ///               , mpl::int_<0>()
    ///               , mpl::plus<_state, mpl::int_<1> >()
    ///             >
    ///         >
    ///     >
    /// {};
    /// \endcode
    struct _ : transform<_>
    {
        typedef _ proto_grammar;

        template<typename Expr, typename State, typename Data>
        struct impl : transform_impl<Expr, State, Data>
        {
            typedef Expr result_type;

            /// \param expr An expression
            /// \return \c e
            #ifdef BOOST_PROTO_STRICT_RESULT_OF
            result_type
            #else
            typename impl::expr_param
            #endif
            operator()(
                typename impl::expr_param e
              , typename impl::state_param
              , typename impl::data_param
            ) const
            {
                return e;
            }
        };
    };

    namespace detail
    {
        template<typename Expr, typename State, typename Data>
        struct _and_impl<proto::and_<>, Expr, State, Data>
          : proto::_::impl<Expr, State, Data>
        {};

        template<typename G0, typename Expr, typename State, typename Data>
        struct _and_impl<proto::and_<G0>, Expr, State, Data>
          : proto::when<proto::_, G0>::template impl<Expr, State, Data>
        {};
    }

    /// \brief Inverts the set of expressions matched by a grammar. When
    /// used as a transform, \c not_\<\> returns the current expression
    /// unchanged.
    ///
    /// If an expression type \c E does not match a grammar \c G, then
    /// \c E \e does match <tt>not_\<G\></tt>. For example,
    /// <tt>not_\<terminal\<_\> \></tt> will match any non-terminal.
    template<typename Grammar>
    struct not_ : transform<not_<Grammar> >
    {
        typedef not_ proto_grammar;

        template<typename Expr, typename State, typename Data>
        struct impl : transform_impl<Expr, State, Data>
        {
            typedef Expr result_type;

            /// \param e An expression
            /// \pre <tt>matches\<Expr,not_\>::value</tt> is \c true.
            /// \return \c e
            #ifdef BOOST_PROTO_STRICT_RESULT_OF
            result_type
            #else
            typename impl::expr_param
            #endif
            operator()(
                typename impl::expr_param e
              , typename impl::state_param
              , typename impl::data_param
            ) const
            {
                return e;
            }
        };
    };

    /// \brief Used to select one grammar or another based on the result
    /// of a compile-time Boolean. When used as a transform, \c if_\<\>
    /// selects between two transforms based on a compile-time Boolean.
    ///
    /// When <tt>if_\<If,Then,Else\></tt> is used as a grammar, \c If
    /// must be a Proto transform and \c Then and \c Else must be grammars.
    /// An expression type \c E matches <tt>if_\<If,Then,Else\></tt> if
    /// <tt>boost::result_of\<when\<_,If\>(E,int,int)\>::type::value</tt>
    /// is \c true and \c E matches \c U; or, if
    /// <tt>boost::result_of\<when\<_,If\>(E,int,int)\>::type::value</tt>
    /// is \c false and \c E matches \c V.
    ///
    /// The template parameter \c Then defaults to \c _
    /// and \c Else defaults to \c not\<_\>, so an expression type \c E
    /// will match <tt>if_\<If\></tt> if and only if
    /// <tt>boost::result_of\<when\<_,If\>(E,int,int)\>::type::value</tt>
    /// is \c true.
    ///
    /// \code
    /// // A grammar that only matches integral terminals,
    /// // using is_integral<> from Boost.Type_traits.
    /// struct IsIntegral
    ///   : and_<
    ///         terminal<_>
    ///       , if_< is_integral<_value>() >
    ///     >
    /// {};
    /// \endcode
    ///
    /// When <tt>if_\<If,Then,Else\></tt> is used as a transform, \c If,
    /// \c Then and \c Else must be Proto transforms. When applying
    /// the transform to an expression \c E, state \c S and data \c V,
    /// if <tt>boost::result_of\<when\<_,If\>(E,S,V)\>::type::value</tt>
    /// is \c true then the \c Then transform is applied; otherwise
    /// the \c Else transform is applied.
    ///
    /// \code
    /// // Match a terminal. If the terminal is integral, return
    /// // mpl::true_; otherwise, return mpl::false_.
    /// struct IsIntegral2
    ///   : when<
    ///         terminal<_>
    ///       , if_<
    ///             is_integral<_value>()
    ///           , mpl::true_()
    ///           , mpl::false_()
    ///         >
    ///     >
    /// {};
    /// \endcode
    template<
        typename If
      , typename Then   // = _
      , typename Else   // = not_<_>
    >
    struct if_ : transform<if_<If, Then, Else> >
    {
        typedef if_ proto_grammar;

        template<typename Expr, typename State, typename Data>
        struct impl : transform_impl<Expr, State, Data>
        {
            typedef
                typename when<_, If>::template impl<Expr, State, Data>::result_type
            condition;

            typedef
                typename mpl::if_c<
                    remove_reference<condition>::type::value
                  , when<_, Then>
                  , when<_, Else>
                >::type
            which;

            typedef typename which::template impl<Expr, State, Data>::result_type result_type;

            /// \param e An expression
            /// \param s The current state
            /// \param d A data of arbitrary type
            /// \return <tt>which::impl<Expr, State, Data>()(e, s, d)</tt>
            result_type operator ()(
                typename impl::expr_param e
              , typename impl::state_param s
              , typename impl::data_param d
            ) const
            {
                return typename which::template impl<Expr, State, Data>()(e, s, d);
            }
        };
    };

    /// \brief For matching one of a set of alternate grammars. Alternates
    /// tried in order to avoid ambiguity. When used as a transform, \c or_\<\>
    /// applies the transform associated with the first grammar that matches
    /// the expression.
    ///
    /// An expression type \c E matches <tt>or_\<B0,B1,...Bn\></tt> if \c E
    /// matches any \c Bx for \c x in <tt>[0,n)</tt>.
    ///
    /// When applying <tt>or_\<B0,B1,...Bn\></tt> as a transform with an
    /// expression \c e of type \c E, state \c s and data \c d, it is
    /// equivalent to <tt>Bx()(e, s, d)</tt>, where \c x is the lowest
    /// number such that <tt>matches\<E,Bx\>::value</tt> is \c true.
    template<BOOST_PROTO_LOGICAL_typename_G>
    struct or_ : transform<or_<BOOST_PROTO_LOGICAL_G> >
    {
        typedef or_ proto_grammar;

        /// \param e An expression
        /// \param s The current state
        /// \param d A data of arbitrary type
        /// \pre <tt>matches\<Expr,or_\>::value</tt> is \c true.
        /// \return <tt>which()(e, s, d)</tt>, where <tt>which</tt> is the
        /// sub-grammar that matched <tt>Expr</tt>.

        template<typename Expr, typename State, typename Data>
        struct impl
          : detail::matches_<
                typename Expr::proto_derived_expr
              , typename Expr::proto_grammar
              , or_
            >::which::template impl<Expr, State, Data>
        {};

        template<typename Expr, typename State, typename Data>
        struct impl<Expr &, State, Data>
          : detail::matches_<
                typename Expr::proto_derived_expr
              , typename Expr::proto_grammar
              , or_
            >::which::template impl<Expr &, State, Data>
        {};
    };

    /// \brief For matching all of a set of grammars. When used as a
    /// transform, \c and_\<\> applies the transforms associated with
    /// the each grammar in the set, and returns the result of the last.
    ///
    /// An expression type \c E matches <tt>and_\<B0,B1,...Bn\></tt> if \c E
    /// matches all \c Bx for \c x in <tt>[0,n)</tt>.
    ///
    /// When applying <tt>and_\<B0,B1,...Bn\></tt> as a transform with an
    /// expression \c e, state \c s and data \c d, it is
    /// equivalent to <tt>(B0()(e, s, d),B1()(e, s, d),...Bn()(e, s, d))</tt>.
    template<BOOST_PROTO_LOGICAL_typename_G>
    struct and_ : transform<and_<BOOST_PROTO_LOGICAL_G> >
    {
        typedef and_ proto_grammar;

        template<typename Expr, typename State, typename Data>
        struct impl
          : detail::_and_impl<and_, Expr, State, Data>
        {};
    };

    /// \brief For matching one of a set of alternate grammars, which
    /// are looked up based on some property of an expression. The
    /// property on which to dispatch is specified by the \c Transform
    /// template parameter, which defaults to <tt>tag_of\<_\>()</tt>.
    /// That is, when the \c Trannsform is not specified, the alternate
    /// grammar is looked up using the tag type of the current expression.
    ///
    /// When used as a transform, \c switch_\<\> applies the transform
    /// associated with the grammar that matches the expression.
    ///
    /// \note \c switch_\<\> is functionally identical to \c or_\<\> but
    /// is often more efficient. It does a fast, O(1) lookup using the
    /// result of the specified transform to find a sub-grammar that may
    /// potentially match the expression.
    ///
    /// An expression type \c E matches <tt>switch_\<C,T\></tt> if \c E
    /// matches <tt>C::case_\<boost::result_of\<T(E)\>::type\></tt>.
    ///
    /// When applying <tt>switch_\<C,T\></tt> as a transform with an
    /// expression \c e of type \c E, state \c s of type \S and data
    /// \c d of type \c D, it is equivalent to
    /// <tt>C::case_\<boost::result_of\<T(E,S,D)\>::type\>()(e, s, d)</tt>.
    template<typename Cases, typename Transform>
    struct switch_ : transform<switch_<Cases, Transform> >
    {
        typedef switch_ proto_grammar;

        template<typename Expr, typename State, typename Data>
        struct impl
          : Cases::template case_<
                typename when<_, Transform>::template impl<Expr, State, Data>::result_type
            >::template impl<Expr, State, Data>
        {};
    };

    /// INTERNAL ONLY (This is merely a compile-time optimization for the common case)
    ///
    template<typename Cases>
    struct switch_<Cases> : transform<switch_<Cases> >
    {
        typedef switch_ proto_grammar;

        template<typename Expr, typename State, typename Data>
        struct impl
          : Cases::template case_<typename Expr::proto_tag>::template impl<Expr, State, Data>
        {};

        template<typename Expr, typename State, typename Data>
        struct impl<Expr &, State, Data>
          : Cases::template case_<typename Expr::proto_tag>::template impl<Expr &, State, Data>
        {};
    };

    /// \brief For forcing exact matches of terminal types.
    ///
    /// By default, matching terminals ignores references and
    /// cv-qualifiers. For instance, a terminal expression of
    /// type <tt>terminal\<int const &\>::type</tt> will match
    /// the grammar <tt>terminal\<int\></tt>. If that is not
    /// desired, you can force an exact match with
    /// <tt>terminal\<exact\<int\> \></tt>. This will only
    /// match integer terminals where the terminal is held by
    /// value.
    template<typename T>
    struct exact
    {};

    /// \brief For matching terminals that are convertible to
    /// a type.
    ///
    /// Use \c convertible_to\<\> to match a terminal that is
    /// convertible to some type. For example, the grammar
    /// <tt>terminal\<convertible_to\<int\> \></tt> will match
    /// any terminal whose argument is convertible to an integer.
    ///
    /// \note The trait \c is_convertible\<\> from Boost.Type_traits
    /// is used to determinal convertibility.
    template<typename T>
    struct convertible_to
    {};

    /// \brief For matching a Grammar to a variable number of
    /// sub-expressions.
    ///
    /// An expression type <tt>expr\<AT, listN\<A0,...An,U0,...Um\> \></tt>
    /// matches a grammar <tt>expr\<BT, listM\<B0,...Bn,vararg\<V\> \> \></tt>
    /// if \c BT is \c _ or \c AT, and if \c Ax matches \c Bx
    /// for each \c x in <tt>[0,n)</tt> and if \c Ux matches \c V
    /// for each \c x in <tt>[0,m)</tt>.
    ///
    /// For example:
    ///
    /// \code
    /// // Match any function call expression, irregardless
    /// // of the number of function arguments:
    /// struct Function
    ///   : function< vararg<_> >
    /// {};
    /// \endcode
    ///
    /// When used as a transform, <tt>vararg\<G\></tt> applies
    /// <tt>G</tt>'s transform.
    template<typename Grammar>
    struct vararg
      : Grammar
    {
        /// INTERNAL ONLY
        typedef void proto_is_vararg_;
    };

    /// INTERNAL ONLY
    ///
    template<BOOST_PROTO_LOGICAL_typename_G>
    struct is_callable<or_<BOOST_PROTO_LOGICAL_G> >
      : mpl::true_
    {};

    /// INTERNAL ONLY
    ///
    template<BOOST_PROTO_LOGICAL_typename_G>
    struct is_callable<and_<BOOST_PROTO_LOGICAL_G> >
      : mpl::true_
    {};

    /// INTERNAL ONLY
    ///
    template<typename Grammar>
    struct is_callable<not_<Grammar> >
      : mpl::true_
    {};

    /// INTERNAL ONLY
    ///
    template<typename If, typename Then, typename Else>
    struct is_callable<if_<If, Then, Else> >
      : mpl::true_
    {};

    /// INTERNAL ONLY
    ///
    template<typename Grammar>
    struct is_callable<vararg<Grammar> >
      : mpl::true_
    {};

    /// INTERNAL ONLY
    ///
    template<typename Cases, typename Transform>
    struct is_callable<switch_<Cases, Transform> >
      : mpl::true_
    {};

}}

#undef BOOST_PROTO_LOGICAL_typename_G
#undef BOOST_PROTO_LOGICAL_G

#if defined(_MSC_VER) && (_MSC_VER >= 1020)
# pragma warning(pop)
#endif

#endif


text:
#include "elysium/log.h"

#include "chainparamsbase.h"
#include "util.h"
#include "utiltime.h"

#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/once.hpp>

#include <assert.h>
#include <stdio.h>
#include <atomic>
#include <string>
#include <vector>

// Default log files
const std::string LOG_FILENAME    = "exodus.log";

// Options
static const long LOG_BUFFERSIZE  =  8000000; //  8 MB
static const long LOG_SHRINKSIZE  = 50000000; // 50 MB

// Debug flags
bool elysium_debug_parser_data        = 0;
bool elysium_debug_parser_readonly    = 0;
//! Print information to potential DEx payments and outputs
bool elysium_debug_parser_dex         = 1;
bool elysium_debug_parser             = 0;
bool elysium_debug_verbose            = 0;
bool elysium_debug_verbose2           = 0;
bool elysium_debug_verbose3           = 0;
bool elysium_debug_vin                = 0;
bool elysium_debug_script             = 0;
bool elysium_debug_dex                = 1;
bool elysium_debug_send               = 1;
bool elysium_debug_tokens             = 0;
//! Print information about payloads with non-sequential sequence number
bool elysium_debug_spec               = 0;
bool elysium_debug_ely                = 0;
bool elysium_debug_tally              = 1;
bool elysium_debug_sp                 = 1;
bool elysium_debug_sto                = 1;
bool elysium_debug_txdb               = 0;
bool elysium_debug_tradedb            = 1;
bool elysium_debug_persistence        = 0;
bool elysium_debug_ui                 = 0;
bool elysium_debug_pending            = 1;
bool elysium_debug_metadex1           = 0;
bool elysium_debug_metadex2           = 0;
//! Print orderbook before and after each trade
bool elysium_debug_metadex3           = 0;
//! Print transaction fields, when interpreting packets
bool elysium_debug_packets            = 1;
//! Print transaction fields, when interpreting packets (in RPC mode)
bool elysium_debug_packets_readonly   = 0;
bool elysium_debug_walletcache        = 0;
//! Print each line added to consensus hash
bool elysium_debug_consensus_hash     = 0;
//! Print consensus hashes for each block when parsing
bool elysium_debug_consensus_hash_every_block = 0;
//! Print extra info on alert processing
bool elysium_debug_alerts             = 1;
//! Print consensus hashes for each transaction when parsing
bool elysium_debug_consensus_hash_every_transaction = 0;
//! Debug fees
bool elysium_debug_fees               = 1;

/**
 * LogPrintf() has been broken a couple of times now
 * by well-meaning people adding mutexes in the most straightforward way.
 * It breaks because it may be called by global destructors during shutdown.
 * Since the order of destruction of static/global objects is undefined,
 * defining a mutex as a global object doesn't work (the mutex gets
 * destroyed, and then some later destructor calls OutputDebugStringF,
 * maybe indirectly, and you get a core dump at shutdown trying to lock
 * the mutex).
 */
static boost::once_flag debugLogInitFlag = BOOST_ONCE_INIT;
/**
 * We use boost::call_once() to make sure these are initialized
 * in a thread-safe manner the first time called:
 */
static FILE* fileout = NULL;
static boost::mutex* mutexDebugLog = NULL;
/** Flag to indicate, whether the Elysium log file should be reopened. */
extern std::atomic<bool> fReopenElysiumLog;

/**
 * @return The current timestamp in the format: 2009-01-03 18:15:05
 */
static std::string GetTimestamp()
{
    return DateTimeStrFormat("%Y-%m-%d %H:%M:%S", GetTime());
}

/**
 * Prints to the standard output, usually the console.
 *
 * The configuration option "-logtimestamps" can be used to indicate, whether
 * the message should be prepended with a timestamp.
 *
 * @param str[in]  The message to print
 * @return The total number of characters written
 */
static int ConsolePrint(const std::string& str)
{
    int ret = 0; // Number of characters written
    static bool fStartedNewLine = true;

    if (fLogTimestamps && fStartedNewLine) {
        ret = fprintf(stdout, "%s %s", GetTimestamp().c_str(), str.c_str());
    } else {
        ret = fwrite(str.data(), 1, str.size(), stdout);
    }
    if (!str.empty() && str[str.size()-1] == '\n') {
        fStartedNewLine = true;
    } else {
        fStartedNewLine = false;
    }
    fflush(stdout);

    return ret;
}

/**
 * Returns path for debug log file.
 *
 * The log file can be specified via startup option "--elysiumlogfile=/path/to/exodus.log",
 * and if none is provided, then the client's datadir is used as default location.
 */
static boost::filesystem::path GetLogPath()
{
    boost::filesystem::path pathLogFile;
    std::string strLogPath = GetArg("-elysiumlogfile", "");

    if (!strLogPath.empty()) {
        pathLogFile = boost::filesystem::path(strLogPath);
        TryCreateDirectory(pathLogFile.parent_path());
    } else {
        pathLogFile = GetDataDir() / LOG_FILENAME;
    }

    return pathLogFile;
}

/**
 * Opens debug log file.
 */
static void DebugLogInit()
{
    assert(fileout == NULL);
    assert(mutexDebugLog == NULL);

    boost::filesystem::path pathDebug = GetLogPath();
    fileout = fopen(pathDebug.string().c_str(), "a");

    if (fileout) {
        setbuf(fileout, NULL); // Unbuffered
    } else {
        ConsolePrint(tfm::format("Failed to open debug log file: %s\n", pathDebug.string()));
    }

    mutexDebugLog = new boost::mutex();
}

/**
 * Prints to log file.
 *
 * The configuration options "-logtimestamps" can be used to indicate, whether
 * the message to log should be prepended with a timestamp.
 *
 * If "-printtoconsole" is enabled, then the message is written to the standard
 * output, usually the console, instead of a log file.
 *
 * @param str[in]  The message to log
 * @return The total number of characters written
 */
int LogFilePrint(const std::string& str)
{
    int ret = 0; // Number of characters written
    if (fPrintToConsole) {
        // Print to console
        ret = ConsolePrint(str);
    }
    else if (fPrintToDebugLog && AreBaseParamsConfigured()) {
        static bool fStartedNewLine = true;
        boost::call_once(&DebugLogInit, debugLogInitFlag);

        if (fileout == NULL) {
            return ret;
        }
        boost::mutex::scoped_lock scoped_lock(*mutexDebugLog);

        // Reopen the log file, if requested
        if (fReopenElysiumLog) {
        	fReopenElysiumLog = false;
            boost::filesystem::path pathDebug = GetLogPath();
            if (freopen(pathDebug.string().c_str(), "a", fileout) != NULL) {
                setbuf(fileout, NULL); // Unbuffered
            }
        }

        // Printing log timestamps can be useful for profiling
        if (fLogTimestamps && fStartedNewLine) {
            ret += fprintf(fileout, "%s ", GetTimestamp().c_str());
        }
        if (!str.empty() && str[str.size()-1] == '\n') {
            fStartedNewLine = true;
        } else {
            fStartedNewLine = false;
        }
        ret += fwrite(str.data(), 1, str.size(), fileout);
    }

    return ret;
}

/**
 * Determine whether to override compiled debug levels via enumerating startup option --elysiumdebug.
 *
 * Example usage (granular categories)    : --elysiumdebug=parser --elysiumdebug=metadex1 --elysiumdebug=ui
 * Example usage (enable all categories)  : --elysiumdebug=all
 * Example usage (disable all debugging)  : --elysiumdebug=none
 * Example usage (disable all except XYZ) : --elysiumdebug=none --omnidebug=parser --elysiumdebug=sto
 */
void InitDebugLogLevels()
{
    if (!IsArgSet("-elysiumdebug")) {
        return;
    }

    const std::vector<std::string>& debugLevels = mapMultiArgs.at("-elysiumdebug");

    for (std::vector<std::string>::const_iterator it = debugLevels.begin(); it != debugLevels.end(); ++it) {
        if (*it == "parser_data") elysium_debug_parser_data = true;
        if (*it == "parser_readonly") elysium_debug_parser_readonly = true;
        if (*it == "parser_dex") elysium_debug_parser_dex = true;
        if (*it == "parser") elysium_debug_parser = true;
        if (*it == "verbose") elysium_debug_verbose = true;
        if (*it == "verbose2") elysium_debug_verbose2 = true;
        if (*it == "verbose3") elysium_debug_verbose3 = true;
        if (*it == "vin") elysium_debug_vin = true;
        if (*it == "script") elysium_debug_script = true;
        if (*it == "dex") elysium_debug_dex = true;
        if (*it == "send") elysium_debug_send = true;
        if (*it == "tokens") elysium_debug_tokens = true;
        if (*it == "spec") elysium_debug_spec = true;
        if (*it == "ely") elysium_debug_ely = true;
        if (*it == "tally") elysium_debug_tally = true;
        if (*it == "sp") elysium_debug_sp = true;
        if (*it == "sto") elysium_debug_sto = true;
        if (*it == "txdb") elysium_debug_txdb = true;
        if (*it == "tradedb") elysium_debug_tradedb = true;
        if (*it == "persistence") elysium_debug_persistence = true;
        if (*it == "ui") elysium_debug_ui = true;
        if (*it == "pending") elysium_debug_pending = true;
        if (*it == "metadex1") elysium_debug_metadex1 = true;
        if (*it == "metadex2") elysium_debug_metadex2 = true;
        if (*it == "metadex3") elysium_debug_metadex3 = true;
        if (*it == "packets") elysium_debug_packets = true;
        if (*it == "packets_readonly") elysium_debug_packets_readonly = true;
        if (*it == "walletcache") elysium_debug_walletcache = true;
        if (*it == "consensus_hash") elysium_debug_consensus_hash = true;
        if (*it == "consensus_hash_every_block") elysium_debug_consensus_hash_every_block = true;
        if (*it == "alerts") elysium_debug_alerts = true;
        if (*it == "consensus_hash_every_transaction") elysium_debug_consensus_hash_every_transaction = true;
        if (*it == "fees") elysium_debug_fees = true;
        if (*it == "none" || *it == "all") {
            bool allDebugState = false;
            if (*it == "all") allDebugState = true;
            elysium_debug_parser_data = allDebugState;
            elysium_debug_parser_readonly = allDebugState;
            elysium_debug_parser_dex = allDebugState;
            elysium_debug_parser = allDebugState;
            elysium_debug_verbose = allDebugState;
            elysium_debug_verbose2 = allDebugState;
            elysium_debug_verbose3 = allDebugState;
            elysium_debug_vin = allDebugState;
            elysium_debug_script = allDebugState;
            elysium_debug_dex = allDebugState;
            elysium_debug_send = allDebugState;
            elysium_debug_tokens = allDebugState;
            elysium_debug_spec = allDebugState;
            elysium_debug_ely = allDebugState;
            elysium_debug_tally = allDebugState;
            elysium_debug_sp = allDebugState;
            elysium_debug_sto = allDebugState;
            elysium_debug_txdb = allDebugState;
            elysium_debug_tradedb = allDebugState;
            elysium_debug_persistence = allDebugState;
            elysium_debug_ui = allDebugState;
            elysium_debug_pending = allDebugState;
            elysium_debug_metadex1 = allDebugState;
            elysium_debug_metadex2 = allDebugState;
            elysium_debug_metadex3 = allDebugState;
            elysium_debug_packets =  allDebugState;
            elysium_debug_packets_readonly =  allDebugState;
            elysium_debug_walletcache = allDebugState;
            elysium_debug_consensus_hash = allDebugState;
            elysium_debug_consensus_hash_every_block = allDebugState;
            elysium_debug_alerts = allDebugState;
            elysium_debug_consensus_hash_every_transaction = allDebugState;
            elysium_debug_fees = allDebugState;
        }
    }
}

/**
 * Scrolls debug log, if it's getting too big.
 */
void ShrinkDebugLog()
{
    boost::filesystem::path pathLog = GetLogPath();
    FILE* file = fopen(pathLog.string().c_str(), "r");

    if (file && boost::filesystem::file_size(pathLog) > LOG_SHRINKSIZE) {
        // Restart the file with some of the end
        char* pch = new char[LOG_BUFFERSIZE];
        if (NULL != pch) {
            fseek(file, -LOG_BUFFERSIZE, SEEK_END);
            int nBytes = fread(pch, 1, LOG_BUFFERSIZE, file);
            fclose(file);
            file = NULL;

            file = fopen(pathLog.string().c_str(), "w");
            if (file) {
                fwrite(pch, 1, nBytes, file);
                fclose(file);
                file = NULL;
            }
            delete[] pch;
        }
    } else if (NULL != file) {
        fclose(file);
        file = NULL;
    }
}

ext: cpp

max_stars_repo_name: ConsulTent/firo

max_issues_repo_name: ConsulTent/firo

max_forks_repo_name: ConsulTent/firo


text:
/* ----------------------------------------------------------------------------

 * GTSAM Copyright 2010, Georgia Tech Research Corporation,
 * Atlanta, Georgia 30332-0415
 * All Rights Reserved
 * Authors: Frank Dellaert, et al. (see THANKS for the full author list)

 * See LICENSE for the license information

 * -------------------------------------------------------------------------- */

/**
 * @file    testSymbolicEliminationTree.cpp
 * @brief
 * @author  Richard Roberts
 * @date Oct 14, 2010
 */

#include <CppUnitLite/TestHarness.h>

#include <vector>
#include <boost/make_shared.hpp>
#include <boost/assign/list_of.hpp>

#include <gtsam/base/TestableAssertions.h>
#include <gtsam/symbolic/SymbolicEliminationTree.h>
#include <gtsam/inference/Symbol.h>

#include "symbolicExampleGraphs.h"

using namespace gtsam;
using namespace gtsam::symbol_shorthand;
using namespace std;
using boost::assign::list_of;

class EliminationTreeTester {
public:
  // build hardcoded tree
  static SymbolicEliminationTree buildHardcodedTree(const SymbolicFactorGraph& fg) {

    SymbolicEliminationTree::sharedNode leaf0(new SymbolicEliminationTree::Node);
    leaf0->key = 0;
    leaf0->factors.push_back(fg[0]);
    leaf0->factors.push_back(fg[1]);

    SymbolicEliminationTree::sharedNode node1(new SymbolicEliminationTree::Node);
    node1->key = 1;
    node1->factors.push_back(fg[2]);
    node1->children.push_back(leaf0);

    SymbolicEliminationTree::sharedNode node2(new SymbolicEliminationTree::Node);
    node2->key = 2;
    node2->factors.push_back(fg[3]);
    node2->children.push_back(node1);

    SymbolicEliminationTree::sharedNode leaf3(new SymbolicEliminationTree::Node);
    leaf3->key = 3;
    leaf3->factors.push_back(fg[4]);

    SymbolicEliminationTree::sharedNode root(new SymbolicEliminationTree::Node);
    root->key = 4;
    root->children.push_back(leaf3);
    root->children.push_back(node2);

    SymbolicEliminationTree tree;
    tree.roots_.push_back(root);
    return tree;
  }

  template<typename ROOTS>
  static SymbolicEliminationTree MakeTree(const ROOTS& roots)
  {
    SymbolicEliminationTree et;
    et.roots_.assign(roots.begin(), roots.end());
    return et;
  }
};

template<typename FACTORS>
static SymbolicEliminationTree::sharedNode MakeNode(Key key, const FACTORS& factors)
{
  SymbolicEliminationTree::sharedNode node = boost::make_shared<SymbolicEliminationTree::Node>();
  node->key = key;
  SymbolicFactorGraph factorsAsGraph = factors;
  node->factors.assign(factorsAsGraph.begin(), factorsAsGraph.end());
  return node;
}

template<typename FACTORS, typename CHILDREN>
static SymbolicEliminationTree::sharedNode MakeNode(Key key, const FACTORS& factors, const CHILDREN& children)
{
  SymbolicEliminationTree::sharedNode node = boost::make_shared<SymbolicEliminationTree::Node>();
  node->key = key;
  SymbolicFactorGraph factorsAsGraph = factors;
  node->factors.assign(factorsAsGraph.begin(), factorsAsGraph.end());
  node->children.assign(children.begin(), children.end());
  return node;
}

/* ************************************************************************* */
TEST(EliminationTree, Create)
{
  SymbolicEliminationTree expected =
    EliminationTreeTester::buildHardcodedTree(simpleTestGraph1);

  // Build from factor graph
  Ordering order;
  order += 0,1,2,3,4;
  SymbolicEliminationTree actual(simpleTestGraph1, order);

  CHECK(assert_equal(expected, actual));
}

/* ************************************************************************* */
TEST(EliminationTree, Create2)
{
  //        l1                  l2
  //    /    |                /  |
  // x1 --- x2 --- x3 --- x4 --- x5
  //                          \  |
  //                            l3
  SymbolicFactorGraph graph;
  graph += SymbolicFactor(X(1), L(1));
  graph += SymbolicFactor(X(1), X(2));
  graph += SymbolicFactor(X(2), L(1));
  graph += SymbolicFactor(X(2), X(3));
  graph += SymbolicFactor(X(3), X(4));
  graph += SymbolicFactor(X(4), L(2));
  graph += SymbolicFactor(X(4), X(5));
  graph += SymbolicFactor(L(2), X(5));
  graph += SymbolicFactor(X(4), L(3));
  graph += SymbolicFactor(X(5), L(3));

  SymbolicEliminationTree expected = EliminationTreeTester::MakeTree(list_of
    (MakeNode(X(3), SymbolicFactorGraph(), list_of
      (MakeNode(X(2), list_of(SymbolicFactor(X(2), X(3))), list_of
        (MakeNode(L(1), list_of(SymbolicFactor(X(2), L(1))), list_of
          (MakeNode(X(1), list_of(SymbolicFactor(X(1), L(1))) (SymbolicFactor(X(1), X(2)))))))))
      (MakeNode(X(4), list_of(SymbolicFactor(X(3), X(4))), list_of
        (MakeNode(L(2), list_of(SymbolicFactor(X(4), L(2))), list_of
          (MakeNode(X(5), list_of(SymbolicFactor(X(4), X(5))) (SymbolicFactor(L(2), X(5))), list_of
            (MakeNode(L(3), list_of(SymbolicFactor(X(4), L(3))) (SymbolicFactor(X(5), L(3))))))))))))));

  Ordering order = list_of(X(1)) (L(3)) (L(1)) (X(5)) (X(2)) (L(2)) (X(4)) (X(3));

  SymbolicEliminationTree actual(graph, order);

  EXPECT(assert_equal(expected, actual));
}

/* ************************************************************************* */
int main() {
  TestResult tr;
  return TestRegistry::runAllTests(tr);
}
/* ************************************************************************* */


text:
#include "board.h"
#include "count_reader.h"
#include <fstream>
#include <chrono>
#include <boost/program_options.hpp>
namespace po = boost::program_options;

/*
  0 - unknown
  1 - (black turn) black cannot move (brown win)
  2 - (brown turn) brown has move to state 1
 2*n - (brown turn) brown has move to state 2*n - 1
 2*n + 1 - (black turn) all black move lead to state 2*m (m <= n)
 */

void usage(char *command) {
  std::cerr << "Usage : " << command << " n count" << std::endl;
  std::cerr << " n - value in the table" << std::endl;
  std::cerr << " [count] - how many samples to show (zero for all) " << std::endl;
  exit(0);
}

template<int SIZE, int capture_type>
void show_board(CountReader<SIZE, capture_type> &cr, Board<SIZE> const& b) {
  // const size_t table_size = (1ull << SIZE) * (capture_type > 1 ? SIZE : Board<SIZE>::HSIZE());
  std::cerr << "b.v=" << b.v << "\n" << b << std::endl;
  Board<SIZE> b1 = b;
  if (b.v >= CountReader<SIZE, capture_type>::table_size()) b1 = b.flip();
  // std::cerr << "b1.v=" << b1.v << "\n" << b1 << std::endl;
  int c = cr.get(b1.v);
  std::cerr << c << std::endl;
  if (c <= 1) return;
  std::cerr << "----" << std::endl;
  auto ns = b.next_states();
  Board<SIZE> best_n = b;
  int loss_count = 0;
  int ns_size = 0;
  for (auto n : ns) {
    // std::cerr << "n=" << n << ",cr.get(n)=" << int(cr.get(n)) << std::endl;
    ns_size++;
    Board<SIZE> n1(n);
    // std::cerr << "n1=" << n1 << std::endl;
    // if (n1.v >= table_size) n1 = n1.flip();
    if (cr.get(n1.v) == 0) loss_count++;
    if (cr.get(n1.v) == c - 1) {
      best_n = Board<SIZE>(n);
    }
  }
  std::cerr << "lost / all = " << loss_count << " / " << ns_size << std::endl;
  if (!(best_n == b))
    show_board<SIZE, capture_type>(cr, best_n);
}

template<int SIZE, int capture_type>
void show() {
  const int SSIZE = Board<SIZE>::WIDTH() * Board<SIZE>::HEIGHT() + 1;
  CountReader<SIZE, capture_type> cr;
  std::string s_all;
  std::string s;
  std::cerr << "Ready" << std::endl;
  while (std::cin >> s) {
    s_all += s;
    if (s_all.size() >= SSIZE) {
      Board<SIZE> b(s_all.substr(0, SSIZE));
      show_board<SIZE, capture_type>(cr,b);
      s_all = s_all.substr(SSIZE, s_all.size());
    }
  }
}

int main(int ac, char **ag) {
  int board_size;
  int capture_type;

  po::options_description options("all_options");
  options.add_options()
    ("board-size,n",
     po::value<int>(&board_size)->default_value(25),
     "board size (25, 31, 33)")
    ("capture-type,t",
     po::value<int>(&capture_type)->default_value(0),
     "capture type : 0 (ALL), 1(any corner), 2(one corner), 3(1,0), 4(2,0)")
    ;
  po::variables_map vm;
  try
    {
      po::store(po::parse_command_line(ac, ag, options), vm);
      po::notify(vm);
    }
  catch (std::exception& e)
    {
      std::cerr << "error in parsing options" << std::endl
		<< e.what() << std::endl;
      std::cerr << options << std::endl;
      return 1;
    }
  if (vm.count("help")) {
    std::cerr << options << std::endl;
    return 0;
  }
  if (board_size == 25) {
    if (capture_type == 0)
      show<25, 0>();
    else if (capture_type == 1)
      show<25, 1>();
    else if (capture_type == 2)
      show<25, 2>();
    else if (capture_type == 3)
      show<25, 3>();
    else if (capture_type == 4)
      show<25, 4>();
    else {
      std::cerr << options << std::endl;
      return 0;
    }
  }
  else if (board_size == 31) {
    if (capture_type == 0)
      show<31, 0>();
  }
  else if (board_size == 33) {
    if (capture_type == 0)
      show<33, 0>();
  }
  else {
    std::cerr << options << std::endl;
    return 0;
  }

}

ext: cc


text:
/*
 *          Copyright Andrey Semashev 2007 - 2015.
 * 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)
 */
/*!
 * \file   settings.hpp
 * \author Andrey Semashev
 * \date   11.10.2009
 *
 * The header contains definition of the library settings container.
 */

#ifndef BOOST_LOG_UTILITY_SETUP_SETTINGS_HPP_INCLUDED_
#define BOOST_LOG_UTILITY_SETUP_SETTINGS_HPP_INCLUDED_

#include <cstddef>
#include <string>
#include <iterator>
#include <boost/assert.hpp>
#include <boost/move/core.hpp>
#include <boost/mpl/if.hpp>
#include <boost/iterator/iterator_adaptor.hpp>
#include <boost/optional/optional.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/core/explicit_operator_bool.hpp>
#include <boost/log/detail/setup_config.hpp>
#include <boost/log/detail/native_typeof.hpp>
#if !defined(BOOST_LOG_TYPEOF)
#include <boost/core/enable_if.hpp>
#endif
#if defined(BOOST_LOG_TYPEOF) && defined(BOOST_NO_CXX11_TRAILING_RESULT_TYPES)
#include <boost/utility/declval.hpp>
#endif
#include <boost/log/detail/header.hpp>

#ifdef BOOST_HAS_PRAGMA_ONCE
#pragma once
#endif

namespace boost {

BOOST_LOG_OPEN_NAMESPACE

namespace aux {

// This workaround is needed for MSVC 10 to work around ICE caused by stack overflow
template< typename SectionT, bool IsConstV >
struct basic_settings_section_iterator_base;

template< typename SectionT >
struct basic_settings_section_iterator_base< SectionT, true >
{
    typedef typename SectionT::BOOST_NESTED_TEMPLATE iter< true > iterator_type;
    typedef typename SectionT::property_tree_type::const_iterator base_iterator_type;
    typedef iterator_adaptor<
        iterator_type,
        base_iterator_type,
        SectionT,
        use_default,
        const SectionT
    > type;
};

template< typename SectionT >
struct basic_settings_section_iterator_base< SectionT, false >
{
    typedef typename SectionT::BOOST_NESTED_TEMPLATE iter< false > iterator_type;
    typedef typename SectionT::property_tree_type::iterator base_iterator_type;
    typedef iterator_adaptor<
        iterator_type,
        base_iterator_type,
        SectionT,
        use_default,
        SectionT
    > type;
};

} // namespace aux

/*!
 * \brief The class represents a reference to the settings container section
 *
 * The section refers to a sub-tree of the library settings container. It does not
 * own the referred sub-tree but allows for convenient access to parameters within the subsection.
 */
template< typename CharT >
class basic_settings_section
{
    template< typename SectionT, bool IsConstV >
    friend struct aux::basic_settings_section_iterator_base;

public:
    //! Character type
    typedef CharT char_type;
    //! String type
    typedef std::basic_string< char_type > string_type;
    //! Property tree type
    typedef property_tree::basic_ptree< std::string, string_type > property_tree_type;
    //! Property tree path type
    typedef typename property_tree_type::path_type path_type;

private:
#if !defined(BOOST_LOG_DOXYGEN_PASS)

    //! A reference proxy object
#ifndef BOOST_LOG_NO_MEMBER_TEMPLATE_FRIENDS
    template< bool IsConstV >
    class ref;
    template< bool IsConstV >
    friend class ref;
#endif
    template< bool IsConstV >
    class ref
    {
    private:
        typedef typename mpl::if_c<
            IsConstV,
            basic_settings_section< char_type > const,
            basic_settings_section< char_type >
        >::type section_type;

    private:
        section_type& m_section;
        path_type m_path;

    public:
        ref(section_type& section, std::string const& section_name) :
            m_section(section),
            m_path(section_name)
        {
        }
        ref(section_type& section, const char* section_name) :
            m_section(section),
            m_path(section_name)
        {
        }

        ref& operator[] (std::string const& param_name)
        {
            m_path /= param_name;
            return *this;
        }

        ref& operator= (string_type const& value)
        {
            BOOST_ASSERT(m_section.m_ptree != NULL);
            m_section.m_ptree->put(m_path, value);
            return *this;
        }

        template< bool V >
        ref& operator= (ref< V > const& value)
        {
            BOOST_ASSERT(m_section.m_ptree != NULL);
            optional< string_type > val = value.get();
            if (!!val)
            {
                m_section.m_ptree->put(m_path, val);
            }
            else if (optional< property_tree_type& > node = m_section.m_ptree->get_child_optional(m_path))
            {
                node.put_value(string_type());
            }

            return *this;
        }

        template< typename T >
        ref& operator= (T const& value)
        {
            BOOST_ASSERT(m_section.m_ptree != NULL);
            m_section.m_ptree->put(m_path, value);
            return *this;
        }

        BOOST_EXPLICIT_OPERATOR_BOOL()

        bool operator! () const
        {
            return !m_section.m_ptree || !m_section.m_ptree->get_child_optional(m_path);
        }

        std::string get_name() const
        {
            return m_path.dump();
        }

        operator optional< string_type > () const
        {
            return get();
        }

        optional< string_type > get() const
        {
            if (m_section.m_ptree)
                return m_section.m_ptree->template get_optional< string_type >(m_path);
            else
                return optional< string_type >();
        }

        template< typename T >
        optional< T > get() const
        {
            if (m_section.m_ptree)
                return m_section.m_ptree->template get_optional< T >(m_path);
            else
                return optional< T >();
        }

        operator section_type () const
        {
            return get_section();
        }

        section_type get_section() const
        {
            if (m_section.m_ptree)
                return section_type(m_section.m_ptree->get_child_optional(m_path).get_ptr());
            else
                return section_type();
        }

#if defined(BOOST_LOG_TYPEOF) && !(defined(__GNUC__) && !defined(__INTEL_COMPILER) && !defined(__clang__) && !defined(__PATHSCALE__) && !defined(__GXX_EXPERIMENTAL_CXX0X__) && (__GNUC__ == 4 && __GNUC_MINOR__ <= 5))
#if !defined(BOOST_NO_CXX11_TRAILING_RESULT_TYPES)
        template< typename T >
        auto or_default(T const& def_value) const -> BOOST_LOG_TYPEOF(property_tree_type().get(typename property_tree_type::path_type(), def_value))
        {
            if (m_section.m_ptree)
                return m_section.m_ptree->get(m_path, def_value);
            else
                return def_value;
        }
#else
        // GCC up to 4.5 (inclusively) segfaults on the following code, if C++11 mode is not enabled
        template< typename T >
        BOOST_LOG_TYPEOF(property_tree_type().get(typename property_tree_type::path_type(), boost::declval< T >())) or_default(T const& def_value) const
        {
            if (m_section.m_ptree)
                return m_section.m_ptree->get(m_path, def_value);
            else
                return def_value;
        }
#endif
#else
        template< typename T >
        T or_default(T const& def_value) const
        {
            if (m_section.m_ptree)
                return m_section.m_ptree->get(m_path, def_value);
            else
                return def_value;
        }

        template< typename T >
        typename boost::enable_if_c< boost::property_tree::detail::is_character< T >::value, std::basic_string< T > >::type
        or_default(const T* def_value) const
        {
            if (m_section.m_ptree)
                return m_section.m_ptree->get(m_path, def_value);
            else
                return def_value;
        }
#endif
        string_type or_default(string_type const& def_value) const
        {
            return get().get_value_or(def_value);
        }
        string_type or_default(typename string_type::value_type const* def_value) const
        {
            if (optional< string_type > val = get())
                return val.get();
            else
                return def_value;
        }
    };

    //! An iterator over subsections and parameters
#ifndef BOOST_LOG_NO_MEMBER_TEMPLATE_FRIENDS
    template< bool IsConstV >
    class iter;
    template< bool IsConstV >
    friend class iter;
#endif
    template< bool IsConstV >
    class iter :
        public aux::basic_settings_section_iterator_base< basic_settings_section< char_type >, IsConstV >::type
    {
        friend class boost::iterator_core_access;

        typedef typename iter::iterator_adaptor_ iterator_adaptor_;
        // NOTE: This typedef must not come from iterator_adaptor_::base_type in order to work around MSVC 10 ICE
        typedef typename aux::basic_settings_section_iterator_base< basic_settings_section< char_type >, IsConstV >::base_iterator_type base_iterator_type;

    public:
        typedef typename iterator_adaptor_::reference reference;

    public:
        BOOST_DEFAULTED_FUNCTION(iter(), {})
        template< bool OtherIsConstV >
        iter(iter< OtherIsConstV > const& that) : iterator_adaptor_(that.base()) {}
        explicit iter(base_iterator_type const& it) : iterator_adaptor_(it) {}

        //! Returns the section name
        std::string const& get_name() const
        {
            return this->base()->first;
        }

    private:
        reference dereference() const
        {
            return reference(const_cast< property_tree_type* >(&this->base()->second));
        }
    };

public:
    typedef ref< true > const_reference;
    typedef ref< false > reference;
    typedef iter< true > const_iterator;
    typedef iter< false > iterator;
    typedef std::reverse_iterator< const_iterator > const_reverse_iterator;
    typedef std::reverse_iterator< iterator > reverse_iterator;

#else

public:
    /*!
     * Constant reference to the parameter value
     */
    typedef implementation_defined const_reference;
    /*!
     * Mutable reference to the parameter value
     */
    typedef implementation_defined reference;

    /*!
     * Constant iterator over nested parameters and subsections
     */
    typedef implementation_defined const_iterator;
    /*!
     * Mutable iterator over nested parameters and subsections
     */
    typedef implementation_defined iterator;

#endif // !defined(BOOST_LOG_DOXYGEN_PASS)

protected:
    //! Parameters
    property_tree_type* m_ptree;

public:
    /*!
     * Default constructor. Creates an empty settings container.
     */
    basic_settings_section() : m_ptree(NULL)
    {
    }

    /*!
     * Copy constructor.
     */
    basic_settings_section(basic_settings_section const& that) : m_ptree(that.m_ptree)
    {
    }

    /*!
     * Checks if the section refers to the container.
     */
    BOOST_EXPLICIT_OPERATOR_BOOL_NOEXCEPT()

    /*!
     * Checks if the section refers to the container.
     */
    bool operator! () const BOOST_NOEXCEPT { return !m_ptree; }

    /*!
     * Returns an iterator over the nested subsections and parameters.
     */
    iterator begin()
    {
        if (m_ptree)
            return iterator(m_ptree->begin());
        else
            return iterator();
    }

    /*!
     * Returns an iterator over the nested subsections and parameters.
     */
    iterator end()
    {
        if (m_ptree)
            return iterator(m_ptree->end());
        else
            return iterator();
    }

    /*!
     * Returns an iterator over the nested subsections and parameters.
     */
    const_iterator begin() const
    {
        if (m_ptree)
            return const_iterator(m_ptree->begin());
        else
            return const_iterator();
    }

    /*!
     * Returns an iterator over the nested subsections and parameters.
     */
    const_iterator end() const
    {
        if (m_ptree)
            return const_iterator(m_ptree->end());
        else
            return const_iterator();
    }

    /*!
     * Returns a reverse iterator over the nested subsections and parameters.
     */
    reverse_iterator rbegin() { return reverse_iterator(begin()); }

    /*!
     * Returns a reverse iterator over the nested subsections and parameters.
     */
    reverse_iterator rend() { return reverse_iterator(end()); }

    /*!
     * Returns a reverse iterator over the nested subsections and parameters.
     */
    const_reverse_iterator rbegin() const { return const_reverse_iterator(begin()); }

    /*!
     * Returns a reverse iterator over the nested subsections and parameters.
     */
    const_reverse_iterator rend() const { return const_reverse_iterator(end()); }

    /*!
     * Checks if the container is empty (i.e. contains no sections and parameters).
     */
    bool empty() const { return m_ptree == NULL || m_ptree->empty(); }

    /*!
     * Accessor to a single parameter. This operator should be used in conjunction
     * with the subsequent subscript operator that designates the parameter name.
     *
     * \param section_name The name of the section in which the parameter resides
     * \return An unspecified reference type that can be used for parameter name specifying
     */
    reference operator[] (std::string const& section_name) { return reference(*this, section_name); }
    /*!
     * Accessor to a single parameter. This operator should be used in conjunction
     * with the subsequent subscript operator that designates the parameter name.
     *
     * \param section_name The name of the section in which the parameter resides
     * \return An unspecified reference type that can be used for parameter name specifying
     */
    const_reference operator[] (std::string const& section_name) const { return const_reference(*this, section_name); }

    /*!
     * Accessor to a single parameter. This operator should be used in conjunction
     * with the subsequent subscript operator that designates the parameter name.
     *
     * \param section_name The name of the section in which the parameter resides
     * \return An unspecified reference type that can be used for parameter name specifying
     */
    reference operator[] (const char* section_name) { return reference(*this, section_name); }
    /*!
     * Accessor to a single parameter. This operator should be used in conjunction
     * with the subsequent subscript operator that designates the parameter name.
     *
     * \param section_name The name of the section in which the parameter resides
     * \return An unspecified reference type that can be used for parameter name specifying
     */
    const_reference operator[] (const char* section_name) const { return const_reference(*this, section_name); }

    /*!
     * Accessor for the embedded property tree
     */
    property_tree_type const& property_tree() const { return *m_ptree; }
    /*!
     * Accessor for the embedded property tree
     */
    property_tree_type& property_tree() { return *m_ptree; }

    /*!
     * Checks if the specified section is present in the container.
     *
     * \param section_name The name of the section
     */
    bool has_section(string_type const& section_name) const
    {
        return m_ptree != NULL && !!m_ptree->get_child_optional(section_name);
    }
    /*!
     * Checks if the specified parameter is present in the container.
     *
     * \param section_name The name of the section in which the parameter resides
     * \param param_name The name of the parameter
     */
    bool has_parameter(string_type const& section_name, string_type const& param_name) const
    {
        if (m_ptree)
        {
            optional< property_tree_type& > section = m_ptree->get_child_optional(section_name);
            if (!!section)
                return (section->find(param_name) != section->not_found());
        }

        return false;
    }

    /*!
     * Swaps two references to settings sections.
     */
    void swap(basic_settings_section& that)
    {
        property_tree_type* const p = m_ptree;
        m_ptree = that.m_ptree;
        that.m_ptree = p;
    }

protected:
    explicit basic_settings_section(property_tree_type* tree) : m_ptree(tree)
    {
    }
};

template< typename CharT >
inline void swap(basic_settings_section< CharT >& left, basic_settings_section< CharT >& right)
{
    left.swap(right);
}

/*!
 * \brief The class represents settings container
 *
 * All settings are presented as a number of named parameters divided into named sections.
 * The parameters values are stored as strings. Individual parameters may be queried via subscript operators, like this:
 *
 *

 * optional< string > param = settings["Section1"]["Param1"]; // reads parameter "Param1" in section "Section1"
 *                                                            // returns an empty value if no such parameter exists
 * settings["Section2"]["Param2"] = 10; // sets the parameter "Param2" in section "Section2"
 *                                      // to value "10"
 *

 *
 * There are also other methods to work with parameters.
 */
template< typename CharT >
class basic_settings :
    public basic_settings_section< CharT >
{
    typedef basic_settings this_type;
    BOOST_COPYABLE_AND_MOVABLE(this_type)

public:
    //! Section type
    typedef basic_settings_section< CharT > section;
    //! Property tree type
    typedef typename section::property_tree_type property_tree_type;

public:
    /*!
     * Default constructor. Creates an empty settings container.
     */
    basic_settings() : section(new property_tree_type())
    {
    }

    /*!
     * Copy constructor.
     */
    basic_settings(basic_settings const& that) :
        section(that.m_ptree ? new property_tree_type(*that.m_ptree) : static_cast< property_tree_type* >(NULL))
    {
    }

    /*!
     * Move constructor.
     */
    basic_settings(BOOST_RV_REF(this_type) that)
    {
        this->swap(that);
    }
    /*!
     * Initializing constructor. Creates a settings container with the copy of the specified property tree.
     */
    explicit basic_settings(property_tree_type const& tree) : section(new property_tree_type(tree))
    {
    }

    /*!
     * Destructor
     */
    ~basic_settings()
    {
        delete this->m_ptree;
    }

    /*!
     * Copy assignment operator.
     */
    basic_settings& operator= (BOOST_COPY_ASSIGN_REF(basic_settings) that)
    {
        if (this != &that)
        {
            basic_settings tmp = that;
            this->swap(tmp);
        }
        return *this;
    }
    /*!
     * Move assignment operator.
     */
    basic_settings& operator= (BOOST_RV_REF(basic_settings) that)
    {
        this->swap(that);
        return *this;
    }
};

#ifdef BOOST_LOG_USE_CHAR
typedef basic_settings< char > settings;                        //!< Convenience typedef for narrow-character logging
typedef basic_settings_section< char > settings_section;        //!< Convenience typedef for narrow-character logging
#endif
#ifdef BOOST_LOG_USE_WCHAR_T
typedef basic_settings< wchar_t > wsettings;                    //!< Convenience typedef for wide-character logging
typedef basic_settings_section< wchar_t > wsettings_section;    //!< Convenience typedef for wide-character logging
#endif

BOOST_LOG_CLOSE_NAMESPACE // namespace log

} // namespace boost

#include <boost/log/detail/footer.hpp>

#endif // BOOST_LOG_UTILITY_SETUP_SETTINGS_HPP_INCLUDED_

ext: hpp


text:
// MIT License

// Copyright (c) 2018 Zhuhao Wang

// 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.

#include "nekit/data_flow/http_data_flow.h"

#include <boost/algorithm/string.hpp>

#include "nekit/utils/base64.h"
#include "nekit/utils/common_error.h"

namespace nekit {
namespace data_flow {

class HttpHeaderRewriterDelegate
    : public utils::HttpMessageStreamRewriterDelegateInterface {
 public:
  HttpHeaderRewriterDelegate(HttpDataFlow* flow) : flow_{flow} {}

  bool OnMethod(utils::HttpMessageStreamRewriter* rewriter) override {
    (void)rewriter;
    return flow_->OnMethod();
  }

  bool OnUrl(utils::HttpMessageStreamRewriter* rewriter) override {
    (void)rewriter;
    return flow_->OnUrl();
  }

  bool OnVersion(utils::HttpMessageStreamRewriter* rewriter) override {
    (void)rewriter;
    return flow_->OnVersion();
  }

  bool OnStatus(utils::HttpMessageStreamRewriter* rewriter) override {
    (void)rewriter;
    return flow_->OnStatus();
  }

  bool OnHeaderPair(utils::HttpMessageStreamRewriter* rewriter) override {
    (void)rewriter;
    return flow_->OnHeaderPair();
  }

  bool OnHeaderComplete(utils::HttpMessageStreamRewriter* rewriter) override {
    (void)rewriter;
    return flow_->OnHeaderComplete();
  }

  bool OnMessageComplete(utils::HttpMessageStreamRewriter* rewriter,
                         size_t buffer_offset, bool upgrade) override {
    (void)rewriter;
    return flow_->OnMessageComplete(buffer_offset, upgrade);
  }

 private:
  HttpDataFlow* flow_;
};

std::string HttpDataFlow::Credential::BasicAuthenticationEncode() {
  return nekit::utils::Base64::Encode(username_ + ":" + password_);
}

HttpDataFlow::HttpDataFlow(std::shared_ptr<utils::Endpoint> server_endpoint,
                           std::shared_ptr<utils::Session> session,
                           std::unique_ptr<RemoteDataFlowInterface>&& data_flow,
                           std::unique_ptr<Credential> credential)
    : server_endpoint_{server_endpoint},
      session_{session},
      data_flow_{std::move(data_flow)},
      credential_{std::move(credential)},
      rewriter_{utils::HttpMessageStreamRewriter::Type::Response,
                std::make_shared<HttpHeaderRewriterDelegate>(this)} {
  rewriter_.SetSkipBodyInResponse(true);
}

HttpDataFlow::~HttpDataFlow() {
  connect_cancelable_.Cancel();
  connect_action_cancelable_.Cancel();
}

utils::Cancelable HttpDataFlow::Read(DataEventHandler handler) {
  return data_flow_->Read(handler);
}

utils::Cancelable HttpDataFlow::Write(utils::Buffer&& buffer,
                                      EventHandler handler) {
  return data_flow_->Write(std::move(buffer), handler);
}

utils::Cancelable HttpDataFlow::CloseWrite(EventHandler handler) {
  return data_flow_->CloseWrite(handler);
}

const FlowStateMachine& HttpDataFlow::StateMachine() const {
  if (state_machine_.State() != FlowState::Established)
    return state_machine_;
  else
    return data_flow_->StateMachine();
}

DataFlowInterface* HttpDataFlow::NextHop() const { return data_flow_.get(); }

DataType HttpDataFlow::FlowDataType() const { return DataType::Stream; }

std::shared_ptr<utils::Session> HttpDataFlow::Session() const {
  return session_;
}

utils::Runloop* HttpDataFlow::GetRunloop() { return session_->GetRunloop(); }

utils::Cancelable HttpDataFlow::Connect(
    std::shared_ptr<utils::Endpoint> endpoint, EventHandler handler) {
  target_endpoint_ = endpoint;

  BOOST_ASSERT(target_endpoint_);

  state_machine_.ConnectBegin();

  connect_cancelable_ = utils::Cancelable();
  connect_action_cancelable_ = data_flow_->Connect(
      server_endpoint_, [this, handler, cancelable{connect_cancelable_}](
                            utils::Result<void>&& result) {
        if (cancelable.canceled()) {
          return;
        }

        if (!result) {
          state_machine_.Errored();
          handler(std::move(result));
          return;
        };

        std::ostringstream os;
        os << "CONNECT " << target_endpoint_->host() << ":"
           << target_endpoint_->port() << " HTTP/1.1\r\n";
        os << "Host: " << target_endpoint_->host() << ":"
           << target_endpoint_->port() << "\r\n";
        if (credential_) {
          os << "Proxy-Authorization: Basic "
             << credential_->BasicAuthenticationEncode() << "\r\n";
        }
        os << "\r\n";

        std::string request = os.str();

        auto buffer = utils::Buffer(request.size());
        buffer.SetData(0, request.size(), request.c_str());

        connect_action_cancelable_ = data_flow_->Write(
            std::move(buffer), [this, handler, cancelable{cancelable}](
                                   utils::Result<void>&& result) {
              if (cancelable.canceled()) {
                return;
              }

              if (!result) {
                state_machine_.Errored();
                handler(std::move(result));
                return;
              }

              ReadResponse(handler);
            });
      });

  return connect_cancelable_;
}

RemoteDataFlowInterface* HttpDataFlow::NextRemoteHop() const {
  return data_flow_.get();
}

std::shared_ptr<utils::Endpoint> HttpDataFlow::ConnectingTo() {
  return target_endpoint_;
}

void HttpDataFlow::ReadResponse(EventHandler handler) {
  connect_action_cancelable_ =
      data_flow_->Read([this, handler, cancelable{connect_cancelable_}](
                           utils::Result<utils::Buffer>&& buffer) {
        if (cancelable.canceled()) {
          return;
        }

        if (!buffer) {
          state_machine_.Errored();
          if (utils::CommonErrorCategory::IsEof(buffer.error())) {
            handler(utils::MakeErrorResult(HttpErrorCode::InvalidResponse));
          } else {
            handler(utils::MakeErrorResult(std::move(buffer).error()));
          }
          return;
        }

        auto result = rewriter_.RewriteBuffer(&*buffer);
        if (!result) {
          state_machine_.Errored();
          handler(std::move(result));
          return;
        }

        if (finish_response_) {
          if (success_response_) {
            buffer->ShrinkFront(header_offset_);
            if (*buffer) {
              pending_payload_ = *std::move(buffer);
            }

            state_machine_.Connected();
            handler({});
          } else {
            state_machine_.Errored();
            handler(utils::MakeErrorResult(HttpErrorCode::ConnectError));
          }
          return;
        }

        ReadResponse(handler);
      });
}

bool HttpDataFlow::OnMethod() { return false; }

bool HttpDataFlow::OnUrl() { return false; }

bool HttpDataFlow::OnVersion() { return true; }

bool HttpDataFlow::OnStatus() {
  success_response_ = boost::istarts_with(rewriter_.CurrentToken(), "200");

  return true;
}

bool HttpDataFlow::OnHeaderPair() { return true; }

bool HttpDataFlow::OnHeaderComplete() { return true; }

bool HttpDataFlow::OnMessageComplete(size_t buffer_offset, bool upgrade) {
  (void)upgrade;
  header_offset_ = buffer_offset;
  finish_response_ = true;
  return true;
}

std::string HttpErrorCategory::Description(const utils::Error& error) const {
  switch ((HttpErrorCode)error.ErrorCode()) {
    case HttpErrorCode::InvalidResponse:
      return "server send an invalid response";
    case HttpErrorCode::ConnectError:
      return "connect failed since the server returns a non 200 response";
  }
}

std::string HttpErrorCategory::DebugDescription(
    const utils::Error& error) const {
  return Description(error);
}

}  // namespace data_flow
}  // namespace nekit

max_stars_repo_name: fossabot/libnekit

max_issues_repo_name: fossabot/libnekit

max_forks_repo_name: fossabot/libnekit


text:
// ---------------------------------------------------------------------------|
// Yuma Test Harness includes
// ---------------------------------------------------------------------------|
#include "test/support/nc-query-util/nc-query-utils.h"

// ---------------------------------------------------------------------------|
// STD Includes
// ---------------------------------------------------------------------------|
#include <boost/xpressive/xpressive.hpp>
#include <boost/lexical_cast.hpp>

// ---------------------------------------------------------------------------|
// Boost Test Framework
// ---------------------------------------------------------------------------|
#include <boost/test/unit_test.hpp>

// ---------------------------------------------------------------------------|
// Global namespace usage
// ---------------------------------------------------------------------------|
using namespace std;

// ---------------------------------------------------------------------------|
namespace YumaTest
{

// ---------------------------------------------------------------------------|
string extractMessageIdStr( const std::string& query )
{
    using namespace boost::xpressive;

    sregex re = sregex::compile( "message-id=\"(\\d+)\"" );
    smatch what;

    // find a whole word
    BOOST_REQUIRE_MESSAGE( regex_search( query, what, re ),
                           "Invalid XML Query - No message-id!" );
    return what[1];
}

// ---------------------------------------------------------------------------|
uint16_t extractMessageId( const std::string& query )
{
    return boost::lexical_cast<uint16_t>( extractMessageIdStr( query ) );
}

}


text:
#include "sse_server.hpp"
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/format.hpp>
#include <functional>

void sse_server::broadcast(const std::string& msg) {
  std::string full_msg = "data: " + msg + "\n\n";
  std::vector<std::tuple<bucket_ptr_type, bucket_type::NODE_PTR>> remove_tuples;
  // benchmarking seems to indicate that client removal for each bucket as they are
  // processed beats removing all after a full broadcast - I'm having trouble grasping why.
  for (auto& bucket : _sse_client_buckets) {
    bucket->lock();
    bucket_type::NODE_PTR iterator = bucket->get_front();
    while (iterator != nullptr) {
      if (iterator->data->is_dead()) remove_tuples.push_back(std::make_tuple(bucket, iterator));
      else iterator->data->send(full_msg);
      iterator = iterator->next;
    }
    bucket->unlock();
  }
  for (auto& remove_tuple : remove_tuples) {
    auto bucket = std::get<0>(remove_tuple);
    bucket->lock();
    if (bucket->remove(std::get<1>(remove_tuple))) --_sse_client_count;
    bucket->unlock();
  }
}

void sse_server::do_accept() {
  _acceptor.async_accept(_socket,
      [this](boost::system::error_code ec) {
        if (!ec) {
          // pass control to the http handler
          auto socketptr = std::make_shared<tcp::socket>(std::move(_socket));
          std::make_shared<http_handler>(socketptr, _handlers)->start();
        }
        do_accept();
      });
}

void sse_server::write(std::shared_ptr<tcp::socket>& socket, const std::string& msg, write_cb cb) {
  boost::asio::async_write(*socket, boost::asio::buffer(msg, msg.length()), cb);
}

void sse_server::init_handlers() {
  http_handler::handler_map handlers = {
    {"GET /connections", [this](std::shared_ptr<tcp::socket>& socket, http_handler::read_body_func read_body) {
      std::string msg = boost::str(boost::format("%d") % _sse_client_count);
      write(socket,
        "HTTP/1.1 200 OK\r\n"
        "Content-Type: text/plain\r\n"
        "Content-Length: " + boost::str(boost::format("%d") % msg.length()) + "\r\n"
        "Connection: close\r\n"
        "Access-Control-Allow-Origin: *\r\n"
        "Cache-Control: no-cache\r\n"
        "\r\n" + msg,
        [this, socket](boost::system::error_code, std::size_t) {
          boost::system::error_code ec;
          socket->shutdown(tcp::socket::shutdown_both, ec);
        });
    }},
    {"GET /sse", [this](std::shared_ptr<tcp::socket>& socket, http_handler::read_body_func read_body) {
      write(socket,
        "HTTP/1.1 200 OK\r\n"
        "Content-Type: text/event-stream\r\n"
        "Connection: keep-alive\r\n"
        "Access-Control-Allow-Origin: *\r\n"
        "Cache-Control: no-cache\r\n"
        "\r\n"
        ":ok\n\n",
        [this, socket](boost::system::error_code ec, std::size_t) {
          if (ec) {
            socket->shutdown(tcp::socket::shutdown_both, ec);
          }
          else {
            auto& bucket = _sse_client_buckets[_sse_client_bucket_counter % _sse_client_bucket_count];
            ++_sse_client_bucket_counter;
            bucket->push(std::make_shared<sse_client>(std::move(socket)));
            ++_sse_client_count;
          }
        });
    }},
    {"OPTIONS /connections", [this](std::shared_ptr<tcp::socket>& socket, http_handler::read_body_func read_body) {
      write(socket,
        "HTTP/1.1 204 No Content\r\n"
        "Connection: close\r\n"
        "Access-Control-Allow-Origin: *\r\n"
        "\r\n",
        [this, socket](boost::system::error_code, std::size_t) {
          boost::system::error_code ec;
          socket->shutdown(tcp::socket::shutdown_both, ec);
        });
    }},
    {"OPTIONS /sse", [this](std::shared_ptr<tcp::socket>& socket, http_handler::read_body_func read_body) {
      write(socket,
        "HTTP/1.1 204 No Content\r\n"
        "Connection: close\r\n"
        "Access-Control-Allow-Origin: *\r\n"
        "\r\n",
        [this, socket](boost::system::error_code, std::size_t) {
          boost::system::error_code ec;
          socket->shutdown(tcp::socket::shutdown_both, ec);
        });
    }},
    {"POST /broadcast", [this](std::shared_ptr<tcp::socket>& socket, http_handler::read_body_func read_body) {
      read_body(
        [this, &socket](std::string body) {
          broadcast(body);
          write(socket,
            "HTTP/1.1 202 Accepted\r\n"
            "Content-Type: text/plain\r\n"
            "Connection: close\r\n"
            "Cache-Control: no-cache\r\n"
            "\r\n",
            [this, socket](boost::system::error_code ec, std::size_t) {
              socket->shutdown(tcp::socket::shutdown_both, ec);
            });
        });
    }}
  };
  _handlers = std::make_shared<http_handler::handler_map>(std::move(handlers));
}

max_stars_repo_name: einaros/sse-broadcast-benchmark

max_issues_repo_name: einaros/sse-broadcast-benchmark

max_forks_repo_name: einaros/sse-broadcast-benchmark


text:
/*
 * @name BookFiler Module - SSH
 * @author Branden Lee
 * @version 1.00
 * @license MIT
 * @brief SSH module for BookFiler™ applications.
 */

#ifndef BOOKFILER_MODULE_SSH_CLIENT_H
#define BOOKFILER_MODULE_SSH_CLIENT_H

// config
#include "config.hpp"

// AVOID ERROR BECAUSE OF swprintf
#undef __STRICT_ANSI__
// #define FOR WIN7. CAN'T FIND sdkddkver.h ON MINGW
#define _WIN32_WINNT 0x0601

// C++
#include <utility>

/* rapidjson v1.1 (2016-8-25)
 * Developed by Tencent
 * License: MITs
 */
#include <rapidjson/document.h>
#include <rapidjson/filewritestream.h>
#include <rapidjson/ostreamwrapper.h>
#include <rapidjson/reader.h> // rapidjson::ParseResult
#include <rapidjson/stringbuffer.h>
#include <rapidjson/writer.h>

/* boost 1.72.0
 * License: Boost Software License (similar to BSD and MIT)
 */
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/bind/protect.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/function.hpp>
#include <boost/lexical_cast.hpp>

// Local Project
#include "ClientState.hpp"
#include "Util.hpp"
#include <BookFiler-Module-ssh/Interface.hpp>

/*
 * bookfiler - ssh
 * ssh utilities. The main feature is the ssh tunnel for mysql
 */
namespace bookfiler {
namespace ssh {

// Please, note: The class isn't called TestSSH because I lack imagination.
// The name comes from the fact that this hasn't yet seen anything
// beyond basic testing.
/*!
 * \todo Create exceptions, instead of using logic_error
 */
class ClientImpl : public Client {
public:
  ClientImpl(std::map<std::string, newSshClientType>);
  ~ClientImpl();
  int connect();
  int command(std::string const &command);
  int send(std::string bufferStr, size_t len);
  int read(std::string &bufferStr, size_t &len);
  int commandOpenClose(std::string const &command);
  int setSettingsDoc(std::shared_ptr<rapidjson::Value> settingsDoc_);
  int tunnel();
  int forwarding();

private:
  std::shared_ptr<rapidjson::Value> settingsDoc;
  std::shared_ptr<ClientState> clientState;
  std::shared_ptr<std::thread> threadIo;
  enum state { WORK_DONE, STILL_WORKING };

  void LoopAsync(boost::function<state()> DoWork, bool isRead);
  void LoopTimer(boost::function<state()> DoWork);

  void ConnectSocket();
  void CreateSSHSession();
  state DoCreateChannel();
  state DoExecute();
  state writeCommandChannel();
  /* do commandChannelReadStr.clear() before calling
   */
  state readCommandChannel();
  /* do listenChannelReadStr.clear() before calling
   */
  state readListenChannel();
  state DoCloseChannel();
  void Cleanup();

  void runIoContext();

  std::string commandStr, commandChannelReadStr, listenChannelReadStr;
  boost::asio::io_service ioContext;
  std::shared_ptr<boost::asio::ip::tcp::socket> sockPtr;
  std::shared_ptr<boost::asio::deadline_timer> dtimerPtr;
  LIBSSH2_SESSION *session = nullptr;
  LIBSSH2_LISTENER *listener = nullptr;
  LIBSSH2_CHANNEL *commandChannel = nullptr;
  LIBSSH2_CHANNEL *listenChannel = nullptr;
  size_t writtenBytes, commandChannelReadLen, commandStrLen;
};

} // namespace ssh
} // namespace bookfiler

#endif
// end BOOKFILER_MODULE_SSH_CLIENT_H

max_stars_repo_name: bradosia/BookFiler-Module-SSH-libssh

max_issues_repo_name: bradosia/BookFiler-Module-SSH-libssh

max_forks_repo_name: bradosia/BookFiler-Module-SSH-libssh


text:
#include <boost/filesystem.hpp>

#include "modules/bio_base/bwt_file.h"
#include "modules/bio_base/flat_ref.h"
#include "modules/bio_format/fasta_ref_importer.h"
#include "modules/bio_mapred/make_bwt.h"
#include "modules/io/defaults.h"
#include "modules/io/file_io.h"
#include "modules/io/log.h"
#include "modules/io/make_unique.h"
#include "modules/io/progress_tracker_types.h"
#include "modules/pipeline/build_reference_task.h"
#include "modules/pipeline/dataset_meta.h"
#include "modules/pipeline/dataset_path.h"
#include "tools/version.h"

REGISTER_TASK(build_reference_task);

namespace fs = boost::filesystem;

build_reference_task::build_reference_task(
	const std::string& out_dir,
	const std::string& reference_name)
	: m_out_dir(out_dir)
	, m_ref_name(reference_name)
{
	SPLOG("build_reference_task::build_reference_task> making reference for: %s", reference_name.c_str());
}

void build_reference_task::run()
{
	std::string prefix = "build_reference_task::run>";
	SPLOG("%s entering run, saving to %s", prefix.c_str(), m_out_dir.c_str());

	// TODO: implement real progress for flat and bwt generation.
	// These are estimates that do not smoothly increase!
	static const double import_fraction = 0.26;                 // 26% of the total time importing fasta
	static const double flat_fraction = import_fraction + 0.32; // 32% flat
	static const double bwt_fraction = flat_fraction + 0.39;    // 42% bwt, but underreport so we're not hung on 100%

	path out_dir_path(m_out_dir);
	path new_ref_dir_path = out_dir_path.append(m_ref_name);
	path fasta_tmp_path = new_ref_dir_path.append(defaults.original_fasta);

	path reference_fasta_path = new_ref_dir_path.append(defaults.reference_fasta);
	path alu_fasta_path = new_ref_dir_path.append(defaults.alu_fasta);
	path reference_ref_path = new_ref_dir_path.append(defaults.reference_ref);
	path reference_bwt_path = new_ref_dir_path.append(defaults.reference_bwt);

	size_t fasta_size = fasta_tmp_path.size();

	if (m_state == IMPORT_FASTA) {
		split_progress(import_fraction, 1 - import_fraction);
		// =========  IMPORT FASTA ===============================================
		SPLOG("%s importing new reference fasta file for %s", prefix.c_str(), m_ref_name.c_str());

		if (fasta_size == 0) {
			throw io_exception(prefix + " fasta file '" + m_ref_name + "' is empty!");
		}

		const size_t write_modulo = 1 + fasta_size / 20000;

		progress_t update = [&](size_t read, size_t written) {
			update_progress(written / (double)(2*fasta_size));
			return write_modulo;
		};

		std::vector<std::string> dummy_scaf_order;

		file_reader raw_in(fasta_tmp_path.bare_path());
		fasta_ref_importer fri(new_ref_dir_path.bare_path(), raw_in, dummy_scaf_order, m_min_n_run, update);
		fri.run();
		raw_in.close();

		update_progress(1.0);

		// =========  DONE IMPORTING FASTA ===============================================

		// ======== VERIFY FASTA IMPORT OUTPUT ==============================================
		std::string import_failed(prefix + " fasta import failed: ");
		path::exist_enum e = reference_fasta_path.exists();
		if (e != path::e_file) {
			throw io_exception(import_failed + reference_fasta_path.bare_path() + " does not exist.");
		}

		path ref_path = new_ref_dir_path.append(defaults.karyotype);
		if (ref_path.exists() == path::e_no_exist) {
			throw io_exception(import_failed + ref_path.bare_path() + " does not exist");
		}
		// ======== DONE VERIFYING FASTA IMPORT OUTPUT =======================================

		m_state = MAKE_FLAT;
	}
	else if (m_state == MAKE_FLAT) {
		SPLOG("import done");
		SPLOG("Making .ref");
		split_progress(flat_fraction, 1 - flat_fraction);

		// Make the flat reference from the pre-processed fasta.
		// This will change when the old reference_assembly stuff is removed.
		file_reader in(reference_fasta_path.bare_path());
		file_writer flat(reference_ref_path.bare_path());

		flat_ref_builder flb(in, flat);
		flb.run();

		try {
			flat_ref ref(reference_ref_path.bare_path());
		}
		catch(const io_exception&) {
			fs::remove(reference_ref_path.bare_path());
			throw;
		}
		m_state = MAKE_BWT;
		update_progress(1.0);
	}
	else if (m_state == MAKE_BWT) {
		SPLOG("Making .ref done");
		SPLOG("Making bwt");
		split_progress(bwt_fraction, 1 - bwt_fraction);
		auto bwt_task = make_unique<make_bwt_task>();
		bwt_task->input_ref = reference_ref_path.bare_path();
		bwt_task->output_bwt = reference_bwt_path.bare_path();

		add_subtask(std::move(bwt_task));

		update_progress(0.99);

		m_state = DONE;
	}
	else if (m_state == DONE) {
		SPLOG("Making bwt done");

		dataset_meta dm;
		dm.type = datatype_registry::find("reference");

		// successfully terminate the task by setting the output
		update_progress(1.0);
		set_output(dm.the_manifest);
	}
	else {
		throw io_exception(prefix + " Unknown state");
	}
}

max_stars_repo_name: spiralgenetics/biograph

max_issues_repo_name: spiralgenetics/biograph

max_forks_repo_name: spiralgenetics/biograph