summaryrefslogtreecommitdiff
path: root/hash.c
diff options
context:
space:
mode:
authormatz <matz@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2006-09-22 08:36:02 +0000
committermatz <matz@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2006-09-22 08:36:02 +0000
commit70360efac388686eb848b5bfbbb3be7a755451c6 (patch)
tree09b95c12a0d418145b7070a895ac8f9e35bb84f6 /hash.c
parent51281b961be085be5a29088ada5118699035306b (diff)
* 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
Diffstat (limited to 'hash.c')
-rw-r--r--hash.c84
1 files changed, 77 insertions, 7 deletions
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);