Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 2101 lines (1834 sloc) 50.058 kB
9595725 update copyrights to 2011
Laurent Sansonetti authored
1 /*
2 * This file is covered by the Ruby license. See COPYING for more details.
3 *
4 * Copyright (C) 2007-2011, Apple Inc. All rights reserved.
5 * Copyright (C) 1993-2007 Yukihiro Matsumoto
6 */
9c1d230 committing experimental branch content
Laurent Sansonetti authored
7
d0898dd include/ruby/macruby.h -> macruby_internal.h
Laurent Sansonetti authored
8 #include "macruby_internal.h"
9c1d230 committing experimental branch content
Laurent Sansonetti authored
9 #include "ruby/node.h"
10 #include "ruby/util.h"
cb65416 the great schism, part I
Laurent Sansonetti authored
11 #include "vm.h"
301b43b ported to rb_objc_block_call() + misc cleanup
Laurent Sansonetti authored
12 #include "id.h"
40a433d Improve core/enumerable pass rate
Thibault Martin-Lagardette authored
13 #include "array.h"
9c1d230 committing experimental branch content
Laurent Sansonetti authored
14
15 VALUE rb_mEnumerable;
78bea84 optimized dummy calls to <=>:
Laurent Sansonetti authored
16 static ID id_each, id_eqq, id_next, id_size;
9c1d230 committing experimental branch content
Laurent Sansonetti authored
17
18 static VALUE
19 enum_values_pack(int argc, VALUE *argv)
20 {
21 if (argc == 0) return Qnil;
22 if (argc == 1) return argv[0];
23 return rb_ary_new4(argc, argv);
24 }
25
26 #define ENUM_WANT_SVALUE() do { \
27 i = enum_values_pack(argc, argv); \
28 } while (0)
29
30 #define enum_yield rb_yield_values2
31
32 static VALUE
33 grep_i(VALUE i, VALUE *arg, int argc, VALUE *argv)
34 {
35 ENUM_WANT_SVALUE();
36
37 if (RTEST(rb_funcall(arg[0], id_eqq, 1, i))) {
38 rb_ary_push(arg[1], i);
39 }
40 return Qnil;
41 }
42
43 static VALUE
44 grep_iter_i(VALUE i, VALUE *arg, int argc, VALUE *argv)
45 {
46 ENUM_WANT_SVALUE();
47
48 if (RTEST(rb_funcall(arg[0], id_eqq, 1, i))) {
49 rb_ary_push(arg[1], rb_yield(i));
50 }
51 return Qnil;
52 }
53
54 /*
55 * call-seq:
56 * enum.grep(pattern) => array
57 * enum.grep(pattern) {| obj | block } => array
58 *
59 * Returns an array of every element in <i>enum</i> for which
60 * <code>Pattern === element</code>. If the optional <em>block</em> is
61 * supplied, each matching element is passed to it, and the block's
62 * result is stored in the output array.
63 *
64 * (1..100).grep 38..44 #=> [38, 39, 40, 41, 42, 43, 44]
65 * c = IO.constants
66 * c.grep(/SEEK/) #=> [:SEEK_SET, :SEEK_CUR, :SEEK_END]
67 * res = c.grep(/SEEK/) {|v| IO.const_get(v) }
68 * res #=> [0, 1, 2]
69 *
70 */
71
72 static VALUE
73 enum_grep(VALUE obj, SEL sel, VALUE pat)
74 {
75 VALUE ary = rb_ary_new();
76 VALUE arg[2];
77
78 arg[0] = pat;
79 arg[1] = ary;
80
70ea0b5 per-vm method cache + misc fixes/improvements
Laurent Sansonetti authored
81 rb_objc_block_call(obj, selEach, 0, 0, rb_block_given_p() ? grep_iter_i : grep_i, (VALUE)arg);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
82
83 return ary;
84 }
85
86 static VALUE
87 count_i(VALUE i, VALUE memop, int argc, VALUE *argv)
88 {
89 VALUE *memo = (VALUE*)memop;
90
91 ENUM_WANT_SVALUE();
92
93 if (rb_equal(i, memo[1])) {
94 memo[0]++;
95 }
96 return Qnil;
97 }
98
99 static VALUE
100 count_iter_i(VALUE i, VALUE memop, int argc, VALUE *argv)
101 {
102 VALUE *memo = (VALUE*)memop;
103
104 if (RTEST(enum_yield(argc, argv))) {
105 memo[0]++;
106 }
107 return Qnil;
108 }
109
110 static VALUE
111 count_all_i(VALUE i, VALUE memop, int argc, VALUE *argv)
112 {
113 VALUE *memo = (VALUE*)memop;
114
115 memo[0]++;
116 return Qnil;
117 }
118
119 /*
120 * call-seq:
121 * enum.count => int
122 * enum.count(item) => int
123 * enum.count {| obj | block } => int
124 *
125 * Returns the number of items in <i>enum</i>, where #size is called
126 * if it responds to it, otherwise the items are counted through
127 * enumeration. If an argument is given, counts the number of items
128 * in <i>enum</i>, for which equals to <i>item</i>. If a block is
129 * given, counts the number of elements yielding a true value.
130 *
131 * ary = [1, 2, 4, 2]
132 * ary.count # => 4
133 * ary.count(2) # => 2
134 * ary.count{|x|x%2==0} # => 3
135 *
136 */
137
138 static VALUE
139 enum_count(VALUE obj, SEL sel, int argc, VALUE *argv)
140 {
141 VALUE memo[2]; /* [count, condition value] */
142 rb_block_call_func *func;
143
144 if (argc == 0) {
145 if (rb_block_given_p()) {
146 func = count_iter_i;
147 }
148 else {
149 if (rb_respond_to(obj, id_size)) {
150 return rb_funcall(obj, id_size, 0, 0);
151 }
152 func = count_all_i;
153 }
154 }
155 else {
156 rb_scan_args(argc, argv, "1", &memo[1]);
157 if (rb_block_given_p()) {
158 rb_warn("given block not used");
159 }
160 func = count_i;
161 }
162
163 memo[0] = 0;
70ea0b5 per-vm method cache + misc fixes/improvements
Laurent Sansonetti authored
164 rb_objc_block_call(obj, selEach, 0, 0, func, (VALUE)&memo);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
165 return INT2NUM(memo[0]);
166 }
167
168 static VALUE
169 find_i(VALUE i, VALUE *memo, int argc, VALUE *argv)
170 {
171 ENUM_WANT_SVALUE();
172
173 if (RTEST(rb_yield(i))) {
174 *memo = i;
175 rb_iter_break();
176 }
177 return Qnil;
178 }
179
180 /*
181 * call-seq:
182 * enum.detect(ifnone = nil) {| obj | block } => obj or nil
183 * enum.find(ifnone = nil) {| obj | block } => obj or nil
184 *
185 * Passes each entry in <i>enum</i> to <em>block</em>. Returns the
186 * first for which <em>block</em> is not <code>false</code>. If no
187 * object matches, calls <i>ifnone</i> and returns its result when it
188 * is specified, or returns <code>nil</code>
189 *
190 * (1..10).detect {|i| i % 5 == 0 and i % 7 == 0 } #=> nil
191 * (1..100).detect {|i| i % 5 == 0 and i % 7 == 0 } #=> 35
192 *
193 */
194
195 static VALUE
196 enum_find(VALUE obj, SEL sel, int argc, VALUE *argv)
197 {
198 VALUE memo = Qundef;
199 VALUE if_none;
200
201 rb_scan_args(argc, argv, "01", &if_none);
202 RETURN_ENUMERATOR(obj, argc, argv);
70ea0b5 per-vm method cache + misc fixes/improvements
Laurent Sansonetti authored
203 rb_objc_block_call(obj, selEach, 0, 0, find_i, (VALUE)&memo);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
204 if (memo != Qundef) {
205 return memo;
206 }
207 if (!NIL_P(if_none)) {
208 return rb_funcall(if_none, rb_intern("call"), 0, 0);
209 }
210 return Qnil;
211 }
212
213 static VALUE
214 find_index_i(VALUE i, VALUE memop, int argc, VALUE *argv)
215 {
216 VALUE *memo = (VALUE*)memop;
217
218 ENUM_WANT_SVALUE();
219
220 if (rb_equal(i, memo[2])) {
221 memo[0] = UINT2NUM(memo[1]);
222 rb_iter_break();
223 }
224 memo[1]++;
225 return Qnil;
226 }
227
228 static VALUE
229 find_index_iter_i(VALUE i, VALUE memop, int argc, VALUE *argv)
230 {
231 VALUE *memo = (VALUE*)memop;
232
233 if (RTEST(enum_yield(argc, argv))) {
234 memo[0] = UINT2NUM(memo[1]);
235 rb_iter_break();
236 }
237 memo[1]++;
238 return Qnil;
239 }
240
241 /*
242 * call-seq:
243 * enum.find_index(value) => int or nil
244 * enum.find_index {| obj | block } => int or nil
245 *
246 * Compares each entry in <i>enum</i> with <em>value</em> or passes
247 * to <em>block</em>. Returns the index for the first for which the
248 * evaluated value is non-false. If no object matches, returns
249 * <code>nil</code>
250 *
251 * (1..10).find_index {|i| i % 5 == 0 and i % 7 == 0 } #=> nil
252 * (1..100).find_index {|i| i % 5 == 0 and i % 7 == 0 } #=> 34
253 * (1..100).find_index(50) #=> 49
254 *
255 */
256
257 static VALUE
258 enum_find_index(VALUE obj, SEL sel, int argc, VALUE *argv)
259 {
260 VALUE memo[3]; /* [return value, current index, condition value] */
261 rb_block_call_func *func;
262
263 if (argc == 0) {
264 RETURN_ENUMERATOR(obj, 0, 0);
265 func = find_index_iter_i;
266 }
267 else {
268 rb_scan_args(argc, argv, "1", &memo[2]);
269 if (rb_block_given_p()) {
270 rb_warn("given block not used");
271 }
272 func = find_index_i;
273 }
274
275 memo[0] = Qnil;
276 memo[1] = 0;
70ea0b5 per-vm method cache + misc fixes/improvements
Laurent Sansonetti authored
277 rb_objc_block_call(obj, selEach, 0, 0, func, (VALUE)memo);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
278 return memo[0];
279 }
280
281 static VALUE
282 find_all_i(VALUE i, VALUE ary, int argc, VALUE *argv)
283 {
284 ENUM_WANT_SVALUE();
285
286 if (RTEST(rb_yield(i))) {
287 rb_ary_push(ary, i);
288 }
289 return Qnil;
290 }
291
292 /*
293 * call-seq:
294 * enum.find_all {| obj | block } => array
295 * enum.select {| obj | block } => array
296 *
297 * Returns an array containing all elements of <i>enum</i> for which
298 * <em>block</em> is not <code>false</code> (see also
299 * <code>Enumerable#reject</code>).
300 *
301 * (1..10).find_all {|i| i % 3 == 0 } #=> [3, 6, 9]
302 *
303 */
304
305 static VALUE
306 enum_find_all(VALUE obj, SEL sel)
307 {
308 VALUE ary;
309
310 RETURN_ENUMERATOR(obj, 0, 0);
311
312 ary = rb_ary_new();
70ea0b5 per-vm method cache + misc fixes/improvements
Laurent Sansonetti authored
313 rb_objc_block_call(obj, selEach, 0, 0, find_all_i, ary);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
314
315 return ary;
316 }
317
318 static VALUE
319 reject_i(VALUE i, VALUE ary, int argc, VALUE *argv)
320 {
321 ENUM_WANT_SVALUE();
322
323 if (!RTEST(rb_yield(i))) {
324 rb_ary_push(ary, i);
325 }
326 return Qnil;
327 }
328
329 /*
330 * call-seq:
331 * enum.reject {| obj | block } => array
332 *
333 * Returns an array for all elements of <i>enum</i> for which
334 * <em>block</em> is false (see also <code>Enumerable#find_all</code>).
335 *
336 * (1..10).reject {|i| i % 3 == 0 } #=> [1, 2, 4, 5, 7, 8, 10]
337 *
338 */
339
340 static VALUE
341 enum_reject(VALUE obj, SEL sel)
342 {
343 VALUE ary;
344
345 RETURN_ENUMERATOR(obj, 0, 0);
346
347 ary = rb_ary_new();
70ea0b5 per-vm method cache + misc fixes/improvements
Laurent Sansonetti authored
348 rb_objc_block_call(obj, selEach, 0, 0, reject_i, ary);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
349
350 return ary;
351 }
352
353 static VALUE
354 collect_i(VALUE i, VALUE ary, int argc, VALUE *argv)
355 {
356 rb_ary_push(ary, enum_yield(argc, argv));
357
358 return Qnil;
359 }
360
361 static VALUE
362 collect_all(VALUE i, VALUE ary, int argc, VALUE *argv)
363 {
364 rb_ary_push(ary, enum_values_pack(argc, argv));
365
366 return Qnil;
367 }
368
369 /*
370 * call-seq:
371 * enum.collect {| obj | block } => array
372 * enum.map {| obj | block } => array
373 *
374 * Returns a new array with the results of running <em>block</em> once
375 * for every element in <i>enum</i>.
376 *
377 * (1..4).collect {|i| i*i } #=> [1, 4, 9, 16]
378 * (1..4).collect { "cat" } #=> ["cat", "cat", "cat", "cat"]
379 *
380 */
381
382 static VALUE
383 enum_collect(VALUE obj, SEL sel)
384 {
385 VALUE ary;
386
387 RETURN_ENUMERATOR(obj, 0, 0);
388
389 ary = rb_ary_new();
70ea0b5 per-vm method cache + misc fixes/improvements
Laurent Sansonetti authored
390 rb_objc_block_call(obj, selEach, 0, 0, collect_i, ary);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
391
392 return ary;
393 }
394
40a433d Improve core/enumerable pass rate
Thibault Martin-Lagardette authored
395 static VALUE
396 flat_map_i(VALUE i, VALUE ary, int argc, VALUE *argv)
397 {
398 VALUE tmp;
399
400 i = enum_yield(argc, argv);
401 tmp = rb_check_array_type(i);
402
403 if (NIL_P(tmp)) {
404 rb_ary_push(ary, i);
405 }
406 else {
407 rb_ary_concat(ary, tmp);
408 }
409 return Qnil;
410 }
411
412 /*
413 * call-seq:
414 * enum.flat_map {| obj | block } => array
415 * enum.collect_concat {| obj | block } => array
416 *
417 * Returns a new array with the concatenated results of running
418 * <em>block</em> once for every element in <i>enum</i>.
419 *
420 * [[1,2],[3,4]].flat_map {|i| i } #=> [1, 2, 3, 4]
421 *
422 */
423
424 static VALUE
425 enum_flat_map(VALUE obj, SEL sel)
426 {
427 VALUE ary;
428
429 RETURN_ENUMERATOR(obj, 0, 0);
430
431 ary = rb_ary_new();
70ea0b5 per-vm method cache + misc fixes/improvements
Laurent Sansonetti authored
432 rb_objc_block_call(obj, selEach, 0, 0, flat_map_i, ary);
40a433d Improve core/enumerable pass rate
Thibault Martin-Lagardette authored
433
434 return ary;
435 }
436
9c1d230 committing experimental branch content
Laurent Sansonetti authored
437 /*
438 * call-seq:
439 * enum.to_a => array
440 * enum.entries => array
441 *
442 * Returns an array containing the items in <i>enum</i>.
443 *
444 * (1..7).to_a #=> [1, 2, 3, 4, 5, 6, 7]
445 * { 'a'=>1, 'b'=>2, 'c'=>3 }.to_a #=> [["a", 1], ["b", 2], ["c", 3]]
446 */
447 static VALUE
448 enum_to_a(VALUE obj, SEL sel, int argc, VALUE *argv)
449 {
450 VALUE ary = rb_ary_new();
451
70ea0b5 per-vm method cache + misc fixes/improvements
Laurent Sansonetti authored
452 rb_objc_block_call(obj, selEach, argc, argv, collect_all, ary);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
453
454 return ary;
455 }
456
457 static VALUE
458 inject_i(VALUE i, VALUE p, int argc, VALUE *argv)
459 {
460 VALUE *memo = (VALUE *)p;
461
462 ENUM_WANT_SVALUE();
463
464 if (memo[0] == Qundef) {
465 memo[0] = i;
466 }
467 else {
468 memo[0] = rb_yield_values(2, memo[0], i);
469 }
470 return Qnil;
471 }
472
473 static VALUE
474 inject_op_i(VALUE i, VALUE p, int argc, VALUE *argv)
475 {
476 VALUE *memo = (VALUE *)p;
477
478 ENUM_WANT_SVALUE();
479
480 if (memo[0] == Qundef) {
481 memo[0] = i;
482 }
483 else {
484 memo[0] = rb_funcall(memo[0], (ID)memo[1], 1, i);
485 }
486 return Qnil;
487 }
488
489 /*
490 * call-seq:
491 * enum.inject(initial, sym) => obj
492 * enum.inject(sym) => obj
493 * enum.inject(initial) {| memo, obj | block } => obj
494 * enum.inject {| memo, obj | block } => obj
495 *
496 * enum.reduce(initial, sym) => obj
497 * enum.reduce(sym) => obj
498 * enum.reduce(initial) {| memo, obj | block } => obj
499 * enum.reduce {| memo, obj | block } => obj
500 *
501 * Combines all elements of <i>enum</i> by applying a binary
502 * operation, specified by a block or a symbol that names a
503 * method or operator.
504 *
505 * If you specify a block, then for each element in <i>enum<i>
506 * the block is passed an accumulator value (<i>memo</i>) and the element.
507 * If you specify a symbol instead, then each element in the collection
508 * will be passed to the named method of <i>memo</i>.
509 * In either case, the result becomes the new value for <i>memo</i>.
510 * At the end of the iteration, the final value of <i>memo</i> is the
511 * return value fo the method.
512 *
513 * If you do not explicitly specify an <i>initial</i> value for <i>memo</i>,
514 * then uses the first element of collection is used as the initial value
515 * of <i>memo</i>.
516 *
517 * Examples:
518 *
519 * # Sum some numbers
520 * (5..10).reduce(:+) #=> 45
521 * # Same using a block and inject
522 * (5..10).inject {|sum, n| sum + n } #=> 45
523 * # Multiply some numbers
524 * (5..10).reduce(1, :*) #=> 151200
525 * # Same using a block
526 * (5..10).inject(1) {|product, n| product * n } #=> 151200
527 * # find the longest word
528 * longest = %w{ cat sheep bear }.inject do |memo,word|
529 * memo.length > word.length ? memo : word
530 * end
531 * longest #=> "sheep"
532 *
533 */
534 static VALUE
535 enum_inject(VALUE obj, SEL sel, int argc, VALUE *argv)
536 {
537 VALUE memo[2];
538 VALUE (*iter)(VALUE, VALUE, int, VALUE*) = inject_i;
539
540 switch (rb_scan_args(argc, argv, "02", &memo[0], &memo[1])) {
541 case 0:
542 memo[0] = Qundef;
543 break;
544 case 1:
545 if (rb_block_given_p()) {
546 break;
547 }
548 memo[1] = (VALUE)rb_to_id(memo[0]);
549 memo[0] = Qundef;
550 iter = inject_op_i;
551 break;
552 case 2:
553 if (rb_block_given_p()) {
554 rb_warning("given block not used");
555 }
556 memo[1] = (VALUE)rb_to_id(memo[1]);
557 iter = inject_op_i;
558 break;
559 }
70ea0b5 per-vm method cache + misc fixes/improvements
Laurent Sansonetti authored
560 rb_objc_block_call(obj, selEach, 0, 0, iter, (VALUE)memo);
38a26b8 implemented NODE_IFUNC-type blocks
Laurent Sansonetti authored
561 if (memo[0] == Qundef) {
562 return Qnil;
563 }
9c1d230 committing experimental branch content
Laurent Sansonetti authored
564 return memo[0];
565 }
566
567 static VALUE
568 partition_i(VALUE i, VALUE *ary, int argc, VALUE *argv)
569 {
570 ENUM_WANT_SVALUE();
571
572 if (RTEST(rb_yield(i))) {
573 rb_ary_push(ary[0], i);
574 }
575 else {
576 rb_ary_push(ary[1], i);
577 }
578 return Qnil;
579 }
580
581 /*
582 * call-seq:
583 * enum.partition {| obj | block } => [ true_array, false_array ]
584 *
585 * Returns two arrays, the first containing the elements of
586 * <i>enum</i> for which the block evaluates to true, the second
587 * containing the rest.
588 *
589 * (1..6).partition {|i| (i&1).zero?} #=> [[2, 4, 6], [1, 3, 5]]
590 *
591 */
592
593 static VALUE
594 enum_partition(VALUE obj, SEL sel)
595 {
596 VALUE ary[2];
597
598 RETURN_ENUMERATOR(obj, 0, 0);
599
600 ary[0] = rb_ary_new();
601 ary[1] = rb_ary_new();
70ea0b5 per-vm method cache + misc fixes/improvements
Laurent Sansonetti authored
602 rb_objc_block_call(obj, selEach, 0, 0, partition_i, (VALUE)ary);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
603
604 return rb_assoc_new(ary[0], ary[1]);
605 }
606
607 static VALUE
608 group_by_i(VALUE i, VALUE hash, int argc, VALUE *argv)
609 {
610 VALUE group;
611 VALUE values;
612
613 ENUM_WANT_SVALUE();
614
615 group = rb_yield(i);
616 values = rb_hash_aref(hash, group);
617 if (NIL_P(values)) {
2af1f13 avoid using rb_ary_new3()
Laurent Sansonetti authored
618 values = rb_ary_new4(1, &i);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
619 rb_hash_aset(hash, group, values);
620 }
621 else {
622 rb_ary_push(values, i);
623 }
624 return Qnil;
625 }
626
627 /*
628 * call-seq:
629 * enum.group_by {| obj | block } => a_hash
630 *
631 * Returns a hash, which keys are evaluated result from the
632 * block, and values are arrays of elements in <i>enum</i>
633 * corresponding to the key.
634 *
635 * (1..6).group_by {|i| i%3} #=> {0=>[3, 6], 1=>[1, 4], 2=>[2, 5]}
636 *
637 */
638
639 static VALUE
640 enum_group_by(VALUE obj, SEL sel)
641 {
642 VALUE hash;
643
644 RETURN_ENUMERATOR(obj, 0, 0);
645
646 hash = rb_hash_new();
70ea0b5 per-vm method cache + misc fixes/improvements
Laurent Sansonetti authored
647 rb_objc_block_call(obj, selEach, 0, 0, group_by_i, hash);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
648
649 return hash;
650 }
651
652 static VALUE
653 first_i(VALUE i, VALUE *ary, int argc, VALUE *argv)
654 {
655 ENUM_WANT_SVALUE();
656
657 if (NIL_P(ary[0])) {
658 ary[1] = i;
659 rb_iter_break();
660 }
661 else {
662 long n = NUM2LONG(ary[0]);
663
664 if (n <= 0) {
665 rb_iter_break();
666 }
8e41e1c fixing a bunch of minor IO bugs
Laurent Sansonetti authored
667 else {
668 rb_ary_push(ary[1], i);
669 n--;
670 ary[0] = INT2NUM(n);
671 }
9c1d230 committing experimental branch content
Laurent Sansonetti authored
672 }
673 return Qnil;
674 }
675
676 /*
677 * call-seq:
678 * enum.first -> obj or nil
679 * enum.first(n) -> an_array
680 *
681 * Returns the first element, or the first +n+ elements, of the enumerable.
682 * If the enumerable is empty, the first form returns <code>nil</code>, and the
683 * second form returns an empty array.
684 *
685 */
686
687 static VALUE
688 enum_first(VALUE obj, SEL sel, int argc, VALUE *argv)
689 {
690 VALUE n, ary[2];
691
692 if (argc == 0) {
693 ary[0] = ary[1] = Qnil;
694 }
695 else {
696 rb_scan_args(argc, argv, "01", &n);
697 ary[0] = n;
698 ary[1] = rb_ary_new2(NUM2LONG(n));
699 }
70ea0b5 per-vm method cache + misc fixes/improvements
Laurent Sansonetti authored
700 rb_objc_block_call(obj, selEach, 0, 0, first_i, (VALUE)ary);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
701
702 return ary[1];
703 }
704
705
706 /*
707 * call-seq:
708 * enum.sort => array
709 * enum.sort {| a, b | block } => array
710 *
711 * Returns an array containing the items in <i>enum</i> sorted,
712 * either according to their own <code><=></code> method, or by using
713 * the results of the supplied block. The block should return -1, 0, or
714 * +1 depending on the comparison between <i>a</i> and <i>b</i>. As of
715 * Ruby 1.8, the method <code>Enumerable#sort_by</code> implements a
716 * built-in Schwartzian Transform, useful when key computation or
717 * comparison is expensive..
718 *
719 * %w(rhea kea flea).sort #=> ["flea", "kea", "rhea"]
720 * (1..10).sort {|a,b| b <=> a} #=> [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
721 */
722
723 static VALUE
724 enum_sort(VALUE obj, SEL sel)
725 {
726 return rb_ary_sort(enum_to_a(obj, 0, 0, 0));
727 }
728
729 static VALUE
730 sort_by_i(VALUE i, VALUE ary, int argc, VALUE *argv)
731 {
732 NODE *memo;
733
734 ENUM_WANT_SVALUE();
735 #if !WITH_OBJC
736 if (RBASIC(ary)->klass) {
737 rb_raise(rb_eRuntimeError, "sort_by reentered");
738 }
739 #endif
740 memo = rb_node_newnode(NODE_MEMO, rb_yield(i), i, 0);
741 rb_ary_push(ary, (VALUE)memo);
742 return Qnil;
743 }
744
745 static int
0cd758f adding a new optimized Array for default allocations plus various opt…
Laurent Sansonetti authored
746 sort_by_cmp(void *data, const void *ap, const void *bp)
9c1d230 committing experimental branch content
Laurent Sansonetti authored
747 {
748 VALUE a = (*(NODE *const *)ap)->u1.value;
749 VALUE b = (*(NODE *const *)bp)->u1.value;
78bea84 optimized dummy calls to <=>:
Laurent Sansonetti authored
750 return rb_cmpint(rb_objs_cmp(a, b), a, b);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
751 }
752
753 /*
754 * call-seq:
755 * enum.sort_by {| obj | block } => array
756 *
757 * Sorts <i>enum</i> using a set of keys generated by mapping the
758 * values in <i>enum</i> through the given block.
759 *
760 * %w{ apple pear fig }.sort_by {|word| word.length}
761 * #=> ["fig", "pear", "apple"]
762 *
763 * The current implementation of <code>sort_by</code> generates an
764 * array of tuples containing the original collection element and the
765 * mapped value. This makes <code>sort_by</code> fairly expensive when
766 * the keysets are simple
767 *
768 * require 'benchmark'
769 * include Benchmark
770 *
771 * a = (1..100000).map {rand(100000)}
772 *
773 * bm(10) do |b|
774 * b.report("Sort") { a.sort }
775 * b.report("Sort by") { a.sort_by {|a| a} }
776 * end
777 *
778 * <em>produces:</em>
779 *
780 * user system total real
781 * Sort 0.180000 0.000000 0.180000 ( 0.175469)
782 * Sort by 1.980000 0.040000 2.020000 ( 2.013586)
783 *
784 * However, consider the case where comparing the keys is a non-trivial
785 * operation. The following code sorts some files on modification time
786 * using the basic <code>sort</code> method.
787 *
788 * files = Dir["*"]
789 * sorted = files.sort {|a,b| File.new(a).mtime <=> File.new(b).mtime}
790 * sorted #=> ["mon", "tues", "wed", "thurs"]
791 *
792 * This sort is inefficient: it generates two new <code>File</code>
793 * objects during every comparison. A slightly better technique is to
794 * use the <code>Kernel#test</code> method to generate the modification
795 * times directly.
796 *
797 * files = Dir["*"]
798 * sorted = files.sort { |a,b|
799 * test(?M, a) <=> test(?M, b)
800 * }
801 * sorted #=> ["mon", "tues", "wed", "thurs"]
802 *
803 * This still generates many unnecessary <code>Time</code> objects. A
804 * more efficient technique is to cache the sort keys (modification
805 * times in this case) before the sort. Perl users often call this
806 * approach a Schwartzian Transform, after Randal Schwartz. We
807 * construct a temporary array, where each element is an array
808 * containing our sort key along with the filename. We sort this array,
809 * and then extract the filename from the result.
810 *
811 * sorted = Dir["*"].collect { |f|
812 * [test(?M, f), f]
813 * }.sort.collect { |f| f[1] }
814 * sorted #=> ["mon", "tues", "wed", "thurs"]
815 *
816 * This is exactly what <code>sort_by</code> does internally.
817 *
818 * sorted = Dir["*"].sort_by {|f| test(?M, f)}
819 * sorted #=> ["mon", "tues", "wed", "thurs"]
820 */
821
822 static VALUE
823 enum_sort_by(VALUE obj, SEL sel)
824 {
825 RETURN_ENUMERATOR(obj, 0, 0);
826
0cd758f adding a new optimized Array for default allocations plus various opt…
Laurent Sansonetti authored
827 VALUE ary;
9c1d230 committing experimental branch content
Laurent Sansonetti authored
828 if (TYPE(obj) == T_ARRAY) {
829 ary = rb_ary_new2(RARRAY_LEN(obj));
830 }
831 else {
832 ary = rb_ary_new();
833 }
70ea0b5 per-vm method cache + misc fixes/improvements
Laurent Sansonetti authored
834 rb_objc_block_call(obj, selEach, 0, 0, sort_by_i, ary);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
835 if (RARRAY_LEN(ary) > 1) {
0cd758f adding a new optimized Array for default allocations plus various opt…
Laurent Sansonetti authored
836 qsort_r((VALUE *)RARRAY_PTR(ary), RARRAY_LEN(ary), sizeof(VALUE), NULL,
837 sort_by_cmp);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
838 }
0cd758f adding a new optimized Array for default allocations plus various opt…
Laurent Sansonetti authored
839 for (long i = 0; i < RARRAY_LEN(ary); i++) {
9c1d230 committing experimental branch content
Laurent Sansonetti authored
840 rb_ary_store(ary, i, RNODE(RARRAY_AT(ary, i))->u2.value);
841 }
842 return ary;
843 }
844
845 #define DEFINE_ENUMFUNCS(name) \
846 static VALUE \
847 name##_i(VALUE i, VALUE *memo, int argc, VALUE *argv) \
848 { \
849 return enum_##name##_func(enum_values_pack(argc, argv), memo); \
850 } \
851 \
852 static VALUE \
853 name##_iter_i(VALUE i, VALUE *memo, int argc, VALUE *argv) \
854 { \
855 return enum_##name##_func(enum_yield(argc, argv), memo); \
856 }
857
858 static VALUE
859 enum_all_func(VALUE result, VALUE *memo)
860 {
861 if (!RTEST(result)) {
862 *memo = Qfalse;
863 rb_iter_break();
864 }
865 return Qnil;
866 }
867
868 DEFINE_ENUMFUNCS(all)
869
870 /*
871 * call-seq:
872 * enum.all? [{|obj| block } ] => true or false
873 *
874 * Passes each element of the collection to the given block. The method
875 * returns <code>true</code> if the block never returns
876 * <code>false</code> or <code>nil</code>. If the block is not given,
877 * Ruby adds an implicit block of <code>{|obj| obj}</code> (that is
878 * <code>all?</code> will return <code>true</code> only if none of the
879 * collection members are <code>false</code> or <code>nil</code>.)
880 *
881 * %w{ant bear cat}.all? {|word| word.length >= 3} #=> true
882 * %w{ant bear cat}.all? {|word| word.length >= 4} #=> false
883 * [ nil, true, 99 ].all? #=> false
884 *
885 */
886
887 static VALUE
888 enum_all(VALUE obj, SEL sel)
889 {
890 VALUE result = Qtrue;
891
70ea0b5 per-vm method cache + misc fixes/improvements
Laurent Sansonetti authored
892 rb_objc_block_call(obj, selEach, 0, 0, rb_block_given_p() ? all_iter_i : all_i, (VALUE)&result);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
893 return result;
894 }
895
896 static VALUE
897 enum_any_func(VALUE result, VALUE *memo)
898 {
899 if (RTEST(result)) {
900 *memo = Qtrue;
901 rb_iter_break();
902 }
903 return Qnil;
904 }
905
906 DEFINE_ENUMFUNCS(any)
907
908 /*
909 * call-seq:
910 * enum.any? [{|obj| block } ] => true or false
911 *
912 * Passes each element of the collection to the given block. The method
913 * returns <code>true</code> if the block ever returns a value other
914 * than <code>false</code> or <code>nil</code>. If the block is not
915 * given, Ruby adds an implicit block of <code>{|obj| obj}</code> (that
916 * is <code>any?</code> will return <code>true</code> if at least one
917 * of the collection members is not <code>false</code> or
918 * <code>nil</code>.
919 *
920 * %w{ant bear cat}.any? {|word| word.length >= 3} #=> true
921 * %w{ant bear cat}.any? {|word| word.length >= 4} #=> true
922 * [ nil, true, 99 ].any? #=> true
923 *
924 */
925
926 static VALUE
927 enum_any(VALUE obj, SEL sel)
928 {
929 VALUE result = Qfalse;
930
70ea0b5 per-vm method cache + misc fixes/improvements
Laurent Sansonetti authored
931 rb_objc_block_call(obj, selEach, 0, 0, rb_block_given_p() ? any_iter_i : any_i, (VALUE)&result);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
932 return result;
933 }
934
935 static VALUE
936 enum_one_func(VALUE result, VALUE *memo)
937 {
938 if (RTEST(result)) {
939 if (*memo == Qundef) {
940 *memo = Qtrue;
941 }
942 else if (*memo == Qtrue) {
943 *memo = Qfalse;
944 rb_iter_break();
945 }
946 }
947 return Qnil;
948 }
949
950 DEFINE_ENUMFUNCS(one)
951
952 /*
953 * call-seq:
954 * enum.one? [{|obj| block }] => true or false
955 *
956 * Passes each element of the collection to the given block. The method
957 * returns <code>true</code> if the block returns <code>true</code>
958 * exactly once. If the block is not given, <code>one?</code> will return
959 * <code>true</code> only if exactly one of the collection members is
960 * true.
961 *
962 * %w{ant bear cat}.one? {|word| word.length == 4} #=> true
963 * %w{ant bear cat}.one? {|word| word.length > 4} #=> false
964 * %w{ant bear cat}.one? {|word| word.length < 4} #=> false
965 * [ nil, true, 99 ].one? #=> false
966 * [ nil, true, false ].one? #=> true
967 *
968 */
969
970 static VALUE
971 enum_one(VALUE obj, SEL sel)
972 {
973 VALUE result = Qundef;
974
70ea0b5 per-vm method cache + misc fixes/improvements
Laurent Sansonetti authored
975 rb_objc_block_call(obj, selEach, 0, 0, rb_block_given_p() ? one_iter_i : one_i, (VALUE)&result);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
976 if (result == Qundef) return Qfalse;
977 return result;
978 }
979
980 static VALUE
981 enum_none_func(VALUE result, VALUE *memo)
982 {
983 if (RTEST(result)) {
984 *memo = Qfalse;
985 rb_iter_break();
986 }
987 return Qnil;
988 }
989
990 DEFINE_ENUMFUNCS(none)
991
992 /*
993 * call-seq:
994 * enum.none? [{|obj| block }] => true or false
995 *
996 * Passes each element of the collection to the given block. The method
997 * returns <code>true</code> if the block never returns <code>true</code>
998 * for all elements. If the block is not given, <code>none?</code> will return
999 * <code>true</code> only if none of the collection members is true.
1000 *
1001 * %w{ant bear cat}.none? {|word| word.length == 5} #=> true
1002 * %w{ant bear cat}.none? {|word| word.length >= 4} #=> false
1003 * [].none? #=> true
1004 * [nil].none? #=> true
1005 * [nil,false].none? #=> true
1006 */
1007 static VALUE
1008 enum_none(VALUE obj, SEL sel)
1009 {
1010 VALUE result = Qtrue;
1011
70ea0b5 per-vm method cache + misc fixes/improvements
Laurent Sansonetti authored
1012 rb_objc_block_call(obj, selEach, 0, 0, rb_block_given_p() ? none_iter_i : none_i, (VALUE)&result);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1013 return result;
1014 }
1015
1016 static VALUE
1017 min_i(VALUE i, VALUE *memo, int argc, VALUE *argv)
1018 {
1019 VALUE cmp;
1020
1021 ENUM_WANT_SVALUE();
1022
1023 if (*memo == Qundef) {
1024 *memo = i;
1025 }
1026 else {
78bea84 optimized dummy calls to <=>:
Laurent Sansonetti authored
1027 cmp = rb_objs_cmp(i, *memo);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1028 if (rb_cmpint(cmp, i, *memo) < 0) {
1029 *memo = i;
1030 }
1031 }
1032 return Qnil;
1033 }
1034
1035 static VALUE
1036 min_ii(VALUE i, VALUE *memo, int argc, VALUE *argv)
1037 {
1038 VALUE cmp;
1039
1040 ENUM_WANT_SVALUE();
1041
1042 if (*memo == Qundef) {
1043 *memo = i;
1044 }
1045 else {
1046 VALUE ary = memo[1];
1047 rb_ary_store(ary, 0, i);
1048 rb_ary_store(ary, 1, *memo);
1049 cmp = rb_yield(ary);
1050 if (rb_cmpint(cmp, i, *memo) < 0) {
1051 *memo = i;
1052 }
1053 }
1054 return Qnil;
1055 }
1056
1057
1058 /*
1059 * call-seq:
1060 * enum.min => obj
1061 * enum.min {| a,b | block } => obj
1062 *
1063 * Returns the object in <i>enum</i> with the minimum value. The
1064 * first form assumes all objects implement <code>Comparable</code>;
1065 * the second uses the block to return <em>a <=> b</em>.
1066 *
1067 * a = %w(albatross dog horse)
1068 * a.min #=> "albatross"
1069 * a.min {|a,b| a.length <=> b.length } #=> "dog"
1070 */
1071
1072 static VALUE
1073 enum_min(VALUE obj, SEL sel)
1074 {
1075 VALUE result[2];
1076
1077 result[0] = Qundef;
1078 if (rb_block_given_p()) {
2af1f13 avoid using rb_ary_new3()
Laurent Sansonetti authored
1079 VALUE elems[] = { Qnil, Qnil };
1080 result[1] = rb_ary_new4(2, elems);
70ea0b5 per-vm method cache + misc fixes/improvements
Laurent Sansonetti authored
1081 rb_objc_block_call(obj, selEach, 0, 0, min_ii, (VALUE)result);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1082 }
1083 else {
70ea0b5 per-vm method cache + misc fixes/improvements
Laurent Sansonetti authored
1084 rb_objc_block_call(obj, selEach, 0, 0, min_i, (VALUE)result);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1085 }
1086 if (result[0] == Qundef) return Qnil;
1087 return result[0];
1088 }
1089
1090 static VALUE
1091 max_i(VALUE i, VALUE *memo, int argc, VALUE *argv)
1092 {
1093 VALUE cmp;
1094
1095 ENUM_WANT_SVALUE();
1096
1097 if (*memo == Qundef) {
1098 *memo = i;
1099 }
1100 else {
78bea84 optimized dummy calls to <=>:
Laurent Sansonetti authored
1101 cmp = rb_objs_cmp(i, *memo);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1102 if (rb_cmpint(cmp, i, *memo) > 0) {
1103 *memo = i;
1104 }
1105 }
1106 return Qnil;
1107 }
1108
1109 static VALUE
1110 max_ii(VALUE i, VALUE *memo, int argc, VALUE *argv)
1111 {
1112 VALUE cmp;
1113
1114 ENUM_WANT_SVALUE();
1115
1116 if (*memo == Qundef) {
1117 *memo = i;
1118 }
1119 else {
1120 VALUE ary = memo[1];
1121 rb_ary_store(ary, 0, i);
1122 rb_ary_store(ary, 1, *memo);
1123 cmp = rb_yield(ary);
1124 if (rb_cmpint(cmp, i, *memo) > 0) {
1125 *memo = i;
1126 }
1127 }
1128 return Qnil;
1129 }
1130
1131 /*
1132 * call-seq:
1133 * enum.max => obj
1134 * enum.max {|a,b| block } => obj
1135 *
1136 * Returns the object in _enum_ with the maximum value. The
1137 * first form assumes all objects implement <code>Comparable</code>;
1138 * the second uses the block to return <em>a <=> b</em>.
1139 *
1140 * a = %w(albatross dog horse)
1141 * a.max #=> "horse"
1142 * a.max {|a,b| a.length <=> b.length } #=> "albatross"
1143 */
1144
1145 static VALUE
1146 enum_max(VALUE obj, SEL sel)
1147 {
1148 VALUE result[2];
1149
1150 result[0] = Qundef;
1151 if (rb_block_given_p()) {
2af1f13 avoid using rb_ary_new3()
Laurent Sansonetti authored
1152 VALUE elems[] = { Qnil, Qnil };
1153 result[1] = rb_ary_new4(2, elems);
70ea0b5 per-vm method cache + misc fixes/improvements
Laurent Sansonetti authored
1154 rb_objc_block_call(obj, selEach, 0, 0, max_ii, (VALUE)result);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1155 }
1156 else {
70ea0b5 per-vm method cache + misc fixes/improvements
Laurent Sansonetti authored
1157 rb_objc_block_call(obj, selEach, 0, 0, max_i, (VALUE)result);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1158 }
1159 if (result[0] == Qundef) return Qnil;
1160 return result[0];
1161 }
1162
1163 static VALUE
1164 minmax_i(VALUE i, VALUE *memo, int argc, VALUE *argv)
1165 {
1166 int n;
1167
1168 ENUM_WANT_SVALUE();
1169
1170 if (memo[0] == Qundef) {
1171 memo[0] = i;
1172 memo[1] = i;
1173 }
1174 else {
78bea84 optimized dummy calls to <=>:
Laurent Sansonetti authored
1175 n = rb_cmpint(rb_objs_cmp(i, memo[0]), i, memo[0]);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1176 if (n < 0) {
1177 memo[0] = i;
1178 }
78bea84 optimized dummy calls to <=>:
Laurent Sansonetti authored
1179 n = rb_cmpint(rb_objs_cmp(i, memo[1]), i, memo[1]);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1180 if (n > 0) {
1181 memo[1] = i;
1182 }
1183 }
1184 return Qnil;
1185 }
1186
1187 static VALUE
1188 minmax_ii(VALUE i, VALUE *memo, int argc, VALUE *argv)
1189 {
1190 int n;
1191
1192 ENUM_WANT_SVALUE();
1193
1194 if (memo[0] == Qundef) {
1195 memo[0] = i;
1196 memo[1] = i;
1197 }
1198 else {
1199 VALUE ary = memo[2];
1200
1201 rb_ary_store(ary, 0, i);
1202 rb_ary_store(ary, 1, memo[0]);
1203 n = rb_cmpint(rb_yield(ary), i, memo[0]);
1204 if (n < 0) {
1205 memo[0] = i;
1206 }
1207 rb_ary_store(ary, 0, i);
1208 rb_ary_store(ary, 1, memo[1]);
1209 n = rb_cmpint(rb_yield(ary), i, memo[1]);
1210 if (n > 0) {
1211 memo[1] = i;
1212 }
1213 }
1214 return Qnil;
1215 }
1216
1217 /*
1218 * call-seq:
1219 * enum.minmax => [min,max]
1220 * enum.minmax {|a,b| block } => [min,max]
1221 *
1222 * Returns two elements array which contains the minimum and the
1223 * maximum value in the enumerable. The first form assumes all
1224 * objects implement <code>Comparable</code>; the second uses the
1225 * block to return <em>a <=> b</em>.
1226 *
1227 * a = %w(albatross dog horse)
1228 * a.minmax #=> ["albatross", "horse"]
1229 * a.minmax {|a,b| a.length <=> b.length } #=> ["dog", "albatross"]
1230 */
1231
1232 static VALUE
1233 enum_minmax(VALUE obj, SEL sel)
1234 {
1235 VALUE result[3];
2af1f13 avoid using rb_ary_new3()
Laurent Sansonetti authored
1236 VALUE elems[] = { Qnil, Qnil };
1237 VALUE ary = rb_ary_new4(2, elems);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1238
1239 result[0] = Qundef;
1240 if (rb_block_given_p()) {
1241 result[2] = ary;
70ea0b5 per-vm method cache + misc fixes/improvements
Laurent Sansonetti authored
1242 rb_objc_block_call(obj, selEach, 0, 0, minmax_ii, (VALUE)result);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1243 }
1244 else {
70ea0b5 per-vm method cache + misc fixes/improvements
Laurent Sansonetti authored
1245 rb_objc_block_call(obj, selEach, 0, 0, minmax_i, (VALUE)result);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1246 }
1247 if (result[0] != Qundef) {
1248 rb_ary_store(ary, 0, result[0]);
1249 rb_ary_store(ary, 1, result[1]);
1250 }
1251 return ary;
1252 }
1253
1254 static VALUE
1255 min_by_i(VALUE i, VALUE *memo, int argc, VALUE *argv)
1256 {
1257 VALUE v;
1258
1259 ENUM_WANT_SVALUE();
1260
1261 v = rb_yield(i);
1262 if (memo[0] == Qundef) {
1263 memo[0] = v;
1264 memo[1] = i;
1265 }
78bea84 optimized dummy calls to <=>:
Laurent Sansonetti authored
1266 else if (rb_cmpint(rb_objs_cmp(v, memo[0]), v, memo[0]) < 0) {
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1267 memo[0] = v;
1268 memo[1] = i;
1269 }
1270 return Qnil;
1271 }
1272
1273 /*
1274 * call-seq:
1275 * enum.min_by {| obj| block } => obj
1276 *
1277 * Returns the object in <i>enum</i> that gives the minimum
1278 * value from the given block.
1279 *
1280 * a = %w(albatross dog horse)
1281 * a.min_by {|x| x.length } #=> "dog"
1282 */
1283
1284 static VALUE
1285 enum_min_by(VALUE obj, SEL sel)
1286 {
1287 VALUE memo[2];
1288
1289 RETURN_ENUMERATOR(obj, 0, 0);
1290
1291 memo[0] = Qundef;
1292 memo[1] = Qnil;
70ea0b5 per-vm method cache + misc fixes/improvements
Laurent Sansonetti authored
1293 rb_objc_block_call(obj, selEach, 0, 0, min_by_i, (VALUE)memo);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1294 return memo[1];
1295 }
1296
1297 static VALUE
1298 max_by_i(VALUE i, VALUE *memo, int argc, VALUE *argv)
1299 {
1300 VALUE v;
1301
1302 ENUM_WANT_SVALUE();
1303
1304 v = rb_yield(i);
1305 if (memo[0] == Qundef) {
1306 memo[0] = v;
1307 memo[1] = i;
1308 }
78bea84 optimized dummy calls to <=>:
Laurent Sansonetti authored
1309 else if (rb_cmpint(rb_objs_cmp(v, memo[0]), v, memo[0]) > 0) {
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1310 memo[0] = v;
1311 memo[1] = i;
1312 }
1313 return Qnil;
1314 }
1315
1316 /*
1317 * call-seq:
1318 * enum.max_by {| obj| block } => obj
1319 *
1320 * Returns the object in <i>enum</i> that gives the maximum
1321 * value from the given block.
1322 *
1323 * a = %w(albatross dog horse)
1324 * a.max_by {|x| x.length } #=> "albatross"
1325 */
1326
1327 static VALUE
1328 enum_max_by(VALUE obj, SEL sel)
1329 {
1330 VALUE memo[2];
1331
1332 RETURN_ENUMERATOR(obj, 0, 0);
1333
1334 memo[0] = Qundef;
1335 memo[1] = Qnil;
70ea0b5 per-vm method cache + misc fixes/improvements
Laurent Sansonetti authored
1336 rb_objc_block_call(obj, selEach, 0, 0, max_by_i, (VALUE)memo);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1337 return memo[1];
1338 }
1339
1340 static VALUE
1341 minmax_by_i(VALUE i, VALUE *memo, int argc, VALUE *argv)
1342 {
1343 VALUE v;
1344
1345 ENUM_WANT_SVALUE();
1346
1347 v = rb_yield(i);
1348 if (memo[0] == Qundef) {
1349 memo[0] = v;
1350 memo[1] = v;
1351 memo[2] = i;
1352 memo[3] = i;
1353 }
1354 else {
78bea84 optimized dummy calls to <=>:
Laurent Sansonetti authored
1355 if (rb_cmpint(rb_objs_cmp(v, memo[0]), v, memo[0]) < 0) {
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1356 memo[0] = v;
1357 memo[2] = i;
1358 }
78bea84 optimized dummy calls to <=>:
Laurent Sansonetti authored
1359 if (rb_cmpint(rb_objs_cmp(v, memo[1]), v, memo[1]) > 0) {
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1360 memo[1] = v;
1361 memo[3] = i;
1362 }
1363 }
1364 return Qnil;
1365 }
1366
1367 /*
1368 * call-seq:
1369 * enum.minmax_by {| obj| block } => [min, max]
1370 *
1371 * Returns two elements array array containing the objects in
1372 * <i>enum</i> that gives the minimum and maximum values respectively
1373 * from the given block.
1374 *
1375 * a = %w(albatross dog horse)
1376 * a.minmax_by {|x| x.length } #=> ["dog", "albatross"]
1377 */
1378
1379 static VALUE
1380 enum_minmax_by(VALUE obj, SEL sel)
1381 {
1382 VALUE memo[4];
1383
1384 RETURN_ENUMERATOR(obj, 0, 0);
1385
1386 memo[0] = Qundef;
1387 memo[1] = Qundef;
1388 memo[2] = Qnil;
1389 memo[3] = Qnil;
70ea0b5 per-vm method cache + misc fixes/improvements
Laurent Sansonetti authored
1390 rb_objc_block_call(obj, selEach, 0, 0, minmax_by_i, (VALUE)memo);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1391 return rb_assoc_new(memo[2], memo[3]);
1392 }
1393
1394 static VALUE
1395 member_i(VALUE iter, VALUE *memo, int argc, VALUE *argv)
1396 {
1397 if (rb_equal(enum_values_pack(argc, argv), memo[0])) {
1398 memo[1] = Qtrue;
1399 rb_iter_break();
1400 }
1401 return Qnil;
1402 }
1403
1404 /*
1405 * call-seq:
1406 * enum.include?(obj) => true or false
1407 * enum.member?(obj) => true or false
1408 *
1409 * Returns <code>true</code> if any member of <i>enum</i> equals
1410 * <i>obj</i>. Equality is tested using <code>==</code>.
1411 *
1412 * IO.constants.include? :SEEK_SET #=> true
1413 * IO.constants.include? :SEEK_NO_FURTHER #=> false
1414 *
1415 */
1416
1417 static VALUE
1418 enum_member(VALUE obj, SEL sel, VALUE val)
1419 {
1420 VALUE memo[2];
1421
1422 memo[0] = val;
1423 memo[1] = Qfalse;
70ea0b5 per-vm method cache + misc fixes/improvements
Laurent Sansonetti authored
1424 rb_objc_block_call(obj, selEach, 0, 0, member_i, (VALUE)memo);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1425 return memo[1];
1426 }
1427
1428 static VALUE
1429 each_with_index_i(VALUE i, VALUE memo, int argc, VALUE *argv)
1430 {
1431 long n = (*(VALUE *)memo)++;
1432
1433 return rb_yield_values(2, enum_values_pack(argc, argv), INT2NUM(n));
1434 }
1435
1436 /*
1437 * call-seq:
1438 * enum.each_with_index {|obj, i| block } -> enum
1439 *
1440 * Calls <em>block</em> with two arguments, the item and its index,
1441 * for each item in <i>enum</i>. Given arguments are passed through
1442 * to #each().
1443 *
1444 * hash = Hash.new
1445 * %w(cat dog wombat).each_with_index {|item, index|
1446 * hash[item] = index
1447 * }
1448 * hash #=> {"cat"=>0, "dog"=>1, "wombat"=>2}
1449 *
1450 */
1451
1452 static VALUE
1453 enum_each_with_index(VALUE obj, SEL sel, int argc, VALUE *argv)
1454 {
1455 long memo;
1456
1457 RETURN_ENUMERATOR(obj, argc, argv);
1458
1459 memo = 0;
70ea0b5 per-vm method cache + misc fixes/improvements
Laurent Sansonetti authored
1460 rb_objc_block_call(obj, selEach, argc, argv, each_with_index_i, (VALUE)&memo);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1461 return obj;
1462 }
1463
1464
1465 /*
1466 * call-seq:
1467 * enum.reverse_each {|item| block }
1468 *
1469 * Traverses <i>enum</i> in reverse order.
1470 */
1471
1472 static VALUE
1473 enum_reverse_each(VALUE obj, SEL sel, int argc, VALUE *argv)
1474 {
1475 VALUE ary;
1476 long i;
1477
1478 RETURN_ENUMERATOR(obj, argc, argv);
1479
1480 ary = enum_to_a(obj, 0, argc, argv);
1481
1482 for (i = RARRAY_LEN(ary); --i >= 0; ) {
1483 rb_yield(RARRAY_AT(ary, i));
1484 RETURN_IF_BROKEN();
1485 }
1486
1487 return obj;
1488 }
1489
40a433d Improve core/enumerable pass rate
Thibault Martin-Lagardette authored
1490 static VALUE
1491 each_val_i(VALUE i, VALUE p, int argc, VALUE *argv)
1492 {
1493 ENUM_WANT_SVALUE();
1494 rb_yield(i);
1495 return Qnil;
1496 }
1497
1498 /*
1499 * call-seq:
1500 * enum.each_entry {|obj| block} => enum
1501 *
1502 * Calls <i>block</i> once for each element in <i>self</i>, passing that
1503 * element as a parameter, converting multiple values from yield to an
1504 * array.
1505 *
1506 * class Foo
1507 * include Enumerable
1508 * def each
1509 * yield 1
1510 * yield 1,2
1511 * end
1512 * end
1513 * Foo.new.each_entry{|o| print o, " -- "}
1514 *
1515 * produces:
1516 *
1517 * 1 -- [1, 2] --
1518 */
1519
1520 static VALUE
1521 enum_each_entry(VALUE obj, SEL sel, int argc, VALUE *argv)
1522 {
1523 RETURN_ENUMERATOR(obj, argc, argv);
70ea0b5 per-vm method cache + misc fixes/improvements
Laurent Sansonetti authored
1524 rb_objc_block_call(obj, selEach, argc, argv, each_val_i, 0);
40a433d Improve core/enumerable pass rate
Thibault Martin-Lagardette authored
1525 return obj;
1526 }
1527
1528 static VALUE
1529 each_slice_i(VALUE i, VALUE *memo, int argc, VALUE *argv)
1530 {
1531 VALUE ary = memo[0];
1532 VALUE v = Qnil;
1533 long size = (long)memo[1];
1534 ENUM_WANT_SVALUE();
1535
1536 rb_ary_push(ary, i);
1537
1538 if (RARRAY_LEN(ary) == size) {
1539 v = rb_yield(ary);
1540 memo[0] = rb_ary_new2(size);
1541 }
1542
1543 return v;
1544 }
1545
1546 /*
1547 * call-seq:
1548 * e.each_slice(n) {...}
1549 * e.each_slice(n)
1550 *
1551 * Iterates the given block for each slice of <n> elements. If no
1552 * block is given, returns an enumerator.
1553 *
1554 * e.g.:
1555 * (1..10).each_slice(3) {|a| p a}
1556 * # outputs below
1557 * [1, 2, 3]
1558 * [4, 5, 6]
1559 * [7, 8, 9]
1560 * [10]
1561 *
1562 */
1563 static VALUE
1564 enum_each_slice(VALUE obj, SEL sel, VALUE n)
1565 {
1566 long size = NUM2LONG(n);
1567 VALUE args[2], ary;
1568
1569 if (size <= 0) {
1570 rb_raise(rb_eArgError, "invalid slice size");
1571 }
1572 RETURN_ENUMERATOR(obj, 1, &n);
1573 args[0] = rb_ary_new2(size);
1574 args[1] = (VALUE)size;
1575
70ea0b5 per-vm method cache + misc fixes/improvements
Laurent Sansonetti authored
1576 rb_objc_block_call(obj, selEach, 0, 0, each_slice_i, (VALUE)args);
40a433d Improve core/enumerable pass rate
Thibault Martin-Lagardette authored
1577
1578 ary = args[0];
1579 if (RARRAY_LEN(ary) > 0) {
1580 rb_yield(ary);
1581 }
1582
1583 return Qnil;
1584 }
1585
1586 static VALUE
1587 each_cons_i(VALUE i, VALUE *memo, int argc, VALUE *argv)
1588 {
1589 VALUE ary = memo[0];
1590 VALUE v = Qnil;
1591 long size = (long)memo[1];
1592 ENUM_WANT_SVALUE();
1593
1594 if (RARRAY_LEN(ary) == size) {
1595 rb_ary_shift(ary);
1596 }
1597 rb_ary_push(ary, i);
1598 if (RARRAY_LEN(ary) == size) {
1599 v = rb_yield(rb_ary_dup(ary));
1600 }
1601 return v;
1602 }
1603
1604 /*
1605 * call-seq:
1606 * each_cons(n) {...}
1607 * each_cons(n)
1608 *
1609 * Iterates the given block for each array of consecutive <n>
1610 * elements. If no block is given, returns an enumerator.
1611 *
1612 * e.g.:
1613 * (1..10).each_cons(3) {|a| p a}
1614 * # outputs below
1615 * [1, 2, 3]
1616 * [2, 3, 4]
1617 * [3, 4, 5]
1618 * [4, 5, 6]
1619 * [5, 6, 7]
1620 * [6, 7, 8]
1621 * [7, 8, 9]
1622 * [8, 9, 10]
1623 *
1624 */
1625 static VALUE
1626 enum_each_cons(VALUE obj, SEL sel, VALUE n)
1627 {
1628 long size = NUM2LONG(n);
1629 VALUE args[2];
1630
1631 if (size <= 0) {
1632 rb_raise(rb_eArgError, "invalid size");
1633 }
1634 RETURN_ENUMERATOR(obj, 1, &n);
1635 args[0] = rb_ary_new2(size);
1636 args[1] = (VALUE)size;
1637
70ea0b5 per-vm method cache + misc fixes/improvements
Laurent Sansonetti authored
1638 rb_objc_block_call(obj, selEach, 0, 0, each_cons_i, (VALUE)args);
40a433d Improve core/enumerable pass rate
Thibault Martin-Lagardette authored
1639
1640 return Qnil;
1641 }
1642
1643 static VALUE
1644 each_with_object_i(VALUE i, VALUE memo, int argc, VALUE *argv)
1645 {
1646 ENUM_WANT_SVALUE();
1647 return rb_yield_values(2, i, memo);
1648 }
1649
1650 /*
1651 * call-seq:
1652 * each_with_object(obj) {|(*args), memo_obj| ... }
1653 * each_with_object(obj)
1654 *
1655 * Iterates the given block for each element with an arbitrary
1656 * object given, and returns the initially given object.
1657 *
1658 * If no block is given, returns an enumerator.
1659 *
1660 * e.g.:
1661 * evens = (1..10).each_with_object([]) {|i, a| a << i*2 }
1662 * # => [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
1663 *
1664 */
1665 static VALUE
1666 enum_each_with_object(VALUE obj, SEL sel, VALUE memo)
1667 {
1668 RETURN_ENUMERATOR(obj, 1, &memo);
1669
70ea0b5 per-vm method cache + misc fixes/improvements
Laurent Sansonetti authored
1670 rb_objc_block_call(obj, selEach, 0, 0, each_with_object_i, (VALUE)memo);
40a433d Improve core/enumerable pass rate
Thibault Martin-Lagardette authored
1671
1672 return memo;
1673 }
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1674
1675 static VALUE
1676 zip_ary(VALUE val, NODE *memo, int argc, VALUE *argv)
1677 {
1678 volatile VALUE result = memo->u1.value;
1679 volatile VALUE args = memo->u2.value;
1680 int n = memo->u3.cnt++;
1681 volatile VALUE tmp;
1682 int i;
1683
1684 tmp = rb_ary_new2(RARRAY_LEN(args) + 1);
1685 rb_ary_store(tmp, 0, enum_values_pack(argc, argv));
1686 for (i=0; i<RARRAY_LEN(args); i++) {
1687 VALUE e = RARRAY_AT(args, i);
1688
1689 if (RARRAY_LEN(e) <= n) {
1690 rb_ary_push(tmp, Qnil);
1691 }
1692 else {
1693 rb_ary_push(tmp, RARRAY_AT(e, n));
1694 }
1695 }
1696 if (NIL_P(result)) {
1697 rb_yield(tmp);
1698 }
1699 else {
1700 rb_ary_push(result, tmp);
1701 }
1702 return Qnil;
1703 }
1704
1705 static VALUE
1706 call_next(VALUE *v)
1707 {
1708 return v[0] = rb_funcall(v[1], id_next, 0, 0);
1709 }
1710
1711 static VALUE
1712 call_stop(VALUE *v)
1713 {
1714 return v[0] = Qundef;
1715 }
1716
1717 static VALUE
1718 zip_i(VALUE val, NODE *memo, int argc, VALUE *argv)
1719 {
1720 volatile VALUE result = memo->u1.value;
1721 volatile VALUE args = memo->u2.value;
1722 volatile VALUE tmp;
1723 int i;
1724
1725 tmp = rb_ary_new2(RARRAY_LEN(args) + 1);
1726 rb_ary_store(tmp, 0, enum_values_pack(argc, argv));
1727 for (i=0; i<RARRAY_LEN(args); i++) {
1728 if (NIL_P(RARRAY_AT(args, i))) {
1729 rb_ary_push(tmp, Qnil);
1730 }
1731 else {
1732 VALUE v[2];
1733
1734 v[1] = RARRAY_AT(args, i);
1735 rb_rescue2(call_next, (VALUE)v, call_stop, (VALUE)v, rb_eStopIteration, 0);
1736 if (v[0] == Qundef) {
1737 rb_ary_store(args, i, Qnil);
1738 v[0] = Qnil;
1739 }
1740 rb_ary_push(tmp, v[0]);
1741 }
1742 }
1743 if (NIL_P(result)) {
1744 rb_yield(tmp);
1745 }
1746 else {
1747 rb_ary_push(result, tmp);
1748 }
1749 return Qnil;
1750 }
1751
1752 /*
1753 * call-seq:
1754 * enum.zip(arg, ...) => enumerator
1755 * enum.zip(arg, ...) {|arr| block } => nil
1756 *
1757 * Takes one element from <i>enum</i> and merges corresponding
1758 * elements from each <i>args</i>. This generates a sequence of
1759 * <em>n</em>-element arrays, where <em>n</em> is one more than the
1760 * count of arguments. The length of the resulting sequence will be
1761 * <code>enum#size</code. If the size of any argument is less than
1762 * <code>enum#size</code>, <code>nil</code> values are supplied. If
1763 * a block is given, it is invoked for each output array, otherwise
1764 * an array of arrays is returned.
1765 *
1766 * a = [ 4, 5, 6 ]
1767 * b = [ 7, 8, 9 ]
1768 *
1769 * [1,2,3].zip(a, b) #=> [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
1770 * [1,2].zip(a,b) #=> [[1, 4, 7], [2, 5, 8]]
1771 * a.zip([1,2],[8]) #=> [[4, 1, 8], [5, 2, nil], [6, nil, nil]]
1772 *
1773 */
1774
1775 static VALUE
1776 enum_zip(VALUE obj, SEL sel, int argc, VALUE *argv)
1777 {
1778 int i;
1779 ID conv;
1780 NODE *memo;
1781 VALUE result = Qnil;
40a433d Improve core/enumerable pass rate
Thibault Martin-Lagardette authored
1782 VALUE args = rb_ary_new4(argc, argv);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1783 int allary = Qtrue;
1784
40a433d Improve core/enumerable pass rate
Thibault Martin-Lagardette authored
1785 for (i = 0; i < argc; i++) {
1786 VALUE ary = rb_check_array_type(argv[i]);
1787 if (NIL_P(ary)) {
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1788 allary = Qfalse;
1789 break;
1790 }
40a433d Improve core/enumerable pass rate
Thibault Martin-Lagardette authored
1791 rary_store(args, i, ary);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1792 }
1793 if (!allary) {
1794 conv = rb_intern("to_enum");
40a433d Improve core/enumerable pass rate
Thibault Martin-Lagardette authored
1795 for (i = 0; i < argc; i++) {
1796 VALUE res = rb_funcall(argv[i], conv, 1, ID2SYM(id_each));
1797 rary_store(args, i, res);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1798 }
1799 }
1800 if (!rb_block_given_p()) {
1801 result = rb_ary_new();
1802 }
40a433d Improve core/enumerable pass rate
Thibault Martin-Lagardette authored
1803 memo = rb_node_newnode(NODE_MEMO, result, args, 0);
70ea0b5 per-vm method cache + misc fixes/improvements
Laurent Sansonetti authored
1804 rb_objc_block_call(obj, selEach, 0, 0, allary ? zip_ary : zip_i, (VALUE)memo);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1805
1806 return result;
1807 }
1808
1809 static VALUE
1810 take_i(VALUE i, VALUE *arg, int argc, VALUE *argv)
1811 {
1812 rb_ary_push(arg[0], enum_values_pack(argc, argv));
40a433d Improve core/enumerable pass rate
Thibault Martin-Lagardette authored
1813 if (--arg[1] == 0) {
1814 rb_iter_break();
1815 }
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1816 return Qnil;
1817 }
1818
1819 /*
1820 * call-seq:
1821 * enum.take(n) => array
1822 *
1823 * Returns first n elements from <i>enum</i>.
1824 *
1825 * a = [1, 2, 3, 4, 5, 0]
1826 * a.take(3) # => [1, 2, 3]
1827 *
1828 */
1829
1830 static VALUE
1831 enum_take(VALUE obj, SEL sel, VALUE n)
1832 {
1833 VALUE args[2];
1834 long len = NUM2LONG(n);
1835
1836 if (len < 0) {
1837 rb_raise(rb_eArgError, "attempt to take negative size");
1838 }
1839
40a433d Improve core/enumerable pass rate
Thibault Martin-Lagardette authored
1840 if (len == 0) {
1841 return rb_ary_new2(0);
1842 }
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1843 args[0] = rb_ary_new();
40a433d Improve core/enumerable pass rate
Thibault Martin-Lagardette authored
1844 args[1] = len;
70ea0b5 per-vm method cache + misc fixes/improvements
Laurent Sansonetti authored
1845 rb_objc_block_call(obj, selEach, 0, 0, take_i, (VALUE)args);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1846 return args[0];
1847 }
1848
1849
1850 static VALUE
1851 take_while_i(VALUE i, VALUE *ary, int argc, VALUE *argv)
1852 {
40a433d Improve core/enumerable pass rate
Thibault Martin-Lagardette authored
1853 if (!RTEST(enum_yield(argc, argv))) {
1854 rb_iter_break();
1855 }
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1856 rb_ary_push(*ary, enum_values_pack(argc, argv));
1857 return Qnil;
1858 }
1859
1860 /*
1861 * call-seq:
1862 * enum.take_while {|arr| block } => array
1863 *
1864 * Passes elements to the block until the block returns nil or false,
1865 * then stops iterating and returns an array of all prior elements.
1866 *
1867 * a = [1, 2, 3, 4, 5, 0]
1868 * a.take_while {|i| i < 3 } # => [1, 2]
1869 *
1870 */
1871
1872 static VALUE
1873 enum_take_while(VALUE obj, SEL sel)
1874 {
1875 VALUE ary;
1876
1877 RETURN_ENUMERATOR(obj, 0, 0);
1878 ary = rb_ary_new();
70ea0b5 per-vm method cache + misc fixes/improvements
Laurent Sansonetti authored
1879 rb_objc_block_call(obj, selEach, 0, 0, take_while_i, (VALUE)&ary);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1880 return ary;
1881 }
1882
1883 static VALUE
1884 drop_i(VALUE i, VALUE *arg, int argc, VALUE *argv)
1885 {
1886 if (arg[1] == 0) {
1887 rb_ary_push(arg[0], enum_values_pack(argc, argv));
1888 }
1889 else {
1890 arg[1]--;
1891 }
1892 return Qnil;
1893 }
1894
1895 /*
1896 * call-seq:
1897 * enum.drop(n) => array
1898 *
1899 * Drops first n elements from <i>enum</i>, and returns rest elements
1900 * in an array.
1901 *
1902 * a = [1, 2, 3, 4, 5, 0]
1903 * a.drop(3) # => [4, 5, 0]
1904 *
1905 */
1906
1907 static VALUE
1908 enum_drop(VALUE obj, SEL sel, VALUE n)
1909 {
1910 VALUE args[2];
1911 long len = NUM2LONG(n);
1912
1913 if (len < 0) {
1914 rb_raise(rb_eArgError, "attempt to drop negative size");
1915 }
1916
1917 args[1] = len;
1918 args[0] = rb_ary_new();
70ea0b5 per-vm method cache + misc fixes/improvements
Laurent Sansonetti authored
1919 rb_objc_block_call(obj, selEach, 0, 0, drop_i, (VALUE)args);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1920 return args[0];
1921 }
1922
1923
1924 static VALUE
1925 drop_while_i(VALUE i, VALUE *args, int argc, VALUE *argv)
1926 {
1927 ENUM_WANT_SVALUE();
1928
1929 if (!args[1] && !RTEST(rb_yield(i))) {
1930 args[1] = Qtrue;
1931 }
1932 if (args[1]) {
1933 rb_ary_push(args[0], i);
1934 }
1935 return Qnil;
1936 }
1937
1938 /*
1939 * call-seq:
1940 * enum.drop_while {|arr| block } => array
1941 *
1942 * Drops elements up to, but not including, the first element for
1943 * which the block returns nil or false and returns an array
1944 * containing the remaining elements.
1945 *
1946 * a = [1, 2, 3, 4, 5, 0]
1947 * a.drop_while {|i| i < 3 } # => [3, 4, 5, 0]
1948 *
1949 */
1950
1951 static VALUE
1952 enum_drop_while(VALUE obj, SEL sel)
1953 {
1954 VALUE args[2];
1955
1956 RETURN_ENUMERATOR(obj, 0, 0);
1957 args[0] = rb_ary_new();
1958 args[1] = Qfalse;
70ea0b5 per-vm method cache + misc fixes/improvements
Laurent Sansonetti authored
1959 rb_objc_block_call(obj, selEach, 0, 0, drop_while_i, (VALUE)args);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1960 return args[0];
1961 }
1962
1963 static VALUE
1964 cycle_i(VALUE i, VALUE ary, int argc, VALUE *argv)
1965 {
1966 ENUM_WANT_SVALUE();
1967
1968 rb_ary_push(ary, i);
1969 rb_yield(i);
1970 return Qnil;
1971 }
1972
1973 /*
1974 * call-seq:
1975 * enum.cycle {|obj| block }
1976 * enum.cycle(n) {|obj| block }
1977 *
1978 * Calls <i>block</i> for each element of <i>enum</i> repeatedly _n_
1979 * times or forever if none or nil is given. If a non-positive
1980 * number is given or the collection is empty, does nothing. Returns
1981 * nil if the loop has finished without getting interrupted.
1982 *
1983 * Enumerable#cycle saves elements in an internal array so changes
1984 * to <i>enum</i> after the first pass have no effect.
1985 *
1986 * a = ["a", "b", "c"]
1987 * a.cycle {|x| puts x } # print, a, b, c, a, b, c,.. forever.
1988 * a.cycle(2) {|x| puts x } # print, a, b, c, a, b, c.
1989 *
1990 */
1991
1992 static VALUE
1993 enum_cycle(VALUE obj, SEL sel, int argc, VALUE *argv)
1994 {
1995 VALUE ary;
1996 VALUE nv = Qnil;
1997 long n, i, len;
1998
1999 rb_scan_args(argc, argv, "01", &nv);
2000
2001 RETURN_ENUMERATOR(obj, argc, argv);
2002 if (NIL_P(nv)) {
2003 n = -1;
2004 }
2005 else {
2006 n = NUM2LONG(nv);
2007 if (n <= 0) return Qnil;
2008 }
2009 ary = rb_ary_new();
2010 #if !WITH_OBJC
2011 RBASIC(ary)->klass = 0;
2012 #endif
70ea0b5 per-vm method cache + misc fixes/improvements
Laurent Sansonetti authored
2013 rb_objc_block_call(obj, selEach, 0, 0, cycle_i, ary);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
2014 len = RARRAY_LEN(ary);
2015 if (len == 0) return Qnil;
2016 while (n < 0 || 0 < --n) {
2017 for (i=0; i<len; i++) {
2018 rb_yield(RARRAY_AT(ary, i));
2019 RETURN_IF_BROKEN();
2020 }
2021 }
2022 return Qnil; /* not reached */
2023 }
2024
2025 /*
2026 * The <code>Enumerable</code> mixin provides collection classes with
2027 * several traversal and searching methods, and with the ability to
2028 * sort. The class must provide a method <code>each</code>, which
2029 * yields successive members of the collection. If
2030 * <code>Enumerable#max</code>, <code>#min</code>, or
2031 * <code>#sort</code> is used, the objects in the collection must also
2032 * implement a meaningful <code><=></code> operator, as these methods
2033 * rely on an ordering between members of the collection.
2034 */
2035
2036 void
2037 Init_Enumerable(void)
2038 {
2039 rb_mEnumerable = rb_define_module("Enumerable");
2040
2041 rb_objc_define_method(rb_mEnumerable, "to_a", enum_to_a, -1);
2042 rb_objc_define_method(rb_mEnumerable, "entries", enum_to_a, -1);
2043
2044 rb_objc_define_method(rb_mEnumerable,"sort", enum_sort, 0);
2045 rb_objc_define_method(rb_mEnumerable,"sort_by", enum_sort_by, 0);
2046 rb_objc_define_method(rb_mEnumerable,"grep", enum_grep, 1);
2047 #if WITH_OBJC
2048 /* FIXME we cannot define count because it overlaps with
2049 * NSArray#count, NSDictionary#count, etc...
2050 */
2051 rb_objc_define_method(rb_mEnumerable,"_count", enum_count, -1);
2052 #else
2053 rb_objc_define_method(rb_mEnumerable,"count", enum_count, -1);
2054 #endif
2055 rb_objc_define_method(rb_mEnumerable, "find", enum_find, -1);
2056 rb_objc_define_method(rb_mEnumerable, "detect", enum_find, -1);
2057 rb_objc_define_method(rb_mEnumerable, "find_index", enum_find_index, -1);
2058 rb_objc_define_method(rb_mEnumerable, "find_all", enum_find_all, 0);
2059 rb_objc_define_method(rb_mEnumerable, "select", enum_find_all, 0);
2060 rb_objc_define_method(rb_mEnumerable, "reject", enum_reject, 0);
2061 rb_objc_define_method(rb_mEnumerable, "collect", enum_collect, 0);
2062 rb_objc_define_method(rb_mEnumerable, "map", enum_collect, 0);
40a433d Improve core/enumerable pass rate
Thibault Martin-Lagardette authored
2063 rb_objc_define_method(rb_mEnumerable, "flat_map", enum_flat_map, 0);
2064 rb_objc_define_method(rb_mEnumerable, "collect_concat", enum_flat_map, 0);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
2065 rb_objc_define_method(rb_mEnumerable, "inject", enum_inject, -1);
2066 rb_objc_define_method(rb_mEnumerable, "reduce", enum_inject, -1);
2067 rb_objc_define_method(rb_mEnumerable, "partition", enum_partition, 0);
2068 rb_objc_define_method(rb_mEnumerable, "group_by", enum_group_by, 0);
2069 rb_objc_define_method(rb_mEnumerable, "first", enum_first, -1);
2070 rb_objc_define_method(rb_mEnumerable, "all?", enum_all, 0);
2071 rb_objc_define_method(rb_mEnumerable, "any?", enum_any, 0);
2072 rb_objc_define_method(rb_mEnumerable, "one?", enum_one, 0);
2073 rb_objc_define_method(rb_mEnumerable, "none?", enum_none, 0);
2074 rb_objc_define_method(rb_mEnumerable, "min", enum_min, 0);
2075 rb_objc_define_method(rb_mEnumerable, "max", enum_max, 0);
2076 rb_objc_define_method(rb_mEnumerable, "minmax", enum_minmax, 0);
2077 rb_objc_define_method(rb_mEnumerable, "min_by", enum_min_by, 0);
2078 rb_objc_define_method(rb_mEnumerable, "max_by", enum_max_by, 0);
2079 rb_objc_define_method(rb_mEnumerable, "minmax_by", enum_minmax_by, 0);
2080 rb_objc_define_method(rb_mEnumerable, "member?", enum_member, 1);
2081 rb_objc_define_method(rb_mEnumerable, "include?", enum_member, 1);
2082 rb_objc_define_method(rb_mEnumerable, "each_with_index", enum_each_with_index, -1);
2083 rb_objc_define_method(rb_mEnumerable, "reverse_each", enum_reverse_each, -1);
40a433d Improve core/enumerable pass rate
Thibault Martin-Lagardette authored
2084 rb_objc_define_method(rb_mEnumerable, "each_entry", enum_each_entry, -1);
2085 rb_objc_define_method(rb_mEnumerable, "each_slice", enum_each_slice, 1);
2086 rb_objc_define_method(rb_mEnumerable, "each_cons", enum_each_cons, 1);
2087 rb_objc_define_method(rb_mEnumerable, "each_with_object", enum_each_with_object, 1);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
2088 rb_objc_define_method(rb_mEnumerable, "zip", enum_zip, -1);
2089 rb_objc_define_method(rb_mEnumerable, "take", enum_take, 1);
2090 rb_objc_define_method(rb_mEnumerable, "take_while", enum_take_while, 0);
2091 rb_objc_define_method(rb_mEnumerable, "drop", enum_drop, 1);
2092 rb_objc_define_method(rb_mEnumerable, "drop_while", enum_drop_while, 0);
2093 rb_objc_define_method(rb_mEnumerable, "cycle", enum_cycle, -1);
2094
2095 id_eqq = rb_intern("===");
2096 id_each = rb_intern("each");
2097 id_next = rb_intern("next");
2098 id_size = rb_intern("size");
2099 }
2100
Something went wrong with that request. Please try again.