tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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