DUNE PDELab (git)

traversal.hh
1// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2// vi: set et ts=4 sw=2 sts=2:
3// SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root
4// SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-GPL-2.0-only-with-PDELab-exception
5
6#ifndef DUNE_TYPETREE_TRAVERSAL_HH
7#define DUNE_TYPETREE_TRAVERSAL_HH
8
9#include <utility>
10
11#include <dune/common/hybridutilities.hh>
12#include <dune/common/std/type_traits.hh>
13
14#include <dune/typetree/childextraction.hh>
15#include <dune/typetree/nodetags.hh>
16#include <dune/typetree/treepath.hh>
17#include <dune/typetree/visitor.hh>
18
19namespace Dune {
20 namespace TypeTree {
21
27#ifndef DOXYGEN
29 struct NoOp
30 {
31 template<class... T>
32 constexpr void operator()(T&&...) const { /* do nothing */ }
33 };
34#endif
35
36 namespace Detail {
37
38 // SFINAE template check that Tree has a degree() function and a child() function accepting integer indices
39 template<class Tree>
40 using DynamicTraversalConcept = decltype((
41 std::declval<Tree>().degree(),
42 std::declval<Tree>().child(0u)
43 ));
44
45 // SFINAE template check that Tree has static (constexpr) function Tree::degree()
46 template<class Tree>
47 using StaticTraversalConcept = decltype((
48 std::integral_constant<std::size_t, Tree::degree()>{}
49 ));
50
51
52 template<class Tree, TreePathType::Type pathType, class Prefix,
53 std::enable_if_t<Tree::isLeaf, int> = 0>
54 constexpr auto leafTreePathTuple(Prefix prefix)
55 {
56 return std::make_tuple(prefix);
57 }
58
59 template<class Tree, TreePathType::Type pathType, class Prefix,
60 std::enable_if_t<not Tree::isLeaf, int> = 0>
61 constexpr auto leafTreePathTuple(Prefix prefix);
62
63 template<class Tree, TreePathType::Type pathType, class Prefix, std::size_t... indices,
64 std::enable_if_t<(Tree::isComposite or (Tree::isPower and (pathType!=TreePathType::dynamic))), int> = 0>
65 constexpr auto leafTreePathTuple(Prefix prefix, std::index_sequence<indices...>)
66 {
67 return std::tuple_cat(Detail::leafTreePathTuple<TypeTree::Child<Tree,indices>, pathType>(Dune::TypeTree::push_back(prefix, Dune::index_constant<indices>{}))...);
68 }
69
70 template<class Tree, TreePathType::Type pathType, class Prefix, std::size_t... indices,
71 std::enable_if_t<(Tree::isPower and (pathType==TreePathType::dynamic)), int> = 0>
72 constexpr auto leafTreePathTuple(Prefix prefix, std::index_sequence<indices...>)
73 {
74 return std::tuple_cat(Detail::leafTreePathTuple<TypeTree::Child<Tree,indices>, pathType>(Dune::TypeTree::push_back(prefix, indices))...);
75 }
76
77 template<class Tree, TreePathType::Type pathType, class Prefix,
78 std::enable_if_t<not Tree::isLeaf, int>>
79 constexpr auto leafTreePathTuple(Prefix prefix)
80 {
81 return Detail::leafTreePathTuple<Tree, pathType>(prefix, std::make_index_sequence<Tree::degree()>{});
82 }
83
84 /* The signature is the same as for the public applyToTree
85 * function in Dune::Typetree, despite the additionally passed
86 * treePath argument. The path passed here is associated to
87 * the tree and the relative paths of the children (wrt. to tree)
88 * are appended to this. Hence the behavior of the public function
89 * is resembled by passing an empty treePath.
90 */
91
92 /*
93 * This is the overload for leaf traversal
94 */
95 template<class T, class TreePath, class V,
96 std::enable_if_t<std::decay_t<T>::isLeaf, int> = 0>
97 void applyToTree(T&& tree, TreePath treePath, V&& visitor)
98 {
99 visitor.leaf(tree, treePath);
100 }
101
102 /*
103 * This is the general overload doing child traversal.
104 */
105 template<class T, class TreePath, class V,
106 std::enable_if_t<not std::decay_t<T>::isLeaf, int> = 0>
107 void applyToTree(T&& tree, TreePath treePath, V&& visitor)
108 {
109 using Tree = std::remove_reference_t<T>;
110 using Visitor = std::remove_reference_t<V>;
111 visitor.pre(tree, treePath);
112
113 // check which type of traversal is supported by the tree
114 using allowDynamicTraversal = Dune::Std::is_detected<DynamicTraversalConcept,Tree>;
115 using allowStaticTraversal = Dune::Std::is_detected<StaticTraversalConcept,Tree>;
116
117 // the tree must support either dynamic or static traversal
118 static_assert(allowDynamicTraversal::value || allowStaticTraversal::value);
119
120 // the visitor may specify preferred dynamic traversal
121 using preferDynamicTraversal = std::bool_constant<Visitor::treePathType == TreePathType::dynamic>;
122
123 // create a dynamic or static index range
124 auto indices = [&]{
125 if constexpr(preferDynamicTraversal::value && allowDynamicTraversal::value)
126 return Dune::range(std::size_t(tree.degree()));
127 else
128 return Dune::range(tree.degree());
129 }();
130
131 if constexpr(allowDynamicTraversal::value || allowStaticTraversal::value) {
132 Hybrid::forEach(indices, [&](auto i) {
133 auto&& child = tree.child(i);
134 using Child = std::decay_t<decltype(child)>;
135
136 visitor.beforeChild(tree, child, treePath, i);
137
138 // This requires that visitor.in(...) can always be instantiated,
139 // even if there's a single child only.
140 if (i>0)
141 visitor.in(tree, treePath);
142
143 constexpr bool visitChild = Visitor::template VisitChild<Tree,Child,TreePath>::value;
144 if constexpr(visitChild) {
145 auto childTreePath = Dune::TypeTree::push_back(treePath, i);
146 applyToTree(child, childTreePath, visitor);
147 }
148
149 visitor.afterChild(tree, child, treePath, i);
150 });
151 }
152 visitor.post(tree, treePath);
153 }
154
155 /* Traverse tree and visit each node. The signature is the same
156 * as for the public forEachNode function in Dune::Typtree,
157 * despite the additionally passed treePath argument. The path
158 * passed here is associated to the tree and the relative
159 * paths of the children (wrt. to tree) are appended to this.
160 * Hence the behavior of the public function is resembled
161 * by passing an empty treePath.
162 */
163 template<class T, class TreePath, class PreFunc, class LeafFunc, class PostFunc>
164 void forEachNode(T&& tree, TreePath treePath, PreFunc&& preFunc, LeafFunc&& leafFunc, PostFunc&& postFunc)
165 {
166 using Tree = std::decay_t<T>;
167 if constexpr(Tree::isLeaf) {
168 leafFunc(tree, treePath);
169 } else {
170 preFunc(tree, treePath);
171
172 // check which type of traversal is supported by the tree, prefer dynamic traversal
173 using allowDynamicTraversal = Dune::Std::is_detected<DynamicTraversalConcept,Tree>;
174 using allowStaticTraversal = Dune::Std::is_detected<StaticTraversalConcept,Tree>;
175
176 // the tree must support either dynamic or static traversal
177 static_assert(allowDynamicTraversal::value || allowStaticTraversal::value);
178
179 if constexpr(allowDynamicTraversal::value) {
180 // Specialization for dynamic traversal
181 for (std::size_t i = 0; i < tree.degree(); ++i) {
182 auto childTreePath = Dune::TypeTree::push_back(treePath, i);
183 forEachNode(tree.child(i), childTreePath, preFunc, leafFunc, postFunc);
184 }
185 } else if constexpr(allowStaticTraversal::value) {
186 // Specialization for static traversal
187 auto indices = std::make_index_sequence<Tree::degree()>{};
188 Hybrid::forEach(indices, [&](auto i) {
189 auto childTreePath = Dune::TypeTree::push_back(treePath, i);
190 forEachNode(tree.child(i), childTreePath, preFunc, leafFunc, postFunc);
191 });
192 }
193 postFunc(tree, treePath);
194 }
195 }
196
197 } // namespace Detail
198
199
200 // ********************************************************************************
201 // Public Interface
202 // ********************************************************************************
203
217 template<class Tree, TreePathType::Type pathType=TreePathType::dynamic>
218 constexpr auto leafTreePathTuple()
219 {
220 return Detail::leafTreePathTuple<std::decay_t<Tree>, pathType>(hybridTreePath());
221 }
222
224
238 template<typename Tree, typename Visitor>
239 void applyToTree(Tree&& tree, Visitor&& visitor)
240 {
241 Detail::applyToTree(tree, hybridTreePath(), visitor);
242 }
243
253 template<class Tree, class NodeFunc>
254 void forEachNode(Tree&& tree, NodeFunc&& nodeFunc)
255 {
256 Detail::forEachNode(tree, hybridTreePath(), nodeFunc, nodeFunc, NoOp{});
257 }
258
268 template<class Tree, class LeafFunc>
269 void forEachLeafNode(Tree&& tree, LeafFunc&& leafFunc)
270 {
271 Detail::forEachNode(tree, hybridTreePath(), NoOp{}, leafFunc, NoOp{});
272 }
273
275
276 } // namespace TypeTree
277} //namespace Dune
278
279#endif // DUNE_TYPETREE_TRAVERSAL_HH
std::integral_constant< std::size_t, i > index_constant
An index constant with value i.
Definition: indices.hh:29
typename detected_or< nonesuch, Op, Args... >::value_t is_detected
Detects whether Op<Args...> is valid.
Definition: type_traits.hh:145
constexpr void forEach(Range &&range, F &&f)
Range based for loop.
Definition: hybridutilities.hh:256
std::size_t degree(const Node &node)
Returns the degree of node as run time information.
Definition: nodeinterface.hh:79
constexpr HybridTreePath< T..., std::size_t > push_back(const HybridTreePath< T... > &tp, std::size_t i)
Appends a run time index to a HybridTreePath.
Definition: treepath.hh:416
constexpr auto hybridTreePath(const T &... t)
Constructs a new HybridTreePath from the given indices.
Definition: treepath.hh:312
constexpr auto treePath(const T &... t)
Constructs a new HybridTreePath from the given indices.
Definition: treepath.hh:326
void forEachNode(Tree &&tree, NodeFunc &&nodeFunc)
Traverse tree and visit each node.
Definition: traversal.hh:254
constexpr auto leafTreePathTuple()
Create tuple of tree paths to leafs.
Definition: traversal.hh:218
void forEachLeafNode(Tree &&tree, LeafFunc &&leafFunc)
Traverse tree and visit each leaf node.
Definition: traversal.hh:269
void applyToTree(Tree &&tree, Visitor &&visitor)
Apply visitor to TypeTree.
Definition: traversal.hh:239
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:225
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:128
Dune namespace.
Definition: alignedallocator.hh:13
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden  |  generated with Hugo v0.111.3 (Nov 24, 23:30, 2024)