ruby-changes:41776
From: naruse <ko1@a...>
Date: Wed, 17 Feb 2016 12:21:12 +0900 (JST)
Subject: [ruby-changes:41776] naruse:r53850 (trunk): * string.c (rb_str_init): introduce String.new(capacity: size)
naruse 2016-02-17 12:21:35 +0900 (Wed, 17 Feb 2016) New Revision: 53850 https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=53850 Log: * string.c (rb_str_init): introduce String.new(capacity: size) [Feature #12024] Modified files: trunk/ChangeLog trunk/NEWS trunk/string.c trunk/test/-ext-/string/test_capacity.rb trunk/test/ruby/test_string.rb Index: ChangeLog =================================================================== --- ChangeLog (revision 53849) +++ ChangeLog (revision 53850) @@ -1,3 +1,8 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1 +Wed Feb 17 12:14:59 2016 NARUSE, Yui <naruse@r...> + + * string.c (rb_str_init): introduce String.new(capacity: size) + [Feature #12024] + Tue Feb 16 19:10:08 2016 Martin Duerst <duerst@i...> * enc/unicode/case-folding.rb, casefold.h: Used only first element Index: string.c =================================================================== --- string.c (revision 53849) +++ string.c (revision 53850) @@ -1350,33 +1350,72 @@ rb_str_resurrect(VALUE str) https://github.com/ruby/ruby/blob/trunk/string.c#L1350 * call-seq: * String.new(str="") -> new_str * String.new(str="", encoding: enc) -> new_str + * String.new(str="", capacity: size) -> new_str * * Returns a new string object containing a copy of <i>str</i>. + * * The optional <i>enc</i> argument specifies the encoding of the new string. * If not specified, the encoding of <i>str</i> (or ASCII-8BIT, if <i>str</i> * is not specified) is used. + * + * The optional <i>size</i> argument specifies the size of internal buffer. + * This may improve performance, when the string will be concatenated many + * times (and call many realloc). */ static VALUE rb_str_init(int argc, VALUE *argv, VALUE str) { - static ID keyword_ids[1]; - VALUE orig, opt, enc; + static ID keyword_ids[2]; + VALUE orig, opt, enc, vcapa; + VALUE kwargs[2]; int n; - if (!keyword_ids[0]) + if (!keyword_ids[0]) { keyword_ids[0] = rb_id_encoding(); + CONST_ID(keyword_ids[1], "capacity"); + } n = rb_scan_args(argc, argv, "01:", &orig, &opt); - if (argc > 0 && n == 1) - rb_str_replace(str, orig); if (!NIL_P(opt)) { - rb_get_kwargs(opt, keyword_ids, 0, 1, &enc); + rb_get_kwargs(opt, keyword_ids, 0, 2, kwargs); + enc = kwargs[0]; + vcapa = kwargs[1]; + if (vcapa != Qundef && !NIL_P(vcapa)) { + long capa = NUM2LONG(vcapa); + if (capa < STR_BUF_MIN_SIZE) { + capa = STR_BUF_MIN_SIZE; + } + if (n == 1) { + long len = RSTRING_LEN(orig); + if (capa < len) { + capa = len; + } + RSTRING(str)->as.heap.ptr = ALLOC_N(char, capa+1); + memcpy(RSTRING(str)->as.heap.ptr, RSTRING_PTR(orig), RSTRING_LEN(orig)); + RSTRING(str)->as.heap.len = len; + rb_enc_cr_str_exact_copy(str, orig); + } + else { + RSTRING(str)->as.heap.ptr = ALLOC_N(char, capa+1); + RSTRING(str)->as.heap.ptr[0] = '\0'; + } + FL_SET(str, STR_NOEMBED); + RSTRING(str)->as.heap.aux.capa = capa; + } + else if (n == 1) { + StringValue(orig); + str_replace(str, orig); + } if (enc != Qundef && !NIL_P(enc)) { rb_enc_associate(str, rb_to_encoding(enc)); ENC_CODERANGE_CLEAR(str); } } + else if (n == 1) { + StringValue(orig); + str_replace(str, orig); + } return str; } Index: NEWS =================================================================== --- NEWS (revision 53849) +++ NEWS (revision 53850) @@ -20,6 +20,10 @@ with all sufficient information, see the https://github.com/ruby/ruby/blob/trunk/NEWS#L20 * Dir.empty?. [Feature #10121] +* String + + * String.new(capacity: size) [Feature #12024] + === Stdlib updates (outstanding ones only) * CSV Index: test/ruby/test_string.rb =================================================================== --- test/ruby/test_string.rb (revision 53849) +++ test/ruby/test_string.rb (revision 53850) @@ -45,6 +45,18 @@ class TestString < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_string.rb#L45 src.force_encoding("euc-jp") assert_equal(src, S(src, encoding: "utf-8")) assert_equal(Encoding::UTF_8, S(src, encoding: "utf-8").encoding) + + assert_equal("", S(capacity: 1000)) + assert_equal(Encoding::ASCII_8BIT, S(capacity: 1000).encoding) + + assert_equal("", S(capacity: 1000, encoding: "euc-jp")) + assert_equal(Encoding::EUC_JP, S(capacity: 1000, encoding: "euc-jp").encoding) + + assert_equal("", S("", capacity: 1000)) + assert_equal(__ENCODING__, S("", capacity: 1000).encoding) + + assert_equal("", S("", capacity: 1000, encoding: "euc-jp")) + assert_equal(Encoding::EUC_JP, S("", capacity: 1000, encoding: "euc-jp").encoding) end def test_AREF # '[]' Index: test/-ext-/string/test_capacity.rb =================================================================== --- test/-ext-/string/test_capacity.rb (revision 53849) +++ test/-ext-/string/test_capacity.rb (revision 53850) @@ -4,16 +4,29 @@ require '-test-/string' https://github.com/ruby/ruby/blob/trunk/test/-ext-/string/test_capacity.rb#L4 require 'rbconfig/sizeof' class Test_StringCapacity < Test::Unit::TestCase + def capa(str) + Bug::String.capacity(str) + end + def test_capacity_embeded size = RbConfig::SIZEOF['void*'] * 3 - 1 - assert_equal size, Bug::String.capacity('foo') + assert_equal size, capa('foo') end def test_capacity_shared - assert_equal 0, Bug::String.capacity(:abcdefghijklmnopqrstuvwxyz.to_s) + assert_equal 0, capa(:abcdefghijklmnopqrstuvwxyz.to_s) end def test_capacity_normal - assert_equal 128, Bug::String.capacity('1'*128) + assert_equal 128, capa('1'*128) + end + + def test_s_new_capacity + assert_equal("", String.new(capacity: 1000)) + assert_equal(String, String.new(capacity: 1000).class) + assert_equal(10000, capa(String.new(capacity: 10000))) + + assert_equal("", String.new(capacity: -1000)) + assert_equal(capa(String.new(capacity: -10000)), capa(String.new(capacity: -1000))) end end -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/