mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
merge revision(s) e019dd24df4ed7063ad80d4c2e4070141793f598,7954bb056be30e86c419fe3792064d28990a4999,7d3fdfb27dac456827b004d9e66a44b15f8cd762: [Backport #17736]
Ensure the receiver is modifiable before shrinking [Bug #17736] * Ensure the receiver is modifiable before shinking [Bug #17736] * Assert the receivers are not modified --- array.c | 1 + test/ruby/test_array.rb | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) Some Hash destructive methods ensure the receiver modifiable [Bug #17736] refs: * https://bugs.ruby-lang.org/issues/17736 * https://github.com/ruby/ruby/pull/4296 This commit aims to cover following methods * Hash#select! * Hash#filter! * Hash#keep_if * Hash#reject! * Hash#delete_if I think these are not all. --- * Ensure the receiver is modifiable or not * Assert the receiver is not modified --- hash.c | 2 ++ test/ruby/test_hash.rb | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) Hash#transform_values! ensures receiver modifiable in block [Bug #17736] --- hash.c | 1 + test/ruby/test_hash.rb | 9 +++++++++ 2 files changed, 10 insertions(+)
This commit is contained in:
parent
86f7e55dfb
commit
44b87adc07
5 changed files with 92 additions and 1 deletions
1
array.c
1
array.c
|
@ -3838,6 +3838,7 @@ select_bang_ensure(VALUE a)
|
||||||
|
|
||||||
if (i2 < len && i2 < i1) {
|
if (i2 < len && i2 < i1) {
|
||||||
long tail = 0;
|
long tail = 0;
|
||||||
|
rb_ary_modify(ary);
|
||||||
if (i1 < len) {
|
if (i1 < len) {
|
||||||
tail = len - i1;
|
tail = len - i1;
|
||||||
RARRAY_PTR_USE_TRANSIENT(ary, ptr, {
|
RARRAY_PTR_USE_TRANSIENT(ary, ptr, {
|
||||||
|
|
3
hash.c
3
hash.c
|
@ -2476,6 +2476,7 @@ static int
|
||||||
delete_if_i(VALUE key, VALUE value, VALUE hash)
|
delete_if_i(VALUE key, VALUE value, VALUE hash)
|
||||||
{
|
{
|
||||||
if (RTEST(rb_yield_values(2, key, value))) {
|
if (RTEST(rb_yield_values(2, key, value))) {
|
||||||
|
rb_hash_modify(hash);
|
||||||
return ST_DELETE;
|
return ST_DELETE;
|
||||||
}
|
}
|
||||||
return ST_CONTINUE;
|
return ST_CONTINUE;
|
||||||
|
@ -2753,6 +2754,7 @@ static int
|
||||||
keep_if_i(VALUE key, VALUE value, VALUE hash)
|
keep_if_i(VALUE key, VALUE value, VALUE hash)
|
||||||
{
|
{
|
||||||
if (!RTEST(rb_yield_values(2, key, value))) {
|
if (!RTEST(rb_yield_values(2, key, value))) {
|
||||||
|
rb_hash_modify(hash);
|
||||||
return ST_DELETE;
|
return ST_DELETE;
|
||||||
}
|
}
|
||||||
return ST_CONTINUE;
|
return ST_CONTINUE;
|
||||||
|
@ -3322,6 +3324,7 @@ transform_values_foreach_replace(st_data_t *key, st_data_t *value, st_data_t arg
|
||||||
{
|
{
|
||||||
VALUE new_value = rb_yield((VALUE)*value);
|
VALUE new_value = rb_yield((VALUE)*value);
|
||||||
VALUE hash = (VALUE)argp;
|
VALUE hash = (VALUE)argp;
|
||||||
|
rb_hash_modify(hash);
|
||||||
RB_OBJ_WRITE(hash, value, new_value);
|
RB_OBJ_WRITE(hash, value, new_value);
|
||||||
return ST_CONTINUE;
|
return ST_CONTINUE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -754,6 +754,15 @@ class TestArray < Test::Unit::TestCase
|
||||||
a = @cls[ 5, 6, 7, 8, 9, 10 ]
|
a = @cls[ 5, 6, 7, 8, 9, 10 ]
|
||||||
assert_equal(9, a.delete_if {|i| break i if i > 8; i < 7})
|
assert_equal(9, a.delete_if {|i| break i if i > 8; i < 7})
|
||||||
assert_equal(@cls[7, 8, 9, 10], a, bug2545)
|
assert_equal(@cls[7, 8, 9, 10], a, bug2545)
|
||||||
|
|
||||||
|
assert_raise(FrozenError) do
|
||||||
|
a = @cls[1, 2, 3, 42]
|
||||||
|
a.delete_if do
|
||||||
|
a.freeze
|
||||||
|
true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
assert_equal(@cls[1, 2, 3, 42], a)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_dup
|
def test_dup
|
||||||
|
@ -1322,6 +1331,15 @@ class TestArray < Test::Unit::TestCase
|
||||||
a = @cls[ 5, 6, 7, 8, 9, 10 ]
|
a = @cls[ 5, 6, 7, 8, 9, 10 ]
|
||||||
assert_equal(9, a.reject! {|i| break i if i > 8; i < 7})
|
assert_equal(9, a.reject! {|i| break i if i > 8; i < 7})
|
||||||
assert_equal(@cls[7, 8, 9, 10], a, bug2545)
|
assert_equal(@cls[7, 8, 9, 10], a, bug2545)
|
||||||
|
|
||||||
|
assert_raise(FrozenError) do
|
||||||
|
a = @cls[1, 2, 3, 42]
|
||||||
|
a.reject! do
|
||||||
|
a.freeze
|
||||||
|
true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
assert_equal(@cls[1, 2, 3, 42], a)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_shared_array_reject!
|
def test_shared_array_reject!
|
||||||
|
@ -2599,6 +2617,15 @@ class TestArray < Test::Unit::TestCase
|
||||||
a = @cls[ 1, 2, 3, 4, 5 ]
|
a = @cls[ 1, 2, 3, 4, 5 ]
|
||||||
a.select! {|i| a.clear if i == 5; false }
|
a.select! {|i| a.clear if i == 5; false }
|
||||||
assert_equal(0, a.size, bug13053)
|
assert_equal(0, a.size, bug13053)
|
||||||
|
|
||||||
|
assert_raise(FrozenError) do
|
||||||
|
a = @cls[1, 2, 3, 42]
|
||||||
|
a.select! do
|
||||||
|
a.freeze
|
||||||
|
false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
assert_equal(@cls[1, 2, 3, 42], a)
|
||||||
end
|
end
|
||||||
|
|
||||||
# also select!
|
# also select!
|
||||||
|
@ -2614,6 +2641,15 @@ class TestArray < Test::Unit::TestCase
|
||||||
a = @cls[ 1, 2, 3, 4, 5 ]
|
a = @cls[ 1, 2, 3, 4, 5 ]
|
||||||
assert_equal(a, a.keep_if { |i| i > 3 })
|
assert_equal(a, a.keep_if { |i| i > 3 })
|
||||||
assert_equal(@cls[4, 5], a)
|
assert_equal(@cls[4, 5], a)
|
||||||
|
|
||||||
|
assert_raise(FrozenError) do
|
||||||
|
a = @cls[1, 2, 3, 42]
|
||||||
|
a.keep_if do
|
||||||
|
a.freeze
|
||||||
|
false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
assert_equal(@cls[1, 2, 3, 42], a)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_filter
|
def test_filter
|
||||||
|
|
|
@ -419,6 +419,15 @@ class TestHash < Test::Unit::TestCase
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
assert_equal(base.size, n)
|
assert_equal(base.size, n)
|
||||||
|
|
||||||
|
h = base.dup
|
||||||
|
assert_raise(FrozenError) do
|
||||||
|
h.delete_if do
|
||||||
|
h.freeze
|
||||||
|
true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
assert_equal(base.dup, h)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_keep_if
|
def test_keep_if
|
||||||
|
@ -426,6 +435,14 @@ class TestHash < Test::Unit::TestCase
|
||||||
assert_equal({3=>4,5=>6}, h.keep_if {|k, v| k + v >= 7 })
|
assert_equal({3=>4,5=>6}, h.keep_if {|k, v| k + v >= 7 })
|
||||||
h = @cls[1=>2,3=>4,5=>6]
|
h = @cls[1=>2,3=>4,5=>6]
|
||||||
assert_equal({1=>2,3=>4,5=>6}, h.keep_if{true})
|
assert_equal({1=>2,3=>4,5=>6}, h.keep_if{true})
|
||||||
|
h = @cls[1=>2,3=>4,5=>6]
|
||||||
|
assert_raise(FrozenError) do
|
||||||
|
h.keep_if do
|
||||||
|
h.freeze
|
||||||
|
false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
assert_equal(@cls[1=>2,3=>4,5=>6], h)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_compact
|
def test_compact
|
||||||
|
@ -722,6 +739,15 @@ class TestHash < Test::Unit::TestCase
|
||||||
h = base.dup
|
h = base.dup
|
||||||
assert_equal(h3, h.reject! {|k,v| v })
|
assert_equal(h3, h.reject! {|k,v| v })
|
||||||
assert_equal(h3, h)
|
assert_equal(h3, h)
|
||||||
|
|
||||||
|
h = base.dup
|
||||||
|
assert_raise(FrozenError) do
|
||||||
|
h.reject! do
|
||||||
|
h.freeze
|
||||||
|
true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
assert_equal(base.dup, h)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_replace
|
def test_replace
|
||||||
|
@ -1025,6 +1051,14 @@ class TestHash < Test::Unit::TestCase
|
||||||
assert_equal({3=>4,5=>6}, h)
|
assert_equal({3=>4,5=>6}, h)
|
||||||
h = @cls[1=>2,3=>4,5=>6]
|
h = @cls[1=>2,3=>4,5=>6]
|
||||||
assert_equal(nil, h.select!{true})
|
assert_equal(nil, h.select!{true})
|
||||||
|
h = @cls[1=>2,3=>4,5=>6]
|
||||||
|
assert_raise(FrozenError) do
|
||||||
|
h.select! do
|
||||||
|
h.freeze
|
||||||
|
false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
assert_equal(@cls[1=>2,3=>4,5=>6], h)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_slice
|
def test_slice
|
||||||
|
@ -1077,6 +1111,14 @@ class TestHash < Test::Unit::TestCase
|
||||||
assert_equal({3=>4,5=>6}, h)
|
assert_equal({3=>4,5=>6}, h)
|
||||||
h = @cls[1=>2,3=>4,5=>6]
|
h = @cls[1=>2,3=>4,5=>6]
|
||||||
assert_equal(nil, h.filter!{true})
|
assert_equal(nil, h.filter!{true})
|
||||||
|
h = @cls[1=>2,3=>4,5=>6]
|
||||||
|
assert_raise(FrozenError) do
|
||||||
|
h.filter! do
|
||||||
|
h.freeze
|
||||||
|
false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
assert_equal(@cls[1=>2,3=>4,5=>6], h)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_clear2
|
def test_clear2
|
||||||
|
@ -1720,6 +1762,15 @@ class TestHash < Test::Unit::TestCase
|
||||||
x = @cls[a: 1, b: 2, c: 3]
|
x = @cls[a: 1, b: 2, c: 3]
|
||||||
y = x.transform_values!.with_index {|v, i| "#{v}.#{i}" }
|
y = x.transform_values!.with_index {|v, i| "#{v}.#{i}" }
|
||||||
assert_equal(%w(1.0 2.1 3.2), y.values_at(:a, :b, :c))
|
assert_equal(%w(1.0 2.1 3.2), y.values_at(:a, :b, :c))
|
||||||
|
|
||||||
|
x = @cls[a: 1, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7, h: 8, i: 9, j: 10]
|
||||||
|
assert_raise(FrozenError) do
|
||||||
|
x.transform_values!() do |v|
|
||||||
|
x.freeze if v == 2
|
||||||
|
v.succ
|
||||||
|
end
|
||||||
|
end
|
||||||
|
assert_equal(@cls[a: 2, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7, h: 8, i: 9, j: 10], x)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_broken_hash_value
|
def test_broken_hash_value
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
# define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR
|
# define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR
|
||||||
#define RUBY_VERSION_TEENY 2
|
#define RUBY_VERSION_TEENY 2
|
||||||
#define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR
|
#define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR
|
||||||
#define RUBY_PATCHLEVEL 86
|
#define RUBY_PATCHLEVEL 87
|
||||||
|
|
||||||
#define RUBY_RELEASE_YEAR 2021
|
#define RUBY_RELEASE_YEAR 2021
|
||||||
#define RUBY_RELEASE_MONTH 5
|
#define RUBY_RELEASE_MONTH 5
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue