mirror of
https://github.com/openjdk/jdk.git
synced 2026-05-11 05:59:52 +00:00
8349525: RBTree: provide leftmost, rightmost, and a simple way to print trees
Reviewed-by: jsjolen, cnorrbin
This commit is contained in:
parent
e9278de3f8
commit
7d52f1e64d
@ -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;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user