Browse Source

[master] Merge branch 'trac2089'

Jelte Jansen 12 years ago
parent
commit
d6bd43c2a3
2 changed files with 130 additions and 28 deletions
  1. 87 25
      src/lib/datasrc/rbtree.h
  2. 43 3
      src/lib/datasrc/tests/rbtree_unittest.cc

+ 87 - 25
src/lib/datasrc/rbtree.h

@@ -123,6 +123,8 @@ public:
     /// set to on by the \c setFlag() method.
     enum Flags {
         FLAG_CALLBACK = 1, ///< Callback enabled. See \ref callback
+        FLAG_RED = 2, ///< Node color; 1 if node is red, 0 if node is black.
+        FLAG_SUBTREE_ROOT = 4, ///< Set if the node is the root of a subtree
         FLAG_USER1 = 0x80000000U, ///< Application specific flag
         FLAG_USER2 = 0x40000000U, ///< Application specific flag
         FLAG_USER3 = 0x20000000U  ///< Application specific flag
@@ -246,6 +248,36 @@ private:
         return (&null_node);
     }
 
+    /// \brief Returns the color of this node
+    RBNodeColor getColor() const {
+        if ((flags_ & FLAG_RED) != 0) {
+            return (RED);
+        } else {
+            return (BLACK);
+        }
+    }
+
+    /// \brief Sets the color of this node
+    void setColor(const RBNodeColor color) {
+        if (color == RED) {
+            flags_ |= FLAG_RED;
+        } else {
+            flags_ &= ~FLAG_RED;
+        }
+    }
+
+    void setSubTreeRoot(bool root) {
+        if (root) {
+            flags_ |= FLAG_SUBTREE_ROOT;
+        } else {
+            flags_ &= ~FLAG_SUBTREE_ROOT;
+        }
+    }
+
+    bool isSubTreeRoot() const {
+        return ((flags_ & FLAG_SUBTREE_ROOT) != 0);
+    }
+
     /// \brief return the next node which is bigger than current node
     /// in the same subtree
     ///
@@ -299,7 +331,6 @@ private:
     RBNode<T>*  parent_;
     RBNode<T>*  left_;
     RBNode<T>*  right_;
-    RBNodeColor color_;
     //@}
 
     /// \brief Relative name of the node.
@@ -332,11 +363,10 @@ RBNode<T>::RBNode() :
     parent_(NULL),
     left_(NULL),
     right_(NULL),
-    color_(BLACK),
     // dummy name, the value doesn't matter:
     name_(isc::dns::Name::ROOT_NAME()),
     down_(NULL),
-    flags_(0)
+    flags_(FLAG_SUBTREE_ROOT)
 {
     // Some compilers object to use of "this" in initializer lists.
     parent_ = this;
@@ -350,10 +380,9 @@ RBNode<T>::RBNode(const isc::dns::Name& name) :
     parent_(NULL_NODE()),
     left_(NULL_NODE()),
     right_(NULL_NODE()),
-    color_(RED),
     name_(name),
     down_(NULL_NODE()),
-    flags_(0)
+    flags_(FLAG_RED | FLAG_SUBTREE_ROOT)
 {
 }
 
@@ -1374,10 +1403,13 @@ RBTree<T>::insert(const isc::dns::Name& target_name, RBNode<T>** new_node) {
         *current_root = node.get();
         //node is the new root of sub tree, so its init color
         // is BLACK
-        node->color_ = RBNode<T>::BLACK;
+        node->setColor(RBNode<T>::BLACK);
+        node->setSubTreeRoot(true);
     } else if (order < 0) {
+        node->setSubTreeRoot(false);
         parent->left_ = node.get();
     } else {
+        node->setSubTreeRoot(false);
         parent->right_ = node.get();
     }
     insertRebalance(current_root, node.get());
@@ -1409,10 +1441,19 @@ RBTree<T>::nodeFission(RBNode<T>& node, const isc::dns::Name& base_name) {
     // even if code after the call to this function throws an exception.
     std::swap(node.data_, down_node->data_);
     std::swap(node.flags_, down_node->flags_);
+
     down_node->down_ = node.down_;
     node.down_ = down_node.get();
+
+    // Restore the color of the node (may have gotten changed by the flags swap)
+    node.setColor(down_node->getColor());
+
     // root node of sub tree, the initial color is BLACK
-    down_node->color_ = RBNode<T>::BLACK;
+    down_node->setColor(RBNode<T>::BLACK);
+
+    // mark it as the root of a subtree
+    down_node->setSubTreeRoot(true);
+
     ++node_count_;
     down_node.release();
 }
@@ -1423,44 +1464,44 @@ void
 RBTree<T>::insertRebalance(RBNode<T>** root, RBNode<T>* node) {
 
     RBNode<T>* uncle;
-    while (node != *root && node->parent_->color_ == RBNode<T>::RED) {
+    while (node != *root && node->parent_->getColor() == RBNode<T>::RED) {
         if (node->parent_ == node->parent_->parent_->left_) {
             uncle = node->parent_->parent_->right_;
 
-            if (uncle->color_ == RBNode<T>::RED) {
-                node->parent_->color_ = RBNode<T>::BLACK;
-                uncle->color_ = RBNode<T>::BLACK;
-                node->parent_->parent_->color_ = RBNode<T>::RED;
+            if (uncle->getColor() == RBNode<T>::RED) {
+                node->parent_->setColor(RBNode<T>::BLACK);
+                uncle->setColor(RBNode<T>::BLACK);
+                node->parent_->parent_->setColor(RBNode<T>::RED);
                 node = node->parent_->parent_;
             } else {
                 if (node == node->parent_->right_) {
                     node = node->parent_;
                     leftRotate(root, node);
                 }
-                node->parent_->color_ = RBNode<T>::BLACK;
-                node->parent_->parent_->color_ = RBNode<T>::RED;
+                node->parent_->setColor(RBNode<T>::BLACK);
+                node->parent_->parent_->setColor(RBNode<T>::RED);
                 rightRotate(root, node->parent_->parent_);
             }
         } else {
             uncle = node->parent_->parent_->left_;
-            if (uncle->color_ == RBNode<T>::RED) {
-                node->parent_->color_ = RBNode<T>::BLACK;
-                uncle->color_ = RBNode<T>::BLACK;
-                node->parent_->parent_->color_ = RBNode<T>::RED;
+            if (uncle->getColor() == RBNode<T>::RED) {
+                node->parent_->setColor(RBNode<T>::BLACK);
+                uncle->setColor(RBNode<T>::BLACK);
+                node->parent_->parent_->setColor(RBNode<T>::RED);
                 node = node->parent_->parent_;
             } else {
                 if (node == node->parent_->left_) {
                     node = node->parent_;
                     rightRotate(root, node);
                 }
-                node->parent_->color_ = RBNode<T>::BLACK;
-                node->parent_->parent_->color_ = RBNode<T>::RED;
+                node->parent_->setColor(RBNode<T>::BLACK);
+                node->parent_->parent_->setColor(RBNode<T>::RED);
                 leftRotate(root, node->parent_->parent_);
             }
         }
     }
 
-    (*root)->color_ = RBNode<T>::BLACK;
+    (*root)->setColor(RBNode<T>::BLACK);
 }
 
 
@@ -1469,23 +1510,30 @@ RBNode<T>*
 RBTree<T>::leftRotate(RBNode<T>** root, RBNode<T>* node) {
     RBNode<T>* right = node->right_;
     node->right_ = right->left_;
-    if (right->left_ != NULLNODE)
+    if (right->left_ != NULLNODE) {
         right->left_->parent_ = node;
+        right->left_->setSubTreeRoot(false);
+    } else {
+        right->left_->setSubTreeRoot(true);
+    }
 
     right->parent_ = node->parent_;
 
     if (node->parent_ != NULLNODE) {
+        right->setSubTreeRoot(false);
         if (node == node->parent_->left_) {
             node->parent_->left_ = right;
         } else  {
             node->parent_->right_ = right;
         }
     } else {
+        right->setSubTreeRoot(true);
         *root = right;
     }
 
     right->left_ = node;
     node->parent_ = right;
+    node->setSubTreeRoot(false);
     return (node);
 }
 
@@ -1494,22 +1542,30 @@ RBNode<T>*
 RBTree<T>::rightRotate(RBNode<T>** root, RBNode<T>* node) {
     RBNode<T>* left = node->left_;
     node->left_ = left->right_;
-    if (left->right_ != NULLNODE)
+    if (left->right_ != NULLNODE) {
         left->right_->parent_ = node;
+        left->right_->setSubTreeRoot(false);
+    } else {
+        left->right_->setSubTreeRoot(true);
+    }
 
     left->parent_ = node->parent_;
 
     if (node->parent_ != NULLNODE) {
+        left->setSubTreeRoot(false);
         if (node == node->parent_->right_) {
             node->parent_->right_ = left;
         } else  {
             node->parent_->left_ = left;
         }
     } else {
+        left->setSubTreeRoot(true);
         *root = left;
     }
     left->right_ = node;
     node->parent_ = left;
+    node->setSubTreeRoot(false);
+
     return (node);
 }
 
@@ -1535,8 +1591,14 @@ RBTree<T>::dumpTreeHelper(std::ostream& os, const RBNode<T>* node,
 
     indent(os, depth);
     os << node->name_.toText() << " ("
-              << ((node->color_ == RBNode<T>::BLACK) ? "black" : "red") << ")";
-    os << ((node->isEmpty()) ? "[invisible] \n" : "\n");
+              << ((node->getColor() == RBNode<T>::BLACK) ? "black" : "red") << ")";
+    if (node->isEmpty()) {
+        os << " [invisible]";
+    }
+    if (node->isSubTreeRoot()) {
+        os << " [subtreeroot]";
+    }
+    os << "\n";
 
     if (node->down_ != NULLNODE) {
         indent(os, depth + 1);

File diff suppressed because it is too large
+ 43 - 3
src/lib/datasrc/tests/rbtree_unittest.cc