ruby-changes:4498
From: ko1@a...
Date: Mon, 14 Apr 2008 00:00:16 +0900 (JST)
Subject: [ruby-changes:4498] knu - Ruby:r15991 (trunk): * enum.c (enum_cycle): Make Enumerable#cycle do a finite loop when
knu 2008-04-13 23:59:55 +0900 (Sun, 13 Apr 2008) New Revision: 15991 Modified files: trunk/ChangeLog trunk/array.c trunk/enum.c Log: * enum.c (enum_cycle): Make Enumerable#cycle do a finite loop when the number of cycles is specified. * array.c (rb_ary_cycle): Ditto for Array#cycle. http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/array.c?r1=15991&r2=15990&diff_format=u http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/ChangeLog?r1=15991&r2=15990&diff_format=u http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/enum.c?r1=15991&r2=15990&diff_format=u Index: array.c =================================================================== --- array.c (revision 15990) +++ array.c (revision 15991) @@ -2938,25 +2938,41 @@ /* * call-seq: * ary.cycle {|obj| block } + * ary.cycle(n) {|obj| block } * - * Calls <i>block</i> repeatedly forever. + * Calls <i>block</i> for each element repeatedly _n_ times or + * forever if none or nil is given. If a non-positive number is + * given or the array is empty, does nothing. Returns nil if the + * loop has finished without getting interrupted. * * a = ["a", "b", "c"] * a.cycle {|x| puts x } # print, a, b, c, a, b, c,.. forever. + * a.cycle(2) {|x| puts x } # print, a, b, c, a, b, c. * */ static VALUE -rb_ary_cycle(VALUE ary) +rb_ary_cycle(int argc, VALUE *argv, VALUE ary) { - long i; + long n, i; + VALUE nv = Qnil; - RETURN_ENUMERATOR(ary, 0, 0); - while (RARRAY_LEN(ary) > 0) { - for (i=0; i<RARRAY_LEN(ary); i++) { - rb_yield(RARRAY_PTR(ary)[i]); - } + rb_scan_args(argc, argv, "01", &nv); + + RETURN_ENUMERATOR(ary, argc, argv); + if (NIL_P(nv)) { + n = -1; } + else { + n = NUM2LONG(nv); + if (n <= 0) return Qnil; + } + + while (RARRAY_LEN(ary) > 0 && (n < 0 || 0 < n--)) { + for (i=0; i<RARRAY_LEN(ary); i++) { + rb_yield(RARRAY_PTR(ary)[i]); + } + } return Qnil; } @@ -3430,7 +3446,7 @@ rb_define_method(rb_cArray, "shuffle!", rb_ary_shuffle_bang, 0); rb_define_method(rb_cArray, "shuffle", rb_ary_shuffle, 0); rb_define_method(rb_cArray, "choice", rb_ary_choice, 0); - rb_define_method(rb_cArray, "cycle", rb_ary_cycle, 0); + rb_define_method(rb_cArray, "cycle", rb_ary_cycle, -1); rb_define_method(rb_cArray, "permutation", rb_ary_permutation, -1); rb_define_method(rb_cArray, "combination", rb_ary_combination, 1); rb_define_method(rb_cArray, "product", rb_ary_product, -1); Index: ChangeLog =================================================================== --- ChangeLog (revision 15990) +++ ChangeLog (revision 15991) @@ -1,3 +1,10 @@ +Sun Apr 13 23:53:58 2008 Akinori MUSHA <knu@i...> + + * enum.c (enum_cycle): Make Enumerable#cycle do a finite loop when + the number of cycles is specified. + + * array.c (rb_ary_cycle): Ditto for Array#cycle. + Sun Apr 13 18:52:27 2008 Nobuyoshi Nakada <nobu@r...> * thread_pthread.c (lock_func): should not check interrupts in Index: enum.c =================================================================== --- enum.c (revision 15990) +++ enum.c (revision 15991) @@ -1656,33 +1656,48 @@ /* * call-seq: * enum.cycle {|obj| block } + * enum.cycle(n) {|obj| block } * - * Calls <i>block</i> for each element of <i>enum</i> repeatedly - * forever. Returns nil if and only if the collection is empty. + * Calls <i>block</i> for each element of <i>enum</i> repeatedly _n_ + * times or forever if none or nil is given. If a non-positive + * number is given or the collection is empty, does nothing. Returns + * nil if the loop has finished without getting interrupted. + * * Enumerable#cycle saves elements in an internal array so changes * to <i>enum</i> after the first pass have no effect. * * a = ["a", "b", "c"] * a.cycle {|x| puts x } # print, a, b, c, a, b, c,.. forever. + * a.cycle(2) {|x| puts x } # print, a, b, c, a, b, c. * */ static VALUE -enum_cycle(VALUE obj) +enum_cycle(int argc, VALUE *argv, VALUE obj) { VALUE ary; - long i, len; + VALUE nv = Qnil; + long n, i, len; - RETURN_ENUMERATOR(obj, 0, 0); + rb_scan_args(argc, argv, "01", &nv); + + RETURN_ENUMERATOR(obj, argc, argv); + if (NIL_P(nv)) { + n = -1; + } + else { + n = NUM2LONG(nv); + if (n <= 0) return Qnil; + } ary = rb_ary_new(); RBASIC(ary)->klass = 0; rb_block_call(obj, id_each, 0, 0, cycle_i, ary); len = RARRAY_LEN(ary); if (len == 0) return Qnil; - for (;;) { - for (i=0; i<len; i++) { - rb_yield(RARRAY_PTR(ary)[i]); - } + while (n < 0 || 0 < --n) { + for (i=0; i<len; i++) { + rb_yield(RARRAY_PTR(ary)[i]); + } } return Qnil; /* not reached */ } @@ -1741,7 +1756,7 @@ rb_define_method(rb_mEnumerable, "take_while", enum_take_while, 0); 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, 0); + rb_define_method(rb_mEnumerable, "cycle", enum_cycle, -1); id_eqq = rb_intern("==="); id_each = rb_intern("each"); -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/