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 
9 #include <dune/typetree/nodeinterface.hh>
10 #include <dune/typetree/nodetags.hh>
11 #include <dune/typetree/treepath.hh>
12 #include <dune/typetree/visitor.hh>
13 #include <dune/typetree/traversal.hh>
14 
15 namespace Dune {
16   namespace TypeTree {
17 
18     /** \addtogroup Tree Traversal
19      *  \ingroup TypeTree
20      *  \{
21      */
22 
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>
applyToTreePair(T1 && tree1,T2 && tree2,TreePath treePath,V && visitor)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>
applyToTreePair(T1 && tree1,T2 && tree2,TreePath treePath,V && visitor)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 
110     //! Apply visitor to a pair of TypeTrees.
111     /**
112      * This function applies the given visitor to the given tree. Both visitor and tree may be const
113      * or non-const. If the compiler supports rvalue references, they may even be a non-const temporary;
114      * otherwise both trees must be either const or non-const. If they have different constness, both will
115      * be promoted to const.
116      *
117      * \note The visitor must implement the interface laid out by DefaultPairVisitor (most easily achieved by
118      *       inheriting from it) and specify the required type of tree traversal (static or dynamic) by
119      *       inheriting from either StaticTraversal or DynamicTraversal.
120      *
121      * \param tree1   The first tree the visitor will be applied to.
122      * \param tree2   The second tree the visitor will be applied to.
123      * \param visitor The visitor to apply to the trees.
124      */
125     template<typename Tree1, typename Tree2, typename Visitor>
applyToTreePair(Tree1 && tree1,Tree2 && tree2,Visitor && visitor)126     void applyToTreePair(Tree1&& tree1, Tree2&& tree2, Visitor&& visitor)
127     {
128       Detail::applyToTreePair(tree1, tree2, hybridTreePath(), visitor);
129     }
130 
131     //! \} group Tree Traversal
132 
133   } // namespace TypeTree
134 } //namespace Dune
135 
136 #endif // DUNE_TYPETREE_PAIRTRAVERSAL_HH
137