DUNE-ACFEM (unstable)

transform.hh
1#ifndef __DUNE_ACFEM_EXPRESSIONS_TRANSFORM_HH__
2#define __DUNE_ACFEM_EXPRESSIONS_TRANSFORM_HH__
3
4#include "../common/typetraits.hh"
5#include "storage.hh"
6#include "terminal.hh"
7#include "treeoperand.hh"
8#include "examine.hh"
9
10namespace Dune::ACFem::Expressions {
11
19 template<class Optimize = OptimizeTop>
20 struct Operate
21 {
22 template<class F, class... Arg>
23 constexpr decltype(auto) operator()(F&& f, Arg&&... arg) const
24 {
25 return operate(Optimize{}, std::forward<F>(f), std::forward<Arg>(arg)...);
26 }
27 };
28
32 template<class Optimize = OptimizeTop>
34 {
35 template<class F, class... Arg>
36 constexpr decltype(auto) operator()(F&& f, Arg&&... arg) const
37 {
38 return operate(Optimize{}, std::forward<F>(f), std::decay_t<Arg>(arg)...);
39 }
40 };
41
47 {
48 template<class F, class... Arg>
49 constexpr decltype(auto) operator()(F&& f, Arg&&... arg) const
50 {
51 return 0;
52 }
53 };
54
55 using NoTreePos = FalseType;
56 using DoTreePos = TrueType;
57 using NoParent = FalseType;
58
59 template<class F, class E, class TreePos, class Parent>
60 struct IsTransformInvocable
61 : std::is_invocable<F, E, TreePos, Parent>
62 {};
63
64 template<class F, class E, class TreePos>
65 struct IsTransformInvocable<F, E, TreePos, FalseType>
66 : std::is_invocable<F, E, TreePos>
67 {};
68
69 template<class F, class E, class Parent>
70 struct IsTransformInvocable<F, E, FalseType, Parent>
71 : std::is_invocable<F, E, Parent>
72 {};
73
74 template<class F, class E>
75 struct IsTransformInvocable<F, E, FalseType, FalseType>
76 : std::is_invocable<F, E>
77 {};
78
79 namespace {
80
81 template<class TreePos, std::size_t Idx>
82 struct AppendTreePosHelper
83 {
84 using Type = PushBack<Idx, TreePos>;
85 };
86
87 template<std::size_t Idx>
88 struct AppendTreePosHelper<FalseType, Idx>
89 {
90 using Type = FalseType;
91 };
92
93 }
94
95 template<class TreePos, std::size_t Idx>
96 using AppendTreePos = typename AppendTreePosHelper<TreePos, Idx>::Type;
97
98 template<
99 class E, class F,
100 class Operation = Operate<OptimizeTop>,
101 class TreePos = NoTreePos,
102 class Parent = NoParent,
103 std::enable_if_t<IsTransformInvocable<F, E, TreePos, Parent>::value, int> = 0>
104 constexpr decltype(auto) transform(E&& e, F&& f, Operation&& op = Operation{}, TreePos = TreePos{}, Parent&& parent = Parent{})
105 {
106 //std::clog << "invoc TR rvref: " << std::is_rvalue_reference<decltype(e)>::value << std::endl;
107 //std::clog << " " << e.name() << std::endl;
108
109 if constexpr (std::is_same<Parent, FalseType>::value) {
110 if constexpr (std::is_same<TreePos, FalseType>::value) {
111 return std::forward<F>(f)(std::forward<E>(e));
112 } else {
113 return std::forward<F>(f)(std::forward<E>(e), TreePos{});
114 }
115 } else {
116 return std::forward<F>(f)(std::forward<E>(e), TreePos{}, std::forward<Parent>(parent));
117 }
118 }
119
120 namespace {
121
122 template<class E, class F, class Operation, class TreePos, class Parent>
123 constexpr bool doNotTransform()
124 {
125 if constexpr (IsTransformInvocable<F, E, TreePos, Parent>::value) {
126 return false;
127 } else if constexpr (!IsExpression<E>::value) {
128 return true;
129 } else if constexpr (IsSelfExpression<E>::value) {
130 return true;
131 } else if constexpr (IsPlaceholderExpression<E>::value) {
132 return true;
133 } else if constexpr (std::is_same<F, FalseType>::value) {
134 return false;
135 } else if constexpr (ExamineTreeOr<E, TreePos, Parent, IsApplicableTo, F>::value) {
136 return false;
137 } else {
138 return true;
139 }
140 }
141
142#if 0
143 template<class E, class F, class Operation, class TreePos, class Parent>
144 struct DoNotTransform
145#endif
146
147 } // NS anonymous
148
149 template<
150 class E, class F,
151 class Operation = Operate<OptimizeTop>,
152 class TreePos = NoTreePos,
153 class Parent = NoParent,
154 std::enable_if_t<(
155#if 1
156 doNotTransform<E, F, Operation, TreePos, Parent>()
157#else
158 !IsTransformInvocable<F, E, TreePos, Parent>::value
159 && ((!std::is_same<F, FalseType>::value
160 && !ExamineTreeOr<E, TreePos, Parent, IsApplicableTo, F>::value)
161 // just forward non-expressions (no expression interface)
162 || !IsExpression<E>::value
163 // just forward expression terminals (inifinte recursion)
164 || IsSelfExpression<E>::value
165 // just forward placeholders (not constructible here)
166 || IsPlaceholderExpression<E>::value
167 )
168#endif
169 ), int> = 0>
170 constexpr decltype(auto) transform(E&& e, F&& f, Operation&& op = Operation{}, TreePos = TreePos{}, Parent&& = Parent{})
171 {
172 //std::clog << "noTR rvref: " << std::is_rvalue_reference<decltype(e)>::value << std::endl;
173
174 return forwardReturnValue<E>(e);
175 }
176
177 namespace {
178
179 template<class E, class F,
180 class Operation, class TreePos, class Parent,
181 std::size_t... ArgIndex>
182 decltype(auto) transformHelper(E&& e, F&& f, Operation&& op, TreePos, Parent&&, IndexSequence<ArgIndex...>)
183 {
184 static_assert(IsExpression<E>::value && Arity<E>::value == sizeof...(ArgIndex),
185 "Internal error: helper function called with inconsistent arguments.");
186 //std::clog << "helper rvref: " << std::is_rvalue_reference<decltype(e)>::value << std::endl;
187
188 if constexpr (std::is_same<Parent, FalseType>::value) {
189 return
190 std::forward<Operation>(op)(
191 std::forward<E>(e).operation(),
192 transform(
193 std::forward<E>(e).template operand<ArgIndex>(),
194 std::forward<F>(f),
195 std::forward<Operation>(op),
196 AppendTreePos<TreePos, ArgIndex>{},
197 FalseType{}
198 )...
199 );
200 } else {
201 return
202 std::forward<Operation>(op)(
203 std::forward<E>(e).operation(),
204 transform(
205 std::forward<E>(e).template operand<ArgIndex>(),
206 std::forward<F>(f),
207 std::forward<Operation>(op),
208 AppendTreePos<TreePos, ArgIndex>{},
209 std::forward<E>(e)
210 )...
211 );
212 }
213 }
214 }
215
216 namespace {
217
218 template<class E, class F, class Operation, class TreePos, class Parent>
219 constexpr bool doTransformRecurse()
220 {
221 if constexpr (IsTransformInvocable<F, E, TreePos, Parent>::value) {
222 return false;
223 } else if constexpr (!IsExpression<E>::value) {
224 return false;
225 } else if constexpr (IsSelfExpression<E>::value) {
226 return false;
227 } else if constexpr (IsPlaceholderExpression<E>::value) {
228 return false;
229 } else if constexpr (std::is_same<F, FalseType>::value) {
230 return true;
231 } else if constexpr (ExamineTreeOr<E, TreePos, Parent, IsApplicableTo, F>::value) {
232 return true;
233 } else {
234 return false;
235 }
236 }
237
238 } // NS anonymous
239
240 template<
241 class E, class F,
242 class Operation = Operate<OptimizeTop>,
243 class TreePos = NoTreePos,
244 class Parent = NoParent,
245 std::enable_if_t<(
246#if 1
247 doTransformRecurse<E, F, Operation, TreePos, Parent>()
248#else
249 !IsTransformInvocable<F, E, TreePos, Parent>::value
250 && (std::is_same<F, FalseType>::value
251 || ExamineTreeOr<E, TreePos, Parent, IsApplicableTo, F>::value
252 )
253 // We must not try to descend into non-expresssions
254 && IsExpression<E>::value
255 // We must not descend into self expressions as
256 // they are their own operand
257 && !IsSelfExpression<E>::value
258 // We must not descend into placeholders because
259 // we do not know how to reconstruct them.
260 && !IsPlaceholderExpression<E>::value
261#endif
262 ), int> = 0>
263 decltype(auto) transform(E&& e, F&& f, Operation&& op = Operation{}, TreePos = TreePos{}, Parent&& parent = Parent{})
264 {
265 //std::clog << "rec TR rvref: " << std::is_rvalue_reference<decltype(e)>::value << std::endl;
266
267 return transformHelper(
268 std::forward<E>(e),
269 std::forward<F>(f),
270 std::forward<Operation>(op),
271 TreePos{},
272 std::forward<Parent>(parent),
273 MakeIndexSequence<Arity<E>::value>{}
274 );
275 }
276
281 template<class E, class F, class TreePos = NoTreePos, class Parent = NoParent, std::enable_if_t<IsExpression<E>::value, int> = 0>
282 auto traverse(E&& e, F&& f, TreePos = TreePos{}, Parent&& parent = Parent{})
283 {
284 return transform(std::forward<E>(e), std::forward<F>(f), DontOperate{}, TreePos{}, std::forward<Parent>(parent));
285 }
286
290 template<class E, class Optimize = OptimizeTop, class TreePos = IndexSequence<> >
291 auto deepCopy(E&& e, Optimize = Optimize{}, TreePos = TreePos{})
292 {
293 return transform(std::forward<E>(e), FalseType{}, OperateClone<Optimize>{}, TreePos{});
294 }
295
300 template<class T, class...>
302 : BoolConstant<(IsPlaceholderExpression<T>::value
303 || IsIndeterminateExpression<T>::value
304 )>
305 {};
306
319 template<class From, class To,
320 template<class...> class When = std::is_same,
321 template<class...> class Ignore = ReplaceDefaultIgnore>
323 {
324 using FromType = From;
325
326 ReplaceFunctor(To&& to = To{})
327 : to_(std::forward<To>(to))
328 {}
329
330 template<class T,
331 std::enable_if_t<(!When<T, FromType>::value
332 && Ignore<T, FromType>::value
333 ), int> = 0>
334 constexpr decltype(auto) operator()(T&& t) const
335 {
336 return forwardReturnValue<T>(t);
337 }
338
339 template<class T, std::size_t... TreePos,
340 std::enable_if_t<(!When<MPL::TypeTuple<T, IndexSequence<TreePos...> >, FromType>::value
341 && (Ignore<MPL::TypeTuple<T, IndexSequence<TreePos...> >, FromType>::value
342 || Ignore<T, FromType>::value
343 )
344 ), int> = 0>
345 constexpr decltype(auto) operator()(T&& t, IndexSequence<TreePos...>) const
346 {
347 return forwardReturnValue<T>(t);
348 }
349
350 template<class T, class Parent,
351 std::enable_if_t<(!IsSequence<Parent>::value
352 && !When<MPL::TypeTuple<T, Parent>, FromType>::value
353 && (Ignore<MPL::TypeTuple<T, Parent>, FromType>::value
354 || Ignore<T, FromType>::value
355 )
356 ), int> = 0>
357 constexpr decltype(auto) operator()(T&& t, Parent&& parent) const
358 {
359 return forwardReturnValue<T>(t);
360 }
361
362 template<class T, class TreePos, class Parent,
363 std::enable_if_t<(!When<MPL::TypeTuple<T, TreePos, Parent>, FromType>::value
364 && (Ignore<MPL::TypeTuple<T, TreePos, Parent>, FromType>::value
365 || Ignore<MPL::TypeTuple<T, TreePos>, FromType>::value
366 || Ignore<T, FromType>::value
367 )
368 ), int> = 0>
369 constexpr decltype(auto) operator()(T&& t, TreePos, Parent&& parent) const
370 {
371 return forwardReturnValue<T>(t);
372 }
373
374 template<class T, std::enable_if_t<When<T, FromType>::value, int> = 0>
375 constexpr decltype(auto) operator()(T&& t) const
376 {
377 return to_;
378 }
379
380 template<class T, std::size_t... TreePos, std::enable_if_t<When<MPL::TypeTuple<T, IndexSequence<TreePos...> >, FromType>::value, int> = 0>
381 constexpr decltype(auto) operator()(T&& t, IndexSequence<TreePos...>) const
382 {
383 return to_;
384 }
385
386 template<class T, class Parent, std::enable_if_t<!IsIndexSequence<Parent>::value && When<MPL::TypeTuple<T, Parent>, FromType>::value, int> = 0>
387 constexpr decltype(auto) operator()(T&&, Parent&&) const
388 {
389 return to_;
390 }
391
392 template<class T, class TreePos, class Parent, std::enable_if_t<When<MPL::TypeTuple<T, TreePos, Parent>, FromType>::value, int> = 0>
393 constexpr decltype(auto) operator()(T&&, TreePos, Parent&&) const
394 {
395 return to_;
396 }
397
398 To to_;
399 };
400
404 template<class To,
405 template<class...> class When,
406 template<class...> class Ignore = ReplaceDefaultIgnore>
408 : ReplaceFunctor<void, To, PredicateProxy<When>::template ForwardFirst, Ignore>
409 {
410 using ReplaceFunctor<void, To, PredicateProxy<When>::template ForwardFirst, Ignore>::ReplaceFunctor;
411 };
412
417 template<class E, class Dummy, class SFINAE = void>
419 : BoolConstant<(!IsExpression<E>::value
420 || IsSelfExpression<E>::value
421 || ReplaceDefaultIgnore<E>::value)>
422 {};
423
424 template<class E, class Dummy>
425 struct DefaultTerminalPredicate<E, Dummy, std::enable_if_t<MPL::IsTypeTupleV<E> && size<E>() != 0> >
426 : DefaultTerminalPredicate<MPL::TypeTupleElement<0, E>, Dummy>
427 {};
428
432 template<template<class...> class TerminalPredicate = DefaultTerminalPredicate>
434 : ReplaceFunctor<void, int, AlwaysFalse, TerminalPredicate>
435 {};
436
440 template<std::size_t N,
441 template<class...> class When,
442 template<class...> class Ignore = ReplaceDefaultIgnore>
444 {
445 template<class T,
446 std::enable_if_t<(!When<T>::value
447 && Ignore<T, void>::value
448 ), int> = 0>
449 constexpr decltype(auto) operator()(T&& t) const
450 {
451 return std::forward<T>(t);
452 }
453
454 template<class T, class TreePos,
455 std::enable_if_t<(!When<MPL::TypeTuple<T, TreePos> >::value
456 && (Ignore<MPL::TypeTuple<T, TreePos>, void>::value || Ignore<T, void>::value)
457 ), int> = 0>
458 constexpr decltype(auto) operator()(T&& t, TreePos) const
459 {
460 return std::forward<T>(t);
461 }
462
463 template<class T, std::enable_if_t<When<T>::value, int> = 0>
464 constexpr decltype(auto) operator()(T&& t) const
465 {
466 return std::forward<T>(t).template operand<N>();
467 }
468
469 template<class T, class TreePos, std::enable_if_t<When<MPL::TypeTuple<T, TreePos> >::value, int> = 0>
470 constexpr decltype(auto) operator()(T&& t, TreePos) const
471 {
472 return std::forward<T>(t).template operand<N>();
473 }
474 };
475
476 template<
477 class From, class To, class E, class Optimize = OptimizeTop,
478 class TreePos = NoTreePos, class Parent = NoParent>
479 auto replace(E&& e, To&& to, From&& = From(), Optimize = Optimize{}, TreePos = TreePos{}, Parent&& parent = Parent{})
480 {
481 return transform(
482 std::forward<E>(e),
483 ReplaceFunctor<AsExpression<From>, AsExpression<To> >(
484 asExpression(std::forward<To>(to))
485 ),
486 Operate<Optimize>{},
487 TreePos{},
488 std::forward<Parent>(parent));
489 }
490
492 template<std::size_t Id, class To, class E, class Optimize = OptimizeTop,
493 class TreePos = NoTreePos, class Parent = NoParent>
494 decltype(auto) replaceIndeterminate(E&& e, To&& to, IndexConstant<Id> = IndexConstant<Id>{}, Optimize = Optimize{}, TreePos = TreePos{}, Parent&& parent = Parent{})
495 {
496 //std::clog << "replIndet rvref: " << std::is_rvalue_reference<decltype(e)>::value << std::endl;
497
498 return transform(
499 std::forward<E>(e),
500 ReplaceFunctor<IndexConstant<Id>, AsExpression<To>, IndeterminateMatch>(
501 asExpression(std::forward<To>(to))
502 ),
503 Operate<Optimize>{},
504 TreePos{},
505 std::forward<Parent>(parent)
506 );
507 }
508
513 template<template<class...> class Predicate, template<class...> class Ignore,
514 class To, class E,
515 class Optimize = OptimizeTop, class TreePos = NoTreePos, class Parent = NoParent>
516 decltype(auto) replaceMatching(E&& e, To&& to, Optimize = Optimize{}, TreePos = TreePos{}, Parent&& parent = Parent{})
517 {
518 using Replace = ReplaceFunctor<
519 To, To, Predicate, PredicateProxy<Ignore>::template ForwardFirst>;
520
521 return transform(std::forward<E>(e), Replace(std::forward<To>(to)),
522 Operate<Optimize>{}, TreePos{}, std::forward<Parent>(parent));
523 }
524
527 template<template<class...> class Predicate,
528 class To, class E,
529 class Optimize = OptimizeTop, class TreePos = NoTreePos, class Parent = NoParent>
530 decltype(auto) replaceMatching(E&& e, To&& to, Optimize = Optimize{}, TreePos = TreePos{}, Parent&& parent = Parent{})
531 {
532 return replaceMatching<Predicate, AlwaysFalse>(std::forward<E>(e), std::forward<To>(to),
533 Optimize{}, TreePos{}, std::forward<Parent>(parent));
534 }
535
536}
537
538#endif // __DUNE_ACFEM_EXPRESSIONS_TRANSFORM_HH__
constexpr decltype(auto) asExpression(T &&t)
Return a non-closure expression as is.
Definition: interface.hh:122
OptimizeTag< Policy::OptimizationLevelMax::value > OptimizeTop
The top-level optmization tag.
Definition: optimizationbase.hh:59
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
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.
Operation functor which does not operate and collapes the entire expression to a dummy return value o...
Definition: transform.hh:47
Operation functor for transform().
Definition: transform.hh:34
Default operation functor for transform.
Definition: transform.hh:21
Replace matching expressions by their operand no.
Definition: transform.hh:444
Replace all expression operands of type T where When<T, From> is std::true_type by an instance of To.
Definition: transform.hh:323
Variant o ReplaceFunctor where When may be a simple unary IsSomething trait.
Definition: transform.hh:409
Definition: transform.hh:435
Definition: types.hh:279
Wrap the given predicate class F into another one with spcial requirements.
Definition: types.hh:218
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden & Uni Heidelberg  |  generated with Hugo v0.111.3 (Sep 4, 22:38, 2025)