summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorYukihiro "Matz" Matsumoto <[email protected]>2018-04-28 11:24:26 +0900
committerYukihiro "Matz" Matsumoto <[email protected]>2018-04-28 11:26:23 +0900
commit50a9c5d7c704e84c6bdec9affa270824fed02034 (patch)
tree59b7fb5558399a37d0de50dbf208cccec39a8f6c
parent4b29abc565b5791d6d39b28358e2c82c17d3c500 (diff)
downloadmruby-50a9c5d7c704e84c6bdec9affa270824fed02034.tar.gz
mruby-50a9c5d7c704e84c6bdec9affa270824fed02034.zip
Update the patch to not use `funcall` in C; ref #4013
-rw-r--r--mrblib/enum.rb11
-rw-r--r--src/enum.c64
2 files changed, 29 insertions, 46 deletions
diff --git a/mrblib/enum.rb b/mrblib/enum.rb
index 20638f7e8..a97a26f97 100644
--- a/mrblib/enum.rb
+++ b/mrblib/enum.rb
@@ -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
diff --git a/src/enum.c b/src/enum.c
index ed3ebdd9f..94103e35e 100644
--- a/src/enum.c
+++ b/src/enum.c
@@ -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));
}
-