summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog6
-rw-r--r--hash.c84
-rw-r--r--object.c14
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 <matz@ruby-lang.org>
+
+ * 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 <matz@ruby-lang.org>
* 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
@@ -1304,6 +1304,23 @@ struct equal_data {
};
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)
{
VALUE val2;
@@ -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 <code>true</code> if <i>hash</i> and <i>other</i> 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 <code>eql?</code>).
+ */
+
+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 <code>b</code>).
*
* The <code>eql?</code> method returns <code>true</code> if
- <i>obj</i> and <i>anObject</i> have the
- * same value. Used by <code>Hash</code> to test members for equality.
- * For objects of class <code>Object</code>, <code>eql?</code> is
- * synonymous with <code>==</code>. Subclasses normally continue this
- * tradition, but there are exceptions. <code>Numeric</code> types, for
- * example, perform type conversion across <code>==</code>, but not
- * across <code>eql?</code>, so:
+ * <i>obj</i> and <i>anObject</i> have the same value. Used by
+ * <code>Hash</code> to test members for equality. For objects of
+ * class <code>Object</code>, <code>eql?</code> is synonymous with
+ * <code>==</code>. Subclasses normally continue this tradition, but
+ * there are exceptions. <code>Numeric</code> types, for example,
+ * perform type conversion across <code>==</code>, but not across
+ * <code>eql?</code>, so:
*
* 1 == 1.0 #=> true
* 1.eql? 1.0 #=> false