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/