Improved Enumerable::Lazy#flat_map

|        |compare-ruby|built-ruby|
|:-------|-----------:|---------:|
|num3    |     96.333k|  160.732k|
|        |           -|     1.67x|
|num10   |     96.615k|  159.150k|
|        |           -|     1.65x|
|ary2    |    103.836k|  172.787k|
|        |           -|     1.66x|
|ary10   |    109.249k|  177.252k|
|        |           -|     1.62x|
|ary20   |    106.628k|  177.371k|
|        |           -|     1.66x|
|ary50   |    107.135k|  162.282k|
|        |           -|     1.51x|
|ary100  |    106.513k|  177.626k|
|        |           -|     1.67x|
This commit is contained in:
Nobuyoshi Nakada 2020-07-22 00:58:48 +09:00
Родитель 89a86788e6
Коммит 6b3cff12f6
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 7CD2805BFA3770C6
3 изменённых файлов: 62 добавлений и 44 удалений

Просмотреть файл

@ -0,0 +1,16 @@
prelude: |
num = (1..).lazy.take(100)
ary2 = [[1,2]].cycle.lazy.take(10)
ary10 = [[*1..10]].cycle.lazy.take(10)
ary20 = [[*1..20]].cycle.lazy.take(10)
ary50 = [[*1..50]].cycle.lazy.take(10)
ary100 = [[*1..100]].cycle.lazy.take(10)
benchmark:
num3: num.flat_map {|x| x}.take(3).to_a
num10: num.flat_map {|x| x}.take(3).to_a
ary2: ary2.flat_map {|x| x}.take(3).to_a
ary10: ary10.flat_map {|x| x}.take(3).to_a
ary20: ary20.flat_map {|x| x}.take(3).to_a
ary50: ary50.flat_map {|x| x}.take(3).to_a
ary100: ary100.flat_map {|x| x}.take(3).to_a

Просмотреть файл

@ -1605,6 +1605,7 @@ lazy_init_block_i(RB_BLOCK_CALL_FUNC_ARGLIST(val, m))
#define LAZY_MEMO_BREAK_P(memo) ((memo)->memo_flags & LAZY_MEMO_BREAK)
#define LAZY_MEMO_PACKED_P(memo) ((memo)->memo_flags & LAZY_MEMO_PACKED)
#define LAZY_MEMO_SET_BREAK(memo) ((memo)->memo_flags |= LAZY_MEMO_BREAK)
#define LAZY_MEMO_RESET_BREAK(memo) ((memo)->memo_flags &= ~LAZY_MEMO_BREAK)
#define LAZY_MEMO_SET_VALUE(memo, value) MEMO_V2_SET(memo, value)
#define LAZY_MEMO_SET_PACKED(memo) ((memo)->memo_flags |= LAZY_MEMO_PACKED)
#define LAZY_MEMO_RESET_PACKED(memo) ((memo)->memo_flags &= ~LAZY_MEMO_PACKED)
@ -2058,57 +2059,56 @@ lazy_map(VALUE obj)
return lazy_add_method(obj, 0, 0, Qnil, Qnil, &lazy_map_funcs);
}
static VALUE
lazy_flat_map_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, yielder))
{
VALUE arg = rb_enum_values_pack(argc, argv);
return rb_funcallv(yielder, idLTLT, 1, &arg);
}
struct flat_map_i_arg {
struct MEMO *result;
long index;
};
static VALUE
lazy_flat_map_each(VALUE obj, VALUE yielder)
lazy_flat_map_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, y))
{
rb_block_call(obj, id_each, 0, 0, lazy_flat_map_i, yielder);
return Qnil;
struct flat_map_i_arg *arg = (struct flat_map_i_arg *)y;
return lazy_yielder_yield(arg->result, arg->index, argc, argv);
}
static VALUE
lazy_flat_map_to_ary(VALUE obj, VALUE yielder)
static struct MEMO *
lazy_flat_map_proc(VALUE proc_entry, struct MEMO *result, VALUE memos, long memo_index)
{
VALUE ary = rb_check_array_type(obj);
if (NIL_P(ary)) {
rb_funcall(yielder, idLTLT, 1, obj);
VALUE value = lazyenum_yield_values(proc_entry, result);
VALUE ary = 0;
const long proc_index = memo_index + 1;
int break_p = LAZY_MEMO_BREAK_P(result);
if (RB_TYPE_P(value, T_ARRAY)) {
ary = value;
}
else {
long i;
for (i = 0; i < RARRAY_LEN(ary); i++) {
rb_funcall(yielder, idLTLT, 1, RARRAY_AREF(ary, i));
}
else if (rb_respond_to(value, id_force) && rb_respond_to(value, id_each)) {
struct flat_map_i_arg arg = {.result = result, .index = proc_index};
LAZY_MEMO_RESET_BREAK(result);
rb_block_call(value, id_each, 0, 0, lazy_flat_map_i, (VALUE)&arg);
if (break_p) LAZY_MEMO_SET_BREAK(result);
return 0;
}
return Qnil;
if (ary || !NIL_P(ary = rb_check_array_type(value))) {
long i;
LAZY_MEMO_RESET_BREAK(result);
for (i = 0; i + 1 < RARRAY_LEN(ary); i++) {
lazy_yielder_yield(result, proc_index, 1, &RARRAY_AREF(ary, i));
}
if (break_p) LAZY_MEMO_SET_BREAK(result);
if (i >= RARRAY_LEN(ary)) return 0;
value = RARRAY_AREF(ary, i);
}
LAZY_MEMO_SET_VALUE(result, value);
LAZY_MEMO_RESET_PACKED(result);
return result;
}
static VALUE
lazy_flat_map_proc(RB_BLOCK_CALL_FUNC_ARGLIST(val, m))
{
VALUE result = rb_yield_values2(argc - 1, &argv[1]);
if (RB_TYPE_P(result, T_ARRAY)) {
long i;
for (i = 0; i < RARRAY_LEN(result); i++) {
rb_funcall(argv[0], idLTLT, 1, RARRAY_AREF(result, i));
}
}
else {
if (rb_respond_to(result, id_force) && rb_respond_to(result, id_each)) {
lazy_flat_map_each(result, argv[0]);
}
else {
lazy_flat_map_to_ary(result, argv[0]);
}
}
return Qnil;
}
static const lazyenum_funcs lazy_flat_map_funcs = {
lazy_flat_map_proc, 0,
};
/*
* call-seq:
@ -2140,9 +2140,7 @@ lazy_flat_map(VALUE obj)
rb_raise(rb_eArgError, "tried to call lazy flat_map without a block");
}
return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
lazy_flat_map_proc, 0),
Qnil, 0);
return lazy_add_method(obj, 0, 0, Qnil, Qnil, &lazy_flat_map_funcs);
}
static struct MEMO *

Просмотреть файл

@ -160,6 +160,10 @@ class TestLazyEnumerator < Test::Unit::TestCase
assert_equal([{?a=>97}, {?b=>98}, {?c=>99}], [?a, ?b, ?c].lazy.flat_map {|x| {x=>x.ord}}.force)
end
def test_flat_map_take
assert_equal([1,2]*3, [[1,2]].cycle.lazy.take(3).flat_map {|x| x}.to_a)
end
def test_reject
a = Step.new(1..6)
assert_equal(4, a.reject {|x| x < 4}.first)