#include <vector>
#include <iostream>
using namespace std;
#include <boost/proto/proto.hpp>
#include <boost/type_traits/is_arithmetic.hpp>
namespace nt2 { namespace containers
{
//////////////////////////////////////////////////////////////////////////////
// Main container expression class
//////////////////////////////////////////////////////////////////////////////
template< class Expression
, class Category
, class Tag = typename Expression::proto_tag
, class Dummy = boost::proto::is_proto_expr
> class expr;
} }
namespace nt2 { namespace meta
{
////////////////////////////////////////////////////////////////////////////
/// Proto grammar gathering 'low level' C++ operators
////////////////////////////////////////////////////////////////////////////
template<class Grammar>
struct low_level
: boost::proto::or_< boost::proto::address_of<Grammar>
, boost::proto::dereference<Grammar>
> {};
} }
namespace nt2 { namespace containers
{
// Container grammmar
struct grammar
: boost::proto:: // to change to proper block<_,_> type
or_ < boost::proto::terminal< std::vector<boost::proto::_,boost::proto::_> >
, boost::proto::and_< boost::proto::terminal<boost::proto::_>
, boost::proto::
if_<boost::is_arithmetic<boost::proto::_value>()>
>
, boost::proto::and_< boost::proto ::nary_expr< boost::proto::_
, boost::proto::
vararg< grammar >
>
, boost::proto::not_< meta::low_level<boost::proto::_> >
>
> {};
//////////////////////////////////////////////////////////////////////////////
// Container expression generator
// A container expression bear its category and tag in its type for
// overloading purpose
//////////////////////////////////////////////////////////////////////////////
template<class Category> struct generator
{
template<class Sig> struct result;
template<class This, class X>
struct result<This(X)> { typedef expr<X,Category> type; };
template<class X> inline typename result<generator(X)>::type const
operator()(X const &xpr) const
{
typename result<generator(X)>::type const that(xpr);
return that;
}
};
////////////////////////////////////////////////////////////////////////////////
// Container expression domain
////////////////////////////////////////////////////////////////////////////////
template<class Category>
struct domain : boost::proto::domain< generator<Category>
, grammar
, typename Category::parent_domain
> {};
} }
namespace nt2 { namespace meta
{
template<class Tag> struct is_assignment_operator : boost::mpl::false_ {};
#define NT2_REGISTER_ASSIGNMENT_OPERATOR(TAG) \
template<> struct is_assignment_operator<TAG> : boost::mpl::true_ {} \
/**/
// Those tags invalidate the evaluation of their children
NT2_REGISTER_ASSIGNMENT_OPERATOR(boost::proto::tag::comma );
NT2_REGISTER_ASSIGNMENT_OPERATOR(boost::proto::tag::assign );
NT2_REGISTER_ASSIGNMENT_OPERATOR(boost::proto::tag::plus_assign );
NT2_REGISTER_ASSIGNMENT_OPERATOR(boost::proto::tag::minus_assign );
NT2_REGISTER_ASSIGNMENT_OPERATOR(boost::proto::tag::multiplies_assign );
NT2_REGISTER_ASSIGNMENT_OPERATOR(boost::proto::tag::divides_assign );
NT2_REGISTER_ASSIGNMENT_OPERATOR(boost::proto::tag::modulus_assign );
NT2_REGISTER_ASSIGNMENT_OPERATOR(boost::proto::tag::bitwise_and_assign );
NT2_REGISTER_ASSIGNMENT_OPERATOR(boost::proto::tag::bitwise_or_assign );
NT2_REGISTER_ASSIGNMENT_OPERATOR(boost::proto::tag::bitwise_xor_assign );
NT2_REGISTER_ASSIGNMENT_OPERATOR(boost::proto::tag::shift_left_assign );
NT2_REGISTER_ASSIGNMENT_OPERATOR(boost::proto::tag::shift_right_assign );
} }
namespace nt2 { namespace containers
{
////////////////////////////////////////////////////////////////////////////////
// Container expression
// take care of building container AST and handle their evaluation
////////////////////////////////////////////////////////////////////////////////
template<class X, class C, class Tag, class Dummy>
struct expr : boost::proto::extends<X, expr<X, C, Tag>, domain<C> >
{
typedef C nt2_category_tag;
typedef boost::proto::extends<X, expr<X,C,Tag>, domain<C> > base_type;
explicit expr(X const &expr = X()) : base_type(expr), mEnabler(true)
{
enable(typename meta::is_assignment_operator<Tag>::type() );
}
~expr()
{
eval( typename meta::is_assignment_operator<Tag>::type() );
}
protected:
////////////////////////////////////////////////////////////////////////////
// if the expression is an assignment, prevent children multi-evaluation
////////////////////////////////////////////////////////////////////////////
void enable( boost::mpl::true_ const&)
{
boost::proto::right(*this).mEnabler =
boost::proto::left(*this).mEnabler = false;
}
////////////////////////////////////////////////////////////////////////////
// if the expression is an assignment, start the numeric evaluation
////////////////////////////////////////////////////////////////////////////
void eval( boost::mpl::true_ const&)
{
if(mEnabler) boost::proto::display_expr(*this);
}
////////////////////////////////////////////////////////////////////////////
// if the expression is not an assignment, then we don't have anything to do
////////////////////////////////////////////////////////////////////////////
void enable( boost::mpl::false_ const&) {}
void eval( boost::mpl::false_ const&) {}
public:
mutable bool mEnabler;
};
template<class T,class Category> struct facade
{
typedef typename boost::proto::terminal< std::vector<T> >::type terminal_type;
typedef expr<terminal_type, Category> type;
};
struct table_tag
{
typedef boost::proto::default_domain parent_domain;
};
template<class T>
struct table : public facade<T,table_tag>::type
{
typedef typename facade<T,table_tag>::type parent;
BOOST_PROTO_EXTENDS_USING_ASSIGN(parent)
};
struct vector_tag
{
typedef domain<table_tag> parent_domain;
};
template<class T>
struct vector : public facade<T,vector_tag>::type
{
typedef typename facade<T,vector_tag>::type parent;
BOOST_PROTO_EXTENDS_USING_ASSIGN(parent)
};
} }
namespace nt2 { using containers::table; }
namespace nt2 { using containers::vector; }
namespace nt2
{
struct iota_ {};
template<class B, class S,class E>
struct iota_value
{
typedef B begin_type;
typedef S step_type;
typedef E end_type;
B begin;
S step;
E end;
};
template<class I0,class I1>
typename boost::proto
::result_of::make_expr< iota_
, containers::domain<containers::table_tag>
, iota_value<I0,int,I1>
>::type const
iota( I0 const& begin, I1 const& end )
{
iota_value<I0,int,I1> that ={begin,1,end};
return boost::proto::make_expr<iota_, containers::domain<containers::table_tag> >(that);
}
}
int main()
{
nt2::table<int> t;
nt2::vector<int> x,y;
t = t + nt2::iota(0,5);
}