#include <boost/proto/proto.hpp>
////////////////////////////////////////////////////////////////////////////////
// Strip potential parens around macro parameters.
// Details are in http://article.gmane.org/gmane.comp.lib.boost.user/61011
////////////////////////////////////////////////////////////////////////////////
#define NT2_PP_DETAILS_APPLY(macro, args) NT2_PP_DETAILS_APPLY_I(macro, args)
#define NT2_PP_DETAILS_APPLY_I(macro, args) macro args
#define NT2_PP_DETAILS_STRIP_PARENS_I(...) 1,1
#define NT2_PP_DETAILS_EVAL(test, x) NT2_PP_DETAILS_EVAL_I(test, x)
#define NT2_PP_DETAILS_EVAL_I(test, x) NT2_PP_DETAILS_MAYBE_STRIP_PARENS(NT2_PP_DETAILS_TEST_ARITY test, x)
#define NT2_PP_DETAILS_TEST_ARITY(...) NT2_PP_DETAILS_APPLY(NT2_PP_DETAILS_TEST_ARITY_I, (__VA_ARGS__, 2, 1))
#define NT2_PP_DETAILS_TEST_ARITY_I(a,b,c,...) c
#define NT2_PP_DETAILS_MAYBE_STRIP_PARENS(cond, x) NT2_PP_DETAILS_MAYBE_STRIP_PARENS_I(cond, x)
#define NT2_PP_DETAILS_MAYBE_STRIP_PARENS_I(cond, x) BOOST_PP_CAT(NT2_PP_DETAILS_MAYBE_STRIP_PARENS_, cond)(x)
#define NT2_PP_DETAILS_MAYBE_STRIP_PARENS_1(x) x
#define NT2_PP_DETAILS_MAYBE_STRIP_PARENS_2(x) NT2_PP_DETAILS_APPLY(NT2_PP_DETAILS_MAYBE_STRIP_PARENS_2_I, x)
#define NT2_PP_DETAILS_MAYBE_STRIP_PARENS_2_I(...) __VA_ARGS__
#define NT2_PP_STRIP(x) NT2_PP_DETAILS_EVAL((NT2_PP_DETAILS_STRIP_PARENS_I x), x)
////////////////////////////////////////////////////////////////////////////////
// Proto basic extends for template domain
////////////////////////////////////////////////////////////////////////////////
#define BOOST_PROTO_BASIC_EXTENDS_TPL(Expr, Derived, Domain) \
BOOST_PROTO_BASIC_EXTENDS_( NT2_PP_STRIP(Expr) \
, NT2_PP_STRIP(Derived) \
, NT2_PP_STRIP(Domain) \
) \
typedef void proto_is_aggregate_; \
typedef typename NT2_PP_STRIP(Domain)::proto_generator proto_generator; \
namespace nt2 { namespace simd
{
////////////////////////////////////////////////////////////////////////////////
// Some forward
////////////////////////////////////////////////////////////////////////////////
template< class Type, class Cardinal> struct domain;
template< class Expression
, class Type
, class Cardinal
, class Dummy = boost::proto::is_proto_expr
>
struct expression;
////////////////////////////////////////////////////////////////////////////////
// Fake data to be stored in terminals
////////////////////////////////////////////////////////////////////////////////
template<class T, class C>
struct data {};
////////////////////////////////////////////////////////////////////////////////
// the template grammar
////////////////////////////////////////////////////////////////////////////////
template<class T, class C>
struct grammar
: boost::proto
::or_ < boost::proto::terminal< data<T,C> >
, boost::proto::
and_< boost::proto::
nary_expr < boost::proto::_
, boost::proto::vararg< grammar<T,C> >
>
, boost::proto::
not_< boost::proto::or_ < boost::proto::
address_of< grammar<T,C> >
, boost::proto::
dereference< grammar<T,C> >
, boost::proto::
comma < grammar<T,C>
, grammar<T,C>
>
>
>
>
>
{};
////////////////////////////////////////////////////////////////////////////////
// The template generator
////////////////////////////////////////////////////////////////////////////////
template<class Type,class Cardinal> struct generator
{
template<class Sig> struct result;
template<class This, class Expr>
struct result<This(Expr)> { typedef expression<Expr,Type,Cardinal> type; };
template<class Expr>
expression<Expr,Type,Cardinal> const operator()(Expr const &xpr) const
{
expression<Expr,Type,Cardinal> const that = {xpr};
return that;
}
};
////////////////////////////////////////////////////////////////////////////////
// simd expression
////////////////////////////////////////////////////////////////////////////////
template<class Expr,class Type,class Cardinal, class Dummy>
struct expression
{
////////////////////////////////////////////////////////////////////////////
// Make this a proto expression
////////////////////////////////////////////////////////////////////////////
typedef domain<Type,Cardinal> domain_type;
typedef expression<Expr,Type,Cardinal,Dummy> self_type;
BOOST_PROTO_BASIC_EXTENDS_TPL(Expr, self_type, domain_type)
};
////////////////////////////////////////////////////////////////////////////////
// simd expression domain
////////////////////////////////////////////////////////////////////////////////
template<class Type,class Cardinal>
struct domain : boost::proto::domain< generator<Type,Cardinal>
, grammar<Type,Cardinal>
>
{
};
template<class Type,std::size_t Cardinal,class BP = boost::proto::is_proto_expr>
struct pack
{
////////////////////////////////////////////////////////////////////////////
// Data holder of pack terminals
////////////////////////////////////////////////////////////////////////////
typedef data<Type,boost::mpl::size_t<Cardinal> > data_type;
////////////////////////////////////////////////////////////////////////////
// Make pack a POD proto expression
////////////////////////////////////////////////////////////////////////////
BOOST_PROTO_BASIC_EXTENDS_TPL
( typename boost::proto::terminal<data_type>::type
, (pack<Type,Cardinal>)
, (simd::domain<Type, boost::mpl::size_t<Cardinal> >)
)
};
// The exponent bits function turn pack<float,4> into pack<int,4>
struct exponentbits_ {};
boost::proto::
result_of::make_expr< exponentbits_, domain<int,boost::mpl::size_t<4> >,pack<float,4> const& >::type
exponentbits( pack<float,4> const& x)
{
return boost::proto::
make_expr< exponentbits_, domain<int,boost::mpl::size_t<4> > >( boost::cref(x) );
}
} }
int main()
{
nt2::simd::pack<float,4> x;
nt2::simd::pack<int,4> y;
boost::proto::display_expr(x+x); // ok
//boost::proto::display_expr(y+x); // not ok -- expected
boost::proto::display_expr(exponentbits(x));
boost::proto::display_expr(exponentbits(x)+y); // not ok - unexpected.
// fails with:
/*
* /Users/joelfalcou/nt2/sandbox/proto.cpp:161:46:
* error: no match for 'operator+' in
* 'nt2::simd::exponentbits(((const nt2::simd::pack<float, 4ul>&)((const nt2::simd::pack<float, 4ul>*)(& x)))) + y'
*/
}