DUNE PDELab (2.7)

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