tree: implement simpler version without macros
This commit is contained in:
parent
3db46f068f
commit
9799eec661
@ -347,11 +347,9 @@ int ep_port_register_socket_handle(ep_port_t* port_info,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ep_port_unregister_socket_handle(ep_port_t* port_info,
|
||||
ep_sock_t* sock_info) {
|
||||
if (tree_del(&port_info->sock_tree, &sock_info->tree_node) < 0)
|
||||
return_error(-1, ERROR_NOT_FOUND);
|
||||
return 0;
|
||||
void ep_port_unregister_socket_handle(ep_port_t* port_info,
|
||||
ep_sock_t* sock_info) {
|
||||
tree_del(&port_info->sock_tree, &sock_info->tree_node);
|
||||
}
|
||||
|
||||
ep_sock_t* ep_port_find_socket(ep_port_t* port_info, SOCKET socket) {
|
||||
|
||||
@ -51,8 +51,8 @@ WEPOLL_INTERNAL void ep_port_release_poll_group(ep_port_t* port_info,
|
||||
WEPOLL_INTERNAL int ep_port_register_socket_handle(ep_port_t* port_info,
|
||||
ep_sock_t* sock_info,
|
||||
SOCKET socket);
|
||||
WEPOLL_INTERNAL int ep_port_unregister_socket_handle(ep_port_t* port_info,
|
||||
ep_sock_t* sock_info);
|
||||
WEPOLL_INTERNAL void ep_port_unregister_socket_handle(ep_port_t* port_info,
|
||||
ep_sock_t* sock_info);
|
||||
WEPOLL_INTERNAL ep_sock_t* ep_port_find_socket(ep_port_t* port_info,
|
||||
SOCKET socket);
|
||||
|
||||
|
||||
272
src/tree.c
272
src/tree.c
@ -1,23 +1,56 @@
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "error.h"
|
||||
#include "rb.h"
|
||||
#include "tree.h"
|
||||
#include "util.h"
|
||||
|
||||
static inline int _tree_compare(tree_node_t* a, tree_node_t* b) {
|
||||
if (a->key < b->key)
|
||||
return -1;
|
||||
else if (a->key > b->key)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
static void _tree_rotate_left(tree_t* tree, tree_node_t* node) {
|
||||
tree_node_t* p = node;
|
||||
tree_node_t* q = node->right;
|
||||
tree_node_t* parent = p->parent;
|
||||
|
||||
if (parent) {
|
||||
if (parent->left == p)
|
||||
parent->left = q;
|
||||
else
|
||||
parent->right = q;
|
||||
} else {
|
||||
tree->root = q;
|
||||
}
|
||||
|
||||
q->parent = parent;
|
||||
p->parent = q;
|
||||
p->right = q->left;
|
||||
if (p->right)
|
||||
p->right->parent = p;
|
||||
q->left = p;
|
||||
}
|
||||
|
||||
RB_GENERATE_STATIC(tree, tree_node, node, _tree_compare);
|
||||
static void _tree_rotate_right(tree_t* tree, tree_node_t* node) {
|
||||
tree_node_t* p = node;
|
||||
tree_node_t* q = node->left;
|
||||
tree_node_t* parent = p->parent;
|
||||
|
||||
if (parent) {
|
||||
if (parent->left == p)
|
||||
parent->left = q;
|
||||
else
|
||||
parent->right = q;
|
||||
} else {
|
||||
tree->root = q;
|
||||
}
|
||||
|
||||
q->parent = parent;
|
||||
p->parent = q;
|
||||
p->left = q->right;
|
||||
if (p->left)
|
||||
p->left->parent = p;
|
||||
q->right = p;
|
||||
}
|
||||
|
||||
void tree_init(tree_t* tree) {
|
||||
RB_INIT(tree);
|
||||
memset(tree, 0, sizeof *tree);
|
||||
}
|
||||
|
||||
void tree_node_init(tree_node_t* node) {
|
||||
@ -25,39 +58,210 @@ void tree_node_init(tree_node_t* node) {
|
||||
}
|
||||
|
||||
int tree_add(tree_t* tree, tree_node_t* node, uintptr_t key) {
|
||||
tree_node_t* existing_node;
|
||||
tree_node_t* parent;
|
||||
tree_node_t* grandparent;
|
||||
tree_node_t* uncle;
|
||||
|
||||
parent = tree->root;
|
||||
if (parent) {
|
||||
for (;;) {
|
||||
if (key < parent->key) {
|
||||
if (parent->left) {
|
||||
parent = parent->left;
|
||||
} else {
|
||||
parent->left = node;
|
||||
break;
|
||||
}
|
||||
} else if (key > parent->key) {
|
||||
if (parent->right) {
|
||||
parent = parent->right;
|
||||
} else {
|
||||
parent->right = node;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
tree->root = node;
|
||||
}
|
||||
|
||||
node->key = key;
|
||||
existing_node = RB_INSERT(tree, tree, node);
|
||||
node->left = node->right = NULL;
|
||||
node->parent = parent;
|
||||
node->red = true;
|
||||
|
||||
if (existing_node != NULL)
|
||||
return -1;
|
||||
while (parent && parent->red) {
|
||||
grandparent = parent->parent;
|
||||
if (parent == grandparent->left) {
|
||||
uncle = grandparent->right;
|
||||
if (uncle && uncle->red) {
|
||||
parent->red = uncle->red = false;
|
||||
grandparent->red = true;
|
||||
node = grandparent;
|
||||
} else {
|
||||
if (node == parent->right) {
|
||||
_tree_rotate_left(tree, parent);
|
||||
node = parent;
|
||||
parent = node->parent;
|
||||
}
|
||||
parent->red = false;
|
||||
grandparent->red = true;
|
||||
_tree_rotate_right(tree, grandparent);
|
||||
}
|
||||
} else {
|
||||
uncle = grandparent->left;
|
||||
if (uncle && uncle->red) {
|
||||
parent->red = uncle->red = false;
|
||||
grandparent->red = true;
|
||||
node = grandparent;
|
||||
} else {
|
||||
if (node == parent->left) {
|
||||
_tree_rotate_right(tree, parent);
|
||||
node = parent;
|
||||
parent = node->parent;
|
||||
}
|
||||
parent->red = false;
|
||||
grandparent->red = true;
|
||||
_tree_rotate_left(tree, grandparent);
|
||||
}
|
||||
}
|
||||
parent = node->parent;
|
||||
}
|
||||
tree->root->red = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tree_del(tree_t* tree, tree_node_t* node) {
|
||||
tree_node_t* removed_node;
|
||||
void tree_del(tree_t* tree, tree_node_t* node) {
|
||||
tree_node_t* parent = node->parent;
|
||||
tree_node_t* left = node->left;
|
||||
tree_node_t* right = node->right;
|
||||
tree_node_t* next;
|
||||
tree_node_t* sibling;
|
||||
bool red;
|
||||
|
||||
removed_node = RB_REMOVE(tree, tree, node);
|
||||
if (!left) {
|
||||
next = right;
|
||||
} else if (!right) {
|
||||
next = left;
|
||||
} else {
|
||||
next = right;
|
||||
while (next->left)
|
||||
next = next->left;
|
||||
}
|
||||
|
||||
if (removed_node == NULL)
|
||||
return -1;
|
||||
else
|
||||
assert(removed_node == node);
|
||||
if (parent) {
|
||||
if (parent->left == node)
|
||||
parent->left = next;
|
||||
else
|
||||
parent->right = next;
|
||||
} else {
|
||||
tree->root = next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
if (left && right) {
|
||||
red = next->red;
|
||||
next->red = node->red;
|
||||
next->left = left;
|
||||
left->parent = next;
|
||||
if (next != right) {
|
||||
parent = next->parent;
|
||||
next->parent = node->parent;
|
||||
node = next->right;
|
||||
parent->left = node;
|
||||
next->right = right;
|
||||
right->parent = next;
|
||||
} else {
|
||||
next->parent = parent;
|
||||
parent = next;
|
||||
node = next->right;
|
||||
}
|
||||
} else {
|
||||
red = node->red;
|
||||
node = next;
|
||||
}
|
||||
|
||||
if (node)
|
||||
node->parent = parent;
|
||||
if (red)
|
||||
return;
|
||||
if (node && node->red) {
|
||||
node->red = false;
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
if (node == tree->root)
|
||||
break;
|
||||
if (node == parent->left) {
|
||||
sibling = parent->right;
|
||||
if (sibling->red) {
|
||||
sibling->red = false;
|
||||
parent->red = true;
|
||||
_tree_rotate_left(tree, parent);
|
||||
sibling = parent->right;
|
||||
}
|
||||
if ((sibling->left && sibling->left->red) ||
|
||||
(sibling->right && sibling->right->red)) {
|
||||
if (!sibling->right || !sibling->right->red) {
|
||||
sibling->left->red = false;
|
||||
sibling->red = true;
|
||||
_tree_rotate_right(tree, sibling);
|
||||
sibling = parent->right;
|
||||
}
|
||||
sibling->red = parent->red;
|
||||
parent->red = sibling->right->red = false;
|
||||
_tree_rotate_left(tree, parent);
|
||||
node = tree->root;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
sibling = parent->left;
|
||||
if (sibling->red) {
|
||||
sibling->red = false;
|
||||
parent->red = true;
|
||||
_tree_rotate_right(tree, parent);
|
||||
sibling = parent->left;
|
||||
}
|
||||
if ((sibling->left && sibling->left->red) ||
|
||||
(sibling->right && sibling->right->red)) {
|
||||
if (!sibling->left || !sibling->left->red) {
|
||||
sibling->right->red = false;
|
||||
sibling->red = true;
|
||||
_tree_rotate_left(tree, sibling);
|
||||
sibling = parent->left;
|
||||
}
|
||||
sibling->red = parent->red;
|
||||
parent->red = sibling->left->red = false;
|
||||
_tree_rotate_right(tree, parent);
|
||||
node = tree->root;
|
||||
break;
|
||||
}
|
||||
}
|
||||
sibling->red = true;
|
||||
node = parent;
|
||||
parent = parent->parent;
|
||||
} while (!node->red);
|
||||
|
||||
if (node)
|
||||
node->red = false;
|
||||
}
|
||||
|
||||
tree_node_t* tree_find(tree_t* tree, uintptr_t key) {
|
||||
tree_node_t lookup;
|
||||
|
||||
memset(&lookup, 0, sizeof lookup);
|
||||
lookup.key = key;
|
||||
|
||||
return RB_FIND(tree, tree, &lookup);
|
||||
tree_node_t* tree_find(const tree_t* tree, uintptr_t key) {
|
||||
tree_node_t* node = tree->root;
|
||||
while (node) {
|
||||
if (key < node->key)
|
||||
node = node->left;
|
||||
else if (key > node->key)
|
||||
node = node->right;
|
||||
else
|
||||
return node;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tree_node_t* tree_root(tree_t* tree) {
|
||||
return RB_ROOT(tree);
|
||||
tree_node_t* tree_root(const tree_t* tree) {
|
||||
return tree->root;
|
||||
}
|
||||
|
||||
23
src/tree.h
23
src/tree.h
@ -1,28 +1,39 @@
|
||||
#ifndef WEPOLL_TREE_H_
|
||||
#define WEPOLL_TREE_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "internal.h"
|
||||
#include "rb.h"
|
||||
#include "util.h"
|
||||
|
||||
/* NB: the tree functions do not set errno or LastError when they fail. Each of
|
||||
* the API functions has at most one failure mode. It is up to the caller to
|
||||
* set an appropriate error code when necessary.
|
||||
*/
|
||||
|
||||
typedef RB_HEAD(tree, tree_node) tree_t;
|
||||
typedef struct tree tree_t;
|
||||
typedef struct tree_node tree_node_t;
|
||||
|
||||
typedef struct tree {
|
||||
tree_node_t* root;
|
||||
} tree_t;
|
||||
|
||||
typedef struct tree_node {
|
||||
RB_ENTRY(tree_node) node;
|
||||
tree_node_t* left;
|
||||
tree_node_t* right;
|
||||
tree_node_t* parent;
|
||||
uintptr_t key;
|
||||
bool red;
|
||||
} tree_node_t;
|
||||
|
||||
WEPOLL_INTERNAL void tree_init(tree_t* tree);
|
||||
WEPOLL_INTERNAL void tree_node_init(tree_node_t* node);
|
||||
|
||||
WEPOLL_INTERNAL int tree_add(tree_t* tree, tree_node_t* node, uintptr_t key);
|
||||
WEPOLL_INTERNAL int tree_del(tree_t* tree, tree_node_t* node);
|
||||
WEPOLL_INTERNAL void tree_del(tree_t* tree, tree_node_t* node);
|
||||
|
||||
WEPOLL_INTERNAL tree_node_t* tree_find(tree_t* tree, uintptr_t key);
|
||||
WEPOLL_INTERNAL tree_node_t* tree_root(tree_t* tree);
|
||||
WEPOLL_INTERNAL tree_node_t* tree_find(const tree_t* tree, uintptr_t key);
|
||||
WEPOLL_INTERNAL tree_node_t* tree_root(const tree_t* tree);
|
||||
|
||||
#endif /* WEPOLL_TREE_H_ */
|
||||
|
||||
179
test/test-tree.c
Normal file
179
test/test-tree.c
Normal file
@ -0,0 +1,179 @@
|
||||
#include <malloc.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "test-util.h"
|
||||
#include "tree.h"
|
||||
#include "util.h"
|
||||
|
||||
#define NODE_COUNT 1000
|
||||
static_assert(NODE_COUNT <= RAND_MAX, "NODE_COUNT too high");
|
||||
|
||||
typedef void (*test_op_t)(tree_t* tree, uintptr_t key);
|
||||
|
||||
static size_t count_subtree(const tree_node_t* node) {
|
||||
if (node == NULL)
|
||||
return 0;
|
||||
else
|
||||
return 1 + count_subtree(node->left) + count_subtree(node->right);
|
||||
}
|
||||
|
||||
static size_t count_tree(const tree_t* tree) {
|
||||
return count_subtree(tree_root(tree));
|
||||
}
|
||||
|
||||
static size_t check_subtree_structure(const tree_node_t* node) {
|
||||
size_t black_height_left;
|
||||
size_t black_height_right;
|
||||
|
||||
if (!node)
|
||||
return 0;
|
||||
|
||||
black_height_left = check_subtree_structure(node->left);
|
||||
black_height_right = check_subtree_structure(node->right);
|
||||
check(black_height_left == black_height_right);
|
||||
|
||||
if (node->red) {
|
||||
check(!node->left || !node->left->red);
|
||||
check(!node->right || !node->right->red);
|
||||
return black_height_left;
|
||||
} else {
|
||||
return black_height_left + 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void check_tree_structure(const tree_t* tree) {
|
||||
check_subtree_structure(tree_root(tree));
|
||||
}
|
||||
|
||||
static void check_tree_count(const tree_t* tree, size_t expected_count) {
|
||||
size_t count = count_tree(tree);
|
||||
check(count == expected_count);
|
||||
}
|
||||
|
||||
static void keys_increasing(tree_t* tree, test_op_t op) {
|
||||
ssize_t i;
|
||||
for (i = 0; i < NODE_COUNT; i++)
|
||||
op(tree, i);
|
||||
}
|
||||
|
||||
static void keys_decreasing(tree_t* tree, test_op_t op) {
|
||||
ssize_t i;
|
||||
for (i = NODE_COUNT - 1; i >= 0; i--)
|
||||
op(tree, i);
|
||||
}
|
||||
|
||||
static void keys_random(tree_t* tree, test_op_t op) {
|
||||
uintptr_t keys[NODE_COUNT];
|
||||
uintptr_t index, key;
|
||||
ssize_t left;
|
||||
|
||||
for (index = 0; index < NODE_COUNT; index++)
|
||||
keys[index] = index;
|
||||
|
||||
for (left = NODE_COUNT - 1; left >= 0; left--) {
|
||||
index = left > 0 ? rand() % left : 0;
|
||||
key = keys[index];
|
||||
keys[index] = keys[left];
|
||||
op(tree, key);
|
||||
};
|
||||
}
|
||||
|
||||
static void add(tree_t* tree, uintptr_t key) {
|
||||
tree_node_t* node;
|
||||
size_t before_count;
|
||||
int r;
|
||||
|
||||
before_count = count_tree(tree);
|
||||
|
||||
node = malloc(sizeof *node);
|
||||
check(node != NULL);
|
||||
tree_node_init(node);
|
||||
|
||||
r = tree_add(tree, node, key);
|
||||
check(r == 0);
|
||||
check(node->key == key);
|
||||
|
||||
check_tree_structure(tree);
|
||||
check_tree_count(tree, before_count + 1);
|
||||
}
|
||||
|
||||
static void add_error(tree_t* tree, uintptr_t key) {
|
||||
tree_node_t node;
|
||||
size_t before_count;
|
||||
int r;
|
||||
|
||||
before_count = count_tree(tree);
|
||||
|
||||
tree_node_init(&node);
|
||||
r = tree_add(tree, &node, key);
|
||||
check(r == -1);
|
||||
|
||||
check_tree_structure(tree);
|
||||
check_tree_count(tree, before_count);
|
||||
}
|
||||
|
||||
static void find_del(tree_t* tree, uintptr_t key) {
|
||||
tree_node_t* node;
|
||||
size_t before_count;
|
||||
|
||||
before_count = count_tree(tree);
|
||||
|
||||
node = tree_find(tree, key);
|
||||
check(node != NULL);
|
||||
check(node->key == key);
|
||||
|
||||
tree_del(tree, node);
|
||||
free(node);
|
||||
|
||||
check_tree_structure(tree);
|
||||
check_tree_count(tree, before_count - 1);
|
||||
}
|
||||
|
||||
static void find_error(tree_t* tree, uintptr_t key) {
|
||||
tree_node_t* node;
|
||||
size_t before_count;
|
||||
|
||||
before_count = count_tree(tree);
|
||||
|
||||
node = tree_find(tree, key);
|
||||
check(node == NULL);
|
||||
|
||||
check_tree_structure(tree);
|
||||
check_tree_count(tree, before_count);
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
tree_t tree;
|
||||
tree_init(&tree);
|
||||
|
||||
keys_increasing(&tree, add);
|
||||
check_tree_count(&tree, NODE_COUNT);
|
||||
keys_increasing(&tree, add_error);
|
||||
keys_increasing(&tree, find_del);
|
||||
check_tree_count(&tree, 0);
|
||||
keys_increasing(&tree, find_error);
|
||||
|
||||
keys_decreasing(&tree, add);
|
||||
check_tree_count(&tree, NODE_COUNT);
|
||||
keys_decreasing(&tree, add_error);
|
||||
keys_decreasing(&tree, find_del);
|
||||
check_tree_count(&tree, 0);
|
||||
keys_decreasing(&tree, find_error);
|
||||
|
||||
keys_random(&tree, add);
|
||||
check_tree_count(&tree, NODE_COUNT);
|
||||
keys_random(&tree, add_error);
|
||||
keys_random(&tree, find_del);
|
||||
check_tree_count(&tree, 0);
|
||||
keys_random(&tree, find_error);
|
||||
|
||||
keys_random(&tree, add);
|
||||
check_tree_count(&tree, NODE_COUNT);
|
||||
keys_increasing(&tree, add_error);
|
||||
keys_decreasing(&tree, find_del);
|
||||
check_tree_count(&tree, 0);
|
||||
keys_random(&tree, find_error);
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user