From: Nobuyoshi Nakada Date: 2009-08-05T02:32:23+09:00 Subject: [ruby-core:24750] Re: [Feature #1882] MatchData#== Hi, At Wed, 5 Aug 2009 01:29:40 +0900, Run Paint Run Run wrote in [ruby-core:24748]: > Terribly unimportant, even by my standards, but could > MatchData have a sensible #== defined? Currently two > logically identical MatchData objects return false for #==. And #hash and #eql? too? Index: re.c =================================================================== --- re.c (revision 24394) +++ re.c (working copy) @@ -2531,4 +2531,53 @@ rb_reg_equal(VALUE re1, VALUE re2) } +/* + * call-seq: + * mtch.hash => integer + * + * Produce a hash based on the target string, regexp and matched + * positions of this matchdata. + */ + +static VALUE +match_hash(VALUE match) +{ + const struct re_registers *regs; + VALUE h; + unsigned long hashval = rb_hash_start(rb_str_hash(RMATCH(match)->str)); + + h = rb_reg_hash(RMATCH(match)->regexp); + rb_hash_uint(hashval, FIX2LONG(h)); + regs = RMATCH_REGS(match); + hashval = rb_hash_uint(hashval, regs->num_regs); + hashval = rb_hash_uint(hashval, rb_memhash(regs->beg, regs->num_regs * sizeof(*regs->beg))); + hashval = rb_hash_uint(hashval, rb_memhash(regs->end, regs->num_regs * sizeof(*regs->end))); + hashval = rb_hash_end(hashval); + return LONG2FIX(hashval); +} + +/* + * call-seq: + * mtch == mtch2 => true or false + * + * Equality---Two matchdata are equal if their target strings, + * patterns, and matched positions are identical. + */ + +static VALUE +match_equal(VALUE match1, VALUE match2) +{ + const struct re_registers *regs1, *regs2; + if (match1 == match2) return Qtrue; + if (TYPE(match2) != T_MATCH) return Qfalse; + if (!rb_str_equal(RMATCH(match1)->str, RMATCH(match2)->str)) return Qfalse; + if (!rb_reg_equal(RMATCH(match1)->regexp, RMATCH(match2)->regexp)) return Qfalse; + regs1 = RMATCH_REGS(match1); + regs2 = RMATCH_REGS(match2); + if (regs1->num_regs != regs2->num_regs) return Qfalse; + if (memcmp(regs1->beg, regs2->beg, regs1->num_regs * sizeof(*regs1->beg))) return Qfalse; + if (memcmp(regs1->end, regs2->end, regs1->num_regs * sizeof(*regs1->end))) return Qfalse; + return Qtrue; +} + static VALUE reg_operand(VALUE s, int check) @@ -3451,3 +3500,6 @@ Init_Regexp(void) rb_define_method(rb_cMatch, "inspect", match_inspect, 0); rb_define_method(rb_cMatch, "string", match_string, 0); + rb_define_method(rb_cMatch, "hash", match_hash, 0); + rb_define_method(rb_cMatch, "eql?", match_equal, 1); + rb_define_method(rb_cMatch, "==", match_equal, 1); } Index: test/ruby/test_regexp.rb =================================================================== --- test/ruby/test_regexp.rb (revision 24394) +++ test/ruby/test_regexp.rb (working copy) @@ -765,3 +765,11 @@ class TestRegexp < Test::Unit::TestCase assert_nothing_raised { 0x7fffffff.chr("utf-8").size } end + + def test_matchdata + a = "haystack".match(/hay/) + b = "haystack".match(/hay/) + assert_equal(a, b) + h = {a => 42} + assert_equal(42, h[b]) + end end -- Nobu Nakada