OSDN Git Service

ruby-1.9.1-rc1
[splhack/AndroidRuby.git] / lib / ruby-1.9.1-rc1 / enumerator.c
1 /************************************************
2
3   enumerator.c - provides Enumerator class
4
5   $Author: yugui $
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 20712 2008-12-13 01:59:42Z yugui $
12
13 ************************************************/
14
15 #include "ruby/ruby.h"
16
17 /*
18  * Document-class: Enumerator
19  *
20  * A class which provides a method `each' to be used as an Enumerable
21  * object.
22  */
23 VALUE rb_cEnumerator;
24 static VALUE sym_each;
25 static ID id_rewind;
26
27 VALUE rb_eStopIteration;
28
29 struct enumerator {
30     VALUE obj;
31     ID    meth;
32     VALUE args;
33     VALUE fib;
34     VALUE dst;
35     VALUE no_next;
36 };
37
38 static VALUE rb_cGenerator, rb_cYielder;
39
40 struct generator {
41     VALUE proc;
42 };
43
44 struct yielder {
45     VALUE proc;
46 };
47
48 static VALUE generator_allocate(VALUE klass);
49 static VALUE generator_init(VALUE obj, VALUE proc);
50
51 /*
52  * Enumerator
53  */
54 static void
55 enumerator_mark(void *p)
56 {
57     struct enumerator *ptr = p;
58     rb_gc_mark(ptr->obj);
59     rb_gc_mark(ptr->args);
60     rb_gc_mark(ptr->fib);
61     rb_gc_mark(ptr->dst);
62 }
63
64 static struct enumerator *
65 enumerator_ptr(VALUE obj)
66 {
67     struct enumerator *ptr;
68
69     Data_Get_Struct(obj, struct enumerator, ptr);
70     if (RDATA(obj)->dmark != enumerator_mark) {
71         rb_raise(rb_eTypeError,
72                  "wrong argument type %s (expected %s)",
73                  rb_obj_classname(obj), rb_class2name(rb_cEnumerator));
74     }
75     if (!ptr || ptr->obj == Qundef) {
76         rb_raise(rb_eArgError, "uninitialized enumerator");
77     }
78     return ptr;
79 }
80
81 /*
82  *  call-seq:
83  *    obj.to_enum(method = :each, *args)
84  *    obj.enum_for(method = :each, *args)
85  *
86  *  Returns Enumerator.new(self, method, *args).
87  *
88  *  e.g.:
89  *
90  *     str = "xyz"
91  *
92  *     enum = str.enum_for(:each_byte)
93  *     a = enum.map {|b| '%02x' % b } #=> ["78", "79", "7a"]
94  *
95  *     # protects an array from being modified
96  *     a = [1, 2, 3]
97  *     some_method(a.to_enum)
98  *
99  */
100 static VALUE
101 obj_to_enum(int argc, VALUE *argv, VALUE obj)
102 {
103     VALUE meth = sym_each;
104
105     if (argc > 0) {
106         --argc;
107         meth = *argv++;
108     }
109     return rb_enumeratorize(obj, meth, argc, argv);
110 }
111
112 static VALUE
113 each_slice_i(VALUE val, VALUE *memo)
114 {
115     VALUE ary = memo[0];
116     VALUE v = Qnil;
117     long size = (long)memo[1];
118
119     rb_ary_push(ary, val);
120
121     if (RARRAY_LEN(ary) == size) {
122         v = rb_yield(ary);
123         memo[0] = rb_ary_new2(size);
124     }
125
126     return v;
127 }
128
129 /*
130  *  call-seq:
131  *    e.each_slice(n) {...}
132  *    e.each_slice(n)
133  *
134  *  Iterates the given block for each slice of <n> elements.  If no
135  *  block is given, returns an enumerator.
136  *
137  *  e.g.:
138  *      (1..10).each_slice(3) {|a| p a}
139  *      # outputs below
140  *      [1, 2, 3]
141  *      [4, 5, 6]
142  *      [7, 8, 9]
143  *      [10]
144  *
145  */
146 static VALUE
147 enum_each_slice(VALUE obj, VALUE n)
148 {
149     long size = NUM2LONG(n);
150     VALUE args[2], ary;
151
152     if (size <= 0) rb_raise(rb_eArgError, "invalid slice size");
153     RETURN_ENUMERATOR(obj, 1, &n);
154     args[0] = rb_ary_new2(size);
155     args[1] = (VALUE)size;
156
157     rb_block_call(obj, SYM2ID(sym_each), 0, 0, each_slice_i, (VALUE)args);
158
159     ary = args[0];
160     if (RARRAY_LEN(ary) > 0) rb_yield(ary);
161
162     return Qnil;
163 }
164
165 static VALUE
166 each_cons_i(VALUE val, VALUE *memo)
167 {
168     VALUE ary = memo[0];
169     VALUE v = Qnil;
170     long size = (long)memo[1];
171
172     if (RARRAY_LEN(ary) == size) {
173         rb_ary_shift(ary);
174     }
175     rb_ary_push(ary, val);
176     if (RARRAY_LEN(ary) == size) {
177         v = rb_yield(rb_ary_dup(ary));
178     }
179     return v;
180 }
181
182 /*
183  *  call-seq:
184  *    each_cons(n) {...}
185  *    each_cons(n)
186  *
187  *  Iterates the given block for each array of consecutive <n>
188  *  elements.  If no block is given, returns an enumerator.
189  *
190  *  e.g.:
191  *      (1..10).each_cons(3) {|a| p a}
192  *      # outputs below
193  *      [1, 2, 3]
194  *      [2, 3, 4]
195  *      [3, 4, 5]
196  *      [4, 5, 6]
197  *      [5, 6, 7]
198  *      [6, 7, 8]
199  *      [7, 8, 9]
200  *      [8, 9, 10]
201  *
202  */
203 static VALUE
204 enum_each_cons(VALUE obj, VALUE n)
205 {
206     long size = NUM2LONG(n);
207     VALUE args[2];
208
209     if (size <= 0) rb_raise(rb_eArgError, "invalid size");
210     RETURN_ENUMERATOR(obj, 1, &n);
211     args[0] = rb_ary_new2(size);
212     args[1] = (VALUE)size;
213
214     rb_block_call(obj, SYM2ID(sym_each), 0, 0, each_cons_i, (VALUE)args);
215
216     return Qnil;
217 }
218
219 static VALUE
220 each_with_object_i(VALUE val, VALUE memo)
221 {
222     return rb_yield_values(2, val, memo);
223 }
224
225 /*
226  *  call-seq:
227  *    each_with_object(obj) {|(*args), memo_obj| ... }
228  *    each_with_object(obj)
229  *
230  *  Iterates the given block for each element with an arbitrary
231  *  object given, and returns the initially given object.
232
233  *  If no block is given, returns an enumerator.
234  *
235  *  e.g.:
236  *      evens = (1..10).each_with_object([]) {|i, a| a << i*2 }
237  *      # => [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
238  *
239  */
240 static VALUE
241 enum_each_with_object(VALUE obj, VALUE memo)
242 {
243     RETURN_ENUMERATOR(obj, 1, &memo);
244
245     rb_block_call(obj, SYM2ID(sym_each), 0, 0, each_with_object_i, memo);
246
247     return memo;
248 }
249
250 static VALUE
251 enumerator_allocate(VALUE klass)
252 {
253     struct enumerator *ptr;
254     VALUE enum_obj;
255
256     enum_obj = Data_Make_Struct(klass, struct enumerator, enumerator_mark, -1, ptr);
257     ptr->obj = Qundef;
258
259     return enum_obj;
260 }
261
262 static VALUE
263 enumerator_each_i(VALUE v, VALUE enum_obj, int argc, VALUE *argv)
264 {
265     return rb_yield_values2(argc, argv);
266 }
267
268 static VALUE
269 enumerator_init(VALUE enum_obj, VALUE obj, VALUE meth, int argc, VALUE *argv)
270 {
271     struct enumerator *ptr;
272
273     Data_Get_Struct(enum_obj, struct enumerator, ptr);
274
275     if (!ptr) {
276         rb_raise(rb_eArgError, "unallocated enumerator");
277     }
278
279     ptr->obj  = obj;
280     ptr->meth = rb_to_id(meth);
281     if (argc) ptr->args = rb_ary_new4(argc, argv);
282     ptr->fib = 0;
283     ptr->dst = Qnil;
284     ptr->no_next = Qfalse;
285
286     return enum_obj;
287 }
288
289 /*
290  *  call-seq:
291  *    Enumerator.new(obj, method = :each, *args)
292  *    Enumerator.new { |y| ... }
293  *
294  *  Creates a new Enumerator object, which is to be used as an
295  *  Enumerable object iterating in a given way.
296  *
297  *  In the first form, a generated Enumerator iterates over the given
298  *  object using the given method with the given arguments passed.
299  *  Use of this form is discouraged.  Use Kernel#enum_for(), alias
300  *  to_enum, instead.
301  *
302  *    e = Enumerator.new(ObjectSpace, :each_object)
303  *        #-> ObjectSpace.enum_for(:each_object)
304  *
305  *    e.select { |obj| obj.is_a?(Class) }  #=> array of all classes
306  *
307  *  In the second form, iteration is defined by the given block, in
308  *  which a "yielder" object given as block parameter can be used to
309  *  yield a value by calling the +yield+ method, alias +<<+.
310  *
311  *    fib = Enumerator.new { |y|
312  *      a = b = 1
313  *      loop {
314  *        y << a
315  *        a, b = b, a + b
316  *      }
317  *    }
318  *
319  *    p fib.take(10) #=> [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
320  */
321 static VALUE
322 enumerator_initialize(int argc, VALUE *argv, VALUE obj)
323 {
324     VALUE recv, meth = sym_each;
325
326     if (argc == 0) {
327         if (!rb_block_given_p())
328             rb_raise(rb_eArgError, "wrong number of argument (0 for 1+)");
329
330         recv = generator_init(generator_allocate(rb_cGenerator), rb_block_proc());
331     } else {
332         recv = *argv++;
333         if (--argc) {
334             meth = *argv++;
335             --argc;
336         }
337     }
338
339     return enumerator_init(obj, recv, meth, argc, argv);
340 }
341
342 /* :nodoc: */
343 static VALUE
344 enumerator_init_copy(VALUE obj, VALUE orig)
345 {
346     struct enumerator *ptr0, *ptr1;
347
348     ptr0 = enumerator_ptr(orig);
349     if (ptr0->fib) {
350         /* Fibers cannot be copied */
351         rb_raise(rb_eTypeError, "can't copy execution context");
352     }
353
354     Data_Get_Struct(obj, struct enumerator, ptr1);
355
356     if (!ptr1) {
357         rb_raise(rb_eArgError, "unallocated enumerator");
358     }
359
360     ptr1->obj  = ptr0->obj;
361     ptr1->meth = ptr0->meth;
362     ptr1->args = ptr0->args;
363     ptr1->fib  = 0;
364
365     return obj;
366 }
367
368 VALUE
369 rb_enumeratorize(VALUE obj, VALUE meth, int argc, VALUE *argv)
370 {
371     return enumerator_init(enumerator_allocate(rb_cEnumerator), obj, meth, argc, argv);
372 }
373
374 /*
375  *  call-seq:
376  *    enum.each {...}
377  *
378  *  Iterates the given block using the object and the method specified
379  *  in the first place.  If no block is given, returns self.
380  *
381  */
382 static VALUE
383 enumerator_each(VALUE obj)
384 {
385     struct enumerator *e;
386     int argc = 0;
387     VALUE *argv = 0;
388
389     if (!rb_block_given_p()) return obj;
390     e = enumerator_ptr(obj);
391     if (e->args) {
392         argc = RARRAY_LEN(e->args);
393         argv = RARRAY_PTR(e->args);
394     }
395     return rb_block_call(e->obj, e->meth, argc, argv,
396                          enumerator_each_i, (VALUE)e);
397 }
398
399 static VALUE
400 enumerator_with_index_i(VALUE val, VALUE *memo)
401 {
402     val = rb_yield_values(2, val, INT2FIX(*memo));
403     ++*memo;
404     return val;
405 }
406
407 /*
408  *  call-seq:
409  *    e.with_index {|(*args), idx| ... }
410  *    e.with_index
411  *
412  *  Iterates the given block for each element with an index, which
413  *  start from 0.  If no block is given, returns an enumerator.
414  *
415  */
416 static VALUE
417 enumerator_with_index(VALUE obj)
418 {
419     struct enumerator *e;
420     VALUE memo = 0;
421     int argc = 0;
422     VALUE *argv = 0;
423
424     RETURN_ENUMERATOR(obj, 0, 0);
425     e = enumerator_ptr(obj);
426     if (e->args) {
427         argc = RARRAY_LEN(e->args);
428         argv = RARRAY_PTR(e->args);
429     }
430     return rb_block_call(e->obj, e->meth, argc, argv,
431                          enumerator_with_index_i, (VALUE)&memo);
432 }
433
434 static VALUE
435 enumerator_with_object_i(VALUE val, VALUE memo)
436 {
437     return rb_yield_values(2, val, memo);
438 }
439
440 /*
441  *  call-seq:
442  *    e.with_object(obj) {|(*args), memo_obj| ... }
443  *    e.with_object(obj)
444  *
445  *  Iterates the given block for each element with an arbitrary
446  *  object given, and returns the initially given object.
447  *
448  *  If no block is given, returns an enumerator.
449  *
450  */
451 static VALUE
452 enumerator_with_object(VALUE obj, VALUE memo)
453 {
454     struct enumerator *e;
455     int argc = 0;
456     VALUE *argv = 0;
457
458     RETURN_ENUMERATOR(obj, 1, &memo);
459     e = enumerator_ptr(obj);
460     if (e->args) {
461         argc = RARRAY_LEN(e->args);
462         argv = RARRAY_PTR(e->args);
463     }
464     rb_block_call(e->obj, e->meth, argc, argv,
465                   enumerator_with_object_i, memo);
466
467     return memo;
468 }
469
470 static VALUE
471 next_ii(VALUE i, VALUE obj, int argc, VALUE *argv)
472 {
473     rb_fiber_yield(argc, argv);
474     return Qnil;
475 }
476
477 static VALUE
478 next_i(VALUE curr, VALUE obj)
479 {
480     struct enumerator *e = enumerator_ptr(obj);
481     VALUE nil = Qnil;
482
483     rb_block_call(obj, rb_intern("each"), 0, 0, next_ii, obj);
484     e->no_next = Qtrue;
485     return rb_fiber_yield(1, &nil);
486 }
487
488 static void
489 next_init(VALUE obj, struct enumerator *e)
490 {
491     VALUE curr = rb_fiber_current();
492     e->dst = curr;
493     e->fib = rb_fiber_new(next_i, obj);
494 }
495
496 /*
497  * call-seq:
498  *   e.next   => object
499  *
500  * Returns the next object in the enumerator, and move the internal
501  * position forward.  When the position reached at the end, internal
502  * position is rewound then StopIteration is raised.
503  *
504  * Note that enumeration sequence by next method does not affect other
505  * non-external enumeration methods, unless underlying iteration
506  * methods itself has side-effect, e.g. IO#each_line.
507  *
508  */
509
510 static VALUE
511 enumerator_next(VALUE obj)
512 {
513     struct enumerator *e = enumerator_ptr(obj);
514     VALUE curr, v;
515     curr = rb_fiber_current();
516
517     if (!e->fib || !rb_fiber_alive_p(e->fib)) {
518         next_init(obj, e);
519     }
520
521     v = rb_fiber_resume(e->fib, 1, &curr);
522     if (e->no_next) {
523         e->fib = 0;
524         e->dst = Qnil;
525         e->no_next = Qfalse;
526         rb_raise(rb_eStopIteration, "iteration reached at end");
527     }
528     return v;
529 }
530
531 /*
532  * call-seq:
533  *   e.rewind   => e
534  *
535  * Rewinds the enumeration sequence by the next method.
536  *
537  * If the enclosed object responds to a "rewind" method, it is called.
538  */
539
540 static VALUE
541 enumerator_rewind(VALUE obj)
542 {
543     struct enumerator *e = enumerator_ptr(obj);
544
545     if (rb_respond_to(e->obj, id_rewind))
546         rb_funcall(e->obj, id_rewind, 0);
547
548     e->fib = 0;
549     e->dst = Qnil;
550     e->no_next = Qfalse;
551     return obj;
552 }
553
554 /*
555  * Yielder
556  */
557 static void
558 yielder_mark(void *p)
559 {
560     struct yielder *ptr = p;
561     rb_gc_mark(ptr->proc);
562 }
563
564 static struct yielder *
565 yielder_ptr(VALUE obj)
566 {
567     struct yielder *ptr;
568
569     Data_Get_Struct(obj, struct yielder, ptr);
570     if (RDATA(obj)->dmark != yielder_mark) {
571         rb_raise(rb_eTypeError,
572                  "wrong argument type %s (expected %s)",
573                  rb_obj_classname(obj), rb_class2name(rb_cYielder));
574     }
575     if (!ptr || ptr->proc == Qundef) {
576         rb_raise(rb_eArgError, "uninitialized yielder");
577     }
578     return ptr;
579 }
580
581 /* :nodoc: */
582 static VALUE
583 yielder_allocate(VALUE klass)
584 {
585     struct yielder *ptr;
586     VALUE obj;
587
588     obj = Data_Make_Struct(klass, struct yielder, yielder_mark, -1, ptr);
589     ptr->proc = Qundef;
590
591     return obj;
592 }
593
594 static VALUE
595 yielder_init(VALUE obj, VALUE proc)
596 {
597     struct yielder *ptr;
598
599     Data_Get_Struct(obj, struct yielder, ptr);
600
601     if (!ptr) {
602         rb_raise(rb_eArgError, "unallocated yielder");
603     }
604
605     ptr->proc = proc;
606
607     return obj;
608 }
609
610 /* :nodoc: */
611 static VALUE
612 yielder_initialize(VALUE obj)
613 {
614     rb_need_block();
615
616     return yielder_init(obj, rb_block_proc());
617 }
618
619 /* :nodoc: */
620 static VALUE
621 yielder_yield(VALUE obj, VALUE args)
622 {
623     struct yielder *ptr = yielder_ptr(obj);
624
625     rb_proc_call(ptr->proc, args);
626
627     return obj;
628 }
629
630 static VALUE
631 yielder_new_i(VALUE dummy)
632 {
633     return yielder_init(yielder_allocate(rb_cYielder), rb_block_proc());
634 }
635
636 static VALUE
637 yielder_yield_i(VALUE obj, VALUE memo, int argc, VALUE *argv)
638 {
639     return rb_yield_values2(argc, argv);
640 }
641
642 static VALUE
643 yielder_new(void)
644 {
645     return rb_iterate(yielder_new_i, (VALUE)0, yielder_yield_i, (VALUE)0);
646 }
647
648 /*
649  * Generator
650  */
651 static void
652 generator_mark(void *p)
653 {
654     struct generator *ptr = p;
655     rb_gc_mark(ptr->proc);
656 }
657
658 static struct generator *
659 generator_ptr(VALUE obj)
660 {
661     struct generator *ptr;
662
663     Data_Get_Struct(obj, struct generator, ptr);
664     if (RDATA(obj)->dmark != generator_mark) {
665         rb_raise(rb_eTypeError,
666                  "wrong argument type %s (expected %s)",
667                  rb_obj_classname(obj), rb_class2name(rb_cGenerator));
668     }
669     if (!ptr || ptr->proc == Qundef) {
670         rb_raise(rb_eArgError, "uninitialized generator");
671     }
672     return ptr;
673 }
674
675 /* :nodoc: */
676 static VALUE
677 generator_allocate(VALUE klass)
678 {
679     struct generator *ptr;
680     VALUE obj;
681
682     obj = Data_Make_Struct(klass, struct generator, generator_mark, -1, ptr);
683     ptr->proc = Qundef;
684
685     return obj;
686 }
687
688 static VALUE
689 generator_init(VALUE obj, VALUE proc)
690 {
691     struct generator *ptr;
692
693     Data_Get_Struct(obj, struct generator, ptr);
694
695     if (!ptr) {
696         rb_raise(rb_eArgError, "unallocated generator");
697     }
698
699     ptr->proc = proc;
700
701     return obj;
702 }
703
704 VALUE rb_obj_is_proc(VALUE proc);
705
706 /* :nodoc: */
707 static VALUE
708 generator_initialize(int argc, VALUE *argv, VALUE obj)
709 {
710     VALUE proc;
711
712     if (argc == 0) {
713         rb_need_block();
714
715         proc = rb_block_proc();
716     } else {
717         rb_scan_args(argc, argv, "1", &proc);
718
719         if (!rb_obj_is_proc(proc))
720             rb_raise(rb_eTypeError,
721                      "wrong argument type %s (expected Proc)",
722                      rb_obj_classname(proc));
723
724         if (rb_block_given_p()) {
725             rb_warn("given block not used");
726         }
727     }
728
729     return generator_init(obj, proc);
730 }
731
732 /* :nodoc: */
733 static VALUE
734 generator_init_copy(VALUE obj, VALUE orig)
735 {
736     struct generator *ptr0, *ptr1;
737
738     ptr0 = generator_ptr(orig);
739
740     Data_Get_Struct(obj, struct generator, ptr1);
741
742     if (!ptr1) {
743         rb_raise(rb_eArgError, "unallocated generator");
744     }
745
746     ptr1->proc = ptr0->proc;
747
748     return obj;
749 }
750
751 /* :nodoc: */
752 static VALUE
753 generator_each(VALUE obj)
754 {
755     struct generator *ptr = generator_ptr(obj);
756     VALUE yielder;
757
758     yielder = yielder_new();
759
760     rb_proc_call(ptr->proc, rb_ary_new3(1, yielder));
761
762     return obj;
763 }
764
765 void
766 Init_Enumerator(void)
767 {
768     rb_define_method(rb_mKernel, "to_enum", obj_to_enum, -1);
769     rb_define_method(rb_mKernel, "enum_for", obj_to_enum, -1);
770
771     rb_define_method(rb_mEnumerable, "each_slice", enum_each_slice, 1);
772     rb_define_method(rb_mEnumerable, "each_cons", enum_each_cons, 1);
773     rb_define_method(rb_mEnumerable, "each_with_object", enum_each_with_object, 1);
774
775     rb_cEnumerator = rb_define_class("Enumerator", rb_cObject);
776     rb_include_module(rb_cEnumerator, rb_mEnumerable);
777
778     rb_define_alloc_func(rb_cEnumerator, enumerator_allocate);
779     rb_define_method(rb_cEnumerator, "initialize", enumerator_initialize, -1);
780     rb_define_method(rb_cEnumerator, "initialize_copy", enumerator_init_copy, 1);
781     rb_define_method(rb_cEnumerator, "each", enumerator_each, 0);
782     rb_define_method(rb_cEnumerator, "each_with_index", enumerator_with_index, 0);
783     rb_define_method(rb_cEnumerator, "each_with_object", enumerator_with_object, 1);
784     rb_define_method(rb_cEnumerator, "with_index", enumerator_with_index, 0);
785     rb_define_method(rb_cEnumerator, "with_object", enumerator_with_object, 1);
786     rb_define_method(rb_cEnumerator, "next", enumerator_next, 0);
787     rb_define_method(rb_cEnumerator, "rewind", enumerator_rewind, 0);
788
789     rb_eStopIteration = rb_define_class("StopIteration", rb_eIndexError);
790
791     /* Generator */
792     rb_cGenerator = rb_define_class_under(rb_cEnumerator, "Generator", rb_cObject);
793     rb_include_module(rb_cGenerator, rb_mEnumerable);
794     rb_define_alloc_func(rb_cGenerator, generator_allocate);
795     rb_define_method(rb_cGenerator, "initialize", generator_initialize, -1);
796     rb_define_method(rb_cGenerator, "initialize_copy", generator_init_copy, 1);
797     rb_define_method(rb_cGenerator, "each", generator_each, 0);
798
799     /* Yielder */
800     rb_cYielder = rb_define_class_under(rb_cEnumerator, "Yielder", rb_cObject);
801     rb_define_alloc_func(rb_cYielder, yielder_allocate);
802     rb_define_method(rb_cYielder, "initialize", yielder_initialize, 0);
803     rb_define_method(rb_cYielder, "yield", yielder_yield, -2);
804     rb_define_method(rb_cYielder, "<<", yielder_yield, -2);
805
806     sym_each = ID2SYM(rb_intern("each"));
807     id_rewind = rb_intern("rewind");
808
809     rb_provide("enumerator.so");        /* for backward compatibility */
810 }