|
Ruby 1.9.2p290(2011-07-09revision32553)
|
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
1.7.3