"Fossies" - the Fresh Open Source Software Archive 
Member "dune-typetree-2.8.0/dune/typetree/transformation.hh" (31 Aug 2021, 23610 Bytes) of package /linux/misc/dune/dune-typetree-2.8.0.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "transformation.hh" see the
Fossies "Dox" file reference documentation and the last
Fossies "Diffs" side-by-side code changes report:
2.8.0_vs_2.9.0.
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>
13 #include <dune/common/exceptions.hh>
14 #include <dune/common/typetraits.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
21 namespace Dune {
22 namespace TypeTree {
23
24 /** \addtogroup Transformation
25 * \ingroup TypeTree
26 * \{
27 */
28
29 #ifdef DOXYGEN
30
31 //! Register transformation descriptor to transform SourceNode with Transformation.
32 /**
33 * The tree transformation engine expects this function to return a struct describing
34 * how to perform the Transformation for the type SourceNode, which has ImplementationTag Tag.
35 * This function has to be specialized for every combination of Transformation and Tag that
36 * the transformation engine should support.
37 *
38 * \note The arguments are given as pointers to avoid problems with incomplete types.
39 *
40 * \note The specialization does not have to placed in the namespace Dune::TypeTree,
41 * it can simply reside in the same namespace as either the SourceNode or the Tag.
42 *
43 * \note This function will never be really called, the engine only extracts the return type.
44 * It is thus not necessary to actually implement the function, it is sufficient to
45 * declare it.
46 *
47 * \tparam SourceNode The type of the node in the source tree that should be transformed.
48 * \tparam Transformation The type of the transformation to apply to the source node.
49 * \tparam Tag The implementation tag of the source node.
50 */
51 template<typename SourceNode, typename Transformation, typename Tag>
52 void registerNodeTransformation(SourceNode*, Transformation*, Tag*);
53
54 #else // DOXYGEN
55
56 /**
57 * \tparam S C++ type of source node.
58 * \tparam T Tag identifying the transformation.
59 * \tparam Tag Tag identifying the source type.
60 *
61 * Tag may be identical for different implementation of the same concept
62 * (i.e. all leaf GridFunctionSpace), but this is not required. This
63 * allows you to handle different leaf GridFunctionSpace implementation
64 * differently. Tag should be extracted from S::ImplementationTag.
65 */
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
82 //! Transform a TypeTree.
83 /**
84 * This struct can be used to apply a transformation to a given TypeTree. It exports the type of
85 * the resulting (transformed) tree and contains methods to actually transform tree instances.
86 *
87 * \tparam SourceTree = The TypeTree that should be transformed.
88 * \tparam Transformation = The Transformation to apply to the TypeTree.
89 * \tparam Tag = This parameter is an implementation detail and must always be set to its default value.
90 * \tparam recursive = This parameter is an implementation detail and must always be set to its default value.
91 */
92 template<typename SourceTree, typename Transformation, typename Tag = StartTag, bool recursive = true>
93 struct TransformTree
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
108 //! The type of the transformed tree.
109 typedef transformed_type type;
110
111 typedef type Type;
112
113 //! Apply transformation to an existing tree s.
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
119 //! Apply transformation to an existing tree s.
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
125 //! Apply transformation to an existing tree s.
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
131 //! Apply transformation to an existing tree s.
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
137 //! Apply transformation to storage type of an existing tree, returning a heap-allocated storage type
138 //! instance of the transformed tree.
139 static transformed_storage_type transform_storage(std::shared_ptr<const SourceTree> sp, const Transformation& t = Transformation())
140 {
141 return TransformTree<SourceTree,Transformation,NodeTag<SourceTree>,NodeTransformation::recursive>::transform_storage(sp,t);
142 }
143
144 //! Apply transformation to storage type of an existing tree, returning a heap-allocated storage type
145 //! instance of the transformed tree.
146 static transformed_storage_type transform_storage(std::shared_ptr<const SourceTree> sp, Transformation& t)
147 {
148 return TransformTree<SourceTree,Transformation,NodeTag<SourceTree>,NodeTransformation::recursive>::transform_storage(sp,t);
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 {
169 return NodeTransformation::transform(s,t);
170 }
171
172 // delegate instance transformation to per-node specification
173 static transformed_type transform(const S& s, const T& t)
174 {
175 return NodeTransformation::transform(s,t);
176 }
177
178 // delegate instance transformation to per-node specification
179 static transformed_type transform(std::shared_ptr<const S> sp, T& t)
180 {
181 return NodeTransformation::transform(sp,t);
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 {
187 return NodeTransformation::transform(sp,t);
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 {
216 return NodeTransformation::transform(s,t);
217 }
218
219 // delegate instance transformation to per-node specification
220 static transformed_type transform(const S& s, const T& t)
221 {
222 return NodeTransformation::transform(s,t);
223 }
224
225 // delegate instance transformation to per-node specification
226 static transformed_type transform(std::shared_ptr<const S> sp, T& t)
227 {
228 return NodeTransformation::transform(sp,t);
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 {
234 return NodeTransformation::transform(sp,t);
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::CHILDREN>();
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
510 //! \} group Traversal
511
512 } // namespace TypeTree
513 } //namespace Dune
514
515 #endif // DUNE_TYPETREE_TRANSFORMATION_HH