From: "H.Yamamoto" Date: 2005-05-08T20:11:18+09:00 Subject: [ruby-dev:26132] [BUG] Hash#hash on 1.9 山本です。 Hash#hash の結果が、中身が等しいにもかかわらず 違う値になることがあります。 ///////////////////////////// // コード a = {1=>nil, 2=>nil, []=>nil, {}=>nil, 5=>nil} b = a.clone p a p b p a.hash p b.hash p a.eql?(b) ///////////////////////////// // 結果 {5=>nil, []=>nil, 1=>nil, {}=>nil, 2=>nil} {[]=>nil, 5=>nil, 1=>nil, {}=>nil, 2=>nil} 3640 10552 true これは、Hash の格納順が不定だからです。Hash#hash を求めるたびに 配列を確保するのもどうかと思ったのですが、下のパッチで一応動きます。 Index: hash.c =================================================================== RCS file: /src/ruby/hash.c,v retrieving revision 1.149 diff -u -w -b -p -r1.149 hash.c --- hash.c 5 May 2005 23:08:47 -0000 1.149 +++ hash.c 8 May 2005 10:52:10 -0000 @@ -1497,21 +1497,11 @@ rb_hash_eql(hash1, hash2) } static int -rb_hash_hash_i(key, value, hp) - VALUE key, value; - long *hp; +rb_hash_hash_i(key, value, a) + VALUE key, value, a; { - long h = *hp; - VALUE n; - - h = (h << 1) | (h<0 ? 1 : 0); - n = rb_hash(key); - h ^= NUM2LONG(n); - h = (h << 1) | (h<0 ? 1 : 0); - n = rb_hash(value); - h ^= NUM2LONG(n); - - *hp = h; + rb_ary_push(a, rb_hash(key)); + rb_ary_push(a, rb_hash(value)); return ST_CONTINUE; } @@ -1520,14 +1510,21 @@ recursive_hash(hash, dummy, recur) VALUE hash, dummy; int recur; { - long h; - VALUE n; + long h, i; + VALUE n, a; if (recur) { return LONG2FIX(0); } h = RHASH(hash)->tbl->num_entries; - rb_hash_foreach(hash, rb_hash_hash_i, (VALUE)&h); + a = rb_ary_new2(h*2); + rb_hash_foreach(hash, rb_hash_hash_i, a); + rb_ary_sort_bang(a); + for (i = 0; i < RARRAY(a)->len; i++) { + h = (h << 1) | (h<0 ? 1 : 0); + n = RARRAY(a)->ptr[i]; + h ^= NUM2LONG(n); + } h = (h << 1) | (h<0 ? 1 : 0); n = rb_hash(RHASH(hash)->ifnone); h ^= NUM2LONG(n); ////////////////////////////////////////////// // パッチ後 {5=>nil, []=>nil, 1=>nil, {}=>nil, 2=>nil} {[]=>nil, 5=>nil, 1=>nil, {}=>nil, 2=>nil} 10726 10726 true