Ruby
1.9.3p484(2013-11-22revision43786)
Main Page
Modules
Data Structures
Files
File List
Globals
enumerator.c
Go to the documentation of this file.
1
/************************************************
2
3
enumerator.c - provides Enumerator class
4
5
$Author: marcandre $
6
7
Copyright (C) 2001-2003 Akinori MUSHA
8
9
$Idaemons: /home/cvs/rb/enumerator/enumerator.c,v 1.1.1.1 2001/07/15 10:12:48 knu Exp $
10
$RoughId: enumerator.c,v 1.6 2003/07/27 11:03:24 nobu Exp $
11
$Id: enumerator.c 34713 2012-02-20 23:55:19Z marcandre $
12
13
************************************************/
14
15
#include "
ruby/ruby.h
"
16
17
/*
18
* Document-class: Enumerator
19
*
20
* A class which allows both internal and external iteration.
21
*
22
* An Enumerator can be created by the following methods.
23
* - Kernel#to_enum
24
* - Kernel#enum_for
25
* - Enumerator.new
26
*
27
* Most methods have two forms: a block form where the contents
28
* are evaluated for each item in the enumeration, and a non-block form
29
* which returns a new Enumerator wrapping the iteration.
30
*
31
* enumerator = %w(one two three).each
32
* puts enumerator.class # => Enumerator
33
* enumerator.each_with_object("foo") do |item,obj|
34
* puts "#{obj}: #{item}"
35
* end
36
* # foo: one
37
* # foo: two
38
* # foo: three
39
* enum_with_obj = enumerator.each_with_object("foo")
40
* puts enum_with_obj.class # => Enumerator
41
* enum_with_obj.each do |item,obj|
42
* puts "#{obj: #{item}"
43
* end
44
* # foo: one
45
* # foo: two
46
* # foo: three
47
*
48
* This allows you to chain Enumerators together. For example, you
49
* can map a list's elements to strings containing the index
50
* and the element as a string via:
51
*
52
* puts %w[foo bar baz].map.with_index {|w,i| "#{i}:#{w}" }
53
* # => ["0:foo", "1:bar", "2:baz"]
54
*
55
* An Enumerator can also be used as an external iterator.
56
* For example, Enumerator#next returns the next value of the iterator
57
* or raises StopIteration if the Enumerator is at the end.
58
*
59
* e = [1,2,3].each # returns an enumerator object.
60
* puts e.next # => 1
61
* puts e.next # => 2
62
* puts e.next # => 3
63
* puts e.next # raises StopIteration
64
*
65
* You can use this to implement an internal iterator as follows:
66
*
67
* def ext_each(e)
68
* while true
69
* begin
70
* vs = e.next_values
71
* rescue StopIteration
72
* return $!.result
73
* end
74
* y = yield(*vs)
75
* e.feed y
76
* end
77
* end
78
*
79
* o = Object.new
80
*
81
* def o.each
82
* puts yield
83
* puts yield(1)
84
* puts yield(1, 2)
85
* 3
86
* end
87
*
88
* # use o.each as an internal iterator directly.
89
* puts o.each {|*x| puts x; [:b, *x] }
90
* # => [], [:b], [1], [:b, 1], [1, 2], [:b, 1, 2], 3
91
*
92
* # convert o.each to an external iterator for
93
* # implementing an internal iterator.
94
* puts ext_each(o.to_enum) {|*x| puts x; [:b, *x] }
95
* # => [], [:b], [1], [:b, 1], [1, 2], [:b, 1, 2], 3
96
*
97
*/
98
VALUE
rb_cEnumerator
;
99
static
ID
id_rewind
,
id_each
;
100
static
VALUE
sym_each
;
101
102
VALUE
rb_eStopIteration
;
103
104
struct
enumerator
{
105
VALUE
obj
;
106
ID
meth
;
107
VALUE
args
;
108
VALUE
fib
;
109
VALUE
dst
;
110
VALUE
lookahead
;
111
VALUE
feedvalue
;
112
VALUE
stop_exc
;
113
};
114
115
static
VALUE
rb_cGenerator
,
rb_cYielder
;
116
117
struct
generator
{
118
VALUE
proc
;
119
};
120
121
struct
yielder
{
122
VALUE
proc
;
123
};
124
125
static
VALUE
generator_allocate
(
VALUE
klass);
126
static
VALUE
generator_init
(
VALUE
obj,
VALUE
proc);
127
128
/*
129
* Enumerator
130
*/
131
static
void
132
enumerator_mark
(
void
*
p
)
133
{
134
struct
enumerator
*ptr =
p
;
135
rb_gc_mark
(ptr->
obj
);
136
rb_gc_mark
(ptr->
args
);
137
rb_gc_mark
(ptr->
fib
);
138
rb_gc_mark
(ptr->
dst
);
139
rb_gc_mark
(ptr->
lookahead
);
140
rb_gc_mark
(ptr->
feedvalue
);
141
rb_gc_mark
(ptr->
stop_exc
);
142
}
143
144
#define enumerator_free RUBY_TYPED_DEFAULT_FREE
145
146
static
size_t
147
enumerator_memsize
(
const
void
*
p
)
148
{
149
return
p ?
sizeof
(
struct
enumerator
) : 0;
150
}
151
152
static
const
rb_data_type_t
enumerator_data_type
= {
153
"enumerator"
,
154
{
155
enumerator_mark
,
156
enumerator_free
,
157
enumerator_memsize
,
158
},
159
};
160
161
static
struct
enumerator
*
162
enumerator_ptr
(
VALUE
obj
)
163
{
164
struct
enumerator
*ptr;
165
166
TypedData_Get_Struct
(obj,
struct
enumerator
, &
enumerator_data_type
, ptr);
167
if
(!ptr || ptr->
obj
==
Qundef
) {
168
rb_raise
(
rb_eArgError
,
"uninitialized enumerator"
);
169
}
170
return
ptr;
171
}
172
173
/*
174
* call-seq:
175
* obj.to_enum(method = :each, *args)
176
* obj.enum_for(method = :each, *args)
177
*
178
* Creates a new Enumerator which will enumerate by on calling +method+ on
179
* +obj+.
180
*
181
* +method+:: the method to call on +obj+ to generate the enumeration
182
* +args+:: arguments that will be passed in +method+ <i>in addition</i>
183
* to the item itself. Note that the number of args
184
* must not exceed the number expected by +method+
185
*
186
* === Example
187
*
188
* str = "xyz"
189
*
190
* enum = str.enum_for(:each_byte)
191
* enum.each { |b| puts b }
192
* # => 120
193
* # => 121
194
* # => 122
195
*
196
* # protect an array from being modified by some_method
197
* a = [1, 2, 3]
198
* some_method(a.to_enum)
199
*
200
*/
201
static
VALUE
202
obj_to_enum
(
int
argc
,
VALUE
*
argv
,
VALUE
obj
)
203
{
204
VALUE
meth
=
sym_each
;
205
206
if
(argc > 0) {
207
--
argc
;
208
meth = *argv++;
209
}
210
return
rb_enumeratorize
(obj, meth, argc, argv);
211
}
212
213
static
VALUE
214
enumerator_allocate
(
VALUE
klass)
215
{
216
struct
enumerator
*ptr;
217
VALUE
enum_obj;
218
219
enum_obj =
TypedData_Make_Struct
(klass,
struct
enumerator
, &
enumerator_data_type
, ptr);
220
ptr->
obj
=
Qundef
;
221
222
return
enum_obj;
223
}
224
225
static
VALUE
226
enumerator_init
(
VALUE
enum_obj,
VALUE
obj
,
VALUE
meth
,
int
argc
,
VALUE
*
argv
)
227
{
228
struct
enumerator
*ptr;
229
230
TypedData_Get_Struct
(enum_obj,
struct
enumerator
, &
enumerator_data_type
, ptr);
231
232
if
(!ptr) {
233
rb_raise
(
rb_eArgError
,
"unallocated enumerator"
);
234
}
235
236
ptr->
obj
=
obj
;
237
ptr->
meth
=
rb_to_id
(meth);
238
if
(argc) ptr->
args
=
rb_ary_new4
(argc, argv);
239
ptr->
fib
= 0;
240
ptr->
dst
=
Qnil
;
241
ptr->
lookahead
=
Qundef
;
242
ptr->
feedvalue
=
Qundef
;
243
ptr->
stop_exc
=
Qfalse
;
244
245
return
enum_obj;
246
}
247
248
/*
249
* call-seq:
250
* Enumerator.new { |yielder| ... }
251
* Enumerator.new(obj, method = :each, *args)
252
*
253
* Creates a new Enumerator object, which can be used as an
254
* Enumerable.
255
*
256
* In the first form, iteration is defined by the given block, in
257
* which a "yielder" object, given as block parameter, can be used to
258
* yield a value by calling the +yield+ method (aliased as +<<+):
259
*
260
* fib = Enumerator.new do |y|
261
* a = b = 1
262
* loop do
263
* y << a
264
* a, b = b, a + b
265
* end
266
* end
267
*
268
* p fib.take(10) # => [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
269
*
270
* In the second, deprecated, form, a generated Enumerator iterates over the
271
* given object using the given method with the given arguments passed.
272
*
273
* Use of this form is discouraged. Use Kernel#enum_for or Kernel#to_enum
274
* instead.
275
*
276
* e = Enumerator.new(ObjectSpace, :each_object)
277
* #-> ObjectSpace.enum_for(:each_object)
278
*
279
* e.select { |obj| obj.is_a?(Class) } #=> array of all classes
280
*
281
*/
282
static
VALUE
283
enumerator_initialize
(
int
argc
,
VALUE
*
argv
,
VALUE
obj
)
284
{
285
VALUE
recv,
meth
=
sym_each
;
286
287
if
(argc == 0) {
288
if
(!
rb_block_given_p
())
289
rb_raise
(
rb_eArgError
,
"wrong number of argument (0 for 1+)"
);
290
291
recv =
generator_init
(
generator_allocate
(
rb_cGenerator
),
rb_block_proc
());
292
}
293
else
{
294
recv = *argv++;
295
if
(--argc) {
296
meth = *argv++;
297
--
argc
;
298
}
299
}
300
301
return
enumerator_init
(obj, recv, meth, argc, argv);
302
}
303
304
/* :nodoc: */
305
static
VALUE
306
enumerator_init_copy
(
VALUE
obj
,
VALUE
orig)
307
{
308
struct
enumerator
*ptr0, *ptr1;
309
310
ptr0 =
enumerator_ptr
(orig);
311
if
(ptr0->
fib
) {
312
/* Fibers cannot be copied */
313
rb_raise
(
rb_eTypeError
,
"can't copy execution context"
);
314
}
315
316
TypedData_Get_Struct
(obj,
struct
enumerator
, &
enumerator_data_type
, ptr1);
317
318
if
(!ptr1) {
319
rb_raise
(
rb_eArgError
,
"unallocated enumerator"
);
320
}
321
322
ptr1->
obj
= ptr0->
obj
;
323
ptr1->
meth
= ptr0->
meth
;
324
ptr1->
args
= ptr0->
args
;
325
ptr1->
fib
= 0;
326
ptr1->
lookahead
=
Qundef
;
327
ptr1->
feedvalue
=
Qundef
;
328
329
return
obj
;
330
}
331
332
VALUE
333
rb_enumeratorize
(
VALUE
obj
,
VALUE
meth
,
int
argc
,
VALUE
*
argv
)
334
{
335
return
enumerator_init
(
enumerator_allocate
(
rb_cEnumerator
), obj, meth, argc, argv);
336
}
337
338
static
VALUE
339
enumerator_block_call
(
VALUE
obj
,
rb_block_call_func
*
func
,
VALUE
arg
)
340
{
341
int
argc
= 0;
342
VALUE
*
argv
= 0;
343
const
struct
enumerator
*e =
enumerator_ptr
(obj);
344
ID
meth
= e->
meth
;
345
346
if
(e->
args
) {
347
argc =
RARRAY_LENINT
(e->
args
);
348
argv =
RARRAY_PTR
(e->
args
);
349
}
350
return
rb_block_call
(e->
obj
, meth, argc, argv, func, arg);
351
}
352
353
/*
354
* call-seq:
355
* enum.each {...}
356
*
357
* Iterates over the block according to how this Enumerable was constructed.
358
* If no block is given, returns self.
359
*
360
*/
361
static
VALUE
362
enumerator_each
(
VALUE
obj
)
363
{
364
if
(!
rb_block_given_p
())
return
obj
;
365
return
enumerator_block_call
(obj, 0, obj);
366
}
367
368
static
VALUE
369
enumerator_with_index_i
(
VALUE
val,
VALUE
m,
int
argc
,
VALUE
*
argv
)
370
{
371
VALUE
idx;
372
VALUE
*memo = (
VALUE
*)m;
373
374
idx =
INT2FIX
(*memo);
375
++*memo;
376
377
if
(argc <= 1)
378
return
rb_yield_values
(2, val, idx);
379
380
return
rb_yield_values
(2,
rb_ary_new4
(argc, argv), idx);
381
}
382
383
/*
384
* call-seq:
385
* e.with_index(offset = 0) {|(*args), idx| ... }
386
* e.with_index(offset = 0)
387
*
388
* Iterates the given block for each element with an index, which
389
* starts from +offset+. If no block is given, returns a new Enumerator
390
* that includes the index, starting from +offset+
391
*
392
* +offset+:: the starting index to use
393
*
394
*/
395
static
VALUE
396
enumerator_with_index
(
int
argc
,
VALUE
*
argv
,
VALUE
obj
)
397
{
398
VALUE
memo;
399
400
rb_scan_args
(argc, argv,
"01"
, &memo);
401
RETURN_ENUMERATOR
(obj, argc, argv);
402
memo =
NIL_P
(memo) ? 0 : (
VALUE
)
NUM2LONG
(memo);
403
return
enumerator_block_call
(obj,
enumerator_with_index_i
, (
VALUE
)&memo);
404
}
405
406
/*
407
* call-seq:
408
* e.each_with_index {|(*args), idx| ... }
409
* e.each_with_index
410
*
411
* Same as Enumerator#with_index(0), i.e. there is no starting offset.
412
*
413
* If no block is given, a new Enumerator is returned that includes the index.
414
*
415
*/
416
static
VALUE
417
enumerator_each_with_index
(
VALUE
obj
)
418
{
419
return
enumerator_with_index
(0,
NULL
, obj);
420
}
421
422
static
VALUE
423
enumerator_with_object_i
(
VALUE
val,
VALUE
memo,
int
argc
,
VALUE
*
argv
)
424
{
425
if
(argc <= 1)
426
return
rb_yield_values
(2, val, memo);
427
428
return
rb_yield_values
(2,
rb_ary_new4
(argc, argv), memo);
429
}
430
431
/*
432
* call-seq:
433
* e.with_object(obj) {|(*args), obj| ... }
434
* e.with_object(obj)
435
*
436
* Iterates the given block for each element with an arbitrary object, +obj+,
437
* and returns +obj+
438
*
439
* If no block is given, returns a new Enumerator.
440
*
441
* === Example
442
*
443
* to_three = Enumerator.new do |y|
444
* 3.times do |x|
445
* y << x
446
* end
447
* end
448
*
449
* to_three_with_string = to_three.with_object("foo")
450
* to_three_with_string.each do |x,string|
451
* puts "#{string}: #{x}"
452
* end
453
*
454
* # => foo:0
455
* # => foo:1
456
* # => foo:2
457
*/
458
static
VALUE
459
enumerator_with_object
(
VALUE
obj
,
VALUE
memo)
460
{
461
RETURN_ENUMERATOR
(obj, 1, &memo);
462
enumerator_block_call
(obj,
enumerator_with_object_i
, memo);
463
464
return
memo;
465
}
466
467
static
VALUE
468
next_ii
(
VALUE
i
,
VALUE
obj
,
int
argc
,
VALUE
*
argv
)
469
{
470
struct
enumerator
*e =
enumerator_ptr
(obj);
471
VALUE
feedvalue
=
Qnil
;
472
VALUE
args
=
rb_ary_new4
(argc, argv);
473
rb_fiber_yield
(1, &args);
474
if
(e->
feedvalue
!=
Qundef
) {
475
feedvalue = e->
feedvalue
;
476
e->
feedvalue
=
Qundef
;
477
}
478
return
feedvalue
;
479
}
480
481
static
VALUE
482
next_i
(
VALUE
curr,
VALUE
obj
)
483
{
484
struct
enumerator
*e =
enumerator_ptr
(obj);
485
VALUE
nil =
Qnil
;
486
VALUE
result
;
487
488
result =
rb_block_call
(obj,
id_each
, 0, 0,
next_ii
, obj);
489
e->
stop_exc
=
rb_exc_new2
(
rb_eStopIteration
,
"iteration reached an end"
);
490
rb_ivar_set
(e->
stop_exc
,
rb_intern
(
"result"
), result);
491
return
rb_fiber_yield
(1, &nil);
492
}
493
494
static
void
495
next_init
(
VALUE
obj
,
struct
enumerator
*e)
496
{
497
VALUE
curr =
rb_fiber_current
();
498
e->
dst
= curr;
499
e->
fib
=
rb_fiber_new
(
next_i
, obj);
500
e->
lookahead
=
Qundef
;
501
}
502
503
static
VALUE
504
get_next_values
(
VALUE
obj
,
struct
enumerator
*e)
505
{
506
VALUE
curr, vs;
507
508
if
(e->
stop_exc
)
509
rb_exc_raise
(e->
stop_exc
);
510
511
curr =
rb_fiber_current
();
512
513
if
(!e->
fib
|| !
rb_fiber_alive_p
(e->
fib
)) {
514
next_init
(obj, e);
515
}
516
517
vs =
rb_fiber_resume
(e->
fib
, 1, &curr);
518
if
(e->
stop_exc
) {
519
e->
fib
= 0;
520
e->
dst
=
Qnil
;
521
e->
lookahead
=
Qundef
;
522
e->
feedvalue
=
Qundef
;
523
rb_exc_raise
(e->
stop_exc
);
524
}
525
return
vs;
526
}
527
528
/*
529
* call-seq:
530
* e.next_values -> array
531
*
532
* Returns the next object as an array in the enumerator, and move the
533
* internal position forward. When the position reached at the end,
534
* StopIteration is raised.
535
*
536
* This method can be used to distinguish <code>yield</code> and <code>yield
537
* nil</code>.
538
*
539
* === Example
540
*
541
* o = Object.new
542
* def o.each
543
* yield
544
* yield 1
545
* yield 1, 2
546
* yield nil
547
* yield [1, 2]
548
* end
549
* e = o.to_enum
550
* p e.next_values
551
* p e.next_values
552
* p e.next_values
553
* p e.next_values
554
* p e.next_values
555
* e = o.to_enum
556
* p e.next
557
* p e.next
558
* p e.next
559
* p e.next
560
* p e.next
561
*
562
* ## yield args next_values next
563
* # yield [] nil
564
* # yield 1 [1] 1
565
* # yield 1, 2 [1, 2] [1, 2]
566
* # yield nil [nil] nil
567
* # yield [1, 2] [[1, 2]] [1, 2]
568
*
569
* Note that +next_values+ does not affect other non-external enumeration
570
* methods unless underlying iteration method itself has side-effect, e.g.
571
* IO#each_line.
572
*
573
*/
574
575
static
VALUE
576
enumerator_next_values
(
VALUE
obj
)
577
{
578
struct
enumerator
*e =
enumerator_ptr
(obj);
579
VALUE
vs;
580
581
if
(e->
lookahead
!=
Qundef
) {
582
vs = e->
lookahead
;
583
e->
lookahead
=
Qundef
;
584
return
vs;
585
}
586
587
return
get_next_values
(obj, e);
588
}
589
590
static
VALUE
591
ary2sv
(
VALUE
args
,
int
dup)
592
{
593
if
(
TYPE
(args) !=
T_ARRAY
)
594
return
args
;
595
596
switch
(
RARRAY_LEN
(args)) {
597
case
0:
598
return
Qnil
;
599
600
case
1:
601
return
RARRAY_PTR
(args)[0];
602
603
default
:
604
if
(dup)
605
return
rb_ary_dup
(args);
606
return
args
;
607
}
608
}
609
610
/*
611
* call-seq:
612
* e.next -> object
613
*
614
* Returns the next object in the enumerator, and move the internal position
615
* forward. When the position reached at the end, StopIteration is raised.
616
*
617
* === Example
618
*
619
* a = [1,2,3]
620
* e = a.to_enum
621
* p e.next #=> 1
622
* p e.next #=> 2
623
* p e.next #=> 3
624
* p e.next #raises StopIteration
625
*
626
* Note that enumeration sequence by +next+ does not affect other non-external
627
* enumeration methods, unless the underlying iteration methods itself has
628
* side-effect, e.g. IO#each_line.
629
*
630
*/
631
632
static
VALUE
633
enumerator_next
(
VALUE
obj
)
634
{
635
VALUE
vs =
enumerator_next_values
(obj);
636
return
ary2sv
(vs, 0);
637
}
638
639
static
VALUE
640
enumerator_peek_values
(
VALUE
obj
)
641
{
642
struct
enumerator
*e =
enumerator_ptr
(obj);
643
644
if
(e->
lookahead
==
Qundef
) {
645
e->
lookahead
=
get_next_values
(obj, e);
646
}
647
return
e->
lookahead
;
648
}
649
650
/*
651
* call-seq:
652
* e.peek_values -> array
653
*
654
* Returns the next object as an array, similar to Enumerator#next_values, but
655
* doesn't move the internal position forward. If the position is already at
656
* the end, StopIteration is raised.
657
*
658
* === Example
659
*
660
* o = Object.new
661
* def o.each
662
* yield
663
* yield 1
664
* yield 1, 2
665
* end
666
* e = o.to_enum
667
* p e.peek_values #=> []
668
* e.next
669
* p e.peek_values #=> [1]
670
* p e.peek_values #=> [1]
671
* e.next
672
* p e.peek_values #=> [1, 2]
673
* e.next
674
* p e.peek_values # raises StopIteration
675
*
676
*/
677
678
static
VALUE
679
enumerator_peek_values_m
(
VALUE
obj
)
680
{
681
return
rb_ary_dup
(
enumerator_peek_values
(obj));
682
}
683
684
/*
685
* call-seq:
686
* e.peek -> object
687
*
688
* Returns the next object in the enumerator, but doesn't move the internal
689
* position forward. If the position is already at the end, StopIteration
690
* is raised.
691
*
692
* === Example
693
*
694
* a = [1,2,3]
695
* e = a.to_enum
696
* p e.next #=> 1
697
* p e.peek #=> 2
698
* p e.peek #=> 2
699
* p e.peek #=> 2
700
* p e.next #=> 2
701
* p e.next #=> 3
702
* p e.next #raises StopIteration
703
*
704
*/
705
706
static
VALUE
707
enumerator_peek
(
VALUE
obj
)
708
{
709
VALUE
vs =
enumerator_peek_values
(obj);
710
return
ary2sv
(vs, 1);
711
}
712
713
/*
714
* call-seq:
715
* e.feed obj -> nil
716
*
717
* Sets the value to be returned by the next yield inside +e+.
718
*
719
* If the value is not set, the yield returns nil.
720
*
721
* This value is cleared after being yielded.
722
*
723
* o = Object.new
724
* def o.each
725
* x = yield # (2) blocks
726
* p x # (5) => "foo"
727
* x = yield # (6) blocks
728
* p x # (8) => nil
729
* x = yield # (9) blocks
730
* p x # not reached w/o another e.next
731
* end
732
*
733
* e = o.to_enum
734
* e.next # (1)
735
* e.feed "foo" # (3)
736
* e.next # (4)
737
* e.next # (7)
738
* # (10)
739
*/
740
741
static
VALUE
742
enumerator_feed
(
VALUE
obj
,
VALUE
v
)
743
{
744
struct
enumerator
*e =
enumerator_ptr
(obj);
745
746
if
(e->
feedvalue
!=
Qundef
) {
747
rb_raise
(
rb_eTypeError
,
"feed value already set"
);
748
}
749
e->
feedvalue
=
v
;
750
751
return
Qnil
;
752
}
753
754
/*
755
* call-seq:
756
* e.rewind -> e
757
*
758
* Rewinds the enumeration sequence to the beginning.
759
*
760
* If the enclosed object responds to a "rewind" method, it is called.
761
*/
762
763
static
VALUE
764
enumerator_rewind
(
VALUE
obj
)
765
{
766
struct
enumerator
*e =
enumerator_ptr
(obj);
767
768
rb_check_funcall
(e->
obj
,
id_rewind
, 0, 0);
769
770
e->
fib
= 0;
771
e->
dst
=
Qnil
;
772
e->
lookahead
=
Qundef
;
773
e->
feedvalue
=
Qundef
;
774
e->
stop_exc
=
Qfalse
;
775
return
obj
;
776
}
777
778
static
VALUE
779
inspect_enumerator
(
VALUE
obj
,
VALUE
dummy,
int
recur
)
780
{
781
struct
enumerator
*e;
782
const
char
*cname;
783
VALUE
eobj, str;
784
int
tainted, untrusted;
785
786
TypedData_Get_Struct
(obj,
struct
enumerator
, &
enumerator_data_type
, e);
787
788
cname =
rb_obj_classname
(obj);
789
790
if
(!e || e->
obj
==
Qundef
) {
791
return
rb_sprintf
(
"#<%s: uninitialized>"
, cname);
792
}
793
794
if
(recur) {
795
str =
rb_sprintf
(
"#<%s: ...>"
, cname);
796
OBJ_TAINT
(str);
797
return
str;
798
}
799
800
eobj = e->
obj
;
801
802
tainted =
OBJ_TAINTED
(eobj);
803
untrusted =
OBJ_UNTRUSTED
(eobj);
804
805
/* (1..100).each_cons(2) => "#<Enumerator: 1..100:each_cons(2)>" */
806
str =
rb_sprintf
(
"#<%s: "
, cname);
807
rb_str_concat
(str,
rb_inspect
(eobj));
808
rb_str_buf_cat2
(str,
":"
);
809
rb_str_buf_cat2
(str,
rb_id2name
(e->
meth
));
810
811
if
(e->
args
) {
812
long
argc
=
RARRAY_LEN
(e->
args
);
813
VALUE
*
argv
=
RARRAY_PTR
(e->
args
);
814
815
rb_str_buf_cat2
(str,
"("
);
816
817
while
(argc--) {
818
VALUE
arg
= *argv++;
819
820
rb_str_concat
(str,
rb_inspect
(arg));
821
rb_str_buf_cat2
(str, argc > 0 ?
", "
:
")"
);
822
823
if
(
OBJ_TAINTED
(arg)) tainted =
TRUE
;
824
if
(
OBJ_UNTRUSTED
(arg)) untrusted =
TRUE
;
825
}
826
}
827
828
rb_str_buf_cat2
(str,
">"
);
829
830
if
(tainted)
OBJ_TAINT
(str);
831
if
(untrusted)
OBJ_UNTRUST
(str);
832
return
str;
833
}
834
835
/*
836
* call-seq:
837
* e.inspect -> string
838
*
839
* Creates a printable version of <i>e</i>.
840
*/
841
842
static
VALUE
843
enumerator_inspect
(
VALUE
obj
)
844
{
845
return
rb_exec_recursive
(
inspect_enumerator
, obj, 0);
846
}
847
848
/*
849
* Yielder
850
*/
851
static
void
852
yielder_mark
(
void
*p)
853
{
854
struct
yielder
*ptr =
p
;
855
rb_gc_mark
(ptr->
proc
);
856
}
857
858
#define yielder_free RUBY_TYPED_DEFAULT_FREE
859
860
static
size_t
861
yielder_memsize
(
const
void
*p)
862
{
863
return
p ?
sizeof
(
struct
yielder
) : 0;
864
}
865
866
static
const
rb_data_type_t
yielder_data_type
= {
867
"yielder"
,
868
{
869
yielder_mark
,
870
yielder_free
,
871
yielder_memsize
,
872
},
873
};
874
875
static
struct
yielder
*
876
yielder_ptr
(
VALUE
obj)
877
{
878
struct
yielder
*ptr;
879
880
TypedData_Get_Struct
(obj,
struct
yielder
, &
yielder_data_type
, ptr);
881
if
(!ptr || ptr->
proc
==
Qundef
) {
882
rb_raise
(
rb_eArgError
,
"uninitialized yielder"
);
883
}
884
return
ptr;
885
}
886
887
/* :nodoc: */
888
static
VALUE
889
yielder_allocate
(
VALUE
klass)
890
{
891
struct
yielder
*ptr;
892
VALUE
obj;
893
894
obj =
TypedData_Make_Struct
(klass,
struct
yielder
, &
yielder_data_type
, ptr);
895
ptr->
proc
=
Qundef
;
896
897
return
obj;
898
}
899
900
static
VALUE
901
yielder_init
(
VALUE
obj,
VALUE
proc
)
902
{
903
struct
yielder
*ptr;
904
905
TypedData_Get_Struct
(obj,
struct
yielder
, &
yielder_data_type
, ptr);
906
907
if
(!ptr) {
908
rb_raise
(
rb_eArgError
,
"unallocated yielder"
);
909
}
910
911
ptr->
proc
=
proc
;
912
913
return
obj;
914
}
915
916
/* :nodoc: */
917
static
VALUE
918
yielder_initialize
(
VALUE
obj)
919
{
920
rb_need_block
();
921
922
return
yielder_init
(obj,
rb_block_proc
());
923
}
924
925
/* :nodoc: */
926
static
VALUE
927
yielder_yield
(
VALUE
obj,
VALUE
args
)
928
{
929
struct
yielder
*ptr =
yielder_ptr
(obj);
930
931
return
rb_proc_call
(ptr->
proc
, args);
932
}
933
934
/* :nodoc: */
935
static
VALUE
yielder_yield_push
(
VALUE
obj,
VALUE
args
)
936
{
937
yielder_yield
(obj, args);
938
return
obj;
939
}
940
941
static
VALUE
942
yielder_yield_i
(
VALUE
obj,
VALUE
memo,
int
argc
,
VALUE
*
argv
)
943
{
944
return
rb_yield_values2
(argc, argv);
945
}
946
947
static
VALUE
948
yielder_new
(
void
)
949
{
950
return
yielder_init
(
yielder_allocate
(
rb_cYielder
),
rb_proc_new
(
yielder_yield_i
, 0));
951
}
952
953
/*
954
* Generator
955
*/
956
static
void
957
generator_mark
(
void
*p)
958
{
959
struct
generator
*ptr =
p
;
960
rb_gc_mark
(ptr->
proc
);
961
}
962
963
#define generator_free RUBY_TYPED_DEFAULT_FREE
964
965
static
size_t
966
generator_memsize
(
const
void
*p)
967
{
968
return
p ?
sizeof
(
struct
generator
) : 0;
969
}
970
971
static
const
rb_data_type_t
generator_data_type
= {
972
"generator"
,
973
{
974
generator_mark
,
975
generator_free
,
976
generator_memsize
,
977
},
978
};
979
980
static
struct
generator
*
981
generator_ptr
(
VALUE
obj)
982
{
983
struct
generator
*ptr;
984
985
TypedData_Get_Struct
(obj,
struct
generator
, &
generator_data_type
, ptr);
986
if
(!ptr || ptr->
proc
==
Qundef
) {
987
rb_raise
(
rb_eArgError
,
"uninitialized generator"
);
988
}
989
return
ptr;
990
}
991
992
/* :nodoc: */
993
static
VALUE
994
generator_allocate
(
VALUE
klass)
995
{
996
struct
generator
*ptr;
997
VALUE
obj;
998
999
obj =
TypedData_Make_Struct
(klass,
struct
generator
, &
generator_data_type
, ptr);
1000
ptr->
proc
=
Qundef
;
1001
1002
return
obj;
1003
}
1004
1005
static
VALUE
1006
generator_init
(
VALUE
obj,
VALUE
proc
)
1007
{
1008
struct
generator
*ptr;
1009
1010
TypedData_Get_Struct
(obj,
struct
generator
, &
generator_data_type
, ptr);
1011
1012
if
(!ptr) {
1013
rb_raise
(
rb_eArgError
,
"unallocated generator"
);
1014
}
1015
1016
ptr->
proc
=
proc
;
1017
1018
return
obj;
1019
}
1020
1021
/* :nodoc: */
1022
static
VALUE
1023
generator_initialize
(
int
argc
,
VALUE
*
argv
,
VALUE
obj)
1024
{
1025
VALUE
proc
;
1026
1027
if
(argc == 0) {
1028
rb_need_block
();
1029
1030
proc =
rb_block_proc
();
1031
}
else
{
1032
rb_scan_args
(argc, argv,
"1"
, &proc);
1033
1034
if
(!
rb_obj_is_proc
(proc))
1035
rb_raise
(
rb_eTypeError
,
1036
"wrong argument type %s (expected Proc)"
,
1037
rb_obj_classname
(proc));
1038
1039
if
(
rb_block_given_p
()) {
1040
rb_warn
(
"given block not used"
);
1041
}
1042
}
1043
1044
return
generator_init
(obj, proc);
1045
}
1046
1047
/* :nodoc: */
1048
static
VALUE
1049
generator_init_copy
(
VALUE
obj,
VALUE
orig)
1050
{
1051
struct
generator
*ptr0, *ptr1;
1052
1053
ptr0 =
generator_ptr
(orig);
1054
1055
TypedData_Get_Struct
(obj,
struct
generator
, &
generator_data_type
, ptr1);
1056
1057
if
(!ptr1) {
1058
rb_raise
(
rb_eArgError
,
"unallocated generator"
);
1059
}
1060
1061
ptr1->
proc
= ptr0->
proc
;
1062
1063
return
obj;
1064
}
1065
1066
/* :nodoc: */
1067
static
VALUE
1068
generator_each
(
VALUE
obj)
1069
{
1070
struct
generator
*ptr =
generator_ptr
(obj);
1071
VALUE
yielder
;
1072
1073
yielder =
yielder_new
();
1074
1075
return
rb_proc_call
(ptr->
proc
,
rb_ary_new3
(1, yielder));
1076
}
1077
1078
/*
1079
* Document-class: StopIteration
1080
*
1081
* Raised to stop the iteration, in particular by Enumerator#next. It is
1082
* rescued by Kernel#loop.
1083
*
1084
* loop do
1085
* puts "Hello"
1086
* raise StopIteration
1087
* puts "World"
1088
* end
1089
* puts "Done!"
1090
*
1091
* <em>produces:</em>
1092
*
1093
* Hello
1094
* Done!
1095
*/
1096
1097
/*
1098
* call-seq:
1099
* result -> value
1100
*
1101
* Returns the return value of the iterator.
1102
*
1103
* o = Object.new
1104
* def o.each
1105
* yield 1
1106
* yield 2
1107
* yield 3
1108
* 100
1109
* end
1110
*
1111
* e = o.to_enum
1112
*
1113
* puts e.next #=> 1
1114
* puts e.next #=> 2
1115
* puts e.next #=> 3
1116
*
1117
* begin
1118
* e.next
1119
* rescue StopIteration => ex
1120
* puts ex.result #=> 100
1121
* end
1122
*
1123
*/
1124
static
VALUE
1125
stop_result
(
VALUE
self
)
1126
{
1127
return
rb_attr_get
(
self
,
rb_intern
(
"result"
));
1128
}
1129
1130
void
1131
Init_Enumerator
(
void
)
1132
{
1133
rb_define_method
(
rb_mKernel
,
"to_enum"
,
obj_to_enum
, -1);
1134
rb_define_method
(
rb_mKernel
,
"enum_for"
,
obj_to_enum
, -1);
1135
1136
rb_cEnumerator
=
rb_define_class
(
"Enumerator"
,
rb_cObject
);
1137
rb_include_module
(
rb_cEnumerator
,
rb_mEnumerable
);
1138
1139
rb_define_alloc_func
(
rb_cEnumerator
,
enumerator_allocate
);
1140
rb_define_method
(
rb_cEnumerator
,
"initialize"
,
enumerator_initialize
, -1);
1141
rb_define_method
(
rb_cEnumerator
,
"initialize_copy"
,
enumerator_init_copy
, 1);
1142
rb_define_method
(
rb_cEnumerator
,
"each"
,
enumerator_each
, 0);
1143
rb_define_method
(
rb_cEnumerator
,
"each_with_index"
,
enumerator_each_with_index
, 0);
1144
rb_define_method
(
rb_cEnumerator
,
"each_with_object"
,
enumerator_with_object
, 1);
1145
rb_define_method
(
rb_cEnumerator
,
"with_index"
,
enumerator_with_index
, -1);
1146
rb_define_method
(
rb_cEnumerator
,
"with_object"
,
enumerator_with_object
, 1);
1147
rb_define_method
(
rb_cEnumerator
,
"next_values"
,
enumerator_next_values
, 0);
1148
rb_define_method
(
rb_cEnumerator
,
"peek_values"
,
enumerator_peek_values_m
, 0);
1149
rb_define_method
(
rb_cEnumerator
,
"next"
,
enumerator_next
, 0);
1150
rb_define_method
(
rb_cEnumerator
,
"peek"
,
enumerator_peek
, 0);
1151
rb_define_method
(
rb_cEnumerator
,
"feed"
,
enumerator_feed
, 1);
1152
rb_define_method
(
rb_cEnumerator
,
"rewind"
,
enumerator_rewind
, 0);
1153
rb_define_method
(
rb_cEnumerator
,
"inspect"
,
enumerator_inspect
, 0);
1154
1155
rb_eStopIteration
=
rb_define_class
(
"StopIteration"
,
rb_eIndexError
);
1156
rb_define_method
(
rb_eStopIteration
,
"result"
,
stop_result
, 0);
1157
1158
/* Generator */
1159
rb_cGenerator
=
rb_define_class_under
(
rb_cEnumerator
,
"Generator"
,
rb_cObject
);
1160
rb_include_module
(
rb_cGenerator
,
rb_mEnumerable
);
1161
rb_define_alloc_func
(
rb_cGenerator
,
generator_allocate
);
1162
rb_define_method
(
rb_cGenerator
,
"initialize"
,
generator_initialize
, -1);
1163
rb_define_method
(
rb_cGenerator
,
"initialize_copy"
,
generator_init_copy
, 1);
1164
rb_define_method
(
rb_cGenerator
,
"each"
,
generator_each
, 0);
1165
1166
/* Yielder */
1167
rb_cYielder
=
rb_define_class_under
(
rb_cEnumerator
,
"Yielder"
,
rb_cObject
);
1168
rb_define_alloc_func
(
rb_cYielder
,
yielder_allocate
);
1169
rb_define_method
(
rb_cYielder
,
"initialize"
,
yielder_initialize
, 0);
1170
rb_define_method
(
rb_cYielder
,
"yield"
,
yielder_yield
, -2);
1171
rb_define_method
(
rb_cYielder
,
"<<"
,
yielder_yield_push
, -2);
1172
1173
id_rewind
=
rb_intern
(
"rewind"
);
1174
id_each
=
rb_intern
(
"each"
);
1175
sym_each
=
ID2SYM
(
id_each
);
1176
1177
rb_provide
(
"enumerator.so"
);
/* for backward compatibility */
1178
}
1179
Generated on Fri Nov 22 2013 07:03:55 for Ruby by
1.8.3