1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

* 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.

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@35019 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
shugo 2012-03-14 13:04:18 +00:00
parent 0b35e9e5dd
commit c8860b504e
3 changed files with 130 additions and 9 deletions

View file

@ -1,3 +1,17 @@
Wed Mar 14 22:01:06 2012 Shugo Maeda <shugo@ruby-lang.org>
* 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@ruby-lang.org>
* enumerator.c (lazy_take): add Enumerable::Lazy#take.

View file

@ -1161,10 +1161,12 @@ generator_each(int argc, VALUE *argv, VALUE obj)
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 @@ lazy_take_func(VALUE val, VALUE args, int argc, VALUE *argv)
{
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;
@ -1429,6 +1429,73 @@ lazy_take(VALUE obj, VALUE n)
(VALUE) memo);
}
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)
{
@ -1524,11 +1591,15 @@ InitVM_Enumerator(void)
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);

View file

@ -145,10 +145,46 @@ class TestLazyEnumerator < Test::Unit::TestCase
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