• Main Page
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

enumerator.c

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

Generated on Wed Sep 8 2010 09:54:36 for Ruby by  doxygen 1.7.1