178 lines
4.7 KiB
C
178 lines
4.7 KiB
C
#include <stddef.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include <rbpTree.h>
|
|
|
|
#define CHECK(expr) do { \
|
|
if (!(expr)) { \
|
|
fprintf(stderr, "CHECK failed: %s:%d: %s\n", __FILE__, __LINE__, #expr); \
|
|
return 1; \
|
|
} \
|
|
} while (0)
|
|
|
|
typedef struct TestNode_s {
|
|
int key;
|
|
RBP_Node_s link;
|
|
} TestNode_s;
|
|
|
|
typedef struct WalkState_s {
|
|
int expected;
|
|
int count;
|
|
} WalkState_s;
|
|
|
|
static SNINT node_compare(void *a, void *b)
|
|
{
|
|
const TestNode_s *x = a;
|
|
const TestNode_s *y = b;
|
|
return (x->key > y->key) - (x->key < y->key);
|
|
}
|
|
|
|
static SNINT key_compare(void *key, void *node)
|
|
{
|
|
const int *k = key;
|
|
const TestNode_s *n = node;
|
|
return (*k > n->key) - (*k < n->key);
|
|
}
|
|
|
|
static BOOL count_destroy(void *node)
|
|
{
|
|
TestNode_s *n = node;
|
|
n->key = -n->key;
|
|
return TRUE;
|
|
}
|
|
|
|
static BOOL in_order_check(void *node, NINT depth, ADDR user_data)
|
|
{
|
|
TestNode_s *n = node;
|
|
WalkState_s *state = (WalkState_s *)user_data;
|
|
|
|
(void)depth;
|
|
if (n->key != state->expected) {
|
|
fprintf(stderr, "in-order expected %d, got %d\n", state->expected, n->key);
|
|
return FALSE;
|
|
}
|
|
state->expected += 1;
|
|
state->count += 1;
|
|
return TRUE;
|
|
}
|
|
|
|
static int expect_node(TestNode_s *node, int key)
|
|
{
|
|
if (node == NULL || node->key != key) {
|
|
fprintf(stderr, "expected key %d, got %s%d\n", key,
|
|
node ? "" : "NULL/", node ? node->key : -1);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int audit_tree(RBP_Tree_s *tree, RBP_Node_s *root, int expected_nodes)
|
|
{
|
|
RBP_Audit_s audit;
|
|
|
|
RBP_Audit(tree, root, &audit);
|
|
if (audit.nodes != expected_nodes) {
|
|
fprintf(stderr, "audit expected %d nodes, got %ld\n",
|
|
expected_nodes, (long)audit.nodes);
|
|
return 1;
|
|
}
|
|
if (expected_nodes == 0)
|
|
return 0;
|
|
if (audit.maxDepth >= MAX_DEPTH) {
|
|
fprintf(stderr, "tree depth unexpectedly high: %ld\n", (long)audit.maxDepth);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int main(void)
|
|
{
|
|
RBP_Tree_s tree;
|
|
RBP_Node_s *root = NULL;
|
|
TestNode_s nodes[64];
|
|
int order[] = {31, 7, 55, 3, 15, 47, 63, 0, 5, 11, 19, 39, 51, 59, 61,
|
|
1, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30,
|
|
32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60,
|
|
62, 9, 13, 17, 21, 23, 25, 27, 29, 33, 35, 37, 41, 43, 45,
|
|
49, 53, 57};
|
|
int i;
|
|
int key;
|
|
TestNode_s *node;
|
|
WalkState_s walk;
|
|
|
|
CHECK((int)(sizeof(order) / sizeof(order[0])) == 64);
|
|
|
|
RBP_Init(&tree, (SNINT (*)(void))node_compare,
|
|
(SNINT (*)(void))key_compare,
|
|
(BOOL (*)(void))count_destroy, NULL,
|
|
offsetof(TestNode_s, link));
|
|
|
|
for (i = 0; i < 64; i++) {
|
|
nodes[i].key = order[i];
|
|
RBP_Insert(&tree, &root, &nodes[i]);
|
|
CHECK(root != NULL);
|
|
CHECK(root->red == FALSE);
|
|
CHECK(audit_tree(&tree, root, i + 1) == 0);
|
|
}
|
|
|
|
for (i = 0; i < 64; i++) {
|
|
key = i;
|
|
CHECK(expect_node(RBP_Find(&tree, root, &key), i) == 0);
|
|
}
|
|
|
|
key = -1;
|
|
CHECK(expect_node(RBP_FindCeiling(&tree, root, &key), 0) == 0);
|
|
CHECK(RBP_FindFloor(&tree, root, &key) == NULL);
|
|
key = 64;
|
|
CHECK(RBP_FindCeiling(&tree, root, &key) == NULL);
|
|
CHECK(expect_node(RBP_FindFloor(&tree, root, &key), 63) == 0);
|
|
key = 37;
|
|
CHECK(expect_node(RBP_FindCeiling(&tree, root, &key), 37) == 0);
|
|
CHECK(expect_node(RBP_FindFloor(&tree, root, &key), 37) == 0);
|
|
key = 37;
|
|
node = RBP_Find(&tree, root, &key);
|
|
CHECK(expect_node(RBP_Succ(&tree, node), 38) == 0);
|
|
CHECK(expect_node(RBP_Pred(&tree, node), 36) == 0);
|
|
CHECK(expect_node(RBP_Min(&tree, root), 0) == 0);
|
|
CHECK(expect_node(RBP_Max(&tree, root), 63) == 0);
|
|
|
|
memset(&walk, 0, sizeof(walk));
|
|
walk.expected = 0;
|
|
RBP_InOrder(&tree, root, in_order_check, (ADDR)&walk);
|
|
CHECK(walk.count == 64);
|
|
CHECK(walk.expected == 64);
|
|
|
|
for (i = 0; i < 64; i += 2) {
|
|
key = i;
|
|
node = RBP_Find(&tree, root, &key);
|
|
CHECK(node != NULL);
|
|
RBP_Delete(&tree, &root, node);
|
|
CHECK(audit_tree(&tree, root, 64 - (i / 2) - 1) == 0);
|
|
}
|
|
|
|
for (i = 0; i < 64; i++) {
|
|
key = i;
|
|
node = RBP_Find(&tree, root, &key);
|
|
if ((i & 1) == 0)
|
|
CHECK(node == NULL);
|
|
else
|
|
CHECK(expect_node(node, i) == 0);
|
|
}
|
|
|
|
key = 4;
|
|
CHECK(expect_node(RBP_FindCeiling(&tree, root, &key), 5) == 0);
|
|
CHECK(expect_node(RBP_FindFloor(&tree, root, &key), 3) == 0);
|
|
|
|
RBP_DestroyTree(&tree, &root);
|
|
CHECK(root == NULL);
|
|
CHECK(audit_tree(&tree, root, 0) == 0);
|
|
for (i = 0; i < 64; i++) {
|
|
if (order[i] & 1)
|
|
CHECK(nodes[i].key < 0);
|
|
}
|
|
|
|
return 0;
|
|
}
|