From 71e3caff42d95da470d82d4ca3260c69a042a19a Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Tue, 25 Jun 2019 09:01:57 -0700 Subject: [PATCH] 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. --- string.c | 3 +++ test/-ext-/string/test_capacity.rb | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/string.c b/string.c index 030465235aa3..8ac33e3e52a8 100644 --- a/string.c +++ b/string.c @@ -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) { diff --git a/test/-ext-/string/test_capacity.rb b/test/-ext-/string/test_capacity.rb index 65444123a721..df59e767781d 100644 --- a/test/-ext-/string/test_capacity.rb +++ b/test/-ext-/string/test_capacity.rb @@ -37,4 +37,23 @@ def test_io_read 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