Traversal.hpp 3.88 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
#include <amdis/common/Loops.hpp>
8
#include <amdis/common/TypeTraits.hpp>
9

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

16

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

26
#ifndef DOXYGEN
27

28
  // some implementation details
29

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

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

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

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

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


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

70
#endif
71
72


73
74
75
76
77
78
79
80
81
  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>;

82
      v.pre(FWD(n),tp);
83
84
85

      auto const deg = hybridDegree(NodeTag{}, n);
      forEach(Dune::range(deg), [&](auto const _k)
86
87
      {
        // always call beforeChild(), regardless of the value of visit
88
        v.beforeChild(FWD(n),n.child(_k),tp,_k);
89

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

95
        // always call afterChild(), regardless of the value of visit
96
        v.afterChild(FWD(n),n.child(_k),tp,_k);
97

98
        // if this is not the last child, call infix callback
99
        if (notLastChild(_k, deg))
100
          v.in(FWD(n),tp);
101
      });
102

103
      v.post(FWD(n),tp);
104
105
    }
  };
106

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

  //! 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)
  {
132
133
134
    using Node = std::remove_reference_t<Tree>;
    using NodeTag = Dune::TypeTree::NodeTag<Node>;
    using TreePath = Dune::TypeTree::HybridTreePath<>;
135
    TraverseTree<NodeTag>::apply(FWD(tree), FWD(visitor), TreePath{});
136
137
138
  }

} // end namespace AMDiS