[前][次][番号順一覧][スレッド一覧]

ruby-changes:4443

From: ko1@a...
Date: Wed, 9 Apr 2008 20:13:25 +0900 (JST)
Subject: [ruby-changes:4443] knu - Ruby:r15934 (ruby_1_8): * enumerator.c, inits.c (rb_call_inits), ruby.h, intern.h,

knu	2008-04-09 20:13:04 +0900 (Wed, 09 Apr 2008)

  New Revision: 15934

  Added files:
    branches/ruby_1_8/enumerator.c
  Removed directories:
    branches/ruby_1_8/ext/enumerator/
  Modified files:
    branches/ruby_1_8/ChangeLog
    branches/ruby_1_8/common.mk
    branches/ruby_1_8/enum.c
    branches/ruby_1_8/inits.c
    branches/ruby_1_8/intern.h
    branches/ruby_1_8/ruby.h

  Log:
    * enumerator.c, inits.c (rb_call_inits), ruby.h, intern.h,
      ext/enumerator, common.mk (OBJS, enumerator.$(OBJEXT)): Make the
      enumerator module built-in,
    
    * enumerator.c: New method: Enumerable::Enumerator#with_index.
    
    * enum.c (enum_each_with_index): Enumerable#each_with_index now
      returns an enumerator instead of raising an exception if no
      block is given.  Enumerable#enum_with_index, formerly defined in
      the enumerator module, is kept as an alias to each_with_index
      for backward compatibility.

  Deleted: branches/ruby_1_8/ext/enumerator/
    % svn ls -r 15934 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/ext/enumerator/

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/common.mk?r1=15934&r2=15933&diff_format=u
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/intern.h?r1=15934&r2=15933&diff_format=u
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/enum.c?r1=15934&r2=15933&diff_format=u
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/ruby.h?r1=15934&r2=15933&diff_format=u
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/inits.c?r1=15934&r2=15933&diff_format=u
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/ChangeLog?r1=15934&r2=15933&diff_format=u
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/enumerator.c

Index: ruby_1_8/intern.h
===================================================================
--- ruby_1_8/intern.h	(revision 15933)
+++ ruby_1_8/intern.h	(revision 15934)
@@ -128,6 +128,14 @@
 int rb_cmpint _((VALUE, VALUE, VALUE));
 NORETURN(void rb_cmperr _((VALUE, VALUE)));
 /* enum.c */
+VALUE rb_block_call _((VALUE, ID, int, VALUE*, VALUE (*)(ANYARGS), VALUE));
+/* enumerator.c */
+VALUE rb_enumeratorize _((VALUE, VALUE, int, VALUE *));
+#define RETURN_ENUMERATOR(obj, argc, argv) do {				\
+	if (!rb_block_given_p())					\
+	    return rb_enumeratorize(obj, ID2SYM(rb_frame_last_func()),	\
+				    argc, argv);			\
+    } while (0)
 /* error.c */
 RUBY_EXTERN int ruby_nerrs;
 VALUE rb_exc_new _((VALUE, const char*, long));
Index: ruby_1_8/ChangeLog
===================================================================
--- ruby_1_8/ChangeLog	(revision 15933)
+++ ruby_1_8/ChangeLog	(revision 15934)
@@ -1,3 +1,17 @@
+Wed Apr  9 19:58:31 2008  Akinori MUSHA  <knu@i...>
+
+	* enumerator.c, inits.c (rb_call_inits), ruby.h, intern.h,
+	  ext/enumerator, common.mk (OBJS, enumerator.$(OBJEXT)): Make the
+	  enumerator module built-in,
+
+	* enumerator.c: New method: Enumerable::Enumerator#with_index.
+
+	* enum.c (enum_each_with_index): Enumerable#each_with_index now
+	  returns an enumerator instead of raising an exception if no
+	  block is given.  Enumerable#enum_with_index, formerly defined in
+	  the enumerator module, is kept as an alias to each_with_index
+	  for backward compatibility.
+
 Wed Apr  9 19:43:51 2008  Akinori MUSHA  <knu@i...>
 
 	* eval.c (rb_obj_method, rb_proc_call), intern.h: Export.
