dune-typetree  2.7.1
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 childStorage(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 
222  template<typename Node, typename... Indices>
223 #ifdef DOXYGEN
224  ImplementationDefined child(Node&& node, HybridTreePath<Indices...> treePath)
225 #else
226  decltype(auto) child(Node&& node, HybridTreePath<Indices...> tp)
227 #endif
228  {
229  return impl::child(std::forward<Node>(node),tp,std::index_sequence_for<Indices...>{});
230  }
231 
232  template<typename Node, typename... Indices>
233 #ifdef DOXYGEN
234  ImplementationDefined child(Node&& node, HybridTreePath<Indices...> treePath)
235 #else
236  auto childStorage(Node&& node, HybridTreePath<Indices...> tp)
237 #endif
238  {
239  static_assert(sizeof...(Indices) > 0, "childStorage() cannot be called with an empty TreePath");
240  return impl::childStorage(&node,tp,std::index_sequence_for<Indices...>{});
241  }
242 
243 
244 #ifndef DOXYGEN
245 
246  namespace impl {
247 
248  template<typename T>
249  struct filter_void
250  {
251  using type = T;
252  };
253 
254  template<>
255  struct filter_void<void>
256  {};
257 
258  template<typename Node, std::size_t... indices>
259  struct _Child
260  : public filter_void<std::decay_t<decltype(child(std::declval<Node>(),index_constant<indices>{}...))>>
261  {};
262 
263  }
264 
265 #endif // DOXYGEN
266 
268 
275  template<typename Node, std::size_t... indices>
276  using Child = typename impl::_Child<Node,indices...>::type;
277 
278 
279 #ifndef DOXYGEN
280 
281  namespace impl {
282 
283  template<typename Node, typename TreePath>
284  struct _ChildForTreePath
285  {
286  using type = typename std::decay<decltype(child(std::declval<Node>(),std::declval<TreePath>()))>::type;
287  };
288 
289  }
290 
291 #endif // DOXYGEN
292 
294 
302  template<typename Node, typename TreePath>
303  using ChildForTreePath = typename impl::_ChildForTreePath<Node,TreePath>::type;
304 
305 
306 #ifndef DOXYGEN
307 
308  namespace impl {
309 
310  // By default, types are flat indices if they are integral
311  template<typename T>
312  struct _is_flat_index
313  {
314  using type = std::is_integral<T>;
315  };
316 
317  // And so is any index_constant
318  template<std::size_t i>
319  struct _is_flat_index<index_constant<i>>
320  {
321  using type = std::true_type;
322  };
323 
324  }
325 
326 #endif // DOXYGEN
327 
329  /*
330  * This type trait can be used to check whether T is a flat index (i.e. either `std::size_t`
331  * or `index_constant`). The type trait normalizes T before doing the check, so it will also
332  * work correctly for references and cv-qualified types.
333  */
334  template<typename T>
335  using is_flat_index = typename impl::_is_flat_index<std::decay_t<T>>::type;
336 
337 #ifndef DOXYGEN
338 
339  namespace impl {
340 
341  // helper function for check in member child() functions that tolerates being passed something that
342  // isn't a TreePath. It will just return 0 in that case
343 
344  template<typename T>
345  constexpr typename std::enable_if<
347  bool
348  >::type
349  _non_empty_tree_path(T)
350  {
351  return false;
352  }
353 
354  template<typename T>
355  constexpr typename std::enable_if<
357  bool
358  >::type
359  _non_empty_tree_path(T t)
360  {
361  return treePathSize(t) > 0;
362  }
363 
364  }
365 
366 #endif // DOXYGEN
367 
369 
370  } // namespace TypeTree
371 } //namespace Dune
372 
373 #endif // DUNE_TYPETREE_CHILDEXTRACTION_HH
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:335
ImplementationDefined childStorage(Node &&node, Indices... indices)
Definition: childextraction.hh:189
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:276
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::_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:303
ImplementationDefined child(Node &&node, HybridTreePath< Indices... > treePath)
Extracts the child of a node given by a HybridTreePath object.
Definition: childextraction.hh:224
typename std::decay_t< Node >::NodeTag NodeTag
Returns the node tag of the given Node.
Definition: nodeinterface.hh:62
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
constexpr std::size_t treePathSize(const HybridTreePath< T... > &)
Returns the size (number of components) of the given HybridTreePath.
Definition: treepath.hh:196
constexpr HybridTreePath< T... > treePath(const T &... t)
Constructs a new HybridTreePath from the given indices.
Definition: treepath.hh:188
Definition: accumulate_static.hh:13
A hybrid version of TreePath that supports both compile time and run time indices.
Definition: treepath.hh:79