ruby-changes:12846
From: akr <ko1@a...>
Date: Tue, 18 Aug 2009 21:03:15 +0900 (JST)
Subject: [ruby-changes:12846] Ruby:r24578 (trunk): * enumerator.c (enumerator_peek): new method Enumerator#peek.
akr 2009-08-18 21:02:53 +0900 (Tue, 18 Aug 2009) New Revision: 24578 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=24578 Log: * enumerator.c (enumerator_peek): new method Enumerator#peek. (enumerator_next): don't rewind at end. [ruby-dev:38932] Modified files: trunk/ChangeLog trunk/enumerator.c trunk/test/ruby/test_enumerator.rb Index: ChangeLog =================================================================== --- ChangeLog (revision 24577) +++ ChangeLog (revision 24578) @@ -1,3 +1,9 @@ +Tue Aug 18 21:00:26 2009 Tanaka Akira <akr@f...> + + * enumerator.c (enumerator_peek): new method Enumerator#peek. + (enumerator_next): don't rewind at end. + [ruby-dev:38932] + Tue Aug 18 13:46:14 2009 TAKANO Mitsuhiro (takano32) <tak@n...> * touch test/rdoc/empty.dat to run test_rdoc_parser.rb Index: enumerator.c =================================================================== --- enumerator.c (revision 24577) +++ enumerator.c (revision 24578) @@ -32,6 +32,7 @@ VALUE args; VALUE fib; VALUE dst; + VALUE lookahead; VALUE no_next; }; @@ -59,6 +60,7 @@ rb_gc_mark(ptr->args); rb_gc_mark(ptr->fib); rb_gc_mark(ptr->dst); + rb_gc_mark(ptr->lookahead); } static struct enumerator * @@ -281,6 +283,7 @@ if (argc) ptr->args = rb_ary_new4(argc, argv); ptr->fib = 0; ptr->dst = Qnil; + ptr->lookahead = Qundef; ptr->no_next = Qfalse; return enum_obj; @@ -361,6 +364,7 @@ ptr1->meth = ptr0->meth; ptr1->args = ptr0->args; ptr1->fib = 0; + ptr1->lookahead = Qundef; return obj; } @@ -519,6 +523,7 @@ VALUE curr = rb_fiber_current(); e->dst = curr; e->fib = rb_fiber_new(next_i, obj); + e->lookahead = Qundef; } /* @@ -526,8 +531,8 @@ * e.next => object * * Returns the next object in the enumerator, and move the internal - * position forward. When the position reached at the end, internal - * position is rewound then StopIteration is raised. + * position forward. When the position reached at the end, StopIteration + * is raised. * * Note that enumeration sequence by next method does not affect other * non-external enumeration methods, unless underlying iteration @@ -540,6 +545,16 @@ { struct enumerator *e = enumerator_ptr(obj); VALUE curr, v; + + if (e->lookahead != Qundef) { + v = e->lookahead; + e->lookahead = Qundef; + return v; + } + + if (e->no_next) + rb_raise(rb_eStopIteration, "iteration reached at end"); + curr = rb_fiber_current(); if (!e->fib || !rb_fiber_alive_p(e->fib)) { @@ -550,7 +565,7 @@ if (e->no_next) { e->fib = 0; e->dst = Qnil; - e->no_next = Qfalse; + e->lookahead = Qundef; rb_raise(rb_eStopIteration, "iteration reached at end"); } return v; @@ -558,6 +573,32 @@ /* * call-seq: + * e.peek => object + * + * Returns the next object in the enumerator, but don't move the internal + * position forward. When the position reached at the end, StopIteration + * is raised. + * + */ + +static VALUE +enumerator_peek(VALUE obj) +{ + struct enumerator *e = enumerator_ptr(obj); + VALUE v; + + if (e->lookahead != Qundef) { + v = e->lookahead; + return v; + } + + v = enumerator_next(obj); + e->lookahead = v; + return v; +} + +/* + * call-seq: * e.rewind => e * * Rewinds the enumeration sequence by the next method. @@ -575,6 +616,7 @@ e->fib = 0; e->dst = Qnil; + e->lookahead = Qundef; e->no_next = Qfalse; return obj; } @@ -868,6 +910,7 @@ rb_define_method(rb_cEnumerator, "with_index", enumerator_with_index, -1); rb_define_method(rb_cEnumerator, "with_object", enumerator_with_object, 1); rb_define_method(rb_cEnumerator, "next", enumerator_next, 0); + rb_define_method(rb_cEnumerator, "peek", enumerator_peek, 0); rb_define_method(rb_cEnumerator, "rewind", enumerator_rewind, 0); rb_define_method(rb_cEnumerator, "inspect", enumerator_inspect, 0); Index: test/ruby/test_enumerator.rb =================================================================== --- test/ruby/test_enumerator.rb (revision 24577) +++ test/ruby/test_enumerator.rb (revision 24578) @@ -130,5 +130,27 @@ assert_equal(3, e.next) assert_raise(StopIteration) { e.next } end + + def test_peek + a = [1] + e = a.each + assert_equal(1, e.peek) + assert_equal(1, e.peek) + assert_equal(1, e.next) + assert_raise(StopIteration) { e.peek } + assert_raise(StopIteration) { e.peek } + end + + def test_next_after_stopiteration + a = [1] + e = a.each + assert_equal(1, e.next) + assert_raise(StopIteration) { e.next } + assert_raise(StopIteration) { e.next } + e.rewind + assert_equal(1, e.next) + assert_raise(StopIteration) { e.next } + assert_raise(StopIteration) { e.next } + end end -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/