kern
diff src/rbtree.c @ 68:0a205396e1a0
- added a generic red-black tree data structure
- added a VM map as an red-black tree of vm_pages in the process structure
- constructed the vm map of the memory passed by the kernel initially to the first process.
author | John Tsiombikas <nuclear@mutantstargoat.com> |
---|---|
date | Mon, 10 Oct 2011 04:16:01 +0300 |
parents | |
children | b45e2d5f0ae1 |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/rbtree.c Mon Oct 10 04:16:01 2011 +0300 1.3 @@ -0,0 +1,457 @@ 1.4 +#include <stdio.h> 1.5 +#include <stdlib.h> 1.6 +#include <string.h> 1.7 +#include "rbtree.h" 1.8 + 1.9 +#define INT2PTR(x) ((void*)(x)) 1.10 +#define PTR2INT(x) ((int)(x)) 1.11 + 1.12 +static int cmpaddr(void *ap, void *bp); 1.13 +static int cmpint(void *ap, void *bp); 1.14 + 1.15 +static int count_nodes(struct rbnode *node); 1.16 +static void del_tree(struct rbnode *node, void (*delfunc)(struct rbnode*, void*), void *cls); 1.17 +static struct rbnode *insert(struct rbtree *rb, struct rbnode *tree, void *key, void *data); 1.18 +static struct rbnode *delete(struct rbtree *rb, struct rbnode *tree, void *key); 1.19 +/*static struct rbnode *find(struct rbtree *rb, struct rbnode *node, void *key);*/ 1.20 +static void traverse(struct rbnode *node, void (*func)(struct rbnode*, void*), void *cls); 1.21 + 1.22 +struct rbtree *rb_create(rb_cmp_func_t cmp_func) 1.23 +{ 1.24 + struct rbtree *rb; 1.25 + 1.26 + if(!(rb = malloc(sizeof *rb))) { 1.27 + return 0; 1.28 + } 1.29 + if(rb_init(rb, cmp_func) == -1) { 1.30 + free(rb); 1.31 + return 0; 1.32 + } 1.33 + return rb; 1.34 +} 1.35 + 1.36 +void rb_free(struct rbtree *rb) 1.37 +{ 1.38 + rb_destroy(rb); 1.39 + free(rb); 1.40 +} 1.41 + 1.42 + 1.43 +int rb_init(struct rbtree *rb, rb_cmp_func_t cmp_func) 1.44 +{ 1.45 + memset(rb, 0, sizeof *rb); 1.46 + 1.47 + if(cmp_func == RB_KEY_INT) { 1.48 + rb->cmp = cmpint; 1.49 + } else if(cmp_func == RB_KEY_STRING) { 1.50 + rb->cmp = (rb_cmp_func_t)strcmp; 1.51 + } else { 1.52 + rb->cmp = cmpaddr; 1.53 + } 1.54 + 1.55 + rb->alloc = malloc; 1.56 + rb->free = free; 1.57 + return 0; 1.58 +} 1.59 + 1.60 +void rb_destroy(struct rbtree *rb) 1.61 +{ 1.62 + del_tree(rb->root, rb->del, rb->del_cls); 1.63 +} 1.64 + 1.65 +void rb_set_allocator(struct rbtree *rb, rb_alloc_func_t alloc, rb_free_func_t free) 1.66 +{ 1.67 + rb->alloc = alloc; 1.68 + rb->free = free; 1.69 +} 1.70 + 1.71 + 1.72 +void rb_set_compare_func(struct rbtree *rb, rb_cmp_func_t func) 1.73 +{ 1.74 + rb->cmp = func; 1.75 +} 1.76 + 1.77 +void rb_set_delete_func(struct rbtree *rb, rb_del_func_t func, void *cls) 1.78 +{ 1.79 + rb->del = func; 1.80 + rb->del_cls = cls; 1.81 +} 1.82 + 1.83 +int rb_size(struct rbtree *rb) 1.84 +{ 1.85 + return count_nodes(rb->root); 1.86 +} 1.87 + 1.88 +int rb_insert(struct rbtree *rb, void *key, void *data) 1.89 +{ 1.90 + rb->root = insert(rb, rb->root, key, data); 1.91 + rb->root->red = 0; 1.92 + return 0; 1.93 +} 1.94 + 1.95 +int rb_inserti(struct rbtree *rb, int key, void *data) 1.96 +{ 1.97 + rb->root = insert(rb, rb->root, INT2PTR(key), data); 1.98 + rb->root->red = 0; 1.99 + return 0; 1.100 +} 1.101 + 1.102 + 1.103 +int rb_delete(struct rbtree *rb, void *key) 1.104 +{ 1.105 + rb->root = delete(rb, rb->root, key); 1.106 + rb->root->red = 0; 1.107 + return 0; 1.108 +} 1.109 + 1.110 +int rb_deletei(struct rbtree *rb, int key) 1.111 +{ 1.112 + rb->root = delete(rb, rb->root, INT2PTR(key)); 1.113 + rb->root->red = 0; 1.114 + return 0; 1.115 +} 1.116 + 1.117 + 1.118 +void *rb_find(struct rbtree *rb, void *key) 1.119 +{ 1.120 + struct rbnode *node = rb->root; 1.121 + 1.122 + while(node) { 1.123 + int cmp = rb->cmp(key, node->key); 1.124 + if(cmp == 0) { 1.125 + return node; 1.126 + } 1.127 + node = cmp < 0 ? node->left : node->right; 1.128 + } 1.129 + return 0; 1.130 +} 1.131 + 1.132 +void *rb_findi(struct rbtree *rb, int key) 1.133 +{ 1.134 + return rb_find(rb, INT2PTR(key)); 1.135 +} 1.136 + 1.137 + 1.138 +void rb_foreach(struct rbtree *rb, void (*func)(struct rbnode*, void*), void *cls) 1.139 +{ 1.140 + traverse(rb->root, func, cls); 1.141 +} 1.142 + 1.143 + 1.144 +struct rbnode *rb_root(struct rbtree *rb) 1.145 +{ 1.146 + return rb->root; 1.147 +} 1.148 + 1.149 +void rb_begin(struct rbtree *rb) 1.150 +{ 1.151 + rb->rstack = 0; 1.152 + rb->iter = rb->root; 1.153 +} 1.154 + 1.155 +#define push(sp, x) ((x)->next = (sp), (sp) = (x)) 1.156 +#define pop(sp) ((sp) = (sp)->next) 1.157 +#define top(sp) (sp) 1.158 + 1.159 +struct rbnode *rb_next(struct rbtree *rb) 1.160 +{ 1.161 + struct rbnode *res = 0; 1.162 + 1.163 + while(rb->rstack || rb->iter) { 1.164 + if(rb->iter) { 1.165 + push(rb->rstack, rb->iter); 1.166 + rb->iter = rb->iter->left; 1.167 + } else { 1.168 + rb->iter = top(rb->rstack); 1.169 + pop(rb->rstack); 1.170 + res = rb->iter; 1.171 + rb->iter = rb->iter->right; 1.172 + break; 1.173 + } 1.174 + } 1.175 + return res; 1.176 +} 1.177 + 1.178 +void *rb_node_key(struct rbnode *node) 1.179 +{ 1.180 + return node ? node->key : 0; 1.181 +} 1.182 + 1.183 +int rb_node_keyi(struct rbnode *node) 1.184 +{ 1.185 + return node ? PTR2INT(node->key) : 0; 1.186 +} 1.187 + 1.188 +void *rb_node_data(struct rbnode *node) 1.189 +{ 1.190 + return node ? node->data : 0; 1.191 +} 1.192 + 1.193 +static int cmpaddr(void *ap, void *bp) 1.194 +{ 1.195 + return ap < bp ? -1 : (ap > bp ? 1 : 0); 1.196 +} 1.197 + 1.198 +static int cmpint(void *ap, void *bp) 1.199 +{ 1.200 + return PTR2INT(ap) - PTR2INT(bp); 1.201 +} 1.202 + 1.203 + 1.204 +/* ---- left-leaning 2-3 red-black implementation ---- */ 1.205 + 1.206 +/* helper prototypes */ 1.207 +static int is_red(struct rbnode *tree); 1.208 +static void color_flip(struct rbnode *tree); 1.209 +static struct rbnode *rot_left(struct rbnode *a); 1.210 +static struct rbnode *rot_right(struct rbnode *a); 1.211 +static struct rbnode *find_min(struct rbnode *tree); 1.212 +static struct rbnode *del_min(struct rbtree *rb, struct rbnode *tree); 1.213 +/*static struct rbnode *move_red_right(struct rbnode *tree);*/ 1.214 +static struct rbnode *move_red_left(struct rbnode *tree); 1.215 +static struct rbnode *fix_up(struct rbnode *tree); 1.216 + 1.217 +static int count_nodes(struct rbnode *node) 1.218 +{ 1.219 + if(!node) 1.220 + return 0; 1.221 + 1.222 + return 1 + count_nodes(node->left) + count_nodes(node->right); 1.223 +} 1.224 + 1.225 +static void del_tree(struct rbnode *node, rb_del_func_t delfunc, void *cls) 1.226 +{ 1.227 + if(!node) 1.228 + return; 1.229 + 1.230 + del_tree(node->left, delfunc, cls); 1.231 + del_tree(node->right, delfunc, cls); 1.232 + 1.233 + delfunc(node, cls); 1.234 + free(node); 1.235 +} 1.236 + 1.237 +static struct rbnode *insert(struct rbtree *rb, struct rbnode *tree, void *key, void *data) 1.238 +{ 1.239 + int cmp; 1.240 + 1.241 + if(!tree) { 1.242 + struct rbnode *node = rb->alloc(sizeof *node); 1.243 + node->red = 1; 1.244 + node->key = key; 1.245 + node->data = data; 1.246 + node->left = node->right = 0; 1.247 + return node; 1.248 + } 1.249 + 1.250 + cmp = rb->cmp(key, tree->key); 1.251 + 1.252 + if(cmp < 0) { 1.253 + tree->left = insert(rb, tree->left, key, data); 1.254 + } else if(cmp > 0) { 1.255 + tree->right = insert(rb, tree->right, key, data); 1.256 + } else { 1.257 + tree->data = data; 1.258 + } 1.259 + 1.260 + /* fix right-leaning reds */ 1.261 + if(is_red(tree->right)) { 1.262 + tree = rot_left(tree); 1.263 + } 1.264 + /* fix two reds in a row */ 1.265 + if(is_red(tree->left) && is_red(tree->left->left)) { 1.266 + tree = rot_right(tree); 1.267 + } 1.268 + 1.269 + /* if 4-node, split it by color inversion */ 1.270 + if(is_red(tree->left) && is_red(tree->right)) { 1.271 + color_flip(tree); 1.272 + } 1.273 + 1.274 + return tree; 1.275 +} 1.276 + 1.277 +static struct rbnode *delete(struct rbtree *rb, struct rbnode *tree, void *key) 1.278 +{ 1.279 + int cmp; 1.280 + 1.281 + if(!tree) { 1.282 + return 0; 1.283 + } 1.284 + 1.285 + cmp = rb->cmp(key, tree->key); 1.286 + 1.287 + if(cmp < 0) { 1.288 + if(!is_red(tree->left) && !is_red(tree->left->left)) { 1.289 + tree = move_red_left(tree); 1.290 + } 1.291 + tree->left = delete(rb, tree->left, key); 1.292 + } else { 1.293 + /* need reds on the right */ 1.294 + if(is_red(tree->left)) { 1.295 + tree = rot_right(tree); 1.296 + } 1.297 + 1.298 + /* found it at the bottom (XXX what certifies left is null?) */ 1.299 + if(cmp == 0 && !tree->right) { 1.300 + if(rb->del) { 1.301 + rb->del(tree, rb->del_cls); 1.302 + } 1.303 + rb->free(tree); 1.304 + return 0; 1.305 + } 1.306 + 1.307 + if(!is_red(tree->right) && !is_red(tree->right->left)) { 1.308 + tree = move_red_left(tree); 1.309 + } 1.310 + 1.311 + if(key == tree->key) { 1.312 + struct rbnode *rmin = find_min(tree->right); 1.313 + tree->key = rmin->key; 1.314 + tree->data = rmin->data; 1.315 + tree->right = del_min(rb, tree->right); 1.316 + } else { 1.317 + tree->right = delete(rb, tree->right, key); 1.318 + } 1.319 + } 1.320 + 1.321 + return fix_up(tree); 1.322 +} 1.323 + 1.324 +/*static struct rbnode *find(struct rbtree *rb, struct rbnode *node, void *key) 1.325 +{ 1.326 + int cmp; 1.327 + 1.328 + if(!node) 1.329 + return 0; 1.330 + 1.331 + if((cmp = rb->cmp(key, node->key)) == 0) { 1.332 + return node; 1.333 + } 1.334 + return find(rb, cmp < 0 ? node->left : node->right, key); 1.335 +}*/ 1.336 + 1.337 +static void traverse(struct rbnode *node, void (*func)(struct rbnode*, void*), void *cls) 1.338 +{ 1.339 + if(!node) 1.340 + return; 1.341 + 1.342 + traverse(node->left, func, cls); 1.343 + func(node, cls); 1.344 + traverse(node->right, func, cls); 1.345 +} 1.346 + 1.347 +/* helpers */ 1.348 + 1.349 +static int is_red(struct rbnode *tree) 1.350 +{ 1.351 + return tree && tree->red; 1.352 +} 1.353 + 1.354 +static void color_flip(struct rbnode *tree) 1.355 +{ 1.356 + tree->red = !tree->red; 1.357 + tree->left->red = !tree->left->red; 1.358 + tree->right->red = !tree->right->red; 1.359 +} 1.360 + 1.361 +static struct rbnode *rot_left(struct rbnode *a) 1.362 +{ 1.363 + struct rbnode *b = a->right; 1.364 + a->right = b->left; 1.365 + b->left = a; 1.366 + b->red = a->red; 1.367 + a->red = 1; 1.368 + return b; 1.369 +} 1.370 + 1.371 +static struct rbnode *rot_right(struct rbnode *a) 1.372 +{ 1.373 + struct rbnode *b = a->left; 1.374 + a->left = b->right; 1.375 + b->right = a; 1.376 + b->red = a->red; 1.377 + a->red = 1; 1.378 + return b; 1.379 +} 1.380 + 1.381 +static struct rbnode *find_min(struct rbnode *tree) 1.382 +{ 1.383 + struct rbnode *node; 1.384 + 1.385 + if(!tree) 1.386 + return 0; 1.387 + 1.388 + while(node->left) { 1.389 + node = node->left; 1.390 + } 1.391 + return node; 1.392 +} 1.393 + 1.394 +static struct rbnode *del_min(struct rbtree *rb, struct rbnode *tree) 1.395 +{ 1.396 + if(!tree->left) { 1.397 + if(rb->del) { 1.398 + rb->del(tree->left, rb->del_cls); 1.399 + } 1.400 + rb->free(tree->left); 1.401 + return 0; 1.402 + } 1.403 + 1.404 + /* make sure we've got red (3/4-nodes) at the left side so we can delete at the bottom */ 1.405 + if(!is_red(tree->left) && !is_red(tree->left->left)) { 1.406 + tree = move_red_left(tree); 1.407 + } 1.408 + tree->left = del_min(rb, tree->left); 1.409 + 1.410 + /* fix right-reds, red-reds, and split 4-nodes on the way up */ 1.411 + return fix_up(tree); 1.412 +} 1.413 + 1.414 +#if 0 1.415 +/* push a red link on this node to the right */ 1.416 +static struct rbnode *move_red_right(struct rbnode *tree) 1.417 +{ 1.418 + /* flipping it makes both children go red, so we have a red to the right */ 1.419 + color_flip(tree); 1.420 + 1.421 + /* if after the flip we've got a red-red situation to the left, fix it */ 1.422 + if(is_red(tree->left->left)) { 1.423 + tree = rot_right(tree); 1.424 + color_flip(tree); 1.425 + } 1.426 + return tree; 1.427 +} 1.428 +#endif 1.429 + 1.430 +/* push a red link on this node to the left */ 1.431 +static struct rbnode *move_red_left(struct rbnode *tree) 1.432 +{ 1.433 + /* flipping it makes both children go red, so we have a red to the left */ 1.434 + color_flip(tree); 1.435 + 1.436 + /* if after the flip we've got a red-red on the right-left, fix it */ 1.437 + if(is_red(tree->right->left)) { 1.438 + tree->right = rot_right(tree->right); 1.439 + tree = rot_left(tree); 1.440 + color_flip(tree); 1.441 + } 1.442 + return tree; 1.443 +} 1.444 + 1.445 +static struct rbnode *fix_up(struct rbnode *tree) 1.446 +{ 1.447 + /* fix right-leaning */ 1.448 + if(is_red(tree->right)) { 1.449 + tree = rot_left(tree); 1.450 + } 1.451 + /* change invalid red-red pairs into a proper 4-node */ 1.452 + if(is_red(tree->left) && is_red(tree->left->left)) { 1.453 + tree = rot_right(tree); 1.454 + } 1.455 + /* split 4-nodes */ 1.456 + if(is_red(tree->left) && is_red(tree->right)) { 1.457 + color_flip(tree); 1.458 + } 1.459 + return tree; 1.460 +}