if (node->getFlag(domain_flag::WILD) && // maybe a wildcard, check only
(options & ZoneFinder::NO_WILDCARD) == 0) { // if not disabled.
if (node_path.getLastComparisonResult().getRelation() ==
- NameComparisonResult::COMMONANCESTOR &&
- node_path.getLastComparisonResult().getCommonLabels() > 1) {
- // Wildcard canceled. Treat it as NXDOMAIN.
- // Note: Because the way the tree stores relative names, we
- // will have exactly one common label (the ".") in case we have
- // nothing common under the node we got, and we will get
- // more common labels otherwise (yes, this relies on the
- // internal RBTree structure, which leaks out through this
- // little bit).
+ NameComparisonResult::COMMONANCESTOR) {
+ // This means, e.g., we have *.wild.example and
+ // bar.foo.wild.example and are looking for
+ // baz.foo.wild.example. The common ancestor, foo.wild.example,
+ // should cancel wildcard. Treat it as NXDOMAIN.
LOG_DEBUG(logger, DBG_TRACE_DATA,
DATASRC_MEM_WILDCARD_CANCEL).arg(name);
return (ResultType(ZoneFinder::NXDOMAIN, NULL,
#include <exceptions/exceptions.h>
#include <util/memory_segment.h>
#include <dns/name.h>
+#include <dns/labelsequence.h>
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/interprocess/offset_ptr.hpp>
+#include <boost/static_assert.hpp>
#include <ostream>
#include <algorithm>
namespace isc {
namespace datasrc {
-namespace helper {
-
-/// \brief Helper function to remove the base domain from super domain.
-///
-/// The precondition of this function is the super_name contains the
-/// sub_name so
-/// \code Name a("a.b.c");
-/// Name b("b.c");
-/// Name c = a - b;
-/// \endcode
-/// c will contain "a".
-///
-/// \note Functions in this namespace is not intended to be used outside of
-/// RBTree implementation.
-inline isc::dns::Name
-operator-(const isc::dns::Name& super_name, const isc::dns::Name& sub_name) {
- return (super_name.split(0, super_name.getLabelCount() -
- sub_name.getLabelCount()));
-}
-}
-
/// Forward declare RBTree class here is convinent for following friend
/// class declare inside RBNode and RBTreeNodeChain
template <typename T>
/// "null" node.
RBNode();
- /// \brief Constructor from the node name.
- ///
- /// \param name The *relative* domain name (if this will live inside
- /// a.b.c and is called d.e.a.b.c, then you pass d.e).
- RBNode(const isc::dns::Name& name);
+ /// \brief Constructor from normal nodes.
+ RBNode(size_t labels_capacity);
/// \brief Destructor
~RBNode();
/// \param mem_sgmt A \c MemorySegment from which memory for the new
/// \c RBNode is allocated.
static RBNode<T>* create(util::MemorySegment& mem_sgmt,
- const dns::Name& name)
+ const dns::LabelSequence& labels)
{
- void* p = mem_sgmt.allocate(sizeof(RBNode<T>));
- return (new(p) RBNode<T>(name));
+ const size_t labels_len = labels.getSerializedLength();
+ void* p = mem_sgmt.allocate(sizeof(RBNode<T>) + labels_len);
+ RBNode<T>* node = new(p) RBNode<T>(labels_len);
+ labels.serialize(node->getLabelsData(), labels_len);
+ return (node);
}
/// \brief Destruct and deallocate \c RBNode
/// that was originally created by the \c create() method (the behavior
/// is undefined if this condition isn't met).
static void destroy(util::MemorySegment& mem_sgmt, RBNode<T>* rbnode) {
+ const size_t labels_capacity = rbnode->labels_capacity_;
rbnode->~RBNode<T>();
- mem_sgmt.deallocate(rbnode, sizeof(RBNode<T>));
+ mem_sgmt.deallocate(rbnode, sizeof(RBNode<T>) + labels_capacity);
+ }
+
+ /// TBD
+ void resetLabels(const dns::LabelSequence& labels) {
+ labels.serialize(getLabelsData(), labels_capacity_);
+ }
+
+ /// TBD
+ const void* getLabelsData() const {
+ return (this + 1);
+ }
+
+ /// TBD
+ void* getLabelsData() {
+ return (this + 1);
}
public:
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
+ FLAG_USER1 = 0x400000U, ///< Application specific flag
+ FLAG_USER2 = 0x200000U, ///< Application specific flag
+ FLAG_USER3 = 0x100000U ///< Application specific flag
};
private:
// Some flag values are expected to be used for internal purposes
///
/// To get the absolute name of one node, the node path from the top node
/// to current node has to be recorded.
- const isc::dns::Name& getName() const { return (name_); }
+ const isc::dns::Name getName() const {
+ assert(labels_capacity_ != 0);
+ return (dns::Name(dns::LabelSequence(getLabelsData()).toText()));
+ }
+
+ dns::LabelSequence getLabels() const {
+ assert(labels_capacity_ != 0);
+ return (dns::LabelSequence(getLabelsData()));
+ }
/// \brief Return the data stored in this node.
///
RBNodeColor color_;
//@}
- /// \brief Relative name of the node.
- isc::dns::Name name_;
/// \brief Data stored here.
NodeDataPtr data_;
/// RBTree::find().
///
/// \todo It might be needed to put it into more general attributes field.
- uint32_t flags_;
+ uint32_t flags_ : 23; // largest flag being 0x400000
+ const uint32_t labels_capacity_ : 9; // range is 0..511
+ /// TBD
+ BOOST_STATIC_ASSERT((1 << 9) > dns::LabelSequence::MAX_SERIALIZED_LENGTH);
};
-
// This is only to support NULL nodes.
template <typename T>
RBNode<T>::RBNode() :
parent_(NULL),
left_(NULL),
right_(NULL),
- // dummy name, the value doesn't matter:
- name_(isc::dns::Name::ROOT_NAME()),
down_(NULL),
- flags_(FLAG_SUBTREE_ROOT)
+ flags_(FLAG_SUBTREE_ROOT),
+ labels_capacity_(0)
{
// Some compilers object to use of "this" in initializer lists.
parent_ = this;
}
template <typename T>
-RBNode<T>::RBNode(const isc::dns::Name& name) :
+RBNode<T>::RBNode(size_t labels_capacity) :
parent_(NULL_NODE()),
left_(NULL_NODE()),
right_(NULL_NODE()),
- name_(name),
down_(NULL_NODE()),
- flags_(FLAG_RED | FLAG_SUBTREE_ROOT)
+ flags_(FLAG_RED | FLAG_SUBTREE_ROOT),
+ labels_capacity_(labels_capacity)
{
}
-
template <typename T>
RBNode<T>::~RBNode() {
}
/// of old node will be move into new node, and old node became
/// non-terminal
void nodeFission(util::MemorySegment& mem_sgmt, RBNode<T>& node,
- const isc::dns::Name& sub_name);
+ const isc::dns::LabelSequence& sub_labels);
//@}
RBNode<T>* NULLNODE;
bool (*callback)(const RBNode<T>&, CBARG),
CBARG callback_arg) const
{
- using namespace helper;
-
if (!node_path.isEmpty()) {
isc_throw(isc::BadValue, "RBTree::find is given a non empty chain");
}
RBNode<T>* node = root_.get();
Result ret = NOTFOUND;
- isc::dns::Name name = target_name;
+ dns::LabelSequence target_labels(target_name);
while (node != NULLNODE) {
node_path.last_compared_ = node;
- node_path.last_comparison_ = name.compare(node->name_);
+ node_path.last_comparison_ = target_labels.compare(node->getLabels());
const isc::dns::NameComparisonResult::NameRelation relation =
node_path.last_comparison_.getRelation();
ret = EXACTMATCH;
}
break;
+ } else if (relation == isc::dns::NameComparisonResult::NONE) {
+ // If the two labels have no hierarchical relationship in terms
+ // of matching, we should continue the binary search.
+ node = (node_path.last_comparison_.getOrder() < 0) ?
+ node->getLeft() : node->getRight();
} else {
- 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". In this case the two
- // sequences of labels have essentially no hierarchical
- // relationship in terms of matching, so we should continue the
- // binary search. One important exception is when the node
- // represents the root name ("."), in which case the comparison
- // result must indeed be considered subdomain matching. (We use
- // getLength() to check if the name is root, which is an equivalent
- // but cheaper way).
- if (common_label_count == 1 && node->name_.getLength() != 1) {
- node = (node_path.last_comparison_.getOrder() < 0) ?
- node->getLeft() : node->getRight();
- } else if (relation == isc::dns::NameComparisonResult::SUBDOMAIN) {
+ if (relation == isc::dns::NameComparisonResult::SUBDOMAIN) {
if (needsReturnEmptyNode_ || !node->isEmpty()) {
ret = PARTIALMATCH;
*target = node;
}
}
node_path.push(node);
- name = name - node->name_;
+ target_labels.stripRight(
+ node_path.last_comparison_.getCommonLabels());
node = node->getDown();
} else {
break;
// all the cases and decide where to go from there.
switch (node_path.last_comparison_.getRelation()) {
case dns::NameComparisonResult::COMMONANCESTOR:
+ case dns::NameComparisonResult::NONE:
// We compared with a leaf in the tree and wanted to go to one of
// the children. But the child was not there. It now depends on the
// direction in which we wanted to go.
// already, which located the exact node. The rest of the function
// goes one domain left and returns it for us.
break;
- default:
- // This must not happen as Name::compare() never returns NONE.
- isc_throw(isc::Unexpected, "Name::compare() returned unexpected result");
}
// So, the node_path now contains the path to a node we want previous for.
RBTree<T>::insert(util::MemorySegment& mem_sgmt,
const isc::dns::Name& target_name, RBNode<T>** new_node)
{
- using namespace helper;
RBNode<T>* parent = NULLNODE;
RBNode<T>* current = root_.get();
RBNode<T>* up_node = NULLNODE;
- isc::dns::Name name = target_name;
+ isc::dns::LabelSequence target_labels(target_name);
int order = -1;
while (current != NULLNODE) {
const isc::dns::NameComparisonResult compare_result =
- name.compare(current->name_);
+ target_labels.compare(current->getLabels());
const isc::dns::NameComparisonResult::NameRelation relation =
compare_result.getRelation();
if (relation == isc::dns::NameComparisonResult::EQUAL) {
*new_node = current;
}
return (ALREADYEXISTS);
+ } else if (relation == isc::dns::NameComparisonResult::NONE) {
+ parent = current;
+ order = compare_result.getOrder();
+ current = order < 0 ? current->getLeft() : current->getRight();
+ } else if (relation == isc::dns::NameComparisonResult::SUBDOMAIN) {
+ // insert sub domain to sub tree
+ parent = NULLNODE;
+ up_node = current;
+ target_labels.stripRight(compare_result.getCommonLabels());
+ current = current->getDown();
} else {
- const int common_label_count = compare_result.getCommonLabels();
- // Note: see find() for the check of getLength().
- if (common_label_count == 1 && current->name_.getLength() != 1) {
- parent = current;
- order = compare_result.getOrder();
- current = order < 0 ? current->getLeft() : current->getRight();
- } else {
- // insert sub domain to sub tree
- if (relation == isc::dns::NameComparisonResult::SUBDOMAIN) {
- parent = NULLNODE;
- up_node = current;
- name = name - current->name_;
- current = current->getDown();
- } else {
- // The number of labels in common is fewer
- // than the number of labels at the current
- // node, so the current node must be adjusted
- // to have just the common suffix, and a down
- // pointer made to a new tree.
- const isc::dns::Name common_ancestor = name.split(
- name.getLabelCount() - common_label_count,
- common_label_count);
- nodeFission(mem_sgmt, *current, common_ancestor);
- }
- }
+ // The number of labels in common is fewer
+ // than the number of labels at the current
+ // node, so the current node must be adjusted
+ // to have just the common suffix, and a down
+ // pointer made to a new tree.
+ dns::LabelSequence common_ancestor = target_labels;
+ common_ancestor.stripLeft(target_labels.getLabelCount() -
+ compare_result.getCommonLabels());
+ nodeFission(mem_sgmt, *current, common_ancestor);
}
}
&(up_node->down_) : &root_;
// Once a new node is created, no exception will be thrown until the end
// of the function, so we can simply create and hold a new node pointer.
- RBNode<T>* node = RBNode<T>::create(mem_sgmt, name);
+ RBNode<T>* node = RBNode<T>::create(mem_sgmt, target_labels);
node->parent_ = parent;
if (parent == NULLNODE) {
*current_root = node;
template <typename T>
void
RBTree<T>::nodeFission(util::MemorySegment& mem_sgmt, RBNode<T>& node,
- const isc::dns::Name& base_name)
+ const isc::dns::LabelSequence& base_labels)
{
- using namespace helper;
- const isc::dns::Name sub_name = node.name_ - base_name;
- // Note: the following code is not entirely exception safe (name copy
- // can result in exception), but will soon be so within Trac #2091.
- RBNode<T>* down_node = RBNode<T>::create(mem_sgmt, sub_name);
- node.name_ = base_name;
- // the rest of this function should be exception free so that it keeps
- // consistent behavior (i.e., a weak form of strong exception guarantee)
- // even if code after the call to this function throws an exception.
+ dns::LabelSequence sub_labels = node.getLabels();
+ sub_labels.stripRight(base_labels.getLabelCount());
+
+ // Once a new node is created, no exception will be thrown until
+ // the end of the function, and it will keep consistent behavior
+ // (i.e., a weak form of strong exception guarantee) even if code
+ // after the call to this function throws an exception.
+ RBNode<T>* down_node = RBNode<T>::create(mem_sgmt, sub_labels);
+ node.resetLabels(base_labels);
+
std::swap(node.data_, down_node->data_);
- std::swap(node.flags_, down_node->flags_);
+
+ // Swap flags bitfields; yes, this is ugly. The right solution is to
+ // implement the above note, then we won't have to swap the flags in the
+ // first place.
+ struct {
+ uint32_t flags_ : 23;
+ uint32_t unused_ : 9;
+ } tmp;
+ tmp.flags_ = node.flags_;
+ node.flags_ = down_node->flags_;
+ down_node->flags_ = tmp.flags_;
down_node->down_ = node.getDown();
node.down_ = down_node;
}
indent(os, depth);
- os << node->name_.toText() << " ("
+ os << node->getName().toText() << " ("
<< ((node->getColor() == RBNode<T>::BLACK) ? "black" : "red") << ")";
if (node->isEmpty()) {
os << " [invisible]";
const RBNode<T>* down = node->getDown();
if (down != NULLNODE) {
indent(os, depth + 1);
- os << "begin down from " << node->name_.toText() << "\n";
+ os << "begin down from " << node->getName().toText() << "\n";
dumpTreeHelper(os, down, depth + 1);
indent(os, depth + 1);
- os << "end down from " << node->name_.toText() << "\n";
+ os << "end down from " << node->getName().toText() << "\n";
}
dumpTreeHelper(os, node->getLeft(), depth + 1);
dumpTreeHelper(os, node->getRight(), depth + 1);
/* The initial structure of rbtree
*
+* .
+ * |
* b
* / \
* a d.e.f
};
TEST_F(RBTreeTest, nodeCount) {
- EXPECT_EQ(14, rbtree.getNodeCount());
+ EXPECT_EQ(15, rbtree.getNodeCount());
// Delete all nodes, then the count should be set to 0. This also tests
// the behavior of deleteAllNodes().
Name("d.e.f"),
&rbtnode));
EXPECT_EQ(Name("d.e.f"), rbtnode->getName());
- EXPECT_EQ(14, rbtree.getNodeCount());
+ EXPECT_EQ(15, rbtree.getNodeCount());
- //insert not exist node
- EXPECT_EQ(RBTree<int>::SUCCESS, rbtree.insert(mem_sgmt_, Name("."),
+ // insert not exist node
+ EXPECT_EQ(RBTree<int>::SUCCESS, rbtree.insert(mem_sgmt_, Name("0"),
&rbtnode));
- EXPECT_EQ(Name("."), rbtnode->getName());
- EXPECT_EQ(15, rbtree.getNodeCount());
+ EXPECT_EQ(Name("0"), rbtnode->getName());
+ EXPECT_EQ(16, rbtree.getNodeCount());
EXPECT_EQ(RBTree<int>::SUCCESS, rbtree.insert(mem_sgmt_,
Name("example.com"),
&rbtnode));
- EXPECT_EQ(16, rbtree.getNodeCount());
+ EXPECT_EQ(17, rbtree.getNodeCount());
rbtnode->setData(RBNode<int>::NodeDataPtr(new int(12)));
- // return ALREADYEXISTS, since node "example.com" already has been explicitly inserted
+ // return ALREADYEXISTS, since node "example.com" already has
+ // been explicitly inserted
EXPECT_EQ(RBTree<int>::ALREADYEXISTS, rbtree.insert(mem_sgmt_,
Name("example.com"),
&rbtnode));
- EXPECT_EQ(16, rbtree.getNodeCount());
+ EXPECT_EQ(17, rbtree.getNodeCount());
// split the node "d.e.f"
EXPECT_EQ(RBTree<int>::SUCCESS, rbtree.insert(mem_sgmt_, Name("k.e.f"),
&rbtnode));
EXPECT_EQ(Name("k"), rbtnode->getName());
- EXPECT_EQ(18, rbtree.getNodeCount());
+ EXPECT_EQ(19, rbtree.getNodeCount());
// split the node "g.h"
EXPECT_EQ(RBTree<int>::ALREADYEXISTS, rbtree.insert(mem_sgmt_, Name("h"),
&rbtnode));
EXPECT_EQ(Name("h"), rbtnode->getName());
- EXPECT_EQ(19, rbtree.getNodeCount());
+ EXPECT_EQ(20, rbtree.getNodeCount());
// add child domain
EXPECT_EQ(RBTree<int>::SUCCESS, rbtree.insert(mem_sgmt_,
Name("m.p.w.y.d.e.f"),
&rbtnode));
EXPECT_EQ(Name("m"), rbtnode->getName());
- EXPECT_EQ(20, rbtree.getNodeCount());
+ EXPECT_EQ(21, rbtree.getNodeCount());
EXPECT_EQ(RBTree<int>::SUCCESS, rbtree.insert(mem_sgmt_,
Name("n.p.w.y.d.e.f"),
&rbtnode));
EXPECT_EQ(Name("n"), rbtnode->getName());
- EXPECT_EQ(21, rbtree.getNodeCount());
+ EXPECT_EQ(22, rbtree.getNodeCount());
EXPECT_EQ(RBTree<int>::SUCCESS, rbtree.insert(mem_sgmt_, Name("l.a"),
&rbtnode));
EXPECT_EQ(Name("l"), rbtnode->getName());
- EXPECT_EQ(22, rbtree.getNodeCount());
+ EXPECT_EQ(23, rbtree.getNodeCount());
EXPECT_EQ(RBTree<int>::SUCCESS, rbtree.insert(mem_sgmt_, Name("r.d.e.f"),
&rbtnode));
EXPECT_EQ(RBTree<int>::SUCCESS, rbtree.insert(mem_sgmt_, Name("s.d.e.f"),
&rbtnode));
- EXPECT_EQ(24, rbtree.getNodeCount());
+ EXPECT_EQ(25, rbtree.getNodeCount());
EXPECT_EQ(RBTree<int>::SUCCESS, rbtree.insert(mem_sgmt_,
Name("h.w.y.d.e.f"),
rbtree_expose_empty_node.find(Name("m.d.e.f"), &crbtnode));
// find rbtnode
- EXPECT_EQ(RBTree<int>::EXACTMATCH, rbtree.find(Name("q.w.y.d.e.f"), &rbtnode));
+ EXPECT_EQ(RBTree<int>::EXACTMATCH, rbtree.find(Name("q.w.y.d.e.f"),
+ &rbtnode));
EXPECT_EQ(Name("q"), rbtnode->getName());
}
/*
*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, k.g.h
+ * ., 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, k.g.h
+ * . (no data, can't be found)
+ * |
* b
* / \
* a d.e.f
}
// We should have reached the start of the tree.
+ ASSERT_NE(static_cast<void*>(NULL), node);
+ EXPECT_EQ(".", node->getLabels().toText());
+
+ // With one more call it results in NULL
+ node = rbtree.previousNode(node_path);
EXPECT_EQ(static_cast<void*>(NULL), node);
// Calling previousNode() yet again should still return NULL without
EXPECT_EQ(RBTree<int>::EXACTMATCH,
rbtree.find(Name(names[0]), &node, node_path));
EXPECT_NE(static_cast<void*>(NULL), node);
- EXPECT_EQ(static_cast<void*>(NULL), rbtree.previousNode(node_path));
+ node = rbtree.previousNode(node_path);
+ ASSERT_NE(static_cast<void*>(NULL), node);
+ EXPECT_EQ(".", node->getLabels().toText());
node = NULL;
node_path.clear();
}
{
SCOPED_TRACE("Start before the first");
- // If we start before the lowest (0 < a), we should not get a node nor
+ // If we start before the lowest (. < 0. < a.), we should not get a
+ // node. Its previous node should be the root.
EXPECT_EQ(RBTree<int>::NOTFOUND,
rbtree.find<void*>(Name("0"), &node, node_path, NULL, NULL));
EXPECT_EQ(static_cast<void*>(NULL), node);
- EXPECT_EQ(static_cast<void*>(NULL), rbtree.previousNode(node_path));
+ node = rbtree.previousNode(node_path);
+ ASSERT_NE(static_cast<void*>(NULL), node);
+ EXPECT_EQ(".", node->getLabels().toText());
node = NULL;
node_path.clear();
}
EXPECT_EQ(RBTree<int>::EXACTMATCH,
tree.find(Name("x.d.e.f"), &expected_node, chain));
EXPECT_EQ(expected_node, chain.getLastComparedNode());
- // 2 = # labels of "x."
- comparisonChecks(chain, 0, 2, NameComparisonResult::EQUAL);
+ // 1 = # labels of "x" (note: excluding ".")
+ comparisonChecks(chain, 0, 1, NameComparisonResult::EQUAL);
chain.clear();
// Partial match, search stopped at the matching node, which should be
EXPECT_EQ(RBTree<int>::PARTIALMATCH,
tree.find(Name("x.k.g.h"), &crbtnode, chain));
EXPECT_EQ(expected_node, chain.getLastComparedNode());
- // k.g.h < x.k.g.h, 2 = # labels of "k."
- comparisonChecks(chain, 1, 2, NameComparisonResult::SUBDOMAIN);
+ // k.g.h < x.k.g.h, 1 = # labels of "k"
+ comparisonChecks(chain, 1, 1, NameComparisonResult::SUBDOMAIN);
chain.clear();
// Partial match, search stopped in the subtree below the matching node
EXPECT_EQ(RBTree<int>::PARTIALMATCH,
tree.find(Name("a.d.e.f"), &crbtnode, chain));
EXPECT_EQ(expected_node, chain.getLastComparedNode());
- // a < x, 1 = # labels of "." (trailing dot)
- comparisonChecks(chain, -1, 1, NameComparisonResult::COMMONANCESTOR);
+ // a < x, no common labels
+ comparisonChecks(chain, -1, 0, NameComparisonResult::NONE);
chain.clear();
// Partial match, search stopped in the subtree below the matching node
EXPECT_EQ(RBTree<int>::PARTIALMATCH,
tree.find(Name("zz.d.e.f"), &crbtnode, chain));
EXPECT_EQ(expected_node, chain.getLastComparedNode());
- // zz > z, 1 = # labels of "." (trailing dot)
- comparisonChecks(chain, 1, 1, NameComparisonResult::COMMONANCESTOR);
+ // zz > z, no common label
+ comparisonChecks(chain, 1, 0, NameComparisonResult::NONE);
chain.clear();
// Partial match, search stopped at a node for a super domain of the
EXPECT_EQ(RBTree<int>::PARTIALMATCH,
tree.find(Name("y.d.e.f"), &crbtnode, chain));
EXPECT_EQ(expected_node, chain.getLastComparedNode());
- // y < w.y, 2 = # labels of "y."
- comparisonChecks(chain, -1, 2, NameComparisonResult::SUPERDOMAIN);
+ // y < w.y, 1 = # labels of "y"
+ comparisonChecks(chain, -1, 1, NameComparisonResult::SUPERDOMAIN);
chain.clear();
// Partial match, search stopped at a node that share a common ancestor
EXPECT_EQ(RBTree<int>::PARTIALMATCH,
tree.find(Name("z.y.d.e.f"), &crbtnode, chain));
EXPECT_EQ(expected_node, chain.getLastComparedNode());
- // z.y > w.y, 2 = # labels of "y."
- comparisonChecks(chain, 1, 2, NameComparisonResult::COMMONANCESTOR);
+ // z.y > w.y, 1 = # labels of "y"
+ comparisonChecks(chain, 1, 1, NameComparisonResult::COMMONANCESTOR);
chain.clear();
- // Search stops in the highest level after following a left branch.
+ // Search stops in the highest level (under ".") after following a left
+ // branch. (find() still returns PARTIALMATCH due to the top level ".")
EXPECT_EQ(RBTree<int>::EXACTMATCH, tree.find(Name("c"), &expected_node));
- EXPECT_EQ(RBTree<int>::NOTFOUND,
+ EXPECT_EQ(RBTree<int>::PARTIALMATCH,
tree.find(Name("bb"), &crbtnode, chain));
EXPECT_EQ(expected_node, chain.getLastComparedNode());
- // bb < c, 1 = # labels of "." (trailing dot)
- comparisonChecks(chain, -1, 1, NameComparisonResult::COMMONANCESTOR);
+ // bb < c, no common label
+ //comparisonChecks(chain, -1, 1, NameComparisonResult::COMMONANCESTOR);
+ comparisonChecks(chain, -1, 0, NameComparisonResult::NONE);
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,
+ // Search stops in the highest level (under ".") after following a right
+ // branch. (the expected node is the same as the previous case)
+ EXPECT_EQ(RBTree<int>::PARTIALMATCH,
tree.find(Name("d"), &crbtnode, chain));
EXPECT_EQ(expected_node, chain.getLastComparedNode());
- // d > c, 1 = # labels of "." (trailing dot)
- comparisonChecks(chain, 1, 1, NameComparisonResult::COMMONANCESTOR);
+ // d > c, no common label
+ comparisonChecks(chain, 1, 0, NameComparisonResult::NONE);
chain.clear();
}
std::ostringstream str;
std::ostringstream str2;
rbtree.dumpTree(str);
- str2 << "tree has 14 node(s)\n"
- "b. (black) [subtreeroot]\n"
- " a. (black)\n"
- " NULL\n"
- " NULL\n"
- " d.e.f. (black) [invisible]\n"
- " begin down from d.e.f.\n"
- " w.y. (black) [invisible] [subtreeroot]\n"
- " begin down from w.y.\n"
- " p. (black) [subtreeroot]\n"
- " o. (red)\n"
+ str2 << "tree has 15 node(s)\n"
+ ". (black) [invisible] [subtreeroot]\n"
+ " begin down from .\n"
+ " b. (black) [subtreeroot]\n"
+ " a. (black)\n"
+ " NULL\n"
+ " NULL\n"
+ " d.e.f. (black) [invisible]\n"
+ " begin down from d.e.f.\n"
+ " w.y. (black) [invisible] [subtreeroot]\n"
+ " begin down from w.y.\n"
+ " p. (black) [subtreeroot]\n"
+ " o. (red)\n"
+ " NULL\n"
+ " NULL\n"
+ " q. (red)\n"
+ " NULL\n"
+ " NULL\n"
+ " end down from w.y.\n"
+ " x. (red)\n"
" NULL\n"
" NULL\n"
- " q. (red)\n"
+ " z. (red)\n"
+ " begin down from z.\n"
+ " j. (black) [subtreeroot]\n"
+ " NULL\n"
+ " NULL\n"
+ " end down from z.\n"
" NULL\n"
" NULL\n"
- " end down from w.y.\n"
- " x. (red)\n"
+ " end down from d.e.f.\n"
+ " c. (red)\n"
" NULL\n"
" NULL\n"
- " z. (red)\n"
- " begin down from z.\n"
- " j. (black) [subtreeroot]\n"
- " NULL\n"
+ " g.h. (red)\n"
+ " begin down from g.h.\n"
+ " i. (black) [subtreeroot]\n"
" NULL\n"
- " end down from z.\n"
+ " k. (red)\n"
+ " NULL\n"
+ " NULL\n"
+ " end down from g.h.\n"
" NULL\n"
" NULL\n"
- " end down from d.e.f.\n"
- " c. (red)\n"
- " NULL\n"
- " NULL\n"
- " g.h. (red)\n"
- " begin down from g.h.\n"
- " i. (black) [subtreeroot]\n"
- " NULL\n"
- " k. (red)\n"
- " NULL\n"
- " NULL\n"
- " end down from g.h.\n"
- " NULL\n"
- " NULL\n";
+ " end down from .\n"
+ " NULL\n"
+ " NULL\n";
EXPECT_EQ(str2.str(), str.str());
}