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