Dune Core Modules (2.9.0)

transformation.hh
1// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2// vi: set et ts=4 sw=2 sts=2:
3
4#ifndef DUNE_TYPETREE_TRANSFORMATION_HH
5#define DUNE_TYPETREE_TRANSFORMATION_HH
6
7#include <array>
8#include <tuple>
9#include <memory>
10#include <utility>
11
12#include <dune/common/hybridutilities.hh>
15#include <dune/typetree/typetraits.hh>
16#include <dune/typetree/nodeinterface.hh>
17#include <dune/typetree/nodetags.hh>
18#include <dune/typetree/utility.hh>
19
20
21namespace Dune {
22 namespace TypeTree {
23
29#ifdef DOXYGEN
30
32
51 template<typename SourceNode, typename Transformation, typename Tag>
52 void registerNodeTransformation(SourceNode*, Transformation*, Tag*);
53
54#else // DOXYGEN
55
66 template<typename S, typename T, typename Tag>
67 struct LookupNodeTransformation
68 {
69
70 typedef decltype(registerNodeTransformation(declptr<S>(),declptr<T>(),declptr<Tag>())) lookup_type;
71
72 typedef typename evaluate_if_meta_function<
73 lookup_type
74 >::type type;
75
76 static_assert((!std::is_same<type,void>::value), "Unable to find valid transformation descriptor");
77 };
78
79#endif // DOXYGEN
80
81
83
92 template<typename SourceTree, typename Transformation, typename Tag = StartTag, bool recursive = true>
94 {
95
96#ifndef DOXYGEN
97
98 typedef typename LookupNodeTransformation<SourceTree,Transformation,typename SourceTree::ImplementationTag>::type NodeTransformation;
99
100 // the type of the new tree that will result from this transformation
101 typedef typename TransformTree<SourceTree,Transformation,NodeTag<SourceTree>,NodeTransformation::recursive>::transformed_type transformed_type;
102
103 // the storage type of the new tree that will result from this transformation
104 typedef typename TransformTree<SourceTree,Transformation,NodeTag<SourceTree>,NodeTransformation::recursive>::transformed_storage_type transformed_storage_type;
105
106#endif // DOXYGEN
107
109 typedef transformed_type type;
110
111 typedef type Type;
112
114 static transformed_type transform(const SourceTree& s, const Transformation& t = Transformation())
115 {
116 return TransformTree<SourceTree,Transformation,NodeTag<SourceTree>,NodeTransformation::recursive>::transform(s,t);
117 }
118
120 static transformed_type transform(const SourceTree& s, Transformation& t)
121 {
122 return TransformTree<SourceTree,Transformation,NodeTag<SourceTree>,NodeTransformation::recursive>::transform(s,t);
123 }
124
126 static transformed_type transform(std::shared_ptr<const SourceTree> sp, const Transformation& t = Transformation())
127 {
128 return TransformTree<SourceTree,Transformation,NodeTag<SourceTree>,NodeTransformation::recursive>::transform(sp,t);
129 }
130
132 static transformed_type transform(std::shared_ptr<const SourceTree> sp, Transformation& t)
133 {
134 return TransformTree<SourceTree,Transformation,NodeTag<SourceTree>,NodeTransformation::recursive>::transform(sp,t);
135 }
136
139 static transformed_storage_type transform_storage(std::shared_ptr<const SourceTree> sp, const Transformation& t = Transformation())
140 {
142 }
143
146 static transformed_storage_type transform_storage(std::shared_ptr<const SourceTree> sp, Transformation& t)
147 {
149 }
150
151
152 };
153
154#ifndef DOXYGEN // internal per-node implementations of the transformation algorithm
155
156 // handle a leaf node - this is easy
157 template<typename S, typename T, bool recursive>
158 struct TransformTree<S,T,LeafNodeTag,recursive>
159 {
160 // get transformed type from specification
161 typedef typename LookupNodeTransformation<S,T,ImplementationTag<S>>::type NodeTransformation;
162
163 typedef typename NodeTransformation::transformed_type transformed_type;
164 typedef typename NodeTransformation::transformed_storage_type transformed_storage_type;
165
166 // delegate instance transformation to per-node specification
167 static transformed_type transform(const S& s, T& t)
168 {
170 }
171
172 // delegate instance transformation to per-node specification
173 static transformed_type transform(const S& s, const T& t)
174 {
176 }
177
178 // delegate instance transformation to per-node specification
179 static transformed_type transform(std::shared_ptr<const S> sp, T& t)
180 {
182 }
183
184 // delegate instance transformation to per-node specification
185 static transformed_type transform(std::shared_ptr<const S> sp, const T& t)
186 {
188 }
189
190 static transformed_storage_type transform_storage(std::shared_ptr<const S> sp, T& t)
191 {
192 return NodeTransformation::transform_storage(sp,t);
193 }
194
195 static transformed_storage_type transform_storage(std::shared_ptr<const S> sp, const T& t)
196 {
197 return NodeTransformation::transform_storage(sp,t);
198 }
199
200 };
201
202
203 // common implementation for non-recursive transformation of non-leaf nodes
204 template<typename S, typename T>
205 struct TransformTreeNonRecursive
206 {
207 // get transformed type from specification
208 typedef typename LookupNodeTransformation<S,T,ImplementationTag<S>>::type NodeTransformation;
209
210 typedef typename NodeTransformation::transformed_type transformed_type;
211 typedef typename NodeTransformation::transformed_storage_type transformed_storage_type;
212
213 // delegate instance transformation to per-node specification
214 static transformed_type transform(const S& s, T& t)
215 {
217 }
218
219 // delegate instance transformation to per-node specification
220 static transformed_type transform(const S& s, const T& t)
221 {
223 }
224
225 // delegate instance transformation to per-node specification
226 static transformed_type transform(std::shared_ptr<const S> sp, T& t)
227 {
229 }
230
231 // delegate instance transformation to per-node specification
232 static transformed_type transform(std::shared_ptr<const S> sp, const T& t)
233 {
235 }
236
237 static transformed_storage_type transform_storage(std::shared_ptr<const S> sp, T& t)
238 {
239 return NodeTransformation::transform_storage(sp,t);
240 }
241
242 static transformed_storage_type transform_storage(std::shared_ptr<const S> sp, const T& t)
243 {
244 return NodeTransformation::transform_storage(sp,t);
245 }
246
247 };
248
249
250 namespace Impl {
251
252 // Helper class to handle recursive power nodes
253 template<class Source, class Transformation, class Tag>
254 class RecursivePowerTransformTree
255 {
256 // We only know two types of tags!
257 static_assert(std::is_same_v<Tag,PowerNodeTag> or std::is_same_v<Tag,DynamicPowerNodeTag>);
258
259 using ChildType = typename Source::ChildType;
260
261 // in case degree is dynamic, provid a vector correctly initialized
262 template<class NodeStorage>
263 static auto node_storage_provider(const std::size_t& degree)
264 {
265 return std::vector<NodeStorage>(degree);
266 }
267
268 // in case degree is static, provid an array
269 template<class NodeStorage, class StaticIndex>
270 static auto node_storage_provider(StaticIndex)
271 {
272 return std::array<NodeStorage,std::size_t(StaticIndex{})>();
273 }
274
275 public:
276 // get transformed type from specification
277 // Handling this transformation in a way that makes the per-node specification easy to write
278 // is a little involved:
279 // The problem is that the transformed power node must be parameterized on the transformed child
280 // type. So we need to transform the child type and pass the transformed child type to an inner
281 // template of the node transformation struct called result (see example of such a specification
282 // further down).
283 using NodeTransformation = typename LookupNodeTransformation<Source,Transformation,ImplementationTag<Source>>::type;
284 using ChildNodeTransformation = typename LookupNodeTransformation<ChildType,Transformation,ImplementationTag<ChildType>>::type;
285
286 private:
287 // Since every child is same type, is enough to get transformation once
288 using ChildTreeTransformation = TransformTree<ChildType,
289 Transformation,
290 NodeTag<ChildType>,
291 ChildNodeTransformation::recursive>;
292
293 // Get transformed type of children
294 using transformed_child_type = typename ChildTreeTransformation::transformed_type;
295 using transformed_child_storage_type = typename ChildTreeTransformation::transformed_storage_type;
296 public:
297 // Apply transformation from children to current node
298 using transformed_type = typename NodeTransformation::template result<transformed_child_type>::type;
299 using transformed_storage_type = typename NodeTransformation::template result<transformed_child_type>::storage_type;
300
301 // Transform an instance of source tree.
302 static transformed_type transform(const Source& source, Transformation& transformation)
303 {
304 auto children_storage = node_storage_provider<std::shared_ptr<transformed_child_type>>(source.degree());
305 for (std::size_t k = 0; k < source.degree(); ++k) {
306 children_storage[k] = ChildTreeTransformation::transform_storage(source.childStorage(k),transformation);
307 }
308 return NodeTransformation::transform(source,transformation,children_storage);
309 }
310
311 // Transform an instance of source tree.
312 static transformed_type transform(const Source& source, const Transformation& transformation)
313 {
314 auto children_storage = node_storage_provider<std::shared_ptr<transformed_child_type>>(source.degree());
315 for (std::size_t k = 0; k < source.degree(); ++k) {
316 children_storage[k] = ChildTreeTransformation::transform_storage(source.childStorage(k),transformation);
317 }
318 return NodeTransformation::transform(source,transformation,children_storage);
319 }
320
321 // Transform an instance of source tree.
322 static transformed_type transform(std::shared_ptr<const Source> source_ptr, Transformation& transformation)
323 {
324 auto children_storage = node_storage_provider<std::shared_ptr<transformed_child_type>>(source_ptr->degree());
325 for (std::size_t k = 0; k < source_ptr->degree(); ++k) {
326 children_storage[k] = ChildTreeTransformation::transform_storage(source_ptr->childStorage(k),transformation);
327 }
328 return NodeTransformation::transform(source_ptr,transformation,children_storage);
329 }
330
331 // Transform an instance of source tree.
332 static transformed_type transform(std::shared_ptr<const Source> source_ptr, const Transformation& transformation)
333 {
334 auto children_storage = node_storage_provider<std::shared_ptr<transformed_child_type>>(source_ptr->degree());
335 for (std::size_t k = 0; k < source_ptr->degree(); ++k) {
336 children_storage[k] = ChildTreeTransformation::transform_storage(source_ptr->childStorage(k),transformation);
337 }
338 return NodeTransformation::transform(source_ptr,transformation,children_storage);
339 }
340
341 // Transform an instance of source tree ptr.
342 static transformed_storage_type transform_storage(std::shared_ptr<const Source> source_ptr, Transformation& transformation)
343 {
344 auto children_storage = node_storage_provider<transformed_child_storage_type>(source_ptr->degree());
345 for (std::size_t k = 0; k < source_ptr->degree(); ++k) {
346 children_storage[k] = ChildTreeTransformation::transform_storage(source_ptr->childStorage(k),transformation);
347 }
348 return NodeTransformation::transform_storage(source_ptr,transformation,children_storage);
349 }
350
351 // Transform an instance of source tree ptr.
352 static transformed_storage_type transform_storage(std::shared_ptr<const Source> source_ptr, const Transformation& transformation)
353 {
354 auto children_storage = node_storage_provider<transformed_child_storage_type>(source_ptr->degree());
355 for (std::size_t k = 0; k < source_ptr->degree(); ++k) {
356 children_storage[k] = ChildTreeTransformation::transform_storage(source_ptr->childStorage(k),transformation);
357 }
358 return NodeTransformation::transform_storage(source_ptr,transformation,children_storage);
359 }
360
361 };
362 } // namespace Impl
363
364 // Recursive version of the PowerNode transformation for static nodes.
365 template<typename Source, typename Transformation>
366 struct TransformTree<Source,Transformation,PowerNodeTag,true>
367 : public Impl::RecursivePowerTransformTree<Source,Transformation,PowerNodeTag>
368 {};
369
370 // Recursive version of the DynamicPowerNode transformation for static nodes.
371 template<typename Source, typename Transformation>
372 struct TransformTree<Source,Transformation,DynamicPowerNodeTag,true>
373 : public Impl::RecursivePowerTransformTree<Source,Transformation,DynamicPowerNodeTag>
374 {};
375
376 // non-recursive version of the PowerNode transformation.
377 template<typename S, typename T>
378 struct TransformTree<S,T,PowerNodeTag,false>
379 : public TransformTreeNonRecursive<S,T>
380 {};
381
382 // non-recursive version of the DynamicPowerNodeTag transformation.
383 template<typename S, typename T>
384 struct TransformTree<S,T,DynamicPowerNodeTag,false>
385 : public TransformTreeNonRecursive<S,T>
386 {};
387
388 // helper struct that does the actual transformation for a composite node. We need this additional struct
389 // to extract the template argument list with the types of all children from the node, which we cannot do
390 // directly in the transformation<> template, as the type passed to transformation<> will usually be a
391 // derived type and will normally have more template arguments than just the children. This declaration
392 // just introduces the type of the helper struct, we always instantiate the specialization defined below;
393 template<typename S, typename Children, typename T>
394 struct transform_composite_node;
395
396 // specialized version of the helper struct which extracts the template argument list with the children from
397 // its second template parameter, which has to be CompositeNode::ChildTypes. Apart from that, the struct is
398 // similar to the one for a PowerNode, but it obviously delegates transformation of the children to the TMP.
399 template<typename S, typename T, typename... C>
400 struct transform_composite_node<S,std::tuple<C...>,T>
401 {
402
403 // transformed type, using the same nested struct trick as the PowerNode
404 typedef ImplementationTag<S> Tag;
405 typedef typename LookupNodeTransformation<S,T,Tag>::type NodeTransformation;
406 typedef typename NodeTransformation::template result<typename TransformTree<C,
407 T,
408 NodeTag<C>,
409 LookupNodeTransformation<C,T,ImplementationTag<C>>::type::recursive
410 >::transformed_type...
411 >::type transformed_type;
412
413 typedef typename NodeTransformation::template result<typename TransformTree<C,
414 T,
415 NodeTag<C>,
416 LookupNodeTransformation<C,T,ImplementationTag<C>>::type::recursive
417 >::transformed_type...
418 >::storage_type transformed_storage_type;
419
420 // Retrieve the transformation descriptor for the child with index i.
421 // This little helper improves really improves the readability of the
422 // transformation functions.
423 template<std::size_t i>
424 struct ChildTransformation
425 : public TransformTree<typename S::template Child<i>::Type,
426 T,
427 NodeTag<typename S::template Child<i>::Type>,
428 LookupNodeTransformation<
429 typename S::template Child<i>::Type,
430 T,
431 ImplementationTag<typename S::template Child<i>::Type>
432 >::type::recursive
433 >
434 {};
435
436 template<std::size_t i, typename Tuple, typename Value>
437 static void setElement(Tuple& tuple, Value&& value)
438 {
439 std::get<i>(tuple) = std::forward<Value>(value);
440 }
441
442 template<typename Trafo, std::size_t... i>
443 static transformed_type transform(const S& s, Trafo&& t, std::index_sequence<i...> indices)
444 {
445 std::tuple<typename ChildTransformation<i>::transformed_storage_type...> storage;
446 Dune::Hybrid::Impl::evaluateFoldExpression<int>({(setElement<i>(storage, ChildTransformation<i>::transform_storage(s.template childStorage<i>(), std::forward<Trafo>(t))),0)...});
447 return NodeTransformation::transform(s, std::forward<Trafo>(t), std::get<i>(storage)...);
448 }
449
450 template<typename Trafo, std::size_t... i>
451 static transformed_storage_type transform_storage(std::shared_ptr<const S> sp, Trafo&& t, std::index_sequence<i...> indices)
452 {
453 std::tuple<typename ChildTransformation<i>::transformed_storage_type...> storage;
454 Dune::Hybrid::Impl::evaluateFoldExpression<int>({(setElement<i>(storage, ChildTransformation<i>::transform_storage(sp->template childStorage<i>(), std::forward<Trafo>(t))),0)...});
455 return NodeTransformation::transform_storage(sp, std::forward<Trafo>(t), std::get<i>(storage)...);
456 }
457 };
458
459
460 // the specialization of transformation<> for the CompositeNode. This just extracts the
461 // CompositeNode::ChildTypes member and forwards to the helper struct
462 template<typename S, typename T>
463 struct TransformTree<S,T,CompositeNodeTag,true>
464 {
465
466 private:
467
468 typedef typename S::ChildTypes ChildTypes;
469
470 static auto child_indices()
471 {
472 return std::make_index_sequence<S::degree()>();
473 }
474
475 public:
476
477 typedef typename transform_composite_node<S,ChildTypes,T>::transformed_type transformed_type;
478 typedef typename transform_composite_node<S,ChildTypes,T>::transformed_storage_type transformed_storage_type;
479
480 static transformed_type transform(const S& s, T& t)
481 {
482 return transform_composite_node<S,ChildTypes,T>::transform(s,t,child_indices());
483 }
484
485 static transformed_type transform(const S& s, const T& t)
486 {
487 return transform_composite_node<S,ChildTypes,T>::transform(s,t,child_indices());
488 }
489
490 static transformed_storage_type transform_storage(std::shared_ptr<const S> sp, T& t)
491 {
492 return transform_composite_node<S,ChildTypes,T>::transform_storage(sp,t,child_indices());
493 }
494
495 static transformed_storage_type transform_storage(std::shared_ptr<const S> sp, const T& t)
496 {
497 return transform_composite_node<S,ChildTypes,T>::transform_storage(sp,t,child_indices());
498 }
499
500 };
501
502 // non-recursive version of the CompositeNode transformation.
503 template<typename S, typename T>
504 struct TransformTree<S,T,CompositeNodeTag,false>
505 : public TransformTreeNonRecursive<S,T>
506 {};
507
508#endif // DOXYGEN
509
511
512 } // namespace TypeTree
513} //namespace Dune
514
515#endif // DUNE_TYPETREE_TRANSFORMATION_HH
A few common exception classes.
Traits for type conversions and type information.
std::size_t degree(const Node &node)
Returns the degree of node as run time information.
Definition: nodeinterface.hh:85
void registerNodeTransformation(SourceNode *, Transformation *, Tag *)
Register transformation descriptor to transform SourceNode with Transformation.
Dune namespace.
Definition: alignedallocator.hh:13
std::vector< decltype(std::declval< Op >()(std::declval< T >())) > transform(const std::vector< T > &in, Op op)
copy a vector, performing an operation on each element
Definition: misc.hh:24
STL namespace.
Transform a TypeTree.
Definition: transformation.hh:94
static transformed_type transform(std::shared_ptr< const SourceTree > sp, Transformation &t)
Apply transformation to an existing tree s.
Definition: transformation.hh:132
static transformed_type transform(std::shared_ptr< const SourceTree > sp, const Transformation &t=Transformation())
Apply transformation to an existing tree s.
Definition: transformation.hh:126
static transformed_type transform(const SourceTree &s, Transformation &t)
Apply transformation to an existing tree s.
Definition: transformation.hh:120
transformed_type type
The type of the transformed tree.
Definition: transformation.hh:109
static transformed_type transform(const SourceTree &s, const Transformation &t=Transformation())
Apply transformation to an existing tree s.
Definition: transformation.hh:114
static transformed_storage_type transform_storage(std::shared_ptr< const SourceTree > sp, const Transformation &t=Transformation())
Definition: transformation.hh:139
static transformed_storage_type transform_storage(std::shared_ptr< const SourceTree > sp, Transformation &t)
Definition: transformation.hh:146
Meta function that evaluates its argument iff it inherits from meta_function.
Definition: typetraits.hh:140
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden  |  generated with Hugo v0.111.3 (Jul 15, 22:36, 2024)