Ruby: enum.c Source File

Ruby 3.0.5p211 (2022-11-24 revision ba5cf0f7c52d4d35cc6a173c89eda98ceffa2dcf)

enum.c
Go to the documentation of this file.
1/**********************************************************************
2
3 enum.c -
4
5 $Author$
6 created at: Fri Oct 1 15:15:19 JST 1993
7
8 Copyright (C) 1993-2007 Yukihiro Matsumoto
9
10**********************************************************************/
11
12#include "id.h"
13#include "internal.h"
14#include "internal/compar.h"
15#include "internal/enum.h"
16#include "internal/hash.h"
17#include "internal/imemo.h"
18#include "internal/numeric.h"
19#include "internal/object.h"
20#include "internal/proc.h"
21#include "internal/rational.h"
22#include "internal/re.h"
23#include "ruby/util.h"
24#include "ruby_assert.h"
25#include "symbol.h"
26
27 VALUE rb_mEnumerable;
28
29static ID id_next;
30
31#define id_div idDiv
32#define id_each idEach
33#define id_eqq idEqq
34#define id_cmp idCmp
35#define id_lshift idLTLT
36#define id_call idCall
37#define id_size idSize
38
39 VALUE
40rb_enum_values_pack(int argc, const VALUE *argv)
41{
42 if (argc == 0) return Qnil;
43 if (argc == 1) return argv[0];
44 return rb_ary_new4(argc, argv);
45}
46
47#define ENUM_WANT_SVALUE() do { \
48 i = rb_enum_values_pack(argc, argv); \
49} while (0)
50
51static VALUE
52enum_yield(int argc, VALUE ary)
53{
54 if (argc > 1)
55 return rb_yield_force_blockarg(ary);
56 if (argc == 1)
57 return rb_yield(ary);
58 return rb_yield_values2(0, 0);
59}
60
61static VALUE
62enum_yield_array(VALUE ary)
63{
64 long len = RARRAY_LEN(ary);
65
66 if (len > 1)
67 return rb_yield_force_blockarg(ary);
68 if (len == 1)
69 return rb_yield(RARRAY_AREF(ary, 0));
70 return rb_yield_values2(0, 0);
71}
72
73static VALUE
74grep_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, args))
75{
76 struct MEMO *memo = MEMO_CAST(args);
77 ENUM_WANT_SVALUE();
78
79 if (RTEST(rb_funcallv(memo->v1, id_eqq, 1, &i)) == RTEST(memo->u3.value)) {
80 rb_ary_push(memo->v2, i);
81 }
82 return Qnil;
83}
84
85static VALUE
86grep_regexp_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, args))
87{
88 struct MEMO *memo = MEMO_CAST(args);
89 VALUE converted_element, match;
90 ENUM_WANT_SVALUE();
91
92 /* In case element can't be converted to a Symbol or String: not a match (don't raise) */
93 converted_element = SYMBOL_P(i) ? i : rb_check_string_type(i);
94 match = NIL_P(converted_element) ? Qfalse : rb_reg_match_p(memo->v1, i, 0);
95 if (match == memo->u3.value) {
96 rb_ary_push(memo->v2, i);
97 }
98 return Qnil;
99}
100
101static VALUE
102grep_iter_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, args))
103{
104 struct MEMO *memo = MEMO_CAST(args);
105 ENUM_WANT_SVALUE();
106
107 if (RTEST(rb_funcallv(memo->v1, id_eqq, 1, &i)) == RTEST(memo->u3.value)) {
108 rb_ary_push(memo->v2, enum_yield(argc, i));
109 }
110 return Qnil;
111}
112
113static VALUE
114enum_grep0(VALUE obj, VALUE pat, VALUE test)
115{
116 VALUE ary = rb_ary_new();
117 struct MEMO *memo = MEMO_NEW(pat, ary, test);
118 rb_block_call_func_t fn;
119 if (rb_block_given_p()) {
120 fn = grep_iter_i;
121 }
122 else if (RB_TYPE_P(pat, T_REGEXP) &&
123 LIKELY(rb_method_basic_definition_p(CLASS_OF(pat), idEqq))) {
124 fn = grep_regexp_i;
125 }
126 else {
127 fn = grep_i;
128 }
129 rb_block_call(obj, id_each, 0, 0, fn, (VALUE)memo);
130
131 return ary;
132}
133
134/*
135 * call-seq:
136 * enum.grep(pattern) -> array
137 * enum.grep(pattern) { |obj| block } -> array
138 *
139 * Returns an array of every element in <i>enum</i> for which
140 * <code>Pattern === element</code>. If the optional <em>block</em> is
141 * supplied, each matching element is passed to it, and the block's
142 * result is stored in the output array.
143 *
144 * (1..100).grep 38..44 #=> [38, 39, 40, 41, 42, 43, 44]
145 * c = IO.constants
146 * c.grep(/SEEK/) #=> [:SEEK_SET, :SEEK_CUR, :SEEK_END]
147 * res = c.grep(/SEEK/) { |v| IO.const_get(v) }
148 * res #=> [0, 1, 2]
149 *
150 */
151
152static VALUE
153enum_grep(VALUE obj, VALUE pat)
154{
155 return enum_grep0(obj, pat, Qtrue);
156}
157
158/*
159 * call-seq:
160 * enum.grep_v(pattern) -> array
161 * enum.grep_v(pattern) { |obj| block } -> array
162 *
163 * Inverted version of Enumerable#grep.
164 * Returns an array of every element in <i>enum</i> for which
165 * not <code>Pattern === element</code>.
166 *
167 * (1..10).grep_v 2..5 #=> [1, 6, 7, 8, 9, 10]
168 * res =(1..10).grep_v(2..5) { |v| v * 2 }
169 * res #=> [2, 12, 14, 16, 18, 20]
170 *
171 */
172
173static VALUE
174enum_grep_v(VALUE obj, VALUE pat)
175{
176 return enum_grep0(obj, pat, Qfalse);
177}
178
179#define COUNT_BIGNUM IMEMO_FL_USER0
180#define MEMO_V3_SET(m, v) RB_OBJ_WRITE((m), &(m)->u3.value, (v))
181
182static void
183imemo_count_up(struct MEMO *memo)
184{
185 if (memo->flags & COUNT_BIGNUM) {
186 MEMO_V3_SET(memo, rb_int_succ(memo->u3.value));
187 }
188 else if (++memo->u3.cnt == 0) {
189 /* overflow */
190 unsigned long buf[2] = {0, 1};
191 MEMO_V3_SET(memo, rb_big_unpack(buf, 2));
192 memo->flags |= COUNT_BIGNUM;
193 }
194}
195
196static VALUE
197imemo_count_value(struct MEMO *memo)
198{
199 if (memo->flags & COUNT_BIGNUM) {
200 return memo->u3.value;
201 }
202 else {
203 return ULONG2NUM(memo->u3.cnt);
204 }
205}
206
207static VALUE
208count_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, memop))
209{
210 struct MEMO *memo = MEMO_CAST(memop);
211
212 ENUM_WANT_SVALUE();
213
214 if (rb_equal(i, memo->v1)) {
215 imemo_count_up(memo);
216 }
217 return Qnil;
218}
219
220static VALUE
221count_iter_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, memop))
222{
223 struct MEMO *memo = MEMO_CAST(memop);
224
225 if (RTEST(rb_yield_values2(argc, argv))) {
226 imemo_count_up(memo);
227 }
228 return Qnil;
229}
230
231static VALUE
232count_all_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, memop))
233{
234 struct MEMO *memo = MEMO_CAST(memop);
235
236 imemo_count_up(memo);
237 return Qnil;
238}
239
240/*
241 * call-seq:
242 * enum.count -> int
243 * enum.count(item) -> int
244 * enum.count { |obj| block } -> int
245 *
246 * Returns the number of items in +enum+ through enumeration.
247 * If an argument is given, the number of items in +enum+ that
248 * are equal to +item+ are counted. If a block is given, it
249 * counts the number of elements yielding a true value.
250 *
251 * ary = [1, 2, 4, 2]
252 * ary.count #=> 4
253 * ary.count(2) #=> 2
254 * ary.count{ |x| x%2==0 } #=> 3
255 *
256 */
257
258static VALUE
259enum_count(int argc, VALUE *argv, VALUE obj)
260{
261 VALUE item = Qnil;
262 struct MEMO *memo;
263 rb_block_call_func *func;
264
265 if (argc == 0) {
266 if (rb_block_given_p()) {
267 func = count_iter_i;
268 }
269 else {
270 func = count_all_i;
271 }
272 }
273 else {
274 rb_scan_args(argc, argv, "1", &item);
275 if (rb_block_given_p()) {
276 rb_warn("given block not used");
277 }
278 func = count_i;
279 }
280
281 memo = MEMO_NEW(item, 0, 0);
282 rb_block_call(obj, id_each, 0, 0, func, (VALUE)memo);
283 return imemo_count_value(memo);
284}
285
286static VALUE
287find_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, memop))
288{
289 ENUM_WANT_SVALUE();
290
291 if (RTEST(enum_yield(argc, i))) {
292 struct MEMO *memo = MEMO_CAST(memop);
293 MEMO_V1_SET(memo, i);
294 memo->u3.cnt = 1;
295 rb_iter_break();
296 }
297 return Qnil;
298}
299
300/*
301 * call-seq:
302 * enum.detect(ifnone = nil) { |obj| block } -> obj or nil
303 * enum.find(ifnone = nil) { |obj| block } -> obj or nil
304 * enum.detect(ifnone = nil) -> an_enumerator
305 * enum.find(ifnone = nil) -> an_enumerator
306 *
307 * Passes each entry in <i>enum</i> to <em>block</em>. Returns the
308 * first for which <em>block</em> is not false. If no
309 * object matches, calls <i>ifnone</i> and returns its result when it
310 * is specified, or returns <code>nil</code> otherwise.
311 *
312 * If no block is given, an enumerator is returned instead.
313 *
314 * (1..100).detect #=> #<Enumerator: 1..100:detect>
315 * (1..100).find #=> #<Enumerator: 1..100:find>
316 *
317 * (1..10).detect { |i| i % 5 == 0 && i % 7 == 0 } #=> nil
318 * (1..10).find { |i| i % 5 == 0 && i % 7 == 0 } #=> nil
319 * (1..10).detect(-> {0}) { |i| i % 5 == 0 && i % 7 == 0 } #=> 0
320 * (1..10).find(-> {0}) { |i| i % 5 == 0 && i % 7 == 0 } #=> 0
321 * (1..100).detect { |i| i % 5 == 0 && i % 7 == 0 } #=> 35
322 * (1..100).find { |i| i % 5 == 0 && i % 7 == 0 } #=> 35
323 *
324 */
325
326static VALUE
327enum_find(int argc, VALUE *argv, VALUE obj)
328{
329 struct MEMO *memo;
330 VALUE if_none;
331
332 if_none = rb_check_arity(argc, 0, 1) ? argv[0] : Qnil;
333 RETURN_ENUMERATOR(obj, argc, argv);
334 memo = MEMO_NEW(Qundef, 0, 0);
335 rb_block_call(obj, id_each, 0, 0, find_i, (VALUE)memo);
336 if (memo->u3.cnt) {
337 return memo->v1;
338 }
339 if (!NIL_P(if_none)) {
340 return rb_funcallv(if_none, id_call, 0, 0);
341 }
342 return Qnil;
343}
344
345static VALUE
346find_index_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, memop))
347{
348 struct MEMO *memo = MEMO_CAST(memop);
349
350 ENUM_WANT_SVALUE();
351
352 if (rb_equal(i, memo->v2)) {
353 MEMO_V1_SET(memo, imemo_count_value(memo));
354 rb_iter_break();
355 }
356 imemo_count_up(memo);
357 return Qnil;
358}
359
360static VALUE
361find_index_iter_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, memop))
362{
363 struct MEMO *memo = MEMO_CAST(memop);
364
365 if (RTEST(rb_yield_values2(argc, argv))) {
366 MEMO_V1_SET(memo, imemo_count_value(memo));
367 rb_iter_break();
368 }
369 imemo_count_up(memo);
370 return Qnil;
371}
372
373/*
374 * call-seq:
375 * enum.find_index(value) -> int or nil
376 * enum.find_index { |obj| block } -> int or nil
377 * enum.find_index -> an_enumerator
378 *
379 * Compares each entry in <i>enum</i> with <em>value</em> or passes
380 * to <em>block</em>. Returns the index for the first for which the
381 * evaluated value is non-false. If no object matches, returns
382 * <code>nil</code>
383 *
384 * If neither block nor argument is given, an enumerator is returned instead.
385 *
386 * (1..10).find_index { |i| i % 5 == 0 && i % 7 == 0 } #=> nil
387 * (1..100).find_index { |i| i % 5 == 0 && i % 7 == 0 } #=> 34
388 * (1..100).find_index(50) #=> 49
389 *
390 */
391
392static VALUE
393enum_find_index(int argc, VALUE *argv, VALUE obj)
394{
395 struct MEMO *memo; /* [return value, current index, ] */
396 VALUE condition_value = Qnil;
397 rb_block_call_func *func;
398
399 if (argc == 0) {
400 RETURN_ENUMERATOR(obj, 0, 0);
401 func = find_index_iter_i;
402 }
403 else {
404 rb_scan_args(argc, argv, "1", &condition_value);
405 if (rb_block_given_p()) {
406 rb_warn("given block not used");
407 }
408 func = find_index_i;
409 }
410
411 memo = MEMO_NEW(Qnil, condition_value, 0);
412 rb_block_call(obj, id_each, 0, 0, func, (VALUE)memo);
413 return memo->v1;
414}
415
416static VALUE
417find_all_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, ary))
418{
419 ENUM_WANT_SVALUE();
420
421 if (RTEST(enum_yield(argc, i))) {
422 rb_ary_push(ary, i);
423 }
424 return Qnil;
425}
426
427static VALUE
428enum_size(VALUE self, VALUE args, VALUE eobj)
429{
430 return rb_check_funcall_default(self, id_size, 0, 0, Qnil);
431}
432
433static long
434limit_by_enum_size(VALUE obj, long n)
435{
436 unsigned long limit;
437 VALUE size = rb_check_funcall(obj, id_size, 0, 0);
438 if (!FIXNUM_P(size)) return n;
439 limit = FIX2ULONG(size);
440 return ((unsigned long)n > limit) ? (long)limit : n;
441}
442
443static int
444enum_size_over_p(VALUE obj, long n)
445{
446 VALUE size = rb_check_funcall(obj, id_size, 0, 0);
447 if (!FIXNUM_P(size)) return 0;
448 return ((unsigned long)n > FIX2ULONG(size));
449}
450
451/*
452 * call-seq:
453 * enum.find_all { |obj| block } -> array
454 * enum.select { |obj| block } -> array
455 * enum.filter { |obj| block } -> array
456 * enum.find_all -> an_enumerator
457 * enum.select -> an_enumerator
458 * enum.filter -> an_enumerator
459 *
460 * Returns an array containing all elements of +enum+
461 * for which the given +block+ returns a true value.
462 *
463 * The <i>find_all</i> and <i>select</i> methods are aliases.
464 * There is no performance benefit to either.
465 *
466 * If no block is given, an Enumerator is returned instead.
467 *
468 *
469 * (1..10).find_all { |i| i % 3 == 0 } #=> [3, 6, 9]
470 *
471 * [1,2,3,4,5].select { |num| num.even? } #=> [2, 4]
472 *
473 * [:foo, :bar].filter { |x| x == :foo } #=> [:foo]
474 *
475 * See also Enumerable#reject, Enumerable#grep.
476 */
477
478static VALUE
479enum_find_all(VALUE obj)
480{
481 VALUE ary;
482
483 RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);
484
485 ary = rb_ary_new();
486 rb_block_call(obj, id_each, 0, 0, find_all_i, ary);
487
488 return ary;
489}
490
491static VALUE
492filter_map_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, ary))
493{
494 i = rb_yield_values2(argc, argv);
495
496 if (RTEST(i)) {
497 rb_ary_push(ary, i);
498 }
499
500 return Qnil;
501}
502
503/*
504 * call-seq:
505 * enum.filter_map { |obj| block } -> array
506 * enum.filter_map -> an_enumerator
507 *
508 * Returns a new array containing the truthy results (everything except
509 * +false+ or +nil+) of running the +block+ for every element in +enum+.
510 *
511 * If no block is given, an Enumerator is returned instead.
512 *
513 *
514 * (1..10).filter_map { |i| i * 2 if i.even? } #=> [4, 8, 12, 16, 20]
515 *
516 */
517static VALUE
518enum_filter_map(VALUE obj)
519{
520 VALUE ary;
521
522 RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);
523
524 ary = rb_ary_new();
525 rb_block_call(obj, id_each, 0, 0, filter_map_i, ary);
526
527 return ary;
528}
529
530
531static VALUE
532reject_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, ary))
533{
534 ENUM_WANT_SVALUE();
535
536 if (!RTEST(enum_yield(argc, i))) {
537 rb_ary_push(ary, i);
538 }
539 return Qnil;
540}
541
542/*
543 * call-seq:
544 * enum.reject { |obj| block } -> array
545 * enum.reject -> an_enumerator
546 *
547 * Returns an array for all elements of +enum+ for which the given
548 * +block+ returns <code>false</code>.
549 *
550 * If no block is given, an Enumerator is returned instead.
551 *
552 * (1..10).reject { |i| i % 3 == 0 } #=> [1, 2, 4, 5, 7, 8, 10]
553 *
554 * [1, 2, 3, 4, 5].reject { |num| num.even? } #=> [1, 3, 5]
555 *
556 * See also Enumerable#find_all.
557 */
558
559static VALUE
560enum_reject(VALUE obj)
561{
562 VALUE ary;
563
564 RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);
565
566 ary = rb_ary_new();
567 rb_block_call(obj, id_each, 0, 0, reject_i, ary);
568
569 return ary;
570}
571
572static VALUE
573collect_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, ary))
574{
575 rb_ary_push(ary, rb_yield_values2(argc, argv));
576
577 return Qnil;
578}
579
580static VALUE
581collect_all(RB_BLOCK_CALL_FUNC_ARGLIST(i, ary))
582{
583 rb_ary_push(ary, rb_enum_values_pack(argc, argv));
584
585 return Qnil;
586}
587
588/*
589 * call-seq:
590 * enum.collect { |obj| block } -> array
591 * enum.map { |obj| block } -> array
592 * enum.collect -> an_enumerator
593 * enum.map -> an_enumerator
594 *
595 * Returns a new array with the results of running <em>block</em> once
596 * for every element in <i>enum</i>.
597 *
598 * If no block is given, an enumerator is returned instead.
599 *
600 * (1..4).map { |i| i*i } #=> [1, 4, 9, 16]
601 * (1..4).collect { "cat" } #=> ["cat", "cat", "cat", "cat"]
602 *
603 */
604
605static VALUE
606enum_collect(VALUE obj)
607{
608 VALUE ary;
609 int min_argc, max_argc;
610
611 RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);
612
613 ary = rb_ary_new();
614 min_argc = rb_block_min_max_arity(&max_argc);
615 rb_lambda_call(obj, id_each, 0, 0, collect_i, min_argc, max_argc, ary);
616
617 return ary;
618}
619
620static VALUE
621flat_map_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, ary))
622{
623 VALUE tmp;
624
625 i = rb_yield_values2(argc, argv);
626 tmp = rb_check_array_type(i);
627
628 if (NIL_P(tmp)) {
629 rb_ary_push(ary, i);
630 }
631 else {
632 rb_ary_concat(ary, tmp);
633 }
634 return Qnil;
635}
636
637/*
638 * call-seq:
639 * enum.flat_map { |obj| block } -> array
640 * enum.collect_concat { |obj| block } -> array
641 * enum.flat_map -> an_enumerator
642 * enum.collect_concat -> an_enumerator
643 *
644 * Returns a new array with the concatenated results of running
645 * <em>block</em> once for every element in <i>enum</i>.
646 *
647 * If no block is given, an enumerator is returned instead.
648 *
649 * [1, 2, 3, 4].flat_map { |e| [e, -e] } #=> [1, -1, 2, -2, 3, -3, 4, -4]
650 * [[1, 2], [3, 4]].flat_map { |e| e + [100] } #=> [1, 2, 100, 3, 4, 100]
651 *
652 */
653
654static VALUE
655enum_flat_map(VALUE obj)
656{
657 VALUE ary;
658
659 RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);
660
661 ary = rb_ary_new();
662 rb_block_call(obj, id_each, 0, 0, flat_map_i, ary);
663
664 return ary;
665}
666
667/*
668 * call-seq:
669 * enum.to_a(*args) -> array
670 * enum.entries(*args) -> array
671 *
672 * Returns an array containing the items in <i>enum</i>.
673 *
674 * (1..7).to_a #=> [1, 2, 3, 4, 5, 6, 7]
675 * { 'a'=>1, 'b'=>2, 'c'=>3 }.to_a #=> [["a", 1], ["b", 2], ["c", 3]]
676 *
677 * require 'prime'
678 * Prime.entries 10 #=> [2, 3, 5, 7]
679 */
680static VALUE
681enum_to_a(int argc, VALUE *argv, VALUE obj)
682{
683 VALUE ary = rb_ary_new();
684
685 rb_block_call_kw(obj, id_each, argc, argv, collect_all, ary, RB_PASS_CALLED_KEYWORDS);
686
687 return ary;
688}
689
690static VALUE
691enum_hashify(VALUE obj, int argc, const VALUE *argv, rb_block_call_func *iter)
692{
693 VALUE hash = rb_hash_new();
694 rb_block_call(obj, id_each, argc, argv, iter, hash);
695 return hash;
696}
697
698static VALUE
699enum_to_h_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, hash))
700{
701 ENUM_WANT_SVALUE();
702 return rb_hash_set_pair(hash, i);
703}
704
705static VALUE
706enum_to_h_ii(RB_BLOCK_CALL_FUNC_ARGLIST(i, hash))
707{
708 return rb_hash_set_pair(hash, rb_yield_values2(argc, argv));
709}
710
711/*
712 * call-seq:
713 * enum.to_h(*args) -> hash
714 * enum.to_h(*args) {...} -> hash
715 *
716 * Returns the result of interpreting <i>enum</i> as a list of
717 * <tt>[key, value]</tt> pairs.
718 *
719 * %i[hello world].each_with_index.to_h
720 * # => {:hello => 0, :world => 1}
721 *
722 * If a block is given, the results of the block on each element of
723 * the enum will be used as pairs.
724 *
725 * (1..5).to_h {|x| [x, x ** 2]}
726 * #=> {1=>1, 2=>4, 3=>9, 4=>16, 5=>25}
727 */
728
729static VALUE
730enum_to_h(int argc, VALUE *argv, VALUE obj)
731{
732 rb_block_call_func *iter = rb_block_given_p() ? enum_to_h_ii : enum_to_h_i;
733 return enum_hashify(obj, argc, argv, iter);
734}
735
736static VALUE
737inject_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, p))
738{
739 struct MEMO *memo = MEMO_CAST(p);
740
741 ENUM_WANT_SVALUE();
742
743 if (memo->v1 == Qundef) {
744 MEMO_V1_SET(memo, i);
745 }
746 else {
747 MEMO_V1_SET(memo, rb_yield_values(2, memo->v1, i));
748 }
749 return Qnil;
750}
751
752static VALUE
753inject_op_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, p))
754{
755 struct MEMO *memo = MEMO_CAST(p);
756 VALUE name;
757
758 ENUM_WANT_SVALUE();
759
760 if (memo->v1 == Qundef) {
761 MEMO_V1_SET(memo, i);
762 }
763 else if (SYMBOL_P(name = memo->u3.value)) {
764 const ID mid = SYM2ID(name);
765 MEMO_V1_SET(memo, rb_funcallv_public(memo->v1, mid, 1, &i));
766 }
767 else {
768 VALUE args[2];
769 args[0] = name;
770 args[1] = i;
771 MEMO_V1_SET(memo, rb_f_send(numberof(args), args, memo->v1));
772 }
773 return Qnil;
774}
775
776static VALUE
777ary_inject_op(VALUE ary, VALUE init, VALUE op)
778{
779 ID id;
780 VALUE v, e;
781 long i, n;
782
783 if (RARRAY_LEN(ary) == 0)
784 return init == Qundef ? Qnil : init;
785
786 if (init == Qundef) {
787 v = RARRAY_AREF(ary, 0);
788 i = 1;
789 if (RARRAY_LEN(ary) == 1)
790 return v;
791 }
792 else {
793 v = init;
794 i = 0;
795 }
796
797 id = SYM2ID(op);
798 if (id == idPLUS) {
799 if (RB_INTEGER_TYPE_P(v) &&
800 rb_method_basic_definition_p(rb_cInteger, idPLUS) &&
801 rb_obj_respond_to(v, idPLUS, FALSE)) {
802 n = 0;
803 for (; i < RARRAY_LEN(ary); i++) {
804 e = RARRAY_AREF(ary, i);
805 if (FIXNUM_P(e)) {
806 n += FIX2LONG(e); /* should not overflow long type */
807 if (!FIXABLE(n)) {
808 v = rb_big_plus(LONG2NUM(n), v);
809 n = 0;
810 }
811 }
812 else if (RB_TYPE_P(e, T_BIGNUM))
813 v = rb_big_plus(e, v);
814 else
815 goto not_integer;
816 }
817 if (n != 0)
818 v = rb_fix_plus(LONG2FIX(n), v);
819 return v;
820
821 not_integer:
822 if (n != 0)
823 v = rb_fix_plus(LONG2FIX(n), v);
824 }
825 }
826 for (; i < RARRAY_LEN(ary); i++) {
827 VALUE arg = RARRAY_AREF(ary, i);
828 v = rb_funcallv_public(v, id, 1, &arg);
829 }
830 return v;
831}
832
833/*
834 * call-seq:
835 * enum.inject(initial, sym) -> obj
836 * enum.inject(sym) -> obj
837 * enum.inject(initial) { |memo, obj| block } -> obj
838 * enum.inject { |memo, obj| block } -> obj
839 * enum.reduce(initial, sym) -> obj
840 * enum.reduce(sym) -> obj
841 * enum.reduce(initial) { |memo, obj| block } -> obj
842 * enum.reduce { |memo, obj| block } -> obj
843 *
844 * Combines all elements of <i>enum</i> by applying a binary
845 * operation, specified by a block or a symbol that names a
846 * method or operator.
847 *
848 * The <i>inject</i> and <i>reduce</i> methods are aliases. There
849 * is no performance benefit to either.
850 *
851 * If you specify a block, then for each element in <i>enum</i>
852 * the block is passed an accumulator value (<i>memo</i>) and the element.
853 * If you specify a symbol instead, then each element in the collection
854 * will be passed to the named method of <i>memo</i>.
855 * In either case, the result becomes the new value for <i>memo</i>.
856 * At the end of the iteration, the final value of <i>memo</i> is the
857 * return value for the method.
858 *
859 * If you do not explicitly specify an <i>initial</i> value for <i>memo</i>,
860 * then the first element of collection is used as the initial value
861 * of <i>memo</i>.
862 *
863 *
864 * # Sum some numbers
865 * (5..10).reduce(:+) #=> 45
866 * # Same using a block and inject
867 * (5..10).inject { |sum, n| sum + n } #=> 45
868 * # Multiply some numbers
869 * (5..10).reduce(1, :*) #=> 151200
870 * # Same using a block
871 * (5..10).inject(1) { |product, n| product * n } #=> 151200
872 * # find the longest word
873 * longest = %w{ cat sheep bear }.inject do |memo, word|
874 * memo.length > word.length ? memo : word
875 * end
876 * longest #=> "sheep"
877 *
878 */
879static VALUE
880enum_inject(int argc, VALUE *argv, VALUE obj)
881{
882 struct MEMO *memo;
883 VALUE init, op;
884 rb_block_call_func *iter = inject_i;
885 ID id;
886
887 switch (rb_scan_args(argc, argv, "02", &init, &op)) {
888 case 0:
889 init = Qundef;
890 break;
891 case 1:
892 if (rb_block_given_p()) {
893 break;
894 }
895 id = rb_check_id(&init);
896 op = id ? ID2SYM(id) : init;
897 init = Qundef;
898 iter = inject_op_i;
899 break;
900 case 2:
901 if (rb_block_given_p()) {
902 rb_warning("given block not used");
903 }
904 id = rb_check_id(&op);
905 if (id) op = ID2SYM(id);
906 iter = inject_op_i;
907 break;
908 }
909
910 if (iter == inject_op_i &&
911 SYMBOL_P(op) &&
912 RB_TYPE_P(obj, T_ARRAY) &&
913 rb_method_basic_definition_p(CLASS_OF(obj), id_each)) {
914 return ary_inject_op(obj, init, op);
915 }
916
917 memo = MEMO_NEW(init, Qnil, op);
918 rb_block_call(obj, id_each, 0, 0, iter, (VALUE)memo);
919 if (memo->v1 == Qundef) return Qnil;
920 return memo->v1;
921}
922
923static VALUE
924partition_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, arys))
925{
926 struct MEMO *memo = MEMO_CAST(arys);
927 VALUE ary;
928 ENUM_WANT_SVALUE();
929
930 if (RTEST(enum_yield(argc, i))) {
931 ary = memo->v1;
932 }
933 else {
934 ary = memo->v2;
935 }
936 rb_ary_push(ary, i);
937 return Qnil;
938}
939
940/*
941 * call-seq:
942 * enum.partition { |obj| block } -> [ true_array, false_array ]
943 * enum.partition -> an_enumerator
944 *
945 * Returns two arrays, the first containing the elements of
946 * <i>enum</i> for which the block evaluates to true, the second
947 * containing the rest.
948 *
949 * If no block is given, an enumerator is returned instead.
950 *
951 * (1..6).partition { |v| v.even? } #=> [[2, 4, 6], [1, 3, 5]]
952 *
953 */
954
955static VALUE
956enum_partition(VALUE obj)
957{
958 struct MEMO *memo;
959
960 RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);
961
962 memo = MEMO_NEW(rb_ary_new(), rb_ary_new(), 0);
963 rb_block_call(obj, id_each, 0, 0, partition_i, (VALUE)memo);
964
965 return rb_assoc_new(memo->v1, memo->v2);
966}
967
968static VALUE
969group_by_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, hash))
970{
971 VALUE group;
972 VALUE values;
973
974 ENUM_WANT_SVALUE();
975
976 group = enum_yield(argc, i);
977 values = rb_hash_aref(hash, group);
978 if (!RB_TYPE_P(values, T_ARRAY)) {
979 values = rb_ary_new3(1, i);
980 rb_hash_aset(hash, group, values);
981 }
982 else {
983 rb_ary_push(values, i);
984 }
985 return Qnil;
986}
987
988/*
989 * call-seq:
990 * enum.group_by { |obj| block } -> a_hash
991 * enum.group_by -> an_enumerator
992 *
993 * Groups the collection by result of the block. Returns a hash where the
994 * keys are the evaluated result from the block and the values are
995 * arrays of elements in the collection that correspond to the key.
996 *
997 * If no block is given an enumerator is returned.
998 *
999 * (1..6).group_by { |i| i%3 } #=> {0=>[3, 6], 1=>[1, 4], 2=>[2, 5]}
1000 *
1001 */
1002
1003static VALUE
1004enum_group_by(VALUE obj)
1005{
1006 RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);
1007
1008 return enum_hashify(obj, 0, 0, group_by_i);
1009}
1010
1011static void
1012tally_up(VALUE hash, VALUE group)
1013{
1014 VALUE tally = rb_hash_aref(hash, group);
1015 if (NIL_P(tally)) {
1016 tally = INT2FIX(1);
1017 }
1018 else if (FIXNUM_P(tally) && tally < INT2FIX(FIXNUM_MAX)) {
1019 tally += INT2FIX(1) & ~FIXNUM_FLAG;
1020 }
1021 else {
1022 tally = rb_big_plus(tally, INT2FIX(1));
1023 }
1024 rb_hash_aset(hash, group, tally);
1025}
1026
1027static VALUE
1028tally_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, hash))
1029{
1030 ENUM_WANT_SVALUE();
1031 tally_up(hash, i);
1032 return Qnil;
1033}
1034
1035/*
1036 * call-seq:
1037 * enum.tally -> a_hash
1038 *
1039 * Tallies the collection, i.e., counts the occurrences of each element.
1040 * Returns a hash with the elements of the collection as keys and the
1041 * corresponding counts as values.
1042 *
1043 * ["a", "b", "c", "b"].tally #=> {"a"=>1, "b"=>2, "c"=>1}
1044 */
1045
1046static VALUE
1047enum_tally(VALUE obj)
1048{
1049 return enum_hashify(obj, 0, 0, tally_i);
1050}
1051
1052 NORETURN(static VALUE first_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, params)));
1053static VALUE
1054first_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, params))
1055{
1056 struct MEMO *memo = MEMO_CAST(params);
1057 ENUM_WANT_SVALUE();
1058
1059 MEMO_V1_SET(memo, i);
1060 rb_iter_break();
1061
1062 UNREACHABLE_RETURN(Qnil);
1063}
1064
1065static VALUE enum_take(VALUE obj, VALUE n);
1066
1067/*
1068 * call-seq:
1069 * enum.first -> obj or nil
1070 * enum.first(n) -> an_array
1071 *
1072 * Returns the first element, or the first +n+ elements, of the enumerable.
1073 * If the enumerable is empty, the first form returns <code>nil</code>, and the
1074 * second form returns an empty array.
1075 *
1076 * %w[foo bar baz].first #=> "foo"
1077 * %w[foo bar baz].first(2) #=> ["foo", "bar"]
1078 * %w[foo bar baz].first(10) #=> ["foo", "bar", "baz"]
1079 * [].first #=> nil
1080 * [].first(10) #=> []
1081 *
1082 */
1083
1084static VALUE
1085enum_first(int argc, VALUE *argv, VALUE obj)
1086{
1087 struct MEMO *memo;
1088 rb_check_arity(argc, 0, 1);
1089 if (argc > 0) {
1090 return enum_take(obj, argv[0]);
1091 }
1092 else {
1093 memo = MEMO_NEW(Qnil, 0, 0);
1094 rb_block_call(obj, id_each, 0, 0, first_i, (VALUE)memo);
1095 return memo->v1;
1096 }
1097}
1098
1099
1100/*
1101 * call-seq:
1102 * enum.sort -> array
1103 * enum.sort { |a, b| block } -> array
1104 *
1105 * Returns an array containing the items in <i>enum</i> sorted.
1106 *
1107 * Comparisons for the sort will be done using the items' own
1108 * <code><=></code> operator or using an optional code block.
1109 *
1110 * The block must implement a comparison between +a+ and +b+ and return
1111 * an integer less than 0 when +b+ follows +a+, +0+ when +a+ and +b+
1112 * are equivalent, or an integer greater than 0 when +a+ follows +b+.
1113 *
1114 * The result is not guaranteed to be stable. When the comparison of two
1115 * elements returns +0+, the order of the elements is unpredictable.
1116 *
1117 * %w(rhea kea flea).sort #=> ["flea", "kea", "rhea"]
1118 * (1..10).sort { |a, b| b <=> a } #=> [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
1119 *
1120 * See also Enumerable#sort_by. It implements a Schwartzian transform
1121 * which is useful when key computation or comparison is expensive.
1122 */
1123
1124static VALUE
1125enum_sort(VALUE obj)
1126{
1127 return rb_ary_sort_bang(enum_to_a(0, 0, obj));
1128}
1129
1130#define SORT_BY_BUFSIZE 16
1131 struct sort_by_data {
1132 const VALUE ary;
1133 const VALUE buf;
1134 long n;
1135};
1136
1137static VALUE
1138sort_by_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, _data))
1139{
1140 struct sort_by_data *data = (struct sort_by_data *)&MEMO_CAST(_data)->v1;
1141 VALUE ary = data->ary;
1142 VALUE v;
1143
1144 ENUM_WANT_SVALUE();
1145
1146 v = enum_yield(argc, i);
1147
1148 if (RBASIC(ary)->klass) {
1149 rb_raise(rb_eRuntimeError, "sort_by reentered");
1150 }
1151 if (RARRAY_LEN(data->buf) != SORT_BY_BUFSIZE*2) {
1152 rb_raise(rb_eRuntimeError, "sort_by reentered");
1153 }
1154
1155 RARRAY_ASET(data->buf, data->n*2, v);
1156 RARRAY_ASET(data->buf, data->n*2+1, i);
1157 data->n++;
1158 if (data->n == SORT_BY_BUFSIZE) {
1159 rb_ary_concat(ary, data->buf);
1160 data->n = 0;
1161 }
1162 return Qnil;
1163}
1164
1165static int
1166sort_by_cmp(const void *ap, const void *bp, void *data)
1167{
1168 struct cmp_opt_data cmp_opt = { 0, 0 };
1169 VALUE a;
1170 VALUE b;
1171 VALUE ary = (VALUE)data;
1172
1173 if (RBASIC(ary)->klass) {
1174 rb_raise(rb_eRuntimeError, "sort_by reentered");
1175 }
1176
1177 a = *(VALUE *)ap;
1178 b = *(VALUE *)bp;
1179
1180 return OPTIMIZED_CMP(a, b, cmp_opt);
1181}
1182
1183/*
1184 * call-seq:
1185 * enum.sort_by { |obj| block } -> array
1186 * enum.sort_by -> an_enumerator
1187 *
1188 * Sorts <i>enum</i> using a set of keys generated by mapping the
1189 * values in <i>enum</i> through the given block.
1190 *
1191 * The result is not guaranteed to be stable. When two keys are equal,
1192 * the order of the corresponding elements is unpredictable.
1193 *
1194 * If no block is given, an enumerator is returned instead.
1195 *
1196 * %w{apple pear fig}.sort_by { |word| word.length }
1197 * #=> ["fig", "pear", "apple"]
1198 *
1199 * The current implementation of #sort_by generates an array of
1200 * tuples containing the original collection element and the mapped
1201 * value. This makes #sort_by fairly expensive when the keysets are
1202 * simple.
1203 *
1204 * require 'benchmark'
1205 *
1206 * a = (1..100000).map { rand(100000) }
1207 *
1208 * Benchmark.bm(10) do |b|
1209 * b.report("Sort") { a.sort }
1210 * b.report("Sort by") { a.sort_by { |a| a } }
1211 * end
1212 *
1213 * <em>produces:</em>
1214 *
1215 * user system total real
1216 * Sort 0.180000 0.000000 0.180000 ( 0.175469)
1217 * Sort by 1.980000 0.040000 2.020000 ( 2.013586)
1218 *
1219 * However, consider the case where comparing the keys is a non-trivial
1220 * operation. The following code sorts some files on modification time
1221 * using the basic #sort method.
1222 *
1223 * files = Dir["*"]
1224 * sorted = files.sort { |a, b| File.new(a).mtime <=> File.new(b).mtime }
1225 * sorted #=> ["mon", "tues", "wed", "thurs"]
1226 *
1227 * This sort is inefficient: it generates two new File
1228 * objects during every comparison. A slightly better technique is to
1229 * use the Kernel#test method to generate the modification
1230 * times directly.
1231 *
1232 * files = Dir["*"]
1233 * sorted = files.sort { |a, b|
1234 * test(?M, a) <=> test(?M, b)
1235 * }
1236 * sorted #=> ["mon", "tues", "wed", "thurs"]
1237 *
1238 * This still generates many unnecessary Time objects. A more
1239 * efficient technique is to cache the sort keys (modification times
1240 * in this case) before the sort. Perl users often call this approach
1241 * a Schwartzian transform, after Randal Schwartz. We construct a
1242 * temporary array, where each element is an array containing our
1243 * sort key along with the filename. We sort this array, and then
1244 * extract the filename from the result.
1245 *
1246 * sorted = Dir["*"].collect { |f|
1247 * [test(?M, f), f]
1248 * }.sort.collect { |f| f[1] }
1249 * sorted #=> ["mon", "tues", "wed", "thurs"]
1250 *
1251 * This is exactly what #sort_by does internally.
1252 *
1253 * sorted = Dir["*"].sort_by { |f| test(?M, f) }
1254 * sorted #=> ["mon", "tues", "wed", "thurs"]
1255 *
1256 * To produce the reverse of a specific order, the following can be used:
1257 *
1258 * ary.sort_by { ... }.reverse!
1259 */
1260
1261static VALUE
1262enum_sort_by(VALUE obj)
1263{
1264 VALUE ary, buf;
1265 struct MEMO *memo;
1266 long i;
1267 struct sort_by_data *data;
1268
1269 RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);
1270
1271 if (RB_TYPE_P(obj, T_ARRAY) && RARRAY_LEN(obj) <= LONG_MAX/2) {
1272 ary = rb_ary_new2(RARRAY_LEN(obj)*2);
1273 }
1274 else {
1275 ary = rb_ary_new();
1276 }
1277 RBASIC_CLEAR_CLASS(ary);
1278 buf = rb_ary_tmp_new(SORT_BY_BUFSIZE*2);
1279 rb_ary_store(buf, SORT_BY_BUFSIZE*2-1, Qnil);
1280 memo = MEMO_NEW(0, 0, 0);
1281 data = (struct sort_by_data *)&memo->v1;
1282 RB_OBJ_WRITE(memo, &data->ary, ary);
1283 RB_OBJ_WRITE(memo, &data->buf, buf);
1284 data->n = 0;
1285 rb_block_call(obj, id_each, 0, 0, sort_by_i, (VALUE)memo);
1286 ary = data->ary;
1287 buf = data->buf;
1288 if (data->n) {
1289 rb_ary_resize(buf, data->n*2);
1290 rb_ary_concat(ary, buf);
1291 }
1292 if (RARRAY_LEN(ary) > 2) {
1293 RARRAY_PTR_USE(ary, ptr,
1294 ruby_qsort(ptr, RARRAY_LEN(ary)/2, 2*sizeof(VALUE),
1295 sort_by_cmp, (void *)ary));
1296 }
1297 if (RBASIC(ary)->klass) {
1298 rb_raise(rb_eRuntimeError, "sort_by reentered");
1299 }
1300 for (i=1; i<RARRAY_LEN(ary); i+=2) {
1301 RARRAY_ASET(ary, i/2, RARRAY_AREF(ary, i));
1302 }
1303 rb_ary_resize(ary, RARRAY_LEN(ary)/2);
1304 RBASIC_SET_CLASS_RAW(ary, rb_cArray);
1305
1306 return ary;
1307}
1308
1309#define ENUMFUNC(name) argc ? name##_eqq : rb_block_given_p() ? name##_iter_i : name##_i
1310
1311#define MEMO_ENUM_NEW(v1) (rb_check_arity(argc, 0, 1), MEMO_NEW((v1), (argc ? *argv : 0), 0))
1312
1313#define DEFINE_ENUMFUNCS(name) \
1314static VALUE enum_##name##_func(VALUE result, struct MEMO *memo); \
1315\
1316static VALUE \
1317name##_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, memo)) \
1318{ \
1319 return enum_##name##_func(rb_enum_values_pack(argc, argv), MEMO_CAST(memo)); \
1320} \
1321\
1322static VALUE \
1323name##_iter_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, memo)) \
1324{ \
1325 return enum_##name##_func(rb_yield_values2(argc, argv), MEMO_CAST(memo)); \
1326} \
1327\
1328static VALUE \
1329name##_eqq(RB_BLOCK_CALL_FUNC_ARGLIST(i, memo)) \
1330{ \
1331 ENUM_WANT_SVALUE(); \
1332 return enum_##name##_func(rb_funcallv(MEMO_CAST(memo)->v2, id_eqq, 1, &i), MEMO_CAST(memo)); \
1333} \
1334\
1335static VALUE \
1336enum_##name##_func(VALUE result, struct MEMO *memo)
1337
1338#define WARN_UNUSED_BLOCK(argc) do { \
1339 if ((argc) > 0 && rb_block_given_p()) { \
1340 rb_warn("given block not used"); \
1341 } \
1342} while (0)
1343
1344 DEFINE_ENUMFUNCS(all)
1345{
1346 if (!RTEST(result)) {
1347 MEMO_V1_SET(memo, Qfalse);
1348 rb_iter_break();
1349 }
1350 return Qnil;
1351}
1352
1353/*
1354 * call-seq:
1355 * enum.all? [{ |obj| block } ] -> true or false
1356 * enum.all?(pattern) -> true or false
1357 *
1358 * Passes each element of the collection to the given block. The method
1359 * returns <code>true</code> if the block never returns
1360 * <code>false</code> or <code>nil</code>. If the block is not given,
1361 * Ruby adds an implicit block of <code>{ |obj| obj }</code> which will
1362 * cause #all? to return +true+ when none of the collection members are
1363 * +false+ or +nil+.
1364 *
1365 * If instead a pattern is supplied, the method returns whether
1366 * <code>pattern === element</code> for every collection member.
1367 *
1368 * %w[ant bear cat].all? { |word| word.length >= 3 } #=> true
1369 * %w[ant bear cat].all? { |word| word.length >= 4 } #=> false
1370 * %w[ant bear cat].all?(/t/) #=> false
1371 * [1, 2i, 3.14].all?(Numeric) #=> true
1372 * [nil, true, 99].all? #=> false
1373 * [].all? #=> true
1374 *
1375 */
1376
1377static VALUE
1378enum_all(int argc, VALUE *argv, VALUE obj)
1379{
1380 struct MEMO *memo = MEMO_ENUM_NEW(Qtrue);
1381 WARN_UNUSED_BLOCK(argc);
1382 rb_block_call(obj, id_each, 0, 0, ENUMFUNC(all), (VALUE)memo);
1383 return memo->v1;
1384}
1385
1386 DEFINE_ENUMFUNCS(any)
1387{
1388 if (RTEST(result)) {
1389 MEMO_V1_SET(memo, Qtrue);
1390 rb_iter_break();
1391 }
1392 return Qnil;
1393}
1394
1395/*
1396 * call-seq:
1397 * enum.any? [{ |obj| block }] -> true or false
1398 * enum.any?(pattern) -> true or false
1399 *
1400 * Passes each element of the collection to the given block. The method
1401 * returns <code>true</code> if the block ever returns a value other
1402 * than <code>false</code> or <code>nil</code>. If the block is not
1403 * given, Ruby adds an implicit block of <code>{ |obj| obj }</code> that
1404 * will cause #any? to return +true+ if at least one of the collection
1405 * members is not +false+ or +nil+.
1406 *
1407 * If instead a pattern is supplied, the method returns whether
1408 * <code>pattern === element</code> for any collection member.
1409 *
1410 * %w[ant bear cat].any? { |word| word.length >= 3 } #=> true
1411 * %w[ant bear cat].any? { |word| word.length >= 4 } #=> true
1412 * %w[ant bear cat].any?(/d/) #=> false
1413 * [nil, true, 99].any?(Integer) #=> true
1414 * [nil, true, 99].any? #=> true
1415 * [].any? #=> false
1416 *
1417 */
1418
1419static VALUE
1420enum_any(int argc, VALUE *argv, VALUE obj)
1421{
1422 struct MEMO *memo = MEMO_ENUM_NEW(Qfalse);
1423 WARN_UNUSED_BLOCK(argc);
1424 rb_block_call(obj, id_each, 0, 0, ENUMFUNC(any), (VALUE)memo);
1425 return memo->v1;
1426}
1427
1428 DEFINE_ENUMFUNCS(one)
1429{
1430 if (RTEST(result)) {
1431 if (memo->v1 == Qundef) {
1432 MEMO_V1_SET(memo, Qtrue);
1433 }
1434 else if (memo->v1 == Qtrue) {
1435 MEMO_V1_SET(memo, Qfalse);
1436 rb_iter_break();
1437 }
1438 }
1439 return Qnil;
1440}
1441
1442 struct nmin_data {
1443 long n;
1444 long bufmax;
1445 long curlen;
1446 VALUE buf;
1447 VALUE limit;
1448 int (*cmpfunc)(const void *, const void *, void *);
1449 int rev: 1; /* max if 1 */
1450 int by: 1; /* min_by if 1 */
1451};
1452
1453static VALUE
1454cmpint_reenter_check(struct nmin_data *data, VALUE val)
1455{
1456 if (RBASIC(data->buf)->klass) {
1457 rb_raise(rb_eRuntimeError, "%s%s reentered",
1458 data->rev ? "max" : "min",
1459 data->by ? "_by" : "");
1460 }
1461 return val;
1462}
1463
1464static int
1465nmin_cmp(const void *ap, const void *bp, void *_data)
1466{
1467 struct cmp_opt_data cmp_opt = { 0, 0 };
1468 struct nmin_data *data = (struct nmin_data *)_data;
1469 VALUE a = *(const VALUE *)ap, b = *(const VALUE *)bp;
1470#define rb_cmpint(cmp, a, b) rb_cmpint(cmpint_reenter_check(data, (cmp)), a, b)
1471 return OPTIMIZED_CMP(a, b, cmp_opt);
1472#undef rb_cmpint
1473}
1474
1475static int
1476nmin_block_cmp(const void *ap, const void *bp, void *_data)
1477{
1478 struct nmin_data *data = (struct nmin_data *)_data;
1479 VALUE a = *(const VALUE *)ap, b = *(const VALUE *)bp;
1480 VALUE cmp = rb_yield_values(2, a, b);
1481 cmpint_reenter_check(data, cmp);
1482 return rb_cmpint(cmp, a, b);
1483}
1484
1485static void
1486nmin_filter(struct nmin_data *data)
1487{
1488 long n;
1489 VALUE *beg;
1490 int eltsize;
1491 long numelts;
1492
1493 long left, right;
1494 long store_index;
1495
1496 long i, j;
1497
1498 if (data->curlen <= data->n)
1499 return;
1500
1501 n = data->n;
1502 beg = RARRAY_PTR(data->buf);
1503 eltsize = data->by ? 2 : 1;
1504 numelts = data->curlen;
1505
1506 left = 0;
1507 right = numelts-1;
1508
1509#define GETPTR(i) (beg+(i)*eltsize)
1510
1511#define SWAP(i, j) do { \
1512 VALUE tmp[2]; \
1513 memcpy(tmp, GETPTR(i), sizeof(VALUE)*eltsize); \
1514 memcpy(GETPTR(i), GETPTR(j), sizeof(VALUE)*eltsize); \
1515 memcpy(GETPTR(j), tmp, sizeof(VALUE)*eltsize); \
1516} while (0)
1517
1518 while (1) {
1519 long pivot_index = left + (right-left)/2;
1520 long num_pivots = 1;
1521
1522 SWAP(pivot_index, right);
1523 pivot_index = right;
1524
1525 store_index = left;
1526 i = left;
1527 while (i <= right-num_pivots) {
1528 int c = data->cmpfunc(GETPTR(i), GETPTR(pivot_index), data);
1529 if (data->rev)
1530 c = -c;
1531 if (c == 0) {
1532 SWAP(i, right-num_pivots);
1533 num_pivots++;
1534 continue;
1535 }
1536 if (c < 0) {
1537 SWAP(i, store_index);
1538 store_index++;
1539 }
1540 i++;
1541 }
1542 j = store_index;
1543 for (i = right; right-num_pivots < i; i--) {
1544 if (i <= j)
1545 break;
1546 SWAP(j, i);
1547 j++;
1548 }
1549
1550 if (store_index <= n && n <= store_index+num_pivots)
1551 break;
1552
1553 if (n < store_index) {
1554 right = store_index-1;
1555 }
1556 else {
1557 left = store_index+num_pivots;
1558 }
1559 }
1560#undef GETPTR
1561#undef SWAP
1562
1563 data->limit = RARRAY_AREF(data->buf, store_index*eltsize); /* the last pivot */
1564 data->curlen = data->n;
1565 rb_ary_resize(data->buf, data->n * eltsize);
1566}
1567
1568static VALUE
1569nmin_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, _data))
1570{
1571 struct nmin_data *data = (struct nmin_data *)_data;
1572 VALUE cmpv;
1573
1574 ENUM_WANT_SVALUE();
1575
1576 if (data->by)
1577 cmpv = enum_yield(argc, i);
1578 else
1579 cmpv = i;
1580
1581 if (data->limit != Qundef) {
1582 int c = data->cmpfunc(&cmpv, &data->limit, data);
1583 if (data->rev)
1584 c = -c;
1585 if (c >= 0)
1586 return Qnil;
1587 }
1588
1589 if (data->by)
1590 rb_ary_push(data->buf, cmpv);
1591 rb_ary_push(data->buf, i);
1592
1593 data->curlen++;
1594
1595 if (data->curlen == data->bufmax) {
1596 nmin_filter(data);
1597 }
1598
1599 return Qnil;
1600}
1601
1602 VALUE
1603rb_nmin_run(VALUE obj, VALUE num, int by, int rev, int ary)
1604{
1605 VALUE result;
1606 struct nmin_data data;
1607
1608 data.n = NUM2LONG(num);
1609 if (data.n < 0)
1610 rb_raise(rb_eArgError, "negative size (%ld)", data.n);
1611 if (data.n == 0)
1612 return rb_ary_new2(0);
1613 if (LONG_MAX/4/(by ? 2 : 1) < data.n)
1614 rb_raise(rb_eArgError, "too big size");
1615 data.bufmax = data.n * 4;
1616 data.curlen = 0;
1617 data.buf = rb_ary_tmp_new(data.bufmax * (by ? 2 : 1));
1618 data.limit = Qundef;
1619 data.cmpfunc = by ? nmin_cmp :
1620 rb_block_given_p() ? nmin_block_cmp :
1621 nmin_cmp;
1622 data.rev = rev;
1623 data.by = by;
1624 if (ary) {
1625 long i;
1626 for (i = 0; i < RARRAY_LEN(obj); i++) {
1627 VALUE args[1];
1628 args[0] = RARRAY_AREF(obj, i);
1629 nmin_i(obj, (VALUE)&data, 1, args, Qundef);
1630 }
1631 }
1632 else {
1633 rb_block_call(obj, id_each, 0, 0, nmin_i, (VALUE)&data);
1634 }
1635 nmin_filter(&data);
1636 result = data.buf;
1637 if (by) {
1638 long i;
1639 RARRAY_PTR_USE(result, ptr, {
1640 ruby_qsort(ptr,
1641 RARRAY_LEN(result)/2,
1642 sizeof(VALUE)*2,
1643 data.cmpfunc, (void *)&data);
1644 for (i=1; i<RARRAY_LEN(result); i+=2) {
1645 ptr[i/2] = ptr[i];
1646 }
1647 });
1648 rb_ary_resize(result, RARRAY_LEN(result)/2);
1649 }
1650 else {
1651 RARRAY_PTR_USE(result, ptr, {
1652 ruby_qsort(ptr, RARRAY_LEN(result), sizeof(VALUE),
1653 data.cmpfunc, (void *)&data);
1654 });
1655 }
1656 if (rev) {
1657 rb_ary_reverse(result);
1658 }
1659 RBASIC_SET_CLASS(result, rb_cArray);
1660 return result;
1661
1662}
1663
1664/*
1665 * call-seq:
1666 * enum.one? [{ |obj| block }] -> true or false
1667 * enum.one?(pattern) -> true or false
1668 *
1669 * Passes each element of the collection to the given block. The method
1670 * returns <code>true</code> if the block returns <code>true</code>
1671 * exactly once. If the block is not given, <code>one?</code> will return
1672 * <code>true</code> only if exactly one of the collection members is
1673 * true.
1674 *
1675 * If instead a pattern is supplied, the method returns whether
1676 * <code>pattern === element</code> for exactly one collection member.
1677 *
1678 * %w{ant bear cat}.one? { |word| word.length == 4 } #=> true
1679 * %w{ant bear cat}.one? { |word| word.length > 4 } #=> false
1680 * %w{ant bear cat}.one? { |word| word.length < 4 } #=> false
1681 * %w{ant bear cat}.one?(/t/) #=> false
1682 * [ nil, true, 99 ].one? #=> false
1683 * [ nil, true, false ].one? #=> true
1684 * [ nil, true, 99 ].one?(Integer) #=> true
1685 * [].one? #=> false
1686 *
1687 */
1688static VALUE
1689enum_one(int argc, VALUE *argv, VALUE obj)
1690{
1691 struct MEMO *memo = MEMO_ENUM_NEW(Qundef);
1692 VALUE result;
1693
1694 WARN_UNUSED_BLOCK(argc);
1695 rb_block_call(obj, id_each, 0, 0, ENUMFUNC(one), (VALUE)memo);
1696 result = memo->v1;
1697 if (result == Qundef) return Qfalse;
1698 return result;
1699}
1700
1701 DEFINE_ENUMFUNCS(none)
1702{
1703 if (RTEST(result)) {
1704 MEMO_V1_SET(memo, Qfalse);
1705 rb_iter_break();
1706 }
1707 return Qnil;
1708}
1709
1710/*
1711 * call-seq:
1712 * enum.none? [{ |obj| block }] -> true or false
1713 * enum.none?(pattern) -> true or false
1714 *
1715 * Passes each element of the collection to the given block. The method
1716 * returns <code>true</code> if the block never returns <code>true</code>
1717 * for all elements. If the block is not given, <code>none?</code> will return
1718 * <code>true</code> only if none of the collection members is true.
1719 *
1720 * If instead a pattern is supplied, the method returns whether
1721 * <code>pattern === element</code> for none of the collection members.
1722 *
1723 * %w{ant bear cat}.none? { |word| word.length == 5 } #=> true
1724 * %w{ant bear cat}.none? { |word| word.length >= 4 } #=> false
1725 * %w{ant bear cat}.none?(/d/) #=> true
1726 * [1, 3.14, 42].none?(Float) #=> false
1727 * [].none? #=> true
1728 * [nil].none? #=> true
1729 * [nil, false].none? #=> true
1730 * [nil, false, true].none? #=> false
1731 */
1732static VALUE
1733enum_none(int argc, VALUE *argv, VALUE obj)
1734{
1735 struct MEMO *memo = MEMO_ENUM_NEW(Qtrue);
1736
1737 WARN_UNUSED_BLOCK(argc);
1738 rb_block_call(obj, id_each, 0, 0, ENUMFUNC(none), (VALUE)memo);
1739 return memo->v1;
1740}
1741
1742 struct min_t {
1743 VALUE min;
1744 struct cmp_opt_data cmp_opt;
1745};
1746
1747static VALUE
1748min_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, args))
1749{
1750 struct min_t *memo = MEMO_FOR(struct min_t, args);
1751
1752 ENUM_WANT_SVALUE();
1753
1754 if (memo->min == Qundef) {
1755 memo->min = i;
1756 }
1757 else {
1758 if (OPTIMIZED_CMP(i, memo->min, memo->cmp_opt) < 0) {
1759 memo->min = i;
1760 }
1761 }
1762 return Qnil;
1763}
1764
1765static VALUE
1766min_ii(RB_BLOCK_CALL_FUNC_ARGLIST(i, args))
1767{
1768 VALUE cmp;
1769 struct min_t *memo = MEMO_FOR(struct min_t, args);
1770
1771 ENUM_WANT_SVALUE();
1772
1773 if (memo->min == Qundef) {
1774 memo->min = i;
1775 }
1776 else {
1777 cmp = rb_yield_values(2, i, memo->min);
1778 if (rb_cmpint(cmp, i, memo->min) < 0) {
1779 memo->min = i;
1780 }
1781 }
1782 return Qnil;
1783}
1784
1785
1786/*
1787 * call-seq:
1788 * enum.min -> obj
1789 * enum.min { |a, b| block } -> obj
1790 * enum.min(n) -> array
1791 * enum.min(n) { |a, b| block } -> array
1792 *
1793 * Returns the object in _enum_ with the minimum value. The
1794 * first form assumes all objects implement <code><=></code>;
1795 * the second uses the block to return <em>a <=> b</em>.
1796 *
1797 * a = %w(albatross dog horse)
1798 * a.min #=> "albatross"
1799 * a.min { |a, b| a.length <=> b.length } #=> "dog"
1800 *
1801 * If the +n+ argument is given, minimum +n+ elements are returned
1802 * as a sorted array.
1803 *
1804 * a = %w[albatross dog horse]
1805 * a.min(2) #=> ["albatross", "dog"]
1806 * a.min(2) {|a, b| a.length <=> b.length } #=> ["dog", "horse"]
1807 * [5, 1, 3, 4, 2].min(3) #=> [1, 2, 3]
1808 */
1809
1810static VALUE
1811enum_min(int argc, VALUE *argv, VALUE obj)
1812{
1813 VALUE memo;
1814 struct min_t *m = NEW_CMP_OPT_MEMO(struct min_t, memo);
1815 VALUE result;
1816 VALUE num;
1817
1818 if (rb_check_arity(argc, 0, 1) && !NIL_P(num = argv[0]))
1819 return rb_nmin_run(obj, num, 0, 0, 0);
1820
1821 m->min = Qundef;
1822 m->cmp_opt.opt_methods = 0;
1823 m->cmp_opt.opt_inited = 0;
1824 if (rb_block_given_p()) {
1825 rb_block_call(obj, id_each, 0, 0, min_ii, memo);
1826 }
1827 else {
1828 rb_block_call(obj, id_each, 0, 0, min_i, memo);
1829 }
1830 result = m->min;
1831 if (result == Qundef) return Qnil;
1832 return result;
1833}
1834
1835 struct max_t {
1836 VALUE max;
1837 struct cmp_opt_data cmp_opt;
1838};
1839
1840static VALUE
1841max_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, args))
1842{
1843 struct max_t *memo = MEMO_FOR(struct max_t, args);
1844
1845 ENUM_WANT_SVALUE();
1846
1847 if (memo->max == Qundef) {
1848 memo->max = i;
1849 }
1850 else {
1851 if (OPTIMIZED_CMP(i, memo->max, memo->cmp_opt) > 0) {
1852 memo->max = i;
1853 }
1854 }
1855 return Qnil;
1856}
1857
1858static VALUE
1859max_ii(RB_BLOCK_CALL_FUNC_ARGLIST(i, args))
1860{
1861 struct max_t *memo = MEMO_FOR(struct max_t, args);
1862 VALUE cmp;
1863
1864 ENUM_WANT_SVALUE();
1865
1866 if (memo->max == Qundef) {
1867 memo->max = i;
1868 }
1869 else {
1870 cmp = rb_yield_values(2, i, memo->max);
1871 if (rb_cmpint(cmp, i, memo->max) > 0) {
1872 memo->max = i;
1873 }
1874 }
1875 return Qnil;
1876}
1877
1878/*
1879 * call-seq:
1880 * enum.max -> obj
1881 * enum.max { |a, b| block } -> obj
1882 * enum.max(n) -> array
1883 * enum.max(n) { |a, b| block } -> array
1884 *
1885 * Returns the object in _enum_ with the maximum value. The
1886 * first form assumes all objects implement <code><=></code>;
1887 * the second uses the block to return <em>a <=> b</em>.
1888 *
1889 * a = %w(albatross dog horse)
1890 * a.max #=> "horse"
1891 * a.max { |a, b| a.length <=> b.length } #=> "albatross"
1892 *
1893 * If the +n+ argument is given, maximum +n+ elements are returned
1894 * as an array, sorted in descending order.
1895 *
1896 * a = %w[albatross dog horse]
1897 * a.max(2) #=> ["horse", "dog"]
1898 * a.max(2) {|a, b| a.length <=> b.length } #=> ["albatross", "horse"]
1899 * [5, 1, 3, 4, 2].max(3) #=> [5, 4, 3]
1900 */
1901
1902static VALUE
1903enum_max(int argc, VALUE *argv, VALUE obj)
1904{
1905 VALUE memo;
1906 struct max_t *m = NEW_CMP_OPT_MEMO(struct max_t, memo);
1907 VALUE result;
1908 VALUE num;
1909
1910 if (rb_check_arity(argc, 0, 1) && !NIL_P(num = argv[0]))
1911 return rb_nmin_run(obj, num, 0, 1, 0);
1912
1913 m->max = Qundef;
1914 m->cmp_opt.opt_methods = 0;
1915 m->cmp_opt.opt_inited = 0;
1916 if (rb_block_given_p()) {
1917 rb_block_call(obj, id_each, 0, 0, max_ii, (VALUE)memo);
1918 }
1919 else {
1920 rb_block_call(obj, id_each, 0, 0, max_i, (VALUE)memo);
1921 }
1922 result = m->max;
1923 if (result == Qundef) return Qnil;
1924 return result;
1925}
1926
1927 struct minmax_t {
1928 VALUE min;
1929 VALUE max;
1930 VALUE last;
1931 struct cmp_opt_data cmp_opt;
1932};
1933
1934static void
1935minmax_i_update(VALUE i, VALUE j, struct minmax_t *memo)
1936{
1937 int n;
1938
1939 if (memo->min == Qundef) {
1940 memo->min = i;
1941 memo->max = j;
1942 }
1943 else {
1944 n = OPTIMIZED_CMP(i, memo->min, memo->cmp_opt);
1945 if (n < 0) {
1946 memo->min = i;
1947 }
1948 n = OPTIMIZED_CMP(j, memo->max, memo->cmp_opt);
1949 if (n > 0) {
1950 memo->max = j;
1951 }
1952 }
1953}
1954
1955static VALUE
1956minmax_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, _memo))
1957{
1958 struct minmax_t *memo = MEMO_FOR(struct minmax_t, _memo);
1959 int n;
1960 VALUE j;
1961
1962 ENUM_WANT_SVALUE();
1963
1964 if (memo->last == Qundef) {
1965 memo->last = i;
1966 return Qnil;
1967 }
1968 j = memo->last;
1969 memo->last = Qundef;
1970
1971 n = OPTIMIZED_CMP(j, i, memo->cmp_opt);
1972 if (n == 0)
1973 i = j;
1974 else if (n < 0) {
1975 VALUE tmp;
1976 tmp = i;
1977 i = j;
1978 j = tmp;
1979 }
1980
1981 minmax_i_update(i, j, memo);
1982
1983 return Qnil;
1984}
1985
1986static void
1987minmax_ii_update(VALUE i, VALUE j, struct minmax_t *memo)
1988{
1989 int n;
1990
1991 if (memo->min == Qundef) {
1992 memo->min = i;
1993 memo->max = j;
1994 }
1995 else {
1996 n = rb_cmpint(rb_yield_values(2, i, memo->min), i, memo->min);
1997 if (n < 0) {
1998 memo->min = i;
1999 }
2000 n = rb_cmpint(rb_yield_values(2, j, memo->max), j, memo->max);
2001 if (n > 0) {
2002 memo->max = j;
2003 }
2004 }
2005}
2006
2007static VALUE
2008minmax_ii(RB_BLOCK_CALL_FUNC_ARGLIST(i, _memo))
2009{
2010 struct minmax_t *memo = MEMO_FOR(struct minmax_t, _memo);
2011 int n;
2012 VALUE j;
2013
2014 ENUM_WANT_SVALUE();
2015
2016 if (memo->last == Qundef) {
2017 memo->last = i;
2018 return Qnil;
2019 }
2020 j = memo->last;
2021 memo->last = Qundef;
2022
2023 n = rb_cmpint(rb_yield_values(2, j, i), j, i);
2024 if (n == 0)
2025 i = j;
2026 else if (n < 0) {
2027 VALUE tmp;
2028 tmp = i;
2029 i = j;
2030 j = tmp;
2031 }
2032
2033 minmax_ii_update(i, j, memo);
2034
2035 return Qnil;
2036}
2037
2038/*
2039 * call-seq:
2040 * enum.minmax -> [min, max]
2041 * enum.minmax { |a, b| block } -> [min, max]
2042 *
2043 * Returns a two element array which contains the minimum and the
2044 * maximum value in the enumerable. The first form assumes all
2045 * objects implement <code><=></code>; the second uses the
2046 * block to return <em>a <=> b</em>.
2047 *
2048 * a = %w(albatross dog horse)
2049 * a.minmax #=> ["albatross", "horse"]
2050 * a.minmax { |a, b| a.length <=> b.length } #=> ["dog", "albatross"]
2051 */
2052
2053static VALUE
2054enum_minmax(VALUE obj)
2055{
2056 VALUE memo;
2057 struct minmax_t *m = NEW_CMP_OPT_MEMO(struct minmax_t, memo);
2058
2059 m->min = Qundef;
2060 m->last = Qundef;
2061 m->cmp_opt.opt_methods = 0;
2062 m->cmp_opt.opt_inited = 0;
2063 if (rb_block_given_p()) {
2064 rb_block_call(obj, id_each, 0, 0, minmax_ii, memo);
2065 if (m->last != Qundef)
2066 minmax_ii_update(m->last, m->last, m);
2067 }
2068 else {
2069 rb_block_call(obj, id_each, 0, 0, minmax_i, memo);
2070 if (m->last != Qundef)
2071 minmax_i_update(m->last, m->last, m);
2072 }
2073 if (m->min != Qundef) {
2074 return rb_assoc_new(m->min, m->max);
2075 }
2076 return rb_assoc_new(Qnil, Qnil);
2077}
2078
2079static VALUE
2080min_by_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, args))
2081{
2082 struct cmp_opt_data cmp_opt = { 0, 0 };
2083 struct MEMO *memo = MEMO_CAST(args);
2084 VALUE v;
2085
2086 ENUM_WANT_SVALUE();
2087
2088 v = enum_yield(argc, i);
2089 if (memo->v1 == Qundef) {
2090 MEMO_V1_SET(memo, v);
2091 MEMO_V2_SET(memo, i);
2092 }
2093 else if (OPTIMIZED_CMP(v, memo->v1, cmp_opt) < 0) {
2094 MEMO_V1_SET(memo, v);
2095 MEMO_V2_SET(memo, i);
2096 }
2097 return Qnil;
2098}
2099
2100/*
2101 * call-seq:
2102 * enum.min_by {|obj| block } -> obj
2103 * enum.min_by -> an_enumerator
2104 * enum.min_by(n) {|obj| block } -> array
2105 * enum.min_by(n) -> an_enumerator
2106 *
2107 * Returns the object in <i>enum</i> that gives the minimum
2108 * value from the given block.
2109 *
2110 * If no block is given, an enumerator is returned instead.
2111 *
2112 * a = %w(albatross dog horse)
2113 * a.min_by { |x| x.length } #=> "dog"
2114 *
2115 * If the +n+ argument is given, minimum +n+ elements are returned
2116 * as an array. These +n+ elements are sorted by the value from the
2117 * given block.
2118 *
2119 * a = %w[albatross dog horse]
2120 * p a.min_by(2) {|x| x.length } #=> ["dog", "horse"]
2121 */
2122
2123static VALUE
2124enum_min_by(int argc, VALUE *argv, VALUE obj)
2125{
2126 struct MEMO *memo;
2127 VALUE num;
2128
2129 rb_check_arity(argc, 0, 1);
2130
2131 RETURN_SIZED_ENUMERATOR(obj, argc, argv, enum_size);
2132
2133 if (argc && !NIL_P(num = argv[0]))
2134 return rb_nmin_run(obj, num, 1, 0, 0);
2135
2136 memo = MEMO_NEW(Qundef, Qnil, 0);
2137 rb_block_call(obj, id_each, 0, 0, min_by_i, (VALUE)memo);
2138 return memo->v2;
2139}
2140
2141static VALUE
2142max_by_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, args))
2143{
2144 struct cmp_opt_data cmp_opt = { 0, 0 };
2145 struct MEMO *memo = MEMO_CAST(args);
2146 VALUE v;
2147
2148 ENUM_WANT_SVALUE();
2149
2150 v = enum_yield(argc, i);
2151 if (memo->v1 == Qundef) {
2152 MEMO_V1_SET(memo, v);
2153 MEMO_V2_SET(memo, i);
2154 }
2155 else if (OPTIMIZED_CMP(v, memo->v1, cmp_opt) > 0) {
2156 MEMO_V1_SET(memo, v);
2157 MEMO_V2_SET(memo, i);
2158 }
2159 return Qnil;
2160}
2161
2162/*
2163 * call-seq:
2164 * enum.max_by {|obj| block } -> obj
2165 * enum.max_by -> an_enumerator
2166 * enum.max_by(n) {|obj| block } -> obj
2167 * enum.max_by(n) -> an_enumerator
2168 *
2169 * Returns the object in <i>enum</i> that gives the maximum
2170 * value from the given block.
2171 *
2172 * If no block is given, an enumerator is returned instead.
2173 *
2174 * a = %w(albatross dog horse)
2175 * a.max_by { |x| x.length } #=> "albatross"
2176 *
2177 * If the +n+ argument is given, maximum +n+ elements are returned
2178 * as an array. These +n+ elements are sorted by the value from the
2179 * given block, in descending order.
2180 *
2181 * a = %w[albatross dog horse]
2182 * a.max_by(2) {|x| x.length } #=> ["albatross", "horse"]
2183 *
2184 * enum.max_by(n) can be used to implement weighted random sampling.
2185 * Following example implements and use Enumerable#wsample.
2186 *
2187 * module Enumerable
2188 * # weighted random sampling.
2189 * #
2190 * # Pavlos S. Efraimidis, Paul G. Spirakis
2191 * # Weighted random sampling with a reservoir
2192 * # Information Processing Letters
2193 * # Volume 97, Issue 5 (16 March 2006)
2194 * def wsample(n)
2195 * self.max_by(n) {|v| rand ** (1.0/yield(v)) }
2196 * end
2197 * end
2198 * e = (-20..20).to_a*10000
2199 * a = e.wsample(20000) {|x|
2200 * Math.exp(-(x/5.0)**2) # normal distribution
2201 * }
2202 * # a is 20000 samples from e.
2203 * p a.length #=> 20000
2204 * h = a.group_by {|x| x }
2205 * -10.upto(10) {|x| puts "*" * (h[x].length/30.0).to_i if h[x] }
2206 * #=> *
2207 * # ***
2208 * # ******
2209 * # ***********
2210 * # ******************
2211 * # *****************************
2212 * # *****************************************
2213 * # ****************************************************
2214 * # ***************************************************************
2215 * # ********************************************************************
2216 * # ***********************************************************************
2217 * # ***********************************************************************
2218 * # **************************************************************
2219 * # ****************************************************
2220 * # ***************************************
2221 * # ***************************
2222 * # ******************
2223 * # ***********
2224 * # *******
2225 * # ***
2226 * # *
2227 *
2228 */
2229
2230static VALUE
2231enum_max_by(int argc, VALUE *argv, VALUE obj)
2232{
2233 struct MEMO *memo;
2234 VALUE num;
2235
2236 rb_check_arity(argc, 0, 1);
2237
2238 RETURN_SIZED_ENUMERATOR(obj, argc, argv, enum_size);
2239
2240 if (argc && !NIL_P(num = argv[0]))
2241 return rb_nmin_run(obj, num, 1, 1, 0);
2242
2243 memo = MEMO_NEW(Qundef, Qnil, 0);
2244 rb_block_call(obj, id_each, 0, 0, max_by_i, (VALUE)memo);
2245 return memo->v2;
2246}
2247
2248 struct minmax_by_t {
2249 VALUE min_bv;
2250 VALUE max_bv;
2251 VALUE min;
2252 VALUE max;
2253 VALUE last_bv;
2254 VALUE last;
2255};
2256
2257static void
2258minmax_by_i_update(VALUE v1, VALUE v2, VALUE i1, VALUE i2, struct minmax_by_t *memo)
2259{
2260 struct cmp_opt_data cmp_opt = { 0, 0 };
2261
2262 if (memo->min_bv == Qundef) {
2263 memo->min_bv = v1;
2264 memo->max_bv = v2;
2265 memo->min = i1;
2266 memo->max = i2;
2267 }
2268 else {
2269 if (OPTIMIZED_CMP(v1, memo->min_bv, cmp_opt) < 0) {
2270 memo->min_bv = v1;
2271 memo->min = i1;
2272 }
2273 if (OPTIMIZED_CMP(v2, memo->max_bv, cmp_opt) > 0) {
2274 memo->max_bv = v2;
2275 memo->max = i2;
2276 }
2277 }
2278}
2279
2280static VALUE
2281minmax_by_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, _memo))
2282{
2283 struct cmp_opt_data cmp_opt = { 0, 0 };
2284 struct minmax_by_t *memo = MEMO_FOR(struct minmax_by_t, _memo);
2285 VALUE vi, vj, j;
2286 int n;
2287
2288 ENUM_WANT_SVALUE();
2289
2290 vi = enum_yield(argc, i);
2291
2292 if (memo->last_bv == Qundef) {
2293 memo->last_bv = vi;
2294 memo->last = i;
2295 return Qnil;
2296 }
2297 vj = memo->last_bv;
2298 j = memo->last;
2299 memo->last_bv = Qundef;
2300
2301 n = OPTIMIZED_CMP(vj, vi, cmp_opt);
2302 if (n == 0) {
2303 i = j;
2304 vi = vj;
2305 }
2306 else if (n < 0) {
2307 VALUE tmp;
2308 tmp = i;
2309 i = j;
2310 j = tmp;
2311 tmp = vi;
2312 vi = vj;
2313 vj = tmp;
2314 }
2315
2316 minmax_by_i_update(vi, vj, i, j, memo);
2317
2318 return Qnil;
2319}
2320
2321/*
2322 * call-seq:
2323 * enum.minmax_by { |obj| block } -> [min, max]
2324 * enum.minmax_by -> an_enumerator
2325 *
2326 * Returns a two element array containing the objects in
2327 * <i>enum</i> that correspond to the minimum and maximum values respectively
2328 * from the given block.
2329 *
2330 * If no block is given, an enumerator is returned instead.
2331 *
2332 * a = %w(albatross dog horse)
2333 * a.minmax_by { |x| x.length } #=> ["dog", "albatross"]
2334 */
2335
2336static VALUE
2337enum_minmax_by(VALUE obj)
2338{
2339 VALUE memo;
2340 struct minmax_by_t *m = NEW_MEMO_FOR(struct minmax_by_t, memo);
2341
2342 RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);
2343
2344 m->min_bv = Qundef;
2345 m->max_bv = Qundef;
2346 m->min = Qnil;
2347 m->max = Qnil;
2348 m->last_bv = Qundef;
2349 m->last = Qundef;
2350 rb_block_call(obj, id_each, 0, 0, minmax_by_i, memo);
2351 if (m->last_bv != Qundef)
2352 minmax_by_i_update(m->last_bv, m->last_bv, m->last, m->last, m);
2353 m = MEMO_FOR(struct minmax_by_t, memo);
2354 return rb_assoc_new(m->min, m->max);
2355}
2356
2357static VALUE
2358member_i(RB_BLOCK_CALL_FUNC_ARGLIST(iter, args))
2359{
2360 struct MEMO *memo = MEMO_CAST(args);
2361
2362 if (rb_equal(rb_enum_values_pack(argc, argv), memo->v1)) {
2363 MEMO_V2_SET(memo, Qtrue);
2364 rb_iter_break();
2365 }
2366 return Qnil;
2367}
2368
2369/*
2370 * call-seq:
2371 * enum.include?(obj) -> true or false
2372 * enum.member?(obj) -> true or false
2373 *
2374 * Returns <code>true</code> if any member of <i>enum</i> equals
2375 * <i>obj</i>. Equality is tested using <code>==</code>.
2376 *
2377 * (1..10).include? 5 #=> true
2378 * (1..10).include? 15 #=> false
2379 * (1..10).member? 5 #=> true
2380 * (1..10).member? 15 #=> false
2381 *
2382 */
2383
2384static VALUE
2385enum_member(VALUE obj, VALUE val)
2386{
2387 struct MEMO *memo = MEMO_NEW(val, Qfalse, 0);
2388
2389 rb_block_call(obj, id_each, 0, 0, member_i, (VALUE)memo);
2390 return memo->v2;
2391}
2392
2393static VALUE
2394each_with_index_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, memo))
2395{
2396 struct MEMO *m = MEMO_CAST(memo);
2397 VALUE n = imemo_count_value(m);
2398
2399 imemo_count_up(m);
2400 return rb_yield_values(2, rb_enum_values_pack(argc, argv), n);
2401}
2402
2403/*
2404 * call-seq:
2405 * enum.each_with_index(*args) { |obj, i| block } -> enum
2406 * enum.each_with_index(*args) -> an_enumerator
2407 *
2408 * Calls <em>block</em> with two arguments, the item and its index,
2409 * for each item in <i>enum</i>. Given arguments are passed through
2410 * to #each().
2411 *
2412 * If no block is given, an enumerator is returned instead.
2413 *
2414 * hash = Hash.new
2415 * %w(cat dog wombat).each_with_index { |item, index|
2416 * hash[item] = index
2417 * }
2418 * hash #=> {"cat"=>0, "dog"=>1, "wombat"=>2}
2419 *
2420 */
2421
2422static VALUE
2423enum_each_with_index(int argc, VALUE *argv, VALUE obj)
2424{
2425 struct MEMO *memo;
2426
2427 RETURN_SIZED_ENUMERATOR(obj, argc, argv, enum_size);
2428
2429 memo = MEMO_NEW(0, 0, 0);
2430 rb_block_call(obj, id_each, argc, argv, each_with_index_i, (VALUE)memo);
2431 return obj;
2432}
2433
2434
2435/*
2436 * call-seq:
2437 * enum.reverse_each(*args) { |item| block } -> enum
2438 * enum.reverse_each(*args) -> an_enumerator
2439 *
2440 * Builds a temporary array and traverses that array in reverse order.
2441 *
2442 * If no block is given, an enumerator is returned instead.
2443 *
2444 * (1..3).reverse_each { |v| p v }
2445 *
2446 * produces:
2447 *
2448 * 3
2449 * 2
2450 * 1
2451 */
2452
2453static VALUE
2454enum_reverse_each(int argc, VALUE *argv, VALUE obj)
2455{
2456 VALUE ary;
2457 long len;
2458
2459 RETURN_SIZED_ENUMERATOR(obj, argc, argv, enum_size);
2460
2461 ary = enum_to_a(argc, argv, obj);
2462
2463 len = RARRAY_LEN(ary);
2464 while (len--) {
2465 long nlen;
2466 rb_yield(RARRAY_AREF(ary, len));
2467 nlen = RARRAY_LEN(ary);
2468 if (nlen < len) {
2469 len = nlen;
2470 }
2471 }
2472
2473 return obj;
2474}
2475
2476
2477static VALUE
2478each_val_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, p))
2479{
2480 ENUM_WANT_SVALUE();
2481 enum_yield(argc, i);
2482 return Qnil;
2483}
2484
2485/*
2486 * call-seq:
2487 * enum.each_entry { |obj| block } -> enum
2488 * enum.each_entry -> an_enumerator
2489 *
2490 * Calls <i>block</i> once for each element in +self+, passing that
2491 * element as a parameter, converting multiple values from yield to an
2492 * array.
2493 *
2494 * If no block is given, an enumerator is returned instead.
2495 *
2496 * class Foo
2497 * include Enumerable
2498 * def each
2499 * yield 1
2500 * yield 1, 2
2501 * yield
2502 * end
2503 * end
2504 * Foo.new.each_entry{ |o| p o }
2505 *
2506 * produces:
2507 *
2508 * 1
2509 * [1, 2]
2510 * nil
2511 *
2512 */
2513
2514static VALUE
2515enum_each_entry(int argc, VALUE *argv, VALUE obj)
2516{
2517 RETURN_SIZED_ENUMERATOR(obj, argc, argv, enum_size);
2518 rb_block_call(obj, id_each, argc, argv, each_val_i, 0);
2519 return obj;
2520}
2521
2522static VALUE
2523add_int(VALUE x, long n)
2524{
2525 const VALUE y = LONG2NUM(n);
2526 if (RB_INTEGER_TYPE_P(x)) return rb_int_plus(x, y);
2527 return rb_funcallv(x, '+', 1, &y);
2528}
2529
2530static VALUE
2531div_int(VALUE x, long n)
2532{
2533 const VALUE y = LONG2NUM(n);
2534 if (RB_INTEGER_TYPE_P(x)) return rb_int_idiv(x, y);
2535 return rb_funcallv(x, id_div, 1, &y);
2536}
2537
2538#define dont_recycle_block_arg(arity) ((arity) == 1 || (arity) < 0)
2539
2540static VALUE
2541each_slice_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, m))
2542{
2543 struct MEMO *memo = MEMO_CAST(m);
2544 VALUE ary = memo->v1;
2545 VALUE v = Qnil;
2546 long size = memo->u3.cnt;
2547 ENUM_WANT_SVALUE();
2548
2549 rb_ary_push(ary, i);
2550
2551 if (RARRAY_LEN(ary) == size) {
2552 v = rb_yield(ary);
2553
2554 if (memo->v2) {
2555 MEMO_V1_SET(memo, rb_ary_new2(size));
2556 }
2557 else {
2558 rb_ary_clear(ary);
2559 }
2560 }
2561
2562 return v;
2563}
2564
2565static VALUE
2566enum_each_slice_size(VALUE obj, VALUE args, VALUE eobj)
2567{
2568 VALUE n, size;
2569 long slice_size = NUM2LONG(RARRAY_AREF(args, 0));
2570 ID infinite_p;
2571 CONST_ID(infinite_p, "infinite?");
2572 if (slice_size <= 0) rb_raise(rb_eArgError, "invalid slice size");
2573
2574 size = enum_size(obj, 0, 0);
2575 if (size == Qnil) return Qnil;
2576 if (RB_FLOAT_TYPE_P(size) && RTEST(rb_funcall(size, infinite_p, 0))) {
2577 return size;
2578 }
2579
2580 n = add_int(size, slice_size-1);
2581 return div_int(n, slice_size);
2582}
2583
2584/*
2585 * call-seq:
2586 * enum.each_slice(n) { ... } -> nil
2587 * enum.each_slice(n) -> an_enumerator
2588 *
2589 * Iterates the given block for each slice of <n> elements. If no
2590 * block is given, returns an enumerator.
2591 *
2592 * (1..10).each_slice(3) { |a| p a }
2593 * # outputs below
2594 * [1, 2, 3]
2595 * [4, 5, 6]
2596 * [7, 8, 9]
2597 * [10]
2598 *
2599 */
2600static VALUE
2601enum_each_slice(VALUE obj, VALUE n)
2602{
2603 long size = NUM2LONG(n);
2604 VALUE ary;
2605 struct MEMO *memo;
2606 int arity;
2607
2608 if (size <= 0) rb_raise(rb_eArgError, "invalid slice size");
2609 RETURN_SIZED_ENUMERATOR(obj, 1, &n, enum_each_slice_size);
2610 size = limit_by_enum_size(obj, size);
2611 ary = rb_ary_new2(size);
2612 arity = rb_block_arity();
2613 memo = MEMO_NEW(ary, dont_recycle_block_arg(arity), size);
2614 rb_block_call(obj, id_each, 0, 0, each_slice_i, (VALUE)memo);
2615 ary = memo->v1;
2616 if (RARRAY_LEN(ary) > 0) rb_yield(ary);
2617
2618 return Qnil;
2619}
2620
2621static VALUE
2622each_cons_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, args))
2623{
2624 struct MEMO *memo = MEMO_CAST(args);
2625 VALUE ary = memo->v1;
2626 VALUE v = Qnil;
2627 long size = memo->u3.cnt;
2628 ENUM_WANT_SVALUE();
2629
2630 if (RARRAY_LEN(ary) == size) {
2631 rb_ary_shift(ary);
2632 }
2633 rb_ary_push(ary, i);
2634 if (RARRAY_LEN(ary) == size) {
2635 if (memo->v2) {
2636 ary = rb_ary_dup(ary);
2637 }
2638 v = rb_yield(ary);
2639 }
2640 return v;
2641}
2642
2643static VALUE
2644enum_each_cons_size(VALUE obj, VALUE args, VALUE eobj)
2645{
2646 struct cmp_opt_data cmp_opt = { 0, 0 };
2647 const VALUE zero = LONG2FIX(0);
2648 VALUE n, size;
2649 long cons_size = NUM2LONG(RARRAY_AREF(args, 0));
2650 if (cons_size <= 0) rb_raise(rb_eArgError, "invalid size");
2651
2652 size = enum_size(obj, 0, 0);
2653 if (size == Qnil) return Qnil;
2654
2655 n = add_int(size, 1 - cons_size);
2656 return (OPTIMIZED_CMP(n, zero, cmp_opt) == -1) ? zero : n;
2657}
2658
2659/*
2660 * call-seq:
2661 * enum.each_cons(n) { ... } -> nil
2662 * enum.each_cons(n) -> an_enumerator
2663 *
2664 * Iterates the given block for each array of consecutive <n>
2665 * elements. If no block is given, returns an enumerator.
2666 *
2667 * e.g.:
2668 * (1..10).each_cons(3) { |a| p a }
2669 * # outputs below
2670 * [1, 2, 3]
2671 * [2, 3, 4]
2672 * [3, 4, 5]
2673 * [4, 5, 6]
2674 * [5, 6, 7]
2675 * [6, 7, 8]
2676 * [7, 8, 9]
2677 * [8, 9, 10]
2678 *
2679 */
2680static VALUE
2681enum_each_cons(VALUE obj, VALUE n)
2682{
2683 long size = NUM2LONG(n);
2684 struct MEMO *memo;
2685 int arity;
2686
2687 if (size <= 0) rb_raise(rb_eArgError, "invalid size");
2688 RETURN_SIZED_ENUMERATOR(obj, 1, &n, enum_each_cons_size);
2689 arity = rb_block_arity();
2690 if (enum_size_over_p(obj, size)) return Qnil;
2691 memo = MEMO_NEW(rb_ary_new2(size), dont_recycle_block_arg(arity), size);
2692 rb_block_call(obj, id_each, 0, 0, each_cons_i, (VALUE)memo);
2693
2694 return Qnil;
2695}
2696
2697static VALUE
2698each_with_object_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, memo))
2699{
2700 ENUM_WANT_SVALUE();
2701 return rb_yield_values(2, i, memo);
2702}
2703
2704/*
2705 * call-seq:
2706 * enum.each_with_object(obj) { |(*args), memo_obj| ... } -> obj
2707 * enum.each_with_object(obj) -> an_enumerator
2708 *
2709 * Iterates the given block for each element with an arbitrary
2710 * object given, and returns the initially given object.
2711 *
2712 * If no block is given, returns an enumerator.
2713 *
2714 * evens = (1..10).each_with_object([]) { |i, a| a << i*2 }
2715 * #=> [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
2716 *
2717 */
2718static VALUE
2719enum_each_with_object(VALUE obj, VALUE memo)
2720{
2721 RETURN_SIZED_ENUMERATOR(obj, 1, &memo, enum_size);
2722
2723 rb_block_call(obj, id_each, 0, 0, each_with_object_i, memo);
2724
2725 return memo;
2726}
2727
2728static VALUE
2729zip_ary(RB_BLOCK_CALL_FUNC_ARGLIST(val, memoval))
2730{
2731 struct MEMO *memo = (struct MEMO *)memoval;
2732 VALUE result = memo->v1;
2733 VALUE args = memo->v2;
2734 long n = memo->u3.cnt++;
2735 VALUE tmp;
2736 int i;
2737
2738 tmp = rb_ary_new2(RARRAY_LEN(args) + 1);
2739 rb_ary_store(tmp, 0, rb_enum_values_pack(argc, argv));
2740 for (i=0; i<RARRAY_LEN(args); i++) {
2741 VALUE e = RARRAY_AREF(args, i);
2742
2743 if (RARRAY_LEN(e) <= n) {
2744 rb_ary_push(tmp, Qnil);
2745 }
2746 else {
2747 rb_ary_push(tmp, RARRAY_AREF(e, n));
2748 }
2749 }
2750 if (NIL_P(result)) {
2751 enum_yield_array(tmp);
2752 }
2753 else {
2754 rb_ary_push(result, tmp);
2755 }
2756
2757 RB_GC_GUARD(args);
2758
2759 return Qnil;
2760}
2761
2762static VALUE
2763call_next(VALUE w)
2764{
2765 VALUE *v = (VALUE *)w;
2766 return v[0] = rb_funcallv(v[1], id_next, 0, 0);
2767}
2768
2769static VALUE
2770call_stop(VALUE w, VALUE _)
2771{
2772 VALUE *v = (VALUE *)w;
2773 return v[0] = Qundef;
2774}
2775
2776static VALUE
2777zip_i(RB_BLOCK_CALL_FUNC_ARGLIST(val, memoval))
2778{
2779 struct MEMO *memo = (struct MEMO *)memoval;
2780 VALUE result = memo->v1;
2781 VALUE args = memo->v2;
2782 VALUE tmp;
2783 int i;
2784
2785 tmp = rb_ary_new2(RARRAY_LEN(args) + 1);
2786 rb_ary_store(tmp, 0, rb_enum_values_pack(argc, argv));
2787 for (i=0; i<RARRAY_LEN(args); i++) {
2788 if (NIL_P(RARRAY_AREF(args, i))) {
2789 rb_ary_push(tmp, Qnil);
2790 }
2791 else {
2792 VALUE v[2];
2793
2794 v[1] = RARRAY_AREF(args, i);
2795 rb_rescue2(call_next, (VALUE)v, call_stop, (VALUE)v, rb_eStopIteration, (VALUE)0);
2796 if (v[0] == Qundef) {
2797 RARRAY_ASET(args, i, Qnil);
2798 v[0] = Qnil;
2799 }
2800 rb_ary_push(tmp, v[0]);
2801 }
2802 }
2803 if (NIL_P(result)) {
2804 enum_yield_array(tmp);
2805 }
2806 else {
2807 rb_ary_push(result, tmp);
2808 }
2809
2810 RB_GC_GUARD(args);
2811
2812 return Qnil;
2813}
2814
2815/*
2816 * call-seq:
2817 * enum.zip(arg, ...) -> an_array_of_array
2818 * enum.zip(arg, ...) { |arr| block } -> nil
2819 *
2820 * Takes one element from <i>enum</i> and merges corresponding
2821 * elements from each <i>args</i>. This generates a sequence of
2822 * <em>n</em>-element arrays, where <em>n</em> is one more than the
2823 * count of arguments. The length of the resulting sequence will be
2824 * <code>enum#size</code>. If the size of any argument is less than
2825 * <code>enum#size</code>, <code>nil</code> values are supplied. If
2826 * a block is given, it is invoked for each output array, otherwise
2827 * an array of arrays is returned.
2828 *
2829 * a = [ 4, 5, 6 ]
2830 * b = [ 7, 8, 9 ]
2831 *
2832 * a.zip(b) #=> [[4, 7], [5, 8], [6, 9]]
2833 * [1, 2, 3].zip(a, b) #=> [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
2834 * [1, 2].zip(a, b) #=> [[1, 4, 7], [2, 5, 8]]
2835 * a.zip([1, 2], [8]) #=> [[4, 1, 8], [5, 2, nil], [6, nil, nil]]
2836 *
2837 * c = []
2838 * a.zip(b) { |x, y| c << x + y } #=> nil
2839 * c #=> [11, 13, 15]
2840 *
2841 */
2842
2843static VALUE
2844enum_zip(int argc, VALUE *argv, VALUE obj)
2845{
2846 int i;
2847 ID conv;
2848 struct MEMO *memo;
2849 VALUE result = Qnil;
2850 VALUE args = rb_ary_new4(argc, argv);
2851 int allary = TRUE;
2852
2853 argv = RARRAY_PTR(args);
2854 for (i=0; i<argc; i++) {
2855 VALUE ary = rb_check_array_type(argv[i]);
2856 if (NIL_P(ary)) {
2857 allary = FALSE;
2858 break;
2859 }
2860 argv[i] = ary;
2861 }
2862 if (!allary) {
2863 static const VALUE sym_each = STATIC_ID2SYM(id_each);
2864 CONST_ID(conv, "to_enum");
2865 for (i=0; i<argc; i++) {
2866 if (!rb_respond_to(argv[i], id_each)) {
2867 rb_raise(rb_eTypeError, "wrong argument type %"PRIsVALUE" (must respond to :each)",
2868 rb_obj_class(argv[i]));
2869 }
2870 argv[i] = rb_funcallv(argv[i], conv, 1, &sym_each);
2871 }
2872 }
2873 if (!rb_block_given_p()) {
2874 result = rb_ary_new();
2875 }
2876
2877 /* TODO: use NODE_DOT2 as memo(v, v, -) */
2878 memo = MEMO_NEW(result, args, 0);
2879 rb_block_call(obj, id_each, 0, 0, allary ? zip_ary : zip_i, (VALUE)memo);
2880
2881 return result;
2882}
2883
2884static VALUE
2885take_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, args))
2886{
2887 struct MEMO *memo = MEMO_CAST(args);
2888 rb_ary_push(memo->v1, rb_enum_values_pack(argc, argv));
2889 if (--memo->u3.cnt == 0) rb_iter_break();
2890 return Qnil;
2891}
2892
2893/*
2894 * call-seq:
2895 * enum.take(n) -> array
2896 *
2897 * Returns first n elements from <i>enum</i>.
2898 *
2899 * a = [1, 2, 3, 4, 5, 0]
2900 * a.take(3) #=> [1, 2, 3]
2901 * a.take(30) #=> [1, 2, 3, 4, 5, 0]
2902 *
2903 */
2904
2905static VALUE
2906enum_take(VALUE obj, VALUE n)
2907{
2908 struct MEMO *memo;
2909 VALUE result;
2910 long len = NUM2LONG(n);
2911
2912 if (len < 0) {
2913 rb_raise(rb_eArgError, "attempt to take negative size");
2914 }
2915
2916 if (len == 0) return rb_ary_new2(0);
2917 result = rb_ary_new2(len);
2918 memo = MEMO_NEW(result, 0, len);
2919 rb_block_call(obj, id_each, 0, 0, take_i, (VALUE)memo);
2920 return result;
2921}
2922
2923
2924static VALUE
2925take_while_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, ary))
2926{
2927 if (!RTEST(rb_yield_values2(argc, argv))) rb_iter_break();
2928 rb_ary_push(ary, rb_enum_values_pack(argc, argv));
2929 return Qnil;
2930}
2931
2932/*
2933 * call-seq:
2934 * enum.take_while { |obj| block } -> array
2935 * enum.take_while -> an_enumerator
2936 *
2937 * Passes elements to the block until the block returns +nil+ or +false+,
2938 * then stops iterating and returns an array of all prior elements.
2939 *
2940 * If no block is given, an enumerator is returned instead.
2941 *
2942 * a = [1, 2, 3, 4, 5, 0]
2943 * a.take_while { |i| i < 3 } #=> [1, 2]
2944 *
2945 */
2946
2947static VALUE
2948enum_take_while(VALUE obj)
2949{
2950 VALUE ary;
2951
2952 RETURN_ENUMERATOR(obj, 0, 0);
2953 ary = rb_ary_new();
2954 rb_block_call(obj, id_each, 0, 0, take_while_i, ary);
2955 return ary;
2956}
2957
2958static VALUE
2959drop_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, args))
2960{
2961 struct MEMO *memo = MEMO_CAST(args);
2962 if (memo->u3.cnt == 0) {
2963 rb_ary_push(memo->v1, rb_enum_values_pack(argc, argv));
2964 }
2965 else {
2966 memo->u3.cnt--;
2967 }
2968 return Qnil;
2969}
2970
2971/*
2972 * call-seq:
2973 * enum.drop(n) -> array
2974 *
2975 * Drops first n elements from <i>enum</i>, and returns rest elements
2976 * in an array.
2977 *
2978 * a = [1, 2, 3, 4, 5, 0]
2979 * a.drop(3) #=> [4, 5, 0]
2980 *
2981 */
2982
2983static VALUE
2984enum_drop(VALUE obj, VALUE n)
2985{
2986 VALUE result;
2987 struct MEMO *memo;
2988 long len = NUM2LONG(n);
2989
2990 if (len < 0) {
2991 rb_raise(rb_eArgError, "attempt to drop negative size");
2992 }
2993
2994 result = rb_ary_new();
2995 memo = MEMO_NEW(result, 0, len);
2996 rb_block_call(obj, id_each, 0, 0, drop_i, (VALUE)memo);
2997 return result;
2998}
2999
3000
3001static VALUE
3002drop_while_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, args))
3003{
3004 struct MEMO *memo = MEMO_CAST(args);
3005 ENUM_WANT_SVALUE();
3006
3007 if (!memo->u3.state && !RTEST(enum_yield(argc, i))) {
3008 memo->u3.state = TRUE;
3009 }
3010 if (memo->u3.state) {
3011 rb_ary_push(memo->v1, i);
3012 }
3013 return Qnil;
3014}
3015
3016/*
3017 * call-seq:
3018 * enum.drop_while { |obj| block } -> array
3019 * enum.drop_while -> an_enumerator
3020 *
3021 * Drops elements up to, but not including, the first element for
3022 * which the block returns +nil+ or +false+ and returns an array
3023 * containing the remaining elements.
3024 *
3025 * If no block is given, an enumerator is returned instead.
3026 *
3027 * a = [1, 2, 3, 4, 5, 0]
3028 * a.drop_while { |i| i < 3 } #=> [3, 4, 5, 0]
3029 *
3030 */
3031
3032static VALUE
3033enum_drop_while(VALUE obj)
3034{
3035 VALUE result;
3036 struct MEMO *memo;
3037
3038 RETURN_ENUMERATOR(obj, 0, 0);
3039 result = rb_ary_new();
3040 memo = MEMO_NEW(result, 0, FALSE);
3041 rb_block_call(obj, id_each, 0, 0, drop_while_i, (VALUE)memo);
3042 return result;
3043}
3044
3045static VALUE
3046cycle_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, ary))
3047{
3048 ENUM_WANT_SVALUE();
3049
3050 rb_ary_push(ary, argc > 1 ? i : rb_ary_new_from_values(argc, argv));
3051 enum_yield(argc, i);
3052 return Qnil;
3053}
3054
3055static VALUE
3056enum_cycle_size(VALUE self, VALUE args, VALUE eobj)
3057{
3058 long mul = 0;
3059 VALUE n = Qnil;
3060 VALUE size;
3061
3062 if (args && (RARRAY_LEN(args) > 0)) {
3063 n = RARRAY_AREF(args, 0);
3064 if (!NIL_P(n)) mul = NUM2LONG(n);
3065 }
3066
3067 size = enum_size(self, args, 0);
3068 if (NIL_P(size) || FIXNUM_ZERO_P(size)) return size;
3069
3070 if (NIL_P(n)) return DBL2NUM(HUGE_VAL);
3071 if (mul <= 0) return INT2FIX(0);
3072 n = LONG2FIX(mul);
3073 return rb_funcallv(size, '*', 1, &n);
3074}
3075
3076/*
3077 * call-seq:
3078 * enum.cycle(n=nil) { |obj| block } -> nil
3079 * enum.cycle(n=nil) -> an_enumerator
3080 *
3081 * Calls <i>block</i> for each element of <i>enum</i> repeatedly _n_
3082 * times or forever if none or +nil+ is given. If a non-positive
3083 * number is given or the collection is empty, does nothing. Returns
3084 * +nil+ if the loop has finished without getting interrupted.
3085 *
3086 * Enumerable#cycle saves elements in an internal array so changes
3087 * to <i>enum</i> after the first pass have no effect.
3088 *
3089 * If no block is given, an enumerator is returned instead.
3090 *
3091 * a = ["a", "b", "c"]
3092 * a.cycle { |x| puts x } # print, a, b, c, a, b, c,.. forever.
3093 * a.cycle(2) { |x| puts x } # print, a, b, c, a, b, c.
3094 *
3095 */
3096
3097static VALUE
3098enum_cycle(int argc, VALUE *argv, VALUE obj)
3099{
3100 VALUE ary;
3101 VALUE nv = Qnil;
3102 long n, i, len;
3103
3104 rb_check_arity(argc, 0, 1);
3105
3106 RETURN_SIZED_ENUMERATOR(obj, argc, argv, enum_cycle_size);
3107 if (!argc || NIL_P(nv = argv[0])) {
3108 n = -1;
3109 }
3110 else {
3111 n = NUM2LONG(nv);
3112 if (n <= 0) return Qnil;
3113 }
3114 ary = rb_ary_new();
3115 RBASIC_CLEAR_CLASS(ary);
3116 rb_block_call(obj, id_each, 0, 0, cycle_i, ary);
3117 len = RARRAY_LEN(ary);
3118 if (len == 0) return Qnil;
3119 while (n < 0 || 0 < --n) {
3120 for (i=0; i<len; i++) {
3121 enum_yield_array(RARRAY_AREF(ary, i));
3122 }
3123 }
3124 return Qnil;
3125}
3126
3127 struct chunk_arg {
3128 VALUE categorize;
3129 VALUE prev_value;
3130 VALUE prev_elts;
3131 VALUE yielder;
3132};
3133
3134static VALUE
3135chunk_ii(RB_BLOCK_CALL_FUNC_ARGLIST(i, _argp))
3136{
3137 struct chunk_arg *argp = MEMO_FOR(struct chunk_arg, _argp);
3138 VALUE v, s;
3139 VALUE alone = ID2SYM(rb_intern("_alone"));
3140 VALUE separator = ID2SYM(rb_intern("_separator"));
3141
3142 ENUM_WANT_SVALUE();
3143
3144 v = rb_funcallv(argp->categorize, id_call, 1, &i);
3145
3146 if (v == alone) {
3147 if (!NIL_P(argp->prev_value)) {
3148 s = rb_assoc_new(argp->prev_value, argp->prev_elts);
3149 rb_funcallv(argp->yielder, id_lshift, 1, &s);
3150 argp->prev_value = argp->prev_elts = Qnil;
3151 }
3152 v = rb_assoc_new(v, rb_ary_new3(1, i));
3153 rb_funcallv(argp->yielder, id_lshift, 1, &v);
3154 }
3155 else if (NIL_P(v) || v == separator) {
3156 if (!NIL_P(argp->prev_value)) {
3157 v = rb_assoc_new(argp->prev_value, argp->prev_elts);
3158 rb_funcallv(argp->yielder, id_lshift, 1, &v);
3159 argp->prev_value = argp->prev_elts = Qnil;
3160 }
3161 }
3162 else if (SYMBOL_P(v) && (s = rb_sym2str(v), RSTRING_PTR(s)[0] == '_')) {
3163 rb_raise(rb_eRuntimeError, "symbols beginning with an underscore are reserved");
3164 }
3165 else {
3166 if (NIL_P(argp->prev_value)) {
3167 argp->prev_value = v;
3168 argp->prev_elts = rb_ary_new3(1, i);
3169 }
3170 else {
3171 if (rb_equal(argp->prev_value, v)) {
3172 rb_ary_push(argp->prev_elts, i);
3173 }
3174 else {
3175 s = rb_assoc_new(argp->prev_value, argp->prev_elts);
3176 rb_funcallv(argp->yielder, id_lshift, 1, &s);
3177 argp->prev_value = v;
3178 argp->prev_elts = rb_ary_new3(1, i);
3179 }
3180 }
3181 }
3182 return Qnil;
3183}
3184
3185static VALUE
3186chunk_i(RB_BLOCK_CALL_FUNC_ARGLIST(yielder, enumerator))
3187{
3188 VALUE enumerable;
3189 VALUE arg;
3190 struct chunk_arg *memo = NEW_MEMO_FOR(struct chunk_arg, arg);
3191
3192 enumerable = rb_ivar_get(enumerator, rb_intern("chunk_enumerable"));
3193 memo->categorize = rb_ivar_get(enumerator, rb_intern("chunk_categorize"));
3194 memo->prev_value = Qnil;
3195 memo->prev_elts = Qnil;
3196 memo->yielder = yielder;
3197
3198 rb_block_call(enumerable, id_each, 0, 0, chunk_ii, arg);
3199 memo = MEMO_FOR(struct chunk_arg, arg);
3200 if (!NIL_P(memo->prev_elts)) {
3201 arg = rb_assoc_new(memo->prev_value, memo->prev_elts);
3202 rb_funcallv(memo->yielder, id_lshift, 1, &arg);
3203 }
3204 return Qnil;
3205}
3206
3207/*
3208 * call-seq:
3209 * enum.chunk { |elt| ... } -> an_enumerator
3210 *
3211 * Enumerates over the items, chunking them together based on the return
3212 * value of the block.
3213 *
3214 * Consecutive elements which return the same block value are chunked together.
3215 *
3216 * For example, consecutive even numbers and odd numbers can be
3217 * chunked as follows.
3218 *
3219 * [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5].chunk { |n|
3220 * n.even?
3221 * }.each { |even, ary|
3222 * p [even, ary]
3223 * }
3224 * #=> [false, [3, 1]]
3225 * # [true, [4]]
3226 * # [false, [1, 5, 9]]
3227 * # [true, [2, 6]]
3228 * # [false, [5, 3, 5]]
3229 *
3230 * This method is especially useful for sorted series of elements.
3231 * The following example counts words for each initial letter.
3232 *
3233 * open("/usr/share/dict/words", "r:iso-8859-1") { |f|
3234 * f.chunk { |line| line.upcase.ord }.each { |ch, lines| p [ch.chr, lines.length] }
3235 * }
3236 * #=> ["\n", 1]
3237 * # ["A", 1327]
3238 * # ["B", 1372]
3239 * # ["C", 1507]
3240 * # ["D", 791]
3241 * # ...
3242 *
3243 * The following key values have special meaning:
3244 * - +nil+ and +:_separator+ specifies that the elements should be dropped.
3245 * - +:_alone+ specifies that the element should be chunked by itself.
3246 *
3247 * Any other symbols that begin with an underscore will raise an error:
3248 *
3249 * items.chunk { |item| :_underscore }
3250 * #=> RuntimeError: symbols beginning with an underscore are reserved
3251 *
3252 * +nil+ and +:_separator+ can be used to ignore some elements.
3253 *
3254 * For example, the sequence of hyphens in svn log can be eliminated as follows:
3255 *
3256 * sep = "-"*72 + "\n"
3257 * IO.popen("svn log README") { |f|
3258 * f.chunk { |line|
3259 * line != sep || nil
3260 * }.each { |_, lines|
3261 * pp lines
3262 * }
3263 * }
3264 * #=> ["r20018 | knu | 2008-10-29 13:20:42 +0900 (Wed, 29 Oct 2008) | 2 lines\n",
3265 * # "\n",
3266 * # "* README, README.ja: Update the portability section.\n",
3267 * # "\n"]
3268 * # ["r16725 | knu | 2008-05-31 23:34:23 +0900 (Sat, 31 May 2008) | 2 lines\n",
3269 * # "\n",
3270 * # "* README, README.ja: Add a note about default C flags.\n",
3271 * # "\n"]
3272 * # ...
3273 *
3274 * Paragraphs separated by empty lines can be parsed as follows:
3275 *
3276 * File.foreach("README").chunk { |line|
3277 * /\A\s*\z/ !~ line || nil
3278 * }.each { |_, lines|
3279 * pp lines
3280 * }
3281 *
3282 * +:_alone+ can be used to force items into their own chunk.
3283 * For example, you can put lines that contain a URL by themselves,
3284 * and chunk the rest of the lines together, like this:
3285 *
3286 * pattern = /http/
3287 * open(filename) { |f|
3288 * f.chunk { |line| line =~ pattern ? :_alone : true }.each { |key, lines|
3289 * pp lines
3290 * }
3291 * }
3292 *
3293 * If no block is given, an enumerator to `chunk` is returned instead.
3294 */
3295static VALUE
3296enum_chunk(VALUE enumerable)
3297{
3298 VALUE enumerator;
3299
3300 RETURN_SIZED_ENUMERATOR(enumerable, 0, 0, enum_size);
3301
3302 enumerator = rb_obj_alloc(rb_cEnumerator);
3303 rb_ivar_set(enumerator, rb_intern("chunk_enumerable"), enumerable);
3304 rb_ivar_set(enumerator, rb_intern("chunk_categorize"), rb_block_proc());
3305 rb_block_call(enumerator, idInitialize, 0, 0, chunk_i, enumerator);
3306 return enumerator;
3307}
3308
3309
3310 struct slicebefore_arg {
3311 VALUE sep_pred;
3312 VALUE sep_pat;
3313 VALUE prev_elts;
3314 VALUE yielder;
3315};
3316
3317static VALUE
3318slicebefore_ii(RB_BLOCK_CALL_FUNC_ARGLIST(i, _argp))
3319{
3320 struct slicebefore_arg *argp = MEMO_FOR(struct slicebefore_arg, _argp);
3321 VALUE header_p;
3322
3323 ENUM_WANT_SVALUE();
3324
3325 if (!NIL_P(argp->sep_pat))
3326 header_p = rb_funcallv(argp->sep_pat, id_eqq, 1, &i);
3327 else
3328 header_p = rb_funcallv(argp->sep_pred, id_call, 1, &i);
3329 if (RTEST(header_p)) {
3330 if (!NIL_P(argp->prev_elts))
3331 rb_funcallv(argp->yielder, id_lshift, 1, &argp->prev_elts);
3332 argp->prev_elts = rb_ary_new3(1, i);
3333 }
3334 else {
3335 if (NIL_P(argp->prev_elts))
3336 argp->prev_elts = rb_ary_new3(1, i);
3337 else
3338 rb_ary_push(argp->prev_elts, i);
3339 }
3340
3341 return Qnil;
3342}
3343
3344static VALUE
3345slicebefore_i(RB_BLOCK_CALL_FUNC_ARGLIST(yielder, enumerator))
3346{
3347 VALUE enumerable;
3348 VALUE arg;
3349 struct slicebefore_arg *memo = NEW_MEMO_FOR(struct slicebefore_arg, arg);
3350
3351 enumerable = rb_ivar_get(enumerator, rb_intern("slicebefore_enumerable"));
3352 memo->sep_pred = rb_attr_get(enumerator, rb_intern("slicebefore_sep_pred"));
3353 memo->sep_pat = NIL_P(memo->sep_pred) ? rb_ivar_get(enumerator, rb_intern("slicebefore_sep_pat")) : Qnil;
3354 memo->prev_elts = Qnil;
3355 memo->yielder = yielder;
3356
3357 rb_block_call(enumerable, id_each, 0, 0, slicebefore_ii, arg);
3358 memo = MEMO_FOR(struct slicebefore_arg, arg);
3359 if (!NIL_P(memo->prev_elts))
3360 rb_funcallv(memo->yielder, id_lshift, 1, &memo->prev_elts);
3361 return Qnil;
3362}
3363
3364/*
3365 * call-seq:
3366 * enum.slice_before(pattern) -> an_enumerator
3367 * enum.slice_before { |elt| bool } -> an_enumerator
3368 *
3369 * Creates an enumerator for each chunked elements.
3370 * The beginnings of chunks are defined by _pattern_ and the block.
3371
3372 * If <code>_pattern_ === _elt_</code> returns <code>true</code> or the block
3373 * returns <code>true</code> for the element, the element is beginning of a
3374 * chunk.
3375
3376 * The <code>===</code> and _block_ is called from the first element to the last
3377 * element of _enum_. The result for the first element is ignored.
3378
3379 * The result enumerator yields the chunked elements as an array.
3380 * So +each+ method can be called as follows:
3381 *
3382 * enum.slice_before(pattern).each { |ary| ... }
3383 * enum.slice_before { |elt| bool }.each { |ary| ... }
3384 *
3385 * Other methods of the Enumerator class and Enumerable module,
3386 * such as +to_a+, +map+, etc., are also usable.
3387 *
3388 * For example, iteration over ChangeLog entries can be implemented as
3389 * follows:
3390 *
3391 * # iterate over ChangeLog entries.
3392 * open("ChangeLog") { |f|
3393 * f.slice_before(/\A\S/).each { |e| pp e }
3394 * }
3395 *
3396 * # same as above. block is used instead of pattern argument.
3397 * open("ChangeLog") { |f|
3398 * f.slice_before { |line| /\A\S/ === line }.each { |e| pp e }
3399 * }
3400 *
3401 *
3402 * "svn proplist -R" produces multiline output for each file.
3403 * They can be chunked as follows:
3404 *
3405 * IO.popen([{"LC_ALL"=>"C"}, "svn", "proplist", "-R"]) { |f|
3406 * f.lines.slice_before(/\AProp/).each { |lines| p lines }
3407 * }
3408 * #=> ["Properties on '.':\n", " svn:ignore\n", " svk:merge\n"]
3409 * # ["Properties on 'goruby.c':\n", " svn:eol-style\n"]
3410 * # ["Properties on 'complex.c':\n", " svn:mime-type\n", " svn:eol-style\n"]
3411 * # ["Properties on 'regparse.c':\n", " svn:eol-style\n"]
3412 * # ...
3413 *
3414 * If the block needs to maintain state over multiple elements,
3415 * local variables can be used.
3416 * For example, three or more consecutive increasing numbers can be squashed
3417 * as follows (see +chunk_while+ for a better way):
3418 *
3419 * a = [0, 2, 3, 4, 6, 7, 9]
3420 * prev = a[0]
3421 * p a.slice_before { |e|
3422 * prev, prev2 = e, prev
3423 * prev2 + 1 != e
3424 * }.map { |es|
3425 * es.length <= 2 ? es.join(",") : "#{es.first}-#{es.last}"
3426 * }.join(",")
3427 * #=> "0,2-4,6,7,9"
3428 *
3429 * However local variables should be used carefully
3430 * if the result enumerator is enumerated twice or more.
3431 * The local variables should be initialized for each enumeration.
3432 * Enumerator.new can be used to do it.
3433 *
3434 * # Word wrapping. This assumes all characters have same width.
3435 * def wordwrap(words, maxwidth)
3436 * Enumerator.new {|y|
3437 * # cols is initialized in Enumerator.new.
3438 * cols = 0
3439 * words.slice_before { |w|
3440 * cols += 1 if cols != 0
3441 * cols += w.length
3442 * if maxwidth < cols
3443 * cols = w.length
3444 * true
3445 * else
3446 * false
3447 * end
3448 * }.each {|ws| y.yield ws }
3449 * }
3450 * end
3451 * text = (1..20).to_a.join(" ")
3452 * enum = wordwrap(text.split(/\s+/), 10)
3453 * puts "-"*10
3454 * enum.each { |ws| puts ws.join(" ") } # first enumeration.
3455 * puts "-"*10
3456 * enum.each { |ws| puts ws.join(" ") } # second enumeration generates same result as the first.
3457 * puts "-"*10
3458 * #=> ----------
3459 * # 1 2 3 4 5
3460 * # 6 7 8 9 10
3461 * # 11 12 13
3462 * # 14 15 16
3463 * # 17 18 19
3464 * # 20
3465 * # ----------
3466 * # 1 2 3 4 5
3467 * # 6 7 8 9 10
3468 * # 11 12 13
3469 * # 14 15 16
3470 * # 17 18 19
3471 * # 20
3472 * # ----------
3473 *
3474 * mbox contains series of mails which start with Unix From line.
3475 * So each mail can be extracted by slice before Unix From line.
3476 *
3477 * # parse mbox
3478 * open("mbox") { |f|
3479 * f.slice_before { |line|
3480 * line.start_with? "From "
3481 * }.each { |mail|
3482 * unix_from = mail.shift
3483 * i = mail.index("\n")
3484 * header = mail[0...i]
3485 * body = mail[(i+1)..-1]
3486 * body.pop if body.last == "\n"
3487 * fields = header.slice_before { |line| !" \t".include?(line[0]) }.to_a
3488 * p unix_from
3489 * pp fields
3490 * pp body
3491 * }
3492 * }
3493 *
3494 * # split mails in mbox (slice before Unix From line after an empty line)
3495 * open("mbox") { |f|
3496 * emp = true
3497 * f.slice_before { |line|
3498 * prevemp = emp
3499 * emp = line == "\n"
3500 * prevemp && line.start_with?("From ")
3501 * }.each { |mail|
3502 * mail.pop if mail.last == "\n"
3503 * pp mail
3504 * }
3505 * }
3506 *
3507 */
3508static VALUE
3509enum_slice_before(int argc, VALUE *argv, VALUE enumerable)
3510{
3511 VALUE enumerator;
3512
3513 if (rb_block_given_p()) {
3514 if (argc != 0)
3515 rb_error_arity(argc, 0, 0);
3516 enumerator = rb_obj_alloc(rb_cEnumerator);
3517 rb_ivar_set(enumerator, rb_intern("slicebefore_sep_pred"), rb_block_proc());
3518 }
3519 else {
3520 VALUE sep_pat;
3521 rb_scan_args(argc, argv, "1", &sep_pat);
3522 enumerator = rb_obj_alloc(rb_cEnumerator);
3523 rb_ivar_set(enumerator, rb_intern("slicebefore_sep_pat"), sep_pat);
3524 }
3525 rb_ivar_set(enumerator, rb_intern("slicebefore_enumerable"), enumerable);
3526 rb_block_call(enumerator, idInitialize, 0, 0, slicebefore_i, enumerator);
3527 return enumerator;
3528}
3529
3530
3531 struct sliceafter_arg {
3532 VALUE pat;
3533 VALUE pred;
3534 VALUE prev_elts;
3535 VALUE yielder;
3536};
3537
3538static VALUE
3539sliceafter_ii(RB_BLOCK_CALL_FUNC_ARGLIST(i, _memo))
3540{
3541#define UPDATE_MEMO ((void)(memo = MEMO_FOR(struct sliceafter_arg, _memo)))
3542 struct sliceafter_arg *memo;
3543 int split_p;
3544 UPDATE_MEMO;
3545
3546 ENUM_WANT_SVALUE();
3547
3548 if (NIL_P(memo->prev_elts)) {
3549 memo->prev_elts = rb_ary_new3(1, i);
3550 }
3551 else {
3552 rb_ary_push(memo->prev_elts, i);
3553 }
3554
3555 if (NIL_P(memo->pred)) {
3556 split_p = RTEST(rb_funcallv(memo->pat, id_eqq, 1, &i));
3557 UPDATE_MEMO;
3558 }
3559 else {
3560 split_p = RTEST(rb_funcallv(memo->pred, id_call, 1, &i));
3561 UPDATE_MEMO;
3562 }
3563
3564 if (split_p) {
3565 rb_funcallv(memo->yielder, id_lshift, 1, &memo->prev_elts);
3566 UPDATE_MEMO;
3567 memo->prev_elts = Qnil;
3568 }
3569
3570 return Qnil;
3571#undef UPDATE_MEMO
3572}
3573
3574static VALUE
3575sliceafter_i(RB_BLOCK_CALL_FUNC_ARGLIST(yielder, enumerator))
3576{
3577 VALUE enumerable;
3578 VALUE arg;
3579 struct sliceafter_arg *memo = NEW_MEMO_FOR(struct sliceafter_arg, arg);
3580
3581 enumerable = rb_ivar_get(enumerator, rb_intern("sliceafter_enum"));
3582 memo->pat = rb_ivar_get(enumerator, rb_intern("sliceafter_pat"));
3583 memo->pred = rb_attr_get(enumerator, rb_intern("sliceafter_pred"));
3584 memo->prev_elts = Qnil;
3585 memo->yielder = yielder;
3586
3587 rb_block_call(enumerable, id_each, 0, 0, sliceafter_ii, arg);
3588 memo = MEMO_FOR(struct sliceafter_arg, arg);
3589 if (!NIL_P(memo->prev_elts))
3590 rb_funcallv(memo->yielder, id_lshift, 1, &memo->prev_elts);
3591 return Qnil;
3592}
3593
3594/*
3595 * call-seq:
3596 * enum.slice_after(pattern) -> an_enumerator
3597 * enum.slice_after { |elt| bool } -> an_enumerator
3598 *
3599 * Creates an enumerator for each chunked elements.
3600 * The ends of chunks are defined by _pattern_ and the block.
3601 *
3602 * If <code>_pattern_ === _elt_</code> returns <code>true</code> or the block
3603 * returns <code>true</code> for the element, the element is end of a
3604 * chunk.
3605 *
3606 * The <code>===</code> and _block_ is called from the first element to the last
3607 * element of _enum_.
3608 *
3609 * The result enumerator yields the chunked elements as an array.
3610 * So +each+ method can be called as follows:
3611 *
3612 * enum.slice_after(pattern).each { |ary| ... }
3613 * enum.slice_after { |elt| bool }.each { |ary| ... }
3614 *
3615 * Other methods of the Enumerator class and Enumerable module,
3616 * such as +map+, etc., are also usable.
3617 *
3618 * For example, continuation lines (lines end with backslash) can be
3619 * concatenated as follows:
3620 *
3621 * lines = ["foo\n", "bar\\\n", "baz\n", "\n", "qux\n"]
3622 * e = lines.slice_after(/(?<!\\‍)\n\z/)
3623 * p e.to_a
3624 * #=> [["foo\n"], ["bar\\\n", "baz\n"], ["\n"], ["qux\n"]]
3625 * p e.map {|ll| ll[0...-1].map {|l| l.sub(/\\\n\z/, "") }.join + ll.last }
3626 * #=>["foo\n", "barbaz\n", "\n", "qux\n"]
3627 *
3628 */
3629
3630static VALUE
3631enum_slice_after(int argc, VALUE *argv, VALUE enumerable)
3632{
3633 VALUE enumerator;
3634 VALUE pat = Qnil, pred = Qnil;
3635
3636 if (rb_block_given_p()) {
3637 if (0 < argc)
3638 rb_raise(rb_eArgError, "both pattern and block are given");
3639 pred = rb_block_proc();
3640 }
3641 else {
3642 rb_scan_args(argc, argv, "1", &pat);
3643 }
3644
3645 enumerator = rb_obj_alloc(rb_cEnumerator);
3646 rb_ivar_set(enumerator, rb_intern("sliceafter_enum"), enumerable);
3647 rb_ivar_set(enumerator, rb_intern("sliceafter_pat"), pat);
3648 rb_ivar_set(enumerator, rb_intern("sliceafter_pred"), pred);
3649
3650 rb_block_call(enumerator, idInitialize, 0, 0, sliceafter_i, enumerator);
3651 return enumerator;
3652}
3653
3654 struct slicewhen_arg {
3655 VALUE pred;
3656 VALUE prev_elt;
3657 VALUE prev_elts;
3658 VALUE yielder;
3659 int inverted; /* 0 for slice_when and 1 for chunk_while. */
3660};
3661
3662static VALUE
3663slicewhen_ii(RB_BLOCK_CALL_FUNC_ARGLIST(i, _memo))
3664{
3665#define UPDATE_MEMO ((void)(memo = MEMO_FOR(struct slicewhen_arg, _memo)))
3666 struct slicewhen_arg *memo;
3667 int split_p;
3668 UPDATE_MEMO;
3669
3670 ENUM_WANT_SVALUE();
3671
3672 if (memo->prev_elt == Qundef) {
3673 /* The first element */
3674 memo->prev_elt = i;
3675 memo->prev_elts = rb_ary_new3(1, i);
3676 }
3677 else {
3678 VALUE args[2];
3679 args[0] = memo->prev_elt;
3680 args[1] = i;
3681 split_p = RTEST(rb_funcallv(memo->pred, id_call, 2, args));
3682 UPDATE_MEMO;
3683
3684 if (memo->inverted)
3685 split_p = !split_p;
3686
3687 if (split_p) {
3688 rb_funcallv(memo->yielder, id_lshift, 1, &memo->prev_elts);
3689 UPDATE_MEMO;
3690 memo->prev_elts = rb_ary_new3(1, i);
3691 }
3692 else {
3693 rb_ary_push(memo->prev_elts, i);
3694 }
3695
3696 memo->prev_elt = i;
3697 }
3698
3699 return Qnil;
3700#undef UPDATE_MEMO
3701}
3702
3703static VALUE
3704slicewhen_i(RB_BLOCK_CALL_FUNC_ARGLIST(yielder, enumerator))
3705{
3706 VALUE enumerable;
3707 VALUE arg;
3708 struct slicewhen_arg *memo =
3709 NEW_PARTIAL_MEMO_FOR(struct slicewhen_arg, arg, inverted);
3710
3711 enumerable = rb_ivar_get(enumerator, rb_intern("slicewhen_enum"));
3712 memo->pred = rb_attr_get(enumerator, rb_intern("slicewhen_pred"));
3713 memo->prev_elt = Qundef;
3714 memo->prev_elts = Qnil;
3715 memo->yielder = yielder;
3716 memo->inverted = RTEST(rb_attr_get(enumerator, rb_intern("slicewhen_inverted")));
3717
3718 rb_block_call(enumerable, id_each, 0, 0, slicewhen_ii, arg);
3719 memo = MEMO_FOR(struct slicewhen_arg, arg);
3720 if (!NIL_P(memo->prev_elts))
3721 rb_funcallv(memo->yielder, id_lshift, 1, &memo->prev_elts);
3722 return Qnil;
3723}
3724
3725/*
3726 * call-seq:
3727 * enum.slice_when {|elt_before, elt_after| bool } -> an_enumerator
3728 *
3729 * Creates an enumerator for each chunked elements.
3730 * The beginnings of chunks are defined by the block.
3731 *
3732 * This method splits each chunk using adjacent elements,
3733 * _elt_before_ and _elt_after_,
3734 * in the receiver enumerator.
3735 * This method split chunks between _elt_before_ and _elt_after_ where
3736 * the block returns <code>true</code>.
3737 *
3738 * The block is called the length of the receiver enumerator minus one.
3739 *
3740 * The result enumerator yields the chunked elements as an array.
3741 * So +each+ method can be called as follows:
3742 *
3743 * enum.slice_when { |elt_before, elt_after| bool }.each { |ary| ... }
3744 *
3745 * Other methods of the Enumerator class and Enumerable module,
3746 * such as +to_a+, +map+, etc., are also usable.
3747 *
3748 * For example, one-by-one increasing subsequence can be chunked as follows:
3749 *
3750 * a = [1,2,4,9,10,11,12,15,16,19,20,21]
3751 * b = a.slice_when {|i, j| i+1 != j }
3752 * p b.to_a #=> [[1, 2], [4], [9, 10, 11, 12], [15, 16], [19, 20, 21]]
3753 * c = b.map {|a| a.length < 3 ? a : "#{a.first}-#{a.last}" }
3754 * p c #=> [[1, 2], [4], "9-12", [15, 16], "19-21"]
3755 * d = c.join(",")
3756 * p d #=> "1,2,4,9-12,15,16,19-21"
3757 *
3758 * Near elements (threshold: 6) in sorted array can be chunked as follows:
3759 *
3760 * a = [3, 11, 14, 25, 28, 29, 29, 41, 55, 57]
3761 * p a.slice_when {|i, j| 6 < j - i }.to_a
3762 * #=> [[3], [11, 14], [25, 28, 29, 29], [41], [55, 57]]
3763 *
3764 * Increasing (non-decreasing) subsequence can be chunked as follows:
3765 *
3766 * a = [0, 9, 2, 2, 3, 2, 7, 5, 9, 5]
3767 * p a.slice_when {|i, j| i > j }.to_a
3768 * #=> [[0, 9], [2, 2, 3], [2, 7], [5, 9], [5]]
3769 *
3770 * Adjacent evens and odds can be chunked as follows:
3771 * (Enumerable#chunk is another way to do it.)
3772 *
3773 * a = [7, 5, 9, 2, 0, 7, 9, 4, 2, 0]
3774 * p a.slice_when {|i, j| i.even? != j.even? }.to_a
3775 * #=> [[7, 5, 9], [2, 0], [7, 9], [4, 2, 0]]
3776 *
3777 * Paragraphs (non-empty lines with trailing empty lines) can be chunked as follows:
3778 * (See Enumerable#chunk to ignore empty lines.)
3779 *
3780 * lines = ["foo\n", "bar\n", "\n", "baz\n", "qux\n"]
3781 * p lines.slice_when {|l1, l2| /\A\s*\z/ =~ l1 && /\S/ =~ l2 }.to_a
3782 * #=> [["foo\n", "bar\n", "\n"], ["baz\n", "qux\n"]]
3783 *
3784 * Enumerable#chunk_while does the same, except splitting when the block
3785 * returns <code>false</code> instead of <code>true</code>.
3786 */
3787static VALUE
3788enum_slice_when(VALUE enumerable)
3789{
3790 VALUE enumerator;
3791 VALUE pred;
3792
3793 pred = rb_block_proc();
3794
3795 enumerator = rb_obj_alloc(rb_cEnumerator);
3796 rb_ivar_set(enumerator, rb_intern("slicewhen_enum"), enumerable);
3797 rb_ivar_set(enumerator, rb_intern("slicewhen_pred"), pred);
3798 rb_ivar_set(enumerator, rb_intern("slicewhen_inverted"), Qfalse);
3799
3800 rb_block_call(enumerator, idInitialize, 0, 0, slicewhen_i, enumerator);
3801 return enumerator;
3802}
3803
3804/*
3805 * call-seq:
3806 * enum.chunk_while {|elt_before, elt_after| bool } -> an_enumerator
3807 *
3808 * Creates an enumerator for each chunked elements.
3809 * The beginnings of chunks are defined by the block.
3810 *
3811 * This method splits each chunk using adjacent elements,
3812 * _elt_before_ and _elt_after_,
3813 * in the receiver enumerator.
3814 * This method split chunks between _elt_before_ and _elt_after_ where
3815 * the block returns <code>false</code>.
3816 *
3817 * The block is called the length of the receiver enumerator minus one.
3818 *
3819 * The result enumerator yields the chunked elements as an array.
3820 * So +each+ method can be called as follows:
3821 *
3822 * enum.chunk_while { |elt_before, elt_after| bool }.each { |ary| ... }
3823 *
3824 * Other methods of the Enumerator class and Enumerable module,
3825 * such as +to_a+, +map+, etc., are also usable.
3826 *
3827 * For example, one-by-one increasing subsequence can be chunked as follows:
3828 *
3829 * a = [1,2,4,9,10,11,12,15,16,19,20,21]
3830 * b = a.chunk_while {|i, j| i+1 == j }
3831 * p b.to_a #=> [[1, 2], [4], [9, 10, 11, 12], [15, 16], [19, 20, 21]]
3832 * c = b.map {|a| a.length < 3 ? a : "#{a.first}-#{a.last}" }
3833 * p c #=> [[1, 2], [4], "9-12", [15, 16], "19-21"]
3834 * d = c.join(",")
3835 * p d #=> "1,2,4,9-12,15,16,19-21"
3836 *
3837 * Increasing (non-decreasing) subsequence can be chunked as follows:
3838 *
3839 * a = [0, 9, 2, 2, 3, 2, 7, 5, 9, 5]
3840 * p a.chunk_while {|i, j| i <= j }.to_a
3841 * #=> [[0, 9], [2, 2, 3], [2, 7], [5, 9], [5]]
3842 *
3843 * Adjacent evens and odds can be chunked as follows:
3844 * (Enumerable#chunk is another way to do it.)
3845 *
3846 * a = [7, 5, 9, 2, 0, 7, 9, 4, 2, 0]
3847 * p a.chunk_while {|i, j| i.even? == j.even? }.to_a
3848 * #=> [[7, 5, 9], [2, 0], [7, 9], [4, 2, 0]]
3849 *
3850 * Enumerable#slice_when does the same, except splitting when the block
3851 * returns <code>true</code> instead of <code>false</code>.
3852 */
3853static VALUE
3854enum_chunk_while(VALUE enumerable)
3855{
3856 VALUE enumerator;
3857 VALUE pred;
3858
3859 pred = rb_block_proc();
3860
3861 enumerator = rb_obj_alloc(rb_cEnumerator);
3862 rb_ivar_set(enumerator, rb_intern("slicewhen_enum"), enumerable);
3863 rb_ivar_set(enumerator, rb_intern("slicewhen_pred"), pred);
3864 rb_ivar_set(enumerator, rb_intern("slicewhen_inverted"), Qtrue);
3865
3866 rb_block_call(enumerator, idInitialize, 0, 0, slicewhen_i, enumerator);
3867 return enumerator;
3868}
3869
3870 struct enum_sum_memo {
3871 VALUE v, r;
3872 long n;
3873 double f, c;
3874 int block_given;
3875 int float_value;
3876};
3877
3878static void
3879sum_iter_normalize_memo(struct enum_sum_memo *memo)
3880{
3881 assert(FIXABLE(memo->n));
3882 memo->v = rb_fix_plus(LONG2FIX(memo->n), memo->v);
3883 memo->n = 0;
3884
3885 switch (TYPE(memo->r)) {
3886 case T_RATIONAL: memo->v = rb_rational_plus(memo->r, memo->v); break;
3887 case T_UNDEF: break;
3888 default: UNREACHABLE; /* or ...? */
3889 }
3890 memo->r = Qundef;
3891}
3892
3893static void
3894sum_iter_fixnum(VALUE i, struct enum_sum_memo *memo)
3895{
3896 memo->n += FIX2LONG(i); /* should not overflow long type */
3897 if (! FIXABLE(memo->n)) {
3898 memo->v = rb_big_plus(LONG2NUM(memo->n), memo->v);
3899 memo->n = 0;
3900 }
3901}
3902
3903static void
3904sum_iter_bignum(VALUE i, struct enum_sum_memo *memo)
3905{
3906 memo->v = rb_big_plus(i, memo->v);
3907}
3908
3909static void
3910sum_iter_rational(VALUE i, struct enum_sum_memo *memo)
3911{
3912 if (memo->r == Qundef) {
3913 memo->r = i;
3914 }
3915 else {
3916 memo->r = rb_rational_plus(memo->r, i);
3917 }
3918}
3919
3920static void
3921sum_iter_some_value(VALUE i, struct enum_sum_memo *memo)
3922{
3923 memo->v = rb_funcallv(memo->v, idPLUS, 1, &i);
3924}
3925
3926static void
3927sum_iter_Kahan_Babuska(VALUE i, struct enum_sum_memo *memo)
3928{
3929 /*
3930 * Kahan-Babuska balancing compensated summation algorithm
3931 * See https://link.springer.com/article/10.1007/s00607-005-0139-x
3932 */
3933 double x;
3934
3935 switch (TYPE(i)) {
3936 case T_FLOAT: x = RFLOAT_VALUE(i); break;
3937 case T_FIXNUM: x = FIX2LONG(i); break;
3938 case T_BIGNUM: x = rb_big2dbl(i); break;
3939 case T_RATIONAL: x = rb_num2dbl(i); break;
3940 default:
3941 memo->v = DBL2NUM(memo->f);
3942 memo->float_value = 0;
3943 sum_iter_some_value(i, memo);
3944 return;
3945 }
3946
3947 double f = memo->f;
3948
3949 if (isnan(f)) {
3950 return;
3951 }
3952 else if (! isfinite(x)) {
3953 if (isinf(x) && isinf(f) && signbit(x) != signbit(f)) {
3954 i = DBL2NUM(f);
3955 x = nan("");
3956 }
3957 memo->v = i;
3958 memo->f = x;
3959 return;
3960 }
3961 else if (isinf(f)) {
3962 return;
3963 }
3964
3965 double c = memo->c;
3966 double t = f + x;
3967
3968 if (fabs(f) >= fabs(x)) {
3969 c += ((f - t) + x);
3970 }
3971 else {
3972 c += ((x - t) + f);
3973 }
3974 f = t;
3975
3976 memo->f = f;
3977 memo->c = c;
3978}
3979
3980static void
3981sum_iter(VALUE i, struct enum_sum_memo *memo)
3982{
3983 assert(memo != NULL);
3984 if (memo->block_given) {
3985 i = rb_yield(i);
3986 }
3987
3988 if (memo->float_value) {
3989 sum_iter_Kahan_Babuska(i, memo);
3990 }
3991 else switch (TYPE(memo->v)) {
3992 default: sum_iter_some_value(i, memo); return;
3993 case T_FLOAT: sum_iter_Kahan_Babuska(i, memo); return;
3994 case T_FIXNUM:
3995 case T_BIGNUM:
3996 case T_RATIONAL:
3997 switch (TYPE(i)) {
3998 case T_FIXNUM: sum_iter_fixnum(i, memo); return;
3999 case T_BIGNUM: sum_iter_bignum(i, memo); return;
4000 case T_RATIONAL: sum_iter_rational(i, memo); return;
4001 case T_FLOAT:
4002 sum_iter_normalize_memo(memo);
4003 memo->f = NUM2DBL(memo->v);
4004 memo->c = 0.0;
4005 memo->float_value = 1;
4006 sum_iter_Kahan_Babuska(i, memo);
4007 return;
4008 default:
4009 sum_iter_normalize_memo(memo);
4010 sum_iter_some_value(i, memo);
4011 return;
4012 }
4013 }
4014}
4015
4016static VALUE
4017enum_sum_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, args))
4018{
4019 ENUM_WANT_SVALUE();
4020 sum_iter(i, (struct enum_sum_memo *) args);
4021 return Qnil;
4022}
4023
4024static int
4025hash_sum_i(VALUE key, VALUE value, VALUE arg)
4026{
4027 sum_iter(rb_assoc_new(key, value), (struct enum_sum_memo *) arg);
4028 return ST_CONTINUE;
4029}
4030
4031static void
4032hash_sum(VALUE hash, struct enum_sum_memo *memo)
4033{
4034 assert(RB_TYPE_P(hash, T_HASH));
4035 assert(memo != NULL);
4036
4037 rb_hash_foreach(hash, hash_sum_i, (VALUE)memo);
4038}
4039
4040static VALUE
4041int_range_sum(VALUE beg, VALUE end, int excl, VALUE init)
4042{
4043 if (excl) {
4044 if (FIXNUM_P(end))
4045 end = LONG2FIX(FIX2LONG(end) - 1);
4046 else
4047 end = rb_big_minus(end, LONG2FIX(1));
4048 }
4049
4050 if (rb_int_ge(end, beg)) {
4051 VALUE a;
4052 a = rb_int_plus(rb_int_minus(end, beg), LONG2FIX(1));
4053 a = rb_int_mul(a, rb_int_plus(end, beg));
4054 a = rb_int_idiv(a, LONG2FIX(2));
4055 return rb_int_plus(init, a);
4056 }
4057
4058 return init;
4059}
4060
4061/*
4062 * call-seq:
4063 * enum.sum(init=0) -> number
4064 * enum.sum(init=0) {|e| expr } -> number
4065 *
4066 * Returns the sum of elements in an Enumerable.
4067 *
4068 * If a block is given, the block is applied to each element
4069 * before addition.
4070 *
4071 * If <i>enum</i> is empty, it returns <i>init</i>.
4072 *
4073 * For example:
4074 *
4075 * { 1 => 10, 2 => 20 }.sum {|k, v| k * v } #=> 50
4076 * (1..10).sum #=> 55
4077 * (1..10).sum {|v| v * 2 } #=> 110
4078 * ('a'..'z').sum #=> TypeError
4079 *
4080 * This method can be used for non-numeric objects by
4081 * explicit <i>init</i> argument.
4082 *
4083 * { 1 => 10, 2 => 20 }.sum([]) #=> [1, 10, 2, 20]
4084 * "a\nb\nc".each_line.lazy.map(&:chomp).sum("") #=> "abc"
4085 *
4086 * If the method is applied to an Integer range without a block,
4087 * the sum is not done by iteration, but instead using Gauss's summation
4088 * formula.
4089 *
4090 * Enumerable#sum method may not respect method redefinition of "+"
4091 * methods such as Integer#+, or "each" methods such as Range#each.
4092 */
4093static VALUE
4094enum_sum(int argc, VALUE* argv, VALUE obj)
4095{
4096 struct enum_sum_memo memo;
4097 VALUE beg, end;
4098 int excl;
4099
4100 memo.v = (rb_check_arity(argc, 0, 1) == 0) ? LONG2FIX(0) : argv[0];
4101 memo.block_given = rb_block_given_p();
4102 memo.n = 0;
4103 memo.r = Qundef;
4104
4105 if ((memo.float_value = RB_FLOAT_TYPE_P(memo.v))) {
4106 memo.f = RFLOAT_VALUE(memo.v);
4107 memo.c = 0.0;
4108 }
4109 else {
4110 memo.f = 0.0;
4111 memo.c = 0.0;
4112 }
4113
4114 if (RTEST(rb_range_values(obj, &beg, &end, &excl))) {
4115 if (!memo.block_given && !memo.float_value &&
4116 (FIXNUM_P(beg) || RB_TYPE_P(beg, T_BIGNUM)) &&
4117 (FIXNUM_P(end) || RB_TYPE_P(end, T_BIGNUM))) {
4118 return int_range_sum(beg, end, excl, memo.v);
4119 }
4120 }
4121
4122 if (RB_TYPE_P(obj, T_HASH) &&
4123 rb_method_basic_definition_p(CLASS_OF(obj), id_each))
4124 hash_sum(obj, &memo);
4125 else
4126 rb_block_call(obj, id_each, 0, 0, enum_sum_i, (VALUE)&memo);
4127
4128 if (memo.float_value) {
4129 return DBL2NUM(memo.f + memo.c);
4130 }
4131 else {
4132 if (memo.n != 0)
4133 memo.v = rb_fix_plus(LONG2FIX(memo.n), memo.v);
4134 if (memo.r != Qundef) {
4135 memo.v = rb_rational_plus(memo.r, memo.v);
4136 }
4137 return memo.v;
4138 }
4139}
4140
4141static VALUE
4142uniq_func(RB_BLOCK_CALL_FUNC_ARGLIST(i, hash))
4143{
4144 ENUM_WANT_SVALUE();
4145 rb_hash_add_new_element(hash, i, i);
4146 return Qnil;
4147}
4148
4149static VALUE
4150uniq_iter(RB_BLOCK_CALL_FUNC_ARGLIST(i, hash))
4151{
4152 ENUM_WANT_SVALUE();
4153 rb_hash_add_new_element(hash, rb_yield_values2(argc, argv), i);
4154 return Qnil;
4155}
4156
4157/*
4158 * call-seq:
4159 * enum.uniq -> new_ary
4160 * enum.uniq { |item| ... } -> new_ary
4161 *
4162 * Returns a new array by removing duplicate values in +self+.
4163 *
4164 * See also Array#uniq.
4165 */
4166
4167static VALUE
4168enum_uniq(VALUE obj)
4169{
4170 VALUE hash, ret;
4171 rb_block_call_func *const func =
4172 rb_block_given_p() ? uniq_iter : uniq_func;
4173
4174 hash = rb_obj_hide(rb_hash_new());
4175 rb_block_call(obj, id_each, 0, 0, func, hash);
4176 ret = rb_hash_values(hash);
4177 rb_hash_clear(hash);
4178 return ret;
4179}
4180
4181/*
4182 * The Enumerable mixin provides collection classes with several
4183 * traversal and searching methods, and with the ability to sort. The
4184 * class must provide a method #each, which yields
4185 * successive members of the collection. If Enumerable#max, #min, or
4186 * #sort is used, the objects in the collection must also implement a
4187 * meaningful <code><=></code> operator, as these methods rely on an
4188 * ordering between members of the collection.
4189 */
4190
4191void
4192Init_Enumerable(void)
4193{
4194 rb_mEnumerable = rb_define_module("Enumerable");
4195
4196 rb_define_method(rb_mEnumerable, "to_a", enum_to_a, -1);
4197 rb_define_method(rb_mEnumerable, "entries", enum_to_a, -1);
4198 rb_define_method(rb_mEnumerable, "to_h", enum_to_h, -1);
4199
4200 rb_define_method(rb_mEnumerable, "sort", enum_sort, 0);
4201 rb_define_method(rb_mEnumerable, "sort_by", enum_sort_by, 0);
4202 rb_define_method(rb_mEnumerable, "grep", enum_grep, 1);
4203 rb_define_method(rb_mEnumerable, "grep_v", enum_grep_v, 1);
4204 rb_define_method(rb_mEnumerable, "count", enum_count, -1);
4205 rb_define_method(rb_mEnumerable, "find", enum_find, -1);
4206 rb_define_method(rb_mEnumerable, "detect", enum_find, -1);
4207 rb_define_method(rb_mEnumerable, "find_index", enum_find_index, -1);
4208 rb_define_method(rb_mEnumerable, "find_all", enum_find_all, 0);
4209 rb_define_method(rb_mEnumerable, "select", enum_find_all, 0);
4210 rb_define_method(rb_mEnumerable, "filter", enum_find_all, 0);
4211 rb_define_method(rb_mEnumerable, "filter_map", enum_filter_map, 0);
4212 rb_define_method(rb_mEnumerable, "reject", enum_reject, 0);
4213 rb_define_method(rb_mEnumerable, "collect", enum_collect, 0);
4214 rb_define_method(rb_mEnumerable, "map", enum_collect, 0);
4215 rb_define_method(rb_mEnumerable, "flat_map", enum_flat_map, 0);
4216 rb_define_method(rb_mEnumerable, "collect_concat", enum_flat_map, 0);
4217 rb_define_method(rb_mEnumerable, "inject", enum_inject, -1);
4218 rb_define_method(rb_mEnumerable, "reduce", enum_inject, -1);
4219 rb_define_method(rb_mEnumerable, "partition", enum_partition, 0);
4220 rb_define_method(rb_mEnumerable, "group_by", enum_group_by, 0);
4221 rb_define_method(rb_mEnumerable, "tally", enum_tally, 0);
4222 rb_define_method(rb_mEnumerable, "first", enum_first, -1);
4223 rb_define_method(rb_mEnumerable, "all?", enum_all, -1);
4224 rb_define_method(rb_mEnumerable, "any?", enum_any, -1);
4225 rb_define_method(rb_mEnumerable, "one?", enum_one, -1);
4226 rb_define_method(rb_mEnumerable, "none?", enum_none, -1);
4227 rb_define_method(rb_mEnumerable, "min", enum_min, -1);
4228 rb_define_method(rb_mEnumerable, "max", enum_max, -1);
4229 rb_define_method(rb_mEnumerable, "minmax", enum_minmax, 0);
4230 rb_define_method(rb_mEnumerable, "min_by", enum_min_by, -1);
4231 rb_define_method(rb_mEnumerable, "max_by", enum_max_by, -1);
4232 rb_define_method(rb_mEnumerable, "minmax_by", enum_minmax_by, 0);
4233 rb_define_method(rb_mEnumerable, "member?", enum_member, 1);
4234 rb_define_method(rb_mEnumerable, "include?", enum_member, 1);
4235 rb_define_method(rb_mEnumerable, "each_with_index", enum_each_with_index, -1);
4236 rb_define_method(rb_mEnumerable, "reverse_each", enum_reverse_each, -1);
4237 rb_define_method(rb_mEnumerable, "each_entry", enum_each_entry, -1);
4238 rb_define_method(rb_mEnumerable, "each_slice", enum_each_slice, 1);
4239 rb_define_method(rb_mEnumerable, "each_cons", enum_each_cons, 1);
4240 rb_define_method(rb_mEnumerable, "each_with_object", enum_each_with_object, 1);
4241 rb_define_method(rb_mEnumerable, "zip", enum_zip, -1);
4242 rb_define_method(rb_mEnumerable, "take", enum_take, 1);
4243 rb_define_method(rb_mEnumerable, "take_while", enum_take_while, 0);
4244 rb_define_method(rb_mEnumerable, "drop", enum_drop, 1);
4245 rb_define_method(rb_mEnumerable, "drop_while", enum_drop_while, 0);
4246 rb_define_method(rb_mEnumerable, "cycle", enum_cycle, -1);
4247 rb_define_method(rb_mEnumerable, "chunk", enum_chunk, 0);
4248 rb_define_method(rb_mEnumerable, "slice_before", enum_slice_before, -1);
4249 rb_define_method(rb_mEnumerable, "slice_after", enum_slice_after, -1);
4250 rb_define_method(rb_mEnumerable, "slice_when", enum_slice_when, 0);
4251 rb_define_method(rb_mEnumerable, "chunk_while", enum_chunk_while, 0);
4252 rb_define_method(rb_mEnumerable, "sum", enum_sum, -1);
4253 rb_define_method(rb_mEnumerable, "uniq", enum_uniq, 0);
4254
4255 id_next = rb_intern_const("next");
4256}
rb_ary_new_from_values
VALUE rb_ary_new_from_values(long n, const VALUE *elts)
Definition: array.c:788
rb_ary_store
void rb_ary_store(VALUE ary, long idx, VALUE val)
Definition: array.c:1141
rb_ary_reverse
VALUE rb_ary_reverse(VALUE ary)
Definition: array.c:2998
rb_cArray
VALUE rb_cArray
Definition: array.c:40
rb_ary_shift
VALUE rb_ary_shift(VALUE ary)
Definition: array.c:1413
rb_ary_dup
VALUE rb_ary_dup(VALUE ary)
Definition: array.c:2666
rb_ary_push
VALUE rb_ary_push(VALUE ary, VALUE item)
Definition: array.c:1301
rb_ary_new
VALUE rb_ary_new(void)
Definition: array.c:749
rb_ary_concat
VALUE rb_ary_concat(VALUE x, VALUE y)
Definition: array.c:4859
rb_check_array_type
VALUE rb_check_array_type(VALUE ary)
Definition: array.c:988
rb_ary_resize
VALUE rb_ary_resize(VALUE ary, long len)
expands or shrinks ary to len elements.
Definition: array.c:2235
rb_ary_tmp_new
VALUE rb_ary_tmp_new(long capa)
Definition: array.c:846
rb_ary_clear
VALUE rb_ary_clear(VALUE ary)
Definition: array.c:4534
rb_ary_sort_bang
VALUE rb_ary_sort_bang(VALUE ary)
Definition: array.c:3298
rb_assoc_new
VALUE rb_assoc_new(VALUE car, VALUE cdr)
Definition: array.c:975
NORETURN
#define NORETURN(x)
Definition: attributes.h:152
UNREACHABLE
#define UNREACHABLE
Definition: assume.h:30
UNREACHABLE_RETURN
#define UNREACHABLE_RETURN
Definition: assume.h:31
rb_big_minus
VALUE rb_big_minus(VALUE x, VALUE y)
Definition: bignum.c:5850
rb_big_plus
VALUE rb_big_plus(VALUE x, VALUE y)
Definition: bignum.c:5821
rb_big_unpack
VALUE rb_big_unpack(unsigned long *buf, long num_longs)
Definition: bignum.c:3229
rb_big2dbl
double rb_big2dbl(VALUE x)
Definition: bignum.c:5309
rb_define_method
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
Definition: cxxanyargs.hpp:653
mul
#define mul(x, y)
Definition: date_strftime.c:25
ptr
struct RIMemo * ptr
Definition: debug.c:88
assert
#define assert(x)
Definition: dlmalloc.c:1176
RFLOAT_VALUE
#define RFLOAT_VALUE
Definition: double.h:28
NUM2DBL
#define NUM2DBL
Definition: double.h:27
DBL2NUM
#define DBL2NUM
Definition: double.h:29
num
big_t * num
Definition: enough.c:232
id_size
#define id_size
Definition: enum.c:37
UPDATE_MEMO
#define UPDATE_MEMO
COUNT_BIGNUM
#define COUNT_BIGNUM
Definition: enum.c:179
MEMO_V3_SET
#define MEMO_V3_SET(m, v)
Definition: enum.c:180
rb_mEnumerable
VALUE rb_mEnumerable
Definition: enum.c:27
ENUMFUNC
#define ENUMFUNC(name)
Definition: enum.c:1309
rb_cmpint
#define rb_cmpint(cmp, a, b)
SWAP
#define SWAP(i, j)
MEMO_ENUM_NEW
#define MEMO_ENUM_NEW(v1)
Definition: enum.c:1311
id_eqq
#define id_eqq
Definition: enum.c:33
rb_nmin_run
VALUE rb_nmin_run(VALUE obj, VALUE num, int by, int rev, int ary)
Definition: enum.c:1603
WARN_UNUSED_BLOCK
#define WARN_UNUSED_BLOCK(argc)
Definition: enum.c:1338
DEFINE_ENUMFUNCS
#define DEFINE_ENUMFUNCS(name)
Definition: enum.c:1313
SORT_BY_BUFSIZE
#define SORT_BY_BUFSIZE
Definition: enum.c:1130
id_div
#define id_div
Definition: enum.c:31
id_lshift
#define id_lshift
Definition: enum.c:35
ENUM_WANT_SVALUE
#define ENUM_WANT_SVALUE()
Definition: enum.c:47
GETPTR
#define GETPTR(i)
rb_enum_values_pack
VALUE rb_enum_values_pack(int argc, const VALUE *argv)
Definition: enum.c:40
Init_Enumerable
void Init_Enumerable(void)
Definition: enum.c:4192
dont_recycle_block_arg
#define dont_recycle_block_arg(arity)
Definition: enum.c:2538
id_call
#define id_call
Definition: enum.c:36
id_each
#define id_each
Definition: enum.c:32
rb_cEnumerator
VALUE rb_cEnumerator
Definition: enumerator.c:126
rb_eStopIteration
VALUE rb_eStopIteration
Definition: enumerator.c:141
len
uint8_t len
Definition: escape.c:17
numberof
#define numberof(array)
Definition: etc.c:649
RSTRING_PTR
#define RSTRING_PTR(string)
Definition: fbuffer.h:19
LIKELY
#define LIKELY(x)
Definition: ffi_common.h:125
PRIsVALUE
#define PRIsVALUE
Definition: function.c:10
rb_cInteger
VALUE rb_cInteger
Definition: numeric.c:191
CLASS_OF
#define CLASS_OF
Definition: globals.h:153
rb_define_module
VALUE rb_define_module(const char *name)
Definition: class.c:871
rb_scan_args
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Definition: class.c:2296
rb_block_given_p
int rb_block_given_p(void)
Determines if the current method is given a block.
Definition: eval.c:935
rb_raise
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:2917
rb_rescue2
VALUE rb_rescue2(VALUE(*b_proc)(VALUE), VALUE data1, VALUE(*r_proc)(VALUE, VALUE), VALUE data2,...)
An equivalent of rescue clause.
Definition: eval.c:991
rb_eTypeError
VALUE rb_eTypeError
Definition: error.c:1057
rb_eRuntimeError
VALUE rb_eRuntimeError
Definition: error.c:1055
rb_warn
void rb_warn(const char *fmt,...)
Definition: error.c:408
rb_eArgError
VALUE rb_eArgError
Definition: error.c:1058
rb_warning
void rb_warning(const char *fmt,...)
Definition: error.c:439
rb_obj_alloc
VALUE rb_obj_alloc(VALUE)
Allocates an instance of klass.
Definition: object.c:1900
rb_obj_hide
VALUE rb_obj_hide(VALUE obj)
Make the object invisible from Ruby code.
Definition: object.c:92
rb_obj_class
VALUE rb_obj_class(VALUE)
Definition: object.c:245
rb_num2dbl
double rb_num2dbl(VALUE)
Converts a Numeric object to double.
Definition: object.c:3635
rb_equal
VALUE rb_equal(VALUE, VALUE)
This function is an optimized version of calling #==.
Definition: object.c:157
match
unsigned char match[65280+2]
Definition: gun.c:165
rb_hash_values
VALUE rb_hash_values(VALUE hash)
Definition: hash.c:3593
rb_hash_add_new_element
int rb_hash_add_new_element(VALUE hash, VALUE key, VALUE val)
Definition: hash.c:4734
rb_hash_set_pair
VALUE rb_hash_set_pair(VALUE hash, VALUE arg)
Definition: hash.c:3468
rb_hash_foreach
void rb_hash_foreach(VALUE hash, rb_foreach_func *func, VALUE farg)
Definition: hash.c:1498
rb_hash_aref
VALUE rb_hash_aref(VALUE hash, VALUE key)
Definition: hash.c:2046
rb_hash_aset
VALUE rb_hash_aset(VALUE hash, VALUE key, VALUE val)
Definition: hash.c:2901
rb_hash_clear
VALUE rb_hash_clear(VALUE hash)
Definition: hash.c:2819
rb_hash_new
VALUE rb_hash_new(void)
Definition: hash.c:1538
id.h
idPLUS
@ idPLUS
Definition: id.h:85
idEqq
@ idEqq
Definition: id.h:97
imemo.h
IMEMO: Internal memo object.
MEMO_NEW
#define MEMO_NEW(a, b, c)
Definition: imemo.h:122
MEMO_FOR
#define MEMO_FOR(type, value)
Definition: imemo.h:123
NEW_MEMO_FOR
#define NEW_MEMO_FOR(type, value)
Definition: imemo.h:124
MEMO_CAST
#define MEMO_CAST(m)
Definition: imemo.h:121
NEW_PARTIAL_MEMO_FOR
#define NEW_PARTIAL_MEMO_FOR(type, value, member)
Definition: imemo.h:126
FIXABLE
#define FIXABLE
Definition: fixnum.h:25
FIXNUM_MAX
#define FIXNUM_MAX
Definition: fixnum.h:26
rb_iter_break
void rb_iter_break(void)
Definition: vm.c:1786
rb_funcall
VALUE rb_funcall(VALUE, ID, int,...)
Calls a method.
Definition: vm_eval.c:1077
rb_funcallv_public
VALUE rb_funcallv_public(VALUE, ID, int, const VALUE *)
Calls a method.
Definition: vm_eval.c:1137
rb_ary_new4
#define rb_ary_new4
Definition: array.h:74
rb_ary_new3
#define rb_ary_new3
Definition: array.h:73
rb_ary_new2
#define rb_ary_new2
Definition: array.h:72
RETURN_SIZED_ENUMERATOR
#define RETURN_SIZED_ENUMERATOR(obj, argc, argv, size_fn)
Definition: enumerator.h:64
RETURN_ENUMERATOR
#define RETURN_ENUMERATOR(obj, argc, argv)
Definition: enumerator.h:74
rb_error_arity
void rb_error_arity(int, int, int)
Definition: vm_insnhelper.c:442
rb_check_arity
#define rb_check_arity
Definition: error.h:34
rb_block_proc
VALUE rb_block_proc(void)
Definition: proc.c:826
rb_range_values
int rb_range_values(VALUE range, VALUE *begp, VALUE *endp, int *exclp)
Definition: range.c:1310
rb_check_string_type
VALUE rb_check_string_type(VALUE)
Definition: string.c:2462
rb_ivar_get
VALUE rb_ivar_get(VALUE, ID)
Definition: variable.c:1234
rb_attr_get
VALUE rb_attr_get(VALUE, ID)
Definition: variable.c:1242
rb_ivar_set
VALUE rb_ivar_set(VALUE, ID, VALUE)
Definition: variable.c:1493
rb_obj_respond_to
int rb_obj_respond_to(VALUE, ID, int)
Definition: vm_method.c:2545
rb_check_funcall
VALUE rb_check_funcall(VALUE, ID, int, const VALUE *)
Definition: vm_eval.c:619
rb_respond_to
int rb_respond_to(VALUE, ID)
Definition: vm_method.c:2561
ID2SYM
#define ID2SYM
Definition: symbol.h:44
SYM2ID
#define SYM2ID
Definition: symbol.h:45
rb_sym2str
VALUE rb_sym2str(VALUE)
Definition: symbol.c:927
rb_intern
ID rb_intern(const char *)
Definition: symbol.c:785
rb_check_id
ID rb_check_id(volatile VALUE *)
Returns ID for the given name if it is interned already, or 0.
Definition: symbol.c:1069
CONST_ID
#define CONST_ID
Definition: symbol.h:47
isfinite
#define isfinite(x)
Definition: missing.h:187
signbit
int signbit(double x)
Definition: signbit.c:5
nan
double nan(const char *)
Definition: nan.c:7
HUGE_VAL
#define HUGE_VAL
Definition: missing.h:156
util.h
ruby_qsort
void ruby_qsort(void *, const size_t, const size_t, int(*)(const void *, const void *, void *), void *)
compar.h
Internal header for Comparable.
NEW_CMP_OPT_MEMO
#define NEW_CMP_OPT_MEMO(type, value)
Definition: compar.h:28
OPTIMIZED_CMP
#define OPTIMIZED_CMP(a, b, data)
Definition: compar.h:38
enum.h
Internal header for Enumerable.
rb_f_send
VALUE rb_f_send(int argc, VALUE *argv, VALUE recv)
Definition: vm_eval.c:1295
hash.h
Internal header for Hash.
numeric.h
Internal header for Numeric.
rb_int_ge
VALUE rb_int_ge(VALUE x, VALUE y)
Definition: numeric.c:4276
rb_int_minus
VALUE rb_int_minus(VALUE x, VALUE y)
Definition: numeric.c:3636
rb_fix_plus
VALUE rb_fix_plus(VALUE x, VALUE y)
Definition: numeric.c:3591
rb_int_idiv
VALUE rb_int_idiv(VALUE x, VALUE y)
Definition: numeric.c:3830
rb_int_plus
VALUE rb_int_plus(VALUE x, VALUE y)
Definition: numeric.c:3597
rb_int_succ
VALUE rb_int_succ(VALUE num)
Definition: numeric.c:3337
rb_int_mul
VALUE rb_int_mul(VALUE x, VALUE y)
Definition: numeric.c:3686
object.h
Internal header for Object.
proc.h
Internal header for Proc.
rb_block_arity
int rb_block_arity(void)
Definition: proc.c:1193
rb_block_min_max_arity
int rb_block_min_max_arity(int *max)
Definition: proc.c:1226
rational.h
Internal header for Rational.
rb_rational_plus
VALUE rb_rational_plus(VALUE self, VALUE other)
Definition: rational.c:720
re.h
Internal header for Regexp.
rb_reg_match_p
VALUE rb_reg_match_p(VALUE re, VALUE str, long pos)
Definition: re.c:3353
rb_yield_force_blockarg
VALUE rb_yield_force_blockarg(VALUE values)
Definition: vm_eval.c:1413
rb_check_funcall_default
VALUE rb_check_funcall_default(VALUE, ID, int, const VALUE *, VALUE)
Definition: vm_eval.c:647
rb_lambda_call
VALUE rb_lambda_call(VALUE obj, ID mid, int argc, const VALUE *argv, rb_block_call_func_t bl_proc, int min_argc, int max_argc, VALUE data2)
Definition: vm_eval.c:1598
internal.h
bp
#define bp()
Definition: internal.h:105
rb_funcallv
#define rb_funcallv(...)
Definition: internal.h:77
rb_method_basic_definition_p
#define rb_method_basic_definition_p(...)
Definition: internal.h:78
size
voidpf void uLong size
Definition: ioapi.h:138
long
typedef long(ZCALLBACK *tell_file_func) OF((voidpf opaque
int
typedef int(ZCALLBACK *close_file_func) OF((voidpf opaque
buf
voidpf void * buf
Definition: ioapi.h:138
isinf
int isinf(double n)
Definition: isinf.c:56
RB_BLOCK_CALL_FUNC_ARGLIST
#define RB_BLOCK_CALL_FUNC_ARGLIST(yielded_arg, callback_arg)
Definition: iterator.h:31
rb_block_call_kw
VALUE rb_block_call_kw(VALUE, ID, int, const VALUE *, rb_block_call_func_t, VALUE, int)
Definition: vm_eval.c:1584
rb_yield_values
VALUE rb_yield_values(int n,...)
Definition: vm_eval.c:1353
rb_yield_values2
VALUE rb_yield_values2(int n, const VALUE *argv)
Definition: vm_eval.c:1375
rb_block_call_func_t
rb_block_call_func * rb_block_call_func_t
Definition: iterator.h:34
rb_block_call_func
VALUE rb_block_call_func(RB_BLOCK_CALL_FUNC_ARGLIST(yielded_arg, callback_arg))
Definition: iterator.h:33
rb_yield
VALUE rb_yield(VALUE)
Definition: vm_eval.c:1341
LONG_MAX
#define LONG_MAX
Definition: limits.h:36
INT2FIX
#define INT2FIX
Definition: long.h:48
ULONG2NUM
#define ULONG2NUM
Definition: long.h:60
LONG2FIX
#define LONG2FIX
Definition: long.h:49
FIX2ULONG
#define FIX2ULONG
Definition: long.h:47
LONG2NUM
#define LONG2NUM
Definition: long.h:50
FIX2LONG
#define FIX2LONG
Definition: long.h:46
NUM2LONG
#define NUM2LONG
Definition: long.h:51
RB_GC_GUARD
#define RB_GC_GUARD(v)
Definition: memory.h:91
ruby::backward::cxxanyargs::rb_block_call
VALUE rb_block_call(VALUE q, ID w, int e, const VALUE *r, type *t, VALUE y)
Call a method with a block.
Definition: cxxanyargs.hpp:230
id
const int id
Definition: nkf.c:209
name
const char * name
Definition: nkf.c:208
TRUE
#define TRUE
Definition: nkf.h:175
FALSE
#define FALSE
Definition: nkf.h:174
key
key
Definition: openssl_missing.h:185
RARRAY_AREF
#define RARRAY_AREF(a, i)
Definition: psych_emitter.c:7
RARRAY_LEN
#define RARRAY_LEN
Definition: rarray.h:52
RARRAY_PTR_USE
#define RARRAY_PTR_USE(ary, ptr_name, expr)
Definition: rarray.h:235
RBASIC
#define RBASIC(obj)
Definition: rbasic.h:34
NULL
#define NULL
Definition: regenc.h:69
RB_OBJ_WRITE
#define RB_OBJ_WRITE(a, slot, b)
WB for new reference from ‘a’ to ‘b’.
Definition: rgengc.h:107
argc
int argc
Definition: ruby.c:240
argv
char ** argv
Definition: ruby.c:241
ruby_assert.h
RB_INTEGER_TYPE_P
#define RB_INTEGER_TYPE_P(obj)
Definition: ruby_missing.h:15
RB_PASS_CALLED_KEYWORDS
#define RB_PASS_CALLED_KEYWORDS
Definition: scan_args.h:48
Qundef
#define Qundef
Definition: special_consts.h:53
Qtrue
#define Qtrue
Definition: special_consts.h:52
RTEST
#define RTEST
Definition: special_consts.h:42
Qnil
#define Qnil
Definition: special_consts.h:51
Qfalse
#define Qfalse
Definition: special_consts.h:50
NIL_P
#define NIL_P
Definition: special_consts.h:46
FIXNUM_P
#define FIXNUM_P
Definition: special_consts.h:44
f
#define f
ST_CONTINUE
@ ST_CONTINUE
Definition: st.h:99
_
#define _(args)
Definition: stdarg.h:31
MEMO
MEMO.
Definition: imemo.h:105
MEMO::v2
const VALUE v2
Definition: imemo.h:109
MEMO::flags
VALUE flags
Definition: imemo.h:106
MEMO::func
void(* func)(void)
Definition: imemo.h:114
MEMO::v1
const VALUE v1
Definition: imemo.h:108
MEMO::cnt
long cnt
Definition: imemo.h:111
MEMO::u3
union MEMO::@112 u3
MEMO::value
const VALUE value
Definition: imemo.h:113
MEMO::state
long state
Definition: imemo.h:112
chunk_arg
Definition: enum.c:3127
chunk_arg::categorize
VALUE categorize
Definition: enum.c:3128
chunk_arg::yielder
VALUE yielder
Definition: enum.c:3131
chunk_arg::prev_value
VALUE prev_value
Definition: enum.c:3129
chunk_arg::prev_elts
VALUE prev_elts
Definition: enum.c:3130
cmp_opt_data
Definition: compar.h:23
cmp_opt_data::opt_inited
unsigned int opt_inited
Definition: compar.h:25
cmp_opt_data::opt_methods
unsigned int opt_methods
Definition: compar.h:24
enum_sum_memo
Definition: enum.c:3870
enum_sum_memo::v
VALUE v
Definition: enum.c:3871
enum_sum_memo::f
double f
Definition: enum.c:3873
enum_sum_memo::r
VALUE r
Definition: enum.c:3871
enum_sum_memo::n
long n
Definition: enum.c:3872
enum_sum_memo::block_given
int block_given
Definition: enum.c:3874
enum_sum_memo::float_value
int float_value
Definition: enum.c:3875
enum_sum_memo::c
double c
Definition: enum.c:3873
enumerator
Definition: enumerator.c:143
max_t
Definition: enum.c:1835
max_t::max
VALUE max
Definition: enum.c:1836
max_t::cmp_opt
struct cmp_opt_data cmp_opt
Definition: enum.c:1837
min_t
Definition: enum.c:1742
min_t::cmp_opt
struct cmp_opt_data cmp_opt
Definition: enum.c:1744
min_t::min
VALUE min
Definition: enum.c:1743
minmax_by_t
Definition: enum.c:2248
minmax_by_t::max
VALUE max
Definition: enum.c:2252
minmax_by_t::max_bv
VALUE max_bv
Definition: enum.c:2250
minmax_by_t::min
VALUE min
Definition: enum.c:2251
minmax_by_t::min_bv
VALUE min_bv
Definition: enum.c:2249
minmax_by_t::last_bv
VALUE last_bv
Definition: enum.c:2253
minmax_by_t::last
VALUE last
Definition: enum.c:2254
minmax_t
Definition: enum.c:1927
minmax_t::last
VALUE last
Definition: enum.c:1930
minmax_t::min
VALUE min
Definition: enum.c:1928
minmax_t::max
VALUE max
Definition: enum.c:1929
minmax_t::cmp_opt
struct cmp_opt_data cmp_opt
Definition: enum.c:1931
nmin_data
Definition: enum.c:1442
nmin_data::bufmax
long bufmax
Definition: enum.c:1444
nmin_data::n
long n
Definition: enum.c:1443
nmin_data::cmpfunc
int(* cmpfunc)(const void *, const void *, void *)
Definition: enum.c:1448
nmin_data::buf
VALUE buf
Definition: enum.c:1446
nmin_data::rev
int rev
Definition: enum.c:1449
nmin_data::limit
VALUE limit
Definition: enum.c:1447
nmin_data::by
int by
Definition: enum.c:1450
nmin_data::curlen
long curlen
Definition: enum.c:1445
sliceafter_arg
Definition: enum.c:3531
sliceafter_arg::prev_elts
VALUE prev_elts
Definition: enum.c:3534
sliceafter_arg::pat
VALUE pat
Definition: enum.c:3532
sliceafter_arg::yielder
VALUE yielder
Definition: enum.c:3535
sliceafter_arg::pred
VALUE pred
Definition: enum.c:3533
slicebefore_arg
Definition: enum.c:3310
slicebefore_arg::yielder
VALUE yielder
Definition: enum.c:3314
slicebefore_arg::prev_elts
VALUE prev_elts
Definition: enum.c:3313
slicebefore_arg::sep_pat
VALUE sep_pat
Definition: enum.c:3312
slicebefore_arg::sep_pred
VALUE sep_pred
Definition: enum.c:3311
slicewhen_arg
Definition: enum.c:3654
slicewhen_arg::inverted
int inverted
Definition: enum.c:3659
slicewhen_arg::prev_elt
VALUE prev_elt
Definition: enum.c:3656
slicewhen_arg::prev_elts
VALUE prev_elts
Definition: enum.c:3657
slicewhen_arg::pred
VALUE pred
Definition: enum.c:3655
slicewhen_arg::yielder
VALUE yielder
Definition: enum.c:3658
sort_by_data
Definition: enum.c:1131
sort_by_data::ary
const VALUE ary
Definition: enum.c:1132
sort_by_data::buf
const VALUE buf
Definition: enum.c:1133
sort_by_data::n
long n
Definition: enum.c:1134
yielder
Definition: enumerator.c:165
t
#define t
Definition: symbol.c:253
symbol.h
STATIC_ID2SYM
#define STATIC_ID2SYM(id)
Definition: symbol.h:18
VALUE
unsigned long VALUE
Definition: value.h:38
ID
unsigned long ID
Definition: value.h:39
TYPE
#define TYPE(_)
Definition: value_type.h:105
T_FLOAT
#define T_FLOAT
Definition: value_type.h:63
T_BIGNUM
#define T_BIGNUM
Definition: value_type.h:56
T_FIXNUM
#define T_FIXNUM
Definition: value_type.h:62
T_RATIONAL
#define T_RATIONAL
Definition: value_type.h:75
T_HASH
#define T_HASH
Definition: value_type.h:64
T_UNDEF
#define T_UNDEF
Definition: value_type.h:81
T_ARRAY
#define T_ARRAY
Definition: value_type.h:55
SYMBOL_P
#define SYMBOL_P
Definition: value_type.h:87
T_REGEXP
#define T_REGEXP
Definition: value_type.h:76
isnan
#define isnan(x)
Definition: win32.h:346