diff --git a/stix/lib/bigint.c b/stix/lib/bigint.c index a64457a..c900e8e 100644 --- a/stix/lib/bigint.c +++ b/stix/lib/bigint.c @@ -61,19 +61,6 @@ static STIX_INLINE stix_oop_t make_bigint_with_ooi (stix_t* stix, stix_ooi_t i) } } -static STIX_INLINE stix_oow_t count_effective_digits (stix_oop_t oop) -{ - stix_oow_t i; - - for (i = STIX_OBJ_GET_SIZE(oop); i > 1; ) - { - --i; - if (((stix_oop_halfword_t)oop)->slot[i] != 0) return i + 1; - } - - return 1; -} - static STIX_INLINE stix_oop_t clone_bigint (stix_t* stix, stix_oop_t oop, stix_oow_t count) { stix_oop_t z; @@ -94,6 +81,19 @@ static STIX_INLINE stix_oop_t clone_bigint (stix_t* stix, stix_oop_t oop, stix_o return z; } +static STIX_INLINE stix_oow_t count_effective_digits (stix_oop_t oop) +{ + stix_oow_t i; + + for (i = STIX_OBJ_GET_SIZE(oop); i > 1; ) + { + --i; + if (((stix_oop_halfword_t)oop)->slot[i] != 0) return i + 1; + } + + return 1; +} + static stix_oop_t normalize_bigint (stix_t* stix, stix_oop_t oop) { stix_oow_t count; diff --git a/stix/lib/mod-snd.c b/stix/lib/mod-snd.c new file mode 100644 index 0000000..94f1b3b --- /dev/null +++ b/stix/lib/mod-snd.c @@ -0,0 +1,121 @@ +/* + * $Id$ + * + Copyright (c) 2014-2015 Chung, Hyung-Hwan. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include "mod-snd.h" +#include + +/* ------------------------------------------------------------------------ */ + +/* TODO: don't use these macros... */ +#define ACTIVE_STACK_PUSH(stix,v) \ + do { \ + (stix)->sp = (stix)->sp + 1; \ + (stix)->active_context->slot[(stix)->sp] = v; \ + } while (0) + +#define ACTIVE_STACK_POP(stix) ((stix)->sp = (stix)->sp - 1) +#define ACTIVE_STACK_UNPOP(stix) ((stix)->sp = (stix)->sp + 1) +#define ACTIVE_STACK_POPS(stix,count) ((stix)->sp = (stix)->sp - (count)) + +#define ACTIVE_STACK_GET(stix,v_sp) ((stix)->active_context->slot[v_sp]) +#define ACTIVE_STACK_SET(stix,v_sp,v_obj) ((stix)->active_context->slot[v_sp] = v_obj) +#define ACTIVE_STACK_GETTOP(stix) ACTIVE_STACK_GET(stix, (stix)->sp) +#define ACTIVE_STACK_SETTOP(stix,v_obj) ACTIVE_STACK_SET(stix, (stix)->sp, v_obj) + + + +static int prim_open (stix_t* stix, stix_ooi_t nargs) +{ +printf ("<<<<<<<<<<>>>>>>>>>>>>>>>>>\n"); + ACTIVE_STACK_POPS (stix, nargs); + return 1; +} + +static int prim_close (stix_t* stix, stix_ooi_t nargs) +{ +printf ("<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>\n"); + ACTIVE_STACK_POPS (stix, nargs); + return 1; +} + +typedef struct fnctab_t fnctab_t; +struct fnctab_t +{ + const stix_bch_t* name; + stix_prim_impl_t handler; +}; + +static fnctab_t fnctab[] = +{ + { "close", prim_close }, + { "open", prim_open } +}; + + +/* ------------------------------------------------------------------------ */ + +static stix_prim_impl_t query (stix_t* stix, stix_prim_mod_t* mod, const stix_ooch_t* name) +{ + int left, right, mid, n; + + left = 0; right = STIX_COUNTOF(fnctab) - 1; + + while (left <= right) + { + mid = (left + right) / 2; + + n = stix_compoocbcstr (name, fnctab[mid].name); + if (n < 0) right = mid - 1; + else if (n > 0) left = mid + 1; + else + { + return fnctab[mid].handler; + } + } + + +/* + ea.ptr = (stix_char_t*)name; + ea.len = stix_strlen(name); + stix_seterror (stix, STIX_ENOENT, &ea, QSE_NULL); +*/ + return STIX_NULL; +} + + +static void unload (stix_t* stix, stix_prim_mod_t* mod) +{ +} + + +int stix_prim_mod_snd (stix_t* stix, stix_prim_mod_t* mod) +{ + mod->query = query; + mod->unload = unload; + mod->ctx = STIX_NULL; + return 0; +} diff --git a/stix/lib/mod-snd.h b/stix/lib/mod-snd.h new file mode 100644 index 0000000..246fb6f --- /dev/null +++ b/stix/lib/mod-snd.h @@ -0,0 +1,43 @@ +/* + * $Id$ + * + Copyright (c) 2006-2014 Chung, Hyung-Hwan. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _STIX_LIB_MOD_SND_H_ +#define _STIX_LIB_MOD_SND_H_ + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +STIX_EXPORT int stix_prim_mod_snd (stix_t* stix, stix_prim_mod_t* mod); + +#if defined(__cplusplus) +} +#endif + +#endif + diff --git a/stix/lib/stix-rbt.c b/stix/lib/stix-rbt.c new file mode 100644 index 0000000..7b33982 --- /dev/null +++ b/stix/lib/stix-rbt.c @@ -0,0 +1,1002 @@ +/* + * $Id$ + * + Copyright (c) 2014-2015 Chung, Hyung-Hwan. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "stix-rbt.h" +#include "stix-prv.h" + +#define copier_t stix_rbt_copier_t +#define freeer_t stix_rbt_freeer_t +#define comper_t stix_rbt_comper_t +#define keeper_t stix_rbt_keeper_t +#define walker_t stix_rbt_walker_t +#define cbserter_t stix_rbt_cbserter_t + +#define KPTR(p) STIX_RBT_KPTR(p) +#define KLEN(p) STIX_RBT_KLEN(p) +#define VPTR(p) STIX_RBT_VPTR(p) +#define VLEN(p) STIX_RBT_VLEN(p) + +#define KTOB(rbt,len) ((len)*(rbt)->scale[STIX_RBT_KEY]) +#define VTOB(rbt,len) ((len)*(rbt)->scale[STIX_RBT_VAL]) + +#define UPSERT 1 +#define UPDATE 2 +#define ENSERT 3 +#define INSERT 4 + +#define IS_NIL(rbt,x) ((x) == &((rbt)->xnil)) +#define LEFT 0 +#define RIGHT 1 +#define left child[LEFT] +#define right child[RIGHT] +#define rotate_left(rbt,pivot) rotate(rbt,pivot,1); +#define rotate_right(rbt,pivot) rotate(rbt,pivot,0); + +STIX_INLINE stix_rbt_pair_t* stix_rbt_allocpair ( + stix_rbt_t* rbt, void* kptr, stix_size_t klen, void* vptr, stix_size_t vlen) +{ + stix_rbt_pair_t* n; + + copier_t kcop = rbt->style->copier[STIX_RBT_KEY]; + copier_t vcop = rbt->style->copier[STIX_RBT_VAL]; + + stix_size_t as = STIX_SIZEOF(stix_rbt_pair_t); + if (kcop == STIX_RBT_COPIER_INLINE) as += KTOB(rbt,klen); + if (vcop == STIX_RBT_COPIER_INLINE) as += VTOB(rbt,vlen); + + n = (stix_rbt_pair_t*) STIX_MMGR_ALLOC (rbt->mmgr, as); + if (n == STIX_NULL) return STIX_NULL; + + n->color = STIX_RBT_RED; + n->parent = STIX_NULL; + n->child[LEFT] = &rbt->xnil; + n->child[RIGHT] = &rbt->xnil; + + KLEN(n) = klen; + if (kcop == STIX_RBT_COPIER_SIMPLE) + { + KPTR(n) = kptr; + } + else if (kcop == STIX_RBT_COPIER_INLINE) + { + KPTR(n) = n + 1; + if (kptr) STIX_MEMCPY (KPTR(n), kptr, KTOB(rbt,klen)); + } + else + { + KPTR(n) = kcop (rbt, kptr, klen); + if (KPTR(n) == STIX_NULL) + { + STIX_MMGR_FREE (rbt->mmgr, n); + return STIX_NULL; + } + } + + VLEN(n) = vlen; + if (vcop == STIX_RBT_COPIER_SIMPLE) + { + VPTR(n) = vptr; + } + else if (vcop == STIX_RBT_COPIER_INLINE) + { + VPTR(n) = n + 1; + if (kcop == STIX_RBT_COPIER_INLINE) + VPTR(n) = (stix_oob_t*)VPTR(n) + KTOB(rbt,klen); + if (vptr) STIX_MEMCPY (VPTR(n), vptr, VTOB(rbt,vlen)); + } + else + { + VPTR(n) = vcop (rbt, vptr, vlen); + if (VPTR(n) != STIX_NULL) + { + if (rbt->style->freeer[STIX_RBT_KEY] != STIX_NULL) + rbt->style->freeer[STIX_RBT_KEY] (rbt, KPTR(n), KLEN(n)); + STIX_MMGR_FREE (rbt->mmgr, n); + return STIX_NULL; + } + } + + return n; +} + +STIX_INLINE void stix_rbt_freepair (stix_rbt_t* rbt, stix_rbt_pair_t* pair) +{ + if (rbt->style->freeer[STIX_RBT_KEY] != STIX_NULL) + rbt->style->freeer[STIX_RBT_KEY] (rbt, KPTR(pair), KLEN(pair)); + if (rbt->style->freeer[STIX_RBT_VAL] != STIX_NULL) + rbt->style->freeer[STIX_RBT_VAL] (rbt, VPTR(pair), VLEN(pair)); + STIX_MMGR_FREE (rbt->mmgr, pair); +} + +static stix_rbt_style_t style[] = +{ + { + { + STIX_RBT_COPIER_DEFAULT, + STIX_RBT_COPIER_DEFAULT + }, + { + STIX_RBT_FREEER_DEFAULT, + STIX_RBT_FREEER_DEFAULT + }, + STIX_RBT_COMPER_DEFAULT, + STIX_RBT_KEEPER_DEFAULT + }, + + { + { + STIX_RBT_COPIER_INLINE, + STIX_RBT_COPIER_INLINE + }, + { + STIX_RBT_FREEER_DEFAULT, + STIX_RBT_FREEER_DEFAULT + }, + STIX_RBT_COMPER_DEFAULT, + STIX_RBT_KEEPER_DEFAULT + }, + + { + { + STIX_RBT_COPIER_INLINE, + STIX_RBT_COPIER_DEFAULT + }, + { + STIX_RBT_FREEER_DEFAULT, + STIX_RBT_FREEER_DEFAULT + }, + STIX_RBT_COMPER_DEFAULT, + STIX_RBT_KEEPER_DEFAULT + }, + + { + { + STIX_RBT_COPIER_DEFAULT, + STIX_RBT_COPIER_INLINE + }, + { + STIX_RBT_FREEER_DEFAULT, + STIX_RBT_FREEER_DEFAULT + }, + STIX_RBT_COMPER_DEFAULT, + STIX_RBT_KEEPER_DEFAULT + } +}; + +const stix_rbt_style_t* stix_getrbtstyle (stix_rbt_style_kind_t kind) +{ + return &style[kind]; +} + +stix_rbt_t* stix_rbt_open (stix_mmgr_t* mmgr, stix_size_t xtnsize, int kscale, int vscale) +{ + stix_rbt_t* rbt; + + rbt = (stix_rbt_t*) STIX_MMGR_ALLOC (mmgr, STIX_SIZEOF(stix_rbt_t) + xtnsize); + if (rbt == STIX_NULL) return STIX_NULL; + + if (stix_rbt_init (rbt, mmgr, kscale, vscale) <= -1) + { + STIX_MMGR_FREE (mmgr, rbt); + return STIX_NULL; + } + + STIX_MEMSET (rbt + 1, 0, xtnsize); + return rbt; +} + +void stix_rbt_close (stix_rbt_t* rbt) +{ + stix_rbt_fini (rbt); + STIX_MMGR_FREE (rbt->mmgr, rbt); +} + +int stix_rbt_init (stix_rbt_t* rbt, stix_mmgr_t* mmgr, int kscale, int vscale) +{ + /* do not zero out the extension */ + STIX_MEMSET (rbt, 0, STIX_SIZEOF(*rbt)); + rbt->mmgr = mmgr; + + rbt->scale[STIX_RBT_KEY] = (kscale < 1)? 1: kscale; + rbt->scale[STIX_RBT_VAL] = (vscale < 1)? 1: vscale; + rbt->size = 0; + + rbt->style = &style[0]; + + /* self-initializing nil */ + STIX_MEMSET(&rbt->xnil, 0, STIX_SIZEOF(rbt->xnil)); + rbt->xnil.color = STIX_RBT_BLACK; + rbt->xnil.left = &rbt->xnil; + rbt->xnil.right = &rbt->xnil; + + /* root is set to nil initially */ + rbt->root = &rbt->xnil; + + return 0; +} + +void stix_rbt_fini (stix_rbt_t* rbt) +{ + stix_rbt_clear (rbt); +} + +stix_mmgr_t* stix_rbt_getmmgr (stix_rbt_t* rbt) +{ + return rbt->mmgr; +} + +void* stix_rbt_getxtn (stix_rbt_t* rbt) +{ + return (void*)(rbt + 1); +} + +const stix_rbt_style_t* stix_rbt_getstyle (const stix_rbt_t* rbt) +{ + return rbt->style; +} + +void stix_rbt_setstyle (stix_rbt_t* rbt, const stix_rbt_style_t* style) +{ + STIX_ASSERT (style != STIX_NULL); + rbt->style = style; +} + +stix_size_t stix_rbt_getsize (const stix_rbt_t* rbt) +{ + return rbt->size; +} + +stix_rbt_pair_t* stix_rbt_search (const stix_rbt_t* rbt, const void* kptr, stix_size_t klen) +{ + stix_rbt_pair_t* pair = rbt->root; + + while (!IS_NIL(rbt,pair)) + { + int n = rbt->style->comper (rbt, kptr, klen, KPTR(pair), KLEN(pair)); + if (n == 0) return pair; + + if (n > 0) pair = pair->right; + else /* if (n < 0) */ pair = pair->left; + } + + return STIX_NULL; +} + +static void rotate (stix_rbt_t* rbt, stix_rbt_pair_t* pivot, int leftwise) +{ + /* + * == leftwise rotation + * move the pivot pair down to the poistion of the pivot's original + * left child(x). move the pivot's right child(y) to the pivot's original + * position. as 'c1' is between 'y' and 'pivot', move it to the right + * of the new pivot position. + * parent parent + * | | (left or right?) | | + * pivot y + * / \ / \ + * x y =====> pivot c2 + * / \ / \ + * c1 c2 x c1 + * + * == rightwise rotation + * move the pivot pair down to the poistion of the pivot's original + * right child(y). move the pivot's left child(x) to the pivot's original + * position. as 'c2' is between 'x' and 'pivot', move it to the left + * of the new pivot position. + * + * parent parent + * | | (left or right?) | | + * pivot x + * / \ / \ + * x y =====> c1 pivot + * / \ / \ + * c1 c2 c2 y + * + * + * the actual implementation here resolves the pivot's relationship to + * its parent by comparaing pointers as it is not known if the pivot pair + * is the left child or the right child of its parent, + */ + + stix_rbt_pair_t* parent, * z, * c; + int cid1, cid2; + + STIX_ASSERT (pivot != STIX_NULL); + + if (leftwise) + { + cid1 = RIGHT; + cid2 = LEFT; + } + else + { + cid1 = LEFT; + cid2 = RIGHT; + } + + parent = pivot->parent; + /* y for leftwise rotation, x for rightwise rotation */ + z = pivot->child[cid1]; + /* c1 for leftwise rotation, c2 for rightwise rotation */ + c = z->child[cid2]; + + z->parent = parent; + if (parent) + { + if (parent->left == pivot) + { + parent->left = z; + } + else + { + STIX_ASSERT (parent->right == pivot); + parent->right = z; + } + } + else + { + STIX_ASSERT (rbt->root == pivot); + rbt->root = z; + } + + z->child[cid2] = pivot; + if (!IS_NIL(rbt,pivot)) pivot->parent = z; + + pivot->child[cid1] = c; + if (!IS_NIL(rbt,c)) c->parent = pivot; +} + +static void adjust (stix_rbt_t* rbt, stix_rbt_pair_t* pair) +{ + while (pair != rbt->root) + { + stix_rbt_pair_t* tmp, * tmp2, * x_par; + int leftwise; + + x_par = pair->parent; + if (x_par->color == STIX_RBT_BLACK) break; + + STIX_ASSERT (x_par->parent != STIX_NULL); + + if (x_par == x_par->parent->child[LEFT]) + { + tmp = x_par->parent->child[RIGHT]; + tmp2 = x_par->child[RIGHT]; + leftwise = 1; + } + else + { + tmp = x_par->parent->child[LEFT]; + tmp2 = x_par->child[LEFT]; + leftwise = 0; + } + + if (tmp->color == STIX_RBT_RED) + { + x_par->color = STIX_RBT_BLACK; + tmp->color = STIX_RBT_BLACK; + x_par->parent->color = STIX_RBT_RED; + pair = x_par->parent; + } + else + { + if (pair == tmp2) + { + pair = x_par; + rotate (rbt, pair, leftwise); + x_par = pair->parent; + } + + x_par->color = STIX_RBT_BLACK; + x_par->parent->color = STIX_RBT_RED; + rotate (rbt, x_par->parent, !leftwise); + } + } +} + +static stix_rbt_pair_t* change_pair_val ( + stix_rbt_t* rbt, stix_rbt_pair_t* pair, void* vptr, stix_size_t vlen) +{ + if (VPTR(pair) == vptr && VLEN(pair) == vlen) + { + /* if the old value and the new value are the same, + * it just calls the handler for this condition. + * No value replacement occurs. */ + if (rbt->style->keeper != STIX_NULL) + { + rbt->style->keeper (rbt, vptr, vlen); + } + } + else + { + copier_t vcop = rbt->style->copier[STIX_RBT_VAL]; + void* ovptr = VPTR(pair); + stix_size_t ovlen = VLEN(pair); + + /* place the new value according to the copier */ + if (vcop == STIX_RBT_COPIER_SIMPLE) + { + VPTR(pair) = vptr; + VLEN(pair) = vlen; + } + else if (vcop == STIX_RBT_COPIER_INLINE) + { + if (ovlen == vlen) + { + if (vptr) STIX_MEMCPY (VPTR(pair), vptr, VTOB(rbt,vlen)); + } + else + { + /* need to reconstruct the pair */ + stix_rbt_pair_t* p = stix_rbt_allocpair (rbt, + KPTR(pair), KLEN(pair), + vptr, vlen); + if (p == STIX_NULL) return STIX_NULL; + + p->color = pair->color; + p->left = pair->left; + p->right = pair->right; + p->parent = pair->parent; + + if (pair->parent) + { + if (pair->parent->left == pair) + { + pair->parent->left = p; + } + else + { + STIX_ASSERT (pair->parent->right == pair); + pair->parent->right = p; + } + } + if (!IS_NIL(rbt,pair->left)) pair->left->parent = p; + if (!IS_NIL(rbt,pair->right)) pair->right->parent = p; + + if (pair == rbt->root) rbt->root = p; + + stix_rbt_freepair (rbt, pair); + return p; + } + } + else + { + void* nvptr = vcop (rbt, vptr, vlen); + if (nvptr == STIX_NULL) return STIX_NULL; + VPTR(pair) = nvptr; + VLEN(pair) = vlen; + } + + /* free up the old value */ + if (rbt->style->freeer[STIX_RBT_VAL] != STIX_NULL) + { + rbt->style->freeer[STIX_RBT_VAL] (rbt, ovptr, ovlen); + } + } + + return pair; +} + +static stix_rbt_pair_t* insert ( + stix_rbt_t* rbt, void* kptr, stix_size_t klen, void* vptr, stix_size_t vlen, int opt) +{ + stix_rbt_pair_t* x_cur = rbt->root; + stix_rbt_pair_t* x_par = STIX_NULL; + stix_rbt_pair_t* x_new; + + while (!IS_NIL(rbt,x_cur)) + { + int n = rbt->style->comper (rbt, kptr, klen, KPTR(x_cur), KLEN(x_cur)); + if (n == 0) + { + switch (opt) + { + case UPSERT: + case UPDATE: + return change_pair_val (rbt, x_cur, vptr, vlen); + + case ENSERT: + /* return existing pair */ + return x_cur; + + case INSERT: + /* return failure */ + return STIX_NULL; + } + } + + x_par = x_cur; + + if (n > 0) x_cur = x_cur->right; + else /* if (n < 0) */ x_cur = x_cur->left; + } + + if (opt == UPDATE) return STIX_NULL; + + x_new = stix_rbt_allocpair (rbt, kptr, klen, vptr, vlen); + if (x_new == STIX_NULL) return STIX_NULL; + + if (x_par == STIX_NULL) + { + /* the tree contains no pair */ + STIX_ASSERT (rbt->root == &rbt->xnil); + rbt->root = x_new; + } + else + { + /* perform normal binary insert */ + int n = rbt->style->comper (rbt, kptr, klen, KPTR(x_par), KLEN(x_par)); + if (n > 0) + { + STIX_ASSERT (x_par->right == &rbt->xnil); + x_par->right = x_new; + } + else + { + STIX_ASSERT (x_par->left == &rbt->xnil); + x_par->left = x_new; + } + + x_new->parent = x_par; + adjust (rbt, x_new); + } + + rbt->root->color = STIX_RBT_BLACK; + rbt->size++; + return x_new; +} + +stix_rbt_pair_t* stix_rbt_upsert ( + stix_rbt_t* rbt, void* kptr, stix_size_t klen, void* vptr, stix_size_t vlen) +{ + return insert (rbt, kptr, klen, vptr, vlen, UPSERT); +} + +stix_rbt_pair_t* stix_rbt_ensert ( + stix_rbt_t* rbt, void* kptr, stix_size_t klen, void* vptr, stix_size_t vlen) +{ + return insert (rbt, kptr, klen, vptr, vlen, ENSERT); +} + +stix_rbt_pair_t* stix_rbt_insert ( + stix_rbt_t* rbt, void* kptr, stix_size_t klen, void* vptr, stix_size_t vlen) +{ + return insert (rbt, kptr, klen, vptr, vlen, INSERT); +} + + +stix_rbt_pair_t* stix_rbt_update ( + stix_rbt_t* rbt, void* kptr, stix_size_t klen, void* vptr, stix_size_t vlen) +{ + return insert (rbt, kptr, klen, vptr, vlen, UPDATE); +} + +stix_rbt_pair_t* stix_rbt_cbsert ( + stix_rbt_t* rbt, void* kptr, stix_size_t klen, cbserter_t cbserter, void* ctx) +{ + stix_rbt_pair_t* x_cur = rbt->root; + stix_rbt_pair_t* x_par = STIX_NULL; + stix_rbt_pair_t* x_new; + + while (!IS_NIL(rbt,x_cur)) + { + int n = rbt->style->comper (rbt, kptr, klen, KPTR(x_cur), KLEN(x_cur)); + if (n == 0) + { + /* back up the contents of the current pair + * in case it is reallocated */ + stix_rbt_pair_t tmp; + + tmp = *x_cur; + + /* call the callback function to manipulate the pair */ + x_new = cbserter (rbt, x_cur, kptr, klen, ctx); + if (x_new == STIX_NULL) + { + /* error returned by the callback function */ + return STIX_NULL; + } + + if (x_new != x_cur) + { + /* the current pair has been reallocated, which implicitly + * means the previous contents were wiped out. so the contents + * backed up will be used for restoration/migration */ + + x_new->color = tmp.color; + x_new->left = tmp.left; + x_new->right = tmp.right; + x_new->parent = tmp.parent; + + if (tmp.parent) + { + if (tmp.parent->left == x_cur) + { + tmp.parent->left = x_new; + } + else + { + STIX_ASSERT (tmp.parent->right == x_cur); + tmp.parent->right = x_new; + } + } + if (!IS_NIL(rbt,tmp.left)) tmp.left->parent = x_new; + if (!IS_NIL(rbt,tmp.right)) tmp.right->parent = x_new; + + if (x_cur == rbt->root) rbt->root = x_new; + } + + return x_new; + } + + x_par = x_cur; + + if (n > 0) x_cur = x_cur->right; + else /* if (n < 0) */ x_cur = x_cur->left; + } + + x_new = cbserter (rbt, STIX_NULL, kptr, klen, ctx); + if (x_new == STIX_NULL) return STIX_NULL; + + if (x_par == STIX_NULL) + { + /* the tree contains no pair */ + STIX_ASSERT (rbt->root == &rbt->xnil); + rbt->root = x_new; + } + else + { + /* perform normal binary insert */ + int n = rbt->style->comper (rbt, kptr, klen, KPTR(x_par), KLEN(x_par)); + if (n > 0) + { + STIX_ASSERT (x_par->right == &rbt->xnil); + x_par->right = x_new; + } + else + { + STIX_ASSERT (x_par->left == &rbt->xnil); + x_par->left = x_new; + } + + x_new->parent = x_par; + adjust (rbt, x_new); + } + + rbt->root->color = STIX_RBT_BLACK; + rbt->size++; + return x_new; +} + + +static void adjust_for_delete (stix_rbt_t* rbt, stix_rbt_pair_t* pair, stix_rbt_pair_t* par) +{ + while (pair != rbt->root && pair->color == STIX_RBT_BLACK) + { + stix_rbt_pair_t* tmp; + + if (pair == par->left) + { + tmp = par->right; + if (tmp->color == STIX_RBT_RED) + { + tmp->color = STIX_RBT_BLACK; + par->color = STIX_RBT_RED; + rotate_left (rbt, par); + tmp = par->right; + } + + if (tmp->left->color == STIX_RBT_BLACK && + tmp->right->color == STIX_RBT_BLACK) + { + if (!IS_NIL(rbt,tmp)) tmp->color = STIX_RBT_RED; + pair = par; + par = pair->parent; + } + else + { + if (tmp->right->color == STIX_RBT_BLACK) + { + if (!IS_NIL(rbt,tmp->left)) + tmp->left->color = STIX_RBT_BLACK; + tmp->color = STIX_RBT_RED; + rotate_right (rbt, tmp); + tmp = par->right; + } + + tmp->color = par->color; + if (!IS_NIL(rbt,par)) par->color = STIX_RBT_BLACK; + if (tmp->right->color == STIX_RBT_RED) + tmp->right->color = STIX_RBT_BLACK; + + rotate_left (rbt, par); + pair = rbt->root; + } + } + else + { + STIX_ASSERT (pair == par->right); + tmp = par->left; + if (tmp->color == STIX_RBT_RED) + { + tmp->color = STIX_RBT_BLACK; + par->color = STIX_RBT_RED; + rotate_right (rbt, par); + tmp = par->left; + } + + if (tmp->left->color == STIX_RBT_BLACK && + tmp->right->color == STIX_RBT_BLACK) + { + if (!IS_NIL(rbt,tmp)) tmp->color = STIX_RBT_RED; + pair = par; + par = pair->parent; + } + else + { + if (tmp->left->color == STIX_RBT_BLACK) + { + if (!IS_NIL(rbt,tmp->right)) + tmp->right->color = STIX_RBT_BLACK; + tmp->color = STIX_RBT_RED; + rotate_left (rbt, tmp); + tmp = par->left; + } + tmp->color = par->color; + if (!IS_NIL(rbt,par)) par->color = STIX_RBT_BLACK; + if (tmp->left->color == STIX_RBT_RED) + tmp->left->color = STIX_RBT_BLACK; + + rotate_right (rbt, par); + pair = rbt->root; + } + } + } + + pair->color = STIX_RBT_BLACK; +} + +static void delete_pair (stix_rbt_t* rbt, stix_rbt_pair_t* pair) +{ + stix_rbt_pair_t* x, * y, * par; + + STIX_ASSERT (pair && !IS_NIL(rbt,pair)); + + if (IS_NIL(rbt,pair->left) || IS_NIL(rbt,pair->right)) + { + y = pair; + } + else + { + /* find a successor with NIL as a child */ + y = pair->right; + while (!IS_NIL(rbt,y->left)) y = y->left; + } + + x = IS_NIL(rbt,y->left)? y->right: y->left; + + par = y->parent; + if (!IS_NIL(rbt,x)) x->parent = par; + + if (par) + { + if (y == par->left) + par->left = x; + else + par->right = x; + } + else + { + rbt->root = x; + } + + if (y == pair) + { + if (y->color == STIX_RBT_BLACK && !IS_NIL(rbt,x)) + adjust_for_delete (rbt, x, par); + + stix_rbt_freepair (rbt, y); + } + else + { + if (y->color == STIX_RBT_BLACK && !IS_NIL(rbt,x)) + adjust_for_delete (rbt, x, par); + +#if 1 + if (pair->parent) + { + if (pair->parent->left == pair) pair->parent->left = y; + if (pair->parent->right == pair) pair->parent->right = y; + } + else + { + rbt->root = y; + } + + y->parent = pair->parent; + y->left = pair->left; + y->right = pair->right; + y->color = pair->color; + + if (pair->left->parent == pair) pair->left->parent = y; + if (pair->right->parent == pair) pair->right->parent = y; +#else + *y = *pair; + if (y->parent) + { + if (y->parent->left == pair) y->parent->left = y; + if (y->parent->right == pair) y->parent->right = y; + } + else + { + rbt->root = y; + } + + if (y->left->parent == pair) y->left->parent = y; + if (y->right->parent == pair) y->right->parent = y; +#endif + + stix_rbt_freepair (rbt, pair); + } + + rbt->size--; +} + +int stix_rbt_delete (stix_rbt_t* rbt, const void* kptr, stix_size_t klen) +{ + stix_rbt_pair_t* pair; + + pair = stix_rbt_search (rbt, kptr, klen); + if (pair == STIX_NULL) return -1; + + delete_pair (rbt, pair); + return 0; +} + +void stix_rbt_clear (stix_rbt_t* rbt) +{ + /* TODO: improve this */ + while (!IS_NIL(rbt,rbt->root)) delete_pair (rbt, rbt->root); +} + +#if 0 +static STIX_INLINE stix_rbt_walk_t walk_recursively ( + stix_rbt_t* rbt, walker_t walker, void* ctx, stix_rbt_pair_t* pair) +{ + if (!IS_NIL(rbt,pair->left)) + { + if (walk_recursively (rbt, walker, ctx, pair->left) == STIX_RBT_WALK_STOP) + return STIX_RBT_WALK_STOP; + } + + if (walker (rbt, pair, ctx) == STIX_RBT_WALK_STOP) return STIX_RBT_WALK_STOP; + + if (!IS_NIL(rbt,pair->right)) + { + if (walk_recursively (rbt, walker, ctx, pair->right) == STIX_RBT_WALK_STOP) + return STIX_RBT_WALK_STOP; + } + + return STIX_RBT_WALK_FORWARD; +} +#endif + +static STIX_INLINE void walk (stix_rbt_t* rbt, walker_t walker, void* ctx, int l, int r) +{ + stix_rbt_pair_t* x_cur = rbt->root; + stix_rbt_pair_t* prev = rbt->root->parent; + + while (x_cur && !IS_NIL(rbt,x_cur)) + { + if (prev == x_cur->parent) + { + /* the previous node is the parent of the current node. + * it indicates that we're going down to the child[l] */ + if (!IS_NIL(rbt,x_cur->child[l])) + { + /* go to the child[l] child */ + prev = x_cur; + x_cur = x_cur->child[l]; + } + else + { + if (walker (rbt, x_cur, ctx) == STIX_RBT_WALK_STOP) break; + + if (!IS_NIL(rbt,x_cur->child[r])) + { + /* go down to the right node if exists */ + prev = x_cur; + x_cur = x_cur->child[r]; + } + else + { + /* otherwise, move up to the parent */ + prev = x_cur; + x_cur = x_cur->parent; + } + } + } + else if (prev == x_cur->child[l]) + { + /* the left child has been already traversed */ + + if (walker (rbt, x_cur, ctx) == STIX_RBT_WALK_STOP) break; + + if (!IS_NIL(rbt,x_cur->child[r])) + { + /* go down to the right node if it exists */ + prev = x_cur; + x_cur = x_cur->child[r]; + } + else + { + /* otherwise, move up to the parent */ + prev = x_cur; + x_cur = x_cur->parent; + } + } + else + { + /* both the left child and the right child have been traversed */ + STIX_ASSERT (prev == x_cur->child[r]); + /* just move up to the parent */ + prev = x_cur; + x_cur = x_cur->parent; + } + } +} + +void stix_rbt_walk (stix_rbt_t* rbt, walker_t walker, void* ctx) +{ + walk (rbt, walker, ctx, LEFT, RIGHT); +} + +void stix_rbt_rwalk (stix_rbt_t* rbt, walker_t walker, void* ctx) +{ + walk (rbt, walker, ctx, RIGHT, LEFT); +} + +int stix_rbt_dflcomp (const stix_rbt_t* rbt, const void* kptr1, stix_size_t klen1, const void* kptr2, stix_size_t klen2) +{ + stix_size_t min; + int n, nn; + + if (klen1 < klen2) + { + min = klen1; + nn = -1; + } + else + { + min = klen2; + nn = (klen1 == klen2)? 0: 1; + } + + n = STIX_MEMCMP (kptr1, kptr2, KTOB(rbt,min)); + if (n == 0) n = nn; + return n; +} + diff --git a/stix/lib/stix-rbt.h b/stix/lib/stix-rbt.h new file mode 100644 index 0000000..4b5a4bd --- /dev/null +++ b/stix/lib/stix-rbt.h @@ -0,0 +1,607 @@ +/* + * $Id$ + * + Copyright (c) 2014-2015 Chung, Hyung-Hwan. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _STIX_RBT_H_ +#define _STIX_RBT_H_ + +#include "stix-cmn.h" + +/**@file + * This file provides a red-black tree encapsulated in the #stix_rbt_t type that + * implements a self-balancing binary search tree.Its interface is very close + * to #stix_htb_t. + * + * This sample code adds a series of keys and values and print them + * in descending key order. + * @code + * #include + * #include + * #include + * + * static stix_rbt_walk_t walk (stix_rbt_t* rbt, stix_rbt_pair_t* pair, void* ctx) + * { + * stix_printf (STIX_T("key = %d, value = %d\n"), + * *(int*)STIX_RBT_KPTR(pair), *(int*)STIX_RBT_VPTR(pair)); + * return STIX_RBT_WALK_FORWARD; + * } + * + * int main () + * { + * stix_rbt_t* s1; + * int i; + * + * s1 = stix_rbt_open (STIX_MMGR_GETDFL(), 0, 1, 1); // error handling skipped + * stix_rbt_setstyle (s1, stix_getrbtstyle(STIX_RBT_STYLE_INLINE_COPIERS)); + * + * for (i = 0; i < 20; i++) + * { + * int x = i * 20; + * stix_rbt_insert (s1, &i, STIX_SIZEOF(i), &x, STIX_SIZEOF(x)); // eror handling skipped + * } + * + * stix_rbt_rwalk (s1, walk, STIX_NULL); + * + * stix_rbt_close (s1); + * return 0; + * } + * @endcode + */ + +typedef struct stix_rbt_t stix_rbt_t; +typedef struct stix_rbt_pair_t stix_rbt_pair_t; + +/** + * The stix_rbt_walk_t type defines values that the callback function can + * return to control stix_rbt_walk() and stix_rbt_rwalk(). + */ +enum stix_rbt_walk_t +{ + STIX_RBT_WALK_STOP = 0, + STIX_RBT_WALK_FORWARD = 1 +}; +typedef enum stix_rbt_walk_t stix_rbt_walk_t; + +/** + * The stix_rbt_id_t type defines IDs to indicate a key or a value in various + * functions + */ +enum stix_rbt_id_t +{ + STIX_RBT_KEY = 0, /**< indicate a key */ + STIX_RBT_VAL = 1 /**< indicate a value */ +}; +typedef enum stix_rbt_id_t stix_rbt_id_t; + +/** + * The stix_rbt_copier_t type defines a pair contruction callback. + */ +typedef void* (*stix_rbt_copier_t) ( + stix_rbt_t* rbt /* red-black tree */, + void* dptr /* pointer to a key or a value */, + stix_size_t dlen /* length of a key or a value */ +); + +/** + * The stix_rbt_freeer_t defines a key/value destruction callback. + */ +typedef void (*stix_rbt_freeer_t) ( + stix_rbt_t* rbt, /**< red-black tree */ + void* dptr, /**< pointer to a key or a value */ + stix_size_t dlen /**< length of a key or a value */ +); + +/** + * The stix_rbt_comper_t type defines a key comparator that is called when + * the rbt needs to compare keys. A red-black tree is created with a default + * comparator which performs bitwise comparison of two keys. + * The comparator should return 0 if the keys are the same, 1 if the first + * key is greater than the second key, -1 otherwise. + */ +typedef int (*stix_rbt_comper_t) ( + const stix_rbt_t* rbt, /**< red-black tree */ + const void* kptr1, /**< key pointer */ + stix_size_t klen1, /**< key length */ + const void* kptr2, /**< key pointer */ + stix_size_t klen2 /**< key length */ +); + +/** + * The stix_rbt_keeper_t type defines a value keeper that is called when + * a value is retained in the context that it should be destroyed because + * it is identical to a new value. Two values are identical if their + * pointers and lengths are equal. + */ +typedef void (*stix_rbt_keeper_t) ( + stix_rbt_t* rbt, /**< red-black tree */ + void* vptr, /**< value pointer */ + stix_size_t vlen /**< value length */ +); + +/** + * The stix_rbt_walker_t defines a pair visitor. + */ +typedef stix_rbt_walk_t (*stix_rbt_walker_t) ( + stix_rbt_t* rbt, /**< red-black tree */ + stix_rbt_pair_t* pair, /**< pointer to a key/value pair */ + void* ctx /**< pointer to user-defined data */ +); + +/** + * The stix_rbt_cbserter_t type defines a callback function for stix_rbt_cbsert(). + * The stix_rbt_cbserter() function calls it to allocate a new pair for the + * key pointed to by @a kptr of the length @a klen and the callback context + * @a ctx. The second parameter @a pair is passed the pointer to the existing + * pair for the key or #STIX_NULL in case of no existing key. The callback + * must return a pointer to a new or a reallocated pair. When reallocating the + * existing pair, this callback must destroy the existing pair and return the + * newly reallocated pair. It must return #STIX_NULL for failure. + */ +typedef stix_rbt_pair_t* (*stix_rbt_cbserter_t) ( + stix_rbt_t* rbt, /**< red-black tree */ + stix_rbt_pair_t* pair, /**< pair pointer */ + void* kptr, /**< key pointer */ + stix_size_t klen, /**< key length */ + void* ctx /**< callback context */ +); + +/** + * The stix_rbt_pair_t type defines red-black tree pair. A pair is composed + * of a key and a value. It maintains pointers to the beginning of a key and + * a value plus their length. The length is scaled down with the scale factor + * specified in an owning tree. Use macros defined in the + */ +struct stix_rbt_pair_t +{ + struct + { + void* ptr; + stix_size_t len; + } key; + + struct + { + void* ptr; + stix_size_t len; + } val; + + /* management information below */ + enum + { + STIX_RBT_RED, + STIX_RBT_BLACK + } color; + stix_rbt_pair_t* parent; + stix_rbt_pair_t* child[2]; /* left and right */ +}; + +typedef struct stix_rbt_style_t stix_rbt_style_t; + +/** + * The stix_rbt_style_t type defines callback function sets for key/value + * pair manipulation. + */ +struct stix_rbt_style_t +{ + stix_rbt_copier_t copier[2]; /**< key and value copier */ + stix_rbt_freeer_t freeer[2]; /**< key and value freeer */ + stix_rbt_comper_t comper; /**< key comparator */ + stix_rbt_keeper_t keeper; /**< value keeper */ +}; + +/** + * The stix_rbt_style_kind_t type defines the type of predefined + * callback set for pair manipulation. + */ +enum stix_rbt_style_kind_t +{ + /** store the key and the value pointer */ + STIX_RBT_STYLE_DEFAULT, + /** copy both key and value into the pair */ + STIX_RBT_STYLE_INLINE_COPIERS, + /** copy the key into the pair but store the value pointer */ + STIX_RBT_STYLE_INLINE_KEY_COPIER, + /** copy the value into the pair but store the key pointer */ + STIX_RBT_STYLE_INLINE_VALUE_COPIER +}; + +typedef enum stix_rbt_style_kind_t stix_rbt_style_kind_t; + +/** + * The stix_rbt_t type defines a red-black tree. + */ +struct stix_rbt_t +{ + stix_mmgr_t* mmgr; + const stix_rbt_style_t* style; + stix_oob_t scale[2]; /**< length scale */ + stix_rbt_pair_t xnil; /**< internal nil node */ + stix_size_t size; /**< number of pairs */ + stix_rbt_pair_t* root; /**< root pair */ +}; + +/** + * The STIX_RBT_COPIER_SIMPLE macros defines a copier that remembers the + * pointer and length of data in a pair. + */ +#define STIX_RBT_COPIER_SIMPLE ((stix_rbt_copier_t)1) + +/** + * The STIX_RBT_COPIER_INLINE macros defines a copier that copies data into + * a pair. + */ +#define STIX_RBT_COPIER_INLINE ((stix_rbt_copier_t)2) + +#define STIX_RBT_COPIER_DEFAULT (STIX_RBT_COPIER_SIMPLE) +#define STIX_RBT_FREEER_DEFAULT (STIX_NULL) +#define STIX_RBT_COMPER_DEFAULT (stix_rbt_dflcomp) +#define STIX_RBT_KEEPER_DEFAULT (STIX_NULL) + +/** + * The STIX_RBT_SIZE() macro returns the number of pairs in red-black tree. + */ +#define STIX_RBT_SIZE(m) ((const stix_size_t)(m)->size) +#define STIX_RBT_KSCALE(m) ((const int)(m)->scale[STIX_RBT_KEY]) +#define STIX_RBT_VSCALE(m) ((const int)(m)->scale[STIX_RBT_VAL]) + +#define STIX_RBT_KPTL(p) (&(p)->key) +#define STIX_RBT_VPTL(p) (&(p)->val) + +#define STIX_RBT_KPTR(p) ((p)->key.ptr) +#define STIX_RBT_KLEN(p) ((p)->key.len) +#define STIX_RBT_VPTR(p) ((p)->val.ptr) +#define STIX_RBT_VLEN(p) ((p)->val.len) + +#define STIX_RBT_NEXT(p) ((p)->next) + +#if defined(__cplusplus) +extern "C" { +#endif + +/** + * The stix_getrbtstyle() functions returns a predefined callback set for + * pair manipulation. + */ +STIX_EXPORT const stix_rbt_style_t* stix_getrbtstyle ( + stix_rbt_style_kind_t kind +); + +/** + * The stix_rbt_open() function creates a red-black tree. + * @return stix_rbt_t pointer on success, STIX_NULL on failure. + */ +STIX_EXPORT stix_rbt_t* stix_rbt_open ( + stix_mmgr_t* mmgr, /**< memory manager */ + stix_size_t xtnsize, /**< extension size in bytes */ + int kscale, /**< key scale */ + int vscale /**< value scale */ +); + +/** + * The stix_rbt_close() function destroys a red-black tree. + */ +STIX_EXPORT void stix_rbt_close ( + stix_rbt_t* rbt /**< red-black tree */ +); + +/** + * The stix_rbt_init() function initializes a red-black tree + */ +STIX_EXPORT int stix_rbt_init ( + stix_rbt_t* rbt, /**< red-black tree */ + stix_mmgr_t* mmgr, /**< memory manager */ + int kscale, /**< key scale */ + int vscale /**< value scale */ +); + +/** + * The stix_rbt_fini() funtion finalizes a red-black tree + */ +STIX_EXPORT void stix_rbt_fini ( + stix_rbt_t* rbt /**< red-black tree */ +); + +STIX_EXPORT stix_mmgr_t* stix_rbt_getmmgr ( + stix_rbt_t* rbt +); + +STIX_EXPORT void* stix_rbt_getxtn ( + stix_rbt_t* rbt +); + +/** + * The stix_rbt_getstyle() function gets manipulation callback function set. + */ +STIX_EXPORT const stix_rbt_style_t* stix_rbt_getstyle ( + const stix_rbt_t* rbt /**< red-black tree */ +); + +/** + * The stix_rbt_setstyle() function sets internal manipulation callback + * functions for data construction, destruction, comparison, etc. + * The callback structure pointed to by \a style must outlive the tree + * pointed to by \a htb as the tree doesn't copy the contents of the + * structure. + */ +STIX_EXPORT void stix_rbt_setstyle ( + stix_rbt_t* rbt, /**< red-black tree */ + const stix_rbt_style_t* style /**< callback function set */ +); + +/** + * The stix_rbt_getsize() function gets the number of pairs in red-black tree. + */ +STIX_EXPORT stix_size_t stix_rbt_getsize ( + const stix_rbt_t* rbt /**< red-black tree */ +); + +/** + * The stix_rbt_search() function searches red-black tree to find a pair with a + * matching key. It returns the pointer to the pair found. If it fails + * to find one, it returns STIX_NULL. + * @return pointer to the pair with a maching key, + * or STIX_NULL if no match is found. + */ +STIX_EXPORT stix_rbt_pair_t* stix_rbt_search ( + const stix_rbt_t* rbt, /**< red-black tree */ + const void* kptr, /**< key pointer */ + stix_size_t klen /**< the size of the key */ +); + +/** + * The stix_rbt_upsert() function searches red-black tree for the pair with a + * matching key. If one is found, it updates the pair. Otherwise, it inserts + * a new pair with the key and the value given. It returns the pointer to the + * pair updated or inserted. + * @return a pointer to the updated or inserted pair on success, + * STIX_NULL on failure. + */ +STIX_EXPORT stix_rbt_pair_t* stix_rbt_upsert ( + stix_rbt_t* rbt, /**< red-black tree */ + void* kptr, /**< key pointer */ + stix_size_t klen, /**< key length */ + void* vptr, /**< value pointer */ + stix_size_t vlen /**< value length */ +); + +/** + * The stix_rbt_ensert() function inserts a new pair with the key and the value + * given. If there exists a pair with the key given, the function returns + * the pair containing the key. + * @return pointer to a pair on success, STIX_NULL on failure. + */ +STIX_EXPORT stix_rbt_pair_t* stix_rbt_ensert ( + stix_rbt_t* rbt, /**< red-black tree */ + void* kptr, /**< key pointer */ + stix_size_t klen, /**< key length */ + void* vptr, /**< value pointer */ + stix_size_t vlen /**< value length */ +); + +/** + * The stix_rbt_insert() function inserts a new pair with the key and the value + * given. If there exists a pair with the key given, the function returns + * STIX_NULL without channging the value. + * @return pointer to the pair created on success, STIX_NULL on failure. + */ +STIX_EXPORT stix_rbt_pair_t* stix_rbt_insert ( + stix_rbt_t* rbt, /**< red-black tree */ + void* kptr, /**< key pointer */ + stix_size_t klen, /**< key length */ + void* vptr, /**< value pointer */ + stix_size_t vlen /**< value length */ +); + +/** + * The stix_rbt_update() function updates the value of an existing pair + * with a matching key. + * @return pointer to the pair on success, STIX_NULL on no matching pair + */ +STIX_EXPORT stix_rbt_pair_t* stix_rbt_update ( + stix_rbt_t* rbt, /**< red-black tree */ + void* kptr, /**< key pointer */ + stix_size_t klen, /**< key length */ + void* vptr, /**< value pointer */ + stix_size_t vlen /**< value length */ +); + +/** + * The stix_rbt_cbsert() function inserts a key/value pair by delegating pair + * allocation to a callback function. Depending on the callback function, + * it may behave like stix_rbt_insert(), stix_rbt_upsert(), stix_rbt_update(), + * stix_rbt_ensert(), or totally differently. The sample code below inserts + * a new pair if the key is not found and appends the new value to the + * existing value delimited by a comma if the key is found. + * + * @code + * stix_rbt_walk_t print_map_pair (stix_rbt_t* map, stix_rbt_pair_t* pair, void* ctx) + * { + * stix_printf (STIX_T("%.*s[%d] => %.*s[%d]\n"), + * (int)STIX_RBT_KLEN(pair), STIX_RBT_KPTR(pair), (int)STIX_RBT_KLEN(pair), + * (int)STIX_RBT_VLEN(pair), STIX_RBT_VPTR(pair), (int)STIX_RBT_VLEN(pair)); + * return STIX_RBT_WALK_FORWARD; + * } + * + * stix_rbt_pair_t* cbserter ( + * stix_rbt_t* rbt, stix_rbt_pair_t* pair, + * void* kptr, stix_size_t klen, void* ctx) + * { + * stix_cstr_t* v = (stix_cstr_t*)ctx; + * if (pair == STIX_NULL) + * { + * // no existing key for the key + * return stix_rbt_allocpair (rbt, kptr, klen, v->ptr, v->len); + * } + * else + * { + * // a pair with the key exists. + * // in this sample, i will append the new value to the old value + * // separated by a comma + * stix_rbt_pair_t* new_pair; + * stix_char_t comma = STIX_T(','); + * stix_oob_t* vptr; + * + * // allocate a new pair, but without filling the actual value. + * // note vptr is given STIX_NULL for that purpose + * new_pair = stix_rbt_allocpair ( + * rbt, kptr, klen, STIX_NULL, pair->vlen + 1 + v->len); + * if (new_pair == STIX_NULL) return STIX_NULL; + * + * // fill in the value space + * vptr = new_pair->vptr; + * stix_memcpy (vptr, pair->vptr, pair->vlen*STIX_SIZEOF(stix_char_t)); + * vptr += pair->vlen*STIX_SIZEOF(stix_char_t); + * stix_memcpy (vptr, &comma, STIX_SIZEOF(stix_char_t)); + * vptr += STIX_SIZEOF(stix_char_t); + * stix_memcpy (vptr, v->ptr, v->len*STIX_SIZEOF(stix_char_t)); + * + * // this callback requires the old pair to be destroyed + * stix_rbt_freepair (rbt, pair); + * + * // return the new pair + * return new_pair; + * } + * } + * + * int main () + * { + * stix_rbt_t* s1; + * int i; + * stix_char_t* keys[] = { STIX_T("one"), STIX_T("two"), STIX_T("three") }; + * stix_char_t* vals[] = { STIX_T("1"), STIX_T("2"), STIX_T("3"), STIX_T("4"), STIX_T("5") }; + * + * s1 = stix_rbt_open ( + * STIX_MMGR_GETDFL(), 0, + * STIX_SIZEOF(stix_char_t), STIX_SIZEOF(stix_char_t) + * ); // note error check is skipped + * stix_rbt_setstyle (s1, &style1); + * + * for (i = 0; i < STIX_COUNTOF(vals); i++) + * { + * stix_cstr_t ctx; + * ctx.ptr = vals[i]; ctx.len = stix_strlen(vals[i]); + * stix_rbt_cbsert (s1, + * keys[i%STIX_COUNTOF(keys)], stix_strlen(keys[i%STIX_COUNTOF(keys)]), + * cbserter, &ctx + * ); // note error check is skipped + * } + * stix_rbt_walk (s1, print_map_pair, STIX_NULL); + * + * stix_rbt_close (s1); + * return 0; + * } + * @endcode + */ +STIX_EXPORT stix_rbt_pair_t* stix_rbt_cbsert ( + stix_rbt_t* rbt, /**< red-black tree */ + void* kptr, /**< key pointer */ + stix_size_t klen, /**< key length */ + stix_rbt_cbserter_t cbserter, /**< callback function */ + void* ctx /**< callback context */ +); + +/** + * The stix_rbt_delete() function deletes a pair with a matching key + * @return 0 on success, -1 on failure + */ +STIX_EXPORT int stix_rbt_delete ( + stix_rbt_t* rbt, /**< red-black tree */ + const void* kptr, /**< key pointer */ + stix_size_t klen /**< key size */ +); + +/** + * The stix_rbt_clear() function empties a red-black tree. + */ +STIX_EXPORT void stix_rbt_clear ( + stix_rbt_t* rbt /**< red-black tree */ +); + +/** + * The stix_rbt_walk() function traverses a red-black tree in preorder + * from the leftmost child. + */ +STIX_EXPORT void stix_rbt_walk ( + stix_rbt_t* rbt, /**< red-black tree */ + stix_rbt_walker_t walker, /**< callback function for each pair */ + void* ctx /**< pointer to user-specific data */ +); + +/** + * The stix_rbt_walk() function traverses a red-black tree in preorder + * from the rightmost child. + */ +STIX_EXPORT void stix_rbt_rwalk ( + stix_rbt_t* rbt, /**< red-black tree */ + stix_rbt_walker_t walker, /**< callback function for each pair */ + void* ctx /**< pointer to user-specific data */ +); + +/** + * The stix_rbt_allocpair() function allocates a pair for a key and a value + * given. But it does not chain the pair allocated into the red-black tree @a rbt. + * Use this function at your own risk. + * + * Take note of he following special behavior when the copier is + * #STIX_RBT_COPIER_INLINE. + * - If @a kptr is #STIX_NULL, the key space of the size @a klen is reserved but + * not propagated with any data. + * - If @a vptr is #STIX_NULL, the value space of the size @a vlen is reserved + * but not propagated with any data. + */ +STIX_EXPORT stix_rbt_pair_t* stix_rbt_allocpair ( + stix_rbt_t* rbt, + void* kptr, + stix_size_t klen, + void* vptr, + stix_size_t vlen +); + +/** + * The stix_rbt_freepair() function destroys a pair. But it does not detach + * the pair destroyed from the red-black tree @a rbt. Use this function at your + * own risk. + */ +STIX_EXPORT void stix_rbt_freepair ( + stix_rbt_t* rbt, + stix_rbt_pair_t* pair +); + +/** + * The stix_rbt_dflcomp() function defines the default key comparator. + */ +STIX_EXPORT int stix_rbt_dflcomp ( + const stix_rbt_t* rbt, + const void* kptr1, + stix_size_t klen1, + const void* kptr2, + stix_size_t klen2 +); + +#if defined(__cplusplus) +} +#endif + +#endif