Ruby: enumerator.c Source File

Ruby 3.4.9p82 (2026-03-11 revision 76cca827ab52ab1d346a728f068d5b8da3e2952b)

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