TreeContainer.hpp 11.8 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
#pragma once

#include <array>
#include <functional>
#include <type_traits>
#include <utility>

#include <dune/common/indices.hh>
#include <dune/common/tuplevector.hh>

#include <dune/typetree/treepath.hh>

#include <amdis/common/Apply.hpp>
Praetorius, Simon's avatar
Praetorius, Simon committed
14
#include <amdis/common/TypeTraits.hpp>
15
#include <amdis/typetree/TreePath.hpp>
16
17
18
19
20

// NOTE: backport of dune/typetree/treecontainer.hh

namespace AMDiS
{
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
  /// \brief Vector data-structure with tree-path index access and hierarchic structure
  /// given by the `Container` template type
  /**
   * This Vector container is parametrized with the actual container type that is stored
   * internally. Access to the elements of the container is possible by using a tree-path
   * index.
   *
   * The internal container is constructed by the \ref ContainerFactory, storing for each
   * tree node a corresponding array or tuple plus a value. The data-structure to hold
   * both, the value and the container is defined in \ref ValueAndContainer.
   **/
  template <class Container>
  class TreeContainerStorage
  {
    using Self = TreeContainerStorage;

    template <class C>
    static constexpr decltype(auto)
    accessByTreePath(C&& container, Dune::TypeTree::HybridTreePath<> const&)
    {
      return container.value();
    }

    template <class C, class... T>
    static constexpr decltype(auto)
    accessByTreePath(C&& container, Dune::TypeTree::HybridTreePath<T...> const& path)
    {
      auto head = Dune::TypeTree::treePathEntry(path,Dune::Indices::_0);
      return accessByTreePath(container[head], pop_front(path));
    }

  public:
    /// \brief Default-construct the tree-container
    TreeContainerStorage()
      : container_()
    {}

    TreeContainerStorage(Container const& container)
      : container_(container)
    {}

    /// \brief Construct the tree-container from a given container storage
    TreeContainerStorage(Container&& container)
      : container_(std::move(container))
    {}

    /// \brief Access a (const) element of the container by treepath
    template <class... T>
    decltype(auto) operator[](Dune::TypeTree::HybridTreePath<T...> const& path) const
    {
      return accessByTreePath(container_, path);
    }

    /// \brief Access a (mutable) element of the container by treepath
    template <class... T>
    decltype(auto) operator[](Dune::TypeTree::HybridTreePath<T...> const& path)
    {
      return accessByTreePath(container_, path);
    }

    /// \brief Obtain the container (const)
    Container const& data() const
    {
      return container_;
    }

    /// \brief Obtain the container (mutable)
    Container& data()
    {
      return container_;
    }

    /// \brief Compare two containers for equality
    bool operator==(TreeContainerStorage const& other) const
    {
      return container_ == other.container_;
    }

    /// \brief Compare two containers for inequality
    bool operator!=(TreeContainerStorage const& other) const
    {
      return container_ != other.container_;
    }

  private:
    Container container_;
  };


110
111
  namespace Impl
  {
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
    template <class Value, class Container>
    class ValueAndContainer
    {
    public:
      template <class V, class C>
      ValueAndContainer(V&& value, C&& container)
        : value_(FWD(value))
        , container_(FWD(container))
      {}

      ValueAndContainer()
        : value_()
        , container_()
      {}

      template <class I>
      auto& operator[](I const& i) { return container_[i]; }

      template <class I>
      auto const& operator[](I const& i) const { return container_[i]; }

      Value& value() { return value_; }
      Value const& value() const { return value_; }

      Container& container() { return container_; }
      Container const& container() const { return container_; }

      bool operator==(ValueAndContainer const& other) const
      {
        return value_ == other.value_ && container_ == other.container_;
      }

    private:
      Value value_;
      Container container_;
    };

    template <class Value>
    class ValueAndContainer<Value,void>
    {
    public:
      template <class V, Dune::disableCopyMove<ValueAndContainer,V> = 0>
      ValueAndContainer(V&& value)
        : value_(FWD(value))
      {}

