Resize capacity for fstring

When a string is #frozen, it's capacity is resized to fit (if it is much
larger), since we know it will no longer be mutated.

    > puts ObjectSpace.dump(String.new("a"*30, capacity: 1000))
    {"type":"STRING", "class":"0x7feaf00b7bf0", "bytesize":30, "capacity":1000, "value":"...
    > puts ObjectSpace.dump(String.new("a"*30, capacity: 1000).freeze)
    {"type":"STRING", "class":"0x7feaf00b7bf0", "frozen":true, "bytesize":30, "value":"...

(ObjectSpace.dump doesn't show capacity if capacity is equal to bytesize)

Previously, if we dedup into an fstring, using String#-@, capacity would
not be reduced.

    > puts ObjectSpace.dump(-String.new("a"*30, capacity: 1000))
    {"type":"STRING", "class":"0x7feaf00b7bf0", "frozen":true, "fstring":true, "bytesize":30, "capacity":1000, "value":"...

This commit makes rb_fstring call rb_str_resize, the same as
rb_str_freeze does.

Closes: https://github.com/ruby/ruby/pull/2256
This commit is contained in:
John Hawthorn 2019-06-25 09:01:57 -07:00 committed by Nobuyoshi Nakada
parent fe0ddf0e58
commit 04bc4c0662
2 changed files with 22 additions and 0 deletions

View File

@ -321,6 +321,9 @@ rb_fstring(VALUE str)
return str;
}
if (!OBJ_FROZEN(str))
rb_str_resize(str, RSTRING_LEN(str));
fstr = register_fstring(str);
if (!bare) {

View File

@ -37,4 +37,23 @@ class Test_StringCapacity < Test::Unit::TestCase
open(__FILE__) {|f|s = f.read(1024*1024)}
assert_operator(capa(s), :<=, s.bytesize+4096)
end
def test_literal_capacity
s = "I am testing string literal capacity"
assert_equal(s.length, capa(s))
end
def test_capacity_frozen
s = String.new("I am testing", capacity: 1000)
s << "fstring capacity"
s.freeze
assert_equal(s.length, capa(s))
end
def test_capacity_fstring
s = String.new("I am testing", capacity: 1000)
s << "fstring capacity"
s = -s
assert_equal(s.length, capa(s))
end
end