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

ruby-changes:3459

From: ko1@a...
Date: 8 Jan 2008 18:50:20 +0900
Subject: [ruby-changes:3459] matz - Ruby:r14952 (trunk): * enum.c (enum_zip): honor length of the receiver, not the

matz	2008-01-08 18:50:01 +0900 (Tue, 08 Jan 2008)

  New Revision: 14952

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

  Log:
    * enum.c (enum_zip): honor length of the receiver, not the
      shortest length.  [ruby-core:14738]
    
    * enum.c (enum_zip): returns array not enumerator for no block
      form.  [ruby-core:14738]
    
    * enumerator.c (next_ii): do not ignore multiple values yielded.
    
    * array.c (rb_ary_zip): faster version without creating generators.

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/array.c?r1=14952&r2=14951&diff_format=u
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/ChangeLog?r1=14952&r2=14951&diff_format=u
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/enum.c?r1=14952&r2=14951&diff_format=u
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/enumerator.c?r1=14952&r2=14951&diff_format=u

Index: array.c
===================================================================
--- array.c	(revision 14951)
+++ array.c	(revision 14952)
@@ -1983,8 +1983,86 @@
     return ary;
 }
 
+static VALUE
+take_i(VALUE val, VALUE *args, int argc, VALUE *argv)
+{
+    if (args[1]-- == 0) rb_iter_break();
+    if (argc > 1) val = rb_ary_new4(argc, argv);
+    rb_ary_push(args[0], val);
+    return Qnil;
+}
+
+static VALUE
+take_items(VALUE obj, long n)
+{
+    VALUE result = rb_ary_new2(n);
+    VALUE args[2];
+
+    args[0] = result; args[1] = (VALUE)n;
+    rb_block_call(obj, rb_intern("each"), 0, 0, take_i, (VALUE)args);
+    return result;
+}
+
+
 /*
  *  call-seq:
+ *     array.zip(arg, ...)                   -> an_array
+ *     array.zip(arg, ...) {| arr | block }  -> nil
+ *  
+ *  Converts any arguments to arrays, then merges elements of
+ *  <i>self</i> with corresponding elements from each argument. This
+ *  generates a sequence of <code>self.size</code> <em>n</em>-element
+ *  arrays, where <em>n</em> is one more that the count of arguments. If
+ *  the size of any argument is less than <code>enumObj.size</code>,
+ *  <code>nil</code> values are supplied. If a block given, it is
+ *  invoked for each output array, otherwise an array of arrays is
+ *  returned.
+ *     
+ *     a = [ 4, 5, 6 ]
+ *     b = [ 7, 8, 9 ]
+ *     
+ *     [1,2,3].zip(a, b)      #=> [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
+ *     [1,2].zip(a,b)         #=> [[1, 4, 7], [2, 5, 8]]
+ *     a.zip([1,2],[8])       #=> [[4,1,8], [5,2,nil], [6,nil,nil]]
+ */
+
+static VALUE
+rb_ary_zip(argc, argv, ary)
+    int argc;
+    VALUE *argv;
+    VALUE ary;
+{
+    int i, j;
+    long len;
+    VALUE result = Qnil;
+
+    len = RARRAY_LEN(ary);
+    for (i=0; i<argc; i++) {
+	argv[i] = take_items(argv[i], len);
+    }
+    if (!rb_block_given_p()) {
+	result = rb_ary_new2(len);
+    }
+
+    for (i=0; i<RARRAY_LEN(ary); i++) {
+	VALUE tmp = rb_ary_new2(argc+1);
+
+	rb_ary_push(tmp, rb_ary_elt(ary, i));
+	for (j=0; j<argc; j++) {
+	    rb_ary_push(tmp, rb_ary_elt(argv[j], i));
+	}
+	if (NIL_P(result)) {
+	    rb_yield(tmp);
+	}
+	else {
+	    rb_ary_push(result, tmp);
+	}
+    }
+    return result;
+}
+
+/*
+ *  call-seq:
  *     array.transpose -> an_array
  *  
  *  Assumes that <i>self</i> is an array of arrays and transposes the
@@ -3299,6 +3377,7 @@
     rb_define_method(rb_cArray, "delete_if", rb_ary_delete_if, 0);
     rb_define_method(rb_cArray, "reject", rb_ary_reject, 0);
     rb_define_method(rb_cArray, "reject!", rb_ary_reject_bang, 0);
+    rb_define_method(rb_cArray, "zip", rb_ary_zip, -1);
     rb_define_method(rb_cArray, "transpose", rb_ary_transpose, 0);
     rb_define_method(rb_cArray, "replace", rb_ary_replace, 1);
     rb_define_method(rb_cArray, "clear", rb_ary_clear, 0);
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 14951)
+++ ChangeLog	(revision 14952)
@@ -2,6 +2,18 @@
 
 	* bin/ri, lib/rdoc/ri/*: Replace with Ryan Davis' cached ri.
 
+Tue Jan  8 17:32:07 2008  Yukihiro Matsumoto  <matz@r...>
+
+	* enum.c (enum_zip): honor length of the receiver, not the
+	  shortest length.  [ruby-core:14738]
+
+	* enum.c (enum_zip): returns array not enumerator for no block
+	  form.  [ruby-core:14738]
+
+	* enumerator.c (next_ii): do not ignore multiple values yielded.
+
+	* array.c (rb_ary_zip): faster version without creating generators.
+
 Tue Jan  8 15:47:43 2008  NAKAMURA Usaku  <usa@r...>
 
 	* enc/utf{16,32}_{be,le}.c: use &OnigEncodingName(*) instead of
Index: enumerator.c
===================================================================
--- enumerator.c	(revision 14951)
+++ enumerator.c	(revision 14952)
@@ -365,9 +365,9 @@
 }
 
 static VALUE
-next_ii(VALUE i, VALUE obj)
+next_ii(VALUE i, VALUE obj, int argc, VALUE *argv)
 {
-    rb_fiber_yield(1, &i);
+    rb_fiber_yield(argc, argv);
     return Qnil;
 }
 
Index: enum.c
===================================================================
--- enum.c	(revision 14951)
+++ enum.c	(revision 14952)
@@ -1347,6 +1347,18 @@
 
 
 static VALUE
+call_next(VALUE *v)
+{
+    return v[0] = rb_funcall(v[1], id_next, 0, 0);
+}
+
+static VALUE
+call_stop(VALUE *v)
+{
+    return v[0] = Qundef;
+}
+
+static VALUE
 zip_i(VALUE val, NODE *memo, int argc, VALUE *argv)
 {
     volatile VALUE result = memo->u1.value;
@@ -1357,8 +1369,20 @@
     tmp = rb_ary_new2(RARRAY_LEN(args) + 1);
     rb_ary_store(tmp, 0, enum_values_pack(argc, argv));
     for (i=0; i<RARRAY_LEN(args); i++) {
-	VALUE v = rb_funcall(RARRAY_PTR(args)[i], id_next, 0, 0);
-	rb_ary_push(tmp, v);
+	if (NIL_P(RARRAY_PTR(args)[i])) {
+	    rb_ary_push(tmp, Qnil);
+	}
+	else {
+	    VALUE v[2];
+
+	    v[1] = RARRAY_PTR(args)[i];
+	    rb_rescue2(call_next, (VALUE)v, call_stop, (VALUE)v, rb_eStopIteration, 0);
+	    if (v[0] == Qundef) {
+		RARRAY_PTR(args)[i] = Qnil;
+		v[0] = Qnil;
+	    }
+	    rb_ary_push(tmp, v[0]);
+	}
     }
     if (NIL_P(result)) {
 	rb_yield(tmp);
@@ -1369,12 +1393,6 @@
     return Qnil;
 }
 
-static VALUE
-zip_b(NODE *memo)
-{
-    return rb_block_call(memo->u3.value, id_each, 0, 0, zip_i, (VALUE)memo);
-}
-
 /*
  *  call-seq:
  *     enum.zip(arg, ...)                   => enumerator
@@ -1401,16 +1419,19 @@
 enum_zip(int argc, VALUE *argv, VALUE obj)
 {
     int i;
-    VALUE result;
+    ID conv;
     NODE *memo;
+    VALUE result = Qnil;
 
+    conv = rb_intern("to_enum");
     for (i=0; i<argc; i++) {
-	argv[i] = rb_funcall(argv[i], rb_intern("to_enum"), 1, ID2SYM(id_each));
+	argv[i] = rb_funcall(argv[i], conv, 1, ID2SYM(id_each));
     }
-    RETURN_ENUMERATOR(obj, argc, argv);
-    result = rb_block_given_p() ? Qnil : rb_ary_new();
-    memo = rb_node_newnode(NODE_MEMO, result, rb_ary_new4(argc, argv), obj);
-    rb_rescue2(zip_b, (VALUE)memo, 0, 0, rb_eStopIteration, (VALUE)0);
+    if (!rb_block_given_p()) {
+	result = rb_ary_new();
+    }
+    memo = rb_node_newnode(NODE_MEMO, result, rb_ary_new4(argc, argv), 0);
+    rb_block_call(obj, id_each, 0, 0, zip_i, (VALUE)memo);
 
     return result;
 }

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

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