enumerator.c

Go to the documentation of this file.
00001 /************************************************
00002 
00003   enumerator.c - provides Enumerator class
00004 
00005   $Author: nagachika $
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 46677 2014-07-03 15:46:17Z nagachika $
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  *
00036  *   enumerator.each_with_object("foo") do |item, obj|
00037  *     puts "#{obj}: #{item}"
00038  *   end
00039  *
00040  *   # foo: one
00041  *   # foo: two
00042  *   # foo: three
00043  *
00044  *   enum_with_obj = enumerator.each_with_object("foo")
00045  *   puts enum_with_obj.class # => Enumerator
00046  *
00047  *   enum_with_obj.each do |item, obj|
00048  *     puts "#{obj}: #{item}"
00049  *   end
00050  *
00051  *   # foo: one
00052  *   # foo: two
00053  *   # foo: three
00054  *
00055  * This allows you to chain Enumerators together.  For example, you
00056  * can map a list's elements to strings containing the index
00057  * and the element as a string via:
00058  *
00059  *   puts %w[foo bar baz].map.with_index { |w, i| "#{i}:#{w}" }
00060  *   # => ["0:foo", "1:bar", "2:baz"]
00061  *
00062  * An Enumerator can also be used as an external iterator.
00063  * For example, Enumerator#next returns the next value of the iterator
00064  * or raises StopIteration if the Enumerator is at the end.
00065  *
00066  *   e = [1,2,3].each   # returns an enumerator object.
00067  *   puts e.next   # => 1
00068  *   puts e.next   # => 2
00069  *   puts e.next   # => 3
00070  *   puts e.next   # raises StopIteration
00071  *
00072  * You can use this to implement an internal iterator as follows:
00073  *
00074  *   def ext_each(e)
00075  *     while true
00076  *       begin
00077  *         vs = e.next_values
00078  *       rescue StopIteration
00079  *         return $!.result
00080  *       end
00081  *       y = yield(*vs)
00082  *       e.feed y
00083  *     end
00084  *   end
00085  *
00086  *   o = Object.new
00087  *
00088  *   def o.each
00089  *     puts yield
00090  *     puts yield(1)
00091  *     puts yield(1, 2)
00092  *     3
00093  *   end
00094  *
00095  *   # use o.each as an internal iterator directly.
00096  *   puts o.each {|*x| puts x; [:b, *x] }
00097  *   # => [], [:b], [1], [:b, 1], [1, 2], [:b, 1, 2], 3
00098  *
00099  *   # convert o.each to an external iterator for
00100  *   # implementing an internal iterator.
00101  *   puts ext_each(o.to_enum) {|*x| puts x; [:b, *x] }
00102  *   # => [], [:b], [1], [:b, 1], [1, 2], [:b, 1, 2], 3
00103  *
00104  */
00105 VALUE rb_cEnumerator;
00106 VALUE rb_cLazy;
00107 static ID id_rewind, id_each, id_new, id_initialize, id_yield, id_call, id_size, id_to_enum;
00108 static ID id_eqq, id_next, id_result, id_lazy, id_receiver, id_arguments, id_memo, id_method, id_force;
00109 static VALUE sym_each, sym_cycle;
00110 
00111 VALUE rb_eStopIteration;
00112 
00113 struct enumerator {
00114     VALUE obj;
00115     ID    meth;
00116     VALUE args;
00117     VALUE fib;
00118     VALUE dst;
00119     VALUE lookahead;
00120     VALUE feedvalue;
00121     VALUE stop_exc;
00122     VALUE size;
00123     rb_enumerator_size_func *size_fn;
00124 };
00125 
00126 static VALUE rb_cGenerator, rb_cYielder;
00127 
00128 struct generator {
00129     VALUE proc;
00130 };
00131 
00132 struct yielder {
00133     VALUE proc;
00134 };
00135 
00136 static VALUE generator_allocate(VALUE klass);
00137 static VALUE generator_init(VALUE obj, VALUE proc);
00138 
00139 /*
00140  * Enumerator
00141  */
00142 static void
00143 enumerator_mark(void *p)
00144 {
00145     struct enumerator *ptr = p;
00146     rb_gc_mark(ptr->obj);
00147     rb_gc_mark(ptr->args);
00148     rb_gc_mark(ptr->fib);
00149     rb_gc_mark(ptr->dst);
00150     rb_gc_mark(ptr->lookahead);
00151     rb_gc_mark(ptr->feedvalue);
00152     rb_gc_mark(ptr->stop_exc);
00153     rb_gc_mark(ptr->size);
00154 }
00155 
00156 #define enumerator_free RUBY_TYPED_DEFAULT_FREE
00157 
00158 static size_t
00159 enumerator_memsize(const void *p)
00160 {
00161     return p ? sizeof(struct enumerator) : 0;
00162 }
00163 
00164 static const rb_data_type_t enumerator_data_type = {
00165     "enumerator",
00166     {
00167         enumerator_mark,
00168         enumerator_free,
00169         enumerator_memsize,
00170     },
00171     NULL, NULL, RUBY_TYPED_FREE_IMMEDIATELY
00172 };
00173 
00174 static struct enumerator *
00175 enumerator_ptr(VALUE obj)
00176 {
00177     struct enumerator *ptr;
00178 
00179     TypedData_Get_Struct(obj, struct enumerator, &enumerator_data_type, ptr);
00180     if (!ptr || ptr->obj == Qundef) {
00181         rb_raise(rb_eArgError, "uninitialized enumerator");
00182     }
00183     return ptr;
00184 }
00185 
00186 /*
00187  * call-seq:
00188  *   obj.to_enum(method = :each, *args)                 -> enum
00189  *   obj.enum_for(method = :each, *args)                -> enum
00190  *   obj.to_enum(method = :each, *args) {|*args| block} -> enum
00191  *   obj.enum_for(method = :each, *args){|*args| block} -> enum
00192  *
00193  * Creates a new Enumerator which will enumerate by calling +method+ on
00194  * +obj+, passing +args+ if any.
00195  *
00196  * If a block is given, it will be used to calculate the size of
00197  * the enumerator without the need to iterate it (see Enumerator#size).
00198  *
00199  * === Examples
00200  *
00201  *   str = "xyz"
00202  *
00203  *   enum = str.enum_for(:each_byte)
00204  *   enum.each { |b| puts b }
00205  *   # => 120
00206  *   # => 121
00207  *   # => 122
00208  *
00209  *   # protect an array from being modified by some_method
00210  *   a = [1, 2, 3]
00211  *   some_method(a.to_enum)
00212  *
00213  * It is typical to call to_enum when defining methods for
00214  * a generic Enumerable, in case no block is passed.
00215  *
00216  * Here is such an example, with parameter passing and a sizing block:
00217  *
00218  *   module Enumerable
00219  *     # a generic method to repeat the values of any enumerable
00220  *     def repeat(n)
00221  *       raise ArgumentError, "#{n} is negative!" if n < 0
00222  *       unless block_given?
00223  *         return to_enum(__method__, n) do # __method__ is :repeat here
00224  *           sz = size     # Call size and multiply by n...
00225  *           sz * n if sz  # but return nil if size itself is nil
00226  *         end
00227  *       end
00228  *       each do |*val|
00229  *         n.times { yield *val }
00230  *       end
00231  *     end
00232  *   end
00233  *
00234  *   %i[hello world].repeat(2) { |w| puts w }
00235  *     # => Prints 'hello', 'hello', 'world', 'world'
00236  *   enum = (1..14).repeat(3)
00237  *     # => returns an Enumerator when called without a block
00238  *   enum.first(4) # => [1, 1, 1, 2]
00239  *   enum.size # => 42
00240  */
00241 static VALUE
00242 obj_to_enum(int argc, VALUE *argv, VALUE obj)
00243 {
00244     VALUE enumerator, meth = sym_each;
00245 
00246     if (argc > 0) {
00247         --argc;
00248         meth = *argv++;
00249     }
00250     enumerator = rb_enumeratorize_with_size(obj, meth, argc, argv, 0);
00251     if (rb_block_given_p()) {
00252         enumerator_ptr(enumerator)->size = rb_block_proc();
00253     }
00254     return enumerator;
00255 }
00256 
00257 static VALUE
00258 enumerator_allocate(VALUE klass)
00259 {
00260     struct enumerator *ptr;
00261     VALUE enum_obj;
00262 
00263     enum_obj = TypedData_Make_Struct(klass, struct enumerator, &enumerator_data_type, ptr);
00264     ptr->obj = Qundef;
00265 
00266     return enum_obj;
00267 }
00268 
00269 static VALUE
00270 enumerator_init(VALUE enum_obj, VALUE obj, VALUE meth, int argc, VALUE *argv, rb_enumerator_size_func *size_fn, VALUE size)
00271 {
00272     struct enumerator *ptr;
00273 
00274     rb_check_frozen(enum_obj);
00275     TypedData_Get_Struct(enum_obj, struct enumerator, &enumerator_data_type, ptr);
00276 
00277     if (!ptr) {
00278         rb_raise(rb_eArgError, "unallocated enumerator");
00279     }
00280 
00281     ptr->obj  = obj;
00282     ptr->meth = rb_to_id(meth);
00283     if (argc) ptr->args = rb_ary_new4(argc, argv);
00284     ptr->fib = 0;
00285     ptr->dst = Qnil;
00286     ptr->lookahead = Qundef;
00287     ptr->feedvalue = Qundef;
00288     ptr->stop_exc = Qfalse;
00289     ptr->size = size;
00290     ptr->size_fn = size_fn;
00291 
00292     return enum_obj;
00293 }
00294 
00295 /*
00296  * call-seq:
00297  *   Enumerator.new(size = nil) { |yielder| ... }
00298  *   Enumerator.new(obj, method = :each, *args)
00299  *
00300  * Creates a new Enumerator object, which can be used as an
00301  * Enumerable.
00302  *
00303  * In the first form, iteration is defined by the given block, in
00304  * which a "yielder" object, given as block parameter, can be used to
00305  * yield a value by calling the +yield+ method (aliased as +<<+):
00306  *
00307  *   fib = Enumerator.new do |y|
00308  *     a = b = 1
00309  *     loop do
00310  *       y << a
00311  *       a, b = b, a + b
00312  *     end
00313  *   end
00314  *
00315  *   p fib.take(10) # => [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
00316  *
00317  * The optional parameter can be used to specify how to calculate the size
00318  * in a lazy fashion (see Enumerator#size). It can either be a value or
00319  * a callable object.
00320  *
00321  * In the second, deprecated, form, a generated Enumerator iterates over the
00322  * given object using the given method with the given arguments passed.
00323  *
00324  * Use of this form is discouraged.  Use Kernel#enum_for or Kernel#to_enum
00325  * instead.
00326  *
00327  *   e = Enumerator.new(ObjectSpace, :each_object)
00328  *       #-> ObjectSpace.enum_for(:each_object)
00329  *
00330  *   e.select { |obj| obj.is_a?(Class) }  #=> array of all classes
00331  *
00332  */
00333 static VALUE
00334 enumerator_initialize(int argc, VALUE *argv, VALUE obj)
00335 {
00336     VALUE recv, meth = sym_each;
00337     VALUE size = Qnil;
00338 
00339     if (rb_block_given_p()) {
00340         rb_check_arity(argc, 0, 1);
00341         recv = generator_init(generator_allocate(rb_cGenerator), rb_block_proc());
00342         if (argc) {
00343             if (NIL_P(argv[0]) || rb_respond_to(argv[0], id_call) ||
00344                 (RB_TYPE_P(argv[0], T_FLOAT) && RFLOAT_VALUE(argv[0]) == INFINITY)) {
00345                 size = argv[0];
00346             }
00347             else {
00348                 size = rb_to_int(argv[0]);
00349             }
00350             argc = 0;
00351         }
00352     }
00353     else {
00354         rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS);
00355         rb_warn("Enumerator.new without a block is deprecated; use Object#to_enum");
00356         recv = *argv++;
00357         if (--argc) {
00358             meth = *argv++;
00359             --argc;
00360         }
00361     }
00362 
00363     return enumerator_init(obj, recv, meth, argc, argv, 0, size);
00364 }
00365 
00366 /* :nodoc: */
00367 static VALUE
00368 enumerator_init_copy(VALUE obj, VALUE orig)
00369 {
00370     struct enumerator *ptr0, *ptr1;
00371 
00372     if (!OBJ_INIT_COPY(obj, orig)) return obj;
00373     ptr0 = enumerator_ptr(orig);
00374     if (ptr0->fib) {
00375         /* Fibers cannot be copied */
00376         rb_raise(rb_eTypeError, "can't copy execution context");
00377     }
00378 
00379     TypedData_Get_Struct(obj, struct enumerator, &enumerator_data_type, ptr1);
00380 
00381     if (!ptr1) {
00382         rb_raise(rb_eArgError, "unallocated enumerator");
00383     }
00384 
00385     ptr1->obj  = ptr0->obj;
00386     ptr1->meth = ptr0->meth;
00387     ptr1->args = ptr0->args;
00388     ptr1->fib  = 0;
00389     ptr1->lookahead  = Qundef;
00390     ptr1->feedvalue  = Qundef;
00391     ptr1->size  = ptr0->size;
00392     ptr1->size_fn  = ptr0->size_fn;
00393 
00394     return obj;
00395 }
00396 
00397 /*
00398  * For backwards compatibility; use rb_enumeratorize_with_size
00399  */
00400 VALUE
00401 rb_enumeratorize(VALUE obj, VALUE meth, int argc, VALUE *argv)
00402 {
00403     return rb_enumeratorize_with_size(obj, meth, argc, argv, 0);
00404 }
00405 
00406 static VALUE
00407 lazy_to_enum_i(VALUE self, VALUE meth, int argc, VALUE *argv, rb_enumerator_size_func *size_fn);
00408 
00409 VALUE
00410 rb_enumeratorize_with_size(VALUE obj, VALUE meth, int argc, VALUE *argv, rb_enumerator_size_func *size_fn)
00411 {
00412     /* Similar effect as calling obj.to_enum, i.e. dispatching to either
00413        Kernel#to_enum vs Lazy#to_enum */
00414     if (RTEST(rb_obj_is_kind_of(obj, rb_cLazy)))
00415         return lazy_to_enum_i(obj, meth, argc, argv, size_fn);
00416     else
00417         return enumerator_init(enumerator_allocate(rb_cEnumerator),
00418                                obj, meth, argc, argv, size_fn, Qnil);
00419 }
00420 
00421 static VALUE
00422 enumerator_block_call(VALUE obj, rb_block_call_func *func, VALUE arg)
00423 {
00424     int argc = 0;
00425     VALUE *argv = 0;
00426     const struct enumerator *e = enumerator_ptr(obj);
00427     ID meth = e->meth;
00428 
00429     if (e->args) {
00430         argc = RARRAY_LENINT(e->args);
00431         argv = RARRAY_PTR(e->args);
00432     }
00433     return rb_block_call(e->obj, meth, argc, argv, func, arg);
00434 }
00435 
00436 /*
00437  * call-seq:
00438  *   enum.each { |elm| block }                    -> obj
00439  *   enum.each                                    -> enum
00440  *   enum.each(*appending_args) { |elm| block }   -> obj
00441  *   enum.each(*appending_args)                   -> an_enumerator
00442  *
00443  * Iterates over the block according to how this Enumerator was constructed.
00444  * If no block and no arguments are given, returns self.
00445  *
00446  * === Examples
00447  *
00448  *   "Hello, world!".scan(/\w+/)                     #=> ["Hello", "world"]
00449  *   "Hello, world!".to_enum(:scan, /\w+/).to_a      #=> ["Hello", "world"]
00450  *   "Hello, world!".to_enum(:scan).each(/\w+/).to_a #=> ["Hello", "world"]
00451  *
00452  *   obj = Object.new
00453  *
00454  *   def obj.each_arg(a, b=:b, *rest)
00455  *     yield a
00456  *     yield b
00457  *     yield rest
00458  *     :method_returned
00459  *   end
00460  *
00461  *   enum = obj.to_enum :each_arg, :a, :x
00462  *
00463  *   enum.each.to_a                  #=> [:a, :x, []]
00464  *   enum.each.equal?(enum)          #=> true
00465  *   enum.each { |elm| elm }         #=> :method_returned
00466  *
00467  *   enum.each(:y, :z).to_a          #=> [:a, :x, [:y, :z]]
00468  *   enum.each(:y, :z).equal?(enum)  #=> false
00469  *   enum.each(:y, :z) { |elm| elm } #=> :method_returned
00470  *
00471  */
00472 static VALUE
00473 enumerator_each(int argc, VALUE *argv, VALUE obj)
00474 {
00475     if (argc > 0) {
00476         struct enumerator *e = enumerator_ptr(obj = rb_obj_dup(obj));
00477         VALUE args = e->args;
00478         if (args) {
00479 #if SIZEOF_INT < SIZEOF_LONG
00480             /* check int range overflow */
00481             rb_long2int(RARRAY_LEN(args) + argc);
00482 #endif
00483             args = rb_ary_dup(args);
00484             rb_ary_cat(args, argv, argc);
00485         }
00486         else {
00487             args = rb_ary_new4(argc, argv);
00488         }
00489         e->args = args;
00490     }
00491     if (!rb_block_given_p()) return obj;
00492     return enumerator_block_call(obj, 0, obj);
00493 }
00494 
00495 static VALUE
00496 enumerator_with_index_i(RB_BLOCK_CALL_FUNC_ARGLIST(val, m))
00497 {
00498     NODE *memo = (NODE *)m;
00499     VALUE idx = memo->u1.value;
00500     memo->u1.value = rb_int_succ(idx);
00501 
00502     if (argc <= 1)
00503         return rb_yield_values(2, val, idx);
00504 
00505     return rb_yield_values(2, rb_ary_new4(argc, argv), idx);
00506 }
00507 
00508 static VALUE
00509 enumerator_size(VALUE obj);
00510 
00511 static VALUE
00512 enumerator_enum_size(VALUE obj, VALUE args, VALUE eobj)
00513 {
00514     return enumerator_size(obj);
00515 }
00516 
00517 /*
00518  * call-seq:
00519  *   e.with_index(offset = 0) {|(*args), idx| ... }
00520  *   e.with_index(offset = 0)
00521  *
00522  * Iterates the given block for each element with an index, which
00523  * starts from +offset+.  If no block is given, returns a new Enumerator
00524  * that includes the index, starting from +offset+
00525  *
00526  * +offset+:: the starting index to use
00527  *
00528  */
00529 static VALUE
00530 enumerator_with_index(int argc, VALUE *argv, VALUE obj)
00531 {
00532     VALUE memo;
00533 
00534     rb_scan_args(argc, argv, "01", &memo);
00535     RETURN_SIZED_ENUMERATOR(obj, argc, argv, enumerator_enum_size);
00536     if (NIL_P(memo))
00537         memo = INT2FIX(0);
00538     else
00539         memo = rb_to_int(memo);
00540     return enumerator_block_call(obj, enumerator_with_index_i, (VALUE)NEW_MEMO(memo, 0, 0));
00541 }
00542 
00543 /*
00544  * call-seq:
00545  *   e.each_with_index {|(*args), idx| ... }
00546  *   e.each_with_index
00547  *
00548  * Same as Enumerator#with_index(0), i.e. there is no starting offset.
00549  *
00550  * If no block is given, a new Enumerator is returned that includes the index.
00551  *
00552  */
00553 static VALUE
00554 enumerator_each_with_index(VALUE obj)
00555 {
00556     return enumerator_with_index(0, NULL, obj);
00557 }
00558 
00559 static VALUE
00560 enumerator_with_object_i(RB_BLOCK_CALL_FUNC_ARGLIST(val, memo))
00561 {
00562     if (argc <= 1)
00563         return rb_yield_values(2, val, memo);
00564 
00565     return rb_yield_values(2, rb_ary_new4(argc, argv), memo);
00566 }
00567 
00568 /*
00569  * call-seq:
00570  *   e.each_with_object(obj) {|(*args), obj| ... }
00571  *   e.each_with_object(obj)
00572  *   e.with_object(obj) {|(*args), obj| ... }
00573  *   e.with_object(obj)
00574  *
00575  * Iterates the given block for each element with an arbitrary object, +obj+,
00576  * and returns +obj+
00577  *
00578  * If no block is given, returns a new Enumerator.
00579  *
00580  * === Example
00581  *
00582  *   to_three = Enumerator.new do |y|
00583  *     3.times do |x|
00584  *       y << x
00585  *     end
00586  *   end
00587  *
00588  *   to_three_with_string = to_three.with_object("foo")
00589  *   to_three_with_string.each do |x,string|
00590  *     puts "#{string}: #{x}"
00591  *   end
00592  *
00593  *   # => foo:0
00594  *   # => foo:1
00595  *   # => foo:2
00596  */
00597 static VALUE
00598 enumerator_with_object(VALUE obj, VALUE memo)
00599 {
00600     RETURN_SIZED_ENUMERATOR(obj, 1, &memo, enumerator_enum_size);
00601     enumerator_block_call(obj, enumerator_with_object_i, memo);
00602 
00603     return memo;
00604 }
00605 
00606 static VALUE
00607 next_ii(RB_BLOCK_CALL_FUNC_ARGLIST(i, obj))
00608 {
00609     struct enumerator *e = enumerator_ptr(obj);
00610     VALUE feedvalue = Qnil;
00611     VALUE args = rb_ary_new4(argc, argv);
00612     rb_fiber_yield(1, &args);
00613     if (e->feedvalue != Qundef) {
00614         feedvalue = e->feedvalue;
00615         e->feedvalue = Qundef;
00616     }
00617     return feedvalue;
00618 }
00619 
00620 static VALUE
00621 next_i(VALUE curr, VALUE obj)
00622 {
00623     struct enumerator *e = enumerator_ptr(obj);
00624     VALUE nil = Qnil;
00625     VALUE result;
00626 
00627     result = rb_block_call(obj, id_each, 0, 0, next_ii, obj);
00628     e->stop_exc = rb_exc_new2(rb_eStopIteration, "iteration reached an end");
00629     rb_ivar_set(e->stop_exc, id_result, result);
00630     return rb_fiber_yield(1, &nil);
00631 }
00632 
00633 static void
00634 next_init(VALUE obj, struct enumerator *e)
00635 {
00636     VALUE curr = rb_fiber_current();
00637     e->dst = curr;
00638     e->fib = rb_fiber_new(next_i, obj);
00639     e->lookahead = Qundef;
00640 }
00641 
00642 static VALUE
00643 get_next_values(VALUE obj, struct enumerator *e)
00644 {
00645     VALUE curr, vs;
00646 
00647     if (e->stop_exc)
00648         rb_exc_raise(e->stop_exc);
00649 
00650     curr = rb_fiber_current();
00651 
00652     if (!e->fib || !rb_fiber_alive_p(e->fib)) {
00653         next_init(obj, e);
00654     }
00655 
00656     vs = rb_fiber_resume(e->fib, 1, &curr);
00657     if (e->stop_exc) {
00658         e->fib = 0;
00659         e->dst = Qnil;
00660         e->lookahead = Qundef;
00661         e->feedvalue = Qundef;
00662         rb_exc_raise(e->stop_exc);
00663     }
00664     return vs;
00665 }
00666 
00667 /*
00668  * call-seq:
00669  *   e.next_values   -> array
00670  *
00671  * Returns the next object as an array in the enumerator, and move the
00672  * internal position forward.  When the position reached at the end,
00673  * StopIteration is raised.
00674  *
00675  * This method can be used to distinguish <code>yield</code> and <code>yield
00676  * nil</code>.
00677  *
00678  * === Example
00679  *
00680  *   o = Object.new
00681  *   def o.each
00682  *     yield
00683  *     yield 1
00684  *     yield 1, 2
00685  *     yield nil
00686  *     yield [1, 2]
00687  *   end
00688  *   e = o.to_enum
00689  *   p e.next_values
00690  *   p e.next_values
00691  *   p e.next_values
00692  *   p e.next_values
00693  *   p e.next_values
00694  *   e = o.to_enum
00695  *   p e.next
00696  *   p e.next
00697  *   p e.next
00698  *   p e.next
00699  *   p e.next
00700  *
00701  *   ## yield args       next_values      next
00702  *   #  yield            []               nil
00703  *   #  yield 1          [1]              1
00704  *   #  yield 1, 2       [1, 2]           [1, 2]
00705  *   #  yield nil        [nil]            nil
00706  *   #  yield [1, 2]     [[1, 2]]         [1, 2]
00707  *
00708  * Note that +next_values+ does not affect other non-external enumeration
00709  * methods unless underlying iteration method itself has side-effect, e.g.
00710  * IO#each_line.
00711  *
00712  */
00713 
00714 static VALUE
00715 enumerator_next_values(VALUE obj)
00716 {
00717     struct enumerator *e = enumerator_ptr(obj);
00718     VALUE vs;
00719 
00720     if (e->lookahead != Qundef) {
00721         vs = e->lookahead;
00722         e->lookahead = Qundef;
00723         return vs;
00724     }
00725 
00726     return get_next_values(obj, e);
00727 }
00728 
00729 static VALUE
00730 ary2sv(VALUE args, int dup)
00731 {
00732     if (!RB_TYPE_P(args, T_ARRAY))
00733         return args;
00734 
00735     switch (RARRAY_LEN(args)) {
00736       case 0:
00737         return Qnil;
00738 
00739       case 1:
00740         return RARRAY_AREF(args, 0);
00741 
00742       default:
00743         if (dup)
00744             return rb_ary_dup(args);
00745         return args;
00746     }
00747 }
00748 
00749 /*
00750  * call-seq:
00751  *   e.next   -> object
00752  *
00753  * Returns the next object in the enumerator, and move the internal position
00754  * forward.  When the position reached at the end, StopIteration is raised.
00755  *
00756  * === Example
00757  *
00758  *   a = [1,2,3]
00759  *   e = a.to_enum
00760  *   p e.next   #=> 1
00761  *   p e.next   #=> 2
00762  *   p e.next   #=> 3
00763  *   p e.next   #raises StopIteration
00764  *
00765  * Note that enumeration sequence by +next+ does not affect other non-external
00766  * enumeration methods, unless the underlying iteration methods itself has
00767  * side-effect, e.g. IO#each_line.
00768  *
00769  */
00770 
00771 static VALUE
00772 enumerator_next(VALUE obj)
00773 {
00774     VALUE vs = enumerator_next_values(obj);
00775     return ary2sv(vs, 0);
00776 }
00777 
00778 static VALUE
00779 enumerator_peek_values(VALUE obj)
00780 {
00781     struct enumerator *e = enumerator_ptr(obj);
00782 
00783     if (e->lookahead == Qundef) {
00784         e->lookahead = get_next_values(obj, e);
00785     }
00786     return e->lookahead;
00787 }
00788 
00789 /*
00790  * call-seq:
00791  *   e.peek_values   -> array
00792  *
00793  * Returns the next object as an array, similar to Enumerator#next_values, but
00794  * doesn't move the internal position forward.  If the position is already at
00795  * the end, StopIteration is raised.
00796  *
00797  * === Example
00798  *
00799  *   o = Object.new
00800  *   def o.each
00801  *     yield
00802  *     yield 1
00803  *     yield 1, 2
00804  *   end
00805  *   e = o.to_enum
00806  *   p e.peek_values    #=> []
00807  *   e.next
00808  *   p e.peek_values    #=> [1]
00809  *   p e.peek_values    #=> [1]
00810  *   e.next
00811  *   p e.peek_values    #=> [1, 2]
00812  *   e.next
00813  *   p e.peek_values    # raises StopIteration
00814  *
00815  */
00816 
00817 static VALUE
00818 enumerator_peek_values_m(VALUE obj)
00819 {
00820     return rb_ary_dup(enumerator_peek_values(obj));
00821 }
00822 
00823 /*
00824  * call-seq:
00825  *   e.peek   -> object
00826  *
00827  * Returns the next object in the enumerator, but doesn't move the internal
00828  * position forward.  If the position is already at the end, StopIteration
00829  * is raised.
00830  *
00831  * === Example
00832  *
00833  *   a = [1,2,3]
00834  *   e = a.to_enum
00835  *   p e.next   #=> 1
00836  *   p e.peek   #=> 2
00837  *   p e.peek   #=> 2
00838  *   p e.peek   #=> 2
00839  *   p e.next   #=> 2
00840  *   p e.next   #=> 3
00841  *   p e.peek   #raises StopIteration
00842  *
00843  */
00844 
00845 static VALUE
00846 enumerator_peek(VALUE obj)
00847 {
00848     VALUE vs = enumerator_peek_values(obj);
00849     return ary2sv(vs, 1);
00850 }
00851 
00852 /*
00853  * call-seq:
00854  *   e.feed obj   -> nil
00855  *
00856  * Sets the value to be returned by the next yield inside +e+.
00857  *
00858  * If the value is not set, the yield returns nil.
00859  *
00860  * This value is cleared after being yielded.
00861  *
00862  *   # Array#map passes the array's elements to "yield" and collects the
00863  *   # results of "yield" as an array.
00864  *   # Following example shows that "next" returns the passed elements and
00865  *   # values passed to "feed" are collected as an array which can be
00866  *   # obtained by StopIteration#result.
00867  *   e = [1,2,3].map
00868  *   p e.next           #=> 1
00869  *   e.feed "a"
00870  *   p e.next           #=> 2
00871  *   e.feed "b"
00872  *   p e.next           #=> 3
00873  *   e.feed "c"
00874  *   begin
00875  *     e.next
00876  *   rescue StopIteration
00877  *     p $!.result      #=> ["a", "b", "c"]
00878  *   end
00879  *
00880  *   o = Object.new
00881  *   def o.each
00882  *     x = yield         # (2) blocks
00883  *     p x               # (5) => "foo"
00884  *     x = yield         # (6) blocks
00885  *     p x               # (8) => nil
00886  *     x = yield         # (9) blocks
00887  *     p x               # not reached w/o another e.next
00888  *   end
00889  *
00890  *   e = o.to_enum
00891  *   e.next              # (1)
00892  *   e.feed "foo"        # (3)
00893  *   e.next              # (4)
00894  *   e.next              # (7)
00895  *                       # (10)
00896  */
00897 
00898 static VALUE
00899 enumerator_feed(VALUE obj, VALUE v)
00900 {
00901     struct enumerator *e = enumerator_ptr(obj);
00902 
00903     if (e->feedvalue != Qundef) {
00904         rb_raise(rb_eTypeError, "feed value already set");
00905     }
00906     e->feedvalue = v;
00907 
00908     return Qnil;
00909 }
00910 
00911 /*
00912  * call-seq:
00913  *   e.rewind   -> e
00914  *
00915  * Rewinds the enumeration sequence to the beginning.
00916  *
00917  * If the enclosed object responds to a "rewind" method, it is called.
00918  */
00919 
00920 static VALUE
00921 enumerator_rewind(VALUE obj)
00922 {
00923     struct enumerator *e = enumerator_ptr(obj);
00924 
00925     rb_check_funcall(e->obj, id_rewind, 0, 0);
00926 
00927     e->fib = 0;
00928     e->dst = Qnil;
00929     e->lookahead = Qundef;
00930     e->feedvalue = Qundef;
00931     e->stop_exc = Qfalse;
00932     return obj;
00933 }
00934 
00935 static VALUE append_method(VALUE obj, VALUE str, ID default_method, VALUE default_args);
00936 
00937 static VALUE
00938 inspect_enumerator(VALUE obj, VALUE dummy, int recur)
00939 {
00940     struct enumerator *e;
00941     VALUE eobj, str, cname;
00942 
00943     TypedData_Get_Struct(obj, struct enumerator, &enumerator_data_type, e);
00944 
00945     cname = rb_obj_class(obj);
00946 
00947     if (!e || e->obj == Qundef) {
00948         return rb_sprintf("#<%"PRIsVALUE": uninitialized>", rb_class_path(cname));
00949     }
00950 
00951     if (recur) {
00952         str = rb_sprintf("#<%"PRIsVALUE": ...>", rb_class_path(cname));
00953         OBJ_TAINT(str);
00954         return str;
00955     }
00956 
00957     eobj = rb_attr_get(obj, id_receiver);
00958     if (NIL_P(eobj)) {
00959         eobj = e->obj;
00960     }
00961 
00962     /* (1..100).each_cons(2) => "#<Enumerator: 1..100:each_cons(2)>" */
00963     str = rb_sprintf("#<%"PRIsVALUE": %+"PRIsVALUE, rb_class_path(cname), eobj);
00964     append_method(obj, str, e->meth, e->args);
00965 
00966     rb_str_buf_cat2(str, ">");
00967 
00968     return str;
00969 }
00970 
00971 static VALUE
00972 append_method(VALUE obj, VALUE str, ID default_method, VALUE default_args)
00973 {
00974     VALUE method, eargs;
00975 
00976     method = rb_attr_get(obj, id_method);
00977     if (method != Qfalse) {
00978         ID mid = default_method;
00979         if (!NIL_P(method)) {
00980             Check_Type(method, T_SYMBOL);
00981             mid = SYM2ID(method);
00982         }
00983         rb_str_buf_cat2(str, ":");
00984         rb_str_buf_append(str, rb_id2str(mid));
00985     }
00986 
00987     eargs = rb_attr_get(obj, id_arguments);
00988     if (NIL_P(eargs)) {
00989         eargs = default_args;
00990     }
00991     if (eargs != Qfalse) {
00992         long   argc = RARRAY_LEN(eargs);
00993         const VALUE *argv = RARRAY_CONST_PTR(eargs); /* WB: no new reference */
00994 
00995         if (argc > 0) {
00996             rb_str_buf_cat2(str, "(");
00997 
00998             while (argc--) {
00999                 VALUE arg = *argv++;
01000 
01001                 rb_str_append(str, rb_inspect(arg));
01002                 rb_str_buf_cat2(str, argc > 0 ? ", " : ")");
01003                 OBJ_INFECT(str, arg);
01004             }
01005         }
01006     }
01007 
01008     return str;
01009 }
01010 
01011 /*
01012  * call-seq:
01013  *   e.inspect  -> string
01014  *
01015  * Creates a printable version of <i>e</i>.
01016  */
01017 
01018 static VALUE
01019 enumerator_inspect(VALUE obj)
01020 {
01021     return rb_exec_recursive(inspect_enumerator, obj, 0);
01022 }
01023 
01024 /*
01025  * call-seq:
01026  *   e.size          -> int, Float::INFINITY or nil
01027  *
01028  * Returns the size of the enumerator, or +nil+ if it can't be calculated lazily.
01029  *
01030  *   (1..100).to_a.permutation(4).size # => 94109400
01031  *   loop.size # => Float::INFINITY
01032  *   (1..100).drop_while.size # => nil
01033  */
01034 
01035 static VALUE
01036 enumerator_size(VALUE obj)
01037 {
01038     struct enumerator *e = enumerator_ptr(obj);
01039     int argc = 0;
01040     const VALUE *argv = NULL;
01041     VALUE size;
01042 
01043     if (e->size_fn) {
01044         return (*e->size_fn)(e->obj, e->args, obj);
01045     }
01046     if (e->args) {
01047         argc = (int)RARRAY_LEN(e->args);
01048         argv = RARRAY_CONST_PTR(e->args);
01049     }
01050     size = rb_check_funcall(e->size, id_call, argc, argv);
01051     if (size != Qundef) return size;
01052     return e->size;
01053 }
01054 
01055 /*
01056  * Yielder
01057  */
01058 static void
01059 yielder_mark(void *p)
01060 {
01061     struct yielder *ptr = p;
01062     rb_gc_mark(ptr->proc);
01063 }
01064 
01065 #define yielder_free RUBY_TYPED_DEFAULT_FREE
01066 
01067 static size_t
01068 yielder_memsize(const void *p)
01069 {
01070     return p ? sizeof(struct yielder) : 0;
01071 }
01072 
01073 static const rb_data_type_t yielder_data_type = {
01074     "yielder",
01075     {
01076         yielder_mark,
01077         yielder_free,
01078         yielder_memsize,
01079     },
01080     NULL, NULL, RUBY_TYPED_FREE_IMMEDIATELY
01081 };
01082 
01083 static struct yielder *
01084 yielder_ptr(VALUE obj)
01085 {
01086     struct yielder *ptr;
01087 
01088     TypedData_Get_Struct(obj, struct yielder, &yielder_data_type, ptr);
01089     if (!ptr || ptr->proc == Qundef) {
01090         rb_raise(rb_eArgError, "uninitialized yielder");
01091     }
01092     return ptr;
01093 }
01094 
01095 /* :nodoc: */
01096 static VALUE
01097 yielder_allocate(VALUE klass)
01098 {
01099     struct yielder *ptr;
01100     VALUE obj;
01101 
01102     obj = TypedData_Make_Struct(klass, struct yielder, &yielder_data_type, ptr);
01103     ptr->proc = Qundef;
01104 
01105     return obj;
01106 }
01107 
01108 static VALUE
01109 yielder_init(VALUE obj, VALUE proc)
01110 {
01111     struct yielder *ptr;
01112 
01113     TypedData_Get_Struct(obj, struct yielder, &yielder_data_type, ptr);
01114 
01115     if (!ptr) {
01116         rb_raise(rb_eArgError, "unallocated yielder");
01117     }
01118 
01119     ptr->proc = proc;
01120 
01121     return obj;
01122 }
01123 
01124 /* :nodoc: */
01125 static VALUE
01126 yielder_initialize(VALUE obj)
01127 {
01128     rb_need_block();
01129 
01130     return yielder_init(obj, rb_block_proc());
01131 }
01132 
01133 /* :nodoc: */
01134 static VALUE
01135 yielder_yield(VALUE obj, VALUE args)
01136 {
01137     struct yielder *ptr = yielder_ptr(obj);
01138 
01139     return rb_proc_call(ptr->proc, args);
01140 }
01141 
01142 /* :nodoc: */
01143 static VALUE yielder_yield_push(VALUE obj, VALUE args)
01144 {
01145     yielder_yield(obj, args);
01146     return obj;
01147 }
01148 
01149 static VALUE
01150 yielder_yield_i(RB_BLOCK_CALL_FUNC_ARGLIST(obj, memo))
01151 {
01152     return rb_yield_values2(argc, argv);
01153 }
01154 
01155 static VALUE
01156 yielder_new(void)
01157 {
01158     return yielder_init(yielder_allocate(rb_cYielder), rb_proc_new(yielder_yield_i, 0));
01159 }
01160 
01161 /*
01162  * Generator
01163  */
01164 static void
01165 generator_mark(void *p)
01166 {
01167     struct generator *ptr = p;
01168     rb_gc_mark(ptr->proc);
01169 }
01170 
01171 #define generator_free RUBY_TYPED_DEFAULT_FREE
01172 
01173 static size_t
01174 generator_memsize(const void *p)
01175 {
01176     return p ? sizeof(struct generator) : 0;
01177 }
01178 
01179 static const rb_data_type_t generator_data_type = {
01180     "generator",
01181     {
01182         generator_mark,
01183         generator_free,
01184         generator_memsize,
01185     },
01186     NULL, NULL, RUBY_TYPED_FREE_IMMEDIATELY
01187 };
01188 
01189 static struct generator *
01190 generator_ptr(VALUE obj)
01191 {
01192     struct generator *ptr;
01193 
01194     TypedData_Get_Struct(obj, struct generator, &generator_data_type, ptr);
01195     if (!ptr || ptr->proc == Qundef) {
01196         rb_raise(rb_eArgError, "uninitialized generator");
01197     }
01198     return ptr;
01199 }
01200 
01201 /* :nodoc: */
01202 static VALUE
01203 generator_allocate(VALUE klass)
01204 {
01205     struct generator *ptr;
01206     VALUE obj;
01207 
01208     obj = TypedData_Make_Struct(klass, struct generator, &generator_data_type, ptr);
01209     ptr->proc = Qundef;
01210 
01211     return obj;
01212 }
01213 
01214 static VALUE
01215 generator_init(VALUE obj, VALUE proc)
01216 {
01217     struct generator *ptr;
01218 
01219     rb_check_frozen(obj);
01220     TypedData_Get_Struct(obj, struct generator, &generator_data_type, ptr);
01221 
01222     if (!ptr) {
01223         rb_raise(rb_eArgError, "unallocated generator");
01224     }
01225 
01226     ptr->proc = proc;
01227 
01228     return obj;
01229 }
01230 
01231 /* :nodoc: */
01232 static VALUE
01233 generator_initialize(int argc, VALUE *argv, VALUE obj)
01234 {
01235     VALUE proc;
01236 
01237     if (argc == 0) {
01238         rb_need_block();
01239 
01240         proc = rb_block_proc();
01241     }
01242     else {
01243         rb_scan_args(argc, argv, "1", &proc);
01244 
01245         if (!rb_obj_is_proc(proc))
01246             rb_raise(rb_eTypeError,
01247                      "wrong argument type %s (expected Proc)",
01248                      rb_obj_classname(proc));
01249 
01250         if (rb_block_given_p()) {
01251             rb_warn("given block not used");
01252         }
01253     }
01254 
01255     return generator_init(obj, proc);
01256 }
01257 
01258 /* :nodoc: */
01259 static VALUE
01260 generator_init_copy(VALUE obj, VALUE orig)
01261 {
01262     struct generator *ptr0, *ptr1;
01263 
01264     if (!OBJ_INIT_COPY(obj, orig)) return obj;
01265 
01266     ptr0 = generator_ptr(orig);
01267 
01268     TypedData_Get_Struct(obj, struct generator, &generator_data_type, ptr1);
01269 
01270     if (!ptr1) {
01271         rb_raise(rb_eArgError, "unallocated generator");
01272     }
01273 
01274     ptr1->proc = ptr0->proc;
01275 
01276     return obj;
01277 }
01278 
01279 /* :nodoc: */
01280 static VALUE
01281 generator_each(int argc, VALUE *argv, VALUE obj)
01282 {
01283     struct generator *ptr = generator_ptr(obj);
01284     VALUE args = rb_ary_new2(argc + 1);
01285 
01286     rb_ary_push(args, yielder_new());
01287     if (argc > 0) {
01288         rb_ary_cat(args, argv, argc);
01289     }
01290 
01291     return rb_proc_call(ptr->proc, args);
01292 }
01293 
01294 /* Lazy Enumerator methods */
01295 static VALUE
01296 enum_size(VALUE self)
01297 {
01298     VALUE r = rb_check_funcall(self, id_size, 0, 0);
01299     return (r == Qundef) ? Qnil : r;
01300 }
01301 
01302 static VALUE
01303 lazyenum_size(VALUE self, VALUE args, VALUE eobj)
01304 {
01305     return enum_size(self);
01306 }
01307 
01308 static VALUE
01309 lazy_size(VALUE self)
01310 {
01311     return enum_size(rb_ivar_get(self, id_receiver));
01312 }
01313 
01314 static VALUE
01315 lazy_receiver_size(VALUE generator, VALUE args, VALUE lazy)
01316 {
01317     return lazy_size(lazy);
01318 }
01319 
01320 static VALUE
01321 lazy_init_iterator(RB_BLOCK_CALL_FUNC_ARGLIST(val, m))
01322 {
01323     VALUE result;
01324     if (argc == 1) {
01325         VALUE args[2];
01326         args[0] = m;
01327         args[1] = val;
01328         result = rb_yield_values2(2, args);
01329     }
01330     else {
01331         VALUE args;
01332         int len = rb_long2int((long)argc + 1);
01333 
01334         args = rb_ary_tmp_new(len);
01335         rb_ary_push(args, m);
01336         if (argc > 0) {
01337             rb_ary_cat(args, argv, argc);
01338         }
01339         result = rb_yield_values2(len, RARRAY_CONST_PTR(args));
01340         RB_GC_GUARD(args);
01341     }
01342     if (result == Qundef) rb_iter_break();
01343     return Qnil;
01344 }
01345 
01346 static VALUE
01347 lazy_init_block_i(RB_BLOCK_CALL_FUNC_ARGLIST(val, m))
01348 {
01349     rb_block_call(m, id_each, argc-1, argv+1, lazy_init_iterator, val);
01350     return Qnil;
01351 }
01352 
01353 /*
01354  * call-seq:
01355  *   Lazy.new(obj, size=nil) { |yielder, *values| ... }
01356  *
01357  * Creates a new Lazy enumerator. When the enumerator is actually enumerated
01358  * (e.g. by calling #force), +obj+ will be enumerated and each value passed
01359  * to the given block. The block can yield values back using +yielder+.
01360  * For example, to create a method +filter_map+ in both lazy and
01361  * non-lazy fashions:
01362  *
01363  *   module Enumerable
01364  *     def filter_map(&block)
01365  *       map(&block).compact
01366  *     end
01367  *   end
01368  *
01369  *   class Enumerator::Lazy
01370  *     def filter_map
01371  *       Lazy.new(self) do |yielder, *values|
01372  *         result = yield *values
01373  *         yielder << result if result
01374  *       end
01375  *     end
01376  *   end
01377  *
01378  *   (1..Float::INFINITY).lazy.filter_map{|i| i*i if i.even?}.first(5)
01379  *       # => [4, 16, 36, 64, 100]
01380  */
01381 static VALUE
01382 lazy_initialize(int argc, VALUE *argv, VALUE self)
01383 {
01384     VALUE obj, size = Qnil;
01385     VALUE generator;
01386 
01387     rb_check_arity(argc, 1, 2);
01388     if (!rb_block_given_p()) {
01389         rb_raise(rb_eArgError, "tried to call lazy new without a block");
01390     }
01391     obj = argv[0];
01392     if (argc > 1) {
01393         size = argv[1];
01394     }
01395     generator = generator_allocate(rb_cGenerator);
01396     rb_block_call(generator, id_initialize, 0, 0, lazy_init_block_i, obj);
01397     enumerator_init(self, generator, sym_each, 0, 0, 0, size);
01398     rb_ivar_set(self, id_receiver, obj);
01399 
01400     return self;
01401 }
01402 
01403 static VALUE
01404 lazy_set_method(VALUE lazy, VALUE args, rb_enumerator_size_func *size_fn)
01405 {
01406     ID id = rb_frame_this_func();
01407     struct enumerator *e = enumerator_ptr(lazy);
01408     rb_ivar_set(lazy, id_method, ID2SYM(id));
01409     if (NIL_P(args)) {
01410         /* Qfalse indicates that the arguments are empty */
01411         rb_ivar_set(lazy, id_arguments, Qfalse);
01412     }
01413     else {
01414         rb_ivar_set(lazy, id_arguments, args);
01415     }
01416     e->size_fn = size_fn;
01417     return lazy;
01418 }
01419 
01420 /*
01421  * call-seq:
01422  *   e.lazy -> lazy_enumerator
01423  *
01424  * Returns a lazy enumerator, whose methods map/collect,
01425  * flat_map/collect_concat, select/find_all, reject, grep, zip, take,
01426  * take_while, drop, and drop_while enumerate values only on an
01427  * as-needed basis.  However, if a block is given to zip, values
01428  * are enumerated immediately.
01429  *
01430  * === Example
01431  *
01432  * The following program finds pythagorean triples:
01433  *
01434  *   def pythagorean_triples
01435  *     (1..Float::INFINITY).lazy.flat_map {|z|
01436  *       (1..z).flat_map {|x|
01437  *         (x..z).select {|y|
01438  *           x**2 + y**2 == z**2
01439  *         }.map {|y|
01440  *           [x, y, z]
01441  *         }
01442  *       }
01443  *     }
01444  *   end
01445  *   # show first ten pythagorean triples
01446  *   p pythagorean_triples.take(10).force # take is lazy, so force is needed
01447  *   p pythagorean_triples.first(10)      # first is eager
01448  *   # show pythagorean triples less than 100
01449  *   p pythagorean_triples.take_while { |*, z| z < 100 }.force
01450  */
01451 static VALUE
01452 enumerable_lazy(VALUE obj)
01453 {
01454     VALUE result = lazy_to_enum_i(obj, sym_each, 0, 0, lazyenum_size);
01455     /* Qfalse indicates that the Enumerator::Lazy has no method name */
01456     rb_ivar_set(result, id_method, Qfalse);
01457     return result;
01458 }
01459 
01460 static VALUE
01461 lazy_to_enum_i(VALUE obj, VALUE meth, int argc, VALUE *argv, rb_enumerator_size_func *size_fn)
01462 {
01463     return enumerator_init(enumerator_allocate(rb_cLazy),
01464                            obj, meth, argc, argv, size_fn, Qnil);
01465 }
01466 
01467 /*
01468  * call-seq:
01469  *   lzy.to_enum(method = :each, *args)                 -> lazy_enum
01470  *   lzy.enum_for(method = :each, *args)                -> lazy_enum
01471  *   lzy.to_enum(method = :each, *args) {|*args| block} -> lazy_enum
01472  *   lzy.enum_for(method = :each, *args){|*args| block} -> lazy_enum
01473  *
01474  * Similar to Kernel#to_enum, except it returns a lazy enumerator.
01475  * This makes it easy to define Enumerable methods that will
01476  * naturally remain lazy if called from a lazy enumerator.
01477  *
01478  * For example, continuing from the example in Kernel#to_enum:
01479  *
01480  *   # See Kernel#to_enum for the definition of repeat
01481  *   r = 1..Float::INFINITY
01482  *   r.repeat(2).first(5) # => [1, 1, 2, 2, 3]
01483  *   r.repeat(2).class # => Enumerator
01484  *   r.repeat(2).map{|n| n ** 2}.first(5) # => endless loop!
01485  *   # works naturally on lazy enumerator:
01486  *   r.lazy.repeat(2).class # => Enumerator::Lazy
01487  *   r.lazy.repeat(2).map{|n| n ** 2}.first(5) # => [1, 1, 4, 4, 9]
01488  */
01489 
01490 static VALUE
01491 lazy_to_enum(int argc, VALUE *argv, VALUE self)
01492 {
01493     VALUE lazy, meth = sym_each;
01494 
01495     if (argc > 0) {
01496         --argc;
01497         meth = *argv++;
01498     }
01499     lazy = lazy_to_enum_i(self, meth, argc, argv, 0);
01500     if (rb_block_given_p()) {
01501         enumerator_ptr(lazy)->size = rb_block_proc();
01502     }
01503     return lazy;
01504 }
01505 
01506 static VALUE
01507 lazy_map_func(RB_BLOCK_CALL_FUNC_ARGLIST(val, m))
01508 {
01509     VALUE result = rb_yield_values2(argc - 1, &argv[1]);
01510 
01511     rb_funcall(argv[0], id_yield, 1, result);
01512     return Qnil;
01513 }
01514 
01515 static VALUE
01516 lazy_map(VALUE obj)
01517 {
01518     if (!rb_block_given_p()) {
01519         rb_raise(rb_eArgError, "tried to call lazy map without a block");
01520     }
01521 
01522     return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
01523                                          lazy_map_func, 0),
01524                            Qnil, lazy_receiver_size);
01525 }
01526 
01527 static VALUE
01528 lazy_flat_map_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, yielder))
01529 {
01530     return rb_funcall2(yielder, id_yield, argc, argv);
01531 }
01532 
01533 static VALUE
01534 lazy_flat_map_each(VALUE obj, VALUE yielder)
01535 {
01536     rb_block_call(obj, id_each, 0, 0, lazy_flat_map_i, yielder);
01537     return Qnil;
01538 }
01539 
01540 static VALUE
01541 lazy_flat_map_to_ary(VALUE obj, VALUE yielder)
01542 {
01543     VALUE ary = rb_check_array_type(obj);
01544     if (NIL_P(ary)) {
01545         rb_funcall(yielder, id_yield, 1, obj);
01546     }
01547     else {
01548         long i;
01549         for (i = 0; i < RARRAY_LEN(ary); i++) {
01550             rb_funcall(yielder, id_yield, 1, RARRAY_AREF(ary, i));
01551         }
01552     }
01553     return Qnil;
01554 }
01555 
01556 static VALUE
01557 lazy_flat_map_func(RB_BLOCK_CALL_FUNC_ARGLIST(val, m))
01558 {
01559     VALUE result = rb_yield_values2(argc - 1, &argv[1]);
01560     if (RB_TYPE_P(result, T_ARRAY)) {
01561         long i;
01562         for (i = 0; i < RARRAY_LEN(result); i++) {
01563             rb_funcall(argv[0], id_yield, 1, RARRAY_AREF(result, i));
01564         }
01565     }
01566     else {
01567         if (rb_respond_to(result, id_force) && rb_respond_to(result, id_each)) {
01568             lazy_flat_map_each(result, argv[0]);
01569         }
01570         else {
01571             lazy_flat_map_to_ary(result, argv[0]);
01572         }
01573     }
01574     return Qnil;
01575 }
01576 
01577 /*
01578  *  call-seq:
01579  *     lazy.collect_concat { |obj| block } -> a_lazy_enumerator
01580  *     lazy.flat_map       { |obj| block } -> a_lazy_enumerator
01581  *
01582  *  Returns a new lazy enumerator with the concatenated results of running
01583  *  <i>block</i> once for every element in <i>lazy</i>.
01584  *
01585  *    ["foo", "bar"].lazy.flat_map {|i| i.each_char.lazy}.force
01586  *    #=> ["f", "o", "o", "b", "a", "r"]
01587  *
01588  *  A value <i>x</i> returned by <i>block</i> is decomposed if either of
01589  *  the following conditions is true:
01590  *
01591  *    a) <i>x</i> responds to both each and force, which means that
01592  *       <i>x</i> is a lazy enumerator.
01593  *    b) <i>x</i> is an array or responds to to_ary.
01594  *
01595  *  Otherwise, <i>x</i> is contained as-is in the return value.
01596  *
01597  *    [{a:1}, {b:2}].lazy.flat_map {|i| i}.force
01598  *    #=> [{:a=>1}, {:b=>2}]
01599  */
01600 static VALUE
01601 lazy_flat_map(VALUE obj)
01602 {
01603     if (!rb_block_given_p()) {
01604         rb_raise(rb_eArgError, "tried to call lazy flat_map without a block");
01605     }
01606 
01607     return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
01608                                          lazy_flat_map_func, 0),
01609                            Qnil, 0);
01610 }
01611 
01612 static VALUE
01613 lazy_select_func(RB_BLOCK_CALL_FUNC_ARGLIST(val, m))
01614 {
01615     VALUE element = rb_enum_values_pack(argc - 1, argv + 1);
01616 
01617     if (RTEST(rb_yield(element))) {
01618         return rb_funcall(argv[0], id_yield, 1, element);
01619     }
01620     return Qnil;
01621 }
01622 
01623 static VALUE
01624 lazy_select(VALUE obj)
01625 {
01626     if (!rb_block_given_p()) {
01627         rb_raise(rb_eArgError, "tried to call lazy select without a block");
01628     }
01629 
01630     return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
01631                                          lazy_select_func, 0),
01632                            Qnil, 0);
01633 }
01634 
01635 static VALUE
01636 lazy_reject_func(RB_BLOCK_CALL_FUNC_ARGLIST(val, m))
01637 {
01638     VALUE element = rb_enum_values_pack(argc - 1, argv + 1);
01639 
01640     if (!RTEST(rb_yield(element))) {
01641         return rb_funcall(argv[0], id_yield, 1, element);
01642     }
01643     return Qnil;
01644 }
01645 
01646 static VALUE
01647 lazy_reject(VALUE obj)
01648 {
01649     if (!rb_block_given_p()) {
01650         rb_raise(rb_eArgError, "tried to call lazy reject without a block");
01651     }
01652 
01653     return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
01654                                          lazy_reject_func, 0),
01655                            Qnil, 0);
01656 }
01657 
01658 static VALUE
01659 lazy_grep_func(RB_BLOCK_CALL_FUNC_ARGLIST(val, m))
01660 {
01661     VALUE i = rb_enum_values_pack(argc - 1, argv + 1);
01662     VALUE result = rb_funcall(m, id_eqq, 1, i);
01663 
01664     if (RTEST(result)) {
01665         rb_funcall(argv[0], id_yield, 1, i);
01666     }
01667     return Qnil;
01668 }
01669 
01670 static VALUE
01671 lazy_grep_iter(RB_BLOCK_CALL_FUNC_ARGLIST(val, m))
01672 {
01673     VALUE i = rb_enum_values_pack(argc - 1, argv + 1);
01674     VALUE result = rb_funcall(m, id_eqq, 1, i);
01675 
01676     if (RTEST(result)) {
01677         rb_funcall(argv[0], id_yield, 1, rb_yield(i));
01678     }
01679     return Qnil;
01680 }
01681 
01682 static VALUE
01683 lazy_grep(VALUE obj, VALUE pattern)
01684 {
01685     return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
01686                                          rb_block_given_p() ?
01687                                          lazy_grep_iter : lazy_grep_func,
01688                                          pattern),
01689                            rb_ary_new3(1, pattern), 0);
01690 }
01691 
01692 static VALUE
01693 call_next(VALUE obj)
01694 {
01695     return rb_funcall(obj, id_next, 0);
01696 }
01697 
01698 static VALUE
01699 next_stopped(VALUE obj)
01700 {
01701     return Qnil;
01702 }
01703 
01704 static VALUE
01705 lazy_zip_arrays_func(RB_BLOCK_CALL_FUNC_ARGLIST(val, arrays))
01706 {
01707     VALUE yielder, ary, memo;
01708     long i, count;
01709 
01710     yielder = argv[0];
01711     memo = rb_attr_get(yielder, id_memo);
01712     count = NIL_P(memo) ? 0 : NUM2LONG(memo);
01713 
01714     ary = rb_ary_new2(RARRAY_LEN(arrays) + 1);
01715     rb_ary_push(ary, argv[1]);
01716     for (i = 0; i < RARRAY_LEN(arrays); i++) {
01717         rb_ary_push(ary, rb_ary_entry(RARRAY_AREF(arrays, i), count));
01718     }
01719     rb_funcall(yielder, id_yield, 1, ary);
01720     rb_ivar_set(yielder, id_memo, LONG2NUM(++count));
01721     return Qnil;
01722 }
01723 
01724 static VALUE
01725 lazy_zip_func(RB_BLOCK_CALL_FUNC_ARGLIST(val, zip_args))
01726 {
01727     VALUE yielder, ary, arg, v;
01728     long i;
01729 
01730     yielder = argv[0];
01731     arg = rb_attr_get(yielder, id_memo);
01732     if (NIL_P(arg)) {
01733         arg = rb_ary_new2(RARRAY_LEN(zip_args));
01734         for (i = 0; i < RARRAY_LEN(zip_args); i++) {
01735             rb_ary_push(arg, rb_funcall(RARRAY_AREF(zip_args, i), id_to_enum, 0));
01736         }
01737         rb_ivar_set(yielder, id_memo, arg);
01738     }
01739 
01740     ary = rb_ary_new2(RARRAY_LEN(arg) + 1);
01741     v = Qnil;
01742     if (--argc > 0) {
01743         ++argv;
01744         v = argc > 1 ? rb_ary_new_from_values(argc, argv) : *argv;
01745     }
01746     rb_ary_push(ary, v);
01747     for (i = 0; i < RARRAY_LEN(arg); i++) {
01748         v = rb_rescue2(call_next, RARRAY_AREF(arg, i), next_stopped, 0,
01749                        rb_eStopIteration, (VALUE)0);
01750         rb_ary_push(ary, v);
01751     }
01752     rb_funcall(yielder, id_yield, 1, ary);
01753     return Qnil;
01754 }
01755 
01756 static VALUE
01757 lazy_zip(int argc, VALUE *argv, VALUE obj)
01758 {
01759     VALUE ary, v;
01760     long i;
01761     rb_block_call_func *func = lazy_zip_arrays_func;
01762 
01763     if (rb_block_given_p()) {
01764         return rb_call_super(argc, argv);
01765     }
01766 
01767     ary = rb_ary_new2(argc);
01768     for (i = 0; i < argc; i++) {
01769         v = rb_check_array_type(argv[i]);
01770         if (NIL_P(v)) {
01771             for (; i < argc; i++) {
01772                 if (!rb_respond_to(argv[i], id_each)) {
01773                     rb_raise(rb_eTypeError, "wrong argument type %s (must respond to :each)",
01774                         rb_obj_classname(argv[i]));
01775                 }
01776             }
01777             ary = rb_ary_new4(argc, argv);
01778             func = lazy_zip_func;
01779             break;
01780         }
01781         rb_ary_push(ary, v);
01782     }
01783 
01784     return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
01785                                          func, ary),
01786                            ary, lazy_receiver_size);
01787 }
01788 
01789 static VALUE
01790 lazy_take_func(RB_BLOCK_CALL_FUNC_ARGLIST(val, args))
01791 {
01792     long remain;
01793     VALUE memo = rb_attr_get(argv[0], id_memo);
01794     if (NIL_P(memo)) {
01795         memo = args;
01796     }
01797 
01798     rb_funcall2(argv[0], id_yield, argc - 1, argv + 1);
01799     if ((remain = NUM2LONG(memo)-1) == 0) {
01800         return Qundef;
01801     }
01802     else {
01803         rb_ivar_set(argv[0], id_memo, LONG2NUM(remain));
01804         return Qnil;
01805     }
01806 }
01807 
01808 static VALUE
01809 lazy_take_size(VALUE generator, VALUE args, VALUE lazy)
01810 {
01811     VALUE receiver = lazy_size(lazy);
01812     long len = NUM2LONG(RARRAY_AREF(rb_ivar_get(lazy, id_arguments), 0));
01813     if (NIL_P(receiver) || (FIXNUM_P(receiver) && FIX2LONG(receiver) < len))
01814         return receiver;
01815     return LONG2NUM(len);
01816 }
01817 
01818 static VALUE
01819 lazy_take(VALUE obj, VALUE n)
01820 {
01821     long len = NUM2LONG(n);
01822     VALUE lazy;
01823 
01824     if (len < 0) {
01825         rb_raise(rb_eArgError, "attempt to take negative size");
01826     }
01827     if (len == 0) {
01828         VALUE len = INT2FIX(0);
01829         lazy = lazy_to_enum_i(obj, sym_cycle, 1, &len, 0);
01830     }
01831     else {
01832         lazy = rb_block_call(rb_cLazy, id_new, 1, &obj,
01833                                          lazy_take_func, n);
01834     }
01835     return lazy_set_method(lazy, rb_ary_new3(1, n), lazy_take_size);
01836 }
01837 
01838 static VALUE
01839 lazy_take_while_func(RB_BLOCK_CALL_FUNC_ARGLIST(val, args))
01840 {
01841     VALUE result = rb_yield_values2(argc - 1, &argv[1]);
01842     if (!RTEST(result)) return Qundef;
01843     rb_funcall2(argv[0], id_yield, argc - 1, argv + 1);
01844     return Qnil;
01845 }
01846 
01847 static VALUE
01848 lazy_take_while(VALUE obj)
01849 {
01850     if (!rb_block_given_p()) {
01851         rb_raise(rb_eArgError, "tried to call lazy take_while without a block");
01852     }
01853     return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
01854                                          lazy_take_while_func, 0),
01855                            Qnil, 0);
01856 }
01857 
01858 static VALUE
01859 lazy_drop_size(VALUE generator, VALUE args, VALUE lazy)
01860 {
01861     long len = NUM2LONG(RARRAY_AREF(rb_ivar_get(lazy, id_arguments), 0));
01862     VALUE receiver = lazy_size(lazy);
01863     if (NIL_P(receiver))
01864         return receiver;
01865     if (FIXNUM_P(receiver)) {
01866         len = FIX2LONG(receiver) - len;
01867         return LONG2FIX(len < 0 ? 0 : len);
01868     }
01869     return rb_funcall(receiver, '-', 1, LONG2NUM(len));
01870 }
01871 
01872 static VALUE
01873 lazy_drop_func(RB_BLOCK_CALL_FUNC_ARGLIST(val, args))
01874 {
01875     long remain;
01876     VALUE memo = rb_attr_get(argv[0], id_memo);
01877     if (NIL_P(memo)) {
01878         memo = args;
01879     }
01880     if ((remain = NUM2LONG(memo)) == 0) {
01881         rb_funcall2(argv[0], id_yield, argc - 1, argv + 1);
01882     }
01883     else {
01884         rb_ivar_set(argv[0], id_memo, LONG2NUM(--remain));
01885     }
01886     return Qnil;
01887 }
01888 
01889 static VALUE
01890 lazy_drop(VALUE obj, VALUE n)
01891 {
01892     long len = NUM2LONG(n);
01893 
01894     if (len < 0) {
01895         rb_raise(rb_eArgError, "attempt to drop negative size");
01896     }
01897     return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
01898                                          lazy_drop_func, n),
01899                            rb_ary_new3(1, n), lazy_drop_size);
01900 }
01901 
01902 static VALUE
01903 lazy_drop_while_func(RB_BLOCK_CALL_FUNC_ARGLIST(val, args))
01904 {
01905     VALUE memo = rb_attr_get(argv[0], id_memo);
01906     if (NIL_P(memo) && !RTEST(rb_yield_values2(argc - 1, &argv[1]))) {
01907         rb_ivar_set(argv[0], id_memo, memo = Qtrue);
01908     }
01909     if (memo == Qtrue) {
01910         rb_funcall2(argv[0], id_yield, argc - 1, argv + 1);
01911     }
01912     return Qnil;
01913 }
01914 
01915 static VALUE
01916 lazy_drop_while(VALUE obj)
01917 {
01918     if (!rb_block_given_p()) {
01919         rb_raise(rb_eArgError, "tried to call lazy drop_while without a block");
01920     }
01921     return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
01922                                          lazy_drop_while_func, 0),
01923                            Qnil, 0);
01924 }
01925 
01926 static VALUE
01927 lazy_super(int argc, VALUE *argv, VALUE lazy)
01928 {
01929     return enumerable_lazy(rb_call_super(argc, argv));
01930 }
01931 
01932 static VALUE
01933 lazy_lazy(VALUE obj)
01934 {
01935     return obj;
01936 }
01937 
01938 /*
01939  * Document-class: StopIteration
01940  *
01941  * Raised to stop the iteration, in particular by Enumerator#next. It is
01942  * rescued by Kernel#loop.
01943  *
01944  *   loop do
01945  *     puts "Hello"
01946  *     raise StopIteration
01947  *     puts "World"
01948  *   end
01949  *   puts "Done!"
01950  *
01951  * <em>produces:</em>
01952  *
01953  *   Hello
01954  *   Done!
01955  */
01956 
01957 /*
01958  * call-seq:
01959  *   result       -> value
01960  *
01961  * Returns the return value of the iterator.
01962  *
01963  *   o = Object.new
01964  *   def o.each
01965  *     yield 1
01966  *     yield 2
01967  *     yield 3
01968  *     100
01969  *   end
01970  *
01971  *   e = o.to_enum
01972  *
01973  *   puts e.next                   #=> 1
01974  *   puts e.next                   #=> 2
01975  *   puts e.next                   #=> 3
01976  *
01977  *   begin
01978  *     e.next
01979  *   rescue StopIteration => ex
01980  *     puts ex.result              #=> 100
01981  *   end
01982  *
01983  */
01984 
01985 static VALUE
01986 stop_result(VALUE self)
01987 {
01988     return rb_attr_get(self, id_result);
01989 }
01990 
01991 void
01992 InitVM_Enumerator(void)
01993 {
01994     rb_define_method(rb_mKernel, "to_enum", obj_to_enum, -1);
01995     rb_define_method(rb_mKernel, "enum_for", obj_to_enum, -1);
01996 
01997     rb_cEnumerator = rb_define_class("Enumerator", rb_cObject);
01998     rb_include_module(rb_cEnumerator, rb_mEnumerable);
01999 
02000     rb_define_alloc_func(rb_cEnumerator, enumerator_allocate);
02001     rb_define_method(rb_cEnumerator, "initialize", enumerator_initialize, -1);
02002     rb_define_method(rb_cEnumerator, "initialize_copy", enumerator_init_copy, 1);
02003     rb_define_method(rb_cEnumerator, "each", enumerator_each, -1);
02004     rb_define_method(rb_cEnumerator, "each_with_index", enumerator_each_with_index, 0);
02005     rb_define_method(rb_cEnumerator, "each_with_object", enumerator_with_object, 1);
02006     rb_define_method(rb_cEnumerator, "with_index", enumerator_with_index, -1);
02007     rb_define_method(rb_cEnumerator, "with_object", enumerator_with_object, 1);
02008     rb_define_method(rb_cEnumerator, "next_values", enumerator_next_values, 0);
02009     rb_define_method(rb_cEnumerator, "peek_values", enumerator_peek_values_m, 0);
02010     rb_define_method(rb_cEnumerator, "next", enumerator_next, 0);
02011     rb_define_method(rb_cEnumerator, "peek", enumerator_peek, 0);
02012     rb_define_method(rb_cEnumerator, "feed", enumerator_feed, 1);
02013     rb_define_method(rb_cEnumerator, "rewind", enumerator_rewind, 0);
02014     rb_define_method(rb_cEnumerator, "inspect", enumerator_inspect, 0);
02015     rb_define_method(rb_cEnumerator, "size", enumerator_size, 0);
02016 
02017     /* Lazy */
02018     rb_cLazy = rb_define_class_under(rb_cEnumerator, "Lazy", rb_cEnumerator);
02019     rb_define_method(rb_mEnumerable, "lazy", enumerable_lazy, 0);
02020     rb_define_method(rb_cLazy, "initialize", lazy_initialize, -1);
02021     rb_define_method(rb_cLazy, "to_enum", lazy_to_enum, -1);
02022     rb_define_method(rb_cLazy, "enum_for", lazy_to_enum, -1);
02023     rb_define_method(rb_cLazy, "map", lazy_map, 0);
02024     rb_define_method(rb_cLazy, "collect", lazy_map, 0);
02025     rb_define_method(rb_cLazy, "flat_map", lazy_flat_map, 0);
02026     rb_define_method(rb_cLazy, "collect_concat", lazy_flat_map, 0);
02027     rb_define_method(rb_cLazy, "select", lazy_select, 0);
02028     rb_define_method(rb_cLazy, "find_all", lazy_select, 0);
02029     rb_define_method(rb_cLazy, "reject", lazy_reject, 0);
02030     rb_define_method(rb_cLazy, "grep", lazy_grep, 1);
02031     rb_define_method(rb_cLazy, "zip", lazy_zip, -1);
02032     rb_define_method(rb_cLazy, "take", lazy_take, 1);
02033     rb_define_method(rb_cLazy, "take_while", lazy_take_while, 0);
02034     rb_define_method(rb_cLazy, "drop", lazy_drop, 1);
02035     rb_define_method(rb_cLazy, "drop_while", lazy_drop_while, 0);
02036     rb_define_method(rb_cLazy, "lazy", lazy_lazy, 0);
02037     rb_define_method(rb_cLazy, "chunk", lazy_super, -1);
02038     rb_define_method(rb_cLazy, "slice_before", lazy_super, -1);
02039 
02040     rb_define_alias(rb_cLazy, "force", "to_a");
02041 
02042     rb_eStopIteration = rb_define_class("StopIteration", rb_eIndexError);
02043     rb_define_method(rb_eStopIteration, "result", stop_result, 0);
02044 
02045     /* Generator */
02046     rb_cGenerator = rb_define_class_under(rb_cEnumerator, "Generator", rb_cObject);
02047     rb_include_module(rb_cGenerator, rb_mEnumerable);
02048     rb_define_alloc_func(rb_cGenerator, generator_allocate);
02049     rb_define_method(rb_cGenerator, "initialize", generator_initialize, -1);
02050     rb_define_method(rb_cGenerator, "initialize_copy", generator_init_copy, 1);
02051     rb_define_method(rb_cGenerator, "each", generator_each, -1);
02052 
02053     /* Yielder */
02054     rb_cYielder = rb_define_class_under(rb_cEnumerator, "Yielder", rb_cObject);
02055     rb_define_alloc_func(rb_cYielder, yielder_allocate);
02056     rb_define_method(rb_cYielder, "initialize", yielder_initialize, 0);
02057     rb_define_method(rb_cYielder, "yield", yielder_yield, -2);
02058     rb_define_method(rb_cYielder, "<<", yielder_yield_push, -2);
02059 
02060     rb_provide("enumerator.so");        /* for backward compatibility */
02061 }
02062 
02063 void
02064 Init_Enumerator(void)
02065 {
02066     id_rewind = rb_intern("rewind");
02067     id_each = rb_intern("each");
02068     id_call = rb_intern("call");
02069     id_size = rb_intern("size");
02070     id_yield = rb_intern("yield");
02071     id_new = rb_intern("new");
02072     id_initialize = rb_intern("initialize");
02073     id_next = rb_intern("next");
02074     id_result = rb_intern("result");
02075     id_lazy = rb_intern("lazy");
02076     id_eqq = rb_intern("===");
02077     id_receiver = rb_intern("receiver");
02078     id_arguments = rb_intern("arguments");
02079     id_memo = rb_intern("memo");
02080     id_method = rb_intern("method");
02081     id_force = rb_intern("force");
02082     id_to_enum = rb_intern("to_enum");
02083     sym_each = ID2SYM(id_each);
02084     sym_cycle = ID2SYM(rb_intern("cycle"));
02085 
02086     InitVM(Enumerator);
02087 }
02088 

Generated on 19 Jul 2016 for Ruby by  doxygen 1.4.7