DUNE-ACFEM (unstable)

storage.hh
1#ifndef __DUNE_ACFEM_EXPRESSIONS_STORAGE_HH__
2#define __DUNE_ACFEM_EXPRESSIONS_STORAGE_HH__
3
4#include "../common/types.hh"
5#include "../mpl/access.hh"
6#include "policy.hh"
7#include "typetraits.hh"
8#include "expressiontraits.hh"
9#include "expressionoperations.hh"
10
11namespace Dune
12{
13
14 namespace ACFem
15 {
16
17 namespace Expressions
18 {
32 namespace StorageImpl {
33
34 template<class Op, class SFINAE = void>
35 struct IsSubExpressionOperation
36 : FalseType
37 {};
38
39 template<class TreePos>
40 struct IsSubExpressionOperation<SubExpressionOperation<TreePos> >
41 : TrueType
42 {};
43
44 template<class C, class SFINAE = void>
45 struct HasSubExpressionOperation
46 : FalseType
47 {};
48
49 template<class C>
50 struct HasSubExpressionOperation<C, VoidType<typename std::decay_t<C>::OperationType> >
51 : IsSubExpressionOperation<typename std::decay_t<C>::OperationType>
52 {};
53
54 }
55
57 template<class T>
58 static constexpr bool EmitByValueV = IsTypedValue<T>::value && !StorageImpl::HasSubExpressionOperation<T>::value;
59
60 template<class F, class... T>
61 class Storage
62 {
63 using ThisType = Storage;
64 protected:
65 using StorageType = std::tuple<T...>;
66 public:
67 using FunctorType = F;
68 using OperationType = typename FunctorType::OperationType;
69
70 template<std::size_t I>
71 using OperandType = TupleElement<I, StorageType>;
72
73 template<std::size_t I>
74 using DecayOperand = std::decay_t<OperandType<I> >;
75
76 static constexpr std::size_t arity_ = sizeof...(T);
77
78 private:
79 // work around a clang is_constructible bug when
80 // is_constructible would be called with too few
81 // arguments. clang seemingly tries to test
82 // default-construction of missing arguments and fails.
83 template<class... C>
84 struct TypeTuple
85 {};
86
87 template<class Args, class SFINAE = void>
88 struct IsStorageConstructibleHelper
89 : FalseType
90 {};
91
92 // for clang: allow failure if the number of arguments does not match.
93 template<class... TArg>
94 struct IsStorageConstructibleHelper<
95 TypeTuple<TArg...>,
96 std::enable_if_t<(sizeof...(T)) != (sizeof...(TArg))>
97 >
98 : FalseType
99 {};
100
101 template<class... TArg>
102 struct IsStorageConstructibleHelper<
103 TypeTuple<TArg...>,
104 std::enable_if_t<(sizeof...(T)) == (sizeof...(TArg))>
105 >
106 : std::is_constructible<StorageType, TArg...>
107 {};
108
109 template<class... TArg>
110 using IsStorageConstructible = IsStorageConstructibleHelper<TypeTuple<TArg...> >;
111
112 public:
113 template<
114 class... 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)...)
118 {}
119
120 template<class... TArg, std::enable_if_t<IsStorageConstructible<TArg...>::value, int> = 0>
121 Storage(TArg&&... t)
122 : Storage(F{}, std::forward<TArg>(t)...)
123 {}
124
125 FunctorType operation()&&
126 {
127 return functor_;
128 }
129
130 decltype(auto) operation()&
131 {
132 return functor_;
133 }
134
135 const auto& operation() const&
136 {
137 return functor_;
138 }
139
141 template<std::size_t I>
142 static constexpr bool emitByValue_ = EmitByValueV<OperandType<I> >;
143
144 template<
145 std::size_t I,
146 std::enable_if_t<emitByValue_<I>, int> = 0>
147 DecayOperand<I> operand(IndexConstant<I> = IndexConstant<I>{}) const
148 {
149 return get<I>(operands_);
150 }
151
161 template<std::size_t I, std::enable_if_t<!emitByValue_<I>, int> = 0>
162 OperandType<I>&& operand(IndexConstant<I> = IndexConstant<I>{}) &&
163 {
164 return get<I>(operands_);
165 }
166
177 template<
178 std::size_t I,
179 std::enable_if_t<!emitByValue_<I>, int> = 0>
180 decltype(auto) operand(IndexConstant<I> = IndexConstant<I>{}) &
181 {
182 return get<I>(operands_);
183 }
184
195 template<
196 std::size_t I,
197 std::enable_if_t<!emitByValue_<I>, int> = 0>
198 decltype(auto) operand(IndexConstant<I> = IndexConstant<I>{}) const&
199 {
200 return get<I>(operands_);
201 }
202
203 static constexpr std::size_t arity()
204 {
205 return sizeof...(T);
206 }
207
208 protected:
209 F functor_;
210 StorageType operands_;
211 };
212
214
215 template<class F, class T0, class T1>
216 class Storage<F, T0, T1>
217 {
218 using ThisType = Storage;
219 public:
220 using FunctorType = F;
221 using OperationType = typename FunctorType::OperationType;
222
223 template<std::size_t I>
224 using OperandType = ConditionalType<I == 0, T0, T1>;
225
226 template<std::size_t I>
227 using DecayOperand = std::decay_t<OperandType<I> >;
228
229 static constexpr std::size_t arity_ = 2;
230
231 template<
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))
236 {}
237
238 template<
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))
243 {}
244
245 FunctorType operation()&&
246 {
247 return functor_;
248 }
249
250 decltype(auto) operation()&
251 {
252 return functor_;
253 }
254
255 const auto& operation() const&
256 {
257 return functor_;
258 }
259
269 template<std::size_t I>
270 decltype(auto) operand(IndexConstant<I> = IndexConstant<I>{}) &&
271 {
272 if constexpr (I == 0) {
273 if constexpr (EmitByValueV<T0>) {
274 return static_cast<std::decay_t<T0> >(t0_);
275 } else {
276 return static_cast<T0&&>(t0_);
277 }
278 } else {
279 if constexpr (EmitByValueV<T1>) {
280 return static_cast<std::decay_t<T1> >(t1_);
281 } else {
282 return static_cast<T1&&>(t1_);
283 }
284 }
285 }
286
297 template<std::size_t I>
298 decltype(auto) operand(IndexConstant<I> = IndexConstant<I>{}) &
299 {
300 if constexpr (I == 0) {
301 if constexpr (EmitByValueV<T0>) {
302 return static_cast<std::decay_t<T0> >(t0_);
303 } else {
304 return static_cast<T0&>(t0_);
305 }
306 } else {
307 if constexpr (EmitByValueV<T1>) {
308 return static_cast<std::decay_t<T1> >(t1_);
309 } else {
310 return static_cast<T1&>(t1_);
311 }
312 }
313 }
314
325 template<std::size_t I>
326 decltype(auto) operand(IndexConstant<I> = IndexConstant<I>{}) const&
327 {
328 if constexpr (I == 0) {
329 if constexpr (EmitByValueV<T0>) {
330 return static_cast<std::decay_t<T0> >(t0_);
331 } else {
332 return static_cast<const T0&>(t0_);
333 }
334 } else {
335 if constexpr (EmitByValueV<T1>) {
336 return static_cast<std::decay_t<T1> >(t1_);
337 } else {
338 return static_cast<const T1&>(t1_);
339 }
340 }
341 }
342
343 static constexpr std::size_t arity()
344 {
345 return 2;
346 }
347
348 protected:
349 F functor_;
350 T0 t0_;
351 T1 t1_;
352 };
353
355
356 template<class F, class T0>
357 class Storage<F, T0>
358 {
359 using ThisType = Storage;
360 public:
361 using FunctorType = F;
362 using OperationType = typename FunctorType::OperationType;
363
364 template<std::size_t I>
365 using OperandType = T0;
366
367 template<std::size_t I>
368 using DecayOperand = std::decay_t<T0>;
369
370 static constexpr std::size_t arity_ = 1;
371
372 template<
373 class T0Arg,
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))
377 {}
378
379 template<
380 class T0Arg,
381 std::enable_if_t<std::is_constructible<T0, T0Arg>::value, int> = 0>
382 Storage(T0Arg&& t0)
383 : Storage(F{}, std::forward<T0Arg>(t0))
384 {}
385
386 FunctorType operation()&&
387 {
388 return functor_;
389 }
390
391 decltype(auto) operation()&
392 {
393 return functor_;
394 }
395
396 const auto& operation() const&
397 {
398 return functor_;
399 }
400
401 private:
403 static constexpr bool emitByValue_ = EmitByValueV<T0>;
404
405 public:
406 template<std::size_t I>
407 decltype(auto) operand(IndexConstant<I> = IndexConstant<I>{}) &&
408 {
409 if constexpr (emitByValue_) {
410 return static_cast<std::decay_t<T0> >(t0_);
411 } else {
412 return static_cast<T0&&>(t0_);
413 }
414 }
415
416 template<std::size_t I>
417 decltype(auto) operand(IndexConstant<I> = IndexConstant<I>{}) &
418 {
419 if constexpr (emitByValue_) {
420 return static_cast<std::decay_t<T0> >(t0_);
421 } else {
422 return static_cast<T0&>(t0_);
423 }
424 }
425
426 template<std::size_t I>
427 decltype(auto) operand(IndexConstant<I> = IndexConstant<I>{}) const&
428 {
429 if constexpr (emitByValue_) {
430 return static_cast<std::decay_t<T0> >(t0_);
431 } else {
432 return static_cast<const T0&>(t0_);
433 }
434 }
435
436 static constexpr std::size_t arity()
437 {
438 return 1;
439 }
440
441 protected:
442 F functor_;
443 T0 t0_;
444 };
445
447
448 template<class T, class SFINAE = void>
449 struct IsExpression
450 : FalseType
451 {};
452
454 template<class T>
455 struct IsExpression<
456 T,
457 VoidType<void
458 // check for methods, gcc does not like this with non-static methods.
459// , decltype(std::declval<std::decay_t<T> >().operation())
460// , decltype(std::declval<T>().template operand<0>())
461 , decltype(std::decay_t<T>::arity())
462 // check for types
463#if 0
464 , typename std::decay_t<T>::template OperandType<0>
465 , typename std::decay_t<T>::FunctorType
466 , typename std::decay_t<T>::OperationType
467#endif
468 >
469 >
470 : TrueType
471 {
472#if 0
473 static_assert(sizeof(decltype(std::declval<T>().template operand<0>())) >= 0,
474 "Expressions should define the operand template.");
475#endif
476 };
477
478 template<class F, class SFINAE = void>
479 struct IsFunctor
480 : FalseType
481 {};
482
483 template<class F>
484 struct IsFunctor<F, VoidType<typename std::decay_t<F>::OperationType, typename std::decay_t<F>::InvertibleOperation> >
485 : TrueType
486 {};
487
488 namespace impl {
489 template<class T, class SFINAE = void>
490 struct ExpressionFunctor
491 {
492 using Type = void;
493 };
494
495 template<class T>
496 struct ExpressionFunctor<T, std::enable_if_t<IsExpression<T>::value> >
497 {
498 using Type = typename std::decay_t<T>::FunctorType;
499 };
500
501 template<class T, class SFINAE = void>
502 struct ExpressionOperation
503 {
504 using Type = void;
505 };
506
507 template<class T>
508 struct ExpressionOperation<T, std::enable_if_t<IsExpression<T>::value> >
509 {
510 using Type = typename std::decay_t<T>::OperationType;
511 };
512
513 template<class T, class SFINAE = void>
514 struct ExpressionArity
515 {
516 using Type = IndexConstant<0>;
517 };
518
519 template<class T>
520 struct ExpressionArity<T, std::enable_if_t<IsExpression<T>::value> >
521 {
522 using Type = IndexConstant<std::decay_t<T>::arity()>;
523 };
524
525 template<std::size_t I, class T, class SFINAE = void>
526 struct ExpressionOperand;
527
528 template<std::size_t I, class T>
529 struct ExpressionOperand<
530 I, T,
531 std::enable_if_t<(ExpressionArity<T>::Type::value > I)> >
532 {
533 using Type = typename std::decay_t<T>::template OperandType<I>;
534 };
535
536 }
537
538 template<std::size_t I, class T>
539 using Operand = typename impl::ExpressionOperand<I, T>::Type;
540
541 template<class T>
542 using Functor = typename impl::ExpressionFunctor<T>::Type;
543
544 template<class T>
545 using Operation = typename impl::ExpressionOperation<T>::Type;
546
547 template<class T>
548 using Arity = typename impl::ExpressionArity<T>::Type;
549
551 template<std::size_t N, class T>
553 : BoolConstant<Arity<T>::value == N>
554 {};
555
557 template<class T>
559 : IsExpressionOfArity<1, T>
560 {};
561
563 template<class T>
565 : IsExpressionOfArity<2, T>
566 {};
567
568 namespace {
569
570 template<template<class...> class Predicate, class E, class Seq, class... Rest>
571 struct AnyOperandIsExpander;
572
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)>
576 {};
577
578 template<template<class...> class Predicate, class E, class Seq, class... Rest>
579 struct AllOperandsAreExpander;
580
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)>
584 {};
585
586 }
587
588 template<template<class...> class Predicate, class T, class... Rest>
589 using AnyOperandIs = AnyOperandIsExpander<Predicate, T, MakeIndexSequence<Arity<T>::value>, Rest...>;
590
591 template<template<class...> class Predicate, class T, class... Rest>
592 using AllOperandsAre = AllOperandsAreExpander<Predicate, T, MakeIndexSequence<Arity<T>::value>, Rest...>;
593
594 template<template<class...> class Predicate, std::size_t N, class T, class SFINAE = void>
595 struct OperandHasProperty
596 : FalseType
597 {};
598
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> >
602 {};
603
607 template<class T, class SFINAE = void>
609 : FalseType
610 {};
611
613 template<class T>
614 struct SameOperandFunctors<T, std::enable_if_t<IsUnaryExpression<T>::value> >
615 : TrueType
616 {};
617
619 template<class T>
621 T,
622 std::enable_if_t<(IsBinaryExpression<T>::value
623 && std::is_same<Functor<Operand<0, T> >, Functor<Operand<1, T> > >::value
624 )> >
625 : TrueType
626 {};
627
629 template<class T>
631 T,
632 std::enable_if_t<(IsExpression<T>::value
633 && Arity<T>::value> 2
634 )> >
635 : FalseType
636 {
637 static_assert(Arity<T>::value> 2, "Not Implemented for more than binary expressions.");
638 };
639
640 template<std::size_t I, class T>
641 decltype(auto) operand(T&& t, IndexConstant<I> = IndexConstant<I>{})
642 {
643 static_assert(IsExpression<T>::value, "Trying to get operand from non-expression.");
644 return std::forward<T>(t).template operand<I>();
645 }
646
647 template<class T>
648 decltype(auto) operation(T&& t)
649 {
650 static_assert(IsExpression<T>::value, "Trying to get operation from non-expression.");
651 return t.operation();
652 }
653
654 template<class T>
655 constexpr std::size_t arity()
656 {
657 static_assert(IsExpression<T>::value, "Trying to get arity from non-expression.");
658 return std::decay_t<T>::arity();
659 }
660
661 template<class T>
662 constexpr std::size_t arity(T&&)
663 {
664 return arity<T>();
665 }
666
667 template<std::size_t I, class T>
668 constexpr inline bool ByValueOperandV = EmitByValueV<Operand<I, T> >;
669
676 template<class T>
679 &&
682 || (!std::is_reference<T>::value && ExpressionTraits<T>::isIndependent))>;
683
685 template<std::size_t I, class T>
687 {
688 // This could happen if ByValueOperand is in effect
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.");
694
695 // This is the bad one
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.");
700 }
701
703 template<class F, class... T>
704 constexpr auto storage(const F& f, T&&... t)
705 {
706 return Storage<F, T...>(f, std::forward<T>(t)...);
707 }
708
710
712
713 } // Expressions
714
715 using Expressions::IsExpression;
716 using Expressions::IsExpressionOfArity;
717 using Expressions::IsUnaryExpression;
718 using Expressions::IsBinaryExpression;
720
721 } // ACFem
722
723} // Dune
724
725#endif // __DUNE_ACFEM_EXPRESSIONS_STORAGE_HH__
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
STL namespace.
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
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden  |  generated with Hugo v0.111.3 (Jul 15, 22:36, 2024)