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
20VALUE rb_mEnumerable;
21
22static ID id_next;
23static ID id_div;
24static ID id_call;
25static 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
32VALUE
33rb_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
46static VALUE
47grep_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
58static VALUE
59grep_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
88static VALUE
89enum_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
99static VALUE
100count_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
112static VALUE
113count_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
123static VALUE
124count_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
150static VALUE
151enum_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
178static VALUE
179find_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
211static VALUE
212enum_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
230static VALUE
231find_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
245static VALUE
246find_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
277static VALUE
278enum_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
301static VALUE
302find_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
312static VALUE
313enum_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
340static VALUE
341enum_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
353static VALUE
354reject_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
381static VALUE
382enum_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
394static VALUE
395collect_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
402static VALUE
403collect_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
428static VALUE
429enum_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
441static VALUE
442flat_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
475static VALUE
476enum_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 */
498static VALUE
499enum_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
509static VALUE
510inject_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
526static VALUE
527inject_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 */
586static VALUE
587enum_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
618static VALUE
619partition_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
650static VALUE
651enum_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
663static VALUE
664group_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
698static VALUE
699enum_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
712static VALUE
713first_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
724static 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
742static VALUE
743enum_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
775static VALUE
776enum_sort(VALUE obj)
777{
778    return rb_ary_sort(enum_to_a(0, 0, obj));
779}
780
781#define SORT_BY_BUFSIZE 16
782struct sort_by_data {
783    VALUE ary;
784    VALUE buf;
785    long n;
786};
787
788static VALUE
789sort_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
816static int
817sort_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
904static VALUE
905enum_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) \
956static VALUE enum_##name##_func(VALUE result, NODE *memo); \
957\
958static VALUE \
959name##_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\
964static VALUE \
965name##_iter_i(VALUE i, VALUE memo, int argc, VALUE *argv) \
966{ \
967    return enum_##name##_func(enum_yield(argc, argv), RNODE(memo));	\
968} \
969\
970static VALUE \
971enum_##name##_func(VALUE result, NODE *memo)
972
973DEFINE_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
999static VALUE
1000enum_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
1007DEFINE_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
1033static VALUE
1034enum_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
1041DEFINE_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
1073static VALUE
1074enum_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
1085DEFINE_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 */
1109static VALUE
1110enum_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
1117static VALUE
1118min_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
1137static VALUE
1138min_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
1172static VALUE
1173enum_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
1189static VALUE
1190max_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
1209static VALUE
1210max_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
1243static VALUE
1244enum_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
1260struct minmax_t {
1261    VALUE min;
1262    VALUE max;
1263    VALUE last;
1264};
1265
1266STATIC_ASSERT(minmax_t, sizeof(struct minmax_t) <= sizeof(NODE) - offsetof(NODE, u1));
1267
1268static void
1269minmax_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
1289static VALUE
1290minmax_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
1320static void
1321minmax_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
1341static VALUE
1342minmax_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
1387static VALUE
1388enum_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
1413static VALUE
1414min_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
1447static VALUE
1448enum_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
1459static VALUE
1460max_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
1493static VALUE
1494enum_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
1505struct 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
1514static void
1515minmax_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
1535static VALUE
1536minmax_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
1590static VALUE
1591enum_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
1611static VALUE
1612member_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
1636static VALUE
1637enum_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
1645static VALUE
1646each_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
1672static VALUE
1673enum_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
1703static VALUE
1704enum_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
1721static VALUE
1722each_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
1758static VALUE
1759enum_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
1766static VALUE
1767each_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
1785static VALUE
1786enum_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 */
1815static VALUE
1816enum_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
1833static VALUE
1834each_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
1852static VALUE
1853enum_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 */
1887static VALUE
1888enum_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
1901static VALUE
1902each_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 */
1922static VALUE
1923enum_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
1932static VALUE
1933zip_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
1962static VALUE
1963call_next(VALUE *v)
1964{
1965    return v[0] = rb_funcall(v[1], id_next, 0, 0);
1966}
1967
1968static VALUE
1969call_stop(VALUE *v)
1970{
1971    return v[0] = Qundef;
1972}
1973
1974static VALUE
1975zip_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
2032static VALUE
2033enum_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
2071static VALUE
2072take_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
2091static VALUE
2092enum_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
2110static VALUE
2111take_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
2133static VALUE
2134enum_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
2144static VALUE
2145drop_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
2169static VALUE
2170enum_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
2187static VALUE
2188drop_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
2218static VALUE
2219enum_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
2231static VALUE
2232cycle_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
2241static VALUE
2242enum_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
2280static VALUE
2281enum_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
2310struct chunk_arg {
2311    VALUE categorize;
2312    VALUE state;
2313    VALUE prev_value;
2314    VALUE prev_elts;
2315    VALUE yielder;
2316};
2317
2318static VALUE
2319chunk_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
2368static VALUE
2369chunk_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 */
2486static VALUE
2487enum_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
2505struct slicebefore_arg {
2506    VALUE sep_pred;
2507    VALUE sep_pat;
2508    VALUE state;
2509    VALUE prev_elts;
2510    VALUE yielder;
2511};
2512
2513static VALUE
2514slicebefore_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
2542static VALUE
2543slicebefore_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 */
2703static VALUE
2704enum_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
2737void
2738Init_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}
2799