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