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