summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorYukihiro "Matz" Matsumoto <[email protected]>2014-04-01 14:56:23 +0900
committerYukihiro "Matz" Matsumoto <[email protected]>2014-04-01 14:56:23 +0900
commit1690fc4c99162aece186fd6e4f5d8fe43e34564e (patch)
tree96fb10f6f8fd2ac9c4e0151810ed6a4d53e6cb93
parent8b141b07b67b185caaaf2945fe9a6c1f7208e647 (diff)
downloadmruby-1690fc4c99162aece186fd6e4f5d8fe43e34564e.tar.gz
mruby-1690fc4c99162aece186fd6e4f5d8fe43e34564e.zip
implement Hash#== and eql? in Ruby
-rw-r--r--mrblib/hash.rb33
-rw-r--r--src/hash.c100
2 files changed, 33 insertions, 100 deletions
diff --git a/mrblib/hash.rb b/mrblib/hash.rb
index d15fa434e..853f6ed97 100644
--- a/mrblib/hash.rb
+++ b/mrblib/hash.rb
@@ -3,6 +3,39 @@
#
# ISO 15.2.13
class Hash
+ ##
+ # Equality---Two hashes are equal if they each contain the same number
+ # of keys and if each key-value pair is equal to (according to
+ # <code>Object#==</code>) the corresponding elements in the other
+ # hash.
+ #
+ # ISO 15.2.13.4.1
+ def == (hash)
+ return true if self.equal?(hash)
+ hash = hash.to_hash
+ return false if self.size != hash.size
+ self.each do |k,v|
+ return false unless hash.key?(k)
+ return false unless self[k] == hash[k]
+ end
+ return true
+ end
+
+ ##
+ # Returns <code>true</code> if <i>hash</i> and <i>other</i> are
+ # both hashes with the same content compared by eql?.
+ #
+ # ISO 15.2.13.4.32 (x)
+ def eql?(hash)
+ return true if self.equal?(hash)
+ hash = hash.to_hash
+ return false if self.size != hash.size
+ self.each do |k,v|
+ return false unless hash.key?(k)
+ return false unless self[k].eql?(hash[k])
+ end
+ return true
+ end
##
# Delete the element with the key +key+.
diff --git a/src/hash.c b/src/hash.c
index 63262fc70..05e0ac333 100644
--- a/src/hash.c
+++ b/src/hash.c
@@ -873,104 +873,6 @@ mrb_hash_has_value(mrb_state *mrb, mrb_value hash)
return mrb_false_value();
}
-static mrb_value
-hash_equal(mrb_state *mrb, mrb_value hash1, mrb_value hash2, mrb_bool eql)
-{
- khash_t(ht) *h1, *h2;
- mrb_bool eq;
-
- if (mrb_obj_equal(mrb, hash1, hash2)) return mrb_true_value();
- if (!mrb_hash_p(hash2)) {
- if (!mrb_respond_to(mrb, hash2, mrb_intern_lit(mrb, "to_hash"))) {
- return mrb_false_value();
- }
- else {
- if (eql) {
- eq = mrb_eql(mrb, hash2, hash1);
- }
- else {
- eq = mrb_equal(mrb, hash2, hash1);
- }
- return mrb_bool_value(eq);
- }
- }
- h1 = RHASH_TBL(hash1);
- h2 = RHASH_TBL(hash2);
- if (!h1) {
- return mrb_bool_value(!h2);
- }
- if (!h2) return mrb_false_value();
- if (kh_size(h1) != kh_size(h2)) return mrb_false_value();
- else {
- khiter_t k1, k2;
- mrb_value key;
-
- for (k1 = kh_begin(h1); k1 != kh_end(h1); k1++) {
- if (!kh_exist(h1, k1)) continue;
- key = kh_key(h1,k1);
- k2 = kh_get(ht, mrb, h2, key);
- if (k2 != kh_end(h2)) {
- if (eql)
- eq = mrb_eql(mrb, kh_value(h1,k1).v, kh_value(h2,k2).v);
- else
- eq = mrb_equal(mrb, kh_value(h1,k1).v, kh_value(h2,k2).v);
- if (eq) {
- continue; /* next key */
- }
- }
- return mrb_false_value();
- }
- }
- return mrb_true_value();
-}
-
-/* 15.2.13.4.1 */
-/*
- * call-seq:
- * hsh == other_hash -> true or false
- *
- * Equality---Two hashes are equal if they each contain the same number
- * of keys and if each key-value pair is equal to (according to
- * <code>Object#==</code>) the corresponding elements in the other
- * hash.
- *
- * h1 = { "a" => 1, "c" => 2 }
- * h2 = { 7 => 35, "c" => 2, "a" => 1 }
- * h3 = { "a" => 1, "c" => 2, 7 => 35 }
- * h4 = { "a" => 1, "d" => 2, "f" => 35 }
- * h1 == h2 #=> false
- * h2 == h3 #=> true
- * h3 == h4 #=> false
- *
- */
-
-static mrb_value
-mrb_hash_equal(mrb_state *mrb, mrb_value hash1)
-{
- mrb_value hash2;
-
- mrb_get_args(mrb, "o", &hash2);
- return hash_equal(mrb, hash1, hash2, FALSE);
-}
-
-/* 15.2.13.4.32 (x)*/
-/*
- * 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 mrb_value
-mrb_hash_eql(mrb_state *mrb, mrb_value hash1)
-{
- mrb_value hash2;
-
- mrb_get_args(mrb, "o", &hash2);
- return hash_equal(mrb, hash1, hash2, TRUE);
-}
-
void
mrb_init_hash(mrb_state *mrb)
{
@@ -979,7 +881,6 @@ mrb_init_hash(mrb_state *mrb)
h = mrb->hash_class = mrb_define_class(mrb, "Hash", mrb->object_class);
MRB_SET_INSTANCE_TT(h, MRB_TT_HASH);
- mrb_define_method(mrb, h, "==", mrb_hash_equal, MRB_ARGS_REQ(1)); /* 15.2.13.4.1 */
mrb_define_method(mrb, h, "[]", mrb_hash_aget, MRB_ARGS_REQ(1)); /* 15.2.13.4.2 */
mrb_define_method(mrb, h, "[]=", mrb_hash_aset, MRB_ARGS_REQ(2)); /* 15.2.13.4.3 */
mrb_define_method(mrb, h, "clear", mrb_hash_clear, MRB_ARGS_NONE()); /* 15.2.13.4.4 */
@@ -1007,5 +908,4 @@ mrb_init_hash(mrb_state *mrb)
mrb_define_method(mrb, h, "values", mrb_hash_values, MRB_ARGS_NONE()); /* 15.2.13.4.28 */
mrb_define_method(mrb, h, "to_hash", mrb_hash_to_hash, MRB_ARGS_NONE()); /* 15.2.13.4.29 (x)*/
- mrb_define_method(mrb, h, "eql?", mrb_hash_eql, MRB_ARGS_REQ(1)); /* 15.2.13.4.32 (x)*/
}