dune-typetree  2.6-rc1
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 <utility>
8 
9 #include <dune/common/concept.hh>
10 #include <dune/common/documentation.hh>
11 #include <dune/common/typetraits.hh>
12 #include <dune/common/shared_ptr.hh>
13 
16 
17 
18 namespace Dune {
19  namespace TypeTree {
20 
25 
26 #ifndef DOXYGEN
27 
28  namespace impl {
29 
30  // ********************************************************************************
31  // end of the recursion, there are no child indices, so just return the node itself
32  // ********************************************************************************
33 
34  struct IsPointerLike {
35  template <class Node>
36  auto require(const Node& node) -> decltype(*node);
37  };
38 
39  template<typename Node>
40  auto child(Node&& node) -> decltype(std::forward<Node>(node))
41  {
42  return std::forward<Node>(node);
43  }
44 
45  // for now, this wants the passed-in object to be pointer-like. I don't know how clever
46  // that is in the long run, though.
47  template<typename Node, typename std::enable_if_t<Dune::models<IsPointerLike,Node>(),int> = 0>
48  auto childStorage(Node&& node)
49  {
50  return std::forward<Node>(node);
51  }
52 
53  // ********************************************************************************
54  // next index is a compile-time constant
55  // ********************************************************************************
56 
57  // we need a concept to make sure that the node has a templated child()
58  // method
59  struct HasTemplateChildMethod {
60  template <class Node>
61  auto require(const Node& node) -> decltype(node.template child<0>());
62  };
63 
64  // The actual implementation is rather simple, we just use an overload that requires the first index
65  // to be an index_constant, get the child and then recurse.
66  // It only gets ugly due to the enable_if, but without that trick, the error messages for the user
67  // can get *very* obscure (they are bad enough as it is).
68  template<typename Node, std::size_t i, typename... J,
69  typename std::enable_if<
70  Dune::models<HasTemplateChildMethod, Node>() &&
71  (i < StaticDegree<Node>::value), int>::type = 0>
72  decltype(auto) child(Node&& node, index_constant<i>, J... j)
73  {
74  return child(std::forward<Node>(node).template child<i>(),j...);
75  }
76 
77  template<typename Node, std::size_t i, typename... J,
78  typename std::enable_if<
79  Dune::models<HasTemplateChildMethod, decltype(*std::declval<std::decay_t<Node>>())>() &&
80  (i < StaticDegree<decltype(*std::declval<Node>())>::value), int>::type = 0>
81  decltype(auto) childStorage(Node&& node, index_constant<i>, J... j)
82  {
83  return childStorage(std::forward<Node>(node)->template childStorage<i>(),j...);
84  }
85 
86  // This overload is only present to give useful compiler
87  // error messages via static_assert in case the other overloads
88  // fail.
89  template<typename Node, std::size_t i, typename... J,
90  typename std::enable_if<
91  (!Dune::models<HasTemplateChildMethod, Node>()) ||
92  (i >= StaticDegree<Node>::value), int>::type = 0>
93  void child(Node&& node, index_constant<i>, J... j)
94  {
95  static_assert(Dune::models<HasTemplateChildMethod, Node>(), "Node does not have a template method child()");
96  static_assert(i < StaticDegree<Node>::value, "Child index out of range");
97  }
98 
99  // ********************************************************************************
100  // next index is a run-time value
101  // ********************************************************************************
102 
103  // The actual implemention here overloads on std::size_t. It is a little less ugly because it currently
104  // has a hard requirement on the PowerNode Tag (although only using is_convertible, as tags can be
105  // inherited (important!).
106  template<typename Node, typename... J>
107  decltype(auto)
108  child(
109  Node&& node,
110  std::enable_if_t<
111  std::is_convertible<
112  NodeTag<Node>,
113  PowerNodeTag
114  >{},
115  std::size_t> i,
116  J... j
117  )
118  {
119  return child(std::forward<Node>(node).child(i),j...);
120  }
121 
122  template<typename Node, typename... J>
123  decltype(auto)
124  childStorage(
125  Node&& node,
126  std::enable_if_t<
127  std::is_convertible<
128  NodeTag<decltype(*std::declval<Node>())>,
129  PowerNodeTag
130  >{},
131  std::size_t> i,
132  J... j
133  )
134  {
135  return childStorage(std::forward<Node>(node)->childStorage(i),j...);
136  }
137 
138  template<typename Node, typename... Indices, std::size_t... i>
139  decltype(auto) child(Node&& node, HybridTreePath<Indices...> tp, std::index_sequence<i...>)
140  {
141  return child(std::forward<Node>(node),treePathEntry<i>(tp)...);
142  }
143 
144  template<typename Node, typename... Indices, std::size_t... i>
145  decltype(auto) childStorage(Node&& node, HybridTreePath<Indices...> tp, std::index_sequence<i...>)
146  {
147  return childStorage(std::forward<Node>(node),treePathEntry<i>(tp)...);
148  }
149 
150  } // namespace imp
151 
152 #endif // DOXYGEN
153 
155 
177  template<typename Node, typename... Indices>
178 #ifdef DOXYGEN
179  ImplementationDefined child(Node&& node, Indices... indices)
180 #else
181  decltype(auto) child(Node&& node, Indices... indices)
182 #endif
183  {
184  return impl::child(std::forward<Node>(node),indices...);
185  }
186 
187  template<typename Node, typename... Indices>
188 #ifdef DOXYGEN
189  ImplementationDefined child(Node&& node, Indices... indices)
190 #else
191  auto childStorage(Node&& node, Indices... indices)
192 #endif
193  {
194  //static_assert(sizeof...(Indices) > 0, "childStorage() cannot be called with an empty list of child indices");
195  return impl::childStorage(&node,indices...);
196  }
197 
199 
217  template<typename Node, std::size_t... Indices>
218 #ifdef DOXYGEN
219  ImplementationDefined child(Node&& node, TreePath<Indices...> treePath)
220 #else
221  decltype(auto) child(Node&& node, TreePath<Indices...>)
222 #endif
223  {
224  return child(std::forward<Node>(node),index_constant<Indices>{}...);
225  }
226 
227  template<typename Node, std::size_t... Indices>
228 #ifdef DOXYGEN
229  ImplementationDefined childStorage(Node&& node, TreePath<Indices...> treePath)
230 #else
231  auto childStorage(Node&& node, TreePath<Indices...>)
232 #endif
233  {
234  static_assert(sizeof...(Indices) > 0, "childStorage() cannot be called with an empty TreePath");
235  return impl::childStorage(&node,index_constant<Indices>{}...);
236  }
237 
239 
262  template<typename Node, typename... Indices>
263 #ifdef DOXYGEN
264  ImplementationDefined child(Node&& node, HybridTreePath<Indices...> treePath)
265 #else
266  decltype(auto) child(Node&& node, HybridTreePath<Indices...> tp)
267 #endif
268  {
269  return impl::child(std::forward<Node>(node),tp,std::index_sequence_for<Indices...>{});
270  }
271 
272  template<typename Node, typename... Indices>
273 #ifdef DOXYGEN
274  ImplementationDefined child(Node&& node, HybridTreePath<Indices...> treePath)
275 #else
276  auto childStorage(Node&& node, HybridTreePath<Indices...> tp)
277 #endif
278  {
279  static_assert(sizeof...(Indices) > 0, "childStorage() cannot be called with an empty TreePath");
280  return impl::childStorage(&node,tp,std::index_sequence_for<Indices...>{});
281  }
282 
283 
284 #ifndef DOXYGEN
285 
286  namespace impl {
287 
288  template<typename Node, std::size_t... indices>
289  struct _Child
290  {
291  using type = std::decay_t<decltype(child(std::declval<Node>(),index_constant<indices>{}...))>;
292  };
293 
294  }
295 
296 #endif // DOXYGEN
297 
299 
306  template<typename Node, std::size_t... indices>
307  using Child = typename impl::_Child<Node,indices...>::type;
308 
309 
310 #ifndef DOXYGEN
311 
312  namespace impl {
313 
314  template<typename Node, typename TreePath>
315  struct _ChildForTreePath
316  {
317  using type = typename std::decay<decltype(child(std::declval<Node>(),std::declval<TreePath>()))>::type;
318  };
319 
320  }
321 
322 #endif // DOXYGEN
323 
325 
333  template<typename Node, typename TreePath>
334  using ChildForTreePath = typename impl::_ChildForTreePath<Node,TreePath>::type;
335 
336 
337 #ifndef DOXYGEN
338 
339  namespace impl {
340 
341  // By default, types are flat indices if they are integral
342  template<typename T>
343  struct _is_flat_index
344  {
345  using type = std::is_integral<T>;
346  };
347 
348  // And so is any index_constant
349  template<std::size_t i>
350  struct _is_flat_index<index_constant<i>>
351  {
352  using type = std::true_type;
353  };
354 
355  }
356 
357 #endif // DOXYGEN
358 
360  /*
361  * This type trait can be used to check whether T is a flat index (i.e. either `std::size_t`
362  * or `index_constant`). The type trait normalizes T before doing the check, so it will also
363  * work correctly for references and cv-qualified types.
364  */
365  template<typename T>
366  using is_flat_index = typename impl::_is_flat_index<std::decay_t<T>>::type;
367 
368 #ifndef DOXYGEN
369 
370  namespace impl {
371 
372  // helper struct to perform lazy return type evaluation in the forwarding member child() methods
373  // of nodes
374  template<typename Node>
375  struct _lazy_member_child_decltype
376  {
377  template<typename... Indices>
378  struct evaluate
379  {
380  using type = decltype(Dune::TypeTree::child(std::declval<Node>(),std::declval<Indices>()...));
381  };
382  };
383 
384  // helper function for check in member child() functions that tolerates being passed something that
385  // isn't a TreePath. It will just return 0 in that case
386 
387  template<typename T>
388  constexpr typename std::enable_if<
390  bool
391  >::type
392  _non_empty_tree_path(T)
393  {
394  return false;
395  }
396 
397  template<typename T>
398  constexpr typename std::enable_if<
399  !Dune::TypeTree::is_flat_index<T>::value,
400  bool
401  >::type
402  _non_empty_tree_path(T t)
403  {
404  return treePathSize(t) > 0;
405  }
406 
407  }
408 
409 #endif // DOXYGEN
410 
412 
413  } // namespace TypeTree
414 } //namespace Dune
415 
416 #endif // DUNE_TYPETREE_CHILDEXTRACTION_HH
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:179
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:307
ImplementationDefined childStorage(Node &&node, TreePath< Indices... > treePath)
Definition: childextraction.hh:229
Definition: accumulate_static.hh:13
constexpr std::size_t treePathSize(const TreePath< i... > &)
Returns the size (number of components) of the given TreePath.
Definition: treepath.hh:51
STL namespace.
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:334
typename impl::_is_flat_index< std::decay_t< T > >::type is_flat_index
Type trait that determines whether T is a flat index in the context of child extraction.
Definition: childextraction.hh:366
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
A hybrid version of TreePath that supports both compile time and run time indices.
Definition: treepath.hh:322
typename std::decay_t< Node >::NodeTag NodeTag
Returns the node tag of the given Node.
Definition: nodeinterface.hh:62
Definition: treepath.hh:30
ImplementationDefined child(Node &&node, HybridTreePath< Indices... > treePath)
Extracts the child of a node given by a HybridTreePath object.
Definition: childextraction.hh:264