2012-02-07 00:29:20 -05:00
|
|
|
#include <ruby.h>
|
|
|
|
#include <ruby/st.h>
|
|
|
|
|
2012-02-07 00:43:49 -05:00
|
|
|
static void
|
|
|
|
numhash_free(void *ptr)
|
|
|
|
{
|
|
|
|
if (ptr) st_free_table(ptr);
|
|
|
|
}
|
|
|
|
|
2014-09-26 21:28:47 -04:00
|
|
|
static size_t
|
|
|
|
numhash_memsize(const void *ptr)
|
|
|
|
{
|
|
|
|
return ptr ? st_memsize(ptr) : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const rb_data_type_t numhash_type = {
|
|
|
|
"numhash",
|
|
|
|
{0, numhash_free, numhash_memsize,},
|
|
|
|
NULL, NULL,
|
|
|
|
RUBY_TYPED_FREE_IMMEDIATELY|RUBY_TYPED_WB_PROTECTED,
|
|
|
|
};
|
|
|
|
|
2012-02-07 00:29:20 -05:00
|
|
|
static VALUE
|
|
|
|
numhash_alloc(VALUE klass)
|
|
|
|
{
|
2014-09-26 21:28:47 -04:00
|
|
|
return TypedData_Wrap_Struct(klass, &numhash_type, 0);
|
2012-02-07 00:29:20 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
numhash_init(VALUE self)
|
|
|
|
{
|
2014-09-26 21:28:47 -04:00
|
|
|
st_table *tbl = (st_table *)Check_TypedStruct(self, &numhash_type);
|
2012-02-07 00:29:20 -05:00
|
|
|
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;
|
2014-09-26 21:28:47 -04:00
|
|
|
st_table *tbl = (st_table *)Check_TypedStruct(self, &numhash_type);
|
2012-02-07 00:29:20 -05:00
|
|
|
if (!SPECIAL_CONST_P(key)) rb_raise(rb_eArgError, "not a special const");
|
2014-09-26 21:28:47 -04:00
|
|
|
if (st_lookup(tbl, (st_data_t)key, &data))
|
2012-02-07 00:29:20 -05:00
|
|
|
return (VALUE)data;
|
|
|
|
return Qnil;
|
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
numhash_aset(VALUE self, VALUE key, VALUE data)
|
|
|
|
{
|
2014-09-26 21:28:47 -04:00
|
|
|
st_table *tbl = (st_table *)Check_TypedStruct(self, &numhash_type);
|
2012-02-07 00:29:20 -05:00
|
|
|
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");
|
2014-09-26 21:28:47 -04:00
|
|
|
st_insert(tbl, (st_data_t)key, (st_data_t)data);
|
2012-02-07 00:29:20 -05:00
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2012-03-31 00:20:45 -04:00
|
|
|
numhash_i(st_data_t key, st_data_t value, st_data_t arg)
|
2012-02-07 00:29:20 -05:00
|
|
|
{
|
|
|
|
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)
|
|
|
|
{
|
2014-09-26 21:28:47 -04:00
|
|
|
st_table *table = (st_table *)Check_TypedStruct(self, &numhash_type);
|
2012-03-10 09:52:19 -05:00
|
|
|
st_data_t data = (st_data_t)self;
|
|
|
|
return st_foreach_check(table, numhash_i, data, data) ? Qtrue : Qfalse;
|
2012-02-07 00:29:20 -05:00
|
|
|
}
|
|
|
|
|
2012-02-07 00:52:15 -05:00
|
|
|
static int
|
2012-03-29 10:50:20 -04:00
|
|
|
update_func(st_data_t *key, st_data_t *value, st_data_t arg, int existing)
|
2012-02-07 00:52:15 -05:00
|
|
|
{
|
2012-03-29 10:50:20 -04:00
|
|
|
VALUE ret = rb_yield_values(existing ? 2 : 1, (VALUE)*key, (VALUE)*value);
|
2012-02-07 00:52:15 -05:00
|
|
|
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)
|
|
|
|
{
|
2014-09-26 21:28:47 -04:00
|
|
|
st_table *table = (st_table *)Check_TypedStruct(self, &numhash_type);
|
|
|
|
if (st_update(table, (st_data_t)key, update_func, 0))
|
2012-02-07 00:52:15 -05:00
|
|
|
return Qtrue;
|
|
|
|
else
|
|
|
|
return Qfalse;
|
|
|
|
}
|
|
|
|
|
2012-03-10 09:52:06 -05:00
|
|
|
#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)
|
|
|
|
{
|
2014-09-26 21:28:47 -04:00
|
|
|
st_table *table = (st_table *)Check_TypedStruct(self, &numhash_type);
|
|
|
|
return ST2NUM(table->num_entries);
|
2012-03-10 09:52:06 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
numhash_delete_safe(VALUE self, VALUE key)
|
|
|
|
{
|
2014-09-26 21:28:47 -04:00
|
|
|
st_table *table = (st_table *)Check_TypedStruct(self, &numhash_type);
|
2012-03-10 09:52:06 -05:00
|
|
|
st_data_t val, k = (st_data_t)key;
|
2014-09-26 21:28:47 -04:00
|
|
|
if (st_delete_safe(table, &k, &val, (st_data_t)self)) {
|
2012-03-10 09:52:06 -05:00
|
|
|
return val;
|
|
|
|
}
|
|
|
|
return Qnil;
|
|
|
|
}
|
|
|
|
|
2012-02-07 00:29:20 -05:00
|
|
|
void
|
|
|
|
Init_numhash(void)
|
|
|
|
{
|
|
|
|
VALUE st = rb_define_class_under(rb_define_module("Bug"), "StNumHash", rb_cData);
|
|
|
|
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);
|
2012-02-07 00:52:15 -05:00
|
|
|
rb_define_method(st, "update", numhash_update, 1);
|
2012-03-10 09:52:06 -05:00
|
|
|
rb_define_method(st, "size", numhash_size, 0);
|
|
|
|
rb_define_method(st, "delete_safe", numhash_delete_safe, 1);
|
2012-02-07 00:29:20 -05:00
|
|
|
}
|
2012-02-07 00:52:15 -05:00
|
|
|
|