Clean the rbtree implementation
This commit is contained in:
		
							parent
							
								
									9a34d1d71f
								
							
						
					
					
						commit
						e94cdc9783
					
				@ -6,14 +6,6 @@
 | 
			
		||||
#ifndef LIBCDSB_SRC_INTERNAL_RBTREE_H
 | 
			
		||||
#define LIBCDSB_SRC_INTERNAL_RBTREE_H
 | 
			
		||||
 | 
			
		||||
typedef enum libcdsb_rbtree_iter_flags {
 | 
			
		||||
    RBI_INORDER   = 0,
 | 
			
		||||
    RBI_PREORDER  = 1,
 | 
			
		||||
    RBI_POSTORDER = 2,
 | 
			
		||||
 | 
			
		||||
    RBI_REVERSE   = 4,
 | 
			
		||||
} rbiter_f;
 | 
			
		||||
 | 
			
		||||
typedef struct libcdsb_rbtree_node {
 | 
			
		||||
    struct libcdsb_rbtree_node* left;
 | 
			
		||||
    struct libcdsb_rbtree_node* right;
 | 
			
		||||
@ -23,30 +15,17 @@ typedef struct libcdsb_rbtree_node {
 | 
			
		||||
    short colored;
 | 
			
		||||
} rbnode_t;
 | 
			
		||||
 | 
			
		||||
typedef struct libcdsb_rbtree_iter {
 | 
			
		||||
    struct libcdsb_rbtree_node* cursor;
 | 
			
		||||
    int flags;
 | 
			
		||||
} rbiter_t;
 | 
			
		||||
 | 
			
		||||
extern const rbnode_t LIBCDSB_RBTREE_NODE_EMPTY[1];
 | 
			
		||||
extern rbnode_t LIBCDSB_RBTREE_NODE_EMPTY[1];
 | 
			
		||||
 | 
			
		||||
extern void*     libcdsb_rbtree_node_create(void* value, rbnode_t* parent, int colored, int size);
 | 
			
		||||
extern void      libcdsb_rbtree_node_fixup (rbnode_t** root, rbnode_t* node);
 | 
			
		||||
extern rbnode_t* libcdsb_rbtree_node_delete(rbnode_t** root, rbnode_t* node);
 | 
			
		||||
 | 
			
		||||
extern _Bool     libcdsb_rbtree_iter_init (rbiter_t* iter, rbnode_t *const *root, rbiter_f flags);
 | 
			
		||||
extern rbnode_t* libcdsb_rbtree_iter_next (rbiter_t* iter);
 | 
			
		||||
extern void      libcdsb_rbtree_iter_reset(rbiter_t* iter);
 | 
			
		||||
 | 
			
		||||
#define rbnode_empty           ((rbnode_t*)LIBCDSB_RBTREE_NODE_EMPTY)
 | 
			
		||||
#define rbnode_create(v, p, c) ((rbnode_t*)libcdsb_rbtree_node_create(v, p, c, sizeof(rbnode_t)))
 | 
			
		||||
#define rbnode_fixup           libcdsb_rbtree_node_fixup
 | 
			
		||||
#define rbnode_delete          libcdsb_rbtree_node_delete
 | 
			
		||||
 | 
			
		||||
#define rbiter_init  libcdsb_rbtree_iter_init
 | 
			
		||||
#define rbiter_next  libcdsb_rbtree_iter_next
 | 
			
		||||
#define rbiter_reset libcdsb_rbtree_iter_reset
 | 
			
		||||
 | 
			
		||||
#define rbnode_is_empty(n) ((n) == rbnode_empty)
 | 
			
		||||
#define rbnode_is_root(n)  rbnode_is_empty((n)->parent)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										194
									
								
								src/rbtree.c
									
									
									
									
									
								
							
							
						
						
									
										194
									
								
								src/rbtree.c
									
									
									
									
									
								
							@ -3,9 +3,6 @@
 | 
			
		||||
 | 
			
		||||
#include "__internal/rbtree.h"
 | 
			
		||||
 | 
			
		||||
#define RBI_BREAK ((rbiter_f)3)
 | 
			
		||||
#define RBI_FIRST ((rbiter_f)8)
 | 
			
		||||
 | 
			
		||||
typedef enum libcdsb_rbtree_node_direction {
 | 
			
		||||
    RBD_LEFT  = 1,
 | 
			
		||||
    RBD_RIGHT = 2
 | 
			
		||||
@ -16,7 +13,7 @@ typedef enum libcdsb_rbtree_node_direction {
 | 
			
		||||
 | 
			
		||||
/*#####################################################################################################################*/
 | 
			
		||||
 | 
			
		||||
const rbnode_t LIBCDSB_RBTREE_NODE_EMPTY[1] = {{
 | 
			
		||||
rbnode_t LIBCDSB_RBTREE_NODE_EMPTY[1] = {{
 | 
			
		||||
   .colored = 0,
 | 
			
		||||
   .value   = 0,
 | 
			
		||||
   .parent  = rbnode_empty,
 | 
			
		||||
@ -45,105 +42,12 @@ static inline void rotate(rbnode_t **x, rbnode_t *c, rbdir_t d) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void replace(rbnode_t** x, rbnode_t* c, rbnode_t* n) {
 | 
			
		||||
    rbnode_t* p;
 | 
			
		||||
 | 
			
		||||
    p = c->parent;
 | 
			
		||||
 | 
			
		||||
    if (!rbnode_is_empty(p)) {
 | 
			
		||||
        if (p->left == c) {
 | 
			
		||||
            p->left = n;
 | 
			
		||||
        } else p->right = n;
 | 
			
		||||
    if (!rbnode_is_root(c)) {
 | 
			
		||||
        if (c->parent->left == c) {
 | 
			
		||||
            c->parent->left = n;
 | 
			
		||||
        } else c->parent->right = n;
 | 
			
		||||
    } else *x = n;
 | 
			
		||||
 | 
			
		||||
    n->parent = p;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*#####################################################################################################################*/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static rbnode_t* inorder_next(rbnode_t* c, rbiter_f f) {
 | 
			
		||||
    rbdir_t d = (f&RBI_REVERSE) ? RBD_RIGHT : RBD_LEFT;
 | 
			
		||||
    rbnode_t*   p;
 | 
			
		||||
 | 
			
		||||
    for (;;) {
 | 
			
		||||
        if (rbnode_is_empty(rbdir_inv(c, d))) {
 | 
			
		||||
            p = c->parent;
 | 
			
		||||
 | 
			
		||||
            if (rbnode_is_root(p) || rbdir_dir(p, d) == c) {
 | 
			
		||||
                return p;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            c = p;
 | 
			
		||||
            p = c->parent;
 | 
			
		||||
 | 
			
		||||
            if (rbnode_is_root(p) || rbdir_dir(p, d) == c) {
 | 
			
		||||
                return p;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            do {
 | 
			
		||||
                c = p;
 | 
			
		||||
                p = c->parent;
 | 
			
		||||
            } while(rbdir_inv(p, d) == c);
 | 
			
		||||
 | 
			
		||||
            c = p;
 | 
			
		||||
 | 
			
		||||
        } else { c = rbdir_inv(c, d); break; }
 | 
			
		||||
 | 
			
		||||
        if (rbnode_is_root(c)) return c;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    while (!rbnode_is_empty(rbdir_dir(c, d)))
 | 
			
		||||
        c = rbdir_dir(c, d);
 | 
			
		||||
 | 
			
		||||
    return c;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static rbnode_t* postorder_next(rbnode_t* c, rbiter_f f) {
 | 
			
		||||
    rbdir_t d = (f&RBI_REVERSE) ? RBD_RIGHT : RBD_LEFT;
 | 
			
		||||
    rbnode_t*   p;
 | 
			
		||||
 | 
			
		||||
    if (rbnode_is_empty(p = c->parent))
 | 
			
		||||
        return c;
 | 
			
		||||
 | 
			
		||||
    if (rbdir_dir(p, d) == c && !rbnode_is_empty(rbdir_inv(p, d))) {
 | 
			
		||||
        c = rbdir_inv(p, d);
 | 
			
		||||
 | 
			
		||||
        while (!rbnode_is_empty(c)) {
 | 
			
		||||
            p = c;
 | 
			
		||||
            c = (!rbnode_is_empty(rbdir_inv(p, d)))
 | 
			
		||||
                ? rbdir_inv(p, d)
 | 
			
		||||
                : rbdir_dir(p, d);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return p;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static rbnode_t* preorder_next(rbnode_t* c, rbiter_f f) {
 | 
			
		||||
    rbdir_t d = (f&RBI_REVERSE) ? RBD_RIGHT : RBD_LEFT;
 | 
			
		||||
    rbnode_t*   p;
 | 
			
		||||
 | 
			
		||||
    if (!rbnode_is_empty(rbdir_dir(c, d)))
 | 
			
		||||
        return rbdir_dir(c, d);
 | 
			
		||||
 | 
			
		||||
    for (;;) {
 | 
			
		||||
        if (!rbnode_is_empty(rbdir_inv(c, d))) {
 | 
			
		||||
            return rbdir_inv(c, d);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        p = c->parent;
 | 
			
		||||
 | 
			
		||||
        while (rbdir_inv(p, d) == c) {
 | 
			
		||||
            c = p;
 | 
			
		||||
            p = c->parent;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (rbnode_is_empty(p))
 | 
			
		||||
            return c;
 | 
			
		||||
 | 
			
		||||
        c = p;
 | 
			
		||||
    }
 | 
			
		||||
    n->parent = c->parent;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -290,89 +194,3 @@ void* libcdsb_rbtree_node_create(void* v, rbnode_t* p, int c, int n) {
 | 
			
		||||
 | 
			
		||||
    return x;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*#####################################################################################################################*/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
_Bool libcdsb_rbtree_iter_init(rbiter_t* iter, rbnode_t *const *root, rbiter_f f) {
 | 
			
		||||
    rbdir_t   d = (f&RBI_REVERSE) ? RBD_RIGHT : RBD_LEFT;
 | 
			
		||||
    rbnode_t* c = *root;
 | 
			
		||||
 | 
			
		||||
    if (!rbnode_is_empty(c)) {
 | 
			
		||||
        if (!(f&RBI_BREAK)) {
 | 
			
		||||
            while (rbdir_dir(c, d) != rbnode_empty) {
 | 
			
		||||
                c = rbdir_dir(c, d);
 | 
			
		||||
            }
 | 
			
		||||
        } else if ((f&RBI_BREAK) == RBI_POSTORDER) {
 | 
			
		||||
            rbnode_t* p;
 | 
			
		||||
 | 
			
		||||
            do {
 | 
			
		||||
                p = c;
 | 
			
		||||
                c = (!rbnode_is_empty(rbdir_dir(c, d))) ? rbdir_dir(c, d) : rbdir_inv(c, d);
 | 
			
		||||
            } while (!rbnode_is_empty(c));
 | 
			
		||||
 | 
			
		||||
            c = p;
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        iter->cursor = rbnode_empty;
 | 
			
		||||
        iter->flags  = 0;
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    iter->cursor = c;
 | 
			
		||||
    iter->flags  = f|RBI_FIRST;
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void libcdsb_rbtree_iter_reset(rbiter_t* iter) {
 | 
			
		||||
    if (iter->flags&RBI_FIRST) return;
 | 
			
		||||
 | 
			
		||||
    while (!rbnode_is_empty(iter->cursor->parent)) {
 | 
			
		||||
        iter->cursor = iter->cursor->parent;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if ((iter->flags&RBI_BREAK) == RBI_BREAK) {
 | 
			
		||||
        libcdsb_rbtree_iter_init(iter, &iter->cursor, iter->flags&~RBI_BREAK);
 | 
			
		||||
    } else libcdsb_rbtree_iter_init(iter, &iter->cursor, iter->flags);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
rbnode_t* libcdsb_rbtree_iter_next(rbiter_t* iter) {
 | 
			
		||||
 | 
			
		||||
    rbnode_t* c;
 | 
			
		||||
 | 
			
		||||
    c = iter->cursor;
 | 
			
		||||
 | 
			
		||||
    if (rbnode_is_empty(c))
 | 
			
		||||
        return rbnode_empty;
 | 
			
		||||
 | 
			
		||||
    if (!(iter->flags&RBI_FIRST)) {
 | 
			
		||||
        if (rbnode_is_root(c)) {
 | 
			
		||||
            if ((iter->flags&RBI_BREAK) == RBI_INORDER) {
 | 
			
		||||
                iter->flags |= RBI_BREAK;
 | 
			
		||||
            } else {
 | 
			
		||||
                libcdsb_rbtree_iter_reset(iter);
 | 
			
		||||
                if (iter->flags&RBI_POSTORDER) {
 | 
			
		||||
                    iter->flags |= RBI_BREAK;
 | 
			
		||||
                    return c;
 | 
			
		||||
                } else return rbnode_empty;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    } else if ((iter->flags&RBI_BREAK) == RBI_BREAK) {
 | 
			
		||||
        iter->flags = (iter->flags&~(RBI_BREAK^RBI_POSTORDER));
 | 
			
		||||
        return rbnode_empty;
 | 
			
		||||
    } else iter->flags &= ~RBI_FIRST;
 | 
			
		||||
 | 
			
		||||
    switch (iter->flags&RBI_BREAK) {
 | 
			
		||||
        case RBI_POSTORDER: iter->cursor = postorder_next(c, iter->flags); break;
 | 
			
		||||
        case  RBI_PREORDER: iter->cursor =  preorder_next(c, iter->flags); break;
 | 
			
		||||
        case   RBI_INORDER:
 | 
			
		||||
                   default: iter->cursor =   inorder_next(c, iter->flags); break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return c;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user