Traversal.hpp 3.95 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
#include <amdis/common/Loops.hpp>

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

15

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

25
#ifndef DOXYGEN
26

27
  // some implementation details
28

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

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

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

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

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


58
59
60
61
62
63
64
65
66
67
  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;
  }
68

69
#endif
70
71


72
73
74
75
76
77
78
79
80
81
82
83
84
  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)
85
86
      {
        // always call beforeChild(), regardless of the value of visit
87
        v.beforeChild(std::forward<N>(n),n.child(_k),tp,_k);
88

89
        // descend to child
90
91
92
        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));
93

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

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

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

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

  //! 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)
  {
131
132
133
134
    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{});
135
136
137
  }

} // end namespace AMDiS