wangzelin.wzl 93a1074b0c patch 4.0
2022-10-24 17:57:12 +08:00

440 lines
11 KiB
C++

/**
* Copyright (c) 2021 OceanBase
* OceanBase CE is licensed under Mulan PubL v2.
* You can use this software according to the terms and conditions of the Mulan PubL v2.
* You may obtain a copy of Mulan PubL v2 at:
* http://license.coscl.org.cn/MulanPubL-2.0
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PubL v2 for more details.
*/
#include <unistd.h>
#include <stdarg.h>
#include <errno.h>
#include <time.h>
#include "lib/container/ob_rbtree.h"
#include "gtest/gtest.h"
namespace oceanbase
{
namespace container
{
#ifndef UNUSED
#define UNUSED(v) ((void)(v))
#endif
typedef struct node_s node_t;
struct node_s
{
#define NODE_MAGIC 0x9823af7e
int magic;
RBNODE(node_t, rblink);
int key;
inline int compare(const node_s *node) const
{
int ret = 0;
EXPECT_EQ(this->magic, NODE_MAGIC);
EXPECT_EQ(node->magic, NODE_MAGIC);
ret = (key > node->key) - (key < node->key);
if (ret == 0) {
/*
* Duplicates are not allowed in the tree, so force an
* arbitrary ordering for non-identical items with equal keys.
*/
ret = (((uintptr_t)this) > ((uintptr_t)node))
- (((uintptr_t)this) < ((uintptr_t)node));
}
return ret;
}
};
typedef ObRbTree<node_t, ObDummyCompHelper<node_t>> tree_t;
TEST (TestRbTree, empty)
{
int ret = OB_SUCCESS;
node_t *r_node = NULL;
tree_t tree;
node_t key;
tree.init_tree();
bool tmp = tree.is_empty();
EXPECT_EQ(tmp, true);
r_node = tree.get_first();
if (OB_FAIL(ret)) {
fprintf(stderr, "red black tree get first fail %d", ret);
EXPECT_EQ(ret, OB_SUCCESS);
} else {
ASSERT_TRUE(r_node == NULL);
}
r_node = tree.get_last();
if (OB_FAIL(ret)) {
fprintf(stderr, "red black tree get last fail %d", ret);
EXPECT_EQ(ret, OB_SUCCESS);
} else {
ASSERT_TRUE(r_node == NULL);
}
key.key = 0;
key.magic = NODE_MAGIC;
ret = tree.search(&key, r_node);
if (OB_FAIL(ret)) {
fprintf(stderr, "red black tree search fail %d", ret);
EXPECT_EQ(ret, OB_SUCCESS);
} else {
ASSERT_TRUE(r_node == NULL);
}
key.key = 0;
key.magic = NODE_MAGIC;
ret = tree.nsearch(&key, r_node);
if (OB_FAIL(ret)) {
fprintf(stderr, "red black tree nsearch fail %d", ret);
EXPECT_EQ(ret, OB_SUCCESS);
} else {
ASSERT_TRUE(r_node == NULL);
}
ret = tree.psearch(&key, r_node);
if (OB_FAIL(ret)) {
fprintf(stderr, "red black tree psarch fail %d", ret);
EXPECT_EQ(ret, OB_SUCCESS);
} else {
ASSERT_TRUE(r_node == NULL);
}
}
static unsigned tree_recurse(node_t *node, uint64_t black_height,
unsigned black_depth, tree_t &rbtree)
{
unsigned ret = 0;
node_t *left_node = NULL;
node_t *right_node = NULL;
if (node == NULL) {
return ret;
}
left_node = rbtree.get_left(node);
right_node = rbtree.get_right(node);
if (!rbtree.get_red(node)) {
black_depth++;
}
/* Red nodes must be interleaved with black nodes. */
if (rbtree.get_red(node)) {
if (left_node != NULL) {
EXPECT_EQ(rbtree.get_red(left_node), false);
}
if (right_node != NULL) {
EXPECT_EQ(rbtree.get_red(right_node), false);
}
}
/* Self. */
EXPECT_EQ(node->magic, NODE_MAGIC);
/* Left subtree. */
if (left_node != NULL) {
ret += tree_recurse(left_node, black_height, black_depth, rbtree);
} else {
ret += (black_depth != black_height);
}
/* Right subtree. */
if (right_node != NULL) {
ret += tree_recurse(right_node, black_height, black_depth, rbtree);
} else {
ret += (black_depth != black_height);
}
return ret;
}
static node_t *tree_iterate_cb(tree_t *tree, node_t *node, void *data)
{
unsigned *i = (unsigned *)data;
node_t *search_node = NULL;
int ret = OB_SUCCESS;
EXPECT_EQ(node->magic, NODE_MAGIC);
/* Test rb_search(). */
ret = tree->search(node, search_node);
if (OB_FAIL(ret)) {
fprintf(stderr, "red black tree search fail %d", ret);
EXPECT_EQ(ret, OB_SUCCESS);
} else {
EXPECT_EQ(node, search_node);
}
/* Test rb_nsearch(). */
ret = tree->nsearch(node, search_node);
if (OB_FAIL(ret)) {
fprintf(stderr, "red black tree nsearch fail %d", ret);
EXPECT_EQ(ret, OB_SUCCESS);
} else {
EXPECT_EQ(node, search_node);
}
/* Test rb_psearch(). */
ret = tree->psearch( node, search_node);
if (OB_FAIL(ret)) {
fprintf(stderr, "red black tree psearch fail %d", ret);
EXPECT_EQ(ret, OB_SUCCESS);
} else {
EXPECT_EQ(node, search_node);
}
(*i)++;
return NULL;
}
static unsigned tree_iterate(tree_t *tree)
{
unsigned i = 0;
tree->iter_rbtree(tree, NULL, tree_iterate_cb, (void *)&i);
return i;
}
static unsigned tree_iterate_reverse(tree_t *tree)
{
unsigned i = 0;
tree->reverse_iter_rbtree(tree, NULL, tree_iterate_cb, (void *)&i);
return i;
}
static void node_remove(tree_t *tree, node_t *node, unsigned nnodes)
{
int ret = OB_SUCCESS;
node_t *search_node = NULL;
uint64_t black_height = 0;
unsigned imbalances = 0;
int count = 0;
ret = tree->remove(node);
if (OB_FAIL(ret)) {
fprintf(stderr, "red black tree remove fail %d", ret);
}
assert(ret == OB_SUCCESS);
/* Test rb_nsearch(). */
ret = tree->nsearch(node, search_node);
if (OB_FAIL(ret)) {
fprintf(stderr, "red tree nsearch fail %d", ret);
assert(ret == OB_SUCCESS);
} else {
if (NULL != search_node) {
ASSERT_TRUE(search_node->key >= node->key);
}
}
/* Test rb_psearch(). */
ret = tree->psearch(node,search_node);
if (OB_FAIL(ret)) {
fprintf(stderr, "red tree psearch fail %d", ret);
EXPECT_EQ(ret, OB_SUCCESS);
} else {
if (NULL != search_node) {
ASSERT_TRUE(search_node->key <= node->key);
}
}
node->magic = 0;
black_height = tree->get_black_height(tree);
imbalances = tree_recurse(tree->get_root(), black_height, 0, *tree);
EXPECT_EQ(imbalances, 0);
count = tree_iterate(tree);
EXPECT_EQ(count, nnodes - 1);
count = tree_iterate_reverse(tree);
EXPECT_EQ(count, nnodes - 1);
}
static node_t *remove_iterate_cb(tree_t *tree, node_t *node, void *data)
{
int ret = OB_SUCCESS;
node_t *tmp_node = NULL;
unsigned *nnodes = (unsigned *)data;
ret = tree->get_next(node, tmp_node);
if (OB_FAIL(ret)) {
fprintf(stderr, "red black tree get next fail %d", ret);
EXPECT_EQ(ret, OB_SUCCESS);
} else {
node_remove(tree, node, *nnodes);
return tmp_node;
}
return NULL;
}
static node_t *remove_reverse_iterate_cb(tree_t *tree, node_t *node, void *data) {
int ret = OB_SUCCESS;
node_t *tmp_node = NULL;
unsigned *nnodes = (unsigned *)data;
ret = tree->get_prev(node, tmp_node);
if (OB_FAIL(ret)) {
fprintf(stderr, "red black tree get prev fail %d", ret);
assert(ret == OB_SUCCESS);
EXPECT_EQ(ret, OB_SUCCESS);
} else {
node_remove(tree, node, *nnodes);
return tmp_node;
}
return NULL;
}
static void destroy_cb(node_t *node , void *data) {
UNUSED(node);
unsigned *nnodes = (unsigned *)data;
assert(*nnodes > 0);
(*nnodes)--;
}
TEST (TestRbTree, random)
{
#define NNODES 25
#define NBAGS 250
#define SEED 42
int bag[NNODES];
tree_t tree;
node_t nodes[NNODES];
uint64_t black_height;
unsigned i, j, k, imbalances;
srand((unsigned)time(NULL));
i = 2;
int tmp = 0;
bool test_bool = false;
node_t *tmp_node = NULL;
node_t *pre_node = NULL;
UNUSED(pre_node);
for (i = 0; i < NBAGS; i++) {
switch (i) {
case 0:
/* Insert in order. */
for (j = 0; j < NNODES; j++) {
bag[j] = j;
}
break;
case 1:
/* Insert in reverse order. */
for (j = 0; j < NNODES; j++) {
bag[j] = NNODES - j - 1;
}
break;
default:{
//cout <<"Enter default"<<endl;
for (j = 0; j < NNODES; j++) {
bag[j] = rand()%100;
}
}
}
for (j = 1; j <= NNODES; j++) {
/* Initialize tree and nodes. */
tree.init_tree();
for (k = 0; k < j; k++) {
nodes[k].magic = NODE_MAGIC;
nodes[k].key = bag[k];
}
/* Insert nodes. */
for (k = 0; k < j; k++) {
int ret = tree.insert(&nodes[k]);
EXPECT_EQ(ret, OB_SUCCESS);
black_height = tree.get_black_height(&tree);
imbalances = tree_recurse(tree.get_root(),
black_height, 0, tree);
EXPECT_EQ(imbalances, 0);
tmp = tree_iterate(&tree);
EXPECT_EQ(tmp, k+1);
tmp = tree_iterate_reverse(&tree);
EXPECT_EQ(tmp, k+1);
test_bool = tree.is_empty();
EXPECT_EQ(test_bool, false);
tmp_node = tree.get_first();
if (OB_FAIL(ret)) {
fprintf(stderr, "red black tree get first fail %d", ret);
EXPECT_EQ(ret, OB_SUCCESS);
} else {
ASSERT_TRUE(tmp_node != NULL);
}
tmp_node = tree.get_last();
if (OB_FAIL(ret)) {
fprintf(stderr, "red black tree get last fail %d", ret);
EXPECT_EQ(ret, OB_SUCCESS);
} else {
ASSERT_TRUE(tmp_node != NULL);
}
ret = tree.get_next(&nodes[k],tmp_node);
EXPECT_EQ(ret, OB_SUCCESS);
ret = tree.get_prev(&nodes[k],tmp_node);
EXPECT_EQ(ret, OB_SUCCESS);
}
switch (i % 5) {
case 0:
for (k = 0; k < j; k++) {
node_remove(&tree,&nodes[k],j-k);
}
break;
case 1:
for (k = j;k > 0; k--) {
node_remove(&tree, &nodes[k-1],k);
}
break;
case 2: {
node_t *start = NULL;
unsigned nnodes = j;
start = NULL;
do {
start = tree.iter_rbtree(&tree, start,
remove_iterate_cb, (void *)&nnodes);
nnodes--;
} while (start != NULL);
assert(nnodes == 0);
break;
} case 3: {
node_t *start = NULL;
unsigned nnodes = j;
do {
start = tree.reverse_iter_rbtree(&tree, start,
remove_reverse_iterate_cb,
(void *)&nnodes);
nnodes--;
} while (start != NULL);
assert(nnodes == 0);
break;
} case 4: {
unsigned nnodes = j;
tree.destroy(&tree, destroy_cb, &nnodes);
assert(nnodes == 0);
break;
} default:
break;
}
}
}
#undef NNODES
#undef NBAGS
#undef SEED
}
}
}
int main(int argc, char **argv) {
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}