Index: ruby_1_8/enumerator.c
===================================================================
--- ruby_1_8/enumerator.c	(revision 0)
+++ ruby_1_8/enumerator.c	(revision 15934)
@@ -0,0 +1,414 @@
+/************************************************
+
+  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.h"
+
+/*
+ * Document-class: Enumerable::Enumerator
+ *
+ * A class which provides a method `each' to be used as an Enumerable
+ * object.
+ */
+VALUE rb_cEnumerator;
+static VALUE sym_each, sym_call;
+
+static VALUE
+proc_call(proc, args)
+    VALUE proc;
+    VALUE args;
+{
+    if (TYPE(args) != T_ARRAY) {
+	args = rb_ary_new3(1, args);
+    }
+    return rb_proc_call(proc, args);
+}
+
+struct enumerator {
+    VALUE method;
+    VALUE proc;
+    VALUE args;
+    rb_block_call_func *iter;
+};
+
+static void
+enumerator_mark(p)
+    void *p;
+{
+    struct enumerator *ptr = p;
+    rb_gc_mark(ptr->method);
+    rb_gc_mark(ptr->proc);
+    rb_gc_mark(ptr->args);
+}
+
+static struct enumerator *
+enumerator_ptr(obj)
+    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 Enumerable::Enumerator)",
+		 rb_obj_classname(obj));
+    }
+    if (!ptr) {
+	rb_raise(rb_eArgError, "uninitialized enumerator");
+    }
+    return ptr;
+}
+
+static VALUE
+enumerator_iter_i(i, enum_obj, argc, argv)
+    VALUE i;
+    VALUE enum_obj;
+    int argc;
+    VALUE *argv;
+{
+    struct enumerator *e = (struct enumerator *)enum_obj;
+    return rb_yield(proc_call(e->proc, i));
+}
+
+/*
+ *  call-seq:
+ *    obj.to_enum(method = :each, *args)
+ *    obj.enum_for(method = :each, *args)
+ *
+ *  Returns Enumerable::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(argc, argv, obj)
+    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(val, memo)
+    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) {...}
+ *
+ *  Iterates the given block for each slice of <n> elements.
+ *
+ *  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(obj, n)
+    VALUE obj, 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(val, memo)
+    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) {...}
+ *
+ *  Iterates the given block for each array of consecutive <n>
+ *  elements.
+ *
+ *  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(obj, n)
+    VALUE obj, 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(klass)
+    VALUE klass;
+{
+    struct enumerator *ptr;
+    return Data_Make_Struct(klass, struct enumerator,
+			    enumerator_mark, -1, ptr);
+}
+
+static VALUE
+enumerator_each_i(v, enum_obj)
+    VALUE v;
+    VALUE enum_obj;
+{
+    return rb_yield(v);
+}
+
+static VALUE
+enumerator_init(enum_obj, obj, meth, argc, argv)
+    VALUE enum_obj;
+    VALUE obj;
+    VALUE meth;
+    int argc;
+    VALUE *argv;
+{
+    struct enumerator *ptr = enumerator_ptr(enum_obj);
+
+    ptr->method = rb_obj_method(obj, meth);
+    if (rb_block_given_p()) {
+	ptr->proc = rb_block_proc();
+	ptr->iter = enumerator_iter_i;
+    }
+    else {
+	ptr->iter = enumerator_each_i;
+    }
+    if (argc) ptr->args = rb_ary_new4(argc, argv);
+
+    return enum_obj;
+}
+
+/*
+ *  call-seq:
+ *    Enumerable::Enumerator.new(obj, method = :each, *args)
+ *
+ *  Creates a new Enumerable::Enumerator object, which is to be
+ *  used as an Enumerable object using the given object's given
+ *  method with the given arguments.
+ *
+ *  e.g.:
+ *      str = "xyz"
+ *
+ *      enum = Enumerable::Enumerator.new(str, :each_byte)
+ *      a = enum.map {|b| '%02x' % b } #=> ["78", "79", "7a"]
+ *
+ */
+static VALUE
+enumerator_initialize(argc, argv, obj)
+    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(obj, orig)
+    VALUE obj;
+    VALUE orig;
+{
+    struct enumerator *ptr0, *ptr1;
+
+    ptr0 = enumerator_ptr(orig);
+    ptr1 = enumerator_ptr(obj);
+
+    ptr1->method = ptr0->method;
+    ptr1->proc = ptr0->proc;
+    ptr1->iter = ptr0->iter;
+    ptr1->args = ptr0->args;
+
+    return obj;
+}
+
+VALUE
+rb_enumeratorize(obj, meth, argc, argv)
+    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.
+ *
+ */
+static VALUE
+enumerator_each(obj)
+    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->method, SYM2ID(sym_call), argc, argv, e->iter, (VALUE)e);
+}
+
+static VALUE
+enumerator_with_index_i(val, memo)
+    VALUE val;
+    VALUE *memo;
+{
+    val = rb_yield_values(2, val, INT2FIX(*memo));
+    ++*memo;
+    return val;
+}
+
+/*
+ *  call-seq:
+ *    e.with_index {|(*args), idx| ... }
+ *
+ *  Iterates the given block for each elements with an index, which
+ *  start from 0.
+ *
+ */
+static VALUE
+enumerator_with_index(obj)
+    VALUE obj;
+{
+    struct enumerator *e = enumerator_ptr(obj);
+    VALUE memo = 0;
+    int argc = 0;
+    VALUE *argv = 0;
+
+    RETURN_ENUMERATOR(obj, 0, 0);
+    if (e->args) {
+	argc = RARRAY_LEN(e->args);
+	argv = RARRAY_PTR(e->args);
+    }
+    return rb_block_call(e->method, SYM2ID(sym_call), argc, argv,
+			 enumerator_with_index_i, (VALUE)&memo);
+}
+
+void
+Init_Enumerator()
+{
+    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, "enum_slice", enum_each_slice, 1);
+    rb_define_method(rb_mEnumerable, "each_cons", enum_each_cons, 1);
+    rb_define_method(rb_mEnumerable, "enum_cons", enum_each_cons, 1);
+
+    rb_cEnumerator = rb_define_class_under(rb_mEnumerable, "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, "with_index", enumerator_with_index, 0);
+
+    sym_each		= ID2SYM(rb_intern("each"));
+    sym_call		= ID2SYM(rb_intern("call"));
+
+    rb_provide("enumerator.so");	/* for backward compatibility */
+}

