tree: implement simpler version without macros

This commit is contained in:
Bert Belder 2018-02-12 01:14:16 +01:00
parent 3db46f068f
commit 9799eec661
No known key found for this signature in database
GPG Key ID: 7A77887B2E2ED461
5 changed files with 439 additions and 47 deletions

View File

@ -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) {

View File

@ -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);

View File

@ -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;
}

View File

@ -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
View 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);
}