dune-typetree  2.8.0
treecontainer.hh
Go to the documentation of this file.
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 
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>
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>
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) :
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>
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>
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
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
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:126
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
Definition: accumulate_static.hh:13
auto makeTreeContainerVectorBackend(Container &&container)
Definition: treecontainer.hh:222
Definition: treecontainer.hh:37
auto operator()(const Node &node)
Definition: treecontainer.hh:61
ContainerFactory(LeafToValue leafToValue)
Create ContainerFactory.
Definition: treecontainer.hh:56
void resize(const Tree &tree)
Resize the (nested) container depending on the degree of the tree nodes.
Definition: treecontainer.hh:202
Container & data()
Definition: treecontainer.hh:212
TreeContainerVectorBackend(Container &&container)
Move the passed container into the internal storage.
Definition: treecontainer.hh:169
TreeContainerVectorBackend()
Default constructor. The stored container might need to be resized before usage.
Definition: treecontainer.hh:184
TreeContainerVectorBackend(const Tree &tree)
Default construct the container and perform a resize depending on the tree-node degrees.
Definition: treecontainer.hh:175
const Container & data() const
Definition: treecontainer.hh:207
auto operator()(const Node &node) const
Definition: treecontainer.hh:238
A hybrid version of TreePath that supports both compile time and run time indices.
Definition: treepath.hh:79