Property changes on: ruby_1_8/enumerator.c
___________________________________________________________________
Name: svn:eol-style
   + LF
Name: svn:keywords
   + Author Date Id Revision

Index: ruby_1_8/inits.c
===================================================================
--- ruby_1_8/inits.c	(revision 15933)
+++ ruby_1_8/inits.c	(revision 15934)
@@ -18,6 +18,7 @@
 void Init_Comparable _((void));
 void Init_Dir _((void));
 void Init_Enumerable _((void));
+void Init_Enumerator _((void));
 void Init_Exception _((void));
 void Init_syserr _((void));
 void Init_eval _((void));
@@ -79,6 +80,7 @@
     Init_Binding();
     Init_Math();
     Init_GC();
+    Init_Enumerator();
     Init_marshal();
     Init_version();
 }
Index: ruby_1_8/enum.c
===================================================================
--- ruby_1_8/enum.c	(revision 15933)
+++ ruby_1_8/enum.c	(revision 15934)
@@ -17,7 +17,42 @@
 VALUE rb_mEnumerable;
 static ID id_each, id_eqq, id_cmp;
 
+struct iter_method_arg {
+    VALUE obj;
+    ID mid;
+    int argc;
+    VALUE *argv;
+};
+
+static VALUE
+iterate_method(obj)
+    VALUE obj;
+{
+    struct iter_method_arg *arg;
+
+    arg = (struct iter_method_arg *)obj;
+    return rb_funcall2(arg->obj, arg->mid, arg->argc, arg->argv);
+}
+
 VALUE
