/* * avl.c -- libavl wrapper for Ruby * by Filip Pizlo, 2001 * * History: * * August 2001, v 0.1: it works with the basic avl datatype * * License: * * Public domain. * */ #include #include VALUE fp_module_AVL, fp_class_AVL; static ID cmp, eql; struct fp_avl_element_struct; typedef struct fp_avl_element_struct fp_avl_element; struct fp_avl_element_struct { VALUE key, value; }; static fp_avl_element *fp_avl_element_create(VALUE key,VALUE value) { fp_avl_element *ret; if (!rb_respond_to(key,cmp)) rb_raise(rb_eTypeError,"The key must implement <=>"); ret=ALLOC(fp_avl_element); ret->key=key; ret->value=value; return ret; } static int fp_avl_element_init(fp_avl_element *ele,VALUE key,VALUE value) { if (!rb_respond_to(key,cmp)) rb_raise(rb_eTypeError,"The key must implement <=>"); ele->key=key; ele->value=value; return 0; } static int fp_class_AVL_compare(fp_avl_element *a,fp_avl_element *b, void *arg) { return FIX2INT(rb_funcall(a->key,cmp,1,b->key)); } static int fp_class_AVL_mark_element(fp_avl_element *ele,void *arg) { rb_gc_mark(ele->key); rb_gc_mark(ele->value); } static void fp_class_AVL_mark(avl_tree *tree) { avl_walk(tree,fp_class_AVL_mark_element,NULL); } static void fp_class_AVL_free(avl_tree *tree) { avl_destroy(tree,free); } VALUE fp_class_AVL_new(VALUE class) { avl_tree *tree=avl_create(fp_class_AVL_compare,NULL); VALUE ret=Data_Wrap_Struct(class,fp_class_AVL_mark,fp_class_AVL_free,tree); rb_obj_call_init(ret,0,NULL); return ret; } static VALUE fp_class_AVL_init(VALUE self) { return self; } VALUE fp_class_AVL_count(VALUE self) { return INT2FIX(avl_count(DATA_PTR(self))); } VALUE fp_class_AVL_insert(VALUE self,VALUE key,VALUE val) { fp_avl_element *ele=fp_avl_element_create(key,val); ele=avl_insert(DATA_PTR(self),ele); return ele==NULL?Qnil:ele->value; } VALUE fp_class_AVL_replace(VALUE self,VALUE key,VALUE val) { fp_avl_element *ele=fp_avl_element_create(key,val); ele=avl_replace(DATA_PTR(self),ele); return ele==NULL?Qnil:ele->value; } VALUE fp_class_AVL_delete(VALUE self,VALUE key) { fp_avl_element ele,*pEle; fp_avl_element_init(&ele,key,Qnil); pEle=avl_delete(DATA_PTR(self),&ele); return pEle==NULL?Qnil:pEle->value; } VALUE fp_class_AVL_find(VALUE self,VALUE key) { fp_avl_element ele,*pEle; fp_avl_element_init(&ele,key,Qnil); pEle=avl_find(DATA_PTR(self),&ele); return pEle==NULL?Qnil:pEle->value; } VALUE fp_class_AVL_find_close(VALUE self,VALUE key) { fp_avl_element ele,*pEle; fp_avl_element_init(&ele,key,Qnil); pEle=avl_find_close(DATA_PTR(self),&ele); return pEle==NULL?Qnil:pEle->value; } VALUE fp_class_AVL_each(VALUE self) { avl_traverser trav={0}; fp_avl_element *ele; while ((ele=avl_traverse(DATA_PTR(self),&trav))!=NULL) rb_yield(rb_assoc_new(ele->key,ele->value)); return Qnil; } VALUE fp_class_AVL_each_key(VALUE self) { avl_traverser trav={0}; fp_avl_element *ele; while ((ele=avl_traverse(DATA_PTR(self),&trav))!=NULL) rb_yield(ele->key); return Qnil; } VALUE fp_class_AVL_each_value(VALUE self) { avl_traverser trav={0}; fp_avl_element *ele; while ((ele=avl_traverse(DATA_PTR(self),&trav))!=NULL) rb_yield(ele->value); return Qnil; } VALUE fp_class_AVL_equal(VALUE self,VALUE other) { avl_tree *me=DATA_PTR(self),*her; avl_traverser trav={0}; fp_avl_element *ele,*ele2; if (rb_obj_is_instance_of(other,fp_class_AVL)!=Qtrue) return Qfalse; her=DATA_PTR(other); if (avl_count(me)!=avl_count(her)) return Qfalse; while ((ele=avl_traverse(me,&trav))!=NULL) { ele2=avl_find(her,ele); if (ele2==NULL) return Qfalse; if (!rb_equal(ele->value,ele2->value)) return Qfalse; } return Qtrue; } VALUE fp_class_AVL_empty(VALUE self) { return avl_count(DATA_PTR(self))?Qfalse:Qtrue; } void Init_AVL() { fp_module_AVL=rb_define_module("AVL"); // main AVL class fp_class_AVL=rb_define_class_under(fp_module_AVL,"AVL",rb_cObject); rb_define_singleton_method(fp_class_AVL,"new",fp_class_AVL_new,0); // primary methods rb_define_method(fp_class_AVL,"initialize",fp_class_AVL_init,0); rb_define_method(fp_class_AVL,"count",fp_class_AVL_count,0); rb_define_method(fp_class_AVL,"insert",fp_class_AVL_insert,2); rb_define_method(fp_class_AVL,"replace",fp_class_AVL_replace,2); rb_define_method(fp_class_AVL,"delete",fp_class_AVL_delete,1); rb_define_method(fp_class_AVL,"find",fp_class_AVL_find,1); rb_define_method(fp_class_AVL,"find_close",fp_class_AVL_find_close,1); rb_define_method(fp_class_AVL,"each",fp_class_AVL_each,0); // en-ruby-ization methods rb_define_method(fp_class_AVL,"[]",fp_class_AVL_find,1); rb_define_method(fp_class_AVL,"[]=",fp_class_AVL_replace,2); rb_define_method(fp_class_AVL,"each_key",fp_class_AVL_each_key,0); rb_define_method(fp_class_AVL,"each_value",fp_class_AVL_each_value,0); rb_define_method(fp_class_AVL,"each_pair",fp_class_AVL_each,0); rb_define_method(fp_class_AVL,"==",fp_class_AVL_equal,1); rb_define_method(fp_class_AVL,"empty?",fp_class_AVL_empty,0); // get some symbols... cmp=rb_intern("<=>"); eql=rb_intern("=="); }