diff --git a/triqs/clef/clef.hpp b/triqs/clef/clef.hpp index 5262c91f..5356856b 100644 --- a/triqs/clef/clef.hpp +++ b/triqs/clef/clef.hpp @@ -35,8 +35,8 @@ #define TRIQS_CLEF_MAXNARGS 8 -namespace triqs { namespace clef { - typedef unsigned long long ull_t; +namespace triqs { namespace clef { + using ull_t = unsigned long long; namespace tags { struct function_class{}; struct function{}; struct subscript{}; struct terminal{}; struct if_else{}; struct unary_op{}; struct binary_op{}; } // Compute the type to put in the expression tree. @@ -45,11 +45,13 @@ namespace triqs { namespace clef { template struct force_copy_in_expr : std::false_type{}; template struct force_copy_in_expr : force_copy_in_expr{}; - template< class T > struct expr_storage_t {typedef T type;}; - template< class T > struct expr_storage_t : std::conditional::value, typename std::remove_const::type ,std::reference_wrapper>{}; - template< class T > struct expr_storage_t {typedef T type;}; - template< class T > struct expr_storage_t {typedef T type;}; - template< class T > struct expr_storage_t {typedef T type;}; + template< class T > struct expr_storage_impl {typedef T type;}; + template< class T > struct expr_storage_impl : std::conditional::value, typename std::remove_const::type ,std::reference_wrapper>{}; + template< class T > struct expr_storage_impl {typedef T type;}; + template< class T > struct expr_storage_impl {typedef T type;}; + template< class T > struct expr_storage_impl {typedef T type;}; + + template using expr_storage_t = typename expr_storage_impl::type; // helper type /* --------------------------------------------------------------------------------------------------- * Placeholder and corresponding traits @@ -64,13 +66,13 @@ namespace triqs { namespace clef { }; // placeholder will always be copied (they are empty anyway). - template< int N > struct force_copy_in_expr> : std::true_type{}; + template struct force_copy_in_expr> : std::true_type {}; - // represent a couple (placeholder, value). - template struct pair { + // represent a couple (placeholder, value). + template struct pair { U rhs; static constexpr int p = N; - typedef typename remove_cv_ref ::type value_type; + using value_type = typename remove_cv_ref::type; }; // ph_set is a trait that given a pack of type, returns the set of placeholders they contain @@ -101,7 +103,7 @@ namespace triqs { namespace clef { * --------------------------------------------------------------------------------------------------- */ template struct expr { // T can be U, U & (a reference or a value). - typedef std::tuple childs_t; + using childs_t = std::tuple; childs_t childs; expr(expr const & x) = default; expr(expr && x) noexcept : childs(std::move(x.childs)) {} @@ -109,11 +111,11 @@ namespace triqs { namespace clef { template expr(Tag, Args&&...args) : childs(std::forward(args)...) {} // [] returns a new lazy expression, with one more layer template - expr::type > operator[](Args && args) const + expr > operator[](Args && args) const { return {tags::subscript(), *this,std::forward(args)};} // () also ... template< typename... Args > - expr::type...> operator()(Args && ... args) const + expr...> operator()(Args && ... args) const { return {tags::function(), *this,std::forward(args)...};} // assignement is in general deleted expr & operator= (expr const &) = delete; // no ordinary assignment @@ -151,20 +153,27 @@ namespace triqs { namespace clef { }; /// [ ] Call - template<> struct operation { + template<> struct operation { template auto operator()(F&& f, Args&& args) const DECL_AND_RETURN(_cl(std::forward(f))[_cl(std::forward(args))]); }; // all binary operators.... -#define TRIQS_CLEF_OPERATION(TAG,OP)\ - namespace tags { struct TAG : binary_op { static const char * name() { return BOOST_PP_STRINGIZE(OP);} };}\ - template<> struct operation {\ - template auto operator()(L && l, R && r) const DECL_AND_RETURN ( _cl(std::forward(l)) OP _cl(std::forward(r)));\ - };\ - template\ - typename std::enable_if::value, expr::type,typename expr_storage_t::type> >::type \ - operator OP (L && l, R && r) { return {tags::TAG(),std::forward(l),std::forward(r)};}\ +#define TRIQS_CLEF_OPERATION(TAG, OP) \ + namespace tags { \ + struct TAG : binary_op { \ + static const char* name() { return BOOST_PP_STRINGIZE(OP); } \ + }; \ + } \ + template \ + typename std::enable_if::value, expr, expr_storage_t>>::type operator OP( \ + L&& l, R&& r) { \ + return {tags::TAG(), std::forward(l), std::forward(r)}; \ + } \ + template <> struct operation { \ + template \ + auto operator()(L&& l, R&& r) const DECL_AND_RETURN(_cl(std::forward(l)) OP _cl(std::forward(r))); \ + }; TRIQS_CLEF_OPERATION(plus, +); TRIQS_CLEF_OPERATION(minus, -); @@ -178,14 +187,19 @@ namespace triqs { namespace clef { #undef TRIQS_CLEF_OPERATION // all unary operators.... -#define TRIQS_CLEF_OPERATION(TAG,OP)\ - namespace tags { struct TAG : unary_op { static const char * name() { return BOOST_PP_STRINGIZE(OP);} };}\ - template<> struct operation {\ - template auto operator()(L && l) const DECL_AND_RETURN (OP _cl(std::forward(l)));\ - };\ - template\ - typename std::enable_if::value, expr::type> >::type \ - operator OP (L && l) { return {tags::TAG(),std::forward(l)};}\ +#define TRIQS_CLEF_OPERATION(TAG, OP) \ + namespace tags { \ + struct TAG : unary_op { \ + static const char* name() { return BOOST_PP_STRINGIZE(OP); } \ + }; \ + } \ + template \ + typename std::enable_if::value, expr>>::type operator OP(L&& l) { \ + return {tags::TAG(), std::forward(l)}; \ + } \ + template <> struct operation { \ + template auto operator()(L&& l) const DECL_AND_RETURN(OP _cl(std::forward(l))); \ + }; TRIQS_CLEF_OPERATION(negate, -); TRIQS_CLEF_OPERATION(loginot, !); @@ -199,71 +213,96 @@ namespace triqs { namespace clef { }; // operator is : if_else( Condition, A, B) template - expr::type,typename expr_storage_t::type,typename expr_storage_t::type> + expr,expr_storage_t,expr_storage_t> if_else(C && c, A && a, B && b) { return {tags::if_else(),std::forward(c),std::forward(a),std::forward(b)};} /* --------------------------------------------------------------------------------------------------- * Evaluation of the expression tree. * --------------------------------------------------------------------------------------------------- */ - template struct _or; - template struct _or : std::integral_constant::value>{}; - template<> struct _or<> : std::false_type{}; + //template struct _or; + //template struct _or : std::integral_constant::value>{}; + //template<> struct _or<> : std::false_type{}; + + // just to try + constexpr bool __or() { return false;} + template constexpr bool __or(bool b, B... bs) { return b || __or(bs...); } // Generic case : do nothing (for the leaf of the tree including placeholder) - template struct evaluator{ - typedef is_any_lazy is_lazy; - T operator()(T const & k, Pairs const &... pairs) { return k;} + template struct evaluator { + static constexpr bool is_lazy = is_any_lazy::value; + T const & operator()(T const& k, Pairs const&... pairs) const { return k; } }; // placeholder - template struct evaluator< placeholder, pair, Pairs... > { - typedef evaluator< placeholder, Pairs...> eval_t; - typedef typename eval_t::is_lazy is_lazy; - auto operator()(placeholder, pair const &, Pairs const& ... pairs) DECL_AND_RETURN( eval_t()(placeholder(), pairs...)); + template struct evaluator, pair, Pairs...> { + using eval_t = evaluator, Pairs...>; + static constexpr bool is_lazy = eval_t::is_lazy; + auto operator()(placeholder, pair const&, Pairs const&... pairs) const + DECL_AND_RETURN(eval_t()(placeholder(), pairs...)); }; - template struct evaluator< placeholder, pair, Pairs... > { - typedef std::false_type is_lazy; - T operator()(placeholder, pair const & p, Pairs const& ...) { return p.rhs;} + template struct evaluator, pair, Pairs...> { + static constexpr bool is_lazy = false; + T operator()(placeholder, pair const& p, Pairs const&...) const { return p.rhs; } }; - template struct operation2; - template struct operation2 { - template - expr::type ...> operator()(Args && ... args) const { - return {Tag(), std::forward(args)...}; - } + // any object hold by reference wrapper is redirected to the evaluator of the object + template struct evaluator, Contexts...> { + using ev_t = evaluator; + static constexpr bool is_lazy = ev_t::is_lazy; + auto operator()(std::reference_wrapper const& x, Contexts const&... contexts) const DECL_AND_RETURN(ev_t {}(x.get(), contexts...)); }; - template struct operation2 { - template - auto operator()(Args && ... args) const DECL_AND_RETURN( operation()(std::forward(args)...)); - //void operator() (...) const {} + + // dispatching the evaluation : if lazy, we make a new clef expression, if not we call the operation + template struct op_dispatch; + + template struct op_dispatch { + template expr...> operator()(Args&&... args) const { + return {Tag(), std::forward(args)...}; + } + }; + + template struct op_dispatch { + template + auto operator()(Args&&... args) const DECL_AND_RETURN(operation()(std::forward(args)...)); }; // general expr node + +#ifdef TRIQS_USE_C14_DRAFT__ + template struct evaluator, Pairs...> { + + static constexpr bool is_lazy = __or(evaluator::is_lazy...); + + auto operator()(expr const& ex, Pairs const&... pairs) const { + auto eval_in_context = [&pairs](auto const& _child) { return eval(_child, pairs); }; + return triqs::tuple::apply_compose(op_dispatch{}, eval_in_context, ex.childs); + } + }; +#else + // WORKAROUND FOR C++11 compilers template struct evaluator_node_gal; - template struct evaluator_node_gal<1, expr, Pairs...> { - typedef _or::is_lazy... > is_lazy; - typedef operation2 OPTYPE; - auto operator()(expr const & ex, Pairs const & ... pairs) const - DECL_AND_RETURN (OPTYPE()(eval(std::get<0>(ex.childs),pairs...))); + template struct evaluator_node_gal<1, expr, Pairs...> { + static constexpr bool is_lazy = __or(evaluator::is_lazy...); + auto operator()(expr const& ex, Pairs const&... pairs) const + DECL_AND_RETURN(op_dispatch {}(eval(std::get<0>(ex.childs), pairs...))); }; - template struct evaluator_node_gal<2, expr, Pairs...> { - typedef _or::is_lazy... > is_lazy; - typedef operation2 OPTYPE; - auto operator()(expr const & ex, Pairs const & ... pairs) const - DECL_AND_RETURN (OPTYPE()(eval(std::get<0>(ex.childs),pairs...),eval(std::get<1>(ex.childs),pairs...))); + template struct evaluator_node_gal<2, expr, Pairs...> { + static constexpr bool is_lazy = __or(evaluator::is_lazy...); + auto operator()(expr const& ex, Pairs const&... pairs) const DECL_AND_RETURN(op_dispatch { + }(eval(std::get<0>(ex.childs), pairs...), eval(std::get<1>(ex.childs), pairs...))); }; -#define AUX(z,p,unused) eval(std::get

