Dune Core Modules (2.9.0)

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