TreeData.hpp 6.92 KB
Newer Older
1
2
#pragma once

3
#include <algorithm>
4
5
#include <type_traits>
#include <utility>
6
#include <vector>
7

8
//#include <dune/typetree/traversal.hh>
9
#include <dune/typetree/typetree.hh>
10
#include <amdis/utility/Visitor.hpp>
11
12
13

namespace AMDiS
{
14
15
16
17
18
  namespace tag
  {
    struct store {};
  }

19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
  /**
  * \brief Container allowing to attach data to each node of a tree
  *
  * \ingroup Utility
  *
  * This provides operator[](Node) for accessing the data attached to the node.
  * For storing the data each node is identified via its treeIndex() method
  * which is supposed to return an index which is unique wrt the tree. These
  * indices need not to be consecutive but they are used to access an
  * internal vector<void*>. This may lead to wasted memory if the maximal
  * treeIndex() is much larger then the number of nodes within the tree.
  *
  * Before using the container it must be initialized by providing the
  * tree. The stored data objects will be created on initialization. Hence
  * the type of these data objects must be default constructible.
  *
  * Notice that the data per node can only be interpreted if the
  * node type is known. Hence the tree will be traversed on initilization,
  * copy, assignment, and destruction of a TreeData container.
  *
  * \tparam T Type of the tree
  * \tparam ND The data stored for a node of type Node will be of type ND<Node>
  * \tparam LO Set this flag if data should only be attached to leaf nodes.
  */
43
  template <class T, template<class> class ND, bool LO>
44
45
46
47
48
49
50
51
52
53
54
55
56
  class TreeData
  {
  public:
    //! Type of tree the data is associated with
    using Tree = T;

    //! Type used for indices and size information
    using size_type = typename Tree::size_type;

    //! Set if data should only be associated to the leafs
    static const bool leafOnly = LO;

    //! Template to determine the data type for given node type
57
    template <class Node>
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
    using NodeData = ND<Node>;

  public:
    //! Default constructor
    TreeData()
      : tree_(nullptr)
    {}

    /**
      * \brief Construct from tree
      *
      * This default creates the data object associated to each node in the tree.
      * A reference to the tree is stored because it's needed for destruction
      * of the tree data.
      * See also \ref init.
      */
74
    TreeData(Tree const& tree, tag::store)
75
76
77
78
79
      : tree_(&tree)
    {
      initData();
    }

80
81
82
83
    explicit TreeData(Tree& tree)
      : TreeData(tree, tag::store{})
    {}

84
    //! Copy constructor
85
86
    TreeData(TreeData const& other)
      : tree_(other.tree_)
87
    {
88
      initData();
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
      copyData(other);
    }

    //! Move constructor
    TreeData(TreeData&& other)
      : TreeData()
    {
      swap(other);
    }

    /**
      * \brief Initialize from tree
      *
      * This default creates the data object associated to each node in the tree.
      * A reference to the tree is stored because it's needed for destruction
      * of the tree data.
      */
106
    void init(Tree const& tree, tag::store)
107
108
109
110
111
112
    {
      destroyData();
      tree_ = &tree;
      initData();
    }

113
114
115
116
117
    void init(Tree& tree)
    {
      init(tree, tag::store{});
    }

118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
    //! Copy and Move assignment
    TreeData& operator=(TreeData other)
    {
      swap(other);
      return *this;
    }

    //! Destructor
    ~TreeData()
    {
      destroyData();
    }

    //! Return the attached tree (maybe nullptr)
    Tree const* tree() const
    {
      return tree_;
    }

    //! Get mutable reference to data associated to given node
    template<class Node>
    NodeData<Node>& operator[](const Node& node)
    {
141
142
      assert(initialized_);
      assert(data_.size() > node.treeIndex());
143
144
145
146
147
148
149
      return *(NodeData<Node>*)(data_[node.treeIndex()]);
    }

    //! Get reference to data associated to given node
    template<class Node>
    const NodeData<Node>& operator[](const Node& node) const
    {
150
151
      assert(initialized_);
      assert(data_.size() > node.treeIndex());
152
153
154
155
156
157
158
159
160
      return *(NodeData<Node>*)(data_[node.treeIndex()]);
    }

    //! Swap tree and data container with `other`
    void swap(TreeData& other)
    {
      using std::swap;
      swap(tree_, other.tree_);
      swap(data_, other.data_);
161
      swap(initialized_, other.initialized_);
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
    }

  protected:
    // For each node allocate memory and store the void* in the \ref data_
    void initData()
    {
      std::size_t s = 0;
      apply([&s](const auto& node, auto) {
        s = std::max(s, node.treeIndex()+1);
      });

      data_.resize(s, nullptr);
      apply([this](const auto& node, auto) {
        using Node = std::remove_reference_t<decltype(node)>;
        data_[node.treeIndex()] = new NodeData<Node>;
      });
178
      initialized_ = true;
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
    }

    // Deep copy of node data
    void copyData(const TreeData& other)
    {
      apply([&other,this](const auto& node, auto) {
        (*this)[node] = other[node];
      });
    }

    // For each node, delete the allocated node data
    void destroyData()
    {
      apply([this](const auto& node, auto) {
        using Node = std::remove_reference_t<decltype(node)>;
        auto* p = (NodeData<Node>*)(data_[node.treeIndex()]);
        delete p;
      });
      tree_ = nullptr;
198
      initialized_ = false;
199
200
201
202
203
204
205
206
207
208
209
210
    }

  protected:
    // apply functor `func` to each (leaf) node of the tree, but only if `tree_` is set
    template <class Func>
    void apply(Func&& func)
    {
      if (tree_)
        applyImpl(func, std::integral_constant<bool, leafOnly>{});
    }

    template <class Func>
211
    void applyImpl(Func&& func, std::true_type) { forEachLeafNode_(*tree_, func); }
212
213

    template <class Func>
214
    void applyImpl(Func&& func, std::false_type) { forEachNode_(*tree_, func); }
215
216
217
218

  protected:
    const Tree* tree_ = nullptr;
    std::vector<void*> data_;
219
220

    bool initialized_ = false;
221
222
223
  };


224
225
  namespace Impl
  {
226
    template <class Tree, template <class,class> class NodeData>
227
228
    struct RowNodeData
    {
229
230
231
232
233
234
235
236
237
      template <class RowNode>
      struct ColNodeData
      {
        template <class ColNode>
        using type = NodeData<RowNode, ColNode>;
      };

      template <class RowNode>
      using type = TreeData<Tree, ColNodeData<RowNode>::template type, false>;
238
239
    };

240
241
242
  } // end namespace Impl


243
  template <class GlobalBasis, template <class,class> class NodeData,
244
    class Tree = typename GlobalBasis::LocalView::Tree,
245
    template <class> class ND = Impl::RowNodeData<Tree, NodeData>::template type>
246
  class MatrixData
247
      : public TreeData<Tree, ND, false>
248
  {
249
    using Super = TreeData<Tree, ND, false>;
250
251

  public:
252
    void init(Tree const& tree, tag::store)
253
    {
254
      Super::init(tree, tag::store{});
255
      forEachNode_(tree, [&,this](auto const& node, auto&&)
256
      {
257
        (*this)[node].init(tree, tag::store{});
258
259
      });
    }
260
261
262
263
264

    void init(Tree& tree)
    {
      init(tree, tag::store{});
    }
265
266
267
  };


268
  template <class GlobalBasis, template <class> class NodeData,
269
270
    class Tree = typename GlobalBasis::LocalView::Tree>
  class VectorData
271
      : public TreeData<Tree, NodeData, false>
272
  {};
273
274

} // end namespace AMDiS