mirror of
https://github.com/triqs/dft_tools
synced 2024-12-25 13:53:40 +01:00
clef: add version c14
- a slightly different version for c++14, to avoid some decltype and have clearer error messages. only in c++1y mode.
This commit is contained in:
parent
3fd3f38446
commit
2fdba13bc5
614
triqs/clef/clef.c11.hpp
Normal file
614
triqs/clef/clef.c11.hpp
Normal file
@ -0,0 +1,614 @@
|
||||
/*******************************************************************************
|
||||
*
|
||||
* TRIQS: a Toolbox for Research in Interacting Quantum Systems
|
||||
*
|
||||
* Copyright (C) 2012-2013 by O. Parcollet
|
||||
*
|
||||
* TRIQS is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU General Public License as published by the Free Software
|
||||
* Foundation, either version 3 of the License, or (at your option) any later
|
||||
* version.
|
||||
*
|
||||
* TRIQS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* TRIQS. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
******************************************************************************/
|
||||
#ifndef TRIQS_CLEF_CORE_H
|
||||
#define TRIQS_CLEF_CORE_H
|
||||
#include <triqs/utility/first_include.hpp>
|
||||
#include <triqs/utility/macros.hpp>
|
||||
#include <triqs/utility/compiler_details.hpp>
|
||||
#include <triqs/utility/tuple_tools.hpp>
|
||||
#include <triqs/utility/c14.hpp>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <complex>
|
||||
#include <boost/preprocessor/stringize.hpp>
|
||||
#include <boost/preprocessor/repetition/repeat_from_to.hpp>
|
||||
#include <boost/preprocessor/repetition/enum.hpp>
|
||||
#include <boost/preprocessor/arithmetic/inc.hpp>
|
||||
|
||||
#define TRIQS_CLEF_MAXNARGS 8
|
||||
|
||||
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.
|
||||
// If T is a lvalue reference, pack it into a reference_wrapper, unless force_copy_in_expr<T>::value == true
|
||||
// If T is an rvalue reference, we store it as the type (using move semantics).
|
||||
template<typename T> struct force_copy_in_expr : std::false_type{};
|
||||
template<typename T> struct force_copy_in_expr<T const> : force_copy_in_expr<T>{};
|
||||
|
||||
template< class T > struct expr_storage_impl {typedef T type;};
|
||||
template< class T > struct expr_storage_impl<T&> : std::conditional<force_copy_in_expr<T>::value, typename std::remove_const<T>::type ,std::reference_wrapper<T>>{};
|
||||
template< class T > struct expr_storage_impl<T&&> {typedef T type;};
|
||||
template< class T > struct expr_storage_impl<const T&&> {typedef T type;};
|
||||
template< class T > struct expr_storage_impl<const T> {typedef T type;};
|
||||
|
||||
template <class T> using expr_storage_t = typename expr_storage_impl<T>::type; // helper type
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------
|
||||
* Placeholder and corresponding traits
|
||||
* --------------------------------------------------------------------------------------------------- */
|
||||
template<int i, typename T> struct pair; // forward
|
||||
|
||||
// a placeholder is an empty struct, labelled by an int.
|
||||
template<int N> struct placeholder {
|
||||
static_assert( (N>=0) && (N<64) , "Placeholder number limited to [0,63]");
|
||||
static constexpr int index = N;
|
||||
template <typename RHS> pair<N,RHS> operator = (RHS && rhs) { return {std::forward<RHS>(rhs)};}
|
||||
};
|
||||
|
||||
// placeholder will always be copied (they are empty anyway).
|
||||
template <int N> struct force_copy_in_expr<placeholder<N>> : std::true_type {};
|
||||
|
||||
// represent a couple (placeholder, value).
|
||||
template <int N, typename U> struct pair {
|
||||
U rhs;
|
||||
static constexpr int p = N;
|
||||
using value_type = typename remove_cv_ref<U>::type;
|
||||
};
|
||||
|
||||
// ph_set is a trait that given a pack of type, returns the set of placeholders they contain
|
||||
// it returns a int in binary coding : bit N in the int is 1 iif at least one T is lazy and contains placeholder<N>
|
||||
template<typename... T> struct ph_set;
|
||||
template<typename T0, typename... T> struct ph_set<T0,T...>{static constexpr ull_t value= ph_set<T0>::value| ph_set<T...>::value;};
|
||||
template<typename T> struct ph_set<T> {static constexpr ull_t value= 0;};
|
||||
template<int N> struct ph_set<placeholder<N>> {static constexpr ull_t value= 1ull<<N;};
|
||||
template<int i, typename T> struct ph_set<pair<i,T> > : ph_set<placeholder<i>>{};
|
||||
|
||||
// in_any_lazy : trait to detect if any of Args is a lazy expression
|
||||
template<typename... Args> struct is_any_lazy : std::false_type {};
|
||||
template<int N> struct is_any_lazy <placeholder <N> > : std::true_type {};
|
||||
template <typename T> struct is_any_lazy< T > : std::false_type {};
|
||||
template <typename T> struct is_any_lazy< T&& > : is_any_lazy<T> {};
|
||||
template <typename T> struct is_any_lazy< T& > : is_any_lazy<T> {};
|
||||
template <typename T> struct is_any_lazy< T const > : is_any_lazy<T> {};
|
||||
template<typename T, typename... Args> struct is_any_lazy<T, Args...> :
|
||||
std::integral_constant<bool, is_any_lazy<T>::value || is_any_lazy<Args...>::value> {};
|
||||
|
||||
template<typename T>
|
||||
constexpr bool ClefExpression() { return is_any_lazy<T>::value;}
|
||||
|
||||
template<typename T> struct is_clef_expression : is_any_lazy<T>{};
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------
|
||||
* Node of the expression tree
|
||||
* --------------------------------------------------------------------------------------------------- */
|
||||
template<typename Tag, typename... T> struct expr {
|
||||
// T can be U, U & (a reference or a value).
|
||||
using childs_t = std::tuple<T...>;
|
||||
childs_t childs;
|
||||
expr(expr const & x) = default;
|
||||
expr(expr && x) noexcept : childs(std::move(x.childs)) {}
|
||||
// a constructor with the Tag make it unambiguous with other constructors...
|
||||
template<typename... Args> expr(Tag, Args&&...args) : childs(std::forward<Args>(args)...) {}
|
||||
// [] returns a new lazy expression, with one more layer
|
||||
template<typename Args>
|
||||
expr<tags::subscript, expr, expr_storage_t<Args> > operator[](Args && args) const
|
||||
{ return {tags::subscript(), *this,std::forward<Args>(args)};}
|
||||
// () also ...
|
||||
template< typename... Args >
|
||||
expr<tags::function, expr, expr_storage_t<Args>...> operator()(Args && ... args) const
|
||||
{ return {tags::function(), *this,std::forward<Args>(args)...};}
|
||||
// assignement is in general deleted
|
||||
expr & operator= (expr const &) = delete; // no ordinary assignment
|
||||
expr & operator= (expr &&) = default; // move assign ok
|
||||
// however, this is ok in the case f(i,j) = expr, where f is a clef::function
|
||||
template<typename RHS, typename CH = childs_t>
|
||||
ENABLE_IF(std::is_base_of<tags::function_class, typename std::tuple_element<0,CH>::type>)
|
||||
operator= (RHS const & rhs) { *this << rhs;}
|
||||
template<typename RHS, typename CH = childs_t>
|
||||
DISABLE_IF(std::is_base_of<tags::function_class, typename std::tuple_element<0,CH>::type>)
|
||||
operator= (RHS const & rhs) = delete;
|
||||
};
|
||||
// set some traits
|
||||
template<typename Tag, typename... T> struct ph_set< expr<Tag,T... > > : ph_set<T...> {};
|
||||
template<typename Tag, typename... T> struct is_any_lazy< expr<Tag,T... > >: std::true_type {};
|
||||
// if we want that subexpression are copied ?
|
||||
template<typename Tag, typename... T> struct force_copy_in_expr< expr<Tag,T... > > : std::true_type{};
|
||||
|
||||
template <typename Tag, typename... T> using expr_node_t = expr<Tag, expr_storage_t<T>...>;
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------
|
||||
* The basic operations put in a template....
|
||||
* --------------------------------------------------------------------------------------------------- */
|
||||
template<typename Tag> struct operation;
|
||||
|
||||
// a little function to clean the reference_wrapper
|
||||
template<typename U> U _cl(U && x) { return std::forward<U>(x);}
|
||||
template<typename U> auto _cl(std::reference_wrapper<U> x) DECL_AND_RETURN(x.get());
|
||||
|
||||
/// Terminal
|
||||
template<> struct operation<tags::terminal> { template<typename L> L operator()(L&& l) const { return std::forward<L>(l);} };
|
||||
|
||||
/// Function call
|
||||
template<> struct operation<tags::function> {
|
||||
template <typename F, typename... Args>
|
||||
auto operator()(F&& f, Args&&... args) const DECL_AND_RETURN(_cl(std::forward<F>(f))(_cl(std::forward<Args>(args))...));
|
||||
};
|
||||
|
||||
/// [ ] Call
|
||||
template<> struct operation<tags::subscript> {
|
||||
template <typename F, typename Args>
|
||||
auto operator()(F&& f, Args&& args) const DECL_AND_RETURN(_cl(std::forward<F>(f))[_cl(std::forward<Args>(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 <typename L, typename R> \
|
||||
std14::enable_if_t<is_any_lazy<L, R>::value, expr<tags::TAG, expr_storage_t<L>, expr_storage_t<R>>> operator OP(L&& l, R&& r) { \
|
||||
return {tags::TAG(), std::forward<L>(l), std::forward<R>(r)}; \
|
||||
} \
|
||||
template <> struct operation<tags::TAG> { \
|
||||
template <typename L, typename R> \
|
||||
auto operator()(L&& l, R&& r) const DECL_AND_RETURN(_cl(std::forward<L>(l)) OP _cl(std::forward<R>(r))); \
|
||||
};
|
||||
|
||||
TRIQS_CLEF_OPERATION(plus, +);
|
||||
TRIQS_CLEF_OPERATION(minus, -);
|
||||
TRIQS_CLEF_OPERATION(multiplies, *);
|
||||
TRIQS_CLEF_OPERATION(divides, /);
|
||||
TRIQS_CLEF_OPERATION(greater, >);
|
||||
TRIQS_CLEF_OPERATION(less, <);
|
||||
TRIQS_CLEF_OPERATION(leq, <=);
|
||||
TRIQS_CLEF_OPERATION(geq, >=);
|
||||
TRIQS_CLEF_OPERATION(eq, ==);
|
||||
#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 <typename L> \
|
||||
std14::enable_if_t<is_any_lazy<L>::value, expr<tags::TAG, expr_storage_t<L>>> operator OP(L&& l) { \
|
||||
return {tags::TAG(), std::forward<L>(l)}; \
|
||||
} \
|
||||
template <> struct operation<tags::TAG> { \
|
||||
template <typename L> auto operator()(L&& l) const DECL_AND_RETURN(OP _cl(std::forward<L>(l))); \
|
||||
};
|
||||
|
||||
TRIQS_CLEF_OPERATION(negate, -);
|
||||
TRIQS_CLEF_OPERATION(loginot, !);
|
||||
#undef TRIQS_CLEF_OPERATION
|
||||
|
||||
/// the only ternary node : expression if
|
||||
template<> struct operation<tags::if_else> {
|
||||
// A and B MUST be the same
|
||||
template<typename C, typename A, typename B> A operator()(C const & c, A const & a, B const & b) const {return _cl(c) ? _cl(a): _cl(b);}
|
||||
//template<typename C, typename A, typename B> auto operator()(C const & c, A const & a, B const & b) const DECL_AND_RETURN (_cl(c) ? _cl(a): _cl(b));
|
||||
};
|
||||
// operator is : if_else( Condition, A, B)
|
||||
template<typename C, typename A, typename B>
|
||||
expr<tags::if_else,expr_storage_t<C>,expr_storage_t<A>,expr_storage_t<B>>
|
||||
if_else(C && c, A && a, B && b) { return {tags::if_else(),std::forward<C>(c),std::forward<A>(a),std::forward<B>(b)};}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------
|
||||
* Evaluation of the expression tree.
|
||||
* --------------------------------------------------------------------------------------------------- */
|
||||
|
||||
constexpr bool __or() { return false;}
|
||||
template<typename ... B> constexpr bool __or(bool b, B... bs) { return b || __or(bs...); }
|
||||
|
||||
// Generic case : do nothing (for the leaf of the tree including placeholder)
|
||||
template <typename T, typename... Pairs> struct evaluator {
|
||||
static constexpr bool is_lazy = is_any_lazy<T>::value;
|
||||
T const & operator()(T const& k, Pairs const&... pairs) const { return k; }
|
||||
};
|
||||
|
||||
// The general eval function for expressions : declaration only
|
||||
template<typename T, typename... Pairs>
|
||||
auto eval (T const & ex, Pairs const &... pairs) ->decltype( evaluator<T, Pairs...>()(ex, pairs...));
|
||||
|
||||
// placeholder
|
||||
template <int N, int i, typename T, typename... Pairs> struct evaluator<placeholder<N>, pair<i, T>, Pairs...> {
|
||||
using eval_t = evaluator<placeholder<N>, Pairs...>;
|
||||
static constexpr bool is_lazy = eval_t::is_lazy;
|
||||
auto operator()(placeholder<N>, pair<i, T> const&, Pairs const&... pairs) const
|
||||
DECL_AND_RETURN(eval_t()(placeholder<N>(), pairs...));
|
||||
};
|
||||
|
||||
template <int N, typename T, typename... Pairs> struct evaluator<placeholder<N>, pair<N, T>, Pairs...> {
|
||||
static constexpr bool is_lazy = false;
|
||||
T operator()(placeholder<N>, pair<N, T> const& p, Pairs const&...) const { return p.rhs; }
|
||||
};
|
||||
|
||||
// any object hold by reference wrapper is redirected to the evaluator of the object
|
||||
template <typename T, typename... Contexts> struct evaluator<std::reference_wrapper<T>, Contexts...> {
|
||||
//using ev_t = evaluator<T, Contexts...>;
|
||||
static constexpr bool is_lazy = false;//ev_t::is_lazy;
|
||||
auto operator()(std::reference_wrapper<T> const& x, Contexts const&... contexts) const DECL_AND_RETURN(eval(x.get(), contexts...));
|
||||
};
|
||||
|
||||
// dispatching the evaluation : if lazy, we make a new clef expression, if not we call the operation
|
||||
template <typename Tag, bool IsLazy> struct op_dispatch;
|
||||
|
||||
template <typename Tag> struct op_dispatch<Tag, true> {
|
||||
template <typename... Args> expr<Tag, expr_storage_t<Args>...> operator()(Args&&... args) const {
|
||||
return {Tag(), std::forward<Args>(args)...};
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Tag> struct op_dispatch<Tag, false> {
|
||||
template <typename... Args>
|
||||
auto operator()(Args&&... args) const DECL_AND_RETURN(operation<Tag>()(std::forward<Args>(args)...));
|
||||
};
|
||||
|
||||
// general expr node
|
||||
|
||||
#ifdef TRIQS_USE_C14_DRAFT__
|
||||
template <typename Tag, typename... Childs, typename... Pairs> struct evaluator<expr<Tag, Childs...>, Pairs...> {
|
||||
|
||||
static constexpr bool is_lazy = __or(evaluator<Childs, Pairs...>::is_lazy...);
|
||||
|
||||
auto operator()(expr<Tag, Childs...> const& ex, Pairs const&... pairs) const {
|
||||
auto eval_in_context = [&pairs...](auto const& _child) { return eval(_child, pairs...); };
|
||||
return tuple::apply_compose(op_dispatch<Tag, is_lazy>{}, eval_in_context, ex.childs);
|
||||
}
|
||||
};
|
||||
#else
|
||||
// WORKAROUND FOR C++11 compilers
|
||||
template<int arity, typename Expr, typename... Pairs> struct evaluator_node_gal;
|
||||
|
||||
template <typename Tag, typename... Childs, typename... Pairs> struct evaluator_node_gal<1, expr<Tag, Childs...>, Pairs...> {
|
||||
static constexpr bool is_lazy = __or(evaluator<Childs, Pairs...>::is_lazy...);
|
||||
auto operator()(expr<Tag, Childs...> const& ex, Pairs const&... pairs) const
|
||||
DECL_AND_RETURN(op_dispatch<Tag, is_lazy> {}(eval(std::get<0>(ex.childs), pairs...)));
|
||||
};
|
||||
|
||||
template <typename Tag, typename... Childs, typename... Pairs> struct evaluator_node_gal<2, expr<Tag, Childs...>, Pairs...> {
|
||||
static constexpr bool is_lazy = __or(evaluator<Childs, Pairs...>::is_lazy...);
|
||||
auto operator()(expr<Tag, Childs...> const& ex, Pairs const&... pairs) const
|
||||
DECL_AND_RETURN(op_dispatch<Tag, is_lazy> {}(eval(std::get<0>(ex.childs), pairs...), eval(std::get<1>(ex.childs), pairs...)));
|
||||
};
|
||||
|
||||
// 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<p>(ex.childs), pairs...)
|
||||
#define IMPL(z, NN, unused) \
|
||||
template <typename Tag, typename... Childs, typename... Pairs> struct evaluator_node_gal<NN, expr<Tag, Childs...>, Pairs...> { \
|
||||
static constexpr bool is_lazy = __or(evaluator<Childs, Pairs...>::is_lazy...); \
|
||||
auto operator()(expr<Tag, Childs...> const& ex, Pairs const&... pairs) const \
|
||||
DECL_AND_RETURN(op_dispatch<Tag, is_lazy> {}(BOOST_PP_ENUM(NN, AUX, nil))); \
|
||||
};
|
||||
BOOST_PP_REPEAT_FROM_TO(3,BOOST_PP_INC(TRIQS_CLEF_MAXNARGS), IMPL, nil);
|
||||
#undef AUX
|
||||
#undef IMPL
|
||||
|
||||
template<typename Tag, typename... Childs, typename... Pairs>
|
||||
struct evaluator<expr<Tag, Childs...>, Pairs...> : evaluator_node_gal<sizeof...(Childs), expr<Tag, Childs...>, Pairs...>{};
|
||||
#endif
|
||||
|
||||
// The general eval function for expressions
|
||||
template <typename T, typename... Pairs>
|
||||
auto eval(T const& ex, Pairs const&... pairs) DECL_AND_RETURN(evaluator<T, Pairs...>()(ex, pairs...));
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------
|
||||
* Apply a function object to all the leaves of the expression tree
|
||||
* --------------------------------------------------------------------------------------------------- */
|
||||
|
||||
template <typename F> struct apply_on_each_leaf_impl {
|
||||
F f;
|
||||
template <typename T> std::c14::enable_if_t<is_clef_expression<T>::value> operator()(T const& ex) {
|
||||
tuple::for_each(ex.childs, *this);
|
||||
}
|
||||
template <typename T> std::c14::enable_if_t<!is_clef_expression<T>::value> operator()(T const& x) { f(x); }
|
||||
template <typename T> std::c14::enable_if_t<!is_clef_expression<T>::value> operator()(std::reference_wrapper<T> const& x) {
|
||||
f(x.get());
|
||||
}
|
||||
};
|
||||
|
||||
template <typename F, typename Expr> void apply_on_each_leaf(F&& f, Expr const& ex) {
|
||||
auto impl = apply_on_each_leaf_impl<F>{std::forward<F>(f)};
|
||||
impl(ex);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------
|
||||
* make_function : transform an expression to a function
|
||||
* --------------------------------------------------------------------------------------------------- */
|
||||
|
||||
template< typename Expr, int... Is> struct make_fun_impl {
|
||||
Expr ex; // keep a copy of the expression
|
||||
make_fun_impl(Expr const & ex_) : ex(ex_) {}
|
||||
|
||||
template<typename... Args>
|
||||
auto operator()(Args &&... args) const
|
||||
DECL_AND_RETURN( evaluator<Expr,pair<Is,Args>...>() ( ex, pair<Is,Args>{std::forward<Args>(args)}...));
|
||||
};
|
||||
|
||||
// values of the ph, excluding the Is ...
|
||||
template<ull_t x, int... Is> struct ph_filter;
|
||||
template<ull_t x, int I0, int... Is> struct ph_filter<x,I0,Is...> { static constexpr ull_t value = ph_filter<x,Is...>::value & (~ (1ull<<I0));};
|
||||
template<ull_t x> struct ph_filter<x> { static constexpr ull_t value = x; };
|
||||
|
||||
template< typename Expr, int... Is> struct ph_set<make_fun_impl<Expr,Is...> > { static constexpr ull_t value = ph_filter <ph_set<Expr>::value, Is...>::value;};
|
||||
template< typename Expr, int... Is> struct is_any_lazy<make_fun_impl<Expr,Is...> > : std::integral_constant<bool,ph_set<make_fun_impl<Expr,Is...>>::value !=0>{};
|
||||
template< typename Expr, int... Is> struct force_copy_in_expr<make_fun_impl<Expr,Is...> > : std::true_type{};
|
||||
|
||||
template< typename Expr, typename ... Phs>
|
||||
make_fun_impl<typename remove_cv_ref <Expr>::type,Phs::index...>
|
||||
make_function(Expr && ex, Phs...) { return {ex}; }
|
||||
|
||||
namespace result_of {
|
||||
template< typename Expr, typename ... Phs> struct make_function {
|
||||
using type = make_fun_impl<typename remove_cv_ref<Expr>::type, Phs::index...>;
|
||||
};
|
||||
}
|
||||
|
||||
template< typename Expr, int... Is,typename... Pairs> struct evaluator<make_fun_impl<Expr,Is...>, Pairs...> {
|
||||
using e_t = evaluator<Expr, Pairs...>;
|
||||
//using is_lazy = std::integral_constant<bool, ph_set<make_fun_impl<Expr, Is...>>::value != ph_set<Pairs...>::value>;
|
||||
static constexpr bool is_lazy = (ph_set<make_fun_impl<Expr, Is...>>::value != ph_set<Pairs...>::value);
|
||||
auto operator()(make_fun_impl<Expr,Is...> const & f, Pairs const & ... pairs) const DECL_AND_RETURN( make_function( e_t()(f.ex, pairs...),placeholder<Is>()...));
|
||||
};
|
||||
|
||||
template<int ... N> struct ph_list {};
|
||||
template<int ... N> ph_list<N...> var( placeholder<N> ...) { return {};}
|
||||
|
||||
template<typename Expr, int ... N>
|
||||
auto operator >> (ph_list<N...>, Expr const & ex) DECL_AND_RETURN( make_function(ex, placeholder<N>()...));
|
||||
|
||||
/* --------------------------------------------------------------------------------------------------
|
||||
* make_function
|
||||
* x_ >> expression is the same as make_function(expression,x)
|
||||
* --------------------------------------------------------------------------------------------------- */
|
||||
|
||||
template <int N, typename Expr>
|
||||
make_fun_impl<Expr,N > operator >> (placeholder<N> p, Expr&& ex) { return {ex}; }
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------
|
||||
* Auto assign for ()
|
||||
* --------------------------------------------------------------------------------------------------- */
|
||||
|
||||
// by default it is deleted = not implemented : every class has to define it...
|
||||
template<typename T, typename F> void triqs_clef_auto_assign (T,F) = delete;
|
||||
|
||||
// remove the ref_wrapper, terminal ...
|
||||
template<typename T, typename F> void triqs_clef_auto_assign (std::reference_wrapper<T> R ,F && f) { triqs_clef_auto_assign(R.get(),std::forward<F>(f));}
|
||||
template<typename T, typename F> void triqs_clef_auto_assign (expr<tags::terminal,T> const & t,F && f) { triqs_clef_auto_assign(std::get<0>(t.childs),std::forward<F>(f));}
|
||||
|
||||
// auto assign of an expr ? (for chain calls) : just reuse the same operator
|
||||
template<typename Tag, typename... Childs, typename RHS>
|
||||
void triqs_clef_auto_assign (expr<Tag,Childs...> && ex, RHS const & rhs) { ex << rhs;}
|
||||
|
||||
template<typename Tag, typename... Childs, typename RHS>
|
||||
void triqs_clef_auto_assign (expr<Tag,Childs...> const & ex, RHS const & rhs) { ex << rhs;}
|
||||
|
||||
// The case A(x_,y_) = RHS : we form the function (make_function) and call auto_assign (by ADL)
|
||||
template<typename F, typename RHS, int... Is>
|
||||
void operator<<(expr<tags::function, F, placeholder<Is>...> && ex, RHS && rhs) {
|
||||
triqs_clef_auto_assign(std::get<0>(ex.childs), make_function(std::forward<RHS>(rhs), placeholder<Is>()...));
|
||||
}
|
||||
template<typename F, typename RHS, int... Is>
|
||||
void operator<<(expr<tags::function, F, placeholder<Is>...> const & ex, RHS && rhs) {
|
||||
triqs_clef_auto_assign(std::get<0>(ex.childs), make_function(std::forward<RHS>(rhs), placeholder<Is>()...));
|
||||
}
|
||||
template<typename F, typename RHS, int... Is>
|
||||
void operator<<(expr<tags::function, F, placeholder<Is>...> & ex, RHS && rhs) {
|
||||
triqs_clef_auto_assign(std::get<0>(ex.childs), make_function(std::forward<RHS>(rhs), placeholder<Is>()...));
|
||||
}
|
||||
|
||||
// any other case e.g. f(x_+y_) = RHS etc .... which makes no sense : compiler will stop
|
||||
template<typename F, typename RHS, typename... T>
|
||||
void operator<<(expr<tags::function, F, T...> && ex, RHS && rhs) = delete;
|
||||
template<typename F, typename RHS, typename... T>
|
||||
void operator<<(expr<tags::function, F, T...> const & ex, RHS && rhs) = delete;
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------
|
||||
* Auto assign for []
|
||||
* --------------------------------------------------------------------------------------------------- */
|
||||
|
||||
// by default it is deleted = not implemented : every class has to define it...
|
||||
template<typename T, typename F> void triqs_clef_auto_assign_subscript (T,F) = delete;
|
||||
|
||||
// remove the ref_wrapper, terminal ...
|
||||
template<typename T, typename F> void triqs_clef_auto_assign_subscript (std::reference_wrapper<T> R ,F && f)
|
||||
{ triqs_clef_auto_assign_subscript(R.get(),std::forward<F>(f));}
|
||||
template<typename T, typename F> void triqs_clef_auto_assign_subscript (expr<tags::terminal,T> const & t,F && f)
|
||||
{ triqs_clef_auto_assign_subscript(std::get<0>(t.childs),std::forward<F>(f));}
|
||||
|
||||
// auto assign of an expr ? (for chain calls) : just reuse the same operator
|
||||
template<typename Tag, typename... Childs, typename RHS>
|
||||
void triqs_clef_auto_assign_subscript (expr<Tag,Childs...> && ex, RHS const & rhs) { ex << rhs;}
|
||||
|
||||
template<typename Tag, typename... Childs, typename RHS>
|
||||
void triqs_clef_auto_assign_subscript (expr<Tag,Childs...> const & ex, RHS const & rhs) { ex << rhs;}
|
||||
|
||||
// Same thing for the [ ]
|
||||
template<typename F, typename RHS, int... Is>
|
||||
void operator<<(expr<tags::subscript, F, placeholder<Is>...> const & ex, RHS && rhs) {
|
||||
triqs_clef_auto_assign_subscript(std::get<0>(ex.childs), make_function(std::forward<RHS>(rhs), placeholder<Is>()...));
|
||||
}
|
||||
template<typename F, typename RHS, int... Is>
|
||||
void operator<<(expr<tags::subscript, F, placeholder<Is>...> && ex, RHS && rhs) {
|
||||
triqs_clef_auto_assign_subscript(std::get<0>(ex.childs), make_function(std::forward<RHS>(rhs), placeholder<Is>()...));
|
||||
}
|
||||
|
||||
template<typename F, typename RHS, typename... T>
|
||||
void operator<<(expr<tags::subscript, F, T...> && ex, RHS && rhs) = delete;
|
||||
|
||||
template<typename F, typename RHS, typename... T>
|
||||
void operator<<(expr<tags::subscript, F, T...> const & ex, RHS && rhs) = delete;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------------
|
||||
* Create a terminal node of an object. the from clone version force copying the object
|
||||
* --------------------------------------------------------------------------------------------------- */
|
||||
|
||||
// make a node with the ref, unless it is an rvalue (which is moved).
|
||||
template<typename T> expr<tags::terminal,expr_storage_t<T> >
|
||||
make_expr(T && x){ return {tags::terminal(), std::forward<T>(x)};}
|
||||
|
||||
// make a node from a copy of the object
|
||||
template<typename T> expr<tags::terminal,typename remove_cv_ref<T>::type >
|
||||
make_expr_from_clone(T && x){ return {tags::terminal(), std::forward<T>(x)};}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------------
|
||||
* Create a call node of an object
|
||||
* The object can be kept as a : a ref, a copy, a view
|
||||
* --------------------------------------------------------------------------------------------------- */
|
||||
|
||||
template<typename T> struct arity { static constexpr int value =-1;};
|
||||
|
||||
namespace _result_of {
|
||||
template< typename Obj, typename... Args > struct make_expr_call :
|
||||
std::enable_if< is_any_lazy<Args...>::value, expr<tags::function,expr_storage_t<Obj>, expr_storage_t<Args> ...> > {
|
||||
static_assert (((arity<Obj>::value==-1) || (arity<Obj>::value == sizeof...(Args))), "Object called with a wrong number of arguments");
|
||||
};
|
||||
}
|
||||
template< typename Obj, typename... Args >
|
||||
typename _result_of::make_expr_call<Obj,Args...>::type
|
||||
make_expr_call(Obj&& obj, Args &&... args) { return {tags::function(),std::forward<Obj>(obj), std::forward<Args>(args)...};}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------------
|
||||
* Create a [] call (subscript) node of an object
|
||||
* The object can be kept as a : a ref, a copy, a view
|
||||
* --------------------------------------------------------------------------------------------------- */
|
||||
|
||||
namespace _result_of {
|
||||
template< typename Obj, typename Arg> struct make_expr_subscript :
|
||||
std::enable_if< is_any_lazy<Arg>::value, expr<tags::subscript,expr_storage_t<Obj>, expr_storage_t<Arg>> > {};
|
||||
}
|
||||
template< typename Obj, typename Arg>
|
||||
typename _result_of::make_expr_subscript<Obj,Arg>::type
|
||||
make_expr_subscript(Obj&& obj, Arg && arg) { return {tags::subscript(),std::forward<Obj>(obj), std::forward<Arg>(arg)};}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------------
|
||||
* function class : stores any expression polymorphically
|
||||
* f(x_,y_ ) = an expression associates this expression dynamically to f, which
|
||||
* can then be used as a std::function of the same signature...
|
||||
* --------------------------------------------------------------------------------------------------- */
|
||||
template<typename F> class function;
|
||||
|
||||
template<typename ReturnType, typename... T> class function<ReturnType(T...)> : tags::function_class {
|
||||
using std_function_type = std::function<ReturnType(T...)>;
|
||||
mutable std::shared_ptr <void> _exp; // CLEAN THIS MUTABLE ?
|
||||
mutable std::shared_ptr < std_function_type > _fnt_ptr;
|
||||
public:
|
||||
function():_fnt_ptr{std::make_shared<std_function_type> ()}{}
|
||||
|
||||
template <typename Expr, typename... X>
|
||||
explicit function(Expr const& _e, X... x)
|
||||
: _exp(std::make_shared<Expr>(_e)), _fnt_ptr(new std_function_type(make_function(_e, x...))) {}
|
||||
|
||||
ReturnType operator()(T const &... t) const { return (*_fnt_ptr)(t...);}
|
||||
|
||||
template< typename... Args>
|
||||
auto operator()( Args&&... args ) const DECL_AND_RETURN(make_expr_call (*this,std::forward<Args>(args)...));
|
||||
|
||||
template<typename RHS> friend void triqs_clef_auto_assign (function const & x, RHS rhs) {
|
||||
* (x._fnt_ptr) = std_function_type (rhs);
|
||||
x._exp = std::make_shared<typename std::remove_cv<decltype(rhs.ex)>::type> (rhs.ex);
|
||||
}
|
||||
|
||||
};
|
||||
template<typename F> struct force_copy_in_expr <function<F>> : std::true_type{};
|
||||
|
||||
/* --------------------------------------------------------------------------------------------------
|
||||
* The macro to make any function lazy
|
||||
* TRIQS_CLEF_MAKE_FNT_LAZY (Arity,FunctionName ) : creates a new function in the triqs::lazy namespace
|
||||
* 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 <typename... A> auto operator()(A&&... a) const DECL_AND_RETURN(name(std::forward<A>(a)...)); \
|
||||
}; \
|
||||
template <typename... A> auto name(A&&... a) DECL_AND_RETURN(make_expr_call(name##_lazy_impl(), std::forward<A>(a)...));
|
||||
|
||||
|
||||
#define TRIQS_CLEF_MAKE_FNT_LAZY_BIS(name) \
|
||||
struct name##_lazy_impl { \
|
||||
template <typename... A> auto operator()(A&&... a) const -> decltype(name(std::forward<A>(a)...)); \
|
||||
}; \
|
||||
template <typename... A> auto name(A&&... a) DECL_AND_RETURN(make_expr_call(name##_lazy_impl(), std::forward<A>(a)...)); \
|
||||
template <typename... A> auto name##_lazy_impl::operator()(A&&... a) const DECL_AND_RETURN(name(std::forward<A>(a)...));
|
||||
|
||||
#define TRIQS_CLEF_EXTEND_FNT_LAZY(FUN, TRAIT) \
|
||||
template <typename A> \
|
||||
std::c14::enable_if_t<TRAIT<A>::value, clef::expr_node_t<clef::tags::function, clef::FUN##_lazy_impl, A>> FUN(A&& a) { \
|
||||
return {clef::tags::function{}, clef::FUN##_lazy_impl{}, std::forward<A>(a)}; \
|
||||
}
|
||||
|
||||
#define TRIQS_CLEF_IMPLEMENT_LAZY_METHOD(TY, name) \
|
||||
struct __clef_lazy_method_impl_##TY##_##name { \
|
||||
template <typename X, typename... A> auto operator()(X&& x, A&&... a) const DECL_AND_RETURN(x.name(std::forward<A>(a)...)); \
|
||||
friend std::ostream& operator<<(std::ostream& out, __clef_lazy_method_impl_##TY##_##name const& x) { \
|
||||
return out << "apply_method:"<< BOOST_PP_STRINGIZE(name); \
|
||||
} \
|
||||
}; \
|
||||
template <typename... A> \
|
||||
auto name(A&&... a) DECL_AND_RETURN(make_expr_call(__clef_lazy_method_impl_##TY##_##name{}, *this, std::forward<A>(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>(args)...)); \
|
||||
\
|
||||
template <typename... Args> \
|
||||
auto operator()(Args&&... args) & DECL_AND_RETURN(make_expr_call(*this, std::forward<Args>(args)...)); \
|
||||
\
|
||||
template <typename... Args> \
|
||||
auto operator()(Args&&... args) && DECL_AND_RETURN(make_expr_call(std::move(*this), std::forward<Args>(args)...));
|
||||
|
||||
/* --------------------------------------------------------------------------------------------------
|
||||
* sum of expressions
|
||||
* --------------------------------------------------------------------------------------------------- */
|
||||
|
||||
// sum a function f on a domain D, using a simple foreach
|
||||
template <typename F, typename D>
|
||||
auto sum_f_domain_impl(F const& f, D const& d)
|
||||
-> std::c14::enable_if_t<!triqs::clef::is_any_lazy<F, D>::value, decltype(f(*(d.begin())))> {
|
||||
auto res = decltype(f(*(d.begin()))) {};
|
||||
using p_t = typename std::decay<decltype(*(d.begin()))>::type;
|
||||
foreach(d, [&res, &f](p_t const& x) { res = res + f(x); });
|
||||
return res;
|
||||
}
|
||||
|
||||
TRIQS_CLEF_MAKE_FNT_LAZY(sum_f_domain_impl);
|
||||
|
||||
// sum( expression, i = domain)
|
||||
template <typename Expr, int N, typename D> auto sum(Expr const& f, clef::pair<N, D> const& d)
|
||||
DECL_AND_RETURN(sum_f_domain_impl(make_function(f, clef::placeholder<N>()), d.rhs));
|
||||
|
||||
// two or more indices : sum recursively
|
||||
template <typename Expr, typename D0, int N0, typename D1, int N1, typename... D, int... N>
|
||||
auto sum(Expr const& f, clef::pair<N0, D0> const& d0, clef::pair<N1, D1> const& d1, clef::pair<N, D> const&... d)
|
||||
DECL_AND_RETURN(sum(sum(f, d0), d1, d...));
|
||||
|
||||
}} // namespace triqs::clef
|
||||
#endif
|
607
triqs/clef/clef.c14.hpp
Normal file
607
triqs/clef/clef.c14.hpp
Normal file
@ -0,0 +1,607 @@
|
||||
/*******************************************************************************
|
||||
*
|
||||
* TRIQS: a Toolbox for Research in Interacting Quantum Systems
|
||||
*
|
||||
* Copyright (C) 2012-2013 by O. Parcollet
|
||||
*
|
||||
* TRIQS is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU General Public License as published by the Free Software
|
||||
* Foundation, either version 3 of the License, or (at your option) any later
|
||||
* version.
|
||||
*
|
||||
* TRIQS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* TRIQS. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
******************************************************************************/
|
||||
#pragma once
|
||||
#include <triqs/utility/first_include.hpp>
|
||||
#include <triqs/utility/macros.hpp>
|
||||
#include <triqs/utility/compiler_details.hpp>
|
||||
#include <triqs/utility/tuple_tools.hpp>
|
||||
#include <triqs/utility/c14.hpp>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <complex>
|
||||
#include <boost/preprocessor/stringize.hpp>
|
||||
#include <boost/preprocessor/repetition/repeat_from_to.hpp>
|
||||
#include <boost/preprocessor/repetition/enum.hpp>
|
||||
#include <boost/preprocessor/arithmetic/inc.hpp>
|
||||
|
||||
//#define TRIQS_CLEF_MAXNARGS 8
|
||||
|
||||
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.
|
||||
// If T is a lvalue reference, pack it into a reference_wrapper, unless force_copy_in_expr<T>::value == true
|
||||
// If T is an rvalue reference, we store it as the type (using move semantics).
|
||||
template<typename T> struct force_copy_in_expr : std::false_type{};
|
||||
template<typename T> struct force_copy_in_expr<T const> : force_copy_in_expr<T>{};
|
||||
|
||||
template< class T> struct expr_storage_impl {using type=T;};
|
||||
template< class T> struct expr_storage_impl<T&> : std::conditional<force_copy_in_expr<T>::value, typename std::remove_const<T>::type ,std::reference_wrapper<T>>{};
|
||||
template< class T> struct expr_storage_impl<T&&> {using type=T;};
|
||||
template< class T> struct expr_storage_impl<const T&&> {using type=T;};
|
||||
template< class T> struct expr_storage_impl<const T> {using type=T;};
|
||||
|
||||
template <class T> using expr_storage_t = typename expr_storage_impl<T>::type; // helper type
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------
|
||||
* Placeholder and corresponding traits
|
||||
* --------------------------------------------------------------------------------------------------- */
|
||||
template<int i, typename T> struct pair; // forward
|
||||
|
||||
// a placeholder is an empty struct, labelled by an int.
|
||||
template<int N> struct placeholder {
|
||||
static_assert( (N>=0) && (N<64) , "Placeholder number limited to [0,63]");
|
||||
static constexpr int index = N;
|
||||
template <typename RHS> pair<N,RHS> operator = (RHS && rhs) { return {std::forward<RHS>(rhs)};}
|
||||
};
|
||||
|
||||
// placeholder will always be copied (they are empty anyway).
|
||||
template <int N> struct force_copy_in_expr<placeholder<N>> : std::true_type {};
|
||||
|
||||
// represent a couple (placeholder, value).
|
||||
template <int N, typename U> struct pair {
|
||||
U rhs;
|
||||
static constexpr int p = N;
|
||||
using value_type = typename remove_cv_ref<U>::type;
|
||||
};
|
||||
|
||||
// ph_set is a trait that given a pack of type, returns the set of placeholders they contain
|
||||
// it returns a int in binary coding : bit N in the int is 1 iif at least one T is lazy and contains placeholder<N>
|
||||
template<typename... T> struct ph_set;
|
||||
template<typename T0, typename... T> struct ph_set<T0,T...>{static constexpr ull_t value= ph_set<T0>::value| ph_set<T...>::value;};
|
||||
template<typename T> struct ph_set<T> {static constexpr ull_t value= 0;};
|
||||
template<int N> struct ph_set<placeholder<N>> {static constexpr ull_t value= 1ull<<N;};
|
||||
template<int i, typename T> struct ph_set<pair<i,T> > : ph_set<placeholder<i>>{};
|
||||
|
||||
// in_any_lazy : trait to detect if any of Args is a lazy expression
|
||||
template<typename... Args> struct is_any_lazy : std::false_type {};
|
||||
template<int N> struct is_any_lazy <placeholder <N> > : std::true_type {};
|
||||
template <typename T> struct is_any_lazy< T > : std::false_type {};
|
||||
template <typename T> struct is_any_lazy< T&& > : is_any_lazy<T> {};
|
||||
template <typename T> struct is_any_lazy< T& > : is_any_lazy<T> {};
|
||||
template <typename T> struct is_any_lazy< T const > : is_any_lazy<T> {};
|
||||
template<typename T, typename... Args> struct is_any_lazy<T, Args...> :
|
||||
std::integral_constant<bool, is_any_lazy<T>::value || is_any_lazy<Args...>::value> {};
|
||||
|
||||
template<typename T>
|
||||
constexpr bool ClefExpression() { return is_any_lazy<T>::value;}
|
||||
|
||||
template<typename T> struct is_clef_expression : is_any_lazy<T>{};
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------
|
||||
* Node of the expression tree
|
||||
* --------------------------------------------------------------------------------------------------- */
|
||||
template<typename Tag, typename... T> struct expr {
|
||||
// T can be U, U & (a reference or a value).
|
||||
using childs_t = std::tuple<T...>;
|
||||
childs_t childs;
|
||||
expr(expr const & x) = default;
|
||||
expr(expr && x) noexcept : childs(std::move(x.childs)) {}
|
||||
// a constructor with the Tag make it unambiguous with other constructors...
|
||||
template<typename... Args> expr(Tag, Args&&...args) : childs(std::forward<Args>(args)...) {}
|
||||
// [] returns a new lazy expression, with one more layer
|
||||
template<typename Args>
|
||||
expr<tags::subscript, expr, expr_storage_t<Args> > operator[](Args && args) const
|
||||
{ return {tags::subscript(), *this,std::forward<Args>(args)};}
|
||||
// () also ...
|
||||
template< typename... Args >
|
||||
expr<tags::function, expr, expr_storage_t<Args>...> operator()(Args && ... args) const
|
||||
{ return {tags::function(), *this,std::forward<Args>(args)...};}
|
||||
// assignement is in general deleted
|
||||
expr & operator= (expr const &) = delete; // no ordinary assignment
|
||||
expr & operator= (expr &&) = default; // move assign ok
|
||||
// however, this is ok in the case f(i,j) = expr, where f is a clef::function
|
||||
template<typename RHS, typename CH = childs_t>
|
||||
ENABLE_IF(std::is_base_of<tags::function_class, typename std::tuple_element<0,CH>::type>)
|
||||
operator= (RHS const & rhs) { *this << rhs;}
|
||||
template<typename RHS, typename CH = childs_t>
|
||||
DISABLE_IF(std::is_base_of<tags::function_class, typename std::tuple_element<0,CH>::type>)
|
||||
operator= (RHS const & rhs) = delete;
|
||||
};
|
||||
// set some traits
|
||||
template<typename Tag, typename... T> struct ph_set< expr<Tag,T... > > : ph_set<T...> {};
|
||||
template<typename Tag, typename... T> struct is_any_lazy< expr<Tag,T... > >: std::true_type {};
|
||||
// if we want that subexpression are copied ?
|
||||
template<typename Tag, typename... T> struct force_copy_in_expr< expr<Tag,T... > > : std::true_type{};
|
||||
|
||||
template <typename Tag, typename... T> using expr_node_t = expr<Tag, expr_storage_t<T>...>;
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------
|
||||
* The basic operations put in a template....
|
||||
* --------------------------------------------------------------------------------------------------- */
|
||||
template<typename Tag> struct operation;
|
||||
|
||||
// a little function to clean the reference_wrapper
|
||||
template<typename U> U _cl(U && x) { return std::forward<U>(x);}
|
||||
template<typename U> decltype(auto) _cl(std::reference_wrapper<U> x) { return x.get();}
|
||||
|
||||
/// Terminal
|
||||
template<> struct operation<tags::terminal> { template<typename L> L operator()(L&& l) const { return std::forward<L>(l);} };
|
||||
|
||||
/// Function call
|
||||
template<> struct operation<tags::function> {
|
||||
template <typename F, typename... Args>
|
||||
decltype(auto) operator()(F&& f, Args&&... args) const { return _cl(std::forward<F>(f))(_cl(std::forward<Args>(args))...);}
|
||||
};
|
||||
|
||||
/// [ ] Call
|
||||
template<> struct operation<tags::subscript> {
|
||||
template <typename F, typename Args>
|
||||
decltype(auto) operator()(F&& f, Args&& args) const { return _cl(std::forward<F>(f))[_cl(std::forward<Args>(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 <typename L, typename R> \
|
||||
std14::enable_if_t<is_any_lazy<L, R>::value, expr<tags::TAG, expr_storage_t<L>, expr_storage_t<R>>> operator OP(L&& l, R&& r) { \
|
||||
return {tags::TAG(), std::forward<L>(l), std::forward<R>(r)}; \
|
||||
} \
|
||||
template <> struct operation<tags::TAG> { \
|
||||
template <typename L, typename R> decltype(auto) operator()(L&& l, R&& r) const { \
|
||||
return _cl(std::forward<L>(l)) OP _cl(std::forward<R>(r)); \
|
||||
} \
|
||||
};
|
||||
|
||||
TRIQS_CLEF_OPERATION(plus, +);
|
||||
TRIQS_CLEF_OPERATION(minus, -);
|
||||
TRIQS_CLEF_OPERATION(multiplies, *);
|
||||
TRIQS_CLEF_OPERATION(divides, /);
|
||||
TRIQS_CLEF_OPERATION(greater, >);
|
||||
TRIQS_CLEF_OPERATION(less, <);
|
||||
TRIQS_CLEF_OPERATION(leq, <=);
|
||||
TRIQS_CLEF_OPERATION(geq, >=);
|
||||
TRIQS_CLEF_OPERATION(eq, ==);
|
||||
#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 <typename L> std14::enable_if_t<is_any_lazy<L>::value, expr<tags::TAG, expr_storage_t<L>>> operator OP(L&& l) { \
|
||||
return {tags::TAG(), std::forward<L>(l)}; \
|
||||
} \
|
||||
template <> struct operation<tags::TAG> { \
|
||||
template <typename L> decltype(auto) operator()(L&& l) const { return OP _cl(std::forward<L>(l)); } \
|
||||
};
|
||||
|
||||
TRIQS_CLEF_OPERATION(negate, -);
|
||||
TRIQS_CLEF_OPERATION(loginot, !);
|
||||
#undef TRIQS_CLEF_OPERATION
|
||||
|
||||
/// the only ternary node : expression if
|
||||
template<> struct operation<tags::if_else> {
|
||||
// A and B MUST be the same
|
||||
template<typename C, typename A, typename B> A operator()(C const & c, A const & a, B const & b) const {return _cl(c) ? _cl(a): _cl(b);}
|
||||
//template<typename C, typename A, typename B> auto operator()(C const & c, A const & a, B const & b) const DECL_AND_RETURN (_cl(c) ? _cl(a): _cl(b));
|
||||
};
|
||||
// operator is : if_else( Condition, A, B)
|
||||
template<typename C, typename A, typename B>
|
||||
expr<tags::if_else,expr_storage_t<C>,expr_storage_t<A>,expr_storage_t<B>>
|
||||
if_else(C && c, A && a, B && b) { return {tags::if_else(),std::forward<C>(c),std::forward<A>(a),std::forward<B>(b)};}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------
|
||||
* Evaluation of the expression tree.
|
||||
* --------------------------------------------------------------------------------------------------- */
|
||||
|
||||
constexpr bool __or() { return false;}
|
||||
template <typename... B> constexpr bool __or(bool b, B... bs) { return b || __or(bs...); }
|
||||
|
||||
// Generic case : do nothing (for the leaf of the tree including placeholder)
|
||||
template <typename T, typename... Pairs> struct evaluator {
|
||||
static constexpr bool is_lazy = is_any_lazy<T>::value;
|
||||
T const & operator()(T const& k, Pairs const&... pairs) const { return k; }
|
||||
};
|
||||
|
||||
// The general eval function for expressions : declaration only
|
||||
template <typename T, typename... Pairs> decltype(auto) eval(T const& ex, Pairs const&... pairs);
|
||||
|
||||
// placeholder
|
||||
template <int N, int i, typename T, typename... Pairs> struct evaluator<placeholder<N>, pair<i, T>, Pairs...> {
|
||||
using eval_t = evaluator<placeholder<N>, Pairs...>;
|
||||
static constexpr bool is_lazy = eval_t::is_lazy;
|
||||
decltype(auto) operator()(placeholder<N>, pair<i, T> const&, Pairs const&... pairs) const { return eval_t()(placeholder<N>(), pairs...);}
|
||||
};
|
||||
|
||||
template <int N, typename T, typename... Pairs> struct evaluator<placeholder<N>, pair<N, T>, Pairs...> {
|
||||
static constexpr bool is_lazy = false;
|
||||
T operator()(placeholder<N>, pair<N, T> const& p, Pairs const&...) const { return p.rhs; }
|
||||
};
|
||||
|
||||
// any object hold by reference wrapper is redirected to the evaluator of the object
|
||||
template <typename T, typename... Contexts> struct evaluator<std::reference_wrapper<T>, Contexts...> {
|
||||
static constexpr bool is_lazy = false;
|
||||
decltype(auto) operator()(std::reference_wrapper<T> const& x, Contexts const&... contexts) const { return eval(x.get(), contexts...);}
|
||||
};
|
||||
|
||||
// dispatching the evaluation : if lazy, we make a new clef expression, if not we call the operation
|
||||
template <typename Tag, bool IsLazy> struct op_dispatch;
|
||||
|
||||
template <typename Tag> struct op_dispatch<Tag, true> {
|
||||
template <typename... Args> expr<Tag, expr_storage_t<Args>...> operator()(Args&&... args) const {
|
||||
return {Tag(), std::forward<Args>(args)...};
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Tag> struct op_dispatch<Tag, false> {
|
||||
template <typename... Args> decltype(auto) operator()(Args&&... args) const {
|
||||
return operation<Tag>()(std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
// apply_compose not ready
|
||||
#ifdef TRIQS_USE_C14_DRAFT__
|
||||
// general expr node
|
||||
template <typename Tag, typename... Childs, typename... Pairs> struct evaluator<expr<Tag, Childs...>, Pairs...> {
|
||||
|
||||
static constexpr bool is_lazy = __or(evaluator<Childs, Pairs...>::is_lazy...);
|
||||
|
||||
decltype(auto) operator()(expr<Tag, Childs...> const& ex, Pairs const&... pairs) const {
|
||||
auto eval_in_context = [&pairs...](auto const& _child) { return eval(_child, pairs...); };
|
||||
return tuple::apply_compose(op_dispatch<Tag, is_lazy>{}, eval_in_context, ex.childs);
|
||||
}
|
||||
};
|
||||
#else
|
||||
// WORKAROUND FOR C++11 compilers
|
||||
template<int arity, typename Expr, typename... Pairs> struct evaluator_node_gal;
|
||||
|
||||
template <typename Tag, typename... Childs, typename... Pairs> struct evaluator_node_gal<1, expr<Tag, Childs...>, Pairs...> {
|
||||
static constexpr bool is_lazy = __or(evaluator<Childs, Pairs...>::is_lazy...);
|
||||
auto operator()(expr<Tag, Childs...> const& ex, Pairs const&... pairs) const
|
||||
DECL_AND_RETURN(op_dispatch<Tag, is_lazy> {}(eval(std::get<0>(ex.childs), pairs...)));
|
||||
};
|
||||
|
||||
template <typename Tag, typename... Childs, typename... Pairs> struct evaluator_node_gal<2, expr<Tag, Childs...>, Pairs...> {
|
||||
static constexpr bool is_lazy = __or(evaluator<Childs, Pairs...>::is_lazy...);
|
||||
auto operator()(expr<Tag, Childs...> const& ex, Pairs const&... pairs) const
|
||||
DECL_AND_RETURN(op_dispatch<Tag, is_lazy> {}(eval(std::get<0>(ex.childs), pairs...), eval(std::get<1>(ex.childs), pairs...)));
|
||||
};
|
||||
|
||||
#define TRIQS_CLEF_MAXNARGS 8
|
||||
|
||||
// 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<p>(ex.childs), pairs...)
|
||||
#define IMPL(z, NN, unused) \
|
||||
template <typename Tag, typename... Childs, typename... Pairs> struct evaluator_node_gal<NN, expr<Tag, Childs...>, Pairs...> { \
|
||||
static constexpr bool is_lazy = __or(evaluator<Childs, Pairs...>::is_lazy...); \
|
||||
auto operator()(expr<Tag, Childs...> const& ex, Pairs const&... pairs) const \
|
||||
DECL_AND_RETURN(op_dispatch<Tag, is_lazy> {}(BOOST_PP_ENUM(NN, AUX, nil))); \
|
||||
};
|
||||
BOOST_PP_REPEAT_FROM_TO(3,BOOST_PP_INC(TRIQS_CLEF_MAXNARGS), IMPL, nil);
|
||||
#undef AUX
|
||||
#undef IMPL
|
||||
|
||||
template<typename Tag, typename... Childs, typename... Pairs>
|
||||
struct evaluator<expr<Tag, Childs...>, Pairs...> : evaluator_node_gal<sizeof...(Childs), expr<Tag, Childs...>, Pairs...>{};
|
||||
#endif
|
||||
|
||||
// The general eval function for expressions
|
||||
template <typename T, typename... Pairs>
|
||||
decltype(auto) eval(T const& ex, Pairs const&... pairs) { return evaluator<T, Pairs...>()(ex, pairs...);}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------
|
||||
* Apply a function object to all the leaves of the expression tree
|
||||
* --------------------------------------------------------------------------------------------------- */
|
||||
|
||||
template <typename F> struct apply_on_each_leaf_impl {
|
||||
F f;
|
||||
template <typename T> std::c14::enable_if_t<is_clef_expression<T>::value> operator()(T const& ex) {
|
||||
tuple::for_each(ex.childs, *this);
|
||||
}
|
||||
template <typename T> std::c14::enable_if_t<!is_clef_expression<T>::value> operator()(T const& x) { f(x); }
|
||||
template <typename T> std::c14::enable_if_t<!is_clef_expression<T>::value> operator()(std::reference_wrapper<T> const& x) {
|
||||
f(x.get());
|
||||
}
|
||||
};
|
||||
|
||||
template <typename F, typename Expr> void apply_on_each_leaf(F&& f, Expr const& ex) {
|
||||
auto impl = apply_on_each_leaf_impl<F>{std::forward<F>(f)};
|
||||
impl(ex);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------
|
||||
* make_function : transform an expression to a function
|
||||
* --------------------------------------------------------------------------------------------------- */
|
||||
|
||||
template< typename Expr, int... Is> struct make_fun_impl {
|
||||
Expr ex; // keep a copy of the expression
|
||||
make_fun_impl(Expr const & ex_) : ex(ex_) {}
|
||||
|
||||
template<typename... Args>
|
||||
decltype(auto) operator()(Args &&... args) const { return evaluator<Expr,pair<Is,Args>...>() ( ex, pair<Is,Args>{std::forward<Args>(args)}...);}
|
||||
};
|
||||
|
||||
// values of the ph, excluding the Is ...
|
||||
template<ull_t x, int... Is> struct ph_filter;
|
||||
template<ull_t x, int I0, int... Is> struct ph_filter<x,I0,Is...> { static constexpr ull_t value = ph_filter<x,Is...>::value & (~ (1ull<<I0));};
|
||||
template<ull_t x> struct ph_filter<x> { static constexpr ull_t value = x; };
|
||||
|
||||
template< typename Expr, int... Is> struct ph_set<make_fun_impl<Expr,Is...> > { static constexpr ull_t value = ph_filter <ph_set<Expr>::value, Is...>::value;};
|
||||
template< typename Expr, int... Is> struct is_any_lazy<make_fun_impl<Expr,Is...> > : std::integral_constant<bool,ph_set<make_fun_impl<Expr,Is...>>::value !=0>{};
|
||||
template< typename Expr, int... Is> struct force_copy_in_expr<make_fun_impl<Expr,Is...> > : std::true_type{};
|
||||
|
||||
template< typename Expr, typename ... Phs>
|
||||
make_fun_impl<typename remove_cv_ref <Expr>::type,Phs::index...>
|
||||
make_function(Expr && ex, Phs...) { return {ex}; }
|
||||
|
||||
namespace result_of {
|
||||
template< typename Expr, typename ... Phs> struct make_function {
|
||||
using type = make_fun_impl<typename remove_cv_ref<Expr>::type, Phs::index...>;
|
||||
};
|
||||
}
|
||||
|
||||
template< typename Expr, int... Is,typename... Pairs> struct evaluator<make_fun_impl<Expr,Is...>, Pairs...> {
|
||||
using e_t = evaluator<Expr, Pairs...>;
|
||||
//using is_lazy = std::integral_constant<bool, ph_set<make_fun_impl<Expr, Is...>>::value != ph_set<Pairs...>::value>;
|
||||
static constexpr bool is_lazy = (ph_set<make_fun_impl<Expr, Is...>>::value != ph_set<Pairs...>::value);
|
||||
decltype(auto) operator()(make_fun_impl<Expr,Is...> const & f, Pairs const & ... pairs) const { return make_function( e_t()(f.ex, pairs...),placeholder<Is>()...);}
|
||||
};
|
||||
|
||||
template<int ... N> struct ph_list {};
|
||||
template<int ... N> ph_list<N...> var( placeholder<N> ...) { return {};}
|
||||
|
||||
template<typename Expr, int ... N>
|
||||
decltype(auto) operator >> (ph_list<N...>, Expr const & ex) { return make_function(ex, placeholder<N>()...);}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------------
|
||||
* make_function
|
||||
* x_ >> expression is the same as make_function(expression,x)
|
||||
* --------------------------------------------------------------------------------------------------- */
|
||||
|
||||
template <int N, typename Expr>
|
||||
make_fun_impl<Expr,N > operator >> (placeholder<N> p, Expr&& ex) { return {ex}; }
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------
|
||||
* Auto assign for ()
|
||||
* --------------------------------------------------------------------------------------------------- */
|
||||
|
||||
// by default it is deleted = not implemented : every class has to define it...
|
||||
template<typename T, typename F> void triqs_clef_auto_assign (T,F) = delete;
|
||||
|
||||
// remove the ref_wrapper, terminal ...
|
||||
template <typename T, typename F> void triqs_clef_auto_assign(std::reference_wrapper<T> R, F&& f) {
|
||||
triqs_clef_auto_assign(R.get(), std::forward<F>(f));
|
||||
}
|
||||
template <typename T, typename F> void triqs_clef_auto_assign(expr<tags::terminal, T> const& t, F&& f) {
|
||||
triqs_clef_auto_assign(std::get<0>(t.childs), std::forward<F>(f));
|
||||
}
|
||||
|
||||
// auto assign of an expr ? (for chain calls) : just reuse the same operator
|
||||
template <typename Tag, typename... Childs, typename RHS>
|
||||
void triqs_clef_auto_assign(expr<Tag, Childs...>&& ex, RHS const& rhs) {
|
||||
ex << rhs;
|
||||
}
|
||||
|
||||
template <typename Tag, typename... Childs, typename RHS>
|
||||
void triqs_clef_auto_assign(expr<Tag, Childs...> const& ex, RHS const& rhs) {
|
||||
ex << rhs;
|
||||
}
|
||||
|
||||
// The case A(x_,y_) = RHS : we form the function (make_function) and call auto_assign (by ADL)
|
||||
template <typename F, typename RHS, int... Is> void operator<<(expr<tags::function, F, placeholder<Is>...>&& ex, RHS&& rhs) {
|
||||
triqs_clef_auto_assign(std::get<0>(ex.childs), make_function(std::forward<RHS>(rhs), placeholder<Is>()...));
|
||||
}
|
||||
template <typename F, typename RHS, int... Is>
|
||||
void operator<<(expr<tags::function, F, placeholder<Is>...> const& ex, RHS&& rhs) {
|
||||
triqs_clef_auto_assign(std::get<0>(ex.childs), make_function(std::forward<RHS>(rhs), placeholder<Is>()...));
|
||||
}
|
||||
template <typename F, typename RHS, int... Is> void operator<<(expr<tags::function, F, placeholder<Is>...>& ex, RHS&& rhs) {
|
||||
triqs_clef_auto_assign(std::get<0>(ex.childs), make_function(std::forward<RHS>(rhs), placeholder<Is>()...));
|
||||
}
|
||||
|
||||
// any other case e.g. f(x_+y_) = RHS etc .... which makes no sense : compiler will stop
|
||||
template <typename F, typename RHS, typename... T> void operator<<(expr<tags::function, F, T...>&& ex, RHS&& rhs) = delete;
|
||||
template <typename F, typename RHS, typename... T> void operator<<(expr<tags::function, F, T...>& ex, RHS&& rhs) = delete;
|
||||
template <typename F, typename RHS, typename... T> void operator<<(expr<tags::function, F, T...> const& ex, RHS&& rhs) = delete;
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------
|
||||
* Auto assign for []
|
||||
* --------------------------------------------------------------------------------------------------- */
|
||||
|
||||
// by default it is deleted = not implemented : every class has to define it...
|
||||
template<typename T, typename F> void triqs_clef_auto_assign_subscript (T,F) = delete;
|
||||
|
||||
// remove the ref_wrapper, terminal ...
|
||||
template<typename T, typename F> void triqs_clef_auto_assign_subscript (std::reference_wrapper<T> R ,F && f)
|
||||
{ triqs_clef_auto_assign_subscript(R.get(),std::forward<F>(f));}
|
||||
template<typename T, typename F> void triqs_clef_auto_assign_subscript (expr<tags::terminal,T> const & t,F && f)
|
||||
{ triqs_clef_auto_assign_subscript(std::get<0>(t.childs),std::forward<F>(f));}
|
||||
|
||||
// auto assign of an expr ? (for chain calls) : just reuse the same operator
|
||||
template<typename Tag, typename... Childs, typename RHS>
|
||||
void triqs_clef_auto_assign_subscript (expr<Tag,Childs...> && ex, RHS const & rhs) { ex << rhs;}
|
||||
|
||||
template<typename Tag, typename... Childs, typename RHS>
|
||||
void triqs_clef_auto_assign_subscript (expr<Tag,Childs...> const & ex, RHS const & rhs) { ex << rhs;}
|
||||
|
||||
// Same thing for the [ ]
|
||||
template<typename F, typename RHS, int... Is>
|
||||
void operator<<(expr<tags::subscript, F, placeholder<Is>...> const & ex, RHS && rhs) {
|
||||
triqs_clef_auto_assign_subscript(std::get<0>(ex.childs), make_function(std::forward<RHS>(rhs), placeholder<Is>()...));
|
||||
}
|
||||
template<typename F, typename RHS, int... Is>
|
||||
void operator<<(expr<tags::subscript, F, placeholder<Is>...> && ex, RHS && rhs) {
|
||||
triqs_clef_auto_assign_subscript(std::get<0>(ex.childs), make_function(std::forward<RHS>(rhs), placeholder<Is>()...));
|
||||
}
|
||||
|
||||
template <typename F, typename RHS, typename... T> void operator<<(expr<tags::subscript, F, T...>&& ex, RHS&& rhs) = delete;
|
||||
template <typename F, typename RHS, typename... T> void operator<<(expr<tags::subscript, F, T...>& ex, RHS&& rhs) = delete;
|
||||
template <typename F, typename RHS, typename... T> void operator<<(expr<tags::subscript, F, T...> const& ex, RHS&& rhs) = delete;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------------
|
||||
* Create a terminal node of an object. the from clone version force copying the object
|
||||
* --------------------------------------------------------------------------------------------------- */
|
||||
|
||||
// make a node with the ref, unless it is an rvalue (which is moved).
|
||||
template<typename T> expr<tags::terminal,expr_storage_t<T> >
|
||||
make_expr(T && x){ return {tags::terminal(), std::forward<T>(x)};}
|
||||
|
||||
// make a node from a copy of the object
|
||||
template<typename T> expr<tags::terminal,typename remove_cv_ref<T>::type >
|
||||
make_expr_from_clone(T && x){ return {tags::terminal(), std::forward<T>(x)};}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------------
|
||||
* Create a call node of an object
|
||||
* The object can be kept as a : a ref, a copy, a view
|
||||
* --------------------------------------------------------------------------------------------------- */
|
||||
|
||||
template<typename T> struct arity { static constexpr int value =-1;};
|
||||
|
||||
namespace _result_of {
|
||||
template< typename Obj, typename... Args > struct make_expr_call :
|
||||
std::enable_if< is_any_lazy<Args...>::value, expr<tags::function,expr_storage_t<Obj>, expr_storage_t<Args> ...> > {
|
||||
static_assert (((arity<Obj>::value==-1) || (arity<Obj>::value == sizeof...(Args))), "Object called with a wrong number of arguments");
|
||||
};
|
||||
}
|
||||
template< typename Obj, typename... Args >
|
||||
typename _result_of::make_expr_call<Obj,Args...>::type
|
||||
make_expr_call(Obj&& obj, Args &&... args) { return {tags::function(),std::forward<Obj>(obj), std::forward<Args>(args)...};}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------------
|
||||
* Create a [] call (subscript) node of an object
|
||||
* The object can be kept as a : a ref, a copy, a view
|
||||
* --------------------------------------------------------------------------------------------------- */
|
||||
|
||||
namespace _result_of {
|
||||
template< typename Obj, typename Arg> struct make_expr_subscript :
|
||||
std::enable_if< is_any_lazy<Arg>::value, expr<tags::subscript,expr_storage_t<Obj>, expr_storage_t<Arg>> > {};
|
||||
}
|
||||
template< typename Obj, typename Arg>
|
||||
typename _result_of::make_expr_subscript<Obj,Arg>::type
|
||||
make_expr_subscript(Obj&& obj, Arg && arg) { return {tags::subscript(),std::forward<Obj>(obj), std::forward<Arg>(arg)};}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------------
|
||||
* function class : stores any expression polymorphically
|
||||
* f(x_,y_ ) = an expression associates this expression dynamically to f, which
|
||||
* can then be used as a std::function of the same signature...
|
||||
* --------------------------------------------------------------------------------------------------- */
|
||||
template<typename F> class function;
|
||||
|
||||
template<typename ReturnType, typename... T> class function<ReturnType(T...)> : tags::function_class {
|
||||
using std_function_type = std::function<ReturnType(T...)>;
|
||||
mutable std::shared_ptr <void> _exp; // CLEAN THIS MUTABLE ?
|
||||
mutable std::shared_ptr < std_function_type > _fnt_ptr;
|
||||
public:
|
||||
function():_fnt_ptr{std::make_shared<std_function_type> ()}{}
|
||||
|
||||
template <typename Expr, typename... X>
|
||||
explicit function(Expr const& _e, X... x)
|
||||
: _exp(std::make_shared<Expr>(_e)), _fnt_ptr(new std_function_type(make_function(_e, x...))) {}
|
||||
|
||||
ReturnType operator()(T const &... t) const { return (*_fnt_ptr)(t...);}
|
||||
|
||||
template< typename... Args>
|
||||
auto operator()( Args&&... args ) const DECL_AND_RETURN(make_expr_call (*this,std::forward<Args>(args)...));
|
||||
|
||||
template<typename RHS> friend void triqs_clef_auto_assign (function const & x, RHS rhs) {
|
||||
* (x._fnt_ptr) = std_function_type (rhs);
|
||||
x._exp = std::make_shared<typename std::remove_cv<decltype(rhs.ex)>::type> (rhs.ex);
|
||||
}
|
||||
|
||||
};
|
||||
template<typename F> struct force_copy_in_expr <function<F>> : std::true_type{};
|
||||
|
||||
/* --------------------------------------------------------------------------------------------------
|
||||
* The macro to make any function lazy
|
||||
* TRIQS_CLEF_MAKE_FNT_LAZY (Arity,FunctionName ) : creates a new function in the triqs::lazy namespace
|
||||
* 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 <typename... A> decltype(auto) operator()(A&&... a) const { return name(std::forward<A>(a)...);} \
|
||||
}; \
|
||||
template <typename... A> auto name(A&&... a) DECL_AND_RETURN(make_expr_call(name##_lazy_impl(), std::forward<A>(a)...));
|
||||
|
||||
#define TRIQS_CLEF_EXTEND_FNT_LAZY(FUN, TRAIT) \
|
||||
template <typename A> \
|
||||
std::c14::enable_if_t<TRAIT<A>::value, clef::expr_node_t<clef::tags::function, clef::FUN##_lazy_impl, A>> FUN(A&& a) { \
|
||||
return {clef::tags::function{}, clef::FUN##_lazy_impl{}, std::forward<A>(a)}; \
|
||||
}
|
||||
|
||||
#define TRIQS_CLEF_IMPLEMENT_LAZY_METHOD(TY, name) \
|
||||
struct __clef_lazy_method_impl_##TY##_##name { \
|
||||
template <typename X, typename... A> decltype(auto) operator()(X&& x, A&&... a) const { return x.name(std::forward<A>(a)...);} \
|
||||
friend std::ostream& operator<<(std::ostream& out, __clef_lazy_method_impl_##TY##_##name const& x) { \
|
||||
return out << "apply_method:"<< BOOST_PP_STRINGIZE(name); \
|
||||
} \
|
||||
}; \
|
||||
template <typename... A> \
|
||||
auto name(A&&... a) DECL_AND_RETURN(make_expr_call(__clef_lazy_method_impl_##TY##_##name{}, *this, std::forward<A>(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>(args)...)); \
|
||||
\
|
||||
template <typename... Args> \
|
||||
auto operator()(Args&&... args) & DECL_AND_RETURN(make_expr_call(*this, std::forward<Args>(args)...)); \
|
||||
\
|
||||
template <typename... Args> \
|
||||
auto operator()(Args&&... args) && DECL_AND_RETURN(make_expr_call(std::move(*this), std::forward<Args>(args)...));
|
||||
|
||||
/* --------------------------------------------------------------------------------------------------
|
||||
* sum of expressions
|
||||
* --------------------------------------------------------------------------------------------------- */
|
||||
|
||||
// sum a function f on a domain D, using a simple foreach
|
||||
template <typename F, typename D>
|
||||
auto sum_f_domain_impl(F const& f, D const& d)
|
||||
-> std::c14::enable_if_t<!triqs::clef::is_any_lazy<F, D>::value, decltype(f(*(d.begin())))> {
|
||||
auto res = decltype(f(*(d.begin()))) {};
|
||||
using p_t = typename std::decay<decltype(*(d.begin()))>::type;
|
||||
foreach(d, [&res, &f](p_t const& x) { res = res + f(x); });
|
||||
return res;
|
||||
}
|
||||
|
||||
TRIQS_CLEF_MAKE_FNT_LAZY(sum_f_domain_impl);
|
||||
|
||||
// sum( expression, i = domain)
|
||||
template <typename Expr, int N, typename D> decltype(auto) sum(Expr const& f, clef::pair<N, D> const& d) {
|
||||
return sum_f_domain_impl(make_function(f, clef::placeholder<N>()), d.rhs);
|
||||
}
|
||||
|
||||
// two or more indices : sum recursively
|
||||
template <typename Expr, typename D0, int N0, typename D1, int N1, typename... D, int... N>
|
||||
auto sum(Expr const& f, clef::pair<N0, D0> const& d0, clef::pair<N1, D1> const& d1, clef::pair<N, D> const&... d) {
|
||||
return sum(sum(f, d0), d1, d...);
|
||||
}
|
||||
}} // namespace triqs::clef
|
@ -18,597 +18,12 @@
|
||||
* TRIQS. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
******************************************************************************/
|
||||
#ifndef TRIQS_CLEF_CORE_H
|
||||
#define TRIQS_CLEF_CORE_H
|
||||
#include <triqs/utility/first_include.hpp>
|
||||
#include <triqs/utility/macros.hpp>
|
||||
#include <triqs/utility/compiler_details.hpp>
|
||||
#include <triqs/utility/tuple_tools.hpp>
|
||||
#include <triqs/utility/c14.hpp>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <complex>
|
||||
#include <boost/preprocessor/stringize.hpp>
|
||||
#include <boost/preprocessor/repetition/repeat_from_to.hpp>
|
||||
#include <boost/preprocessor/repetition/enum.hpp>
|
||||
#include <boost/preprocessor/arithmetic/inc.hpp>
|
||||
|
||||
#define TRIQS_CLEF_MAXNARGS 8
|
||||
|
||||
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.
|
||||
// If T is a lvalue reference, pack it into a reference_wrapper, unless force_copy_in_expr<T>::value == true
|
||||
// If T is an rvalue reference, we store it as the type (using move semantics).
|
||||
template<typename T> struct force_copy_in_expr : std::false_type{};
|
||||
template<typename T> struct force_copy_in_expr<T const> : force_copy_in_expr<T>{};
|
||||
|
||||
template< class T > struct expr_storage_impl {typedef T type;};
|
||||
template< class T > struct expr_storage_impl<T&> : std::conditional<force_copy_in_expr<T>::value, typename std::remove_const<T>::type ,std::reference_wrapper<T>>{};
|
||||
template< class T > struct expr_storage_impl<T&&> {typedef T type;};
|
||||
template< class T > struct expr_storage_impl<const T&&> {typedef T type;};
|
||||
template< class T > struct expr_storage_impl<const T> {typedef T type;};
|
||||
|
||||
template <class T> using expr_storage_t = typename expr_storage_impl<T>::type; // helper type
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------
|
||||
* Placeholder and corresponding traits
|
||||
* --------------------------------------------------------------------------------------------------- */
|
||||
template<int i, typename T> struct pair; // forward
|
||||
|
||||
// a placeholder is an empty struct, labelled by an int.
|
||||
template<int N> struct placeholder {
|
||||
static_assert( (N>=0) && (N<64) , "Placeholder number limited to [0,63]");
|
||||
static constexpr int index = N;
|
||||
template <typename RHS> pair<N,RHS> operator = (RHS && rhs) { return {std::forward<RHS>(rhs)};}
|
||||
};
|
||||
|
||||
// placeholder will always be copied (they are empty anyway).
|
||||
template <int N> struct force_copy_in_expr<placeholder<N>> : std::true_type {};
|
||||
|
||||
// represent a couple (placeholder, value).
|
||||
template <int N, typename U> struct pair {
|
||||
U rhs;
|
||||
static constexpr int p = N;
|
||||
using value_type = typename remove_cv_ref<U>::type;
|
||||
};
|
||||
|
||||
// ph_set is a trait that given a pack of type, returns the set of placeholders they contain
|
||||
// it returns a int in binary coding : bit N in the int is 1 iif at least one T is lazy and contains placeholder<N>
|
||||
template<typename... T> struct ph_set;
|
||||
template<typename T0, typename... T> struct ph_set<T0,T...>{static constexpr ull_t value= ph_set<T0>::value| ph_set<T...>::value;};
|
||||
template<typename T> struct ph_set<T> {static constexpr ull_t value= 0;};
|
||||
template<int N> struct ph_set<placeholder<N>> {static constexpr ull_t value= 1ull<<N;};
|
||||
template<int i, typename T> struct ph_set<pair<i,T> > : ph_set<placeholder<i>>{};
|
||||
|
||||
// in_any_lazy : trait to detect if any of Args is a lazy expression
|
||||
template<typename... Args> struct is_any_lazy : std::false_type {};
|
||||
template<int N> struct is_any_lazy <placeholder <N> > : std::true_type {};
|
||||
template <typename T> struct is_any_lazy< T > : std::false_type {};
|
||||
template <typename T> struct is_any_lazy< T&& > : is_any_lazy<T> {};
|
||||
template <typename T> struct is_any_lazy< T& > : is_any_lazy<T> {};
|
||||
template <typename T> struct is_any_lazy< T const > : is_any_lazy<T> {};
|
||||
template<typename T, typename... Args> struct is_any_lazy<T, Args...> :
|
||||
std::integral_constant<bool, is_any_lazy<T>::value || is_any_lazy<Args...>::value> {};
|
||||
|
||||
template<typename T>
|
||||
constexpr bool ClefExpression() { return is_any_lazy<T>::value;}
|
||||
|
||||
template<typename T> struct is_clef_expression : is_any_lazy<T>{};
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------
|
||||
* Node of the expression tree
|
||||
* --------------------------------------------------------------------------------------------------- */
|
||||
template<typename Tag, typename... T> struct expr {
|
||||
// T can be U, U & (a reference or a value).
|
||||
using childs_t = std::tuple<T...>;
|
||||
childs_t childs;
|
||||
expr(expr const & x) = default;
|
||||
expr(expr && x) noexcept : childs(std::move(x.childs)) {}
|
||||
// a constructor with the Tag make it unambiguous with other constructors...
|
||||
template<typename... Args> expr(Tag, Args&&...args) : childs(std::forward<Args>(args)...) {}
|
||||
// [] returns a new lazy expression, with one more layer
|
||||
template<typename Args>
|
||||
expr<tags::subscript, expr, expr_storage_t<Args> > operator[](Args && args) const
|
||||
{ return {tags::subscript(), *this,std::forward<Args>(args)};}
|
||||
// () also ...
|
||||
template< typename... Args >
|
||||
expr<tags::function, expr, expr_storage_t<Args>...> operator()(Args && ... args) const
|
||||
{ return {tags::function(), *this,std::forward<Args>(args)...};}
|
||||
// assignement is in general deleted
|
||||
expr & operator= (expr const &) = delete; // no ordinary assignment
|
||||
expr & operator= (expr &&) = default; // move assign ok
|
||||
// however, this is ok in the case f(i,j) = expr, where f is a clef::function
|
||||
template<typename RHS, typename CH = childs_t>
|
||||
ENABLE_IF(std::is_base_of<tags::function_class, typename std::tuple_element<0,CH>::type>)
|
||||
operator= (RHS const & rhs) { *this << rhs;}
|
||||
template<typename RHS, typename CH = childs_t>
|
||||
DISABLE_IF(std::is_base_of<tags::function_class, typename std::tuple_element<0,CH>::type>)
|
||||
operator= (RHS const & rhs) = delete;
|
||||
};
|
||||
// set some traits
|
||||
template<typename Tag, typename... T> struct ph_set< expr<Tag,T... > > : ph_set<T...> {};
|
||||
template<typename Tag, typename... T> struct is_any_lazy< expr<Tag,T... > >: std::true_type {};
|
||||
// if we want that subexpression are copied ?
|
||||
template<typename Tag, typename... T> struct force_copy_in_expr< expr<Tag,T... > > : std::true_type{};
|
||||
|
||||
template <typename Tag, typename... T> using expr_node_t = expr<Tag, expr_storage_t<T>...>;
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------
|
||||
* The basic operations put in a template....
|
||||
* --------------------------------------------------------------------------------------------------- */
|
||||
template<typename Tag> struct operation;
|
||||
|
||||
// a little function to clean the reference_wrapper
|
||||
template<typename U> U _cl(U && x) { return std::forward<U>(x);}
|
||||
template<typename U> auto _cl(std::reference_wrapper<U> x) DECL_AND_RETURN(x.get());
|
||||
|
||||
/// Terminal
|
||||
template<> struct operation<tags::terminal> { template<typename L> L operator()(L&& l) const { return std::forward<L>(l);} };
|
||||
|
||||
/// Function call
|
||||
template<> struct operation<tags::function> {
|
||||
template <typename F, typename... Args>
|
||||
auto operator()(F&& f, Args&&... args) const DECL_AND_RETURN(_cl(std::forward<F>(f))(_cl(std::forward<Args>(args))...));
|
||||
};
|
||||
|
||||
/// [ ] Call
|
||||
template<> struct operation<tags::subscript> {
|
||||
template <typename F, typename Args>
|
||||
auto operator()(F&& f, Args&& args) const DECL_AND_RETURN(_cl(std::forward<F>(f))[_cl(std::forward<Args>(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 <typename L, typename R> \
|
||||
std14::enable_if_t<is_any_lazy<L, R>::value, expr<tags::TAG, expr_storage_t<L>, expr_storage_t<R>>> operator OP(L&& l, R&& r) { \
|
||||
return {tags::TAG(), std::forward<L>(l), std::forward<R>(r)}; \
|
||||
} \
|
||||
template <> struct operation<tags::TAG> { \
|
||||
template <typename L, typename R> \
|
||||
auto operator()(L&& l, R&& r) const DECL_AND_RETURN(_cl(std::forward<L>(l)) OP _cl(std::forward<R>(r))); \
|
||||
};
|
||||
|
||||
TRIQS_CLEF_OPERATION(plus, +);
|
||||
TRIQS_CLEF_OPERATION(minus, -);
|
||||
TRIQS_CLEF_OPERATION(multiplies, *);
|
||||
TRIQS_CLEF_OPERATION(divides, /);
|
||||
TRIQS_CLEF_OPERATION(greater, >);
|
||||
TRIQS_CLEF_OPERATION(less, <);
|
||||
TRIQS_CLEF_OPERATION(leq, <=);
|
||||
TRIQS_CLEF_OPERATION(geq, >=);
|
||||
TRIQS_CLEF_OPERATION(eq, ==);
|
||||
#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 <typename L> \
|
||||
std14::enable_if_t<is_any_lazy<L>::value, expr<tags::TAG, expr_storage_t<L>>> operator OP(L&& l) { \
|
||||
return {tags::TAG(), std::forward<L>(l)}; \
|
||||
} \
|
||||
template <> struct operation<tags::TAG> { \
|
||||
template <typename L> auto operator()(L&& l) const DECL_AND_RETURN(OP _cl(std::forward<L>(l))); \
|
||||
};
|
||||
|
||||
TRIQS_CLEF_OPERATION(negate, -);
|
||||
TRIQS_CLEF_OPERATION(loginot, !);
|
||||
#undef TRIQS_CLEF_OPERATION
|
||||
|
||||
/// the only ternary node : expression if
|
||||
template<> struct operation<tags::if_else> {
|
||||
// A and B MUST be the same
|
||||
template<typename C, typename A, typename B> A operator()(C const & c, A const & a, B const & b) const {return _cl(c) ? _cl(a): _cl(b);}
|
||||
//template<typename C, typename A, typename B> auto operator()(C const & c, A const & a, B const & b) const DECL_AND_RETURN (_cl(c) ? _cl(a): _cl(b));
|
||||
};
|
||||
// operator is : if_else( Condition, A, B)
|
||||
template<typename C, typename A, typename B>
|
||||
expr<tags::if_else,expr_storage_t<C>,expr_storage_t<A>,expr_storage_t<B>>
|
||||
if_else(C && c, A && a, B && b) { return {tags::if_else(),std::forward<C>(c),std::forward<A>(a),std::forward<B>(b)};}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------
|
||||
* Evaluation of the expression tree.
|
||||
* --------------------------------------------------------------------------------------------------- */
|
||||
|
||||
constexpr bool __or() { return false;}
|
||||
template<typename ... B> constexpr bool __or(bool b, B... bs) { return b || __or(bs...); }
|
||||
|
||||
// Generic case : do nothing (for the leaf of the tree including placeholder)
|
||||
template <typename T, typename... Pairs> struct evaluator {
|
||||
static constexpr bool is_lazy = is_any_lazy<T>::value;
|
||||
T const & operator()(T const& k, Pairs const&... pairs) const { return k; }
|
||||
};
|
||||
|
||||
// The general eval function for expressions : declaration only
|
||||
template<typename T, typename... Pairs>
|
||||
auto eval (T const & ex, Pairs const &... pairs) ->decltype( evaluator<T, Pairs...>()(ex, pairs...));
|
||||
|
||||
// placeholder
|
||||
template <int N, int i, typename T, typename... Pairs> struct evaluator<placeholder<N>, pair<i, T>, Pairs...> {
|
||||
using eval_t = evaluator<placeholder<N>, Pairs...>;
|
||||
static constexpr bool is_lazy = eval_t::is_lazy;
|
||||
auto operator()(placeholder<N>, pair<i, T> const&, Pairs const&... pairs) const
|
||||
DECL_AND_RETURN(eval_t()(placeholder<N>(), pairs...));
|
||||
};
|
||||
|
||||
template <int N, typename T, typename... Pairs> struct evaluator<placeholder<N>, pair<N, T>, Pairs...> {
|
||||
static constexpr bool is_lazy = false;
|
||||
T operator()(placeholder<N>, pair<N, T> const& p, Pairs const&...) const { return p.rhs; }
|
||||
};
|
||||
|
||||
// any object hold by reference wrapper is redirected to the evaluator of the object
|
||||
template <typename T, typename... Contexts> struct evaluator<std::reference_wrapper<T>, Contexts...> {
|
||||
//using ev_t = evaluator<T, Contexts...>;
|
||||
static constexpr bool is_lazy = false;//ev_t::is_lazy;
|
||||
auto operator()(std::reference_wrapper<T> const& x, Contexts const&... contexts) const DECL_AND_RETURN(eval(x.get(), contexts...));
|
||||
};
|
||||
|
||||
// dispatching the evaluation : if lazy, we make a new clef expression, if not we call the operation
|
||||
template <typename Tag, bool IsLazy> struct op_dispatch;
|
||||
|
||||
template <typename Tag> struct op_dispatch<Tag, true> {
|
||||
template <typename... Args> expr<Tag, expr_storage_t<Args>...> operator()(Args&&... args) const {
|
||||
return {Tag(), std::forward<Args>(args)...};
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Tag> struct op_dispatch<Tag, false> {
|
||||
template <typename... Args>
|
||||
auto operator()(Args&&... args) const DECL_AND_RETURN(operation<Tag>()(std::forward<Args>(args)...));
|
||||
};
|
||||
|
||||
// general expr node
|
||||
|
||||
#ifdef TRIQS_USE_C14_DRAFT__
|
||||
template <typename Tag, typename... Childs, typename... Pairs> struct evaluator<expr<Tag, Childs...>, Pairs...> {
|
||||
|
||||
static constexpr bool is_lazy = __or(evaluator<Childs, Pairs...>::is_lazy...);
|
||||
|
||||
auto operator()(expr<Tag, Childs...> const& ex, Pairs const&... pairs) const {
|
||||
auto eval_in_context = [&pairs...](auto const& _child) { return eval(_child, pairs...); };
|
||||
return tuple::apply_compose(op_dispatch<Tag, is_lazy>{}, eval_in_context, ex.childs);
|
||||
}
|
||||
};
|
||||
#pragma once
|
||||
#if defined(__cpp_generic_lambdas) && defined (__cpp_decltype_auto) && defined(__cpp_return_type_deduction)
|
||||
// simplest code, in c++14
|
||||
#include "./clef.c14.hpp"
|
||||
#else
|
||||
// WORKAROUND FOR C++11 compilers
|
||||
template<int arity, typename Expr, typename... Pairs> struct evaluator_node_gal;
|
||||
|
||||
template <typename Tag, typename... Childs, typename... Pairs> struct evaluator_node_gal<1, expr<Tag, Childs...>, Pairs...> {
|
||||
static constexpr bool is_lazy = __or(evaluator<Childs, Pairs...>::is_lazy...);
|
||||
auto operator()(expr<Tag, Childs...> const& ex, Pairs const&... pairs) const
|
||||
DECL_AND_RETURN(op_dispatch<Tag, is_lazy> {}(eval(std::get<0>(ex.childs), pairs...)));
|
||||
};
|
||||
|
||||
template <typename Tag, typename... Childs, typename... Pairs> struct evaluator_node_gal<2, expr<Tag, Childs...>, Pairs...> {
|
||||
static constexpr bool is_lazy = __or(evaluator<Childs, Pairs...>::is_lazy...);
|
||||
auto operator()(expr<Tag, Childs...> const& ex, Pairs const&... pairs) const
|
||||
DECL_AND_RETURN(op_dispatch<Tag, is_lazy> {}(eval(std::get<0>(ex.childs), pairs...), eval(std::get<1>(ex.childs), pairs...)));
|
||||
};
|
||||
|
||||
// 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<p>(ex.childs), pairs...)
|
||||
#define IMPL(z, NN, unused) \
|
||||
template <typename Tag, typename... Childs, typename... Pairs> struct evaluator_node_gal<NN, expr<Tag, Childs...>, Pairs...> { \
|
||||
static constexpr bool is_lazy = __or(evaluator<Childs, Pairs...>::is_lazy...); \
|
||||
auto operator()(expr<Tag, Childs...> const& ex, Pairs const&... pairs) const \
|
||||
DECL_AND_RETURN(op_dispatch<Tag, is_lazy> {}(BOOST_PP_ENUM(NN, AUX, nil))); \
|
||||
};
|
||||
BOOST_PP_REPEAT_FROM_TO(3,BOOST_PP_INC(TRIQS_CLEF_MAXNARGS), IMPL, nil);
|
||||
#undef AUX
|
||||
#undef IMPL
|
||||
|
||||
template<typename Tag, typename... Childs, typename... Pairs>
|
||||
struct evaluator<expr<Tag, Childs...>, Pairs...> : evaluator_node_gal<sizeof...(Childs), expr<Tag, Childs...>, Pairs...>{};
|
||||
// workaround for C++11
|
||||
#include "./clef.c11.hpp"
|
||||
#endif
|
||||
|
||||
// The general eval function for expressions
|
||||
template <typename T, typename... Pairs>
|
||||
auto eval(T const& ex, Pairs const&... pairs) DECL_AND_RETURN(evaluator<T, Pairs...>()(ex, pairs...));
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------
|
||||
* Apply a function object to all the leaves of the expression tree
|
||||
* --------------------------------------------------------------------------------------------------- */
|
||||
|
||||
template <typename F> struct apply_on_each_leaf_impl {
|
||||
F f;
|
||||
template <typename T> std::c14::enable_if_t<is_clef_expression<T>::value> operator()(T const& ex) {
|
||||
tuple::for_each(ex.childs, *this);
|
||||
}
|
||||
template <typename T> std::c14::enable_if_t<!is_clef_expression<T>::value> operator()(T const& x) { f(x); }
|
||||
template <typename T> std::c14::enable_if_t<!is_clef_expression<T>::value> operator()(std::reference_wrapper<T> const& x) {
|
||||
f(x.get());
|
||||
}
|
||||
};
|
||||
|
||||
template <typename F, typename Expr> void apply_on_each_leaf(F&& f, Expr const& ex) {
|
||||
auto impl = apply_on_each_leaf_impl<F>{std::forward<F>(f)};
|
||||
impl(ex);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------
|
||||
* make_function : transform an expression to a function
|
||||
* --------------------------------------------------------------------------------------------------- */
|
||||
|
||||
template< typename Expr, int... Is> struct make_fun_impl {
|
||||
Expr ex; // keep a copy of the expression
|
||||
make_fun_impl(Expr const & ex_) : ex(ex_) {}
|
||||
|
||||
template<typename... Args>
|
||||
auto operator()(Args &&... args) const
|
||||
DECL_AND_RETURN( evaluator<Expr,pair<Is,Args>...>() ( ex, pair<Is,Args>{std::forward<Args>(args)}...));
|
||||
};
|
||||
|
||||
// values of the ph, excluding the Is ...
|
||||
template<ull_t x, int... Is> struct ph_filter;
|
||||
template<ull_t x, int I0, int... Is> struct ph_filter<x,I0,Is...> { static constexpr ull_t value = ph_filter<x,Is...>::value & (~ (1ull<<I0));};
|
||||
template<ull_t x> struct ph_filter<x> { static constexpr ull_t value = x; };
|
||||
|
||||
template< typename Expr, int... Is> struct ph_set<make_fun_impl<Expr,Is...> > { static constexpr ull_t value = ph_filter <ph_set<Expr>::value, Is...>::value;};
|
||||
template< typename Expr, int... Is> struct is_any_lazy<make_fun_impl<Expr,Is...> > : std::integral_constant<bool,ph_set<make_fun_impl<Expr,Is...>>::value !=0>{};
|
||||
template< typename Expr, int... Is> struct force_copy_in_expr<make_fun_impl<Expr,Is...> > : std::true_type{};
|
||||
|
||||
template< typename Expr, typename ... Phs>
|
||||
make_fun_impl<typename remove_cv_ref <Expr>::type,Phs::index...>
|
||||
make_function(Expr && ex, Phs...) { return {ex}; }
|
||||
|
||||
namespace result_of {
|
||||
template< typename Expr, typename ... Phs> struct make_function {
|
||||
using type = make_fun_impl<typename remove_cv_ref<Expr>::type, Phs::index...>;
|
||||
};
|
||||
}
|
||||
|
||||
template< typename Expr, int... Is,typename... Pairs> struct evaluator<make_fun_impl<Expr,Is...>, Pairs...> {
|
||||
using e_t = evaluator<Expr, Pairs...>;
|
||||
//using is_lazy = std::integral_constant<bool, ph_set<make_fun_impl<Expr, Is...>>::value != ph_set<Pairs...>::value>;
|
||||
static constexpr bool is_lazy = (ph_set<make_fun_impl<Expr, Is...>>::value != ph_set<Pairs...>::value);
|
||||
auto operator()(make_fun_impl<Expr,Is...> const & f, Pairs const & ... pairs) const DECL_AND_RETURN( make_function( e_t()(f.ex, pairs...),placeholder<Is>()...));
|
||||
};
|
||||
|
||||
template<int ... N> struct ph_list {};
|
||||
template<int ... N> ph_list<N...> var( placeholder<N> ...) { return {};}
|
||||
|
||||
template<typename Expr, int ... N>
|
||||
auto operator >> (ph_list<N...>, Expr const & ex) DECL_AND_RETURN( make_function(ex, placeholder<N>()...));
|
||||
|
||||
/* --------------------------------------------------------------------------------------------------
|
||||
* make_function
|
||||
* x_ >> expression is the same as make_function(expression,x)
|
||||
* --------------------------------------------------------------------------------------------------- */
|
||||
|
||||
template <int N, typename Expr>
|
||||
make_fun_impl<Expr,N > operator >> (placeholder<N> p, Expr&& ex) { return {ex}; }
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------
|
||||
* Auto assign for ()
|
||||
* --------------------------------------------------------------------------------------------------- */
|
||||
|
||||
// by default it is deleted = not implemented : every class has to define it...
|
||||
template<typename T, typename F> void triqs_clef_auto_assign (T,F) = delete;
|
||||
|
||||
// remove the ref_wrapper, terminal ...
|
||||
template<typename T, typename F> void triqs_clef_auto_assign (std::reference_wrapper<T> R ,F && f) { triqs_clef_auto_assign(R.get(),std::forward<F>(f));}
|
||||
template<typename T, typename F> void triqs_clef_auto_assign (expr<tags::terminal,T> const & t,F && f) { triqs_clef_auto_assign(std::get<0>(t.childs),std::forward<F>(f));}
|
||||
|
||||
// auto assign of an expr ? (for chain calls) : just reuse the same operator
|
||||
template<typename Tag, typename... Childs, typename RHS>
|
||||
void triqs_clef_auto_assign (expr<Tag,Childs...> && ex, RHS const & rhs) { ex << rhs;}
|
||||
|
||||
template<typename Tag, typename... Childs, typename RHS>
|
||||
void triqs_clef_auto_assign (expr<Tag,Childs...> const & ex, RHS const & rhs) { ex << rhs;}
|
||||
|
||||
// The case A(x_,y_) = RHS : we form the function (make_function) and call auto_assign (by ADL)
|
||||
template<typename F, typename RHS, int... Is>
|
||||
void operator<<(expr<tags::function, F, placeholder<Is>...> && ex, RHS && rhs) {
|
||||
triqs_clef_auto_assign(std::get<0>(ex.childs), make_function(std::forward<RHS>(rhs), placeholder<Is>()...));
|
||||
}
|
||||
template<typename F, typename RHS, int... Is>
|
||||
void operator<<(expr<tags::function, F, placeholder<Is>...> const & ex, RHS && rhs) {
|
||||
triqs_clef_auto_assign(std::get<0>(ex.childs), make_function(std::forward<RHS>(rhs), placeholder<Is>()...));
|
||||
}
|
||||
template<typename F, typename RHS, int... Is>
|
||||
void operator<<(expr<tags::function, F, placeholder<Is>...> & ex, RHS && rhs) {
|
||||
triqs_clef_auto_assign(std::get<0>(ex.childs), make_function(std::forward<RHS>(rhs), placeholder<Is>()...));
|
||||
}
|
||||
|
||||
// any other case e.g. f(x_+y_) = RHS etc .... which makes no sense : compiler will stop
|
||||
template<typename F, typename RHS, typename... T>
|
||||
void operator<<(expr<tags::function, F, T...> && ex, RHS && rhs) = delete;
|
||||
template<typename F, typename RHS, typename... T>
|
||||
void operator<<(expr<tags::function, F, T...> const & ex, RHS && rhs) = delete;
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------
|
||||
* Auto assign for []
|
||||
* --------------------------------------------------------------------------------------------------- */
|
||||
|
||||
// by default it is deleted = not implemented : every class has to define it...
|
||||
template<typename T, typename F> void triqs_clef_auto_assign_subscript (T,F) = delete;
|
||||
|
||||
// remove the ref_wrapper, terminal ...
|
||||
template<typename T, typename F> void triqs_clef_auto_assign_subscript (std::reference_wrapper<T> R ,F && f)
|
||||
{ triqs_clef_auto_assign_subscript(R.get(),std::forward<F>(f));}
|
||||
template<typename T, typename F> void triqs_clef_auto_assign_subscript (expr<tags::terminal,T> const & t,F && f)
|
||||
{ triqs_clef_auto_assign_subscript(std::get<0>(t.childs),std::forward<F>(f));}
|
||||
|
||||
// auto assign of an expr ? (for chain calls) : just reuse the same operator
|
||||
template<typename Tag, typename... Childs, typename RHS>
|
||||
void triqs_clef_auto_assign_subscript (expr<Tag,Childs...> && ex, RHS const & rhs) { ex << rhs;}
|
||||
|
||||
template<typename Tag, typename... Childs, typename RHS>
|
||||
void triqs_clef_auto_assign_subscript (expr<Tag,Childs...> const & ex, RHS const & rhs) { ex << rhs;}
|
||||
|
||||
// Same thing for the [ ]
|
||||
template<typename F, typename RHS, int... Is>
|
||||
void operator<<(expr<tags::subscript, F, placeholder<Is>...> const & ex, RHS && rhs) {
|
||||
triqs_clef_auto_assign_subscript(std::get<0>(ex.childs), make_function(std::forward<RHS>(rhs), placeholder<Is>()...));
|
||||
}
|
||||
template<typename F, typename RHS, int... Is>
|
||||
void operator<<(expr<tags::subscript, F, placeholder<Is>...> && ex, RHS && rhs) {
|
||||
triqs_clef_auto_assign_subscript(std::get<0>(ex.childs), make_function(std::forward<RHS>(rhs), placeholder<Is>()...));
|
||||
}
|
||||
|
||||
template<typename F, typename RHS, typename... T>
|
||||
void operator<<(expr<tags::subscript, F, T...> && ex, RHS && rhs) = delete;
|
||||
|
||||
template<typename F, typename RHS, typename... T>
|
||||
void operator<<(expr<tags::subscript, F, T...> const & ex, RHS && rhs) = delete;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------------
|
||||
* Create a terminal node of an object. the from clone version force copying the object
|
||||
* --------------------------------------------------------------------------------------------------- */
|
||||
|
||||
// make a node with the ref, unless it is an rvalue (which is moved).
|
||||
template<typename T> expr<tags::terminal,expr_storage_t<T> >
|
||||
make_expr(T && x){ return {tags::terminal(), std::forward<T>(x)};}
|
||||
|
||||
// make a node from a copy of the object
|
||||
template<typename T> expr<tags::terminal,typename remove_cv_ref<T>::type >
|
||||
make_expr_from_clone(T && x){ return {tags::terminal(), std::forward<T>(x)};}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------------
|
||||
* Create a call node of an object
|
||||
* The object can be kept as a : a ref, a copy, a view
|
||||
* --------------------------------------------------------------------------------------------------- */
|
||||
|
||||
template<typename T> struct arity { static constexpr int value =-1;};
|
||||
|
||||
namespace _result_of {
|
||||
template< typename Obj, typename... Args > struct make_expr_call :
|
||||
std::enable_if< is_any_lazy<Args...>::value, expr<tags::function,expr_storage_t<Obj>, expr_storage_t<Args> ...> > {
|
||||
static_assert (((arity<Obj>::value==-1) || (arity<Obj>::value == sizeof...(Args))), "Object called with a wrong number of arguments");
|
||||
};
|
||||
}
|
||||
template< typename Obj, typename... Args >
|
||||
typename _result_of::make_expr_call<Obj,Args...>::type
|
||||
make_expr_call(Obj&& obj, Args &&... args) { return {tags::function(),std::forward<Obj>(obj), std::forward<Args>(args)...};}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------------
|
||||
* Create a [] call (subscript) node of an object
|
||||
* The object can be kept as a : a ref, a copy, a view
|
||||
* --------------------------------------------------------------------------------------------------- */
|
||||
|
||||
namespace _result_of {
|
||||
template< typename Obj, typename Arg> struct make_expr_subscript :
|
||||
std::enable_if< is_any_lazy<Arg>::value, expr<tags::subscript,expr_storage_t<Obj>, expr_storage_t<Arg>> > {};
|
||||
}
|
||||
template< typename Obj, typename Arg>
|
||||
typename _result_of::make_expr_subscript<Obj,Arg>::type
|
||||
make_expr_subscript(Obj&& obj, Arg && arg) { return {tags::subscript(),std::forward<Obj>(obj), std::forward<Arg>(arg)};}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------------
|
||||
* function class : stores any expression polymorphically
|
||||
* f(x_,y_ ) = an expression associates this expression dynamically to f, which
|
||||
* can then be used as a std::function of the same signature...
|
||||
* --------------------------------------------------------------------------------------------------- */
|
||||
template<typename F> class function;
|
||||
|
||||
template<typename ReturnType, typename... T> class function<ReturnType(T...)> : tags::function_class {
|
||||
using std_function_type = std::function<ReturnType(T...)>;
|
||||
mutable std::shared_ptr <void> _exp; // CLEAN THIS MUTABLE ?
|
||||
mutable std::shared_ptr < std_function_type > _fnt_ptr;
|
||||
public:
|
||||
function():_fnt_ptr{std::make_shared<std_function_type> ()}{}
|
||||
|
||||
template <typename Expr, typename... X>
|
||||
explicit function(Expr const& _e, X... x)
|
||||
: _exp(std::make_shared<Expr>(_e)), _fnt_ptr(new std_function_type(make_function(_e, x...))) {}
|
||||
|
||||
ReturnType operator()(T const &... t) const { return (*_fnt_ptr)(t...);}
|
||||
|
||||
template< typename... Args>
|
||||
auto operator()( Args&&... args ) const DECL_AND_RETURN(make_expr_call (*this,std::forward<Args>(args)...));
|
||||
|
||||
template<typename RHS> friend void triqs_clef_auto_assign (function const & x, RHS rhs) {
|
||||
* (x._fnt_ptr) = std_function_type (rhs);
|
||||
x._exp = std::make_shared<typename std::remove_cv<decltype(rhs.ex)>::type> (rhs.ex);
|
||||
}
|
||||
|
||||
};
|
||||
template<typename F> struct force_copy_in_expr <function<F>> : std::true_type{};
|
||||
|
||||
/* --------------------------------------------------------------------------------------------------
|
||||
* The macro to make any function lazy
|
||||
* TRIQS_CLEF_MAKE_FNT_LAZY (Arity,FunctionName ) : creates a new function in the triqs::lazy namespace
|
||||
* 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 <typename... A> auto operator()(A&&... a) const DECL_AND_RETURN(name(std::forward<A>(a)...)); \
|
||||
}; \
|
||||
template <typename... A> auto name(A&&... a) DECL_AND_RETURN(make_expr_call(name##_lazy_impl(), std::forward<A>(a)...));
|
||||
|
||||
|
||||
#define TRIQS_CLEF_MAKE_FNT_LAZY_BIS(name) \
|
||||
struct name##_lazy_impl { \
|
||||
template <typename... A> auto operator()(A&&... a) const -> decltype(name(std::forward<A>(a)...)); \
|
||||
}; \
|
||||
template <typename... A> auto name(A&&... a) DECL_AND_RETURN(make_expr_call(name##_lazy_impl(), std::forward<A>(a)...)); \
|
||||
template <typename... A> auto name##_lazy_impl::operator()(A&&... a) const DECL_AND_RETURN(name(std::forward<A>(a)...));
|
||||
|
||||
#define TRIQS_CLEF_EXTEND_FNT_LAZY(FUN, TRAIT) \
|
||||
template <typename A> \
|
||||
std::c14::enable_if_t<TRAIT<A>::value, clef::expr_node_t<clef::tags::function, clef::FUN##_lazy_impl, A>> FUN(A&& a) { \
|
||||
return {clef::tags::function{}, clef::FUN##_lazy_impl{}, std::forward<A>(a)}; \
|
||||
}
|
||||
|
||||
#define TRIQS_CLEF_IMPLEMENT_LAZY_METHOD(TY, name) \
|
||||
struct __clef_lazy_method_impl_##TY##_##name { \
|
||||
template <typename X, typename... A> auto operator()(X&& x, A&&... a) const DECL_AND_RETURN(x.name(std::forward<A>(a)...)); \
|
||||
friend std::ostream& operator<<(std::ostream& out, __clef_lazy_method_impl_##TY##_##name const& x) { \
|
||||
return out << "apply_method:"<< BOOST_PP_STRINGIZE(name); \
|
||||
} \
|
||||
}; \
|
||||
template <typename... A> \
|
||||
auto name(A&&... a) DECL_AND_RETURN(make_expr_call(__clef_lazy_method_impl_##TY##_##name{}, *this, std::forward<A>(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>(args)...)); \
|
||||
\
|
||||
template <typename... Args> \
|
||||
auto operator()(Args&&... args) & DECL_AND_RETURN(make_expr_call(*this, std::forward<Args>(args)...)); \
|
||||
\
|
||||
template <typename... Args> \
|
||||
auto operator()(Args&&... args) && DECL_AND_RETURN(make_expr_call(std::move(*this), std::forward<Args>(args)...));
|
||||
|
||||
/* --------------------------------------------------------------------------------------------------
|
||||
* sum of expressions
|
||||
* --------------------------------------------------------------------------------------------------- */
|
||||
|
||||
// sum a function f on a domain D, using a simple foreach
|
||||
template <typename F, typename D>
|
||||
auto sum_f_domain_impl(F const& f, D const& d)
|
||||
-> std::c14::enable_if_t<!triqs::clef::is_any_lazy<F, D>::value, decltype(f(*(d.begin())))> {
|
||||
auto res = decltype(f(*(d.begin()))) {};
|
||||
using p_t = typename std::decay<decltype(*(d.begin()))>::type;
|
||||
foreach(d, [&res, &f](p_t const& x) { res = res + f(x); });
|
||||
return res;
|
||||
}
|
||||
|
||||
TRIQS_CLEF_MAKE_FNT_LAZY(sum_f_domain_impl);
|
||||
|
||||
// sum( expression, i = domain)
|
||||
template <typename Expr, int N, typename D> auto sum(Expr const& f, clef::pair<N, D> const& d)
|
||||
DECL_AND_RETURN(sum_f_domain_impl(make_function(f, clef::placeholder<N>()), d.rhs));
|
||||
|
||||
// two or more indices : sum recursively
|
||||
template <typename Expr, typename D0, int N0, typename D1, int N1, typename... D, int... N>
|
||||
auto sum(Expr const& f, clef::pair<N0, D0> const& d0, clef::pair<N1, D1> const& d1, clef::pair<N, D> const&... d)
|
||||
DECL_AND_RETURN(sum(sum(f, d0), d1, d...));
|
||||
|
||||
}} // namespace triqs::clef
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user