TreeTraversal.h (8323B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef mozilla_layers_TreeTraversal_h 8 #define mozilla_layers_TreeTraversal_h 9 10 #include <queue> 11 #include <type_traits> 12 13 namespace mozilla { 14 namespace layers { 15 16 /* 17 * Returned by |aPostAction| and |aPreAction| in ForEachNode, indicates 18 * the behavior to follow either action: 19 * 20 * TraversalFlag::Skip - the node's children are not traversed. If this 21 * flag is returned by |aPreAction|, |aPostAction| is skipped for the 22 * current node, as well. 23 * TraversalFlag::Continue - traversal continues normally. 24 * TraversalFlag::Abort - traversal stops immediately. 25 */ 26 enum class TraversalFlag { Skip, Continue, Abort }; 27 28 /* 29 * Iterator types to be specified in traversal function calls: 30 * 31 * ForwardIterator - for nodes using GetFirstChild() and GetNextSibling() 32 * ReverseIterator - for nodes using GetLastChild() and GetPrevSibling() 33 */ 34 class ForwardIterator { 35 public: 36 template <typename Node> 37 static Node* FirstChild(Node* n) { 38 return n->GetFirstChild(); 39 } 40 template <typename Node> 41 static Node* NextSibling(Node* n) { 42 return n->GetNextSibling(); 43 } 44 template <typename Node> 45 static Node FirstChild(Node n) { 46 return n.GetFirstChild(); 47 } 48 template <typename Node> 49 static Node NextSibling(Node n) { 50 return n.GetNextSibling(); 51 } 52 }; 53 class ReverseIterator { 54 public: 55 template <typename Node> 56 static Node* FirstChild(Node* n) { 57 return n->GetLastChild(); 58 } 59 template <typename Node> 60 static Node* NextSibling(Node* n) { 61 return n->GetPrevSibling(); 62 } 63 template <typename Node> 64 static Node FirstChild(Node n) { 65 return n.GetLastChild(); 66 } 67 template <typename Node> 68 static Node NextSibling(Node n) { 69 return n.GetPrevSibling(); 70 } 71 }; 72 73 /* 74 * Do a depth-first traversal of the tree rooted at |aRoot|, performing 75 * |aPreAction| before traversal of children and |aPostAction| after. 76 * 77 * Returns true if traversal aborted, false if continued normally. If 78 * TraversalFlag::Skip is returned in |aPreAction|, then |aPostAction| 79 * is not performed. 80 * 81 * |Iterator| should have static methods named NextSibling() and FirstChild() 82 * that accept an argument of type Node. For convenience, classes 83 * |ForwardIterator| and |ReverseIterator| are provided which implement these 84 * methods as GetNextSibling()/GetFirstChild() and 85 * GetPrevSibling()/GetLastChild(), respectively. 86 */ 87 template <typename Iterator, typename Node, typename PreAction, 88 typename PostAction> 89 static auto ForEachNode(Node aRoot, const PreAction& aPreAction, 90 const PostAction& aPostAction) 91 -> std::enable_if_t< 92 std::is_same_v<decltype(aPreAction(aRoot)), TraversalFlag> && 93 std::is_same_v<decltype(aPostAction(aRoot)), TraversalFlag>, 94 bool> { 95 if (!aRoot) { 96 return false; 97 } 98 99 TraversalFlag result = aPreAction(aRoot); 100 101 if (result == TraversalFlag::Abort) { 102 return true; 103 } 104 105 if (result == TraversalFlag::Continue) { 106 for (Node child = Iterator::FirstChild(aRoot); child; 107 child = Iterator::NextSibling(child)) { 108 bool abort = ForEachNode<Iterator>(child, aPreAction, aPostAction); 109 if (abort) { 110 return true; 111 } 112 } 113 114 result = aPostAction(aRoot); 115 116 if (result == TraversalFlag::Abort) { 117 return true; 118 } 119 } 120 121 return false; 122 } 123 124 /* 125 * Do a depth-first traversal of the tree rooted at |aRoot|, performing 126 * |aPreAction| before traversal of children and |aPostAction| after. 127 */ 128 template <typename Iterator, typename Node, typename PreAction, 129 typename PostAction> 130 static auto ForEachNode(Node aRoot, const PreAction& aPreAction, 131 const PostAction& aPostAction) 132 -> std::enable_if_t<std::is_same_v<decltype(aPreAction(aRoot)), void> && 133 std::is_same_v<decltype(aPostAction(aRoot)), void>, 134 void> { 135 if (!aRoot) { 136 return; 137 } 138 139 aPreAction(aRoot); 140 141 for (Node child = Iterator::FirstChild(aRoot); child; 142 child = Iterator::NextSibling(child)) { 143 ForEachNode<Iterator>(child, aPreAction, aPostAction); 144 } 145 146 aPostAction(aRoot); 147 } 148 149 /* 150 * ForEachNode pre-order traversal, using TraversalFlag. 151 */ 152 template <typename Iterator, typename Node, typename PreAction> 153 auto ForEachNode(Node aRoot, const PreAction& aPreAction) -> std::enable_if_t< 154 std::is_same_v<decltype(aPreAction(aRoot)), TraversalFlag>, bool> { 155 return ForEachNode<Iterator>( 156 aRoot, aPreAction, [](Node aNode) { return TraversalFlag::Continue; }); 157 } 158 159 /* 160 * ForEachNode pre-order, not using TraversalFlag. 161 */ 162 template <typename Iterator, typename Node, typename PreAction> 163 auto ForEachNode(Node aRoot, const PreAction& aPreAction) 164 -> std::enable_if_t<std::is_same_v<decltype(aPreAction(aRoot)), void>, 165 void> { 166 ForEachNode<Iterator>(aRoot, aPreAction, [](Node aNode) {}); 167 } 168 169 /* 170 * ForEachNode post-order traversal, using TraversalFlag. 171 */ 172 template <typename Iterator, typename Node, typename PostAction> 173 auto ForEachNodePostOrder(Node aRoot, const PostAction& aPostAction) 174 -> std::enable_if_t< 175 std::is_same_v<decltype(aPostAction(aRoot)), TraversalFlag>, bool> { 176 return ForEachNode<Iterator>( 177 aRoot, [](Node aNode) { return TraversalFlag::Continue; }, aPostAction); 178 } 179 180 /* 181 * ForEachNode post-order, not using TraversalFlag. 182 */ 183 template <typename Iterator, typename Node, typename PostAction> 184 auto ForEachNodePostOrder(Node aRoot, const PostAction& aPostAction) 185 -> std::enable_if_t<std::is_same_v<decltype(aPostAction(aRoot)), void>, 186 void> { 187 ForEachNode<Iterator>(aRoot, [](Node aNode) {}, aPostAction); 188 } 189 190 /* 191 * Do a breadth-first search of the tree rooted at |aRoot|, and return the 192 * first visited node that satisfies |aCondition|, or nullptr if no such node 193 * was found. 194 * 195 * |Iterator| and |Node| have all the same requirements seen in ForEachNode()'s 196 * definition, but in addition to those, |Node| must be able to express a null 197 * value, returned from Node() 198 */ 199 template <typename Iterator, typename Node, typename Condition> 200 Node BreadthFirstSearch(Node aRoot, const Condition& aCondition) { 201 if (!aRoot) { 202 return Node(); 203 } 204 205 std::queue<Node> queue; 206 queue.push(aRoot); 207 while (!queue.empty()) { 208 Node node = queue.front(); 209 queue.pop(); 210 211 if (aCondition(node)) { 212 return node; 213 } 214 215 for (Node child = Iterator::FirstChild(node); child; 216 child = Iterator::NextSibling(child)) { 217 queue.push(child); 218 } 219 } 220 221 return Node(); 222 } 223 224 /* 225 * Do a pre-order, depth-first search of the tree rooted at |aRoot|, and 226 * return the first visited node that satisfies |aCondition|, or nullptr 227 * if no such node was found. 228 * 229 * |Iterator| and |Node| have all the same requirements seen in ForEachNode()'s 230 * definition, but in addition to those, |Node| must be able to express a null 231 * value, returned from Node(). 232 */ 233 template <typename Iterator, typename Node, typename Condition> 234 Node DepthFirstSearch(Node aRoot, const Condition& aCondition) { 235 Node result = Node(); 236 237 ForEachNode<Iterator>(aRoot, [&aCondition, &result](Node aNode) { 238 if (aCondition(aNode)) { 239 result = aNode; 240 return TraversalFlag::Abort; 241 } 242 243 return TraversalFlag::Continue; 244 }); 245 246 return result; 247 } 248 249 /* 250 * Perform a post-order, depth-first search starting at aRoot. 251 * 252 * |Iterator| and |Node| have all the same requirements seen in ForEachNode()'s 253 * definition, but in addition to those, |Node| must be able to express a null 254 * value, returned from Node(). 255 */ 256 template <typename Iterator, typename Node, typename Condition> 257 Node DepthFirstSearchPostOrder(Node aRoot, const Condition& aCondition) { 258 Node result = Node(); 259 260 ForEachNodePostOrder<Iterator>(aRoot, [&aCondition, &result](Node aNode) { 261 if (aCondition(aNode)) { 262 result = aNode; 263 return TraversalFlag::Abort; 264 } 265 266 return TraversalFlag::Continue; 267 }); 268 269 return result; 270 } 271 272 } // namespace layers 273 } // namespace mozilla 274 275 #endif // mozilla_layers_TreeTraversal_h