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