(ex.childs),pairs...) -#define IMPL(z, NN, unused) \ - template struct evaluator_node_gal, Pairs...> {\ - typedef _or::is_lazy... > is_lazy;\ - typedef operation2 OPTYPE;\ - auto operator()(expr const & ex, Pairs const & ... pairs) const\ - DECL_AND_RETURN ( OPTYPE()(BOOST_PP_ENUM(NN,AUX,nil)));\ +// the general case for more than 2 nodes. I put 1 and 2 nodes apart, just because it is the most frequent +// and macros yield more obscure error messages in case of a pb ... +#define AUX(z, p, unused) eval(std::get

(ex.childs), pairs...) +#define IMPL(z, NN, unused) \ + template struct evaluator_node_gal, Pairs...> { \ + static constexpr bool is_lazy = __or(evaluator::is_lazy...); \ + auto operator()(expr const& ex, Pairs const&... pairs) const \ + DECL_AND_RETURN(op_dispatch {}(BOOST_PP_ENUM(NN, AUX, nil))); \ }; BOOST_PP_REPEAT_FROM_TO(3,BOOST_PP_INC(TRIQS_CLEF_MAXNARGS), IMPL, nil); #undef AUX @@ -271,6 +310,8 @@ namespace triqs { namespace clef { template struct evaluator, Pairs...> : evaluator_node_gal, Pairs...>{}; +#endif + // The general eval function for expressions template @@ -303,14 +344,15 @@ namespace triqs { namespace clef { make_function(Expr && ex, Phs...) { return {ex}; } namespace result_of { - template< typename Expr, typename ... Phs> struct make_function { - typedef make_fun_impl::type,Phs::index...> type; + template< typename Expr, typename ... Phs> struct make_function { + using type = make_fun_impl::type, Phs::index...>; }; } template< typename Expr, int... Is,typename... Pairs> struct evaluator, Pairs...> { - typedef evaluator e_t; - typedef std::integral_constant >::value != ph_set::value> is_lazy; + using e_t = evaluator; + //using is_lazy = std::integral_constant>::value != ph_set::value>; + static constexpr bool is_lazy = (ph_set>::value != ph_set::value); auto operator()(make_fun_impl const & f, Pairs const & ... pairs) const DECL_AND_RETURN( make_function( e_t()(f.ex, pairs...),placeholder()...)); }; @@ -407,7 +449,7 @@ namespace triqs { namespace clef { * --------------------------------------------------------------------------------------------------- */ // make a node with the ref, unless it is an rvalue (which is moved). - template expr::type > + template expr > make_expr(T && x){ return {tags::terminal(), std::forward(x)};} // make a node from a copy of the object @@ -423,7 +465,7 @@ namespace triqs { namespace clef { namespace _result_of { template< typename Obj, typename... Args > struct make_expr_call : - std::enable_if< is_any_lazy::value, expr::type, typename expr_storage_t::type ...> > { + std::enable_if< is_any_lazy::value, expr, expr_storage_t ...> > { static_assert (((arity::value==-1) || (arity::value == sizeof...(Args))), "Object called with a wrong number of arguments"); }; } @@ -438,7 +480,7 @@ namespace triqs { namespace clef { namespace _result_of { template< typename Obj, typename Arg> struct make_expr_subscript : - std::enable_if< is_any_lazy::value, expr::type, typename expr_storage_t::type> > {}; + std::enable_if< is_any_lazy::value, expr, expr_storage_t> > {}; } template< typename Obj, typename Arg> typename _result_of::make_expr_subscript::type @@ -452,7 +494,7 @@ namespace triqs { namespace clef { template class function; template class function : tags::function_class { - typedef std::function std_function_type; + using std_function_type = std::function; mutable std::shared_ptr _exp; // CLEAN THIS MUTABLE ? mutable std::shared_ptr < std_function_type > _fnt_ptr; public: @@ -481,31 +523,32 @@ namespace triqs { namespace clef { * taking expressions (at least one argument has to be an expression) * The lookup happens by ADL, so IT MUST BE USED IN THE triqs::lazy namespace * --------------------------------------------------------------------------------------------------- */ -#define TRIQS_CLEF_MAKE_FNT_LAZY(name)\ - struct name##_lazy_impl { \ - template auto operator()(A&&... a) const DECL_AND_RETURN (name(std::forward(a)...));\ - };\ - template< typename... A> \ - auto name( A&& ... a) DECL_AND_RETURN(make_expr_call(name##_lazy_impl(),std::forward(a)...)); +#define TRIQS_CLEF_MAKE_FNT_LAZY(name) \ + struct name##_lazy_impl { \ + template auto operator()(A&&... a) const -> decltype(name(std::forward(a)...)); \ + }; \ + template auto name(A&&... a) DECL_AND_RETURN(make_expr_call(name##_lazy_impl(), std::forward(a)...)); \ + template auto name##_lazy_impl::operator()(A&&... a) const DECL_AND_RETURN(name(std::forward(a)...)); -#define TRIQS_CLEF_IMPLEMENT_LAZY_METHOD(TY,name)\ - struct __clef_lazy_method_impl_##name { \ - TY * _x;\ - template auto operator()(A&&... a) const DECL_AND_RETURN (_x->name(std::forward(a)...));\ - friend std::ostream & operator<<(std::ostream & out, __clef_lazy_method_impl_##name const & x) { return out< \ - auto name( A&& ... a) DECL_AND_RETURN (make_expr_call(__clef_lazy_method_impl_##name{this},std::forward(a)...)); - -#define TRIQS_CLEF_IMPLEMENT_LAZY_CALL(...)\ - template< typename... Args>\ - auto operator()(Args&&... args ) const & DECL_AND_RETURN(make_expr_call (*this,std::forward(args)...));\ - \ - template< typename... Args>\ - auto operator()(Args&&... args ) & DECL_AND_RETURN(make_expr_call (*this,std::forward(args)...));\ - \ - template< typename... Args>\ - auto operator()(Args&&... args ) && DECL_AND_RETURN(make_expr_call (std::move(*this),std::forward(args)...));\ +#define TRIQS_CLEF_IMPLEMENT_LAZY_METHOD(TY, name) \ + struct __clef_lazy_method_impl_##name { \ + TY* _x; \ + template auto operator()(A&&... a) const DECL_AND_RETURN(_x -> name(std::forward(a)...)); \ + friend std::ostream& operator<<(std::ostream& out, __clef_lazy_method_impl_##name const& x) { \ + return out << BOOST_PP_STRINGIZE(TY) << "." << BOOST_PP_STRINGIZE(name); \ + } \ + }; \ + template \ + auto name(A&&... a) DECL_AND_RETURN(make_expr_call(__clef_lazy_method_impl_##name{this}, std::forward(a)...)); +#define TRIQS_CLEF_IMPLEMENT_LAZY_CALL(...) \ + template \ + auto operator()(Args&&... args) const& DECL_AND_RETURN(make_expr_call(*this, std::forward(args)...)); \ + \ + template \ + auto operator()(Args&&... args) & DECL_AND_RETURN(make_expr_call(*this, std::forward(args)...)); \ + \ + template \ + auto operator()(Args&&... args) && DECL_AND_RETURN(make_expr_call(std::move(*this), std::forward(args)...)); }} // namespace triqs::clef #endif