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