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

ruby-changes:22902

From: nobu <ko1@a...>
Date: Fri, 9 Mar 2012 00:30:47 +0900 (JST)
Subject: [ruby-changes:22902] nobu:r34951 (trunk): * enumerator.c: add Enumerable#lazy. based on the patch by

nobu	2012-03-09 00:30:28 +0900 (Fri, 09 Mar 2012)

  New Revision: 34951

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=34951

  Log:
    * enumerator.c: add Enumerable#lazy. based on the patch by
      Innokenty Mikhailov at <https://github.com/ruby/ruby/pull/101>
      [ruby-core:37164] [Feature #4890]

  Modified files:
    trunk/ChangeLog
    trunk/NEWS
    trunk/enumerator.c

Index: ChangeLog
===================================================================
--- ChangeLog	(revision 34950)
+++ ChangeLog	(revision 34951)
@@ -1,3 +1,9 @@
+Fri Mar  9 00:30:23 2012  Nobuyoshi Nakada  <nobu@r...>
+
+	* enumerator.c: add Enumerable#lazy. based on the patch by
+	  Innokenty Mikhailov at <https://github.com/ruby/ruby/pull/101>
+	  [ruby-core:37164] [Feature #4890]
+
 Fri Mar  9 00:25:59 2012  Nobuyoshi Nakada  <nobu@r...>
 
 	* enumerator.c (enumerator_each, generator_each): pass arguments to
Index: enumerator.c
===================================================================
--- enumerator.c	(revision 34950)
+++ enumerator.c	(revision 34951)
@@ -102,7 +102,8 @@
  *
  */
 VALUE rb_cEnumerator;
-static ID id_rewind, id_each;
+VALUE rb_cLazy;
+static ID id_rewind, id_each, id_new, id_initialize, id_yield, id_call;
 static VALUE sym_each;
 
 VALUE rb_eStopIteration;
@@ -1200,7 +1201,160 @@
  *   end
  *
  */
+
+/* Lazy Enumerator methods */
 static VALUE
+lazy_init_iterator(VALUE val, VALUE m, int argc, VALUE *argv)
+{
+    VALUE args[2];
+    args[0] = m;
+    args[1] = val;
+    return rb_yield_values2(2, args);
+}
+
+static VALUE
+lazy_init_yielder(VALUE val, VALUE m, int argc, VALUE *argv)
+{
+    return rb_funcall2(m, id_yield, 1, &val);
+}
+
+static VALUE
+lazy_init_block_i(VALUE val, VALUE m, int argc, VALUE *argv)
+{
+    return rb_block_call(m, id_each, argc-1, argv+1, lazy_init_iterator, val);
+}
+
+static VALUE
+lazy_init_block(VALUE val, VALUE m, int argc, VALUE *argv)
+{
+    return rb_block_call(m, id_each, argc-1, argv+1, lazy_init_yielder, val);
+}
+
+static VALUE
+lazy_initialize(int argc, VALUE *argv, VALUE obj)
+{
+    VALUE generator, arg;
+
+    if (argc < 1) rb_raise(rb_eArgError, "wrong number of arguments(%d for 1+)", argc);
+    --argc;
+    arg = *argv++;
+    generator = generator_allocate(rb_cGenerator);
+    rb_block_call(generator, id_initialize, 0, 0,
+		  (rb_block_given_p() ? lazy_init_block_i: lazy_init_block),
+		  arg);
+    enumerator_init(obj, generator, sym_each, argc, argv);
+
+    return obj;
+}
+
+/*
+ * call-seq:
+ *   e.lazy -> lazy_enumerator
+ */
+static VALUE
+enumerable_lazy(int argc, VALUE *argv, VALUE obj)
+{
+    if (argc > 0) {
+	VALUE ret, buff, *args = ALLOCV_N(VALUE, buff, argc + 1);
+	args[0] = obj;
+	MEMCPY(args + 1, argv, VALUE, argc);
+	ret = rb_class_new_instance(argc + 1, args, rb_cLazy);
+	ALLOCV_END(buff);
+	return ret;
+    }
+    else {
+	return rb_class_new_instance(1, &obj, rb_cLazy);
+    }
+}
+
+static VALUE
+lazy_map_func(VALUE val, VALUE m, int argc, VALUE *argv)
+{
+    VALUE result = rb_yield_values2(argc - 1, &argv[1]);
+
+    return rb_funcall(argv[0], id_yield, 1, result);
+}
+
+static VALUE
+lazy_map(VALUE obj)
+{
+    if (!rb_block_given_p()) {
+	rb_raise(rb_eArgError, "tried to call lazy map without a block");
+    }
+
+    return rb_block_call(rb_cLazy, id_new, 1, &obj, lazy_map_func, 0);
+}
+
+
+static VALUE
+lazy_select_func(VALUE val, VALUE m, int argc, VALUE *argv)
+{
+    VALUE element = argv[1];
+    VALUE result = rb_yield_values2(argc - 1, &argv[1]);
+
+    if (RTEST(result)) {
+	return rb_funcall(argv[0], id_yield, 1, element);
+    }
+    else {
+	return result;
+    }
+}
+
+static VALUE
+lazy_select(VALUE obj)
+{
+    if (!rb_block_given_p()) {
+	rb_raise(rb_eArgError, "tried to call lazy select without a block");
+    }
+
+    return rb_block_call(rb_cLazy, id_new, 1, &obj, lazy_select_func, 0);
+}
+
+static VALUE
+lazy_reject_func(VALUE val, VALUE m, int argc, VALUE *argv)
+{
+    VALUE element = argv[1];
+    VALUE result = rb_yield_values2(argc - 1, &argv[1]);
+
+    if (!RTEST(result)) {
+	return rb_funcall(argv[0], id_yield, 1, element);
+    }
+    else {
+	return result;
+    }
+}
+
+static VALUE
+lazy_reject(VALUE obj)
+{
+    if (!rb_block_given_p()) {
+	rb_raise(rb_eArgError, "tried to call lazy reject without a block");
+    }
+
+    return rb_block_call(rb_cLazy, id_new, 1, &obj, lazy_reject_func, 0);
+}
+
+static VALUE
+lazy_grep_func(VALUE val, VALUE m, int argc, VALUE *argv)
+{
+    VALUE element = argv[1];
+    VALUE result = rb_funcall(m, rb_intern("=~"), 1, element);
+
+    if (RTEST(result)) {
+	return rb_funcall(argv[0], id_yield, 1, element);
+    }
+    else {
+	return result;
+    }
+}
+
+static VALUE
+lazy_grep(VALUE obj, VALUE pattern)
+{
+    return rb_block_call(rb_cLazy, id_new, 1, &obj, lazy_grep_func, pattern);
+}
+
+static VALUE
 stop_result(VALUE self)
 {
     return rb_attr_get(self, rb_intern("result"));
@@ -1231,6 +1385,18 @@
     rb_define_method(rb_cEnumerator, "rewind", enumerator_rewind, 0);
     rb_define_method(rb_cEnumerator, "inspect", enumerator_inspect, 0);
 
+    /* Enumerable::Lazy */
+    rb_cLazy = rb_define_class_under(rb_mEnumerable, "Lazy", rb_cEnumerator);
+    rb_define_method(rb_mEnumerable, "lazy", enumerable_lazy, -1);
+    rb_define_method(rb_cLazy, "initialize", lazy_initialize, -1);
+    rb_define_method(rb_cLazy, "map", lazy_map, 0);
+    rb_define_method(rb_cLazy, "select", lazy_select, 0);
+    rb_define_method(rb_cLazy, "reject", lazy_reject, 0);
+    rb_define_method(rb_cLazy, "grep", lazy_grep, 1);
+
+    rb_define_alias(rb_cLazy, "collect", "map");
+    rb_define_alias(rb_cLazy, "find_all", "select");
+
     rb_eStopIteration = rb_define_class("StopIteration", rb_eIndexError);
     rb_define_method(rb_eStopIteration, "result", stop_result, 0);
 
@@ -1251,6 +1417,10 @@
 
     id_rewind = rb_intern("rewind");
     id_each = rb_intern("each");
+    id_call = rb_intern("call");
+    id_yield = rb_intern("yield");
+    id_new = rb_intern("new");
+    id_initialize = rb_intern("initialize");
     sym_each = ID2SYM(id_each);
 
     rb_provide("enumerator.so");	/* for backward compatibility */
Index: NEWS
===================================================================
--- NEWS	(revision 34950)
+++ NEWS	(revision 34951)
@@ -17,6 +17,10 @@
 
 * builtin classes
 
+  * Enumerable
+    * added method:
+      * added Enumerable#lazy method for lazy enumeration.
+
   * Kernel
     * added method:
       * added Kernel#Hash conversion method like Array() or Float().

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

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