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

ruby-changes:22970

From: shugo <ko1@a...>
Date: Wed, 14 Mar 2012 22:04:31 +0900 (JST)
Subject: [ruby-changes:22970] shugo:r35019 (trunk): * enumerator.c (lazy_init_iterator): break when Qundef is returned

shugo	2012-03-14 22:04:18 +0900 (Wed, 14 Mar 2012)

  New Revision: 35019

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

  Log:
    * enumerator.c (lazy_init_iterator): break when Qundef is returned
      to make obj.drop(3).take(2) work properly.
    
    * enumerator.c (lazy_take_while): add Enumerable::Lazy#take_while.
    
    * enumerator.c (lazy_drop): add Enumerable::Lazy#drop.
    
    * enumerator.c (lazy_drop_while): add Enumerable::Lazy#drop_while.
    
    * enumerator.c (InitVM_Enumerator): add Enumerable::Lazy#force as an
      alias of to_a.

  Modified files:
    trunk/ChangeLog
    trunk/enumerator.c
    trunk/test/ruby/test_lazy_enumerator.rb

Index: ChangeLog
===================================================================
--- ChangeLog	(revision 35018)
+++ ChangeLog	(revision 35019)
@@ -1,3 +1,17 @@
+Wed Mar 14 22:01:06 2012  Shugo Maeda  <shugo@r...>
+
+	* enumerator.c (lazy_init_iterator): break when Qundef is returned
+	  to make obj.drop(3).take(2) work properly.
+
+	* enumerator.c (lazy_take_while): add Enumerable::Lazy#take_while.
+
+	* enumerator.c (lazy_drop): add Enumerable::Lazy#drop.
+
+	* enumerator.c (lazy_drop_while): add Enumerable::Lazy#drop_while.
+
+	* enumerator.c (InitVM_Enumerator): add Enumerable::Lazy#force as an
+	  alias of to_a.
+
 Wed Mar 14 19:28:40 2012  Shugo Maeda  <shugo@r...>
 
 	* enumerator.c (lazy_take): add Enumerable::Lazy#take.
Index: enumerator.c
===================================================================
--- enumerator.c	(revision 35018)
+++ enumerator.c	(revision 35019)
@@ -1161,10 +1161,12 @@
 static VALUE
 lazy_init_iterator(VALUE val, VALUE m, int argc, VALUE *argv)
 {
-    VALUE args[2];
+    VALUE args[2], result;
     args[0] = m;
     args[1] = val;
-    return rb_yield_values2(2, args);
+    result = rb_yield_values2(2, args);
+    if (result == Qundef) rb_iter_break();
+    return result;
 }
 
 static VALUE
@@ -1407,9 +1409,7 @@
 {
     NODE *memo = RNODE(args);
 
-    if (memo->u3.cnt == 0) {
-	return Qundef;
-    }
+    if (memo->u3.cnt == 0) return Qundef;
     rb_funcall2(argv[0], id_yield, argc - 1, argv + 1);
     memo->u3.cnt--;
     return Qnil;
@@ -1430,6 +1430,73 @@
 }
 
 static VALUE
