rbtree
changeset 0:6621337b6378
red-black tree lib
author | John Tsiombikas <nuclear@mutantstargoat.com> |
---|---|
date | Sun, 09 Oct 2011 07:48:14 +0300 |
parents | |
children | 3b219820ebe8 |
files | .hgignore Makefile.in configure src/rbtree.c src/rbtree.h test/Makefile test/test.c |
diffstat | 7 files changed, 1051 insertions(+), 0 deletions(-) [+] |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/.hgignore Sun Oct 09 07:48:14 2011 +0300 1.3 @@ -0,0 +1,6 @@ 1.4 +\.o$ 1.5 +\.d$ 1.6 +\.swp$ 1.7 +^Makefile$ 1.8 +rbtree\.a$ 1.9 +rbtree\.so
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 2.2 +++ b/Makefile.in Sun Oct 09 07:48:14 2011 +0300 2.3 @@ -0,0 +1,58 @@ 2.4 +src = $(wildcard src/*.c) 2.5 +obj = $(src:.c=.o) 2.6 +dep = $(obj:.o=.d) 2.7 + 2.8 +name = rbtree 2.9 + 2.10 +AR = ar 2.11 +CC = gcc 2.12 +CFLAGS = -pedantic -Wall $(dbg) $(opt) -fPIC 2.13 + 2.14 +ifeq ($(shell uname -s), Darwin) 2.15 + lib_a = $(name).a 2.16 + lib_so = $(name).dylib 2.17 + shared = -dynamiclib $(lib_so) 2.18 +else 2.19 + lib_a = lib$(name).a 2.20 + devlink = lib$(name).so 2.21 + soname = $(devlink).0 2.22 + lib_so = $(soname).0 2.23 + shared = -shared -Wl,-soname=$(soname) 2.24 +endif 2.25 + 2.26 +.PHONY: all 2.27 +all: $(lib_so) $(lib_a) 2.28 + 2.29 +$(lib_a): $(obj) 2.30 + $(AR) rcs $(lib_a) $(obj) 2.31 + 2.32 +$(lib_so): $(obj) 2.33 + $(CC) -o $@ $(shared) $(obj) $(LDFLAGS) 2.34 + 2.35 +-include $(dep) 2.36 + 2.37 +%.d: %.c 2.38 + @$(CPP) $(CFLAGS) $< -MM -MT $(@:.d=.o) >$@ 2.39 + 2.40 +.PHONY: clean 2.41 +clean: 2.42 + rm -f $(obj) $(lib_a) $(lib_so) 2.43 + 2.44 +.PHONY: install 2.45 +install: 2.46 + mkdir -p $(PREFIX)/include $(PREFIX)/lib 2.47 + cp src/rbtree.h $(PREFIX)/include/rbtree.h 2.48 + cp $(lib_a) $(PREFIX)/lib/$(lib_a) 2.49 + cp $(lib_so) $(PREFIX)/lib/$(lib_so) 2.50 + [ -n "$(soname)" ] \ 2.51 + && rm -f $(PREFIX)/lib/$(soname) $(PREFIX)/lib/$(devlink) \ 2.52 + && ln -s $(PREFIX)/lib/$(lib_so) $(PREFIX)/lib/$(soname) \ 2.53 + && ln -s $(PREFIX)/lib/$(soname) $(PREFIX)/lib/$(devlink) \ 2.54 + || true 2.55 + 2.56 +.PHONY: uninstall 2.57 + rm -f $(PREFIX)/include/rbtree.h 2.58 + rm -f $(PREFIX)/lib/$(lib_a) 2.59 + rm -f $(PREFIX)/lib/$(lib_so) 2.60 + rm -f $(PREFIX)/lib/$(soname) 2.61 + rm -f $(PREFIX)/lib/$(devlink)
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 3.2 +++ b/configure Sun Oct 09 07:48:14 2011 +0300 3.3 @@ -0,0 +1,36 @@ 3.4 +#!/bin/sh 3.5 + 3.6 +prefix=/usr/local 3.7 +opt=false 3.8 +dbg=true 3.9 + 3.10 +while [ $# != 0 ]; do 3.11 + case $1 in 3.12 + --prefix=*) 3.13 + prefix=`echo $1 | sed 's/^--prefix=//'` 3.14 + ;; 3.15 + --enable-opt) 3.16 + opt=true 3.17 + ;; 3.18 + --disable-opt) 3.19 + opt=false 3.20 + ;; 3.21 + --enable-dbg) 3.22 + dbg=true 3.23 + ;; 3.24 + --disable-dbg) 3.25 + dbg=false 3.26 + ;; 3.27 + esac 3.28 + shift 3.29 +done 3.30 + 3.31 +echo 'Configuring librbtree...' 3.32 + 3.33 +echo "# do not modify this file manually, it's generated by configure" >Makefile 3.34 +echo "PREFIX = $prefix" >>Makefile 3.35 +$opt && echo '-O3' | xargs echo 'opt =' >>Makefile 3.36 +$dbg && echo '-g' | xargs echo 'dbg =' >>Makefile 3.37 +cat Makefile.in >>Makefile 3.38 + 3.39 +echo 'Done. Run make (or gmake) to compile.'
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 4.2 +++ b/src/rbtree.c Sun Oct 09 07:48:14 2011 +0300 4.3 @@ -0,0 +1,456 @@ 4.4 +#include <stdio.h> 4.5 +#include <stdlib.h> 4.6 +#include <string.h> 4.7 +#include "rbtree.h" 4.8 + 4.9 +#define INT2PTR(x) ((void*)(x)) 4.10 +#define PTR2INT(x) ((int)(x)) 4.11 + 4.12 +struct rbtree { 4.13 + struct rbnode *root; 4.14 + 4.15 + rb_alloc_func_t alloc; 4.16 + rb_free_func_t free; 4.17 + 4.18 + rb_cmp_func_t cmp; 4.19 + rb_del_func_t del; 4.20 + void *del_cls; 4.21 + 4.22 + struct rbnode *rstack, *iter; 4.23 +}; 4.24 + 4.25 +static int cmpaddr(void *ap, void *bp); 4.26 +static int cmpint(void *ap, void *bp); 4.27 + 4.28 +static int count_nodes(struct rbnode *node); 4.29 +static void del_tree(struct rbnode *node, void (*delfunc)(struct rbnode*, void*), void *cls); 4.30 +static struct rbnode *insert(struct rbtree *rb, struct rbnode *tree, void *key, void *data); 4.31 +static struct rbnode *delete(struct rbtree *rb, struct rbnode *tree, void *key); 4.32 +static struct rbnode *find(struct rbtree *rb, struct rbnode *node, void *key); 4.33 +static void traverse(struct rbnode *node, void (*func)(struct rbnode*, void*), void *cls); 4.34 + 4.35 +struct rbtree *rb_create(rb_cmp_func_t cmp_func) 4.36 +{ 4.37 + struct rbtree *rb; 4.38 + 4.39 + if(!(rb = malloc(sizeof *rb))) { 4.40 + return 0; 4.41 + } 4.42 + if(rb_init(rb, cmp_func) == -1) { 4.43 + free(rb); 4.44 + return 0; 4.45 + } 4.46 + return rb; 4.47 +} 4.48 + 4.49 +void rb_free(struct rbtree *rb) 4.50 +{ 4.51 + rb_destroy(rb); 4.52 + free(rb); 4.53 +} 4.54 + 4.55 + 4.56 +int rb_init(struct rbtree *rb, rb_cmp_func_t cmp_func) 4.57 +{ 4.58 + memset(rb, 0, sizeof *rb); 4.59 + 4.60 + if(cmp_func == RB_KEY_INT) { 4.61 + rb->cmp = cmpint; 4.62 + } else if(cmp_func == RB_KEY_STRING) { 4.63 + rb->cmp = (rb_cmp_func_t)strcmp; 4.64 + } else { 4.65 + rb->cmp = cmpaddr; 4.66 + } 4.67 + 4.68 + rb->alloc = malloc; 4.69 + rb->free = free; 4.70 + return 0; 4.71 +} 4.72 + 4.73 +void rb_destroy(struct rbtree *rb) 4.74 +{ 4.75 + del_tree(rb->root, rb->del, rb->del_cls); 4.76 +} 4.77 + 4.78 +void rb_set_allocator(struct rbtree *rb, rb_alloc_func_t alloc, rb_free_func_t free) 4.79 +{ 4.80 + rb->alloc = alloc; 4.81 + rb->free = free; 4.82 +} 4.83 + 4.84 + 4.85 +void rb_set_compare_func(struct rbtree *rb, rb_cmp_func_t func) 4.86 +{ 4.87 + rb->cmp = func; 4.88 +} 4.89 + 4.90 +void rb_set_delete_func(struct rbtree *rb, rb_del_func_t func, void *cls) 4.91 +{ 4.92 + rb->del = func; 4.93 + rb->del_cls = cls; 4.94 +} 4.95 + 4.96 +int rb_size(struct rbtree *rb) 4.97 +{ 4.98 + return count_nodes(rb->root); 4.99 +} 4.100 + 4.101 +int rb_insert(struct rbtree *rb, void *key, void *data) 4.102 +{ 4.103 + rb->root = insert(rb, rb->root, key, data); 4.104 + rb->root->red = 0; 4.105 + return 0; 4.106 +} 4.107 + 4.108 +int rb_inserti(struct rbtree *rb, int key, void *data) 4.109 +{ 4.110 + rb->root = insert(rb, rb->root, INT2PTR(key), data); 4.111 + rb->root->red = 0; 4.112 + return 0; 4.113 +} 4.114 + 4.115 + 4.116 +int rb_delete(struct rbtree *rb, void *key) 4.117 +{ 4.118 + rb->root = delete(rb, rb->root, key); 4.119 + rb->root->red = 0; 4.120 + return 0; 4.121 +} 4.122 + 4.123 +int rb_deletei(struct rbtree *rb, int key) 4.124 +{ 4.125 + rb->root = delete(rb, rb->root, INT2PTR(key)); 4.126 + rb->root->red = 0; 4.127 + return 0; 4.128 +} 4.129 + 4.130 + 4.131 +void *rb_find(struct rbtree *rb, void *key) 4.132 +{ 4.133 + return find(rb, rb->root, key); 4.134 +} 4.135 + 4.136 +void *rb_findi(struct rbtree *rb, int key) 4.137 +{ 4.138 + return find(rb, rb->root, INT2PTR(key)); 4.139 +} 4.140 + 4.141 + 4.142 +void rb_foreach(struct rbtree *rb, void (*func)(struct rbnode*, void*), void *cls) 4.143 +{ 4.144 + traverse(rb->root, func, cls); 4.145 +} 4.146 + 4.147 + 4.148 +struct rbnode *rb_root(struct rbtree *rb) 4.149 +{ 4.150 + return rb->root; 4.151 +} 4.152 + 4.153 +void rb_begin(struct rbtree *rb) 4.154 +{ 4.155 + rb->rstack = 0; 4.156 + rb->iter = rb->root; 4.157 +} 4.158 + 4.159 +#define push(sp, x) ((x)->next = (sp), (sp) = (x)) 4.160 +#define pop(sp) ((sp) = (sp)->next) 4.161 +#define top(sp) (sp) 4.162 + 4.163 +struct rbnode *rb_next(struct rbtree *rb) 4.164 +{ 4.165 + struct rbnode *res = 0; 4.166 + 4.167 + while(rb->rstack || rb->iter) { 4.168 + if(rb->iter) { 4.169 + push(rb->rstack, rb->iter); 4.170 + rb->iter = rb->iter->left; 4.171 + } else { 4.172 + rb->iter = top(rb->rstack); 4.173 + pop(rb->rstack); 4.174 + res = rb->iter; 4.175 + rb->iter = rb->iter->right; 4.176 + break; 4.177 + } 4.178 + } 4.179 + return res; 4.180 +} 4.181 + 4.182 +void *rb_node_key(struct rbnode *node) 4.183 +{ 4.184 + return node ? node->key : 0; 4.185 +} 4.186 + 4.187 +int rb_node_keyi(struct rbnode *node) 4.188 +{ 4.189 + return node ? PTR2INT(node->key) : 0; 4.190 +} 4.191 + 4.192 +void *rb_node_data(struct rbnode *node) 4.193 +{ 4.194 + return node ? node->data : 0; 4.195 +} 4.196 + 4.197 +static int cmpaddr(void *ap, void *bp) 4.198 +{ 4.199 + return ap < bp ? -1 : (ap > bp ? 1 : 0); 4.200 +} 4.201 + 4.202 +static int cmpint(void *ap, void *bp) 4.203 +{ 4.204 + return PTR2INT(ap) - PTR2INT(bp); 4.205 +} 4.206 + 4.207 + 4.208 +/* ---- left-leaning 2-3 red-black implementation ---- */ 4.209 + 4.210 +/* helper prototypes */ 4.211 +static int is_red(struct rbnode *tree); 4.212 +static void color_flip(struct rbnode *tree); 4.213 +static struct rbnode *rot_left(struct rbnode *a); 4.214 +static struct rbnode *rot_right(struct rbnode *a); 4.215 +static struct rbnode *find_min(struct rbnode *tree); 4.216 +static struct rbnode *del_min(struct rbtree *rb, struct rbnode *tree); 4.217 +/*static struct rbnode *move_red_right(struct rbnode *tree);*/ 4.218 +static struct rbnode *move_red_left(struct rbnode *tree); 4.219 +static struct rbnode *fix_up(struct rbnode *tree); 4.220 + 4.221 +static int count_nodes(struct rbnode *node) 4.222 +{ 4.223 + if(!node) 4.224 + return 0; 4.225 + 4.226 + return 1 + count_nodes(node->left) + count_nodes(node->right); 4.227 +} 4.228 + 4.229 +static void del_tree(struct rbnode *node, rb_del_func_t delfunc, void *cls) 4.230 +{ 4.231 + if(!node) 4.232 + return; 4.233 + 4.234 + del_tree(node->left, delfunc, cls); 4.235 + del_tree(node->right, delfunc, cls); 4.236 + 4.237 + delfunc(node, cls); 4.238 + free(node); 4.239 +} 4.240 + 4.241 +static struct rbnode *insert(struct rbtree *rb, struct rbnode *tree, void *key, void *data) 4.242 +{ 4.243 + int cmp; 4.244 + 4.245 + if(!tree) { 4.246 + struct rbnode *node = rb->alloc(sizeof *node); 4.247 + node->red = 1; 4.248 + node->key = key; 4.249 + node->data = data; 4.250 + node->left = node->right = 0; 4.251 + return node; 4.252 + } 4.253 + 4.254 + cmp = rb->cmp(key, tree->key); 4.255 + 4.256 + if(cmp < 0) { 4.257 + tree->left = insert(rb, tree->left, key, data); 4.258 + } else if(cmp > 0) { 4.259 + tree->right = insert(rb, tree->right, key, data); 4.260 + } else { 4.261 + tree->data = data; 4.262 + } 4.263 + 4.264 + /* fix right-leaning reds */ 4.265 + if(is_red(tree->right)) { 4.266 + tree = rot_left(tree); 4.267 + } 4.268 + /* fix two reds in a row */ 4.269 + if(is_red(tree->left) && is_red(tree->left->left)) { 4.270 + tree = rot_right(tree); 4.271 + } 4.272 + 4.273 + /* if 4-node, split it by color inversion */ 4.274 + if(is_red(tree->left) && is_red(tree->right)) { 4.275 + color_flip(tree); 4.276 + } 4.277 + 4.278 + return tree; 4.279 +} 4.280 + 4.281 +static struct rbnode *delete(struct rbtree *rb, struct rbnode *tree, void *key) 4.282 +{ 4.283 + int cmp; 4.284 + 4.285 + if(!tree) { 4.286 + return 0; 4.287 + } 4.288 + 4.289 + cmp = rb->cmp(key, tree->key); 4.290 + 4.291 + if(cmp < 0) { 4.292 + if(!is_red(tree->left) && !is_red(tree->left->left)) { 4.293 + tree = move_red_left(tree); 4.294 + } 4.295 + tree->left = delete(rb, tree->left, key); 4.296 + } else { 4.297 + /* need reds on the right */ 4.298 + if(is_red(tree->left)) { 4.299 + tree = rot_right(tree); 4.300 + } 4.301 + 4.302 + /* found it at the bottom (XXX what certifies left is null?) */ 4.303 + if(cmp == 0 && !tree->right) { 4.304 + if(rb->del) { 4.305 + rb->del(tree, rb->del_cls); 4.306 + } 4.307 + rb->free(tree); 4.308 + return 0; 4.309 + } 4.310 + 4.311 + if(!is_red(tree->right) && !is_red(tree->right->left)) { 4.312 + tree = move_red_left(tree); 4.313 + } 4.314 + 4.315 + if(key == tree->key) { 4.316 + struct rbnode *rmin = find_min(tree->right); 4.317 + tree->key = rmin->key; 4.318 + tree->data = rmin->data; 4.319 + tree->right = del_min(rb, tree->right); 4.320 + } else { 4.321 + tree->right = delete(rb, tree->right, key); 4.322 + } 4.323 + } 4.324 + 4.325 + return fix_up(tree); 4.326 +} 4.327 + 4.328 +static struct rbnode *find(struct rbtree *rb, struct rbnode *node, void *key) 4.329 +{ 4.330 + int cmp; 4.331 + 4.332 + if(!node) 4.333 + return 0; 4.334 + 4.335 + if((cmp = rb->cmp(key, node->key)) == 0) { 4.336 + return node; 4.337 + } 4.338 + return find(rb, cmp < 0 ? node->left : node->right, key); 4.339 +} 4.340 + 4.341 +static void traverse(struct rbnode *node, void (*func)(struct rbnode*, void*), void *cls) 4.342 +{ 4.343 + if(!node) 4.344 + return; 4.345 + 4.346 + traverse(node->left, func, cls); 4.347 + func(node, cls); 4.348 + traverse(node->right, func, cls); 4.349 +} 4.350 + 4.351 +/* helpers */ 4.352 + 4.353 +static int is_red(struct rbnode *tree) 4.354 +{ 4.355 + return tree && tree->red; 4.356 +} 4.357 + 4.358 +static void color_flip(struct rbnode *tree) 4.359 +{ 4.360 + tree->red = !tree->red; 4.361 + tree->left->red = !tree->left->red; 4.362 + tree->right->red = !tree->right->red; 4.363 +} 4.364 + 4.365 +static struct rbnode *rot_left(struct rbnode *a) 4.366 +{ 4.367 + struct rbnode *b = a->right; 4.368 + a->right = b->left; 4.369 + b->left = a; 4.370 + b->red = a->red; 4.371 + a->red = 1; 4.372 + return b; 4.373 +} 4.374 + 4.375 +static struct rbnode *rot_right(struct rbnode *a) 4.376 +{ 4.377 + struct rbnode *b = a->left; 4.378 + a->left = b->right; 4.379 + b->right = a; 4.380 + b->red = a->red; 4.381 + a->red = 1; 4.382 + return b; 4.383 +} 4.384 + 4.385 +static struct rbnode *find_min(struct rbnode *tree) 4.386 +{ 4.387 + if(!tree || !tree->left) { 4.388 + return tree; 4.389 + } 4.390 + return find_min(tree->left); 4.391 +} 4.392 + 4.393 +static struct rbnode *del_min(struct rbtree *rb, struct rbnode *tree) 4.394 +{ 4.395 + if(!tree->left) { 4.396 + if(rb->del) { 4.397 + rb->del(tree->left, rb->del_cls); 4.398 + } 4.399 + rb->free(tree->left); 4.400 + return 0; 4.401 + } 4.402 + 4.403 + /* make sure we've got red (3/4-nodes) at the left side so we can delete at the bottom */ 4.404 + if(!is_red(tree->left) && !is_red(tree->left->left)) { 4.405 + tree = move_red_left(tree); 4.406 + } 4.407 + tree->left = del_min(rb, tree->left); 4.408 + 4.409 + /* fix right-reds, red-reds, and split 4-nodes on the way up */ 4.410 + return fix_up(tree); 4.411 +} 4.412 + 4.413 +#if 0 4.414 +/* push a red link on this node to the right */ 4.415 +static struct rbnode *move_red_right(struct rbnode *tree) 4.416 +{ 4.417 + /* flipping it makes both children go red, so we have a red to the right */ 4.418 + color_flip(tree); 4.419 + 4.420 + /* if after the flip we've got a red-red situation to the left, fix it */ 4.421 + if(is_red(tree->left->left)) { 4.422 + tree = rot_right(tree); 4.423 + color_flip(tree); 4.424 + } 4.425 + return tree; 4.426 +} 4.427 +#endif 4.428 + 4.429 +/* push a red link on this node to the left */ 4.430 +static struct rbnode *move_red_left(struct rbnode *tree) 4.431 +{ 4.432 + /* flipping it makes both children go red, so we have a red to the left */ 4.433 + color_flip(tree); 4.434 + 4.435 + /* if after the flip we've got a red-red on the right-left, fix it */ 4.436 + if(is_red(tree->right->left)) { 4.437 + tree->right = rot_right(tree->right); 4.438 + tree = rot_left(tree); 4.439 + color_flip(tree); 4.440 + } 4.441 + return tree; 4.442 +} 4.443 + 4.444 +static struct rbnode *fix_up(struct rbnode *tree) 4.445 +{ 4.446 + /* fix right-leaning */ 4.447 + if(is_red(tree->right)) { 4.448 + tree = rot_left(tree); 4.449 + } 4.450 + /* change invalid red-red pairs into a proper 4-node */ 4.451 + if(is_red(tree->left) && is_red(tree->left->left)) { 4.452 + tree = rot_right(tree); 4.453 + } 4.454 + /* split 4-nodes */ 4.455 + if(is_red(tree->left) && is_red(tree->right)) { 4.456 + color_flip(tree); 4.457 + } 4.458 + return tree; 4.459 +}
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 5.2 +++ b/src/rbtree.h Sun Oct 09 07:48:14 2011 +0300 5.3 @@ -0,0 +1,68 @@ 5.4 +#ifndef RBTREE_H_ 5.5 +#define RBTREE_H_ 5.6 + 5.7 +struct rbtree; 5.8 + 5.9 + 5.10 +struct rbnode { 5.11 + void *key, *data; 5.12 + int red; 5.13 + struct rbnode *left, *right; 5.14 + struct rbnode *next; /* for iterator stack */ 5.15 +}; 5.16 + 5.17 + 5.18 +typedef void *(*rb_alloc_func_t)(size_t); 5.19 +typedef void (*rb_free_func_t)(void*); 5.20 + 5.21 +typedef int (*rb_cmp_func_t)(void*, void*); 5.22 +typedef void (*rb_del_func_t)(struct rbnode*, void*); 5.23 + 5.24 +#define RB_KEY_ADDR (rb_cmp_func_t)(0) 5.25 +#define RB_KEY_INT (rb_cmp_func_t)(1) 5.26 +#define RB_KEY_STRING (rb_cmp_func_t)(3) 5.27 + 5.28 +typedef struct rbnode* rbiter_t; 5.29 + 5.30 +#ifdef __cplusplus 5.31 +extern "C" { 5.32 +#endif 5.33 + 5.34 +struct rbtree *rb_create(rb_cmp_func_t cmp_func); 5.35 +void rb_free(struct rbtree *rb); 5.36 + 5.37 +int rb_init(struct rbtree *rb, rb_cmp_func_t cmp_func); 5.38 +void rb_destroy(struct rbtree *rb); 5.39 + 5.40 +void rb_set_allocator(struct rbtree *rb, rb_alloc_func_t alloc, rb_free_func_t free); 5.41 +void rb_set_compare_func(struct rbtree *rb, rb_cmp_func_t func); 5.42 +void rb_set_delete_func(struct rbtree *rb, rb_del_func_t func, void *cls); 5.43 + 5.44 +int rb_size(struct rbtree *rb); 5.45 + 5.46 +int rb_insert(struct rbtree *rb, void *key, void *data); 5.47 +int rb_inserti(struct rbtree *rb, int key, void *data); 5.48 + 5.49 +int rb_delete(struct rbtree *rb, void *key); 5.50 +int rb_deletei(struct rbtree *rb, int key); 5.51 + 5.52 +void *rb_find(struct rbtree *rb, void *key); 5.53 +void *rb_findi(struct rbtree *rb, int key); 5.54 + 5.55 +void rb_foreach(struct rbtree *rb, void (*func)(struct rbnode*, void*), void *cls); 5.56 + 5.57 +struct rbnode *rb_root(struct rbtree *rb); 5.58 + 5.59 +void rb_begin(struct rbtree *rb); 5.60 +struct rbnode *rb_node_next(struct rbtree *rb); 5.61 + 5.62 +void *rb_node_key(struct rbnode *node); 5.63 +int rb_node_keyi(struct rbnode *node); 5.64 +void *rb_node_data(struct rbnode *node); 5.65 + 5.66 +#ifdef __cplusplus 5.67 +} 5.68 +#endif 5.69 + 5.70 + 5.71 +#endif /* RBTREE_H_ */
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 6.2 +++ b/test/Makefile Sun Oct 09 07:48:14 2011 +0300 6.3 @@ -0,0 +1,32 @@ 6.4 +obj = test.o 6.5 +bin = test 6.6 + 6.7 +font = linux-libertine.ttf 6.8 + 6.9 +CC = gcc 6.10 +CFLAGS = -pedantic -Wall -g -I../src -I/usr/local/include 6.11 +LDFLAGS = -L.. -L/usr/local/lib $(libgl) -lrbtree -ldrawtext 6.12 + 6.13 +ifeq ($(shell uname -s), Darwin) 6.14 + libgl = -framework OpenGL -framework GLUT 6.15 +else 6.16 + libgl = -lGL -lglut 6.17 +endif 6.18 + 6.19 +.PHONY: all 6.20 +all: $(bin) $(font) 6.21 + 6.22 +$(bin): $(obj) 6.23 + $(CC) -o $@ $(obj) $(LDFLAGS) 6.24 + 6.25 +$(font): 6.26 + wget http://downloads.sourceforge.net/project/linuxlibertine/linuxlibertine/5.1.3-2/LinLibertineTTF_5.1.3_2011_06_21.tgz 6.27 + mkdir -p linlibertine 6.28 + cd linlibertine; tar xzvf ../LinLibertineTTF_5.1.3_2011_06_21.tgz 6.29 + rm -f LinLibertineTTF_5.1.3_2011_06_21.tgz 6.30 + cp linlibertine/LinLibertine_R.ttf $@ 6.31 + 6.32 + 6.33 +.PHONY: clean 6.34 +clean: 6.35 + rm -f $(obj) $(bin)
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 7.2 +++ b/test/test.c Sun Oct 09 07:48:14 2011 +0300 7.3 @@ -0,0 +1,395 @@ 7.4 +#include <stdio.h> 7.5 +#include <stdlib.h> 7.6 +#include <string.h> 7.7 +#include <ctype.h> 7.8 +#include <math.h> 7.9 +#include <assert.h> 7.10 +#include <alloca.h> 7.11 + 7.12 +#ifndef __APPLE__ 7.13 +#include <GL/glut.h> 7.14 +#else 7.15 +#include <GLUT/glut.h> 7.16 +#endif 7.17 +#include <rbtree.h> 7.18 +#include <drawtext.h> 7.19 + 7.20 +#define FONTSZ 18 7.21 + 7.22 +void init_gl(int argc, char **argv); 7.23 +float rbvis_width(struct rbnode *tree); 7.24 +void rbvis_draw(struct rbnode *tree, float x, float y); 7.25 + 7.26 +void draw_roundbox(float xsz, float ysz, float rad, int segm, const float *col, float border, const float *bcol); 7.27 +void draw_fillet(float rad, int segm); 7.28 + 7.29 +struct rbtree *tree; 7.30 +int num_nodes; 7.31 +struct dtx_font *font; 7.32 +char input_buffer[64]; 7.33 +int win_xsz, win_ysz; 7.34 + 7.35 +int main(int argc, char **argv) 7.36 +{ 7.37 + int i; 7.38 + 7.39 + if(argv[1]) { 7.40 + if(!isdigit(argv[1][0])) { 7.41 + fprintf(stderr, "pass a fucking number, not: %s\n", argv[1]); 7.42 + return 1; 7.43 + } 7.44 + num_nodes = atoi(argv[1]); 7.45 + } 7.46 + 7.47 + if(!(font = dtx_open_font("linux-libertine.ttf", FONTSZ))) { 7.48 + fprintf(stderr, "failed to open font\n"); 7.49 + return 1; 7.50 + } 7.51 + 7.52 + if(!(tree = rb_create(RB_KEY_INT))) { 7.53 + return 1; 7.54 + } 7.55 + 7.56 + for(i=0; i<num_nodes; i++) { 7.57 + rb_inserti(tree, i, 0); 7.58 + } 7.59 + 7.60 + init_gl(argc, argv); 7.61 + return 0; 7.62 +} 7.63 + 7.64 +#define NWIDTH 28.0 7.65 +#define NHEIGHT 24.0 7.66 +#define PADDING 0 7.67 +#define DY (NHEIGHT + NHEIGHT / 2.0) 7.68 + 7.69 +#define VIS(node) ((struct visinfo*)(node)->data) 7.70 + 7.71 +void disp(void); 7.72 +void reshape(int x, int y); 7.73 +void keyb(unsigned char key, int x, int y); 7.74 +void draw_rect(float x, float y, float width, float height, const char *text, int red); 7.75 +void draw_link(float x0, float y0, float x1, float y1, int red); 7.76 + 7.77 +void init_gl(int argc, char **argv) 7.78 +{ 7.79 + glutInitWindowSize(1280, 720); 7.80 + glutInit(&argc, argv); 7.81 + glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_MULTISAMPLE); 7.82 + 7.83 + glutCreateWindow("foo"); 7.84 + 7.85 + dtx_use_font(font, FONTSZ); 7.86 + 7.87 + glutDisplayFunc(disp); 7.88 + glutReshapeFunc(reshape); 7.89 + glutKeyboardFunc(keyb); 7.90 + 7.91 + glEnable(GL_DEPTH_TEST); 7.92 + glEnable(GL_MULTISAMPLE); 7.93 + 7.94 + glutMainLoop(); 7.95 +} 7.96 + 7.97 +void disp(void) 7.98 +{ 7.99 + struct rbnode *root = rb_root(tree); 7.100 + 7.101 + glClearColor(0.57, 0.64, 0.59, 1.0); 7.102 + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 7.103 + 7.104 + glMatrixMode(GL_MODELVIEW); 7.105 + glLoadIdentity(); 7.106 + 7.107 + if(input_buffer[0]) { 7.108 + char *prompt = "select node to delete: "; 7.109 + char *buf = alloca(strlen(prompt) + strlen(input_buffer)); 7.110 + 7.111 + glPushMatrix(); 7.112 + glTranslatef(10, 10, -0.9); 7.113 + glColor3f(0, 0, 0); 7.114 + sprintf(buf, "%s%s", prompt, input_buffer); 7.115 + dtx_string(buf); 7.116 + glPopMatrix(); 7.117 + } 7.118 + 7.119 + if(root) { 7.120 + rbvis_draw(root, rbvis_width(root->left) + NWIDTH, 550); 7.121 + } 7.122 + 7.123 + glutSwapBuffers(); 7.124 + assert(glGetError() == GL_NO_ERROR); 7.125 +} 7.126 + 7.127 + 7.128 +float rbvis_width(struct rbnode *tree) 7.129 +{ 7.130 + if(!tree) 7.131 + return NWIDTH; 7.132 + 7.133 + return NWIDTH + rbvis_width(tree->left) + rbvis_width(tree->right) + PADDING * 3.0; 7.134 +} 7.135 + 7.136 +void rbvis_draw(struct rbnode *tree, float x, float y) 7.137 +{ 7.138 + float leftx, rightx, nexty; 7.139 + static const float hxsz = NWIDTH / 2.0; 7.140 + static const float hysz = NHEIGHT / 2.0; 7.141 + char text[16]; 7.142 + 7.143 + if(!tree) 7.144 + return; 7.145 + 7.146 + leftx = x - (tree->left ? rbvis_width(tree->left->right) + NWIDTH : rbvis_width(tree->left) / 2.0); 7.147 + rightx = x + (tree->right ? rbvis_width(tree->right->left) + NWIDTH : rbvis_width(tree->right) / 2.0); 7.148 + 7.149 + nexty = y - DY; 7.150 + 7.151 + sprintf(text, "%d", rb_node_keyi(tree)); 7.152 + draw_rect(x - hxsz, y - hysz, NWIDTH, NHEIGHT, text, tree->red); 7.153 + 7.154 + rbvis_draw(tree->left, leftx, nexty); 7.155 + rbvis_draw(tree->right, rightx, nexty); 7.156 + 7.157 + if(tree->left) 7.158 + draw_link(x, y, leftx, nexty, tree->left->red); 7.159 + if(tree->right) 7.160 + draw_link(x, y, rightx, nexty, tree->right->red); 7.161 +} 7.162 + 7.163 +void draw_rect(float x, float y, float width, float height, const char *text, int red) 7.164 +{ 7.165 + float node_col[] = {0.63, 0.71, 0.82, 1.0}; 7.166 + float bord_col[] = {0, 0, 0, 1}; 7.167 + 7.168 + if(red) { 7.169 + bord_col[0] = 1.0; 7.170 + } 7.171 + 7.172 + glMatrixMode(GL_MODELVIEW); 7.173 + glPushMatrix(); 7.174 + glTranslatef(x + width / 2.0, y + height / 2.0, 0.0); 7.175 + 7.176 + draw_roundbox(width, height, 8, 6, node_col, 1.2, bord_col); 7.177 + 7.178 + glColor3f(0.15, 0.15, 0.15); 7.179 + glTranslatef(-dtx_string_width(text) / 2.0, -dtx_string_height(text) / 2.0, 0.1); 7.180 + dtx_string(text); 7.181 + glMatrixMode(GL_MODELVIEW); 7.182 + glPopMatrix(); 7.183 +} 7.184 + 7.185 +void draw_link(float x0, float y0, float x1, float y1, int red) 7.186 +{ 7.187 + glPushAttrib(GL_LINE_BIT); 7.188 + if(red) { 7.189 + glLineWidth(3); 7.190 + } else { 7.191 + glLineWidth(2); 7.192 + } 7.193 + 7.194 + glBegin(GL_LINES); 7.195 + if(red) { 7.196 + glColor3f(0.8, 0.36, 0.3); 7.197 + } else { 7.198 + glColor3f(0, 0, 0); 7.199 + } 7.200 + glVertex3f(x0, y0, -0.8); 7.201 + glVertex3f(x1, y1, -0.8); 7.202 + glEnd(); 7.203 + 7.204 + glPopAttrib(); 7.205 +} 7.206 + 7.207 +void draw_roundbox(float xsz, float ysz, float rad, int segm, const float *col, float border, const float *bcol) 7.208 +{ 7.209 + float hin_xsz, hin_ysz; 7.210 + 7.211 + if(border > 0.0f) { 7.212 + glPushMatrix(); 7.213 + glTranslatef(0, 0, -0.001); 7.214 + draw_roundbox(xsz + 2 * border, ysz + 2 * border, rad + border, segm, bcol, 0.0, bcol); 7.215 + glPopMatrix(); 7.216 + } 7.217 + 7.218 + /* half inner size */ 7.219 + hin_xsz = (xsz - 2.0 * rad) / 2.0; 7.220 + hin_ysz = (ysz - 2.0 * rad) / 2.0; 7.221 + 7.222 + glColor4fv(col); 7.223 + 7.224 + glBegin(GL_QUADS); 7.225 + /* center */ 7.226 + glVertex2f(-hin_xsz, -hin_ysz); 7.227 + glVertex2f(hin_xsz, -hin_ysz); 7.228 + glVertex2f(hin_xsz, hin_ysz); 7.229 + glVertex2f(-hin_xsz, hin_ysz); 7.230 + /* right */ 7.231 + glVertex2f(hin_xsz, -hin_ysz); 7.232 + glVertex2f(hin_xsz + rad, -hin_ysz); 7.233 + glVertex2f(hin_xsz + rad, hin_ysz); 7.234 + glVertex2f(hin_xsz, hin_ysz); 7.235 + /* top */ 7.236 + glVertex2f(-hin_xsz, hin_ysz); 7.237 + glVertex2f(hin_xsz, hin_ysz); 7.238 + glVertex2f(hin_xsz, hin_ysz + rad); 7.239 + glVertex2f(-hin_xsz, hin_ysz + rad); 7.240 + /* left */ 7.241 + glVertex2f(-hin_xsz - rad, -hin_ysz); 7.242 + glVertex2f(-hin_xsz, -hin_ysz); 7.243 + glVertex2f(-hin_xsz, hin_ysz); 7.244 + glVertex2f(-hin_xsz - rad, hin_ysz); 7.245 + /* bottom */ 7.246 + glVertex2f(-hin_xsz, -hin_ysz - rad); 7.247 + glVertex2f(hin_xsz, -hin_ysz - rad); 7.248 + glVertex2f(hin_xsz, -hin_ysz); 7.249 + glVertex2f(-hin_xsz, -hin_ysz); 7.250 + glEnd(); 7.251 + 7.252 + glMatrixMode(GL_MODELVIEW); 7.253 + 7.254 + glPushMatrix(); 7.255 + glTranslatef(hin_xsz, hin_ysz, 0); 7.256 + draw_fillet(rad, segm); 7.257 + glPopMatrix(); 7.258 + 7.259 + glPushMatrix(); 7.260 + glTranslatef(-hin_xsz, hin_ysz, 0); 7.261 + glRotatef(90, 0, 0, 1); 7.262 + draw_fillet(rad, segm); 7.263 + glPopMatrix(); 7.264 + 7.265 + glPushMatrix(); 7.266 + glTranslatef(-hin_xsz, -hin_ysz, 0); 7.267 + glRotatef(180, 0, 0, 1); 7.268 + draw_fillet(rad, segm); 7.269 + glPopMatrix(); 7.270 + 7.271 + glPushMatrix(); 7.272 + glTranslatef(hin_xsz, -hin_ysz, 0); 7.273 + glRotatef(270, 0, 0, 1); 7.274 + draw_fillet(rad, segm); 7.275 + glPopMatrix(); 7.276 +} 7.277 + 7.278 +void draw_fillet(float rad, int segm) 7.279 +{ 7.280 + int i; 7.281 + 7.282 + glBegin(GL_TRIANGLE_FAN); 7.283 + glVertex2f(0, 0); 7.284 + for(i=0; i<segm; i++) { 7.285 + float theta = 0.5 * M_PI * (float)i / (float)(segm - 1); 7.286 + float x = cos(theta) * rad; 7.287 + float y = sin(theta) * rad; 7.288 + glVertex2f(x, y); 7.289 + } 7.290 + glEnd(); 7.291 +} 7.292 + 7.293 + 7.294 +void reshape(int x, int y) 7.295 +{ 7.296 + win_xsz = x; 7.297 + win_ysz = y; 7.298 + 7.299 + glViewport(0, 0, x, y); 7.300 + 7.301 + glMatrixMode(GL_PROJECTION); 7.302 + glLoadIdentity(); 7.303 + glOrtho(0, x, 0, y, -1, 1); 7.304 +} 7.305 + 7.306 +void keyb(unsigned char key, int x, int y) 7.307 +{ 7.308 + static int wposx = -1, wposy; 7.309 + static char *inp_next; 7.310 + 7.311 + switch(key) { 7.312 + case 27: 7.313 + exit(0); 7.314 + 7.315 + case 'f': 7.316 + case 'F': 7.317 + if(wposx >= 0) { 7.318 + glutPositionWindow(wposx, wposy); 7.319 + wposx = -1; 7.320 + } else { 7.321 + wposx = glutGet(GLUT_WINDOW_X); 7.322 + wposy = glutGet(GLUT_WINDOW_Y); 7.323 + glutFullScreen(); 7.324 + } 7.325 + break; 7.326 + 7.327 + case 'a': 7.328 + rb_inserti(tree, num_nodes++, 0); 7.329 + glutPostRedisplay(); 7.330 + break; 7.331 + 7.332 + case 'r': 7.333 + { 7.334 + int x; 7.335 + do { 7.336 + x = rand() % 1024; 7.337 + } while(rb_findi(tree, x)); 7.338 + 7.339 + rb_inserti(tree, x, 0); 7.340 + } 7.341 + glutPostRedisplay(); 7.342 + break; 7.343 + 7.344 + case 'd': 7.345 + inp_next = input_buffer; 7.346 + *inp_next++ = ' '; 7.347 + *inp_next = 0; 7.348 + glutPostRedisplay(); 7.349 + break; 7.350 + 7.351 + case '0': 7.352 + case '1': 7.353 + case '2': 7.354 + case '3': 7.355 + case '4': 7.356 + case '5': 7.357 + case '6': 7.358 + case '7': 7.359 + case '8': 7.360 + case '9': 7.361 + if(inp_next) { 7.362 + *inp_next++ = key; 7.363 + *inp_next = 0; 7.364 + glutPostRedisplay(); 7.365 + } 7.366 + break; 7.367 + 7.368 + case '\b': 7.369 + if(inp_next > input_buffer) { 7.370 + *--inp_next = 0; 7.371 + glutPostRedisplay(); 7.372 + } 7.373 + break; 7.374 + 7.375 + case '\n': 7.376 + case '\r': 7.377 + if(inp_next) { 7.378 + int x; 7.379 + char *endp; 7.380 + 7.381 + *inp_next = 0; 7.382 + inp_next = 0; 7.383 + 7.384 + if((x = strtol(input_buffer, &endp, 10)), endp == input_buffer) { 7.385 + fprintf(stderr, "invalid input: %s\n", input_buffer); 7.386 + } else if(!rb_findi(tree, x)) { 7.387 + fprintf(stderr, "%d not found in the tree\n", x); 7.388 + } else { 7.389 + printf("deleting: %d\n", x); 7.390 + rb_deletei(tree, x); 7.391 + } 7.392 + input_buffer[0] = 0; 7.393 + glutPostRedisplay(); 7.394 + } 7.395 + break; 7.396 + } 7.397 +} 7.398 +