#include <iostream>
#include <boost/proto/proto.hpp>
#include <boost/lexical_cast.hpp>
using namespace std;
namespace bp = boost::proto;
namespace bm = boost::mpl;
template<class SimdDesc> struct simd_context;
////////////////////////////////////////////////////////////////////////////////
// SIMD value holder (empty for test purpose) and value descriptor
////////////////////////////////////////////////////////////////////////////////
template<class Type, int Cardinal> struct simd_info
{
typedef Type type;
typedef bm::int_<Cardinal> card;
};
template<class SimdDesc> struct simd_value
{
typedef typename SimdDesc::type type;
type value;
template<class X>type eval(X const& xpr)
{
return bp::eval(xpr,simd_context<SimdDesc>());
}
};
////////////////////////////////////////////////////////////////////////////////
// Grammar helpers
////////////////////////////////////////////////////////////////////////////////
template<class Lambda>
struct lambda_grammar : bp::and_< bp::terminal<bp::_>
, bp::if_< bm::apply1<Lambda,bp::_value>()>
> {};
template<class Grammar> struct low_level
: bp::or_< bp::address_of<Grammar>
, bp::dereference<Grammar>
, bp::comma<Grammar,Grammar>
> {};
////////////////////////////////////////////////////////////////////////////////
// SIMD Grammar
////////////////////////////////////////////////////////////////////////////////
struct simd_grammar
: bp::or_< bp::terminal< simd_value<bp::_> >
, lambda_grammar< boost::is_arithmetic<bm::_> >
, bp::and_< bp::nary_expr< bp::_
, bp::vararg< simd_grammar >
>
, bp::not_<low_level<bp::_> >
>
> {};
//////////////////////////////////////////////////////////////////////////////
// simd_expr forward declaration
//////////////////////////////////////////////////////////////////////////////
template<class X,class SwarType,class BP = bp::is_proto_expr> struct simd_expr;
//////////////////////////////////////////////////////////////////////////////
// SIMD Expression Generator - SIMD Expression use a template parameters
// so proto expression generator should be extended
//////////////////////////////////////////////////////////////////////////////
template<class SimdDesc> struct simd_generator
{
template<class Sig> struct result;
template<class This, class Expr> struct result<This(Expr)>
{
typedef simd_expr<Expr,SimdDesc> type;
};
template<class Expr> simd_expr<Expr,SimdDesc> const
operator()(Expr const &expr) const
{
simd_expr<Expr,SimdDesc> that = {expr};
return that;
}
};
//////////////////////////////////////////////////////////////////////////////
// SIMD Expression Intrinsic
// In this exampel they're stupidly useless but in SIMD mode
// they contains SIMD specific intrinsic or asm code
//////////////////////////////////////////////////////////////////////////////
template<class Tag,class Target> struct intrinsic;
//////////////////////////////////////////////////////////////////////////////
// SIMD Expression Evaluation Context
//////////////////////////////////////////////////////////////////////////////
template<class SimdDesc>
struct simd_context
: bp::callable_context< simd_context<SimdDesc> const
, bp::null_context const
>
{
//////////////////////////////////////////////////////////////////////////
// reuslt_of of context use the intrinsic result_of support
//////////////////////////////////////////////////////////////////////////
template<class Sig> struct result;
template<class This,class Tag,class X>
struct result<This(Tag,X)>
{
typedef typename boost::result_of<intrinsic<Tag,typename SimdDesc::type>(X)>::type type;
};
template<class This,class Tag,class L,class R>
struct result<This(Tag,L,R)>
{
typedef typename boost::result_of<intrinsic<Tag,typename SimdDesc::type>(L,R)>::type type;
};
template<class This,class X>
struct result<This(bp::tag::terminal,X)>
{
typedef typename SimdDesc::type type;
};
template<class This,class X>
struct result<This(bp::tag::terminal,simd_value<X>)>
{
typedef typename X::type type;
};
template<class V> inline
typename boost::enable_if<boost::is_arithmetic<V>
,typename boost::result_of<simd_context(bp::tag::terminal,V)>::type
>::type
operator()(bp::tag::terminal,V const& v) const
{
return v;
}
template<class V> inline
typename boost::disable_if<boost::is_arithmetic<V>
,typename boost::result_of<simd_context(bp::tag::terminal,V)>::type
>::type
operator()(bp::tag::terminal,V const& v) const
{
return v.value;
}
template<class Tag,class X> inline
typename boost::result_of<simd_context(Tag,X)>::type
operator()(Tag, X const& x ) const
{
intrinsic<Tag,typename SimdDesc::type> callee;
return callee(x);
}
template<class Tag,class L,class R> inline
typename boost::result_of<simd_context(Tag,L,R)>::type
operator()(Tag , L const& l, R const& r ) const
{
intrinsic<Tag,typename SimdDesc::type> callee;
return callee(l,r);
}
};
//////////////////////////////////////////////////////////////////////////////
// SIMD Domain forward
//////////////////////////////////////////////////////////////////////////////
template<class SimdDesc> struct simd_domain;
//////////////////////////////////////////////////////////////////////////////
// SIMD Expression
//////////////////////////////////////////////////////////////////////////////
template<class X,class SimdDesc,class BP> struct simd_expr
{
typedef SimdDesc info_type;
typedef X content_type;
typedef typename SimdDesc::type value_type; // This expression contains value_type elements
typedef simd_domain<info_type> domain_type;
BOOST_PROTO_BASIC_EXTENDS(X, simd_expr, domain_type)
//////////////////////////////////////////////////////////////////////////
// simd_expr<X,S> can be casted to its underlying SIMD native type for ease
// of writing of intrinsic
//////////////////////////////////////////////////////////////////////////
operator value_type() const
{
// Extracts the SIMD type from simd_data, here just returns its value
return eval();
}
value_type eval() const
{
// Extracts the SIMD type from simd_data, here just returns its value
simd_value<info_type> data;
return data.eval(*this);
}
};
////////////////////////////////////////////////////////////////////////////
// Tell proto that in the simd_domain, all expressions should be
// wrapped in simd_expr<>
////////////////////////////////////////////////////////////////////////////
template<class SimdDesc>
struct simd_domain : bp::domain< simd_generator<SimdDesc>
, simd_grammar
> {};
////////////////////////////////////////////////////////////////////////////
// Build a simd_expr from normalized type
////////////////////////////////////////////////////////////////////////////
template<class Type,int Cardinal> struct make_simd_expr
{
typedef simd_info<Type,Cardinal> info_type;
typedef simd_value<info_type> vec_type;
typedef typename bp::terminal<vec_type>::type term_;
typedef simd_expr<term_,info_type> type;
};
template<class Type,int Cardinal,class BP = bp::is_proto_expr>
struct vec : public make_simd_expr<Type,Cardinal>::type
{
typedef typename make_simd_expr<Type,Cardinal>::type parent;
typedef typename parent::value_type value_type;
vec() {}
template<class A0>
vec( A0 const& v ) { bp::value(*this).value = v; }
template<class X>
vec( simd_expr<X, simd_info<Type,Cardinal> > const& xpr )
{
bp::value(*this).value = bp::eval(xpr, simd_context<simd_info<Type,Cardinal> >());
}
template<class X>
vec& operator=( simd_expr<X, simd_info<Type,Cardinal> > const& xpr )
{
bp::value(*this).value = bp::eval(xpr, simd_context<simd_info<Type,Cardinal> >());
return *this;
}
//////////////////////////////////////////////////////////////////////////
// vec<T,C> can be casted to its underlying SIMD native type for ease of
// writing of intrinsic
//////////////////////////////////////////////////////////////////////////
operator value_type() const
{
// Extracts the SIMD type from simd_data, here just returns its value
return parent::eval();
}
//////////////////////////////////////////////////////////////////////////
// access ot the scalar components of the vector type /useless here
//////////////////////////////////////////////////////////////////////////
Type& operator[](int i) { return bp::value(*this).value; }
Type operator[](int i) const { return bp::value(*this).value; }
};
/////////////////////////////////////////////////////////////////////////////
// Some intrinsics
/////////////////////////////////////////////////////////////////////////////
template<class Target>
struct intrinsic<bp::tag::plus,Target>
{
typedef Target result_type;
template<class A0, class A1> inline
result_type operator()( A0 const& a0, A1 const& a1) const
{
return result_type(a0) + result_type(a1);
}
};
struct to_float_ {};
template<class Target> struct intrinsic<to_float_,Target>
{
typedef Target result_type;
template<class A0> inline
result_type operator()( A0 const& a0 ) const
{
return "(" + boost::lexical_cast<result_type>( a0.eval() ) + ")";
}
};
template<class A0>
typename bp::result_of::make_expr< to_float_
, simd_domain< simd_info<std::string
,4
>
>
, A0 const&
>::type
to_float( A0 const& a0 )
{
return bp::make_expr< to_float_
, simd_domain< simd_info<std::string
,4
>
>
>( boost::cref(a0) );
}
int main()
{
vec<int,4> v(3);
vec<int,4> u(5);
vec<int,4> z;
vec<std::string,4> f;
z = u+v;
z = (u+v)+(z+z);
cout << z[0] << endl;
//f = to_float(z); // don't work
cout << to_float(z).eval() << endl; //don't work either
}