DUNE PDELab (2.8)

treecontainer.hh
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>
16
17#include <dune/typetree/treepath.hh>
18
19namespace 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
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:
169 TreeContainerVectorBackend(Container&& container) :
170 container_(std::move(container))
171 {}
172
174 template <class Tree, TypeTreeConcept<Tree> = true>
175 TreeContainerVectorBackend(const Tree& tree) :
176 TreeContainerVectorBackend()
177 {
178 this->resize(tree);
179 }
180
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
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
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
288 template<class Value, class Tree>
289 auto makeTreeContainer(const Tree& tree)
290 {
291 return makeTreeContainer(tree, [](const auto&) {return Value{};});
292 }
293
297 template<class Value, class Tree>
298 using UniformTreeContainer = std::decay_t<decltype(makeTreeContainer<Value>(std::declval<const Tree&>()))>;
299
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
307
308 } // namespace TypeTree
309} //namespace Dune
310
311#endif // DUNE_TYPETREE_TREECONTAINER_HH
decltype(auto) unpackIntegerSequence(F &&f, std::integer_sequence< I, i... > sequence)
Unpack an std::integer_sequence<I,i...> to std::integral_constant<I,i>...
Definition: indices.hh:123
constexpr index_constant< 0 > _0
Compile time index with value 0.
Definition: indices.hh:51
constexpr void forEach(Range &&range, F &&f)
Range based for loop.
Definition: hybridutilities.hh:266
std::size_t degree(const Node &node)
Returns the degree of node as run time information.
Definition: nodeinterface.hh:76
constexpr HybridTreePath< T... > treePath(const T &... t)
Constructs a new HybridTreePath from the given indices.
Definition: treepath.hh:188
std::decay_t< decltype(makeTreeContainer< Value >(std::declval< const Tree & >()))> UniformTreeContainer
Alias to container type generated by makeTreeContainer for given tree type and uniform value type.
Definition: treecontainer.hh:298
std::decay_t< decltype(makeTreeContainer(std::declval< const Tree & >(), std::declval< Detail::LeafToDefaultConstructibleValue< LeafToValue > >()))> TreeContainer
Alias to container type generated by makeTreeContainer for give tree type and when using LeafToValue ...
Definition: treecontainer.hh:304
auto makeTreeContainer(const Tree &tree)
Create container havin the same structure as the given tree.
Definition: treecontainer.hh:289
Dune namespace.
Definition: alignedallocator.hh:11
STL namespace.
Utilities for reduction like operations on ranges.
Helper class for tagging priorities.
Definition: typeutilities.hh:85
Helper class for tagging priorities.
Definition: typeutilities.hh:71
Provides the TupleVector class that augments std::tuple by operator[].
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden  |  generated with Hugo v0.111.3 (Dec 22, 23:30, 2024)