Update configs. IGNORE BROKEN CHANGESETS CLOSED TREE NO BUG a=release ba=release
[gecko.git] / gfx / layers / TreeTraversal.h
blob4c02a4e5b5fbbf10fa13069c1ebdf64e17e64527
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/. */
7 #ifndef mozilla_layers_TreeTraversal_h
8 #define mozilla_layers_TreeTraversal_h
10 #include <queue>
11 #include <type_traits>
13 namespace mozilla {
14 namespace layers {
17 * Returned by |aPostAction| and |aPreAction| in ForEachNode, indicates
18 * the behavior to follow either action:
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.
26 enum class TraversalFlag { Skip, Continue, Abort };
29 * Iterator types to be specified in traversal function calls:
31 * ForwardIterator - for nodes using GetFirstChild() and GetNextSibling()
32 * ReverseIterator - for nodes using GetLastChild() and GetPrevSibling()
34 class ForwardIterator {
35 public:
36 template <typename Node>
37 static Node* FirstChild(Node* n) {
38 return n->GetFirstChild();
40 template <typename Node>
41 static Node* NextSibling(Node* n) {
42 return n->GetNextSibling();
44 template <typename Node>
45 static Node FirstChild(Node n) {
46 return n.GetFirstChild();
48 template <typename Node>
49 static Node NextSibling(Node n) {
50 return n.GetNextSibling();
53 class ReverseIterator {
54 public:
55 template <typename Node>
56 static Node* FirstChild(Node* n) {
57 return n->GetLastChild();
59 template <typename Node>
60 static Node* NextSibling(Node* n) {
61 return n->GetPrevSibling();
63 template <typename Node>
64 static Node FirstChild(Node n) {
65 return n.GetLastChild();
67 template <typename Node>
68 static Node NextSibling(Node n) {
69 return n.GetPrevSibling();
74 * Do a depth-first traversal of the tree rooted at |aRoot|, performing
75 * |aPreAction| before traversal of children and |aPostAction| after.
77 * Returns true if traversal aborted, false if continued normally. If
78 * TraversalFlag::Skip is returned in |aPreAction|, then |aPostAction|
79 * is not performed.
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.
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;
99 TraversalFlag result = aPreAction(aRoot);
101 if (result == TraversalFlag::Abort) {
102 return true;
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;
114 result = aPostAction(aRoot);
116 if (result == TraversalFlag::Abort) {
117 return true;
121 return false;
125 * Do a depth-first traversal of the tree rooted at |aRoot|, performing
126 * |aPreAction| before traversal of children and |aPostAction| after.
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;
139 aPreAction(aRoot);
141 for (Node child = Iterator::FirstChild(aRoot); child;
142 child = Iterator::NextSibling(child)) {
143 ForEachNode<Iterator>(child, aPreAction, aPostAction);
146 aPostAction(aRoot);
150 * ForEachNode pre-order traversal, using TraversalFlag.
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; });
160 * ForEachNode pre-order, not using TraversalFlag.
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) {});
170 * ForEachNode post-order traversal, using TraversalFlag.
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);
181 * ForEachNode post-order, not using TraversalFlag.
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>(
188 aRoot, [](Node aNode) {}, aPostAction);
192 * Do a breadth-first search of the tree rooted at |aRoot|, and return the
193 * first visited node that satisfies |aCondition|, or nullptr if no such node
194 * was found.
196 * |Iterator| and |Node| have all the same requirements seen in ForEachNode()'s
197 * definition, but in addition to those, |Node| must be able to express a null
198 * value, returned from Node()
200 template <typename Iterator, typename Node, typename Condition>
201 Node BreadthFirstSearch(Node aRoot, const Condition& aCondition) {
202 if (!aRoot) {
203 return Node();
206 std::queue<Node> queue;
207 queue.push(aRoot);
208 while (!queue.empty()) {
209 Node node = queue.front();
210 queue.pop();
212 if (aCondition(node)) {
213 return node;
216 for (Node child = Iterator::FirstChild(node); child;
217 child = Iterator::NextSibling(child)) {
218 queue.push(child);
222 return Node();
226 * Do a pre-order, depth-first search of the tree rooted at |aRoot|, and
227 * return the first visited node that satisfies |aCondition|, or nullptr
228 * if no such node was found.
230 * |Iterator| and |Node| have all the same requirements seen in ForEachNode()'s
231 * definition, but in addition to those, |Node| must be able to express a null
232 * value, returned from Node().
234 template <typename Iterator, typename Node, typename Condition>
235 Node DepthFirstSearch(Node aRoot, const Condition& aCondition) {
236 Node result = Node();
238 ForEachNode<Iterator>(aRoot, [&aCondition, &result](Node aNode) {
239 if (aCondition(aNode)) {
240 result = aNode;
241 return TraversalFlag::Abort;
244 return TraversalFlag::Continue;
247 return result;
251 * Perform a post-order, depth-first search starting at aRoot.
253 * |Iterator| and |Node| have all the same requirements seen in ForEachNode()'s
254 * definition, but in addition to those, |Node| must be able to express a null
255 * value, returned from Node().
257 template <typename Iterator, typename Node, typename Condition>
258 Node DepthFirstSearchPostOrder(Node aRoot, const Condition& aCondition) {
259 Node result = Node();
261 ForEachNodePostOrder<Iterator>(aRoot, [&aCondition, &result](Node aNode) {
262 if (aCondition(aNode)) {
263 result = aNode;
264 return TraversalFlag::Abort;
267 return TraversalFlag::Continue;
270 return result;
273 } // namespace layers
274 } // namespace mozilla
276 #endif // mozilla_layers_TreeTraversal_h