Parcourir la source

add hard part code

hanfeng il y a 14 ans
Parent
commit
e01dadd724
2 fichiers modifiés avec 177 ajouts et 24 suppressions
  1. 129 24
      src/lib/datasrc/rbtree.h
  2. 48 0
      src/lib/datasrc/tests/rbtree_unittest.cc

+ 129 - 24
src/lib/datasrc/rbtree.h

@@ -29,6 +29,7 @@
 #include <exception>
 #include <ostream>
 #include <algorithm>
+#include <stack>
 
 namespace isc {
 namespace datasrc {
@@ -142,6 +143,10 @@ public:
     /// non-terminal domains, but it is possible (yet probably meaningless)
     /// empty nodes anywhere.
     bool isEmpty() const { return (data_.get() == NULL); }
+
+    /// \brief return the next node which is bigger than current node
+    /// in the same tree
+    const RBNode<T> *successor() const;
     //@}
 
     /// \name Setter functions.
@@ -239,6 +244,31 @@ template <typename T>
 RBNode<T>::~RBNode() {
 }
 
+template <typename T>
+const RBNode<T> *
+RBNode<T>::successor()const {
+    const RBNode<T> *current = this;
+    // If it has right node, the successor is the left-most node of the right
+    // subtree.
+    if (right_ != NULL_NODE()) {
+        current = right_;
+        while (current->left_ != NULL_NODE()) {
+            current = current->left_;
+        }
+        return (current);
+    }
+
+
+    // Otherwise go up until we find the first left branch on our path to
+    // root.  If found, the parent of the branch is the successor.
+    // Otherwise, we return the null node
+    const RBNode<T>* parent = current->parent_;
+    while (parent != NULL_NODE() && current == parent->right_) {
+        current = parent;
+        parent = parent->parent_;
+    }
+    return (parent);
+}
 
 // note: the following class description is documented using multiline comments
 // because the verbatim diagram contain a backslash, which could be interpreted
@@ -315,6 +345,9 @@ public:
         ALREADYEXISTS,
     };
 
+    /// save the nodes along the path from root to the target node
+    typedef typename std::stack<const RBNode<T> *> NodeChain;
+
     /// \name Constructor and Destructor
     //@{
     /// The constructor.
@@ -425,6 +458,34 @@ public:
     Result find(const isc::dns::Name& name, const RBNode<T>** node) const {
         return (find<void*>(name, node, NULL, NULL));
     }
+
+    /// \param name What should be found.
+    /// \param node_path It will save all the ancestor nodes
+    ///     to the tree containing node. If we looked for o.w.y.d.e.f in the
+    ///     \ref diagram, the node_path will have w.y node and d.e.f node. 
+    /// with the node path, we can also get the next node of current node
+    /// \param node The found node.
+    template <typename CBARG>
+    Result findEx(const isc::dns::Name& name, NodeChain &node_path,
+                      RBNode<T>** node,
+                      bool (*callback)(const RBNode<T>&, CBARG),
+                      CBARG callback_arg) const;
+ 
+    template <typename CBARG>
+    Result findEx(const isc::dns::Name& name, NodeChain &node_path,
+                      const RBNode<T>** node,
+                      bool (*callback)(const RBNode<T>&, CBARG),
+                      CBARG callback_arg) const;
+ 
+
+    /// \brief return the next node which is bigger than node
+    /// \param node_path store the path from base to sub domains in reverse order
+    /// the node_path is fetched through findEx function call, next_node_path will
+    /// store the node path to next_node
+    const RBNode<T> *nextNode(const RBNode<T> *node, const NodeChain &node_path,
+                              NodeChain &next_node_path) const;
+
+
     //@}
 
     /// \brief Get the total number of nodes in the tree
@@ -506,18 +567,7 @@ private:
     ///
     /// Internal searching function.
     ///
-    /// \param name What should be found.
-    /// \param up It will point to the node whose down pointer points
-    ///     to the tree containing node. If we looked for o.w.y.d.e.f in the
-    ///     \ref diagram, the up would point to the w.y node.
-    ///     This parameter is not used currently, but it will be soon.
-    /// \param node The found node.
-    template <typename CBARG>
-    Result findHelper(const isc::dns::Name& name, const RBNode<T>** up,
-                      RBNode<T>** node,
-                      bool (*callback)(const RBNode<T>&, CBARG),
-                      CBARG callback_arg) const;
-    void dumpTreeHelper(std::ostream& os, const RBNode<T>* node,
+   void dumpTreeHelper(std::ostream& os, const RBNode<T>* node,
                         unsigned int depth) const;
     /// \brief Indentation helper function for dumpTree
     static void indent(std::ostream& os, unsigned int depth);
@@ -586,8 +636,8 @@ RBTree<T,S>::find(const isc::dns::Name& name, RBNode<T>** node,
                 bool (*callback)(const RBNode<T>&, CBARG),
                 CBARG callback_arg) const
 {
-    const RBNode<T>* up_node = NULLNODE;
-    return (findHelper(name, &up_node, node, callback, callback_arg));
+    NodeChain node_path;
+    return (findEx(name, node_path, node, callback, callback_arg));
 }
 
 template <typename T, bool S>
@@ -597,10 +647,10 @@ RBTree<T,S>::find(const isc::dns::Name& name, const RBNode<T>** node,
                 bool (*callback)(const RBNode<T>&, CBARG),
                 CBARG callback_arg) const
 {
-    const RBNode<T>* up_node;
-    RBNode<T>* target_node;
-    const typename RBTree<T>::Result ret =
-        findHelper(name, &up_node, &target_node, callback, callback_arg);
+    NodeChain node_path;
+    RBNode<T>* target_node = NULLNODE;
+    const typename RBTree<T,S>::Result ret =
+        findEx(name, node_path, &target_node, callback, callback_arg);
     if (ret != NOTFOUND) {
         *node = target_node;
     }
@@ -610,8 +660,8 @@ RBTree<T,S>::find(const isc::dns::Name& name, const RBNode<T>** node,
 template <typename T, bool returnEmptyNode>
 template <typename CBARG>
 typename RBTree<T,returnEmptyNode>::Result
-RBTree<T,returnEmptyNode>::findHelper(const isc::dns::Name& target_name,
-                                      const RBNode<T>** up_node,
+RBTree<T,returnEmptyNode>::findEx(const isc::dns::Name& target_name,
+                                      NodeChain &node_path,
                                       RBNode<T>** target,
                                       bool (*callback)(const RBNode<T>&, CBARG),
                                       CBARG callback_arg) const
@@ -619,8 +669,7 @@ RBTree<T,returnEmptyNode>::findHelper(const isc::dns::Name& target_name,
     using namespace helper;
 
     RBNode<T>* node = root_;
-    typename RBTree<T>::Result ret = NOTFOUND;
-    *up_node = NULLNODE;
+    typename RBTree<T,returnEmptyNode>::Result ret = NOTFOUND;
     isc::dns::Name name = target_name;
 
     while (node != NULLNODE) {
@@ -643,7 +692,7 @@ RBTree<T,returnEmptyNode>::findHelper(const isc::dns::Name& target_name,
                     node->left_ : node->right_;
             } else if (relation == isc::dns::NameComparisonResult::SUBDOMAIN) {
                 if (returnEmptyNode || !node->isEmpty()) {
-                    ret = RBTree<T>::PARTIALMATCH;
+                    ret = RBTree<T,returnEmptyNode>::PARTIALMATCH;
                     *target = node;
                     if (callback != NULL && node->callback_required_) {
                         if ((callback)(*node, callback_arg)) {
@@ -651,7 +700,7 @@ RBTree<T,returnEmptyNode>::findHelper(const isc::dns::Name& target_name,
                         }
                     }
                 }
-                *up_node = node;
+                node_path.push(node);
                 name = name - node->name_;
                 node = node->down_;
             } else {
@@ -663,6 +712,62 @@ RBTree<T,returnEmptyNode>::findHelper(const isc::dns::Name& target_name,
     return (ret);
 }
 
+template <typename T, bool S>
+template <typename CBARG>
+typename RBTree<T,S>::Result
+RBTree<T,S>::findEx(const isc::dns::Name& target_name,
+                                      NodeChain &node_path,
+                                      const RBNode<T>** target,
+                                      bool (*callback)(const RBNode<T>&, CBARG),
+                                      CBARG callback_arg) const
+{
+    RBNode<T> *node = NULLNODE;
+    const typename RBTree<T,S>::Result ret =
+        findEx(target_name, node_path, &node, callback, callback_arg);
+    if (ret != NOTFOUND) {
+        *target = node;
+    }
+    return (ret);
+}
+
+template <typename T, bool S>    
+const RBNode<T> *
+RBTree<T, S>::nextNode(const RBNode<T> *node, const NodeChain &node_path,
+                                NodeChain &next_node_path) const
+{
+    next_node_path = node_path;
+    // if node has sub domain, the next domain is the samllest
+    // domain in sub domain tree
+    if (node->down_ != NULLNODE) {
+        next_node_path.push(node);
+        const RBNode<T> *left_most = node->down_;
+        while (left_most->left_ != NULLNODE) {
+            left_most = left_most->left_;
+        }
+        return (left_most);
+    }
+
+    // otherwise found the successor node in current level
+    const RBNode<T> *successor = node->successor();
+    if (successor != NULLNODE) {
+        return (successor);
+    }
+
+    // if no successor found move to up level, the next successor
+    // is the successor of up node in the up level tree, if 
+    // up node doesn't has successor we gonna keep moving to up
+    // level
+    while (!next_node_path.empty()) {
+        const RBNode<T> *up_node_successor = next_node_path.top()->successor();
+        next_node_path.pop();
+        if (up_node_successor != NULLNODE) {
+            return (up_node_successor);
+        }
+    }
+
+    return (NULLNODE);
+}
+
 
 template <typename T, bool returnEmptyNode>
 typename RBTree<T,returnEmptyNode>::Result

+ 48 - 0
src/lib/datasrc/tests/rbtree_unittest.cc

@@ -277,6 +277,54 @@ TEST_F(RBTreeTest, callback) {
     EXPECT_FALSE(callback_called);
 }
 
+/*
+ *the domain order should be:
+ * a, b, c, d.e.f, x.d.e.f, w.y.d.e.f, o.w.y.d.e.f, p.w.y.d.e.f, q.w.y.d.e.f, 
+ * z.d.e.f, j.z.d.e.f, g.h, i.g.h
+ *             b
+ *           /   \
+ *          a    d.e.f
+ *              /  |   \
+ *             c   |    g.h
+ *                 |     |
+ *                w.y    i
+ *              /  |  \
+ *             x   |   z
+ *                 |   |
+ *                 p   j
+ *               /   \
+ *              o     q
+ 
+ * */
+Name nodeAbsoluteName(const RBNode<int> *node, const RBTree<int>::NodeChain &node_path) {
+    isc::dns::Name absoluteName = node->getName();
+    RBTree<int>::NodeChain node_path_copy = node_path;
+    while (!node_path_copy.empty()) {
+        absoluteName = absoluteName.concatenate(node_path_copy.top()->getName());
+        node_path_copy.pop();
+    }   
+    return (absoluteName);
+}
+
+void testNodeAdjacentHelper(const RBTree<int, true> &tree, const Name &currentDomain, const Name &nextDomain) {
+    RBTree<int>::NodeChain node_path;
+    RBTree<int>::NodeChain next_node_path;
+    const RBNode<int> *node;
+    EXPECT_EQ(RBTree<int>::EXACTMATCH, tree.findEx<void *>(currentDomain, node_path, &node, NULL, NULL));
+    node = tree.nextNode(node, node_path, next_node_path);
+    EXPECT_EQ(nextDomain, nodeAbsoluteName(node,  next_node_path));
+}
+
+TEST_F(RBTreeTest, nextNode) {
+    const char *names[] = {"a", "b", "c", "d.e.f", "x.d.e.f", "w.y.d.e.f", "o.w.y.d.e.f", "p.w.y.d.e.f", "q.w.y.d.e.f",
+       "z.d.e.f", "j.z.d.e.f", "g.h", "i.g.h"};
+    int name_count = sizeof(names) / sizeof(names[0]);
+    int i = 0;
+    for (; i < name_count - 1; ++i) {
+        testNodeAdjacentHelper(rbtree_expose_empty_node, Name(names[i]), Name(names[i + 1]));
+    }
+}
+
 TEST_F(RBTreeTest, dumpTree) {
     std::ostringstream str;
     std::ostringstream str2;