dune-typetree 3.0-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 <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
18namespace 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)
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<
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 childStorage(Node &&node, TreePath< Indices... > treePath)
Definition childextraction.hh:229
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
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 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:334
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 TreePath< i... > &)
Returns the size (number of components) of the given TreePath.
Definition treepath.hh:51
Definition accumulate_static.hh:13
Definition treepath.hh:30
A hybrid version of TreePath that supports both compile time and run time indices.
Definition treepath.hh:323