Ruby: enumerator.c Source File

Ruby 4.0.6p0 (2026-07-14 revision 03b6d3f8898a28604fe6cb00eae3226b821168f4)

enumerator.c
1/************************************************
2
3 enumerator.c - provides Enumerator class
4
5 $Author$
6
7 Copyright (C) 2001-2003 Akinori MUSHA
8
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$
12
13************************************************/
14
15#include "ruby/internal/config.h"
16
17#ifdef HAVE_FLOAT_H
18#include <float.h>
19#endif
20
21#include <limits.h>
22#include "id.h"
23#include "internal.h"
24#include "internal/class.h"
25#include "internal/enumerator.h"
26#include "internal/error.h"
27#include "internal/hash.h"
28#include "internal/imemo.h"
29#include "internal/numeric.h"
30#include "internal/range.h"
31#include "internal/rational.h"
32#include "ruby/ruby.h"
33
34/*
35 * Document-class: Enumerator
36 *
37 * A class which allows both internal and external iteration.
38 *
39 * An Enumerator can be created by the following methods.
40 * - Object#to_enum
41 * - Object#enum_for
42 * - Enumerator.new
43 *
44 * Most methods have two forms: a block form where the contents
45 * are evaluated for each item in the enumeration, and a non-block form
46 * which returns a new Enumerator wrapping the iteration.
47 *
48 * enumerator = %w(one two three).each
49 * puts enumerator.class # => Enumerator
50 *
51 * enumerator.each_with_object("foo") do |item, obj|
52 * puts "#{obj}: #{item}"
53 * end
54 *
55 * # foo: one
56 * # foo: two
57 * # foo: three
58 *
59 * enum_with_obj = enumerator.each_with_object("foo")
60 * puts enum_with_obj.class # => Enumerator
61 *
62 * enum_with_obj.each do |item, obj|
63 * puts "#{obj}: #{item}"
64 * end
65 *
66 * # foo: one
67 * # foo: two
68 * # foo: three
69 *
70 * This allows you to chain Enumerators together. For example, you
71 * can map a list's elements to strings containing the index
72 * and the element as a string via:
73 *
74 * puts %w[foo bar baz].map.with_index { |w, i| "#{i}:#{w}" }
75 * # => ["0:foo", "1:bar", "2:baz"]
76 *
77 * == External Iteration
78 *
79 * An Enumerator can also be used as an external iterator.
80 * For example, Enumerator#next returns the next value of the iterator
81 * or raises StopIteration if the Enumerator is at the end.
82 *
83 * e = [1,2,3].each # returns an enumerator object.
84 * puts e.next # => 1
85 * puts e.next # => 2
86 * puts e.next # => 3
87 * puts e.next # raises StopIteration
88 *
89 * +next+, +next_values+, +peek+, and +peek_values+ are the only methods
90 * which use external iteration (and Array#zip(Enumerable-not-Array) which uses +next+ internally).
91 *
92 * These methods do not affect other internal enumeration methods,
93 * unless the underlying iteration method itself has side-effect, e.g. IO#each_line.
94 *
95 * FrozenError will be raised if these methods are called against a frozen enumerator.
96 * Since +rewind+ and +feed+ also change state for external iteration,
97 * these methods may raise FrozenError too.
98 *
99 * External iteration differs *significantly* from internal iteration
100 * due to using a Fiber:
101 * - The Fiber adds some overhead compared to internal enumeration.
102 * - The stacktrace will only include the stack from the Enumerator, not above.
103 * - Fiber-local variables are *not* inherited inside the Enumerator Fiber,
104 * which instead starts with no Fiber-local variables.
105 * - Fiber storage variables *are* inherited and are designed
106 * to handle Enumerator Fibers. Assigning to a Fiber storage variable
107 * only affects the current Fiber, so if you want to change state
108 * in the caller Fiber of the Enumerator Fiber, you need to use an
109 * extra indirection (e.g., use some object in the Fiber storage
110 * variable and mutate some ivar of it).
111 *
112 * Concretely:
113 *
114 * Thread.current[:fiber_local] = 1
115 * Fiber[:storage_var] = 1
116 * e = Enumerator.new do |y|
117 * p Thread.current[:fiber_local] # for external iteration: nil, for internal iteration: 1
118 * p Fiber[:storage_var] # => 1, inherited
119 * Fiber[:storage_var] += 1
120 * y << 42
121 * end
122 *
123 * p e.next # => 42
124 * p Fiber[:storage_var] # => 1 (it ran in a different Fiber)
125 *
126 * e.each { p _1 }
127 * p Fiber[:storage_var] # => 2 (it ran in the same Fiber/"stack" as the current Fiber)
128 *
129 * == Convert External Iteration to Internal Iteration
130 *
131 * You can use an external iterator to implement an internal iterator as follows:
132 *
133 * def ext_each(e)
134 * while true
135 * begin
136 * vs = e.next_values
137 * rescue StopIteration
138 * return $!.result
139 * end
140 * y = yield(*vs)
141 * e.feed y
142 * end
143 * end
144 *
145 * o = Object.new
146 *
147 * def o.each
148 * puts yield
149 * puts yield(1)
150 * puts yield(1, 2)
151 * 3
152 * end
153 *
154 * # use o.each as an internal iterator directly.
155 * puts o.each {|*x| puts x; [:b, *x] }
156 * # => [], [:b], [1], [:b, 1], [1, 2], [:b, 1, 2], 3
157 *
158 * # convert o.each to an external iterator for
159 * # implementing an internal iterator.
160 * puts ext_each(o.to_enum) {|*x| puts x; [:b, *x] }
161 * # => [], [:b], [1], [:b, 1], [1, 2], [:b, 1, 2], 3
162 *
163 */
164 VALUE rb_cEnumerator;
165static VALUE rb_cLazy;
166static ID id_rewind, id_to_enum, id_each_entry;
167static ID id_next, id_result, id_receiver, id_arguments, id_memo, id_method, id_force;
168static VALUE sym_each, sym_yield;
169
170static VALUE lazy_use_super_method;
171
172extern ID ruby_static_id_cause;
173
174#define id_call idCall
175#define id_cause ruby_static_id_cause
176#define id_each idEach
177#define id_eqq idEqq
178#define id_initialize idInitialize
179#define id_size idSize
180
181 VALUE rb_eStopIteration;
182
183 struct enumerator {
184 VALUE obj;
185 ID meth;
186 VALUE args;
187 VALUE fib;
188 VALUE dst;
189 VALUE lookahead;
190 VALUE feedvalue;
191 VALUE stop_exc;
192 VALUE size;
193 VALUE procs;
194 rb_enumerator_size_func *size_fn;
195 int kw_splat;
196};
197
198RUBY_REFERENCES(enumerator_refs) = {
199 RUBY_REF_EDGE(struct enumerator, obj),
200 RUBY_REF_EDGE(struct enumerator, args),
201 RUBY_REF_EDGE(struct enumerator, fib),
202 RUBY_REF_EDGE(struct enumerator, dst),
203 RUBY_REF_EDGE(struct enumerator, lookahead),
204 RUBY_REF_EDGE(struct enumerator, feedvalue),
205 RUBY_REF_EDGE(struct enumerator, stop_exc),
206 RUBY_REF_EDGE(struct enumerator, size),
207 RUBY_REF_EDGE(struct enumerator, procs),
208 RUBY_REF_END
209};
210
211static VALUE rb_cGenerator, rb_cYielder, rb_cEnumProducer;
212
213 struct generator {
214 VALUE proc;
215 VALUE obj;
216};
217
218 struct yielder {
219 VALUE proc;
220};
221
222 struct producer {
223 VALUE init;
224 VALUE proc;
225 VALUE size;
226};
227
228typedef struct MEMO *lazyenum_proc_func(VALUE, struct MEMO *, VALUE, long);
229typedef VALUE lazyenum_size_func(VALUE, VALUE);
230typedef int lazyenum_precheck_func(VALUE proc_entry);
231 typedef struct {
232 lazyenum_proc_func *proc;
233 lazyenum_size_func *size;
234 lazyenum_precheck_func *precheck;
235} lazyenum_funcs;
236
237 struct proc_entry {
238 VALUE proc;
239 VALUE memo;
240 const lazyenum_funcs *fn;
241};
242
243static VALUE generator_allocate(VALUE klass);
244static VALUE generator_init(VALUE obj, VALUE proc);
245
246static VALUE rb_cEnumChain;
247
248 struct enum_chain {
249 VALUE enums;
250 long pos;
251};
252
253static VALUE rb_cEnumProduct;
254
255 struct enum_product {
256 VALUE enums;
257};
258
259 VALUE rb_cArithSeq;
260
261static const rb_data_type_t enumerator_data_type = {
262 "enumerator",
263 {
264 RUBY_REFS_LIST_PTR(enumerator_refs),
265 RUBY_TYPED_DEFAULT_FREE,
266 NULL, // Nothing allocated externally, so don't need a memsize function
267 NULL,
268 },
269 0, NULL, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_DECL_MARKING | RUBY_TYPED_EMBEDDABLE
270};
271
272static struct enumerator *
273enumerator_ptr(VALUE obj)
274{
275 struct enumerator *ptr;
276
277 TypedData_Get_Struct(obj, struct enumerator, &enumerator_data_type, ptr);
278 if (!ptr || UNDEF_P(ptr->obj)) {
279 rb_raise(rb_eArgError, "uninitialized enumerator");
280 }
281 return ptr;
282}
283
284static void
285proc_entry_mark_and_move(void *p)
286{
287 struct proc_entry *ptr = p;
288 rb_gc_mark_and_move(&ptr->proc);
289 rb_gc_mark_and_move(&ptr->memo);
290}
291
292static const rb_data_type_t proc_entry_data_type = {
293 "proc_entry",
294 {
295 proc_entry_mark_and_move,
296 RUBY_TYPED_DEFAULT_FREE,
297 NULL, // Nothing allocated externally, so don't need a memsize function
298 proc_entry_mark_and_move,
299 },
300 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE
301};
302
303static struct proc_entry *
304proc_entry_ptr(VALUE proc_entry)
305{
306 struct proc_entry *ptr;
307
308 TypedData_Get_Struct(proc_entry, struct proc_entry, &proc_entry_data_type, ptr);
309
310 return ptr;
311}
312
313/*
314 * call-seq:
315 * obj.to_enum(method = :each, *args) -> enum
316 * obj.enum_for(method = :each, *args) -> enum
317 * obj.to_enum(method = :each, *args) {|*args| block} -> enum
318 * obj.enum_for(method = :each, *args){|*args| block} -> enum
319 *
320 * Creates a new Enumerator which will enumerate by calling +method+ on
321 * +obj+, passing +args+ if any. What was _yielded_ by method becomes
322 * values of enumerator.
323 *
324 * If a block is given, it will be used to calculate the size of
325 * the enumerator without the need to iterate it (see Enumerator#size).
326 *
327 * === Examples
328 *
329 * str = "xyz"
330 *
331 * enum = str.enum_for(:each_byte)
332 * enum.each { |b| puts b }
333 * # => 120
334 * # => 121
335 * # => 122
336 *
337 * # protect an array from being modified by some_method
338 * a = [1, 2, 3]
339 * some_method(a.to_enum)
340 *
341 * # String#split in block form is more memory-effective:
342 * very_large_string.split("|") { |chunk| return chunk if chunk.include?('DATE') }
343 * # This could be rewritten more idiomatically with to_enum:
344 * very_large_string.to_enum(:split, "|").lazy.grep(/DATE/).first
345 *
346 * It is typical to call to_enum when defining methods for
347 * a generic Enumerable, in case no block is passed.
348 *
349 * Here is such an example, with parameter passing and a sizing block:
350 *
351 * module Enumerable
352 * # a generic method to repeat the values of any enumerable
353 * def repeat(n)
354 * raise ArgumentError, "#{n} is negative!" if n < 0
355 * unless block_given?
356 * return to_enum(__method__, n) do # __method__ is :repeat here
357 * sz = size # Call size and multiply by n...
358 * sz * n if sz # but return nil if size itself is nil
359 * end
360 * end
361 * each do |*val|
362 * n.times { yield *val }
363 * end
364 * end
365 * end
366 *
367 * %i[hello world].repeat(2) { |w| puts w }
368 * # => Prints 'hello', 'hello', 'world', 'world'
369 * enum = (1..14).repeat(3)
370 * # => returns an Enumerator when called without a block
371 * enum.first(4) # => [1, 1, 1, 2]
372 * enum.size # => 42
373 */
374static VALUE
375obj_to_enum(int argc, VALUE *argv, VALUE obj)
376{
377 VALUE enumerator, meth = sym_each;
378
379 if (argc > 0) {
380 --argc;
381 meth = *argv++;
382 }
383 enumerator = rb_enumeratorize_with_size(obj, meth, argc, argv, 0);
384 if (rb_block_given_p()) {
385 RB_OBJ_WRITE(enumerator, &enumerator_ptr(enumerator)->size, rb_block_proc());
386 }
387 return enumerator;
388}
389
390static VALUE
391enumerator_allocate(VALUE klass)
392{
393 struct enumerator *ptr;
394 VALUE enum_obj;
395
396 enum_obj = TypedData_Make_Struct(klass, struct enumerator, &enumerator_data_type, ptr);
397 ptr->obj = Qundef;
398
399 return enum_obj;
400}
401
402static VALUE
403enumerator_init(VALUE enum_obj, VALUE obj, VALUE meth, int argc, const VALUE *argv, rb_enumerator_size_func *size_fn, VALUE size, int kw_splat)
404{
405 struct enumerator *ptr;
406
407 rb_check_frozen(enum_obj);
408 TypedData_Get_Struct(enum_obj, struct enumerator, &enumerator_data_type, ptr);
409
410 if (!ptr) {
411 rb_raise(rb_eArgError, "unallocated enumerator");
412 }
413
414 RB_OBJ_WRITE(enum_obj, &ptr->obj, obj);
415 ptr->meth = rb_to_id(meth);
416 if (argc) RB_OBJ_WRITE(enum_obj, &ptr->args, rb_ary_new4(argc, argv));
417 ptr->fib = 0;
418 ptr->dst = Qnil;
419 ptr->lookahead = Qundef;
420 ptr->feedvalue = Qundef;
421 ptr->stop_exc = Qfalse;
422 RB_OBJ_WRITE(enum_obj, &ptr->size, size);
423 ptr->size_fn = size_fn;
424 ptr->kw_splat = kw_splat;
425
426 return enum_obj;
427}
428
429static VALUE
430convert_to_feasible_size_value(VALUE obj)
431{
432 if (NIL_P(obj)) {
433 return obj;
434 }
435 else if (rb_respond_to(obj, id_call)) {
436 return obj;
437 }
438 else if (RB_FLOAT_TYPE_P(obj) && RFLOAT_VALUE(obj) == HUGE_VAL) {
439 return obj;
440 }
441 else {
442 return rb_to_int(obj);
443 }
444}
445
446/*
447 * call-seq:
448 * Enumerator.new(size = nil) { |yielder| ... }
449 *
450 * Creates a new Enumerator object, which can be used as an
451 * Enumerable.
452 *
453 * Iteration is defined by the given block, in
454 * which a "yielder" object, given as block parameter, can be used to
455 * yield a value by calling the +yield+ method (aliased as <code><<</code>):
456 *
457 * fib = Enumerator.new do |y|
458 * a = b = 1
459 * loop do
460 * y << a
461 * a, b = b, a + b
462 * end
463 * end
464 *
465 * fib.take(10) # => [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
466 *
467 * The optional parameter can be used to specify how to calculate the size
468 * in a lazy fashion (see Enumerator#size). It can either be a value or
469 * a callable object.
470 */
471static VALUE
472enumerator_initialize(int argc, VALUE *argv, VALUE obj)
473{
474 VALUE iter = rb_block_proc();
475 VALUE recv = generator_init(generator_allocate(rb_cGenerator), iter);
476 VALUE arg0 = rb_check_arity(argc, 0, 1) ? argv[0] : Qnil;
477 VALUE size = convert_to_feasible_size_value(arg0);
478
479 return enumerator_init(obj, recv, sym_each, 0, 0, 0, size, false);
480}
481
482/* :nodoc: */
483static VALUE
484enumerator_init_copy(VALUE obj, VALUE orig)
485{
486 struct enumerator *ptr0, *ptr1;
487
488 if (!OBJ_INIT_COPY(obj, orig)) return obj;
489 ptr0 = enumerator_ptr(orig);
490 if (ptr0->fib) {
491 /* Fibers cannot be copied */
492 rb_raise(rb_eTypeError, "can't copy execution context");
493 }
494
495 TypedData_Get_Struct(obj, struct enumerator, &enumerator_data_type, ptr1);
496
497 if (!ptr1) {
498 rb_raise(rb_eArgError, "unallocated enumerator");
499 }
500
501 RB_OBJ_WRITE(obj, &ptr1->obj, ptr0->obj);
502 ptr1->meth = ptr0->meth;
503 RB_OBJ_WRITE(obj, &ptr1->args, ptr0->args);
504 ptr1->fib = 0;
505 ptr1->lookahead = Qundef;
506 ptr1->feedvalue = Qundef;
507 RB_OBJ_WRITE(obj, &ptr1->size, ptr0->size);
508 ptr1->size_fn = ptr0->size_fn;
509
510 return obj;
511}
512
513/*
514 * For backwards compatibility; use rb_enumeratorize_with_size
515 */
516 VALUE
517rb_enumeratorize(VALUE obj, VALUE meth, int argc, const VALUE *argv)
518{
519 return rb_enumeratorize_with_size(obj, meth, argc, argv, 0);
520}
521
522static VALUE lazy_to_enum_i(VALUE self, VALUE meth, int argc, const VALUE *argv, rb_enumerator_size_func *size_fn, int kw_splat);
523static int lazy_precheck(VALUE procs);
524
525 VALUE
526rb_enumeratorize_with_size_kw(VALUE obj, VALUE meth, int argc, const VALUE *argv, rb_enumerator_size_func *size_fn, int kw_splat)
527{
528 VALUE base_class = rb_cEnumerator;
529
530 if (RTEST(rb_obj_is_kind_of(obj, rb_cLazy))) {
531 base_class = rb_cLazy;
532 }
533 else if (RTEST(rb_obj_is_kind_of(obj, rb_cEnumChain))) {
534 obj = enumerator_init(enumerator_allocate(rb_cEnumerator), obj, sym_each, 0, 0, 0, Qnil, false);
535 }
536
537 return enumerator_init(enumerator_allocate(base_class),
538 obj, meth, argc, argv, size_fn, Qnil, kw_splat);
539}
540
541 VALUE
542rb_enumeratorize_with_size(VALUE obj, VALUE meth, int argc, const VALUE *argv, rb_enumerator_size_func *size_fn)
543{
544 return rb_enumeratorize_with_size_kw(obj, meth, argc, argv, size_fn, rb_keyword_given_p());
545}
546
547static VALUE
548enumerator_block_call(VALUE obj, rb_block_call_func *func, VALUE arg)
549{
550 int argc = 0;
551 const VALUE *argv = 0;
552 const struct enumerator *e = enumerator_ptr(obj);
553 ID meth = e->meth;
554
555 VALUE args = e->args;
556 if (args) {
557 argc = RARRAY_LENINT(args);
558 argv = RARRAY_CONST_PTR(args);
559 }
560
561 VALUE ret = rb_block_call_kw(e->obj, meth, argc, argv, func, arg, e->kw_splat);
562
563 RB_GC_GUARD(args);
564
565 return ret;
566}
567
568/*
569 * call-seq:
570 * enum.each { |elm| block } -> obj
571 * enum.each -> enum
572 * enum.each(*appending_args) { |elm| block } -> obj
573 * enum.each(*appending_args) -> an_enumerator
574 *
575 * Iterates over the block according to how this Enumerator was constructed.
576 * If no block and no arguments are given, returns self.
577 *
578 * === Examples
579 *
580 * "Hello, world!".scan(/\w+/) #=> ["Hello", "world"]
581 * "Hello, world!".to_enum(:scan, /\w+/).to_a #=> ["Hello", "world"]
582 * "Hello, world!".to_enum(:scan).each(/\w+/).to_a #=> ["Hello", "world"]
583 *
584 * obj = Object.new
585 *
586 * def obj.each_arg(a, b=:b, *rest)
587 * yield a
588 * yield b
589 * yield rest
590 * :method_returned
591 * end
592 *
593 * enum = obj.to_enum :each_arg, :a, :x
594 *
595 * enum.each.to_a #=> [:a, :x, []]
596 * enum.each.equal?(enum) #=> true
597 * enum.each { |elm| elm } #=> :method_returned
598 *
599 * enum.each(:y, :z).to_a #=> [:a, :x, [:y, :z]]
600 * enum.each(:y, :z).equal?(enum) #=> false
601 * enum.each(:y, :z) { |elm| elm } #=> :method_returned
602 *
603 */
604static VALUE
605enumerator_each(int argc, VALUE *argv, VALUE obj)
606{
607 struct enumerator *e = enumerator_ptr(obj);
608
609 if (argc > 0) {
610 VALUE args = (e = enumerator_ptr(obj = rb_obj_dup(obj)))->args;
611 if (args) {
612#if SIZEOF_INT < SIZEOF_LONG
613 /* check int range overflow */
614 rb_long2int(RARRAY_LEN(args) + argc);
615#endif
616 args = rb_ary_dup(args);
617 rb_ary_cat(args, argv, argc);
618 }
619 else {
620 args = rb_ary_new4(argc, argv);
621 }
622 RB_OBJ_WRITE(obj, &e->args, args);
623 e->size = Qnil;
624 e->size_fn = 0;
625 }
626 if (!rb_block_given_p()) return obj;
627
628 if (!lazy_precheck(e->procs)) return Qnil;
629
630 return enumerator_block_call(obj, 0, obj);
631}
632
633static VALUE
634enumerator_with_index_i(RB_BLOCK_CALL_FUNC_ARGLIST(val, m))
635{
636 struct MEMO *memo = (struct MEMO *)m;
637 VALUE idx = memo->v1;
638 MEMO_V1_SET(memo, rb_int_succ(idx));
639
640 if (argc <= 1)
641 return rb_yield_values(2, val, idx);
642
643 return rb_yield_values(2, rb_ary_new4(argc, argv), idx);
644}
645
646static VALUE
647enumerator_size(VALUE obj);
648
649static VALUE
650enumerator_enum_size(VALUE obj, VALUE args, VALUE eobj)
651{
652 return enumerator_size(obj);
653}
654
655/*
656 * call-seq:
657 * e.with_index(offset = 0) {|(*args), idx| ... }
658 * e.with_index(offset = 0)
659 *
660 * Iterates the given block for each element with an index, which
661 * starts from +offset+. If no block is given, returns a new Enumerator
662 * that includes the index, starting from +offset+
663 *
664 * +offset+:: the starting index to use
665 *
666 */
667static VALUE
668enumerator_with_index(int argc, VALUE *argv, VALUE obj)
669{
670 VALUE memo;
671
672 rb_check_arity(argc, 0, 1);
673 RETURN_SIZED_ENUMERATOR(obj, argc, argv, enumerator_enum_size);
674 memo = (!argc || NIL_P(memo = argv[0])) ? INT2FIX(0) : rb_to_int(memo);
675 return enumerator_block_call(obj, enumerator_with_index_i, (VALUE)MEMO_NEW(memo, 0, 0));
676}
677
678/*
679 * call-seq:
680 * e.each_with_index {|(*args), idx| ... }
681 * e.each_with_index
682 *
683 * Same as Enumerator#with_index(0), i.e. there is no starting offset.
684 *
685 * If no block is given, a new Enumerator is returned that includes the index.
686 *
687 */
688static VALUE
689enumerator_each_with_index(VALUE obj)
690{
691 return enumerator_with_index(0, NULL, obj);
692}
693
694static VALUE
695enumerator_with_object_i(RB_BLOCK_CALL_FUNC_ARGLIST(val, memo))
696{
697 if (argc <= 1)
698 return rb_yield_values(2, val, memo);
699
700 return rb_yield_values(2, rb_ary_new4(argc, argv), memo);
701}
702
703/*
704 * call-seq:
705 * e.each_with_object(obj) {|(*args), obj| ... }
706 * e.each_with_object(obj)
707 * e.with_object(obj) {|(*args), obj| ... }
708 * e.with_object(obj)
709 *
710 * Iterates the given block for each element with an arbitrary object, +obj+,
711 * and returns +obj+
712 *
713 * If no block is given, returns a new Enumerator.
714 *
715 * === Example
716 *
717 * to_three = Enumerator.new do |y|
718 * 3.times do |x|
719 * y << x
720 * end
721 * end
722 *
723 * to_three_with_string = to_three.with_object("foo")
724 * to_three_with_string.each do |x,string|
725 * puts "#{string}: #{x}"
726 * end
727 *
728 * # => foo: 0
729 * # => foo: 1
730 * # => foo: 2
731 */
732static VALUE
733enumerator_with_object(VALUE obj, VALUE memo)
734{
735 RETURN_SIZED_ENUMERATOR(obj, 1, &memo, enumerator_enum_size);
736 enumerator_block_call(obj, enumerator_with_object_i, memo);
737
738 return memo;
739}
740
741static VALUE
742next_ii(RB_BLOCK_CALL_FUNC_ARGLIST(i, obj))
743{
744 struct enumerator *e = enumerator_ptr(obj);
745 VALUE feedvalue = Qnil;
746 VALUE args = rb_ary_new4(argc, argv);
747 rb_fiber_yield(1, &args);
748 if (!UNDEF_P(e->feedvalue)) {
749 feedvalue = e->feedvalue;
750 e->feedvalue = Qundef;
751 }
752 return feedvalue;
753}
754
755static VALUE
756next_i(RB_BLOCK_CALL_FUNC_ARGLIST(_, obj))
757{
758 struct enumerator *e = enumerator_ptr(obj);
759 VALUE nil = Qnil;
760 VALUE result;
761
762 result = rb_block_call(obj, id_each, 0, 0, next_ii, obj);
763 RB_OBJ_WRITE(obj, &e->stop_exc, rb_exc_new2(rb_eStopIteration, "iteration reached an end"));
764 rb_ivar_set(e->stop_exc, id_result, result);
765 return rb_fiber_yield(1, &nil);
766}
767
768static void
769next_init(VALUE obj, struct enumerator *e)
770{
771 VALUE curr = rb_fiber_current();
772 RB_OBJ_WRITE(obj, &e->dst, curr);
773 RB_OBJ_WRITE(obj, &e->fib, rb_fiber_new(next_i, obj));
774 e->lookahead = Qundef;
775}
776
777static VALUE
778get_next_values(VALUE obj, struct enumerator *e)
779{
780 VALUE curr, vs;
781
782 if (e->stop_exc) {
783 VALUE exc = e->stop_exc;
784 VALUE result = rb_attr_get(exc, id_result);
785 VALUE mesg = rb_attr_get(exc, idMesg);
786 if (!NIL_P(mesg)) mesg = rb_str_dup(mesg);
787 VALUE stop_exc = rb_exc_new_str(rb_eStopIteration, mesg);
788 rb_ivar_set(stop_exc, id_cause, exc);
789 rb_ivar_set(stop_exc, id_result, result);
790 rb_exc_raise(stop_exc);
791 }
792
793 curr = rb_fiber_current();
794
795 if (!e->fib || !rb_fiber_alive_p(e->fib)) {
796 next_init(obj, e);
797 }
798
799 vs = rb_fiber_resume(e->fib, 1, &curr);
800 if (e->stop_exc) {
801 e->fib = 0;
802 e->dst = Qnil;
803 e->lookahead = Qundef;
804 e->feedvalue = Qundef;
805 rb_exc_raise(e->stop_exc);
806 }
807 return vs;
808}
809
810/*
811 * call-seq:
812 * e.next_values -> array
813 *
814 * Returns the next object as an array in the enumerator, and move the
815 * internal position forward. When the position reached at the end,
816 * StopIteration is raised.
817 *
818 * See class-level notes about external iterators.
819 *
820 * This method can be used to distinguish <code>yield</code> and <code>yield
821 * nil</code>.
822 *
823 * === Example
824 *
825 * o = Object.new
826 * def o.each
827 * yield
828 * yield 1
829 * yield 1, 2
830 * yield nil
831 * yield [1, 2]
832 * end
833 * e = o.to_enum
834 * p e.next_values
835 * p e.next_values
836 * p e.next_values
837 * p e.next_values
838 * p e.next_values
839 * e = o.to_enum
840 * p e.next
841 * p e.next
842 * p e.next
843 * p e.next
844 * p e.next
845 *
846 * ## yield args next_values next
847 * # yield [] nil
848 * # yield 1 [1] 1
849 * # yield 1, 2 [1, 2] [1, 2]
850 * # yield nil [nil] nil
851 * # yield [1, 2] [[1, 2]] [1, 2]
852 *
853 */
854
855static VALUE
856enumerator_next_values(VALUE obj)
857{
858 struct enumerator *e = enumerator_ptr(obj);
859 VALUE vs;
860
861 rb_check_frozen(obj);
862
863 if (!UNDEF_P(e->lookahead)) {
864 vs = e->lookahead;
865 e->lookahead = Qundef;
866 return vs;
867 }
868
869 return get_next_values(obj, e);
870}
871
872static VALUE
873ary2sv(VALUE args, int dup)
874{
875 if (!RB_TYPE_P(args, T_ARRAY))
876 return args;
877
878 switch (RARRAY_LEN(args)) {
879 case 0:
880 return Qnil;
881
882 case 1:
883 return RARRAY_AREF(args, 0);
884
885 default:
886 if (dup)
887 return rb_ary_dup(args);
888 return args;
889 }
890}
891
892/*
893 * call-seq:
894 * e.next -> object
895 *
896 * Returns the next object in the enumerator, and move the internal position
897 * forward. When the position reached at the end, StopIteration is raised.
898 *
899 * === Example
900 *
901 * a = [1,2,3]
902 * e = a.to_enum
903 * p e.next #=> 1
904 * p e.next #=> 2
905 * p e.next #=> 3
906 * p e.next #raises StopIteration
907 *
908 * See class-level notes about external iterators.
909 *
910 */
911
912static VALUE
913enumerator_next(VALUE obj)
914{
915 VALUE vs = enumerator_next_values(obj);
916 return ary2sv(vs, 0);
917}
918
919static VALUE
920enumerator_peek_values(VALUE obj)
921{
922 struct enumerator *e = enumerator_ptr(obj);
923
924 rb_check_frozen(obj);
925
926 if (UNDEF_P(e->lookahead)) {
927 RB_OBJ_WRITE(obj, &e->lookahead, get_next_values(obj, e));
928 }
929
930 return e->lookahead;
931}
932
933/*
934 * call-seq:
935 * e.peek_values -> array
936 *
937 * Returns the next object as an array, similar to Enumerator#next_values, but
938 * doesn't move the internal position forward. If the position is already at
939 * the end, StopIteration is raised.
940 *
941 * See class-level notes about external iterators.
942 *
943 * === Example
944 *
945 * o = Object.new
946 * def o.each
947 * yield
948 * yield 1
949 * yield 1, 2
950 * end
951 * e = o.to_enum
952 * p e.peek_values #=> []
953 * e.next
954 * p e.peek_values #=> [1]
955 * p e.peek_values #=> [1]
956 * e.next
957 * p e.peek_values #=> [1, 2]
958 * e.next
959 * p e.peek_values # raises StopIteration
960 *
961 */
962
963static VALUE
964enumerator_peek_values_m(VALUE obj)
965{
966 return rb_ary_dup(enumerator_peek_values(obj));
967}
968
969/*
970 * call-seq:
971 * e.peek -> object
972 *
973 * Returns the next object in the enumerator, but doesn't move the internal
974 * position forward. If the position is already at the end, StopIteration
975 * is raised.
976 *
977 * See class-level notes about external iterators.
978 *
979 * === Example
980 *
981 * a = [1,2,3]
982 * e = a.to_enum
983 * p e.next #=> 1
984 * p e.peek #=> 2
985 * p e.peek #=> 2
986 * p e.peek #=> 2
987 * p e.next #=> 2
988 * p e.next #=> 3
989 * p e.peek #raises StopIteration
990 *
991 */
992
993static VALUE
994enumerator_peek(VALUE obj)
995{
996 VALUE vs = enumerator_peek_values(obj);
997 return ary2sv(vs, 1);
998}
999
1000/*
1001 * call-seq:
1002 * e.feed obj -> nil
1003 *
1004 * Sets the value to be returned by the next yield inside +e+.
1005 *
1006 * If the value is not set, the yield returns nil.
1007 *
1008 * This value is cleared after being yielded.
1009 *
1010 * # Array#map passes the array's elements to "yield" and collects the
1011 * # results of "yield" as an array.
1012 * # Following example shows that "next" returns the passed elements and
1013 * # values passed to "feed" are collected as an array which can be
1014 * # obtained by StopIteration#result.
1015 * e = [1,2,3].map
1016 * p e.next #=> 1
1017 * e.feed "a"
1018 * p e.next #=> 2
1019 * e.feed "b"
1020 * p e.next #=> 3
1021 * e.feed "c"
1022 * begin
1023 * e.next
1024 * rescue StopIteration
1025 * p $!.result #=> ["a", "b", "c"]
1026 * end
1027 *
1028 * o = Object.new
1029 * def o.each
1030 * x = yield # (2) blocks
1031 * p x # (5) => "foo"
1032 * x = yield # (6) blocks
1033 * p x # (8) => nil
1034 * x = yield # (9) blocks
1035 * p x # not reached w/o another e.next
1036 * end
1037 *
1038 * e = o.to_enum
1039 * e.next # (1)
1040 * e.feed "foo" # (3)
1041 * e.next # (4)
1042 * e.next # (7)
1043 * # (10)
1044 */
1045
1046static VALUE
1047enumerator_feed(VALUE obj, VALUE v)
1048{
1049 struct enumerator *e = enumerator_ptr(obj);
1050
1051 rb_check_frozen(obj);
1052
1053 if (!UNDEF_P(e->feedvalue)) {
1054 rb_raise(rb_eTypeError, "feed value already set");
1055 }
1056 RB_OBJ_WRITE(obj, &e->feedvalue, v);
1057
1058 return Qnil;
1059}
1060
1061/*
1062 * call-seq:
1063 * e.rewind -> e
1064 *
1065 * Rewinds the enumeration sequence to the beginning.
1066 *
1067 * If the enclosed object responds to a "rewind" method, it is called.
1068 */
1069
1070static VALUE
1071enumerator_rewind(VALUE obj)
1072{
1073 struct enumerator *e = enumerator_ptr(obj);
1074
1075 rb_check_frozen(obj);
1076
1077 rb_check_funcall(e->obj, id_rewind, 0, 0);
1078
1079 e->fib = 0;
1080 e->dst = Qnil;
1081 e->lookahead = Qundef;
1082 e->feedvalue = Qundef;
1083 e->stop_exc = Qfalse;
1084 return obj;
1085}
1086
1087static struct generator *generator_ptr(VALUE obj);
1088static VALUE append_method(VALUE obj, VALUE str, ID default_method, VALUE default_args);
1089
1090static VALUE
1091inspect_enumerator(VALUE obj, VALUE dummy, int recur)
1092{
1093 struct enumerator *e;
1094 VALUE eobj, str, cname;
1095
1096 TypedData_Get_Struct(obj, struct enumerator, &enumerator_data_type, e);
1097
1098 cname = rb_obj_class(obj);
1099
1100 if (!e || UNDEF_P(e->obj)) {
1101 return rb_sprintf("#<%"PRIsVALUE": uninitialized>", rb_class_path(cname));
1102 }
1103
1104 if (recur) {
1105 str = rb_sprintf("#<%"PRIsVALUE": ...>", rb_class_path(cname));
1106 return str;
1107 }
1108
1109 if (e->procs) {
1110 long i;
1111
1112 eobj = generator_ptr(e->obj)->obj;
1113 /* In case procs chained enumerator traversing all proc entries manually */
1114 if (rb_obj_class(eobj) == cname) {
1115 str = rb_inspect(eobj);
1116 }
1117 else {
1118 str = rb_sprintf("#<%"PRIsVALUE": %+"PRIsVALUE">", rb_class_path(cname), eobj);
1119 }
1120 for (i = 0; i < RARRAY_LEN(e->procs); i++) {
1121 str = rb_sprintf("#<%"PRIsVALUE": %"PRIsVALUE, cname, str);
1122 append_method(RARRAY_AREF(e->procs, i), str, e->meth, e->args);
1123 rb_str_buf_cat2(str, ">");
1124 }
1125 return str;
1126 }
1127
1128 eobj = rb_attr_get(obj, id_receiver);
1129 if (NIL_P(eobj)) {
1130 eobj = e->obj;
1131 }
1132
1133 /* (1..100).each_cons(2) => "#<Enumerator: 1..100:each_cons(2)>" */
1134 str = rb_sprintf("#<%"PRIsVALUE": %+"PRIsVALUE, rb_class_path(cname), eobj);
1135 append_method(obj, str, e->meth, e->args);
1136
1137 rb_str_buf_cat2(str, ">");
1138
1139 return str;
1140}
1141
1142static int
1143key_symbol_p(VALUE key, VALUE val, VALUE arg)
1144{
1145 if (SYMBOL_P(key)) return ST_CONTINUE;
1146 *(int *)arg = FALSE;
1147 return ST_STOP;
1148}
1149
1150static int
1151kwd_append(VALUE key, VALUE val, VALUE str)
1152{
1153 if (!SYMBOL_P(key)) rb_raise(rb_eRuntimeError, "non-symbol key inserted");
1154 rb_str_catf(str, "% "PRIsVALUE": %"PRIsVALUE", ", key, val);
1155 return ST_CONTINUE;
1156}
1157
1158static VALUE
1159append_method(VALUE obj, VALUE str, ID default_method, VALUE default_args)
1160{
1161 VALUE method, eargs;
1162
1163 method = rb_attr_get(obj, id_method);
1164 if (method != Qfalse) {
1165 if (!NIL_P(method)) {
1166 Check_Type(method, T_SYMBOL);
1167 method = rb_sym2str(method);
1168 }
1169 else {
1170 method = rb_id2str(default_method);
1171 }
1172 rb_str_buf_cat2(str, ":");
1173 rb_str_buf_append(str, method);
1174 }
1175
1176 eargs = rb_attr_get(obj, id_arguments);
1177 if (NIL_P(eargs)) {
1178 eargs = default_args;
1179 }
1180 if (eargs != Qfalse) {
1181 long argc = RARRAY_LEN(eargs);
1182 const VALUE *argv = RARRAY_CONST_PTR(eargs); /* WB: no new reference */
1183
1184 if (argc > 0) {
1185 VALUE kwds = Qnil;
1186
1187 rb_str_buf_cat2(str, "(");
1188
1189 if (RB_TYPE_P(argv[argc-1], T_HASH) && !RHASH_EMPTY_P(argv[argc-1])) {
1190 int all_key = TRUE;
1191 rb_hash_foreach(argv[argc-1], key_symbol_p, (VALUE)&all_key);
1192 if (all_key) kwds = argv[--argc];
1193 }
1194
1195 while (argc--) {
1196 VALUE arg = *argv++;
1197
1198 rb_str_append(str, rb_inspect(arg));
1199 rb_str_buf_cat2(str, ", ");
1200 }
1201 if (!NIL_P(kwds)) {
1202 rb_hash_foreach(kwds, kwd_append, str);
1203 }
1204 rb_str_set_len(str, RSTRING_LEN(str)-2);
1205 rb_str_buf_cat2(str, ")");
1206 }
1207 }
1208
1209 return str;
1210}
1211
1212/*
1213 * call-seq:
1214 * e.inspect -> string
1215 *
1216 * Creates a printable version of <i>e</i>.
1217 */
1218
1219static VALUE
1220enumerator_inspect(VALUE obj)
1221{
1222 return rb_exec_recursive(inspect_enumerator, obj, 0);
1223}
1224
1225/*
1226 * call-seq:
1227 * e.size -> int, Float::INFINITY or nil
1228 *
1229 * Returns the size of the enumerator, or +nil+ if it can't be calculated lazily.
1230 *
1231 * (1..100).to_a.permutation(4).size # => 94109400
1232 * loop.size # => Float::INFINITY
1233 * (1..100).drop_while.size # => nil
1234 *
1235 * Note that enumerator size might be inaccurate, and should be rather treated as a hint.
1236 * For example, there is no check that the size provided to ::new is accurate:
1237 *
1238 * e = Enumerator.new(5) { |y| 2.times { y << it} }
1239 * e.size # => 5
1240 * e.to_a.size # => 2
1241 *
1242 * Another example is an enumerator created by ::produce without a +size+ argument.
1243 * Such enumerators return +Infinity+ for size, but this is inaccurate if the passed
1244 * block raises StopIteration:
1245 *
1246 * e = Enumerator.produce(1) { it + 1 }
1247 * e.size # => Infinity
1248 *
1249 * e = Enumerator.produce(1) { it > 3 ? raise(StopIteration) : it + 1 }
1250 * e.size # => Infinity
1251 * e.to_a.size # => 4
1252 */
1253
1254static VALUE
1255enumerator_size(VALUE obj)
1256{
1257 struct enumerator *e = enumerator_ptr(obj);
1258 int argc = 0;
1259 const VALUE *argv = NULL;
1260 VALUE size;
1261
1262 if (e->procs) {
1263 struct generator *g = generator_ptr(e->obj);
1264 VALUE receiver = rb_check_funcall(g->obj, id_size, 0, 0);
1265 long i = 0;
1266
1267 for (i = 0; i < RARRAY_LEN(e->procs); i++) {
1268 VALUE proc = RARRAY_AREF(e->procs, i);
1269 struct proc_entry *entry = proc_entry_ptr(proc);
1270 lazyenum_size_func *size_fn = entry->fn->size;
1271 if (!size_fn) {
1272 return Qnil;
1273 }
1274 receiver = (*size_fn)(proc, receiver);
1275 }
1276 return receiver;
1277 }
1278
1279 if (e->size_fn) {
1280 return (*e->size_fn)(e->obj, e->args, obj);
1281 }
1282 if (e->args) {
1283 argc = (int)RARRAY_LEN(e->args);
1284 argv = RARRAY_CONST_PTR(e->args);
1285 }
1286 size = rb_check_funcall_kw(e->size, id_call, argc, argv, e->kw_splat);
1287 if (!UNDEF_P(size)) return size;
1288 return e->size;
1289}
1290
1291/*
1292 * Yielder
1293 */
1294static void
1295yielder_mark_and_move(void *p)
1296{
1297 struct yielder *ptr = p;
1298 rb_gc_mark_and_move(&ptr->proc);
1299}
1300
1301static const rb_data_type_t yielder_data_type = {
1302 "yielder",
1303 {
1304 yielder_mark_and_move,
1305 RUBY_TYPED_DEFAULT_FREE,
1306 NULL,
1307 yielder_mark_and_move,
1308 },
1309 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE
1310};
1311
1312static struct yielder *
1313yielder_ptr(VALUE obj)
1314{
1315 struct yielder *ptr;
1316
1317 TypedData_Get_Struct(obj, struct yielder, &yielder_data_type, ptr);
1318 if (!ptr || UNDEF_P(ptr->proc)) {
1319 rb_raise(rb_eArgError, "uninitialized yielder");
1320 }
1321 return ptr;
1322}
1323
1324/* :nodoc: */
1325static VALUE
1326yielder_allocate(VALUE klass)
1327{
1328 struct yielder *ptr;
1329 VALUE obj;
1330
1331 obj = TypedData_Make_Struct(klass, struct yielder, &yielder_data_type, ptr);
1332 ptr->proc = Qundef;
1333
1334 return obj;
1335}
1336
1337static VALUE
1338yielder_init(VALUE obj, VALUE proc)
1339{
1340 struct yielder *ptr;
1341
1342 TypedData_Get_Struct(obj, struct yielder, &yielder_data_type, ptr);
1343
1344 if (!ptr) {
1345 rb_raise(rb_eArgError, "unallocated yielder");
1346 }
1347
1348 RB_OBJ_WRITE(obj, &ptr->proc, proc);
1349
1350 return obj;
1351}
1352
1353/* :nodoc: */
1354static VALUE
1355yielder_initialize(VALUE obj)
1356{
1357 rb_need_block();
1358
1359 return yielder_init(obj, rb_block_proc());
1360}
1361
1362/* :nodoc: */
1363static VALUE
1364yielder_yield(VALUE obj, VALUE args)
1365{
1366 struct yielder *ptr = yielder_ptr(obj);
1367
1368 return rb_proc_call_kw(ptr->proc, args, RB_PASS_CALLED_KEYWORDS);
1369}
1370
1371/* :nodoc: */
1372static VALUE
1373yielder_yield_push(VALUE obj, VALUE arg)
1374{
1375 struct yielder *ptr = yielder_ptr(obj);
1376
1377 rb_proc_call_with_block(ptr->proc, 1, &arg, Qnil);
1378
1379 return obj;
1380}
1381
1382/*
1383 * Returns a Proc object that takes arguments and yields them.
1384 *
1385 * This method is implemented so that a Yielder object can be directly
1386 * passed to another method as a block argument.
1387 *
1388 * enum = Enumerator.new { |y|
1389 * Dir.glob("*.rb") { |file|
1390 * File.open(file) { |f| f.each_line(&y) }
1391 * }
1392 * }
1393 */
1394static VALUE
1395yielder_to_proc(VALUE obj)
1396{
1397 VALUE method = rb_obj_method(obj, sym_yield);
1398
1399 return rb_funcall(method, idTo_proc, 0);
1400}
1401
1402static VALUE
1403yielder_yield_i(RB_BLOCK_CALL_FUNC_ARGLIST(obj, memo))
1404{
1405 return rb_yield_values_kw(argc, argv, RB_PASS_CALLED_KEYWORDS);
1406}
1407
1408static VALUE
1409yielder_new(void)
1410{
1411 return yielder_init(yielder_allocate(rb_cYielder), rb_proc_new(yielder_yield_i, 0));
1412}
1413
1414/*
1415 * Generator
1416 */
1417static void
1418generator_mark_and_move(void *p)
1419{
1420 struct generator *ptr = p;
1421 rb_gc_mark_and_move(&ptr->proc);
1422 rb_gc_mark_and_move(&ptr->obj);
1423}
1424
1425static const rb_data_type_t generator_data_type = {
1426 "generator",
1427 {
1428 generator_mark_and_move,
1429 RUBY_TYPED_DEFAULT_FREE,
1430 NULL,
1431 generator_mark_and_move,
1432 },
1433 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE
1434};
1435
1436static struct generator *
1437generator_ptr(VALUE obj)
1438{
1439 struct generator *ptr;
1440
1441 TypedData_Get_Struct(obj, struct generator, &generator_data_type, ptr);
1442 if (!ptr || UNDEF_P(ptr->proc)) {
1443 rb_raise(rb_eArgError, "uninitialized generator");
1444 }
1445 return ptr;
1446}
1447
1448/* :nodoc: */
1449static VALUE
1450generator_allocate(VALUE klass)
1451{
1452 struct generator *ptr;
1453 VALUE obj;
1454
1455 obj = TypedData_Make_Struct(klass, struct generator, &generator_data_type, ptr);
1456 ptr->proc = Qundef;
1457
1458 return obj;
1459}
1460
1461static VALUE
1462generator_init(VALUE obj, VALUE proc)
1463{
1464 struct generator *ptr;
1465
1466 rb_check_frozen(obj);
1467 TypedData_Get_Struct(obj, struct generator, &generator_data_type, ptr);
1468
1469 if (!ptr) {
1470 rb_raise(rb_eArgError, "unallocated generator");
1471 }
1472
1473 RB_OBJ_WRITE(obj, &ptr->proc, proc);
1474
1475 return obj;
1476}
1477
1478/* :nodoc: */
1479static VALUE
1480generator_initialize(int argc, VALUE *argv, VALUE obj)
1481{
1482 VALUE proc;
1483
1484 if (argc == 0) {
1485 rb_need_block();
1486
1487 proc = rb_block_proc();
1488 }
1489 else {
1490 rb_scan_args(argc, argv, "1", &proc);
1491
1492 if (!rb_obj_is_proc(proc))
1493 rb_raise(rb_eTypeError,
1494 "wrong argument type %"PRIsVALUE" (expected Proc)",
1495 rb_obj_class(proc));
1496
1497 if (rb_block_given_p()) {
1498 rb_warn("given block not used");
1499 }
1500 }
1501
1502 return generator_init(obj, proc);
1503}
1504
1505/* :nodoc: */
1506static VALUE
1507generator_init_copy(VALUE obj, VALUE orig)
1508{
1509 struct generator *ptr0, *ptr1;
1510
1511 if (!OBJ_INIT_COPY(obj, orig)) return obj;
1512
1513 ptr0 = generator_ptr(orig);
1514
1515 TypedData_Get_Struct(obj, struct generator, &generator_data_type, ptr1);
1516
1517 if (!ptr1) {
1518 rb_raise(rb_eArgError, "unallocated generator");
1519 }
1520
1521 RB_OBJ_WRITE(obj, &ptr1->proc, ptr0->proc);
1522
1523 return obj;
1524}
1525
1526/* :nodoc: */
1527static VALUE
1528generator_each(int argc, VALUE *argv, VALUE obj)
1529{
1530 struct generator *ptr = generator_ptr(obj);
1531 VALUE args = rb_ary_new2(argc + 1);
1532
1533 rb_ary_push(args, yielder_new());
1534 if (argc > 0) {
1535 rb_ary_cat(args, argv, argc);
1536 }
1537
1538 return rb_proc_call_kw(ptr->proc, args, RB_PASS_CALLED_KEYWORDS);
1539}
1540
1541/* Lazy Enumerator methods */
1542static VALUE
1543enum_size(VALUE self)
1544{
1545 VALUE r = rb_check_funcall(self, id_size, 0, 0);
1546 return UNDEF_P(r) ? Qnil : r;
1547}
1548
1549static VALUE
1550lazyenum_size(VALUE self, VALUE args, VALUE eobj)
1551{
1552 return enum_size(self);
1553}
1554
1555#define lazy_receiver_size lazy_map_size
1556
1557static VALUE
1558lazy_init_iterator(RB_BLOCK_CALL_FUNC_ARGLIST(val, m))
1559{
1560 VALUE result;
1561 if (argc == 1) {
1562 VALUE args[2];
1563 args[0] = m;
1564 args[1] = val;
1565 result = rb_yield_values2(2, args);
1566 }
1567 else {
1568 VALUE args;
1569 int len = rb_long2int((long)argc + 1);
1570 VALUE *nargv = ALLOCV_N(VALUE, args, len);
1571
1572 nargv[0] = m;
1573 if (argc > 0) {
1574 MEMCPY(nargv + 1, argv, VALUE, argc);
1575 }
1576 result = rb_yield_values2(len, nargv);
1577 ALLOCV_END(args);
1578 }
1579 if (UNDEF_P(result)) rb_iter_break();
1580 return Qnil;
1581}
1582
1583static VALUE
1584lazy_init_block_i(RB_BLOCK_CALL_FUNC_ARGLIST(val, m))
1585{
1586 rb_block_call(m, id_each, argc-1, argv+1, lazy_init_iterator, val);
1587 return Qnil;
1588}
1589
1590#define memo_value v2
1591#define memo_flags u3.state
1592#define LAZY_MEMO_BREAK 1
1593#define LAZY_MEMO_PACKED 2
1594#define LAZY_MEMO_BREAK_P(memo) ((memo)->memo_flags & LAZY_MEMO_BREAK)
1595#define LAZY_MEMO_PACKED_P(memo) ((memo)->memo_flags & LAZY_MEMO_PACKED)
1596#define LAZY_MEMO_SET_BREAK(memo) ((memo)->memo_flags |= LAZY_MEMO_BREAK)
1597#define LAZY_MEMO_RESET_BREAK(memo) ((memo)->memo_flags &= ~LAZY_MEMO_BREAK)
1598#define LAZY_MEMO_SET_VALUE(memo, value) MEMO_V2_SET(memo, value)
1599#define LAZY_MEMO_SET_PACKED(memo) ((memo)->memo_flags |= LAZY_MEMO_PACKED)
1600#define LAZY_MEMO_RESET_PACKED(memo) ((memo)->memo_flags &= ~LAZY_MEMO_PACKED)
1601
1602#define LAZY_NEED_BLOCK(func) \
1603 if (!rb_block_given_p()) { \
1604 rb_raise(rb_eArgError, "tried to call lazy " #func " without a block"); \
1605 }
1606
1607static VALUE lazy_yielder_result(struct MEMO *result, VALUE yielder, VALUE procs_array, VALUE memos, long i);
1608
1609static VALUE
1610lazy_init_yielder(RB_BLOCK_CALL_FUNC_ARGLIST(_, m))
1611{
1612 VALUE yielder = RARRAY_AREF(m, 0);
1613 VALUE procs_array = RARRAY_AREF(m, 1);
1614 VALUE memos = rb_attr_get(yielder, id_memo);
1615 struct MEMO *result;
1616
1617 result = MEMO_NEW(m, rb_enum_values_pack(argc, argv),
1618 argc > 1 ? LAZY_MEMO_PACKED : 0);
1619 return lazy_yielder_result(result, yielder, procs_array, memos, 0);
1620}
1621
1622static VALUE
1623lazy_yielder_yield(struct MEMO *result, long memo_index, int argc, const VALUE *argv)
1624{
1625 VALUE m = result->v1;
1626 VALUE yielder = RARRAY_AREF(m, 0);
1627 VALUE procs_array = RARRAY_AREF(m, 1);
1628 VALUE memos = rb_attr_get(yielder, id_memo);
1629 LAZY_MEMO_SET_VALUE(result, rb_enum_values_pack(argc, argv));
1630 if (argc > 1)
1631 LAZY_MEMO_SET_PACKED(result);
1632 else
1633 LAZY_MEMO_RESET_PACKED(result);
1634 return lazy_yielder_result(result, yielder, procs_array, memos, memo_index);
1635}
1636
1637static VALUE
1638lazy_yielder_result(struct MEMO *result, VALUE yielder, VALUE procs_array, VALUE memos, long i)
1639{
1640 int cont = 1;
1641
1642 for (; i < RARRAY_LEN(procs_array); i++) {
1643 VALUE proc = RARRAY_AREF(procs_array, i);
1644 struct proc_entry *entry = proc_entry_ptr(proc);
1645 if (!(*entry->fn->proc)(proc, result, memos, i)) {
1646 cont = 0;
1647 break;
1648 }
1649 }
1650
1651 if (cont) {
1652 rb_funcall2(yielder, idLTLT, 1, &(result->memo_value));
1653 }
1654 if (LAZY_MEMO_BREAK_P(result)) {
1655 rb_iter_break();
1656 }
1657 return result->memo_value;
1658}
1659
1660static VALUE
1661lazy_init_block(RB_BLOCK_CALL_FUNC_ARGLIST(val, m))
1662{
1663 VALUE procs = RARRAY_AREF(m, 1);
1664
1665 rb_ivar_set(val, id_memo, rb_ary_new2(RARRAY_LEN(procs)));
1666 rb_block_call(RARRAY_AREF(m, 0), id_each, 0, 0,
1667 lazy_init_yielder, rb_ary_new3(2, val, procs));
1668 return Qnil;
1669}
1670
1671static VALUE
1672lazy_generator_init(VALUE enumerator, VALUE procs)
1673{
1674 VALUE generator;
1675 VALUE obj;
1676 struct generator *gen_ptr;
1677 struct enumerator *e = enumerator_ptr(enumerator);
1678
1679 if (RARRAY_LEN(procs) > 0) {
1680 struct generator *old_gen_ptr = generator_ptr(e->obj);
1681 obj = old_gen_ptr->obj;
1682 }
1683 else {
1684 obj = enumerator;
1685 }
1686
1687 generator = generator_allocate(rb_cGenerator);
1688
1689 rb_block_call(generator, id_initialize, 0, 0,
1690 lazy_init_block, rb_ary_new3(2, obj, procs));
1691
1692 gen_ptr = generator_ptr(generator);
1693 RB_OBJ_WRITE(generator, &gen_ptr->obj, obj);
1694
1695 return generator;
1696}
1697
1698static int
1699lazy_precheck(VALUE procs)
1700{
1701 if (RTEST(procs)) {
1702 long num_procs = RARRAY_LEN(procs), i = num_procs;
1703 while (i-- > 0) {
1704 VALUE proc = RARRAY_AREF(procs, i);
1705 struct proc_entry *entry = proc_entry_ptr(proc);
1706 lazyenum_precheck_func *precheck = entry->fn->precheck;
1707 if (precheck && !precheck(proc)) return FALSE;
1708 }
1709 }
1710
1711 return TRUE;
1712}
1713
1714/*
1715 * Document-class: Enumerator::Lazy
1716 *
1717 * Enumerator::Lazy is a special type of Enumerator, that allows constructing
1718 * chains of operations without evaluating them immediately, and evaluating
1719 * values on as-needed basis. In order to do so it redefines most of Enumerable
1720 * methods so that they just construct another lazy enumerator.
1721 *
1722 * Enumerator::Lazy can be constructed from any Enumerable with the
1723 * Enumerable#lazy method.
1724 *
1725 * lazy = (1..Float::INFINITY).lazy.select(&:odd?).drop(10).take_while { |i| i < 30 }
1726 * # => #<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator::Lazy: 1..Infinity>:select>:drop(10)>:take_while>
1727 *
1728 * The real enumeration is performed when any non-redefined Enumerable method
1729 * is called, like Enumerable#first or Enumerable#to_a (the latter is aliased
1730 * as #force for more semantic code):
1731 *
1732 * lazy.first(2)
1733 * #=> [21, 23]
1734 *
1735 * lazy.force
1736 * #=> [21, 23, 25, 27, 29]
1737 *
1738 * Note that most Enumerable methods that could be called with or without
1739 * a block, on Enumerator::Lazy will always require a block:
1740 *
1741 * [1, 2, 3].map #=> #<Enumerator: [1, 2, 3]:map>
1742 * [1, 2, 3].lazy.map # ArgumentError: tried to call lazy map without a block
1743 *
1744 * This class allows idiomatic calculations on long or infinite sequences, as well
1745 * as chaining of calculations without constructing intermediate arrays.
1746 *
1747 * Example for working with a slowly calculated sequence:
1748 *
1749 * require 'open-uri'
1750 *
1751 * # This will fetch all URLs before selecting
1752 * # necessary data
1753 * URLS.map { |u| JSON.parse(URI.open(u).read) }
1754 * .select { |data| data.key?('stats') }
1755 * .first(5)
1756 *
1757 * # This will fetch URLs one-by-one, only till
1758 * # there is enough data to satisfy the condition
1759 * URLS.lazy.map { |u| JSON.parse(URI.open(u).read) }
1760 * .select { |data| data.key?('stats') }
1761 * .first(5)
1762 *
1763 * Ending a chain with ".eager" generates a non-lazy enumerator, which
1764 * is suitable for returning or passing to another method that expects
1765 * a normal enumerator.
1766 *
1767 * def active_items
1768 * groups
1769 * .lazy
1770 * .flat_map(&:items)
1771 * .reject(&:disabled)
1772 * .eager
1773 * end
1774 *
1775 * # This works lazily; if a checked item is found, it stops
1776 * # iteration and does not look into remaining groups.
1777 * first_checked = active_items.find(&:checked)
1778 *
1779 * # This returns an array of items like a normal enumerator does.
1780 * all_checked = active_items.select(&:checked)
1781 *
1782 */
1783
1784/*
1785 * call-seq:
1786 * Lazy.new(obj, size=nil) { |yielder, *values| block }
1787 *
1788 * Creates a new Lazy enumerator. When the enumerator is actually enumerated
1789 * (e.g. by calling #force), +obj+ will be enumerated and each value passed
1790 * to the given block. The block can yield values back using +yielder+.
1791 * For example, to create a "filter+map" enumerator:
1792 *
1793 * def filter_map(sequence)
1794 * Lazy.new(sequence) do |yielder, *values|
1795 * result = yield *values
1796 * yielder << result if result
1797 * end
1798 * end
1799 *
1800 * filter_map(1..Float::INFINITY) {|i| i*i if i.even?}.first(5)
1801 * #=> [4, 16, 36, 64, 100]
1802 */
1803static VALUE
1804lazy_initialize(int argc, VALUE *argv, VALUE self)
1805{
1806 VALUE obj, size = Qnil;
1807 VALUE generator;
1808
1809 rb_check_arity(argc, 1, 2);
1810 LAZY_NEED_BLOCK(new);
1811 obj = argv[0];
1812 if (argc > 1) {
1813 size = argv[1];
1814 }
1815 generator = generator_allocate(rb_cGenerator);
1816 rb_block_call(generator, id_initialize, 0, 0, lazy_init_block_i, obj);
1817 enumerator_init(self, generator, sym_each, 0, 0, 0, size, 0);
1818 rb_ivar_set(self, id_receiver, obj);
1819
1820 return self;
1821}
1822
1823#if 0 /* for RDoc */
1824/*
1825 * call-seq:
1826 * lazy.to_a -> array
1827 * lazy.force -> array
1828 *
1829 * Expands +lazy+ enumerator to an array.
1830 * See Enumerable#to_a.
1831 */
1832static VALUE
1833lazy_to_a(VALUE self)
1834{
1835}
1836#endif
1837
1838static void
1839lazy_set_args(VALUE lazy, VALUE args)
1840{
1841 ID id = rb_frame_this_func();
1842 rb_ivar_set(lazy, id_method, ID2SYM(id));
1843 if (NIL_P(args)) {
1844 /* Qfalse indicates that the arguments are empty */
1845 rb_ivar_set(lazy, id_arguments, Qfalse);
1846 }
1847 else {
1848 rb_ivar_set(lazy, id_arguments, args);
1849 }
1850}
1851
1852#if 0
1853static VALUE
1854lazy_set_method(VALUE lazy, VALUE args, rb_enumerator_size_func *size_fn)
1855{
1856 struct enumerator *e = enumerator_ptr(lazy);
1857 lazy_set_args(lazy, args);
1858 e->size_fn = size_fn;
1859 return lazy;
1860}
1861#endif
1862
1863static VALUE
1864lazy_add_method(VALUE obj, int argc, VALUE *argv, VALUE args, VALUE memo,
1865 const lazyenum_funcs *fn)
1866{
1867 struct enumerator *new_e;
1868 VALUE new_obj;
1869 VALUE new_generator;
1870 VALUE new_procs;
1871 struct enumerator *e = enumerator_ptr(obj);
1872 struct proc_entry *entry;
1873 VALUE entry_obj = TypedData_Make_Struct(rb_cObject, struct proc_entry,
1874 &proc_entry_data_type, entry);
1875 if (rb_block_given_p()) {
1876 RB_OBJ_WRITE(entry_obj, &entry->proc, rb_block_proc());
1877 }
1878 entry->fn = fn;
1879 RB_OBJ_WRITE(entry_obj, &entry->memo, args);
1880
1881 lazy_set_args(entry_obj, memo);
1882
1883 new_procs = RTEST(e->procs) ? rb_ary_dup(e->procs) : rb_ary_new();
1884 new_generator = lazy_generator_init(obj, new_procs);
1885 rb_ary_push(new_procs, entry_obj);
1886
1887 new_obj = enumerator_init_copy(enumerator_allocate(rb_cLazy), obj);
1888 new_e = RTYPEDDATA_GET_DATA(new_obj);
1889 RB_OBJ_WRITE(new_obj, &new_e->obj, new_generator);
1890 RB_OBJ_WRITE(new_obj, &new_e->procs, new_procs);
1891
1892 if (argc > 0) {
1893 new_e->meth = rb_to_id(*argv++);
1894 --argc;
1895 }
1896 else {
1897 new_e->meth = id_each;
1898 }
1899
1900 RB_OBJ_WRITE(new_obj, &new_e->args, rb_ary_new4(argc, argv));
1901
1902 return new_obj;
1903}
1904
1905/*
1906 * call-seq:
1907 * e.lazy -> lazy_enumerator
1908 *
1909 * Returns an Enumerator::Lazy, which redefines most Enumerable
1910 * methods to postpone enumeration and enumerate values only on an
1911 * as-needed basis.
1912 *
1913 * === Example
1914 *
1915 * The following program finds pythagorean triples:
1916 *
1917 * def pythagorean_triples
1918 * (1..Float::INFINITY).lazy.flat_map {|z|
1919 * (1..z).flat_map {|x|
1920 * (x..z).select {|y|
1921 * x**2 + y**2 == z**2
1922 * }.map {|y|
1923 * [x, y, z]
1924 * }
1925 * }
1926 * }
1927 * end
1928 * # show first ten pythagorean triples
1929 * p pythagorean_triples.take(10).force # take is lazy, so force is needed
1930 * p pythagorean_triples.first(10) # first is eager
1931 * # show pythagorean triples less than 100
1932 * p pythagorean_triples.take_while { |*, z| z < 100 }.force
1933 */
1934static VALUE
1935enumerable_lazy(VALUE obj)
1936{
1937 VALUE result = lazy_to_enum_i(obj, sym_each, 0, 0, lazyenum_size, rb_keyword_given_p());
1938 /* Qfalse indicates that the Enumerator::Lazy has no method name */
1939 rb_ivar_set(result, id_method, Qfalse);
1940 return result;
1941}
1942
1943static VALUE
1944lazy_to_enum_i(VALUE obj, VALUE meth, int argc, const VALUE *argv, rb_enumerator_size_func *size_fn, int kw_splat)
1945{
1946 return enumerator_init(enumerator_allocate(rb_cLazy),
1947 obj, meth, argc, argv, size_fn, Qnil, kw_splat);
1948}
1949
1950/*
1951 * call-seq:
1952 * lzy.to_enum(method = :each, *args) -> lazy_enum
1953 * lzy.enum_for(method = :each, *args) -> lazy_enum
1954 * lzy.to_enum(method = :each, *args) {|*args| block } -> lazy_enum
1955 * lzy.enum_for(method = :each, *args) {|*args| block } -> lazy_enum
1956 *
1957 * Similar to Object#to_enum, except it returns a lazy enumerator.
1958 * This makes it easy to define Enumerable methods that will
1959 * naturally remain lazy if called from a lazy enumerator.
1960 *
1961 * For example, continuing from the example in Object#to_enum:
1962 *
1963 * # See Object#to_enum for the definition of repeat
1964 * r = 1..Float::INFINITY
1965 * r.repeat(2).first(5) # => [1, 1, 2, 2, 3]
1966 * r.repeat(2).class # => Enumerator
1967 * r.repeat(2).map{|n| n ** 2}.first(5) # => endless loop!
1968 * # works naturally on lazy enumerator:
1969 * r.lazy.repeat(2).class # => Enumerator::Lazy
1970 * r.lazy.repeat(2).map{|n| n ** 2}.first(5) # => [1, 1, 4, 4, 9]
1971 */
1972
1973static VALUE
1974lazy_to_enum(int argc, VALUE *argv, VALUE self)
1975{
1976 VALUE lazy, meth = sym_each, super_meth;
1977
1978 if (argc > 0) {
1979 --argc;
1980 meth = rb_to_symbol(*argv++);
1981 }
1982 if (RTEST((super_meth = rb_hash_aref(lazy_use_super_method, meth)))) {
1983 meth = super_meth;
1984 }
1985 lazy = lazy_to_enum_i(self, meth, argc, argv, 0, rb_keyword_given_p());
1986 if (rb_block_given_p()) {
1987 RB_OBJ_WRITE(lazy, &enumerator_ptr(lazy)->size, rb_block_proc());
1988 }
1989 return lazy;
1990}
1991
1992static VALUE
1993lazy_eager_size(VALUE self, VALUE args, VALUE eobj)
1994{
1995 return enum_size(self);
1996}
1997
1998/*
1999 * call-seq:
2000 * lzy.eager -> enum
2001 *
2002 * Returns a non-lazy Enumerator converted from the lazy enumerator.
2003 */
2004
2005static VALUE
2006lazy_eager(VALUE self)
2007{
2008 return enumerator_init(enumerator_allocate(rb_cEnumerator),
2009 self, sym_each, 0, 0, lazy_eager_size, Qnil, 0);
2010}
2011
2012static VALUE
2013lazyenum_yield(VALUE proc_entry, struct MEMO *result)
2014{
2015 struct proc_entry *entry = proc_entry_ptr(proc_entry);
2016 return rb_proc_call_with_block(entry->proc, 1, &result->memo_value, Qnil);
2017}
2018
2019static VALUE
2020lazyenum_yield_values(VALUE proc_entry, struct MEMO *result)
2021{
2022 struct proc_entry *entry = proc_entry_ptr(proc_entry);
2023 int argc = 1;
2024 const VALUE *argv = &result->memo_value;
2025 if (LAZY_MEMO_PACKED_P(result)) {
2026 const VALUE args = *argv;
2027 argc = RARRAY_LENINT(args);
2028 argv = RARRAY_CONST_PTR(args);
2029 }
2030 return rb_proc_call_with_block(entry->proc, argc, argv, Qnil);
2031}
2032
2033static struct MEMO *
2034lazy_map_proc(VALUE proc_entry, struct MEMO *result, VALUE memos, long memo_index)
2035{
2036 VALUE value = lazyenum_yield_values(proc_entry, result);
2037 LAZY_MEMO_SET_VALUE(result, value);
2038 LAZY_MEMO_RESET_PACKED(result);
2039 return result;
2040}
2041
2042static VALUE
2043lazy_map_size(VALUE entry, VALUE receiver)
2044{
2045 return receiver;
2046}
2047
2048static const lazyenum_funcs lazy_map_funcs = {
2049 lazy_map_proc, lazy_map_size,
2050};
2051
2052/*
2053 * call-seq:
2054 * lazy.collect { |obj| block } -> lazy_enumerator
2055 * lazy.map { |obj| block } -> lazy_enumerator
2056 *
2057 * Like Enumerable#map, but chains operation to be lazy-evaluated.
2058 *
2059 * (1..Float::INFINITY).lazy.map {|i| i**2 }
2060 * #=> #<Enumerator::Lazy: #<Enumerator::Lazy: 1..Infinity>:map>
2061 * (1..Float::INFINITY).lazy.map {|i| i**2 }.first(3)
2062 * #=> [1, 4, 9]
2063 */
2064
2065static VALUE
2066lazy_map(VALUE obj)
2067{
2068 LAZY_NEED_BLOCK(map);
2069 return lazy_add_method(obj, 0, 0, Qnil, Qnil, &lazy_map_funcs);
2070}
2071
2072 struct flat_map_i_arg {
2073 struct MEMO *result;
2074 long index;
2075};
2076
2077static VALUE
2078lazy_flat_map_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, y))
2079{
2080 struct flat_map_i_arg *arg = (struct flat_map_i_arg *)y;
2081
2082 return lazy_yielder_yield(arg->result, arg->index, argc, argv);
2083}
2084
2085static struct MEMO *
2086lazy_flat_map_proc(VALUE proc_entry, struct MEMO *result, VALUE memos, long memo_index)
2087{
2088 VALUE value = lazyenum_yield_values(proc_entry, result);
2089 VALUE ary = 0;
2090 const long proc_index = memo_index + 1;
2091 int break_p = LAZY_MEMO_BREAK_P(result);
2092
2093 if (RB_TYPE_P(value, T_ARRAY)) {
2094 ary = value;
2095 }
2096 else if (rb_respond_to(value, id_force) && rb_respond_to(value, id_each)) {
2097 struct flat_map_i_arg arg = {.result = result, .index = proc_index};
2098 LAZY_MEMO_RESET_BREAK(result);
2099 rb_block_call(value, id_each, 0, 0, lazy_flat_map_i, (VALUE)&arg);
2100 if (break_p) LAZY_MEMO_SET_BREAK(result);
2101 return 0;
2102 }
2103
2104 if (ary || !NIL_P(ary = rb_check_array_type(value))) {
2105 long i;
2106 LAZY_MEMO_RESET_BREAK(result);
2107 for (i = 0; i + 1 < RARRAY_LEN(ary); i++) {
2108 const VALUE argv = RARRAY_AREF(ary, i);
2109 lazy_yielder_yield(result, proc_index, 1, &argv);
2110 }
2111 if (break_p) LAZY_MEMO_SET_BREAK(result);
2112 if (i >= RARRAY_LEN(ary)) return 0;
2113 value = RARRAY_AREF(ary, i);
2114 }
2115 LAZY_MEMO_SET_VALUE(result, value);
2116 LAZY_MEMO_RESET_PACKED(result);
2117 return result;
2118}
2119
2120static const lazyenum_funcs lazy_flat_map_funcs = {
2121 lazy_flat_map_proc, 0,
2122};
2123
2124/*
2125 * call-seq:
2126 * lazy.collect_concat { |obj| block } -> a_lazy_enumerator
2127 * lazy.flat_map { |obj| block } -> a_lazy_enumerator
2128 *
2129 * Returns a new lazy enumerator with the concatenated results of running
2130 * +block+ once for every element in the lazy enumerator.
2131 *
2132 * ["foo", "bar"].lazy.flat_map {|i| i.each_char.lazy}.force
2133 * #=> ["f", "o", "o", "b", "a", "r"]
2134 *
2135 * A value +x+ returned by +block+ is decomposed if either of
2136 * the following conditions is true:
2137 *
2138 * * +x+ responds to both each and force, which means that
2139 * +x+ is a lazy enumerator.
2140 * * +x+ is an array or responds to to_ary.
2141 *
2142 * Otherwise, +x+ is contained as-is in the return value.
2143 *
2144 * [{a:1}, {b:2}].lazy.flat_map {|i| i}.force
2145 * #=> [{:a=>1}, {:b=>2}]
2146 */
2147static VALUE
2148lazy_flat_map(VALUE obj)
2149{
2150 LAZY_NEED_BLOCK(flat_map);
2151 return lazy_add_method(obj, 0, 0, Qnil, Qnil, &lazy_flat_map_funcs);
2152}
2153
2154static struct MEMO *
2155lazy_select_proc(VALUE proc_entry, struct MEMO *result, VALUE memos, long memo_index)
2156{
2157 VALUE chain = lazyenum_yield(proc_entry, result);
2158 if (!RTEST(chain)) return 0;
2159 return result;
2160}
2161
2162static const lazyenum_funcs lazy_select_funcs = {
2163 lazy_select_proc, 0,
2164};
2165
2166/*
2167 * call-seq:
2168 * lazy.find_all { |obj| block } -> lazy_enumerator
2169 * lazy.select { |obj| block } -> lazy_enumerator
2170 * lazy.filter { |obj| block } -> lazy_enumerator
2171 *
2172 * Like Enumerable#select, but chains operation to be lazy-evaluated.
2173 */
2174static VALUE
2175lazy_select(VALUE obj)
2176{
2177 LAZY_NEED_BLOCK(select);
2178 return lazy_add_method(obj, 0, 0, Qnil, Qnil, &lazy_select_funcs);
2179}
2180
2181static struct MEMO *
2182lazy_filter_map_proc(VALUE proc_entry, struct MEMO *result, VALUE memos, long memo_index)
2183{
2184 VALUE value = lazyenum_yield_values(proc_entry, result);
2185 if (!RTEST(value)) return 0;
2186 LAZY_MEMO_SET_VALUE(result, value);
2187 LAZY_MEMO_RESET_PACKED(result);
2188 return result;
2189}
2190
2191static const lazyenum_funcs lazy_filter_map_funcs = {
2192 lazy_filter_map_proc, 0,
2193};
2194
2195/*
2196 * call-seq:
2197 * lazy.filter_map { |obj| block } -> lazy_enumerator
2198 *
2199 * Like Enumerable#filter_map, but chains operation to be lazy-evaluated.
2200 *
2201 * (1..).lazy.filter_map { |i| i * 2 if i.even? }.first(5)
2202 * #=> [4, 8, 12, 16, 20]
2203 */
2204
2205static VALUE
2206lazy_filter_map(VALUE obj)
2207{
2208 LAZY_NEED_BLOCK(filter_map);
2209 return lazy_add_method(obj, 0, 0, Qnil, Qnil, &lazy_filter_map_funcs);
2210}
2211
2212static struct MEMO *
2213lazy_reject_proc(VALUE proc_entry, struct MEMO *result, VALUE memos, long memo_index)
2214{
2215 VALUE chain = lazyenum_yield(proc_entry, result);
2216 if (RTEST(chain)) return 0;
2217 return result;
2218}
2219
2220static const lazyenum_funcs lazy_reject_funcs = {
2221 lazy_reject_proc, 0,
2222};
2223
2224/*
2225 * call-seq:
2226 * lazy.reject { |obj| block } -> lazy_enumerator
2227 *
2228 * Like Enumerable#reject, but chains operation to be lazy-evaluated.
2229 */
2230
2231static VALUE
2232lazy_reject(VALUE obj)
2233{
2234 LAZY_NEED_BLOCK(reject);
2235 return lazy_add_method(obj, 0, 0, Qnil, Qnil, &lazy_reject_funcs);
2236}
2237
2238static struct MEMO *
2239lazy_grep_proc(VALUE proc_entry, struct MEMO *result, VALUE memos, long memo_index)
2240{
2241 struct proc_entry *entry = proc_entry_ptr(proc_entry);
2242 VALUE chain = rb_funcall(entry->memo, id_eqq, 1, result->memo_value);
2243 if (!RTEST(chain)) return 0;
2244 return result;
2245}
2246
2247static struct MEMO *
2248lazy_grep_iter_proc(VALUE proc_entry, struct MEMO *result, VALUE memos, long memo_index)
2249{
2250 struct proc_entry *entry = proc_entry_ptr(proc_entry);
2251 VALUE value, chain = rb_funcall(entry->memo, id_eqq, 1, result->memo_value);
2252
2253 if (!RTEST(chain)) return 0;
2254 value = rb_proc_call_with_block(entry->proc, 1, &(result->memo_value), Qnil);
2255 LAZY_MEMO_SET_VALUE(result, value);
2256 LAZY_MEMO_RESET_PACKED(result);
2257
2258 return result;
2259}
2260
2261static const lazyenum_funcs lazy_grep_iter_funcs = {
2262 lazy_grep_iter_proc, 0,
2263};
2264
2265static const lazyenum_funcs lazy_grep_funcs = {
2266 lazy_grep_proc, 0,
2267};
2268
2269/*
2270 * call-seq:
2271 * lazy.grep(pattern) -> lazy_enumerator
2272 * lazy.grep(pattern) { |obj| block } -> lazy_enumerator
2273 *
2274 * Like Enumerable#grep, but chains operation to be lazy-evaluated.
2275 */
2276
2277static VALUE
2278lazy_grep(VALUE obj, VALUE pattern)
2279{
2280 const lazyenum_funcs *const funcs = rb_block_given_p() ?
2281 &lazy_grep_iter_funcs : &lazy_grep_funcs;
2282 return lazy_add_method(obj, 0, 0, pattern, rb_ary_new3(1, pattern), funcs);
2283}
2284
2285static struct MEMO *
2286lazy_grep_v_proc(VALUE proc_entry, struct MEMO *result, VALUE memos, long memo_index)
2287{
2288 struct proc_entry *entry = proc_entry_ptr(proc_entry);
2289 VALUE chain = rb_funcall(entry->memo, id_eqq, 1, result->memo_value);
2290 if (RTEST(chain)) return 0;
2291 return result;
2292}
2293
2294static struct MEMO *
2295lazy_grep_v_iter_proc(VALUE proc_entry, struct MEMO *result, VALUE memos, long memo_index)
2296{
2297 struct proc_entry *entry = proc_entry_ptr(proc_entry);
2298 VALUE value, chain = rb_funcall(entry->memo, id_eqq, 1, result->memo_value);
2299
2300 if (RTEST(chain)) return 0;
2301 value = rb_proc_call_with_block(entry->proc, 1, &(result->memo_value), Qnil);
2302 LAZY_MEMO_SET_VALUE(result, value);
2303 LAZY_MEMO_RESET_PACKED(result);
2304
2305 return result;
2306}
2307
2308static const lazyenum_funcs lazy_grep_v_iter_funcs = {
2309 lazy_grep_v_iter_proc, 0,
2310};
2311
2312static const lazyenum_funcs lazy_grep_v_funcs = {
2313 lazy_grep_v_proc, 0,
2314};
2315
2316/*
2317 * call-seq:
2318 * lazy.grep_v(pattern) -> lazy_enumerator
2319 * lazy.grep_v(pattern) { |obj| block } -> lazy_enumerator
2320 *
2321 * Like Enumerable#grep_v, but chains operation to be lazy-evaluated.
2322 */
2323
2324static VALUE
2325lazy_grep_v(VALUE obj, VALUE pattern)
2326{
2327 const lazyenum_funcs *const funcs = rb_block_given_p() ?
2328 &lazy_grep_v_iter_funcs : &lazy_grep_v_funcs;
2329 return lazy_add_method(obj, 0, 0, pattern, rb_ary_new3(1, pattern), funcs);
2330}
2331
2332static VALUE
2333call_next(VALUE obj)
2334{
2335 return rb_funcall(obj, id_next, 0);
2336}
2337
2338static VALUE
2339next_stopped(VALUE obj, VALUE _)
2340{
2341 return Qnil;
2342}
2343
2344static struct MEMO *
2345lazy_zip_arrays_func(VALUE proc_entry, struct MEMO *result, VALUE memos, long memo_index)
2346{
2347 struct proc_entry *entry = proc_entry_ptr(proc_entry);
2348 VALUE ary, arrays = entry->memo;
2349 VALUE memo = rb_ary_entry(memos, memo_index);
2350 long i, count = NIL_P(memo) ? 0 : NUM2LONG(memo);
2351
2352 ary = rb_ary_new2(RARRAY_LEN(arrays) + 1);
2353 rb_ary_push(ary, result->memo_value);
2354 for (i = 0; i < RARRAY_LEN(arrays); i++) {
2355 rb_ary_push(ary, rb_ary_entry(RARRAY_AREF(arrays, i), count));
2356 }
2357 LAZY_MEMO_SET_VALUE(result, ary);
2358 rb_ary_store(memos, memo_index, LONG2NUM(++count));
2359 return result;
2360}
2361
2362static struct MEMO *
2363lazy_zip_func(VALUE proc_entry, struct MEMO *result, VALUE memos, long memo_index)
2364{
2365 struct proc_entry *entry = proc_entry_ptr(proc_entry);
2366 VALUE arg = rb_ary_entry(memos, memo_index);
2367 VALUE zip_args = entry->memo;
2368 VALUE ary, v;
2369 long i;
2370
2371 if (NIL_P(arg)) {
2372 arg = rb_ary_new2(RARRAY_LEN(zip_args));
2373 for (i = 0; i < RARRAY_LEN(zip_args); i++) {
2374 rb_ary_push(arg, rb_funcall(RARRAY_AREF(zip_args, i), id_to_enum, 0));
2375 }
2376 rb_ary_store(memos, memo_index, arg);
2377 }
2378
2379 ary = rb_ary_new2(RARRAY_LEN(arg) + 1);
2380 rb_ary_push(ary, result->memo_value);
2381 for (i = 0; i < RARRAY_LEN(arg); i++) {
2382 v = rb_rescue2(call_next, RARRAY_AREF(arg, i), next_stopped, 0,
2383 rb_eStopIteration, (VALUE)0);
2384 rb_ary_push(ary, v);
2385 }
2386 LAZY_MEMO_SET_VALUE(result, ary);
2387 return result;
2388}
2389
2390static const lazyenum_funcs lazy_zip_funcs[] = {
2391 {lazy_zip_func, lazy_receiver_size,},
2392 {lazy_zip_arrays_func, lazy_receiver_size,},
2393};
2394
2395/*
2396 * call-seq:
2397 * lazy.zip(arg, ...) -> lazy_enumerator
2398 * lazy.zip(arg, ...) { |arr| block } -> nil
2399 *
2400 * Like Enumerable#zip, but chains operation to be lazy-evaluated.
2401 * However, if a block is given to zip, values are enumerated immediately.
2402 */
2403static VALUE
2404lazy_zip(int argc, VALUE *argv, VALUE obj)
2405{
2406 VALUE ary, v;
2407 long i;
2408 const lazyenum_funcs *funcs = &lazy_zip_funcs[1];
2409
2410 if (rb_block_given_p()) {
2411 return rb_call_super(argc, argv);
2412 }
2413
2414 ary = rb_ary_new2(argc);
2415 for (i = 0; i < argc; i++) {
2416 v = rb_check_array_type(argv[i]);
2417 if (NIL_P(v)) {
2418 for (; i < argc; i++) {
2419 if (!rb_respond_to(argv[i], id_each)) {
2420 rb_raise(rb_eTypeError, "wrong argument type %"PRIsVALUE" (must respond to :each)",
2421 rb_obj_class(argv[i]));
2422 }
2423 }
2424 ary = rb_ary_new4(argc, argv);
2425 funcs = &lazy_zip_funcs[0];
2426 break;
2427 }
2428 rb_ary_push(ary, v);
2429 }
2430
2431 return lazy_add_method(obj, 0, 0, ary, ary, funcs);
2432}
2433
2434static struct MEMO *
2435lazy_take_proc(VALUE proc_entry, struct MEMO *result, VALUE memos, long memo_index)
2436{
2437 long remain;
2438 struct proc_entry *entry = proc_entry_ptr(proc_entry);
2439 VALUE memo = rb_ary_entry(memos, memo_index);
2440
2441 if (NIL_P(memo)) {
2442 memo = entry->memo;
2443 }
2444
2445 remain = NUM2LONG(memo);
2446 if (--remain == 0) LAZY_MEMO_SET_BREAK(result);
2447 rb_ary_store(memos, memo_index, LONG2NUM(remain));
2448 return result;
2449}
2450
2451static VALUE
2452lazy_take_size(VALUE entry, VALUE receiver)
2453{
2454 long len = NUM2LONG(RARRAY_AREF(rb_ivar_get(entry, id_arguments), 0));
2455 if (NIL_P(receiver) || (FIXNUM_P(receiver) && FIX2LONG(receiver) < len))
2456 return receiver;
2457 return LONG2NUM(len);
2458}
2459
2460static int
2461lazy_take_precheck(VALUE proc_entry)
2462{
2463 struct proc_entry *entry = proc_entry_ptr(proc_entry);
2464 return entry->memo != INT2FIX(0);
2465}
2466
2467static const lazyenum_funcs lazy_take_funcs = {
2468 lazy_take_proc, lazy_take_size, lazy_take_precheck,
2469};
2470
2471/*
2472 * call-seq:
2473 * lazy.take(n) -> lazy_enumerator
2474 *
2475 * Like Enumerable#take, but chains operation to be lazy-evaluated.
2476 */
2477
2478static VALUE
2479lazy_take(VALUE obj, VALUE n)
2480{
2481 long len = NUM2LONG(n);
2482
2483 if (len < 0) {
2484 rb_raise(rb_eArgError, "attempt to take negative size");
2485 }
2486
2487 n = LONG2NUM(len); /* no more conversion */
2488
2489 return lazy_add_method(obj, 0, 0, n, rb_ary_new3(1, n), &lazy_take_funcs);
2490}
2491
2492static struct MEMO *
2493lazy_take_while_proc(VALUE proc_entry, struct MEMO *result, VALUE memos, long memo_index)
2494{
2495 VALUE take = lazyenum_yield_values(proc_entry, result);
2496 if (!RTEST(take)) {
2497 LAZY_MEMO_SET_BREAK(result);
2498 return 0;
2499 }
2500 return result;
2501}
2502
2503static const lazyenum_funcs lazy_take_while_funcs = {
2504 lazy_take_while_proc, 0,
2505};
2506
2507/*
2508 * call-seq:
2509 * lazy.take_while { |obj| block } -> lazy_enumerator
2510 *
2511 * Like Enumerable#take_while, but chains operation to be lazy-evaluated.
2512 */
2513
2514static VALUE
2515lazy_take_while(VALUE obj)
2516{
2517 LAZY_NEED_BLOCK(take_while);
2518 return lazy_add_method(obj, 0, 0, Qnil, Qnil, &lazy_take_while_funcs);
2519}
2520
2521static VALUE
2522lazy_drop_size(VALUE proc_entry, VALUE receiver)
2523{
2524 long len = NUM2LONG(RARRAY_AREF(rb_ivar_get(proc_entry, id_arguments), 0));
2525 if (NIL_P(receiver))
2526 return receiver;
2527 if (FIXNUM_P(receiver)) {
2528 len = FIX2LONG(receiver) - len;
2529 return LONG2FIX(len < 0 ? 0 : len);
2530 }
2531 return rb_funcall(receiver, '-', 1, LONG2NUM(len));
2532}
2533
2534static struct MEMO *
2535lazy_drop_proc(VALUE proc_entry, struct MEMO *result, VALUE memos, long memo_index)
2536{
2537 long remain;
2538 struct proc_entry *entry = proc_entry_ptr(proc_entry);
2539 VALUE memo = rb_ary_entry(memos, memo_index);
2540
2541 if (NIL_P(memo)) {
2542 memo = entry->memo;
2543 }
2544 remain = NUM2LONG(memo);
2545 if (remain > 0) {
2546 --remain;
2547 rb_ary_store(memos, memo_index, LONG2NUM(remain));
2548 return 0;
2549 }
2550
2551 return result;
2552}
2553
2554static const lazyenum_funcs lazy_drop_funcs = {
2555 lazy_drop_proc, lazy_drop_size,
2556};
2557
2558/*
2559 * call-seq:
2560 * lazy.drop(n) -> lazy_enumerator
2561 *
2562 * Like Enumerable#drop, but chains operation to be lazy-evaluated.
2563 */
2564
2565static VALUE
2566lazy_drop(VALUE obj, VALUE n)
2567{
2568 long len = NUM2LONG(n);
2569 VALUE argv[2];
2570 argv[0] = sym_each;
2571 argv[1] = n;
2572
2573 if (len < 0) {
2574 rb_raise(rb_eArgError, "attempt to drop negative size");
2575 }
2576
2577 return lazy_add_method(obj, 2, argv, n, rb_ary_new3(1, n), &lazy_drop_funcs);
2578}
2579
2580static struct MEMO *
2581lazy_drop_while_proc(VALUE proc_entry, struct MEMO* result, VALUE memos, long memo_index)
2582{
2583 struct proc_entry *entry = proc_entry_ptr(proc_entry);
2584 VALUE memo = rb_ary_entry(memos, memo_index);
2585
2586 if (NIL_P(memo)) {
2587 memo = entry->memo;
2588 }
2589
2590 if (!RTEST(memo)) {
2591 VALUE drop = lazyenum_yield_values(proc_entry, result);
2592 if (RTEST(drop)) return 0;
2593 rb_ary_store(memos, memo_index, Qtrue);
2594 }
2595 return result;
2596}
2597
2598static const lazyenum_funcs lazy_drop_while_funcs = {
2599 lazy_drop_while_proc, 0,
2600};
2601
2602/*
2603 * call-seq:
2604 * lazy.drop_while { |obj| block } -> lazy_enumerator
2605 *
2606 * Like Enumerable#drop_while, but chains operation to be lazy-evaluated.
2607 */
2608
2609static VALUE
2610lazy_drop_while(VALUE obj)
2611{
2612 LAZY_NEED_BLOCK(drop_while);
2613 return lazy_add_method(obj, 0, 0, Qfalse, Qnil, &lazy_drop_while_funcs);
2614}
2615
2616static int
2617lazy_uniq_check(VALUE chain, VALUE memos, long memo_index)
2618{
2619 VALUE hash = rb_ary_entry(memos, memo_index);
2620
2621 if (NIL_P(hash)) {
2622 hash = rb_obj_hide(rb_hash_new());
2623 rb_ary_store(memos, memo_index, hash);
2624 }
2625
2626 return rb_hash_add_new_element(hash, chain, Qfalse);
2627}
2628
2629static struct MEMO *
2630lazy_uniq_proc(VALUE proc_entry, struct MEMO *result, VALUE memos, long memo_index)
2631{
2632 if (lazy_uniq_check(result->memo_value, memos, memo_index)) return 0;
2633 return result;
2634}
2635
2636static struct MEMO *
2637lazy_uniq_iter_proc(VALUE proc_entry, struct MEMO *result, VALUE memos, long memo_index)
2638{
2639 VALUE chain = lazyenum_yield(proc_entry, result);
2640
2641 if (lazy_uniq_check(chain, memos, memo_index)) return 0;
2642 return result;
2643}
2644
2645static const lazyenum_funcs lazy_uniq_iter_funcs = {
2646 lazy_uniq_iter_proc, 0,
2647};
2648
2649static const lazyenum_funcs lazy_uniq_funcs = {
2650 lazy_uniq_proc, 0,
2651};
2652
2653/*
2654 * call-seq:
2655 * lazy.uniq -> lazy_enumerator
2656 * lazy.uniq { |item| block } -> lazy_enumerator
2657 *
2658 * Like Enumerable#uniq, but chains operation to be lazy-evaluated.
2659 */
2660
2661static VALUE
2662lazy_uniq(VALUE obj)
2663{
2664 const lazyenum_funcs *const funcs =
2665 rb_block_given_p() ? &lazy_uniq_iter_funcs : &lazy_uniq_funcs;
2666 return lazy_add_method(obj, 0, 0, Qnil, Qnil, funcs);
2667}
2668
2669static struct MEMO *
2670lazy_compact_proc(VALUE proc_entry, struct MEMO *result, VALUE memos, long memo_index)
2671{
2672 if (NIL_P(result->memo_value)) return 0;
2673 return result;
2674}
2675
2676static const lazyenum_funcs lazy_compact_funcs = {
2677 lazy_compact_proc, 0,
2678};
2679
2680/*
2681 * call-seq:
2682 * lazy.compact -> lazy_enumerator
2683 *
2684 * Like Enumerable#compact, but chains operation to be lazy-evaluated.
2685 */
2686
2687static VALUE
2688lazy_compact(VALUE obj)
2689{
2690 return lazy_add_method(obj, 0, 0, Qnil, Qnil, &lazy_compact_funcs);
2691}
2692
2693static struct MEMO *
2694lazy_with_index_proc(VALUE proc_entry, struct MEMO* result, VALUE memos, long memo_index)
2695{
2696 struct proc_entry *entry = proc_entry_ptr(proc_entry);
2697 VALUE memo = rb_ary_entry(memos, memo_index);
2698 VALUE argv[2];
2699
2700 if (NIL_P(memo)) {
2701 memo = entry->memo;
2702 }
2703
2704 argv[0] = result->memo_value;
2705 argv[1] = memo;
2706 if (entry->proc) {
2707 rb_proc_call_with_block(entry->proc, 2, argv, Qnil);
2708 LAZY_MEMO_RESET_PACKED(result);
2709 }
2710 else {
2711 LAZY_MEMO_SET_VALUE(result, rb_ary_new_from_values(2, argv));
2712 LAZY_MEMO_SET_PACKED(result);
2713 }
2714 rb_ary_store(memos, memo_index, LONG2NUM(NUM2LONG(memo) + 1));
2715 return result;
2716}
2717
2718static VALUE
2719lazy_with_index_size(VALUE proc, VALUE receiver)
2720{
2721 return receiver;
2722}
2723
2724static const lazyenum_funcs lazy_with_index_funcs = {
2725 lazy_with_index_proc, lazy_with_index_size,
2726};
2727
2728/*
2729 * call-seq:
2730 * lazy.with_index(offset = 0) {|(*args), idx| block }
2731 * lazy.with_index(offset = 0)
2732 *
2733 * If a block is given, returns a lazy enumerator that will
2734 * iterate over the given block for each element
2735 * with an index, which starts from +offset+, and returns a
2736 * lazy enumerator that yields the same values (without the index).
2737 *
2738 * If a block is not given, returns a new lazy enumerator that
2739 * includes the index, starting from +offset+.
2740 *
2741 * +offset+:: the starting index to use
2742 *
2743 * See Enumerator#with_index.
2744 */
2745static VALUE
2746lazy_with_index(int argc, VALUE *argv, VALUE obj)
2747{
2748 VALUE memo;
2749
2750 rb_scan_args(argc, argv, "01", &memo);
2751 if (NIL_P(memo))
2752 memo = LONG2NUM(0);
2753
2754 return lazy_add_method(obj, 0, 0, memo, rb_ary_new_from_values(1, &memo), &lazy_with_index_funcs);
2755}
2756
2757#if 0 /* for RDoc */
2758
2759/*
2760 * call-seq:
2761 * lazy.chunk { |elt| ... } -> lazy_enumerator
2762 *
2763 * Like Enumerable#chunk, but chains operation to be lazy-evaluated.
2764 */
2765static VALUE
2766lazy_chunk(VALUE self)
2767{
2768}
2769
2770/*
2771 * call-seq:
2772 * lazy.chunk_while {|elt_before, elt_after| bool } -> lazy_enumerator
2773 *
2774 * Like Enumerable#chunk_while, but chains operation to be lazy-evaluated.
2775 */
2776static VALUE
2777lazy_chunk_while(VALUE self)
2778{
2779}
2780
2781/*
2782 * call-seq:
2783 * lazy.slice_after(pattern) -> lazy_enumerator
2784 * lazy.slice_after { |elt| bool } -> lazy_enumerator
2785 *
2786 * Like Enumerable#slice_after, but chains operation to be lazy-evaluated.
2787 */
2788static VALUE
2789lazy_slice_after(VALUE self)
2790{
2791}
2792
2793/*
2794 * call-seq:
2795 * lazy.slice_before(pattern) -> lazy_enumerator
2796 * lazy.slice_before { |elt| bool } -> lazy_enumerator
2797 *
2798 * Like Enumerable#slice_before, but chains operation to be lazy-evaluated.
2799 */
2800static VALUE
2801lazy_slice_before(VALUE self)
2802{
2803}
2804
2805/*
2806 * call-seq:
2807 * lazy.slice_when {|elt_before, elt_after| bool } -> lazy_enumerator
2808 *
2809 * Like Enumerable#slice_when, but chains operation to be lazy-evaluated.
2810 */
2811static VALUE
2812lazy_slice_when(VALUE self)
2813{
2814}
2815# endif
2816
2817static VALUE
2818lazy_super(int argc, VALUE *argv, VALUE lazy)
2819{
2820 return enumerable_lazy(rb_call_super(argc, argv));
2821}
2822
2823/*
2824 * call-seq:
2825 * enum.lazy -> lazy_enumerator
2826 *
2827 * Returns self.
2828 */
2829
2830static VALUE
2831lazy_lazy(VALUE obj)
2832{
2833 return obj;
2834}
2835
2836/*
2837 * Document-class: StopIteration
2838 *
2839 * Raised to stop the iteration, in particular by Enumerator#next. It is
2840 * rescued by Kernel#loop.
2841 *
2842 * loop do
2843 * puts "Hello"
2844 * raise StopIteration
2845 * puts "World"
2846 * end
2847 * puts "Done!"
2848 *
2849 * <em>produces:</em>
2850 *
2851 * Hello
2852 * Done!
2853 */
2854
2855/*
2856 * call-seq:
2857 * result -> value
2858 *
2859 * Returns the return value of the iterator.
2860 *
2861 * o = Object.new
2862 * def o.each
2863 * yield 1
2864 * yield 2
2865 * yield 3
2866 * 100
2867 * end
2868 *
2869 * e = o.to_enum
2870 *
2871 * puts e.next #=> 1
2872 * puts e.next #=> 2
2873 * puts e.next #=> 3
2874 *
2875 * begin
2876 * e.next
2877 * rescue StopIteration => ex
2878 * puts ex.result #=> 100
2879 * end
2880 *
2881 */
2882
2883static VALUE
2884stop_result(VALUE self)
2885{
2886 return rb_attr_get(self, id_result);
2887}
2888
2889/*
2890 * Producer
2891 */
2892
2893static void
2894producer_mark_and_move(void *p)
2895{
2896 struct producer *ptr = p;
2897 rb_gc_mark_and_move(&ptr->init);
2898 rb_gc_mark_and_move(&ptr->proc);
2899 rb_gc_mark_and_move(&ptr->size);
2900}
2901
2902#define producer_free RUBY_TYPED_DEFAULT_FREE
2903
2904static size_t
2905producer_memsize(const void *p)
2906{
2907 return sizeof(struct producer);
2908}
2909
2910static const rb_data_type_t producer_data_type = {
2911 "producer",
2912 {
2913 producer_mark_and_move,
2914 producer_free,
2915 producer_memsize,
2916 producer_mark_and_move,
2917 },
2918 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE
2919};
2920
2921static struct producer *
2922producer_ptr(VALUE obj)
2923{
2924 struct producer *ptr;
2925
2926 TypedData_Get_Struct(obj, struct producer, &producer_data_type, ptr);
2927 if (!ptr || UNDEF_P(ptr->proc)) {
2928 rb_raise(rb_eArgError, "uninitialized producer");
2929 }
2930 return ptr;
2931}
2932
2933/* :nodoc: */
2934static VALUE
2935producer_allocate(VALUE klass)
2936{
2937 struct producer *ptr;
2938 VALUE obj;
2939
2940 obj = TypedData_Make_Struct(klass, struct producer, &producer_data_type, ptr);
2941 ptr->init = Qundef;
2942 ptr->proc = Qundef;
2943 ptr->size = Qnil;
2944
2945 return obj;
2946}
2947
2948static VALUE
2949producer_init(VALUE obj, VALUE init, VALUE proc, VALUE size)
2950{
2951 struct producer *ptr;
2952
2953 TypedData_Get_Struct(obj, struct producer, &producer_data_type, ptr);
2954
2955 if (!ptr) {
2956 rb_raise(rb_eArgError, "unallocated producer");
2957 }
2958
2959 RB_OBJ_WRITE(obj, &ptr->init, init);
2960 RB_OBJ_WRITE(obj, &ptr->proc, proc);
2961 RB_OBJ_WRITE(obj, &ptr->size, size);
2962
2963 return obj;
2964}
2965
2966static VALUE
2967producer_each_stop(VALUE dummy, VALUE exc)
2968{
2969 return rb_attr_get(exc, id_result);
2970}
2971
2972NORETURN(static VALUE producer_each_i(VALUE obj));
2973
2974static VALUE
2975producer_each_i(VALUE obj)
2976{
2977 struct producer *ptr;
2978 VALUE init, proc, curr;
2979
2980 ptr = producer_ptr(obj);
2981 init = ptr->init;
2982 proc = ptr->proc;
2983
2984 if (UNDEF_P(init)) {
2985 curr = Qnil;
2986 }
2987 else {
2988 rb_yield(init);
2989 curr = init;
2990 }
2991
2992 for (;;) {
2993 curr = rb_funcall(proc, id_call, 1, curr);
2994 rb_yield(curr);
2995 }
2996
2997 UNREACHABLE_RETURN(Qnil);
2998}
2999
3000/* :nodoc: */
3001static VALUE
3002producer_each(VALUE obj)
3003{
3004 rb_need_block();
3005
3006 return rb_rescue2(producer_each_i, obj, producer_each_stop, (VALUE)0, rb_eStopIteration, (VALUE)0);
3007}
3008
3009static VALUE
3010producer_size(VALUE obj, VALUE args, VALUE eobj)
3011{
3012 struct producer *ptr = producer_ptr(obj);
3013 VALUE size = ptr->size;
3014
3015 if (NIL_P(size)) return Qnil;
3016 if (RB_INTEGER_TYPE_P(size) || RB_FLOAT_TYPE_P(size)) return size;
3017
3018 return rb_funcall(size, id_call, 0);
3019}
3020
3021/*
3022 * call-seq:
3023 * Enumerator.produce(initial = nil, size: nil) { |prev| block } -> enumerator
3024 *
3025 * Creates an infinite enumerator from any block, just called over and
3026 * over. The result of the previous iteration is passed to the next one.
3027 * If +initial+ is provided, it is passed to the first iteration, and
3028 * becomes the first element of the enumerator; if it is not provided,
3029 * the first iteration receives +nil+, and its result becomes the first
3030 * element of the iterator.
3031 *
3032 * Raising StopIteration from the block stops an iteration.
3033 *
3034 * Enumerator.produce(1, &:succ) # => enumerator of 1, 2, 3, 4, ....
3035 *
3036 * Enumerator.produce { rand(10) } # => infinite random number sequence
3037 *
3038 * ancestors = Enumerator.produce(node) { |prev| node = prev.parent or raise StopIteration }
3039 * enclosing_section = ancestors.find { |n| n.type == :section }
3040 *
3041 * Using ::produce together with Enumerable methods like Enumerable#detect,
3042 * Enumerable#slice_after, Enumerable#take_while can provide Enumerator-based alternatives
3043 * for +while+ and +until+ cycles:
3044 *
3045 * # Find next Tuesday
3046 * require "date"
3047 * Enumerator.produce(Date.today, &:succ).detect(&:tuesday?)
3048 *
3049 * # Simple lexer:
3050 * require "strscan"
3051 * scanner = StringScanner.new("7+38/6")
3052 * PATTERN = %r{\d+|[-/+*]}
3053 * Enumerator.produce { scanner.scan(PATTERN) }.slice_after { scanner.eos? }.first
3054 * # => ["7", "+", "38", "/", "6"]
3055 *
3056 * The optional +size+ keyword argument specifies the size of the enumerator,
3057 * which can be retrieved by Enumerator#size. It can be an integer,
3058 * +Float::INFINITY+, a callable object (such as a lambda), or +nil+ to
3059 * indicate unknown size. When not specified, the size defaults to
3060 * +Float::INFINITY+.
3061 *
3062 * # Infinite enumerator
3063 * enum = Enumerator.produce(1, size: Float::INFINITY, &:succ)
3064 * enum.size # => Float::INFINITY
3065 *
3066 * # Finite enumerator with known/computable size
3067 * abs_dir = File.expand_path("./baz") # => "/foo/bar/baz"
3068 * traverser = Enumerator.produce(abs_dir, size: -> { abs_dir.count("/") + 1 }) {
3069 * raise StopIteration if it == "/"
3070 * File.dirname(it)
3071 * }
3072 * traverser.size # => 4
3073 *
3074 * # Finite enumerator with unknown size
3075 * calendar = Enumerator.produce(Date.today, size: nil) {
3076 * it.monday? ? raise(StopIteration) : it + 1
3077 * }
3078 * calendar.size # => nil
3079 */
3080static VALUE
3081enumerator_s_produce(int argc, VALUE *argv, VALUE klass)
3082{
3083 VALUE init, producer, opts, size;
3084 ID keyword_ids[1];
3085
3086 if (!rb_block_given_p()) rb_raise(rb_eArgError, "no block given");
3087
3088 keyword_ids[0] = rb_intern("size");
3089 rb_scan_args_kw(RB_SCAN_ARGS_LAST_HASH_KEYWORDS, argc, argv, "01:", &init, &opts);
3090 rb_get_kwargs(opts, keyword_ids, 0, 1, &size);
3091
3092 size = UNDEF_P(size) ? DBL2NUM(HUGE_VAL) : convert_to_feasible_size_value(size);
3093
3094 if (argc == 0 || (argc == 1 && !NIL_P(opts))) {
3095 init = Qundef;
3096 }
3097
3098 producer = producer_init(producer_allocate(rb_cEnumProducer), init, rb_block_proc(), size);
3099
3100 return rb_enumeratorize_with_size_kw(producer, sym_each, 0, 0, producer_size, RB_NO_KEYWORDS);
3101}
3102
3103/*
3104 * Document-class: Enumerator::Chain
3105 *
3106 * Enumerator::Chain is a subclass of Enumerator, which represents a
3107 * chain of enumerables that works as a single enumerator.
3108 *
3109 * This type of objects can be created by Enumerable#chain and
3110 * Enumerator#+.
3111 */
3112
3113static void
3114enum_chain_mark_and_move(void *p)
3115{
3116 struct enum_chain *ptr = p;
3117 rb_gc_mark_and_move(&ptr->enums);
3118}
3119
3120#define enum_chain_free RUBY_TYPED_DEFAULT_FREE
3121
3122static size_t
3123enum_chain_memsize(const void *p)
3124{
3125 return sizeof(struct enum_chain);
3126}
3127
3128static const rb_data_type_t enum_chain_data_type = {
3129 "chain",
3130 {
3131 enum_chain_mark_and_move,
3132 enum_chain_free,
3133 enum_chain_memsize,
3134 enum_chain_mark_and_move,
3135 },
3136 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
3137};
3138
3139static struct enum_chain *
3140enum_chain_ptr(VALUE obj)
3141{
3142 struct enum_chain *ptr;
3143
3144 TypedData_Get_Struct(obj, struct enum_chain, &enum_chain_data_type, ptr);
3145 if (!ptr || UNDEF_P(ptr->enums)) {
3146 rb_raise(rb_eArgError, "uninitialized chain");
3147 }
3148 return ptr;
3149}
3150
3151/* :nodoc: */
3152static VALUE
3153enum_chain_allocate(VALUE klass)
3154{
3155 struct enum_chain *ptr;
3156 VALUE obj;
3157
3158 obj = TypedData_Make_Struct(klass, struct enum_chain, &enum_chain_data_type, ptr);
3159 ptr->enums = Qundef;
3160 ptr->pos = -1;
3161
3162 return obj;
3163}
3164
3165/*
3166 * call-seq:
3167 * Enumerator::Chain.new(*enums) -> enum
3168 *
3169 * Generates a new enumerator object that iterates over the elements
3170 * of given enumerable objects in sequence.
3171 *
3172 * e = Enumerator::Chain.new(1..3, [4, 5])
3173 * e.to_a #=> [1, 2, 3, 4, 5]
3174 * e.size #=> 5
3175 */
3176static VALUE
3177enum_chain_initialize(VALUE obj, VALUE enums)
3178{
3179 struct enum_chain *ptr;
3180
3181 rb_check_frozen(obj);
3182 TypedData_Get_Struct(obj, struct enum_chain, &enum_chain_data_type, ptr);
3183
3184 if (!ptr) rb_raise(rb_eArgError, "unallocated chain");
3185
3186 RB_OBJ_WRITE(obj, &ptr->enums, rb_ary_freeze(enums));
3187 ptr->pos = -1;
3188
3189 return obj;
3190}
3191
3192static VALUE
3193new_enum_chain(VALUE enums)
3194{
3195 long i;
3196 VALUE obj = enum_chain_initialize(enum_chain_allocate(rb_cEnumChain), enums);
3197
3198 for (i = 0; i < RARRAY_LEN(enums); i++) {
3199 if (RTEST(rb_obj_is_kind_of(RARRAY_AREF(enums, i), rb_cLazy))) {
3200 return enumerable_lazy(obj);
3201 }
3202 }
3203
3204 return obj;
3205}
3206
3207/* :nodoc: */
3208static VALUE
3209enum_chain_init_copy(VALUE obj, VALUE orig)
3210{
3211 struct enum_chain *ptr0, *ptr1;
3212
3213 if (!OBJ_INIT_COPY(obj, orig)) return obj;
3214 ptr0 = enum_chain_ptr(orig);
3215
3216 TypedData_Get_Struct(obj, struct enum_chain, &enum_chain_data_type, ptr1);
3217
3218 if (!ptr1) rb_raise(rb_eArgError, "unallocated chain");
3219
3220 RB_OBJ_WRITE(obj, &ptr1->enums, ptr0->enums);
3221 ptr1->pos = ptr0->pos;
3222
3223 return obj;
3224}
3225
3226static VALUE
3227enum_chain_total_size(VALUE enums)
3228{
3229 VALUE total = INT2FIX(0);
3230 long i;
3231
3232 for (i = 0; i < RARRAY_LEN(enums); i++) {
3233 VALUE size = enum_size(RARRAY_AREF(enums, i));
3234
3235 if (NIL_P(size) || (RB_FLOAT_TYPE_P(size) && isinf(NUM2DBL(size)))) {
3236 return size;
3237 }
3238 if (!RB_INTEGER_TYPE_P(size)) {
3239 return Qnil;
3240 }
3241
3242 total = rb_funcall(total, '+', 1, size);
3243 }
3244
3245 return total;
3246}
3247
3248/*
3249 * call-seq:
3250 * obj.size -> int, Float::INFINITY or nil
3251 *
3252 * Returns the total size of the enumerator chain calculated by
3253 * summing up the size of each enumerable in the chain. If any of the
3254 * enumerables reports its size as nil or Float::INFINITY, that value
3255 * is returned as the total size.
3256 */
3257static VALUE
3258enum_chain_size(VALUE obj)
3259{
3260 return enum_chain_total_size(enum_chain_ptr(obj)->enums);
3261}
3262
3263static VALUE
3264enum_chain_enum_size(VALUE obj, VALUE args, VALUE eobj)
3265{
3266 return enum_chain_size(obj);
3267}
3268
3269static VALUE
3270enum_chain_enum_no_size(VALUE obj, VALUE args, VALUE eobj)
3271{
3272 return Qnil;
3273}
3274
3275/*
3276 * call-seq:
3277 * obj.each(*args) { |...| ... } -> obj
3278 * obj.each(*args) -> enumerator
3279 *
3280 * Iterates over the elements of the first enumerable by calling the
3281 * "each" method on it with the given arguments, then proceeds to the
3282 * following enumerables in sequence until all of the enumerables are
3283 * exhausted.
3284 *
3285 * If no block is given, returns an enumerator.
3286 */
3287static VALUE
3288enum_chain_each(int argc, VALUE *argv, VALUE obj)
3289{
3290 VALUE enums, block;
3291 struct enum_chain *objptr;
3292 long i;
3293
3294 RETURN_SIZED_ENUMERATOR(obj, argc, argv, argc > 0 ? enum_chain_enum_no_size : enum_chain_enum_size);
3295
3296 objptr = enum_chain_ptr(obj);
3297 enums = objptr->enums;
3298 block = rb_block_proc();
3299
3300 for (i = 0; i < RARRAY_LEN(enums); i++) {
3301 objptr->pos = i;
3302 rb_funcall_with_block(RARRAY_AREF(enums, i), id_each, argc, argv, block);
3303 }
3304
3305 return obj;
3306}
3307
3308/*
3309 * call-seq:
3310 * obj.rewind -> obj
3311 *
3312 * Rewinds the enumerator chain by calling the "rewind" method on each
3313 * enumerable in reverse order. Each call is performed only if the
3314 * enumerable responds to the method.
3315 */
3316static VALUE
3317enum_chain_rewind(VALUE obj)
3318{
3319 struct enum_chain *objptr = enum_chain_ptr(obj);
3320 VALUE enums = objptr->enums;
3321 long i;
3322
3323 for (i = objptr->pos; 0 <= i && i < RARRAY_LEN(enums); objptr->pos = --i) {
3324 rb_check_funcall(RARRAY_AREF(enums, i), id_rewind, 0, 0);
3325 }
3326
3327 return obj;
3328}
3329
3330static VALUE
3331inspect_enum_chain(VALUE obj, VALUE dummy, int recur)
3332{
3333 VALUE klass = rb_obj_class(obj);
3334 struct enum_chain *ptr;
3335
3336 TypedData_Get_Struct(obj, struct enum_chain, &enum_chain_data_type, ptr);
3337
3338 if (!ptr || UNDEF_P(ptr->enums)) {
3339 return rb_sprintf("#<%"PRIsVALUE": uninitialized>", rb_class_path(klass));
3340 }
3341
3342 if (recur) {
3343 return rb_sprintf("#<%"PRIsVALUE": ...>", rb_class_path(klass));
3344 }
3345
3346 return rb_sprintf("#<%"PRIsVALUE": %+"PRIsVALUE">", rb_class_path(klass), ptr->enums);
3347}
3348
3349/*
3350 * call-seq:
3351 * obj.inspect -> string
3352 *
3353 * Returns a printable version of the enumerator chain.
3354 */
3355static VALUE
3356enum_chain_inspect(VALUE obj)
3357{
3358 return rb_exec_recursive(inspect_enum_chain, obj, 0);
3359}
3360
3361/*
3362 * call-seq:
3363 * e.chain(*enums) -> enumerator
3364 *
3365 * Returns an enumerator object generated from this enumerator and
3366 * given enumerables.
3367 *
3368 * e = (1..3).chain([4, 5])
3369 * e.to_a #=> [1, 2, 3, 4, 5]
3370 */
3371static VALUE
3372 enum_chain(int argc, VALUE *argv, VALUE obj)
3373{
3374 VALUE enums = rb_ary_new_from_values(1, &obj);
3375 rb_ary_cat(enums, argv, argc);
3376 return new_enum_chain(enums);
3377}
3378
3379/*
3380 * call-seq:
3381 * e + enum -> enumerator
3382 *
3383 * Returns an enumerator object generated from this enumerator and a
3384 * given enumerable.
3385 *
3386 * e = (1..3).each + [4, 5]
3387 * e.to_a #=> [1, 2, 3, 4, 5]
3388 */
3389static VALUE
3390enumerator_plus(VALUE obj, VALUE eobj)
3391{
3392 return new_enum_chain(rb_ary_new_from_args(2, obj, eobj));
3393}
3394
3395/*
3396 * Document-class: Enumerator::Product
3397 *
3398 * Enumerator::Product generates a Cartesian product of any number of
3399 * enumerable objects. Iterating over the product of enumerable
3400 * objects is roughly equivalent to nested each_entry loops where the
3401 * loop for the rightmost object is put innermost.
3402 *
3403 * innings = Enumerator::Product.new(1..9, ['top', 'bottom'])
3404 *
3405 * innings.each do |i, h|
3406 * p [i, h]
3407 * end
3408 * # [1, "top"]
3409 * # [1, "bottom"]
3410 * # [2, "top"]
3411 * # [2, "bottom"]
3412 * # [3, "top"]
3413 * # [3, "bottom"]
3414 * # ...
3415 * # [9, "top"]
3416 * # [9, "bottom"]
3417 *
3418 * The method used against each enumerable object is `each_entry`
3419 * instead of `each` so that the product of N enumerable objects
3420 * yields an array of exactly N elements in each iteration.
3421 *
3422 * When no enumerator is given, it calls a given block once yielding
3423 * an empty argument list.
3424 *
3425 * This type of objects can be created by Enumerator.product.
3426 */
3427
3428static void
3429enum_product_mark_and_move(void *p)
3430{
3431 struct enum_product *ptr = p;
3432 rb_gc_mark_and_move(&ptr->enums);
3433}
3434
3435#define enum_product_free RUBY_TYPED_DEFAULT_FREE
3436
3437static size_t
3438enum_product_memsize(const void *p)
3439{
3440 return sizeof(struct enum_product);
3441}
3442
3443static const rb_data_type_t enum_product_data_type = {
3444 "product",
3445 {
3446 enum_product_mark_and_move,
3447 enum_product_free,
3448 enum_product_memsize,
3449 enum_product_mark_and_move,
3450 },
3451 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
3452};
3453
3454static struct enum_product *
3455enum_product_ptr(VALUE obj)
3456{
3457 struct enum_product *ptr;
3458
3459 TypedData_Get_Struct(obj, struct enum_product, &enum_product_data_type, ptr);
3460 if (!ptr || UNDEF_P(ptr->enums)) {
3461 rb_raise(rb_eArgError, "uninitialized product");
3462 }
3463 return ptr;
3464}
3465
3466/* :nodoc: */
3467static VALUE
3468enum_product_allocate(VALUE klass)
3469{
3470 struct enum_product *ptr;
3471 VALUE obj;
3472
3473 obj = TypedData_Make_Struct(klass, struct enum_product, &enum_product_data_type, ptr);
3474 ptr->enums = Qundef;
3475
3476 return obj;
3477}
3478
3479/*
3480 * call-seq:
3481 * Enumerator::Product.new(*enums) -> enum
3482 *
3483 * Generates a new enumerator object that generates a Cartesian
3484 * product of given enumerable objects.
3485 *
3486 * e = Enumerator::Product.new(1..3, [4, 5])
3487 * e.to_a #=> [[1, 4], [1, 5], [2, 4], [2, 5], [3, 4], [3, 5]]
3488 * e.size #=> 6
3489 */
3490static VALUE
3491enum_product_initialize(int argc, VALUE *argv, VALUE obj)
3492{
3493 struct enum_product *ptr;
3494 VALUE enums = Qnil, options = Qnil;
3495
3496 rb_scan_args(argc, argv, "*:", &enums, &options);
3497
3498 if (!NIL_P(options) && !RHASH_EMPTY_P(options)) {
3499 rb_exc_raise(rb_keyword_error_new("unknown", rb_hash_keys(options)));
3500 }
3501
3502 rb_check_frozen(obj);
3503 TypedData_Get_Struct(obj, struct enum_product, &enum_product_data_type, ptr);
3504
3505 if (!ptr) rb_raise(rb_eArgError, "unallocated product");
3506
3507 RB_OBJ_WRITE(obj, &ptr->enums, rb_ary_freeze(enums));
3508
3509 return obj;
3510}
3511
3512/* :nodoc: */
3513static VALUE
3514enum_product_init_copy(VALUE obj, VALUE orig)
3515{
3516 struct enum_product *ptr0, *ptr1;
3517
3518 if (!OBJ_INIT_COPY(obj, orig)) return obj;
3519 ptr0 = enum_product_ptr(orig);
3520
3521 TypedData_Get_Struct(obj, struct enum_product, &enum_product_data_type, ptr1);
3522
3523 if (!ptr1) rb_raise(rb_eArgError, "unallocated product");
3524
3525 RB_OBJ_WRITE(obj, &ptr1->enums, ptr0->enums);
3526
3527 return obj;
3528}
3529
3530static VALUE
3531enum_product_total_size(VALUE enums)
3532{
3533 VALUE total = INT2FIX(1);
3534 VALUE sizes = rb_ary_hidden_new(RARRAY_LEN(enums));
3535 long i;
3536
3537 for (i = 0; i < RARRAY_LEN(enums); i++) {
3538 VALUE size = enum_size(RARRAY_AREF(enums, i));
3539 if (size == INT2FIX(0)) {
3540 rb_ary_resize(sizes, 0);
3541 return size;
3542 }
3543 rb_ary_push(sizes, size);
3544 }
3545 for (i = 0; i < RARRAY_LEN(sizes); i++) {
3546 VALUE size = RARRAY_AREF(sizes, i);
3547
3548 if (NIL_P(size) || (RB_TYPE_P(size, T_FLOAT) && isinf(NUM2DBL(size)))) {
3549 return size;
3550 }
3551 if (!RB_INTEGER_TYPE_P(size)) {
3552 return Qnil;
3553 }
3554
3555 total = rb_funcall(total, '*', 1, size);
3556 }
3557
3558 return total;
3559}
3560
3561/*
3562 * call-seq:
3563 * obj.size -> int, Float::INFINITY or nil
3564 *
3565 * Returns the total size of the enumerator product calculated by
3566 * multiplying the sizes of enumerables in the product. If any of the
3567 * enumerables reports its size as nil or Float::INFINITY, that value
3568 * is returned as the size.
3569 */
3570static VALUE
3571enum_product_size(VALUE obj)
3572{
3573 return enum_product_total_size(enum_product_ptr(obj)->enums);
3574}
3575
3576static VALUE
3577enum_product_enum_size(VALUE obj, VALUE args, VALUE eobj)
3578{
3579 return enum_product_size(obj);
3580}
3581
3582 struct product_state {
3583 VALUE obj;
3584 VALUE block;
3585 int argc;
3586 VALUE *argv;
3587 int index;
3588};
3589
3590static VALUE product_each(VALUE, struct product_state *);
3591
3592static VALUE
3593product_each_i(RB_BLOCK_CALL_FUNC_ARGLIST(value, state))
3594{
3595 struct product_state *pstate = (struct product_state *)state;
3596 pstate->argv[pstate->index++] = value;
3597
3598 VALUE val = product_each(pstate->obj, pstate);
3599 pstate->index--;
3600 return val;
3601}
3602
3603static VALUE
3604product_each(VALUE obj, struct product_state *pstate)
3605{
3606 struct enum_product *ptr = enum_product_ptr(obj);
3607 VALUE enums = ptr->enums;
3608
3609 if (pstate->index < pstate->argc) {
3610 VALUE eobj = RARRAY_AREF(enums, pstate->index);
3611
3612 rb_block_call(eobj, id_each_entry, 0, NULL, product_each_i, (VALUE)pstate);
3613 }
3614 else {
3615 rb_funcall(pstate->block, id_call, 1, rb_ary_new_from_values(pstate->argc, pstate->argv));
3616 }
3617
3618 return obj;
3619}
3620
3621static VALUE
3622enum_product_run(VALUE obj, VALUE block)
3623{
3624 struct enum_product *ptr = enum_product_ptr(obj);
3625 int argc = RARRAY_LENINT(ptr->enums);
3626 struct product_state state = {
3627 .obj = obj,
3628 .block = block,
3629 .index = 0,
3630 .argc = argc,
3631 .argv = ALLOCA_N(VALUE, argc),
3632 };
3633
3634 return product_each(obj, &state);
3635}
3636
3637/*
3638 * call-seq:
3639 * obj.each { |...| ... } -> obj
3640 * obj.each -> enumerator
3641 *
3642 * Iterates over the elements of the first enumerable by calling the
3643 * "each_entry" method on it with the given arguments, then proceeds
3644 * to the following enumerables in sequence until all of the
3645 * enumerables are exhausted.
3646 *
3647 * If no block is given, returns an enumerator. Otherwise, returns self.
3648 */
3649static VALUE
3650enum_product_each(VALUE obj)
3651{
3652 RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_product_enum_size);
3653
3654 return enum_product_run(obj, rb_block_proc());
3655}
3656
3657/*
3658 * call-seq:
3659 * obj.rewind -> obj
3660 *
3661 * Rewinds the product enumerator by calling the "rewind" method on
3662 * each enumerable in reverse order. Each call is performed only if
3663 * the enumerable responds to the method.
3664 */
3665static VALUE
3666enum_product_rewind(VALUE obj)
3667{
3668 struct enum_product *ptr = enum_product_ptr(obj);
3669 VALUE enums = ptr->enums;
3670 long i;
3671
3672 for (i = 0; i < RARRAY_LEN(enums); i++) {
3673 rb_check_funcall(RARRAY_AREF(enums, i), id_rewind, 0, 0);
3674 }
3675
3676 return obj;
3677}
3678
3679static VALUE
3680inspect_enum_product(VALUE obj, VALUE dummy, int recur)
3681{
3682 VALUE klass = rb_obj_class(obj);
3683 struct enum_product *ptr;
3684
3685 TypedData_Get_Struct(obj, struct enum_product, &enum_product_data_type, ptr);
3686
3687 if (!ptr || UNDEF_P(ptr->enums)) {
3688 return rb_sprintf("#<%"PRIsVALUE": uninitialized>", rb_class_path(klass));
3689 }
3690
3691 if (recur) {
3692 return rb_sprintf("#<%"PRIsVALUE": ...>", rb_class_path(klass));
3693 }
3694
3695 return rb_sprintf("#<%"PRIsVALUE": %+"PRIsVALUE">", rb_class_path(klass), ptr->enums);
3696}
3697
3698/*
3699 * call-seq:
3700 * obj.inspect -> string
3701 *
3702 * Returns a printable version of the product enumerator.
3703 */
3704static VALUE
3705enum_product_inspect(VALUE obj)
3706{
3707 return rb_exec_recursive(inspect_enum_product, obj, 0);
3708}
3709
3710/*
3711 * call-seq:
3712 * Enumerator.product(*enums) -> enumerator
3713 * Enumerator.product(*enums) { |elts| ... } -> enumerator
3714 *
3715 * Generates a new enumerator object that generates a Cartesian
3716 * product of given enumerable objects. This is equivalent to
3717 * Enumerator::Product.new.
3718 *
3719 * e = Enumerator.product(1..3, [4, 5])
3720 * e.to_a #=> [[1, 4], [1, 5], [2, 4], [2, 5], [3, 4], [3, 5]]
3721 * e.size #=> 6
3722 *
3723 * When a block is given, calls the block with each N-element array
3724 * generated and returns +nil+.
3725 */
3726static VALUE
3727enumerator_s_product(int argc, VALUE *argv, VALUE klass)
3728{
3729 VALUE enums = Qnil, options = Qnil, block = Qnil;
3730
3731 rb_scan_args(argc, argv, "*:&", &enums, &options, &block);
3732
3733 if (!NIL_P(options) && !RHASH_EMPTY_P(options)) {
3734 rb_exc_raise(rb_keyword_error_new("unknown", rb_hash_keys(options)));
3735 }
3736
3737 VALUE obj = enum_product_initialize(argc, argv, enum_product_allocate(rb_cEnumProduct));
3738
3739 if (!NIL_P(block)) {
3740 enum_product_run(obj, block);
3741 return Qnil;
3742 }
3743
3744 return obj;
3745}
3746
3747 struct arith_seq {
3748 struct enumerator enumerator;
3749 VALUE begin;
3750 VALUE end;
3751 VALUE step;
3752 bool exclude_end;
3753};
3754
3755RUBY_REFERENCES(arith_seq_refs) = {
3756 RUBY_REF_EDGE(struct enumerator, obj),
3757 RUBY_REF_EDGE(struct enumerator, args),
3758 RUBY_REF_EDGE(struct enumerator, fib),
3759 RUBY_REF_EDGE(struct enumerator, dst),
3760 RUBY_REF_EDGE(struct enumerator, lookahead),
3761 RUBY_REF_EDGE(struct enumerator, feedvalue),
3762 RUBY_REF_EDGE(struct enumerator, stop_exc),
3763 RUBY_REF_EDGE(struct enumerator, size),
3764 RUBY_REF_EDGE(struct enumerator, procs),
3765
3766 RUBY_REF_EDGE(struct arith_seq, begin),
3767 RUBY_REF_EDGE(struct arith_seq, end),
3768 RUBY_REF_EDGE(struct arith_seq, step),
3769 RUBY_REF_END
3770};
3771
3772static const rb_data_type_t arith_seq_data_type = {
3773 "arithmetic_sequence",
3774 {
3775 RUBY_REFS_LIST_PTR(arith_seq_refs),
3776 RUBY_TYPED_DEFAULT_FREE,
3777 NULL, // Nothing allocated externally, so don't need a memsize function
3778 NULL,
3779 },
3780 .parent = &enumerator_data_type,
3781 .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_DECL_MARKING | RUBY_TYPED_EMBEDDABLE
3782};
3783
3784static VALUE
3785arith_seq_allocate(VALUE klass)
3786{
3787 struct arith_seq *ptr;
3788 VALUE enum_obj;
3789
3790 enum_obj = TypedData_Make_Struct(klass, struct arith_seq, &arith_seq_data_type, ptr);
3791 ptr->enumerator.obj = Qundef;
3792
3793 return enum_obj;
3794}
3795
3796/*
3797 * Document-class: Enumerator::ArithmeticSequence
3798 *
3799 * Enumerator::ArithmeticSequence is a subclass of Enumerator,
3800 * that is a representation of sequences of numbers with common difference.
3801 * Instances of this class can be generated by the Range#step and Numeric#step
3802 * methods.
3803 *
3804 * The class can be used for slicing Array (see Array#slice) or custom
3805 * collections.
3806 */
3807
3808 VALUE
3809rb_arith_seq_new(VALUE obj, VALUE meth, int argc, VALUE const *argv,
3810 rb_enumerator_size_func *size_fn,
3811 VALUE beg, VALUE end, VALUE step, int excl)
3812{
3813 VALUE aseq = enumerator_init(arith_seq_allocate(rb_cArithSeq),
3814 obj, meth, argc, argv, size_fn, Qnil, rb_keyword_given_p());
3815 struct arith_seq *ptr;
3816 TypedData_Get_Struct(aseq, struct arith_seq, &enumerator_data_type, ptr);
3817
3818 RB_OBJ_WRITE(aseq, &ptr->begin, beg);
3819 RB_OBJ_WRITE(aseq, &ptr->end, end);
3820 RB_OBJ_WRITE(aseq, &ptr->step, step);
3821 ptr->exclude_end = excl;
3822
3823 return aseq;
3824}
3825
3826/*
3827 * call-seq: aseq.begin -> num or nil
3828 *
3829 * Returns the number that defines the first element of this arithmetic
3830 * sequence.
3831 */
3832static inline VALUE
3833arith_seq_begin(VALUE self)
3834{
3835 struct arith_seq *ptr;
3836 TypedData_Get_Struct(self, struct arith_seq, &enumerator_data_type, ptr);
3837 return ptr->begin;
3838}
3839
3840/*
3841 * call-seq: aseq.end -> num or nil
3842 *
3843 * Returns the number that defines the end of this arithmetic sequence.
3844 */
3845static inline VALUE
3846arith_seq_end(VALUE self)
3847{
3848 struct arith_seq *ptr;
3849 TypedData_Get_Struct(self, struct arith_seq, &enumerator_data_type, ptr);
3850 return ptr->end;
3851}
3852
3853/*
3854 * call-seq: aseq.step -> num
3855 *
3856 * Returns the number that defines the common difference between
3857 * two adjacent elements in this arithmetic sequence.
3858 */
3859static inline VALUE
3860arith_seq_step(VALUE self)
3861{
3862 struct arith_seq *ptr;
3863 TypedData_Get_Struct(self, struct arith_seq, &enumerator_data_type, ptr);
3864 return ptr->step;
3865}
3866
3867/*
3868 * call-seq: aseq.exclude_end? -> true or false
3869 *
3870 * Returns <code>true</code> if this arithmetic sequence excludes its end value.
3871 */
3872static inline VALUE
3873arith_seq_exclude_end(VALUE self)
3874{
3875 struct arith_seq *ptr;
3876 TypedData_Get_Struct(self, struct arith_seq, &enumerator_data_type, ptr);
3877 return RBOOL(ptr->exclude_end);
3878}
3879
3880static inline int
3881arith_seq_exclude_end_p(VALUE self)
3882{
3883 struct arith_seq *ptr;
3884 TypedData_Get_Struct(self, struct arith_seq, &enumerator_data_type, ptr);
3885 return ptr->exclude_end;
3886}
3887
3888int
3889rb_arithmetic_sequence_extract(VALUE obj, rb_arithmetic_sequence_components_t *component)
3890{
3891 if (rb_obj_is_kind_of(obj, rb_cArithSeq)) {
3892 component->begin = arith_seq_begin(obj);
3893 component->end = arith_seq_end(obj);
3894 component->step = arith_seq_step(obj);
3895 component->exclude_end = arith_seq_exclude_end_p(obj);
3896 return 1;
3897 }
3898 else if (rb_range_values(obj, &component->begin, &component->end, &component->exclude_end)) {
3899 component->step = INT2FIX(1);
3900 return 1;
3901 }
3902
3903 return 0;
3904}
3905
3906 VALUE
3907rb_arithmetic_sequence_beg_len_step(VALUE obj, long *begp, long *lenp, long *stepp, long len, int err)
3908{
3909 RBIMPL_NONNULL_ARG(begp);
3910 RBIMPL_NONNULL_ARG(lenp);
3911 RBIMPL_NONNULL_ARG(stepp);
3912
3913 rb_arithmetic_sequence_components_t aseq;
3914 if (!rb_arithmetic_sequence_extract(obj, &aseq)) {
3915 return Qfalse;
3916 }
3917
3918 long step = NIL_P(aseq.step) ? 1 : NUM2LONG(aseq.step);
3919 *stepp = step;
3920
3921 if (step < 0) {
3922 if (aseq.exclude_end && !NIL_P(aseq.end)) {
3923 /* Handle exclusion before range reversal */
3924 aseq.end = LONG2NUM(NUM2LONG(aseq.end) + 1);
3925
3926 /* Don't exclude the previous beginning */
3927 aseq.exclude_end = 0;
3928 }
3929 VALUE tmp = aseq.begin;
3930 aseq.begin = aseq.end;
3931 aseq.end = tmp;
3932 }
3933
3934 if (err == 0 && (step < -1 || step > 1)) {
3935 if (rb_range_component_beg_len(aseq.begin, aseq.end, aseq.exclude_end, begp, lenp, len, 1) == Qtrue) {
3936 if (*begp > len)
3937 goto out_of_range;
3938 if (*lenp > len)
3939 goto out_of_range;
3940 return Qtrue;
3941 }
3942 }
3943 else {
3944 return rb_range_component_beg_len(aseq.begin, aseq.end, aseq.exclude_end, begp, lenp, len, err);
3945 }
3946
3947 out_of_range:
3948 rb_raise(rb_eRangeError, "%+"PRIsVALUE" out of range", obj);
3949 return Qnil;
3950}
3951
3952static VALUE
3953arith_seq_take(VALUE self, VALUE num)
3954{
3955 VALUE b, e, s, ary;
3956 long n;
3957 int x;
3958
3959 n = NUM2LONG(num);
3960 if (n < 0) {
3961 rb_raise(rb_eArgError, "attempt to take negative size");
3962 }
3963 if (n == 0) {
3964 return rb_ary_new_capa(0);
3965 }
3966
3967 b = arith_seq_begin(self);
3968 e = arith_seq_end(self);
3969 s = arith_seq_step(self);
3970 x = arith_seq_exclude_end_p(self);
3971
3972 if (FIXNUM_P(b) && NIL_P(e) && FIXNUM_P(s)) {
3973 long i = FIX2LONG(b), unit = FIX2LONG(s);
3974 ary = rb_ary_new_capa(n);
3975 while (n > 0 && FIXABLE(i)) {
3976 rb_ary_push(ary, LONG2FIX(i));
3977 i += unit; // FIXABLE + FIXABLE never overflow;
3978 --n;
3979 }
3980 if (n > 0) {
3981 b = LONG2NUM(i);
3982 while (n > 0) {
3983 rb_ary_push(ary, b);
3984 b = rb_big_plus(b, s);
3985 --n;
3986 }
3987 }
3988 return ary;
3989 }
3990 else if (FIXNUM_P(b) && FIXNUM_P(e) && FIXNUM_P(s)) {
3991 long i = FIX2LONG(b);
3992 long end = FIX2LONG(e);
3993 long unit = FIX2LONG(s);
3994 long len;
3995
3996 if (unit >= 0) {
3997 if (!x) end += 1;
3998
3999 len = end - i;
4000 if (len < 0) len = 0;
4001 ary = rb_ary_new_capa((n < len) ? n : len);
4002 while (n > 0 && i < end) {
4003 rb_ary_push(ary, LONG2FIX(i));
4004 if (i > LONG_MAX - unit) break;
4005 i += unit;
4006 --n;
4007 }
4008 }
4009 else {
4010 if (!x) end -= 1;
4011
4012 len = i - end;
4013 if (len < 0) len = 0;
4014 ary = rb_ary_new_capa((n < len) ? n : len);
4015 while (n > 0 && i > end) {
4016 rb_ary_push(ary, LONG2FIX(i));
4017 if (i < LONG_MIN - unit) break;
4018 i += unit;
4019 --n;
4020 }
4021 }
4022 return ary;
4023 }
4024 else if (RB_FLOAT_TYPE_P(b) || RB_FLOAT_TYPE_P(e) || RB_FLOAT_TYPE_P(s)) {
4025 /* generate values like ruby_float_step */
4026
4027 double unit = NUM2DBL(s);
4028 double beg = NUM2DBL(b);
4029 double end = NIL_P(e) ? (unit < 0 ? -1 : 1)*HUGE_VAL : NUM2DBL(e);
4030 double len = ruby_float_step_size(beg, end, unit, x);
4031 long i;
4032
4033 if (n > len)
4034 n = (long)len;
4035
4036 if (isinf(unit)) {
4037 if (len > 0) {
4038 ary = rb_ary_new_capa(1);
4039 rb_ary_push(ary, DBL2NUM(beg));
4040 }
4041 else {
4042 ary = rb_ary_new_capa(0);
4043 }
4044 }
4045 else if (unit == 0) {
4046 VALUE val = DBL2NUM(beg);
4047 ary = rb_ary_new_capa(n);
4048 for (i = 0; i < len; ++i) {
4049 rb_ary_push(ary, val);
4050 }
4051 }
4052 else {
4053 ary = rb_ary_new_capa(n);
4054 for (i = 0; i < n; ++i) {
4055 double d = i*unit+beg;
4056 if (unit >= 0 ? end < d : d < end) d = end;
4057 rb_ary_push(ary, DBL2NUM(d));
4058 }
4059 }
4060
4061 return ary;
4062 }
4063
4064 {
4065 VALUE argv[1];
4066 argv[0] = num;
4067 return rb_call_super(1, argv);
4068 }
4069}
4070
4071/*
4072 * call-seq:
4073 * aseq.first -> num or nil
4074 * aseq.first(n) -> an_array
4075 *
4076 * Returns the first number in this arithmetic sequence,
4077 * or an array of the first +n+ elements.
4078 */
4079static VALUE
4080arith_seq_first(int argc, VALUE *argv, VALUE self)
4081{
4082 VALUE b, e, s;
4083
4084 rb_check_arity(argc, 0, 1);
4085
4086 b = arith_seq_begin(self);
4087 e = arith_seq_end(self);
4088 s = arith_seq_step(self);
4089 if (argc == 0) {
4090 if (NIL_P(b)) {
4091 return Qnil;
4092 }
4093 if (!NIL_P(e)) {
4094 VALUE zero = INT2FIX(0);
4095 int r = rb_cmpint(rb_num_coerce_cmp(s, zero, idCmp), s, zero);
4096 if (r > 0 && RTEST(rb_funcall(b, '>', 1, e))) {
4097 return Qnil;
4098 }
4099 if (r < 0 && RTEST(rb_funcall(b, '<', 1, e))) {
4100 return Qnil;
4101 }
4102 }
4103 return b;
4104 }
4105
4106 return arith_seq_take(self, argv[0]);
4107}
4108
4109static inline VALUE
4110num_plus(VALUE a, VALUE b)
4111{
4112 if (RB_INTEGER_TYPE_P(a)) {
4113 return rb_int_plus(a, b);
4114 }
4115 else if (RB_FLOAT_TYPE_P(a)) {
4116 return rb_float_plus(a, b);
4117 }
4118 else if (RB_TYPE_P(a, T_RATIONAL)) {
4119 return rb_rational_plus(a, b);
4120 }
4121 else {
4122 return rb_funcallv(a, '+', 1, &b);
4123 }
4124}
4125
4126static inline VALUE
4127num_minus(VALUE a, VALUE b)
4128{
4129 if (RB_INTEGER_TYPE_P(a)) {
4130 return rb_int_minus(a, b);
4131 }
4132 else if (RB_FLOAT_TYPE_P(a)) {
4133 return rb_float_minus(a, b);
4134 }
4135 else if (RB_TYPE_P(a, T_RATIONAL)) {
4136 return rb_rational_minus(a, b);
4137 }
4138 else {
4139 return rb_funcallv(a, '-', 1, &b);
4140 }
4141}
4142
4143static inline VALUE
4144num_mul(VALUE a, VALUE b)
4145{
4146 if (RB_INTEGER_TYPE_P(a)) {
4147 return rb_int_mul(a, b);
4148 }
4149 else if (RB_FLOAT_TYPE_P(a)) {
4150 return rb_float_mul(a, b);
4151 }
4152 else if (RB_TYPE_P(a, T_RATIONAL)) {
4153 return rb_rational_mul(a, b);
4154 }
4155 else {
4156 return rb_funcallv(a, '*', 1, &b);
4157 }
4158}
4159
4160static inline VALUE
4161num_idiv(VALUE a, VALUE b)
4162{
4163 VALUE q;
4164 if (RB_INTEGER_TYPE_P(a)) {
4165 q = rb_int_idiv(a, b);
4166 }
4167 else if (RB_FLOAT_TYPE_P(a)) {
4168 q = rb_float_div(a, b);
4169 }
4170 else if (RB_TYPE_P(a, T_RATIONAL)) {
4171 q = rb_rational_div(a, b);
4172 }
4173 else {
4174 q = rb_funcallv(a, idDiv, 1, &b);
4175 }
4176
4177 if (RB_INTEGER_TYPE_P(q)) {
4178 return q;
4179 }
4180 else if (RB_FLOAT_TYPE_P(q)) {
4181 return rb_float_floor(q, 0);
4182 }
4183 else if (RB_TYPE_P(q, T_RATIONAL)) {
4184 return rb_rational_floor(q, 0);
4185 }
4186 else {
4187 return rb_funcall(q, rb_intern("floor"), 0);
4188 }
4189}
4190
4191/*
4192 * call-seq:
4193 * aseq.last -> num or nil
4194 * aseq.last(n) -> an_array
4195 *
4196 * Returns the last number in this arithmetic sequence,
4197 * or an array of the last +n+ elements.
4198 */
4199static VALUE
4200arith_seq_last(int argc, VALUE *argv, VALUE self)
4201{
4202 VALUE b, e, s, len_1, len, last, nv, ary;
4203 int last_is_adjusted;
4204 long n;
4205
4206 e = arith_seq_end(self);
4207 if (NIL_P(e)) {
4208 rb_raise(rb_eRangeError,
4209 "cannot get the last element of endless arithmetic sequence");
4210 }
4211
4212 b = arith_seq_begin(self);
4213 s = arith_seq_step(self);
4214
4215 len_1 = num_idiv(num_minus(e, b), s);
4216 if (rb_num_negative_int_p(len_1)) {
4217 if (argc == 0) {
4218 return Qnil;
4219 }
4220 return rb_ary_new_capa(0);
4221 }
4222
4223 last = num_plus(b, num_mul(s, len_1));
4224 if ((last_is_adjusted = arith_seq_exclude_end_p(self) && rb_equal(last, e))) {
4225 last = num_minus(last, s);
4226 }
4227
4228 if (argc == 0) {
4229 return last;
4230 }
4231
4232 if (last_is_adjusted) {
4233 len = len_1;
4234 }
4235 else {
4236 len = rb_int_plus(len_1, INT2FIX(1));
4237 }
4238
4239 rb_scan_args(argc, argv, "1", &nv);
4240 if (!RB_INTEGER_TYPE_P(nv)) {
4241 nv = rb_to_int(nv);
4242 }
4243 if (RTEST(rb_int_gt(nv, len))) {
4244 nv = len;
4245 }
4246 n = NUM2LONG(nv);
4247 if (n < 0) {
4248 rb_raise(rb_eArgError, "negative array size");
4249 }
4250
4251 ary = rb_ary_new_capa(n);
4252 b = rb_int_minus(last, rb_int_mul(s, nv));
4253 while (n) {
4254 b = rb_int_plus(b, s);
4255 rb_ary_push(ary, b);
4256 --n;
4257 }
4258
4259 return ary;
4260}
4261
4262/*
4263 * call-seq:
4264 * aseq.inspect -> string
4265 *
4266 * Convert this arithmetic sequence to a printable form.
4267 */
4268static VALUE
4269arith_seq_inspect(VALUE self)
4270{
4271 struct enumerator *e;
4272 VALUE eobj, str, eargs;
4273 int range_p;
4274
4275 TypedData_Get_Struct(self, struct enumerator, &enumerator_data_type, e);
4276
4277 eobj = rb_attr_get(self, id_receiver);
4278 if (NIL_P(eobj)) {
4279 eobj = e->obj;
4280 }
4281
4282 range_p = RTEST(rb_obj_is_kind_of(eobj, rb_cRange));
4283 str = rb_sprintf("(%s%"PRIsVALUE"%s.", range_p ? "(" : "", eobj, range_p ? ")" : "");
4284
4285 rb_str_buf_append(str, rb_id2str(e->meth));
4286
4287 eargs = rb_attr_get(eobj, id_arguments);
4288 if (NIL_P(eargs)) {
4289 eargs = e->args;
4290 }
4291 if (eargs != Qfalse) {
4292 long argc = RARRAY_LEN(eargs);
4293 const VALUE *argv = RARRAY_CONST_PTR(eargs); /* WB: no new reference */
4294
4295 if (argc > 0) {
4296 VALUE kwds = Qnil;
4297
4298 rb_str_buf_cat2(str, "(");
4299
4300 if (RB_TYPE_P(argv[argc-1], T_HASH)) {
4301 int all_key = TRUE;
4302 rb_hash_foreach(argv[argc-1], key_symbol_p, (VALUE)&all_key);
4303 if (all_key) kwds = argv[--argc];
4304 }
4305
4306 while (argc--) {
4307 VALUE arg = *argv++;
4308
4309 rb_str_append(str, rb_inspect(arg));
4310 rb_str_buf_cat2(str, ", ");
4311 }
4312 if (!NIL_P(kwds)) {
4313 rb_hash_foreach(kwds, kwd_append, str);
4314 }
4315 rb_str_set_len(str, RSTRING_LEN(str)-2); /* drop the last ", " */
4316 rb_str_buf_cat2(str, ")");
4317 }
4318 }
4319
4320 rb_str_buf_cat2(str, ")");
4321
4322 return str;
4323}
4324
4325/*
4326 * call-seq:
4327 * aseq == obj -> true or false
4328 *
4329 * Returns <code>true</code> only if +obj+ is an Enumerator::ArithmeticSequence,
4330 * has equivalent begin, end, step, and exclude_end? settings.
4331 */
4332static VALUE
4333arith_seq_eq(VALUE self, VALUE other)
4334{
4335 if (!RTEST(rb_obj_is_kind_of(other, rb_cArithSeq))) {
4336 return Qfalse;
4337 }
4338
4339 if (!rb_equal(arith_seq_begin(self), arith_seq_begin(other))) {
4340 return Qfalse;
4341 }
4342
4343 if (!rb_equal(arith_seq_end(self), arith_seq_end(other))) {
4344 return Qfalse;
4345 }
4346
4347 if (!rb_equal(arith_seq_step(self), arith_seq_step(other))) {
4348 return Qfalse;
4349 }
4350
4351 if (arith_seq_exclude_end_p(self) != arith_seq_exclude_end_p(other)) {
4352 return Qfalse;
4353 }
4354
4355 return Qtrue;
4356}
4357
4358/*
4359 * call-seq:
4360 * aseq.hash -> integer
4361 *
4362 * Compute a hash-value for this arithmetic sequence.
4363 * Two arithmetic sequences with same begin, end, step, and exclude_end?
4364 * values will generate the same hash-value.
4365 *
4366 * See also Object#hash.
4367 */
4368static VALUE
4369arith_seq_hash(VALUE self)
4370{
4371 st_index_t hash;
4372 VALUE v;
4373
4374 hash = rb_hash_start(arith_seq_exclude_end_p(self));
4375 v = rb_hash(arith_seq_begin(self));
4376 hash = rb_hash_uint(hash, NUM2LONG(v));
4377 v = rb_hash(arith_seq_end(self));
4378 hash = rb_hash_uint(hash, NUM2LONG(v));
4379 v = rb_hash(arith_seq_step(self));
4380 hash = rb_hash_uint(hash, NUM2LONG(v));
4381 hash = rb_hash_end(hash);
4382
4383 return ST2FIX(hash);
4384}
4385
4386#define NUM_GE(x, y) RTEST(rb_num_coerce_relop((x), (y), idGE))
4387
4388 struct arith_seq_gen {
4389 VALUE current;
4390 VALUE end;
4391 VALUE step;
4392 int excl;
4393};
4394
4395/*
4396 * call-seq:
4397 * aseq.each {|i| block } -> aseq
4398 * aseq.each -> aseq
4399 */
4400static VALUE
4401arith_seq_each(VALUE self)
4402{
4403 VALUE c, e, s, len_1, last;
4404 int x;
4405
4406 if (!rb_block_given_p()) return self;
4407
4408 c = arith_seq_begin(self);
4409 e = arith_seq_end(self);
4410 s = arith_seq_step(self);
4411 x = arith_seq_exclude_end_p(self);
4412
4413 if (!RB_TYPE_P(s, T_COMPLEX) && ruby_float_step(c, e, s, x, TRUE)) {
4414 return self;
4415 }
4416
4417 if (NIL_P(e)) {
4418 while (1) {
4419 rb_yield(c);
4420 c = rb_int_plus(c, s);
4421 }
4422
4423 return self;
4424 }
4425
4426 if (rb_equal(s, INT2FIX(0))) {
4427 while (1) {
4428 rb_yield(c);
4429 }
4430
4431 return self;
4432 }
4433
4434 len_1 = num_idiv(num_minus(e, c), s);
4435 last = num_plus(c, num_mul(s, len_1));
4436 if (x && rb_equal(last, e)) {
4437 last = num_minus(last, s);
4438 }
4439
4440 if (rb_num_negative_int_p(s)) {
4441 while (NUM_GE(c, last)) {
4442 rb_yield(c);
4443 c = num_plus(c, s);
4444 }
4445 }
4446 else {
4447 while (NUM_GE(last, c)) {
4448 rb_yield(c);
4449 c = num_plus(c, s);
4450 }
4451 }
4452
4453 return self;
4454}
4455
4456/*
4457 * call-seq:
4458 * aseq.size -> num or nil
4459 *
4460 * Returns the number of elements in this arithmetic sequence if it is a finite
4461 * sequence. Otherwise, returns <code>nil</code>.
4462 */
4463static VALUE
4464arith_seq_size(VALUE self)
4465{
4466 VALUE b, e, s, len_1, len, last;
4467 int x;
4468
4469 b = arith_seq_begin(self);
4470 e = arith_seq_end(self);
4471 s = arith_seq_step(self);
4472 x = arith_seq_exclude_end_p(self);
4473
4474 if (RB_FLOAT_TYPE_P(b) || RB_FLOAT_TYPE_P(e) || RB_FLOAT_TYPE_P(s)) {
4475 double ee, n;
4476
4477 if (NIL_P(e)) {
4478 if (rb_num_negative_int_p(s)) {
4479 ee = -HUGE_VAL;
4480 }
4481 else {
4482 ee = HUGE_VAL;
4483 }
4484 }
4485 else {
4486 ee = NUM2DBL(e);
4487 }
4488
4489 n = ruby_float_step_size(NUM2DBL(b), ee, NUM2DBL(s), x);
4490 if (isinf(n)) return DBL2NUM(n);
4491 if (POSFIXABLE(n)) return LONG2FIX((long)n);
4492 return rb_dbl2big(n);
4493 }
4494
4495 if (NIL_P(e)) {
4496 return DBL2NUM(HUGE_VAL);
4497 }
4498
4499 if (!rb_obj_is_kind_of(s, rb_cNumeric)) {
4500 s = rb_to_int(s);
4501 }
4502
4503 if (rb_equal(s, INT2FIX(0))) {
4504 return DBL2NUM(HUGE_VAL);
4505 }
4506
4507 len_1 = rb_int_idiv(rb_int_minus(e, b), s);
4508 if (rb_num_negative_int_p(len_1)) {
4509 return INT2FIX(0);
4510 }
4511
4512 last = rb_int_plus(b, rb_int_mul(s, len_1));
4513 if (x && rb_equal(last, e)) {
4514 len = len_1;
4515 }
4516 else {
4517 len = rb_int_plus(len_1, INT2FIX(1));
4518 }
4519
4520 return len;
4521}
4522
4523#define sym(name) ID2SYM(rb_intern_const(name))
4524void
4525InitVM_Enumerator(void)
4526{
4527 ID id_private = rb_intern_const("private");
4528
4529 rb_define_method(rb_mKernel, "to_enum", obj_to_enum, -1);
4530 rb_define_method(rb_mKernel, "enum_for", obj_to_enum, -1);
4531
4532 rb_cEnumerator = rb_define_class("Enumerator", rb_cObject);
4533 rb_include_module(rb_cEnumerator, rb_mEnumerable);
4534
4535 rb_define_alloc_func(rb_cEnumerator, enumerator_allocate);
4536 rb_define_method(rb_cEnumerator, "initialize", enumerator_initialize, -1);
4537 rb_define_method(rb_cEnumerator, "initialize_copy", enumerator_init_copy, 1);
4538 rb_define_method(rb_cEnumerator, "each", enumerator_each, -1);
4539 rb_define_method(rb_cEnumerator, "each_with_index", enumerator_each_with_index, 0);
4540 rb_define_method(rb_cEnumerator, "each_with_object", enumerator_with_object, 1);
4541 rb_define_method(rb_cEnumerator, "with_index", enumerator_with_index, -1);
4542 rb_define_method(rb_cEnumerator, "with_object", enumerator_with_object, 1);
4543 rb_define_method(rb_cEnumerator, "next_values", enumerator_next_values, 0);
4544 rb_define_method(rb_cEnumerator, "peek_values", enumerator_peek_values_m, 0);
4545 rb_define_method(rb_cEnumerator, "next", enumerator_next, 0);
4546 rb_define_method(rb_cEnumerator, "peek", enumerator_peek, 0);
4547 rb_define_method(rb_cEnumerator, "feed", enumerator_feed, 1);
4548 rb_define_method(rb_cEnumerator, "rewind", enumerator_rewind, 0);
4549 rb_define_method(rb_cEnumerator, "inspect", enumerator_inspect, 0);
4550 rb_define_method(rb_cEnumerator, "size", enumerator_size, 0);
4551 rb_define_method(rb_cEnumerator, "+", enumerator_plus, 1);
4552 rb_define_method(rb_mEnumerable, "chain", enum_chain, -1);
4553
4554 /* Lazy */
4555 rb_cLazy = rb_define_class_under(rb_cEnumerator, "Lazy", rb_cEnumerator);
4556 rb_define_method(rb_mEnumerable, "lazy", enumerable_lazy, 0);
4557
4558 rb_define_alias(rb_cLazy, "_enumerable_map", "map");
4559 rb_define_alias(rb_cLazy, "_enumerable_collect", "collect");
4560 rb_define_alias(rb_cLazy, "_enumerable_flat_map", "flat_map");
4561 rb_define_alias(rb_cLazy, "_enumerable_collect_concat", "collect_concat");
4562 rb_define_alias(rb_cLazy, "_enumerable_select", "select");
4563 rb_define_alias(rb_cLazy, "_enumerable_find_all", "find_all");
4564 rb_define_alias(rb_cLazy, "_enumerable_filter", "filter");
4565 rb_define_alias(rb_cLazy, "_enumerable_filter_map", "filter_map");
4566 rb_define_alias(rb_cLazy, "_enumerable_reject", "reject");
4567 rb_define_alias(rb_cLazy, "_enumerable_grep", "grep");
4568 rb_define_alias(rb_cLazy, "_enumerable_grep_v", "grep_v");
4569 rb_define_alias(rb_cLazy, "_enumerable_zip", "zip");
4570 rb_define_alias(rb_cLazy, "_enumerable_take", "take");
4571 rb_define_alias(rb_cLazy, "_enumerable_take_while", "take_while");
4572 rb_define_alias(rb_cLazy, "_enumerable_drop", "drop");
4573 rb_define_alias(rb_cLazy, "_enumerable_drop_while", "drop_while");
4574 rb_define_alias(rb_cLazy, "_enumerable_uniq", "uniq");
4575 rb_define_private_method(rb_cLazy, "_enumerable_with_index", enumerator_with_index, -1);
4576
4577 rb_funcall(rb_cLazy, id_private, 1, sym("_enumerable_map"));
4578 rb_funcall(rb_cLazy, id_private, 1, sym("_enumerable_collect"));
4579 rb_funcall(rb_cLazy, id_private, 1, sym("_enumerable_flat_map"));
4580 rb_funcall(rb_cLazy, id_private, 1, sym("_enumerable_collect_concat"));
4581 rb_funcall(rb_cLazy, id_private, 1, sym("_enumerable_select"));
4582 rb_funcall(rb_cLazy, id_private, 1, sym("_enumerable_find_all"));
4583 rb_funcall(rb_cLazy, id_private, 1, sym("_enumerable_filter"));
4584 rb_funcall(rb_cLazy, id_private, 1, sym("_enumerable_filter_map"));
4585 rb_funcall(rb_cLazy, id_private, 1, sym("_enumerable_reject"));
4586 rb_funcall(rb_cLazy, id_private, 1, sym("_enumerable_grep"));
4587 rb_funcall(rb_cLazy, id_private, 1, sym("_enumerable_grep_v"));
4588 rb_funcall(rb_cLazy, id_private, 1, sym("_enumerable_zip"));
4589 rb_funcall(rb_cLazy, id_private, 1, sym("_enumerable_take"));
4590 rb_funcall(rb_cLazy, id_private, 1, sym("_enumerable_take_while"));
4591 rb_funcall(rb_cLazy, id_private, 1, sym("_enumerable_drop"));
4592 rb_funcall(rb_cLazy, id_private, 1, sym("_enumerable_drop_while"));
4593 rb_funcall(rb_cLazy, id_private, 1, sym("_enumerable_uniq"));
4594
4595 rb_define_method(rb_cLazy, "initialize", lazy_initialize, -1);
4596 rb_define_method(rb_cLazy, "to_enum", lazy_to_enum, -1);
4597 rb_define_method(rb_cLazy, "enum_for", lazy_to_enum, -1);
4598 rb_define_method(rb_cLazy, "eager", lazy_eager, 0);
4599 rb_define_method(rb_cLazy, "map", lazy_map, 0);
4600 rb_define_method(rb_cLazy, "collect", lazy_map, 0);
4601 rb_define_method(rb_cLazy, "flat_map", lazy_flat_map, 0);
4602 rb_define_method(rb_cLazy, "collect_concat", lazy_flat_map, 0);
4603 rb_define_method(rb_cLazy, "select", lazy_select, 0);
4604 rb_define_method(rb_cLazy, "find_all", lazy_select, 0);
4605 rb_define_method(rb_cLazy, "filter", lazy_select, 0);
4606 rb_define_method(rb_cLazy, "filter_map", lazy_filter_map, 0);
4607 rb_define_method(rb_cLazy, "reject", lazy_reject, 0);
4608 rb_define_method(rb_cLazy, "grep", lazy_grep, 1);
4609 rb_define_method(rb_cLazy, "grep_v", lazy_grep_v, 1);
4610 rb_define_method(rb_cLazy, "zip", lazy_zip, -1);
4611 rb_define_method(rb_cLazy, "take", lazy_take, 1);
4612 rb_define_method(rb_cLazy, "take_while", lazy_take_while, 0);
4613 rb_define_method(rb_cLazy, "drop", lazy_drop, 1);
4614 rb_define_method(rb_cLazy, "drop_while", lazy_drop_while, 0);
4615 rb_define_method(rb_cLazy, "lazy", lazy_lazy, 0);
4616 rb_define_method(rb_cLazy, "chunk", lazy_super, -1);
4617 rb_define_method(rb_cLazy, "slice_before", lazy_super, -1);
4618 rb_define_method(rb_cLazy, "slice_after", lazy_super, -1);
4619 rb_define_method(rb_cLazy, "slice_when", lazy_super, -1);
4620 rb_define_method(rb_cLazy, "chunk_while", lazy_super, -1);
4621 rb_define_method(rb_cLazy, "uniq", lazy_uniq, 0);
4622 rb_define_method(rb_cLazy, "compact", lazy_compact, 0);
4623 rb_define_method(rb_cLazy, "with_index", lazy_with_index, -1);
4624
4625 lazy_use_super_method = rb_hash_new_with_size(18);
4626 rb_hash_aset(lazy_use_super_method, sym("map"), sym("_enumerable_map"));
4627 rb_hash_aset(lazy_use_super_method, sym("collect"), sym("_enumerable_collect"));
4628 rb_hash_aset(lazy_use_super_method, sym("flat_map"), sym("_enumerable_flat_map"));
4629 rb_hash_aset(lazy_use_super_method, sym("collect_concat"), sym("_enumerable_collect_concat"));
4630 rb_hash_aset(lazy_use_super_method, sym("select"), sym("_enumerable_select"));
4631 rb_hash_aset(lazy_use_super_method, sym("find_all"), sym("_enumerable_find_all"));
4632 rb_hash_aset(lazy_use_super_method, sym("filter"), sym("_enumerable_filter"));
4633 rb_hash_aset(lazy_use_super_method, sym("filter_map"), sym("_enumerable_filter_map"));
4634 rb_hash_aset(lazy_use_super_method, sym("reject"), sym("_enumerable_reject"));
4635 rb_hash_aset(lazy_use_super_method, sym("grep"), sym("_enumerable_grep"));
4636 rb_hash_aset(lazy_use_super_method, sym("grep_v"), sym("_enumerable_grep_v"));
4637 rb_hash_aset(lazy_use_super_method, sym("zip"), sym("_enumerable_zip"));
4638 rb_hash_aset(lazy_use_super_method, sym("take"), sym("_enumerable_take"));
4639 rb_hash_aset(lazy_use_super_method, sym("take_while"), sym("_enumerable_take_while"));
4640 rb_hash_aset(lazy_use_super_method, sym("drop"), sym("_enumerable_drop"));
4641 rb_hash_aset(lazy_use_super_method, sym("drop_while"), sym("_enumerable_drop_while"));
4642 rb_hash_aset(lazy_use_super_method, sym("uniq"), sym("_enumerable_uniq"));
4643 rb_hash_aset(lazy_use_super_method, sym("with_index"), sym("_enumerable_with_index"));
4644 rb_obj_freeze(lazy_use_super_method);
4645 rb_vm_register_global_object(lazy_use_super_method);
4646
4647#if 0 /* for RDoc */
4648 rb_define_method(rb_cLazy, "to_a", lazy_to_a, 0);
4649 rb_define_method(rb_cLazy, "chunk", lazy_chunk, 0);
4650 rb_define_method(rb_cLazy, "chunk_while", lazy_chunk_while, 0);
4651 rb_define_method(rb_cLazy, "slice_after", lazy_slice_after, 0);
4652 rb_define_method(rb_cLazy, "slice_before", lazy_slice_before, 0);
4653 rb_define_method(rb_cLazy, "slice_when", lazy_slice_when, 0);
4654#endif
4655 rb_define_alias(rb_cLazy, "force", "to_a");
4656
4657 rb_eStopIteration = rb_define_class("StopIteration", rb_eIndexError);
4658 rb_define_method(rb_eStopIteration, "result", stop_result, 0);
4659
4660 /* Generator */
4661 rb_cGenerator = rb_define_class_under(rb_cEnumerator, "Generator", rb_cObject);
4662 rb_include_module(rb_cGenerator, rb_mEnumerable);
4663 rb_define_alloc_func(rb_cGenerator, generator_allocate);
4664 rb_define_method(rb_cGenerator, "initialize", generator_initialize, -1);
4665 rb_define_method(rb_cGenerator, "initialize_copy", generator_init_copy, 1);
4666 rb_define_method(rb_cGenerator, "each", generator_each, -1);
4667
4668 /* Yielder */
4669 rb_cYielder = rb_define_class_under(rb_cEnumerator, "Yielder", rb_cObject);
4670 rb_define_alloc_func(rb_cYielder, yielder_allocate);
4671 rb_define_method(rb_cYielder, "initialize", yielder_initialize, 0);
4672 rb_define_method(rb_cYielder, "yield", yielder_yield, -2);
4673 rb_define_method(rb_cYielder, "<<", yielder_yield_push, 1);
4674 rb_define_method(rb_cYielder, "to_proc", yielder_to_proc, 0);
4675
4676 /* Producer */
4677 rb_cEnumProducer = rb_define_class_under(rb_cEnumerator, "Producer", rb_cObject);
4678 rb_define_alloc_func(rb_cEnumProducer, producer_allocate);
4679 rb_define_method(rb_cEnumProducer, "each", producer_each, 0);
4680 rb_define_singleton_method(rb_cEnumerator, "produce", enumerator_s_produce, -1);
4681
4682 /* Chain */
4683 rb_cEnumChain = rb_define_class_under(rb_cEnumerator, "Chain", rb_cEnumerator);
4684 rb_define_alloc_func(rb_cEnumChain, enum_chain_allocate);
4685 rb_define_method(rb_cEnumChain, "initialize", enum_chain_initialize, -2);
4686 rb_define_method(rb_cEnumChain, "initialize_copy", enum_chain_init_copy, 1);
4687 rb_define_method(rb_cEnumChain, "each", enum_chain_each, -1);
4688 rb_define_method(rb_cEnumChain, "size", enum_chain_size, 0);
4689 rb_define_method(rb_cEnumChain, "rewind", enum_chain_rewind, 0);
4690 rb_define_method(rb_cEnumChain, "inspect", enum_chain_inspect, 0);
4691 rb_undef_method(rb_cEnumChain, "feed");
4692 rb_undef_method(rb_cEnumChain, "next");
4693 rb_undef_method(rb_cEnumChain, "next_values");
4694 rb_undef_method(rb_cEnumChain, "peek");
4695 rb_undef_method(rb_cEnumChain, "peek_values");
4696
4697 /* Product */
4698 rb_cEnumProduct = rb_define_class_under(rb_cEnumerator, "Product", rb_cEnumerator);
4699 rb_define_alloc_func(rb_cEnumProduct, enum_product_allocate);
4700 rb_define_method(rb_cEnumProduct, "initialize", enum_product_initialize, -1);
4701 rb_define_method(rb_cEnumProduct, "initialize_copy", enum_product_init_copy, 1);
4702 rb_define_method(rb_cEnumProduct, "each", enum_product_each, 0);
4703 rb_define_method(rb_cEnumProduct, "size", enum_product_size, 0);
4704 rb_define_method(rb_cEnumProduct, "rewind", enum_product_rewind, 0);
4705 rb_define_method(rb_cEnumProduct, "inspect", enum_product_inspect, 0);
4706 rb_undef_method(rb_cEnumProduct, "feed");
4707 rb_undef_method(rb_cEnumProduct, "next");
4708 rb_undef_method(rb_cEnumProduct, "next_values");
4709 rb_undef_method(rb_cEnumProduct, "peek");
4710 rb_undef_method(rb_cEnumProduct, "peek_values");
4711 rb_define_singleton_method(rb_cEnumerator, "product", enumerator_s_product, -1);
4712
4713 /* ArithmeticSequence */
4714 rb_cArithSeq = rb_define_class_under(rb_cEnumerator, "ArithmeticSequence", rb_cEnumerator);
4715 rb_undef_alloc_func(rb_cArithSeq);
4716 rb_undef_method(CLASS_OF(rb_cArithSeq), "new");
4717 rb_define_method(rb_cArithSeq, "begin", arith_seq_begin, 0);
4718 rb_define_method(rb_cArithSeq, "end", arith_seq_end, 0);
4719 rb_define_method(rb_cArithSeq, "exclude_end?", arith_seq_exclude_end, 0);
4720 rb_define_method(rb_cArithSeq, "step", arith_seq_step, 0);
4721 rb_define_method(rb_cArithSeq, "first", arith_seq_first, -1);
4722 rb_define_method(rb_cArithSeq, "last", arith_seq_last, -1);
4723 rb_define_method(rb_cArithSeq, "inspect", arith_seq_inspect, 0);
4724 rb_define_method(rb_cArithSeq, "==", arith_seq_eq, 1);
4725 rb_define_method(rb_cArithSeq, "===", arith_seq_eq, 1);
4726 rb_define_method(rb_cArithSeq, "eql?", arith_seq_eq, 1);
4727 rb_define_method(rb_cArithSeq, "hash", arith_seq_hash, 0);
4728 rb_define_method(rb_cArithSeq, "each", arith_seq_each, 0);
4729 rb_define_method(rb_cArithSeq, "size", arith_seq_size, 0);
4730
4731 rb_provide("enumerator.so"); /* for backward compatibility */
4732}
4733#undef sym
4734
4735void
4736Init_Enumerator(void)
4737{
4738 id_rewind = rb_intern_const("rewind");
4739 id_next = rb_intern_const("next");
4740 id_result = rb_intern_const("result");
4741 id_receiver = rb_intern_const("receiver");
4742 id_arguments = rb_intern_const("arguments");
4743 id_memo = rb_intern_const("memo");
4744 id_method = rb_intern_const("method");
4745 id_force = rb_intern_const("force");
4746 id_to_enum = rb_intern_const("to_enum");
4747 id_each_entry = rb_intern_const("each_entry");
4748 sym_each = ID2SYM(id_each);
4749 sym_yield = ID2SYM(rb_intern_const("yield"));
4750
4751 InitVM(Enumerator);
4752}
rb_define_method
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
Definition cxxanyargs.hpp:670
rb_define_singleton_method
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
Definition cxxanyargs.hpp:685
rb_define_private_method
#define rb_define_private_method(klass, mid, func, arity)
Defines klass#mid and makes it private.
Definition cxxanyargs.hpp:677
rb_include_module
void rb_include_module(VALUE klass, VALUE module)
Includes a module to a class.
Definition class.c:1684
rb_define_class
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
Definition class.c:1477
rb_define_class_under
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition class.c:1508
rb_define_alias
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
Definition class.c:2842
rb_need_block
void rb_need_block(void)
Declares that the current method needs a block.
Definition eval.c:1042
rb_undef_method
void rb_undef_method(VALUE klass, const char *name)
Defines an undef of a method.
Definition class.c:2654
rb_scan_args_kw
int rb_scan_args_kw(int kw_flag, int argc, const VALUE *argv, const char *fmt,...)
Identical to rb_scan_args(), except it also accepts kw_splat.
Definition class.c:3145
rb_scan_args
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Retrieves argument from argc and argv to given VALUE references according to the format string.
Definition class.c:3132
rb_keyword_given_p
int rb_keyword_given_p(void)
Determines if the current method is given a keyword argument.
Definition eval.c:1034
rb_block_given_p
int rb_block_given_p(void)
Determines if the current method is given a block.
Definition eval.c:1021
rb_get_kwargs
int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *values)
Keyword argument deconstructor.
Definition class.c:2921
T_COMPLEX
#define T_COMPLEX
Old name of RUBY_T_COMPLEX.
Definition value_type.h:59
RB_INTEGER_TYPE_P
#define RB_INTEGER_TYPE_P
Old name of rb_integer_type_p.
Definition value_type.h:87
rb_str_buf_cat2
#define rb_str_buf_cat2
Old name of rb_usascii_str_new_cstr.
Definition string.h:1683
OBJ_INIT_COPY
#define OBJ_INIT_COPY(obj, orig)
Old name of RB_OBJ_INIT_COPY.
Definition object.h:41
RFLOAT_VALUE
#define RFLOAT_VALUE
Old name of rb_float_value.
Definition double.h:28
Qundef
#define Qundef
Old name of RUBY_Qundef.
Definition special_consts.h:62
INT2FIX
#define INT2FIX
Old name of RB_INT2FIX.
Definition long.h:48
T_FLOAT
#define T_FLOAT
Old name of RUBY_T_FLOAT.
Definition value_type.h:64
ID2SYM
#define ID2SYM
Old name of RB_ID2SYM.
Definition symbol.h:44
UNREACHABLE_RETURN
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
Definition assume.h:29
CLASS_OF
#define CLASS_OF
Old name of rb_class_of.
Definition globals.h:205
rb_ary_new4
#define rb_ary_new4
Old name of rb_ary_new_from_values.
Definition array.h:659
FIXABLE
#define FIXABLE
Old name of RB_FIXABLE.
Definition fixnum.h:25
rb_exc_new2
#define rb_exc_new2
Old name of rb_exc_new_cstr.
Definition error.h:37
LONG2FIX
#define LONG2FIX
Old name of RB_INT2FIX.
Definition long.h:49
T_RATIONAL
#define T_RATIONAL
Old name of RUBY_T_RATIONAL.
Definition value_type.h:76
T_HASH
#define T_HASH
Old name of RUBY_T_HASH.
Definition value_type.h:65
NUM2DBL
#define NUM2DBL
Old name of rb_num2dbl.
Definition double.h:27
rb_ary_new3
#define rb_ary_new3
Old name of rb_ary_new_from_args.
Definition array.h:658
LONG2NUM
#define LONG2NUM
Old name of RB_LONG2NUM.
Definition long.h:50
Qtrue
#define Qtrue
Old name of RUBY_Qtrue.
Definition special_consts.h:61
ST2FIX
#define ST2FIX
Old name of RB_ST2FIX.
Definition st_data_t.h:33
Qnil
#define Qnil
Old name of RUBY_Qnil.
Definition special_consts.h:60
Qfalse
#define Qfalse
Old name of RUBY_Qfalse.
Definition special_consts.h:59
FIX2LONG
#define FIX2LONG
Old name of RB_FIX2LONG.
Definition long.h:46
T_ARRAY
#define T_ARRAY
Old name of RUBY_T_ARRAY.
Definition value_type.h:56
NIL_P
#define NIL_P
Old name of RB_NIL_P.
Definition special_consts.h:55
ALLOCV_N
#define ALLOCV_N
Old name of RB_ALLOCV_N.
Definition memory.h:405
POSFIXABLE
#define POSFIXABLE
Old name of RB_POSFIXABLE.
Definition fixnum.h:29
T_SYMBOL
#define T_SYMBOL
Old name of RUBY_T_SYMBOL.
Definition value_type.h:80
DBL2NUM
#define DBL2NUM
Old name of rb_float_new.
Definition double.h:29
NUM2LONG
#define NUM2LONG
Old name of RB_NUM2LONG.
Definition long.h:51
FIXNUM_P
#define FIXNUM_P
Old name of RB_FIXNUM_P.
Definition special_consts.h:53
rb_ary_new2
#define rb_ary_new2
Old name of rb_ary_new_capa.
Definition array.h:657
ALLOCV_END
#define ALLOCV_END
Old name of RB_ALLOCV_END.
Definition memory.h:406
SYMBOL_P
#define SYMBOL_P
Old name of RB_SYMBOL_P.
Definition value_type.h:88
rb_exc_raise
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
Definition eval.c:664
rb_iter_break
void rb_iter_break(void)
Breaks from a block.
Definition vm.c:2280
rb_eRangeError
VALUE rb_eRangeError
RangeError exception.
Definition error.c:1435
rb_eTypeError
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1431
rb_eRuntimeError
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1429
rb_eStopIteration
VALUE rb_eStopIteration
StopIteration exception.
Definition enumerator.c:181
rb_warn
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:466
rb_exc_new_str
VALUE rb_exc_new_str(VALUE etype, VALUE str)
Identical to rb_exc_new_cstr(), except it takes a Ruby's string instead of C's.
Definition error.c:1482
rb_eIndexError
VALUE rb_eIndexError
IndexError exception.
Definition error.c:1433
rb_mKernel
VALUE rb_mKernel
Kernel module.
Definition object.c:60
rb_mEnumerable
VALUE rb_mEnumerable
Enumerable module.
Definition enum.c:27
rb_cEnumerator
VALUE rb_cEnumerator
Enumerator class.
Definition enumerator.c:164
rb_obj_hide
VALUE rb_obj_hide(VALUE obj)
Make the object invisible from Ruby code.
Definition object.c:100
rb_cNumeric
VALUE rb_cNumeric
Numeric class.
Definition numeric.c:198
rb_obj_class
VALUE rb_obj_class(VALUE obj)
Queries the class of an object.
Definition object.c:264
rb_obj_dup
VALUE rb_obj_dup(VALUE obj)
Duplicates the given object.
Definition object.c:582
rb_inspect
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
Definition object.c:686
rb_cRange
VALUE rb_cRange
Range class.
Definition range.c:31
rb_equal
VALUE rb_equal(VALUE lhs, VALUE rhs)
This function is an optimised version of calling #==.
Definition object.c:176
rb_obj_is_kind_of
VALUE rb_obj_is_kind_of(VALUE obj, VALUE klass)
Queries if the given object is an instance (of possibly descendants) of the given class.
Definition object.c:923
rb_obj_freeze
VALUE rb_obj_freeze(VALUE obj)
Just calls rb_obj_freeze_inline() inside.
Definition object.c:1342
rb_to_int
VALUE rb_to_int(VALUE val)
Identical to rb_check_to_int(), except it raises in case of conversion mismatch.
Definition object.c:3306
RB_OBJ_WRITE
#define RB_OBJ_WRITE(old, slot, young)
Declaration of a "back" pointer.
Definition gc.h:603
rb_funcall
VALUE rb_funcall(VALUE recv, ID mid, int n,...)
Calls a method.
Definition vm_eval.c:1117
rb_funcall_with_block
VALUE rb_funcall_with_block(VALUE recv, ID mid, int argc, const VALUE *argv, VALUE procval)
Identical to rb_funcallv_public(), except you can pass a block.
Definition vm_eval.c:1194
rb_funcall2
#define rb_funcall2
Definition eval.h:207
rb_call_super
VALUE rb_call_super(int argc, const VALUE *argv)
This resembles ruby's super.
Definition vm_eval.c:362
rb_ary_new_from_values
VALUE rb_ary_new_from_values(long n, const VALUE *elts)
Identical to rb_ary_new_from_args(), except how objects are passed.
rb_ary_dup
VALUE rb_ary_dup(VALUE ary)
Duplicates an array.
rb_ary_cat
VALUE rb_ary_cat(VALUE ary, const VALUE *train, long len)
Destructively appends multiple elements at the end of the array.
rb_check_array_type
VALUE rb_check_array_type(VALUE obj)
Try converting an object to its array representation using its to_ary method, if any.
rb_ary_new
VALUE rb_ary_new(void)
Allocates a new, empty array.
rb_ary_new_capa
VALUE rb_ary_new_capa(long capa)
Identical to rb_ary_new(), except it additionally specifies how many rooms of objects it should alloc...
rb_ary_resize
VALUE rb_ary_resize(VALUE ary, long len)
Expands or shrinks the passed array to the passed length.
rb_ary_hidden_new
VALUE rb_ary_hidden_new(long capa)
Allocates a hidden (no class) empty array.
rb_ary_push
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
rb_ary_freeze
VALUE rb_ary_freeze(VALUE obj)
Freeze an array, preventing further modifications.
rb_ary_entry
VALUE rb_ary_entry(VALUE ary, long off)
Queries an element of an array.
rb_ary_store
void rb_ary_store(VALUE ary, long key, VALUE val)
Destructively stores the passed value to the passed array's passed index.
rb_fiber_current
VALUE rb_fiber_current(void)
Queries the fiber which is calling this function.
Definition cont.c:2703
RETURN_SIZED_ENUMERATOR
#define RETURN_SIZED_ENUMERATOR(obj, argc, argv, size_fn)
This roughly resembles return enum_for(__callee__) unless block_given?.
Definition enumerator.h:208
rb_enumerator_size_func
VALUE rb_enumerator_size_func(VALUE recv, VALUE argv, VALUE eobj)
This is the type of functions that rb_enumeratorize_with_size() expects.
Definition enumerator.h:45
rb_check_arity
static int rb_check_arity(int argc, int min, int max)
Ensures that the passed integer is in the passed range.
Definition error.h:284
rb_frame_this_func
ID rb_frame_this_func(void)
Queries the name of the Ruby level method that is calling this function.
Definition eval.c:1204
rb_hash_new
VALUE rb_hash_new(void)
Creates a new, empty hash object.
Definition hash.c:1484
rb_provide
void rb_provide(const char *feature)
Declares that the given feature is already provided by someone else.
Definition load.c:695
rb_num_coerce_cmp
VALUE rb_num_coerce_cmp(VALUE lhs, VALUE rhs, ID op)
Identical to rb_num_coerce_bin(), except for return values.
Definition numeric.c:486
rb_obj_method
VALUE rb_obj_method(VALUE recv, VALUE mid)
Creates a method object.
Definition proc.c:2269
rb_block_proc
VALUE rb_block_proc(void)
Constructs a Proc object from implicitly passed components.
Definition proc.c:983
rb_proc_call_with_block
VALUE rb_proc_call_with_block(VALUE recv, int argc, const VALUE *argv, VALUE proc)
Identical to rb_proc_call(), except you can additionally pass another proc object,...
Definition proc.c:1169
rb_proc_call_kw
VALUE rb_proc_call_kw(VALUE recv, VALUE args, int kw_splat)
Identical to rb_proc_call(), except you can specify how to handle the last element of the given array...
Definition proc.c:1125
rb_obj_is_proc
VALUE rb_obj_is_proc(VALUE recv)
Queries if the given object is a proc.
Definition proc.c:120
rb_range_values
int rb_range_values(VALUE range, VALUE *begp, VALUE *endp, int *exclp)
Deconstructs a range into its components.
Definition range.c:1862
rb_hash_uint
#define rb_hash_uint(h, i)
Just another name of st_hash_uint.
Definition string.h:943
rb_hash_end
#define rb_hash_end(h)
Just another name of st_hash_end.
Definition string.h:946
rb_str_append
VALUE rb_str_append(VALUE dst, VALUE src)
Identical to rb_str_buf_append(), except it converts the right hand side before concatenating.
Definition string.c:3799
rb_str_dup
VALUE rb_str_dup(VALUE str)
Duplicates a string.
Definition string.c:1996
rb_str_buf_append
VALUE rb_str_buf_append(VALUE dst, VALUE src)
Identical to rb_str_cat_cstr(), except it takes Ruby's string instead of C's.
Definition string.c:3765
rb_str_set_len
void rb_str_set_len(VALUE str, long len)
Overwrites the length of the string.
Definition string.c:3389
rb_hash_start
st_index_t rb_hash_start(st_index_t i)
Starts a series of hashing.
Definition random.c:1776
rb_exec_recursive
VALUE rb_exec_recursive(VALUE(*f)(VALUE g, VALUE h, int r), VALUE g, VALUE h)
"Recursion" API entry point.
Definition thread.c:5606
rb_ivar_set
VALUE rb_ivar_set(VALUE obj, ID name, VALUE val)
Identical to rb_iv_set(), except it accepts the name as an ID instead of a C string.
Definition variable.c:2030
rb_ivar_get
VALUE rb_ivar_get(VALUE obj, ID name)
Identical to rb_iv_get(), except it accepts the name as an ID instead of a C string.
Definition variable.c:1505
rb_class_path
VALUE rb_class_path(VALUE mod)
Identical to rb_mod_name(), except it returns #<Class: ...> style inspection for anonymous modules.
Definition variable.c:380
rb_respond_to
int rb_respond_to(VALUE obj, ID mid)
Queries if the object responds to the method.
Definition vm_method.c:3463
rb_undef_alloc_func
void rb_undef_alloc_func(VALUE klass)
Deletes the allocator function of a class.
Definition vm_method.c:1711
rb_check_funcall
VALUE rb_check_funcall(VALUE recv, ID mid, int argc, const VALUE *argv)
Identical to rb_funcallv(), except it returns RUBY_Qundef instead of raising rb_eNoMethodError.
Definition vm_eval.c:686
rb_check_funcall_kw
VALUE rb_check_funcall_kw(VALUE recv, ID mid, int argc, const VALUE *argv, int kw_splat)
Identical to rb_check_funcall(), except you can specify how to handle the last element of the given a...
Definition vm_eval.c:680
rb_define_alloc_func
void rb_define_alloc_func(VALUE klass, rb_alloc_func_t func)
Sets the allocator function of a class.
rb_intern_const
static ID rb_intern_const(const char *str)
This is a "tiny optimisation" over rb_intern().
Definition symbol.h:285
rb_sym2str
VALUE rb_sym2str(VALUE symbol)
Obtain a frozen string representation of a symbol (not including the leading colon).
Definition symbol.c:993
rb_to_symbol
VALUE rb_to_symbol(VALUE name)
Identical to rb_intern_str(), except it generates a dynamic symbol if necessary.
Definition string.c:12674
rb_to_id
ID rb_to_id(VALUE str)
Identical to rb_intern_str(), except it tries to convert the parameter object to an instance of rb_cS...
Definition string.c:12664
len
int len
Length of the buffer.
Definition io.h:8
RB_BLOCK_CALL_FUNC_ARGLIST
#define RB_BLOCK_CALL_FUNC_ARGLIST(yielded_arg, callback_arg)
Shim for block function parameters.
Definition iterator.h:58
rb_yield_values
VALUE rb_yield_values(int n,...)
Identical to rb_yield(), except it takes variadic number of parameters and pass them to the block.
Definition vm_eval.c:1395
rb_yield_values2
VALUE rb_yield_values2(int n, const VALUE *argv)
Identical to rb_yield_values(), except it takes the parameters as a C array instead of variadic argum...
Definition vm_eval.c:1417
rb_yield
VALUE rb_yield(VALUE val)
Yields the block.
Definition vm_eval.c:1372
rb_yield_values_kw
VALUE rb_yield_values_kw(int n, const VALUE *argv, int kw_splat)
Identical to rb_yield_values2(), except you can specify how to handle the last element of the given a...
Definition vm_eval.c:1423
rb_block_call_func
VALUE rb_block_call_func(RB_BLOCK_CALL_FUNC_ARGLIST(yielded_arg, callback_arg))
This is the type of a function that the interpreter expect for C-backended blocks.
Definition iterator.h:83
rb_block_call_kw
VALUE rb_block_call_kw(VALUE obj, ID mid, int argc, const VALUE *argv, rb_block_call_func_t proc, VALUE data2, int kw_splat)
Identical to rb_funcallv_kw(), except it additionally passes a function as a block.
Definition vm_eval.c:1570
rb_long2int
#define rb_long2int
Just another name of rb_long2int_inline.
Definition long.h:62
MEMCPY
#define MEMCPY(p1, p2, type, n)
Handy macro to call memcpy.
Definition memory.h:372
ALLOCA_N
#define ALLOCA_N(type, n)
Definition memory.h:292
RB_GC_GUARD
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
Definition memory.h:167
ruby::backward::cxxanyargs::rb_block_call
VALUE rb_block_call(VALUE q, ID w, int e, const VALUE *r, type *t, VALUE y)
Call a method with a block.
Definition cxxanyargs.hpp:232
ruby::backward::cxxanyargs::rb_proc_new
VALUE rb_proc_new(type *q, VALUE w)
Creates a rb_cProc instance.
Definition cxxanyargs.hpp:394
ruby::backward::cxxanyargs::rb_hash_foreach
void rb_hash_foreach(VALUE q, int_type *w, VALUE e)
Iteration over the given hash.
Definition cxxanyargs.hpp:482
ruby::backward::cxxanyargs::rb_rescue2
VALUE rb_rescue2(type *q, VALUE w, type *e, VALUE r,...)
An equivalent of rescue clause.
Definition cxxanyargs.hpp:284
RARRAY_LEN
#define RARRAY_LEN
Just another name of rb_array_len.
Definition rarray.h:51
RARRAY_LENINT
static int RARRAY_LENINT(VALUE ary)
Identical to rb_array_len(), except it differs for the return type.
Definition rarray.h:281
RARRAY_AREF
#define RARRAY_AREF(a, i)
Definition rarray.h:403
RARRAY_CONST_PTR
#define RARRAY_CONST_PTR
Just another name of rb_array_const_ptr.
Definition rarray.h:52
RHASH_EMPTY_P
#define RHASH_EMPTY_P(h)
Checks if the hash is empty.
Definition rhash.h:79
RUBY_TYPED_DEFAULT_FREE
#define RUBY_TYPED_DEFAULT_FREE
This is a value you can set to rb_data_type_struct::dfree.
Definition rtypeddata.h:80
TypedData_Get_Struct
#define TypedData_Get_Struct(obj, type, data_type, sval)
Obtains a C struct from inside of a wrapper Ruby object.
Definition rtypeddata.h:649
rb_data_type_t
struct rb_data_type_struct rb_data_type_t
This is the struct that holds necessary info for a struct.
Definition rtypeddata.h:205
TypedData_Make_Struct
#define TypedData_Make_Struct(klass, type, data_type, sval)
Identical to TypedData_Wrap_Struct, except it allocates a new data region internally instead of takin...
Definition rtypeddata.h:508
ruby.h
InitVM
#define InitVM(ext)
This macro is for internal use.
Definition ruby.h:231
RB_SCAN_ARGS_LAST_HASH_KEYWORDS
#define RB_SCAN_ARGS_LAST_HASH_KEYWORDS
Treat a final argument as keywords if it is a hash, and not as keywords otherwise.
Definition scan_args.h:59
RB_PASS_CALLED_KEYWORDS
#define RB_PASS_CALLED_KEYWORDS
Pass keywords if current method is called with keywords, useful for argument delegation.
Definition scan_args.h:78
RB_NO_KEYWORDS
#define RB_NO_KEYWORDS
Do not pass keywords.
Definition scan_args.h:69
RTEST
#define RTEST
This is an old name of RB_TEST.
Definition special_consts.h:51
_
#define _(args)
This was a transition path from K&R to ANSI.
Definition stdarg.h:35
MEMO
MEMO.
Definition imemo.h:105
arith_seq_gen
Definition enumerator.c:4388
arith_seq
Definition enumerator.c:3747
enum_chain
Definition enumerator.c:248
enum_product
Definition enumerator.c:255
enumerator
Definition enumerator.c:183
flat_map_i_arg
Definition enumerator.c:2072
generator
Definition enumerator.c:213
lazyenum_funcs
Definition enumerator.c:231
proc_entry
Definition enumerator.c:237
producer
Definition enumerator.c:222
product_state
Definition enumerator.c:3582
rb_arithmetic_sequence_components_t
Decomposed Enumerator::ArithmeicSequence.
Definition enumerator.h:53
rb_arithmetic_sequence_components_t::exclude_end
int exclude_end
Whether the endpoint is open or closed.
Definition enumerator.h:57
rb_arithmetic_sequence_components_t::end
VALUE end
"Right" or "highest" endpoint of the sequence.
Definition enumerator.h:55
rb_arithmetic_sequence_components_t::step
VALUE step
Step between a sequence.
Definition enumerator.h:56
rb_arithmetic_sequence_components_t::begin
VALUE begin
"Left" or "lowest" endpoint of the sequence.
Definition enumerator.h:54
yielder
Definition enumerator.c:218
ID
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition value.h:52
VALUE
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40
RB_FLOAT_TYPE_P
static bool RB_FLOAT_TYPE_P(VALUE obj)
Queries if the object is an instance of rb_cFloat.
Definition value_type.h:264
Check_Type
static void Check_Type(VALUE v, enum ruby_value_type t)
Identical to RB_TYPE_P(), except it raises exceptions on predication failure.
Definition value_type.h:433
RB_TYPE_P
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.
Definition value_type.h:376