DUNE PDELab (git)

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// 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_TREECONTAINER_HH
7#define DUNE_TYPETREE_TREECONTAINER_HH
8
9#include <type_traits>
10#include <utility>
11#include <functional>
12#include <array>
13
14#include <dune/common/indices.hh>
15#include <dune/common/hybridutilities.hh>
18
19#include <dune/typetree/treepath.hh>
20
21namespace Dune {
22 namespace TypeTree {
23
24 namespace Detail {
25
26 /*
27 * \brief A factory class creating a hybrid container compatible with a type tree
28 *
29 * This class allows to create a nested hybrid container having the same structure
30 * as a given type tree. Power nodes are represented as std::array's while composite
31 * nodes are represented as Dune::TupleVector's. The stored values for the leaf nodes
32 * are creating using a given predicate. Once created, the factory provides an
33 * operator() creating the container for the tree given as argument.
34 *
35 * \tparam LeafToValue Type of a predicate that determines the stored values at the leafs
36 */
37 template<class LeafToValue>
38 class ContainerFactory
39 {
40 template<class N>
41 using DynamicDegreeConcept = decltype((std::size_t(std::declval<N>().degree()), true));
42
43 template<class N>
44 using StaticDegreeConcept = decltype((std::integral_constant<std::size_t, N::degree()>{}, true));
45
46 template<class N>
47 using DynamicChildAccessConcept = decltype((std::declval<N>().child(0u), true));
48
49 public:
50
58 ContainerFactory(LeafToValue leafToValue) :
59 leafToValue_(leafToValue)
60 {}
61
62 template<class Node>
63 auto operator()(const Node& node)
64 {
65 return (*this)(node, Dune::PriorityTag<5>{});
66 }
67
68 private:
69
70 template<class Node,
71 std::enable_if_t<Node::isLeaf, bool> = true>
72 auto operator()(const Node& node, Dune::PriorityTag<4>)
73 {
74 return leafToValue_(node);
75 }
76
77 template<class Node,
78 StaticDegreeConcept<Node> = true,
79 DynamicChildAccessConcept<Node> = true>
80 auto operator()(const Node& node, Dune::PriorityTag<3>)
81 {
82 return Dune::unpackIntegerSequence([&](auto... indices) {
83 return std::array{(*this)(node.child(indices))...};
84 }, std::make_index_sequence<std::size_t(Node::degree())>());
85 }
86
87 template<class Node,
88 DynamicDegreeConcept<Node> = true,
89 DynamicChildAccessConcept<Node> = true>
90 auto operator()(const Node& node, Dune::PriorityTag<2>)
91 {
92 using TransformedChild = decltype((*this)(node.child(0)));
93 std::vector<TransformedChild> container;
94 container.reserve(node.degree());
95 for (std::size_t i = 0; i < node.degree(); ++i)
96 container.emplace_back((*this)(node.child(i)));
97 return container;
98 }
99
100 template<class Node,
101 StaticDegreeConcept<Node> = true>
102 auto operator()(const Node& node, Dune::PriorityTag<1>)
103 {
104 return Dune::unpackIntegerSequence([&](auto... indices) {
105 return Dune::makeTupleVector((*this)(node.child(indices))...);
106 }, std::make_index_sequence<std::size_t(Node::degree())>());
107 }
108
109 private:
110 LeafToValue leafToValue_;
111 };
112
113
114 /*
115 * \brief Wrap nested container to provide a VectorBackend
116 */
117 template<class Container>
118 class TreeContainerVectorBackend
119 {
120 template<class C>
121 static constexpr decltype(auto) accessByTreePath(C&& container, const HybridTreePath<>& path)
122 {
123 return container;
124 }
125
126 template<class C, class... T>
127 static constexpr decltype(auto) accessByTreePath(C&& container, const HybridTreePath<T...>& path)
128 {
129 auto head = path[Dune::Indices::_0];
130 auto tailPath = Dune::unpackIntegerSequence([&](auto... i){
131 return treePath(path[Dune::index_constant<i+1>{}]...);
132 }, std::make_index_sequence<sizeof...(T)-1>());
133 return accessByTreePath(container[head], tailPath);
134 }
135
136 template<class C, class Tree,
137 std::enable_if_t<Tree::isLeaf, bool> = true>
138 static void resizeImpl(C& /*container*/, const Tree& /*tree*/, Dune::PriorityTag<2>)
139 {
140 /* do nothing */
141 }
142
143 template<class C, class Tree,
144 class = decltype(std::declval<C>().resize(0u))>
145 static void resizeImpl(C& container, const Tree& tree, Dune::PriorityTag<1>)
146 {
147 container.resize(tree.degree());
148 Dune::Hybrid::forEach(Dune::range(tree.degree()), [&](auto i) {
149 resizeImpl(container[i], tree.child(i), Dune::PriorityTag<5>{});
150 });
151 }
152
153 template<class C, class Tree>
154 static void resizeImpl(C& container, const Tree& tree, Dune::PriorityTag<0>)
155 {
156 Dune::Hybrid::forEach(Dune::range(tree.degree()), [&](auto i) {
157 resizeImpl(container[i], tree.child(i), Dune::PriorityTag<5>{});
158 });
159 }
160
161 template<class T>
162 using TypeTreeConcept = decltype((
163 std::declval<T>().degree(),
164 T::isLeaf,
165 T::isPower,
166 T::isComposite,
167 true));
168
169 public:
171 TreeContainerVectorBackend(Container&& container) :
172 container_(std::move(container))
173 {}
174
176 template <class Tree, TypeTreeConcept<Tree> = true>
177 TreeContainerVectorBackend(const Tree& tree) :
178 TreeContainerVectorBackend()
179 {
180 this->resize(tree);
181 }
182
184 template <class C = Container,
185 std::enable_if_t<std::is_default_constructible_v<C>, bool> = true>
186 TreeContainerVectorBackend() :
187 container_()
188 {}
189
190 template<class... T>
191 decltype(auto) operator[](const HybridTreePath<T...>& path) const
192 {
193 return accessByTreePath(container_, path);
194 }
195
196 template<class... T>
197 decltype(auto) operator[](const HybridTreePath<T...>& path)
198 {
199 return accessByTreePath(container_, path);
200 }
201
203 template<class Tree, TypeTreeConcept<Tree> = true>
204 void resize(const Tree& tree)
205 {
206 resizeImpl(container_, tree, Dune::PriorityTag<5>{});
207 }
208
209 const Container& data() const
210 {
211 return container_;
212 }
213
214 Container& data()
215 {
216 return container_;
217 }
218
219 private:
220 Container container_;
221 };
222
223 template<class Container>
224 auto makeTreeContainerVectorBackend(Container&& container)
225 {
226 return TreeContainerVectorBackend<std::decay_t<Container>>(std::forward<Container>(container));
227 }
228
229 /*
230 * \brief A simple lambda for creating default constructible values from a node
231 *
232 * This simply returns LeafToValue<Node>{} for a given Node. It's needed
233 * because using a lambda expression in a using declaration is not allowed
234 * because it's an unevaluated context.
235 */
236 template<template<class Node> class LeafToValue>
237 struct LeafToDefaultConstructibleValue
238 {
239 template<class Node>
240 auto operator()(const Node& node) const
241 {
242 return LeafToValue<Node>{};
243 }
244 };
245
246 } // namespace Detail
247
267 template<class Tree, class LeafToValue>
268 auto makeTreeContainer(const Tree& tree, LeafToValue&& leafToValue)
269 {
270 auto f = std::ref(leafToValue);
271 auto factory = Detail::ContainerFactory<decltype(f)>(f);
272 return Detail::makeTreeContainerVectorBackend(factory(tree));
273 }
274
290 template<class Value, class Tree>
291 auto makeTreeContainer(const Tree& tree)
292 {
293 return makeTreeContainer(tree, [](const auto&) {return Value{};});
294 }
295
299 template<class Value, class Tree>
300 using UniformTreeContainer = std::decay_t<decltype(makeTreeContainer<Value>(std::declval<const Tree&>()))>;
301
305 template<template<class Node> class LeafToValue, class Tree>
306 using TreeContainer = std::decay_t<decltype(makeTreeContainer(std::declval<const Tree&>(), std::declval<Detail::LeafToDefaultConstructibleValue<LeafToValue>>()))>;
307
309
310 } // namespace TypeTree
311} //namespace Dune
312
313#endif // DUNE_TYPETREE_TREECONTAINER_HH
constexpr index_constant< 0 > _0
Compile time index with value 0.
Definition: indices.hh:52
decltype(auto) constexpr 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:124
std::integral_constant< std::size_t, i > index_constant
An index constant with value i.
Definition: indices.hh:29
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 auto treePath(const T &... t)
Constructs a new HybridTreePath from the given indices.
Definition: treepath.hh:326
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:300
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:306
auto makeTreeContainer(const Tree &tree)
Create container havin the same structure as the given tree.
Definition: treecontainer.hh:291
Dune namespace.
Definition: alignedallocator.hh:13
constexpr std::integral_constant< T, I0 > head(std::integer_sequence< T, I0, II... >)
For a sequence [head,tail...) return the single head element.
Definition: integersequence.hh:53
STL namespace.
Utilities for reduction like operations on ranges.
Helper class for tagging priorities.
Definition: typeutilities.hh:87
Helper class for tagging priorities.
Definition: typeutilities.hh:73
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 (Nov 24, 23:30, 2024)