dune-typetree  2.5.0
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>
16 #include <dune/typetree/utility.hh>
17 
18 
19 namespace 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  {
139  return TransformTree<SourceTree,Transformation,NodeTag<SourceTree>,NodeTransformation::recursive>::transform_storage(sp,t);
140  }
141 
144  static transformed_storage_type transform_storage(std::shared_ptr<const SourceTree> sp, Transformation& t)
145  {
146  return TransformTree<SourceTree,Transformation,NodeTag<SourceTree>,NodeTransformation::recursive>::transform_storage(sp,t);
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,
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 transformed_type transform(std::shared_ptr< const SourceTree > sp, const Transformation &t=Transformation())
Apply transformation to an existing tree s.
Definition: transformation.hh:124
Simple holder class for a template argument pack of indices.
Definition: utility.hh:207
static transformed_type transform(const SourceTree &s, const Transformation &t=Transformation())
Apply transformation to an existing tree s.
Definition: transformation.hh:112
typename std::decay_t< T >::ImplementationTag ImplementationTag
Returns the implementation tag of the given Node.
Definition: nodeinterface.hh:66
static transformed_type transform(const SourceTree &s, Transformation &t)
Apply transformation to an existing tree s.
Definition: transformation.hh:118
index_pack< 0, 1,..., n-1 > type
Result.
Definition: utility.hh:217
Definition: accumulate_static.hh:13
transformed_type type
The type of the transformed tree.
Definition: transformation.hh:107
type Type
Definition: transformation.hh:109
STL namespace.
static transformed_storage_type transform_storage(std::shared_ptr< const SourceTree > sp, Transformation &t)
Definition: transformation.hh:144
static const result_type result
Definition: accumulate_static.hh:110
Transform a TypeTree.
Definition: transformation.hh:91
std::integral_constant< std::size_t, degree(static_cast< std::decay_t< Node > * >(nullptr), NodeTag< std::decay_t< Node > >()) > StaticDegree
Returns the statically known degree of the given Node type as a std::integral_constant.
Definition: nodeinterface.hh:105
static transformed_type transform(std::shared_ptr< const SourceTree > sp, Transformation &t)
Apply transformation to an existing tree s.
Definition: transformation.hh:130
typename std::decay_t< Node >::NodeTag NodeTag
Returns the node tag of the given Node.
Definition: nodeinterface.hh:62
void registerNodeTransformation(SourceNode *, Transformation *, Tag *)
Register transformation descriptor to transform SourceNode with Transformation.
static transformed_storage_type transform_storage(std::shared_ptr< const SourceTree > sp, const Transformation &t=Transformation())
Definition: transformation.hh:137