+lazy_take_while_func(VALUE val, VALUE args, int argc, VALUE *argv)
+{
+    VALUE result = rb_yield_values2(argc - 1, &argv[1]);
+    if (!RTEST(result)) return Qundef;
+    rb_funcall2(argv[0], id_yield, argc - 1, argv + 1);
+    return Qnil;
+}
+
+static VALUE
+lazy_take_while(VALUE obj)
+{
+    return rb_block_call(rb_cLazy, id_new, 1, &obj, lazy_take_while_func, 0);
+}
+
+static VALUE
+lazy_drop_func(VALUE val, VALUE args, int argc, VALUE *argv)
+{
+    NODE *memo = RNODE(args);
+
+    if (memo->u3.cnt == 0) {
+	rb_funcall2(argv[0], id_yield, argc - 1, argv + 1);
+    }
+    else {
+	memo->u3.cnt--;
+    }
+    return Qnil;
+}
+
+static VALUE
+lazy_drop(VALUE obj, VALUE n)
+{
+    NODE *memo;
+    long len = NUM2LONG(n);
+
+    if (len < 0) {
+	rb_raise(rb_eArgError, "attempt to drop negative size");
+    }
+    memo = NEW_MEMO(0, 0, len);
+    return rb_block_call(rb_cLazy, id_new, 1, &obj, lazy_drop_func,
+			 (VALUE) memo);
+}
+
+static VALUE
+lazy_drop_while_func(VALUE val, VALUE args, int argc, VALUE *argv)
+{
+    NODE *memo = RNODE(args);
+
+    if (!memo->u3.state && !RTEST(rb_yield_values2(argc - 1, &argv[1]))) {
+	memo->u3.state = TRUE;
+    }
+    if (memo->u3.state) {
+	rb_funcall2(argv[0], id_yield, argc - 1, argv + 1);
+    }
+    return Qnil;
+}
+
+static VALUE
+lazy_drop_while(VALUE obj)
+{
+    NODE *memo;
+
+    memo = NEW_MEMO(0, 0, FALSE);
+    return rb_block_call(rb_cLazy, id_new, 1, &obj, lazy_drop_while_func,
+			 (VALUE) memo);
+}
+
+static VALUE
 lazy_lazy(VALUE obj)
 {
     return obj;
@@ -1524,11 +1591,15 @@
     rb_define_method(rb_cLazy, "grep", lazy_grep, 1);
     rb_define_method(rb_cLazy, "zip", lazy_zip, -1);
     rb_define_method(rb_cLazy, "take", lazy_take, 1);
+    rb_define_method(rb_cLazy, "take_while", lazy_take_while, 0);
+    rb_define_method(rb_cLazy, "drop", lazy_drop, 1);
+    rb_define_method(rb_cLazy, "drop_while", lazy_drop_while, 0);
     rb_define_method(rb_cLazy, "lazy", lazy_lazy, 0);
 
     rb_define_alias(rb_cLazy, "collect", "map");
     rb_define_alias(rb_cLazy, "collect_concat", "flat_map");
     rb_define_alias(rb_cLazy, "find_all", "select");
+    rb_define_alias(rb_cLazy, "force", "to_a");
 
     rb_eStopIteration = rb_define_class("StopIteration", rb_eIndexError);
     rb_define_method(rb_eStopIteration, "result", stop_result, 0);
Index: test/ruby/test_lazy_enumerator.rb
===================================================================
--- test/ruby/test_lazy_enumerator.rb	(revision 35018)
+++ test/ruby/test_lazy_enumerator.rb	(revision 35019)
@@ -145,10 +145,46 @@
   end
 
   def test_take
-    a = Step.new(1..3)
-    assert_equal(1, a.take(2).first)
-    assert_equal(2, a.current)
-    assert_equal(1, a.lazy.take(2).first)
+    a = Step.new(1..10)
+    assert_equal(1, a.take(5).first)
+    assert_equal(5, a.current)
+    assert_equal(1, a.lazy.take(5).first)
     assert_equal(1, a.current)
+    assert_equal((1..5).to_a, a.lazy.take(5).to_a)
   end
+
+  def test_take_while
+    a = Step.new(1..10)
+    assert_equal(1, a.take_while {|i| i < 5}.first)
+    assert_equal(5, a.current)
+    assert_equal(1, a.lazy.take_while {|i| i < 5}.first)
+    assert_equal(1, a.current)
+    assert_equal((1..4).to_a, a.lazy.take_while {|i| i < 5}.to_a)
+  end
+
+  def test_drop
+    a = Step.new(1..10)
+    assert_equal(6, a.drop(5).first)
+    assert_equal(10, a.current)
+    assert_equal(6, a.lazy.drop(5).first)
+    assert_equal(6, a.current)
+    assert_equal((6..10).to_a, a.lazy.drop(5).to_a)
+  end
+
+  def test_drop_while
+    a = Step.new(1..10)
+    assert_equal(5, a.drop_while {|i| i < 5}.first)
+    assert_equal(10, a.current)
+    assert_equal(5, a.lazy.drop_while {|i| i < 5}.first)
+    assert_equal(5, a.current)
+    assert_equal((5..10).to_a, a.lazy.drop_while {|i| i < 5}.to_a)
+  end
+
+  def test_drop_and_take
+    assert_equal([4, 5], (1..Float::INFINITY).lazy.drop(3).take(2).to_a)
+  end
+
+  def test_force
+    assert_equal([1, 2, 3], (1..Float::INFINITY).lazy.take(3).force)
+  end
 end

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

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