Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Sebastian Schrader
Kea
Commits
1de3a156
Commit
1de3a156
authored
Jan 19, 2011
by
hanfeng
Browse files
add search policy for rbtree
parent
332f90f4
Changes
2
Hide whitespace changes
Inline
Side-by-side
src/lib/datasrc/rbtree.h
View file @
1de3a156
...
...
@@ -54,7 +54,7 @@ operator-(const isc::dns::Name& super_name, const isc::dns::Name& sub_name) {
}
}
template
<
typename
T
>
template
<
typename
T
,
typename
SearchPolicy
>
class
RBTree
;
/// \brief \c RBNode is used by RBTree to store any data related to one domain
...
...
@@ -82,7 +82,8 @@ class RBNode : public boost::noncopyable {
private:
/// The RBNode is meant for use from within RBTree, so it has access to
/// it.
friend
class
RBTree
<
T
>
;
template
<
typename
U
,
typename
SearchPolicy
>
friend
class
RBTree
;
/// \name Constructors
///
...
...
@@ -256,6 +257,12 @@ RBNode<T>::~RBNode() {
* - Decreases the memory footprint, as it doesn't store the suffix labels
* multiple times.
*
* Depending on different usage, rbtree will support different search policy.
* Whether return empty node to end user is one policy among them. Search
* policy is as the last template parameter, the default policy will NOT
* return empty node to end user, choose ReturnEmptyNodePolicy is empty node
* is needed
*
* \anchor diagram
*
* with the following names:
...
...
@@ -285,10 +292,6 @@ RBNode<T>::~RBNode() {
/ \
o q
\endverbatim
* \note open problems:
* - current \c find() function only returns non-empty nodes, so there is no
* difference between find a non existent name and a name corresponding to
* an empty non-terminal nodes, but in DNS query logic, they are different
* \todo
* - add remove interface
* - add iterator to iterate over the whole \c RBTree. This may be necessary,
...
...
@@ -296,8 +299,14 @@ RBNode<T>::~RBNode() {
* - since \c RBNode only has down pointer without up pointer, the node path
* during finding should be recorded for later use
*/
template
<
typename
T
>
class
RBTree
:
public
boost
::
noncopyable
{
/// \brief forward declare search policy class, which will affect the behavior
/// of the find function in rbtree whether to return empty node
class
ReturnEmptyNodePolicy
;
class
ReturnNonEmptyNodePolicy
;
template
<
typename
T
,
typename
SearchPolicy
=
ReturnNonEmptyNodePolicy
>
class
RBTree
:
public
boost
::
noncopyable
,
public
SearchPolicy
{
friend
class
RBNode
<
T
>
;
public:
/// \brief The return value for the \c find() and insert() methods
...
...
@@ -531,21 +540,22 @@ private:
unsigned
int
node_count_
;
};
template
<
typename
T
>
RBTree
<
T
>::
RBTree
()
{
template
<
typename
T
,
typename
S
>
RBTree
<
T
,
S
>::
RBTree
()
{
NULLNODE
=
RBNode
<
T
>::
NULL_NODE
();
root_
=
NULLNODE
;
node_count_
=
0
;
}
template
<
typename
T
>
RBTree
<
T
>::~
RBTree
()
{
template
<
typename
T
,
typename
S
>
RBTree
<
T
,
S
>::~
RBTree
()
{
deleteHelper
(
root_
);
assert
(
node_count_
==
0
);
}
template
<
typename
T
>
void
RBTree
<
T
>
::
deleteHelper
(
RBNode
<
T
>
*
root
)
{
template
<
typename
T
,
typename
S
>
void
RBTree
<
T
,
S
>::
deleteHelper
(
RBNode
<
T
>
*
root
)
{
if
(
root
==
NULLNODE
)
{
return
;
}
...
...
@@ -574,9 +584,10 @@ void RBTree<T> ::deleteHelper(RBNode<T> *root) {
--
node_count_
;
}
template
<
typename
T
>
template
<
typename
CBARG
>
typename
RBTree
<
T
>::
Result
RBTree
<
T
>::
find
(
const
isc
::
dns
::
Name
&
name
,
RBNode
<
T
>**
node
,
template
<
typename
T
,
typename
S
>
template
<
typename
CBARG
>
typename
RBTree
<
T
,
S
>::
Result
RBTree
<
T
,
S
>::
find
(
const
isc
::
dns
::
Name
&
name
,
RBNode
<
T
>**
node
,
bool
(
*
callback
)(
const
RBNode
<
T
>&
,
CBARG
),
CBARG
callback_arg
)
const
{
...
...
@@ -584,9 +595,10 @@ RBTree<T>::find(const isc::dns::Name& name, RBNode<T>** node,
return
(
findHelper
(
name
,
&
up_node
,
node
,
callback
,
callback_arg
));
}
template
<
typename
T
>
template
<
typename
CBARG
>
typename
RBTree
<
T
>::
Result
RBTree
<
T
>::
find
(
const
isc
::
dns
::
Name
&
name
,
const
RBNode
<
T
>**
node
,
template
<
typename
T
,
typename
S
>
template
<
typename
CBARG
>
typename
RBTree
<
T
,
S
>::
Result
RBTree
<
T
,
S
>::
find
(
const
isc
::
dns
::
Name
&
name
,
const
RBNode
<
T
>**
node
,
bool
(
*
callback
)(
const
RBNode
<
T
>&
,
CBARG
),
CBARG
callback_arg
)
const
{
...
...
@@ -600,9 +612,10 @@ RBTree<T>::find(const isc::dns::Name& name, const RBNode<T>** node,
return
(
ret
);
}
template
<
typename
T
>
template
<
typename
CBARG
>
typename
RBTree
<
T
>::
Result
RBTree
<
T
>::
findHelper
(
const
isc
::
dns
::
Name
&
target_name
,
template
<
typename
T
,
typename
S
>
template
<
typename
CBARG
>
typename
RBTree
<
T
,
S
>::
Result
RBTree
<
T
,
S
>::
findHelper
(
const
isc
::
dns
::
Name
&
target_name
,
const
RBNode
<
T
>**
up_node
,
RBNode
<
T
>**
target
,
bool
(
*
callback
)(
const
RBNode
<
T
>&
,
CBARG
),
...
...
@@ -621,7 +634,7 @@ RBTree<T>::findHelper(const isc::dns::Name& target_name,
const
isc
::
dns
::
NameComparisonResult
::
NameRelation
relation
=
compare_result
.
getRelation
();
if
(
relation
==
isc
::
dns
::
NameComparisonResult
::
EQUAL
)
{
if
(
!
node
->
isEmpty
())
{
if
(
S
::
returnEmptyNode
()
||
!
node
->
isEmpty
())
{
*
target
=
node
;
ret
=
EXACTMATCH
;
}
...
...
@@ -634,7 +647,7 @@ RBTree<T>::findHelper(const isc::dns::Name& target_name,
node
=
(
compare_result
.
getOrder
()
<
0
)
?
node
->
left_
:
node
->
right_
;
}
else
if
(
relation
==
isc
::
dns
::
NameComparisonResult
::
SUBDOMAIN
)
{
if
(
!
node
->
isEmpty
())
{
if
(
S
::
returnEmptyNode
()
||
!
node
->
isEmpty
())
{
ret
=
RBTree
<
T
>::
PARTIALMATCH
;
*
target
=
node
;
if
(
callback
!=
NULL
&&
node
->
callback_required_
)
{
...
...
@@ -655,9 +668,10 @@ RBTree<T>::findHelper(const isc::dns::Name& target_name,
return
(
ret
);
}
template
<
typename
T
>
typename
RBTree
<
T
>::
Result
RBTree
<
T
>::
insert
(
const
isc
::
dns
::
Name
&
target_name
,
RBNode
<
T
>**
new_node
)
{
template
<
typename
T
,
typename
S
>
typename
RBTree
<
T
,
S
>::
Result
RBTree
<
T
,
S
>::
insert
(
const
isc
::
dns
::
Name
&
target_name
,
RBNode
<
T
>**
new_node
)
{
using
namespace
helper
;
RBNode
<
T
>*
parent
=
NULLNODE
;
RBNode
<
T
>*
current
=
root_
;
...
...
@@ -674,7 +688,12 @@ RBTree<T>::insert(const isc::dns::Name& target_name, RBNode<T>** new_node) {
if
(
new_node
!=
NULL
)
{
*
new_node
=
current
;
}
return
(
ALREADYEXISTS
);
if
(
current
->
isEmpty
()
&&
!
S
::
returnEmptyNode
())
{
return
(
SUCCESS
);
}
else
{
return
(
ALREADYEXISTS
);
}
}
else
{
const
int
common_label_count
=
compare_result
.
getCommonLabels
();
if
(
common_label_count
==
1
)
{
...
...
@@ -730,9 +749,10 @@ RBTree<T>::insert(const isc::dns::Name& target_name, RBNode<T>** new_node) {
return
(
SUCCESS
);
}
template
<
typename
T
>
template
<
typename
T
,
typename
S
>
void
RBTree
<
T
>::
nodeFission
(
RBNode
<
T
>&
node
,
const
isc
::
dns
::
Name
&
base_name
)
{
RBTree
<
T
,
S
>::
nodeFission
(
RBNode
<
T
>&
node
,
const
isc
::
dns
::
Name
&
base_name
)
{
using
namespace
helper
;
const
isc
::
dns
::
Name
sub_name
=
node
.
name_
-
base_name
;
// using auto_ptr here is to avoid memory leak in case of exception raised
...
...
@@ -752,9 +772,10 @@ RBTree<T>::nodeFission(RBNode<T>& node, const isc::dns::Name& base_name) {
down_node
.
release
();
}
template
<
typename
T
>
template
<
typename
T
,
typename
S
>
void
RBTree
<
T
>::
insertRebalance
(
RBNode
<
T
>**
root
,
RBNode
<
T
>*
node
)
{
RBTree
<
T
,
S
>::
insertRebalance
(
RBNode
<
T
>**
root
,
RBNode
<
T
>*
node
)
{
RBNode
<
T
>*
uncle
;
while
(
node
!=
*
root
&&
node
->
parent_
->
color_
==
RBNode
<
T
>::
RED
)
{
...
...
@@ -798,9 +819,9 @@ RBTree<T>::insertRebalance(RBNode<T>** root, RBNode<T>* node) {
}
template
<
typename
T
>
template
<
typename
T
,
typename
S
>
RBNode
<
T
>*
RBTree
<
T
>::
leftRotate
(
RBNode
<
T
>**
root
,
RBNode
<
T
>*
node
)
{
RBTree
<
T
,
S
>::
leftRotate
(
RBNode
<
T
>**
root
,
RBNode
<
T
>*
node
)
{
RBNode
<
T
>*
right
=
node
->
right_
;
node
->
right_
=
right
->
left_
;
if
(
right
->
left_
!=
NULLNODE
)
...
...
@@ -823,9 +844,9 @@ RBTree<T>::leftRotate(RBNode<T>** root, RBNode<T>* node) {
return
(
node
);
}
template
<
typename
T
>
template
<
typename
T
,
typename
S
>
RBNode
<
T
>*
RBTree
<
T
>::
rightRotate
(
RBNode
<
T
>**
root
,
RBNode
<
T
>*
node
)
{
RBTree
<
T
,
S
>::
rightRotate
(
RBNode
<
T
>**
root
,
RBNode
<
T
>*
node
)
{
RBNode
<
T
>*
left
=
node
->
left_
;
node
->
left_
=
left
->
right_
;
if
(
left
->
right_
!=
NULLNODE
)
...
...
@@ -847,17 +868,18 @@ RBTree<T>::rightRotate(RBNode<T>** root, RBNode<T>* node) {
return
(
node
);
}
template
<
typename
T
>
template
<
typename
T
,
typename
S
>
void
RBTree
<
T
>::
dumpTree
(
std
::
ostream
&
os
,
unsigned
int
depth
)
const
{
RBTree
<
T
,
S
>::
dumpTree
(
std
::
ostream
&
os
,
unsigned
int
depth
)
const
{
indent
(
os
,
depth
);
os
<<
"tree has "
<<
node_count_
<<
" node(s)
\n
"
;
dumpTreeHelper
(
os
,
root_
,
depth
);
}
template
<
typename
T
>
template
<
typename
T
,
typename
S
>
void
RBTree
<
T
>::
dumpTreeHelper
(
std
::
ostream
&
os
,
const
RBNode
<
T
>*
node
,
RBTree
<
T
,
S
>::
dumpTreeHelper
(
std
::
ostream
&
os
,
const
RBNode
<
T
>*
node
,
unsigned
int
depth
)
const
{
if
(
node
==
NULLNODE
)
{
...
...
@@ -882,13 +904,33 @@ RBTree<T>::dumpTreeHelper(std::ostream& os, const RBNode<T>* node,
dumpTreeHelper
(
os
,
node
->
right_
,
depth
+
1
);
}
template
<
typename
T
>
template
<
typename
T
,
typename
S
>
void
RBTree
<
T
>::
indent
(
std
::
ostream
&
os
,
unsigned
int
depth
)
{
RBTree
<
T
,
S
>::
indent
(
std
::
ostream
&
os
,
unsigned
int
depth
)
{
static
const
unsigned
int
INDENT_FOR_EACH_DEPTH
=
5
;
os
<<
std
::
string
(
depth
*
INDENT_FOR_EACH_DEPTH
,
' '
);
}
/// \brief search policy for rbtree which will affect the find function
/// behavior, depend on usage for rbtree, sometimes it needs return
/// empty node like using rbtree as zone data, the default search policy
/// for rbtree is ReturnNonEmptyNodePolicy.
/// \note to use policy class instead of just a bool variable to add to
/// the construction function of rbtree is considering the extendibility
/// also it is more clean use policy based programming which typically
/// use template class as the policy class
class
ReturnEmptyNodePolicy
{
public:
bool
returnEmptyNode
()
const
{
return
true
;
}
};
class
ReturnNonEmptyNodePolicy
{
public:
bool
returnEmptyNode
()
const
{
return
false
;
}
};
}
}
...
...
src/lib/datasrc/tests/rbtree_unittest.cc
View file @
1de3a156
...
...
@@ -51,30 +51,21 @@ namespace {
class
RBTreeTest
:
public
::
testing
::
Test
{
protected:
RBTreeTest
()
:
rbtree
()
{
rbtree
.
insert
(
Name
(
"c"
),
&
rbtnode
);
rbtnode
->
setData
(
RBNode
<
int
>::
NodeDataPtr
(
new
int
(
1
)));
rbtree
.
insert
(
Name
(
"b"
),
&
rbtnode
);
rbtnode
->
setData
(
RBNode
<
int
>::
NodeDataPtr
(
new
int
(
2
)));
rbtree
.
insert
(
Name
(
"a"
),
&
rbtnode
);
rbtnode
->
setData
(
RBNode
<
int
>::
NodeDataPtr
(
new
int
(
3
)));
rbtree
.
insert
(
Name
(
"x.d.e.f"
),
&
rbtnode
);
rbtnode
->
setData
(
RBNode
<
int
>::
NodeDataPtr
(
new
int
(
4
)));
rbtree
.
insert
(
Name
(
"z.d.e.f"
),
&
rbtnode
);
rbtnode
->
setData
(
RBNode
<
int
>::
NodeDataPtr
(
new
int
(
5
)));
rbtree
.
insert
(
Name
(
"g.h"
),
&
rbtnode
);
rbtnode
->
setData
(
RBNode
<
int
>::
NodeDataPtr
(
new
int
(
6
)));
rbtree
.
insert
(
Name
(
"i.g.h"
),
&
rbtnode
);
rbtnode
->
setData
(
RBNode
<
int
>::
NodeDataPtr
(
new
int
(
7
)));
rbtree
.
insert
(
Name
(
"o.w.y.d.e.f"
),
&
rbtnode
);
rbtnode
->
setData
(
RBNode
<
int
>::
NodeDataPtr
(
new
int
(
8
)));
rbtree
.
insert
(
Name
(
"j.z.d.e.f"
),
&
rbtnode
);
rbtnode
->
setData
(
RBNode
<
int
>::
NodeDataPtr
(
new
int
(
9
)));
rbtree
.
insert
(
Name
(
"p.w.y.d.e.f"
),
&
rbtnode
);
rbtnode
->
setData
(
RBNode
<
int
>::
NodeDataPtr
(
new
int
(
10
)));
rbtree
.
insert
(
Name
(
"q.w.y.d.e.f"
),
&
rbtnode
);
rbtnode
->
setData
(
RBNode
<
int
>::
NodeDataPtr
(
new
int
(
11
)));
const
char
*
domain_names
[]
=
{
"c"
,
"b"
,
"a"
,
"x.d.e.f"
,
"z.d.e.f"
,
"g.h"
,
"i.g.h"
,
"o.w.y.d.e.f"
,
"j.z.d.e.f"
,
"p.w.y.d.e.f"
,
"q.w.y.d.e.f"
};
int
name_count
=
sizeof
(
domain_names
)
/
sizeof
(
domain_names
[
0
]);
for
(
int
i
=
0
;
i
<
name_count
;
++
i
)
{
rbtree
.
insert
(
Name
(
domain_names
[
i
]),
&
rbtnode
);
rbtnode
->
setData
(
RBNode
<
int
>::
NodeDataPtr
(
new
int
(
i
+
1
)));
rbtree_expose_empty_node
.
insert
(
Name
(
domain_names
[
i
]),
&
rbtnode
);
rbtnode
->
setData
(
RBNode
<
int
>::
NodeDataPtr
(
new
int
(
i
+
1
)));
}
}
RBTree
<
int
>
rbtree
;
RBTree
<
int
,
ReturnEmptyNodePolicy
>
rbtree_expose_empty_node
;
RBNode
<
int
>*
rbtnode
;
const
RBNode
<
int
>*
crbtnode
;
};
...
...
@@ -90,32 +81,64 @@ TEST_F(RBTreeTest, setGetData) {
}
TEST_F
(
RBTreeTest
,
insertNames
)
{
EXPECT_EQ
(
RBTree
<
int
>::
ALREADYEXISTS
,
rbtree
.
insert
(
Name
(
"d.e.f"
),
&
rbtnode
));
//if don't expose empty node, even the node already exsit which is caused by node fission
//we will return succeed
EXPECT_EQ
(
RBTree
<
int
>::
SUCCESS
,
rbtree
.
insert
(
Name
(
"d.e.f"
),
&
rbtnode
));
EXPECT_EQ
(
Name
(
"d.e.f"
),
rbtnode
->
getName
());
EXPECT_EQ
(
13
,
rbtree
.
getNodeCount
());
EXPECT_EQ
(
RBTree
<
int
>::
ALREADYEXISTS
,
rbtree_expose_empty_node
.
insert
(
Name
(
"d.e.f"
),
&
rbtnode
));
EXPECT_EQ
(
Name
(
"d.e.f"
),
rbtnode
->
getName
());
EXPECT_EQ
(
13
,
rbtree_expose_empty_node
.
getNodeCount
());
//insert not exist node
EXPECT_EQ
(
RBTree
<
int
>::
SUCCESS
,
rbtree
.
insert
(
Name
(
"."
),
&
rbtnode
));
EXPECT_EQ
(
Name
(
"."
),
rbtnode
->
getName
());
EXPECT_EQ
(
14
,
rbtree
.
getNodeCount
());
EXPECT_EQ
(
RBTree
<
int
>::
SUCCESS
,
rbtree_expose_empty_node
.
insert
(
Name
(
"."
),
&
rbtnode
));
EXPECT_EQ
(
Name
(
"."
),
rbtnode
->
getName
());
EXPECT_EQ
(
14
,
rbtree_expose_empty_node
.
getNodeCount
());
EXPECT_EQ
(
RBTree
<
int
>::
SUCCESS
,
rbtree
.
insert
(
Name
(
"example.com"
),
&
rbtnode
));
EXPECT_EQ
(
15
,
rbtree
.
getNodeCount
());
rbtnode
->
setData
(
RBNode
<
int
>::
NodeDataPtr
(
new
int
(
12
)));
EXPECT_EQ
(
RBTree
<
int
>::
SUCCESS
,
rbtree_expose_empty_node
.
insert
(
Name
(
"example.com"
),
&
rbtnode
));
EXPECT_EQ
(
15
,
rbtree_expose_empty_node
.
getNodeCount
());
rbtnode
->
setData
(
RBNode
<
int
>::
NodeDataPtr
(
new
int
(
12
)));
// return ALREADYEXISTS, since node "example.com" already has been explicitly inserted
EXPECT_EQ
(
RBTree
<
int
>::
ALREADYEXISTS
,
rbtree
.
insert
(
Name
(
"example.com"
),
&
rbtnode
));
EXPECT_EQ
(
15
,
rbtree
.
getNodeCount
());
EXPECT_EQ
(
RBTree
<
int
>::
ALREADYEXISTS
,
rbtree_expose_empty_node
.
insert
(
Name
(
"example.com"
),
&
rbtnode
));
EXPECT_EQ
(
15
,
rbtree_expose_empty_node
.
getNodeCount
());
// split the node "d.e.f"
EXPECT_EQ
(
RBTree
<
int
>::
SUCCESS
,
rbtree
.
insert
(
Name
(
"k.e.f"
),
&
rbtnode
));
EXPECT_EQ
(
Name
(
"k"
),
rbtnode
->
getName
());
EXPECT_EQ
(
17
,
rbtree
.
getNodeCount
());
EXPECT_EQ
(
RBTree
<
int
>::
SUCCESS
,
rbtree_expose_empty_node
.
insert
(
Name
(
"k.e.f"
),
&
rbtnode
));
EXPECT_EQ
(
Name
(
"k"
),
rbtnode
->
getName
());
EXPECT_EQ
(
17
,
rbtree_expose_empty_node
.
getNodeCount
());
// split the node "g.h"
EXPECT_EQ
(
RBTree
<
int
>::
ALREADYEXIST
S
,
rbtree
.
insert
(
Name
(
"h"
),
&
rbtnode
));
EXPECT_EQ
(
RBTree
<
int
>::
SUCCES
S
,
rbtree
.
insert
(
Name
(
"h"
),
&
rbtnode
));
EXPECT_EQ
(
Name
(
"h"
),
rbtnode
->
getName
());
EXPECT_EQ
(
18
,
rbtree
.
getNodeCount
());
//node fission will create node "h"
EXPECT_EQ
(
RBTree
<
int
>::
ALREADYEXISTS
,
rbtree_expose_empty_node
.
insert
(
Name
(
"h"
),
&
rbtnode
));
EXPECT_EQ
(
Name
(
"h"
),
rbtnode
->
getName
());
EXPECT_EQ
(
18
,
rbtree_expose_empty_node
.
getNodeCount
());
// add child domain
EXPECT_EQ
(
RBTree
<
int
>::
SUCCESS
,
rbtree
.
insert
(
Name
(
"m.p.w.y.d.e.f"
),
&
rbtnode
));
EXPECT_EQ
(
Name
(
"m"
),
rbtnode
->
getName
());
...
...
@@ -124,18 +147,35 @@ TEST_F(RBTreeTest, insertNames) {
EXPECT_EQ
(
Name
(
"n"
),
rbtnode
->
getName
());
EXPECT_EQ
(
20
,
rbtree
.
getNodeCount
());
EXPECT_EQ
(
RBTree
<
int
>::
SUCCESS
,
rbtree_expose_empty_node
.
insert
(
Name
(
"m.p.w.y.d.e.f"
),
&
rbtnode
));
EXPECT_EQ
(
Name
(
"m"
),
rbtnode
->
getName
());
EXPECT_EQ
(
19
,
rbtree_expose_empty_node
.
getNodeCount
());
EXPECT_EQ
(
RBTree
<
int
>::
SUCCESS
,
rbtree_expose_empty_node
.
insert
(
Name
(
"n.p.w.y.d.e.f"
),
&
rbtnode
));
EXPECT_EQ
(
Name
(
"n"
),
rbtnode
->
getName
());
EXPECT_EQ
(
20
,
rbtree_expose_empty_node
.
getNodeCount
());
EXPECT_EQ
(
RBTree
<
int
>::
SUCCESS
,
rbtree
.
insert
(
Name
(
"l.a"
),
&
rbtnode
));
EXPECT_EQ
(
Name
(
"l"
),
rbtnode
->
getName
());
EXPECT_EQ
(
21
,
rbtree
.
getNodeCount
());
EXPECT_EQ
(
RBTree
<
int
>::
SUCCESS
,
rbtree_expose_empty_node
.
insert
(
Name
(
"l.a"
),
&
rbtnode
));
EXPECT_EQ
(
Name
(
"l"
),
rbtnode
->
getName
());
EXPECT_EQ
(
21
,
rbtree_expose_empty_node
.
getNodeCount
());
EXPECT_EQ
(
RBTree
<
int
>::
SUCCESS
,
rbtree
.
insert
(
Name
(
"r.d.e.f"
),
&
rbtnode
));
EXPECT_EQ
(
RBTree
<
int
>::
SUCCESS
,
rbtree
.
insert
(
Name
(
"s.d.e.f"
),
&
rbtnode
));
EXPECT_EQ
(
23
,
rbtree
.
getNodeCount
());
EXPECT_EQ
(
RBTree
<
int
>::
SUCCESS
,
rbtree_expose_empty_node
.
insert
(
Name
(
"r.d.e.f"
),
&
rbtnode
));
EXPECT_EQ
(
RBTree
<
int
>::
SUCCESS
,
rbtree_expose_empty_node
.
insert
(
Name
(
"s.d.e.f"
),
&
rbtnode
));
EXPECT_EQ
(
23
,
rbtree_expose_empty_node
.
getNodeCount
());
EXPECT_EQ
(
RBTree
<
int
>::
SUCCESS
,
rbtree
.
insert
(
Name
(
"h.w.y.d.e.f"
),
&
rbtnode
));
EXPECT_EQ
(
RBTree
<
int
>::
SUCCESS
,
rbtree_expose_empty_node
.
insert
(
Name
(
"h.w.y.d.e.f"
),
&
rbtnode
));
// add more nodes one by one to cover leftRotate and rightRotate
EXPECT_EQ
(
RBTree
<
int
>::
ALREADYEXIST
S
,
rbtree
.
insert
(
Name
(
"f"
),
&
rbtnode
));
EXPECT_EQ
(
RBTree
<
int
>::
SUCCES
S
,
rbtree
.
insert
(
Name
(
"f"
),
&
rbtnode
));
EXPECT_EQ
(
RBTree
<
int
>::
SUCCESS
,
rbtree
.
insert
(
Name
(
"m"
),
&
rbtnode
));
EXPECT_EQ
(
RBTree
<
int
>::
SUCCESS
,
rbtree
.
insert
(
Name
(
"nm"
),
&
rbtnode
));
EXPECT_EQ
(
RBTree
<
int
>::
SUCCESS
,
rbtree
.
insert
(
Name
(
"om"
),
&
rbtnode
));
...
...
@@ -146,8 +186,21 @@ TEST_F(RBTreeTest, insertNames) {
EXPECT_EQ
(
RBTree
<
int
>::
SUCCESS
,
rbtree
.
insert
(
Name
(
"i"
),
&
rbtnode
));
EXPECT_EQ
(
RBTree
<
int
>::
SUCCESS
,
rbtree
.
insert
(
Name
(
"ae"
),
&
rbtnode
));
EXPECT_EQ
(
RBTree
<
int
>::
SUCCESS
,
rbtree
.
insert
(
Name
(
"n"
),
&
rbtnode
));
EXPECT_EQ
(
RBTree
<
int
>::
ALREADYEXISTS
,
rbtree_expose_empty_node
.
insert
(
Name
(
"f"
),
&
rbtnode
));
EXPECT_EQ
(
RBTree
<
int
>::
SUCCESS
,
rbtree_expose_empty_node
.
insert
(
Name
(
"m"
),
&
rbtnode
));
EXPECT_EQ
(
RBTree
<
int
>::
SUCCESS
,
rbtree_expose_empty_node
.
insert
(
Name
(
"nm"
),
&
rbtnode
));
EXPECT_EQ
(
RBTree
<
int
>::
SUCCESS
,
rbtree_expose_empty_node
.
insert
(
Name
(
"om"
),
&
rbtnode
));
EXPECT_EQ
(
RBTree
<
int
>::
SUCCESS
,
rbtree_expose_empty_node
.
insert
(
Name
(
"k"
),
&
rbtnode
));
EXPECT_EQ
(
RBTree
<
int
>::
SUCCESS
,
rbtree_expose_empty_node
.
insert
(
Name
(
"l"
),
&
rbtnode
));
EXPECT_EQ
(
RBTree
<
int
>::
SUCCESS
,
rbtree_expose_empty_node
.
insert
(
Name
(
"fe"
),
&
rbtnode
));
EXPECT_EQ
(
RBTree
<
int
>::
SUCCESS
,
rbtree_expose_empty_node
.
insert
(
Name
(
"ge"
),
&
rbtnode
));
EXPECT_EQ
(
RBTree
<
int
>::
SUCCESS
,
rbtree_expose_empty_node
.
insert
(
Name
(
"i"
),
&
rbtnode
));
EXPECT_EQ
(
RBTree
<
int
>::
SUCCESS
,
rbtree_expose_empty_node
.
insert
(
Name
(
"ae"
),
&
rbtnode
));
EXPECT_EQ
(
RBTree
<
int
>::
SUCCESS
,
rbtree_expose_empty_node
.
insert
(
Name
(
"n"
),
&
rbtnode
));
}
TEST_F
(
RBTreeTest
,
findName
)
{
// find const rbtnode
// exact match
...
...
@@ -196,7 +249,7 @@ TEST_F(RBTreeTest, callback) {
&
subrbtnode
));
subrbtnode
->
setData
(
RBNode
<
int
>::
NodeDataPtr
(
new
int
(
2
)));
RBNode
<
int
>*
parentrbtnode
;
EXPECT_EQ
(
RBTree
<
int
>::
ALREADYEXIST
S
,
rbtree
.
insert
(
Name
(
"example"
),
EXPECT_EQ
(
RBTree
<
int
>::
SUCCES
S
,
rbtree
.
insert
(
Name
(
"example"
),
&
parentrbtnode
));
// the chilld/parent nodes shouldn't "inherit" the callback flag.
// "rbtnode" may be invalid due to the insertion, so we need to re-find
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment