Nakada, Nobuyoshi
7/11/2005 7:42:00 AM
Hi,
At Mon, 11 Jul 2005 14:57:00 +0900,
Yukihiro Matsumoto wrote in [ruby-talk:147731]:
> | $ ./ruby -renumerator -e 'p (1..6).to_enum.with_index{|x,i|p [x,i]}'
> | [1, 0]
> | [2, 1]
> | [3, 2]
> | [4, 3]
> | [5, 4]
> | [6, 5]
> | 1..6
> |
> |A patch based on the current implementation.
>
> Can you commit this patch to the HEAD?
For performance, I'd like to make Enumerator a subclass of
Data instead of Object, in the HEAD.
Index: ext/enumerator/enumerator.c
===================================================================
RCS file: /cvs/ruby/src/ruby/ext/enumerator/enumerator.c,v
retrieving revision 1.5
diff -U2 -p -r1.5 enumerator.c
--- ext/enumerator/enumerator.c 2 Nov 2004 07:38:21 -0000 1.5
+++ ext/enumerator/enumerator.c 11 Jul 2005 07:38:27 -0000
@@ -18,5 +18,77 @@
static VALUE rb_cEnumerator;
static ID sym_each, sym_each_with_index, sym_each_slice, sym_each_cons;
-static ID id_new, id_enum_obj, id_enum_method, id_enum_args;
+#if !defined(HAVE_RB_PROC_CALL) || !defined(HAVE_RB_METHOD_CALL)
+static ID id_call;
+#endif
+
+static VALUE
+proc_call(proc, args)
+ VALUE proc, args;
+{
+#ifdef HAVE_RB_PROC_CALL
+ if (TYPE(args) != T_ARRAY) {
+ args = rb_values_new(1, args);
+ }
+ return rb_proc_call(proc, args);
+#else
+ return rb_funcall2(proc, id_call, 1, &args);
+#endif
+}
+
+static VALUE
+method_call(method, args)
+ VALUE method, args;
+{
+#ifdef HAVE_RB_METHOD_CALL
+ return rb_method_call(RARRAY(args)->len, RARRAY(args)->ptr, method);
+#else
+ return rb_funcall2(method, id_call, RARRAY(args)->len, RARRAY(args)->ptr);
+#endif
+}
+
+struct enumerator {
+ VALUE method;
+ VALUE proc;
+ VALUE args;
+ VALUE (*iter)_((VALUE, struct enumerator *));
+};
+
+static void enumerator_mark _((void *));
+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 _((VALUE, struct enumerator *));
+static VALUE
+enumerator_iter_i(i, e)
+ VALUE i;
+ struct enumerator *e;
+{
+ return rb_yield(proc_call(e->proc, i));
+}
static VALUE
@@ -26,5 +98,7 @@ obj_to_enum(obj, enum_args)
rb_ary_unshift(enum_args, obj);
- return rb_apply(rb_cEnumerator, id_new, enum_args);
+ return rb_class_new_instance(RARRAY(enum_args)->len,
+ RARRAY(enum_args)->ptr,
+ rb_cEnumerator);
}
@@ -33,5 +107,8 @@ enumerator_enum_with_index(obj)
VALUE obj;
{
- return rb_funcall(rb_cEnumerator, id_new, 2, obj, sym_each_with_index);
+ VALUE args[2];
+ args[0] = obj;
+ args[1] = sym_each_with_index;
+ return rb_class_new_instance(2, args, rb_cEnumerator);
}
@@ -39,8 +116,8 @@ static VALUE
each_slice_i(val, memo)
VALUE val;
- NODE *memo;
+ VALUE *memo;
{
- VALUE ary = memo->u1.value;
- long size = memo->u3.cnt;
+ VALUE ary = memo[0];
+ long size = (long)memo[1];
rb_ary_push(ary, val);
@@ -48,5 +125,5 @@ each_slice_i(val, memo)
if (RARRAY(ary)->len == size) {
rb_yield(ary);
- memo->u1.value = rb_ary_new2(size);
+ memo[0] = rb_ary_new2(size);
}
@@ -59,14 +136,14 @@ enum_each_slice(obj, n)
{
long size = NUM2LONG(n);
- NODE *memo;
- VALUE ary;
+ VALUE args[2], ary;
if (size <= 0) rb_raise(rb_eArgError, "invalid slice size");
- memo = rb_node_newnode(NODE_MEMO, rb_ary_new2(size), 0, size);
+ args[0] = rb_ary_new2(size);
+ args[1] = (VALUE)size;
- rb_iterate(rb_each, obj, each_slice_i, (VALUE)memo);
+ rb_iterate(rb_each, obj, each_slice_i, (VALUE)args);
- ary = memo->u1.value;
+ ary = args[0];
if (RARRAY(ary)->len > 0) rb_yield(ary);
@@ -78,5 +155,9 @@ enumerator_enum_slice(obj, n)
VALUE obj, n;
{
- return rb_funcall(rb_cEnumerator, id_new, 3, obj, sym_each_slice, n);
+ VALUE args[2];
+ args[0] = obj;
+ args[1] = sym_each_slice;
+ args[2] = n;
+ return rb_class_new_instance(3, args, rb_cEnumerator);
}
@@ -84,8 +165,8 @@ static VALUE
each_cons_i(val, memo)
VALUE val;
- NODE *memo;
+ VALUE *memo;
{
- VALUE ary = memo->u1.value;
- long size = memo->u3.cnt;
+ VALUE ary = memo[0];
+ long size = (long)memo[1];
if (RARRAY(ary)->len == size) {
@@ -104,10 +185,11 @@ enum_each_cons(obj, n)
{
long size = NUM2LONG(n);
- NODE *memo;
+ VALUE args[2];
if (size <= 0) rb_raise(rb_eArgError, "invalid size");
- memo = rb_node_newnode(NODE_MEMO, rb_ary_new2(size), 0, size);
+ args[0] = rb_ary_new2(size);
+ args[1] = (VALUE)size;
- rb_iterate(rb_each, obj, each_cons_i, (VALUE)memo);
+ rb_iterate(rb_each, obj, each_cons_i, (VALUE)args);
return Qnil;
@@ -118,5 +200,19 @@ enumerator_enum_cons(obj, n)
VALUE obj, n;
{
- return rb_funcall(rb_cEnumerator, id_new, 3, obj, sym_each_cons, n);
+ VALUE args[2];
+ args[0] = obj;
+ args[1] = sym_each_cons;
+ args[2] = n;
+ return rb_class_new_instance(3, args, rb_cEnumerator);
+}
+
+static VALUE enumerator_allocate _((VALUE));
+static VALUE
+enumerator_allocate(klass)
+ VALUE klass;
+{
+ struct enumerator *ptr;
+ return Data_Make_Struct(rb_cEnumerator, struct enumerator,
+ enumerator_mark, -1, ptr);
}
@@ -128,4 +224,5 @@ enumerator_initialize(argc, argv, obj)
{
VALUE enum_obj, enum_method, enum_args;
+ struct enumerator *ptr = enumerator_ptr(obj);
rb_scan_args(argc, argv, "11*", &enum_obj, &enum_method, &enum_args);
@@ -134,16 +231,25 @@ enumerator_initialize(argc, argv, obj)
enum_method = sym_each;
- rb_ivar_set(obj, id_enum_obj, enum_obj);
- rb_ivar_set(obj, id_enum_method, enum_method);
- rb_ivar_set(obj, id_enum_args, enum_args);
+ ptr->method = rb_obj_method(enum_obj, enum_method);
+ if (rb_block_given_p()) {
+ ptr->proc = rb_block_proc();
+ ptr->iter = enumerator_iter_i;
+ }
+ else {
+ ptr->iter = (VALUE (*) _((VALUE, struct enumerator *)))rb_yield;
+ }
+ ptr->args = enum_args;
- return Qnil;
+ return obj;
}
+static VALUE enumerator_iter _((VALUE));
static VALUE
enumerator_iter(memo)
- NODE *memo;
+ VALUE memo;
{
- return rb_apply(memo->u1.value, memo->u2.id, memo->u3.value);
+ struct enumerator *e = (struct enumerator *)memo;
+
+ return method_call(e->method, e->args);
}
@@ -152,14 +258,29 @@ enumerator_each(obj)
VALUE obj;
{
- VALUE val;
+ struct enumerator *e = enumerator_ptr(obj);
- obj = (VALUE)rb_node_newnode(NODE_MEMO,
- rb_ivar_get(obj, id_enum_obj),
- rb_to_id(rb_ivar_get(obj, id_enum_method)),
- rb_ivar_get(obj, id_enum_args));
- val = rb_iterate((VALUE (*)_((VALUE)))enumerator_iter, obj, rb_yield, 0);
+ return rb_iterate(enumerator_iter, (VALUE)e, e->iter, (VALUE)e);
+}
+
+static VALUE
+enumerator_with_index_i(val, memo)
+ VALUE val, *memo;
+{
+ val = rb_yield_values(2, val, INT2FIX(*memo));
+ ++*memo;
return val;
}
+static VALUE
+enumerator_with_index(obj)
+ VALUE obj;
+{
+ struct enumerator *e = enumerator_ptr(obj);
+ VALUE memo = 0;
+
+ return rb_iterate(enumerator_iter, (VALUE)e,
+ enumerator_with_index_i, (VALUE)&memo);
+}
+
void
Init_enumerator()
@@ -181,6 +302,8 @@ Init_enumerator()
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, "each", enumerator_each, 0);
+ rb_define_method(rb_cEnumerator, "with_index", enumerator_with_index, 0);
sym_each = ID2SYM(rb_intern("each"));
@@ -189,7 +312,6 @@ Init_enumerator()
sym_each_cons = ID2SYM(rb_intern("each_cons"));
- id_new = rb_intern("new");
- id_enum_obj = rb_intern("enum_obj");
- id_enum_method = rb_intern("enum_method");
- id_enum_args = rb_intern("enum_args");
+#if !defined(HAVE_RB_PROC_CALL) || !defined(HAVE_RB_METHOD_CALL)
+ id_call = rb_intern("call");
+#endif
}
Index: ext/enumerator/extconf.rb
===================================================================
RCS file: /cvs/ruby/src/ruby/ext/enumerator/extconf.rb,v
retrieving revision 1.1
diff -U2 -p -r1.1 extconf.rb
--- ext/enumerator/extconf.rb 1 Nov 2004 05:04:04 -0000 1.1
+++ ext/enumerator/extconf.rb 23 Jun 2005 02:55:54 -0000
@@ -1,2 +1,5 @@
require 'mkmf'
+
+%w"rb_obj_method rb_method_call".all? {|f| have_func(f, "ruby.h")}
+have_func("rb_proc_call", "ruby.h")
create_makefile('enumerator')
--
Nobu Nakada