rbtree-0.4.6/0000755000004100000410000000000014353333751013043 5ustar www-datawww-datarbtree-0.4.6/MANIFEST0000644000004100000410000000011114353333751014165 0ustar www-datawww-dataLICENSE MANIFEST README depend dict.c dict.h extconf.rb rbtree.c test.rb rbtree-0.4.6/depend0000644000004100000410000000006014353333751014221 0ustar www-datawww-datadict.o: dict.c dict.h rbtree.o: rbtree.c dict.h rbtree-0.4.6/rbtree.c0000644000004100000410000014135714353333751014505 0ustar www-datawww-data/* * MIT License * Copyright (c) 2002-2013 OZAWA Takuma */ #include #ifdef HAVE_RUBY_VERSION_H #include #endif #ifdef HAVE_RUBY_ST_H #include #else #include #endif #include "dict.h" #define RBTREE_PROC_DEFAULT FL_USER2 #define HASH_PROC_DEFAULT FL_USER2 #ifdef RETURN_SIZED_ENUMERATOR #define HAVE_SIZED_ENUMERATOR #else #ifdef RETURN_ENUMERATOR #define RETURN_SIZED_ENUMERATOR(obj, argc, argv, size_fn) RETURN_ENUMERATOR(obj, argc, argv) #else #define RETURN_SIZED_ENUMERATOR(obj, argc, argv, size_fn) ((void)0) #endif #endif #ifndef RARRAY_AREF #define RARRAY_AREF(a, i) (RARRAY_PTR(a)[i]) #endif #ifndef RHASH_SET_IFNONE #define RHASH_SET_IFNONE(h, v) (RHASH(h)->ifnone = (v)) #endif VALUE RBTree; VALUE MultiRBTree; static ID id_cmp; static ID id_call; static ID id_default; static ID id_flatten_bang; typedef struct { dict_t* dict; VALUE ifnone; VALUE cmp_proc; int iter_lev; } rbtree_t; #define RBTREE(rbtree) DATA_PTR(rbtree) #define DICT(rbtree) ((rbtree_t*)RBTREE(rbtree))->dict #define IFNONE(rbtree) ((rbtree_t*)RBTREE(rbtree))->ifnone #define CMP_PROC(rbtree) ((rbtree_t*)RBTREE(rbtree))->cmp_proc #define ITER_LEV(rbtree) ((rbtree_t*)RBTREE(rbtree))->iter_lev #define TO_KEY(arg) ((const void*)arg) #define TO_VAL(arg) ((void*)arg) #define GET_KEY(dnode) ((VALUE)dnode_getkey(dnode)) #define GET_VAL(dnode) ((VALUE)dnode_get(dnode)) #define ASSOC(dnode) rb_assoc_new(GET_KEY(dnode), GET_VAL(dnode)) /*********************************************************************/ static void rbtree_free(rbtree_t* rbtree) { dict_free_nodes(rbtree->dict); xfree(rbtree->dict); xfree(rbtree); } static void rbtree_mark(rbtree_t* rbtree) { if (rbtree == NULL) return; if (rbtree->dict != NULL) { dict_t* dict = rbtree->dict; dnode_t* node; for (node = dict_first(dict); node != NULL; node = dict_next(dict, node)) { rb_gc_mark(GET_KEY(node)); rb_gc_mark(GET_VAL(node)); } } rb_gc_mark(rbtree->ifnone); rb_gc_mark(rbtree->cmp_proc); } static dnode_t* rbtree_alloc_node(void* context) { return ALLOC(dnode_t); } static void rbtree_free_node(dnode_t* node, void* context) { xfree(node); } static void rbtree_check_argument_count(const int argc, const int min, const int max) { if (argc < min || argc > max) { static const char* const message = "wrong number of arguments"; if (min == max) { rb_raise(rb_eArgError, "%s (%d for %d)", message, argc, min); } else if (max == INT_MAX) { rb_raise(rb_eArgError, "%s (%d for %d+)", message, argc, -min - 1); } else { rb_raise(rb_eArgError, "%s (%d for %d..%d)", message, argc, min, max); } } } static void rbtree_check_proc_arity(VALUE proc, const int expected) { #ifdef HAVE_RB_PROC_LAMBDA_P if (rb_proc_lambda_p(proc)) { const int arity = rb_proc_arity(proc); const int min = arity < 0 ? -arity - 1 : arity; const int max = arity < 0 ? INT_MAX : arity; if (expected < min || expected > max) { rb_raise(rb_eTypeError, "proc takes %d arguments", expected); } } #endif } static int rbtree_cmp(const void* key1, const void* key2, void* context) { VALUE result; if (TYPE((VALUE)key1) == T_STRING && TYPE((VALUE)key2) == T_STRING) return rb_str_cmp((VALUE)key1, (VALUE)key2); result = rb_funcall2((VALUE)key1, id_cmp, 1, (VALUE*)&key2); return rb_cmpint(result, (VALUE)key1, (VALUE)key2); } static VALUE rbtree_user_cmp_ensure(VALUE arg) { rbtree_t* rbtree = (rbtree_t*)arg; rbtree->iter_lev--; return Qnil; } static VALUE rbtree_user_cmp_body(VALUE arg) { VALUE *args = (VALUE*)arg; rbtree_t* rbtree = (rbtree_t*)args[2]; rbtree->iter_lev++; return rb_funcall2(rbtree->cmp_proc, id_call, 2, args); } static int rbtree_user_cmp(const void* key1, const void* key2, void* context) { rbtree_t* rbtree = (rbtree_t*)context; VALUE args[3]; VALUE result; args[0] = (VALUE)key1; args[1] = (VALUE)key2; args[2] = (VALUE)rbtree; result = rb_ensure(rbtree_user_cmp_body, (VALUE)&args, rbtree_user_cmp_ensure, (VALUE)rbtree); return rb_cmpint(result, (VALUE)key1, (VALUE)key2); } static void rbtree_modify(VALUE self) { if (ITER_LEV(self) > 0) rb_raise(rb_eTypeError, "can't modify rbtree during iteration"); rb_check_frozen(self); #if defined(HAVE_RB_SAFE_LEVEL) && !defined(RUBY_SAFE_LEVEL_MAX) if (!OBJ_TAINTED(self) && rb_safe_level() >= 4) rb_raise(rb_eSecurityError, "Insecure: can't modify rbtree"); #endif } static VALUE rbtree_alloc(VALUE klass) { dict_t* dict; VALUE rbtree = Data_Wrap_Struct(klass, rbtree_mark, rbtree_free, NULL); RBTREE(rbtree) = ALLOC(rbtree_t); MEMZERO(RBTREE(rbtree), rbtree_t, 1); dict = ALLOC(dict_t); dict_init(dict, rbtree_cmp); dict_set_allocator(dict, rbtree_alloc_node, rbtree_free_node, RBTREE(rbtree)); if (!RTEST(rb_class_inherited_p(klass, RBTree))) dict_allow_dupes(dict); DICT(rbtree) = dict; IFNONE(rbtree) = Qnil; CMP_PROC(rbtree) = Qnil; return rbtree; } VALUE rbtree_aset(VALUE, VALUE, VALUE); VALUE rbtree_has_key(VALUE, VALUE); VALUE rbtree_update(VALUE, VALUE); VALUE rbtree_to_a(VALUE); /*********************************************************************/ static int hash_to_rbtree_i(VALUE key, VALUE value, VALUE rbtree) { if (key != Qundef) rbtree_aset(rbtree, key, value); return ST_CONTINUE; } /* * */ VALUE rbtree_s_create(int argc, VALUE* argv, VALUE klass) { long i; VALUE rbtree; if (argc == 1) { VALUE temp; if (rb_obj_is_kind_of(argv[0], klass)) { rbtree = rbtree_alloc(klass); rbtree_update(rbtree, argv[0]); return rbtree; } if (RTEST(rb_class_inherited_p(klass, RBTree)) && (rb_obj_is_kind_of(argv[0], MultiRBTree) && !rb_obj_is_kind_of(argv[0], RBTree))) { rb_raise(rb_eTypeError, "wrong argument type MultiRBTree (expected RBTree)"); } temp = rb_check_convert_type(argv[0], T_HASH, "Hash", "to_hash"); if (!NIL_P(temp)) { rbtree = rbtree_alloc(klass); rb_hash_foreach(temp, hash_to_rbtree_i, rbtree); return rbtree; } temp = rb_check_array_type(argv[0]); if (!NIL_P(temp)) { rbtree = rbtree_alloc(klass); for (i = 0; i < RARRAY_LEN(temp); i++) { VALUE v = rb_check_array_type(RARRAY_AREF(temp, i)); if (NIL_P(v)) { rb_warn("wrong element type %s at %ld (expected Array)", rb_obj_classname(RARRAY_AREF(temp, i)), i); continue; } switch(RARRAY_LEN(v)) { case 1: rbtree_aset(rbtree, RARRAY_AREF(v, 0), Qnil); break; case 2: rbtree_aset(rbtree, RARRAY_AREF(v, 0), RARRAY_AREF(v, 1)); break; default: rb_warn("invalid number of elements (%ld for 1..2)", RARRAY_LEN(v)); } } return rbtree; } } if (argc % 2 != 0) rb_raise(rb_eArgError, "odd number of arguments for %s", rb_class2name(klass)); rbtree = rbtree_alloc(klass); for (i = 0; i < argc; i += 2) rbtree_aset(rbtree, argv[i], argv[i + 1]); return rbtree; } /* * */ VALUE rbtree_initialize(int argc, VALUE* argv, VALUE self) { rbtree_modify(self); if (rb_block_given_p()) { VALUE proc; rbtree_check_argument_count(argc, 0, 0); proc = rb_block_proc(); rbtree_check_proc_arity(proc, 2); IFNONE(self) = proc; FL_SET(self, RBTREE_PROC_DEFAULT); } else { rbtree_check_argument_count(argc, 0, 1); if (argc == 1) { IFNONE(self) = argv[0]; } } return self; } /*********************************************************************/ typedef enum { NoNodeInserted, KeyAllocationFailed, InsertionSucceeded } insert_result_t; typedef struct { dict_t* dict; dnode_t* node; insert_result_t result; } rbtree_insert_arg_t; static VALUE insert_node_body(VALUE arg_) { rbtree_insert_arg_t* arg = (rbtree_insert_arg_t*)arg_; dict_t* dict = arg->dict; dnode_t* node = arg->node; if (dict_insert(dict, node, dnode_getkey(node))) { if (TYPE(GET_KEY(node)) == T_STRING) { arg->result = KeyAllocationFailed; node->dict_key = TO_KEY(rb_str_new4(GET_KEY(node))); } } else { dict->dict_freenode(node, dict->dict_context); } arg->result = InsertionSucceeded; return Qnil; } static VALUE insert_node_ensure(VALUE arg_) { rbtree_insert_arg_t* arg = (rbtree_insert_arg_t*)arg_; dict_t* dict = arg->dict; dnode_t* node = arg->node; switch (arg->result) { case InsertionSucceeded: break; case NoNodeInserted: dict->dict_freenode(node, dict->dict_context); break; case KeyAllocationFailed: dict_delete_free(dict, node); break; } return Qnil; } static void rbtree_insert(VALUE self, VALUE key, VALUE value) { rbtree_insert_arg_t arg; dict_t* dict = DICT(self); dnode_t* node = dict->dict_allocnode(dict->dict_context); dnode_init(node, TO_VAL(value)); node->dict_key = TO_KEY(key); arg.dict = dict; arg.node = node; arg.result = NoNodeInserted; rb_ensure(insert_node_body, (VALUE)&arg, insert_node_ensure, (VALUE)&arg); } /*********************************************************************/ /* * */ VALUE rbtree_aset(VALUE self, VALUE key, VALUE value) { rbtree_modify(self); if (dict_isfull(DICT(self))) { dnode_t* node = dict_lookup(DICT(self), TO_KEY(key)); if (node == NULL) rb_raise(rb_eIndexError, "rbtree full"); else dnode_put(node, TO_VAL(value)); return value; } rbtree_insert(self, key, value); return value; } /* * */ VALUE rbtree_aref(VALUE self, VALUE key) { dnode_t* node = dict_lookup(DICT(self), TO_KEY(key)); if (node == NULL) return rb_funcall2(self, id_default, 1, &key); else return GET_VAL(node); } /* * */ VALUE rbtree_fetch(int argc, VALUE* argv, VALUE self) { dnode_t* node; rbtree_check_argument_count(argc, 1, 2); if (argc == 2 && rb_block_given_p()) { rb_warn("block supersedes default value argument"); } node = dict_lookup(DICT(self), TO_KEY(argv[0])); if (node != NULL) { return GET_VAL(node); } if (rb_block_given_p()) { return rb_yield(argv[0]); } if (argc == 1) { rb_raise(rb_eIndexError, "key not found"); } return argv[1]; } /* * */ VALUE rbtree_size(VALUE self) { return ULONG2NUM(dict_count(DICT(self))); } /* * */ VALUE rbtree_empty_p(VALUE self) { return dict_isempty(DICT(self)) ? Qtrue : Qfalse; } /* * */ VALUE rbtree_default(int argc, VALUE* argv, VALUE self) { rbtree_check_argument_count(argc, 0, 1); if (FL_TEST(self, RBTREE_PROC_DEFAULT)) { if (argc == 0) { return Qnil; } return rb_funcall(IFNONE(self), id_call, 2, self, argv[0]); } return IFNONE(self); } /* * */ VALUE rbtree_set_default(VALUE self, VALUE ifnone) { rbtree_modify(self); IFNONE(self) = ifnone; FL_UNSET(self, RBTREE_PROC_DEFAULT); return ifnone; } /* * */ VALUE rbtree_default_proc(VALUE self) { if (FL_TEST(self, RBTREE_PROC_DEFAULT)) return IFNONE(self); return Qnil; } /* * */ VALUE rbtree_set_default_proc(VALUE self, VALUE proc) { VALUE temp; rbtree_modify(self); if (NIL_P(proc)) { IFNONE(self) = Qnil; FL_UNSET(self, RBTREE_PROC_DEFAULT); return Qnil; } temp = rb_check_convert_type(proc, T_DATA, "Proc", "to_proc"); if (NIL_P(temp)) { rb_raise(rb_eTypeError, "wrong default_proc type %s (expected Proc)", rb_obj_classname(proc)); } rbtree_check_proc_arity(temp, 2); IFNONE(self) = temp; FL_SET(self, RBTREE_PROC_DEFAULT); return proc; } static VALUE rbtree_recursive_equal(VALUE self, VALUE other, int recursive) { dict_t* dict1 = DICT(self); dict_t* dict2 = DICT(other); dnode_t* node1; dnode_t* node2; if (recursive) return Qtrue; for (node1 = dict_first(dict1), node2 = dict_first(dict2); node1 != NULL && node2 != NULL; node1 = dict_next(dict1, node1), node2 = dict_next(dict2, node2)) { if (!rb_equal(GET_KEY(node1), GET_KEY(node2)) || !rb_equal(GET_VAL(node1), GET_VAL(node2))) { return Qfalse; } } return Qtrue; } /* * */ VALUE rbtree_equal(VALUE self, VALUE other) { if (self == other) return Qtrue; if (!rb_obj_is_kind_of(other, MultiRBTree)) return Qfalse; if (dict_count(DICT(self)) != dict_count(DICT(other)) || DICT(self)->dict_compare != DICT(other)->dict_compare || CMP_PROC(self) != CMP_PROC(other)) { return Qfalse; } #if defined(HAVE_RB_EXEC_RECURSIVE_PAIRED) return rb_exec_recursive_paired(rbtree_recursive_equal, self, other, other); #elif defined(HAVE_RB_EXEC_RECURSIVE) return rb_exec_recursive(rbtree_recursive_equal, self, other); #else return rbtree_recursive_equal(self, other, 0); #endif } /*********************************************************************/ typedef enum { EACH_NEXT, EACH_STOP } each_return_t; typedef each_return_t (*each_callback_func)(dnode_t*, void*); typedef struct { VALUE self; each_callback_func func; void* arg; int reverse; } rbtree_each_arg_t; static VALUE rbtree_each_ensure(VALUE self) { ITER_LEV(self)--; return Qnil; } static VALUE rbtree_each_body(VALUE arg_) { rbtree_each_arg_t* arg = (rbtree_each_arg_t*)arg_; VALUE self = arg->self; dict_t* dict = DICT(self); dnode_t* node; dnode_t* first_node; dnode_t* (*next_func)(dict_t*, dnode_t*); if (arg->reverse) { first_node = dict_last(dict); next_func = dict_prev; } else { first_node = dict_first(dict); next_func = dict_next; } ITER_LEV(self)++; for (node = first_node; node != NULL; node = next_func(dict, node)) { if (arg->func(node, arg->arg) == EACH_STOP) break; } return self; } static VALUE rbtree_for_each(VALUE self, each_callback_func func, void* arg) { rbtree_each_arg_t each_arg; each_arg.self = self; each_arg.func = func; each_arg.arg = arg; each_arg.reverse = 0; return rb_ensure(rbtree_each_body, (VALUE)&each_arg, rbtree_each_ensure, self); } static VALUE rbtree_reverse_for_each(VALUE self, each_callback_func func, void* arg) { rbtree_each_arg_t each_arg; each_arg.self = self; each_arg.func = func; each_arg.arg = arg; each_arg.reverse = 1; return rb_ensure(rbtree_each_body, (VALUE)&each_arg, rbtree_each_ensure, self); } /*********************************************************************/ static each_return_t each_pair_i(dnode_t* node, void* arg) { rb_yield(ASSOC(node)); return EACH_NEXT; } /* * call-seq: * rbtree.each {|key, value| block} => rbtree * rbtree.each_pair {|key, value| block} => rbtree * rbtree.each => enumerator * rbtree.each_pair => enumerator * * Calls block once for each key in order, passing the key-value pair * as parameters. * * Returns an enumerator if no block is given. */ VALUE rbtree_each_pair(VALUE self) { RETURN_SIZED_ENUMERATOR(self, 0, NULL, rbtree_size); return rbtree_for_each(self, each_pair_i, NULL); } static each_return_t each_key_i(dnode_t* node, void* arg) { rb_yield(GET_KEY(node)); return EACH_NEXT; } /* * call-seq: * rbtree.each_key {|key| block} => rbtree * rbtree.each_key => enumerator * * Calls block once for each key in order, passing the key as a * parameter. * * Returns an enumerator if no block is given. */ VALUE rbtree_each_key(VALUE self) { RETURN_SIZED_ENUMERATOR(self, 0, NULL, rbtree_size); return rbtree_for_each(self, each_key_i, NULL); } static each_return_t each_value_i(dnode_t* node, void* arg) { rb_yield(GET_VAL(node)); return EACH_NEXT; } /* * call-seq: * rbtree.each_value {|value| block} => rbtree * rbtree.each_value => enumerator * * Calls block once for each key in order, passing the value as a * parameter. * * Returns an enumerator if no block is given. */ VALUE rbtree_each_value(VALUE self) { RETURN_SIZED_ENUMERATOR(self, 0, NULL, rbtree_size); return rbtree_for_each(self, each_value_i, NULL); } /* * call-seq: * rbtree.reverse_each {|key, value| block} => rbtree * rbtree.reverse_each => enumerator * * Calls block once for each key in reverse order, passing the * key-value pair as parameters. * * Returns an enumerator if no block is given. */ VALUE rbtree_reverse_each(VALUE self) { RETURN_SIZED_ENUMERATOR(self, 0, NULL, rbtree_size); return rbtree_reverse_for_each(self, each_pair_i, NULL); } static each_return_t aset_i(dnode_t* node, void* self) { rbtree_aset((VALUE)self, GET_KEY(node), GET_VAL(node)); return EACH_NEXT; } static void copy_dict(VALUE src, VALUE dest, dict_comp_t cmp_func, VALUE cmp_proc) { VALUE temp = rbtree_alloc(CLASS_OF(dest)); #ifdef HAVE_RB_OBJ_HIDE rb_obj_hide(temp); #else RBASIC(temp)->klass = 0; #endif DICT(temp)->dict_compare = cmp_func; CMP_PROC(temp) = cmp_proc; rbtree_for_each(src, aset_i, (void*)temp); { dict_t* t = DICT(temp); DICT(temp) = DICT(dest); DICT(dest) = t; } rbtree_free(RBTREE(temp)); RBTREE(temp) = NULL; #if defined(RUBY_API_VERSION_CODE) && RUBY_API_VERSION_CODE >= 30100 /* do nothing */ #else rb_gc_force_recycle(temp); #endif DICT(dest)->dict_context = RBTREE(dest); CMP_PROC(dest) = cmp_proc; } /* * */ VALUE rbtree_initialize_copy(VALUE self, VALUE other) { rbtree_modify(self); if (self == other) return self; if (!rb_obj_is_kind_of(other, CLASS_OF(self))) { rb_raise(rb_eTypeError, "wrong argument type %s (expected %s)", rb_obj_classname(other), rb_obj_classname(self)); } copy_dict(other, self, DICT(other)->dict_compare, CMP_PROC(other)); IFNONE(self) = IFNONE(other); if (FL_TEST(other, RBTREE_PROC_DEFAULT)) FL_SET(self, RBTREE_PROC_DEFAULT); else FL_UNSET(self, RBTREE_PROC_DEFAULT); return self; } /* * */ VALUE rbtree_values_at(int argc, VALUE* argv, VALUE self) { long i; VALUE ary = rb_ary_new2(argc); for (i = 0; i < argc; i++) rb_ary_push(ary, rbtree_aref(self, argv[i])); return ary; } static each_return_t key_i(dnode_t* node, void* args_) { VALUE* args = (VALUE*)args_; if (rb_equal(GET_VAL(node), args[1])) { args[0] = GET_KEY(node); return EACH_STOP; } return EACH_NEXT; } /* * */ VALUE rbtree_key(VALUE self, VALUE value) { VALUE args[2]; args[0] = Qnil; args[1] = value; rbtree_for_each(self, key_i, &args); return args[0]; } /* * */ VALUE rbtree_index(VALUE self, VALUE value) { VALUE klass = rb_obj_is_kind_of(self, RBTree) ? RBTree : MultiRBTree; const char* classname = rb_class2name(klass); rb_warn("%s#index is deprecated; use %s#key", classname, classname); return rbtree_key(self, value); } /* * */ VALUE rbtree_clear(VALUE self) { rbtree_modify(self); dict_free_nodes(DICT(self)); return self; } /* * */ VALUE rbtree_delete(VALUE self, VALUE key) { dict_t* dict = DICT(self); dnode_t* node; VALUE value; rbtree_modify(self); node = dict_lookup(dict, TO_KEY(key)); if (node == NULL) return rb_block_given_p() ? rb_yield(key) : Qnil; value = GET_VAL(node); dict_delete_free(dict, node); return value; } /*********************************************************************/ typedef struct dnode_list_t_ { struct dnode_list_t_* prev; dnode_t* node; } dnode_list_t; typedef struct { VALUE self; dnode_list_t* list; int raised; int if_true; } rbtree_remove_if_arg_t; static VALUE rbtree_remove_if_ensure(VALUE arg_) { rbtree_remove_if_arg_t* arg = (rbtree_remove_if_arg_t*)arg_; dict_t* dict = DICT(arg->self); dnode_list_t* list = arg->list; if (--ITER_LEV(arg->self) == 0) { while (list != NULL) { dnode_list_t* l = list; if (!arg->raised) dict_delete_free(dict, l->node); list = l->prev; xfree(l); } } return Qnil; } static VALUE rbtree_remove_if_body(VALUE arg_) { rbtree_remove_if_arg_t* arg = (rbtree_remove_if_arg_t*)arg_; VALUE self = arg->self; dict_t* dict = DICT(self); dnode_t* node; arg->raised = 1; ITER_LEV(self)++; for (node = dict_first(dict); node != NULL; node = dict_next(dict, node)) { VALUE key = GET_KEY(node); VALUE value = GET_VAL(node); if (RTEST(rb_yield_values(2, key, value)) == arg->if_true) { dnode_list_t* l = ALLOC(dnode_list_t); l->node = node; l->prev = arg->list; arg->list = l; } } arg->raised = 0; return self; } static VALUE rbtree_remove_if(VALUE self, const int if_true) { rbtree_remove_if_arg_t arg; RETURN_SIZED_ENUMERATOR(self, 0, NULL, rbtree_size); rbtree_modify(self); arg.self = self; arg.list = NULL; arg.if_true = if_true; return rb_ensure(rbtree_remove_if_body, (VALUE)&arg, rbtree_remove_if_ensure, (VALUE)&arg); } /*********************************************************************/ /* * */ VALUE rbtree_delete_if(VALUE self) { return rbtree_remove_if(self, 1); } /* * */ VALUE rbtree_keep_if(VALUE self) { return rbtree_remove_if(self, 0); } /* * */ VALUE rbtree_reject_bang(VALUE self) { dictcount_t count; RETURN_SIZED_ENUMERATOR(self, 0, NULL, rbtree_size); count = dict_count(DICT(self)); rbtree_delete_if(self); if (count == dict_count(DICT(self))) return Qnil; return self; } /* * */ VALUE rbtree_select_bang(VALUE self) { dictcount_t count; RETURN_SIZED_ENUMERATOR(self, 0, NULL, rbtree_size); count = dict_count(DICT(self)); rbtree_keep_if(self); if (count == dict_count(DICT(self))) return Qnil; return self; } /*********************************************************************/ typedef struct { VALUE result; int if_true; } rbtree_select_if_arg_t; static each_return_t select_i(dnode_t* node, void* arg_) { VALUE key = GET_KEY(node); VALUE value = GET_VAL(node); rbtree_select_if_arg_t* arg = arg_; if (RTEST(rb_yield_values(2, key, value)) == arg->if_true) { rbtree_aset(arg->result, key, value); } return EACH_NEXT; } static VALUE rbtree_select_if(VALUE self, const int if_true) { rbtree_select_if_arg_t arg; RETURN_SIZED_ENUMERATOR(self, 0, NULL, rbtree_size); arg.result = rbtree_alloc(CLASS_OF(self)); arg.if_true = if_true; rbtree_for_each(self, select_i, &arg); return arg.result; } /*********************************************************************/ /* * */ VALUE rbtree_reject(VALUE self) { return rbtree_select_if(self, 0); } /* * */ VALUE rbtree_select(VALUE self) { return rbtree_select_if(self, 1); } static VALUE rbtree_shift_pop(VALUE self, const int shift) { dict_t* dict = DICT(self); dnode_t* node; VALUE assoc; rbtree_modify(self); if (dict_isempty(dict)) return rb_funcall(self, id_default, 1, Qnil); if (shift) node = dict_last(dict); else node = dict_first(dict); assoc = ASSOC(node); dict_delete_free(dict, node); return assoc; } /* * call-seq: * rbtree.shift => array or object or nil * * Removes the first (that is, the smallest) key-value pair and * returns it. */ VALUE rbtree_shift(VALUE self) { return rbtree_shift_pop(self, 0); } /* * call-seq: * rbtree.pop => array or object or nil * * Removes the last (that is, the greatest) key-value pair and returns * it. */ VALUE rbtree_pop(VALUE self) { return rbtree_shift_pop(self, 1); } static each_return_t invert_i(dnode_t* node, void* rbtree) { rbtree_aset((VALUE)rbtree, GET_VAL(node), GET_KEY(node)); return EACH_NEXT; } /* * */ VALUE rbtree_invert(VALUE self) { VALUE rbtree = rbtree_alloc(CLASS_OF(self)); rbtree_for_each(self, invert_i, (void*)rbtree); return rbtree; } static each_return_t update_block_i(dnode_t* node, void* self_) { VALUE self = (VALUE)self_; VALUE key = GET_KEY(node); VALUE value = GET_VAL(node); if (rbtree_has_key(self, key)) value = rb_yield_values(3, key, rbtree_aref(self, key), value); rbtree_aset(self, key, value); return EACH_NEXT; } /* * */ VALUE rbtree_update(VALUE self, VALUE other) { rbtree_modify(self); if (self == other) return self; if (!rb_obj_is_kind_of(other, CLASS_OF(self))) { rb_raise(rb_eTypeError, "wrong argument type %s (expected %s)", rb_obj_classname(other), rb_obj_classname(self)); } if (rb_block_given_p()) rbtree_for_each(other, update_block_i, (void*)self); else rbtree_for_each(other, aset_i, (void*)self); return self; } /* * */ VALUE rbtree_merge(VALUE self, VALUE other) { return rbtree_update(rb_obj_dup(self), other); } static each_return_t to_flat_ary_i(dnode_t* node, void* ary) { rb_ary_push((VALUE)ary, GET_KEY(node)); rb_ary_push((VALUE)ary, GET_VAL(node)); return EACH_NEXT; } /* * */ VALUE rbtree_flatten(int argc, VALUE* argv, VALUE self) { VALUE ary; rbtree_check_argument_count(argc, 0, 1); ary = rb_ary_new2(dict_count(DICT(self)) * 2); rbtree_for_each(self, to_flat_ary_i, (void*)ary); if (argc == 1) { const int level = NUM2INT(argv[0]) - 1; if (level > 0) { argv[0] = INT2FIX(level); rb_funcall2(ary, id_flatten_bang, argc, argv); } } return ary; } /* * */ VALUE rbtree_has_key(VALUE self, VALUE key) { return dict_lookup(DICT(self), TO_KEY(key)) == NULL ? Qfalse : Qtrue; } static each_return_t has_value_i(dnode_t* node, void* args_) { VALUE* args = (VALUE*)args_; if (rb_equal(GET_VAL(node), args[1])) { args[0] = Qtrue; return EACH_STOP; } return EACH_NEXT; } /* * */ VALUE rbtree_has_value(VALUE self, VALUE value) { VALUE args[2]; args[0] = Qfalse; args[1] = value; rbtree_for_each(self, has_value_i, &args); return args[0]; } static each_return_t keys_i(dnode_t* node, void* ary) { rb_ary_push((VALUE)ary, GET_KEY(node)); return EACH_NEXT; } /* * */ VALUE rbtree_keys(VALUE self) { VALUE ary = rb_ary_new2(dict_count(DICT(self))); rbtree_for_each(self, keys_i, (void*)ary); return ary; } static each_return_t values_i(dnode_t* node, void* ary) { rb_ary_push((VALUE)ary, GET_VAL(node)); return EACH_NEXT; } /* * */ VALUE rbtree_values(VALUE self) { VALUE ary = rb_ary_new2(dict_count(DICT(self))); rbtree_for_each(self, values_i, (void*)ary); return ary; } static each_return_t to_a_i(dnode_t* node, void* ary) { rb_ary_push((VALUE)ary, ASSOC(node)); return EACH_NEXT; } #if defined(RUBY_API_VERSION_CODE) && RUBY_API_VERSION_CODE >= 30100 # define RBTREE_OBJ_INFECT(obj1, obj2) #else # define RBTREE_OBJ_INFECT(obj1, obj2) OBJ_INFECT(obj1, obj2) #endif /* * */ VALUE rbtree_to_a(VALUE self) { VALUE ary = rb_ary_new2(dict_count(DICT(self))); rbtree_for_each(self, to_a_i, (void*)ary); RBTREE_OBJ_INFECT(ary, self); return ary; } static each_return_t to_hash_i(dnode_t* node, void* hash) { rb_hash_aset((VALUE)hash, GET_KEY(node), GET_VAL(node)); return EACH_NEXT; } /* * */ VALUE rbtree_to_hash(VALUE self) { VALUE hash; if (!rb_obj_is_kind_of(self, RBTree)) rb_raise(rb_eTypeError, "can't convert MultiRBTree to Hash"); hash = rb_hash_new(); rbtree_for_each(self, to_hash_i, (void*)hash); RHASH_SET_IFNONE(hash, IFNONE(self)); if (FL_TEST(self, RBTREE_PROC_DEFAULT)) FL_SET(hash, HASH_PROC_DEFAULT); RBTREE_OBJ_INFECT(hash, self); return hash; } /* * */ VALUE rbtree_to_rbtree(VALUE self) { return self; } static VALUE rbtree_begin_inspect(VALUE self) { VALUE result = rb_str_new2("#<"); rb_str_cat2(result, rb_obj_classname(self)); rb_str_cat2(result, ": "); return result; } static each_return_t inspect_i(dnode_t* node, void* result_) { VALUE result = (VALUE)result_; VALUE str; if (RSTRING_PTR(result)[0] == '-') RSTRING_PTR(result)[0] = '#'; else rb_str_cat2(result, ", "); str = rb_inspect(GET_KEY(node)); rb_str_append(result, str); RBTREE_OBJ_INFECT(result, str); rb_str_cat2(result, "=>"); str = rb_inspect(GET_VAL(node)); rb_str_append(result, str); RBTREE_OBJ_INFECT(result, str); return EACH_NEXT; } static VALUE inspect_rbtree(VALUE self, VALUE result) { VALUE str; rb_str_cat2(result, "{"); RSTRING_PTR(result)[0] = '-'; rbtree_for_each(self, inspect_i, (void*)result); RSTRING_PTR(result)[0] = '#'; rb_str_cat2(result, "}"); str = rb_inspect(IFNONE(self)); rb_str_cat2(result, ", default="); rb_str_append(result, str); RBTREE_OBJ_INFECT(result, str); str = rb_inspect(CMP_PROC(self)); rb_str_cat2(result, ", cmp_proc="); rb_str_append(result, str); RBTREE_OBJ_INFECT(result, str); rb_str_cat2(result, ">"); RBTREE_OBJ_INFECT(result, self); return result; } static VALUE rbtree_inspect_recursive(VALUE self, VALUE arg, int recursive) { VALUE str = rbtree_begin_inspect(self); if (recursive) return rb_str_cat2(str, "...>"); return inspect_rbtree(self, str); } /* * */ VALUE rbtree_inspect(VALUE self) { #ifdef HAVE_RB_EXEC_RECURSIVE return rb_exec_recursive(rbtree_inspect_recursive, self, Qnil); #else VALUE str = rbtree_begin_inspect(self); if (rb_inspecting_p(self)) return rb_str_cat2(str, "...>"); return rb_protect_inspect(inspect_rbtree, self, str); #endif } /* * call-seq: * rbtree.lower_bound(key) => array or nil * * Retruns the key-value pair corresponding to the lowest key that is * equal to or greater than the given key (inside the lower * boundary). If there is no such key, returns nil. * * rbtree = RBTree["az", 10, "ba", 20] * rbtree.lower_bound("ba") # => ["ba", 20] * * # "ba" is the lowest key that is greater than "b" * rbtree.lower_bound("b") # => ["ba", 20] * * # no key that is equal to or greater than "c" * rbtree.lower_bound("c") # => nil */ VALUE rbtree_lower_bound(VALUE self, VALUE key) { dnode_t* node = dict_lower_bound(DICT(self), TO_KEY(key)); if (node == NULL) return Qnil; return ASSOC(node); } /* * call-seq: * rbtree.upper_bound(key) => array or nil * * Retruns the key-value pair corresponding to the greatest key that * is equal to or lower than the given key (inside the upper * boundary). If there is no such key, returns nil. * * rbtree = RBTree["az", 10, "ba", 20] * rbtree.upper_bound("ba") # => ["ba", 20] * * # "az" is the greatest key that is lower than "b" * rbtree.upper_bound("b") # => ["az", 10] * * # no key that is equal to or lower than "a" * rbtree.upper_bound("a") # => nil */ VALUE rbtree_upper_bound(VALUE self, VALUE key) { dnode_t* node = dict_upper_bound(DICT(self), TO_KEY(key)); if (node == NULL) return Qnil; return ASSOC(node); } /*********************************************************************/ typedef struct { VALUE self; dnode_t* lower_node; dnode_t* upper_node; VALUE result; } rbtree_bound_arg_t; static VALUE rbtree_bound_body(VALUE arg_) { rbtree_bound_arg_t* arg = (rbtree_bound_arg_t*)arg_; VALUE self = arg->self; dict_t* dict = DICT(self); dnode_t* lower_node = arg->lower_node; dnode_t* upper_node = arg->upper_node; const int block_given = rb_block_given_p(); VALUE result = arg->result; dnode_t* node; ITER_LEV(self)++; for (node = lower_node; node != NULL; node = dict_next(dict, node)) { if (block_given) rb_yield_values(2, GET_KEY(node), GET_VAL(node)); else rb_ary_push(result, ASSOC(node)); if (node == upper_node) break; } return result; } #ifdef HAVE_SIZED_ENUMERATOR static VALUE rbtree_bound_size(VALUE self, VALUE args) { VALUE key1 = RARRAY_AREF(args, 0); VALUE key2 = RARRAY_AREF(args, RARRAY_LEN(args) - 1); dnode_t* lower_node = dict_lower_bound(DICT(self), TO_KEY(key1)); dnode_t* upper_node = dict_upper_bound(DICT(self), TO_KEY(key2)); dictcount_t count = 0; dnode_t* node; if (lower_node == NULL || upper_node == NULL || DICT(self)->dict_compare(dnode_getkey(lower_node), dnode_getkey(upper_node), DICT(self)->dict_context) > 0) { return INT2FIX(0); } for (node = lower_node; node != NULL; node = dict_next(DICT(self), node)) { count++; if (node == upper_node) { break; } } return ULONG2NUM(count); } #endif /*********************************************************************/ /* * call-seq: * rbtree.bound(key1, key2 = key1) {|key, value| block} => rbtree * rbtree.bound(key1, key2 = key1) => enumerator * * Calls block once for each key between the result of * rbtree.lower_bound(key1) and rbtree.upper_bound(key2) in order, * passing the key-value pair as parameters. If the lower bound * exceeds the upper bound, block is not called. * * Returns an enumerator if no block is given. * * mrbtree = MultiRBTree["az", 10, "ba", 20, "ba", 30, "bz", 40] * mrbtree.bound("ba").to_a # => [["ba", 20], ["ba", 30]] * mrbtree.bound("b", "c").to_a # => [["ba", 20], ["ba", 30], ["bz", 40]] * * # the lower bound ("ba") exceeds the upper bound ("az") * mrbtree.bound("b").to_a # => [] */ VALUE rbtree_bound(int argc, VALUE* argv, VALUE self) { dict_t* dict = DICT(self); dnode_t* lower_node; dnode_t* upper_node; VALUE result; rbtree_check_argument_count(argc, 1, 2); RETURN_SIZED_ENUMERATOR(self, argc, argv, rbtree_bound_size); lower_node = dict_lower_bound(dict, TO_KEY(argv[0])); upper_node = dict_upper_bound(dict, TO_KEY(argv[argc - 1])); result = rb_block_given_p() ? self : rb_ary_new(); if (lower_node == NULL || upper_node == NULL || DICT(self)->dict_compare(dnode_getkey(lower_node), dnode_getkey(upper_node), DICT(self)->dict_context) > 0) { return result; } else { rbtree_bound_arg_t arg; arg.self = self; arg.lower_node = lower_node; arg.upper_node = upper_node; arg.result = result; return rb_ensure(rbtree_bound_body, (VALUE)&arg, rbtree_each_ensure, self); } } static VALUE rbtree_first_last(VALUE self, const int first) { dict_t* dict = DICT(self); dnode_t* node; if (dict_isempty(dict)) return rb_funcall(self, id_default, 1, Qnil); if (first) node = dict_first(dict); else node = dict_last(dict); return ASSOC(node); } /* * call-seq: * rbtree.first => array or object or nil * * Returns the first (that is, the smallest) key-value pair. */ VALUE rbtree_first(VALUE self) { return rbtree_first_last(self, 1); } /* * call-seq: * rbtree.last => array or object or nil * * Returns the last (that is, the greatest) key-value pair. */ VALUE rbtree_last(VALUE self) { return rbtree_first_last(self, 0); } /* * call-seq: * rbtree.readjust => rbtree * rbtree.readjust(nil) => rbtree * rbtree.readjust(proc) => rbtree * rbtree.readjust {|key1, key2| block} => rbtree * * Sets a proc to compare keys and readjusts elements using the given * block or a Proc object given as an argument. The block takes two * keys and returns a negative integer, 0, or a positive integer as * the first argument is less than, equal to, or greater than the * second one. If no block is given, just readjusts elements using the * current comparison block. If nil is given as an argument the * default comparison block that uses the <=> method is set. * * rbtree = RBTree["a", 10, "b", 20] * rbtree.readjust {|a, b| b <=> a } * rbtree.first # => ["b", 20] * * rbtree.readjust(nil) * rbtree.first # => ["a", 10] */ VALUE rbtree_readjust(int argc, VALUE* argv, VALUE self) { dict_comp_t cmp_func = NULL; VALUE cmp_proc = Qnil; rbtree_modify(self); if (rb_block_given_p()) { rbtree_check_argument_count(argc, 0, 0); cmp_func = rbtree_user_cmp; cmp_proc = rb_block_proc(); rbtree_check_proc_arity(cmp_proc, 2); } else { rbtree_check_argument_count(argc, 0, 1); if (argc == 0) { cmp_func = DICT(self)->dict_compare; cmp_proc = CMP_PROC(self); } else { if (NIL_P(argv[0])) { cmp_func = rbtree_cmp; cmp_proc = Qnil; } else { VALUE proc = rb_check_convert_type(argv[0], T_DATA, "Proc", "to_proc"); if (NIL_P(proc)) { rb_raise(rb_eTypeError, "wrong cmp_proc type %s (expected Proc)", rb_obj_classname(argv[0])); } cmp_func = rbtree_user_cmp; cmp_proc = proc; rbtree_check_proc_arity(cmp_proc, 2); } } } if (dict_isempty(DICT(self))) { DICT(self)->dict_compare = cmp_func; CMP_PROC(self) = cmp_proc; return self; } copy_dict(self, self, cmp_func, cmp_proc); return self; } /* * call-seq: * rbtree.cmp_proc => proc or nil * * Returns the comparison block that is set by * MultiRBTree#readjust. If the default comparison block is set, * returns nil. */ VALUE rbtree_cmp_proc(VALUE self) { return CMP_PROC(self); } /*********************************************************************/ static ID id_breakable; static ID id_comma_breakable; static ID id_group; static ID id_object_group; static ID id_pp; static ID id_text; #if defined(RUBY_VERSION_MAJOR) && RUBY_VERSION_MAJOR == 1 && RUBY_VERSION_MINOR == 8 #define RUBY_1_8 #endif #ifdef RUBY_1_8 static VALUE pp_group(VALUE args_) { VALUE* args = (VALUE*)args_; return rb_funcall(args[0], id_group, 3, args[1], args[2], args[3]); } #endif static VALUE call_group_with_block(VALUE *group_args, VALUE (*blk)(RB_BLOCK_CALL_FUNC_ARGLIST(nil, arg)), VALUE data) { #ifdef RUBY_1_8 return rb_iterate(pp_group, (VALUE)&group_args, blk, data); #else return rb_block_call(group_args[0], id_group, 3, group_args + 1, blk, data); #endif } typedef struct { VALUE pp; dnode_t* node; } pp_pair_arg_t; static VALUE pp_value(RB_BLOCK_CALL_FUNC_ARGLIST(nil, arg)) { pp_pair_arg_t* pair_arg = (pp_pair_arg_t*)arg; VALUE pp = pair_arg->pp; rb_funcall(pp, id_breakable, 1, rb_str_new(NULL, 0)); return rb_funcall(pp, id_pp, 1, GET_VAL(pair_arg->node)); } static VALUE pp_pair(RB_BLOCK_CALL_FUNC_ARGLIST(nil, arg)) { pp_pair_arg_t* pair_arg = (pp_pair_arg_t*)arg; VALUE pp = pair_arg->pp; VALUE group_args[4]; group_args[0] = pp; group_args[1] = INT2FIX(1); group_args[2] = rb_str_new(NULL, 0); group_args[3] = rb_str_new(NULL, 0); rb_funcall(pp, id_pp, 1, GET_KEY(pair_arg->node)); rb_funcall(pp, id_text, 1, rb_str_new2("=>")); return call_group_with_block(group_args, pp_value, (VALUE)pair_arg); } typedef struct { VALUE pp; int first; } pp_each_pair_arg_t; static each_return_t pp_each_pair_i(dnode_t* node, void* each_pair_arg_) { pp_each_pair_arg_t* each_pair_arg = (pp_each_pair_arg_t*)each_pair_arg_; VALUE group_args[4]; pp_pair_arg_t pair_arg; if (each_pair_arg->first) { each_pair_arg->first = 0; } else { rb_funcall(each_pair_arg->pp, id_comma_breakable, 0); } group_args[0] = each_pair_arg->pp; group_args[1] = INT2FIX(0); group_args[2] = rb_str_new(NULL, 0); group_args[3] = rb_str_new(NULL, 0); pair_arg.pp = each_pair_arg->pp; pair_arg.node = node; call_group_with_block(group_args, pp_pair, (VALUE)&pair_arg); return EACH_NEXT; } typedef struct { VALUE pp; VALUE rbtree; } pp_rbtree_arg_t; static VALUE pp_each_pair(RB_BLOCK_CALL_FUNC_ARGLIST(nil, arg)) { pp_rbtree_arg_t* rbtree_arg = (pp_rbtree_arg_t*)arg; pp_each_pair_arg_t each_pair_arg; each_pair_arg.pp = rbtree_arg->pp; each_pair_arg.first = 1; return rbtree_for_each(rbtree_arg->rbtree, pp_each_pair_i, &each_pair_arg); } static VALUE pp_rbtree(RB_BLOCK_CALL_FUNC_ARGLIST(nil, arg)) { pp_rbtree_arg_t* rbtree_arg = (pp_rbtree_arg_t*)arg; VALUE pp = rbtree_arg->pp; VALUE rbtree = rbtree_arg->rbtree; VALUE group_args[4]; group_args[0] = pp; group_args[1] = INT2FIX(1); group_args[2] = rb_str_new2("{"); group_args[3] = rb_str_new2("}"); rb_funcall(pp, id_text, 1, rb_str_new2(": ")); call_group_with_block(group_args, pp_each_pair, (VALUE)rbtree_arg); rb_funcall(pp, id_comma_breakable, 0); rb_funcall(pp, id_text, 1, rb_str_new2("default=")); rb_funcall(pp, id_pp, 1, IFNONE(rbtree)); rb_funcall(pp, id_comma_breakable, 0); rb_funcall(pp, id_text, 1, rb_str_new2("cmp_proc=")); return rb_funcall(pp, id_pp, 1, CMP_PROC(rbtree)); } #ifdef RUBY_1_8 static VALUE pp_rbtree_group(VALUE arg_) { pp_rbtree_arg_t* arg = (pp_rbtree_arg_t*)arg_; return rb_funcall(arg->pp, id_object_group, 1, arg->rbtree); } #endif /*********************************************************************/ /* :nodoc: * */ VALUE rbtree_pretty_print(VALUE self, VALUE pp) { pp_rbtree_arg_t arg; arg.rbtree = self; arg.pp = pp; #ifdef RUBY_1_8 return rb_iterate(pp_rbtree_group, (VALUE)&arg, pp_rbtree, (VALUE)&arg); #else return rb_block_call(arg.pp, id_object_group, 1, &self, pp_rbtree, (VALUE)&arg); #endif } /* :nodoc: * */ VALUE rbtree_pretty_print_cycle(VALUE self, VALUE pp) { return rb_funcall(pp, id_pp, 1, rbtree_inspect_recursive(self, Qnil, 1)); } /*********************************************************************/ /* :nodoc: * */ VALUE rbtree_dump(VALUE self, VALUE limit) { VALUE ary; VALUE result; if (FL_TEST(self, RBTREE_PROC_DEFAULT)) rb_raise(rb_eTypeError, "can't dump rbtree with default proc"); if (CMP_PROC(self) != Qnil) rb_raise(rb_eTypeError, "can't dump rbtree with comparison proc"); ary = rb_ary_new2(dict_count(DICT(self)) * 2 + 1); rbtree_for_each(self, to_flat_ary_i, (void*)ary); rb_ary_push(ary, IFNONE(self)); result = rb_marshal_dump(ary, Qnil); #ifdef HAVE_RB_ARY_RESIZE rb_ary_resize(ary, 0); #else rb_ary_clear(ary); #endif return result; } /* :nodoc: * */ VALUE rbtree_s_load(VALUE klass, VALUE str) { VALUE rbtree = rbtree_alloc(klass); VALUE ary = rb_marshal_load(str); long len = RARRAY_LEN(ary) - 1; long i; for (i = 0; i < len; i += 2) rbtree_aset(rbtree, RARRAY_AREF(ary, i), RARRAY_AREF(ary, i + 1)); IFNONE(rbtree) = RARRAY_AREF(ary, len); #ifdef HAVE_RB_ARY_RESIZE rb_ary_resize(ary, 0); #else rb_ary_clear(ary); #endif return rbtree; } /*********************************************************************/ /* * Document-class: MultiRBTree * * A sorted associative collection that can contain duplicate keys. */ /* * A sorted associative collection that cannot contain duplicate * keys. RBTree is a subclass of MultiRBTree. */ void Init_rbtree(void) { MultiRBTree = rb_define_class("MultiRBTree", #ifdef HAVE_RB_CDATA rb_cData #else rb_cObject #endif ); RBTree = rb_define_class("RBTree", MultiRBTree); rb_include_module(MultiRBTree, rb_mEnumerable); rb_define_alloc_func(MultiRBTree, rbtree_alloc); rb_define_singleton_method(MultiRBTree, "[]", rbtree_s_create, -1); rb_define_method(MultiRBTree, "initialize", rbtree_initialize, -1); rb_define_method(MultiRBTree, "initialize_copy", rbtree_initialize_copy, 1); rb_define_method(MultiRBTree, "to_a", rbtree_to_a, 0); rb_define_method(MultiRBTree, "to_h", rbtree_to_hash, 0); rb_define_method(MultiRBTree, "to_hash", rbtree_to_hash, 0); rb_define_method(MultiRBTree, "to_rbtree", rbtree_to_rbtree, 0); rb_define_method(MultiRBTree, "inspect", rbtree_inspect, 0); rb_define_alias(MultiRBTree, "to_s", "inspect"); rb_define_method(MultiRBTree, "==", rbtree_equal, 1); rb_define_method(MultiRBTree, "[]", rbtree_aref, 1); rb_define_method(MultiRBTree, "fetch", rbtree_fetch, -1); rb_define_method(MultiRBTree, "lower_bound", rbtree_lower_bound, 1); rb_define_method(MultiRBTree, "upper_bound", rbtree_upper_bound, 1); rb_define_method(MultiRBTree, "bound", rbtree_bound, -1); rb_define_method(MultiRBTree, "first", rbtree_first, 0); rb_define_method(MultiRBTree, "last", rbtree_last, 0); rb_define_method(MultiRBTree, "[]=", rbtree_aset, 2); rb_define_method(MultiRBTree, "store", rbtree_aset, 2); rb_define_method(MultiRBTree, "default", rbtree_default, -1); rb_define_method(MultiRBTree, "default=", rbtree_set_default, 1); rb_define_method(MultiRBTree, "default_proc", rbtree_default_proc, 0); rb_define_method(MultiRBTree, "default_proc=", rbtree_set_default_proc, 1); rb_define_method(MultiRBTree, "key", rbtree_key, 1); rb_define_method(MultiRBTree, "index", rbtree_index, 1); rb_define_method(MultiRBTree, "empty?", rbtree_empty_p, 0); rb_define_method(MultiRBTree, "size", rbtree_size, 0); rb_define_method(MultiRBTree, "length", rbtree_size, 0); rb_define_method(MultiRBTree, "each", rbtree_each_pair, 0); rb_define_method(MultiRBTree, "each_value", rbtree_each_value, 0); rb_define_method(MultiRBTree, "each_key", rbtree_each_key, 0); rb_define_method(MultiRBTree, "each_pair", rbtree_each_pair, 0); rb_define_method(MultiRBTree, "reverse_each", rbtree_reverse_each, 0); rb_define_method(MultiRBTree, "keys", rbtree_keys, 0); rb_define_method(MultiRBTree, "values", rbtree_values, 0); rb_define_method(MultiRBTree, "values_at", rbtree_values_at, -1); rb_define_method(MultiRBTree, "shift", rbtree_shift, 0); rb_define_method(MultiRBTree, "pop", rbtree_pop, 0); rb_define_method(MultiRBTree, "delete", rbtree_delete, 1); rb_define_method(MultiRBTree, "delete_if", rbtree_delete_if, 0); rb_define_method(MultiRBTree, "keep_if", rbtree_keep_if, 0); rb_define_method(MultiRBTree, "reject", rbtree_reject, 0); rb_define_method(MultiRBTree, "reject!", rbtree_reject_bang, 0); rb_define_method(MultiRBTree, "select", rbtree_select, 0); rb_define_method(MultiRBTree, "select!", rbtree_select_bang, 0); rb_define_method(MultiRBTree, "clear", rbtree_clear, 0); rb_define_method(MultiRBTree, "invert", rbtree_invert, 0); rb_define_method(MultiRBTree, "update", rbtree_update, 1); rb_define_method(MultiRBTree, "merge!", rbtree_update, 1); rb_define_method(MultiRBTree, "merge", rbtree_merge, 1); rb_define_method(MultiRBTree, "replace", rbtree_initialize_copy, 1); #ifdef HAVE_HASH_FLATTEN rb_define_method(MultiRBTree, "flatten", rbtree_flatten, -1); #endif rb_define_method(MultiRBTree, "include?", rbtree_has_key, 1); rb_define_method(MultiRBTree, "member?", rbtree_has_key, 1); rb_define_method(MultiRBTree, "has_key?", rbtree_has_key, 1); rb_define_method(MultiRBTree, "has_value?", rbtree_has_value, 1); rb_define_method(MultiRBTree, "key?", rbtree_has_key, 1); rb_define_method(MultiRBTree, "value?", rbtree_has_value, 1); rb_define_method(MultiRBTree, "readjust", rbtree_readjust, -1); rb_define_method(MultiRBTree, "cmp_proc", rbtree_cmp_proc, 0); rb_define_method(MultiRBTree, "_dump", rbtree_dump, 1); rb_define_singleton_method(MultiRBTree, "_load", rbtree_s_load, 1); id_cmp = rb_intern("<=>"); id_call = rb_intern("call"); id_default = rb_intern("default"); id_flatten_bang = rb_intern("flatten!"); rb_define_method(MultiRBTree, "pretty_print", rbtree_pretty_print, 1); rb_define_method(MultiRBTree, "pretty_print_cycle", rbtree_pretty_print_cycle, 1); id_breakable = rb_intern("breakable"); id_comma_breakable = rb_intern("comma_breakable"); id_group = rb_intern("group"); id_object_group = rb_intern("object_group"); id_pp = rb_intern("pp"); id_text = rb_intern("text"); } rbtree-0.4.6/LICENSE0000644000004100000410000000204514353333751014051 0ustar www-datawww-dataCopyright (c) 2002-2013 OZAWA Takuma Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. rbtree-0.4.6/rbtree.gemspec0000644000004100000410000000270714353333751015701 0ustar www-datawww-data######################################################### # This file has been automatically generated by gem2tgz # ######################################################### # -*- encoding: utf-8 -*- # stub: rbtree 0.4.6 ruby lib # stub: extconf.rb Gem::Specification.new do |s| s.name = "rbtree".freeze s.version = "0.4.6" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] s.authors = ["OZAWA Takuma".freeze] s.date = "2022-12-10" s.description = "A RBTree is a sorted associative collection that is implemented with a\nRed-Black Tree. It maps keys to values like a Hash, but maintains its\nelements in ascending key order. The interface is the almost identical\nto that of Hash.\n".freeze s.extensions = ["extconf.rb".freeze] s.extra_rdoc_files = ["README".freeze, "rbtree.c".freeze] s.files = ["LICENSE".freeze, "MANIFEST".freeze, "README".freeze, "depend".freeze, "dict.c".freeze, "dict.h".freeze, "extconf.rb".freeze, "rbtree.c".freeze, "test.rb".freeze] s.homepage = "http://rbtree.rubyforge.org/".freeze s.licenses = ["MIT".freeze] s.rdoc_options = ["--title".freeze, "Ruby/RBTree".freeze, "--main".freeze, "README".freeze, "--exclude".freeze, "\\A(?!README|rbtree\\.c).*\\z".freeze] s.required_ruby_version = Gem::Requirement.new(">= 1.8.6".freeze) s.rubygems_version = "3.2.5".freeze s.summary = "A sorted associative collection.".freeze end rbtree-0.4.6/test.rb0000644000004100000410000007034314353333751014356 0ustar www-datawww-databegin require "./rbtree" rescue LoadError require "rubygems" require "rbtree" end require "test/unit.rb" class RBTreeTest < Test::Unit::TestCase def setup @rbtree = RBTree[*%w(b B d D a A c C)] end def have_enumerator? defined?(Enumerable::Enumerator) or defined?(Enumerator) end def test_new assert_nothing_raised { RBTree.new RBTree.new("a") RBTree.new { "a" } } assert_raises(ArgumentError) { RBTree.new("a") {} } assert_raises(ArgumentError) { RBTree.new("a", "a") } if RUBY_VERSION >= "1.9.2" assert_nothing_raised { RBTree.new(&lambda {|a, b|}) RBTree.new(&lambda {|*a|}) RBTree.new(&lambda {|a, *b|}) RBTree.new(&lambda {|a, b, *c|}) } assert_raises(TypeError) { RBTree.new(&lambda {|a|}) } assert_raises(TypeError) { RBTree.new(&lambda {|a, b, c|}) } assert_raises(TypeError) { RBTree.new(&lambda {|a, b, c, *d|}) } end end def test_aref assert_equal("A", @rbtree["a"]) assert_equal("B", @rbtree["b"]) assert_equal("C", @rbtree["c"]) assert_equal("D", @rbtree["d"]) assert_equal(nil, @rbtree["e"]) @rbtree.default = "E" assert_equal("E", @rbtree["e"]) end def test_size assert_equal(4, @rbtree.size) end def test_create rbtree = RBTree[] assert_equal(0, rbtree.size) rbtree = RBTree[@rbtree] assert_equal(4, rbtree.size) assert_equal("A", @rbtree["a"]) assert_equal("B", @rbtree["b"]) assert_equal("C", @rbtree["c"]) assert_equal("D", @rbtree["d"]) rbtree = RBTree[RBTree.new("e")] assert_equal(nil, rbtree.default) rbtree = RBTree[RBTree.new { "e" }] assert_equal(nil, rbtree.default_proc) @rbtree.readjust {|a,b| b <=> a } assert_equal(nil, RBTree[@rbtree].cmp_proc) assert_raises(ArgumentError) { RBTree["e"] } rbtree = RBTree[Hash[*%w(b B d D a A c C)]] assert_equal(4, rbtree.size) assert_equal("A", rbtree["a"]) assert_equal("B", rbtree["b"]) assert_equal("C", rbtree["c"]) assert_equal("D", rbtree["d"]) rbtree = RBTree[[%w(a A), %w(b B), %w(c C), %w(d D)]]; assert_equal(4, rbtree.size) assert_equal("A", rbtree["a"]) assert_equal("B", rbtree["b"]) assert_equal("C", rbtree["c"]) assert_equal("D", rbtree["d"]) # assert_raises(ArgumentError) { RBTree[["a"]] } rbtree = RBTree[[["a"]]] assert_equal(1, rbtree.size) assert_equal(nil, rbtree["a"]) # assert_raises(ArgumentError) { RBTree[[["a", "A", "b", "B"]]] } end def test_clear @rbtree.clear assert_equal(0, @rbtree.size) end def test_aset @rbtree["e"] = "E" assert_equal(5, @rbtree.size) assert_equal("E", @rbtree["e"]) @rbtree["c"] = "E" assert_equal(5, @rbtree.size) assert_equal("E", @rbtree["c"]) assert_raises(ArgumentError) { @rbtree[100] = 100 } assert_equal(5, @rbtree.size) key = "f" @rbtree[key] = "F" cloned_key = @rbtree.last[0] assert_equal("f", cloned_key) assert_not_same(key, cloned_key) assert_equal(true, cloned_key.frozen?) @rbtree["f"] = "F" assert_same(cloned_key, @rbtree.last[0]) rbtree = RBTree.new key = ["g"] rbtree[key] = "G" assert_same(key, rbtree.first[0]) assert_equal(false, key.frozen?) end def test_clone clone = @rbtree.clone assert_equal(4, @rbtree.size) assert_equal("A", @rbtree["a"]) assert_equal("B", @rbtree["b"]) assert_equal("C", @rbtree["c"]) assert_equal("D", @rbtree["d"]) rbtree = RBTree.new("e") clone = rbtree.clone assert_equal("e", clone.default) rbtree = RBTree.new { "e" } clone = rbtree.clone assert_equal("e", clone.default(nil)) rbtree = RBTree.new rbtree.readjust {|a, b| a <=> b } clone = rbtree.clone assert_equal(rbtree.cmp_proc, clone.cmp_proc) end def test_default rbtree = RBTree.new("e") assert_equal("e", rbtree.default) assert_equal("e", rbtree.default("f")) assert_raises(ArgumentError) { rbtree.default("e", "f") } rbtree = RBTree.new {|tree, key| @rbtree[key || "c"] } assert_equal(nil, rbtree.default) assert_equal("C", rbtree.default(nil)) assert_equal("B", rbtree.default("b")) end def test_set_default rbtree = RBTree.new { "e" } rbtree.default = "f" assert_equal("f", rbtree.default) assert_equal(nil, rbtree.default_proc) rbtree = RBTree.new { "e" } rbtree.default = nil assert_equal(nil, rbtree.default) assert_equal(nil, rbtree.default_proc) end def test_default_proc rbtree = RBTree.new("e") assert_equal(nil, rbtree.default_proc) rbtree = RBTree.new { "f" } assert_equal("f", rbtree.default_proc.call) end def test_set_default_proc rbtree = RBTree.new("e") rbtree.default_proc = Proc.new { "f" } assert_equal(nil, rbtree.default) assert_equal("f", rbtree.default_proc.call) rbtree = RBTree.new("e") rbtree.default_proc = nil assert_equal(nil, rbtree.default) assert_equal(nil, rbtree.default_proc) if Symbol.method_defined?(:to_proc) @rbtree.default_proc = :upper_bound assert_equal(%w(d D), @rbtree["e"]) end assert_raises(TypeError) { rbtree.default_proc = "f" } if RUBY_VERSION >= "1.9.2" assert_nothing_raised { @rbtree.default_proc = lambda {|a, b|} @rbtree.default_proc = lambda {|*a|} @rbtree.default_proc = lambda {|a, *b|} @rbtree.default_proc = lambda {|a, b, *c|} } assert_raises(TypeError) { @rbtree.default_proc = lambda {|a|} } assert_raises(TypeError) { @rbtree.default_proc = lambda {|a, b, c|} } assert_raises(TypeError) { @rbtree.default_proc = lambda {|a, b, c, *d|} } end end def test_equal assert_equal(RBTree.new, RBTree.new) assert_equal(@rbtree, @rbtree) assert_not_equal(@rbtree, RBTree.new) rbtree = RBTree[*%w(b B d D a A c C)] assert_equal(@rbtree, rbtree) rbtree["d"] = "A" assert_not_equal(@rbtree, rbtree) rbtree["d"] = "D" rbtree["e"] = "E" assert_not_equal(@rbtree, rbtree) @rbtree["e"] = "E" assert_equal(@rbtree, rbtree) rbtree.default = "e" assert_equal(@rbtree, rbtree) @rbtree.default = "f" assert_equal(@rbtree, rbtree) a = RBTree.new("e") b = RBTree.new { "f" } assert_equal(a, b) assert_equal(b, b.clone) a = RBTree.new b = RBTree.new a.readjust {|x, y| x <=> y } assert_not_equal(a, b) b.readjust(a.cmp_proc) assert_equal(a, b) if RUBY_VERSION >= "1.8.7" a = RBTree.new a[1] = a b = RBTree.new b[1] = b assert_equal(a, b) end end def test_fetch assert_equal("A", @rbtree.fetch("a")) assert_equal("B", @rbtree.fetch("b")) assert_equal("C", @rbtree.fetch("c")) assert_equal("D", @rbtree.fetch("d")) assert_raises(IndexError) { @rbtree.fetch("e") } assert_equal("E", @rbtree.fetch("e", "E")) assert_equal("E", @rbtree.fetch("e") { "E" }) # assert_equal("E", @rbtree.fetch("e", "F") { "E" }) assert_raises(ArgumentError) { @rbtree.fetch } assert_raises(ArgumentError) { @rbtree.fetch("e", "E", "E") } end def test_key assert_equal("a", @rbtree.key("A")) assert_equal(nil, @rbtree.key("E")) end def test_empty_p assert_equal(false, @rbtree.empty?) @rbtree.clear assert_equal(true, @rbtree.empty?) end def test_each result = [] @rbtree.each {|key, val| result << key << val } assert_equal(%w(a A b B c C d D), result) assert_raises(TypeError) { @rbtree.each { @rbtree["e"] = "E" } } assert_equal(4, @rbtree.size) @rbtree.each { @rbtree.each {} assert_raises(TypeError) { @rbtree["e"] = "E" } break } assert_equal(4, @rbtree.size) if have_enumerator? enumerator = @rbtree.each assert_equal(%w(a A b B c C d D), enumerator.to_a.flatten) end end def test_each_key result = [] @rbtree.each_key {|key| result.push(key) } assert_equal(%w(a b c d), result) assert_raises(TypeError) { @rbtree.each_key { @rbtree["e"] = "E" } } assert_equal(4, @rbtree.size) @rbtree.each_key { @rbtree.each_key {} assert_raises(TypeError) { @rbtree["e"] = "E" } break } assert_equal(4, @rbtree.size) if have_enumerator? enumerator = @rbtree.each_key assert_equal(%w(a b c d), enumerator.to_a.flatten) end end def test_each_value result = [] @rbtree.each_value {|val| result.push(val) } assert_equal(%w(A B C D), result) assert_raises(TypeError) { @rbtree.each_value { @rbtree["e"] = "E" } } assert_equal(4, @rbtree.size) @rbtree.each_value { @rbtree.each_value {} assert_raises(TypeError) { @rbtree["e"] = "E" } break } assert_equal(4, @rbtree.size) if have_enumerator? enumerator = @rbtree.each_value assert_equal(%w(A B C D), enumerator.to_a.flatten) end end def test_shift result = @rbtree.shift assert_equal(3, @rbtree.size) assert_equal(%w(a A), result) assert_equal(nil, @rbtree["a"]) 3.times { @rbtree.shift } assert_equal(0, @rbtree.size) assert_equal(nil, @rbtree.shift) @rbtree.default = "e" assert_equal("e", @rbtree.shift) rbtree = RBTree.new { "e" } assert_equal("e", rbtree.shift) end def test_pop result = @rbtree.pop assert_equal(3, @rbtree.size) assert_equal(%w(d D), result) assert_equal(nil, @rbtree["d"]) 3.times { @rbtree.pop } assert_equal(0, @rbtree.size) assert_equal(nil, @rbtree.pop) @rbtree.default = "e" assert_equal("e", @rbtree.pop) rbtree = RBTree.new { "e" } assert_equal("e", rbtree.pop) end def test_delete result = @rbtree.delete("c") assert_equal("C", result) assert_equal(3, @rbtree.size) assert_equal(nil, @rbtree["c"]) assert_equal(nil, @rbtree.delete("e")) assert_equal("E", @rbtree.delete("e") { "E" }) end def test_delete_if result = @rbtree.delete_if {|key, val| val == "A" || val == "B" } assert_same(@rbtree, result) assert_equal(RBTree[*%w(c C d D)], @rbtree) assert_raises(ArgumentError) { @rbtree.delete_if {|key, val| key == "c" or raise ArgumentError } } assert_equal(2, @rbtree.size) assert_raises(TypeError) { @rbtree.delete_if { @rbtree["e"] = "E" } } assert_equal(2, @rbtree.size) @rbtree.delete_if { @rbtree.each { assert_equal(2, @rbtree.size) } assert_raises(TypeError) { @rbtree["e"] = "E" } true } assert_equal(0, @rbtree.size) if have_enumerator? rbtree = RBTree[*%w(b B d D a A c C)] rbtree.delete_if.with_index {|(key, val), i| i < 2 } assert_equal(RBTree[*%w(c C d D)], rbtree) end end def test_keep_if result = @rbtree.keep_if {|key, val| val == "A" || val == "B" } assert_same(@rbtree, result) assert_equal(RBTree[*%w(a A b B)], @rbtree) if have_enumerator? rbtree = RBTree[*%w(b B d D a A c C)] rbtree.keep_if.with_index {|(key, val), i| i < 2 } assert_equal(RBTree[*%w(a A b B)], rbtree) end end def test_reject_bang result = @rbtree.reject! { false } assert_equal(nil, result) assert_equal(4, @rbtree.size) result = @rbtree.reject! {|key, val| val == "A" || val == "B" } assert_same(@rbtree, result) assert_equal(RBTree[*%w(c C d D)], result) if have_enumerator? rbtree = RBTree[*%w(b B d D a A c C)] rbtree.reject!.with_index {|(key, val), i| i < 2 } assert_equal(RBTree[*%w(c C d D)], rbtree) end end def test_reject result = @rbtree.reject { false } assert_equal(RBTree[*%w(a A b B c C d D)], result) assert_equal(4, @rbtree.size) result = @rbtree.reject {|key, val| val == "A" || val == "B" } assert_equal(RBTree[*%w(c C d D)], result) assert_equal(4, @rbtree.size) if have_enumerator? result = @rbtree.reject.with_index {|(key, val), i| i < 2 } assert_equal(RBTree[*%w(c C d D)], result) end end def test_select_bang result = @rbtree.select! { true } assert_equal(nil, result) assert_equal(4, @rbtree.size) result = @rbtree.select! {|key, val| val == "A" || val == "B" } assert_same(@rbtree, result) assert_equal(RBTree[*%w(a A b B)], result) if have_enumerator? rbtree = RBTree[*%w(b B d D a A c C)] rbtree.select!.with_index {|(key, val), i| i < 2 } assert_equal(RBTree[*%w(a A b B)], rbtree) end end def test_select result = @rbtree.select { true } assert_equal(RBTree[*%w(a A b B c C d D)], result) assert_equal(4, @rbtree.size) result = @rbtree.select {|key, val| val == "A" || val == "B" } assert_equal(RBTree[*%w(a A b B)], result) assert_raises(ArgumentError) { @rbtree.select("c") } if have_enumerator? result = @rbtree.select.with_index {|(key, val), i| i < 2 } assert_equal(RBTree[*%w(a A b B)], result) end end def test_values_at result = @rbtree.values_at("d", "a", "e") assert_equal(["D", "A", nil], result) end def test_invert assert_equal(RBTree[*%w(A a B b C c D d)], @rbtree.invert) end def test_update rbtree = RBTree.new rbtree["e"] = "E" @rbtree.update(rbtree) assert_equal(RBTree[*%w(a A b B c C d D e E)], @rbtree) @rbtree.clear @rbtree["d"] = "A" rbtree.clear rbtree["d"] = "B" @rbtree.update(rbtree) {|key, val1, val2| val1 + val2 if key == "d" } assert_equal(RBTree[*%w(d AB)], @rbtree) assert_raises(TypeError) { @rbtree.update("e") } end def test_merge rbtree = RBTree.new rbtree["e"] = "E" result = @rbtree.merge(rbtree) assert_equal(RBTree[*%w(a A b B c C d D e E)], result) assert_equal(4, @rbtree.size) end if MultiRBTree.method_defined?(:flatten) def test_flatten rbtree = RBTree.new rbtree.readjust {|a, b| a.flatten <=> b.flatten } rbtree[["a"]] = ["A"] rbtree[[["b"]]] = [["B"]] assert_equal([["a"], ["A"], [["b"]], [["B"]]], rbtree.flatten) assert_equal([["a"], ["A"], [["b"]], [["B"]]], rbtree.flatten(0)) assert_equal([["a"], ["A"], [["b"]], [["B"]]], rbtree.flatten(1)) assert_equal(["a", "A", ["b"], ["B"]], rbtree.flatten(2)) assert_equal(["a", "A", "b", "B"], rbtree.flatten(3)) assert_raises(TypeError) { @rbtree.flatten("e") } assert_raises(ArgumentError) { @rbtree.flatten(1, 2) } end end def test_has_key assert_equal(true, @rbtree.has_key?("a")) assert_equal(true, @rbtree.has_key?("b")) assert_equal(true, @rbtree.has_key?("c")) assert_equal(true, @rbtree.has_key?("d")) assert_equal(false, @rbtree.has_key?("e")) end def test_has_value assert_equal(true, @rbtree.has_value?("A")) assert_equal(true, @rbtree.has_value?("B")) assert_equal(true, @rbtree.has_value?("C")) assert_equal(true, @rbtree.has_value?("D")) assert_equal(false, @rbtree.has_value?("E")) end def test_keys assert_equal(%w(a b c d), @rbtree.keys) end def test_values assert_equal(%w(A B C D), @rbtree.values) end def test_to_a assert_equal([%w(a A), %w(b B), %w(c C), %w(d D)], @rbtree.to_a) end def test_to_hash @rbtree.default = "e" hash = @rbtree.to_hash assert_equal(@rbtree.to_a.flatten, hash.sort_by {|key, val| key}.flatten) assert_equal("e", hash.default) rbtree = RBTree.new { "e" } hash = rbtree.to_hash if (hash.respond_to?(:default_proc)) assert_equal(rbtree.default_proc, hash.default_proc) else assert_equal(rbtree.default_proc, hash.default) end end def test_to_rbtree assert_same(@rbtree, @rbtree.to_rbtree) end def test_inspect [:to_s, :inspect].each do |method| @rbtree.default = "e" @rbtree.readjust {|a, b| a <=> b} re = /#/ assert_match(re, @rbtree.send(method)) match = re.match(@rbtree.send(method)) tree, default, cmp_proc = match.to_a[1..-1] assert_equal(%({"a"=>"A", "b"=>"B", "c"=>"C", "d"=>"D"}), tree) assert_equal(%("e"), default) assert_match(/#/o, cmp_proc) rbtree = RBTree.new assert_match(re, rbtree.send(method)) match = re.match(rbtree.send(method)) tree, default, cmp_proc = match.to_a[1..-1] assert_equal("{}", tree) assert_equal("nil", default) assert_equal("nil", cmp_proc) next if method == :to_s and RUBY_VERSION < "1.9" rbtree = RBTree.new rbtree[rbtree] = rbtree rbtree.default = rbtree match = re.match(rbtree.send(method)) tree, default, cmp_proc = match.to_a[1..-1] assert_equal("{#=>#}", tree) assert_equal("#", default) assert_equal("nil", cmp_proc) end end def test_lower_bound rbtree = RBTree[*%w(a A c C e E)] assert_equal(%w(c C), rbtree.lower_bound("c")) assert_equal(%w(c C), rbtree.lower_bound("b")) assert_equal(nil, rbtree.lower_bound("f")) end def test_upper_bound rbtree = RBTree[*%w(a A c C e E)] assert_equal(%w(c C), rbtree.upper_bound("c")) assert_equal(%w(c C), rbtree.upper_bound("d")) assert_equal(nil, rbtree.upper_bound("Z")) end def test_bound rbtree = RBTree[*%w(a A c C e E)] assert_equal(%w(a A c C), rbtree.bound("a", "c").to_a.flatten) assert_equal(%w(a A), rbtree.bound("a").to_a.flatten) assert_equal(%w(c C e E), rbtree.bound("b", "f").to_a.flatten) assert_equal([], rbtree.bound("b", "b").to_a) assert_equal([], rbtree.bound("Y", "Z").to_a) assert_equal([], rbtree.bound("f", "g").to_a) assert_equal([], rbtree.bound("f", "Z").to_a) if defined?(Enumerator) and Enumerator.method_defined?(:size) assert_equal(2, rbtree.bound("a", "c").size) assert_equal(1, rbtree.bound("a").size) assert_equal(2, rbtree.bound("b", "f").size) assert_equal(0, rbtree.bound("b", "b").size) assert_equal(0, rbtree.bound("Y", "Z").size) assert_equal(0, rbtree.bound("f", "g").size) assert_equal(0, rbtree.bound("f", "Z").size) end end def test_bound_block result = [] @rbtree.bound("b", "c") {|key, val| result.push(key) } assert_equal(%w(b c), result) assert_raises(TypeError) { @rbtree.bound("a", "d") { @rbtree["e"] = "E" } } assert_equal(4, @rbtree.size) @rbtree.bound("b", "c") { @rbtree.bound("b", "c") {} assert_raises(TypeError) { @rbtree["e"] = "E" } break } assert_equal(4, @rbtree.size) end def test_first assert_equal(%w(a A), @rbtree.first) rbtree = RBTree.new("e") assert_equal("e", rbtree.first) rbtree = RBTree.new { "e" } assert_equal("e", rbtree.first) end def test_last assert_equal(%w(d D), @rbtree.last) rbtree = RBTree.new("e") assert_equal("e", rbtree.last) rbtree = RBTree.new { "e" } assert_equal("e", rbtree.last) end def test_readjust assert_equal(nil, @rbtree.cmp_proc) @rbtree.readjust {|a, b| b <=> a } assert_equal(%w(d c b a), @rbtree.keys) assert_not_equal(nil, @rbtree.cmp_proc) proc = Proc.new {|a,b| a.to_s <=> b.to_s } @rbtree.readjust(proc) assert_equal(%w(a b c d), @rbtree.keys) assert_equal(proc, @rbtree.cmp_proc) @rbtree[0] = nil assert_raises(ArgumentError) { @rbtree.readjust(nil) } assert_equal(5, @rbtree.size) assert_equal(proc, @rbtree.cmp_proc) @rbtree.delete(0) @rbtree.readjust(nil) assert_raises(ArgumentError) { @rbtree[0] = nil } if Symbol.method_defined?(:to_proc) rbtree = RBTree[*%w(a A B b)] assert_equal(%w(B b a A), rbtree.to_a.flatten) rbtree.readjust(:casecmp) assert_equal(%w(a A B b), rbtree.to_a.flatten) end if RUBY_VERSION >= "1.9.2" assert_nothing_raised { @rbtree.readjust(lambda {|a, b| a <=> b }) @rbtree.readjust(lambda {|*a| a[0] <=> a[1] }) @rbtree.readjust(lambda {|a, *b| a <=> b[0] }) @rbtree.readjust(lambda {|a, b, *c| a <=> b }) @rbtree.readjust(&lambda {|a, b| a <=> b }) @rbtree.readjust(&lambda {|*a| a[0] <=> a[1] }) @rbtree.readjust(&lambda {|a, *b| a <=> b[0] }) @rbtree.readjust(&lambda {|a, b, *c| a <=> b }) } assert_raises(TypeError) { @rbtree.readjust(lambda {|a| 1 }) } assert_raises(TypeError) { @rbtree.readjust(lambda {|a, b, c| 1 }) } assert_raises(TypeError) { @rbtree.readjust(lambda {|a, b, c, *d| 1 }) } assert_raises(TypeError) { @rbtree.readjust(&lambda {|a| 1 }) } assert_raises(TypeError) { @rbtree.readjust(&lambda {|a, b, c| 1 }) } assert_raises(TypeError) { @rbtree.readjust(&lambda {|a, b, c, *d| 1 }) } end rbtree = RBTree.new key = ["a"] rbtree[key] = nil rbtree[["e"]] = nil key[0] = "f" assert_equal([["f"], ["e"]], rbtree.keys) rbtree.readjust assert_equal([["e"], ["f"]], rbtree.keys) assert_raises(TypeError) { @rbtree.readjust("e") } assert_raises(ArgumentError) { @rbtree.readjust(proc) {|a,b| a <=> b } } assert_raises(ArgumentError) { @rbtree.readjust(proc, proc) } rbtree = RBTree[("a".."z").to_a.zip(("A".."Z").to_a)] assert_nothing_raised do rbtree.readjust do |a, b| ObjectSpace.each_object(RBTree) do |temp| temp.clear if temp.size == rbtree.size - 1 end a <=> b end end end def test_replace rbtree = RBTree.new { "e" } rbtree.readjust {|a, b| a <=> b} rbtree["a"] = "A" rbtree["e"] = "E" @rbtree.replace(rbtree) assert_equal(%w(a A e E), @rbtree.to_a.flatten) assert_equal(rbtree.default, @rbtree.default) assert_equal(rbtree.cmp_proc, @rbtree.cmp_proc) assert_raises(TypeError) { @rbtree.replace("e") } end def test_reverse_each result = [] @rbtree.reverse_each { |key, val| result.push([key, val]) } assert_equal(%w(d D c C b B a A), result.flatten) if have_enumerator? enumerator = @rbtree.reverse_each assert_equal(%w(d D c C b B a A), enumerator.to_a.flatten) end end def test_marshal assert_equal(@rbtree, Marshal.load(Marshal.dump(@rbtree))) @rbtree.default = "e" assert_equal(@rbtree, Marshal.load(Marshal.dump(@rbtree))) assert_raises(TypeError) { Marshal.dump(RBTree.new { "e" }) } assert_raises(TypeError) { @rbtree.readjust {|a, b| a <=> b} Marshal.dump(@rbtree) } end def test_modify_in_cmp_proc can_clear = false @rbtree.readjust do |a, b| @rbtree.clear if can_clear a <=> b end can_clear = true assert_raises(TypeError) { @rbtree["e"] } end begin require "pp" def test_pp assert_equal(%(#\n), PP.pp(RBTree.new, "")) assert_equal(%(#"A", "b"=>"B"}, default=nil, cmp_proc=nil>\n), PP.pp(RBTree[*%w(a A b B)], "")) rbtree = RBTree[*("a".."z").to_a] rbtree.default = "a" rbtree.readjust {|a, b| a <=> b } expected = <"b", "c"=>"d", "e"=>"f", "g"=>"h", "i"=>"j", "k"=>"l", "m"=>"n", "o"=>"p", "q"=>"r", "s"=>"t", "u"=>"v", "w"=>"x", "y"=>"z"}, default="a", cmp_proc=#{rbtree.cmp_proc}> EOS assert_equal(expected, PP.pp(rbtree, "")) rbtree = RBTree.new rbtree[rbtree] = rbtree rbtree.default = rbtree expected = <"=>"#"}, default="#", cmp_proc=nil> EOS assert_equal(expected, PP.pp(rbtree, "")) end rescue LoadError end end class MultiRBTreeTest < Test::Unit::TestCase def setup @rbtree = MultiRBTree[*%w(a A b B b C b D c C)] end def test_create assert_equal(%w(a A b B b C b D c C), @rbtree.to_a.flatten) assert_equal(MultiRBTree[*%w(a A)], MultiRBTree[RBTree[*%w(a A)]]) assert_raises(TypeError) { RBTree[MultiRBTree[*%w(a A)]] } end def test_size assert_equal(5, @rbtree.size) end def test_clear @rbtree.clear assert_equal(0, @rbtree.size) end def test_empty assert_equal(false, @rbtree.empty?) @rbtree.clear assert_equal(true, @rbtree.empty?) end def test_to_a assert_equal([%w(a A), %w(b B), %w(b C), %w(b D), %w(c C)], @rbtree.to_a) end def test_to_hash assert_raises(TypeError) { @rbtree.to_hash } end def test_to_rbtree assert_equal(@rbtree, @rbtree.to_rbtree) end def test_aref assert_equal("B", @rbtree["b"]) end def test_aset @rbtree["b"] = "A" assert_equal("B", @rbtree["b"]) assert_equal(%w(a A b B b C b D b A c C), @rbtree.to_a.flatten) end def test_equal assert_equal(true, MultiRBTree[*%w(a A b B b C b D c C)] == @rbtree) assert_equal(true, RBTree[*%w(a A)] == MultiRBTree[*%w(a A)]) assert_equal(true, MultiRBTree[*%w(a A)] == RBTree[*%w(a A)]) end def test_replace assert_equal(RBTree[*%w(a A)], MultiRBTree[*%w(a A)].replace(RBTree[*%w(a A)])) assert_raises(TypeError) { RBTree[*%w(a A)].replace(MultiRBTree[*%w(a A)]) } end def test_update assert_equal(MultiRBTree[*%w(a A b B)], MultiRBTree[*%w(a A)].update(RBTree[*%w(b B)])) assert_raises(TypeError) { RBTree[*%w(a A)].update(MultiRBTree[*%w(b B)]) } end def test_clone assert_equal(@rbtree, @rbtree.clone) end def test_each result = [] @rbtree.each {|k, v| result << k << v } assert_equal(%w(a A b B b C b D c C), result) end def test_delete @rbtree.delete("b") assert_equal(4, @rbtree.size) assert_equal(%w(a A b C b D c C), @rbtree.to_a.flatten) @rbtree.delete("b") assert_equal(3, @rbtree.size) assert_equal(%w(a A b D c C), @rbtree.to_a.flatten) @rbtree.delete("b") assert_equal(2, @rbtree.size) assert_equal(%w(a A c C), @rbtree.to_a.flatten) end def test_delete_if @rbtree.delete_if {|k, v| k == "b" } assert_equal(%w(a A c C), @rbtree.to_a.flatten) end def test_keep_if @rbtree.keep_if {|k, v| k != "b" } assert_equal(%w(a A c C), @rbtree.to_a.flatten) end if MultiRBTree.method_defined?(:flatten) def test_flatten assert_equal(%w(a A b B b C b D c C), @rbtree.flatten) end end def test_inspect assert_equal(%(#"A", "b"=>"B", "b"=>"C", "b"=>"D", "c"=>"C"}, default=nil, cmp_proc=nil>), @rbtree.inspect) end def test_readjust @rbtree.readjust {|a, b| b <=> a } assert_equal(%w(c C b B b C b D a A), @rbtree.to_a.flatten) end def test_marshal assert_equal(@rbtree, Marshal.load(Marshal.dump(@rbtree))) end def test_lower_bound assert_equal(%w(b B), @rbtree.lower_bound("b")) end def test_upper_bound assert_equal(%w(b D), @rbtree.upper_bound("b")) end def test_bound assert_equal(%w(b B b C b D), @rbtree.bound("b").to_a.flatten) end def test_first assert_equal(%w(a A), @rbtree.first) end def test_last assert_equal(%w(c C), @rbtree.last) end def test_shift assert_equal(%w(a A), @rbtree.shift) assert_equal(4, @rbtree.size) assert_equal(nil, @rbtree["a"]) end def test_pop assert_equal(%w(c C), @rbtree.pop) assert_equal(4, @rbtree.size) assert_equal(nil, @rbtree["c"]) end def test_has_key assert_equal(true, @rbtree.has_key?("b")) end def test_has_value assert_equal(true, @rbtree.has_value?("B")) assert_equal(true, @rbtree.has_value?("C")) assert_equal(true, @rbtree.has_value?("D")) end def test_values_at assert_equal(%w(A B), @rbtree.values_at("a", "b")) end def test_invert assert_equal(MultiRBTree[*%w(A a B b C b C c D b)], @rbtree.invert) end def test_keys assert_equal(%w(a b b b c), @rbtree.keys) end def test_values assert_equal(%w(A B C D C), @rbtree.values) end def test_key assert_equal("b", @rbtree.key("B")) assert_equal("b", @rbtree.key("C")) assert_equal("b", @rbtree.key("D")) end end rbtree-0.4.6/dict.c0000644000004100000410000010543314353333751014140 0ustar www-datawww-data/* * Dictionary Abstract Data Type * Copyright (C) 1997 Kaz Kylheku * * Free Software License: * * All rights are reserved by the author, with the following exceptions: * Permission is granted to freely reproduce and distribute this software, * possibly in exchange for a fee, provided that this copyright notice appears * intact. Permission is also granted to adapt this software to produce * derivative works, as long as the modified versions carry this copyright * notice and additional notices stating that the work has been modified. * This source code may be translated into executable form and incorporated * into proprietary software; there is no requirement for such software to * contain a copyright notice related to this source. * * $Id: dict.c,v 1.40.2.7 2000/11/13 01:36:44 kaz Exp $ * $Name: kazlib_1_20 $ */ /* * Modified for Ruby/RBTree. */ #include #include #include #define DICT_IMPLEMENTATION #include "dict.h" #ifdef KAZLIB_RCSID static const char rcsid[] = "$Id: dict.c,v 1.40.2.7 2000/11/13 01:36:44 kaz Exp $"; #endif /* * These macros provide short convenient names for structure members, * which are embellished with dict_ prefixes so that they are * properly confined to the documented namespace. It's legal for a * program which uses dict to define, for instance, a macro called ``parent''. * Such a macro would interfere with the dnode_t struct definition. * In general, highly portable and reusable C modules which expose their * structures need to confine structure member names to well-defined spaces. * The resulting identifiers aren't necessarily convenient to use, nor * readable, in the implementation, however! */ #define left dict_left #define right dict_right #define parent dict_parent #define color dict_color #define key dict_key #define data dict_data #define nilnode dict_nilnode #define nodecount dict_nodecount #define compare dict_compare #define allocnode dict_allocnode #define freenode dict_freenode #define context dict_context #define dupes dict_dupes #define dictptr dict_dictptr #define dict_root(D) ((D)->nilnode.left) #define dict_nil(D) (&(D)->nilnode) #define DICT_DEPTH_MAX 64 static dnode_t *dnode_alloc(void *context); static void dnode_free(dnode_t *node, void *context); /* * Perform a ``left rotation'' adjustment on the tree. The given node P and * its right child C are rearranged so that the P instead becomes the left * child of C. The left subtree of C is inherited as the new right subtree * for P. The ordering of the keys within the tree is thus preserved. */ static void rotate_left(dnode_t *upper) { dnode_t *lower, *lowleft, *upparent; lower = upper->right; upper->right = lowleft = lower->left; lowleft->parent = upper; lower->parent = upparent = upper->parent; /* don't need to check for root node here because root->parent is the sentinel nil node, and root->parent->left points back to root */ if (upper == upparent->left) { upparent->left = lower; } else { assert (upper == upparent->right); upparent->right = lower; } lower->left = upper; upper->parent = lower; } /* * This operation is the ``mirror'' image of rotate_left. It is * the same procedure, but with left and right interchanged. */ static void rotate_right(dnode_t *upper) { dnode_t *lower, *lowright, *upparent; lower = upper->left; upper->left = lowright = lower->right; lowright->parent = upper; lower->parent = upparent = upper->parent; if (upper == upparent->right) { upparent->right = lower; } else { assert (upper == upparent->left); upparent->left = lower; } lower->right = upper; upper->parent = lower; } /* * Do a postorder traversal of the tree rooted at the specified * node and free everything under it. Used by dict_free(). */ static void free_nodes(dict_t *dict, dnode_t *node, dnode_t *nil) { if (node == nil) return; free_nodes(dict, node->left, nil); free_nodes(dict, node->right, nil); dict->freenode(node, dict->context); } /* * This procedure performs a verification that the given subtree is a binary * search tree. It performs an inorder traversal of the tree using the * dict_next() successor function, verifying that the key of each node is * strictly lower than that of its successor, if duplicates are not allowed, * or lower or equal if duplicates are allowed. This function is used for * debugging purposes. */ static int verify_bintree(dict_t *dict) { dnode_t *first, *next; first = dict_first(dict); if (dict->dupes) { while (first && (next = dict_next(dict, first))) { if (dict->compare(first->key, next->key, dict->context) > 0) return 0; first = next; } } else { while (first && (next = dict_next(dict, first))) { if (dict->compare(first->key, next->key, dict->context) >= 0) return 0; first = next; } } return 1; } /* * This function recursively verifies that the given binary subtree satisfies * three of the red black properties. It checks that every red node has only * black children. It makes sure that each node is either red or black. And it * checks that every path has the same count of black nodes from root to leaf. * It returns the blackheight of the given subtree; this allows blackheights to * be computed recursively and compared for left and right siblings for * mismatches. It does not check for every nil node being black, because there * is only one sentinel nil node. The return value of this function is the * black height of the subtree rooted at the node ``root'', or zero if the * subtree is not red-black. */ static unsigned int verify_redblack(dnode_t *nil, dnode_t *root) { unsigned height_left, height_right; if (root != nil) { height_left = verify_redblack(nil, root->left); height_right = verify_redblack(nil, root->right); if (height_left == 0 || height_right == 0) return 0; if (height_left != height_right) return 0; if (root->color == dnode_red) { if (root->left->color != dnode_black) return 0; if (root->right->color != dnode_black) return 0; return height_left; } if (root->color != dnode_black) return 0; return height_left + 1; } return 1; } /* * Compute the actual count of nodes by traversing the tree and * return it. This could be compared against the stored count to * detect a mismatch. */ static dictcount_t verify_node_count(dnode_t *nil, dnode_t *root) { if (root == nil) return 0; else return 1 + verify_node_count(nil, root->left) + verify_node_count(nil, root->right); } /* * Verify that the tree contains the given node. This is done by * traversing all of the nodes and comparing their pointers to the * given pointer. Returns 1 if the node is found, otherwise * returns zero. It is intended for debugging purposes. */ static int verify_dict_has_node(dnode_t *nil, dnode_t *root, dnode_t *node) { if (root != nil) { return root == node || verify_dict_has_node(nil, root->left, node) || verify_dict_has_node(nil, root->right, node); } return 0; } /* * Dynamically allocate and initialize a dictionary object. */ dict_t *dict_create(dict_comp_t comp) { dict_t *new = malloc(sizeof *new); if (new) { new->compare = comp; new->allocnode = dnode_alloc; new->freenode = dnode_free; new->context = NULL; new->nodecount = 0; new->nilnode.left = &new->nilnode; new->nilnode.right = &new->nilnode; new->nilnode.parent = &new->nilnode; new->nilnode.color = dnode_black; new->dupes = 0; } return new; } /* * Select a different set of node allocator routines. */ void dict_set_allocator(dict_t *dict, dnode_alloc_t al, dnode_free_t fr, void *context) { assert (dict_count(dict) == 0); assert ((al == NULL && fr == NULL) || (al != NULL && fr != NULL)); dict->allocnode = al ? al : dnode_alloc; dict->freenode = fr ? fr : dnode_free; dict->context = context; } /* * Free a dynamically allocated dictionary object. Removing the nodes * from the tree before deleting it is required. */ void dict_destroy(dict_t *dict) { assert (dict_isempty(dict)); free(dict); } /* * Free all the nodes in the dictionary by using the dictionary's * installed free routine. The dictionary is emptied. */ void dict_free_nodes(dict_t *dict) { dnode_t *nil = dict_nil(dict), *root = dict_root(dict); free_nodes(dict, root, nil); dict->nodecount = 0; dict->nilnode.left = &dict->nilnode; dict->nilnode.right = &dict->nilnode; dict->nilnode.parent = &dict->nilnode; } /* * Obsolescent function, equivalent to dict_free_nodes */ void dict_free(dict_t *dict) { #ifdef KAZLIB_OBSOLESCENT_DEBUG assert ("call to obsolescent function dict_free()" && 0); #endif dict_free_nodes(dict); } /* * Initialize a user-supplied dictionary object. */ dict_t *dict_init(dict_t *dict, dict_comp_t comp) { dict->compare = comp; dict->allocnode = dnode_alloc; dict->freenode = dnode_free; dict->context = NULL; dict->nodecount = 0; dict->nilnode.left = &dict->nilnode; dict->nilnode.right = &dict->nilnode; dict->nilnode.parent = &dict->nilnode; dict->nilnode.color = dnode_black; dict->dupes = 0; return dict; } /* * Initialize a dictionary in the likeness of another dictionary */ void dict_init_like(dict_t *dict, const dict_t *template) { dict->compare = template->compare; dict->allocnode = template->allocnode; dict->freenode = template->freenode; dict->context = template->context; dict->nodecount = 0; dict->nilnode.left = &dict->nilnode; dict->nilnode.right = &dict->nilnode; dict->nilnode.parent = &dict->nilnode; dict->nilnode.color = dnode_black; dict->dupes = template->dupes; assert (dict_similar(dict, template)); } /* * Remove all nodes from the dictionary (without freeing them in any way). */ static void dict_clear(dict_t *dict) { dict->nodecount = 0; dict->nilnode.left = &dict->nilnode; dict->nilnode.right = &dict->nilnode; dict->nilnode.parent = &dict->nilnode; assert (dict->nilnode.color == dnode_black); } /* * Verify the integrity of the dictionary structure. This is provided for * debugging purposes, and should be placed in assert statements. Just because * this function succeeds doesn't mean that the tree is not corrupt. Certain * corruptions in the tree may simply cause undefined behavior. */ int dict_verify(dict_t *dict) { dnode_t *nil = dict_nil(dict), *root = dict_root(dict); /* check that the sentinel node and root node are black */ if (root->color != dnode_black) return 0; if (nil->color != dnode_black) return 0; if (nil->right != nil) return 0; /* nil->left is the root node; check that its parent pointer is nil */ if (nil->left->parent != nil) return 0; /* perform a weak test that the tree is a binary search tree */ if (!verify_bintree(dict)) return 0; /* verify that the tree is a red-black tree */ if (!verify_redblack(nil, root)) return 0; if (verify_node_count(nil, root) != dict_count(dict)) return 0; return 1; } /* * Determine whether two dictionaries are similar: have the same comparison and * allocator functions, and same status as to whether duplicates are allowed. */ int dict_similar(const dict_t *left, const dict_t *right) { if (left->compare != right->compare) return 0; if (left->allocnode != right->allocnode) return 0; if (left->freenode != right->freenode) return 0; if (left->context != right->context) return 0; return 1; } /* * Locate a node in the dictionary having the given key. * If the node is not found, a null a pointer is returned (rather than * a pointer that dictionary's nil sentinel node), otherwise a pointer to the * located node is returned. */ dnode_t *dict_lookup(dict_t *dict, const void *key) { dnode_t *root = dict_root(dict); dnode_t *nil = dict_nil(dict); dnode_t *saved; int result; /* simple binary search adapted for trees that contain duplicate keys */ while (root != nil) { result = dict->compare(key, root->key, dict->context); if (result < 0) root = root->left; else if (result > 0) root = root->right; else { if (!dict->dupes) { /* no duplicates, return match */ return root; } else { /* could be dupes, find leftmost one */ do { saved = root; root = root->left; while (root != nil && dict->compare(key, root->key, dict->context)) root = root->right; } while (root != nil); return saved; } } } return NULL; } /* * Look for the node corresponding to the lowest key that is equal to or * greater than the given key. If there is no such node, return null. */ dnode_t *dict_lower_bound(dict_t *dict, const void *key) { dnode_t *root = dict_root(dict); dnode_t *nil = dict_nil(dict); dnode_t *tentative = 0; while (root != nil) { int result = dict->compare(key, root->key, dict->context); if (result > 0) { root = root->right; } else if (result < 0) { tentative = root; root = root->left; } else { if (!dict->dupes) { return root; } else { tentative = root; root = root->left; } } } return tentative; } /* * Look for the node corresponding to the greatest key that is equal to or * lower than the given key. If there is no such node, return null. */ dnode_t *dict_upper_bound(dict_t *dict, const void *key) { dnode_t *root = dict_root(dict); dnode_t *nil = dict_nil(dict); dnode_t *tentative = 0; while (root != nil) { int result = dict->compare(key, root->key, dict->context); if (result < 0) { root = root->left; } else if (result > 0) { tentative = root; root = root->right; } else { if (!dict->dupes) { return root; } else { tentative = root; root = root->right; } } } return tentative; } /* * Insert a node into the dictionary. The node should have been * initialized with a data field. All other fields are ignored. * The behavior is undefined if the user attempts to insert into * a dictionary that is already full (for which the dict_isfull() * function returns true). */ int dict_insert(dict_t *dict, dnode_t *node, const void *key) { dnode_t *where = dict_root(dict), *nil = dict_nil(dict); dnode_t *parent = nil, *uncle, *grandpa; int result = -1; node->key = key; assert (!dict_isfull(dict)); assert (!dict_contains(dict, node)); assert (!dnode_is_in_a_dict(node)); /* basic binary tree insert */ while (where != nil) { parent = where; result = dict->compare(key, where->key, dict->context); if (!dict->dupes && result == 0) { where->data = node->data; return 0; } else if (result < 0) { where = where->left; } else { where = where->right; } } assert (where == nil); if (result < 0) parent->left = node; else parent->right = node; node->parent = parent; node->left = nil; node->right = nil; dict->nodecount++; /* red black adjustments */ node->color = dnode_red; while (parent->color == dnode_red) { grandpa = parent->parent; if (parent == grandpa->left) { uncle = grandpa->right; if (uncle->color == dnode_red) { /* red parent, red uncle */ parent->color = dnode_black; uncle->color = dnode_black; grandpa->color = dnode_red; node = grandpa; parent = grandpa->parent; } else { /* red parent, black uncle */ if (node == parent->right) { rotate_left(parent); parent = node; assert (grandpa == parent->parent); /* rotation between parent and child preserves grandpa */ } parent->color = dnode_black; grandpa->color = dnode_red; rotate_right(grandpa); break; } } else { /* symmetric cases: parent == parent->parent->right */ uncle = grandpa->left; if (uncle->color == dnode_red) { parent->color = dnode_black; uncle->color = dnode_black; grandpa->color = dnode_red; node = grandpa; parent = grandpa->parent; } else { if (node == parent->left) { rotate_right(parent); parent = node; assert (grandpa == parent->parent); } parent->color = dnode_black; grandpa->color = dnode_red; rotate_left(grandpa); break; } } } dict_root(dict)->color = dnode_black; assert (dict_verify(dict)); return 1; } /* * Delete the given node from the dictionary. If the given node does not belong * to the given dictionary, undefined behavior results. A pointer to the * deleted node is returned. */ dnode_t *dict_delete(dict_t *dict, dnode_t *delete) { dnode_t *nil = dict_nil(dict), *child, *delparent = delete->parent; /* basic deletion */ assert (!dict_isempty(dict)); assert (dict_contains(dict, delete)); /* * If the node being deleted has two children, then we replace it with its * successor (i.e. the leftmost node in the right subtree.) By doing this, * we avoid the traditional algorithm under which the successor's key and * value *only* move to the deleted node and the successor is spliced out * from the tree. We cannot use this approach because the user may hold * pointers to the successor, or nodes may be inextricably tied to some * other structures by way of embedding, etc. So we must splice out the * node we are given, not some other node, and must not move contents from * one node to another behind the user's back. */ if (delete->left != nil && delete->right != nil) { dnode_t *next = dict_next(dict, delete); dnode_t *nextparent = next->parent; dnode_color_t nextcolor = next->color; assert (next != nil); assert (next->parent != nil); assert (next->left == nil); /* * First, splice out the successor from the tree completely, by * moving up its right child into its place. */ child = next->right; child->parent = nextparent; if (nextparent->left == next) { nextparent->left = child; } else { assert (nextparent->right == next); nextparent->right = child; } /* * Now that the successor has been extricated from the tree, install it * in place of the node that we want deleted. */ next->parent = delparent; next->left = delete->left; next->right = delete->right; next->left->parent = next; next->right->parent = next; next->color = delete->color; delete->color = nextcolor; if (delparent->left == delete) { delparent->left = next; } else { assert (delparent->right == delete); delparent->right = next; } } else { assert (delete != nil); assert (delete->left == nil || delete->right == nil); child = (delete->left != nil) ? delete->left : delete->right; child->parent = delparent = delete->parent; if (delete == delparent->left) { delparent->left = child; } else { assert (delete == delparent->right); delparent->right = child; } } delete->parent = NULL; delete->right = NULL; delete->left = NULL; dict->nodecount--; assert (verify_bintree(dict)); /* red-black adjustments */ if (delete->color == dnode_black) { dnode_t *parent, *sister; dict_root(dict)->color = dnode_red; while (child->color == dnode_black) { parent = child->parent; if (child == parent->left) { sister = parent->right; assert (sister != nil); if (sister->color == dnode_red) { sister->color = dnode_black; parent->color = dnode_red; rotate_left(parent); sister = parent->right; assert (sister != nil); } if (sister->left->color == dnode_black && sister->right->color == dnode_black) { sister->color = dnode_red; child = parent; } else { if (sister->right->color == dnode_black) { assert (sister->left->color == dnode_red); sister->left->color = dnode_black; sister->color = dnode_red; rotate_right(sister); sister = parent->right; assert (sister != nil); } sister->color = parent->color; sister->right->color = dnode_black; parent->color = dnode_black; rotate_left(parent); break; } } else { /* symmetric case: child == child->parent->right */ assert (child == parent->right); sister = parent->left; assert (sister != nil); if (sister->color == dnode_red) { sister->color = dnode_black; parent->color = dnode_red; rotate_right(parent); sister = parent->left; assert (sister != nil); } if (sister->right->color == dnode_black && sister->left->color == dnode_black) { sister->color = dnode_red; child = parent; } else { if (sister->left->color == dnode_black) { assert (sister->right->color == dnode_red); sister->right->color = dnode_black; sister->color = dnode_red; rotate_left(sister); sister = parent->left; assert (sister != nil); } sister->color = parent->color; sister->left->color = dnode_black; parent->color = dnode_black; rotate_right(parent); break; } } } child->color = dnode_black; dict_root(dict)->color = dnode_black; } assert (dict_verify(dict)); return delete; } /* * Allocate a node using the dictionary's allocator routine, give it * the data item. */ int dict_alloc_insert(dict_t *dict, const void *key, void *data) { dnode_t *node = dict->allocnode(dict->context); if (node) { dnode_init(node, data); if (!dict_insert(dict, node, key)) dict->freenode(node, dict->context); return 1; } return 0; } void dict_delete_free(dict_t *dict, dnode_t *node) { dict_delete(dict, node); dict->freenode(node, dict->context); } /* * Return the node with the lowest (leftmost) key. If the dictionary is empty * (that is, dict_isempty(dict) returns 1) a null pointer is returned. */ dnode_t *dict_first(dict_t *dict) { dnode_t *nil = dict_nil(dict), *root = dict_root(dict), *left; if (root != nil) while ((left = root->left) != nil) root = left; return (root == nil) ? NULL : root; } /* * Return the node with the highest (rightmost) key. If the dictionary is empty * (that is, dict_isempty(dict) returns 1) a null pointer is returned. */ dnode_t *dict_last(dict_t *dict) { dnode_t *nil = dict_nil(dict), *root = dict_root(dict), *right; if (root != nil) while ((right = root->right) != nil) root = right; return (root == nil) ? NULL : root; } /* * Return the given node's successor node---the node which has the * next key in the the left to right ordering. If the node has * no successor, a null pointer is returned rather than a pointer to * the nil node. */ dnode_t *dict_next(dict_t *dict, dnode_t *curr) { dnode_t *nil = dict_nil(dict), *parent, *left; if (curr->right != nil) { curr = curr->right; while ((left = curr->left) != nil) curr = left; return curr; } parent = curr->parent; while (parent != nil && curr == parent->right) { curr = parent; parent = curr->parent; } return (parent == nil) ? NULL : parent; } /* * Return the given node's predecessor, in the key order. * The nil sentinel node is returned if there is no predecessor. */ dnode_t *dict_prev(dict_t *dict, dnode_t *curr) { dnode_t *nil = dict_nil(dict), *parent, *right; if (curr->left != nil) { curr = curr->left; while ((right = curr->right) != nil) curr = right; return curr; } parent = curr->parent; while (parent != nil && curr == parent->left) { curr = parent; parent = curr->parent; } return (parent == nil) ? NULL : parent; } void dict_allow_dupes(dict_t *dict) { dict->dupes = 1; } #undef dict_count #undef dict_isempty #undef dict_isfull #undef dnode_get #undef dnode_put #undef dnode_getkey dictcount_t dict_count(dict_t *dict) { return dict->nodecount; } int dict_isempty(dict_t *dict) { return dict->nodecount == 0; } int dict_isfull(dict_t *dict) { return dict->nodecount == DICTCOUNT_T_MAX; } int dict_contains(dict_t *dict, dnode_t *node) { return verify_dict_has_node(dict_nil(dict), dict_root(dict), node); } static dnode_t *dnode_alloc(void *context) { return malloc(sizeof *dnode_alloc(NULL)); } static void dnode_free(dnode_t *node, void *context) { free(node); } dnode_t *dnode_create(void *data) { dnode_t *new = malloc(sizeof *new); if (new) { new->data = data; new->parent = NULL; new->left = NULL; new->right = NULL; } return new; } dnode_t *dnode_init(dnode_t *dnode, void *data) { dnode->data = data; dnode->parent = NULL; dnode->left = NULL; dnode->right = NULL; return dnode; } void dnode_destroy(dnode_t *dnode) { assert (!dnode_is_in_a_dict(dnode)); free(dnode); } void *dnode_get(dnode_t *dnode) { return dnode->data; } const void *dnode_getkey(dnode_t *dnode) { return dnode->key; } void dnode_put(dnode_t *dnode, void *data) { dnode->data = data; } int dnode_is_in_a_dict(dnode_t *dnode) { return (dnode->parent && dnode->left && dnode->right); } void dict_process(dict_t *dict, void *context, dnode_process_t function) { dnode_t *node = dict_first(dict), *next; while (node != NULL) { /* check for callback function deleting */ /* the next node from under us */ assert (dict_contains(dict, node)); next = dict_next(dict, node); function(dict, node, context); node = next; } } static void load_begin_internal(dict_load_t *load, dict_t *dict) { load->dictptr = dict; load->nilnode.left = &load->nilnode; load->nilnode.right = &load->nilnode; } void dict_load_begin(dict_load_t *load, dict_t *dict) { assert (dict_isempty(dict)); load_begin_internal(load, dict); } void dict_load_next(dict_load_t *load, dnode_t *newnode, const void *key) { dict_t *dict = load->dictptr; dnode_t *nil = &load->nilnode; assert (!dnode_is_in_a_dict(newnode)); assert (dict->nodecount < DICTCOUNT_T_MAX); #ifndef NDEBUG if (dict->nodecount > 0) { if (dict->dupes) assert (dict->compare(nil->left->key, key, dict->context) <= 0); else assert (dict->compare(nil->left->key, key, dict->context) < 0); } #endif newnode->key = key; nil->right->left = newnode; nil->right = newnode; newnode->left = nil; dict->nodecount++; } void dict_load_end(dict_load_t *load) { dict_t *dict = load->dictptr; dnode_t *tree[DICT_DEPTH_MAX] = { 0 }; dnode_t *curr, *dictnil = dict_nil(dict), *loadnil = &load->nilnode, *next; dnode_t *complete = 0; dictcount_t fullcount = DICTCOUNT_T_MAX, nodecount = dict->nodecount; dictcount_t botrowcount; unsigned baselevel = 0, level = 0, i; assert (dnode_red == 0 && dnode_black == 1); while (fullcount >= nodecount && fullcount) fullcount >>= 1; botrowcount = nodecount - fullcount; for (curr = loadnil->left; curr != loadnil; curr = next) { next = curr->left; if (complete == NULL && botrowcount-- == 0) { assert (baselevel == 0); assert (level == 0); baselevel = level = 1; complete = tree[0]; if (complete != 0) { tree[0] = 0; complete->right = dictnil; while (tree[level] != 0) { tree[level]->right = complete; complete->parent = tree[level]; complete = tree[level]; tree[level++] = 0; } } } if (complete == NULL) { curr->left = dictnil; curr->right = dictnil; curr->color = level % 2; complete = curr; assert (level == baselevel); while (tree[level] != 0) { tree[level]->right = complete; complete->parent = tree[level]; complete = tree[level]; tree[level++] = 0; } } else { curr->left = complete; curr->color = (level + 1) % 2; complete->parent = curr; tree[level] = curr; complete = 0; level = baselevel; } } if (complete == NULL) complete = dictnil; for (i = 0; i < DICT_DEPTH_MAX; i++) { if (tree[i] != 0) { tree[i]->right = complete; complete->parent = tree[i]; complete = tree[i]; } } dictnil->color = dnode_black; dictnil->right = dictnil; complete->parent = dictnil; complete->color = dnode_black; dict_root(dict) = complete; assert (dict_verify(dict)); } void dict_merge(dict_t *dest, dict_t *source) { dict_load_t load; dnode_t *leftnode = dict_first(dest), *rightnode = dict_first(source); assert (dict_similar(dest, source)); if (source == dest) return; dest->nodecount = 0; load_begin_internal(&load, dest); for (;;) { if (leftnode != NULL && rightnode != NULL) { if (dest->compare(leftnode->key, rightnode->key, dest->context) < 0) goto copyleft; else goto copyright; } else if (leftnode != NULL) { goto copyleft; } else if (rightnode != NULL) { goto copyright; } else { assert (leftnode == NULL && rightnode == NULL); break; } copyleft: { dnode_t *next = dict_next(dest, leftnode); #ifndef NDEBUG leftnode->left = NULL; /* suppress assertion in dict_load_next */ #endif dict_load_next(&load, leftnode, leftnode->key); leftnode = next; continue; } copyright: { dnode_t *next = dict_next(source, rightnode); #ifndef NDEBUG rightnode->left = NULL; #endif dict_load_next(&load, rightnode, rightnode->key); rightnode = next; continue; } } dict_clear(source); dict_load_end(&load); } #ifdef KAZLIB_TEST_MAIN #include #include #include #include typedef char input_t[256]; static int tokenize(char *string, ...) { char **tokptr; va_list arglist; int tokcount = 0; va_start(arglist, string); tokptr = va_arg(arglist, char **); while (tokptr) { while (*string && isspace((unsigned char) *string)) string++; if (!*string) break; *tokptr = string; while (*string && !isspace((unsigned char) *string)) string++; tokptr = va_arg(arglist, char **); tokcount++; if (!*string) break; *string++ = 0; } va_end(arglist); return tokcount; } static int comparef(const void *key1, const void *key2) { return strcmp(key1, key2); } static char *dupstring(char *str) { int sz = strlen(str) + 1; char *new = malloc(sz); if (new) memcpy(new, str, sz); return new; } static dnode_t *new_node(void *c) { static dnode_t few[5]; static int count; if (count < 5) return few + count++; return NULL; } static void del_node(dnode_t *n, void *c) { } static int prompt = 0; static void construct(dict_t *d) { input_t in; int done = 0; dict_load_t dl; dnode_t *dn; char *tok1, *tok2, *val; const char *key; char *help = "p turn prompt on\n" "q finish construction\n" "a add new entry\n"; if (!dict_isempty(d)) puts("warning: dictionary not empty!"); dict_load_begin(&dl, d); while (!done) { if (prompt) putchar('>'); fflush(stdout); if (!fgets(in, sizeof(input_t), stdin)) break; switch (in[0]) { case '?': puts(help); break; case 'p': prompt = 1; break; case 'q': done = 1; break; case 'a': if (tokenize(in+1, &tok1, &tok2, (char **) 0) != 2) { puts("what?"); break; } key = dupstring(tok1); val = dupstring(tok2); dn = dnode_create(val); if (!key || !val || !dn) { puts("out of memory"); free((void *) key); free(val); if (dn) dnode_destroy(dn); } dict_load_next(&dl, dn, key); break; default: putchar('?'); putchar('\n'); break; } } dict_load_end(&dl); } int main(void) { input_t in; dict_t darray[10]; dict_t *d = &darray[0]; dnode_t *dn; int i; char *tok1, *tok2, *val; const char *key; char *help = "a add value to dictionary\n" "d delete value from dictionary\n" "l lookup value in dictionary\n" "( lookup lower bound\n" ") lookup upper bound\n" "# switch to alternate dictionary (0-9)\n" "j merge two dictionaries\n" "f free the whole dictionary\n" "k allow duplicate keys\n" "c show number of entries\n" "t dump whole dictionary in sort order\n" "m make dictionary out of sorted items\n" "p turn prompt on\n" "s switch to non-functioning allocator\n" "q quit"; for (i = 0; i < sizeof darray / sizeof *darray; i++) dict_init(&darray[i], DICTCOUNT_T_MAX, comparef); for (;;) { if (prompt) putchar('>'); fflush(stdout); if (!fgets(in, sizeof(input_t), stdin)) break; switch(in[0]) { case '?': puts(help); break; case 'a': if (tokenize(in+1, &tok1, &tok2, (char **) 0) != 2) { puts("what?"); break; } key = dupstring(tok1); val = dupstring(tok2); if (!key || !val) { puts("out of memory"); free((void *) key); free(val); } if (!dict_alloc_insert(d, key, val)) { puts("dict_alloc_insert failed"); free((void *) key); free(val); break; } break; case 'd': if (tokenize(in+1, &tok1, (char **) 0) != 1) { puts("what?"); break; } dn = dict_lookup(d, tok1); if (!dn) { puts("dict_lookup failed"); break; } val = dnode_get(dn); key = dnode_getkey(dn); dict_delete_free(d, dn); free(val); free((void *) key); break; case 'f': dict_free(d); break; case 'l': case '(': case ')': if (tokenize(in+1, &tok1, (char **) 0) != 1) { puts("what?"); break; } dn = 0; switch (in[0]) { case 'l': dn = dict_lookup(d, tok1); break; case '(': dn = dict_lower_bound(d, tok1); break; case ')': dn = dict_upper_bound(d, tok1); break; } if (!dn) { puts("lookup failed"); break; } val = dnode_get(dn); puts(val); break; case 'm': construct(d); break; case 'k': dict_allow_dupes(d); break; case 'c': printf("%lu\n", (unsigned long) dict_count(d)); break; case 't': for (dn = dict_first(d); dn; dn = dict_next(d, dn)) { printf("%s\t%s\n", (char *) dnode_getkey(dn), (char *) dnode_get(dn)); } break; case 'q': exit(0); break; case '\0': break; case 'p': prompt = 1; break; case 's': dict_set_allocator(d, new_node, del_node, NULL); break; case '#': if (tokenize(in+1, &tok1, (char **) 0) != 1) { puts("what?"); break; } else { int dictnum = atoi(tok1); if (dictnum < 0 || dictnum > 9) { puts("invalid number"); break; } d = &darray[dictnum]; } break; case 'j': if (tokenize(in+1, &tok1, &tok2, (char **) 0) != 2) { puts("what?"); break; } else { int dict1 = atoi(tok1), dict2 = atoi(tok2); if (dict1 < 0 || dict1 > 9 || dict2 < 0 || dict2 > 9) { puts("invalid number"); break; } dict_merge(&darray[dict1], &darray[dict2]); } break; default: putchar('?'); putchar('\n'); break; } } return 0; } #endif rbtree-0.4.6/dict.h0000644000004100000410000001104414353333751014137 0ustar www-datawww-data/* * Dictionary Abstract Data Type * Copyright (C) 1997 Kaz Kylheku * * Free Software License: * * All rights are reserved by the author, with the following exceptions: * Permission is granted to freely reproduce and distribute this software, * possibly in exchange for a fee, provided that this copyright notice appears * intact. Permission is also granted to adapt this software to produce * derivative works, as long as the modified versions carry this copyright * notice and additional notices stating that the work has been modified. * This source code may be translated into executable form and incorporated * into proprietary software; there is no requirement for such software to * contain a copyright notice related to this source. * * $Id: dict.h,v 1.22.2.6 2000/11/13 01:36:44 kaz Exp $ * $Name: kazlib_1_20 $ */ /* * Modified for Ruby/RBTree. */ #ifndef DICT_H #define DICT_H #include #ifdef KAZLIB_SIDEEFFECT_DEBUG #include "sfx.h" #endif /* * Blurb for inclusion into C++ translation units */ #ifdef __cplusplus extern "C" { #endif typedef unsigned long dictcount_t; #define DICTCOUNT_T_MAX ULONG_MAX /* * The dictionary is implemented as a red-black tree */ typedef enum { dnode_red, dnode_black } dnode_color_t; typedef struct dnode_t { #if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG) struct dnode_t *dict_left; struct dnode_t *dict_right; struct dnode_t *dict_parent; dnode_color_t dict_color; const void *dict_key; void *dict_data; #else int dict_dummy; #endif } dnode_t; typedef int (*dict_comp_t)(const void *, const void *, void *); typedef dnode_t *(*dnode_alloc_t)(void *); typedef void (*dnode_free_t)(dnode_t *, void *); typedef struct dict_t { #if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG) dnode_t dict_nilnode; dictcount_t dict_nodecount; dict_comp_t dict_compare; dnode_alloc_t dict_allocnode; dnode_free_t dict_freenode; void *dict_context; int dict_dupes; #else int dict_dummmy; #endif } dict_t; typedef void (*dnode_process_t)(dict_t *, dnode_t *, void *); typedef struct dict_load_t { #if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG) dict_t *dict_dictptr; dnode_t dict_nilnode; #else int dict_dummmy; #endif } dict_load_t; extern dict_t *dict_create(dict_comp_t); extern void dict_set_allocator(dict_t *, dnode_alloc_t, dnode_free_t, void *); extern void dict_destroy(dict_t *); extern void dict_free_nodes(dict_t *); extern void dict_free(dict_t *); extern dict_t *dict_init(dict_t *, dict_comp_t); extern void dict_init_like(dict_t *, const dict_t *); extern int dict_verify(dict_t *); extern int dict_similar(const dict_t *, const dict_t *); extern dnode_t *dict_lookup(dict_t *, const void *); extern dnode_t *dict_lower_bound(dict_t *, const void *); extern dnode_t *dict_upper_bound(dict_t *, const void *); extern int dict_insert(dict_t *, dnode_t *, const void *); extern dnode_t *dict_delete(dict_t *, dnode_t *); extern int dict_alloc_insert(dict_t *, const void *, void *); extern void dict_delete_free(dict_t *, dnode_t *); extern dnode_t *dict_first(dict_t *); extern dnode_t *dict_last(dict_t *); extern dnode_t *dict_next(dict_t *, dnode_t *); extern dnode_t *dict_prev(dict_t *, dnode_t *); extern dictcount_t dict_count(dict_t *); extern int dict_isempty(dict_t *); extern int dict_isfull(dict_t *); extern int dict_contains(dict_t *, dnode_t *); extern void dict_allow_dupes(dict_t *); extern int dnode_is_in_a_dict(dnode_t *); extern dnode_t *dnode_create(void *); extern dnode_t *dnode_init(dnode_t *, void *); extern void dnode_destroy(dnode_t *); extern void *dnode_get(dnode_t *); extern const void *dnode_getkey(dnode_t *); extern void dnode_put(dnode_t *, void *); extern void dict_process(dict_t *, void *, dnode_process_t); extern void dict_load_begin(dict_load_t *, dict_t *); extern void dict_load_next(dict_load_t *, dnode_t *, const void *); extern void dict_load_end(dict_load_t *); extern void dict_merge(dict_t *, dict_t *); #if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG) #ifdef KAZLIB_SIDEEFFECT_DEBUG #define dict_isfull(D) (SFX_CHECK(D)->dict_nodecount == (D)->dict_maxcount) #else #define dict_isfull(D) ((D)->dict_nodecount == DICTCOUNT_T_MAX) #endif #define dict_count(D) ((D)->dict_nodecount) #define dict_isempty(D) ((D)->dict_nodecount == 0) #define dnode_get(N) ((N)->dict_data) #define dnode_getkey(N) ((N)->dict_key) #define dnode_put(N, X) ((N)->dict_data = (X)) #endif #ifdef __cplusplus } #endif #endif rbtree-0.4.6/extconf.rb0000644000004100000410000000100214353333751015027 0ustar www-datawww-datarequire 'mkmf' if enable_config('debug') $CFLAGS << ' -g -std=c99 -pedantic -Wall' else $defs << '-DNDEBUG' end have_header('ruby/version.h') have_func('rb_exec_recursive', 'ruby.h') have_func('rb_exec_recursive_paired', 'ruby.h') have_func('rb_proc_lambda_p', 'ruby.h') have_func('rb_ary_resize', 'ruby.h') have_func('rb_obj_hide', 'ruby.h') have_func('rb_safe_level', 'ruby.h') have_func('rb_cData', 'ruby.h') if Hash.method_defined?(:flatten) $defs << '-DHAVE_HASH_FLATTEN' end create_makefile('rbtree') rbtree-0.4.6/README0000644000004100000410000000446214353333751013731 0ustar www-datawww-data= Ruby/RBTree == Description A RBTree is a sorted associative collection that is implemented with a Red-Black Tree. It maps keys to values like a Hash, but maintains its elements in ascending key order. The interface is the almost identical to that of Hash. A Red-Black Tree is a kind of binary tree that automatically balances by itself when a node is inserted or deleted. Lookup, insertion, and deletion are performed in O(log N) time in the expected and worst cases. On the other hand, the average case complexity of lookup/insertion/deletion on a Hash is constant time. A Hash is usually faster than a RBTree where ordering is unimportant. The elements of a RBTree are sorted using the <=> method of their keys or a Proc set by the readjust method. It means all keys should be comparable with each other or a Proc that takes two keys should return a negative integer, 0, or a positive integer as the first argument is less than, equal to, or greater than the second one. RBTree also provides a few additional methods to take advantage of the ordering: * lower_bound, upper_bound, bound * first, last * shift, pop * reverse_each == Example A RBTree cannot contain duplicate keys. Use MultiRBTree that is the parent class of RBTree to store duplicate keys. require "rbtree" rbtree = RBTree["c", 10, "a", 20] rbtree["b"] = 30 p rbtree["b"] # => 30 rbtree.each do |k, v| p [k, v] end # => ["a", 20] ["b", 30] ["c", 10] mrbtree = MultiRBTree["c", 10, "a", 20, "e", 30, "a", 40] p mrbtree.lower_bound("b") # => ["c", 10] mrbtree.bound("a", "d") do |k, v| p [k, v] end # => ["a", 20] ["a", 40] ["c", 10] Note: a RBTree cannot be modified during iteration. == Installation Run the following command. $ sudo gem install rbtree == Changes === 0.4.6 * Make it work with clang 15. === 0.4.5 * Support Ruby 3.2.0-dev (development branch). === 0.4.4 * Remove the rb_safe_level warning on Ruby 2.7. === 0.4.3 * Quick bug fixes for Ruby 3. == License MIT License. Copyright (c) 2002-2013 OZAWA Takuma. dict.c and dict.h are modified copies that are originally in Kazlib 1.20 written by Kaz Kylheku. Its license is similar to the MIT license. See dict.c and dict.h for the details. The web page of Kazlib is at http://www.kylheku.com/~kaz/kazlib.html.