summaryrefslogtreecommitdiff
path: root/test/ruby/test_hash.rb
diff options
context:
space:
mode:
authorKoichi Sasada <ko1@cookpad.com>2019-01-16 10:48:30 +0000
committerKoichi Sasada <ko1@atdot.net>2019-07-31 09:44:23 +0900
commitebd398ac5a4147a1e652d6943c39a29a62f12e66 (patch)
tree79dba6622c591db987f0a9c065fe37cd09a58e98 /test/ruby/test_hash.rb
parent4afd8975242917d319cfb20c7ed635b979ad48d5 (diff)
remove RHash::iter_lev.
iter_lev is used to detect the hash is iterating or not. Usually, iter_lev should be very small number (1 or 2) so `int` is overkill. This patch introduce iter_lev in flags (7 bits, FL13 to FL19) and if iter_lev exceeds this range, save it in hidden attribute. We can get 1 word in RHash. We can't modify frozen objects. Therefore I added new internal API `rb_ivar_set_internal()` which allows us to set an attribute even if the target object is frozen if the name is hidden ivar (the name without `@` prefix).
Diffstat (limited to 'test/ruby/test_hash.rb')
-rw-r--r--test/ruby/test_hash.rb25
1 files changed, 25 insertions, 0 deletions
diff --git a/test/ruby/test_hash.rb b/test/ruby/test_hash.rb
index 243cad8d43..d973b1f763 100644
--- a/test/ruby/test_hash.rb
+++ b/test/ruby/test_hash.rb
@@ -1720,6 +1720,31 @@ class TestHash < Test::Unit::TestCase
assert_equal(keys, h.keys.map(&:hash), msg)
end
+ def hrec h, n, &b
+ if n > 0
+ h.each{hrec(h, n-1, &b)}
+ else
+ yield
+ end
+ end
+
+ def test_huge_iter_level
+ h = @cls[a: 1]
+ assert_raise(RuntimeError){
+ hrec(h, 1000){ h[:c] = 3 }
+ }
+
+ h = @cls[a: 1]
+ hrec(h, 1000){}
+ h[:c] = 3
+ assert_equal(3, h[:c])
+
+ h = @cls[a: 1]
+ h.freeze # set hidden attribute for a frozen object
+ hrec(h, 1000){}
+ assert_equal(1, h.size)
+ end
+
class TestSubHash < TestHash
class SubHash < Hash
def reject(*)