Commit 56baabf6 authored by JINMEI Tatuya's avatar JINMEI Tatuya
Browse files

[trac507] added to rbtree::find() the ability to record info about last matching node.

 - new methods were added to RBTreeNodeChain
 - RBTreeNodeChain::clear() was also added, mainly for the convenience of tests
parent dc5d961a
......@@ -318,7 +318,11 @@ public:
/// The default constructor.
///
/// \exception None
RBTreeNodeChain() : node_count_(0) {}
RBTreeNodeChain() : node_count_(0), last_compared_(NULL),
// XXX: meaningless initial values:
last_comparison_(0, 0,
isc::dns::NameComparisonResult::EQUAL)
{}
/// Copy constructor.
///
......@@ -343,6 +347,23 @@ public:
}
//@}
/// TBD
/// \exception None
void clear() {
node_count_ = 0;
last_compared_ = NULL;
}
/// TBD
/// \exception None
const RBNode<T>* getLastComparedNode() const {
return (last_compared_);
}
const isc::dns::NameComparisonResult& getLastComparisonResult() const {
return (last_comparison_);
}
private:
// The max label count for one domain name is Name::MAX_LABELS (128).
// Since each node in rbtree stores at least one label, and the root
......@@ -352,8 +373,10 @@ private:
// It's also the possible maximum nodes stored in a chain.
const static int RBT_MAX_LEVEL = isc::dns::Name::MAX_LABELS - 1;
const RBNode<T>* nodes_[RBT_MAX_LEVEL];
int node_count_;
const RBNode<T>* nodes_[RBT_MAX_LEVEL];
const RBNode<T>* last_compared_;
isc::dns::NameComparisonResult last_comparison_;
};
......@@ -747,7 +770,7 @@ template <typename CBARG>
typename RBTree<T>::Result
RBTree<T>::find(const isc::dns::Name& target_name,
RBNode<T>** target,
RBTreeNodeChain<T>&,
RBTreeNodeChain<T>& node_path,
bool (*callback)(const RBNode<T>&, CBARG),
CBARG callback_arg) const
{
......@@ -758,10 +781,11 @@ RBTree<T>::find(const isc::dns::Name& target_name,
isc::dns::Name name = target_name;
while (node != NULLNODE) {
const isc::dns::NameComparisonResult compare_result =
name.compare(node->name_);
node_path.last_compared_ = node;
node_path.last_comparison_ = name.compare(node->name_);
const isc::dns::NameComparisonResult::NameRelation relation =
compare_result.getRelation();
node_path.last_comparison_.getRelation();
if (relation == isc::dns::NameComparisonResult::EQUAL) {
if (needsReturnEmptyNode_ || !node->isEmpty()) {
*target = node;
......@@ -769,11 +793,12 @@ RBTree<T>::find(const isc::dns::Name& target_name,
}
break;
} else {
const int common_label_count = compare_result.getCommonLabels();
const int common_label_count =
node_path.last_comparison_.getCommonLabels();
// If the common label count is 1, there is no common label between
// the two names, except the trailing "dot".
if (common_label_count == 1) {
node = (compare_result.getOrder() < 0) ?
node = (node_path.last_comparison_.getOrder() < 0) ?
node->left_ : node->right_;
} else if (relation == isc::dns::NameComparisonResult::SUBDOMAIN) {
if (needsReturnEmptyNode_ || !node->isEmpty()) {
......
......@@ -12,7 +12,6 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include <gtest/gtest.h>
#include <exceptions/exceptions.h>
......@@ -244,6 +243,105 @@ TEST_F(RBTreeTest, callback) {
EXPECT_FALSE(callback_called);
}
// A helper function for getLastComparedNode() below.
void
comparisonChecks(const RBTreeNodeChain<int>& chain,
int expected_order, int expected_common_labels,
NameComparisonResult::NameRelation expected_reln)
{
if (expected_order > 0) {
EXPECT_LT(0, chain.getLastComparisonResult().getOrder());
} else if (expected_order < 0) {
EXPECT_GT(0, chain.getLastComparisonResult().getOrder());
} else {
EXPECT_EQ(0, chain.getLastComparisonResult().getOrder());
}
EXPECT_EQ(expected_common_labels,
chain.getLastComparisonResult().getCommonLabels());
EXPECT_EQ(expected_reln,
chain.getLastComparisonResult().getRelation());
}
TEST_F(RBTreeTest, getLastComparedNode) {
RBTree<int>& tree = rbtree_expose_empty_node; // use the "empty OK" mode
RBTreeNodeChain<int> chain;
// initially there should be no 'last compared'.
EXPECT_EQ(static_cast<void*>(NULL), chain.getLastComparedNode());
// A search for an empty tree should result in no 'last compared', too.
RBTree<int> empty_tree;
EXPECT_EQ(RBTree<int>::NOTFOUND,
empty_tree.find<void*>(Name("a"), &crbtnode, chain, NULL, NULL));
EXPECT_EQ(static_cast<void*>(NULL), chain.getLastComparedNode());
chain.clear();
const RBNode<int>* expected_node;
// Exact match case. The returned node should be last compared.
EXPECT_EQ(RBTree<int>::EXACTMATCH,
tree.find<void*>(Name("x.d.e.f"), &expected_node, chain,
NULL, NULL));
EXPECT_EQ(expected_node, chain.getLastComparedNode());
// 2 = # labels of "x."
comparisonChecks(chain, 0, 2, NameComparisonResult::EQUAL);
chain.clear();
// Partial match, search stopped at the matching node, which should be
// the last compared node.
EXPECT_EQ(RBTree<int>::EXACTMATCH,
tree.find(Name("i.g.h"), &expected_node));
EXPECT_EQ(RBTree<int>::PARTIALMATCH,
tree.find<void*>(Name("x.i.g.h"), &crbtnode, chain,
NULL, NULL));
EXPECT_EQ(expected_node, chain.getLastComparedNode());
// i.g.h < x.i.g.h, 2 = # labels of "i."
comparisonChecks(chain, 1, 2, NameComparisonResult::SUBDOMAIN);
chain.clear();
// Partial match, search stopped in the subtree below the matching node
// after following a left branch.
EXPECT_EQ(RBTree<int>::EXACTMATCH,
tree.find(Name("x.d.e.f"), &expected_node));
EXPECT_EQ(RBTree<int>::PARTIALMATCH,
tree.find<void*>(Name("a.d.e.f"), &crbtnode, chain,
NULL, NULL));
EXPECT_EQ(expected_node, chain.getLastComparedNode());
// a < x, 1 = # labels of "." (trailing dot)
comparisonChecks(chain, -1, 1, NameComparisonResult::COMMONANCESTOR);
chain.clear();
// Partial match, search stopped in the subtree below the matching node
// after following a right branch.
EXPECT_EQ(RBTree<int>::EXACTMATCH,
tree.find(Name("z.d.e.f"), &expected_node));
EXPECT_EQ(RBTree<int>::PARTIALMATCH,
tree.find<void*>(Name("zz.d.e.f"), &crbtnode, chain,
NULL, NULL));
EXPECT_EQ(expected_node, chain.getLastComparedNode());
// zz > z, 1 = # labels of "." (trailing dot)
comparisonChecks(chain, 1, 1, NameComparisonResult::COMMONANCESTOR);
chain.clear();
// Search stops in the highest level after following a left branch.
EXPECT_EQ(RBTree<int>::EXACTMATCH, tree.find(Name("c"), &expected_node));
EXPECT_EQ(RBTree<int>::NOTFOUND,
tree.find<void*>(Name("bb"), &crbtnode, chain, NULL, NULL));
EXPECT_EQ(expected_node, chain.getLastComparedNode());
// bb < c, 1 = # labels of "." (trailing dot)
comparisonChecks(chain, -1, 1, NameComparisonResult::COMMONANCESTOR);
chain.clear();
// Search stops in the highest level after following a right branch.
// (the expected node is the same as the previous case)
EXPECT_EQ(RBTree<int>::NOTFOUND,
tree.find<void*>(Name("d"), &crbtnode, chain, NULL, NULL));
EXPECT_EQ(expected_node, chain.getLastComparedNode());
// d > c, 1 = # labels of "." (trailing dot)
comparisonChecks(chain, 1, 1, NameComparisonResult::COMMONANCESTOR);
chain.clear();
}
TEST_F(RBTreeTest, dumpTree) {
std::ostringstream str;
std::ostringstream str2;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment