1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13: #include "ruby/ruby.h"
14: #include "ruby/node.h"
15: #include "ruby/util.h"
16:
17: VALUE rb_mEnumerable;
18: static ID id_each, id_eqq, id_cmp, id_next;
19:
20: static VALUE
21: enum_values_pack(int argc, VALUE *argv)
22: {
23: if (argc == 0) return Qnil;
24: if (argc == 1) return argv[0];
25: return rb_ary_new4(argc, argv);
26: }
27:
28: static VALUE
29: enum_yield(int argc, VALUE *argv)
30: {
31: return rb_yield(enum_values_pack(argc, argv));
32: }
33:
34: static VALUE
35: grep_i(VALUE i, VALUE *arg, int argc, VALUE *argv)
36: {
37: if (RTEST(rb_funcall(arg[0], id_eqq, 1, i))) {
38: rb_ary_push(arg[1], enum_values_pack(argc, argv));
39: }
40: return Qnil;
41: }
42:
43: static VALUE
44: grep_iter_i(VALUE i, VALUE *arg, int argc, VALUE *argv)
45: {
46: if (RTEST(rb_funcall(arg[0], id_eqq, 1, i))) {
47: rb_ary_push(arg[1], enum_yield(argc, argv));
48: }
49: return Qnil;
50: }
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70: static VALUE
71: enum_grep(VALUE obj, VALUE pat)
72: {
73: VALUE ary = rb_ary_new();
74: VALUE arg[2];
75:
76: arg[0] = pat;
77: arg[1] = ary;
78:
79: rb_block_call(obj, id_each, 0, 0, rb_block_given_p() ? grep_iter_i : grep_i, (VALUE)arg);
80:
81: return ary;
82: }
83:
84: static VALUE
85: count_i(VALUE i, VALUE *arg)
86: {
87: if (rb_equal(i, arg[0])) {
88: arg[1]++;
89: }
90: return Qnil;
91: }
92:
93: static VALUE
94: count_iter_i(VALUE i, long *n, int argc, VALUE *argv)
95: {
96: if (RTEST(enum_yield(argc, argv))) {
97: (*n)++;
98: }
99: return Qnil;
100: }
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116: static VALUE
117: enum_count(int argc, VALUE *argv, VALUE obj)
118: {
119: if (argc == 1) {
120: VALUE item, args[2];
121:
122: if (rb_block_given_p()) {
123: rb_warn("given block not used");
124: }
125: rb_scan_args(argc, argv, "1", &item);
126: args[0] = item;
127: args[1] = 0;
128: rb_block_call(obj, id_each, 0, 0, count_i, (VALUE)&args);
129: return INT2NUM(args[1]);
130: }
131: else if (argc == 0) {
132: long n;
133:
134: RETURN_ENUMERATOR(obj, 0, 0);
135: n = 0;
136: rb_block_call(obj, id_each, 0, 0, count_iter_i, (VALUE)&n);
137: return INT2NUM(n);
138: }
139: else {
140: VALUE v;
141: rb_scan_args(argc, argv, "1", &v);
142: return Qnil;
143: }
144: }
145:
146: static VALUE
147: find_i(VALUE i, VALUE *memo, int argc, VALUE *argv)
148: {
149: if (RTEST(enum_yield(argc, argv))) {
150: *memo = i;
151: rb_iter_break();
152: }
153: return Qnil;
154: }
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171: static VALUE
172: enum_find(int argc, VALUE *argv, VALUE obj)
173: {
174: VALUE memo = Qundef;
175: VALUE if_none;
176:
177: rb_scan_args(argc, argv, "01", &if_none);
178: RETURN_ENUMERATOR(obj, argc, argv);
179: rb_block_call(obj, id_each, 0, 0, find_i, (VALUE)&memo);
180: if (memo != Qundef) {
181: return memo;
182: }
183: if (!NIL_P(if_none)) {
184: return rb_funcall(if_none, rb_intern("call"), 0, 0);
185: }
186: return Qnil;
187: }
188:
189: static VALUE
190: find_index_i(VALUE i, VALUE *memo, int argc, VALUE *argv)
191: {
192: if (RTEST(enum_yield(argc, argv))) {
193: memo[0] = UINT2NUM(memo[1]);
194: rb_iter_break();
195: }
196: memo[1]++;
197: return Qnil;
198: }
199:
200:
201:
202:
203:
204:
205:
206:
207:
208:
209:
210:
211:
212:
213: static VALUE
214: enum_find_index(VALUE obj)
215: {
216: VALUE memo[2];
217:
218: RETURN_ENUMERATOR(obj, 0, 0);
219: memo[0] = Qundef;
220: memo[1] = 0;
221: rb_block_call(obj, id_each, 0, 0, find_index_i, (VALUE)memo);
222: if (memo[0] != Qundef) {
223: return memo[0];
224: }
225: return Qnil;
226: }
227:
228: static VALUE
229: find_all_i(VALUE i, VALUE ary, int argc, VALUE *argv)
230: {
231: if (RTEST(enum_yield(argc, argv))) {
232: rb_ary_push(ary, i);
233: }
234: return Qnil;
235: }
236:
237:
238:
239:
240:
241:
242:
243:
244:
245:
246:
247:
248:
249:
250: static VALUE
251: enum_find_all(VALUE obj)
252: {
253: VALUE ary;
254:
255: RETURN_ENUMERATOR(obj, 0, 0);
256:
257: ary = rb_ary_new();
258: rb_block_call(obj, id_each, 0, 0, find_all_i, ary);
259:
260: return ary;
261: }
262:
263: static VALUE
264: reject_i(VALUE i, VALUE ary, int argc, VALUE *argv)
265: {
266: if (!RTEST(enum_yield(argc, argv))) {
267: rb_ary_push(ary, i);
268: }
269: return Qnil;
270: }
271:
272:
273:
274:
275:
276:
277:
278:
279:
280:
281:
282:
283: static VALUE
284: enum_reject(VALUE obj)
285: {
286: VALUE ary;
287:
288: RETURN_ENUMERATOR(obj, 0, 0);
289:
290: ary = rb_ary_new();
291: rb_block_call(obj, id_each, 0, 0, reject_i, ary);
292:
293: return ary;
294: }
295:
296: static VALUE
297: collect_i(VALUE i, VALUE ary, int argc, VALUE *argv)
298: {
299: rb_ary_push(ary, enum_yield(argc, argv));
300:
301: return Qnil;
302: }
303:
304: static VALUE
305: collect_all(VALUE i, VALUE ary, int argc, VALUE *argv)
306: {
307: rb_ary_push(ary, enum_values_pack(argc, argv));
308:
309: return Qnil;
310: }
311:
312:
313:
314:
315:
316:
317:
318:
319:
320:
321:
322:
323:
324:
325: static VALUE
326: enum_collect(VALUE obj)
327: {
328: VALUE ary;
329:
330: RETURN_ENUMERATOR(obj, 0, 0);
331:
332: ary = rb_ary_new();
333: rb_block_call(obj, id_each, 0, 0, collect_i, ary);
334:
335: return ary;
336: }
337:
338:
339:
340:
341:
342:
343:
344:
345:
346:
347:
348: static VALUE
349: enum_to_a(VALUE obj)
350: {
351: VALUE ary = rb_ary_new();
352:
353: rb_block_call(obj, id_each, 0, 0, collect_all, ary);
354:
355: return ary;
356: }
357:
358: static VALUE
359: inject_i(VALUE i, VALUE p, int argc, VALUE *argv)
360: {
361: VALUE *memo = (VALUE *)p;
362: if (memo[0] == Qundef) {
363: memo[0] = i;
364: }
365: else {
366: memo[0] = rb_yield_values(2, memo[0], enum_values_pack(argc, argv));
367: }
368: return Qnil;
369: }
370:
371: static VALUE
372: inject_op_i(VALUE i, VALUE p, int argc, VALUE *argv)
373: {
374: VALUE *memo = (VALUE *)p;
375:
376: if (memo[0] == Qundef) {
377: memo[0] = enum_values_pack(argc, argv);
378: }
379: else {
380: memo[0] = rb_funcall(memo[0], (ID)memo[1], 1, i);
381: }
382: return Qnil;
383: }
384:
385:
386:
387:
388:
389:
390:
391:
392:
393:
394:
395:
396:
397:
398:
399:
400:
401:
402:
403:
404:
405:
406:
407:
408:
409:
410:
411:
412:
413:
414:
415:
416:
417:
418:
419:
420:
421:
422:
423:
424:
425:
426:
427:
428:
429:
430: static VALUE
431: enum_inject(int argc, VALUE *argv, VALUE obj)
432: {
433: VALUE memo[2];
434: VALUE (*iter)(VALUE, VALUE, int, VALUE*) = inject_i;
435:
436: switch (rb_scan_args(argc, argv, "02", &memo[0], &memo[1])) {
437: case 0:
438: memo[0] = Qundef;
439: break;
440: case 1:
441: if (rb_block_given_p()) {
442: break;
443: }
444: memo[1] = (VALUE)rb_to_id(memo[0]);
445: memo[0] = Qundef;
446: iter = inject_op_i;
447: break;
448: case 2:
449: if (rb_block_given_p()) {
450: rb_warning("given block not used");
451: }
452: memo[1] = (VALUE)rb_to_id(memo[1]);
453: iter = inject_op_i;
454: break;
455: }
456: rb_block_call(obj, id_each, 0, 0, iter, (VALUE)memo);
457: if (memo[0] == Qundef) return Qnil;
458: return memo[0];
459: }
460:
461: static VALUE
462: partition_i(VALUE i, VALUE *ary, int argc, VALUE *argv)
463: {
464: if (RTEST(enum_yield(argc, argv))) {
465: rb_ary_push(ary[0], i);
466: }
467: else {
468: rb_ary_push(ary[1], i);
469: }
470: return Qnil;
471: }
472:
473:
474:
475:
476:
477:
478:
479:
480:
481:
482:
483:
484:
485: static VALUE
486: enum_partition(VALUE obj)
487: {
488: VALUE ary[2];
489:
490: RETURN_ENUMERATOR(obj, 0, 0);
491:
492: ary[0] = rb_ary_new();
493: ary[1] = rb_ary_new();
494: rb_block_call(obj, id_each, 0, 0, partition_i, (VALUE)ary);
495:
496: return rb_assoc_new(ary[0], ary[1]);
497: }
498:
499: static VALUE
500: group_by_i(VALUE i, VALUE hash, int argc, VALUE *argv)
501: {
502: VALUE group = enum_yield(argc, argv);
503: VALUE values;
504:
505: values = rb_hash_aref(hash, group);
506: if (NIL_P(values)) {
507: values = rb_ary_new3(1, i);
508: rb_hash_aset(hash, group, values);
509: }
510: else {
511: rb_ary_push(values, i);
512: }
513: return Qnil;
514: }
515:
516:
517:
518:
519:
520:
521:
522:
523:
524:
525:
526:
527:
528: static VALUE
529: enum_group_by(VALUE obj)
530: {
531: VALUE hash;
532:
533: RETURN_ENUMERATOR(obj, 0, 0);
534:
535: hash = rb_hash_new();
536: rb_block_call(obj, id_each, 0, 0, group_by_i, hash);
537:
538: return hash;
539: }
540:
541: static VALUE
542: first_i(VALUE i, VALUE *ary)
543: {
544: if (NIL_P(ary[0])) {
545: ary[1] = i;
546: rb_iter_break();
547: }
548: else {
549: long n = NUM2LONG(ary[0]);
550:
551: if (n <= 0) {
552: rb_iter_break();
553: }
554: rb_ary_push(ary[1], i);
555: n--;
556: ary[0] = INT2NUM(n);
557: }
558: return Qnil;
559: }
560:
561:
562:
563:
564:
565:
566:
567:
568:
569:
570:
571:
572: static VALUE
573: enum_first(int argc, VALUE *argv, VALUE obj)
574: {
575: VALUE n, ary[2];
576:
577: rb_scan_args(argc, argv, "01", &n);
578:
579: if (argc == 0) {
580: ary[0] = ary[1] = Qnil;
581: }
582: else {
583: ary[0] = n;
584: ary[1] = rb_ary_new2(NUM2LONG(n));
585: }
586: rb_block_call(obj, id_each, 0, 0, first_i, (VALUE)ary);
587:
588: return ary[1];
589: }
590:
591:
592:
593:
594:
595:
596:
597:
598:
599:
600:
601:
602:
603:
604:
605:
606:
607:
608:
609: static VALUE
610: enum_sort(VALUE obj)
611: {
612: return rb_ary_sort(enum_to_a(obj));
613: }
614:
615: static VALUE
616: sort_by_i(VALUE i, VALUE ary, int argc, VALUE *argv)
617: {
618: VALUE v;
619: NODE *memo;
620:
621: v = enum_yield(argc, argv);
622: if (RBASIC(ary)->klass) {
623: rb_raise(rb_eRuntimeError, "sort_by reentered");
624: }
625: memo = rb_node_newnode(NODE_MEMO, v, i, 0);
626: rb_ary_push(ary, (VALUE)memo);
627: return Qnil;
628: }
629:
630: static int
631: sort_by_cmp(const void *ap, const void *bp, void *data)
632: {
633: VALUE a = (*(NODE *const *)ap)->u1.value;
634: VALUE b = (*(NODE *const *)bp)->u1.value;
635: VALUE ary = (VALUE)data;
636:
637: if (RBASIC(ary)->klass) {
638: rb_raise(rb_eRuntimeError, "sort_by reentered");
639: }
640: return rb_cmpint(rb_funcall(a, id_cmp, 1, b), a, b);
641: }
642:
643:
644:
645:
646:
647:
648:
649:
650:
651:
652: