dune-typetree  2.4-dev
childextraction.hh
Go to the documentation of this file.
1 // -*- tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 // vi: set et ts=8 sw=2 sts=2:
3 
4 #ifndef DUNE_TYPETREE_CHILDEXTRACTION_HH
5 #define DUNE_TYPETREE_CHILDEXTRACTION_HH
6 
7 #include <dune/common/documentation.hh>
8 #include <dune/common/typetraits.hh>
9 #include <dune/common/shared_ptr.hh>
10 
12 
13 
14 namespace Dune {
15  namespace TypeTree {
16 
17 
22 
24 
28  template<typename Node, typename TreePath>
30  {
31 
33  typedef typename extract_child_type<
37 
39  typedef typename extract_child_type<
43 
45  typedef typename extract_child_type<
49 
50 
51  };
52 
53 #ifndef DOXYGEN
54 
55  // end of recursion
56  template<typename Node>
57  struct extract_child_type<Node,TypeTree::TreePath<> >
58  {
59  typedef Node type;
60  typedef shared_ptr<Node> storage_type;
61  typedef shared_ptr<const Node> const_storage_type;
62  };
63 
64 #endif // DOXYGEN
65 
66 
67 
68 #ifdef DOXYGEN
69 
71 
98  template<typename Node, typename TreePath>
99  ImplementationDefined& extract_child(Node& node, Treepath tp)
100  {}
101 
103 
130  template<typename Node, typename TreePath>
131  const ImplementationDefined& extract_child(const Node& node, Treepath tp)
132  {}
133 
134 #else // DOXYGEN
135 
136  // ********************************************************************************
137  // non-const implementation
138  // ********************************************************************************
139 
140  template<typename Node, typename TreePath>
141  typename enable_if<
143  typename extract_child_type<Node,TreePath>::type&
144  >::type
145  extract_child(Node& node, TreePath tp)
146  {
149  }
150 
151  template<typename Node, typename TreePath>
152  typename enable_if<
153  TypeTree::TreePathSize<TreePath>::value == 1,
154  typename Node::template Child<TypeTree::TreePathFront<TreePath>::value>::Type&
155  >::type
156  extract_child(Node& node, TreePath tp)
157  {
158  return node.template child<TypeTree::TreePathFront<TreePath>::value>();
159  }
160 
161  template<typename Node, typename TreePath>
162  typename enable_if<
163  TypeTree::TreePathSize<TreePath>::value == 0,
164  Node&
165  >::type
166  extract_child(Node& node, TreePath tp)
167  {
168  return node;
169  }
170 
171  // ********************************************************************************
172  // const implementation
173  // ********************************************************************************
174 
175  template<typename Node, typename TreePath>
176  typename enable_if<
177  (TypeTree::TreePathSize<TreePath>::value > 1),
178  const typename extract_child_type<Node,TreePath>::type&
179  >::type
180  extract_child(const Node& node, TreePath tp)
181  {
182  return extract_child(node.template child<TypeTree::TreePathFront<TreePath>::value>(),
183  typename TypeTree::TreePathPopFront<TreePath>::type());
184  }
185 
186  template<typename Node, typename TreePath>
187  typename enable_if<
188  TypeTree::TreePathSize<TreePath>::value == 1,
189  const typename Node::template Child<TypeTree::TreePathFront<TreePath>::value>::Type&
190  >::type
191  extract_child(const Node& node, TreePath tp)
192  {
193  return node.template child<TypeTree::TreePathFront<TreePath>::value>();
194  }
195 
196  template<typename Node, typename TreePath>
197  typename enable_if<
198  TypeTree::TreePathSize<TreePath>::value == 0,
199  const Node&
200  >::type
201  extract_child(const Node& node, TreePath tp)
202  {
203  return node;
204  }
205 
206 
207 #endif // DOXYGEN
208 
209 
210 
211 #ifdef DOXYGEN
212 
215 
238  template<typename Node, typename TreePath>
239  ImplementationDefined extract_child_storage(Node& node, Treepath tp)
240  {}
241 
244 
267  template<typename Node, typename TreePath>
268  ImplementationDefined extract_child_storage(const Node& node, Treepath tp)
269  {}
270 
271 #else // DOXYGEN
272 
273  // ********************************************************************************
274  // non-const implementation
275  // ********************************************************************************
276 
277  template<typename Node, typename TreePath>
278  typename enable_if<
279  (TypeTree::TreePathSize<TreePath>::value > 1),
280  typename extract_child_type<Node,TreePath>::storage_type
281  >::type
282  extract_child_storage(Node& node, TreePath tp)
283  {
286  }
287 
288  template<typename Node, typename TreePath>
289  typename enable_if<
290  TypeTree::TreePathSize<TreePath>::value == 1,
291  typename Node::template Child<TypeTree::TreePathFront<TreePath>::value>::Storage&
292  >::type
293  extract_child_storage(Node& node, TreePath tp)
294  {
295  return node.template childStorage<TypeTree::TreePathFront<TreePath>::value>();
296  }
297 
298  template<typename Node, typename TreePath>
299  typename enable_if<
300  TypeTree::TreePathSize<TreePath>::value == 0
301  >::type
302  extract_child_storage(Node& node, TreePath tp)
303  {
304  static_assert((Dune::AlwaysFalse<Node>::value),
305  "extract_child_storage only works for real children, not the node itself.");
306  }
307 
308  // ********************************************************************************
309  // const implementation
310  // ********************************************************************************
311 
312  template<typename Node, typename TreePath>
313  typename enable_if<
314  (TypeTree::TreePathSize<TreePath>::value > 1),
315  typename extract_child_type<Node,TreePath>::const_storage_type
316  >::type
317  extract_child_storage(const Node& node, TreePath tp)
318  {
319  return extract_child_storage(node.template child<TypeTree::TreePathFront<TreePath>::value>(),
320  typename TypeTree::TreePathPopFront<TreePath>::type());
321  }
322 
323  template<typename Node, typename TreePath>
324  typename enable_if<
325  TypeTree::TreePathSize<TreePath>::value == 1,
326  typename Node::template Child<TypeTree::TreePathFront<TreePath>::value>::ConstStorage
327  >::type
328  extract_child_storage(const Node& node, TreePath tp)
329  {
330  return node.template childStorage<TypeTree::TreePathFront<TreePath>::value>();
331  }
332 
333  template<typename Node, typename TreePath>
334  typename enable_if<
335  TypeTree::TreePathSize<TreePath>::value == 0
336  >::type
337  extract_child_storage(const Node& node, TreePath tp)
338  {
339  static_assert((Dune::AlwaysFalse<Node>::value),
340  "extract_child_storage only works for real children, not the node itself.");
341  }
342 
343 
344  namespace impl {
345 
346  // ********************************************************************************
347  // end of the recursion, there are no child indices, so just return the node itself
348  // ********************************************************************************
349 
350  template<typename Node>
351  auto child(Node&& node) -> decltype(std::forward<Node>(node))
352  {
353  return std::forward<Node>(node);
354  }
355 
356  // ********************************************************************************
357  // next index is a compile-time constant
358  // ********************************************************************************
359 
360  // we need a little helper trait to make sure that the node has a templated child()
361  // method
362  template<typename Node, typename _ = decltype(std::declval<Node>().template child<0>())>
363  static constexpr auto _has_template_child_method(Node*) -> std::true_type;
364 
365  template<typename Node>
366  static constexpr auto _has_template_child_method(void*) -> std::false_type;
367 
368  // This struct lazily evaluates the return type by recursively calling child. This has
369  // to happen lazily because we only want to do it if the child access at the current
370  // level succeeds; otherwise, we would swamp the user with error messages as the algorithm
371  // walks down the remaining indices
372  //
373  // This struct gets created inside an enable_if, but the nested alias template that triggers
374  // the recursion is only instantiated if the enable_if was successful.
375  template<typename Node>
376  struct _lazy_static_decltype
377  {
378  template<typename I, typename... J>
379  struct evaluate
380  {
381  using type = decltype(child(std::declval<Node>().template child<I::value>(),std::declval<J>()...));
382  };
383  };
384 
385  // The actual implementation is rather simple, we just use an overload that requires the first index
386  // to be an index_constant, get the child and then recurse.
387  // It only gets ugly due to the enable_if, but without that trick, the error messages for the user
388  // can get *very* obscure (they are bad enough as it is, concepts where are you?).
389  template<typename Node, std::size_t i, typename... J>
390  auto child(Node&& node, index_constant<i>, J... j) ->
391  typename std::enable_if<
392  decltype(_has_template_child_method(std::declval<typename std::remove_reference<Node>::type*>()))::value &&
393  (i < std::decay<Node>::type::CHILDREN),
394  _lazy_static_decltype<
395  typename std::remove_reference<Node>::type
396  >
397  >::type::template evaluate<index_constant<i>,J...>::type
398  {
399  return child(std::forward<Node>(node).template child<i>(),j...);
400  }
401 
402  // ********************************************************************************
403  // next index is a run-time value
404  // ********************************************************************************
405 
406 
407  // again, a lazy struct for the recursion to further child nodes (see above for further explanation)
408  template<typename Node>
409  struct _lazy_dynamic_decltype
410  {
411  template<typename... J>
412  struct evaluate
413  {
414  using type = decltype(child(std::declval<Node>().child(0),std::declval<J>()...));
415  };
416  };
417 
418  // The actual implemention here overloads on std::size_t. It is a little less ugly because it currently
419  // has a hard requirement on the PowerNode Tag (although only using is_convertible, as tags can be
420  // inherited (important!).
421  template<typename Node, typename... J>
422  auto child(Node&& node, std::size_t i, J... j) ->
423  typename std::enable_if<
424  std::is_convertible<
425  typename std::remove_reference<Node>::type::NodeTag,
426  PowerNodeTag
427  >::value,
428  _lazy_dynamic_decltype<
429  typename std::remove_reference<Node>::type
430  >
431  >::type::template evaluate<J...>::type
432  {
433  return child(std::forward<Node>(node).template child(i),j...);
434  }
435 
436  template<typename Node, typename... Indices, std::size_t... i>
437  auto child(Node&& node, HybridTreePath<Indices...> tp, Std::index_sequence<i...>) -> decltype(child(std::forward<Node>(node),treePathEntry<i>(tp)...))
438  {
439  return child(std::forward<Node>(node),treePathEntry<i>(tp)...);
440  }
441 
442 
443  } // namespace imp
444 
445 #endif // DOXYGEN
446 
448 
470  template<typename Node, typename... Indices>
471 #ifdef DOXYGEN
472  ImplementationDefined child(Node&& node, Indices... indices)
473 #else
474  auto child(Node&& node, Indices... indices) -> decltype(impl::child(std::forward<Node>(node),indices...))
475 #endif
476  {
477  return impl::child(std::forward<Node>(node),indices...);
478  }
479 
480 
482 
500  template<typename Node, std::size_t... Indices>
501 #ifdef DOXYGEN
502  ImplementationDefined child(Node&& node, TreePath<Indices...> treePath)
503 #else
504  auto child(Node&& node, TreePath<Indices...>) -> decltype(child(std::forward<Node>(node),index_constant<Indices>()...))
505 #endif
506  {
507  return child(std::forward<Node>(node),index_constant<Indices>{}...);
508  }
509 
510 
512 
535  template<typename Node, typename... Indices>
536 #ifdef DOXYGEN
537  ImplementationDefined child(Node&& node, HybridTreePath<Indices...> treePath)
538 #else
539  auto child(Node&& node, HybridTreePath<Indices...> tp) -> decltype(impl::child(std::forward<Node>(node),tp,tp.enumerate()))
540 #endif
541  {
542  return impl::child(std::forward<Node>(node),tp,Std::index_sequence_for<Indices...>{});
543  }
544 
545 #ifndef DOXYGEN
546 
547  namespace impl {
548 
549  template<typename Node, std::size_t... indices>
550  struct _Child
551  {
552  using type = typename std::decay<decltype(child(std::declval<Node>(),index_constant<indices>{}...))>::type;
553  };
554 
555  }
556 
557 #endif // DOXYGEN
558 
560 
567  template<typename Node, std::size_t... indices>
568  using Child = typename impl::_Child<Node,indices...>::type;
569 
570 
571 #ifndef DOXYGEN
572 
573  namespace impl {
574 
575  template<typename Node, typename TreePath>
576  struct _ChildForTreePath
577  {
578  using type = typename std::decay<decltype(child(std::declval<Node>(),std::declval<TreePath>()))>::type;
579  };
580 
581  }
582 
583 #endif // DOXYGEN
584 
586 
594  template<typename Node, typename TreePath>
595  using ChildForTreePath = typename impl::_ChildForTreePath<Node,TreePath>::type;
596 
597 
598 #ifndef DOXYGEN
599 
600  namespace impl {
601 
602  // By default, types are flat indices if they are integral
603  template<typename T>
604  struct _is_flat_index
605  {
606  using type = std::is_integral<T>;
607  };
608 
609  // And so is any index_constant
610  template<std::size_t i>
611  struct _is_flat_index<index_constant<i>>
612  {
613  using type = std::true_type;
614  };
615 
616  }
617 
618 #endif // DOXYGEN
619 
621  /*
622  * This type trait can be used to check whether T is a flat index (i.e. either `std::size_t`
623  * or `index_constant`). The type trait normalizes T before doing the check, so it will also
624  * work correctly for references and cv-qualified types.
625  */
626  template<typename T>
627  using is_flat_index = typename impl::_is_flat_index<typename std::decay<T>::type>::type;
628 
629 #ifndef DOXYGEN
630 
631  namespace impl {
632 
633  // helper struct to perform lazy return type evaluation in the forwarding member child() methods
634  // of nodes
635  template<typename Node>
636  struct _lazy_member_child_decltype
637  {
638  template<typename... Indices>
639  struct evaluate
640  {
641  using type = decltype(Dune::TypeTree::child(std::declval<Node>(),std::declval<Indices>()...));
642  };
643  };
644 
645  // helper function for check in member child() functions that tolerates being passed something that
646  // isn't a TreePath. It will just return 0 in that case
647 
648  template<typename T>
649  constexpr typename std::enable_if<
651  bool
652  >::type
653  _non_empty_tree_path(T)
654  {
655  return false;
656  }
657 
658  template<typename T>
659  constexpr typename std::enable_if<
660  !is_flat_index<T>{},
661  bool
662  >::type
663  _non_empty_tree_path(T t)
664  {
665  return treePathSize(t) > 0;
666  }
667 
668  }
669 
670 #endif // DOXYGEN
671 
673 
674  } // namespace TypeTree
675 } //namespace Dune
676 
677 #endif // DUNE_TYPETREE_CHILDEXTRACTION_HH
extract_child_type< typename Node::template Child< TypeTree::TreePathFront< TreePath >::value >::Type, typename TypeTree::TreePathPopFront< TreePath >::type >::type type
The type of the child.
Definition: childextraction.hh:36
ImplementationDefined & extract_child(Node &node, Treepath tp)
Extract the child of a node located at tp (non-const version).
Definition: childextraction.hh:99
Definition: treepath.hh:94
Definition: treepath.hh:119
Definition: accumulate_static.hh:12
Definition: treepath.hh:42
extract_child_type< typename Node::template Child< TypeTree::TreePathFront< TreePath >::value >::Type, typename TypeTree::TreePathPopFront< TreePath >::type >::const_storage_type const_storage_type
The const storage type of the child.
Definition: childextraction.hh:48
make_index_sequence< impl::_get_pack_length< T...>{}> index_sequence_for
Create an index_sequence for the pack T..., i.e. [0,sizeof...(T)].
Definition: utility.hh:298
constexpr std::size_t treePathSize(const TreePath< i...> &)
Returns the size (number of components) of the given TreePath.
Definition: treepath.hh:51
ImplementationDefined child(Node &&node, Indices...indices)
Extracts the child of a node given by a sequence of compile-time and run-time indices.
Definition: childextraction.hh:472
STL namespace.
extract_child_type< typename Node::template Child< TypeTree::TreePathFront< TreePath >::value >::Type, typename TypeTree::TreePathPopFront< TreePath >::type >::storage_type storage_type
The storage type of the child.
Definition: childextraction.hh:42
std::integral_constant< std::size_t, i > index_constant
An index constant with value i.
Definition: utility.hh:312
typename impl::_is_flat_index< typename std::decay< T >::type >::type is_flat_index
Type trait that determines whether T is a flat index in the context of child extraction.
Definition: childextraction.hh:627
A hybrid version of TreePath that supports both compile time and run time indices.
Definition: treepath.hh:322
Type
Definition: treepath.hh:26
typename impl::_Child< Node, indices...>::type Child
Template alias for the type of a child node given by a list of child indices.
Definition: childextraction.hh:568
ImplementationDefined child(Node &&node, HybridTreePath< Indices...> treePath)
Extracts the child of a node given by a HybridTreePath object.
Definition: childextraction.hh:537
typename impl::_ChildForTreePath< Node, TreePath >::type ChildForTreePath
Template alias for the type of a child node given by a TreePath or a HybridTreePath type...
Definition: childextraction.hh:595
Extract the type of the child of Node at position TreePath.
Definition: childextraction.hh:29
ImplementationDefined extract_child_storage(Node &node, Treepath tp)
Definition: childextraction.hh:239
Definition: treepath.hh:30