/* * Copyright (C) 2012 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * */ typedef enum rbcolour_e { C_BLACK = 0, C_RED = 1 } rbcolour_t; #define RBI_LINK(_n, _t) \ struct _n##_rb_link { \ struct _t *left; \ struct _t *right; \ struct _t *parent; \ rbcolour_t colour; \ } #define RBI_HEAD(_n, _t) \ struct _n##_rb_head { \ struct _t top; \ int count; \ int (* compare)(struct _t *, struct _t *); \ } #define RBI_CODE(_n, _t, _f, _cmp) \ \ typedef void (*_n##_rb_walker_t)(_t *, void *); \ \ _t * _n##_rb_delete(struct _n##_rb_head *, _t *); \ void _n##_rb_init(struct _n##_rb_head *); \ void _n##_rb_insert(struct _n##_rb_head *, _t *); \ _t * _n##_rb_search(struct _n##_rb_head *, void *); \ void _n##_rb_walktree(struct _n##_rb_head *, _n##_rb_walker_t, void *);\ \ static void \ rotate_left(struct _n##_rb_head *head, _t *node) \ { \ _t *parent, *tmp1, *tmp2; \ \ parent = node->_f.parent; \ tmp1 = node->_f.right; \ tmp2 = tmp1->_f.left; \ node->_f.right = tmp2; \ if (tmp2 != & _n##_rb_zero) \ tmp2->_f.parent = node; \ if (parent == & _n##_rb_zero) \ head->top._f.right = tmp1; \ else if (parent->_f.right == node) \ parent->_f.right = tmp1; \ else \ parent->_f.left = tmp1; \ tmp1->_f.left = node; \ tmp1->_f.parent = parent; \ node->_f.parent = tmp1; \ } \ \ static void \ rotate_right(struct _n##_rb_head *head, _t *node) \ { \ _t *parent, *tmp1, *tmp2; \ \ parent = node->_f.parent; \ tmp1 = node->_f.left; \ tmp2 = tmp1->_f.right; \ node->_f.left = tmp2; \ if (tmp2 != &_n##_rb_zero) \ tmp2->_f.parent = node; \ if (parent == &_n##_rb_zero) \ head->top._f.right = tmp1; \ else if (parent->_f.right == node) \ parent->_f.right = tmp1; \ else \ parent->_f.left = tmp1; \ tmp1->_f.right = node; \ tmp1->_f.parent = parent; \ node->_f.parent = tmp1; \ } \ \ void \ _n##_rb_insert(struct _n##_rb_head *head, _t *node) \ { \ _t *n, *parent, **p, *tmp1, *gparent; \ \ parent = &head->top; \ node->_f.left = &_n##_rb_zero; \ node->_f.right = &_n##_rb_zero; \ p = &head->top._f.right; \ while ((n = *p) != &_n##_rb_zero) { \ if (_cmp(node, n) < 0) \ p = &n->_f.left; \ else \ p = &n->_f.right; \ parent = n; \ } \ *p = node; \ node->_f.colour = C_RED; \ node->_f.parent = parent; \ \ while ((node != &_n##_rb_zero) && (parent->_f.colour == C_RED)){\ gparent = parent->_f.parent; \ if (parent == gparent->_f.left) { \ tmp1 = gparent->_f.right; \ if (tmp1->_f.colour == C_RED) { \ parent->_f.colour = C_BLACK; \ tmp1->_f.colour = C_BLACK; \ gparent->_f.colour = C_RED; \ node = gparent; \ } else { \ if (node == parent->_f.right) { \ node = parent; \ rotate_left(head, node); \ parent = node->_f.parent; \ } \ parent->_f.colour = C_BLACK; \ gparent->_f.colour = C_RED; \ rotate_right(head, gparent); \ } \ } else { \ tmp1 = gparent->_f.left; \ if (tmp1->_f.colour == C_RED) { \ parent->_f.colour = C_BLACK; \ tmp1->_f.colour = C_BLACK; \ gparent->_f.colour = C_RED; \ node = gparent; \ } else { \ if (node == parent->_f.left) { \ node = parent; \ rotate_right(head, node); \ parent = node->_f.parent; \ } \ parent->_f.colour = C_BLACK; \ gparent->_f.colour = C_RED; \ rotate_left(head, parent->_f.parent); \ } \ } \ parent = node->_f.parent; \ } \ head->top._f.right->_f.colour = C_BLACK; \ head->count++; \ } \ \ static void \ deleteblack(struct _n##_rb_head *head, _t *parent, _t *node) \ { \ _t *tmp; \ \ while ((node == &_n##_rb_zero || node->_f.colour == C_BLACK) && \ node != &head->top) { \ if (parent->_f.left == node) { \ tmp = parent->_f.right; \ if (tmp->_f.colour == C_RED) { \ tmp->_f.colour = C_BLACK; \ parent->_f.colour = C_RED; \ rotate_left(head, parent); \ tmp = parent->_f.right; \ } \ if ((tmp->_f.left == &_n##_rb_zero || \ tmp->_f.left->_f.colour == C_BLACK) && \ (tmp->_f.right == &_n##_rb_zero || \ tmp->_f.right->_f.colour == C_BLACK)) { \ tmp->_f.colour = C_RED; \ node = parent; \ parent = node->_f.parent; \ } else { \ if (tmp->_f.right == &_n##_rb_zero || \ tmp->_f.right->_f.colour == C_BLACK) {\ _t *tmp2 = tmp->_f.left; \ \ if (tmp2 != &_n##_rb_zero) \ tmp2->_f.colour = C_BLACK;\ tmp->_f.colour = C_RED; \ rotate_right(head, tmp); \ tmp = parent->_f.right; \ } \ tmp->_f.colour = parent->_f.colour; \ parent->_f.colour = C_BLACK; \ if (tmp->_f.right != &_n##_rb_zero) \ tmp->_f.right->_f.colour = C_BLACK;\ rotate_left(head, parent); \ node = head->top._f.right; \ } \ } else { \ tmp = parent->_f.left; \ if (tmp->_f.colour == C_RED) { \ tmp->_f.colour = C_BLACK; \ parent->_f.colour = C_RED; \ rotate_right(head, parent); \ tmp = parent->_f.left; \ } \ if ((tmp->_f.left == &_n##_rb_zero || \ tmp->_f.left->_f.colour == C_BLACK) && \ (tmp->_f.right == &_n##_rb_zero || \ tmp->_f.right->_f.colour == C_BLACK)) { \ tmp->_f.colour = C_RED; \ node = parent; \ parent = node->_f.parent; \ } else { \ if (tmp->_f.left == &_n##_rb_zero || \ tmp->_f.left->_f.colour == C_BLACK) {\ _t *tmp2 = tmp->_f.right; \ \ if (tmp2 != &_n##_rb_zero) \ tmp2->_f.colour = C_BLACK;\ tmp->_f.colour = C_RED; \ rotate_left(head, tmp); \ tmp = parent->_f.left; \ } \ tmp->_f.colour = parent->_f.colour; \ parent->_f.colour = C_BLACK; \ if (tmp->_f.left != &_n##_rb_zero) \ tmp->_f.left->_f.colour = C_BLACK;\ rotate_right(head, parent); \ node = head->top._f.right; \ break; \ } \ } \ } \ if (node != &_n##_rb_zero) \ node->_f.colour = C_BLACK; \ } \ \ _t * \ _n##_rb_delete(struct _n##_rb_head *head, _t *node) \ { \ _t *child, *parent, *old = node, *left; \ rbcolour_t color; \ \ if (node->_f.left == &_n##_rb_zero) { \ child = node->_f.right; \ } else if (node->_f.right == &_n##_rb_zero) { \ child = node->_f.left; \ } else { \ node = node->_f.right; \ while ((left = node->_f.left) != &_n##_rb_zero) \ node = left; \ child = node->_f.right; \ parent = node->_f.parent; \ color = node->_f.colour; \ if (child != &_n##_rb_zero) \ child->_f.parent = parent; \ if (parent != &_n##_rb_zero) { \ if (parent->_f.left == node) \ parent->_f.left = child; \ else \ parent->_f.right = child; \ } else { \ head->top._f.right = child; \ } \ if (node->_f.parent == old) \ parent = node; \ *node = *old; \ if (old->_f.parent != &_n##_rb_zero) { \ if (old->_f.parent->_f.left == old) \ old->_f.parent->_f.left = node; \ else \ old->_f.parent->_f.right = node; \ } else { \ head->top._f.right = child; \ } \ old->_f.left->_f.parent = node; \ if (old->_f.right != &_n##_rb_zero) \ old->_f.right->_f.parent = node; \ if (parent != &_n##_rb_zero) { \ left = parent; \ } \ goto colour; \ } \ parent = node->_f.parent; \ color= node->_f.colour; \ if (child != &_n##_rb_zero) \ child->_f.parent = parent; \ if (parent != &_n##_rb_zero) { \ if (parent->_f.left == node) \ parent->_f.left = child; \ else \ parent->_f.right = child; \ } else { \ head->top._f.right = child; \ } \ colour: \ if (color == C_BLACK) \ deleteblack(head, parent, node); \ head->count--; \ return old; \ } \ \ void \ _n##_rb_init(struct _n##_rb_head *head) \ { \ memset(head, 0, sizeof(*head)); \ memset(&_n##_rb_zero, 0, sizeof(_n##_rb_zero)); \ head->top._f.left = &_n##_rb_zero; \ head->top._f.right = &_n##_rb_zero; \ head->top._f.parent = &head->top; \ _n##_rb_zero._f.left = &_n##_rb_zero; \ _n##_rb_zero._f.right = &_n##_rb_zero; \ _n##_rb_zero._f.parent = &_n##_rb_zero; \ } \ \ void \ _n##_rb_walktree(struct _n##_rb_head *head, _n##_rb_walker_t func, void *arg)\ { \ _t *prev; \ _t *next; \ _t *node = head->top._f.right; \ _t *base; \ \ while (node != &_n##_rb_zero) \ node = node->_f.left; \ \ for (;;) { \ base = node; \ prev = node; \ while ((node->_f.parent->_f.right == node) && \ (node != &_n##_rb_zero)) { \ prev = node; \ node = node->_f.parent; \ } \ \ node = prev; \ for (node = node->_f.parent->_f.right; node != &_n##_rb_zero;\ node = node->_f.left) \ prev = node; \ next = prev; \ \ if (node != &_n##_rb_zero) \ func(node, arg); \ \ node = next; \ if (node == &_n##_rb_zero) \ break; \ } \ } \ \ _t * \ _n##_rb_search(struct _n##_rb_head *head, void *key) \ { \ int match; \ _t *node; \ node = head->top._f.right; \ while (node != &_n##_rb_zero) { \ match = _cmp(key, node); \ if (match == 0) \ break; \ if (match< 0) \ node = node->_f.left; \ else \ node = node->_f.right; \ } \ if (node == &_n##_rb_zero || match != 0) \ return (NULL); \ return (node); \ } #define RBI_DELETE(_n, _h, _v) _n##_rb_delete(_h, _v) #define RBI_FIELD(_n) struct _n##_rb_link #define RBI_INIT(_n, _h) _n##_rb_init(_h) #define RBI_INSERT(_n, _h, _v) _n##_rb_insert(_h, _v) #define RBI_ISEMPTY(_h) ((_h)->count == 0) #define RBI_SEARCH(_n, _h, _k) _n##_rb_search(_h, _k) #define RBI_WALK(_n, _h, _w, _a) _n##_rb_walktree(_h, _w, _a) #define RBI_ZERO(_n) _n##_rb_zero