Update the patch to not use `funcall` in C; ref #4013

parent 4b29abc5
......@@ -333,4 +333,15 @@ module Enumerable
#
# ISO 15.3.2.2.20
alias to_a entries
# redefine #hash 15.3.1.3.15
def hash
h = 12347
i = 0
self.each do |e|
h = __update_hash(h, i, e.hash)
i += 1
end
h
end
end
......@@ -7,55 +7,28 @@
#include <mruby.h>
#include <mruby/proc.h>
typedef struct enumerable_hash_context {
mrb_int hash;
mrb_int index;
} enumerable_hash_context;
/* internal method `__update_hash(oldhash, index, itemhash)` */
static mrb_value
enumerable_hash_each(mrb_state *mrb, mrb_value self)
enum_update_hash(mrb_state *mrb, mrb_value self)
{
mrb_value item;
mrb_value closure;
mrb_get_args(mrb, "o", &item);
closure = mrb_proc_cfunc_env_get(mrb, 0);
if (mrb_cptr_p(closure)) {
mrb_value item_hash;
enumerable_hash_context *context = (enumerable_hash_context *)mrb_cptr(closure);
mrb_int hash;
mrb_int index;
mrb_int hv;
mrb_value item_hash;
item_hash = mrb_funcall(mrb, item, "hash", 0);
if (mrb_fixnum_p(item_hash)) {
context->hash ^= (mrb_fixnum(item_hash) << (context->index % 16));
++context->index;
return mrb_nil_value();
}
mrb_get_args(mrb, "iio", &hash, &index, &item_hash);
if (mrb_fixnum_p(item_hash)) {
hv = mrb_fixnum(item_hash);
}
else if (mrb_float_p(item_hash)) {
hv = (mrb_int)mrb_float(item_hash);
}
else {
mrb_raise(mrb, E_TYPE_ERROR, "can't calculate hash");
}
hash ^= (hv << (index % 16));
mrb_raise(mrb, E_TYPE_ERROR, "can't calculate hash");
}
static mrb_value
enumerable_hash(mrb_state *mrb, mrb_value self)
{
/* redefine #hash 15.3.1.3.15 */
struct RProc *proc;
enumerable_hash_context context;
mrb_value closure;
mrb_value blk;
int ai = mrb_gc_arena_save(mrb);
context.hash = 12347;
context.index = 0;
closure = mrb_cptr_value(mrb, &context);
proc = mrb_proc_new_cfunc_with_env(mrb, enumerable_hash_each, 1, &closure);
blk = mrb_obj_value(proc);
mrb_funcall_with_block(mrb, self, mrb_intern_cstr(mrb, "each"), 0, NULL, blk);
mrb_gc_arena_restore(mrb, ai);
return mrb_fixnum_value(context.hash);
return mrb_fixnum_value(hash);
}
void
......@@ -63,6 +36,5 @@ mrb_init_enumerable(mrb_state *mrb)
{
struct RClass *enumerable;
enumerable = mrb_define_module(mrb, "Enumerable"); /* 15.3.2 */
mrb_define_module_function(mrb, enumerable, "hash", enumerable_hash, MRB_ARGS_NONE());
mrb_define_module_function(mrb, enumerable, "__update_hash", enum_update_hash, MRB_ARGS_REQ(1));
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment