ruby-changes:4463
From: ko1@a...
Date: Thu, 10 Apr 2008 19:53:12 +0900 (JST)
Subject: [ruby-changes:4463] knu - Ruby:r15954 (ruby_1_8): * enumerator.c (rb_eStopIteration), eval.c (rb_f_loop), ruby.h:
knu 2008-04-10 19:52:50 +0900 (Thu, 10 Apr 2008)
New Revision: 15954
Modified files:
branches/ruby_1_8/ChangeLog
branches/ruby_1_8/NEWS
branches/ruby_1_8/enumerator.c
branches/ruby_1_8/eval.c
branches/ruby_1_8/lib/generator.rb
branches/ruby_1_8/ruby.h
Log:
* enumerator.c (rb_eStopIteration), eval.c (rb_f_loop), ruby.h:
Add a new exception class StopIteration, which breaks Kernel#loop
iteration when raised; backported from 1.9.
* enumerator.c (enumerator_next, enumerator_rewind): Implement
#next and #rewind using the "generator" library.
* lib/generator.rb: Implement Enumerable::Enumerator#next and
#rewind.
http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/lib/generator.rb?r1=15954&r2=15953&diff_format=u
http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/ruby.h?r1=15954&r2=15953&diff_format=u
http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/ChangeLog?r1=15954&r2=15953&diff_format=u
http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/enumerator.c?r1=15954&r2=15953&diff_format=u
http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/NEWS?r1=15954&r2=15953&diff_format=u
http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/eval.c?r1=15954&r2=15953&diff_format=u
Index: ruby_1_8/NEWS
===================================================================
--- ruby_1_8/NEWS (revision 15953)
+++ ruby_1_8/NEWS (revision 15954)
@@ -61,10 +61,16 @@
* Regexp.union accepts an array of patterns.
+ * StopIteration
+
+ New exception class that causes Kernel#loop to stop iteration when
+ raised.
+
* enumerator
- * Enumerator is now a built-in module. Almost everything has been
- backported from 1.9, except for the #next and #rewind methods.
+ * Enumerator is now a built-in module. The #next and #rewind
+ methods are implemented using the "generator" library. Use with
+ care and be aware of the performance loss.
* ipaddr
Index: ruby_1_8/ChangeLog
===================================================================
--- ruby_1_8/ChangeLog (revision 15953)
+++ ruby_1_8/ChangeLog (revision 15954)
@@ -1,3 +1,15 @@
+Thu Apr 10 19:49:10 2008 Akinori MUSHA <knu@i...>
+
+ * enumerator.c (rb_eStopIteration), eval.c (rb_f_loop), ruby.h:
+ Add a new exception class StopIteration, which breaks Kernel#loop
+ iteration when raised; backported from 1.9.
+
+ * enumerator.c (enumerator_next, enumerator_rewind): Implement
+ #next and #rewind using the "generator" library.
+
+ * lib/generator.rb: Implement Enumerable::Enumerator#next and
+ #rewind.
+
Thu Apr 10 19:29:48 2008 Akinori MUSHA <knu@i...>
* array.c (rb_ary_first, rb_ary_last): Return a shared array when
Index: ruby_1_8/enumerator.c
===================================================================
--- ruby_1_8/enumerator.c (revision 15953)
+++ ruby_1_8/enumerator.c (revision 15954)
@@ -23,6 +23,8 @@
VALUE rb_cEnumerator;
static VALUE sym_each, sym_call;
+VALUE rb_eStopIteration;
+
static VALUE
proc_call(proc, args)
VALUE proc;
@@ -387,6 +389,45 @@
enumerator_with_index_i, (VALUE)&memo);
}
+/*
+ * call-seq:
+ * 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 rewinded then StopIteration is raised.
+ *
+ * Note that enumeration sequence by next method does not affect other
+ * non-external enumeration methods, unless underlying iteration
+ * methods itself has side-effect, e.g. IO#each_line.
+ *
+ * Caution: Calling this method causes the "generator" library to be
+ * loaded.
+ */
+
+static VALUE
+enumerator_next(obj)
+ VALUE obj;
+{
+ rb_require("generator");
+ return rb_funcall(obj, rb_intern("next"), 0, 0);
+}
+
+/*
+ * call-seq:
+ * e.rewind => e
+ *
+ * Rewinds the enumeration sequence by the next method.
+ */
+
+static VALUE
+enumerator_rewind(obj)
+ VALUE obj;
+{
+ rb_require("generator");
+ return rb_funcall(obj, rb_intern("rewind"), 0, 0);
+}
+
void
Init_Enumerator()
{
@@ -406,7 +447,11 @@
rb_define_method(rb_cEnumerator, "initialize_copy", enumerator_init_copy, 1);
rb_define_method(rb_cEnumerator, "each", enumerator_each, 0);
rb_define_method(rb_cEnumerator, "with_index", enumerator_with_index, 0);
+ rb_define_method(rb_cEnumerator, "next", enumerator_next, 0);
+ rb_define_method(rb_cEnumerator, "rewind", enumerator_rewind, 0);
+ rb_eStopIteration = rb_define_class("StopIteration", rb_eIndexError);
+
sym_each = ID2SYM(rb_intern("each"));
sym_call = ID2SYM(rb_intern("call"));
Index: ruby_1_8/lib/generator.rb
===================================================================
--- ruby_1_8/lib/generator.rb (revision 15953)
+++ ruby_1_8/lib/generator.rb (revision 15954)
@@ -165,6 +165,44 @@
end
end
+class Enumerable::Enumerator
+ def __generator
+ @generator ||= Generator.new(self)
+ end
+ private :__generator
+
+ # call-seq:
+ # 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 rewinded then StopIteration is raised.
+ #
+ # Note that enumeration sequence by next method does not affect other
+ # non-external enumeration methods, unless underlying iteration
+ # methods itself has side-effect, e.g. IO#each_line.
+ #
+ # Caution: This feature internally uses Generator, which uses callcc
+ # to stop and resume enumeration to fetch each value. Use with care
+ # and be aware of the performance loss.
+ def next
+ g = __generator
+ return g.next unless g.end?
+
+ g.rewind
+ raise StopIteration, 'iteration reached at end'
+ end
+
+ # call-seq:
+ # e.rewind => e
+ #
+ # Rewinds the enumeration sequence by the next method.
+ def rewind
+ __generator.rewind
+ self
+ end
+end
+
#
# SyncEnumerator creates an Enumerable object from multiple Enumerable
# objects and enumerates them synchronously.
Index: ruby_1_8/ruby.h
===================================================================
--- ruby_1_8/ruby.h (revision 15953)
+++ ruby_1_8/ruby.h (revision 15954)
@@ -659,6 +659,7 @@
RUBY_EXTERN VALUE rb_eArgError;
RUBY_EXTERN VALUE rb_eEOFError;
RUBY_EXTERN VALUE rb_eIndexError;
+RUBY_EXTERN VALUE rb_eStopIteration;
RUBY_EXTERN VALUE rb_eRangeError;
RUBY_EXTERN VALUE rb_eIOError;
RUBY_EXTERN VALUE rb_eRuntimeError;
Index: ruby_1_8/eval.c
===================================================================
--- ruby_1_8/eval.c (revision 15953)
+++ ruby_1_8/eval.c (revision 15954)
@@ -5157,6 +5157,16 @@
return rb_yield_0(values, 0, 0, 0, avalue);
}
+static VALUE
+loop_i()
+{
+ for (;;) {
+ rb_yield_0(Qundef, 0, 0, 0, Qfalse);
+ CHECK_INTS;
+ }
+ return Qnil;
+}
+
/*
* call-seq:
* loop {|| block }
@@ -5169,15 +5179,14 @@
* break if !line or line =~ /^qQ/
* # ...
* end
+ *
+ * StopIteration raised in the block breaks the loop.
*/
static VALUE
rb_f_loop()
{
- for (;;) {
- rb_yield_0(Qundef, 0, 0, 0, Qfalse);
- CHECK_INTS;
- }
+ rb_rescue2(loop_i, (VALUE)0, 0, 0, rb_eStopIteration, (VALUE)0);
return Qnil; /* dummy */
}
--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/