Ruby 1.9.2p136(2010-12-25revision30365)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

# enumerator.c

Go to the documentation of this file.

    00001 /************************************************
    00002
    00003   enumerator.c - provides Enumerator class
    00004
    00005   $Author: nobu $
    00006
    00007   Copyright (C) 2001-2003 Akinori MUSHA
    00008
    00009   $Idaemons: /home/cvs/rb/enumerator/enumerator.c,v 1.1.1.1 2001/07/15 10:12:48 knu Exp $
    00010   $RoughId: enumerator.c,v 1.6 2003/07/27 11:03:24 nobu Exp $
    00011   $Id: enumerator.c 28085 2010-05-29 18:51:39Z nobu $
    00012
    00013 ************************************************/
    00014
    00015 #include "ruby/ruby.h"
    00016
    00017 /*
    00018  * Document-class: Enumerator
    00019  *
    00020  * A class which provides a method `each' to be used as an Enumerable
    00021  * object.
    00022  *
    00023  * An enumerator can be created by following methods.
    00024  * - Kernel#to_enum
    00025  * - Kernel#enum_for
    00026  * - Enumerator.new
    00027  *
    00028  * Also, most iteration methods without a block returns an enumerator.
    00029  * For example, Array#map returns an enumerator if a block is not given.
    00030  * The enumerator has the with_index method.
    00031  * So ary.map.with_index works as follows.
    00032  *
    00033  *   p %w[foo bar baz].map.with_index {|w,i| "#{i}:#{w}" }
    00034  *   #=> ["0:foo", "1:bar", "2:baz"]
    00035  *
    00036  * An enumerator object can be used as an external iterator.
    00037  * I.e.  Enumerator#next returns the next value of the iterator.
    00038  * Enumerator#next raises StopIteration at end.
    00039  *
    00040  *   e = [1,2,3].each   # returns an enumerator object.
    00041  *   p e.next   #=> 1
    00042  *   p e.next   #=> 2
    00043  *   p e.next   #=> 3
    00044  *   p e.next   #raises StopIteration
    00045  *
    00046  * An external iterator can be used to implement an internal iterator as follows.
    00047  *
    00048  *   def ext_each(e)
    00049  *     while true
    00050  *       begin
    00051  *         vs = e.next_values
    00052  *       rescue StopIteration
    00053  *         return $!.result
    00054  *       end
    00055  *       y = yield(*vs)
    00056  *       e.feed y
    00057  *     end
    00058  *   end
    00059  *
    00060  *   o = Object.new
    00061  *   def o.each
    00062  *     p yield
    00063  *     p yield(1)
    00064  *     p yield(1, 2)
    00065  *     3
    00066  *   end
    00067  *
    00068  *   # use o.each as an internal iterator directly.
    00069  *   p o.each {|*x| p x; [:b, *x] }
    00070  *   #=> [], [:b], [1], [:b, 1], [1, 2], [:b, 1, 2], 3
    00071  *
    00072  *   # convert o.each to an external iterator for
    00073  *   # implementing an internal iterator.
    00074  *   p ext_each(o.to_enum) {|*x| p x; [:b, *x] }
    00075  *   #=> [], [:b], [1], [:b, 1], [1, 2], [:b, 1, 2], 3
    00076  *
    00077  */
    00078 VALUE rb_cEnumerator;
    00079 static ID id_rewind, id_each;
    00080 static VALUE sym_each;
    00081
    00082 VALUE rb_eStopIteration;
    00083
    00084 struct enumerator {
    00085     VALUE obj;
    00086     ID    meth;
    00087     VALUE args;
    00088     VALUE fib;
    00089     VALUE dst;
    00090     VALUE lookahead;
    00091     VALUE feedvalue;
    00092     VALUE stop_exc;
    00093 };
    00094
    00095 static VALUE rb_cGenerator, rb_cYielder;
    00096
    00097 struct generator {
    00098     VALUE proc;
    00099 };
    00100
    00101 struct yielder {
    00102     VALUE proc;
    00103 };
    00104
    00105 static VALUE generator_allocate(VALUE klass);
    00106 static VALUE generator_init(VALUE obj, VALUE proc);
    00107
    00108 /*
    00109  * Enumerator
    00110  */
    00111 static void
    00112 enumerator_mark(void *p)
    00113 {
    00114     struct enumerator *ptr = p;
    00115     rb_gc_mark(ptr->obj);
    00116     rb_gc_mark(ptr->args);
    00117     rb_gc_mark(ptr->fib);
    00118     rb_gc_mark(ptr->dst);
    00119     rb_gc_mark(ptr->lookahead);
    00120     rb_gc_mark(ptr->feedvalue);
    00121     rb_gc_mark(ptr->stop_exc);
    00122 }
    00123
    00124 #define enumerator_free RUBY_TYPED_DEFAULT_FREE
    00125
    00126 static size_t
    00127 enumerator_memsize(const void *p)
    00128 {
    00129     return p ? sizeof(struct enumerator) : 0;
    00130 }
    00131
    00132 static const rb_data_type_t enumerator_data_type = {
    00133     "enumerator",
    00134     enumerator_mark,
    00135     enumerator_free,
    00136     enumerator_memsize,
    00137 };
    00138
    00139 static struct enumerator *
    00140 enumerator_ptr(VALUE obj)
    00141 {
    00142     struct enumerator *ptr;
    00143
    00144     TypedData_Get_Struct(obj, struct enumerator, &enumerator_data_type, ptr);
    00145     if (!ptr || ptr->obj == Qundef) {
    00146         rb_raise(rb_eArgError, "uninitialized enumerator");
    00147     }
    00148     return ptr;
    00149 }
    00150
    00151 /*
    00152  *  call-seq:
    00153  *    obj.to_enum(method = :each, *args)
    00154  *    obj.enum_for(method = :each, *args)
    00155  *
    00156  *  Returns Enumerator.new(self, method, *args).
    00157  *
    00158  *  e.g.:
    00159  *
    00160  *     str = "xyz"
    00161  *
    00162  *     enum = str.enum_for(:each_byte)
    00163  *     a = enum.map {|b| '%02x' % b } #=> ["78", "79", "7a"]
    00164  *
    00165  *     # protects an array from being modified
    00166  *     a = [1, 2, 3]
    00167  *     some_method(a.to_enum)
    00168  *
    00169  */
    00170 static VALUE
    00171 obj_to_enum(int argc, VALUE *argv, VALUE obj)
    00172 {
    00173     VALUE meth = sym_each;
    00174
    00175     if (argc > 0) {
    00176         --argc;
    00177         meth = *argv++;
    00178     }
    00179     return rb_enumeratorize(obj, meth, argc, argv);
    00180 }
    00181
    00182 static VALUE
    00183 enumerator_allocate(VALUE klass)
    00184 {
    00185     struct enumerator *ptr;
    00186     VALUE enum_obj;
    00187
    00188     enum_obj = TypedData_Make_Struct(klass, struct enumerator, &enumerator_data_type, ptr);
    00189     ptr->obj = Qundef;
    00190
    00191     return enum_obj;
    00192 }
    00193
    00194 static VALUE
    00195 enumerator_init(VALUE enum_obj, VALUE obj, VALUE meth, int argc, VALUE *argv)
    00196 {
    00197     struct enumerator *ptr;
    00198
    00199     TypedData_Get_Struct(enum_obj, struct enumerator, &enumerator_data_type, ptr);
    00200
    00201     if (!ptr) {
    00202         rb_raise(rb_eArgError, "unallocated enumerator");
    00203     }
    00204
    00205     ptr->obj  = obj;
    00206     ptr->meth = rb_to_id(meth);
    00207     if (argc) ptr->args = rb_ary_new4(argc, argv);
    00208     ptr->fib = 0;
    00209     ptr->dst = Qnil;
    00210     ptr->lookahead = Qundef;
    00211     ptr->feedvalue = Qundef;
    00212     ptr->stop_exc = Qfalse;
    00213
    00214     return enum_obj;
    00215 }
    00216
    00217 /*
    00218  *  call-seq:
    00219  *    Enumerator.new(obj, method = :each, *args)
    00220  *    Enumerator.new { |y| ... }
    00221  *
    00222  *  Creates a new Enumerator object, which is to be used as an
    00223  *  Enumerable object iterating in a given way.
    00224  *
    00225  *  In the first form, a generated Enumerator iterates over the given
    00226  *  object using the given method with the given arguments passed.
    00227  *  Use of this form is discouraged.  Use Kernel#enum_for(), alias
    00228  *  to_enum, instead.
    00229  *
    00230  *    e = Enumerator.new(ObjectSpace, :each_object)
    00231  *        #-> ObjectSpace.enum_for(:each_object)
    00232  *
    00233  *    e.select { |obj| obj.is_a?(Class) }  #=> array of all classes
    00234  *
    00235  *  In the second form, iteration is defined by the given block, in
    00236  *  which a "yielder" object given as block parameter can be used to
    00237  *  yield a value by calling the +yield+ method, alias +<<+.
    00238  *
    00239  *    fib = Enumerator.new { |y|
    00240  *      a = b = 1
    00241  *      loop {
    00242  *        y << a
    00243  *        a, b = b, a + b
    00244  *      }
    00245  *    }
    00246  *
    00247  *    p fib.take(10) #=> [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
    00248  */
    00249 static VALUE
    00250 enumerator_initialize(int argc, VALUE *argv, VALUE obj)
    00251 {
    00252     VALUE recv, meth = sym_each;
    00253
    00254     if (argc == 0) {
    00255         if (!rb_block_given_p())
    00256             rb_raise(rb_eArgError, "wrong number of argument (0 for 1+)");
    00257
    00258         recv = generator_init(generator_allocate(rb_cGenerator), rb_block_proc());
    00259     }
    00260     else {
    00261         recv = *argv++;
    00262         if (--argc) {
    00263             meth = *argv++;
    00264             --argc;
    00265         }
    00266     }
    00267
    00268     return enumerator_init(obj, recv, meth, argc, argv);
    00269 }
    00270
    00271 /* :nodoc: */
    00272 static VALUE
    00273 enumerator_init_copy(VALUE obj, VALUE orig)
    00274 {
    00275     struct enumerator *ptr0, *ptr1;
    00276
    00277     ptr0 = enumerator_ptr(orig);
    00278     if (ptr0->fib) {
    00279         /* Fibers cannot be copied */
    00280         rb_raise(rb_eTypeError, "can't copy execution context");
    00281     }
    00282
    00283     TypedData_Get_Struct(obj, struct enumerator, &enumerator_data_type, ptr1);
    00284
    00285     if (!ptr1) {
    00286         rb_raise(rb_eArgError, "unallocated enumerator");
    00287     }
    00288
    00289     ptr1->obj  = ptr0->obj;
    00290     ptr1->meth = ptr0->meth;
    00291     ptr1->args = ptr0->args;
    00292     ptr1->fib  = 0;
    00293     ptr1->lookahead  = Qundef;
    00294     ptr1->feedvalue  = Qundef;
    00295
    00296     return obj;
    00297 }
    00298
    00299 VALUE
    00300 rb_enumeratorize(VALUE obj, VALUE meth, int argc, VALUE *argv)
    00301 {
    00302     return enumerator_init(enumerator_allocate(rb_cEnumerator), obj, meth, argc, argv);
    00303 }
    00304
    00305 static VALUE
    00306 enumerator_block_call(VALUE obj, rb_block_call_func *func, VALUE arg)
    00307 {
    00308     int argc = 0;
    00309     VALUE *argv = 0;
    00310     const struct enumerator *e = enumerator_ptr(obj);
    00311     ID meth = e->meth;
    00312
    00313     if (e->args) {
    00314         argc = RARRAY_LENINT(e->args);
    00315         argv = RARRAY_PTR(e->args);
    00316     }
    00317     return rb_block_call(e->obj, meth, argc, argv, func, arg);
    00318 }
    00319
    00320 /*
    00321  *  call-seq:
    00322  *    enum.each {...}
    00323  *
    00324  *  Iterates the given block using the object and the method specified
    00325  *  in the first place.  If no block is given, returns self.
    00326  *
    00327  */
    00328 static VALUE
    00329 enumerator_each(VALUE obj)
    00330 {
    00331     if (!rb_block_given_p()) return obj;
    00332     return enumerator_block_call(obj, 0, obj);
    00333 }
    00334
    00335 static VALUE
    00336 enumerator_with_index_i(VALUE val, VALUE m, int argc, VALUE *argv)
    00337 {
    00338     VALUE idx;
    00339     VALUE *memo = (VALUE *)m;
    00340
    00341     idx = INT2FIX(*memo);
    00342     ++*memo;
    00343
    00344     if (argc <= 1)
    00345         return rb_yield_values(2, val, idx);
    00346
    00347     return rb_yield_values(2, rb_ary_new4(argc, argv), idx);
    00348 }
    00349
    00350 /*
    00351  *  call-seq:
    00352  *    e.with_index(offset = 0) {|(*args), idx| ... }
    00353  *    e.with_index(offset = 0)
    00354  *
    00355  *  Iterates the given block for each element with an index, which
    00356  *  starts from +offset+.  If no block is given, returns an enumerator.
    00357  *
    00358  */
    00359 static VALUE
    00360 enumerator_with_index(int argc, VALUE *argv, VALUE obj)
    00361 {
    00362     VALUE memo;
    00363
    00364     rb_scan_args(argc, argv, "01", &memo);
    00365     RETURN_ENUMERATOR(obj, argc, argv);
    00366     memo = NIL_P(memo) ? 0 : (VALUE)NUM2LONG(memo);
    00367     return enumerator_block_call(obj, enumerator_with_index_i, (VALUE)&memo);
    00368 }
    00369
    00370 /*
    00371  *  call-seq:
    00372  *    e.each_with_index {|(*args), idx| ... }
    00373  *    e.each_with_index
    00374  *
    00375  *  Same as Enumerator#with_index, except each_with_index does not
    00376  *  receive an offset argument.
    00377  *
    00378  */
    00379 static VALUE
    00380 enumerator_each_with_index(VALUE obj)
    00381 {
    00382     return enumerator_with_index(0, NULL, obj);
    00383 }
    00384
    00385 static VALUE
    00386 enumerator_with_object_i(VALUE val, VALUE memo, int argc, VALUE *argv)
    00387 {
    00388     if (argc <= 1)
    00389         return rb_yield_values(2, val, memo);
    00390
    00391     return rb_yield_values(2, rb_ary_new4(argc, argv), memo);
    00392 }
    00393
    00394 /*
    00395  *  call-seq:
    00396  *    e.with_object(obj) {|(*args), memo_obj| ... }
    00397  *    e.with_object(obj)
    00398  *
    00399  *  Iterates the given block for each element with an arbitrary
    00400  *  object given, and returns the initially given object.
    00401  *
    00402  *  If no block is given, returns an enumerator.
    00403  *
    00404  */
    00405 static VALUE
    00406 enumerator_with_object(VALUE obj, VALUE memo)
    00407 {
    00408     RETURN_ENUMERATOR(obj, 1, &memo);
    00409     enumerator_block_call(obj, enumerator_with_object_i, memo);
    00410
    00411     return memo;
    00412 }
    00413
    00414 static VALUE
    00415 next_ii(VALUE i, VALUE obj, int argc, VALUE *argv)
    00416 {
    00417     struct enumerator *e = enumerator_ptr(obj);
    00418     VALUE feedvalue = Qnil;
    00419     VALUE args = rb_ary_new4(argc, argv);
    00420     rb_fiber_yield(1, &args);
    00421     if (e->feedvalue != Qundef) {
    00422         feedvalue = e->feedvalue;
    00423         e->feedvalue = Qundef;
    00424     }
    00425     return feedvalue;
    00426 }
    00427
    00428 static VALUE
    00429 next_i(VALUE curr, VALUE obj)
    00430 {
    00431     struct enumerator *e = enumerator_ptr(obj);
    00432     VALUE nil = Qnil;
    00433     VALUE result;
    00434
    00435     result = rb_block_call(obj, id_each, 0, 0, next_ii, obj);
    00436     e->stop_exc = rb_exc_new2(rb_eStopIteration, "iteration reached an end");
    00437     rb_ivar_set(e->stop_exc, rb_intern("result"), result);
    00438     return rb_fiber_yield(1, &nil);
    00439 }
    00440
    00441 static void
    00442 next_init(VALUE obj, struct enumerator *e)
    00443 {
    00444     VALUE curr = rb_fiber_current();
    00445     e->dst = curr;
    00446     e->fib = rb_fiber_new(next_i, obj);
    00447     e->lookahead = Qundef;
    00448 }
    00449
    00450 static VALUE
    00451 get_next_values(VALUE obj, struct enumerator *e)
    00452 {
    00453     VALUE curr, vs;
    00454
    00455     if (e->stop_exc)
    00456         rb_exc_raise(e->stop_exc);
    00457
    00458     curr = rb_fiber_current();
    00459
    00460     if (!e->fib || !rb_fiber_alive_p(e->fib)) {
    00461         next_init(obj, e);
    00462     }
    00463
    00464     vs = rb_fiber_resume(e->fib, 1, &curr);
    00465     if (e->stop_exc) {
    00466         e->fib = 0;
    00467         e->dst = Qnil;
    00468         e->lookahead = Qundef;
    00469         e->feedvalue = Qundef;
    00470         rb_exc_raise(e->stop_exc);
    00471     }
    00472     return vs;
    00473 }
    00474
    00475 /*
    00476  * call-seq:
    00477  *   e.next_values   -> array
    00478  *
    00479  * Returns the next object as an array in the enumerator,
    00480  * and move the internal position forward.
    00481  * When the position reached at the end, StopIteration is raised.
    00482  *
    00483  * This method can be used to distinguish <code>yield</code> and <code>yield nil</code>.
    00484  *
    00485  *   o = Object.new
    00486  *   def o.each
    00487  *     yield
    00488  *     yield 1
    00489  *     yield 1, 2
    00490  *     yield nil
    00491  *     yield [1, 2]
    00492  *   end
    00493  *   e = o.to_enum
    00494  *   p e.next_values
    00495  *   p e.next_values
    00496  *   p e.next_values
    00497  *   p e.next_values
    00498  *   p e.next_values
    00499  *   e = o.to_enum
    00500  *   p e.next
    00501  *   p e.next
    00502  *   p e.next
    00503  *   p e.next
    00504  *   p e.next
    00505  *
    00506  *   ## yield args       next_values      next
    00507  *   #  yield            []               nil
    00508  *   #  yield 1          [1]              1
    00509  *   #  yield 1, 2       [1, 2]           [1, 2]
    00510  *   #  yield nil        [nil]            nil
    00511  *   #  yield [1, 2]     [[1, 2]]         [1, 2]
    00512  *
    00513  * Note that enumeration sequence by next_values method does not affect other
    00514  * non-external enumeration methods, unless underlying iteration
    00515  * methods itself has side-effect, e.g. IO#each_line.
    00516  *
    00517  */
    00518
    00519 static VALUE
    00520 enumerator_next_values(VALUE obj)
    00521 {
    00522     struct enumerator *e = enumerator_ptr(obj);
    00523     VALUE vs;
    00524
    00525     if (e->lookahead != Qundef) {
    00526         vs = e->lookahead;
    00527         e->lookahead = Qundef;
    00528         return vs;
    00529     }
    00530
    00531     return get_next_values(obj, e);
    00532 }
    00533
    00534 static VALUE
    00535 ary2sv(VALUE args, int dup)
    00536 {
    00537     if (TYPE(args) != T_ARRAY)
    00538         return args;
    00539
    00540     switch (RARRAY_LEN(args)) {
    00541       case 0:
    00542         return Qnil;
    00543
    00544       case 1:
    00545         return RARRAY_PTR(args)[0];
    00546
    00547       default:
    00548         if (dup)
    00549             return rb_ary_dup(args);
    00550         return args;
    00551     }
    00552 }
    00553
    00554 /*
    00555  * call-seq:
    00556  *   e.next   -> object
    00557  *
    00558  * Returns the next object in the enumerator, and move the internal
    00559  * position forward.  When the position reached at the end, StopIteration
    00560  * is raised.
    00561  *
    00562  *   a = [1,2,3]
    00563  *   e = a.to_enum
    00564  *   p e.next   #=> 1
    00565  *   p e.next   #=> 2
    00566  *   p e.next   #=> 3
    00567  *   p e.next   #raises StopIteration
    00568  *
    00569  * Note that enumeration sequence by next method does not affect other
    00570  * non-external enumeration methods, unless underlying iteration
    00571  * methods itself has side-effect, e.g. IO#each_line.
    00572  *
    00573  */
    00574
    00575 static VALUE
    00576 enumerator_next(VALUE obj)
    00577 {
    00578     VALUE vs = enumerator_next_values(obj);
    00579     return ary2sv(vs, 0);
    00580 }
    00581
    00582 static VALUE
    00583 enumerator_peek_values(VALUE obj)
    00584 {
    00585     struct enumerator *e = enumerator_ptr(obj);
    00586
    00587     if (e->lookahead == Qundef) {
    00588         e->lookahead = get_next_values(obj, e);
    00589     }
    00590     return e->lookahead;
    00591 }
    00592
    00593 /*
    00594  * call-seq:
    00595  *   e.peek_values   -> array
    00596  *
    00597  * Returns the next object as an array in the enumerator,
    00598  * but don't move the internal position forward.
    00599  * When the position reached at the end, StopIteration is raised.
    00600  *
    00601  *   o = Object.new
    00602  *   def o.each
    00603  *     yield
    00604  *     yield 1
    00605  *     yield 1, 2
    00606  *   end
    00607  *   e = o.to_enum
    00608  *   p e.peek_values    #=> []
    00609  *   e.next
    00610  *   p e.peek_values    #=> [1]
    00611  *   p e.peek_values    #=> [1]
    00612  *   e.next
    00613  *   p e.peek_values    #=> [1, 2]
    00614  *   e.next
    00615  *   p e.peek_values    # raises StopIteration
    00616  *
    00617  */
    00618
    00619 static VALUE
    00620 enumerator_peek_values_m(VALUE obj)
    00621 {
    00622     return rb_ary_dup(enumerator_peek_values(obj));
    00623 }
    00624
    00625 /*
    00626  * call-seq:
    00627  *   e.peek   -> object
    00628  *
    00629  * Returns the next object in the enumerator, but don't move the internal
    00630  * position forward.  When the position reached at the end, StopIteration
    00631  * is raised.
    00632  *
    00633  *   a = [1,2,3]
    00634  *   e = a.to_enum
    00635  *   p e.next   #=> 1
    00636  *   p e.peek   #=> 2
    00637  *   p e.peek   #=> 2
    00638  *   p e.peek   #=> 2
    00639  *   p e.next   #=> 2
    00640  *   p e.next   #=> 3
    00641  *   p e.next   #raises StopIteration
    00642  *
    00643  */
    00644
    00645 static VALUE
    00646 enumerator_peek(VALUE obj)
    00647 {
    00648     VALUE vs = enumerator_peek_values(obj);
    00649     return ary2sv(vs, 1);
    00650 }
    00651
    00652 /*
    00653  * call-seq:
    00654  *   e.feed obj   -> nil
    00655  *
    00656  * Set the value for the next yield in the enumerator returns.
    00657  *
    00658  * If the value is not set, the yield returns nil.
    00659  *
    00660  * This value is cleared after used.
    00661  *
    00662  *   o = Object.new
    00663  *   def o.each
    00664  *     # (2)
    00665  *     x = yield
    00666  *     p x          #=> "foo"
    00667  *     # (5)
    00668  *     x = yield
    00669  *     p x          #=> nil
    00670  *     # (7)
    00671  *     x = yield
    00672  *     # not reached
    00673  *     p x
    00674  *   end
    00675  *   e = o.to_enum
    00676  *   # (1)
    00677  *   e.next
    00678  *   # (3)
    00679  *   e.feed "foo"
    00680  *   # (4)
    00681  *   e.next
    00682  *   # (6)
    00683  *   e.next
    00684  *   # (8)
    00685  *
    00686  */
    00687
    00688 static VALUE
    00689 enumerator_feed(VALUE obj, VALUE v)
    00690 {
    00691     struct enumerator *e = enumerator_ptr(obj);
    00692
    00693     if (e->feedvalue != Qundef) {
    00694         rb_raise(rb_eTypeError, "feed value already set");
    00695     }
    00696     e->feedvalue = v;
    00697
    00698     return Qnil;
    00699 }
    00700
    00701 /*
    00702  * call-seq:
    00703  *   e.rewind   -> e
    00704  *
    00705  * Rewinds the enumeration sequence by the next method.
    00706  *
    00707  * If the enclosed object responds to a "rewind" method, it is called.
    00708  */
    00709
    00710 static VALUE
    00711 enumerator_rewind(VALUE obj)
    00712 {
    00713     struct enumerator *e = enumerator_ptr(obj);
    00714
    00715     rb_check_funcall(e->obj, id_rewind, 0, 0);
    00716
    00717     e->fib = 0;
    00718     e->dst = Qnil;
    00719     e->lookahead = Qundef;
    00720     e->feedvalue = Qundef;
    00721     e->stop_exc = Qfalse;
    00722     return obj;
    00723 }
    00724
    00725 static VALUE
    00726 inspect_enumerator(VALUE obj, VALUE dummy, int recur)
    00727 {
    00728     struct enumerator *e;
    00729     const char *cname;
    00730     VALUE eobj, str;
    00731     int tainted, untrusted;
    00732
    00733     TypedData_Get_Struct(obj, struct enumerator, &enumerator_data_type, e);
    00734
    00735     cname = rb_obj_classname(obj);
    00736
    00737     if (!e || e->obj == Qundef) {
    00738         return rb_sprintf("#<%s: uninitialized>", cname);
    00739     }
    00740
    00741     if (recur) {
    00742         str = rb_sprintf("#<%s: ...>", cname);
    00743         OBJ_TAINT(str);
    00744         return str;
    00745     }
    00746
    00747     eobj = e->obj;
    00748
    00749     tainted   = OBJ_TAINTED(eobj);
    00750     untrusted = OBJ_UNTRUSTED(eobj);
    00751
    00752     /* (1..100).each_cons(2) => "#<Enumerator: 1..100:each_cons(2)>" */
    00753     str = rb_sprintf("#<%s: ", cname);
    00754     rb_str_concat(str, rb_inspect(eobj));
    00755     rb_str_buf_cat2(str, ":");
    00756     rb_str_buf_cat2(str, rb_id2name(e->meth));
    00757
    00758     if (e->args) {
    00759         long   argc = RARRAY_LEN(e->args);
    00760         VALUE *argv = RARRAY_PTR(e->args);
    00761
    00762         rb_str_buf_cat2(str, "(");
    00763
    00764         while (argc--) {
    00765             VALUE arg = *argv++;
    00766
    00767             rb_str_concat(str, rb_inspect(arg));
    00768             rb_str_buf_cat2(str, argc > 0 ? ", " : ")");
    00769
    00770             if (OBJ_TAINTED(arg)) tainted = TRUE;
    00771             if (OBJ_UNTRUSTED(arg)) untrusted = TRUE;
    00772         }
    00773     }
    00774
    00775     rb_str_buf_cat2(str, ">");
    00776
    00777     if (tainted) OBJ_TAINT(str);
    00778     if (untrusted) OBJ_UNTRUST(str);
    00779     return str;
    00780 }
    00781
    00782 /*
    00783  * call-seq:
    00784  *   e.inspect  -> string
    00785  *
    00786  *  Create a printable version of <i>e</i>.
    00787  */
    00788
    00789 static VALUE
    00790 enumerator_inspect(VALUE obj)
    00791 {
    00792     return rb_exec_recursive(inspect_enumerator, obj, 0);
    00793 }
    00794
    00795 /*
    00796  * Yielder
    00797  */
    00798 static void
    00799 yielder_mark(void *p)
    00800 {
    00801     struct yielder *ptr = p;
    00802     rb_gc_mark(ptr->proc);
    00803 }
    00804
    00805 #define yielder_free RUBY_TYPED_DEFAULT_FREE
    00806
    00807 static size_t
    00808 yielder_memsize(const void *p)
    00809 {
    00810     return p ? sizeof(struct yielder) : 0;
    00811 }
    00812
    00813 static const rb_data_type_t yielder_data_type = {
    00814     "yielder",
    00815     yielder_mark,
    00816     yielder_free,
    00817     yielder_memsize,
    00818 };
    00819
    00820 static struct yielder *
    00821 yielder_ptr(VALUE obj)
    00822 {
    00823     struct yielder *ptr;
    00824
    00825     TypedData_Get_Struct(obj, struct yielder, &yielder_data_type, ptr);
    00826     if (!ptr || ptr->proc == Qundef) {
    00827         rb_raise(rb_eArgError, "uninitialized yielder");
    00828     }
    00829     return ptr;
    00830 }
    00831
    00832 /* :nodoc: */
    00833 static VALUE
    00834 yielder_allocate(VALUE klass)
    00835 {
    00836     struct yielder *ptr;
    00837     VALUE obj;
    00838
    00839     obj = TypedData_Make_Struct(klass, struct yielder, &yielder_data_type, ptr);
    00840     ptr->proc = Qundef;
    00841
    00842     return obj;
    00843 }
    00844
    00845 static VALUE
    00846 yielder_init(VALUE obj, VALUE proc)
    00847 {
    00848     struct yielder *ptr;
    00849
    00850     TypedData_Get_Struct(obj, struct yielder, &yielder_data_type, ptr);
    00851
    00852     if (!ptr) {
    00853         rb_raise(rb_eArgError, "unallocated yielder");
    00854     }
    00855
    00856     ptr->proc = proc;
    00857
    00858     return obj;
    00859 }
    00860
    00861 /* :nodoc: */
    00862 static VALUE
    00863 yielder_initialize(VALUE obj)
    00864 {
    00865     rb_need_block();
    00866
    00867     return yielder_init(obj, rb_block_proc());
    00868 }
    00869
    00870 /* :nodoc: */
    00871 static VALUE
    00872 yielder_yield(VALUE obj, VALUE args)
    00873 {
    00874     struct yielder *ptr = yielder_ptr(obj);
    00875
    00876     return rb_proc_call(ptr->proc, args);
    00877 }
    00878
    00879 /* :nodoc: */
    00880 static VALUE yielder_yield_push(VALUE obj, VALUE args)
    00881 {
    00882     yielder_yield(obj, args);
    00883     return obj;
    00884 }
    00885
    00886 static VALUE
    00887 yielder_yield_i(VALUE obj, VALUE memo, int argc, VALUE *argv)
    00888 {
    00889     return rb_yield_values2(argc, argv);
    00890 }
    00891
    00892 static VALUE
    00893 yielder_new(void)
    00894 {
    00895     return yielder_init(yielder_allocate(rb_cYielder), rb_proc_new(yielder_yield_i, 0));
    00896 }
    00897
    00898 /*
    00899  * Generator
    00900  */
    00901 static void
    00902 generator_mark(void *p)
    00903 {
    00904     struct generator *ptr = p;
    00905     rb_gc_mark(ptr->proc);
    00906 }
    00907
    00908 #define generator_free RUBY_TYPED_DEFAULT_FREE
    00909
    00910 static size_t
    00911 generator_memsize(const void *p)
    00912 {
    00913     return p ? sizeof(struct generator) : 0;
    00914 }
    00915
    00916 static const rb_data_type_t generator_data_type = {
    00917     "generator",
    00918     generator_mark,
    00919     generator_free,
    00920     generator_memsize,
    00921 };
    00922
    00923 static struct generator *
    00924 generator_ptr(VALUE obj)
    00925 {
    00926     struct generator *ptr;
    00927
    00928     TypedData_Get_Struct(obj, struct generator, &generator_data_type, ptr);
    00929     if (!ptr || ptr->proc == Qundef) {
    00930         rb_raise(rb_eArgError, "uninitialized generator");
    00931     }
    00932     return ptr;
    00933 }
    00934
    00935 /* :nodoc: */
    00936 static VALUE
    00937 generator_allocate(VALUE klass)
    00938 {
    00939     struct generator *ptr;
    00940     VALUE obj;
    00941
    00942     obj = TypedData_Make_Struct(klass, struct generator, &generator_data_type, ptr);
    00943     ptr->proc = Qundef;
    00944
    00945     return obj;
    00946 }
    00947
    00948 static VALUE
    00949 generator_init(VALUE obj, VALUE proc)
    00950 {
    00951     struct generator *ptr;
    00952
    00953     TypedData_Get_Struct(obj, struct generator, &generator_data_type, ptr);
    00954
    00955     if (!ptr) {
    00956         rb_raise(rb_eArgError, "unallocated generator");
    00957     }
    00958
    00959     ptr->proc = proc;
    00960
    00961     return obj;
    00962 }
    00963
    00964 VALUE rb_obj_is_proc(VALUE proc);
    00965
    00966 /* :nodoc: */
    00967 static VALUE
    00968 generator_initialize(int argc, VALUE *argv, VALUE obj)
    00969 {
    00970     VALUE proc;
    00971
    00972     if (argc == 0) {
    00973         rb_need_block();
    00974
    00975         proc = rb_block_proc();
    00976     } else {
    00977         rb_scan_args(argc, argv, "1", &proc);
    00978
    00979         if (!rb_obj_is_proc(proc))
    00980             rb_raise(rb_eTypeError,
    00981                      "wrong argument type %s (expected Proc)",
    00982                      rb_obj_classname(proc));
    00983
    00984         if (rb_block_given_p()) {
    00985             rb_warn("given block not used");
    00986         }
    00987     }
    00988
    00989     return generator_init(obj, proc);
    00990 }
    00991
    00992 /* :nodoc: */
    00993 static VALUE
    00994 generator_init_copy(VALUE obj, VALUE orig)
    00995 {
    00996     struct generator *ptr0, *ptr1;
    00997
    00998     ptr0 = generator_ptr(orig);
    00999
    01000     TypedData_Get_Struct(obj, struct generator, &generator_data_type, ptr1);
    01001
    01002     if (!ptr1) {
    01003         rb_raise(rb_eArgError, "unallocated generator");
    01004     }
    01005
    01006     ptr1->proc = ptr0->proc;
    01007
    01008     return obj;
    01009 }
    01010
    01011 /* :nodoc: */
    01012 static VALUE
    01013 generator_each(VALUE obj)
    01014 {
    01015     struct generator *ptr = generator_ptr(obj);
    01016     VALUE yielder;
    01017
    01018     yielder = yielder_new();
    01019
    01020     return rb_proc_call(ptr->proc, rb_ary_new3(1, yielder));
    01021 }
    01022
    01023 /*
    01024  *  Document-class: StopIteration
    01025  *
    01026  *  Raised to stop the iteration, in particular by Enumerator#next. It is
    01027  *  rescued by Kernel#loop.
    01028  *
    01029  *     loop do
    01030  *       puts "Hello"
    01031  *       raise StopIteration
    01032  *       puts "World"
    01033  *     end
    01034  *     puts "Done!"
    01035  *
    01036  *  <em>produces:</em>
    01037  *
    01038  *     Hello
    01039  *     Done!
    01040  */
    01041
    01042 /*
    01043  * call-seq:
    01044  *   stopiteration.result       -> value
    01045  *
    01046  * Returns the return value of the iterator.
    01047  *
    01048  *   o = Object.new
    01049  *   def o.each
    01050  *     yield 1
    01051  *     yield 2
    01052  *     yield 3
    01053  *     100
    01054  *   end
    01055  *   e = o.to_enum
    01056  *   p e.next                   #=> 1
    01057  *   p e.next                   #=> 2
    01058  *   p e.next                   #=> 3
    01059  *   begin
    01060  *     e.next
    01061  *   rescue StopIteration
    01062  *     p $!.result              #=> 100
    01063  *   end
    01064  *
    01065  */
    01066 static VALUE
    01067 stop_result(VALUE self)
    01068 {
    01069     return rb_attr_get(self, rb_intern("result"));
    01070 }
    01071
    01072 void
    01073 Init_Enumerator(void)
    01074 {
    01075     rb_define_method(rb_mKernel, "to_enum", obj_to_enum, -1);
    01076     rb_define_method(rb_mKernel, "enum_for", obj_to_enum, -1);
    01077
    01078     rb_cEnumerator = rb_define_class("Enumerator", rb_cObject);
    01079     rb_include_module(rb_cEnumerator, rb_mEnumerable);
    01080
    01081     rb_define_alloc_func(rb_cEnumerator, enumerator_allocate);
    01082     rb_define_method(rb_cEnumerator, "initialize", enumerator_initialize, -1);
    01083     rb_define_method(rb_cEnumerator, "initialize_copy", enumerator_init_copy, 1);
    01084     rb_define_method(rb_cEnumerator, "each", enumerator_each, 0);
    01085     rb_define_method(rb_cEnumerator, "each_with_index", enumerator_each_with_index, 0);
    01086     rb_define_method(rb_cEnumerator, "each_with_object", enumerator_with_object, 1);
    01087     rb_define_method(rb_cEnumerator, "with_index", enumerator_with_index, -1);
    01088     rb_define_method(rb_cEnumerator, "with_object", enumerator_with_object, 1);
    01089     rb_define_method(rb_cEnumerator, "next_values", enumerator_next_values, 0);
    01090     rb_define_method(rb_cEnumerator, "peek_values", enumerator_peek_values_m, 0);
    01091     rb_define_method(rb_cEnumerator, "next", enumerator_next, 0);
    01092     rb_define_method(rb_cEnumerator, "peek", enumerator_peek, 0);
    01093     rb_define_method(rb_cEnumerator, "feed", enumerator_feed, 1);
    01094     rb_define_method(rb_cEnumerator, "rewind", enumerator_rewind, 0);
    01095     rb_define_method(rb_cEnumerator, "inspect", enumerator_inspect, 0);
    01096
    01097     rb_eStopIteration = rb_define_class("StopIteration", rb_eIndexError);
    01098     rb_define_method(rb_eStopIteration, "result", stop_result, 0);
    01099
    01100     /* Generator */
    01101     rb_cGenerator = rb_define_class_under(rb_cEnumerator, "Generator", rb_cObject);
    01102     rb_include_module(rb_cGenerator, rb_mEnumerable);
    01103     rb_define_alloc_func(rb_cGenerator, generator_allocate);
    01104     rb_define_method(rb_cGenerator, "initialize", generator_initialize, -1);
    01105     rb_define_method(rb_cGenerator, "initialize_copy", generator_init_copy, 1);
    01106     rb_define_method(rb_cGenerator, "each", generator_each, 0);
    01107
    01108     /* Yielder */
    01109     rb_cYielder = rb_define_class_under(rb_cEnumerator, "Yielder", rb_cObject);
    01110     rb_define_alloc_func(rb_cYielder, yielder_allocate);
    01111     rb_define_method(rb_cYielder, "initialize", yielder_initialize, 0);
    01112     rb_define_method(rb_cYielder, "yield", yielder_yield, -2);
    01113     rb_define_method(rb_cYielder, "<<", yielder_yield_push, -2);
    01114
    01115     id_rewind = rb_intern("rewind");
    01116     id_each = rb_intern("each");
    01117     sym_each = ID2SYM(id_each);
    01118
    01119     rb_provide("enumerator.so");        /* for backward compatibility */
    01120 }
    01121