mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
Fix Enumerable#hash on non 32-bit integer conf.
This commit is contained in:
committed by
Yukihiro "Matz" Matsumoto
parent
84b499d02b
commit
4b29abc565
@@ -333,16 +333,4 @@ 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|
|
||||
n = (e.hash & (0x7fffffff >> (i % 16))) << (i % 16)
|
||||
h ^= n
|
||||
i += 1
|
||||
end
|
||||
h
|
||||
end
|
||||
end
|
||||
|
||||
+55
-1
@@ -5,10 +5,64 @@
|
||||
*/
|
||||
|
||||
#include <mruby.h>
|
||||
#include <mruby/proc.h>
|
||||
|
||||
typedef struct enumerable_hash_context {
|
||||
mrb_int hash;
|
||||
mrb_int index;
|
||||
} enumerable_hash_context;
|
||||
|
||||
static mrb_value
|
||||
enumerable_hash_each(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);
|
||||
|
||||
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_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);
|
||||
}
|
||||
|
||||
void
|
||||
mrb_init_enumerable(mrb_state *mrb)
|
||||
{
|
||||
mrb_define_module(mrb, "Enumerable"); /* 15.3.2 */
|
||||
struct RClass *enumerable;
|
||||
enumerable = mrb_define_module(mrb, "Enumerable"); /* 15.3.2 */
|
||||
mrb_define_module_function(mrb, enumerable, "hash", enumerable_hash, MRB_ARGS_NONE());
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user