Ruby 2.0.0p353(2013-11-22revision43784)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

enum.c
Go to the documentation of this file.
1 /**********************************************************************
2
3 enum.c -
4
5 $Author: zzak $
6 created at: Fri Oct 1 15:15:19 JST 1993
7
8 Copyright (C) 1993-2007 Yukihiro Matsumoto
9
10 **********************************************************************/
11
12 #include "ruby/ruby.h"
13 #include "ruby/util.h"
14 #include "node.h"
15 #include "id.h"
16 #include "internal.h"
17
18 #define STATIC_ASSERT(name, expr) typedef int static_assert_##name##_check[1 - 2*!(expr)]
19
20 VALUE rb_mEnumerable;
21
22 static ID id_next;
23 static ID id_div;
24 static ID id_call;
25 static ID id_size;
26
27 #define id_each idEach
28 #define id_eqq idEqq
29 #define id_cmp idCmp
30 #define id_lshift idLTLT
31
32 VALUE
33 rb_enum_values_pack(int argc, VALUE *argv)
34 {
35 if (argc == 0) return Qnil;
36 if (argc == 1) return argv[0];
37 return rb_ary_new4(argc, argv);
38 }
39
40 #define ENUM_WANT_SVALUE() do { \
41 i = rb_enum_values_pack(argc, argv); \
42 } while (0)
43
44 #define enum_yield rb_yield_values2
45
46 static VALUE
47 grep_i(VALUE i, VALUE args, int argc, VALUE *argv)
48 {
49 NODE *memo = RNODE(args);
50 ENUM_WANT_SVALUE();
51
52 if (RTEST(rb_funcall(memo->u1.value, id_eqq, 1, i))) {
53 rb_ary_push(memo->u2.value, i);
54 }
55 return Qnil;
56 }
57
58 static VALUE
59 grep_iter_i(VALUE i, VALUE args, int argc, VALUE *argv)
60 {
61 NODE *memo = RNODE(args);
62 ENUM_WANT_SVALUE();
63
64 if (RTEST(rb_funcall(memo->u1.value, id_eqq, 1, i))) {
65 rb_ary_push(memo->u2.value, rb_yield(i));
66 }
67 return Qnil;
68 }
69
70 /*
71 * call-seq:
72 * enum.grep(pattern) -> array
73 * enum.grep(pattern) { |obj| block } -> array
74 *
75 * Returns an array of every element in <i>enum</i> for which
76 * <code>Pattern === element</code>. If the optional <em>block</em> is
77 * supplied, each matching element is passed to it, and the block's
78 * result is stored in the output array.
79 *
80 * (1..100).grep 38..44 #=> [38, 39, 40, 41, 42, 43, 44]
81 * c = IO.constants
82 * c.grep(/SEEK/) #=> [:SEEK_SET, :SEEK_CUR, :SEEK_END]
83 * res = c.grep(/SEEK/) { |v| IO.const_get(v) }
84 * res #=> [0, 1, 2]
85 *
86 */
87
88 static VALUE
89 enum_grep(VALUE obj, VALUE pat)
90 {
91 VALUE ary = rb_ary_new();
92 NODE *memo = NEW_MEMO(pat, ary, 0);
93
94 rb_block_call(obj, id_each, 0, 0, rb_block_given_p() ? grep_iter_i : grep_i, (VALUE)memo);
95
96 return ary;
97 }
98
99 static VALUE
100 count_i(VALUE i, VALUE memop, int argc, VALUE *argv)
101 {
102 NODE *memo = RNODE(memop);
103
104 ENUM_WANT_SVALUE();
105
106 if (rb_equal(i, memo->u1.value)) {
107 memo->u3.cnt++;
108 }
109 return Qnil;
110 }
111
112 static VALUE
113 count_iter_i(VALUE i, VALUE memop, int argc, VALUE *argv)
114 {
115 NODE *memo = RNODE(memop);
116
117 if (RTEST(enum_yield(argc, argv))) {
118 memo->u3.cnt++;
119 }
120 return Qnil;
121 }
122
123 static VALUE
124 count_all_i(VALUE i, VALUE memop, int argc, VALUE *argv)
125 {
126 NODE *memo = RNODE(memop);
127
128 memo->u3.cnt++;
129 return Qnil;
130 }
131
132 /*
133 * call-seq:
134 * enum.count -> int
135 * enum.count(item) -> int
136 * enum.count { |obj| block } -> int
137 *
138 * Returns the number of items in +enum+ through enumeration.
139 * If an argument is given, the number of items in +enum+ that
140 * are equal to +item+ are counted. If a block is given, it
141 * counts the number of elements yielding a true value.
142 *
143 * ary = [1, 2, 4, 2]
144 * ary.count #=> 4
145 * ary.count(2) #=> 2
146 * ary.count{ |x| x%2==0 } #=> 3
147 *
148 */
149
150 static VALUE
151 enum_count(int argc, VALUE *argv, VALUE obj)
152 {
153 VALUE item = Qnil;
154 NODE *memo;
155 rb_block_call_func *func;
156
157 if (argc == 0) {
158 if (rb_block_given_p()) {
159 func = count_iter_i;
160 }
161 else {
162 func = count_all_i;
163 }
164 }
165 else {
166 rb_scan_args(argc, argv, "1", &item);
167 if (rb_block_given_p()) {
168 rb_warn("given block not used");
169 }
170 func = count_i;
171 }
172
173 memo = NEW_MEMO(item, 0, 0);
174 rb_block_call(obj, id_each, 0, 0, func, (VALUE)memo);
175 return INT2NUM(memo->u3.cnt);
176 }
177
178 static VALUE
179 find_i(VALUE i, VALUE memop, int argc, VALUE *argv)
180 {
181 ENUM_WANT_SVALUE();
182
183 if (RTEST(rb_yield(i))) {
184 NODE *memo = RNODE(memop);
185 memo->u1.value = i;
186 memo->u3.cnt = 1;
187 rb_iter_break();
188 }
189 return Qnil;
190 }
191
192 /*
193 * call-seq:
194 * enum.detect(ifnone = nil) { |obj| block } -> obj or nil
195 * enum.find(ifnone = nil) { |obj| block } -> obj or nil
196 * enum.detect(ifnone = nil) -> an_enumerator
197 * enum.find(ifnone = nil) -> an_enumerator
198 *
199 * Passes each entry in <i>enum</i> to <em>block</em>. Returns the
200 * first for which <em>block</em> is not false. If no
201 * object matches, calls <i>ifnone</i> and returns its result when it
202 * is specified, or returns <code>nil</code> otherwise.
203 *
204 * If no block is given, an enumerator is returned instead.
205 *
206 * (1..10).detect { |i| i % 5 == 0 and i % 7 == 0 } #=> nil
207 * (1..100).detect { |i| i % 5 == 0 and i % 7 == 0 } #=> 35
208 *
209 */
210
211 static VALUE
212 enum_find(int argc, VALUE *argv, VALUE obj)
213 {
214 NODE *memo;
215 VALUE if_none;
216
217 rb_scan_args(argc, argv, "01", &if_none);
218 RETURN_ENUMERATOR(obj, argc, argv);
219 memo = NEW_MEMO(Qundef, 0, 0);
220 rb_block_call(obj, id_each, 0, 0, find_i, (VALUE)memo);
221 if (memo->u3.cnt) {
222 return memo->u1.value;
223 }
224 if (!NIL_P(if_none)) {
225 return rb_funcall(if_none, id_call, 0, 0);
226 }
227 return Qnil;
228 }
229
230 static VALUE
231 find_index_i(VALUE i, VALUE memop, int argc, VALUE *argv)
232 {
233 NODE *memo = RNODE(memop);
234
235 ENUM_WANT_SVALUE();
236
237 if (rb_equal(i, memo->u2.value)) {
238 memo->u1.value = UINT2NUM(memo->u3.cnt);
239 rb_iter_break();
240 }
241 memo->u3.cnt++;
242 return Qnil;
243 }
244
245 static VALUE
246 find_index_iter_i(VALUE i, VALUE memop, int argc, VALUE *argv)
247 {
248 NODE *memo = RNODE(memop);
249
250 if (RTEST(enum_yield(argc, argv))) {
251 memo->u1.value = UINT2NUM(memo->u3.cnt);
252 rb_iter_break();
253 }
254 memo->u3.cnt++;
255 return Qnil;
256 }
257
258 /*
259 * call-seq:
260 * enum.find_index(value) -> int or nil
261 * enum.find_index { |obj| block } -> int or nil
262 * enum.find_index -> an_enumerator
263 *
264 * Compares each entry in <i>enum</i> with <em>value</em> or passes
265 * to <em>block</em>. Returns the index for the first for which the
266 * evaluated value is non-false. If no object matches, returns
267 * <code>nil</code>
268 *
269 * If neither block nor argument is given, an enumerator is returned instead.
270 *
271 * (1..10).find_index { |i| i % 5 == 0 and i % 7 == 0 } #=> nil
272 * (1..100).find_index { |i| i % 5 == 0 and i % 7 == 0 } #=> 34
273 * (1..100).find_index(50) #=> 49
274 *
275 */
276
277 static VALUE
278 enum_find_index(int argc, VALUE *argv, VALUE obj)
279 {
280 NODE *memo; /* [return value, current index, ] */
281 VALUE condition_value = Qnil;
282 rb_block_call_func *func;
283
284 if (argc == 0) {
285 RETURN_ENUMERATOR(obj, 0, 0);
286 func = find_index_iter_i;
287 }
288 else {
289 rb_scan_args(argc, argv, "1", &condition_value);
290 if (rb_block_given_p()) {
291 rb_warn("given block not used");
292 }
293 func = find_index_i;
294 }
295
296 memo = NEW_MEMO(Qnil, condition_value, 0);
297 rb_block_call(obj, id_each, 0, 0, func, (VALUE)memo);
298 return memo->u1.value;
299 }
300
301 static VALUE
302 find_all_i(VALUE i, VALUE ary, int argc, VALUE *argv)
303 {
304 ENUM_WANT_SVALUE();
305
306 if (RTEST(rb_yield(i))) {
307 rb_ary_push(ary, i);
308 }
309 return Qnil;
310 }
311
312 static VALUE
313 enum_size(VALUE self, VALUE args)
314 {
315 VALUE r;
316 r = rb_check_funcall(self, id_size, 0, 0);
317 return (r == Qundef) ? Qnil : r;
318 }
319
320 /*
321 * call-seq:
322 * enum.find_all { |obj| block } -> array
323 * enum.select { |obj| block } -> array
324 * enum.find_all -> an_enumerator
325 * enum.select -> an_enumerator
326 *
327 * Returns an array containing all elements of +enum+
328 * for which the given +block+ returns a true value.
329 *
330 * If no block is given, an Enumerator is returned instead.
331 *
332 *
333 * (1..10).find_all { |i| i % 3 == 0 } #=> [3, 6, 9]
334 *
335 * [1,2,3,4,5].select { |num| num.even? } #=> [2, 4]
336 *
337 * See also Enumerable#reject.
338 */
339
340 static VALUE
341 enum_find_all(VALUE obj)
342 {
343 VALUE ary;
344
345 RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);
346
347 ary = rb_ary_new();
348 rb_block_call(obj, id_each, 0, 0, find_all_i, ary);
349
350 return ary;
351 }
352
353 static VALUE
354 reject_i(VALUE i, VALUE ary, int argc, VALUE *argv)
355 {
356 ENUM_WANT_SVALUE();
357
358 if (!RTEST(rb_yield(i))) {
359 rb_ary_push(ary, i);
360 }
361 return Qnil;
362 }
363
364 /*
365 * call-seq:
366 * enum.reject { |obj| block } -> array
367 * enum.reject -> an_enumerator
368 *
369 * Returns an array for all elements of +enum+ for which the given
370 * +block+ returns false.
371 *
372 * If no block is given, an Enumerator is returned instead.
373 *
374 * (1..10).reject { |i| i % 3 == 0 } #=> [1, 2, 4, 5, 7, 8, 10]
375 *
376 * [1, 2, 3, 4, 5].reject { |num| num.even? } #=> [1, 3, 5]
377 *
378 * See also Enumerable#find_all.
379 */
380
381 static VALUE
382 enum_reject(VALUE obj)
383 {
384 VALUE ary;
385
386 RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);
387
388 ary = rb_ary_new();
389 rb_block_call(obj, id_each, 0, 0, reject_i, ary);
390
391 return ary;
392 }
393
394 static VALUE
395 collect_i(VALUE i, VALUE ary, int argc, VALUE *argv)
396 {
397 rb_ary_push(ary, enum_yield(argc, argv));
398
399 return Qnil;
400 }
401
402 static VALUE
403 collect_all(VALUE i, VALUE ary, int argc, VALUE *argv)
404 {
405 rb_thread_check_ints();
406 rb_ary_push(ary, rb_enum_values_pack(argc, argv));
407
408 return Qnil;
409 }
410
411 /*
412 * call-seq:
413 * enum.collect { |obj| block } -> array
414 * enum.map { |obj| block } -> array
415 * enum.collect -> an_enumerator
416 * enum.map -> an_enumerator
417 *
418 * Returns a new array with the results of running <em>block</em> once
419 * for every element in <i>enum</i>.
420 *
421 * If no block is given, an enumerator is returned instead.
422 *
423 * (1..4).collect { |i| i*i } #=> [1, 4, 9, 16]
424 * (1..4).collect { "cat" } #=> ["cat", "cat", "cat", "cat"]
425 *
426 */
427
428 static VALUE
429 enum_collect(VALUE obj)
430 {
431 VALUE ary;
432
433 RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);
434
435 ary = rb_ary_new();
436 rb_block_call(obj, id_each, 0, 0, collect_i, ary);
437
438 return ary;
439 }
440
441 static VALUE
442 flat_map_i(VALUE i, VALUE ary, int argc, VALUE *argv)
443 {
444 VALUE tmp;
445
446 i = enum_yield(argc, argv);
447 tmp = rb_check_array_type(i);
448
449 if (NIL_P(tmp)) {
450 rb_ary_push(ary, i);
451 }
452 else {
453 rb_ary_concat(ary, tmp);
454 }
455 return Qnil;
456 }
457
458 /*
459 * call-seq:
460 * enum.flat_map { |obj| block } -> array
461 * enum.collect_concat { |obj| block } -> array
462 * enum.flat_map -> an_enumerator
463 * enum.collect_concat -> an_enumerator
464 *
465 * Returns a new array with the concatenated results of running
466 * <em>block</em> once for every element in <i>enum</i>.
467 *
468 * If no block is given, an enumerator is returned instead.
469 *
470 * [1, 2, 3, 4].flat_map { |e| [e, -e] } #=> [1, -1, 2, -2, 3, -3, 4, -4]
471 * [[1, 2], [3, 4]].flat_map { |e| e + [100] } #=> [1, 2, 100, 3, 4, 100]
472 *
473 */
474
475 static VALUE
476 enum_flat_map(VALUE obj)
477 {
478 VALUE ary;
479
480 RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);
481
482 ary = rb_ary_new();
483 rb_block_call(obj, id_each, 0, 0, flat_map_i, ary);
484
485 return ary;
486 }
487
488 /*
489 * call-seq:
490 * enum.to_a -> array
491 * enum.entries -> array
492 *
493 * Returns an array containing the items in <i>enum</i>.
494 *
495 * (1..7).to_a #=> [1, 2, 3, 4, 5, 6, 7]
496 * { 'a'=>1, 'b'=>2, 'c'=>3 }.to_a #=> [["a", 1], ["b", 2], ["c", 3]]
497 */
498 static VALUE
499 enum_to_a(int argc, VALUE *argv, VALUE obj)
500 {
501 VALUE ary = rb_ary_new();
502
503 rb_block_call(obj, id_each, argc, argv, collect_all, ary);
504 OBJ_INFECT(ary, obj);
505
506 return ary;
507 }
508
509 static VALUE
510 inject_i(VALUE i, VALUE p, int argc, VALUE *argv)
511 {
512 NODE *memo = RNODE(p);
513
514 ENUM_WANT_SVALUE();
515
516 if (memo->u2.argc == 0) {
517 memo->u2.argc = 1;
518 memo->u1.value = i;
519 }
520 else {
521 memo->u1.value = rb_yield_values(2, memo->u1.value, i);
522 }
523 return Qnil;
524 }
525
526 static VALUE
527 inject_op_i(VALUE i, VALUE p, int argc, VALUE *argv)
528 {
529 NODE *memo = RNODE(p);
530
531 ENUM_WANT_SVALUE();
532
533 if (memo->u2.argc == 0) {
534 memo->u2.argc = 1;
535 memo->u1.value = i;
536 }
537 else {
538 memo->u1.value = rb_funcall(memo->u1.value, memo->u3.id, 1, i);
539 }
540 return Qnil;
541 }
542
543 /*
544 * call-seq:
545 * enum.inject(initial, sym) -> obj
546 * enum.inject(sym) -> obj
547 * enum.inject(initial) { |memo, obj| block } -> obj
548 * enum.inject { |memo, obj| block } -> obj
549 * enum.reduce(initial, sym) -> obj
550 * enum.reduce(sym) -> obj
551 * enum.reduce(initial) { |memo, obj| block } -> obj
552 * enum.reduce { |memo, obj| block } -> obj
553 *
554 * Combines all elements of <i>enum</i> by applying a binary
555 * operation, specified by a block or a symbol that names a
556 * method or operator.
557 *
558 * If you specify a block, then for each element in <i>enum</i>
559 * the block is passed an accumulator value (<i>memo</i>) and the element.
560 * If you specify a symbol instead, then each element in the collection
561 * will be passed to the named method of <i>memo</i>.
562 * In either case, the result becomes the new value for <i>memo</i>.
563 * At the end of the iteration, the final value of <i>memo</i> is the
564 * return value for the method.
565 *
566 * If you do not explicitly specify an <i>initial</i> value for <i>memo</i>,
567 * then the first element of collection is used as the initial value
568 * of <i>memo</i>.
569 *
570 *
571 * # Sum some numbers
572 * (5..10).reduce(:+) #=> 45
573 * # Same using a block and inject
574 * (5..10).inject { |sum, n| sum + n } #=> 45
575 * # Multiply some numbers
576 * (5..10).reduce(1, :*) #=> 151200
577 * # Same using a block
578 * (5..10).inject(1) { |product, n| product * n } #=> 151200
579 * # find the longest word
580 * longest = %w{ cat sheep bear }.inject do |memo, word|
581 * memo.length > word.length ? memo : word
582 * end
583 * longest #=> "sheep"
584 *
585 */
586 static VALUE
587 enum_inject(int argc, VALUE *argv, VALUE obj)
588 {
589 NODE *memo;
590 VALUE init, op;
591 VALUE (*iter)(VALUE, VALUE, int, VALUE*) = inject_i;
592
593 switch (rb_scan_args(argc, argv, "02", &init, &op)) {
594 case 0:
595 break;
596 case 1:
597 if (rb_block_given_p()) {
598 break;
599 }
600 op = (VALUE)rb_to_id(init);
601 argc = 0;
602 init = Qnil;
603 iter = inject_op_i;
604 break;
605 case 2:
606 if (rb_block_given_p()) {
607 rb_warning("given block not used");
608 }
609 op = (VALUE)rb_to_id(op);
610 iter = inject_op_i;
611 break;
612 }
613 memo = NEW_MEMO(init, argc, op);
614 rb_block_call(obj, id_each, 0, 0, iter, (VALUE)memo);
615 return memo->u1.value;
616 }
617
618 static VALUE
619 partition_i(VALUE i, VALUE arys, int argc, VALUE *argv)
620 {
621 NODE *memo = RNODE(arys);
622 VALUE ary;
623 ENUM_WANT_SVALUE();
624
625 if (RTEST(rb_yield(i))) {
626 ary = memo->u1.value;
627 }
628 else {
629 ary = memo->u2.value;
630 }
631 rb_ary_push(ary, i);
632 return Qnil;
633 }
634
635 /*
636 * call-seq:
637 * enum.partition { |obj| block } -> [ true_array, false_array ]
638 * enum.partition -> an_enumerator
639 *
640 * Returns two arrays, the first containing the elements of
641 * <i>enum</i> for which the block evaluates to true, the second
642 * containing the rest.
643 *
644 * If no block is given, an enumerator is returned instead.
645 *
646 * (1..6).partition { |v| v.even? } #=> [[2, 4, 6], [1, 3, 5]]
647 *
648 */
649
650 static VALUE
651 enum_partition(VALUE obj)
652 {
653 NODE *memo;
654
655 RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);
656
657 memo = NEW_MEMO(rb_ary_new(), rb_ary_new(), 0);
658 rb_block_call(obj, id_each, 0, 0, partition_i, (VALUE)memo);
659
660 return rb_assoc_new(memo->u1.value, memo->u2.value);
661 }
662
663 static VALUE
664 group_by_i(VALUE i, VALUE hash, int argc, VALUE *argv)
665 {
666 VALUE group;
667 VALUE values;
668
669 ENUM_WANT_SVALUE();
670
671 group = rb_yield(i);
672 values = rb_hash_aref(hash, group);
673 if (!RB_TYPE_P(values, T_ARRAY)) {
674 values = rb_ary_new3(1, i);
675 rb_hash_aset(hash, group, values);
676 }
677 else {
678 rb_ary_push(values, i);
679 }
680 return Qnil;
681 }
682
683 /*
684 * call-seq:
685 * enum.group_by { |obj| block } -> a_hash
686 * enum.group_by -> an_enumerator
687 *
688 * Groups the collection by result of the block. Returns a hash where the
689 * keys are the evaluated result from the block and the values are
690 * arrays of elements in the collection that correspond to the key.
691 *
692 * If no block is given an enumerator is returned.
693 *
694 * (1..6).group_by { |i| i%3 } #=> {0=>[3, 6], 1=>[1, 4], 2=>[2, 5]}
695 *
696 */
697
698 static VALUE
699 enum_group_by(VALUE obj)
700 {
701 VALUE hash;
702
703 RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);
704
705 hash = rb_hash_new();
706 rb_block_call(obj, id_each, 0, 0, group_by_i, hash);
707 OBJ_INFECT(hash, obj);
708
709 return hash;
710 }
711
712 static VALUE
713 first_i(VALUE i, VALUE params, int argc, VALUE *argv)
714 {
715 NODE *memo = RNODE(params);
716 ENUM_WANT_SVALUE();
717
718 memo->u1.value = i;
719 rb_iter_break();
720
721 UNREACHABLE;
722 }
723
724 static VALUE enum_take(VALUE obj, VALUE n);
725
726 /*
727 * call-seq:
728 * enum.first -> obj or nil
729 * enum.first(n) -> an_array
730 *
731 * Returns the first element, or the first +n+ elements, of the enumerable.
732 * If the enumerable is empty, the first form returns <code>nil</code>, and the
733 * second form returns an empty array.
734 *
735 * %w[foo bar baz].first #=> "foo"
736 * %w[foo bar baz].first(2) #=> ["foo", "bar"]
737 * %w[foo bar baz].first(10) #=> ["foo", "bar", "baz"]
738 * [].first #=> nil
739 *
740 */
741
742 static VALUE
743 enum_first(int argc, VALUE *argv, VALUE obj)
744 {
745 NODE *memo;
746 rb_check_arity(argc, 0, 1);
747 if (argc > 0) {
748 return enum_take(obj, argv[0]);
749 }
750 else {
751 memo = NEW_MEMO(Qnil, 0, 0);
752 rb_block_call(obj, id_each, 0, 0, first_i, (VALUE)memo);
753 return memo->u1.value;
754 }
755 }
756
757
758 /*
759 * call-seq:
760 * enum.sort -> array
761 * enum.sort { |a, b| block } -> array
762 *
763 * Returns an array containing the items in <i>enum</i> sorted,
764 * either according to their own <code><=></code> method, or by using
765 * the results of the supplied block. The block should return -1, 0, or
766 * +1 depending on the comparison between <i>a</i> and <i>b</i>. As of
767 * Ruby 1.8, the method <code>Enumerable#sort_by</code> implements a
768 * built-in Schwartzian Transform, useful when key computation or
769 * comparison is expensive.
770 *
771 * %w(rhea kea flea).sort #=> ["flea", "kea", "rhea"]
772 * (1..10).sort { |a, b| b <=> a } #=> [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
773 */
774
775 static VALUE
776 enum_sort(VALUE obj)
777 {
778 return rb_ary_sort(enum_to_a(0, 0, obj));
779 }
780
781 #define SORT_BY_BUFSIZE 16
782 struct sort_by_data {
783 VALUE ary;
784 VALUE buf;
785 long n;
786 };
787
788 static VALUE
789 sort_by_i(VALUE i, VALUE _data, int argc, VALUE *argv)
790 {
791 struct sort_by_data *data = (struct sort_by_data *)&RNODE(_data)->u1;
792 VALUE ary = data->ary;
793 VALUE v;
794
795 ENUM_WANT_SVALUE();
796
797 v = rb_yield(i);
798
799 if (RBASIC(ary)->klass) {
800 rb_raise(rb_eRuntimeError, "sort_by reentered");
801 }
802 if (RARRAY_LEN(data->buf) != SORT_BY_BUFSIZE*2) {
803 rb_raise(rb_eRuntimeError, "sort_by reentered");
804 }
805
806 RARRAY_PTR(data->buf)[data->n*2] = v;
807 RARRAY_PTR(data->buf)[data->n*2+1] = i;
808 data->n++;
809 if (data->n == SORT_BY_BUFSIZE) {
810 rb_ary_concat(ary, data->buf);
811 data->n = 0;
812 }
813 return Qnil;
814 }
815
816 static int
817 sort_by_cmp(const void *ap, const void *bp, void *data)
818 {
819 VALUE a;
820 VALUE b;
821 VALUE ary = (VALUE)data;
822
823 if (RBASIC(ary)->klass) {
824 rb_raise(rb_eRuntimeError, "sort_by reentered");
825 }
826
827 a = *(VALUE *)ap;
828 b = *(VALUE *)bp;
829
830 return rb_cmpint(rb_funcall(a, id_cmp, 1, b), a, b);
831 }
832
833 /*
834 * call-seq:
835 * enum.sort_by { |obj| block } -> array
836 * enum.sort_by -> an_enumerator
837 *
838 * Sorts <i>enum</i> using a set of keys generated by mapping the
839 * values in <i>enum</i> through the given block.
840 *
841 * If no block is given, an enumerator is returned instead.
842 *
843 * %w{apple pear fig}.sort_by { |word| word.length}
844 * #=> ["fig", "pear", "apple"]
845 *
846 * The current implementation of <code>sort_by</code> generates an
847 * array of tuples containing the original collection element and the
848 * mapped value. This makes <code>sort_by</code> fairly expensive when
849 * the keysets are simple.
850 *
851 * require 'benchmark'
852 *
853 * a = (1..100000).map { rand(100000) }
854 *
855 * Benchmark.bm(10) do |b|
856 * b.report("Sort") { a.sort }
857 * b.report("Sort by") { a.sort_by { |a| a } }
858 * end
859 *
860 * <em>produces:</em>
861 *
862 * user system total real
863 * Sort 0.180000 0.000000 0.180000 ( 0.175469)
864 * Sort by 1.980000 0.040000 2.020000 ( 2.013586)
865 *
866 * However, consider the case where comparing the keys is a non-trivial
867 * operation. The following code sorts some files on modification time
868 * using the basic <code>sort</code> method.
869 *
870 * files = Dir["*"]
871 * sorted = files.sort { |a, b| File.new(a).mtime <=> File.new(b).mtime }
872 * sorted #=> ["mon", "tues", "wed", "thurs"]
873 *
874 * This sort is inefficient: it generates two new <code>File</code>
875 * objects during every comparison. A slightly better technique is to
876 * use the <code>Kernel#test</code> method to generate the modification
877 * times directly.
878 *
879 * files = Dir["*"]
880 * sorted = files.sort { |a, b|
881 * test(?M, a) <=> test(?M, b)
882 * }
883 * sorted #=> ["mon", "tues", "wed", "thurs"]
884 *
885 * This still generates many unnecessary <code>Time</code> objects. A
886 * more efficient technique is to cache the sort keys (modification
887 * times in this case) before the sort. Perl users often call this
888 * approach a Schwartzian Transform, after Randal Schwartz. We
889 * construct a temporary array, where each element is an array
890 * containing our sort key along with the filename. We sort this array,
891 * and then extract the filename from the result.
892 *
893 * sorted = Dir["*"].collect { |f|
894 * [test(?M, f), f]
895 * }.sort.collect { |f| f[1] }
896 * sorted #=> ["mon", "tues", "wed", "thurs"]
897 *
898 * This is exactly what <code>sort_by</code> does internally.
899 *
900 * sorted = Dir["*"].sort_by { |f| test(?M, f) }
901 * sorted #=> ["mon", "tues", "wed", "thurs"]
902 */
903
904 static VALUE
905 enum_sort_by(VALUE obj)
906 {
907 VALUE ary, buf;
908 NODE *memo;
909 long i;
910 struct sort_by_data *data;
911
912 RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);
913
914 if (RB_TYPE_P(obj, T_ARRAY) && RARRAY_LEN(obj) <= LONG_MAX/2) {
915 ary = rb_ary_new2(RARRAY_LEN(obj)*2);
916 }
917 else {
918 ary = rb_ary_new();
919 }
920 RBASIC(ary)->klass = 0;
921 buf = rb_ary_tmp_new(SORT_BY_BUFSIZE*2);
922 rb_ary_store(buf, SORT_BY_BUFSIZE*2-1, Qnil);
923 memo = NEW_MEMO(0, 0, 0);
924 OBJ_INFECT(memo, obj);
925 data = (struct sort_by_data *)&memo->u1;
926 data->ary = ary;
927 data->buf = buf;
928 data->n = 0;
929 rb_block_call(obj, id_each, 0, 0, sort_by_i, (VALUE)memo);
930 ary = data->ary;
931 buf = data->buf;
932 if (data->n) {
933 rb_ary_resize(buf, data->n*2);
934 rb_ary_concat(ary, buf);
935 }
936 if (RARRAY_LEN(ary) > 2) {
937 ruby_qsort(RARRAY_PTR(ary), RARRAY_LEN(ary)/2, 2*sizeof(VALUE),
938 sort_by_cmp, (void *)ary);
939 }
940 if (RBASIC(ary)->klass) {
941 rb_raise(rb_eRuntimeError, "sort_by reentered");
942 }
943 for (i=1; i<RARRAY_LEN(ary); i+=2) {
944 RARRAY_PTR(ary)[i/2] = RARRAY_PTR(ary)[i];
945 }
946 rb_ary_resize(ary, RARRAY_LEN(ary)/2);
947 RBASIC(ary)->klass = rb_cArray;
948 OBJ_INFECT(ary, memo);
949
950 return ary;
951 }
952
953 #define ENUMFUNC(name) rb_block_given_p() ? name##_iter_i : name##_i
954
955 #define DEFINE_ENUMFUNCS(name) \
956 static VALUE enum_##name##_func(VALUE result, NODE *memo); \
957 \
958 static VALUE \
959 name##_i(VALUE i, VALUE memo, int argc, VALUE *argv) \
960 { \
961 return enum_##name##_func(rb_enum_values_pack(argc, argv), RNODE(memo)); \
962 } \
963 \
964 static VALUE \
965 name##_iter_i(VALUE i, VALUE memo, int argc, VALUE *argv) \
966 { \
967 return enum_##name##_func(enum_yield(argc, argv), RNODE(memo)); \
968 } \
969 \
970 static VALUE \
971 enum_##name##_func(VALUE result, NODE *memo)
972
973 DEFINE_ENUMFUNCS(all)
974 {
975 if (!RTEST(result)) {
976 memo->u1.value = Qfalse;
977 rb_iter_break();
978 }
979 return Qnil;
980 }
981
982 /*
983 * call-seq:
984 * enum.all? [{ |obj| block } ] -> true or false
985 *
986 * Passes each element of the collection to the given block. The method
987 * returns <code>true</code> if the block never returns
988 * <code>false</code> or <code>nil</code>. If the block is not given,
989 * Ruby adds an implicit block of <code>{ |obj| obj }</code> which will
990 * cause #all? to return +true+ when none of the collection members are
991 * +false+ or +nil+.
992 *
993 * %w[ant bear cat].all? { |word| word.length >= 3 } #=> true
994 * %w[ant bear cat].all? { |word| word.length >= 4 } #=> false
995 * [nil, true, 99].all? #=> false
996 *
997 */
998
999 static VALUE
1000 enum_all(VALUE obj)
1001 {
1002 NODE *memo = NEW_MEMO(Qtrue, 0, 0);
1003 rb_block_call(obj, id_each, 0, 0, ENUMFUNC(all), (VALUE)memo);
1004 return memo->u1.value;
1005 }
1006
1007 DEFINE_ENUMFUNCS(any)
1008 {
1009 if (RTEST(result)) {
1010 memo->u1.value = Qtrue;
1011 rb_iter_break();
1012 }
1013 return Qnil;
1014 }
1015
1016 /*
1017 * call-seq:
1018 * enum.any? [{ |obj| block }] -> true or false
1019 *
1020 * Passes each element of the collection to the given block. The method
1021 * returns <code>true</code> if the block ever returns a value other
1022 * than <code>false</code> or <code>nil</code>. If the block is not
1023 * given, Ruby adds an implicit block of <code>{ |obj| obj }</code> that
1024 * will cause #any? to return +true+ if at least one of the collection
1025 * members is not +false+ or +nil+.
1026 *
1027 * %w[ant bear cat].any? { |word| word.length >= 3 } #=> true
1028 * %w[ant bear cat].any? { |word| word.length >= 4 } #=> true
1029 * [nil, true, 99].any? #=> true
1030 *
1031 */
1032
1033 static VALUE
1034 enum_any(VALUE obj)
1035 {
1036 NODE *memo = NEW_MEMO(Qfalse, 0, 0);
1037 rb_block_call(obj, id_each, 0, 0, ENUMFUNC(any), (VALUE)memo);
1038 return memo->u1.value;
1039 }
1040
1041 DEFINE_ENUMFUNCS(one)
1042 {
1043 if (RTEST(result)) {
1044 if (memo->u1.value == Qundef) {
1045 memo->u1.value = Qtrue;
1046 }
1047 else if (memo->u1.value == Qtrue) {
1048 memo->u1.value = Qfalse;
1049 rb_iter_break();
1050 }
1051 }
1052 return Qnil;
1053 }
1054
1055 /*
1056 * call-seq:
1057 * enum.one? [{ |obj| block }] -> true or false
1058 *
1059 * Passes each element of the collection to the given block. The method
1060 * returns <code>true</code> if the block returns <code>true</code>
1061 * exactly once. If the block is not given, <code>one?</code> will return
1062 * <code>true</code> only if exactly one of the collection members is
1063 * true.
1064 *
1065 * %w{ant bear cat}.one? { |word| word.length == 4 } #=> true
1066 * %w{ant bear cat}.one? { |word| word.length > 4 } #=> false
1067 * %w{ant bear cat}.one? { |word| word.length < 4 } #=> false
1068 * [ nil, true, 99 ].one? #=> false
1069 * [ nil, true, false ].one? #=> true
1070 *
1071 */
1072
1073 static VALUE
1074 enum_one(VALUE obj)
1075 {
1076 NODE *memo = NEW_MEMO(Qundef, 0, 0);
1077 VALUE result;
1078
1079 rb_block_call(obj, id_each, 0, 0, ENUMFUNC(one), (VALUE)memo);
1080 result = memo->u1.value;
1081 if (result == Qundef) return Qfalse;
1082 return result;
1083 }
1084
1085 DEFINE_ENUMFUNCS(none)
1086 {
1087 if (RTEST(result)) {
1088 memo->u1.value = Qfalse;
1089 rb_iter_break();
1090 }
1091 return Qnil;
1092 }
1093
1094 /*
1095 * call-seq:
1096 * enum.none? [{ |obj| block }] -> true or false
1097 *
1098 * Passes each element of the collection to the given block. The method
1099 * returns <code>true</code> if the block never returns <code>true</code>
1100 * for all elements. If the block is not given, <code>none?</code> will return
1101 * <code>true</code> only if none of the collection members is true.
1102 *
1103 * %w{ant bear cat}.none? { |word| word.length == 5 } #=> true
1104 * %w{ant bear cat}.none? { |word| word.length >= 4 } #=> false
1105 * [].none? #=> true
1106 * [nil].none? #=> true
1107 * [nil, false].none? #=> true
1108 */
1109 static VALUE
1110 enum_none(VALUE obj)
1111 {
1112 NODE *memo = NEW_MEMO(Qtrue, 0, 0);
1113 rb_block_call(obj, id_each, 0, 0, ENUMFUNC(none), (VALUE)memo);
1114 return memo->u1.value;
1115 }
1116
1117 static VALUE
1118 min_i(VALUE i, VALUE args, int argc, VALUE *argv)
1119 {
1120 VALUE cmp;
1121 NODE *memo = RNODE(args);
1122
1123 ENUM_WANT_SVALUE();
1124
1125 if (memo->u1.value == Qundef) {
1126 memo->u1.value = i;
1127 }
1128 else {
1129 cmp = rb_funcall(i, id_cmp, 1, memo->u1.value);
1130 if (rb_cmpint(cmp, i, memo->u1.value) < 0) {
1131 memo->u1.value = i;
1132 }
1133 }
1134 return Qnil;
1135 }
1136
1137 static VALUE
1138 min_ii(VALUE i, VALUE args, int argc, VALUE *argv)
1139 {
1140 VALUE cmp;
1141 NODE *memo = RNODE(args);
1142
1143 ENUM_WANT_SVALUE();
1144
1145 if (memo->u1.value == Qundef) {
1146 memo->u1.value = i;
1147 }
1148 else {
1149 cmp = rb_yield_values(2, i, memo->u1.value);
1150 if (rb_cmpint(cmp, i, memo->u1.value) < 0) {
1151 memo->u1.value = i;
1152 }
1153 }
1154 return Qnil;
1155 }
1156
1157
1158 /*
1159 * call-seq:
1160 * enum.min -> obj
1161 * enum.min { |a, b| block } -> obj
1162 *
1163 * Returns the object in <i>enum</i> with the minimum value. The
1164 * first form assumes all objects implement <code>Comparable</code>;
1165 * the second uses the block to return <em>a <=> b</em>.
1166 *
1167 * a = %w(albatross dog horse)
1168 * a.min #=> "albatross"
1169 * a.min { |a, b| a.length <=> b.length } #=> "dog"
1170 */
1171
1172 static VALUE
1173 enum_min(VALUE obj)
1174 {
1175 NODE *memo = NEW_MEMO(Qundef, 0, 0);
1176 VALUE result;
1177
1178 if (rb_block_given_p()) {
1179 rb_block_call(obj, id_each, 0, 0, min_ii, (VALUE)memo);
1180 }
1181 else {
1182 rb_block_call(obj, id_each, 0, 0, min_i, (VALUE)memo);
1183 }
1184 result = memo->u1.value;
1185 if (result == Qundef) return Qnil;
1186 return result;
1187 }
1188
1189 static VALUE
1190 max_i(VALUE i, VALUE args, int argc, VALUE *argv)
1191 {
1192 NODE *memo = RNODE(args);
1193 VALUE cmp;
1194
1195 ENUM_WANT_SVALUE();
1196
1197 if (memo->u1.value == Qundef) {
1198 memo->u1.value = i;
1199 }
1200 else {
1201 cmp = rb_funcall(i, id_cmp, 1, memo->u1.value);
1202 if (rb_cmpint(cmp, i, memo->u1.value) > 0) {
1203 memo->u1.value = i;
1204 }
1205 }
1206 return Qnil;
1207 }
1208
1209 static VALUE
1210 max_ii(VALUE i, VALUE args, int argc, VALUE *argv)
1211 {
1212 NODE *memo = RNODE(args);
1213 VALUE cmp;
1214
1215 ENUM_WANT_SVALUE();
1216
1217 if (memo->u1.value == Qundef) {
1218 memo->u1.value = i;
1219 }
1220 else {
1221 cmp = rb_yield_values(2, i, memo->u1.value);
1222 if (rb_cmpint(cmp, i, memo->u1.value) > 0) {
1223 memo->u1.value = i;
1224 }
1225 }
1226 return Qnil;
1227 }
1228
1229 /*
1230 * call-seq:
1231 * enum.max -> obj
1232 * enum.max { |a, b| block } -> obj
1233 *
1234 * Returns the object in _enum_ with the maximum value. The
1235 * first form assumes all objects implement <code>Comparable</code>;
1236 * the second uses the block to return <em>a <=> b</em>.
1237 *
1238 * a = %w(albatross dog horse)
1239 * a.max #=> "horse"
1240 * a.max { |a, b| a.length <=> b.length } #=> "albatross"
1241 */
1242
1243 static VALUE
1244 enum_max(VALUE obj)
1245 {
1246 NODE *memo = NEW_MEMO(Qundef, 0, 0);
1247 VALUE result;
1248
1249 if (rb_block_given_p()) {
1250 rb_block_call(obj, id_each, 0, 0, max_ii, (VALUE)memo);
1251 }
1252 else {
1253 rb_block_call(obj, id_each, 0, 0, max_i, (VALUE)memo);
1254 }
1255 result = memo->u1.value;
1256 if (result == Qundef) return Qnil;
1257 return result;
1258 }
1259
1260 struct minmax_t {
1261 VALUE min;
1262 VALUE max;
1263 VALUE last;
1264 };
1265
1266 STATIC_ASSERT(minmax_t, sizeof(struct minmax_t) <= sizeof(NODE) - offsetof(NODE, u1));
1267
1268 static void
1269 minmax_i_update(VALUE i, VALUE j, struct minmax_t *memo)
1270 {
1271 int n;
1272
1273 if (memo->min == Qundef) {
1274 memo->min = i;
1275 memo->max = j;
1276 }
1277 else {
1278 n = rb_cmpint(rb_funcall(i, id_cmp, 1, memo->min), i, memo->min);
1279 if (n < 0) {
1280 memo->min = i;
1281 }
1282 n = rb_cmpint(rb_funcall(j, id_cmp, 1, memo->max), j, memo->max);
1283 if (n > 0) {
1284 memo->max = j;
1285 }
1286 }
1287 }
1288
1289 static VALUE
1290 minmax_i(VALUE i, VALUE _memo, int argc, VALUE *argv)
1291 {
1292 struct minmax_t *memo = (struct minmax_t *)&RNODE(_memo)->u1.value;
1293 int n;
1294 VALUE j;
1295
1296 ENUM_WANT_SVALUE();
1297
1298 if (memo->last == Qundef) {
1299 memo->last = i;
1300 return Qnil;
1301 }
1302 j = memo->last;
1303 memo->last = Qundef;
1304
1305 n = rb_cmpint(rb_funcall(j, id_cmp, 1, i), j, i);
1306 if (n == 0)
1307 i = j;
1308 else if (n < 0) {
1309 VALUE tmp;
1310 tmp = i;
1311 i = j;
1312 j = tmp;
1313 }
1314
1315 minmax_i_update(i, j, memo);
1316
1317 return Qnil;
1318 }
1319
1320 static void
1321 minmax_ii_update(VALUE i, VALUE j, struct minmax_t *memo)
1322 {
1323 int n;
1324
1325 if (memo->min == Qundef) {
1326 memo->min = i;
1327 memo->max = j;
1328 }
1329 else {
1330 n = rb_cmpint(rb_yield_values(2, i, memo->min), i, memo->min);
1331 if (n < 0) {
1332 memo->min = i;
1333 }
1334 n = rb_cmpint(rb_yield_values(2, j, memo->max), j, memo->max);
1335 if (n > 0) {
1336 memo->max = j;
1337 }
1338 }
1339 }
1340
1341 static VALUE
1342 minmax_ii(VALUE i, VALUE _memo, int argc, VALUE *argv)
1343 {
1344 struct minmax_t *memo = (struct minmax_t *)&RNODE(_memo)->u1.value;
1345 int n;
1346 VALUE j;
1347
1348 ENUM_WANT_SVALUE();
1349
1350 if (memo->last == Qundef) {
1351 memo->last = i;
1352 return Qnil;
1353 }
1354 j = memo->last;
1355 memo->last = Qundef;
1356
1357 n = rb_cmpint(rb_yield_values(2, j, i), j, i);
1358 if (n == 0)
1359 i = j;
1360 else if (n < 0) {
1361 VALUE tmp;
1362 tmp = i;
1363 i = j;
1364 j = tmp;
1365 }
1366
1367 minmax_ii_update(i, j, memo);
1368
1369 return Qnil;
1370 }
1371
1372 /*
1373 * call-seq:
1374 * enum.minmax -> [min, max]
1375 * enum.minmax { |a, b| block } -> [min, max]
1376 *
1377 * Returns two elements array which contains the minimum and the
1378 * maximum value in the enumerable. The first form assumes all
1379 * objects implement <code>Comparable</code>; the second uses the
1380 * block to return <em>a <=> b</em>.
1381 *
1382 * a = %w(albatross dog horse)
1383 * a.minmax #=> ["albatross", "horse"]
1384 * a.minmax { |a, b| a.length <=> b.length } #=> ["dog", "albatross"]
1385 */
1386
1387 static VALUE
1388 enum_minmax(VALUE obj)
1389 {
1390 NODE *memo = NEW_MEMO(Qundef, Qundef, Qundef);
1391 struct minmax_t *m = (struct minmax_t *)&memo->u1.value;
1392 VALUE ary = rb_ary_new3(2, Qnil, Qnil);
1393
1394 m->min = Qundef;
1395 m->last = Qundef;
1396 if (rb_block_given_p()) {
1397 rb_block_call(obj, id_each, 0, 0, minmax_ii, (VALUE)memo);
1398 if (m->last != Qundef)
1399 minmax_ii_update(m->last, m->last, m);
1400 }
1401 else {
1402 rb_block_call(obj, id_each, 0, 0, minmax_i, (VALUE)memo);
1403 if (m->last != Qundef)
1404 minmax_i_update(m->last, m->last, m);
1405 }
1406 if (m->min != Qundef) {
1407 rb_ary_store(ary, 0, m->min);
1408 rb_ary_store(ary, 1, m->max);
1409 }
1410 return ary;
1411 }
1412
1413 static VALUE
1414 min_by_i(VALUE i, VALUE args, int argc, VALUE *argv)
1415 {
1416 NODE *memo = RNODE(args);
1417 VALUE v;
1418
1419 ENUM_WANT_SVALUE();
1420
1421 v = rb_yield(i);
1422 if (memo->u1.value == Qundef) {
1423 memo->u1.value = v;
1424 memo->u2.value = i;
1425 }
1426 else if (rb_cmpint(rb_funcall(v, id_cmp, 1, memo->u1.value), v, memo->u1.value) < 0) {
1427 memo->u1.value = v;
1428 memo->u2.value = i;
1429 }
1430 return Qnil;
1431 }
1432
1433 /*
1434 * call-seq:
1435 * enum.min_by { |obj| block } -> obj
1436 * enum.min_by -> an_enumerator
1437 *
1438 * Returns the object in <i>enum</i> that gives the minimum
1439 * value from the given block.
1440 *
1441 * If no block is given, an enumerator is returned instead.
1442 *
1443 * a = %w(albatross dog horse)
1444 * a.min_by { |x| x.length } #=> "dog"
1445 */
1446
1447 static VALUE
1448 enum_min_by(VALUE obj)
1449 {
1450 NODE *memo;
1451
1452 RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);
1453
1454 memo = NEW_MEMO(Qundef, Qnil, 0);
1455 rb_block_call(obj, id_each, 0, 0, min_by_i, (VALUE)memo);
1456 return memo->u2.value;
1457 }
1458
1459 static VALUE
1460 max_by_i(VALUE i, VALUE args, int argc, VALUE *argv)
1461 {
1462 NODE *memo = RNODE(args);
1463 VALUE v;
1464
1465 ENUM_WANT_SVALUE();
1466
1467 v = rb_yield(i);
1468 if (memo->u1.value == Qundef) {
1469 memo->u1.value = v;
1470 memo->u2.value = i;
1471 }
1472 else if (rb_cmpint(rb_funcall(v, id_cmp, 1, memo->u1.value), v, memo->u1.value) > 0) {
1473 memo->u1.value = v;
1474 memo->u2.value = i;
1475 }
1476 return Qnil;
1477 }
1478
1479 /*
1480 * call-seq:
1481 * enum.max_by { |obj| block } -> obj
1482 * enum.max_by -> an_enumerator
1483 *
1484 * Returns the object in <i>enum</i> that gives the maximum
1485 * value from the given block.
1486 *
1487 * If no block is given, an enumerator is returned instead.
1488 *
1489 * a = %w(albatross dog horse)
1490 * a.max_by { |x| x.length } #=> "albatross"
1491 */
1492
1493 static VALUE
1494 enum_max_by(VALUE obj)
1495 {
1496 NODE *memo;
1497
1498 RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);
1499
1500 memo = NEW_MEMO(Qundef, Qnil, 0);
1501 rb_block_call(obj, id_each, 0, 0, max_by_i, (VALUE)memo);
1502 return memo->u2.value;
1503 }
1504
1505 struct minmax_by_t {
1506 VALUE min_bv;
1507 VALUE max_bv;
1508 VALUE min;
1509 VALUE max;
1510 VALUE last_bv;
1511 VALUE last;
1512 };
1513
1514 static void
1515 minmax_by_i_update(VALUE v1, VALUE v2, VALUE i1, VALUE i2, struct minmax_by_t *memo)
1516 {
1517 if (memo->min_bv == Qundef) {
1518 memo->min_bv = v1;
1519 memo->max_bv = v2;
1520 memo->min = i1;
1521 memo->max = i2;
1522 }
1523 else {
1524 if (rb_cmpint(rb_funcall(v1, id_cmp, 1, memo->min_bv), v1, memo->min_bv) < 0) {
1525 memo->min_bv = v1;
1526 memo->min = i1;
1527 }
1528 if (rb_cmpint(rb_funcall(v2, id_cmp, 1, memo->max_bv), v2, memo->max_bv) > 0) {
1529 memo->max_bv = v2;
1530 memo->max = i2;
1531 }
1532 }
1533 }
1534
1535 static VALUE
1536 minmax_by_i(VALUE i, VALUE _memo, int argc, VALUE *argv)
1537 {
1538 struct minmax_by_t *memo = MEMO_FOR(struct minmax_by_t, _memo);
1539 VALUE vi, vj, j;
1540 int n;
1541
1542 ENUM_WANT_SVALUE();
1543
1544 vi = rb_yield(i);
1545
1546 if (memo->last_bv == Qundef) {
1547 memo->last_bv = vi;
1548 memo->last = i;
1549 return Qnil;
1550 }
1551 vj = memo->last_bv;
1552 j = memo->last;
1553 memo->last_bv = Qundef;
1554
1555 n = rb_cmpint(rb_funcall(vj, id_cmp, 1, vi), vj, vi);
1556 if (n == 0) {
1557 i = j;
1558 vi = vj;
1559 }
1560 else if (n < 0) {
1561 VALUE tmp;
1562 tmp = i;
1563 i = j;
1564 j = tmp;
1565 tmp = vi;
1566 vi = vj;
1567 vj = tmp;
1568 }
1569
1570 minmax_by_i_update(vi, vj, i, j, memo);
1571
1572 return Qnil;
1573 }
1574
1575 /*
1576 * call-seq:
1577 * enum.minmax_by { |obj| block } -> [min, max]
1578 * enum.minmax_by -> an_enumerator
1579 *
1580 * Returns a two element array containing the objects in
1581 * <i>enum</i> that correspond to the minimum and maximum values respectively
1582 * from the given block.
1583 *
1584 * If no block is given, an enumerator is returned instead.
1585 *
1586 * a = %w(albatross dog horse)
1587 * a.minmax_by { |x| x.length } #=> ["dog", "albatross"]
1588 */
1589
1590 static VALUE
1591 enum_minmax_by(VALUE obj)
1592 {
1593 VALUE memo;
1594 struct minmax_by_t *m = NEW_MEMO_FOR(struct minmax_by_t, memo);
1595
1596 RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);
1597
1598 m->min_bv = Qundef;
1599 m->max_bv = Qundef;
1600 m->min = Qnil;
1601 m->max = Qnil;
1602 m->last_bv = Qundef;
1603 m->last = Qundef;
1604 rb_block_call(obj, id_each, 0, 0, minmax_by_i, memo);
1605 if (m->last_bv != Qundef)
1606 minmax_by_i_update(m->last_bv, m->last_bv, m->last, m->last, m);
1607 m = MEMO_FOR(struct minmax_by_t, memo);
1608 return rb_assoc_new(m->min, m->max);
1609 }
1610
1611 static VALUE
1612 member_i(VALUE iter, VALUE args, int argc, VALUE *argv)
1613 {
1614 NODE *memo = RNODE(args);
1615
1616 if (rb_equal(rb_enum_values_pack(argc, argv), memo->u1.value)) {
1617 memo->u2.value = Qtrue;
1618 rb_iter_break();
1619 }
1620 return Qnil;
1621 }
1622
1623 /*
1624 * call-seq:
1625 * enum.include?(obj) -> true or false
1626 * enum.member?(obj) -> true or false
1627 *
1628 * Returns <code>true</code> if any member of <i>enum</i> equals
1629 * <i>obj</i>. Equality is tested using <code>==</code>.
1630 *
1631 * IO.constants.include? :SEEK_SET #=> true
1632 * IO.constants.include? :SEEK_NO_FURTHER #=> false
1633 *
1634 */
1635
1636 static VALUE
1637 enum_member(VALUE obj, VALUE val)
1638 {
1639 NODE *memo = NEW_MEMO(val, Qfalse, 0);
1640
1641 rb_block_call(obj, id_each, 0, 0, member_i, (VALUE)memo);
1642 return memo->u2.value;
1643 }
1644
1645 static VALUE
1646 each_with_index_i(VALUE i, VALUE memo, int argc, VALUE *argv)
1647 {
1648 long n = RNODE(memo)->u3.cnt++;
1649
1650 return rb_yield_values(2, rb_enum_values_pack(argc, argv), INT2NUM(n));
1651 }
1652
1653 /*
1654 * call-seq:
1655 * enum.each_with_index(*args) { |obj, i| block } -> enum
1656 * enum.each_with_index(*args) -> an_enumerator
1657 *
1658 * Calls <em>block</em> with two arguments, the item and its index,
1659 * for each item in <i>enum</i>. Given arguments are passed through
1660 * to #each().
1661 *
1662 * If no block is given, an enumerator is returned instead.
1663 *
1664 * hash = Hash.new
1665 * %w(cat dog wombat).each_with_index { |item, index|
1666 * hash[item] = index
1667 * }
1668 * hash #=> {"cat"=>0, "dog"=>1, "wombat"=>2}
1669 *
1670 */
1671
1672 static VALUE
1673 enum_each_with_index(int argc, VALUE *argv, VALUE obj)
1674 {
1675 NODE *memo;
1676
1677 RETURN_SIZED_ENUMERATOR(obj, argc, argv, enum_size);
1678
1679 memo = NEW_MEMO(0, 0, 0);
1680 rb_block_call(obj, id_each, argc, argv, each_with_index_i, (VALUE)memo);
1681 return obj;
1682 }
1683
1684
1685 /*
1686 * call-seq:
1687 * enum.reverse_each(*args) { |item| block } -> enum
1688 * enum.reverse_each(*args) -> an_enumerator
1689 *
1690 * Builds a temporary array and traverses that array in reverse order.
1691 *
1692 * If no block is given, an enumerator is returned instead.
1693 *
1694 * (1..3).reverse_each { |v| p v }
1695 *
1696 * produces:
1697 *
1698 * 3
1699 * 2
1700 * 1
1701 */
1702
1703 static VALUE
1704 enum_reverse_each(int argc, VALUE *argv, VALUE obj)
1705 {
1706 VALUE ary;
1707 long i;
1708
1709 RETURN_SIZED_ENUMERATOR(obj, argc, argv, enum_size);
1710
1711 ary = enum_to_a(argc, argv, obj);
1712
1713 for (i = RARRAY_LEN(ary); --i >= 0; ) {
1714 rb_yield(RARRAY_PTR(ary)[i]);
1715 }
1716
1717 return obj;
1718 }
1719
1720
1721 static VALUE
1722 each_val_i(VALUE i, VALUE p, int argc, VALUE *argv)
1723 {
1724 ENUM_WANT_SVALUE();
1725 rb_yield(i);
1726 return Qnil;
1727 }
1728
1729 /*
1730 * call-seq:
1731 * enum.each_entry { |obj| block } -> enum
1732 * enum.each_entry -> an_enumerator
1733 *
1734 * Calls <i>block</i> once for each element in +self+, passing that
1735 * element as a parameter, converting multiple values from yield to an
1736 * array.
1737 *
1738 * If no block is given, an enumerator is returned instead.
1739 *
1740 * class Foo
1741 * include Enumerable
1742 * def each
1743 * yield 1
1744 * yield 1, 2
1745 * yield
1746 * end
1747 * end
1748 * Foo.new.each_entry{ |o| p o }
1749 *
1750 * produces:
1751 *
1752 * 1
1753 * [1, 2]
1754 * nil
1755 *
1756 */
1757
1758 static VALUE
1759 enum_each_entry(int argc, VALUE *argv, VALUE obj)
1760 {
1761 RETURN_SIZED_ENUMERATOR(obj, argc, argv, enum_size);
1762 rb_block_call(obj, id_each, argc, argv, each_val_i, 0);
1763 return obj;
1764 }
1765
1766 static VALUE
1767 each_slice_i(VALUE i, VALUE m, int argc, VALUE *argv)
1768 {
1769 NODE *memo = RNODE(m);
1770 VALUE ary = memo->u1.value;
1771 VALUE v = Qnil;
1772 long size = memo->u3.cnt;
1773 ENUM_WANT_SVALUE();
1774
1775 rb_ary_push(ary, i);
1776
1777 if (RARRAY_LEN(ary) == size) {
1778 v = rb_yield(ary);
1779 memo->u1.value = rb_ary_new2(size);
1780 }
1781
1782 return v;
1783 }
1784
1785 static VALUE
1786 enum_each_slice_size(VALUE obj, VALUE args)
1787 {
1788 VALUE n, size;
1789 long slice_size = NUM2LONG(RARRAY_PTR(args)[0]);
1790 if (slice_size <= 0) rb_raise(rb_eArgError, "invalid slice size");
1791
1792 size = enum_size(obj, 0);
1793 if (size == Qnil) return Qnil;
1794
1795 n = rb_funcall(size, '+', 1, LONG2NUM(slice_size-1));
1796 return rb_funcall(n, id_div, 1, LONG2FIX(slice_size));
1797 }
1798
1799 /*
1800 * call-seq:
1801 * enum.each_slice(n) { ... } -> nil
1802 * enum.each_slice(n) -> an_enumerator
1803 *
1804 * Iterates the given block for each slice of <n> elements. If no
1805 * block is given, returns an enumerator.
1806 *
1807 * (1..10).each_slice(3) { |a| p a }
1808 * # outputs below
1809 * [1, 2, 3]
1810 * [4, 5, 6]
1811 * [7, 8, 9]
1812 * [10]
1813 *
1814 */
1815 static VALUE
1816 enum_each_slice(VALUE obj, VALUE n)
1817 {
1818 long size = NUM2LONG(n);
1819 VALUE ary;
1820 NODE *memo;
1821
1822 if (size <= 0) rb_raise(rb_eArgError, "invalid slice size");
1823 RETURN_SIZED_ENUMERATOR(obj, 1, &n, enum_each_slice_size);
1824 ary = rb_ary_new2(size);
1825 memo = NEW_MEMO(ary, 0, size);
1826 rb_block_call(obj, id_each, 0, 0, each_slice_i, (VALUE)memo);
1827 ary = memo->u1.value;
1828 if (RARRAY_LEN(ary) > 0) rb_yield(ary);
1829
1830 return Qnil;
1831 }
1832
1833 static VALUE
1834 each_cons_i(VALUE i, VALUE args, int argc, VALUE *argv)
1835 {
1836 NODE *memo = RNODE(args);
1837 VALUE ary = memo->u1.value;
1838 VALUE v = Qnil;
1839 long size = memo->u3.cnt;
1840 ENUM_WANT_SVALUE();
1841
1842 if (RARRAY_LEN(ary) == size) {
1843 rb_ary_shift(ary);
1844 }
1845 rb_ary_push(ary, i);
1846 if (RARRAY_LEN(ary) == size) {
1847 v = rb_yield(rb_ary_dup(ary));
1848 }
1849 return v;
1850 }
1851
1852 static VALUE
1853 enum_each_cons_size(VALUE obj, VALUE args)
1854 {
1855 VALUE n, size;
1856 long cons_size = NUM2LONG(RARRAY_PTR(args)[0]);
1857 if (cons_size <= 0) rb_raise(rb_eArgError, "invalid size");
1858
1859 size = enum_size(obj, 0);
1860 if (size == Qnil) return Qnil;
1861
1862 n = rb_funcall(size, '+', 1, LONG2NUM(1 - cons_size));
1863 return (rb_cmpint(rb_funcall(n, id_cmp, 1, LONG2FIX(0)), n, LONG2FIX(0)) == -1) ? LONG2FIX(0) : n;
1864 }
1865
1866 /*
1867 * call-seq:
1868 * enum.each_cons(n) { ... } -> nil
1869 * enum.each_cons(n) -> an_enumerator
1870 *
1871 * Iterates the given block for each array of consecutive <n>
1872 * elements. If no block is given, returns an enumerator.
1873 *
1874 * e.g.:
1875 * (1..10).each_cons(3) { |a| p a }
1876 * # outputs below
1877 * [1, 2, 3]
1878 * [2, 3, 4]
1879 * [3, 4, 5]
1880 * [4, 5, 6]
1881 * [5, 6, 7]
1882 * [6, 7, 8]
1883 * [7, 8, 9]
1884 * [8, 9, 10]
1885 *
1886 */
1887 static VALUE
1888 enum_each_cons(VALUE obj, VALUE n)
1889 {
1890 long size = NUM2LONG(n);
1891 NODE *memo;
1892
1893 if (size <= 0) rb_raise(rb_eArgError, "invalid size");
1894 RETURN_SIZED_ENUMERATOR(obj, 1, &n, enum_each_cons_size);
1895 memo = NEW_MEMO(rb_ary_new2(size), 0, size);
1896 rb_block_call(obj, id_each, 0, 0, each_cons_i, (VALUE)memo);
1897
1898 return Qnil;
1899 }
1900
1901 static VALUE
1902 each_with_object_i(VALUE i, VALUE memo, int argc, VALUE *argv)
1903 {
1904 ENUM_WANT_SVALUE();
1905 return rb_yield_values(2, i, memo);
1906 }
1907
1908 /*
1909 * call-seq:
1910 * enum.each_with_object(obj) { |(*args), memo_obj| ... } -> obj
1911 * enum.each_with_object(obj) -> an_enumerator
1912 *
1913 * Iterates the given block for each element with an arbitrary
1914 * object given, and returns the initially given object.
1915 *
1916 * If no block is given, returns an enumerator.
1917 *
1918 * evens = (1..10).each_with_object([]) { |i, a| a << i*2 }
1919 * #=> [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
1920 *
1921 */
1922 static VALUE
1923 enum_each_with_object(VALUE obj, VALUE memo)
1924 {
1925 RETURN_SIZED_ENUMERATOR(obj, 1, &memo, enum_size);
1926
1927 rb_block_call(obj, id_each, 0, 0, each_with_object_i, memo);
1928
1929 return memo;
1930 }
1931
1932 static VALUE
1933 zip_ary(VALUE val, NODE *memo, int argc, VALUE *argv)
1934 {
1935 volatile VALUE result = memo->u1.value;
1936 volatile VALUE args = memo->u2.value;
1937 long n = memo->u3.cnt++;
1938 volatile VALUE tmp;
1939 int i;
1940
1941 tmp = rb_ary_new2(RARRAY_LEN(args) + 1);
1942 rb_ary_store(tmp, 0, rb_enum_values_pack(argc, argv));
1943 for (i=0; i<RARRAY_LEN(args); i++) {
1944 VALUE e = RARRAY_PTR(args)[i];
1945
1946 if (RARRAY_LEN(e) <= n) {
1947 rb_ary_push(tmp, Qnil);
1948 }
1949 else {
1950 rb_ary_push(tmp, RARRAY_PTR(e)[n]);
1951 }
1952 }
1953 if (NIL_P(result)) {
1954 rb_yield(tmp);
1955 }
1956 else {
1957 rb_ary_push(result, tmp);
1958 }
1959 return Qnil;
1960 }
1961
1962 static VALUE
1963 call_next(VALUE *v)
1964 {
1965 return v[0] = rb_funcall(v[1], id_next, 0, 0);
1966 }
1967
1968 static VALUE
1969 call_stop(VALUE *v)
1970 {
1971 return v[0] = Qundef;
1972 }
1973
1974 static VALUE
1975 zip_i(VALUE val, NODE *memo, int argc, VALUE *argv)
1976 {
1977 volatile VALUE result = memo->u1.value;
1978 volatile VALUE args = memo->u2.value;
1979 volatile VALUE tmp;
1980 int i;
1981
1982 tmp = rb_ary_new2(RARRAY_LEN(args) + 1);
1983 rb_ary_store(tmp, 0, rb_enum_values_pack(argc, argv));
1984 for (i=0; i<RARRAY_LEN(args); i++) {
1985 if (NIL_P(RARRAY_PTR(args)[i])) {
1986 rb_ary_push(tmp, Qnil);
1987 }
1988 else {
1989 VALUE v[2];
1990
1991 v[1] = RARRAY_PTR(args)[i];
1992 rb_rescue2(call_next, (VALUE)v, call_stop, (VALUE)v, rb_eStopIteration, (VALUE)0);
1993 if (v[0] == Qundef) {
1994 RARRAY_PTR(args)[i] = Qnil;
1995 v[0] = Qnil;
1996 }
1997 rb_ary_push(tmp, v[0]);
1998 }
1999 }
2000 if (NIL_P(result)) {
2001 rb_yield(tmp);
2002 }
2003 else {
2004 rb_ary_push(result, tmp);
2005 }
2006 return Qnil;
2007 }
2008
2009 /*
2010 * call-seq:
2011 * enum.zip(arg, ...) -> an_array_of_array
2012 * enum.zip(arg, ...) { |arr| block } -> nil
2013 *
2014 * Takes one element from <i>enum</i> and merges corresponding
2015 * elements from each <i>args</i>. This generates a sequence of
2016 * <em>n</em>-element arrays, where <em>n</em> is one more than the
2017 * count of arguments. The length of the resulting sequence will be
2018 * <code>enum#size</code>. If the size of any argument is less than
2019 * <code>enum#size</code>, <code>nil</code> values are supplied. If
2020 * a block is given, it is invoked for each output array, otherwise
2021 * an array of arrays is returned.
2022 *
2023 * a = [ 4, 5, 6 ]
2024 * b = [ 7, 8, 9 ]
2025 *
2026 * [1, 2, 3].zip(a, b) #=> [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
2027 * [1, 2].zip(a, b) #=> [[1, 4, 7], [2, 5, 8]]
2028 * a.zip([1, 2], [8]) #=> [[4, 1, 8], [5, 2, nil], [6, nil, nil]]
2029 *
2030 */
2031
2032 static VALUE
2033 enum_zip(int argc, VALUE *argv, VALUE obj)
2034 {
2035 int i;
2036 ID conv;
2037 NODE *memo;
2038 VALUE result = Qnil;
2039 VALUE args = rb_ary_new4(argc, argv);
2040 int allary = TRUE;
2041
2042 argv = RARRAY_PTR(args);
2043 for (i=0; i<argc; i++) {
2044 VALUE ary = rb_check_array_type(argv[i]);
2045 if (NIL_P(ary)) {
2046 allary = FALSE;
2047 break;
2048 }
2049 argv[i] = ary;
2050 }
2051 if (!allary) {
2052 CONST_ID(conv, "to_enum");
2053 for (i=0; i<argc; i++) {
2054 if (!rb_respond_to(argv[i], id_each)) {
2055 rb_raise(rb_eTypeError, "wrong argument type %s (must respond to :each)",
2056 rb_obj_classname(argv[i]));
2057 }
2058 argv[i] = rb_funcall(argv[i], conv, 1, ID2SYM(id_each));
2059 }
2060 }
2061 if (!rb_block_given_p()) {
2062 result = rb_ary_new();
2063 }
2064 /* use NODE_DOT2 as memo(v, v, -) */
2065 memo = rb_node_newnode(NODE_DOT2, result, args, 0);
2066 rb_block_call(obj, id_each, 0, 0, allary ? zip_ary : zip_i, (VALUE)memo);
2067
2068 return result;
2069 }
2070
2071 static VALUE
2072 take_i(VALUE i, VALUE args, int argc, VALUE *argv)
2073 {
2074 NODE *memo = RNODE(args);
2075 rb_ary_push(memo->u1.value, rb_enum_values_pack(argc, argv));
2076 if (--memo->u3.cnt == 0) rb_iter_break();
2077 return Qnil;
2078 }
2079
2080 /*
2081 * call-seq:
2082 * enum.take(n) -> array
2083 *
2084 * Returns first n elements from <i>enum</i>.
2085 *
2086 * a = [1, 2, 3, 4, 5, 0]
2087 * a.take(3) #=> [1, 2, 3]
2088 *
2089 */
2090
2091 static VALUE
2092 enum_take(VALUE obj, VALUE n)
2093 {
2094 NODE *memo;
2095 VALUE result;
2096 long len = NUM2LONG(n);
2097
2098 if (len < 0) {
2099 rb_raise(rb_eArgError, "attempt to take negative size");
2100 }
2101
2102 if (len == 0) return rb_ary_new2(0);
2103 result = rb_ary_new2(len);
2104 memo = NEW_MEMO(result, 0, len);
2105 rb_block_call(obj, id_each, 0, 0, take_i, (VALUE)memo);
2106 return result;
2107 }
2108
2109
2110 static VALUE
2111 take_while_i(VALUE i, VALUE ary, int argc, VALUE *argv)
2112 {
2113 if (!RTEST(enum_yield(argc, argv))) rb_iter_break();
2114 rb_ary_push(ary, rb_enum_values_pack(argc, argv));
2115 return Qnil;
2116 }
2117
2118 /*
2119 * call-seq:
2120 * enum.take_while { |arr| block } -> array
2121 * enum.take_while -> an_enumerator
2122 *
2123 * Passes elements to the block until the block returns +nil+ or +false+,
2124 * then stops iterating and returns an array of all prior elements.
2125 *
2126 * If no block is given, an enumerator is returned instead.
2127 *
2128 * a = [1, 2, 3, 4, 5, 0]
2129 * a.take_while { |i| i < 3 } #=> [1, 2]
2130 *
2131 */
2132
2133 static VALUE
2134 enum_take_while(VALUE obj)
2135 {
2136 VALUE ary;
2137
2138 RETURN_ENUMERATOR(obj, 0, 0);
2139 ary = rb_ary_new();
2140 rb_block_call(obj, id_each, 0, 0, take_while_i, ary);
2141 return ary;
2142 }
2143
2144 static VALUE
2145 drop_i(VALUE i, VALUE args, int argc, VALUE *argv)
2146 {
2147 NODE *memo = RNODE(args);
2148 if (memo->u3.cnt == 0) {
2149 rb_ary_push(memo->u1.value, rb_enum_values_pack(argc, argv));
2150 }
2151 else {
2152 memo->u3.cnt--;
2153 }
2154 return Qnil;
2155 }
2156
2157 /*
2158 * call-seq:
2159 * enum.drop(n) -> array
2160 *
2161 * Drops first n elements from <i>enum</i>, and returns rest elements
2162 * in an array.
2163 *
2164 * a = [1, 2, 3, 4, 5, 0]
2165 * a.drop(3) #=> [4, 5, 0]
2166 *
2167 */
2168
2169 static VALUE
2170 enum_drop(VALUE obj, VALUE n)
2171 {
2172 VALUE result;
2173 NODE *memo;
2174 long len = NUM2LONG(n);
2175
2176 if (len < 0) {
2177 rb_raise(rb_eArgError, "attempt to drop negative size");
2178 }
2179
2180 result = rb_ary_new();
2181 memo = NEW_MEMO(result, 0, len);
2182 rb_block_call(obj, id_each, 0, 0, drop_i, (VALUE)memo);
2183 return result;
2184 }
2185
2186
2187 static VALUE
2188 drop_while_i(VALUE i, VALUE args, int argc, VALUE *argv)
2189 {
2190 NODE *memo = RNODE(args);
2191 ENUM_WANT_SVALUE();
2192
2193 if (!memo->u3.state && !RTEST(rb_yield(i))) {
2194 memo->u3.state = TRUE;
2195 }
2196 if (memo->u3.state) {
2197 rb_ary_push(memo->u1.value, i);
2198 }
2199 return Qnil;
2200 }
2201
2202 /*
2203 * call-seq:
2204 * enum.drop_while { |arr| block } -> array
2205 * enum.drop_while -> an_enumerator
2206 *
2207 * Drops elements up to, but not including, the first element for
2208 * which the block returns +nil+ or +false+ and returns an array
2209 * containing the remaining elements.
2210 *
2211 * If no block is given, an enumerator is returned instead.
2212 *
2213 * a = [1, 2, 3, 4, 5, 0]
2214 * a.drop_while { |i| i < 3 } #=> [3, 4, 5, 0]
2215 *
2216 */
2217
2218 static VALUE
2219 enum_drop_while(VALUE obj)
2220 {
2221 VALUE result;
2222 NODE *memo;
2223
2224 RETURN_ENUMERATOR(obj, 0, 0);
2225 result = rb_ary_new();
2226 memo = NEW_MEMO(result, 0, FALSE);
2227 rb_block_call(obj, id_each, 0, 0, drop_while_i, (VALUE)memo);
2228 return result;
2229 }
2230
2231 static VALUE
2232 cycle_i(VALUE i, VALUE ary, int argc, VALUE *argv)
2233 {
2234 ENUM_WANT_SVALUE();
2235
2236 rb_ary_push(ary, i);
2237 rb_yield(i);
2238 return Qnil;
2239 }
2240
2241 static VALUE
2242 enum_cycle_size(VALUE self, VALUE args)
2243 {
2244 long mul;
2245 VALUE n = Qnil;
2246 VALUE size = enum_size(self, args);
2247
2248 if (size == Qnil) return Qnil;
2249
2250 if (args && (RARRAY_LEN(args) > 0)) {
2251 n = RARRAY_PTR(args)[0];
2252 }
2253 if (n == Qnil) return DBL2NUM(INFINITY);
2254 mul = NUM2LONG(n);
2255 if (mul <= 0) return INT2FIX(0);
2256 return rb_funcall(size, '*', 1, LONG2FIX(mul));
2257 }
2258
2259 /*
2260 * call-seq:
2261 * enum.cycle(n=nil) { |obj| block } -> nil
2262 * enum.cycle(n=nil) -> an_enumerator
2263 *
2264 * Calls <i>block</i> for each element of <i>enum</i> repeatedly _n_
2265 * times or forever if none or +nil+ is given. If a non-positive
2266 * number is given or the collection is empty, does nothing. Returns
2267 * +nil+ if the loop has finished without getting interrupted.
2268 *
2269 * Enumerable#cycle saves elements in an internal array so changes
2270 * to <i>enum</i> after the first pass have no effect.
2271 *
2272 * If no block is given, an enumerator is returned instead.
2273 *
2274 * a = ["a", "b", "c"]
2275 * a.cycle { |x| puts x } # print, a, b, c, a, b, c,.. forever.
2276 * a.cycle(2) { |x| puts x } # print, a, b, c, a, b, c.
2277 *
2278 */
2279
2280 static VALUE
2281 enum_cycle(int argc, VALUE *argv, VALUE obj)
2282 {
2283 VALUE ary;
2284 VALUE nv = Qnil;
2285 long n, i, len;
2286
2287 rb_scan_args(argc, argv, "01", &nv);
2288
2289 RETURN_SIZED_ENUMERATOR(obj, argc, argv, enum_cycle_size);
2290 if (NIL_P(nv)) {
2291 n = -1;
2292 }
2293 else {
2294 n = NUM2LONG(nv);
2295 if (n <= 0) return Qnil;
2296 }
2297 ary = rb_ary_new();
2298 RBASIC(ary)->klass = 0;
2299 rb_block_call(obj, id_each, 0, 0, cycle_i, ary);
2300 len = RARRAY_LEN(ary);
2301 if (len == 0) return Qnil;
2302 while (n < 0 || 0 < --n) {
2303 for (i=0; i<len; i++) {
2304 rb_yield(RARRAY_PTR(ary)[i]);
2305 }
2306 }
2307 return Qnil;
2308 }
2309
2310 struct chunk_arg {
2311 VALUE categorize;
2312 VALUE state;
2313 VALUE prev_value;
2314 VALUE prev_elts;
2315 VALUE yielder;
2316 };
2317
2318 static VALUE
2319 chunk_ii(VALUE i, VALUE _argp, int argc, VALUE *argv)
2320 {
2321 struct chunk_arg *argp = MEMO_FOR(struct chunk_arg, _argp);
2322 VALUE v;
2323 VALUE alone = ID2SYM(rb_intern("_alone"));
2324 VALUE separator = ID2SYM(rb_intern("_separator"));
2325
2326 ENUM_WANT_SVALUE();
2327
2328 if (NIL_P(argp->state))
2329 v = rb_funcall(argp->categorize, id_call, 1, i);
2330 else
2331 v = rb_funcall(argp->categorize, id_call, 2, i, argp->state);
2332
2333 if (v == alone) {
2334 if (!NIL_P(argp->prev_value)) {
2335 rb_funcall(argp->yielder, id_lshift, 1, rb_assoc_new(argp->prev_value, argp->prev_elts));
2336 argp->prev_value = argp->prev_elts = Qnil;
2337 }
2338 rb_funcall(argp->yielder, id_lshift, 1, rb_assoc_new(v, rb_ary_new3(1, i)));
2339 }
2340 else if (NIL_P(v) || v == separator) {
2341 if (!NIL_P(argp->prev_value)) {
2342 rb_funcall(argp->yielder, id_lshift, 1, rb_assoc_new(argp->prev_value, argp->prev_elts));
2343 argp->prev_value = argp->prev_elts = Qnil;
2344 }
2345 }
2346 else if (SYMBOL_P(v) && rb_id2name(SYM2ID(v))[0] == '_') {
2347 rb_raise(rb_eRuntimeError, "symbol begins with an underscore is reserved");
2348 }
2349 else {
2350 if (NIL_P(argp->prev_value)) {
2351 argp->prev_value = v;
2352 argp->prev_elts = rb_ary_new3(1, i);
2353 }
2354 else {
2355 if (rb_equal(argp->prev_value, v)) {
2356 rb_ary_push(argp->prev_elts, i);
2357 }
2358 else {
2359 rb_funcall(argp->yielder, id_lshift, 1, rb_assoc_new(argp->prev_value, argp->prev_elts));
2360 argp->prev_value = v;
2361 argp->prev_elts = rb_ary_new3(1, i);
2362 }
2363 }
2364 }
2365 return Qnil;
2366 }
2367
2368 static VALUE
2369 chunk_i(VALUE yielder, VALUE enumerator, int argc, VALUE *argv)
2370 {
2371 VALUE enumerable;
2372 VALUE arg;
2373 struct chunk_arg *memo = NEW_MEMO_FOR(struct chunk_arg, arg);
2374
2375 enumerable = rb_ivar_get(enumerator, rb_intern("chunk_enumerable"));
2376 memo->categorize = rb_ivar_get(enumerator, rb_intern("chunk_categorize"));
2377 memo->state = rb_ivar_get(enumerator, rb_intern("chunk_initial_state"));
2378 memo->prev_value = Qnil;
2379 memo->prev_elts = Qnil;
2380 memo->yielder = yielder;
2381
2382 if (!NIL_P(memo->state))
2383 memo->state = rb_obj_dup(memo->state);
2384
2385 rb_block_call(enumerable, id_each, 0, 0, chunk_ii, arg);
2386 memo = MEMO_FOR(struct chunk_arg, arg);
2387 if (!NIL_P(memo->prev_elts))
2388 rb_funcall(memo->yielder, id_lshift, 1, rb_assoc_new(memo->prev_value, memo->prev_elts));
2389 return Qnil;
2390 }
2391
2392 /*
2393 * call-seq:
2394 * enum.chunk { |elt| ... } -> an_enumerator
2395 * enum.chunk(initial_state) { |elt, state| ... } -> an_enumerator
2396 *
2397 * Enumerates over the items, chunking them together based on the return
2398 * value of the block.
2399 *
2400 * Consecutive elements which return the same block value are chunked together.
2401 *
2402 * For example, consecutive even numbers and odd numbers can be
2403 * chunked as follows.
2404 *
2405 * [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5].chunk { |n|
2406 * n.even?
2407 * }.each { |even, ary|
2408 * p [even, ary]
2409 * }
2410 * #=> [false, [3, 1]]
2411 * # [true, [4]]
2412 * # [false, [1, 5, 9]]
2413 * # [true, [2, 6]]
2414 * # [false, [5, 3, 5]]
2415 *
2416 * This method is especially useful for sorted series of elements.
2417 * The following example counts words for each initial letter.
2418 *
2419 * open("/usr/share/dict/words", "r:iso-8859-1") { |f|
2420 * f.chunk { |line| line.ord }.each { |ch, lines| p [ch.chr, lines.length] }
2421 * }
2422 * #=> ["\n", 1]
2423 * # ["A", 1327]
2424 * # ["B", 1372]
2425 * # ["C", 1507]
2426 * # ["D", 791]
2427 * # ...
2428 *
2429 * The following key values have special meaning:
2430 * - +nil+ and +:_separator+ specifies that the elements should be dropped.
2431 * - +:_alone+ specifies that the element should be chunked by itself.
2432 *
2433 * Any other symbols that begin with an underscore will raise an error:
2434 *
2435 * items.chunk { |item| :_underscore }
2436 * #=> RuntimeError: symbol begins with an underscore is reserved
2437 *
2438 * +nil+ and +:_separator+ can be used to ignore some elements.
2439 *
2440 * For example, the sequence of hyphens in svn log can be eliminated as follows:
2441 *
2442 * sep = "-"*72 + "\n"
2443 * IO.popen("svn log README") { |f|
2444 * f.chunk { |line|
2445 * line != sep || nil
2446 * }.each { |_, lines|
2447 * pp lines
2448 * }
2449 * }
2450 * #=> ["r20018 | knu | 2008-10-29 13:20:42 +0900 (Wed, 29 Oct 2008) | 2 lines\n",
2451 * # "\n",
2452 * # "* README, README.ja: Update the portability section.\n",
2453 * # "\n"]
2454 * # ["r16725 | knu | 2008-05-31 23:34:23 +0900 (Sat, 31 May 2008) | 2 lines\n",
2455 * # "\n",
2456 * # "* README, README.ja: Add a note about default C flags.\n",
2457 * # "\n"]
2458 * # ...
2459 *
2460 * Paragraphs separated by empty lines can be parsed as follows:
2461 *
2462 * File.foreach("README").chunk { |line|
2463 * /\A\s*\z/ !~ line || nil
2464 * }.each { |_, lines|
2465 * pp lines
2466 * }
2467 *
2468 * +:_alone+ can be used to force items into their own chunk.
2469 * For example, you can put lines that contain a URL by themselves,
2470 * and chunk the rest of the lines together, like this:
2471 *
2472 * pattern = /http/
2473 * open(filename) { |f|
2474 * f.chunk { |line| line =~ pattern ? :_alone : true }.each { |key, lines|
2475 * pp lines
2476 * }
2477 * }
2478 *
2479 * If the block needs to maintain state over multiple elements,
2480 * an +initial_state+ argument can be used.
2481 * If a non-nil value is given,
2482 * a reference to it is passed as the 2nd argument of the block for the
2483 * +chunk+ method, so state-changes to it persist across block calls.
2484 *
2485 */
2486 static VALUE
2487 enum_chunk(int argc, VALUE *argv, VALUE enumerable)
2488 {
2489 VALUE initial_state;
2490 VALUE enumerator;
2491
2492 if (!rb_block_given_p())
2493 rb_raise(rb_eArgError, "no block given");
2494 rb_scan_args(argc, argv, "01", &initial_state);
2495
2496 enumerator = rb_obj_alloc(rb_cEnumerator);
2497 rb_ivar_set(enumerator, rb_intern("chunk_enumerable"), enumerable);
2498 rb_ivar_set(enumerator, rb_intern("chunk_categorize"), rb_block_proc());
2499 rb_ivar_set(enumerator, rb_intern("chunk_initial_state"), initial_state);
2500 rb_block_call(enumerator, idInitialize, 0, 0, chunk_i, enumerator);
2501 return enumerator;
2502 }
2503
2504
2505 struct slicebefore_arg {
2506 VALUE sep_pred;
2507 VALUE sep_pat;
2508 VALUE state;
2509 VALUE prev_elts;
2510 VALUE yielder;
2511 };
2512
2513 static VALUE
2514 slicebefore_ii(VALUE i, VALUE _argp, int argc, VALUE *argv)
2515 {
2516 struct slicebefore_arg *argp = MEMO_FOR(struct slicebefore_arg, _argp);
2517 VALUE header_p;
2518
2519 ENUM_WANT_SVALUE();
2520
2521 if (!NIL_P(argp->sep_pat))
2522 header_p = rb_funcall(argp->sep_pat, id_eqq, 1, i);
2523 else if (NIL_P(argp->state))
2524 header_p = rb_funcall(argp->sep_pred, id_call, 1, i);
2525 else
2526 header_p = rb_funcall(argp->sep_pred, id_call, 2, i, argp->state);
2527 if (RTEST(header_p)) {
2528 if (!NIL_P(argp->prev_elts))
2529 rb_funcall(argp->yielder, id_lshift, 1, argp->prev_elts);
2530 argp->prev_elts = rb_ary_new3(1, i);
2531 }
2532 else {
2533 if (NIL_P(argp->prev_elts))
2534 argp->prev_elts = rb_ary_new3(1, i);
2535 else
2536 rb_ary_push(argp->prev_elts, i);
2537 }
2538
2539 return Qnil;
2540 }
2541
2542 static VALUE
2543 slicebefore_i(VALUE yielder, VALUE enumerator, int argc, VALUE *argv)
2544 {
2545 VALUE enumerable;
2546 VALUE arg;
2547 struct slicebefore_arg *memo = NEW_MEMO_FOR(struct slicebefore_arg, arg);
2548
2549 enumerable = rb_ivar_get(enumerator, rb_intern("slicebefore_enumerable"));
2550 memo->sep_pred = rb_attr_get(enumerator, rb_intern("slicebefore_sep_pred"));
2551 memo->sep_pat = NIL_P(memo->sep_pred) ? rb_ivar_get(enumerator, rb_intern("slicebefore_sep_pat")) : Qnil;
2552 memo->state = rb_attr_get(enumerator, rb_intern("slicebefore_initial_state"));
2553 memo->prev_elts = Qnil;
2554 memo->yielder = yielder;
2555
2556 if (!NIL_P(memo->state))
2557 memo->state = rb_obj_dup(memo->state);
2558
2559 rb_block_call(enumerable, id_each, 0, 0, slicebefore_ii, arg);
2560 memo = MEMO_FOR(struct slicebefore_arg, arg);
2561 if (!NIL_P(memo->prev_elts))
2562 rb_funcall(memo->yielder, id_lshift, 1, memo->prev_elts);
2563 return Qnil;
2564 }
2565
2566 /*
2567 * call-seq:
2568 * enum.slice_before(pattern) -> an_enumerator
2569 * enum.slice_before { |elt| bool } -> an_enumerator
2570 * enum.slice_before(initial_state) { |elt, state| bool } -> an_enumerator
2571 *
2572 * Creates an enumerator for each chunked elements.
2573 * The beginnings of chunks are defined by _pattern_ and the block.
2574
2575 * If <code>_pattern_ === _elt_</code> returns <code>true</code> or the block
2576 * returns <code>true</code> for the element, the element is beginning of a
2577 * chunk.
2578
2579 * The <code>===</code> and _block_ is called from the first element to the last
2580 * element of _enum_. The result for the first element is ignored.
2581
2582 * The result enumerator yields the chunked elements as an array.
2583 * So +each+ method can be called as follows:
2584 *
2585 * enum.slice_before(pattern).each { |ary| ... }
2586 * enum.slice_before { |elt| bool }.each { |ary| ... }
2587 * enum.slice_before(initial_state) { |elt, state| bool }.each { |ary| ... }
2588 *
2589 * Other methods of the Enumerator class and Enumerable module,
2590 * such as map, etc., are also usable.
2591 *
2592 * For example, iteration over ChangeLog entries can be implemented as
2593 * follows:
2594 *
2595 * # iterate over ChangeLog entries.
2596 * open("ChangeLog") { |f|
2597 * f.slice_before(/\A\S/).each { |e| pp e }
2598 * }
2599 *
2600 * # same as above. block is used instead of pattern argument.
2601 * open("ChangeLog") { |f|
2602 * f.slice_before { |line| /\A\S/ === line }.each { |e| pp e }
2603 * }
2604 *
2605 *
2606 * "svn proplist -R" produces multiline output for each file.
2607 * They can be chunked as follows:
2608 *
2609 * IO.popen([{"LC_ALL"=>"C"}, "svn", "proplist", "-R"]) { |f|
2610 * f.lines.slice_before(/\AProp/).each { |lines| p lines }
2611 * }
2612 * #=> ["Properties on '.':\n", " svn:ignore\n", " svk:merge\n"]
2613 * # ["Properties on 'goruby.c':\n", " svn:eol-style\n"]
2614 * # ["Properties on 'complex.c':\n", " svn:mime-type\n", " svn:eol-style\n"]
2615 * # ["Properties on 'regparse.c':\n", " svn:eol-style\n"]
2616 * # ...
2617 *
2618 * If the block needs to maintain state over multiple elements,
2619 * local variables can be used.
2620 * For example, three or more consecutive increasing numbers can be squashed
2621 * as follows:
2622 *
2623 * a = [0, 2, 3, 4, 6, 7, 9]
2624 * prev = a[0]
2625 * p a.slice_before { |e|
2626 * prev, prev2 = e, prev
2627 * prev2 + 1 != e
2628 * }.map { |es|
2629 * es.length <= 2 ? es.join(",") : "#{es.first}-#{es.last}"
2630 * }.join(",")
2631 * #=> "0,2-4,6,7,9"
2632 *
2633 * However local variables are not appropriate to maintain state
2634 * if the result enumerator is used twice or more.
2635 * In such a case, the last state of the 1st +each+ is used in the 2nd +each+.
2636 * The _initial_state_ argument can be used to avoid this problem.
2637 * If non-nil value is given as _initial_state_,
2638 * it is duplicated for each +each+ method invocation of the enumerator.
2639 * The duplicated object is passed to 2nd argument of the block for
2640 * +slice_before+ method.
2641 *
2642 * # Word wrapping. This assumes all characters have same width.
2643 * def wordwrap(words, maxwidth)
2644 * # if cols is a local variable, 2nd "each" may start with non-zero cols.
2645 * words.slice_before(cols: 0) { |w, h|
2646 * h[:cols] += 1 if h[:cols] != 0
2647 * h[:cols] += w.length
2648 * if maxwidth < h[:cols]
2649 * h[:cols] = w.length
2650 * true
2651 * else
2652 * false
2653 * end
2654 * }
2655 * end
2656 * text = (1..20).to_a.join(" ")
2657 * enum = wordwrap(text.split(/\s+/), 10)
2658 * puts "-"*10
2659 * enum.each { |ws| puts ws.join(" ") }
2660 * puts "-"*10
2661 * #=> ----------
2662 * # 1 2 3 4 5
2663 * # 6 7 8 9 10
2664 * # 11 12 13
2665 * # 14 15 16
2666 * # 17 18 19
2667 * # 20
2668 * # ----------
2669 *
2670 * mbox contains series of mails which start with Unix From line.
2671 * So each mail can be extracted by slice before Unix From line.
2672 *
2673 * # parse mbox
2674 * open("mbox") { |f|
2675 * f.slice_before { |line|
2676 * line.start_with? "From "
2677 * }.each { |mail|
2678 * unix_from = mail.shift
2679 * i = mail.index("\n")
2680 * header = mail[0...i]
2681 * body = mail[(i+1)..-1]
2682 * body.pop if body.last == "\n"
2683 * fields = header.slice_before { |line| !" \t".include?(line[0]) }.to_a
2684 * p unix_from
2685 * pp fields
2686 * pp body
2687 * }
2688 * }
2689 *
2690 * # split mails in mbox (slice before Unix From line after an empty line)
2691 * open("mbox") { |f|
2692 * f.slice_before(emp: true) { |line, h|
2693 * prevemp = h[:emp]
2694 * h[:emp] = line == "\n"
2695 * prevemp && line.start_with?("From ")
2696 * }.each { |mail|
2697 * mail.pop if mail.last == "\n"
2698 * pp mail
2699 * }
2700 * }
2701 *
2702 */
2703 static VALUE
2704 enum_slice_before(int argc, VALUE *argv, VALUE enumerable)
2705 {
2706 VALUE enumerator;
2707
2708 if (rb_block_given_p()) {
2709 VALUE initial_state;
2710 rb_scan_args(argc, argv, "01", &initial_state);
2711 enumerator = rb_obj_alloc(rb_cEnumerator);
2712 rb_ivar_set(enumerator, rb_intern("slicebefore_sep_pred"), rb_block_proc());
2713 rb_ivar_set(enumerator, rb_intern("slicebefore_initial_state"), initial_state);
2714 }
2715 else {
2716 VALUE sep_pat;
2717 rb_scan_args(argc, argv, "1", &sep_pat);
2718 enumerator = rb_obj_alloc(rb_cEnumerator);
2719 rb_ivar_set(enumerator, rb_intern("slicebefore_sep_pat"), sep_pat);
2720 }
2721 rb_ivar_set(enumerator, rb_intern("slicebefore_enumerable"), enumerable);
2722 rb_block_call(enumerator, idInitialize, 0, 0, slicebefore_i, enumerator);
2723 return enumerator;
2724 }
2725
2726 /*
2727 * The <code>Enumerable</code> mixin provides collection classes with
2728 * several traversal and searching methods, and with the ability to
2729 * sort. The class must provide a method <code>each</code>, which
2730 * yields successive members of the collection. If
2731 * <code>Enumerable#max</code>, <code>#min</code>, or
2732 * <code>#sort</code> is used, the objects in the collection must also
2733 * implement a meaningful <code><=></code> operator, as these methods
2734 * rely on an ordering between members of the collection.
2735 */
2736
2737 void
2738 Init_Enumerable(void)
2739 {
2740 #undef rb_intern
2741 #define rb_intern(str) rb_intern_const(str)
2742
2743 rb_mEnumerable = rb_define_module("Enumerable");
2744
2745 rb_define_method(rb_mEnumerable, "to_a", enum_to_a, -1);
2746 rb_define_method(rb_mEnumerable, "entries", enum_to_a, -1);
2747
2748 rb_define_method(rb_mEnumerable, "sort", enum_sort, 0);
2749 rb_define_method(rb_mEnumerable, "sort_by", enum_sort_by, 0);
2750 rb_define_method(rb_mEnumerable, "grep", enum_grep, 1);
2751 rb_define_method(rb_mEnumerable, "count", enum_count, -1);
2752 rb_define_method(rb_mEnumerable, "find", enum_find, -1);
2753 rb_define_method(rb_mEnumerable, "detect", enum_find, -1);
2754 rb_define_method(rb_mEnumerable, "find_index", enum_find_index, -1);
2755 rb_define_method(rb_mEnumerable, "find_all", enum_find_all, 0);
2756 rb_define_method(rb_mEnumerable, "select", enum_find_all, 0);
2757 rb_define_method(rb_mEnumerable, "reject", enum_reject, 0);
2758 rb_define_method(rb_mEnumerable, "collect", enum_collect, 0);
2759 rb_define_method(rb_mEnumerable, "map", enum_collect, 0);
2760 rb_define_method(rb_mEnumerable, "flat_map", enum_flat_map, 0);
2761 rb_define_method(rb_mEnumerable, "collect_concat", enum_flat_map, 0);
2762 rb_define_method(rb_mEnumerable, "inject", enum_inject, -1);
2763 rb_define_method(rb_mEnumerable, "reduce", enum_inject, -1);
2764 rb_define_method(rb_mEnumerable, "partition", enum_partition, 0);
2765 rb_define_method(rb_mEnumerable, "group_by", enum_group_by, 0);
2766 rb_define_method(rb_mEnumerable, "first", enum_first, -1);
2767 rb_define_method(rb_mEnumerable, "all?", enum_all, 0);
2768 rb_define_method(rb_mEnumerable, "any?", enum_any, 0);
2769 rb_define_method(rb_mEnumerable, "one?", enum_one, 0);
2770 rb_define_method(rb_mEnumerable, "none?", enum_none, 0);
2771 rb_define_method(rb_mEnumerable, "min", enum_min, 0);
2772 rb_define_method(rb_mEnumerable, "max", enum_max, 0);
2773 rb_define_method(rb_mEnumerable, "minmax", enum_minmax, 0);
2774 rb_define_method(rb_mEnumerable, "min_by", enum_min_by, 0);
2775 rb_define_method(rb_mEnumerable, "max_by", enum_max_by, 0);
2776 rb_define_method(rb_mEnumerable, "minmax_by", enum_minmax_by, 0);
2777 rb_define_method(rb_mEnumerable, "member?", enum_member, 1);
2778 rb_define_method(rb_mEnumerable, "include?", enum_member, 1);
2779 rb_define_method(rb_mEnumerable, "each_with_index", enum_each_with_index, -1);
2780 rb_define_method(rb_mEnumerable, "reverse_each", enum_reverse_each, -1);
2781 rb_define_method(rb_mEnumerable, "each_entry", enum_each_entry, -1);
2782 rb_define_method(rb_mEnumerable, "each_slice", enum_each_slice, 1);
2783 rb_define_method(rb_mEnumerable, "each_cons", enum_each_cons, 1);
2784 rb_define_method(rb_mEnumerable, "each_with_object", enum_each_with_object, 1);
2785 rb_define_method(rb_mEnumerable, "zip", enum_zip, -1);
2786 rb_define_method(rb_mEnumerable, "take", enum_take, 1);
2787 rb_define_method(rb_mEnumerable, "take_while", enum_take_while, 0);
2788 rb_define_method(rb_mEnumerable, "drop", enum_drop, 1);
2789 rb_define_method(rb_mEnumerable, "drop_while", enum_drop_while, 0);
2790 rb_define_method(rb_mEnumerable, "cycle", enum_cycle, -1);
2791 rb_define_method(rb_mEnumerable, "chunk", enum_chunk, -1);
2792 rb_define_method(rb_mEnumerable, "slice_before", enum_slice_before, -1);
2793
2794 id_next = rb_intern("next");
2795 id_call = rb_intern("call");
2796 id_size = rb_intern("size");
2797 id_div = rb_intern("div");
2798 }
data
VALUE data
Definition: tcltklib.c:3368
id_lshift
#define id_lshift
Definition: enum.c:30
RB_TYPE_P
#define RB_TYPE_P(obj, type)
RARRAY_PTR
RARRAY_PTR(q->result)[0]
count_i
static VALUE count_i(VALUE i, VALUE memop, int argc, VALUE *argv)
Definition: enum.c:100
tmp
volatile VALUE tmp
Definition: tcltklib.c:10209
rb_block_call_func
VALUE rb_block_call_func(VALUE, VALUE, int, VALUE *)
Definition: ripper.y:1393
n
ssize_t n
Definition: bigdecimal.c:5655
ary
volatile VALUE ary
Definition: tcltklib.c:9713
int
VP_EXPORT int
Definition: bigdecimal.c:5050
enum_any
static VALUE enum_any(VALUE obj)
Definition: enum.c:1034
rb_ary_new4
VALUE rb_ary_new4(long n, const VALUE *elts)
Definition: array.c:451
pat
UChar * pat
Definition: regerror.c:390
minmax_ii
static VALUE minmax_ii(VALUE i, VALUE _memo, int argc, VALUE *argv)
Definition: enum.c:1342
enum_all
static VALUE enum_all(VALUE obj)
Definition: enum.c:1000
FALSE
#define FALSE
Definition: nkf.h:174
grep_i
static VALUE grep_i(VALUE i, VALUE args, int argc, VALUE *argv)
Definition: enum.c:47
id_each
#define id_each
Definition: enum.c:27
OBJ_INFECT
#define OBJ_INFECT(x, s)
enumerator
Definition: enumerator.c:113
rb_obj_classname
const char * rb_obj_classname(VALUE)
Definition: variable.c:396
each_cons_i
static VALUE each_cons_i(VALUE i, VALUE args, int argc, VALUE *argv)
Definition: enum.c:1834
chunk_ii
static VALUE chunk_ii(VALUE i, VALUE _argp, int argc, VALUE *argv)
Definition: enum.c:2319
p
Win32OLEIDispatch * p
Definition: win32ole.c:786
chunk_arg::state
VALUE state
Definition: enum.c:2312
enum_each_with_index
static VALUE enum_each_with_index(int argc, VALUE *argv, VALUE obj)
Definition: enum.c:1673
min_by_i
static VALUE min_by_i(VALUE i, VALUE args, int argc, VALUE *argv)
Definition: enum.c:1414
min_ii
static VALUE min_ii(VALUE i, VALUE args, int argc, VALUE *argv)
Definition: enum.c:1138
group_by_i
static VALUE group_by_i(VALUE i, VALUE hash, int argc, VALUE *argv)
Definition: enum.c:664
sort_by_cmp
static int sort_by_cmp(const void *ap, const void *bp, void *data)
Definition: enum.c:817
node.h
ruby.h
rb_ary_sort
VALUE rb_ary_sort(VALUE ary)
Definition: array.c:2373
take_i
static VALUE take_i(VALUE i, VALUE args, int argc, VALUE *argv)
Definition: enum.c:2072
flat_map_i
static VALUE flat_map_i(VALUE i, VALUE ary, int argc, VALUE *argv)
Definition: enum.c:442
find_i
static VALUE find_i(VALUE i, VALUE memop, int argc, VALUE *argv)
Definition: enum.c:179
func
SSL_METHOD *(* func)(void)
Definition: ossl_ssl.c:108
i
ssize_t i
Definition: bigdecimal.c:5655
rb_ary_shift
VALUE rb_ary_shift(VALUE ary)
Definition: array.c:929
enum_each_slice
static VALUE enum_each_slice(VALUE obj, VALUE n)
Definition: enum.c:1816
enum_each_slice_size
static VALUE enum_each_slice_size(VALUE obj, VALUE args)
Definition: enum.c:1786
a
Real * a
Definition: bigdecimal.c:1182
rb_eTypeError
VALUE rb_eTypeError
Definition: error.c:511
enum_cycle_size
static VALUE enum_cycle_size(VALUE self, VALUE args)
Definition: enum.c:2242
rb_obj_dup
VALUE rb_obj_dup(VALUE)
Definition: object.c:338
inject_op_i
static VALUE inject_op_i(VALUE i, VALUE p, int argc, VALUE *argv)
Definition: enum.c:527
slicebefore_arg::state
VALUE state
Definition: enum.c:2508
UNREACHABLE
#define UNREACHABLE
Definition: ruby.h:40
slicebefore_arg::sep_pred
VALUE sep_pred
Definition: enum.c:2506
drop_while_i
static VALUE drop_while_i(VALUE i, VALUE args, int argc, VALUE *argv)
Definition: enum.c:2188
rb_ary_push
VALUE rb_ary_push(VALUE ary, VALUE item)
Definition: array.c:822
enum_each_cons
static VALUE enum_each_cons(VALUE obj, VALUE n)
Definition: enum.c:1888
slicebefore_arg::yielder
VALUE yielder
Definition: enum.c:2510
rb_yield_values
VALUE rb_yield_values(int n,...)
Definition: vm_eval.c:945
rb_ary_tmp_new
VALUE rb_ary_tmp_new(long capa)
Definition: array.c:465
zip_i
static VALUE zip_i(VALUE val, NODE *memo, int argc, VALUE *argv)
Definition: enum.c:1975
chunk_i
static VALUE chunk_i(VALUE yielder, VALUE enumerator, int argc, VALUE *argv)
Definition: enum.c:2369
NIL_P
NIL_P(eventloop_thread)
Definition: tcltklib.c:4068
T_ARRAY
#define T_ARRAY
enum_sort_by
static VALUE enum_sort_by(VALUE obj)
Definition: enum.c:905
enum_member
static VALUE enum_member(VALUE obj, VALUE val)
Definition: enum.c:1637
rb_cEnumerator
VALUE rb_cEnumerator
Definition: enumerator.c:105
rb_funcall
VALUE rb_funcall(VALUE, ID, int,...)
Calls a method.
Definition: vm_eval.c:774
rb_raise
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:1780
RNode::id
ID id
Definition: ripper.y:245
Qtrue
return Qtrue
Definition: tcltklib.c:9610
RETURN_ENUMERATOR
#define RETURN_ENUMERATOR(obj, argc, argv)
DEFINE_ENUMFUNCS
#define DEFINE_ENUMFUNCS(name)
Definition: enum.c:955
enum_slice_before
static VALUE enum_slice_before(int argc, VALUE *argv, VALUE enumerable)
Definition: enum.c:2704
take_while_i
static VALUE take_while_i(VALUE i, VALUE ary, int argc, VALUE *argv)
Definition: enum.c:2111
rb_ary_new3
VALUE rb_ary_new3(long n,...)
Definition: array.c:432
partition_i
static VALUE partition_i(VALUE i, VALUE arys, int argc, VALUE *argv)
Definition: enum.c:619
r
r
Definition: bigdecimal.c:1196
minmax_by_t::max
VALUE max
Definition: enum.c:1509
minmax_t::max
VALUE max
Definition: enum.c:1262
RNode::argc
long argc
Definition: ripper.y:253
chunk_arg::yielder
VALUE yielder
Definition: enum.c:2315
ID2SYM
#define ID2SYM(x)
sort_by_data
Definition: enum.c:782
minmax_t::last
VALUE last
Definition: enum.c:1263
args
VALUE VALUE args
Definition: tcltklib.c:2561
rb_cmpint
int rb_cmpint(VALUE val, VALUE a, VALUE b)
Definition: bignum.c:97
LONG2NUM
#define LONG2NUM(x)
rb_ivar_get
VALUE rb_ivar_get(VALUE, ID)
Definition: variable.c:1116
rb_equal
VALUE rb_equal(VALUE, VALUE)
Definition: object.c:56
slicebefore_i
static VALUE slicebefore_i(VALUE yielder, VALUE enumerator, int argc, VALUE *argv)
Definition: enum.c:2543
id.h
RNode
Definition: ripper.y:240
Init_Enumerable
void Init_Enumerable(void)
Definition: enum.c:2738
each_with_index_i
static VALUE each_with_index_i(VALUE i, VALUE memo, int argc, VALUE *argv)
Definition: enum.c:1646
ENUM_WANT_SVALUE
#define ENUM_WANT_SVALUE()
Definition: enum.c:40
collect_i
static VALUE collect_i(VALUE i, VALUE ary, int argc, VALUE *argv)
Definition: enum.c:395
chunk_arg::prev_value
VALUE prev_value
Definition: enum.c:2313
hash
VALUE hash
Definition: tkutil.c:267
enum_max
static VALUE enum_max(VALUE obj)
Definition: enum.c:1244
enum_max_by
static VALUE enum_max_by(VALUE obj)
Definition: enum.c:1494
rb_iter_break
void rb_iter_break(void)
Definition: vm.c:960
sort_by_data::n
long n
Definition: enum.c:785
id_size
static ID id_size
Definition: enum.c:25
rb_block_proc
VALUE rb_block_proc(void)
Definition: proc.c:479
m
BDIGIT m
Definition: bigdecimal.c:5085
max_ii
static VALUE max_ii(VALUE i, VALUE args, int argc, VALUE *argv)
Definition: enum.c:1210
Qfalse
return Qfalse
Definition: tcltklib.c:6779
enum_take
static VALUE enum_take(VALUE obj, VALUE n)
Definition: enum.c:2092
enum_chunk
static VALUE enum_chunk(int argc, VALUE *argv, VALUE enumerable)
Definition: enum.c:2487
each_val_i
static VALUE each_val_i(VALUE i, VALUE p, int argc, VALUE *argv)
Definition: enum.c:1722
rb_block_given_p
int rb_block_given_p(void)
Definition: eval.c:672
RARRAY_LEN
#define RARRAY_LEN(a)
max_i
static VALUE max_i(VALUE i, VALUE args, int argc, VALUE *argv)
Definition: enum.c:1190
Qnil
#define Qnil
Definition: tcltklib.c:1896
find_all_i
static VALUE find_all_i(VALUE i, VALUE ary, int argc, VALUE *argv)
Definition: enum.c:302
val
#define val
Definition: tcltklib.c:1949
rb_eRuntimeError
VALUE rb_eRuntimeError
Definition: error.c:510
enum_sort
static VALUE enum_sort(VALUE obj)
Definition: enum.c:776
count_all_i
static VALUE count_all_i(VALUE i, VALUE memop, int argc, VALUE *argv)
Definition: enum.c:124
RNode::u2
union RNode::@81 u2
enum_each_entry
static VALUE enum_each_entry(int argc, VALUE *argv, VALUE obj)
Definition: enum.c:1759
rb_ary_new
VALUE rb_ary_new(void)
Definition: array.c:424
enum_inject
static VALUE enum_inject(int argc, VALUE *argv, VALUE obj)
Definition: enum.c:587
ID
unsigned long ID
Definition: ripper.y:105
enum_grep
static VALUE enum_grep(VALUE obj, VALUE pat)
Definition: enum.c:89
enum_find_all
static VALUE enum_find_all(VALUE obj)
Definition: enum.c:341
obj
static VALUE VALUE obj
Definition: tcltklib.c:3158
INT2FIX
#define INT2FIX(i)
SORT_BY_BUFSIZE
#define SORT_BY_BUFSIZE
Definition: enum.c:781
rb_ary_store
void rb_ary_store(VALUE ary, long idx, VALUE val)
Definition: array.c:719
RNode::value
VALUE value
Definition: ripper.y:246
offsetof
#define offsetof(p_type, field)
Definition: addrinfo.h:186
count_iter_i
static VALUE count_iter_i(VALUE i, VALUE memop, int argc, VALUE *argv)
Definition: enum.c:113
minmax_i_update
static void minmax_i_update(VALUE i, VALUE j, struct minmax_t *memo)
Definition: enum.c:1269
one
static double one(void)
Definition: isinf.c:52
enum_first
static VALUE enum_first(int argc, VALUE *argv, VALUE obj)
Definition: enum.c:743
LONG_MAX
#define LONG_MAX
Definition: ruby.h:201
STATIC_ASSERT
#define STATIC_ASSERT(name, expr)
Definition: enum.c:18
buf
unsigned char buf[MIME_BUF_SIZE]
Definition: nkf.c:4308
rb_thread_check_ints
void rb_thread_check_ints(void)
Definition: thread.c:1090
minmax_by_i_update
static void minmax_by_i_update(VALUE v1, VALUE v2, VALUE i1, VALUE i2, struct minmax_by_t *memo)
Definition: enum.c:1515
DBL2NUM
#define DBL2NUM(dbl)
rb_check_funcall
VALUE rb_check_funcall(VALUE, ID, int, VALUE *)
Definition: vm_eval.c:408
RNode::cnt
long cnt
Definition: ripper.y:262
min_i
static VALUE min_i(VALUE i, VALUE args, int argc, VALUE *argv)
Definition: enum.c:1118
argv
VALUE * argv
Definition: tcltklib.c:1971
rb_hash_aset
VALUE rb_hash_aset(VALUE, VALUE, VALUE)
enum_cycle
static VALUE enum_cycle(int argc, VALUE *argv, VALUE obj)
Definition: enum.c:2281
rb_yield
VALUE rb_yield(VALUE)
Definition: vm_eval.c:934
RTEST
#define RTEST(v)
util.h
TRUE
#define TRUE
Definition: nkf.h:175
result
q result
Definition: tcltklib.c:7070
each_with_object_i
static VALUE each_with_object_i(VALUE i, VALUE memo, int argc, VALUE *argv)
Definition: enum.c:1902
rb_mEnumerable
VALUE rb_mEnumerable
Definition: enum.c:20
first_i
static VALUE first_i(VALUE i, VALUE params, int argc, VALUE *argv)
Definition: enum.c:713
chunk_arg::categorize
VALUE categorize
Definition: enum.c:2311
rb_node_newnode
#define rb_node_newnode(type, a1, a2, a3)
Definition: ripper.c:419
drop_i
static VALUE drop_i(VALUE i, VALUE args, int argc, VALUE *argv)
Definition: enum.c:2145
find_index_iter_i
static VALUE find_index_iter_i(VALUE i, VALUE memop, int argc, VALUE *argv)
Definition: enum.c:246
CONST_ID
#define CONST_ID(var, str)
slicebefore_arg
Definition: enum.c:2505
rb_scan_args
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Definition: class.c:1570
cycle_i
static VALUE cycle_i(VALUE i, VALUE ary, int argc, VALUE *argv)
Definition: enum.c:2232
slicebefore_arg::sep_pat
VALUE sep_pat
Definition: enum.c:2507
rb_block_call
VALUE rb_block_call(VALUE, ID, int, VALUE *, VALUE(*)(ANYARGS), VALUE)
Definition: vm_eval.c:1131
rb_assoc_new
VALUE rb_assoc_new(VALUE car, VALUE cdr)
Definition: array.c:545
internal.h
minmax_ii_update
static void minmax_ii_update(VALUE i, VALUE j, struct minmax_t *memo)
Definition: enum.c:1321
minmax_by_t::min_bv
VALUE min_bv
Definition: enum.c:1506
RNode::u3
union RNode::@82 u3
rb_eStopIteration
VALUE rb_eStopIteration
Definition: enumerator.c:111
max_by_i
static VALUE max_by_i(VALUE i, VALUE args, int argc, VALUE *argv)
Definition: enum.c:1460
enum_collect
static VALUE enum_collect(VALUE obj)
Definition: enum.c:429
id_cmp
#define id_cmp
Definition: enum.c:29
argc
int argc
Definition: tcltklib.c:1970
ruby_qsort
void ruby_qsort(void *, const size_t, const size_t, int(*)(const void *, const void *, void *), void *)
minmax_i
static VALUE minmax_i(VALUE i, VALUE _memo, int argc, VALUE *argv)
Definition: enum.c:1290
enum_min
static VALUE enum_min(VALUE obj)
Definition: enum.c:1173
enum_none
static VALUE enum_none(VALUE obj)
Definition: enum.c:1110
rb_rescue2
VALUE rb_rescue2(VALUE(*b_proc)(ANYARGS), VALUE data1, VALUE(*r_proc)(ANYARGS), VALUE data2,...)
Definition: eval.c:701
rb_attr_get
VALUE rb_attr_get(VALUE, ID)
Definition: variable.c:1122
INFINITY
#define INFINITY
Definition: missing.h:138
ENUMFUNC
#define ENUMFUNC(name)
Definition: enum.c:953
enum_one
static VALUE enum_one(VALUE obj)
Definition: enum.c:1074
NEW_MEMO_FOR
#define NEW_MEMO_FOR(type, value)
b
Real * b
Definition: bigdecimal.c:1182
enum_drop_while
static VALUE enum_drop_while(VALUE obj)
Definition: enum.c:2219
enum_yield
#define enum_yield
Definition: enum.c:44
minmax_by_t::max_bv
VALUE max_bv
Definition: enum.c:1507
NEW_MEMO
#define NEW_MEMO(a, b, c)
minmax_by_t::last_bv
VALUE last_bv
Definition: enum.c:1510
slicebefore_arg::prev_elts
VALUE prev_elts
Definition: enum.c:2509
id_call
static ID id_call
Definition: enum.c:24
zip_ary
static VALUE zip_ary(VALUE val, NODE *memo, int argc, VALUE *argv)
Definition: enum.c:1933
rb_to_id
ID rb_to_id(VALUE)
Definition: string.c:8154
slicebefore_ii
static VALUE slicebefore_ii(VALUE i, VALUE _argp, int argc, VALUE *argv)
Definition: enum.c:2514
rb_ivar_set
VALUE rb_ivar_set(VALUE, ID, VALUE)
Definition: variable.c:1128
arg
arg
Definition: ripper.y:1315
rb_ary_resize
VALUE rb_ary_resize(VALUE ary, long len)
expands or shrinks ary to len elements.
Definition: array.c:1513
sort_by_data::ary
VALUE ary
Definition: enum.c:783
enum_reject
static VALUE enum_reject(VALUE obj)
Definition: enum.c:382
rb_enum_values_pack
VALUE rb_enum_values_pack(int argc, VALUE *argv)
Definition: enum.c:33
enum_each_with_object
static VALUE enum_each_with_object(VALUE obj, VALUE memo)
Definition: enum.c:1923
RETURN_SIZED_ENUMERATOR
#define RETURN_SIZED_ENUMERATOR(obj, argc, argv, size_fn)
size
int size
Definition: encoding.c:52
id_div
static ID id_div
Definition: enum.c:23
NUM2LONG
#define NUM2LONG(x)
SYMBOL_P
#define SYMBOL_P(x)
enum_partition
static VALUE enum_partition(VALUE obj)
Definition: enum.c:651
Qundef
#define Qundef
enum_to_a
static VALUE enum_to_a(int argc, VALUE *argv, VALUE obj)
Definition: enum.c:499
mul
#define mul(x, y)
Definition: date_strftime.c:25
enum_minmax_by
static VALUE enum_minmax_by(VALUE obj)
Definition: enum.c:1591
MEMO_FOR
#define MEMO_FOR(type, value)
minmax_by_t
Definition: enum.c:1505
enum_reverse_each
static VALUE enum_reverse_each(int argc, VALUE *argv, VALUE obj)
Definition: enum.c:1704
rb_check_array_type
VALUE rb_check_array_type(VALUE ary)
Definition: array.c:557
minmax_by_t::min
VALUE min
Definition: enum.c:1508
member_i
static VALUE member_i(VALUE iter, VALUE args, int argc, VALUE *argv)
Definition: enum.c:1612
RNode::state
long state
Definition: ripper.y:259
enum_count
static VALUE enum_count(int argc, VALUE *argv, VALUE obj)
Definition: enum.c:151
minmax_by_i
static VALUE minmax_by_i(VALUE i, VALUE _memo, int argc, VALUE *argv)
Definition: enum.c:1536
minmax_t
Definition: enum.c:1260
LONG2FIX
#define LONG2FIX(i)
RBASIC
#define RBASIC(obj)
each_slice_i
static VALUE each_slice_i(VALUE i, VALUE m, int argc, VALUE *argv)
Definition: enum.c:1767
klass
klass
Definition: tcltklib.c:3504
UINT2NUM
#define UINT2NUM(x)
INT2NUM
#define INT2NUM(x)
enum_drop
static VALUE enum_drop(VALUE obj, VALUE n)
Definition: enum.c:2170
rb_respond_to
int rb_respond_to(VALUE, ID)
Definition: vm_method.c:1564
enum_find
static VALUE enum_find(int argc, VALUE *argv, VALUE obj)
Definition: enum.c:212
rb_ary_dup
VALUE rb_ary_dup(VALUE ary)
Definition: array.c:1778
collect_all
static VALUE collect_all(VALUE i, VALUE ary, int argc, VALUE *argv)
Definition: enum.c:403
rb_cArray
VALUE rb_cArray
Definition: array.c:29
rb_ary_concat
VALUE rb_ary_concat(VALUE x, VALUE y)
Definition: array.c:3382
enum_zip
static VALUE enum_zip(int argc, VALUE *argv, VALUE obj)
Definition: enum.c:2033
id_next
static ID id_next
Definition: enum.c:22
enum_min_by
static VALUE enum_min_by(VALUE obj)
Definition: enum.c:1448
rb_ary_new2
VALUE rb_ary_new2(long capa)
Definition: array.c:417
RNode::u1
union RNode::@80 u1
rb_hash_new
VALUE rb_hash_new(void)
Definition: hash.c:234
rb_obj_alloc
VALUE rb_obj_alloc(VALUE)
Definition: object.c:1721
rb_id2name
const char * rb_id2name(ID id)
Definition: ripper.c:17005
chunk_arg
Definition: enum.c:2310
rb_check_arity
#define rb_check_arity(argc, min, max)
enum_flat_map
static VALUE enum_flat_map(VALUE obj)
Definition: enum.c:476
enum_each_cons_size
static VALUE enum_each_cons_size(VALUE obj, VALUE args)
Definition: enum.c:1853
enum_take_while
static VALUE enum_take_while(VALUE obj)
Definition: enum.c:2134
chunk_arg::prev_elts
VALUE prev_elts
Definition: enum.c:2314
enum_find_index
static VALUE enum_find_index(int argc, VALUE *argv, VALUE obj)
Definition: enum.c:278
enum_minmax
static VALUE enum_minmax(VALUE obj)
Definition: enum.c:1388
e
BDIGIT e
Definition: bigdecimal.c:5085
rb_hash_aref
VALUE rb_hash_aref(VALUE, VALUE)
Definition: hash.c:560
VALUE
unsigned long VALUE
Definition: ripper.y:104
rb_warning
void rb_warning(const char *fmt,...)
Definition: error.c:229
separator
static VALUE separator
Definition: file.c:3974
call_stop
static VALUE call_stop(VALUE *v)
Definition: enum.c:1969
NODE_DOT2
#define NODE_DOT2
rb_define_module
VALUE rb_define_module(const char *name)
Definition: class.c:617
rb_intern
#define rb_intern(str)
v
BDIGIT v
Definition: bigdecimal.c:5656
reject_i
static VALUE reject_i(VALUE i, VALUE ary, int argc, VALUE *argv)
Definition: enum.c:354
yielder
Definition: enumerator.c:132
enum_size
static VALUE enum_size(VALUE self, VALUE args)
Definition: enum.c:313
enum_group_by
static VALUE enum_group_by(VALUE obj)
Definition: enum.c:699
RNODE
#define RNODE(obj)
rb_define_method
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Definition: class.c:1344
sort_by_data::buf
VALUE buf
Definition: enum.c:784
sort_by_i
static VALUE sort_by_i(VALUE i, VALUE _data, int argc, VALUE *argv)
Definition: enum.c:789
minmax_t::min
VALUE min
Definition: enum.c:1261
rb_warn
void rb_warn(const char *fmt,...)
Definition: error.c:216
SYM2ID
#define SYM2ID(x)
bp
#define bp()
Definition: vm_debug.h:27
grep_iter_i
static VALUE grep_iter_i(VALUE i, VALUE args, int argc, VALUE *argv)
Definition: enum.c:59
rb_eArgError
VALUE rb_eArgError
Definition: error.c:512
cmp
static ID cmp
Definition: compar.c:16
minmax_by_t::last
VALUE last
Definition: enum.c:1511
inject_i
static VALUE inject_i(VALUE i, VALUE p, int argc, VALUE *argv)
Definition: enum.c:510
call_next
static VALUE call_next(VALUE *v)
Definition: enum.c:1963
find_index_i
static VALUE find_index_i(VALUE i, VALUE memop, int argc, VALUE *argv)
Definition: enum.c:231
id_eqq
#define id_eqq
Definition: enum.c:28
len
size_t len
Definition: tcltklib.c:3568