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

ruby-changes:12262

From: matz <ko1@a...>
Date: Sat, 4 Jul 2009 03:14:52 +0900 (JST)
Subject: [ruby-changes:12262] Ruby:r23951 (trunk): * enum.c (enum_join): add Enumerable#join.

matz	2009-07-04 03:14:33 +0900 (Sat, 04 Jul 2009)

  New Revision: 23951

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=23951

  Log:
    * enum.c (enum_join): add Enumerable#join.
    * array.c (ary_join_1): recursive join for Enumerators (and
      objects with #to_a).
    
    * array.c (rb_ary_join): performance tune.

  Modified files:
    trunk/ChangeLog
    trunk/array.c
    trunk/enum.c

Index: array.c
===================================================================
--- array.c	(revision 23950)
+++ array.c	(revision 23951)
@@ -1519,66 +1519,125 @@
 
 extern VALUE rb_output_fs;
 
+static void ary_join_1(VALUE ary, VALUE sep, long i, VALUE result);
+
 static VALUE
-recursive_join(VALUE ary, VALUE argp, int recur)
+recursive_join(VALUE obj, VALUE argp, int recur)
 {
     VALUE *arg = (VALUE *)argp;
+    VALUE ary = arg[0];
+    VALUE sep = arg[1];
+    VALUE result = arg[2];
+
     if (recur) {
-	return rb_usascii_str_new2("[...]");
+	rb_str_buf_cat_ascii(result, "[...]");
     }
-    return rb_ary_join(arg[0], arg[1]);
+    else {
+	ary_join_1(ary, sep, 0, result);
+    }
+    return Qnil;
 }
 
+static void
+ary_join_0(VALUE ary, VALUE sep, long max, VALUE result)
+{
+    long i;
+    VALUE val;
+
+    for (i=0; i<max; i++) {
+	val = RARRAY_PTR(ary)[i];
+	if (i > 0 && !NIL_P(sep))
+	    rb_str_buf_append(result, sep);
+	rb_str_buf_append(result, val);
+	if (OBJ_TAINTED(val)) OBJ_TAINT(result);
+	if (OBJ_UNTRUSTED(val)) OBJ_TAINT(result);
+    }
+}
+
+static void
+ary_join_1(VALUE ary, VALUE sep, long i, VALUE result)
+{
+    VALUE val, tmp;
+
+    for (; i<RARRAY_LEN(ary); i++) {
+	if (i > 0 && !NIL_P(sep))
+	    rb_str_buf_append(result, sep);
+
+	val = RARRAY_PTR(ary)[i];
+	switch (TYPE(val)) {
+	  case T_STRING:
+	  str_join:
+	    rb_str_buf_append(result, val);
+	    break;
+	  case T_ARRAY:
+	  ary_join:
+	    if (val == ary) {
+		val = rb_usascii_str_new2("[...]");
+		goto str_join;
+	    }
+	    else {
+		VALUE args[3];
+		
+		args[0] = val;
+		args[1] = sep;
+		args[2] = result;
+		rb_exec_recursive(recursive_join, ary, (VALUE)args);
+	    }
+	    break;
+	  default:
+	    tmp = rb_check_string_type(val);
+	    if (!NIL_P(tmp)) {
+		val = tmp;
+		goto str_join;
+	    }
+	    tmp = rb_check_convert_type(val, T_ARRAY, "Array", "to_a");
+	    if (!NIL_P(tmp)) {
+		val = tmp;
+		goto ary_join;
+	    }
+	    val = rb_obj_as_string(val);
+	    goto str_join;
+	}
+    }
+}
+
 VALUE
 rb_ary_join(VALUE ary, VALUE sep)
 {
     long len = 1, i;
     int taint = Qfalse;
     int untrust = Qfalse;
-    VALUE result, tmp;
+    VALUE val, tmp, result;
 
     if (RARRAY_LEN(ary) == 0) return rb_str_new(0, 0);
     if (OBJ_TAINTED(ary) || OBJ_TAINTED(sep)) taint = Qtrue;
     if (OBJ_UNTRUSTED(ary) || OBJ_UNTRUSTED(sep)) untrust = Qtrue;
 
-    for (i=0; i<RARRAY_LEN(ary); i++) {
-	tmp = rb_check_string_type(RARRAY_PTR(ary)[i]);
-	len += NIL_P(tmp) ? 10 : RSTRING_LEN(tmp);
-    }
     if (!NIL_P(sep)) {
 	StringValue(sep);
 	len += RSTRING_LEN(sep) * (RARRAY_LEN(ary) - 1);
     }
-    result = rb_str_buf_new(len);
     for (i=0; i<RARRAY_LEN(ary); i++) {
-	tmp = RARRAY_PTR(ary)[i];
-	switch (TYPE(tmp)) {
-	  case T_STRING:
-	    break;
-	  case T_ARRAY:
-	    if (tmp == ary) {
-		tmp = rb_usascii_str_new2("[...]");
-	    }
-	    else {
-		VALUE args[2];
+	val = RARRAY_PTR(ary)[i];
+	tmp = rb_check_string_type(val);
 
-		args[0] = tmp;
-		args[1] = sep;
-		tmp = rb_exec_recursive(recursive_join, ary, (VALUE)args);
-	    }
-	    break;
-	  default:
-	    tmp = rb_obj_as_string(tmp);
+	if (NIL_P(tmp) || tmp != val) {
+	    result = rb_str_buf_new(len + (RARRAY_LEN(ary)-i)*10);
+	    if (taint) OBJ_TAINT(result);
+	    if (untrust) OBJ_UNTRUST(result);
+	    ary_join_0(ary, sep, i, result);
+	    ary_join_1(ary, sep, i, result);
+	    return result;
 	}
-	if (i > 0 && !NIL_P(sep))
-	    rb_str_buf_append(result, sep);
-	rb_str_buf_append(result, tmp);
-	if (OBJ_TAINTED(tmp)) taint = Qtrue;
-	if (OBJ_UNTRUSTED(tmp)) untrust = Qtrue;
+
+	len += RSTRING_LEN(tmp);
     }
 
+    result = rb_str_buf_new(len);
     if (taint) OBJ_TAINT(result);
     if (untrust) OBJ_UNTRUST(result);
+    ary_join_0(ary, sep, RARRAY_LEN(ary), result);
+
     return result;
 }
 
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 23950)
+++ ChangeLog	(revision 23951)
@@ -79,6 +79,15 @@
 
 	* enum.c (enum_grep): gets rid of type-punning calls.
 
+Wed Jul  1 06:36:28 2009  Yukihiro Matsumoto  <matz@r...>
+
+	* enum.c (enum_join): add Enumerable#join.
+
+	* array.c (ary_join_1): recursive join for Enumerators (and
+	  objects with #to_a).
+
+	* array.c (rb_ary_join): performance tune.
+
 Tue Jun 30 18:19:07 2009  Yukihiro Matsumoto  <matz@r...>
 
 	* hash.c (rb_hash_hash): documentation fix.  a patch from
Index: enum.c
===================================================================
--- enum.c	(revision 23950)
+++ enum.c	(revision 23951)
@@ -1803,6 +1803,17 @@
     return Qnil;		/* not reached */
 }
 
+static VALUE
+enum_join(int argc, VALUE *argv, VALUE obj)
+{
+    VALUE sep;
+
+    rb_scan_args(argc, argv, "01", &sep);
+    if (NIL_P(sep)) sep = rb_output_fs;
+
+    return rb_ary_join(enum_to_a(0, 0, obj), sep);
+}
+
 /*
  *  The <code>Enumerable</code> mixin provides collection classes with
  *  several traversal and searching methods, and with the ability to
@@ -1862,6 +1873,7 @@
     rb_define_method(rb_mEnumerable, "drop", enum_drop, 1);
     rb_define_method(rb_mEnumerable, "drop_while", enum_drop_while, 0);
     rb_define_method(rb_mEnumerable, "cycle", enum_cycle, -1);
+    rb_define_method(rb_mEnumerable, "join", enum_join, -1);
 
     id_eqq  = rb_intern("===");
     id_each = rb_intern("each");

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

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