/* This software is licensed by the MIT License, see LICENSE file */ /* Copyright © 2022 Gregory Lirent */ #include "__internal/rbtree.h" /*#####################################################################################################################*/ static rbnode_t* rbnode_duplicate(const rbnode_t* s, rbnode_t* p, const vtype* info) { return rbnode_create(vnode_duplicate(&s->value, (info) ? *info : VTYPE_POINTER), p, s->colored); } static int rbnode_compare(const rbnode_t* s0, const rbnode_t* s1, vtype* tp) { vtype t = !is_null(tp) ? *tp : VTYPE_POINTER; return vnode_compare(s0->value, t, s1->value, t); } static hash_t rbnode_hash(const rbnode_t* s, vtype* tp) { vtype t = (!is_null(tp)) ? *tp : VTYPE_POINTER; return vnode_hash(s->value, t); } static void rbnode_free(rbnode_t* x, vtype *t) { if (!is_null(t)) vnode_free(&x->value, *t); } /*#####################################################################################################################*/ hash_t libcdsb_rbtree_hash(const void* s, hash_t (*node_hash)(const void* s, void* info), void* info) { rbnode_t *c0, *c1; hash_t hash, v; stack_t z; if (rbnode_is_empty(s)) return 0; if (is_null(node_hash)) node_hash = (void*)rbnode_hash; z.prev = 0; hash = 1; c1 = (void*)s; if (!rbnode_is_empty(z.value = c1->left)) do { c0 = stack_pop(&z); ++hash; if (!rbnode_is_empty(c0->left)) stack_push(&z, c1 = c0->left); if (!rbnode_is_empty(c0->right)) stack_push(&z, c0->right); } while (!is_null(z.value)); v = node_hash(c1, info); c1 = (void*)s; if (!rbnode_is_empty(z.value = c1->right)) do { c0 = stack_pop(&z); ++hash; if (!rbnode_is_empty(c0->left)) stack_push(&z, c1 = c0->left); if (!rbnode_is_empty(c0->right)) stack_push(&z, c0->right); } while (!is_null(z.value)); v += node_hash(c1, info); return hash ^ v; } /*#####################################################################################################################*/ void* libcdsb_rbtree_duplicate(const rbnode_t* s, void* (*node_duplicate)(void* src, void* parent, void* info), void* info) { rbnode_t *p0, *p1, *x; stack_t z; z.prev = 0; z.value = (void*)s; if (is_null(node_duplicate)) { node_duplicate = (void*)rbnode_duplicate; } if (!rbnode_is_empty(s)) { x = node_duplicate(z.value, rbnode_empty, info); stack_push(&z, x); do { p0 = stack_pop(&z); p1 = stack_pop(&z); if (!rbnode_is_empty(p1->left)) { p0->left = node_duplicate(p1->left, p0, info); stack_push(&z, p1->left); stack_push(&z, p0->left); } if (!rbnode_is_empty(p1->right)) { p0->right = node_duplicate(p1->right, p0, info); stack_push(&z, p1->right); stack_push(&z, p0->right); } } while (!is_null(z.value)); } else x = rbnode_empty; return x; } /*#####################################################################################################################*/ int libcdsb_rbtree_compare(const rbnode_t* s0, const rbnode_t* s1, int (*node_compare)(const rbnode_t* s0, const rbnode_t* s1, void* info), void* info) { rbnode_t *c0, *c1; stack_t z; int c = 0; if (s0 == s1) return 0; if (is_null(node_compare)) node_compare = (void*)rbnode_compare; z.prev = 0; z.value = 0; stack_push(&z, (void*)s1); stack_push(&z, (void*)s0); do { c0 = stack_pop(&z); c1 = stack_pop(&z); if (rbnode_is_empty(c0) || rbnode_is_empty(c1)) { if (c0 != c1) { stack_flush(&z); return rbnode_is_empty(c0) ? -1 : 1; } } else if ((c = node_compare(c0, c1, info))) { if (c0->left == c1->right) { // <-- rbnode_empty c = node_compare(c0->right, c1, info); if (!c) c = node_compare(c0, c1->left, info); } else if (c0->right == c1->left) { // <-- rbnode_empty c = node_compare(c0, c1->right, info); if (!c) c = node_compare(c0->left, c1, info); } if (c) { stack_flush(&z); return c; } } else { stack_push(&z, c1->right); stack_push(&z, c0->right); stack_push(&z, c1->left); stack_push(&z, c0->left); } } while (!is_null(z.value)); return 0; } size_t libcdsb_rbtree_size(const void* s) { stack_t z = { .prev = 0, .value = (void*)s }; size_t n = 0; rbnode_t* c; if (!rbnode_is_empty(s)) { while ((c = stack_pop(&z))) { ++n; if (!rbnode_is_empty(c->left)) stack_push(&z, c->left); if (!rbnode_is_empty(c->right)) stack_push(&z, c->right); } } return n; } void libcdsb_rbtree_free(void* x, void (*node_free)(void* x, void* info), void* info) { rbnode_t *t, *c; c = x; if (is_null(node_free)) node_free = (void*)rbnode_free; while (!rbnode_is_empty(x)) { if (!rbnode_is_empty(c->left)) { c = c->left; } else if (!rbnode_is_empty(c->right)) { c = c->right; } else if (!rbnode_is_root(c)) { node_free(c, info); t = c; c = c->parent; if (t == c->left) c->left = rbnode_empty; else c->right = rbnode_empty; free(t); } else { node_free(c, info); x = rbnode_empty; } } }