ruby-changes:31968
From: nobu <ko1@a...>
Date: Sat, 7 Dec 2013 11:16:11 +0900 (JST)
Subject: [ruby-changes:31968] nobu:r44047 (trunk): hash.c: rb_hash_reject without dup
nobu 2013-12-07 11:16:04 +0900 (Sat, 07 Dec 2013) New Revision: 44047 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=44047 Log: hash.c: rb_hash_reject without dup * hash.c (rb_hash_reject): copy unrejected elements only to new hash, so that the change on the original receiver can affect. [ruby-core:58914] [Bug #9223] Modified files: trunk/ChangeLog trunk/hash.c trunk/test/ruby/test_enumerator.rb Index: ChangeLog =================================================================== --- ChangeLog (revision 44046) +++ ChangeLog (revision 44047) @@ -1,3 +1,9 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1 +Sat Dec 7 11:15:52 2013 Nobuyoshi Nakada <nobu@r...> + + * hash.c (rb_hash_reject): copy unrejected elements only to new hash, + so that the change on the original receiver can affect. + [ruby-core:58914] [Bug #9223] + Sat Dec 7 08:25:00 2013 Richo Healey <richo@p...> * test/ruby/test_struct.rb: Add regression test for question marks and Index: hash.c =================================================================== --- hash.c (revision 44046) +++ hash.c (revision 44047) @@ -1092,6 +1092,15 @@ rb_hash_reject_bang(VALUE hash) https://github.com/ruby/ruby/blob/trunk/hash.c#L1092 return hash; } +static int +reject_i(VALUE key, VALUE value, VALUE hash) +{ + if (!RTEST(rb_yield_values(2, key, value))) { + rb_hash_aset(hash, key, value); + } + return ST_CONTINUE; +} + /* * call-seq: * hsh.reject {| key, value | block } -> a_hash @@ -1106,7 +1115,14 @@ rb_hash_reject_bang(VALUE hash) https://github.com/ruby/ruby/blob/trunk/hash.c#L1115 static VALUE rb_hash_reject(VALUE hash) { - return rb_hash_delete_if(rb_obj_dup(hash)); + VALUE ret; + + RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size); + ret = hash_alloc(rb_obj_class(hash)); + if (!RHASH_EMPTY_P(hash)) { + rb_hash_foreach(hash, reject_i, ret); + } + return ret; } /* Index: test/ruby/test_enumerator.rb =================================================================== --- test/ruby/test_enumerator.rb (revision 44046) +++ test/ruby/test_enumerator.rb (revision 44047) @@ -501,9 +501,13 @@ class TestEnumerator < Test::Unit::TestC https://github.com/ruby/ruby/blob/trunk/test/ruby/test_enumerator.rb#L501 def test_size_for_enum_created_from_hash h = {a: 1, b: 2, c: 3} - %i[delete_if reject! select select! keep_if each each_key each_pair].each do |method| - assert_equal 3, h.send(method).size - end + methods = %i[delete_if reject reject! select select! keep_if each each_key each_pair] + enums = methods.map {|method| h.send(method)} + s = enums.group_by(&:size) + assert_equal([3], s.keys, ->{s.reject!{|k| k==3}.inspect}) + h[:d] = 4 + s = enums.group_by(&:size) + assert_equal([4], s.keys, ->{s.reject!{|k| k==4}.inspect}) end def test_size_for_enum_created_from_env -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/