1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
|
#include <ruby.h>
#include <ruby/st.h>
static void
numhash_free(void *ptr)
{
if (ptr) st_free_table(ptr);
}
static size_t
numhash_memsize(const void *ptr)
{
return st_memsize(ptr);
}
static const rb_data_type_t numhash_type = {
"numhash",
{0, numhash_free, numhash_memsize,},
0, 0,
RUBY_TYPED_FREE_IMMEDIATELY|RUBY_TYPED_WB_PROTECTED,
};
static VALUE
numhash_alloc(VALUE klass)
{
return TypedData_Wrap_Struct(klass, &numhash_type, 0);
}
static VALUE
numhash_init(VALUE self)
{
st_table *tbl = (st_table *)Check_TypedStruct(self, &numhash_type);
if (tbl) st_free_table(tbl);
DATA_PTR(self) = st_init_numtable();
return self;
}
static VALUE
numhash_aref(VALUE self, VALUE key)
{
st_data_t data;
st_table *tbl = (st_table *)Check_TypedStruct(self, &numhash_type);
if (!SPECIAL_CONST_P(key)) rb_raise(rb_eArgError, "not a special const");
if (st_lookup(tbl, (st_data_t)key, &data))
return (VALUE)data;
return Qnil;
}
static VALUE
numhash_aset(VALUE self, VALUE key, VALUE data)
{
st_table *tbl = (st_table *)Check_TypedStruct(self, &numhash_type);
if (!SPECIAL_CONST_P(key)) rb_raise(rb_eArgError, "not a special const");
if (!SPECIAL_CONST_P(data)) rb_raise(rb_eArgError, "not a special const");
st_insert(tbl, (st_data_t)key, (st_data_t)data);
return self;
}
static int
numhash_i(st_data_t key, st_data_t value, st_data_t arg, int _)
{
VALUE ret;
ret = rb_yield_values(3, (VALUE)key, (VALUE)value, (VALUE)arg);
if (ret == Qtrue) return ST_CHECK;
return ST_CONTINUE;
}
static VALUE
numhash_each(VALUE self)
{
st_table *table = (st_table *)Check_TypedStruct(self, &numhash_type);
st_data_t data = (st_data_t)self;
return st_foreach_check(table, numhash_i, data, data) ? Qtrue : Qfalse;
}
static int
update_func(st_data_t *key, st_data_t *value, st_data_t arg, int existing)
{
VALUE ret = rb_yield_values(existing ? 2 : 1, (VALUE)*key, (VALUE)*value);
switch (ret) {
case Qfalse:
return ST_STOP;
case Qnil:
return ST_DELETE;
default:
*value = ret;
return ST_CONTINUE;
}
}
static VALUE
numhash_update(VALUE self, VALUE key)
{
st_table *table = (st_table *)Check_TypedStruct(self, &numhash_type);
if (st_update(table, (st_data_t)key, update_func, 0))
return Qtrue;
else
return Qfalse;
}
#if SIZEOF_LONG == SIZEOF_VOIDP
# define ST2NUM(x) ULONG2NUM(x)
#elif SIZEOF_LONG_LONG == SIZEOF_VOIDP
# define ST2NUM(x) ULL2NUM(x)
#endif
static VALUE
numhash_size(VALUE self)
{
st_table *table = (st_table *)Check_TypedStruct(self, &numhash_type);
return ST2NUM(table->num_entries);
}
static VALUE
numhash_delete_safe(VALUE self, VALUE key)
{
st_table *table = (st_table *)Check_TypedStruct(self, &numhash_type);
st_data_t val, k = (st_data_t)key;
if (st_delete_safe(table, &k, &val, (st_data_t)self)) {
return val;
}
return Qnil;
}
void
Init_numhash(void)
{
VALUE st = rb_define_class_under(rb_define_module("Bug"), "StNumHash", rb_cObject);
rb_define_alloc_func(st, numhash_alloc);
rb_define_method(st, "initialize", numhash_init, 0);
rb_define_method(st, "[]", numhash_aref, 1);
rb_define_method(st, "[]=", numhash_aset, 2);
rb_define_method(st, "each", numhash_each, 0);
rb_define_method(st, "update", numhash_update, 1);
rb_define_method(st, "size", numhash_size, 0);
rb_define_method(st, "delete_safe", numhash_delete_safe, 1);
}
|