+rb_block_call(obj, mid, argc, argv, bl_proc, data2)
+    VALUE obj;
+    ID mid;
+    int argc;
+    VALUE *argv;
+    VALUE (*bl_proc) (ANYARGS);
+    VALUE data2;
+{
+    struct iter_method_arg arg;
+
+    arg.obj = obj;
+    arg.mid = mid;
+    arg.argc = argc;
+    arg.argv = argv;
+    return rb_iterate(iterate_method, (VALUE)&arg, bl_proc, data2);
+}
+
+VALUE
 rb_each(obj)
     VALUE obj;
 {
@@ -813,9 +848,11 @@
 enum_each_with_index(obj)
     VALUE obj;
 {
-    VALUE memo = 0;
+    VALUE memo;
 
-    rb_need_block();
+    RETURN_ENUMERATOR(obj, 0, 0);
+
+    memo = 0;
     rb_iterate(rb_each, obj, each_with_index_i, (VALUE)&memo);
     return obj;
 }
@@ -928,6 +965,7 @@
     rb_define_method(rb_mEnumerable,"member?", enum_member, 1);
     rb_define_method(rb_mEnumerable,"include?", enum_member, 1);
     rb_define_method(rb_mEnumerable,"each_with_index", enum_each_with_index, 0);
+    rb_define_method(rb_mEnumerable,"enum_with_index", enum_each_with_index, 0);
     rb_define_method(rb_mEnumerable, "zip", enum_zip, -1);
 
     id_eqq  = rb_intern("===");
Index: ruby_1_8/ruby.h
===================================================================
--- ruby_1_8/ruby.h	(revision 15933)
+++ ruby_1_8/ruby.h	(revision 15934)
@@ -574,6 +574,8 @@
 void rb_sys_warning __((const char*, ...));	/* reports if `-w' specified */
 void rb_warn __((const char*, ...));		/* reports always */
 
+typedef VALUE rb_block_call_func _((VALUE, VALUE, int, VALUE*));
+
 VALUE rb_each _((VALUE));
 VALUE rb_yield _((VALUE));
 VALUE rb_yield_values __((int n, ...));
@@ -622,6 +624,7 @@
 RUBY_EXTERN VALUE rb_cCont;
 RUBY_EXTERN VALUE rb_cDir;
 RUBY_EXTERN VALUE rb_cData;
+RUBY_EXTERN VALUE rb_cEnumerator;
 RUBY_EXTERN VALUE rb_cFalseClass;
 RUBY_EXTERN VALUE rb_cFile;
 RUBY_EXTERN VALUE rb_cFixnum;
Index: ruby_1_8/common.mk
===================================================================
--- ruby_1_8/common.mk	(revision 15933)
+++ ruby_1_8/common.mk	(revision 15934)
@@ -23,6 +23,7 @@
 		dir.$(OBJEXT) \
 		dln.$(OBJEXT) \
 		enum.$(OBJEXT) \
+		enumerator.$(OBJEXT) \
 		error.$(OBJEXT) \
 		eval.$(OBJEXT) \
 		file.$(OBJEXT) \
@@ -370,6 +371,8 @@
 enum.$(OBJEXT): {$(VPATH)}enum.c {$(VPATH)}ruby.h config.h \
   {$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \
   {$(VPATH)}node.h {$(VPATH)}util.h
+enumerator.$(OBJEXT): {$(VPATH)}enumerator.c {$(VPATH)}ruby.h config.h \
+  {$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h
 error.$(OBJEXT): {$(VPATH)}error.c {$(VPATH)}ruby.h config.h \
   {$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \
   {$(VPATH)}env.h {$(VPATH)}st.h

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]