dune-typetree  2.7.1
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 #include <utility>
11 
12 #include <dune/common/exceptions.hh>
13 #include <dune/common/typetraits.hh>
17 #include <dune/typetree/utility.hh>
18 
19 
20 namespace 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  {
140  return TransformTree<SourceTree,Transformation,NodeTag<SourceTree>,NodeTransformation::recursive>::transform_storage(sp,t);
141  }
142 
145  static transformed_storage_type transform_storage(std::shared_ptr<const SourceTree> sp, Transformation& t)
146  {
147  return TransformTree<SourceTree,Transformation,NodeTag<SourceTree>,NodeTransformation::recursive>::transform_storage(sp,t);
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
Dune::TypeTree::TransformTree::transform_storage
static transformed_storage_type transform_storage(std::shared_ptr< const SourceTree > sp, const Transformation &t=Transformation())
Definition: transformation.hh:138
typetraits.hh
utility.hh
Dune::TypeTree::TransformTree::transform
static transformed_type transform(const SourceTree &s, const Transformation &t=Transformation())
Apply transformation to an existing tree s.
Definition: transformation.hh:113
Dune::TypeTree::registerNodeTransformation
void registerNodeTransformation(SourceNode *, Transformation *, Tag *)
Register transformation descriptor to transform SourceNode with Transformation.
nodetags.hh
Dune::TypeTree::TransformTree::transform
static transformed_type transform(std::shared_ptr< const SourceTree > sp, Transformation &t)
Apply transformation to an existing tree s.
Definition: transformation.hh:131
Dune::TypeTree::TransformTree::transform
static transformed_type transform(const SourceTree &s, Transformation &t)
Apply transformation to an existing tree s.
Definition: transformation.hh:119
Dune::TypeTree::TransformTree::transform_storage
static transformed_storage_type transform_storage(std::shared_ptr< const SourceTree > sp, Transformation &t)
Definition: transformation.hh:145
Dune::TypeTree::TransformTree::transform
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
Dune::TypeTree::TransformTree
Transform a TypeTree.
Definition: transformation.hh:92
result
static const result_type result
Definition: accumulate_static.hh:110
nodeinterface.hh
Dune
Definition: accumulate_static.hh:13
Dune::TypeTree::TransformTree::type
transformed_type type
The type of the transformed tree.
Definition: transformation.hh:108
Dune::TypeTree::TransformTree::Type
type Type
Definition: transformation.hh:110