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