Hi,
At Mon, 17 May 2004 20:34:05 +0900,
Kristof Bastiaensen wrote in [ruby-talk:100500]:
5.enum_filter
times){ |i| i[0] == 0 }.collect
=> [2, 4]
=> [0, 2, 4]
Isn't it?
(2)* Enumerable::Enumerator takes a optional block
powers = 4.enum_for
times){ |i| i * i }
powers.collect
=> [0, 1, 4, 9]
I tried the implementation of these two experimentally. But I
feel enum_filter is overdoing after all.
This patch provides block for Enumerable#enum_for and
Enumerable#enum_if instead.
$ ./ruby -renumerator -e 'p 5.enum_for
times){|i| i*i}.to_a'
[0, 1, 4, 9, 16]
$ ./ruby -renumerator -e 'p 5.enum_for
times).enum_if{|i| i[0] == 0}.to_a'
[0, 2, 4]
Just my 2 yens.
Index: eval.c
===================================================================
RCS file: /cvs/ruby/src/ruby/eval.c,v
retrieving revision 1.663
diff -U2 -p -d -r1.663 eval.c
--- eval.c 14 May 2004 16:45:21 -0000 1.663
+++ eval.c 18 May 2004 01:02:30 -0000
@@ -141,5 +141,5 @@ static VALUE rb_f_block_given_p _((void)
static VALUE block_pass _((VALUE,NODE*));
static VALUE rb_cMethod;
-static VALUE method_call _((int, VALUE*, VALUE));
+VALUE rb_method_call _((int, VALUE*, VALUE));
static VALUE rb_cUnboundMethod;
static VALUE umethod_bind _((VALUE, VALUE));
@@ -8116,6 +8116,6 @@ proc_invoke(proc, args, self, klass)
*/
-static VALUE
-proc_call(proc, args)
+VALUE
+rb_proc_call(proc, args)
VALUE proc, args; /* OK */
{
@@ -8606,5 +8606,5 @@ method_unbind(obj)
*/
-static VALUE
+VALUE
rb_obj_method(obj, vid)
VALUE obj;
@@ -8686,6 +8686,6 @@ method_clone(self)
*/
-static VALUE
-method_call(argc, argv, method)
+VALUE
+rb_method_call(argc, argv, method)
int argc;
VALUE *argv;
@@ -8981,5 +8981,5 @@ bmcall(args, method)
a = svalue_to_avalue(args);
- return method_call(RARRAY(a)->len, RARRAY(a)->ptr, method);
+ return rb_method_call(RARRAY(a)->len, RARRAY(a)->ptr, method);
}
@@ -9179,7 +9179,7 @@ Init_Proc()
rb_define_method(rb_cProc, "clone", proc_clone, 0);
- rb_define_method(rb_cProc, "call", proc_call, -2);
+ rb_define_method(rb_cProc, "call", rb_proc_call, -2);
rb_define_method(rb_cProc, "arity", proc_arity, 0);
- rb_define_method(rb_cProc, "[]", proc_call, -2);
+ rb_define_method(rb_cProc, "[]", rb_proc_call, -2);
rb_define_method(rb_cProc, "==", proc_eq, 1);
rb_define_method(rb_cProc, "eql?", proc_eq, 1);
@@ -9199,6 +9199,6 @@ Init_Proc()
rb_define_method(rb_cMethod, "hash", method_hash, 0);
rb_define_method(rb_cMethod, "clone", method_clone, 0);
- rb_define_method(rb_cMethod, "call", method_call, -1);
- rb_define_method(rb_cMethod, "[]", method_call, -1);
+ rb_define_method(rb_cMethod, "call", rb_method_call, -1);
+ rb_define_method(rb_cMethod, "[]", rb_method_call, -1);
rb_define_method(rb_cMethod, "arity", method_arity, 0);
rb_define_method(rb_cMethod, "inspect", method_inspect, 0);
Index: ext/enumerator/enumerator.c
===================================================================
RCS file: /cvs/ruby/src/ruby/ext/enumerator/enumerator.c,v
retrieving revision 1.3
diff -U2 -p -d -r1.3 enumerator.c
--- ext/enumerator/enumerator.c 17 Oct 2003 14:09:43 -0000 1.3
+++ ext/enumerator/enumerator.c 19 May 2004 02:40:29 -0000
@@ -14,9 +14,70 @@
#include "ruby.h"
-#include "node.h"
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(ptr)
+ struct enumerator *ptr;
+{
+ 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_PTR(obj);
+ if (!ptr) {
+ rb_raise(rb_eArgError, "uninitialized enumerator");
+ }
+ return ptr;
+}
+
+static VALUE
+enumerator_iter_i(i, e)
+ VALUE i;
+ struct enumerator *e;
+{
+ return rb_yield(proc_call(e->proc, i));
+}
static VALUE
@@ -26,5 +87,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,14 +96,17 @@ 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);
}
static VALUE
-each_slice_i(val, memo)
+each_slice_i(val, args)
VALUE val;
- NODE *memo;
+ VALUE *args;
{
- VALUE ary = memo->u1.value;
- long size = memo->u3.cnt;
+ VALUE ary = args[0];
+ long size = (long)args[1];
rb_ary_push(ary, val);
@@ -48,5 +114,5 @@ each_slice_i(val, memo)
if (RARRAY(ary)->len == size) {
rb_yield(ary);
- memo->u1.value = rb_ary_new2(size);
+ args[0] = rb_ary_new2(size);
}
@@ -59,17 +125,16 @@ 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);
- rb_gc_force_recycle((VALUE)memo);
return Qnil;
}
@@ -79,14 +144,18 @@ 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);
}
static VALUE
-each_cons_i(val, memo)
+each_cons_i(val, args)
VALUE val;
- NODE *memo;
+ VALUE *args;
{
- VALUE ary = memo->u1.value;
- long size = memo->u3.cnt;
+ VALUE ary = args[0];
+ long size = (long)args[1];
long len = RARRAY(ary)->len;
@@ -107,13 +176,12 @@ enum_each_cons(obj, n)
{
long size = NUM2LONG(n);
- NODE *memo;
- VALUE ary;
+ VALUE args[3];
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);
- rb_gc_force_recycle((VALUE)memo);
return Qnil;
}
@@ -123,5 +191,41 @@ 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_select(i, e)
+ VALUE i;
+ struct enumerator *e;
+{
+ if (!RTEST(proc_call(e->proc, i))) return Qnil;
+ return rb_yield(i);
+}
+
+static VALUE
+enumerator_enum_if(obj, enum_args)
+ VALUE obj, enum_args;
+{
+ rb_ary_unshift(enum_args, obj);
+
+ obj = rb_class_new_instance(RARRAY(enum_args)->len,
+ RARRAY(enum_args)->ptr,
+ rb_cEnumerator);
+ ((struct enumerator *)DATA_PTR(obj))->iter = enumerator_select;
+ return obj;
+}
+
+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);
}
@@ -133,4 +237,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);
@@ -139,16 +244,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 (*)())rb_yield;
+ }
+ ptr->args = enum_args;
- return Qnil;
+ return obj;
}
+static VALUE enumerator_iter _((VALUE));
static VALUE
-enumerator_iter(memo)
- NODE *memo;
+enumerator_iter(arg)
+ VALUE arg;
{
- return rb_apply(memo->u1.value, memo->u2.id, memo->u3.value);
+ struct enumerator *e = (struct enumerator *)arg;
+
+ return method_call(e->method, e->args);
}
@@ -157,13 +271,16 @@ 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);
- rb_gc_force_recycle(obj);
- return val;
+ return rb_iterate(enumerator_iter, (VALUE)e, e->iter, (VALUE)e);
+}
+
+static VALUE
+enumerator_call(obj, args)
+ VALUE obj, args;
+{
+ struct enumerator *e = enumerator_ptr(obj);
+
+ return method_call(e->method, rb_ary_concat(e->args, args));
}
@@ -183,10 +300,13 @@ Init_enumerator()
rb_define_method(rb_mEnumerable, "each_cons", enum_each_cons, 1);
rb_define_method(rb_mEnumerable, "enum_cons", enumerator_enum_cons, 1);
+ rb_define_method(rb_mEnumerable, "enum_if", enumerator_enum_if, -2);
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, "each", enumerator_each, 0);
+ rb_define_method(rb_cEnumerator, "call", enumerator_call, -2);
sym_each = ID2SYM(rb_intern("each"));
@@ -195,7 +315,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: ext/enumerator/extconf.rb
diff -N ext/enumerator/extconf.rb
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ ext/enumerator/extconf.rb 18 May 2004 11:50:10 -0000
@@ -0,0 +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")