Skip to content

Instantly share code, notes, and snippets.

@methodmissing
Created November 6, 2009 01:50
Show Gist options
  • Select an option

  • Save methodmissing/227605 to your computer and use it in GitHub Desktop.

Select an option

Save methodmissing/227605 to your computer and use it in GitHub Desktop.
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