[前][次][番号順一覧][スレッド一覧]

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/

[前][次][番号順一覧][スレッド一覧]