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