1 /************************************************
3 enumerator.c - provides Enumerator class
7 Copyright (C) 2001-2003 Akinori MUSHA
9 $Idaemons: /home/cvs/rb/enumerator/enumerator.c,v 1.1.1.1 2001/07/15 10:12:48 knu Exp $
10 $RoughId: enumerator.c,v 1.6 2003/07/27 11:03:24 nobu Exp $
11 $Id: enumerator.c 20712 2008-12-13 01:59:42Z yugui $
13 ************************************************/
15 #include "ruby/ruby.h"
18 * Document-class: Enumerator
20 * A class which provides a method `each' to be used as an Enumerable
24 static VALUE sym_each;
27 VALUE rb_eStopIteration;
38 static VALUE rb_cGenerator, rb_cYielder;
48 static VALUE generator_allocate(VALUE klass);
49 static VALUE generator_init(VALUE obj, VALUE proc);
55 enumerator_mark(void *p)
57 struct enumerator *ptr = p;
59 rb_gc_mark(ptr->args);
64 static struct enumerator *
65 enumerator_ptr(VALUE obj)
67 struct enumerator *ptr;
69 Data_Get_Struct(obj, struct enumerator, ptr);
70 if (RDATA(obj)->dmark != enumerator_mark) {
71 rb_raise(rb_eTypeError,
72 "wrong argument type %s (expected %s)",
73 rb_obj_classname(obj), rb_class2name(rb_cEnumerator));
75 if (!ptr || ptr->obj == Qundef) {
76 rb_raise(rb_eArgError, "uninitialized enumerator");
83 * obj.to_enum(method = :each, *args)
84 * obj.enum_for(method = :each, *args)
86 * Returns Enumerator.new(self, method, *args).
92 * enum = str.enum_for(:each_byte)
93 * a = enum.map {|b| '%02x' % b } #=> ["78", "79", "7a"]
95 * # protects an array from being modified
97 * some_method(a.to_enum)
101 obj_to_enum(int argc, VALUE *argv, VALUE obj)
103 VALUE meth = sym_each;
109 return rb_enumeratorize(obj, meth, argc, argv);
113 each_slice_i(VALUE val, VALUE *memo)
117 long size = (long)memo[1];
119 rb_ary_push(ary, val);
121 if (RARRAY_LEN(ary) == size) {
123 memo[0] = rb_ary_new2(size);
131 * e.each_slice(n) {...}
134 * Iterates the given block for each slice of <n> elements. If no
135 * block is given, returns an enumerator.
138 * (1..10).each_slice(3) {|a| p a}
147 enum_each_slice(VALUE obj, VALUE n)
149 long size = NUM2LONG(n);
152 if (size <= 0) rb_raise(rb_eArgError, "invalid slice size");
153 RETURN_ENUMERATOR(obj, 1, &n);
154 args[0] = rb_ary_new2(size);
155 args[1] = (VALUE)size;
157 rb_block_call(obj, SYM2ID(sym_each), 0, 0, each_slice_i, (VALUE)args);
160 if (RARRAY_LEN(ary) > 0) rb_yield(ary);
166 each_cons_i(VALUE val, VALUE *memo)
170 long size = (long)memo[1];
172 if (RARRAY_LEN(ary) == size) {
175 rb_ary_push(ary, val);
176 if (RARRAY_LEN(ary) == size) {
177 v = rb_yield(rb_ary_dup(ary));
187 * Iterates the given block for each array of consecutive <n>
188 * elements. If no block is given, returns an enumerator.
191 * (1..10).each_cons(3) {|a| p a}
204 enum_each_cons(VALUE obj, VALUE n)
206 long size = NUM2LONG(n);
209 if (size <= 0) rb_raise(rb_eArgError, "invalid size");
210 RETURN_ENUMERATOR(obj, 1, &n);
211 args[0] = rb_ary_new2(size);
212 args[1] = (VALUE)size;
214 rb_block_call(obj, SYM2ID(sym_each), 0, 0, each_cons_i, (VALUE)args);
220 each_with_object_i(VALUE val, VALUE memo)
222 return rb_yield_values(2, val, memo);
227 * each_with_object(obj) {|(*args), memo_obj| ... }
228 * each_with_object(obj)
230 * Iterates the given block for each element with an arbitrary
231 * object given, and returns the initially given object.
233 * If no block is given, returns an enumerator.
236 * evens = (1..10).each_with_object([]) {|i, a| a << i*2 }
237 * # => [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
241 enum_each_with_object(VALUE obj, VALUE memo)
243 RETURN_ENUMERATOR(obj, 1, &memo);
245 rb_block_call(obj, SYM2ID(sym_each), 0, 0, each_with_object_i, memo);
251 enumerator_allocate(VALUE klass)
253 struct enumerator *ptr;
256 enum_obj = Data_Make_Struct(klass, struct enumerator, enumerator_mark, -1, ptr);
263 enumerator_each_i(VALUE v, VALUE enum_obj, int argc, VALUE *argv)
265 return rb_yield_values2(argc, argv);
269 enumerator_init(VALUE enum_obj, VALUE obj, VALUE meth, int argc, VALUE *argv)
271 struct enumerator *ptr;
273 Data_Get_Struct(enum_obj, struct enumerator, ptr);
276 rb_raise(rb_eArgError, "unallocated enumerator");
280 ptr->meth = rb_to_id(meth);
281 if (argc) ptr->args = rb_ary_new4(argc, argv);
284 ptr->no_next = Qfalse;
291 * Enumerator.new(obj, method = :each, *args)
292 * Enumerator.new { |y| ... }
294 * Creates a new Enumerator object, which is to be used as an
295 * Enumerable object iterating in a given way.
297 * In the first form, a generated Enumerator iterates over the given
298 * object using the given method with the given arguments passed.
299 * Use of this form is discouraged. Use Kernel#enum_for(), alias
302 * e = Enumerator.new(ObjectSpace, :each_object)
303 * #-> ObjectSpace.enum_for(:each_object)
305 * e.select { |obj| obj.is_a?(Class) } #=> array of all classes
307 * In the second form, iteration is defined by the given block, in
308 * which a "yielder" object given as block parameter can be used to
309 * yield a value by calling the +yield+ method, alias +<<+.
311 * fib = Enumerator.new { |y|
319 * p fib.take(10) #=> [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
322 enumerator_initialize(int argc, VALUE *argv, VALUE obj)
324 VALUE recv, meth = sym_each;
327 if (!rb_block_given_p())
328 rb_raise(rb_eArgError, "wrong number of argument (0 for 1+)");
330 recv = generator_init(generator_allocate(rb_cGenerator), rb_block_proc());
339 return enumerator_init(obj, recv, meth, argc, argv);
344 enumerator_init_copy(VALUE obj, VALUE orig)
346 struct enumerator *ptr0, *ptr1;
348 ptr0 = enumerator_ptr(orig);
350 /* Fibers cannot be copied */
351 rb_raise(rb_eTypeError, "can't copy execution context");
354 Data_Get_Struct(obj, struct enumerator, ptr1);
357 rb_raise(rb_eArgError, "unallocated enumerator");
360 ptr1->obj = ptr0->obj;
361 ptr1->meth = ptr0->meth;
362 ptr1->args = ptr0->args;
369 rb_enumeratorize(VALUE obj, VALUE meth, int argc, VALUE *argv)
371 return enumerator_init(enumerator_allocate(rb_cEnumerator), obj, meth, argc, argv);
378 * Iterates the given block using the object and the method specified
379 * in the first place. If no block is given, returns self.
383 enumerator_each(VALUE obj)
385 struct enumerator *e;
389 if (!rb_block_given_p()) return obj;
390 e = enumerator_ptr(obj);
392 argc = RARRAY_LEN(e->args);
393 argv = RARRAY_PTR(e->args);
395 return rb_block_call(e->obj, e->meth, argc, argv,
396 enumerator_each_i, (VALUE)e);
400 enumerator_with_index_i(VALUE val, VALUE *memo)
402 val = rb_yield_values(2, val, INT2FIX(*memo));
409 * e.with_index {|(*args), idx| ... }
412 * Iterates the given block for each element with an index, which
413 * start from 0. If no block is given, returns an enumerator.
417 enumerator_with_index(VALUE obj)
419 struct enumerator *e;
424 RETURN_ENUMERATOR(obj, 0, 0);
425 e = enumerator_ptr(obj);
427 argc = RARRAY_LEN(e->args);
428 argv = RARRAY_PTR(e->args);
430 return rb_block_call(e->obj, e->meth, argc, argv,
431 enumerator_with_index_i, (VALUE)&memo);
435 enumerator_with_object_i(VALUE val, VALUE memo)
437 return rb_yield_values(2, val, memo);
442 * e.with_object(obj) {|(*args), memo_obj| ... }
445 * Iterates the given block for each element with an arbitrary
446 * object given, and returns the initially given object.
448 * If no block is given, returns an enumerator.
452 enumerator_with_object(VALUE obj, VALUE memo)
454 struct enumerator *e;
458 RETURN_ENUMERATOR(obj, 1, &memo);
459 e = enumerator_ptr(obj);
461 argc = RARRAY_LEN(e->args);
462 argv = RARRAY_PTR(e->args);
464 rb_block_call(e->obj, e->meth, argc, argv,
465 enumerator_with_object_i, memo);
471 next_ii(VALUE i, VALUE obj, int argc, VALUE *argv)
473 rb_fiber_yield(argc, argv);
478 next_i(VALUE curr, VALUE obj)
480 struct enumerator *e = enumerator_ptr(obj);
483 rb_block_call(obj, rb_intern("each"), 0, 0, next_ii, obj);
485 return rb_fiber_yield(1, &nil);
489 next_init(VALUE obj, struct enumerator *e)
491 VALUE curr = rb_fiber_current();
493 e->fib = rb_fiber_new(next_i, obj);
500 * Returns the next object in the enumerator, and move the internal
501 * position forward. When the position reached at the end, internal
502 * position is rewound then StopIteration is raised.
504 * Note that enumeration sequence by next method does not affect other
505 * non-external enumeration methods, unless underlying iteration
506 * methods itself has side-effect, e.g. IO#each_line.
511 enumerator_next(VALUE obj)
513 struct enumerator *e = enumerator_ptr(obj);
515 curr = rb_fiber_current();
517 if (!e->fib || !rb_fiber_alive_p(e->fib)) {
521 v = rb_fiber_resume(e->fib, 1, &curr);
526 rb_raise(rb_eStopIteration, "iteration reached at end");
535 * Rewinds the enumeration sequence by the next method.
537 * If the enclosed object responds to a "rewind" method, it is called.
541 enumerator_rewind(VALUE obj)
543 struct enumerator *e = enumerator_ptr(obj);
545 if (rb_respond_to(e->obj, id_rewind))
546 rb_funcall(e->obj, id_rewind, 0);
558 yielder_mark(void *p)
560 struct yielder *ptr = p;
561 rb_gc_mark(ptr->proc);
564 static struct yielder *
565 yielder_ptr(VALUE obj)
569 Data_Get_Struct(obj, struct yielder, ptr);
570 if (RDATA(obj)->dmark != yielder_mark) {
571 rb_raise(rb_eTypeError,
572 "wrong argument type %s (expected %s)",
573 rb_obj_classname(obj), rb_class2name(rb_cYielder));
575 if (!ptr || ptr->proc == Qundef) {
576 rb_raise(rb_eArgError, "uninitialized yielder");
583 yielder_allocate(VALUE klass)
588 obj = Data_Make_Struct(klass, struct yielder, yielder_mark, -1, ptr);
595 yielder_init(VALUE obj, VALUE proc)
599 Data_Get_Struct(obj, struct yielder, ptr);
602 rb_raise(rb_eArgError, "unallocated yielder");
612 yielder_initialize(VALUE obj)
616 return yielder_init(obj, rb_block_proc());
621 yielder_yield(VALUE obj, VALUE args)
623 struct yielder *ptr = yielder_ptr(obj);
625 rb_proc_call(ptr->proc, args);
631 yielder_new_i(VALUE dummy)
633 return yielder_init(yielder_allocate(rb_cYielder), rb_block_proc());
637 yielder_yield_i(VALUE obj, VALUE memo, int argc, VALUE *argv)
639 return rb_yield_values2(argc, argv);
645 return rb_iterate(yielder_new_i, (VALUE)0, yielder_yield_i, (VALUE)0);
652 generator_mark(void *p)
654 struct generator *ptr = p;
655 rb_gc_mark(ptr->proc);
658 static struct generator *
659 generator_ptr(VALUE obj)
661 struct generator *ptr;
663 Data_Get_Struct(obj, struct generator, ptr);
664 if (RDATA(obj)->dmark != generator_mark) {
665 rb_raise(rb_eTypeError,
666 "wrong argument type %s (expected %s)",
667 rb_obj_classname(obj), rb_class2name(rb_cGenerator));
669 if (!ptr || ptr->proc == Qundef) {
670 rb_raise(rb_eArgError, "uninitialized generator");
677 generator_allocate(VALUE klass)
679 struct generator *ptr;
682 obj = Data_Make_Struct(klass, struct generator, generator_mark, -1, ptr);
689 generator_init(VALUE obj, VALUE proc)
691 struct generator *ptr;
693 Data_Get_Struct(obj, struct generator, ptr);
696 rb_raise(rb_eArgError, "unallocated generator");
704 VALUE rb_obj_is_proc(VALUE proc);
708 generator_initialize(int argc, VALUE *argv, VALUE obj)
715 proc = rb_block_proc();
717 rb_scan_args(argc, argv, "1", &proc);
719 if (!rb_obj_is_proc(proc))
720 rb_raise(rb_eTypeError,
721 "wrong argument type %s (expected Proc)",
722 rb_obj_classname(proc));
724 if (rb_block_given_p()) {
725 rb_warn("given block not used");
729 return generator_init(obj, proc);
734 generator_init_copy(VALUE obj, VALUE orig)
736 struct generator *ptr0, *ptr1;
738 ptr0 = generator_ptr(orig);
740 Data_Get_Struct(obj, struct generator, ptr1);
743 rb_raise(rb_eArgError, "unallocated generator");
746 ptr1->proc = ptr0->proc;
753 generator_each(VALUE obj)
755 struct generator *ptr = generator_ptr(obj);
758 yielder = yielder_new();
760 rb_proc_call(ptr->proc, rb_ary_new3(1, yielder));
766 Init_Enumerator(void)
768 rb_define_method(rb_mKernel, "to_enum", obj_to_enum, -1);
769 rb_define_method(rb_mKernel, "enum_for", obj_to_enum, -1);
771 rb_define_method(rb_mEnumerable, "each_slice", enum_each_slice, 1);
772 rb_define_method(rb_mEnumerable, "each_cons", enum_each_cons, 1);
773 rb_define_method(rb_mEnumerable, "each_with_object", enum_each_with_object, 1);
775 rb_cEnumerator = rb_define_class("Enumerator", rb_cObject);
776 rb_include_module(rb_cEnumerator, rb_mEnumerable);
778 rb_define_alloc_func(rb_cEnumerator, enumerator_allocate);
779 rb_define_method(rb_cEnumerator, "initialize", enumerator_initialize, -1);
780 rb_define_method(rb_cEnumerator, "initialize_copy", enumerator_init_copy, 1);
781 rb_define_method(rb_cEnumerator, "each", enumerator_each, 0);
782 rb_define_method(rb_cEnumerator, "each_with_index", enumerator_with_index, 0);
783 rb_define_method(rb_cEnumerator, "each_with_object", enumerator_with_object, 1);
784 rb_define_method(rb_cEnumerator, "with_index", enumerator_with_index, 0);
785 rb_define_method(rb_cEnumerator, "with_object", enumerator_with_object, 1);
786 rb_define_method(rb_cEnumerator, "next", enumerator_next, 0);
787 rb_define_method(rb_cEnumerator, "rewind", enumerator_rewind, 0);
789 rb_eStopIteration = rb_define_class("StopIteration", rb_eIndexError);
792 rb_cGenerator = rb_define_class_under(rb_cEnumerator, "Generator", rb_cObject);
793 rb_include_module(rb_cGenerator, rb_mEnumerable);
794 rb_define_alloc_func(rb_cGenerator, generator_allocate);
795 rb_define_method(rb_cGenerator, "initialize", generator_initialize, -1);
796 rb_define_method(rb_cGenerator, "initialize_copy", generator_init_copy, 1);
797 rb_define_method(rb_cGenerator, "each", generator_each, 0);
800 rb_cYielder = rb_define_class_under(rb_cEnumerator, "Yielder", rb_cObject);
801 rb_define_alloc_func(rb_cYielder, yielder_allocate);
802 rb_define_method(rb_cYielder, "initialize", yielder_initialize, 0);
803 rb_define_method(rb_cYielder, "yield", yielder_yield, -2);
804 rb_define_method(rb_cYielder, "<<", yielder_yield, -2);
806 sym_each = ID2SYM(rb_intern("each"));
807 id_rewind = rb_intern("rewind");
809 rb_provide("enumerator.so"); /* for backward compatibility */