Created
November 6, 2009 01:50
-
-
Save methodmissing/227605 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| diff --git a/hash.c b/hash.c | |
| index ef8b9a8..bd60d5a 100644 | |
| --- a/hash.c | |
| +++ b/hash.c | |
| @@ -33,8 +33,7 @@ rb_hash_freeze(VALUE hash) | |
| VALUE rb_cHash; | |
| static VALUE envtbl; | |
| -static ID id_hash, id_yield, id_default; | |
| - | |
| +static ID id_hash, id_yield, id_default, id_cmp; | |
| static int | |
| rb_any_cmp(VALUE a, VALUE b) | |
| { | |
| @@ -99,6 +98,14 @@ rb_any_hash(VALUE a) | |
| return (st_index_t)RSHIFT(hnum, 1); | |
| } | |
| +static int | |
| +rb_uniform_cmp(VALUE a, VALUE b) | |
| +{ | |
| + if (rb_respond_to(a, id_cmp) && rb_respond_to(b, id_cmp)) | |
| + return FIX2INT(rb_funcall(a, id_cmp, 1, b)); | |
| + rb_raise(rb_eRuntimeError, "object expected to implement a Comparable interface"); | |
| +} | |
| + | |
| static const struct st_hash_type objhash = { | |
| rb_any_cmp, | |
| rb_any_hash, | |
| @@ -109,6 +116,11 @@ static const struct st_hash_type identhash = { | |
| st_numhash, | |
| }; | |
| +static const struct st_hash_type uniformhash = { | |
| + rb_uniform_cmp, | |
| + rb_any_hash, | |
| +}; | |
| + | |
| typedef int st_foreach_func(st_data_t, st_data_t, st_data_t); | |
| struct foreach_safe_arg { | |
| @@ -1852,6 +1864,26 @@ rb_hash_compare_by_id_p(VALUE hash) | |
| return Qfalse; | |
| } | |
| +static VALUE | |
| +rb_hash_uniform(VALUE hash) | |
| +{ | |
| + rb_hash_modify(hash); | |
| + RHASH(hash)->ntbl->type = &uniformhash; | |
| + rb_hash_rehash(hash); | |
| + return hash; | |
| +} | |
| + | |
| +static VALUE | |
| rb_cHash = rb_define_class("Hash", rb_cObject); | |
| @@ -2716,6 +2749,9 @@ Init_Hash(void) | |
| rb_define_method(rb_cHash,"compare_by_identity", rb_hash_compare_by_id, 0); | |
| rb_define_method(rb_cHash,"compare_by_identity?", rb_hash_compare_by_id_p, 0); | |
| + rb_define_method(rb_cHash,"uniform", rb_hash_uniform, 0); | |
| + rb_define_method(rb_cHash,"uniform?", rb_hash_uniform_p, 0); | |
| + | |
| origenviron = environ; | |
| envtbl = rb_obj_alloc(rb_cObject); | |
| rb_extend_object(envtbl, rb_mEnumerable); | |
| diff --git a/test/ruby/test_hash.rb b/test/ruby/test_hash.rb | |
| index c860b25..5ad86a4 100644 | |
| --- a/test/ruby/test_hash.rb | |
| +++ b/test/ruby/test_hash.rb | |
| @@ -861,6 +861,31 @@ class TestHash < Test::Unit::TestCase | |
| assert_equal({o1=>1,o2=>2}.hash, {o2=>2,o1=>1}.hash) | |
| end | |
| + class MemorySlot | |
| + attr_reader :size | |
| + def initialize(size) | |
| + @size = size | |
| + end | |
| + | |
| + def <=>(other) | |
| + size <=> other.size | |
| + end | |
| + alias hash size | |
| + end | |
| + | |
| + def test_uniform | |
| + s = MemorySlot.new(256) | |
| + s1 = MemorySlot.new(512) | |
| + assert(!{}.uniform?) | |
| + h = { s => %w(obj1 obj2 ob3) } | |
| + h.uniform | |
| + assert(h.uniform?) | |
| + assert_equal %w(obj1 obj2 ob3), h[s] | |
| + h[s1] = %w(obj4) | |
| + h[MemorySlot.new(256)] = %w(obj1) | |
| + assert_equal %w(obj1), h[s] | |
| + end | |
| + | |
| def test_hash_bignum_hash | |
| x = 2<<(32-3)-1 | |
| assert_equal({x=>1}.hash, {x=>1}.hash) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment