8349525: RBTree: provide leftmost, rightmost, and a simple way to print trees

Reviewed-by: jsjolen, cnorrbin
This commit is contained in:
Thomas Stuefe 2025-02-08 06:35:27 +00:00
parent e9278de3f8
commit 7d52f1e64d
3 changed files with 253 additions and 75 deletions

View File

@ -30,6 +30,8 @@
#include "utilities/globalDefinitions.hpp"
#include <type_traits>
class outputStream;
// COMPARATOR must have a static function `cmp(a,b)` which returns:
// - an int < 0 when a < b
// - an int == 0 when a == b
@ -43,7 +45,7 @@
template <typename K, typename V, typename COMPARATOR, typename ALLOCATOR>
class RBTree {
friend class RBTreeTest;
typedef RBTree<K, V, COMPARATOR, ALLOCATOR> TreeType;
private:
ALLOCATOR _allocator;
size_t _num_nodes;
@ -61,12 +63,13 @@ public:
const K _key;
V _value;
DEBUG_ONLY(bool _visited);
DEBUG_ONLY(mutable bool _visited);
public:
const K& key() const { return _key; }
V& val() { return _value; }
const V& val() const { return _value; }
void set_val(const V& v) { _value = v; }
private:
bool is_black() const { return (_parent & 0x1) != 0; }
@ -100,20 +103,22 @@ public:
// Returns left child (now parent)
RBNode* rotate_right();
RBNode* prev();
const RBNode* prev() const;
RBNode* next();
const RBNode* next() const;
#ifdef ASSERT
void verify(size_t& num_nodes, size_t& black_nodes_until_leaf,
size_t& shortest_leaf_path, size_t& longest_leaf_path,
size_t& tree_depth, bool expect_visited);
#endif // ASSERT
};
size_t& tree_depth, bool expect_visited) const;
#endif // ASSERT
}; // End: RBNode
typedef TreeType::RBNode NodeType;
private:
RBNode* _root;
DEBUG_ONLY(bool _expected_visited);
DEBUG_ONLY(mutable bool _expected_visited);
RBNode* allocate_node(const K& key, const V& val) {
void* node_place = _allocator.allocate(sizeof(RBNode));
@ -148,6 +153,8 @@ private:
// Assumption: node has at most one child. Two children is handled in `remove()`
void remove_from_tree(RBNode* node);
void print_node_on(outputStream* st, int depth, const NodeType* n) const;
public:
NONCOPYABLE(RBTree);
@ -156,7 +163,7 @@ public:
}
~RBTree() { this->remove_all(); }
size_t size() { return _num_nodes; }
size_t size() const { return _num_nodes; }
// Inserts a node with the given k/v into the tree,
// if the key already exist, the value is updated instead.
@ -257,19 +264,44 @@ public:
RBNode* closest_leq(const K& key) {
return const_cast<RBNode*>(
static_cast<const RBTree<K, V, COMPARATOR, ALLOCATOR>*>(this)->closest_leq(key));
static_cast<const TreeType*>(this)->closest_leq(key));
}
RBNode* closest_gt(const K& key) {
return const_cast<RBNode*>(
static_cast<const RBTree<K, V, COMPARATOR, ALLOCATOR>*>(this)->closest_gt(key));
static_cast<const TreeType*>(this)->closest_gt(key));
}
RBNode* closest_geq(const K& key) {
return const_cast<RBNode*>(
static_cast<const RBTree<K, V, COMPARATOR, ALLOCATOR>*>(this)->closest_geq(key));
static_cast<const TreeType*>(this)->closest_geq(key));
}
// Returns leftmost node, nullptr if tree is empty.
// If COMPARATOR::cmp(a, b) behaves canonically (positive value for a > b), this will the smallest key value.
const RBNode* leftmost() const {
RBNode* n = _root, *n2 = nullptr;
while (n != nullptr) {
n2 = n;
n = n->_left;
}
return n2;
}
// Returns rightmost node, nullptr if tree is empty.
// If COMPARATOR::cmp(a, b) behaves canonically (positive value for a > b), this will the largest key value.
const RBNode* rightmost() const {
RBNode* n = _root, *n2 = nullptr;
while (n != nullptr) {
n2 = n;
n = n->_right;
}
return n2;
}
RBNode* leftmost() { return const_cast<NodeType*>(static_cast<const TreeType*>(this)->leftmost()); }
RBNode* rightmost() { return const_cast<NodeType*>(static_cast<const TreeType*>(this)->rightmost()); }
struct Range {
RBNode* start;
RBNode* end;
@ -280,7 +312,7 @@ public:
// Return the range [start, end)
// where start->key() <= addr < end->key().
// Failure to find the range leads to start and/or end being null.
Range find_enclosing_range(K key) {
Range find_enclosing_range(K key) const {
RBNode* start = closest_leq(key);
RBNode* end = closest_gt(key);
return Range(start, end);
@ -291,7 +323,7 @@ public:
RBNode* find_node(const K& key) {
return const_cast<RBNode*>(
static_cast<const RBTree<K, V, COMPARATOR, ALLOCATOR>*>(this)->find_node(key));
static_cast<const TreeType*>(this)->find_node(key));
}
// Finds the value associated with the key
@ -311,12 +343,12 @@ public:
// Visit all RBNodes in ascending order whose keys are in range [from, to), calling f on each node.
template <typename F>
void visit_range_in_order(const K& from, const K& to, F f);
void visit_range_in_order(const K& from, const K& to, F f) const;
#ifdef ASSERT
// Verifies that the tree is correct and holds rb-properties
void verify_self();
#endif // ASSERT
void verify_self() const NOT_DEBUG({});
void print_on(outputStream* st) const;
};

View File

@ -25,8 +25,10 @@
#ifndef SHARE_UTILITIES_RBTREE_INLINE_HPP
#define SHARE_UTILITIES_RBTREE_INLINE_HPP
#include "metaprogramming/enableIf.hpp"
#include "utilities/debug.hpp"
#include "utilities/globalDefinitions.hpp"
#include "utilities/ostream.hpp"
#include "utilities/powerOfTwo.hpp"
#include "utilities/rbTree.hpp"
@ -87,9 +89,9 @@ RBTree<K, V, COMPARATOR, ALLOCATOR>::RBNode::rotate_right() {
}
template <typename K, typename V, typename COMPARATOR, typename ALLOCATOR>
inline typename RBTree<K, V, COMPARATOR, ALLOCATOR>::RBNode*
RBTree<K, V, COMPARATOR, ALLOCATOR>::RBNode::prev() {
RBNode* node = this;
inline const typename RBTree<K, V, COMPARATOR, ALLOCATOR>::RBNode*
RBTree<K, V, COMPARATOR, ALLOCATOR>::RBNode::prev() const {
const RBNode* node = this;
if (_left != nullptr) { // right subtree exists
node = _left;
while (node->_right != nullptr) {
@ -105,9 +107,9 @@ RBTree<K, V, COMPARATOR, ALLOCATOR>::RBNode::prev() {
}
template <typename K, typename V, typename COMPARATOR, typename ALLOCATOR>
inline typename RBTree<K, V, COMPARATOR, ALLOCATOR>::RBNode*
RBTree<K, V, COMPARATOR, ALLOCATOR>::RBNode::next() {
RBNode* node = this;
inline const typename RBTree<K, V, COMPARATOR, ALLOCATOR>::RBNode*
RBTree<K, V, COMPARATOR, ALLOCATOR>::RBNode::next() const {
const RBNode* node = this;
if (_right != nullptr) { // right subtree exists
node = _right;
while (node->_left != nullptr) {
@ -126,7 +128,7 @@ RBTree<K, V, COMPARATOR, ALLOCATOR>::RBNode::next() {
template <typename K, typename V, typename COMPARATOR, typename ALLOCATOR>
inline void RBTree<K, V, COMPARATOR, ALLOCATOR>::RBNode::verify(
size_t& num_nodes, size_t& black_nodes_until_leaf, size_t& shortest_leaf_path, size_t& longest_leaf_path,
size_t& tree_depth, bool expect_visited) {
size_t& tree_depth, bool expect_visited) const {
assert(expect_visited != _visited, "node already visited");
_visited = !_visited;
@ -479,12 +481,13 @@ inline void RBTree<K, V, COMPARATOR, ALLOCATOR>::remove(RBNode* node) {
template <typename K, typename V, typename COMPARATOR, typename ALLOCATOR>
template <typename F>
inline void RBTree<K, V, COMPARATOR, ALLOCATOR>::visit_in_order(F f) const {
RBNode* to_visit[64];
const RBNode* to_visit[64];
int stack_idx = 0;
RBNode* head = _root;
const RBNode* head = _root;
while (stack_idx > 0 || head != nullptr) {
while (head != nullptr) {
to_visit[stack_idx++] = head;
assert(stack_idx <= (int)(sizeof(to_visit)/sizeof(to_visit[0])), "stack too deep");
head = head->_left;
}
head = to_visit[--stack_idx];
@ -495,11 +498,11 @@ inline void RBTree<K, V, COMPARATOR, ALLOCATOR>::visit_in_order(F f) const {
template <typename K, typename V, typename COMPARATOR, typename ALLOCATOR>
template <typename F>
inline void RBTree<K, V, COMPARATOR, ALLOCATOR>::visit_range_in_order(const K& from, const K& to, F f) {
inline void RBTree<K, V, COMPARATOR, ALLOCATOR>::visit_range_in_order(const K& from, const K& to, F f) const {
assert(COMPARATOR::cmp(from, to) <= 0, "from must be less or equal to to");
RBNode* curr = closest_geq(from);
const RBNode* curr = closest_geq(from);
if (curr == nullptr) return;
RBNode* end = closest_geq(to);
const RBNode* const end = closest_geq(to);
while (curr != nullptr && curr != end) {
f(curr);
@ -509,7 +512,7 @@ inline void RBTree<K, V, COMPARATOR, ALLOCATOR>::visit_range_in_order(const K& f
#ifdef ASSERT
template <typename K, typename V, typename COMPARATOR, typename ALLOCATOR>
inline void RBTree<K, V, COMPARATOR, ALLOCATOR>::verify_self() {
inline void RBTree<K, V, COMPARATOR, ALLOCATOR>::verify_self() const {
if (_root == nullptr) {
assert(_num_nodes == 0, "rbtree has nodes but no root");
return;
@ -538,4 +541,49 @@ inline void RBTree<K, V, COMPARATOR, ALLOCATOR>::verify_self() {
}
#endif // ASSERT
template <typename T,
ENABLE_IF(std::is_integral<T>::value),
ENABLE_IF(std::is_signed<T>::value)>
void print_T(outputStream* st, T x) {
st->print(INT64_FORMAT, (int64_t)x);
}
template <typename T,
ENABLE_IF(std::is_integral<T>::value),
ENABLE_IF(std::is_unsigned<T>::value)>
void print_T(outputStream* st, T x) {
st->print(UINT64_FORMAT, (uint64_t)x);
}
template <typename T,
ENABLE_IF(std::is_pointer<T>::value)>
void print_T(outputStream* st, T x) {
st->print(PTR_FORMAT, p2i(x));
}
template <typename K, typename V, typename COMPARATOR, typename ALLOCATOR>
void RBTree<K, V, COMPARATOR, ALLOCATOR>::print_node_on(outputStream* st, int depth, const NodeType* n) const {
st->print("(%d)", depth);
st->sp(1 + depth * 2);
st->print("@" PTR_FORMAT ": [", p2i(n));
print_T<K>(st, n->key());
st->print("] = ");
print_T<V>(st, n->val());
st->cr();
depth++;
if (n->_right != nullptr) {
print_node_on(st, depth, n->_right);
}
if (n->_left != nullptr) {
print_node_on(st, depth, n->_left);
}
}
template <typename K, typename V, typename COMPARATOR, typename ALLOCATOR>
void RBTree<K, V, COMPARATOR, ALLOCATOR>::print_on(outputStream* st) const {
if (_root != nullptr) {
print_node_on(st, 0, _root);
}
}
#endif // SHARE_UTILITIES_RBTREE_INLINE_HPP

View File

@ -72,13 +72,6 @@ struct ArrayAllocator {
void free(void* ptr) { }
};
#ifdef ASSERT
template<typename K, typename V, typename CMP, typename ALLOC>
void verify_it(RBTree<K, V, CMP, ALLOC>& t) {
t.verify_self();
}
#endif // ASSERT
using RBTreeInt = RBTreeCHeap<int, int, Cmp, mtOther>;
public:
@ -86,6 +79,7 @@ public:
constexpr int up_to = 10;
GrowableArrayCHeap<int, mtTest> nums_seen(up_to, up_to, 0);
RBTreeInt rbtree;
const RBTreeInt& rbtree_const = rbtree;
for (int i = 0; i < up_to; i++) {
rbtree.upsert(i, i);
@ -95,7 +89,7 @@ public:
rbtree.upsert(i, i);
}
rbtree.visit_in_order([&](RBTreeInt::RBNode* node) {
rbtree_const.visit_in_order([&](const RBTreeInt::RBNode* node) {
nums_seen.at(node->key())++;
});
for (int i = 0; i < up_to; i++) {
@ -173,22 +167,23 @@ public:
void test_visitors() {
{ // Tests with 'default' ordering (ascending)
RBTreeInt rbtree;
const RBTreeInt& rbtree_const = rbtree;
using Node = RBTreeInt::RBNode;
rbtree.visit_range_in_order(0, 100, [&](Node* x) {
rbtree_const.visit_range_in_order(0, 100, [&](const Node* x) {
EXPECT_TRUE(false) << "Empty rbtree has no nodes to visit";
});
// Single-element set
rbtree.upsert(1, 0);
int count = 0;
rbtree.visit_range_in_order(0, 100, [&](Node* x) {
rbtree_const.visit_range_in_order(0, 100, [&](const Node* x) {
count++;
});
EXPECT_EQ(1, count);
count = 0;
rbtree.visit_in_order([&](Node* x) {
rbtree_const.visit_in_order([&](const Node* x) {
count++;
});
EXPECT_EQ(1, count);
@ -198,20 +193,20 @@ public:
rbtree.upsert(101, 0);
rbtree.upsert(-1, 0);
count = 0;
rbtree.visit_range_in_order(0, 100, [&](Node* x) {
rbtree_const.visit_range_in_order(0, 100, [&](const Node* x) {
count++;
});
EXPECT_EQ(1, count);
count = 0;
rbtree.visit_in_order([&](Node* x) {
rbtree_const.visit_in_order([&](const Node* x) {
count++;
});
EXPECT_EQ(3, count);
// Visiting empty range [0, 0) == {}
rbtree.upsert(0, 0); // This node should not be visited.
rbtree.visit_range_in_order(0, 0, [&](Node* x) {
rbtree_const.visit_range_in_order(0, 0, [&](const Node* x) {
EXPECT_TRUE(false) << "Empty visiting range should not visit any node";
});
@ -222,7 +217,7 @@ public:
ResourceMark rm;
GrowableArray<int> seen;
rbtree.visit_range_in_order(0, 10, [&](Node* x) {
rbtree_const.visit_range_in_order(0, 10, [&](const Node* x) {
seen.push(x->key());
});
EXPECT_EQ(10, seen.length());
@ -231,7 +226,7 @@ public:
}
seen.clear();
rbtree.visit_in_order([&](Node* x) {
rbtree_const.visit_in_order([&](const Node* x) {
seen.push(x->key());
});
EXPECT_EQ(11, seen.length());
@ -240,7 +235,7 @@ public:
}
seen.clear();
rbtree.visit_range_in_order(10, 12, [&](Node* x) {
rbtree_const.visit_range_in_order(10, 12, [&](const Node* x) {
seen.push(x->key());
});
EXPECT_EQ(1, seen.length());
@ -248,6 +243,7 @@ public:
}
{ // Test with descending ordering
RBTreeCHeap<int, int, CmpInverse, mtOther> rbtree;
const RBTreeCHeap<int, int, CmpInverse, mtOther>& rbtree_const = rbtree;
using Node = RBTreeCHeap<int, int, CmpInverse, mtOther>::RBNode;
for (int i = 0; i < 10; i++) {
@ -255,7 +251,7 @@ public:
}
ResourceMark rm;
GrowableArray<int> seen;
rbtree.visit_range_in_order(9, -1, [&](Node* x) {
rbtree_const.visit_range_in_order(9, -1, [&](const Node* x) {
seen.push(x->key());
});
EXPECT_EQ(10, seen.length());
@ -264,7 +260,7 @@ public:
}
seen.clear();
rbtree.visit_in_order([&](Node* x) {
rbtree_const.visit_in_order([&](const Node* x) {
seen.push(x->key());
});
EXPECT_EQ(10, seen.length());
@ -278,36 +274,38 @@ public:
using Node = RBTreeInt::RBNode;
{
RBTreeInt rbtree;
Node* n = rbtree.closest_leq(0);
const RBTreeInt& rbtree_const = rbtree;
const Node* n = rbtree_const.closest_leq(0);
EXPECT_EQ(nullptr, n);
rbtree.upsert(0, 0);
n = rbtree.closest_leq(0);
n = rbtree_const.closest_leq(0);
EXPECT_EQ(0, n->key());
rbtree.upsert(-1, -1);
n = rbtree.closest_leq(0);
n = rbtree_const.closest_leq(0);
EXPECT_EQ(0, n->key());
rbtree.upsert(6, 0);
n = rbtree.closest_leq(6);
n = rbtree_const.closest_leq(6);
EXPECT_EQ(6, n->key());
n = rbtree.closest_leq(-2);
n = rbtree_const.closest_leq(-2);
EXPECT_EQ(nullptr, n);
}
}
void test_node_prev() {
RBTreeInt _tree;
RBTreeInt rbtree;
const RBTreeInt& rbtree_const = rbtree;
using Node = RBTreeInt::RBNode;
constexpr int num_nodes = 100;
for (int i = num_nodes; i > 0; i--) {
_tree.upsert(i, i);
rbtree.upsert(i, i);
}
Node* node = _tree.find_node(num_nodes);
const Node* node = rbtree_const.find_node(num_nodes);
int count = num_nodes;
while (node != nullptr) {
EXPECT_EQ(count, node->val());
@ -318,16 +316,17 @@ public:
EXPECT_EQ(count, 0);
}
void test_node_next() {
RBTreeInt _tree;
void test_node_next() {
RBTreeInt rbtree;
const RBTreeInt& rbtree_const = rbtree;
using Node = RBTreeInt::RBNode;
constexpr int num_nodes = 100;
for (int i = 0; i < num_nodes; i++) {
_tree.upsert(i, i);
rbtree.upsert(i, i);
}
Node* node = _tree.find_node(0);
const Node* node = rbtree_const.find_node(0);
int count = 0;
while (node != nullptr) {
EXPECT_EQ(count, node->val());
@ -339,8 +338,9 @@ public:
}
void test_stable_nodes() {
using Node = RBTreeInt::RBNode;
RBTreeInt rbtree;
const RBTreeInt& rbtree_const = rbtree;
using Node = RBTreeInt::RBNode;
ResourceMark rm;
GrowableArray<Node*> a(10000);
for (int i = 0; i < 10000; i++) {
@ -359,7 +359,7 @@ public:
// After deleting, nodes should have been moved around but kept their values
for (int i = 0; i < 10000; i++) {
const Node* n = rbtree.find_node(i);
const Node* n = rbtree_const.find_node(i);
if (n != nullptr) {
EXPECT_EQ(a.at(i), n);
}
@ -386,15 +386,48 @@ public:
}
// After deleting, values should have remained consistant
rbtree.visit_in_order([&](Node* node) {
rbtree.visit_in_order([&](const Node* node) {
EXPECT_EQ(node, node->val());
});
}
void test_leftmost_rightmost() {
using Node = RBTreeInt::RBNode;
for (int i = 0; i < 10; i++) {
RBTreeInt rbtree;
const RBTreeInt& rbtree_const = rbtree;
int max = 0, min = INT_MAX;
for (int j = 0; j < 10; j++) {
if (j == 0) {
ASSERT_EQ(rbtree_const.leftmost(), (const Node*)nullptr);
ASSERT_EQ(rbtree_const.rightmost(), (const Node*)nullptr);
} else {
ASSERT_EQ(rbtree_const.rightmost()->key(), max);
ASSERT_EQ(rbtree_const.rightmost()->val(), max);
ASSERT_EQ(rbtree_const.leftmost()->key(), min);
ASSERT_EQ(rbtree_const.leftmost()->val(), min);
ASSERT_EQ(rbtree_const.rightmost(), rbtree.rightmost());
ASSERT_EQ(rbtree_const.leftmost(), rbtree.leftmost());
}
const int r = os::random();
rbtree.upsert(r, r);
min = MIN2(min, r);
max = MAX2(max, r);
}
// Explicitly test non-const variants
Node* n = rbtree.rightmost();
ASSERT_EQ(n->key(), max);
n->set_val(1);
n = rbtree.leftmost();
ASSERT_EQ(n->key(), min);
n->set_val(1);
}
}
#ifdef ASSERT
void test_fill_verify() {
RBTreeInt rbtree;
const RBTreeInt& rbtree_const = rbtree;
ResourceMark rm;
GrowableArray<int> allocations;
@ -412,7 +445,7 @@ public:
rbtree.upsert(allocations.at(i), allocations.at(i));
}
if (i % 100 == 0) {
verify_it(rbtree);
rbtree_const.verify_self();
}
}
@ -425,7 +458,7 @@ public:
rbtree.remove(allocations.at(i));
}
if (i % 100 == 0) {
verify_it(rbtree);
rbtree_const.verify_self();
}
}
@ -434,8 +467,8 @@ public:
rbtree.remove(allocations.at(i));
}
verify_it(rbtree);
EXPECT_EQ(rbtree.size(), 0UL);
rbtree.verify_self();
EXPECT_EQ(rbtree_const.size(), 0UL);
}
void test_nodes_visited_once() {
@ -458,7 +491,7 @@ public:
node += 1;
}
verify_it(tree);
tree.verify_self();
node = start;
for (int i = 0; i < num_nodes; i++) {
@ -507,6 +540,71 @@ TEST_VM_F(RBTreeTest, NodeStableAddressTest) {
this->test_stable_nodes_addresses();
}
TEST_VM_F(RBTreeTest, LeftMostRightMost) {
this->test_leftmost_rightmost();
}
struct PtrCmp {
static int cmp(const void* a, const void* b) {
const uintptr_t ai = p2u(a);
const uintptr_t bi = p2u(b);
return ai == bi ? 0 : (ai > bi ? 1 : -1);
}
};
TEST_VM(RBTreeTestNonFixture, TestPrintPointerTree) {
typedef RBTreeCHeap<const void*, unsigned, PtrCmp, mtTest> TreeType;
TreeType tree;
#ifdef _LP64
const void* const p1 = (const void*) 0x800000000ULL;
const char* const s1 = "[0x0000000800000000] = 1";
const void* const p2 = (const void*) 0xDEADBEEF0ULL;
const char* const s2 = "[0x0000000deadbeef0] = 2";
const void* const p3 = (const void*) 0x7f223fba0ULL;
const char* const s3 = "[0x00000007f223fba0] = 3";
#else
const void* const p1 = (const void*) 0x80000000ULL;
const char* const s1 = "[0x80000000] = 1";
const void* const p2 = (const void*) 0xDEADBEEFLL;
const char* const s2 = "[0xdeadbeef] = 2";
const void* const p3 = (const void*) 0x7f223fbaULL;
const char* const s3 = "[0x7f223fba] = 3";
#endif
tree.upsert(p1, 1);
tree.upsert(p2, 2);
tree.upsert(p3, 3);
stringStream ss;
tree.print_on(&ss);
const char* const N = nullptr;
ASSERT_NE(strstr(ss.base(), s1), N);
ASSERT_NE(strstr(ss.base(), s2), N);
ASSERT_NE(strstr(ss.base(), s3), N);
}
struct IntCmp {
static int cmp(int a, int b) { return a == b ? 0 : (a > b ? 1 : -1); }
};
TEST_VM(RBTreeTestNonFixture, TestPrintIntegerTree) {
typedef RBTree<int, unsigned, IntCmp, RBTreeCHeapAllocator<mtTest> > TreeType;
TreeType tree;
const int i1 = 82924;
const char* const s1 = "[82924] = 1";
const int i2 = -13591;
const char* const s2 = "[-13591] = 2";
const int i3 = 0;
const char* const s3 = "[0] = 3";
tree.upsert(i1, 1);
tree.upsert(i2, 2);
tree.upsert(i3, 3);
stringStream ss;
tree.print_on(&ss);
const char* const N = nullptr;
ASSERT_NE(strstr(ss.base(), s1), N);
ASSERT_NE(strstr(ss.base(), s2), N);
ASSERT_NE(strstr(ss.base(), s3), N);
}
#ifdef ASSERT
TEST_VM_F(RBTreeTest, FillAndVerify) {
this->test_fill_verify();
@ -527,7 +625,7 @@ TEST_VM_F(RBTreeTest, InsertRemoveVerify) {
for (int i = 0; i < n_t2; i++) {
tree.remove(i);
}
verify_it(tree);
tree.verify_self();
}
}
}
@ -544,7 +642,7 @@ TEST_VM_F(RBTreeTest, VerifyItThroughStressTest) {
rbtree.remove(i);
}
if (i % 100 == 0) {
verify_it(rbtree);
rbtree.verify_self();
}
}
for (int i = 0; i < ten_thousand; i++) {
@ -555,7 +653,7 @@ TEST_VM_F(RBTreeTest, VerifyItThroughStressTest) {
rbtree.remove(i);
}
if (i % 100 == 0) {
verify_it(rbtree);
rbtree.verify_self();
}
}
}
@ -566,7 +664,7 @@ TEST_VM_F(RBTreeTest, VerifyItThroughStressTest) {
for (int i = 0; i < one_hundred_thousand; i++) {
rbtree.upsert(i, Nothing());
}
verify_it(rbtree);
rbtree.verify_self();
}
}