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
11 #include <type_traits>
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
{
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
{
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|
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
,
89 static auto ForEachNode(Node aRoot
, const PreAction
& aPreAction
,
90 const PostAction
& aPostAction
)
92 std::is_same_v
<decltype(aPreAction(aRoot
)), TraversalFlag
> &&
93 std::is_same_v
<decltype(aPostAction(aRoot
)), TraversalFlag
>,
99 TraversalFlag result
= aPreAction(aRoot
);
101 if (result
== TraversalFlag::Abort
) {
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
);
114 result
= aPostAction(aRoot
);
116 if (result
== TraversalFlag::Abort
) {
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
,
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>,
141 for (Node child
= Iterator::FirstChild(aRoot
); child
;
142 child
= Iterator::NextSibling(child
)) {
143 ForEachNode
<Iterator
>(child
, aPreAction
, aPostAction
);
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>,
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
)
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>,
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
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
) {
206 std::queue
<Node
> queue
;
208 while (!queue
.empty()) {
209 Node node
= queue
.front();
212 if (aCondition(node
)) {
216 for (Node child
= Iterator::FirstChild(node
); child
;
217 child
= Iterator::NextSibling(child
)) {
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
)) {
241 return TraversalFlag::Abort
;
244 return TraversalFlag::Continue
;
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
)) {
264 return TraversalFlag::Abort
;
267 return TraversalFlag::Continue
;
273 } // namespace layers
274 } // namespace mozilla
276 #endif // mozilla_layers_TreeTraversal_h