1#ifndef __DUNE_ACFEM_EXPRESSIONS_STORAGE_HH__ 
    2#define __DUNE_ACFEM_EXPRESSIONS_STORAGE_HH__ 
    4#include "../common/types.hh" 
    5#include "../mpl/access.hh" 
    8#include "expressiontraits.hh" 
    9#include "expressionoperations.hh" 
   32      namespace StorageImpl {
 
   34        template<
class Op, 
class SFINAE = 
void>
 
   35        struct IsSubExpressionOperation
 
   39        template<
class TreePos>
 
   40        struct IsSubExpressionOperation<SubExpressionOperation<TreePos> >
 
   44        template<
class C, 
class SFINAE = 
void>
 
   45        struct HasSubExpressionOperation
 
   50        struct HasSubExpressionOperation<C, 
VoidType<typename 
std::decay_t<C>::OperationType> >
 
   51          : IsSubExpressionOperation<typename std::decay_t<C>::OperationType>
 
   60      template<
class F, 
class... T>
 
   63        using ThisType = Storage;
 
   65        using StorageType = std::tuple<T...>;
 
   67        using FunctorType = F;
 
   68        using OperationType = 
typename FunctorType::OperationType;
 
   70        template<std::
size_t I>
 
   73        template<std::
size_t I>
 
   74        using DecayOperand = std::decay_t<OperandType<I> >;
 
   76        static constexpr std::size_t arity_ = 
sizeof...(T);
 
   87        template<
class Args, 
class SFINAE = 
void>
 
   88        struct IsStorageConstructibleHelper
 
   93        template<
class... TArg>
 
   94        struct IsStorageConstructibleHelper<
 
   96          std::enable_if_t<(sizeof...(T)) !=  (sizeof...(TArg))>
 
  101        template<
class... TArg>
 
  102        struct IsStorageConstructibleHelper<
 
  104          std::enable_if_t<(sizeof...(T)) ==  (sizeof...(TArg))>
 
  106          : std::is_constructible<StorageType, TArg...>
 
  109        template<
class... TArg>
 
  110        using IsStorageConstructible = IsStorageConstructibleHelper<TypeTuple<TArg...> >;
 
  115          std::enable_if_t<IsStorageConstructible<TArg...>::value, 
int> = 0>
 
  116        Storage(
const FunctorType& f, TArg&&... t)
 
  117          : functor_(f), operands_(std::forward<TArg>(t)...)
 
  120        template<
class... TArg, std::enable_if_t<IsStorageConstructible<TArg...>::value, 
int> = 0>
 
  122          : Storage(F{}, std::forward<TArg>(t)...)
 
  125        FunctorType operation()&&
 
  130        decltype(
auto) operation()&
 
  135        const auto& operation() 
const&
 
  141        template<std::
size_t I>
 
  142        static constexpr bool emitByValue_ = EmitByValueV<OperandType<I> >;
 
  146          std::enable_if_t<emitByValue_<I>, 
int> = 0>
 
  149          return get<I>(operands_);
 
  161        template<std::
size_t I, std::enable_if_t<!emitByValue_<I>, 
int> = 0>
 
  164          return get<I>(operands_);
 
  179          std::enable_if_t<!emitByValue_<I>, 
int> = 0>
 
  182          return get<I>(operands_);
 
  197          std::enable_if_t<!emitByValue_<I>, 
int> = 0>
 
  200          return get<I>(operands_);
 
  203        static constexpr std::size_t arity()
 
  210        StorageType operands_;
 
  215      template<
class F, 
class T0, 
class T1>
 
  216      class Storage<F, T0, T1>
 
  218        using ThisType = Storage;
 
  220        using FunctorType = F;
 
  221        using OperationType = 
typename FunctorType::OperationType;
 
  223        template<std::
size_t I>
 
  224        using OperandType = ConditionalType<I == 0, T0, T1>;
 
  226        template<std::
size_t I>
 
  227        using DecayOperand = std::decay_t<OperandType<I> >;
 
  229        static constexpr std::size_t arity_ = 2;
 
  232          class T0Arg, 
class T1Arg,
 
  233          std::enable_if_t<std::is_constructible<T0, T0Arg>::value && std::is_constructible<T1, T1Arg>::value, 
int> = 0>
 
  234        Storage(
const FunctorType& f, T0Arg&& t0, T1Arg&& t1)
 
  235          : functor_(f), t0_(
std::forward<T0Arg>(t0)), t1_(
std::forward<T1Arg>(t1))
 
  239          class T0Arg, 
class T1Arg,
 
  240          std::enable_if_t<std::is_constructible<T0, T0Arg>::value && std::is_constructible<T1, T1Arg>::value, 
int> = 0>
 
  241        Storage(T0Arg&& t0, T1Arg&& t1)
 
  242          : Storage(F{}, 
std::forward<T0Arg>(t0), 
std::forward<T1Arg>(t1))
 
  245        FunctorType operation()&&
 
  250        decltype(
auto) operation()&
 
  255        const auto& operation() const&
 
  269        template<std::
size_t I>
 
  270        decltype(
auto) operand(IndexConstant<I> = IndexConstant<I>{}) &&
 
  272          if constexpr (I == 0) {
 
  273            if constexpr (EmitByValueV<T0>) {
 
  274              return static_cast<std::decay_t<T0> 
>(t0_);
 
  276              return static_cast<T0&&
>(t0_);
 
  279            if constexpr (EmitByValueV<T1>) {
 
  280              return static_cast<std::decay_t<T1> 
>(t1_);
 
  282              return static_cast<T1&&
>(t1_);
 
  297        template<std::
size_t I>
 
  298        decltype(
auto) operand(IndexConstant<I> = IndexConstant<I>{}) &
 
  300          if constexpr (I == 0) {
 
  301            if constexpr (EmitByValueV<T0>) {
 
  302              return static_cast<std::decay_t<T0> 
>(t0_);
 
  304              return static_cast<T0&
>(t0_);
 
  307            if constexpr (EmitByValueV<T1>) {
 
  308              return static_cast<std::decay_t<T1> 
>(t1_);
 
  310              return static_cast<T1&
>(t1_);
 
  325        template<std::
size_t I>
 
  326        decltype(
auto) operand(IndexConstant<I> = IndexConstant<I>{}) 
const&
 
  328          if constexpr (I == 0) {
 
  329            if constexpr (EmitByValueV<T0>) {
 
  330              return static_cast<std::decay_t<T0> 
>(t0_);
 
  332              return static_cast<const T0&
>(t0_);
 
  335            if constexpr (EmitByValueV<T1>) {
 
  336              return static_cast<std::decay_t<T1> 
>(t1_);
 
  338              return static_cast<const T1&
>(t1_);
 
  343        static constexpr std::size_t arity()
 
  356      template<
class F, 
class T0>
 
  359        using ThisType = Storage;
 
  361        using FunctorType = F;
 
  362        using OperationType = 
typename FunctorType::OperationType;
 
  364        template<std::
size_t I>
 
  365        using OperandType = T0;
 
  367        template<std::
size_t I>
 
  368        using DecayOperand = std::decay_t<T0>;
 
  370        static constexpr std::size_t arity_ = 1;
 
  374          std::enable_if_t<std::is_constructible<T0, T0Arg>::value, 
int> = 0>
 
  375        Storage(
const FunctorType& f, T0Arg&& t0)
 
  376          : functor_(f), t0_(
std::forward<T0Arg>(t0))
 
  381          std::enable_if_t<std::is_constructible<T0, T0Arg>::value, 
int> = 0>
 
  383          : Storage(F{}, 
std::forward<T0Arg>(t0))
 
  386        FunctorType operation()&&
 
  391        decltype(
auto) operation()&
 
  396        const auto& operation() const&
 
  403        static constexpr bool emitByValue_ = EmitByValueV<T0>;
 
  406        template<std::
size_t I>
 
  407        decltype(
auto) operand(IndexConstant<I> = IndexConstant<I>{}) &&
 
  409          if constexpr (emitByValue_) {
 
  410            return static_cast<std::decay_t<T0> 
>(t0_);
 
  412            return static_cast<T0&&
>(t0_);
 
  416        template<std::
size_t I>
 
  417        decltype(
auto) operand(IndexConstant<I> = IndexConstant<I>{}) &
 
  419          if constexpr (emitByValue_) {
 
  420            return static_cast<std::decay_t<T0> 
>(t0_);
 
  422            return static_cast<T0&
>(t0_);
 
  426        template<std::
size_t I>
 
  427        decltype(
auto) operand(IndexConstant<I> = IndexConstant<I>{}) 
const&
 
  429          if constexpr (emitByValue_) {
 
  430            return static_cast<std::decay_t<T0> 
>(t0_);
 
  432            return static_cast<const T0&
>(t0_);
 
  436        static constexpr std::size_t arity()
 
  448      template<
class T, 
class SFINAE = 
void>
 
  461                 , decltype(
std::decay_t<T>::arity())
 
  464                 , typename std::decay_t<T>::template OperandType<0>
 
  465                 , typename std::decay_t<T>::FunctorType
 
  466                 , typename std::decay_t<T>::OperationType
 
  473        static_assert(
sizeof(
decltype(std::declval<T>().template operand<0>())) >= 0,
 
  474                      "Expressions should define the operand template.");
 
  478      template<
class F, 
class SFINAE = 
void>
 
  484      struct IsFunctor<F, 
VoidType<typename 
std::decay_t<F>::OperationType, typename std::decay_t<F>::InvertibleOperation> >
 
  489        template<
class T, 
class SFINAE = 
void>
 
  490        struct ExpressionFunctor
 
  496        struct ExpressionFunctor<T, 
std::enable_if_t<IsExpression<T>::value> >
 
  498          using Type = 
typename std::decay_t<T>::FunctorType;
 
  501        template<
class T, 
class SFINAE = 
void>
 
  502        struct ExpressionOperation
 
  508        struct ExpressionOperation<T, 
std::enable_if_t<IsExpression<T>::value> >
 
  510          using Type = 
typename std::decay_t<T>::OperationType;
 
  513        template<
class T, 
class SFINAE = 
void>
 
  514        struct ExpressionArity
 
  516          using Type = IndexConstant<0>;
 
  520        struct ExpressionArity<T, 
std::enable_if_t<IsExpression<T>::value> >
 
  522          using Type = IndexConstant<std::decay_t<T>::arity()>;
 
  525        template<std::
size_t I, 
class T, 
class SFINAE = 
void>
 
  526        struct ExpressionOperand;
 
  528        template<std::
size_t I, 
class T>
 
  529        struct ExpressionOperand<
 
  531          std::enable_if_t<(ExpressionArity<T>::Type::value > I)> >
 
  533          using Type = 
typename std::decay_t<T>::template OperandType<I>;
 
  538      template<std::
size_t I, 
class T>
 
  539      using Operand = 
typename impl::ExpressionOperand<I, T>::Type;
 
  542      using Functor = 
typename impl::ExpressionFunctor<T>::Type;
 
  545      using Operation = 
typename impl::ExpressionOperation<T>::Type;
 
  548      using Arity = 
typename impl::ExpressionArity<T>::Type;
 
  551      template<std::
size_t N, 
class T>
 
  570        template<
template<
class...> 
class Predicate, 
class E, 
class Seq, 
class... Rest>
 
  571        struct AnyOperandIsExpander;
 
  573        template<
template<
class...> 
class Predicate, 
class E, std::size_t... I, 
class... Rest>
 
  574        struct AnyOperandIsExpander<Predicate, E, 
IndexSequence<I...>, Rest...>
 
  575          : 
BoolConstant<(... || Predicate<Operand<I, E>, Rest...>::value)>
 
  578        template<
template<
class...> 
class Predicate, 
class E, 
class Seq, 
class... Rest>
 
  579        struct AllOperandsAreExpander;
 
  581        template<
template<
class...> 
class Predicate, 
class E, std::size_t... I, 
class... Rest>
 
  582        struct AllOperandsAreExpander<Predicate, E, 
IndexSequence<I...>, Rest...>
 
  583          : 
BoolConstant<(... && Predicate<Operand<I, E>, Rest...>::value)>
 
  588      template<
template<
class...> 
class Predicate, 
class T, 
class... Rest>
 
  589      using AnyOperandIs = AnyOperandIsExpander<Predicate, T, MakeIndexSequence<Arity<T>::value>, Rest...>;
 
  591      template<
template<
class...> 
class Predicate, 
class T, 
class... Rest>
 
  592      using AllOperandsAre = AllOperandsAreExpander<Predicate, T, MakeIndexSequence<Arity<T>::value>, Rest...>;
 
  594      template<
template<
class...> 
class Predicate, std::size_t N, 
class T, 
class SFINAE = 
void>
 
  595      struct OperandHasProperty
 
  599      template<
template<
class...> 
class Predicate, std::size_t N, 
class T>
 
  600      struct OperandHasProperty<Predicate, N, T, 
std::enable_if_t<(Arity<T>::value > N)> >
 
  601        : Predicate<Operand<N, T> >
 
  607      template<
class T, 
class SFINAE = 
void>
 
  622        std::enable_if_t<(IsBinaryExpression<T>::value
 
  623                          && std::is_same<Functor<Operand<0, T> >, Functor<Operand<1, T> > >::value
 
  632        std::enable_if_t<(IsExpression<T>::value
 
  633                          && Arity<T>::value> 2
 
  637        static_assert(Arity<T>::value> 2, 
"Not Implemented for more than binary expressions.");
 
  640      template<std::
size_t I, 
class T>
 
  643        static_assert(IsExpression<T>::value, 
"Trying to get operand from non-expression.");
 
  644        return std::forward<T>(t).template operand<I>();
 
  648      decltype(
auto) operation(T&& t)
 
  650        static_assert(IsExpression<T>::value, 
"Trying to get operation from non-expression.");
 
  651        return t.operation();
 
  655      constexpr std::size_t arity()
 
  657        static_assert(IsExpression<T>::value, 
"Trying to get arity from non-expression.");
 
  658        return std::decay_t<T>::arity();
 
  662      constexpr std::size_t arity(T&&)
 
  667      template<std::
size_t I, 
class T>
 
  668      constexpr inline bool ByValueOperandV = EmitByValueV<Operand<I, T> >;
 
  685      template<std::
size_t I, 
class T>
 
  689        static_assert(!(std::is_rvalue_reference<
decltype(t)>::value
 
  690                        && std::is_reference<Operand<I, T> >::value
 
  691                        && !ByValueOperandV<I, T>
 
  692                        && !std::is_reference<
decltype(std::forward<T>(t).template operand<I>())>::value),
 
  693                      "Reference operand returned by value from rvalue expression.");
 
  696        static_assert(!(std::is_rvalue_reference<
decltype(t)>::value
 
  697                        && !std::is_reference<Operand<I, T> >::value
 
  698                        && std::is_lvalue_reference<
decltype(std::forward<T>(t).template operand<I>())>::value),
 
  699                      "Non-reference operand returned by reference from rvalue expression.");
 
  703      template<
class F, 
class... T>
 
  706        return Storage<F, T...>(f, std::forward<T>(t)...);
 
  715    using Expressions::IsExpression;
 
  716    using Expressions::IsExpressionOfArity;
 
  717    using Expressions::IsUnaryExpression;
 
  718    using Expressions::IsBinaryExpression;
 
Various traits for expressions.
 
constexpr void danglingReferenceCheck(T &&t, IndexConstant< I >=IndexConstant< I >{})
Definition: storage.hh:686
 
constexpr auto storage(const F &f, T &&... t)
Generate an expression storage container.
Definition: storage.hh:704
 
BoolConstant<!ExpressionTraits< T >::isVolatile &&(ExpressionTraits< T >::isTypedValue||ExpressionTraits< T >::isConstant||(!std::is_reference< T >::value &&ExpressionTraits< T >::isIndependent))> IsConstantExprArg
Evaluate to true if an instance of T can be treated as constant argument to an expresion.
Definition: storage.hh:682
 
static constexpr bool EmitByValueV
Force some things to always be emitted as non-references.
Definition: storage.hh:58
 
BoolConstant< ExpressionTraits< T >::isTypedValue > IsTypedValue
Compile-time true if T is a "typed value", e.g. a std::integral_constant.
Definition: expressiontraits.hh:90
 
std::tuple_element_t< N, std::decay_t< TupleLike > > TupleElement
Forward to std::tuple_element<N, std::decay_t<T> >
Definition: access.hh:125
 
Sequence< std::size_t, V... > IndexSequence
Sequence of std::size_t values.
Definition: types.hh:64
 
Constant< bool, V > BoolConstant
Short-cut for integral constant of type bool.
Definition: types.hh:48
 
Constant< std::size_t, V > IndexConstant
Short-cut for integral constant of type std::size_t.
Definition: types.hh:44
 
typename MakeType< void, Other... >::Type VoidType
Generate void regardless of the template argument list.
Definition: types.hh:151
 
BoolConstant< false > FalseType
Alias for std::false_type.
Definition: types.hh:110
 
BoolConstant< true > TrueType
Alias for std::true_type.
Definition: types.hh:107
 
Default expression traits definition is a recursion in order to ease disambiguation.
Definition: expressiontraits.hh:54
 
TrueType if T is an expression of arity 2, otherwise FalseType.
Definition: storage.hh:566
 
TrueType if T is an expression of arity N, otherwise FalseType.
Definition: storage.hh:554
 
TrueType if T is an expression of arity 1, otherwise FalseType.
Definition: storage.hh:560
 
@interal SFINAE default for examining the functors of operands when we do not know whether T has suff...
Definition: storage.hh:610