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