      ValueAndContainer()
        : value_()
      {}

      Value& value() { return value_; }
      Value const& value() const { return value_; }

      bool operator==(ValueAndContainer const& other) const
      {
        return value_ == other.value_;
      }

    private:
      Value value_;
    };

    struct Ignore{};

    template <class Container>
    class ValueAndContainer<Ignore,Container>
    {
    public:
      template <class C>
      ValueAndContainer(Ignore, C&& container)
        : container_(FWD(container))
      {}

      ValueAndContainer()
        : container_()
      {}

      template <class I>
      auto& operator[](I const& i) { return container_[i]; }

      template <class I>
      auto const& operator[](I const& i) const { return container_[i]; }

      Ignore value() { return {}; }
      Ignore value() const { return {}; }

      Container& container() { return container_; }
      Container const& container() const { return container_; }

      bool operator==(ValueAndContainer const& other) const
      {
        return container_ == other.container_;
      }

    private:
      Container container_;
    };


    template <class Value, class Container>
    ValueAndContainer(Value const&, Container const&)
      -> ValueAndContainer<Value,Container>;

    template <class Value>
    ValueAndContainer(Value const&)
      -> ValueAndContainer<Value,void>;


220
221
    /// \brief A factory class creating a hybrid container compatible with a type tree
    /**
222
223
224
225
226
227
228
229
230
231
     * This class allows to create a nested hybrid container having the same structure
     * as a given type tree. Power nodes are represented as std::array's while composite
     * nodes are represented as Dune::TupleVector's. The stored values for the leaf nodes
     * are creating using a given predicate. Once created, the factory provides an
     * operator() creating the container for the tree given as argument.
     *
     * \tparam NodeToValue Type of a predicate that determines the stored values at the
     *                     leafs
     **/
    template <class NodeToValue, bool leafOnly = false>
232
233
234
    class ContainerFactory
    {
    public:
235
      /// \brief Create ContainerFactory
236
237
238
239
240
      /**
        * The given predicate will be stored by value.
        *
        * \param A predicate used to generate the stored values for the leaves
        */
241
242
      ContainerFactory(NodeToValue nodeToValue)
        : nodeToValue_(std::move(nodeToValue))
243
244
      {}

245
246
      /// \brief Return a container for storing the node content
      template <class Node>
247
      auto operator()(Node const& node) const
248
      {
249
        if constexpr (Node::isLeaf)
250
          return ValueAndContainer{value(node)};
251
252
253
        else
        if constexpr (Node::isPower) {
          using TransformedChild = decltype((*this)(node.child(0)));
254
255
256
          return ValueAndContainer{
            value(node),
            std::array<TransformedChild, Node::degree()>()};
257
258
259
        }
        else
        if constexpr (Node::isComposite) {
260
261
262
263
          return ValueAndContainer{
            value(node),
            Tools::apply_indices<Node::degree()>(
            [&](auto... i) { return Dune::makeTupleVector((*this)(node.child(i))...); })};
264
265
266
267
268
269
        }
        else {
          static_assert(Node::isLeaf || Node::isPower || Node::isComposite,
            "Node must be one of leaf,power,composite.");
          return;
        }
270
271
      }

272
273
      template <class Node>
      decltype(auto) value(Node const& node) const
274
      {
275
276
277
278
        if constexpr(!Node::isLeaf && leafOnly)
          return Ignore{};
        else
          return nodeToValue_(node);
279
280
      }

281
    private:
282
      NodeToValue nodeToValue_;
283
284
285
286
287
    };

  } // end namespace Impl


288
  /// \brief Create container having the same structure as the given tree
289
290
291
292
293
294
295
296
  /**
   * This class allows to create a nested hybrid container having the same structure
   * as a given type tree. Power nodes are represented as std::array's while composite
   * nodes are represented as Dune::TupleVector's. The stored values for the leaf nodes
   * are creating using a given predicate. For convenience the created container is
   * not returned directly. Instead, the returned object stores the container and
   * provides operator[] access using a HybridTreePath.
   *
297
298
   * \param tree        The tree which should be mapper to a container
   * \param nodeToValue A predicate used to generate the stored values for the nodes
299
300
301
   *
   * \returns A container matching the tree structure
   */
302
303
  template <bool leafOnly = false, class Tree, class NodeToValue>
  auto makeTreeContainer(Tree const& tree, NodeToValue&& nodeToValue)
304
  {
305
306
307
    auto f = std::ref(nodeToValue);
    auto factory = Impl::ContainerFactory<decltype(f),leafOnly>(f);
    return TreeContainerStorage{factory(tree)};
308
309
310
  }


311
  /// \brief Create container having the same structure as the given tree
312
313
314
315
316
317
318
319
  /**
   * This class allows to create a nested hybrid container having the same structure
   * as a given type tree. Power nodes are represented as std::array's while composite
   * nodes are represented as Dune::TupleVector's. The stored values for the leaf nodes
   * are of the given type Value. For convenience the created container is
   * not returned directly. Instead, the returned object stores the container and
   * provides operator[] access using a HybridTreePath.
   *
320
321
322
   * \tparam Value      Type of the values to be stored for the leafs. Should be default
   *                    constructible.
   * \param nodeToValue A predicate used to generate the stored values for the nodes
323
   *
324
   * \returns           A container matching the tree structure
325
   */
326
  template <class Value, bool leafOnly = false, class Tree>
327
328
  auto makeTreeContainer(Tree const& tree)
  {
329
    return makeTreeContainer<leafOnly>(tree, [](auto&&) { return Value{}; });
330
  }
331

332
  template <template<class> class NodeData, bool leafOnly = false, class Tree>
333
334
  auto makeTreeContainer(Tree const& tree)
  {
335
    return makeTreeContainer<leafOnly>(tree, [](auto&& node) { return NodeData<TYPEOF(node)>{}; });
336
  }
337

338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
  /// Alias to container type generated by makeTreeContainer for given tree type and
  /// uniform value type
  template <class Value, class Tree, bool leafOnly = false>
  using UniformTreeContainer
    = TYPEOF(makeTreeContainer<Value,leafOnly>(std::declval<const Tree&>()));

