Skip to content
This repository
Newer
Older
100644 826 lines (699 sloc) 18.797 kb
95957256 » Laurent Sansonetti
2011-01-15 update copyrights to 2011
1 /*
2 * This file is covered by the Ruby license. See COPYING for more details.
7d7d3e80 » ferrous26
2012-04-22 Change ownership to The MacRuby Team and update copyrights
3 *
4 * Copyright (C) 2012, The MacRuby Team. All rights reserved.
95957256 » Laurent Sansonetti
2011-01-15 update copyrights to 2011
5 * Copyright (C) 2007-2011, Apple Inc. All rights reserved.
6 * Copyright (C) 2001-2003 Akinori MUSHA
7 */
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
8
d0898dd2 » Laurent Sansonetti
2011-01-08 include/ruby/macruby.h -> macruby_internal.h
9 #include "macruby_internal.h"
301b43b1 » Laurent Sansonetti
2009-04-05 ported to rb_objc_block_call() + misc cleanup
10 #include "id.h"
81232c27 » Laurent Sansonetti
2011-01-28 refactor duplicated code
11 #include "ruby/node.h"
12 #include "vm.h"
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
13
14 /*
76080c7c » Watson1978
2011-12-28 update rdoc
15 * Document-class: Enumerator
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
16 *
17 * A class which provides a method `each' to be used as an Enumerable
18 * object.
76080c7c » Watson1978
2011-12-28 update rdoc
19 *
20 * An enumerator can be created by following methods.
21 * - Kernel#to_enum
22 * - Kernel#enum_for
23 * - Enumerator.new
24 *
25 * Also, most iteration methods without a block returns an enumerator.
26 * For example, Array#map returns an enumerator if a block is not given.
27 * The enumerator has the with_index method.
28 * So ary.map.with_index works as follows.
29 *
30 * p %w[foo bar baz].map.with_index {|w,i| "#{i}:#{w}" }
31 * #=> ["0:foo", "1:bar", "2:baz"]
32 *
33 * An enumerator object can be used as an external iterator.
34 * I.e. Enumerator#next returns the next value of the iterator.
35 * Enumerator#next raises StopIteration at end.
36 *
37 * e = [1,2,3].each # returns an enumerator object.
38 * p e.next #=> 1
39 * p e.next #=> 2
40 * p e.next #=> 3
41 * p e.next #raises StopIteration
42 *
43 * An external iterator can be used to implement an internal iterator as follows.
44 *
45 * def ext_each(e)
46 * while true
47 * begin
48 * vs = e.next_values
49 * rescue StopIteration
50 * return $!.result
51 * end
52 * y = yield(*vs)
53 * e.feed y
54 * end
55 * end
56 *
57 * o = Object.new
58 * def o.each
59 * p yield
60 * p yield(1)
61 * p yield(1, 2)
62 * 3
63 * end
64 *
65 * # use o.each as an internal iterator directly.
66 * p o.each {|*x| p x; [:b, *x] }
67 * #=> [], [:b], [1], [:b, 1], [1, 2], [:b, 1, 2], 3
68 *
69 * # convert o.each to an external iterator for
70 * # implementing an internal iterator.
71 * p ext_each(o.to_enum) {|*x| p x; [:b, *x] }
72 * #=> [], [:b], [1], [:b, 1], [1, 2], [:b, 1, 2], 3
73 *
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
74 */
75 VALUE rb_cEnumerator;
76 static VALUE sym_each;
77
78 VALUE rb_eStopIteration;
79
80 struct enumerator {
81 VALUE obj;
a6a914f3 » Laurent Sansonetti
2009-04-05 implemented implicit enumeratorization
82 SEL sel;
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
83 VALUE args;
84 VALUE fib;
85 VALUE dst;
86 VALUE no_next;
87 };
88
dd801db3 » Watson1978
2011-12-28 implement Enumerator::{Generator, Yielder}
89 static VALUE rb_cGenerator, rb_cYielder;
90
91 struct generator {
92 VALUE proc;
93 };
94
95 struct yielder {
96 VALUE proc;
97 };
98
99 static VALUE generator_allocate(VALUE klass, SEL sel);
100 static VALUE generator_init(VALUE obj, VALUE proc);
101
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
102 static struct enumerator *
103 enumerator_ptr(VALUE obj)
104 {
105 struct enumerator *ptr;
106
107 Data_Get_Struct(obj, struct enumerator, ptr);
108 #if 0
109 if (RDATA(obj)->dmark != enumerator_mark) {
110 rb_raise(rb_eTypeError,
111 "wrong argument type %s (expected %s)",
112 rb_obj_classname(obj), rb_class2name(rb_cEnumerator));
113 }
114 #endif
de680866 » Watson1978
2011-12-28 Properly detect if the object is initialized and raise error when app…
115 if (!ptr || ptr->obj == Qundef) {
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
116 rb_raise(rb_eArgError, "uninitialized enumerator");
117 }
118 return ptr;
119 }
120
121 /*
122 * call-seq:
123 * obj.to_enum(method = :each, *args)
124 * obj.enum_for(method = :each, *args)
125 *
76080c7c » Watson1978
2011-12-28 update rdoc
126 * Returns Enumerator.new(self, method, *args).
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
127 *
128 * e.g.:
129 *
130 * str = "xyz"
131 *
132 * enum = str.enum_for(:each_byte)
133 * a = enum.map {|b| '%02x' % b } #=> ["78", "79", "7a"]
134 *
135 * # protects an array from being modified
136 * a = [1, 2, 3]
137 * some_method(a.to_enum)
138 *
139 */
140 static VALUE
141 obj_to_enum(VALUE obj, SEL sel, int argc, VALUE *argv)
142 {
143 VALUE meth = sym_each;
144
145 if (argc > 0) {
146 --argc;
147 meth = *argv++;
148 }
c6a03419 » Laurent Sansonetti
2009-08-14 Kernel#to_enum: implemented
149
e1960f63 » Thibault Martin-Lagardette
2010-03-16 Make sure #to_enum verify param is a symbol
150 ID meth_id = rb_to_id(meth);
81232c27 » Laurent Sansonetti
2011-01-28 refactor duplicated code
151 SEL enum_sel = rb_vm_id_to_sel(meth_id, argc);
c6a03419 » Laurent Sansonetti
2009-08-14 Kernel#to_enum: implemented
152 return rb_enumeratorize(obj, enum_sel, argc, argv);
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
153 }
154
155 static VALUE
5b94e0e8 » Watson1978
2011-03-29 enumerator_allocate() needs sel argument because "alloc" method is de…
156 enumerator_allocate(VALUE klass, SEL sel)
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
157 {
158 struct enumerator *ptr;
de680866 » Watson1978
2011-12-28 Properly detect if the object is initialized and raise error when app…
159 VALUE enum_obj;
160
161 enum_obj = Data_Make_Struct(klass, struct enumerator,
162 NULL, NULL, ptr);
163 ptr->obj = Qundef;
164
165 return enum_obj;
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
166 }
167
168 static VALUE
169 enumerator_each_i(VALUE v, VALUE enum_obj, int argc, VALUE *argv)
170 {
171 return rb_yield_values2(argc, argv);
172 }
173
174 static VALUE
a6a914f3 » Laurent Sansonetti
2009-04-05 implemented implicit enumeratorization
175 enumerator_init(VALUE enum_obj, VALUE obj, SEL sel, int argc, VALUE *argv)
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
176 {
de680866 » Watson1978
2011-12-28 Properly detect if the object is initialized and raise error when app…
177 struct enumerator *ptr;
178
179 Data_Get_Struct(enum_obj, struct enumerator, ptr);
180
181 if (!ptr) {
182 rb_raise(rb_eArgError, "unallocated enumerator");
183 }
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
184
a6a914f3 » Laurent Sansonetti
2009-04-05 implemented implicit enumeratorization
185 GC_WB(&ptr->obj, obj);
186 ptr->sel = sel;
187 if (argc > 0) {
188 GC_WB(&ptr->args, rb_ary_new4(argc, argv));
189 }
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
190 ptr->fib = 0;
191 ptr->dst = Qnil;
192 ptr->no_next = Qfalse;
193
194 return enum_obj;
195 }
196
197 /*
198 * call-seq:
76080c7c » Watson1978
2011-12-28 update rdoc
199 * Enumerator.new(obj, method = :each, *args)
200 * Enumerator.new { |y| ... }
201 *
202 * Creates a new Enumerator object, which is to be used as an
203 * Enumerable object iterating in a given way.
204 *
205 * In the first form, a generated Enumerator iterates over the given
206 * object using the given method with the given arguments passed.
207 * Use of this form is discouraged. Use Kernel#enum_for(), alias
208 * to_enum, instead.
209 *
210 * e = Enumerator.new(ObjectSpace, :each_object)
211 * #-> ObjectSpace.enum_for(:each_object)
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
212 *
76080c7c » Watson1978
2011-12-28 update rdoc
213 * e.select { |obj| obj.is_a?(Class) } #=> array of all classes
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
214 *
76080c7c » Watson1978
2011-12-28 update rdoc
215 * In the second form, iteration is defined by the given block, in
216 * which a "yielder" object given as block parameter can be used to
217 * yield a value by calling the +yield+ method, alias +<<+.
218 *
219 * fib = Enumerator.new { |y|
220 * a = b = 1
221 * loop {
222 * y << a
223 * a, b = b, a + b
224 * }
225 * }
226 *
227 * p fib.take(10) #=> [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
228 */
229 static VALUE
230 enumerator_initialize(VALUE obj, SEL sel, int argc, VALUE *argv)
231 {
232 VALUE recv, meth = sym_each;
233
dd801db3 » Watson1978
2011-12-28 implement Enumerator::{Generator, Yielder}
234 if (argc == 0) {
235 if (!rb_block_given_p())
236 rb_raise(rb_eArgError, "wrong number of argument (0 for 1+)");
237
238 recv = generator_init(generator_allocate(rb_cGenerator, 0), rb_block_proc());
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
239 }
dd801db3 » Watson1978
2011-12-28 implement Enumerator::{Generator, Yielder}
240 else {
241 recv = *argv++;
242 if (--argc) {
243 meth = *argv++;
244 --argc;
245 }
246 }
247
a6a914f3 » Laurent Sansonetti
2009-04-05 implemented implicit enumeratorization
248 ID meth_id = rb_to_id(meth);
81232c27 » Laurent Sansonetti
2011-01-28 refactor duplicated code
249 SEL meth_sel = rb_vm_id_to_sel(meth_id, argc);
a6a914f3 » Laurent Sansonetti
2009-04-05 implemented implicit enumeratorization
250 return enumerator_init(obj, recv, meth_sel, argc, argv);
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
251 }
252
253 /* :nodoc: */
254 static VALUE
255 enumerator_init_copy(VALUE obj, SEL sel, VALUE orig)
256 {
257 struct enumerator *ptr0, *ptr1;
258
259 ptr0 = enumerator_ptr(orig);
260 if (ptr0->fib) {
261 /* Fibers cannot be copied */
262 rb_raise(rb_eTypeError, "can't copy execution context");
263 }
de680866 » Watson1978
2011-12-28 Properly detect if the object is initialized and raise error when app…
264
265 Data_Get_Struct(obj, struct enumerator, ptr1);
266
267 if (!ptr1) {
268 rb_raise(rb_eArgError, "unallocated enumerator");
269 }
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
270
a6a914f3 » Laurent Sansonetti
2009-04-05 implemented implicit enumeratorization
271 GC_WB(&ptr1->obj, ptr0->obj);
272 ptr1->sel = ptr0->sel;
273 if (ptr0->args != 0) {
274 GC_WB(&ptr1->args, ptr0->args);
275 }
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
276 ptr1->fib = 0;
277
278 return obj;
279 }
280
281 VALUE
a6a914f3 » Laurent Sansonetti
2009-04-05 implemented implicit enumeratorization
282 rb_enumeratorize(VALUE obj, SEL sel, int argc, VALUE *argv)
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
283 {
5b94e0e8 » Watson1978
2011-03-29 enumerator_allocate() needs sel argument because "alloc" method is de…
284 return enumerator_init(enumerator_allocate(rb_cEnumerator, 0), obj, sel,
a6a914f3 » Laurent Sansonetti
2009-04-05 implemented implicit enumeratorization
285 argc, argv);
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
286 }
287
288 static VALUE
6f5ed12d » Thibault Martin-Lagardette
2010-05-12 Improve core/enumerator pass rate
289 enumerator_block_call(VALUE obj, VALUE (*func)(ANYARGS), VALUE arg)
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
290 {
291 struct enumerator *e;
292 int argc = 0;
293 const VALUE *argv = 0;
294
295 e = enumerator_ptr(obj);
a6a914f3 » Laurent Sansonetti
2009-04-05 implemented implicit enumeratorization
296 if (e->args != 0) {
f6577370 » Watson1978
2012-07-18 use RARRAY_LENINT() to pass the value into int type arguments
297 argc = RARRAY_LENINT(e->args);
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
298 argv = RARRAY_PTR(e->args);
299 }
70ea0b5a » Laurent Sansonetti
2010-06-01 per-vm method cache + misc fixes/improvements
300 return rb_objc_block_call(e->obj, e->sel, argc, (VALUE *)argv,
6f5ed12d » Thibault Martin-Lagardette
2010-05-12 Improve core/enumerator pass rate
301 func, arg);
302 }
303
304 /*
305 * call-seq:
306 * enum.each {...}
307 *
308 * Iterates the given block using the object and the method specified
309 * in the first place. If no block is given, returns self.
310 *
311 */
312 static VALUE
313 enumerator_each(VALUE obj, SEL sel)
314 {
315 if (!rb_block_given_p()) {
316 return obj;
317 }
318 return enumerator_block_call(obj, enumerator_each_i, obj);
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
319 }
320
321 static VALUE
6f5ed12d » Thibault Martin-Lagardette
2010-05-12 Improve core/enumerator pass rate
322 enumerator_with_index_i(VALUE val, VALUE m, int argc, VALUE *argv)
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
323 {
6f5ed12d » Thibault Martin-Lagardette
2010-05-12 Improve core/enumerator pass rate
324 VALUE idx;
325 VALUE *memo = (VALUE *)m;
326
327 idx = INT2FIX(*memo);
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
328 ++*memo;
6f5ed12d » Thibault Martin-Lagardette
2010-05-12 Improve core/enumerator pass rate
329
330 if (argc <= 1)
331 return rb_yield_values(2, val, idx);
332
333 return rb_yield_values(2, rb_ary_new4(argc, argv), idx);
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
334 }
335
336 /*
337 * call-seq:
6f5ed12d » Thibault Martin-Lagardette
2010-05-12 Improve core/enumerator pass rate
338 * e.with_index(offset = 0) {|(*args), idx| ... }
76080c7c » Watson1978
2011-12-28 update rdoc
339 * e.with_index(offset = 0)
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
340 *
76080c7c » Watson1978
2011-12-28 update rdoc
341 * Iterates the given block for each element with an index, which
6f5ed12d » Thibault Martin-Lagardette
2010-05-12 Improve core/enumerator pass rate
342 * starts from +offset+. If no block is given, returns an enumerator.
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
343 *
344 */
345 static VALUE
6f5ed12d » Thibault Martin-Lagardette
2010-05-12 Improve core/enumerator pass rate
346 enumerator_with_index(VALUE obj, SEL sel, int argc, VALUE *argv)
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
347 {
6f5ed12d » Thibault Martin-Lagardette
2010-05-12 Improve core/enumerator pass rate
348 VALUE memo;
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
349
6f5ed12d » Thibault Martin-Lagardette
2010-05-12 Improve core/enumerator pass rate
350 rb_scan_args(argc, argv, "01", &memo);
351 RETURN_ENUMERATOR(obj, argc, argv);
352 memo = NIL_P(memo) ? 0 : (VALUE)NUM2LONG(memo);
353 return enumerator_block_call(obj, enumerator_with_index_i, (VALUE)&memo);
354 }
355
356 /*
357 * call-seq:
358 * e.each_with_index {|(*args), idx| ... }
359 * e.each_with_index
360 *
76080c7c » Watson1978
2011-12-28 update rdoc
361 * Same as Enumerator#with_index, except each_with_index does not
6f5ed12d » Thibault Martin-Lagardette
2010-05-12 Improve core/enumerator pass rate
362 * receive an offset argument.
363 *
364 */
365 static VALUE
366 enumerator_each_with_index(VALUE obj, SEL sel)
367 {
368 return enumerator_with_index(obj, sel, 0, NULL);
369 }
370
371 static VALUE
372 enumerator_with_object_i(VALUE val, VALUE memo, int argc, VALUE *argv)
373 {
374 if (argc <= 1) {
375 return rb_yield_values(2, val, memo);
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
376 }
6f5ed12d » Thibault Martin-Lagardette
2010-05-12 Improve core/enumerator pass rate
377
378 return rb_yield_values(2, rb_ary_new4(argc, argv), memo);
379 }
380
381 /*
382 * call-seq:
383 * e.with_object(obj) {|(*args), memo_obj| ... }
384 * e.with_object(obj)
385 *
386 * Iterates the given block for each element with an arbitrary
387 * object given, and returns the initially given object.
388 *
389 * If no block is given, returns an enumerator.
390 *
391 */
392 static VALUE
393 enumerator_with_object(VALUE obj, SEL sel, VALUE memo)
394 {
395 RETURN_ENUMERATOR(obj, 1, &memo);
396 enumerator_block_call(obj, enumerator_with_object_i, memo);
397 return memo;
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
398 }
399
400 #if 0
401 static VALUE
402 next_ii(VALUE i, VALUE obj, int argc, VALUE *argv)
403 {
404 rb_fiber_yield(argc, argv);
405 return Qnil;
406 }
407
408 static VALUE
409 next_i(VALUE curr, VALUE obj)
410 {
411 struct enumerator *e = enumerator_ptr(obj);
412 VALUE rnil = Qnil;
413
414 rb_block_call(obj, rb_intern("each"), 0, 0, next_ii, obj);
415 e->no_next = Qtrue;
416 return rb_fiber_yield(1, &rnil);
417 }
418
419 static void
420 next_init(VALUE obj, struct enumerator *e)
421 {
422 VALUE curr = rb_fiber_current();
423 e->dst = curr;
424 e->fib = rb_fiber_new(next_i, obj);
425 }
426 #endif
427
428 /*
429 * call-seq:
76080c7c » Watson1978
2011-12-28 update rdoc
430 * e.next -> object
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
431 *
432 * Returns the next object in the enumerator, and move the internal
76080c7c » Watson1978
2011-12-28 update rdoc
433 * position forward. When the position reached at the end, StopIteration
434 * is raised.
435 *
436 * a = [1,2,3]
437 * e = a.to_enum
438 * p e.next #=> 1
439 * p e.next #=> 2
440 * p e.next #=> 3
441 * p e.next #raises StopIteration
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
442 *
443 * Note that enumeration sequence by next method does not affect other
444 * non-external enumeration methods, unless underlying iteration
445 * methods itself has side-effect, e.g. IO#each_line.
446 *
447 */
448
449 static VALUE
450 enumerator_next(VALUE obj, SEL sel)
451 {
452 // TODO
453 #if 0
454 struct enumerator *e = enumerator_ptr(obj);
455 VALUE curr, v;
456 curr = rb_fiber_current();
457
458 if (!e->fib || !rb_fiber_alive_p(e->fib)) {
459 next_init(obj, e);
460 }
461
462 v = rb_fiber_resume(e->fib, 1, &curr);
463 if (e->no_next) {
464 e->fib = 0;
465 e->dst = Qnil;
466 e->no_next = Qfalse;
467 rb_raise(rb_eStopIteration, "iteration reached at end");
468 }
469 return v;
470 #endif
471 return Qnil;
472 }
473
474 /*
475 * call-seq:
76080c7c » Watson1978
2011-12-28 update rdoc
476 * e.rewind -> e
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
477 *
478 * Rewinds the enumeration sequence by the next method.
76080c7c » Watson1978
2011-12-28 update rdoc
479 *
480 * If the enclosed object responds to a "rewind" method, it is called.
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
481 */
482
483 static VALUE
484 enumerator_rewind(VALUE obj, SEL sel)
485 {
486 struct enumerator *e = enumerator_ptr(obj);
487
488 e->fib = 0;
489 e->dst = Qnil;
490 e->no_next = Qfalse;
491 return obj;
492 }
493
1f07e4b4 » Watson1978
2011-12-28 implement Enumerator#inspect
494 static VALUE
495 inspect_enumerator(VALUE obj, VALUE dummy, int recur)
496 {
497 struct enumerator *e;
498 const char *cname;
499 VALUE eobj, str;
500 int tainted, untrusted;
501
502 Data_Get_Struct(obj, struct enumerator, e);
503
504 cname = rb_obj_classname(obj);
505
506 if (!e || e->obj == Qundef) {
507 return rb_sprintf("#<%s: uninitialized>", cname);
508 }
509
510 if (recur) {
511 str = rb_sprintf("#<%s: ...>", cname);
512 OBJ_TAINT(str);
513 return str;
514 }
515
516 eobj = e->obj;
517
518 tainted = OBJ_TAINTED(eobj);
519 untrusted = OBJ_UNTRUSTED(eobj);
520
521 /* (1..100).each_cons(2) => "#<Enumerator: 1..100:each_cons(2)>" */
522 str = rb_sprintf("#<%s: ", cname);
523 rb_str_concat(str, rb_inspect(eobj));
524 rb_str_buf_cat2(str, ":");
1641827c » Watson1978
2012-04-06 trim a colon from method name which is returned by Enumerator#inspector
525 const char *method_name = sel_getName(e->sel);
526 long length = strlen(method_name);
527 if (method_name[length-1] == ':') {
528 length--;
529 }
a67e7050 » Watson1978
2012-04-06 use rb_str_buf_cat() instead of rb_str_cat()
530 rb_str_buf_cat(str, method_name, length);
1f07e4b4 » Watson1978
2011-12-28 implement Enumerator#inspect
531
532 if (e->args) {
533 long argc = RARRAY_LEN(e->args);
534 VALUE *argv = (VALUE*)RARRAY_PTR(e->args);
535
536 rb_str_buf_cat2(str, "(");
537
538 while (argc--) {
539 VALUE arg = *argv++;
540
541 rb_str_concat(str, rb_inspect(arg));
542 rb_str_buf_cat2(str, argc > 0 ? ", " : ")");
543
544 if (OBJ_TAINTED(arg)) tainted = TRUE;
545 if (OBJ_UNTRUSTED(arg)) untrusted = TRUE;
546 }
547 }
548
549 rb_str_buf_cat2(str, ">");
550
551 if (tainted) OBJ_TAINT(str);
552 if (untrusted) OBJ_UNTRUST(str);
553 return str;
554 }
555
556 /*
557 * call-seq:
558 * e.inspect -> string
559 *
560 * Create a printable version of <i>e</i>.
561 */
562
563 static VALUE
564 enumerator_inspect(VALUE obj, SEL sel)
565 {
566 return rb_exec_recursive(inspect_enumerator, obj, 0);
567 }
568
dd801db3 » Watson1978
2011-12-28 implement Enumerator::{Generator, Yielder}
569 /*
570 * Yielder
571 */
572 #if !WITH_OBJC
573 static void
574 yielder_mark(void *p)
575 {
576 struct yielder *ptr = p;
577 rb_gc_mark(ptr->proc);
578 }
579 #endif
580
581 static struct yielder *
582 yielder_ptr(VALUE obj)
583 {
584 struct yielder *ptr;
585
586 Data_Get_Struct(obj, struct yielder, ptr);
587 #if !WITH_OBJC
588 if (RDATA(obj)->dmark != yielder_mark) {
589 rb_raise(rb_eTypeError,
590 "wrong argument type %s (expected %s)",
591 rb_obj_classname(obj), rb_class2name(rb_cYielder));
592 }
593 #endif
594 if (!ptr || ptr->proc == Qundef) {
595 rb_raise(rb_eArgError, "uninitialized yielder");
596 }
597 return ptr;
598 }
599
600 /* :nodoc: */
601 static VALUE
602 yielder_allocate(VALUE klass, SEL sel)
603 {
604 struct yielder *ptr;
605 VALUE obj;
606
607 obj = Data_Make_Struct(klass, struct yielder, NULL, NULL, ptr);
608 ptr->proc = Qundef;
609
610 return obj;
611 }
612
613 static VALUE
614 yielder_init(VALUE obj, VALUE proc)
615 {
616 struct yielder *ptr;
617
618 Data_Get_Struct(obj, struct yielder, ptr);
619
620 if (!ptr) {
621 rb_raise(rb_eArgError, "unallocated yielder");
622 }
623
624 GC_WB(&ptr->proc, proc);
625
626 return obj;
627 }
628
629 /* :nodoc: */
630 static VALUE
631 yielder_initialize(VALUE obj, SEL sel)
632 {
633 rb_need_block();
634
635 return yielder_init(obj, rb_block_proc());
636 }
637
638 /* :nodoc: */
639 static VALUE
640 yielder_yield(VALUE obj, SEL sel, VALUE args)
641 {
642 struct yielder *ptr = yielder_ptr(obj);
643
644 return rb_proc_call(ptr->proc, args);
645 }
646
647 /* :nodoc: */
648 static VALUE yielder_yield_push(VALUE obj, SEL sel, VALUE args)
649 {
650 yielder_yield(obj, 0, args);
651 return obj;
652 }
653
654 static VALUE
655 yielder_yield_i(VALUE obj, VALUE memo, int argc, VALUE *argv)
656 {
657 return rb_yield_values2(argc, argv);
658 }
659
660 static VALUE
661 yielder_new(void)
662 {
663 return yielder_init(yielder_allocate(rb_cYielder, 0), rb_proc_new(yielder_yield_i, 0));
664 }
665
666 /*
667 * Generator
668 */
669 #if !WITH_OBJC
670 static void
671 generator_mark(void *p)
672 {
673 struct generator *ptr = p;
674 rb_gc_mark(ptr->proc);
675 }
676 #endif
677
678 static struct generator *
679 generator_ptr(VALUE obj)
680 {
681 struct generator *ptr;
682
683 Data_Get_Struct(obj, struct generator, ptr);
684 #if !WITH_OBJC
685 if (RDATA(obj)->dmark != generator_mark) {
686 rb_raise(rb_eTypeError,
687 "wrong argument type %s (expected %s)",
688 rb_obj_classname(obj), rb_class2name(rb_cGenerator));
689 }
690 #endif
691 if (!ptr || ptr->proc == Qundef) {
692 rb_raise(rb_eArgError, "uninitialized generator");
693 }
694 return ptr;
695 }
696
697 /* :nodoc: */
698 static VALUE
699 generator_allocate(VALUE klass, SEL sel)
700 {
701 struct generator *ptr;
702 VALUE obj;
703
704 obj = Data_Make_Struct(klass, struct generator, NULL, NULL, ptr);
705 ptr->proc = Qundef;
706
707 return obj;
708 }
709
710 static VALUE
711 generator_init(VALUE obj, VALUE proc)
712 {
713 struct generator *ptr;
714
715 Data_Get_Struct(obj, struct generator, ptr);
716
717 if (!ptr) {
718 rb_raise(rb_eArgError, "unallocated generator");
719 }
720
721 GC_WB(&ptr->proc, proc);
722
723 return obj;
724 }
725
726 VALUE rb_obj_is_proc(VALUE proc);
727
728 /* :nodoc: */
729 static VALUE
730 generator_initialize(VALUE obj, SEL sel, int argc, VALUE *argv)
731 {
732 VALUE proc;
733
734 if (argc == 0) {
735 rb_need_block();
736
737 proc = rb_block_proc();
738 } else {
739 rb_scan_args(argc, argv, "1", &proc);
740
741 if (!rb_obj_is_proc(proc))
742 rb_raise(rb_eTypeError,
743 "wrong argument type %s (expected Proc)",
744 rb_obj_classname(proc));
745
746 if (rb_block_given_p()) {
747 rb_warn("given block not used");
748 }
749 }
750
751 return generator_init(obj, proc);
752 }
753
754 /* :nodoc: */
755 static VALUE
756 generator_init_copy(VALUE obj, SEL sel, VALUE orig)
757 {
758 struct generator *ptr0, *ptr1;
759
760 ptr0 = generator_ptr(orig);
761
762 Data_Get_Struct(obj, struct generator, ptr1);
763
764 if (!ptr1) {
765 rb_raise(rb_eArgError, "unallocated generator");
766 }
767
768 ptr1->proc = ptr0->proc;
769
770 return obj;
771 }
772
773 /* :nodoc: */
774 static VALUE
775 generator_each(VALUE obj, SEL sel)
776 {
777 struct generator *ptr = generator_ptr(obj);
778 VALUE yielder;
779
780 yielder = yielder_new();
781
782 return rb_proc_call(ptr->proc, rb_ary_new3(1, yielder));
783
784 return obj;
785 }
786
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
787 void
788 Init_Enumerator(void)
789 {
790 rb_objc_define_method(rb_mKernel, "to_enum", obj_to_enum, -1);
791 rb_objc_define_method(rb_mKernel, "enum_for", obj_to_enum, -1);
792
fabdd03c » Laurent Sansonetti
2009-06-06 Enumerator should be a top-level class
793 rb_cEnumerator = rb_define_class("Enumerator", rb_cObject);
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
794 rb_include_module(rb_cEnumerator, rb_mEnumerable);
795
796 rb_objc_define_method(*(VALUE *)rb_cEnumerator, "alloc", enumerator_allocate, 0);
797 rb_objc_define_method(rb_cEnumerator, "initialize", enumerator_initialize, -1);
798 rb_objc_define_method(rb_cEnumerator, "initialize_copy", enumerator_init_copy, 1);
799 rb_objc_define_method(rb_cEnumerator, "each", enumerator_each, 0);
6f5ed12d » Thibault Martin-Lagardette
2010-05-12 Improve core/enumerator pass rate
800 rb_objc_define_method(rb_cEnumerator, "each_with_index", enumerator_each_with_index, 0);
801 rb_objc_define_method(rb_cEnumerator, "each_with_object", enumerator_with_object, 1);
802 rb_objc_define_method(rb_cEnumerator, "with_index", enumerator_with_index, -1);
803 rb_objc_define_method(rb_cEnumerator, "with_object", enumerator_with_object, 1);
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
804 rb_objc_define_method(rb_cEnumerator, "next", enumerator_next, 0);
805 rb_objc_define_method(rb_cEnumerator, "rewind", enumerator_rewind, 0);
1f07e4b4 » Watson1978
2011-12-28 implement Enumerator#inspect
806 rb_objc_define_method(rb_cEnumerator, "inspect", enumerator_inspect, 0);
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
807
808 rb_eStopIteration = rb_define_class("StopIteration", rb_eIndexError);
809
dd801db3 » Watson1978
2011-12-28 implement Enumerator::{Generator, Yielder}
810 /* Generator */
811 rb_cGenerator = rb_define_class_under(rb_cEnumerator, "Generator", rb_cObject);
812 rb_include_module(rb_cGenerator, rb_mEnumerable);
813 rb_objc_define_method(*(VALUE *)rb_cGenerator, "alloc", generator_allocate, 0);
814 rb_objc_define_method(rb_cGenerator, "initialize", generator_initialize, -1);
815 rb_objc_define_method(rb_cGenerator, "initialize_copy", generator_init_copy, 1);
816 rb_objc_define_method(rb_cGenerator, "each", generator_each, 0);
817
818 /* Yielder */
819 rb_cYielder = rb_define_class_under(rb_cEnumerator, "Yielder", rb_cObject);
820 rb_objc_define_method(*(VALUE *)rb_cYielder, "alloc", yielder_allocate, 0);
821 rb_objc_define_method(rb_cYielder, "initialize", yielder_initialize, 0);
822 rb_objc_define_method(rb_cYielder, "yield", yielder_yield, -2);
823 rb_objc_define_method(rb_cYielder, "<<", yielder_yield_push, -2);
824
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
825 sym_each = ID2SYM(rb_intern("each"));
826 }
Something went wrong with that request. Please try again.