Traversal.hpp 3.92 KB
Newer Older
1
#pragma once
2
3
4
5
6

#include <dune/typetree/nodetags.hh>
#include <dune/typetree/treepath.hh>
#include <dune/typetree/visitor.hh>

7
8
namespace AMDiS
{
9
  // forward declaration of main engine struct
10
  template <typename NodeTag, bool visit = true>
11
12
  struct TraverseTree;

13

14
15
16
17
18
  // Do not visit nodes the visitor is not interested in
  template <typename NodeTag>
  struct TraverseTree<NodeTag, false>
  {
    template <typename Node, typename Visitor, typename TreePath>
19
    static void apply(const Node& node, const Visitor& visitor, TreePath const& tp)
20
21
    {}
  };
22

23
#ifndef DOXYGEN
24

25
  // some implementation details
26

27
28
29
  template <class Node, class Index>
  struct HybridChildType
      : HybridChildType<std::remove_const_t<Node>, std::remove_const_t<Index>> {};
30

31
32
  template <class Node>
  struct HybridChildType<Node, std::size_t>
33
  {
34
    using type = typename Node::template Child<0>::Type;
35
  };
36

37
38
39
40
41
  template <class Node, std::size_t K>
  struct HybridChildType<Node, Dune::index_constant<K>>
  {
    using type = typename Node::template Child<K>::Type;
  };
42

43
44
45
46
47
  template <class NodeTag, class Node>
  constexpr std::size_t hybridDegree(NodeTag, Node const& node)
  {
    return Dune::TypeTree::degree(node);
  }
48

49
50
  template <class Node>
  constexpr auto hybridDegree(Dune::TypeTree::CompositeNodeTag, Node const& node)
51
  {
52
53
    return Dune::index_constant<Node::CHILDREN>{};
  }
54
55


56
57
58
59
60
61
62
63
64
65
  template <std::size_t k, std::size_t n>
  constexpr bool notLastChild(Dune::index_constant<k> const&, Dune::index_constant<n> const&)
  {
    return k < n-1;
  }

  constexpr bool notLastChild(std::size_t k, std::size_t n)
  {
    return k < n-1;
  }
66

67
#endif
68
69


70
71
72
73
74
75
76
77
78
79
80
81
82
  template <class NodeTag>
  struct TraverseTree<NodeTag, true>
  {
    template <typename N, typename V, typename TreePath>
    static void apply(N&& n, V&& v, TreePath const& tp)
    {
      using Node = std::remove_reference_t<N>;
      using Visitor = std::remove_reference_t<V>;

      v.pre(std::forward<N>(n),tp);

      auto const deg = hybridDegree(NodeTag{}, n);
      forEach(Dune::range(deg), [&](auto const _k)
83
84
      {
        // always call beforeChild(), regardless of the value of visit
85
        v.beforeChild(std::forward<N>(n),n.child(_k),tp,_k);
86

87
        // descend to child
88
89
90
        using C = typename HybridChildType<Node, decltype(_k)>::type;
        const bool visit = Visitor::template VisitChild<Node,C,TreePath>::value;
        TraverseTree<Dune::TypeTree::NodeTag<C>,visit>::apply(n.child(_k),std::forward<V>(v),push_back(tp, _k));
91

92
        // always call afterChild(), regardless of the value of visit
93
        v.afterChild(std::forward<N>(n),n.child(_k),tp,_k);
94

95
        // if this is not the last child, call infix callback
96
        if (notLastChild(_k, deg))
97
          v.in(std::forward<N>(n),tp);
98
      });
99

100
101
102
      v.post(std::forward<N>(n),tp);
    }
  };
103

104
  // LeafNode - just call the leaf() callback
105
  template <>
106
  struct TraverseTree<Dune::TypeTree::LeafNodeTag, true>
107
108
  {
    template <typename N, typename V, typename TreePath>
109
    static void apply(N&& n, V&& v, TreePath const& tp)
110
    {
111
      v.leaf(std::forward<N>(n),tp);
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
    }
  };

  //! Apply visitor to TypeTree.
  /**
    * This function applies the given visitor to the given tree. Both visitor and tree may be const
    * or non-const (if the compiler supports rvalue references, they may even be a non-const temporary).
    *
    * \note The visitor must implement the interface laid out by DefaultVisitor (most easily achieved by
    *       inheriting from it).
    *
    * \param tree    The tree the visitor will be applied to.
    * \param visitor The visitor to apply to the tree.
    */
  template <typename Tree, typename Visitor>
  void traverseTree(Tree&& tree, Visitor&& visitor)
  {
129
130
131
132
    using Node = std::remove_reference_t<Tree>;
    using NodeTag = Dune::TypeTree::NodeTag<Node>;
    using TreePath = Dune::TypeTree::HybridTreePath<>;
    TraverseTree<NodeTag>::apply(std::forward<Tree>(tree), std::forward<Visitor>(visitor), TreePath{});
133
134
135
  }

} // end namespace AMDiS