From 70360efac388686eb848b5bfbbb3be7a755451c6 Mon Sep 17 00:00:00 2001 From: matz Date: Fri, 22 Sep 2006 08:36:02 +0000 Subject: [PATCH] * hash.c (rb_hash_eql): new method to be used by Hash. * hash.c (rb_hash_hash): ditto. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@10993 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 6 ++++ hash.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++----- object.c | 14 +++++----- 3 files changed, 90 insertions(+), 14 deletions(-) diff --git a/ChangeLog b/ChangeLog index 23defd152a..d67b322c7c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +Fri Sep 22 17:33:29 2006 Yukihiro Matsumoto + + * hash.c (rb_hash_eql): new method to be used by Hash. + + * hash.c (rb_hash_hash): ditto. + Fri Sep 22 06:53:22 2006 Yukihiro Matsumoto * bignum.c (rb_big_hash): use rb_memhash(). diff --git a/hash.c b/hash.c index 337007c39e..11a6bfb847 100644 --- a/hash.c +++ b/hash.c @@ -1303,6 +1303,23 @@ struct equal_data { st_table *tbl; }; +static int +eql_i(VALUE key, VALUE val1, struct equal_data *data) +{ + VALUE val2; + + if (key == Qundef) return ST_CONTINUE; + if (!st_lookup(data->tbl, key, &val2)) { + data->result = Qfalse; + return ST_STOP; + } + if (!rb_eql(val1, val2)) { + data->result = Qfalse; + return ST_STOP; + } + return ST_CONTINUE; +} + static int equal_i(VALUE key, VALUE val1, struct equal_data *data) { @@ -1321,7 +1338,7 @@ equal_i(VALUE key, VALUE val1, struct equal_data *data) } static VALUE -hash_equal(VALUE hash1, VALUE hash2, int eql /* compare default value if true */) +hash_equal(VALUE hash1, VALUE hash2, int eql) { struct equal_data data; @@ -1334,15 +1351,15 @@ hash_equal(VALUE hash1, VALUE hash2, int eql /* compare default value if true */ } if (RHASH(hash1)->tbl->num_entries != RHASH(hash2)->tbl->num_entries) return Qfalse; - if (eql) { - if (!(rb_equal(RHASH(hash1)->ifnone, RHASH(hash2)->ifnone) && - FL_TEST(hash1, HASH_PROC_DEFAULT) == FL_TEST(hash2, HASH_PROC_DEFAULT))) - return Qfalse; - } +#if 0 + if (!(rb_equal(RHASH(hash1)->ifnone, RHASH(hash2)->ifnone) && + FL_TEST(hash1, HASH_PROC_DEFAULT) == FL_TEST(hash2, HASH_PROC_DEFAULT))) + return Qfalse; +#endif data.tbl = RHASH(hash2)->tbl; data.result = Qtrue; - rb_hash_foreach(hash1, equal_i, (st_data_t)&data); + rb_hash_foreach(hash1, eql ? eql_i : equal_i, (st_data_t)&data); return data.result; } @@ -1372,6 +1389,57 @@ rb_hash_equal(VALUE hash1, VALUE hash2) return hash_equal(hash1, hash2, Qfalse); } +/* + * call-seq: + * hash.eql?(other) -> true or false + * + * Returns true if hash and other are + * both hashes with the same content. + */ + +static VALUE +rb_hash_eql(VALUE hash1, VALUE hash2) +{ + return hash_equal(hash1, hash2, Qfalse); +} + +static int +hash_i(VALUE key, VALUE val, int *hval) +{ + if (key == Qundef) return ST_CONTINUE; + *hval ^= rb_hash(key); + *hval ^= rb_hash(val); + return ST_CONTINUE; +} + +static VALUE +recursive_hash(VALUE hash, VALUE dummy, int recur) +{ + int hval; + VALUE n; + + if (recur) { + return LONG2FIX(0); + } + hval = RHASH(hash)->tbl->num_entries; + rb_hash_foreach(hash, hash_i, (st_data_t)&hval); + return INT2FIX(hval); +} + +/* + * call-seq: + * array.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 eql?). + */ + +static VALUE +rb_hash_hash(VALUE hash) +{ + return rb_exec_recursive(recursive_hash, hash, 0); +} + static int rb_hash_invert_i(VALUE key, VALUE value, VALUE hash) { @@ -2330,6 +2398,8 @@ Init_Hash(void) rb_define_method(rb_cHash,"==", rb_hash_equal, 1); rb_define_method(rb_cHash,"[]", rb_hash_aref, 1); + rb_define_method(rb_cHash,"hash", rb_hash_hash, 0); + rb_define_method(rb_cHash,"eql?", rb_hash_eql, 1); rb_define_method(rb_cHash,"fetch", rb_hash_fetch, -1); rb_define_method(rb_cHash,"[]=", rb_hash_aset, 2); rb_define_method(rb_cHash,"store", rb_hash_aset, 2); diff --git a/object.c b/object.c index aef9037488..89742b2ca9 100644 --- a/object.c +++ b/object.c @@ -76,13 +76,13 @@ rb_eql(VALUE obj1, VALUE obj2) * object as b). * * The eql? method returns true if - obj and anObject have the - * same value. Used by Hash to test members for equality. - * For objects of class Object, eql? is - * synonymous with ==. Subclasses normally continue this - * tradition, but there are exceptions. Numeric types, for - * example, perform type conversion across ==, but not - * across eql?, so: + * obj and anObject have the same value. Used by + * Hash to test members for equality. For objects of + * class Object, eql? is synonymous with + * ==. Subclasses normally continue this tradition, but + * there are exceptions. Numeric types, for example, + * perform type conversion across ==, but not across + * eql?, so: * * 1 == 1.0 #=> true * 1.eql? 1.0 #=> false