enum.c
DEFINITIONS
This source file includes following functions.
- rb_each
- grep_i
- grep_iter_i
- enum_grep
- find_i
- enum_find
- find_all_i
- enum_find_all
- reject_i
- enum_reject
- collect_i
- collect_all
- enum_to_a
- enum_collect
- inject_i
- enum_inject
- partition_i
- enum_partition
- enum_sort
- sort_by_i
- sort_by_cmp
- enum_sort_by
- all_i
- enum_all
- any_i
- enum_any
- min_i
- min_ii
- enum_min
- max_i
- max_ii
- enum_max
- member_i
- enum_member
- each_with_index_i
- enum_each_with_index
- Init_Enumerable
1
2
3
4
5
6
7
8
9
10
11
12
13 #include "ruby.h"
14 #include "node.h"
15 #include "util.h"
16
17 VALUE rb_mEnumerable;
18 static ID id_each, id_eqq, id_cmp;
19
20 VALUE
21 rb_each(obj)
22 VALUE obj;
23 {
24 return rb_funcall(obj, id_each, 0, 0);
25 }
26
27 static VALUE
28 grep_i(i, arg)
29 VALUE i, *arg;
30 {
31 if (RTEST(rb_funcall(arg[0], id_eqq, 1, i))) {
32 rb_ary_push(arg[1], i);
33 }
34 return Qnil;
35 }
36
37 static VALUE
38 grep_iter_i(i, arg)
39 VALUE i, *arg;
40 {
41 if (RTEST(rb_funcall(arg[0], id_eqq, 1, i))) {
42 rb_ary_push(arg[1], rb_yield(i));
43 }
44 return Qnil;
45 }
46
47 static VALUE
48 enum_grep(obj, pat)
49 VALUE obj, pat;
50 {
51 VALUE ary = rb_ary_new();
52 VALUE arg[2];
53
54 arg[0] = pat;
55 arg[1] = ary;
56
57 rb_iterate(rb_each, obj, rb_block_given_p() ? grep_iter_i : grep_i, (VALUE)arg);
58
59 return ary;
60 }
61
62 static VALUE
63 find_i(i, memo)
64 VALUE i;
65 NODE *memo;
66 {
67 if (RTEST(rb_yield(i))) {
68 memo->u2.value = Qtrue;
69 memo->u1.value = i;
70 rb_iter_break();
71 }
72 return Qnil;
73 }
74
75 static VALUE
76 enum_find(argc, argv, obj)
77 int argc;
78 VALUE* argv;
79 VALUE obj;
80 {
81 NODE *memo = rb_node_newnode(NODE_MEMO, Qnil, Qfalse, 0);
82 VALUE if_none;
83
84 rb_scan_args(argc, argv, "01", &if_none);
85 rb_iterate(rb_each, obj, find_i, (VALUE)memo);
86 if (memo->u2.value) {
87 VALUE result = memo->u1.value;
88 rb_gc_force_recycle((VALUE)memo);
89 return result;
90 }
91 rb_gc_force_recycle((VALUE)memo);
92 if (!NIL_P(if_none)) {
93 return rb_funcall(if_none, rb_intern("call"), 0, 0);
94 }
95 return Qnil;
96 }
97
98 static VALUE
99 find_all_i(i, ary)
100 VALUE i, ary;
101 {
102 if (RTEST(rb_yield(i))) {
103 rb_ary_push(ary, i);
104 }
105 return Qnil;
106 }
107
108 static VALUE
109 enum_find_all(obj)
110 VALUE obj;
111 {
112 VALUE ary = rb_ary_new();
113
114 rb_iterate(rb_each, obj, find_all_i, ary);
115
116 return ary;
117 }
118
119 static VALUE
120 reject_i(i, ary)
121 VALUE i, ary;
122 {
123 if (!RTEST(rb_yield(i))) {
124 rb_ary_push(ary, i);
125 }
126 return Qnil;
127 }
128
129 static VALUE
130 enum_reject(obj)
131 VALUE obj;
132 {
133 VALUE ary = rb_ary_new();
134
135 rb_iterate(rb_each, obj, reject_i, ary);
136
137 return ary;
138 }
139
140 static VALUE
141 collect_i(i, ary)
142 VALUE i, ary;
143 {
144 rb_ary_push(ary, rb_yield(i));
145
146 return Qnil;
147 }
148
149 static VALUE
150 collect_all(i, ary)
151 VALUE i, ary;
152 {
153 rb_ary_push(ary, i);
154
155 return Qnil;
156 }
157
158 static VALUE
159 enum_to_a(obj)
160 VALUE obj;
161 {
162 VALUE ary = rb_ary_new();
163
164 rb_iterate(rb_each, obj, collect_all, ary);
165
166 return ary;
167 }
168
169 static VALUE
170 enum_collect(obj)
171 VALUE obj;
172 {
173 VALUE ary = rb_ary_new();
174
175 rb_iterate(rb_each, obj, rb_block_given_p() ? collect_i : collect_all, ary);
176
177 return ary;
178 }
179
180 static VALUE
181 inject_i(i, memo)
182 VALUE i;
183 NODE *memo;
184 {
185 if (memo->u2.value) {
186 memo->u2.value = Qfalse;
187 memo->u1.value = i;
188 }
189 else {
190 memo->u1.value = rb_yield(rb_assoc_new(memo->u1.value, i));
191 }
192 return Qnil;
193 }
194
195 static VALUE
196 enum_inject(argc, argv, obj)
197 int argc;
198 VALUE *argv, obj;
199 {
200 NODE *memo;
201 VALUE n;
202
203 if (rb_scan_args(argc, argv, "01", &n) == 1) {
204 memo = rb_node_newnode(NODE_MEMO, n, Qfalse, 0);
205 }
206 else {
207 memo = rb_node_newnode(NODE_MEMO, Qnil, Qtrue, 0);
208 }
209 rb_iterate(rb_each, obj, inject_i, (VALUE)memo);
210 n = memo->u1.value;
211 rb_gc_force_recycle((VALUE)memo);
212 return n;
213 }
214
215 static VALUE
216 partition_i(i, ary)
217 VALUE i, *ary;
218 {
219 if (RTEST(rb_yield(i))) {
220 rb_ary_push(ary[0], i);
221 }
222 else {
223 rb_ary_push(ary[1], i);
224 }
225 return Qnil;
226 }
227
228 static VALUE
229 enum_partition(obj)
230 VALUE obj;
231 {
232 VALUE ary[2];
233
234 ary[0] = rb_ary_new();
235 ary[1] = rb_ary_new();
236 rb_iterate(rb_each, obj, partition_i, (VALUE)ary);
237
238 return rb_assoc_new(ary[0], ary[1]);
239 }
240
241 static VALUE
242 enum_sort(obj)
243 VALUE obj;
244 {
245 return rb_ary_sort(enum_to_a(obj));
246 }
247
248 static VALUE
249 sort_by_i(i, ary)
250 VALUE i, ary;
251 {
252 VALUE v, e;
253
254 v = rb_yield(i);
255 e = rb_assoc_new(v, i);
256 rb_ary_push(ary, e);
257 return Qnil;
258 }
259
260 static int
261 sort_by_cmp(a, b)
262 VALUE *a, *b;
263 {
264 VALUE retval;
265
266 retval = rb_funcall(RARRAY(*a)->ptr[0], id_cmp, 1, RARRAY(*b)->ptr[0]);
267 return rb_cmpint(retval);
268 }
269
270 static VALUE
271 enum_sort_by(obj)
272 VALUE obj;
273 {
274 VALUE ary;
275 long i;
276
277 ary = rb_ary_new2((TYPE(obj) == T_ARRAY) ? RARRAY(obj)->len : 2000);
278 rb_iterate(rb_each, obj, sort_by_i, ary);
279 if (RARRAY(ary)->len > 1) {
280 qsort(RARRAY(ary)->ptr, RARRAY(ary)->len, sizeof(VALUE), sort_by_cmp);
281 }
282 for (i=0; i<RARRAY(ary)->len; i++) {
283 VALUE e = RARRAY(ary)->ptr[i];
284 RARRAY(ary)->ptr[i] = RARRAY(e)->ptr[1];
285 }
286 return ary;
287 }
288
289 static VALUE
290 all_i(i, memo)
291 VALUE i;
292 NODE *memo;
293 {
294 if (!RTEST(rb_yield(i))) {
295 memo->u1.value = Qfalse;
296 rb_iter_break();
297 }
298 return Qnil;
299 }
300
301 static VALUE
302 enum_all(obj)
303 VALUE obj;
304 {
305 VALUE result;
306 NODE *memo = rb_node_newnode(NODE_MEMO, Qnil, 0, 0);
307
308 memo->u1.value = Qtrue;
309 rb_iterate(rb_each, obj, all_i, (VALUE)memo);
310 result = memo->u1.value;
311 rb_gc_force_recycle((VALUE)memo);
312 return result;
313 }
314
315 static VALUE
316 any_i(i, memo)
317 VALUE i;
318 NODE *memo;
319 {
320 if (RTEST(rb_yield(i))) {
321 memo->u1.value = Qtrue;
322 rb_iter_break();
323 }
324 return Qnil;
325 }
326
327 static VALUE
328 enum_any(obj)
329 VALUE obj;
330 {
331 VALUE result;
332 NODE *memo = rb_node_newnode(NODE_MEMO, Qnil, 0, 0);
333
334 memo->u1.value = Qfalse;
335 rb_iterate(rb_each, obj, any_i, (VALUE)memo);
336 result = memo->u1.value;
337 rb_gc_force_recycle((VALUE)memo);
338 return result;
339 }
340
341 static VALUE
342 min_i(i, memo)
343 VALUE i;
344 NODE *memo;
345 {
346 VALUE cmp;
347
348 if (NIL_P(memo->u1.value)) {
349 memo->u1.value = i;
350 }
351 else {
352 cmp = rb_funcall(i, id_cmp, 1, memo->u1.value);
353 if (rb_cmpint(cmp) < 0) {
354 memo->u1.value = i;
355 }
356 }
357 return Qnil;
358 }
359
360 static VALUE
361 min_ii(i, memo)
362 VALUE i;
363 NODE *memo;
364 {
365 VALUE cmp;
366
367 if (NIL_P(memo->u1.value)) {
368 memo->u1.value = i;
369 }
370 else {
371 cmp = rb_yield(rb_assoc_new(i, memo->u1.value));
372 if (rb_cmpint(cmp) < 0) {
373 memo->u1.value = i;
374 }
375 }
376 return Qnil;
377 }
378
379 static VALUE
380 enum_min(obj)
381 VALUE obj;
382 {
383 VALUE result;
384 NODE *memo = rb_node_newnode(NODE_MEMO, Qnil, 0, 0);
385
386 rb_iterate(rb_each, obj, rb_block_given_p() ? min_ii : min_i, (VALUE)memo);
387 result = memo->u1.value;
388 rb_gc_force_recycle((VALUE)memo);
389 return result;
390 }
391
392 static VALUE
393 max_i(i, memo)
394 VALUE i;
395 NODE *memo;
396 {
397 VALUE cmp;
398
399 if (NIL_P(memo->u1.value)) {
400 memo->u1.value = i;
401 }
402 else {
403 cmp = rb_funcall(i, id_cmp, 1, memo->u1.value);
404 if (rb_cmpint(cmp) > 0) {
405 memo->u1.value = i;
406 }
407 }
408 return Qnil;
409 }
410
411 static VALUE
412 max_ii(i, memo)
413 VALUE i;
414 NODE *memo;
415 {
416 VALUE cmp;
417
418 if (NIL_P(memo->u1.value)) {
419 memo->u1.value = i;
420 }
421 else {
422 cmp = rb_yield(rb_assoc_new(i, memo->u1.value));
423 if (rb_cmpint(cmp) > 0) {
424 memo->u1.value = i;
425 }
426 }
427 return Qnil;
428 }
429
430 static VALUE
431 enum_max(obj)
432 VALUE obj;
433 {
434 VALUE result;
435 NODE *memo = rb_node_newnode(NODE_MEMO, Qnil, 0, 0);
436
437 rb_iterate(rb_each, obj, rb_block_given_p() ? max_ii : max_i, (VALUE)memo);
438 result = memo->u1.value;
439 rb_gc_force_recycle((VALUE)memo);
440 return result;
441 }
442
443 static VALUE
444 member_i(item, memo)
445 VALUE item;
446 NODE *memo;
447 {
448 if (rb_equal(item, memo->u1.value)) {
449 memo->u2.value = Qtrue;
450 rb_iter_break();
451 }
452 return Qnil;
453 }
454
455 static VALUE
456 enum_member(obj, val)
457 VALUE obj, val;
458 {
459 VALUE result;
460 NODE *memo = rb_node_newnode(NODE_MEMO, val, Qfalse, 0);
461
462 rb_iterate(rb_each, obj, member_i, (VALUE)memo);
463 result = memo->u2.value;
464 rb_gc_force_recycle((VALUE)memo);
465 return result;
466 }
467
468 static VALUE
469 each_with_index_i(val, memo)
470 VALUE val;
471 NODE *memo;
472 {
473 rb_yield(rb_assoc_new(val, INT2FIX(memo->u3.cnt)));
474 memo->u3.cnt++;
475 return Qnil;
476 }
477
478 static VALUE
479 enum_each_with_index(obj)
480 VALUE obj;
481 {
482 NODE *memo = rb_node_newnode(NODE_MEMO, 0, 0, 0);
483
484 rb_iterate(rb_each, obj, each_with_index_i, (VALUE)memo);
485 rb_gc_force_recycle((VALUE)memo);
486 return obj;
487 }
488
489 void
490 Init_Enumerable()
491 {
492 rb_mEnumerable = rb_define_module("Enumerable");
493
494 rb_define_method(rb_mEnumerable,"to_a", enum_to_a, 0);
495 rb_define_method(rb_mEnumerable,"entries", enum_to_a, 0);
496
497 rb_define_method(rb_mEnumerable,"sort", enum_sort, 0);
498 rb_define_method(rb_mEnumerable,"sort_by", enum_sort_by, 0);
499 rb_define_method(rb_mEnumerable,"grep", enum_grep, 1);
500 rb_define_method(rb_mEnumerable,"find", enum_find, -1);
501 rb_define_method(rb_mEnumerable,"detect", enum_find, -1);
502 rb_define_method(rb_mEnumerable,"find_all", enum_find_all, 0);
503 rb_define_method(rb_mEnumerable,"select", enum_find_all, 0);
504 rb_define_method(rb_mEnumerable,"reject", enum_reject, 0);
505 rb_define_method(rb_mEnumerable,"collect", enum_collect, 0);
506 rb_define_method(rb_mEnumerable,"map", enum_collect, 0);
507 rb_define_method(rb_mEnumerable,"inject", enum_inject, -1);
508 rb_define_method(rb_mEnumerable,"partition", enum_partition, 0);
509 rb_define_method(rb_mEnumerable,"all?", enum_all, 0);
510 rb_define_method(rb_mEnumerable,"any?", enum_any, 0);
511 rb_define_method(rb_mEnumerable,"min", enum_min, 0);
512 rb_define_method(rb_mEnumerable,"max", enum_max, 0);
513 rb_define_method(rb_mEnumerable,"member?", enum_member, 1);
514 rb_define_method(rb_mEnumerable,"include?", enum_member, 1);
515 rb_define_method(rb_mEnumerable,"each_with_index", enum_each_with_index, 0);
516
517 id_eqq = rb_intern("===");
518 id_each = rb_intern("each");
519 id_cmp = rb_intern("<=>");
520 }
521