From: Mukund Sivaraman Date: Tue, 3 Sep 2013 03:07:46 +0000 (+0530) Subject: [2750] Add methods to check RB tree properties (and use them in tests) X-Git-Tag: bind10-1.2.0beta1-release~193^2~4^2~25 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=63e54b17e5b43ee480cb83a4fa0fa6ba08e2ccfa;p=thirdparty%2Fkea.git [2750] Add methods to check RB tree properties (and use them in tests) --- diff --git a/src/lib/datasrc/memory/domaintree.h b/src/lib/datasrc/memory/domaintree.h index 713f703c3f..776603aca5 100644 --- a/src/lib/datasrc/memory/domaintree.h +++ b/src/lib/datasrc/memory/domaintree.h @@ -362,7 +362,7 @@ private: } /// \brief Static variant of isBlack() that also allows NULL nodes. - static bool isBlack(DomainTreeNode* node) { + static bool isBlack(const DomainTreeNode* node) { if (!node) { // NULL nodes are black. return (true); @@ -377,7 +377,7 @@ private: } /// \brief Static variant of isRed() that also allows NULL nodes. - static bool isRed(DomainTreeNode* node) { + static bool isRed(const DomainTreeNode* node) { return (!isBlack(node)); } @@ -1610,6 +1610,22 @@ public: /// must not use it. size_t getHeight() const; +private: + /// \brief Helper method for checkProperties() + bool checkPropertiesHelper(const DomainTreeNode* node) const; + + /// \brief Helper for checkProperties() + bool checkBlackDistanceHelper(const DomainTreeNode* node, + size_t* distance) + const; + +public: + /// \brief Check red-black properties of the DomainTree. + /// + /// Note: This method exists for testing purposes. Non-test code + /// must not use it. + bool checkProperties() const; + /// \name Debug function //@{ /// \brief Print the nodes in the trees. @@ -3042,6 +3058,82 @@ DomainTree::getHeight() const { return (getHeightHelper(root_.get())); } +template +bool +DomainTree::checkPropertiesHelper(const DomainTreeNode* node) const { + if (node == NULL) { + return (true); + } + + // Root nodes should be BLACK. + if (node->isSubTreeRoot() && node->isRed()) { + return (false); + } + + // Both children of RED nodes must be BLACK. + if (node->isRed()) { + if (DomainTreeNode::isRed(node->getLeft()) || + DomainTreeNode::isRed(node->getRight())) + { + return (false); + } + } + + // Repeat tests with this node's children. + return (checkPropertiesHelper(node->getLeft()) && + checkPropertiesHelper(node->getRight()) && + checkPropertiesHelper(node->getDown())); +} + +template +bool +DomainTree::checkBlackDistanceHelper(const DomainTreeNode* node, + size_t* distance) const +{ + if (node == NULL) { + *distance = 1; + return (true); + } + + size_t dl, dr, dd; + if (!checkBlackDistanceHelper(node->getLeft(), &dl)) { + return (false); + } + if (!checkBlackDistanceHelper(node->getRight(), &dr)) { + return (false); + } + if (!checkBlackDistanceHelper(node->getDown(), &dd)) { + return (false); + } + + if (dl != dr) { + return (false); + } + + if (node->isBlack()) { + ++dl; + } + + *distance = dl; + + return (true); +} + +template +bool +DomainTree::checkProperties() const { + if (!checkPropertiesHelper(root_.get())) { + return (false); + } + + // Path from a given node to all its leaves must contain the same + // number of BLACK child nodes. This is done separately here instead + // of inside checkPropertiesHelper() as it would take (n log n) + // complexity otherwise. + size_t dd; + return (checkBlackDistanceHelper(root_.get(), &dd)); +} + template void DomainTree::dumpTree(std::ostream& os, unsigned int depth) const { diff --git a/src/lib/datasrc/tests/memory/domaintree_unittest.cc b/src/lib/datasrc/tests/memory/domaintree_unittest.cc index 5a8b6edea0..6058e44989 100644 --- a/src/lib/datasrc/tests/memory/domaintree_unittest.cc +++ b/src/lib/datasrc/tests/memory/domaintree_unittest.cc @@ -234,6 +234,9 @@ TEST_F(DomainTreeTest, checkDistanceRandom) { // The distance from each node to its sub-tree root must be less // than 2 * log(n). EXPECT_GE(2 * log_num_nodes, mytree.getHeight()); + + // Also check RB tree properties + EXPECT_TRUE(mytree.checkProperties()); } TEST_F(DomainTreeTest, checkDistanceSorted) { @@ -265,6 +268,9 @@ TEST_F(DomainTreeTest, checkDistanceSorted) { // The distance from each node to its sub-tree root must be less // than 2 * log(n). EXPECT_GE(2 * log_num_nodes, mytree.getHeight()); + + // Also check RB tree properties + EXPECT_TRUE(mytree.checkProperties()); } TEST_F(DomainTreeTest, setGetData) { @@ -396,6 +402,9 @@ TEST_F(DomainTreeTest, remove) { tree.find(Name(ordered_names[j]), &node)); tree.remove(mem_sgmt_, node, deleteData); + // Check RB tree properties + EXPECT_TRUE(tree.checkProperties()); + // Now, walk through nodes in order. TestDomainTreeNodeChain node_path; const TestDomainTreeNode* cnode;