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