dune-typetree  2.8.0
pairtraversal.hh
Go to the documentation of this file.
1 // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 // vi: set et ts=4 sw=2 sts=2:
3 
4 #ifndef DUNE_TYPETREE_PAIRTRAVERSAL_HH
5 #define DUNE_TYPETREE_PAIRTRAVERSAL_HH
6 
7 #include <dune/common/std/type_traits.hh>
8 
12 #include <dune/typetree/visitor.hh>
14 
15 namespace Dune {
16  namespace TypeTree {
17 
23  namespace Detail {
24 
25  /* The signature is the same as for the public applyToTreePair
26  * function in Dune::Typtree, despite the additionally passed
27  * treePath argument. The path passed here is associated to
28  * the tree and the relative paths of the children (wrt. to tree)
29  * are appended to this. Hence the behavior of the public function
30  * is resembled by passing an empty treePath.
31  */
32 
33  /*
34  * This is the overload for leaf traversal
35  */
36  template<class T1, class T2, class TreePath, class V,
37  std::enable_if_t<(std::decay_t<T1>::isLeaf or std::decay_t<T2>::isLeaf), int> = 0>
38  void applyToTreePair(T1&& tree1, T2&& tree2, TreePath treePath, V&& visitor)
39  {
40  visitor.leaf(tree1, tree2, treePath);
41  }
42 
43  /*
44  * This is the general overload doing static child traversal.
45  */
46  template<class T1, class T2, class TreePath, class V,
47  std::enable_if_t<not(std::decay_t<T1>::isLeaf or std::decay_t<T2>::isLeaf), int> = 0>
48  void applyToTreePair(T1&& tree1, T2&& tree2, TreePath treePath, V&& visitor)
49  {
50  // Do we really want to take care for const-ness of the Tree
51  // when instanciating VisitChild below? I'd rather expect this:
52  // using Tree1 = std::decay_t<T1>;
53  // using Tree2 = std::decay_t<T2>;
54  // using Visitor = std::decay_t<V>;
55  using Tree1 = std::remove_reference_t<T1>;
56  using Tree2 = std::remove_reference_t<T2>;
57  using Visitor = std::remove_reference_t<V>;
58  visitor.pre(tree1, tree2, treePath);
59 
60  // check which type of traversal is supported by the trees
61  using allowDynamicTraversal = std::conjunction<
62  Dune::Std::is_detected<DynamicTraversalConcept,Tree1>,
63  Dune::Std::is_detected<DynamicTraversalConcept,Tree2>>;
64  using allowStaticTraversal = std::conjunction<
65  Dune::Std::is_detected<StaticTraversalConcept,Tree1>,
66  Dune::Std::is_detected<StaticTraversalConcept,Tree2>>;
67 
68  // both trees must support either dynamic or static traversal
69  static_assert(allowDynamicTraversal::value || allowStaticTraversal::value);
70 
71  // the visitor may specify preferred dynamic traversal
72  using preferDynamicTraversal = std::bool_constant<Visitor::treePathType == TreePathType::dynamic>;
73 
74  // create a dynamic or static index range
75  auto indices = [&]{
76  if constexpr(preferDynamicTraversal::value && allowDynamicTraversal::value)
77  return Dune::range(std::size_t(tree1.degree()));
78  else
79  return Dune::range(tree1.degree());
80  }();
81 
82  if constexpr(allowDynamicTraversal::value || allowStaticTraversal::value) {
83  Dune::Hybrid::forEach(indices, [&](auto i) {
84  auto&& child1 = tree1.child(i);
85  auto&& child2 = tree2.child(i);
86  using Child1 = std::decay_t<decltype(child1)>;
87  using Child2 = std::decay_t<decltype(child2)>;
88 
89  visitor.beforeChild(tree1, child1, tree2, child2, treePath, i);
90 
91  // This requires that visitor.in(...) can always be instantiated,
92  // even if there's a single child only.
93  if (i>0)
94  visitor.in(tree1, tree2, treePath);
95 
96  constexpr bool visitChild = Visitor::template VisitChild<Tree1,Child1,Tree2,Child2,TreePath>::value;
97  if constexpr(visitChild) {
98  auto childTreePath = Dune::TypeTree::push_back(treePath, i);
99  applyToTreePair(child1, child2, childTreePath, visitor);
100  }
101 
102  visitor.afterChild(tree1, child1, tree2, child2, treePath, i);
103  });
104  }
105  visitor.post(tree1, tree2, treePath);
106  }
107 
108  } // namespace Detail
109 
111 
125  template<typename Tree1, typename Tree2, typename Visitor>
126  void applyToTreePair(Tree1&& tree1, Tree2&& tree2, Visitor&& visitor)
127  {
128  Detail::applyToTreePair(tree1, tree2, hybridTreePath(), visitor);
129  }
130 
132 
133  } // namespace TypeTree
134 } //namespace Dune
135 
136 #endif // DUNE_TYPETREE_PAIRTRAVERSAL_HH
void applyToTreePair(Tree1 &&tree1, Tree2 &&tree2, Visitor &&visitor)
Apply visitor to a pair of TypeTrees.
Definition: pairtraversal.hh:126
constexpr HybridTreePath< T... > treePath(const T &... t)
Constructs a new HybridTreePath from the given indices.
Definition: treepath.hh:188
constexpr HybridTreePath< T... > hybridTreePath(const T &... t)
Constructs a new HybridTreePath from the given indices.
Definition: treepath.hh:177
constexpr HybridTreePath< T..., std::size_t > push_back(const HybridTreePath< T... > &tp, std::size_t i)
Appends a run time index to a HybridTreePath.
Definition: treepath.hh:278
HybridTreePath< Dune::index_constant< i >... > TreePath
Definition: treepath.hh:433
Definition: accumulate_static.hh:13
void applyToTreePair(T1 &&tree1, T2 &&tree2, TreePath treePath, V &&visitor)
Definition: pairtraversal.hh:38
A hybrid version of TreePath that supports both compile time and run time indices.
Definition: treepath.hh:79