dune-common  2.11
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 // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root
4 // SPDX-License-Identifier: LicenseRef-GPL-2.0-only-with-DUNE-exception OR LGPL-3.0-or-later
5 
6 #ifndef DUNE_COMMON_TYPETREE_TREECONTAINER_HH
7 #define DUNE_COMMON_TYPETREE_TREECONTAINER_HH
8 
9 #include <type_traits>
10 #include <utility>
11 #include <functional>
12 #include <array>
13 
14 #include <dune/common/indices.hh>
18 
21 
22 namespace Dune::TypeTree {
23 
24  namespace Impl {
25 
37  template<class LeafToValue>
38  class ContainerFactory
39  {
40  public:
41 
49  ContainerFactory(LeafToValue leafToValue) :
50  leafToValue_(leafToValue)
51  {}
52 
53  template<class Node>
54  requires Dune::TypeTree::Concept::TreeNode<Node>
55  auto operator()(const Node& node)
56  {
57  if constexpr (Dune::TypeTree::Concept::LeafTreeNode<Node>)
58  return leafToValue_(node);
59  else
60  {
61  if constexpr (Dune::TypeTree::Concept::UniformInnerTreeNode<Node>)
62  {
63  if constexpr (Dune::TypeTree::Concept::StaticDegreeInnerTreeNode<Node>)
64  {
65  return Dune::unpackIntegerSequence([&](auto... indices) {
66  return std::array{(*this)(node.child(indices))...};
67  }, std::make_index_sequence<std::size_t(Node::degree())>());
68  }
69  else
70  {
71  using TransformedChild = decltype((*this)(node.child(0)));
72  std::vector<TransformedChild> container;
73  container.reserve(node.degree());
74  for (std::size_t i = 0; i < node.degree(); ++i)
75  container.emplace_back((*this)(node.child(i)));
76  return container;
77  }
78  }
79  else
80  {
81  return Dune::unpackIntegerSequence([&](auto... indices) {
82  return Dune::makeTupleVector((*this)(node.child(indices))...);
83  }, std::make_index_sequence<std::size_t(Node::degree())>());
84  }
85  }
86  }
87 
88  private:
89  LeafToValue leafToValue_;
90  };
91 
92 
93  /*
94  * \brief Wrap nested container to provide a VectorBackend
95  */
96  template<class Container>
97  class TreeContainerVectorBackend
98  {
99  template<class C>
100  static constexpr decltype(auto) accessByTreePath(C&& container, const TreePath<>& path)
101  {
102  return container;
103  }
104 
105  template<class C, class... T>
106  static constexpr decltype(auto) accessByTreePath(C&& container, const TreePath<T...>& path)
107  {
108  auto head = path[Dune::Indices::_0];
109  auto tailPath = Dune::unpackIntegerSequence([&](auto... i){
110  return treePath(path[Dune::index_constant<i+1>{}]...);
111  }, std::make_index_sequence<sizeof...(T)-1>());
112  return accessByTreePath(container[head], tailPath);
113  }
114 
115 
116  template<class C, class Tree>
117  static void recursiveResize(C& container, const Tree& tree)
118  {
119  if constexpr (not Dune::TypeTree::Concept::LeafTreeNode<Tree>)
120  {
121  if constexpr (requires { container.resize(0u); })
122  container.resize(tree.degree());
123  Dune::Hybrid::forEach(Dune::range(tree.degree()), [&](auto i) {
124  recursiveResize(container[i], tree.child(i));
125  });
126  }
127  }
128 
129  public:
131  TreeContainerVectorBackend(Container&& container) :
132  container_(std::move(container))
133  {}
134 
136  template <class Tree>
137  requires Dune::TypeTree::Concept::TreeNode<Tree>
138  TreeContainerVectorBackend(const Tree& tree) :
139  TreeContainerVectorBackend()
140  {
141  this->resize(tree);
142  }
143 
145  template <class C = Container,
146  std::enable_if_t<std::is_default_constructible_v<C>, bool> = true>
147  TreeContainerVectorBackend() :
148  container_()
149  {}
150 
151  template<class... T>
152  decltype(auto) operator[](const TreePath<T...>& path) const
153  {
154  return accessByTreePath(container_, path);
155  }
156 
157  template<class... T>
158  decltype(auto) operator[](const TreePath<T...>& path)
159  {
160  return accessByTreePath(container_, path);
161  }
162 
164  template<class Tree>
165  requires Dune::TypeTree::Concept::TreeNode<Tree>
166  void resize(const Tree& tree)
167  {
168  recursiveResize(container_, tree);
169  }
170 
171  const Container& data() const
172  {
173  return container_;
174  }
175 
176  Container& data()
177  {
178  return container_;
179  }
180 
181  private:
182  Container container_;
183  };
184 
185  template<class Container>
186  auto makeTreeContainerVectorBackend(Container&& container)
187  {
188  return TreeContainerVectorBackend<std::decay_t<Container>>(std::forward<Container>(container));
189  }
190 
191  /*
192  * \brief A simple lambda for creating default constructible values from a node
193  *
194  * This simply returns LeafToValue<Node>{} for a given Node. It's needed
195  * because using a lambda expression in a using declaration is not allowed
196  * because it's an unevaluated context.
197  */
198  template<template<class Node> class LeafToValue>
199  struct LeafToDefaultConstructibleValue
200  {
201  template<class Node>
202  auto operator()(const Node& node) const
203  {
204  return LeafToValue<Node>{};
205  }
206  };
207 
208  } // namespace Impl
209 
229  template<class Tree, class LeafToValue>
230  auto makeTreeContainer(const Tree& tree, LeafToValue&& leafToValue)
231  {
232  auto f = std::ref(leafToValue);
233  auto factory = Impl::ContainerFactory<decltype(f)>(f);
234  return Impl::makeTreeContainerVectorBackend(factory(tree));
235  }
236 
252  template<class Value, class Tree>
253  auto makeTreeContainer(const Tree& tree)
254  {
255  return makeTreeContainer(tree, [](const auto&) {return Value{};});
256  }
257 
261  template<class Value, class Tree>
262  using UniformTreeContainer = std::decay_t<decltype(makeTreeContainer<Value>(std::declval<const Tree&>()))>;
263 
267  template<template<class Node> class LeafToValue, class Tree>
268  using TreeContainer = std::decay_t<decltype(makeTreeContainer(std::declval<const Tree&>(), std::declval<Impl::LeafToDefaultConstructibleValue<LeafToValue>>()))>;
269 
271 
272 } //namespace Dune::TypeTree
273 
274 #endif // DUNE_COMMON_TYPETREE_TREECONTAINER_HH
Provides the TupleVector class that augments std::tuple by operator[].
decltype(auto) constexpr unpackIntegerSequence(F &&f, [[maybe_unused]] std::integer_sequence< I, i... > sequence)
Unpack an std::integer_sequence<I,i...> to std::integral_constant<I,i>...
Definition: indices.hh:124
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:262
std::integral_constant< std::size_t, i > index_constant
An index constant with value i.
Definition: indices.hh:29
I i
Definition: hybridmultiindex.hh:328
Utilities for reduction like operations on ranges.
Definition: childaccess.hh:23
Dune::HybridMultiIndex< T... > TreePath
A type for representing tree paths that supports both compile time and run time indices.
Definition: treepath.hh:43
static constexpr IntegralRange< std::decay_t< T > > range(T &&from, U &&to) noexcept
free standing function for setting up a range based for loop over an integer range for (auto i: range...
Definition: rangeutilities.hh:288
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
requires(((std::is_integral_v< T > or Dune::IsIntegralConstant< T >::value) &&...)) const expr auto treePath(const T &... t)
Constructs a new TreePath from the given indices.
Definition: treepath.hh:54
std::decay_t< decltype(makeTreeContainer(std::declval< const Tree & >(), std::declval< Impl::LeafToDefaultConstructibleValue< LeafToValue > >()))> TreeContainer
Alias to container type generated by makeTreeContainer for give tree type and when using LeafToValue ...
Definition: treecontainer.hh:268
constexpr index_constant< 0 > _0
Compile time index with value 0.
Definition: indices.hh:52
STL namespace.
constexpr void forEach(Range &&range, F &&f)
Range based for loop.
Definition: hybridutilities.hh:261
auto makeTreeContainer(const Tree &tree, LeafToValue &&leafToValue)
Create container having the same structure as the given tree.
Definition: treecontainer.hh:230