Skip to content

Commit

Permalink
fix the Array#hash since its method had returned just size of array
Browse files Browse the repository at this point in the history
  • Loading branch information
Watson1978 committed Jun 13, 2012
1 parent 4c6e0e1 commit 2f8fefa
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 25 deletions.
47 changes: 22 additions & 25 deletions NSArray.m
Expand Up @@ -1458,32 +1458,29 @@
return values;
}

// A very naive hashing function for arrays, which hashes the array's length,
// then first and last elements (in case the array has more than 4 elements).
// We cannot rely on the CoreFoundation hashing function for arrays as it's
// simply returning the number of elements, and can trigger huge performance
// problems when using same-sized arrays as keys in Hash objects.
unsigned long
rb_ary_hash(VALUE ary)
static unsigned long
recursive_hash(VALUE ary, VALUE dummy, int recur)
{
const long len = RARRAY_LEN(ary);
unsigned long hash = 0;
if (len > 0) {
VALUE elem = RARRAY_AT(ary, 0);
if (elem == ary) {
// recursive array
return (unsigned long)rb_cRubyArray;
}
hash += rb_hash_code(elem);
if (len > 4) {
elem = RARRAY_AT(ary, len - 1);
if (elem == ary) {
// recursive array
return (unsigned long)rb_cRubyArray;
}
hash = (hash >> 3) ^ rb_hash_code(elem);
long i;
st_index_t h;
VALUE n;

h = rb_hash_start(RARRAY_LEN(ary));
if (recur) {
h = rb_hash_uint(h, NUM2LONG(rb_hash(rb_cArray)));
}
else {
for (i=0; i<RARRAY_LEN(ary); i++) {
n = rb_hash(RARRAY_PTR(ary)[i]);
h = rb_hash_uint(h, NUM2LONG(n));
}
hash += len;
}
return hash;
h = rb_hash_end(h);
return h;
}

unsigned long
rb_ary_hash(VALUE ary)
{
return rb_exec_recursive_outer(recursive_hash, ary, 0);
}
15 changes: 15 additions & 0 deletions array.c
Expand Up @@ -2587,6 +2587,20 @@ rary_eql_fast(rb_ary_t *ary1, rb_ary_t *ary2)
return rb_exec_recursive(recursive_eql_fast, (VALUE)ary1, (VALUE)ary2);
}

/*
* call-seq:
* ary.hash -> fixnum
*
* Compute a hash-code for this array. Two arrays with the same content
* will have the same hash code (and will compare using <code>eql?</code>).
*/

static VALUE
rary_hash(VALUE ary, SEL sel)
{
return LONG2FIX(rb_ary_hash(ary));
}

/*
* call-seq:
* array.include?(obj) -> true or false
Expand Down Expand Up @@ -3790,6 +3804,7 @@ Init_Array(void)
rb_objc_define_method(rb_cRubyArray, "inspect", rary_inspect, 0);
rb_objc_define_method(rb_cRubyArray, "==", rary_equal, 1);
rb_objc_define_method(rb_cRubyArray, "eql?", rary_eql, 1);
rb_objc_define_method(rb_cRubyArray, "hash", rary_hash, 0);
rb_objc_define_method(rb_cRubyArray, "[]", rary_aref, -1);
rb_objc_define_method(rb_cRubyArray, "[]=", rary_aset, -1);
rb_objc_define_method(rb_cRubyArray, "at", rary_at, 1);
Expand Down

0 comments on commit 2f8fefa

Please sign in to comment.