summaryrefslogtreecommitdiff
path: root/trunk/enumerator.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/enumerator.c')
-rw-r--r--trunk/enumerator.c505
1 files changed, 0 insertions, 505 deletions
diff --git a/trunk/enumerator.c b/trunk/enumerator.c
deleted file mode 100644
index a472c83ce2..0000000000
--- a/trunk/enumerator.c
+++ /dev/null
@@ -1,505 +0,0 @@
-/************************************************
-
- enumerator.c - provides Enumerator class
-
- $Author$
-
- Copyright (C) 2001-2003 Akinori MUSHA
-
- $Idaemons: /home/cvs/rb/enumerator/enumerator.c,v 1.1.1.1 2001/07/15 10:12:48 knu Exp $
- $RoughId: enumerator.c,v 1.6 2003/07/27 11:03:24 nobu Exp $
- $Id$
-
-************************************************/
-
-#include "ruby/ruby.h"
-#include "debug.h"
-
-/*
- * Document-class: Enumerator
- *
- * A class which provides a method `each' to be used as an Enumerable
- * object.
- */
-VALUE rb_cEnumerator;
-static VALUE sym_each;
-
-VALUE rb_eStopIteration;
-
-struct enumerator {
- VALUE obj;
- ID meth;
- VALUE args;
- VALUE fib;
- VALUE dst;
- VALUE no_next;
-};
-
-static void
-enumerator_mark(void *p)
-{
- struct enumerator *ptr = p;
- rb_gc_mark(ptr->obj);
- rb_gc_mark(ptr->args);
- rb_gc_mark(ptr->fib);
- rb_gc_mark(ptr->dst);
-}
-
-static struct enumerator *
-enumerator_ptr(VALUE obj)
-{
- struct enumerator *ptr;
-
- Data_Get_Struct(obj, struct enumerator, ptr);
- if (RDATA(obj)->dmark != enumerator_mark) {
- rb_raise(rb_eTypeError,
- "wrong argument type %s (expected %s)",
- rb_obj_classname(obj), rb_class2name(rb_cEnumerator));
- }
- if (!ptr || ptr->obj == Qundef) {
- rb_raise(rb_eArgError, "uninitialized enumerator");
- }
- return ptr;
-}
-
-/*
- * call-seq:
- * obj.to_enum(method = :each, *args)
- * obj.enum_for(method = :each, *args)
- *
- * Returns Enumerator.new(self, method, *args).
- *
- * e.g.:
- *
- * str = "xyz"
- *
- * enum = str.enum_for(:each_byte)
- * a = enum.map {|b| '%02x' % b } #=> ["78", "79", "7a"]
- *
- * # protects an array from being modified
- * a = [1, 2, 3]
- * some_method(a.to_enum)
- *
- */
-static VALUE
-obj_to_enum(int argc, VALUE *argv, VALUE obj)
-{
- VALUE meth = sym_each;
-
- if (argc > 0) {
- --argc;
- meth = *argv++;
- }
- return rb_enumeratorize(obj, meth, argc, argv);
-}
-
-static VALUE
-each_slice_i(VALUE val, VALUE *memo)
-{
- VALUE ary = memo[0];
- VALUE v = Qnil;
- long size = (long)memo[1];
-
- rb_ary_push(ary, val);
-
- if (RARRAY_LEN(ary) == size) {
- v = rb_yield(ary);
- memo[0] = rb_ary_new2(size);
- }
-
- return v;
-}
-
-/*
- * call-seq:
- * e.each_slice(n) {...}
- * e.each_slice(n)
- *
- * Iterates the given block for each slice of <n> elements. If no
- * block is given, returns an enumerator.
- *
- * e.g.:
- * (1..10).each_slice(3) {|a| p a}
- * # outputs below
- * [1, 2, 3]
- * [4, 5, 6]
- * [7, 8, 9]
- * [10]
- *
- */
-static VALUE
-enum_each_slice(VALUE obj, VALUE n)
-{
- long size = NUM2LONG(n);
- VALUE args[2], ary;
-
- if (size <= 0) rb_raise(rb_eArgError, "invalid slice size");
- RETURN_ENUMERATOR(obj, 1, &n);
- args[0] = rb_ary_new2(size);
- args[1] = (VALUE)size;
-
- rb_block_call(obj, SYM2ID(sym_each), 0, 0, each_slice_i, (VALUE)args);
-
- ary = args[0];
- if (RARRAY_LEN(ary) > 0) rb_yield(ary);
-
- return Qnil;
-}
-
-static VALUE
-each_cons_i(VALUE val, VALUE *memo)
-{
- VALUE ary = memo[0];
- VALUE v = Qnil;
- long size = (long)memo[1];
-
- if (RARRAY_LEN(ary) == size) {
- rb_ary_shift(ary);
- }
- rb_ary_push(ary, val);
- if (RARRAY_LEN(ary) == size) {
- v = rb_yield(rb_ary_dup(ary));
- }
- return v;
-}
-
-/*
- * call-seq:
- * each_cons(n) {...}
- * each_cons(n)
- *
- * Iterates the given block for each array of consecutive <n>
- * elements. If no block is given, returns an enumerator.
- *
- * e.g.:
- * (1..10).each_cons(3) {|a| p a}
- * # outputs below
- * [1, 2, 3]
- * [2, 3, 4]
- * [3, 4, 5]
- * [4, 5, 6]
- * [5, 6, 7]
- * [6, 7, 8]
- * [7, 8, 9]
- * [8, 9, 10]
- *
- */
-static VALUE
-enum_each_cons(VALUE obj, VALUE n)
-{
- long size = NUM2LONG(n);
- VALUE args[2];
-
- if (size <= 0) rb_raise(rb_eArgError, "invalid size");
- RETURN_ENUMERATOR(obj, 1, &n);
- args[0] = rb_ary_new2(size);
- args[1] = (VALUE)size;
-
- rb_block_call(obj, SYM2ID(sym_each), 0, 0, each_cons_i, (VALUE)args);
-
- return Qnil;
-}
-
-static VALUE
-enumerator_allocate(VALUE klass)
-{
- struct enumerator *ptr;
- VALUE enum_obj;
-
- enum_obj = Data_Make_Struct(klass, struct enumerator, enumerator_mark, -1, ptr);
- ptr->obj = Qundef;
-
- return enum_obj;
-}
-
-static VALUE
-enumerator_each_i(VALUE v, VALUE enum_obj, int argc, VALUE *argv)
-{
- return rb_yield_values2(argc, argv);
-}
-
-static VALUE
-enumerator_init(VALUE enum_obj, VALUE obj, VALUE meth, int argc, VALUE *argv)
-{
- struct enumerator *ptr;
-
- Data_Get_Struct(enum_obj, struct enumerator, ptr);
-
- if (!ptr) {
- rb_raise(rb_eArgError, "unallocated enumerator");
- }
-
- ptr->obj = obj;
- ptr->meth = rb_to_id(meth);
- if (argc) ptr->args = rb_ary_new4(argc, argv);
- ptr->fib = 0;
- ptr->dst = Qnil;
- ptr->no_next = Qfalse;
-
- return enum_obj;
-}
-
-/*
- * call-seq:
- * Enumerator.new(obj, method = :each, *args)
- *
- * Creates a new Enumerator object, which is to be used as an
- * Enumerable object using the given object's given method with the
- * given arguments.
- *
- * Use of this method is discouraged. Use Kernel#enum_for() instead.
- */
-static VALUE
-enumerator_initialize(int argc, VALUE *argv, VALUE obj)
-{
- VALUE recv, meth = sym_each;
-
- if (argc == 0)
- rb_raise(rb_eArgError, "wrong number of argument (0 for 1)");
- recv = *argv++;
- if (--argc) {
- meth = *argv++;
- --argc;
- }
- return enumerator_init(obj, recv, meth, argc, argv);
-}
-
-/* :nodoc: */
-static VALUE
-enumerator_init_copy(VALUE obj, VALUE orig)
-{
- struct enumerator *ptr0, *ptr1;
-
- ptr0 = enumerator_ptr(orig);
- if (ptr0->fib) {
- /* Fibers cannot be copied */
- rb_raise(rb_eTypeError, "can't copy execution context");
- }
-
- Data_Get_Struct(obj, struct enumerator, ptr1);
-
- if (!ptr1) {
- rb_raise(rb_eArgError, "unallocated enumerator");
- }
-
- ptr1->obj = ptr0->obj;
- ptr1->meth = ptr0->meth;
- ptr1->args = ptr0->args;
- ptr1->fib = 0;
-
- return obj;
-}
-
-VALUE
-rb_enumeratorize(VALUE obj, VALUE meth, int argc, VALUE *argv)
-{
- return enumerator_init(enumerator_allocate(rb_cEnumerator), obj, meth, argc, argv);
-}
-
-/*
- * call-seq:
- * enum.each {...}
- *
- * Iterates the given block using the object and the method specified
- * in the first place. If no block is given, returns self.
- *
- */
-static VALUE
-enumerator_each(VALUE obj)
-{
- struct enumerator *e;
- int argc = 0;
- VALUE *argv = 0;
-
- if (!rb_block_given_p()) return obj;
- e = enumerator_ptr(obj);
- if (e->args) {
- argc = RARRAY_LEN(e->args);
- argv = RARRAY_PTR(e->args);
- }
- return rb_block_call(e->obj, e->meth, argc, argv,
- enumerator_each_i, (VALUE)e);
-}
-
-static VALUE
-enumerator_with_index_i(VALUE val, VALUE *memo)
-{
- val = rb_yield_values(2, val, INT2FIX(*memo));
- ++*memo;
- return val;
-}
-
-/*
- * call-seq:
- * e.with_index {|(*args), idx| ... }
- * e.with_index
- *
- * Iterates the given block for each element with an index, which
- * start from 0. If no block is given, returns an enumerator.
- *
- */
-static VALUE
-enumerator_with_index(VALUE obj)
-{
- struct enumerator *e;
- VALUE memo = 0;
- int argc = 0;
- VALUE *argv = 0;
-
- RETURN_ENUMERATOR(obj, 0, 0);
- e = enumerator_ptr(obj);
- if (e->args) {
- argc = RARRAY_LEN(e->args);
- argv = RARRAY_PTR(e->args);
- }
- return rb_block_call(e->obj, e->meth, argc, argv,
- enumerator_with_index_i, (VALUE)&memo);
-}
-
-static VALUE
-enumerator_with_object_i(VALUE val, VALUE memo)
-{
- return rb_yield_values(2, val, memo);
-}
-
-/*
- * call-seq:
- * e.with_object(obj) {|(*args), memo_obj| ... }
- * e.with_object(obj)
- *
- * Iterates the given block for each element with an arbitrary
- * object given, and returns the memo object.
- *
- * If no block is given, returns an enumerator.
- *
- */
-static VALUE
-enumerator_with_object(VALUE obj, VALUE memo)
-{
- struct enumerator *e;
- int argc = 0;
- VALUE *argv = 0;
-
- RETURN_ENUMERATOR(obj, 0, 0);
- e = enumerator_ptr(obj);
- if (e->args) {
- argc = RARRAY_LEN(e->args);
- argv = RARRAY_PTR(e->args);
- }
- rb_block_call(e->obj, e->meth, argc, argv,
- enumerator_with_object_i, memo);
-
- return memo;
-}
-
-static VALUE
-next_ii(VALUE i, VALUE obj, int argc, VALUE *argv)
-{
- rb_fiber_yield(argc, argv);
- return Qnil;
-}
-
-static VALUE
-next_i(VALUE curr, VALUE obj)
-{
- struct enumerator *e = enumerator_ptr(obj);
- VALUE nil = Qnil;
-
- rb_block_call(obj, rb_intern("each"), 0, 0, next_ii, obj);
- e->no_next = Qtrue;
- return rb_fiber_yield(1, &nil);
-}
-
-static void
-next_init(VALUE obj, struct enumerator *e)
-{
- VALUE curr = rb_fiber_current();
- e->dst = curr;
- e->fib = rb_fiber_new(next_i, obj);
-}
-
-/*
- * call-seq:
- * e.next => object
- *
- * Returns the next object in the enumerator, and move the internal
- * position forward. When the position reached at the end, internal
- * position is rewinded then StopIteration is raised.
- *
- * Note that enumeration sequence by next method does not affect other
- * non-external enumeration methods, unless underlying iteration
- * methods itself has side-effect, e.g. IO#each_line.
- *
- */
-
-static VALUE
-enumerator_next(VALUE obj)
-{
- struct enumerator *e = enumerator_ptr(obj);
- VALUE curr, v;
- curr = rb_fiber_current();
-
- if (!e->fib || !rb_fiber_alive_p(e->fib)) {
- next_init(obj, e);
- }
-
- v = rb_fiber_resume(e->fib, 1, &curr);
- if (e->no_next) {
- e->fib = 0;
- e->dst = Qnil;
- e->no_next = Qfalse;
- rb_raise(rb_eStopIteration, "iteration reached at end");
- }
- return v;
-}
-
-/*
- * call-seq:
- * e.rewind => e
- *
- * Rewinds the enumeration sequence by the next method.
- */
-
-static VALUE
-enumerator_rewind(VALUE obj)
-{
- struct enumerator *e = enumerator_ptr(obj);
-
- e->fib = 0;
- e->dst = Qnil;
- e->no_next = Qfalse;
- return obj;
-}
-
-void
-Init_Enumerator(void)
-{
- rb_define_method(rb_mKernel, "to_enum", obj_to_enum, -1);
- rb_define_method(rb_mKernel, "enum_for", obj_to_enum, -1);
-
- rb_define_method(rb_mEnumerable, "each_slice", enum_each_slice, 1);
- rb_define_method(rb_mEnumerable, "each_cons", enum_each_cons, 1);
-
- rb_cEnumerator = rb_define_class("Enumerator", rb_cObject);
- rb_include_module(rb_cEnumerator, rb_mEnumerable);
-
- rb_define_alloc_func(rb_cEnumerator, enumerator_allocate);
- rb_define_method(rb_cEnumerator, "initialize", enumerator_initialize, -1);
- rb_define_method(rb_cEnumerator, "initialize_copy", enumerator_init_copy, 1);
- rb_define_method(rb_cEnumerator, "each", enumerator_each, 0);
- rb_define_method(rb_cEnumerator, "each_with_index", enumerator_with_index, 0);
- rb_define_method(rb_cEnumerator, "with_index", enumerator_with_index, 0);
-#if 0
- rb_define_method(rb_cEnumerator, "with_object", enumerator_with_object, 1);
-#else
- (void)enumerator_with_object;
-#endif
- rb_define_method(rb_cEnumerator, "next", enumerator_next, 0);
- rb_define_method(rb_cEnumerator, "rewind", enumerator_rewind, 0);
-
- rb_eStopIteration = rb_define_class("StopIteration", rb_eIndexError);
-
- sym_each = ID2SYM(rb_intern("each"));
-
- rb_provide("enumerator.so"); /* for backward compatibility */
-}