  /// Alias to matrix-container type generated by makeTreeContainer for given tree types
  /// and uniform value type
  template <class Value, class RowTree, class ColTree = RowTree, bool leafOnly = false>
  using UniformTreeMatrix
    = UniformTreeContainer<UniformTreeContainer<Value,ColTree,leafOnly>,RowTree,leafOnly>;

  /// Alias to container type generated by makeTreeContainer for give tree type and when
  /// using NodeToValue to create values
  template <template <class Node> class NodeData, class Tree, bool leafOnly = false>
  using TreeContainer
    = TYPEOF(makeTreeContainer<NodeData,leafOnly>(std::declval<const Tree&>()));


  namespace Impl
  {
    template <template <class,class> class NodeData, class Tree, bool leafOnly>
    struct RowNodeData
    {
      template <class RowNode>
      struct ColNodeData
      {
        template <class ColNode>
        using type = NodeData<RowNode, ColNode>;
      };

      template <class RowNode>
      using type = TreeContainer<ColNodeData<RowNode>::template type, Tree, leafOnly>;
    };

  } // end namespace Impl
374

375
376
377
378
379
  /// Alias to matrix-container type generated by makeTreeContainer for give tree type
  /// and when using NodeToValue to create values
  template <template <class,class> class NodeData, class RowTree, class ColTree = RowTree, bool leafOnly = false>
  using TreeMatrix
    = TreeContainer<Impl::RowNodeData<NodeData,ColTree,leafOnly>::template type,RowTree,leafOnly>;
380
381

} //namespace AMDiS