From: Nobuyoshi Nakada Date: 2008-02-06T12:42:19+09:00 Subject: [ruby-dev:33610] Re: Hash#compare_by_identity makes string unusable as key なかだです。 At Tue, 5 Feb 2008 22:19:29 +0900, Yusuke ENDOH wrote in [ruby-dev:33604]: > Hash#[]= が、キーが文字列の場合だけ dup して freeze してから > 保存するのが原因のようです。 短い文字列以外では、freezeされたものが参照できるのでそれを使えば 大丈夫だと思いますが、埋め込まれているは通常の比較をするしかない かも。 > 今日までこのメソッドを知らなかったんですが、このメソッドの > 目的は何なんでしょうか。高速化? たしか、Rails(というかActiveSupport?)から取り込まれた機能のはず です。 > メソッド名がハッシュと何かを比較するみたいだとか、元に戻す > 方法がなくていいのかとか、いろいろ気になる感じです。 戻すには、衝突をどうするか考えないといけないと思います。 Index: hash.c =================================================================== --- hash.c (revision 15384) +++ hash.c (working copy) @@ -1683,7 +1683,28 @@ rb_hash_flatten(int argc, VALUE *argv, V } +int rb_strcmp_by_identity(VALUE, VALUE); +int rb_strhash_by_identity(VALUE); + +static int +strcmp_by_identity(st_data_t x, st_data_t y) +{ + if (TYPE(x) == T_STRING && TYPE(y) == T_STRING) { + return rb_strcmp_by_identity((VALUE)x, (VALUE)y); + } + return x != y; +} + +static int +strhash_by_identity(st_data_t x) +{ + if (TYPE(x) == T_STRING) { + return rb_strhash_by_identity((VALUE)x); + } + return (int)x; +} + static const struct st_hash_type identhash = { - st_numcmp, - st_numhash, + strcmp_by_identity, + strhash_by_identity, }; Index: string.c =================================================================== --- string.c (revision 15384) +++ string.c (working copy) @@ -1601,4 +1601,34 @@ rb_str_eql(VALUE str1, VALUE str2) } +int +rb_strcmp_by_identity(VALUE x, VALUE y) +{ + if ((RBASIC(x)->flags ^ RBASIC(y)->flags) & STR_NOEMBED) { + return Qfalse; + } + if (RBASIC(x)->flags & STR_NOEMBED) { + return !rb_str_eql(x, y); + } + if (RBASIC(x)->flags & ELTS_SHARED) { + x = RSTRING(x)->as.heap.aux.shared; + } + if (RBASIC(y)->flags & ELTS_SHARED) { + y = RSTRING(y)->as.heap.aux.shared; + } + return x != y; +} + +int +rb_strhash_by_identity(VALUE x) +{ + if (RBASIC(x)->flags & STR_NOEMBED) { + return rb_str_hash(x); + } + if (RBASIC(x)->flags & ELTS_SHARED) { + x = RSTRING(x)->as.heap.aux.shared; + } + return (int)x; +} + /* * call-seq: -- --- 僕の前にBugはない。 --- 僕の後ろにBugはできる。 中田 伸悦