"Fossies" - the Fresh Open Source Software Archive 
Member "dune-typetree-2.8.0/dune/typetree/treecontainer.hh" (31 Aug 2021, 11030 Bytes) of package /linux/misc/dune/dune-typetree-2.8.0.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "treecontainer.hh" see the
Fossies "Dox" file reference documentation and the last
Fossies "Diffs" side-by-side code changes report:
2.8.0_vs_2.9.0.
1 // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 // vi: set et ts=4 sw=2 sts=2:
3
4 #ifndef DUNE_TYPETREE_TREECONTAINER_HH
5 #define DUNE_TYPETREE_TREECONTAINER_HH
6
7 #include <type_traits>
8 #include <utility>
9 #include <functional>
10 #include <array>
11
12 #include <dune/common/indices.hh>
13 #include <dune/common/hybridutilities.hh>
14 #include <dune/common/rangeutilities.hh>
15 #include <dune/common/tuplevector.hh>
16
17 #include <dune/typetree/treepath.hh>
18
19 namespace Dune {
20 namespace TypeTree {
21
22 namespace Detail {
23
24 /*
25 * \brief A factory class creating a hybrid container compatible with a type tree
26 *
27 * This class allows to create a nested hybrid container having the same structure
28 * as a given type tree. Power nodes are represented as std::array's while composite
29 * nodes are represented as Dune::TupleVector's. The stored values for the leaf nodes
30 * are creating using a given predicate. Once created, the factory provides an
31 * operator() creating the container for the tree given as argument.
32 *
33 * \tparam LeafToValue Type of a predicate that determines the stored values at the leafs
34 */
35 template<class LeafToValue>
36 class ContainerFactory
37 {
38 template<class N>
39 using DynamicDegreeConcept = decltype((std::size_t(std::declval<N>().degree()), true));
40
41 template<class N>
42 using StaticDegreeConcept = decltype((std::integral_constant<std::size_t, N::degree()>{}, true));
43
44 template<class N>
45 using DynamicChildAccessConcept = decltype((std::declval<N>().child(0u), true));
46
47 public:
48
49 /**
50 * \brief Create ContainerFactory
51 *
52 * The given predicate will be stored by value.
53 *
54 * \param A predicate used to generate the stored values for the leaves
55 */
56 ContainerFactory(LeafToValue leafToValue) :
57 leafToValue_(leafToValue)
58 {}
59
60 template<class Node>
61 auto operator()(const Node& node)
62 {
63 return (*this)(node, Dune::PriorityTag<5>{});
64 }
65
66 private:
67
68 template<class Node,
69 std::enable_if_t<Node::isLeaf, bool> = true>
70 auto operator()(const Node& node, Dune::PriorityTag<4>)
71 {
72 return leafToValue_(node);
73 }
74
75 template<class Node,
76 StaticDegreeConcept<Node> = true,
77 DynamicChildAccessConcept<Node> = true>
78 auto operator()(const Node& node, Dune::PriorityTag<3>)
79 {
80 return Dune::unpackIntegerSequence([&](auto... indices) {
81 return std::array{(*this)(node.child(indices))...};
82 }, std::make_index_sequence<std::size_t(Node::degree())>());
83 }
84
85 template<class Node,
86 DynamicDegreeConcept<Node> = true,
87 DynamicChildAccessConcept<Node> = true>
88 auto operator()(const Node& node, Dune::PriorityTag<2>)
89 {
90 using TransformedChild = decltype((*this)(node.child(0)));
91 std::vector<TransformedChild> container;
92 container.reserve(node.degree());
93 for (std::size_t i = 0; i < node.degree(); ++i)
94 container.emplace_back((*this)(node.child(i)));
95 return container;
96 }
97
98 template<class Node,
99 StaticDegreeConcept<Node> = true>
100 auto operator()(const Node& node, Dune::PriorityTag<1>)
101 {
102 return Dune::unpackIntegerSequence([&](auto... indices) {
103 return Dune::makeTupleVector((*this)(node.child(indices))...);
104 }, std::make_index_sequence<std::size_t(Node::degree())>());
105 }
106
107 private:
108 LeafToValue leafToValue_;
109 };
110
111
112 /*
113 * \brief Wrap nested container to provide a VectorBackend
114 */
115 template<class Container>
116 class TreeContainerVectorBackend
117 {
118 template<class C>
119 static constexpr decltype(auto) accessByTreePath(C&& container, const HybridTreePath<>& path)
120 {
121 return container;
122 }
123
124 template<class C, class... T>
125 static constexpr decltype(auto) accessByTreePath(C&& container, const HybridTreePath<T...>& path)
126 {
127 auto head = path[Dune::Indices::_0];
128 auto tailPath = Dune::unpackIntegerSequence([&](auto... i){
129 return treePath(path[i+1]...);
130 }, std::make_index_sequence<sizeof...(T)-1>());
131 return accessByTreePath(container[head], tailPath);
132 }
133
134 template<class C, class Tree,
135 std::enable_if_t<Tree::isLeaf, bool> = true>
136 static void resizeImpl(C& /*container*/, const Tree& /*tree*/, Dune::PriorityTag<2>)
137 {
138 /* do nothing */
139 }
140
141 template<class C, class Tree,
142 class = decltype(std::declval<C>().resize(0u))>
143 static void resizeImpl(C& container, const Tree& tree, Dune::PriorityTag<1>)
144 {
145 container.resize(tree.degree());
146 Dune::Hybrid::forEach(Dune::range(tree.degree()), [&](auto i) {
147 resizeImpl(container[i], tree.child(i), Dune::PriorityTag<5>{});
148 });
149 }
150
151 template<class C, class Tree>
152 static void resizeImpl(C& container, const Tree& tree, Dune::PriorityTag<0>)
153 {
154 Dune::Hybrid::forEach(Dune::range(tree.degree()), [&](auto i) {
155 resizeImpl(container[i], tree.child(i), Dune::PriorityTag<5>{});
156 });
157 }
158
159 template<class T>
160 using TypeTreeConcept = decltype((
161 std::declval<T>().degree(),
162 T::isLeaf,
163 T::isPower,
164 T::isComposite,
165 true));
166
167 public:
168 //! Move the passed container into the internal storage
169 TreeContainerVectorBackend(Container&& container) :
170 container_(std::move(container))
171 {}
172
173 //! Default construct the container and perform a resize depending on the tree-node degrees.
174 template <class Tree, TypeTreeConcept<Tree> = true>
175 TreeContainerVectorBackend(const Tree& tree) :
176 TreeContainerVectorBackend()
177 {
178 this->resize(tree);
179 }
180
181 //! Default constructor. The stored container might need to be resized before usage.
182 template <class C = Container,
183 std::enable_if_t<std::is_default_constructible_v<C>, bool> = true>
184 TreeContainerVectorBackend() :
185 container_()
186 {}
187
188 template<class... T>
189 decltype(auto) operator[](const HybridTreePath<T...>& path) const
190 {
191 return accessByTreePath(container_, path);
192 }
193
194 template<class... T>
195 decltype(auto) operator[](const HybridTreePath<T...>& path)
196 {
197 return accessByTreePath(container_, path);
198 }
199
200 //! Resize the (nested) container depending on the degree of the tree nodes
201 template<class Tree, TypeTreeConcept<Tree> = true>
202 void resize(const Tree& tree)
203 {
204 resizeImpl(container_, tree, Dune::PriorityTag<5>{});
205 }
206
207 const Container& data() const
208 {
209 return container_;
210 }
211
212 Container& data()
213 {
214 return container_;
215 }
216
217 private:
218 Container container_;
219 };
220
221 template<class Container>
222 auto makeTreeContainerVectorBackend(Container&& container)
223 {
224 return TreeContainerVectorBackend<std::decay_t<Container>>(std::forward<Container>(container));
225 }
226
227 /*
228 * \brief A simple lambda for creating default constructible values from a node
229 *
230 * This simply returns LeafToValue<Node>{} for a given Node. It's needed
231 * because using a lambda expression in a using declaration is not allowed
232 * because it's an unevaluated context.
233 */
234 template<template<class Node> class LeafToValue>
235 struct LeafToDefaultConstructibleValue
236 {
237 template<class Node>
238 auto operator()(const Node& node) const
239 {
240 return LeafToValue<Node>{};
241 }
242 };
243
244 } // namespace Detail
245
246 /** \addtogroup TypeTree
247 * \{
248 */
249
250 /**
251 * \brief Create container havin the same structure as the given tree
252 *
253 * This class allows to create a nested hybrid container having the same structure
254 * as a given type tree. Power nodes are represented as std::array's while composite
255 * nodes are represented as Dune::TupleVector's. The stored values for the leaf nodes
256 * are creating using a given predicate. For convenience the created container is
257 * not returned directly. Instead, the returned object stores the container and
258 * provides operator[] access using a HybridTreePath.
259 *
260 * \param tree The tree which should be mapper to a container
261 * \param leafToValue A predicate used to generate the stored values for the leaves
262 *
263 * \returns A container matching the tree structure
264 */
265 template<class Tree, class LeafToValue>
266 auto makeTreeContainer(const Tree& tree, LeafToValue&& leafToValue)
267 {
268 auto f = std::ref(leafToValue);
269 auto factory = Detail::ContainerFactory<decltype(f)>(f);
270 return Detail::makeTreeContainerVectorBackend(factory(tree));
271 }
272
273 /**
274 * \brief Create container havin the same structure as the given tree
275 *
276 * This class allows to create a nested hybrid container having the same structure
277 * as a given type tree. Power nodes are represented as std::array's while composite
278 * nodes are represented as Dune::TupleVector's. The stored values for the leaf nodes
279 * are of the given type Value. For convenience the created container is
280 * not returned directly. Instead, the returned object stores the container and
281 * provides operator[] access using a HybridTreePath.
282 *
283 * \tparam Value Type of the values to be stored for the leafs. Should be default constructible.
284 * \param leafToValue A predicate used to generate the stored values for the leaves
285 *
286 * \returns A container matching the tree structure
287 */
288 template<class Value, class Tree>
289 auto makeTreeContainer(const Tree& tree)
290 {
291 return makeTreeContainer(tree, [](const auto&) {return Value{};});
292 }
293
294 /**
295 * \brief Alias to container type generated by makeTreeContainer for given tree type and uniform value type
296 */
297 template<class Value, class Tree>
298 using UniformTreeContainer = std::decay_t<decltype(makeTreeContainer<Value>(std::declval<const Tree&>()))>;
299
300 /**
301 * \brief Alias to container type generated by makeTreeContainer for give tree type and when using LeafToValue to create values
302 */
303 template<template<class Node> class LeafToValue, class Tree>
304 using TreeContainer = std::decay_t<decltype(makeTreeContainer(std::declval<const Tree&>(), std::declval<Detail::LeafToDefaultConstructibleValue<LeafToValue>>()))>;
305
306 //! \} group TypeTree
307
308 } // namespace TypeTree
309 } //namespace Dune
310
311 #endif // DUNE_TYPETREE_TREECONTAINER_HH