зеркало из https://github.com/github/ruby.git
Use rb_block_call2 for some Enumerable methods
Enumerable#all?, #any?, #one?, and #none? do not use yielded arguments as an Array. So they can use rb_block_call2 to omit array allocatoin. Enumerable#find does not have to immediately accept yielded arguments as an Array. It can delay array allocation until the predicate block returns truthy. (TODO: Enumerable#count and #find_all seem to be optimizable as well.)
This commit is contained in:
Родитель
114e32b357
Коммит
182822683f
37
enum.c
37
enum.c
|
@ -322,16 +322,32 @@ enum_count(int argc, VALUE *argv, VALUE obj)
|
|||
return imemo_count_value(memo);
|
||||
}
|
||||
|
||||
NORETURN(static void found(VALUE i, VALUE memop));
|
||||
static void
|
||||
found(VALUE i, VALUE memop) {
|
||||
struct MEMO *memo = MEMO_CAST(memop);
|
||||
MEMO_V1_SET(memo, i);
|
||||
memo->u3.cnt = 1;
|
||||
rb_iter_break();
|
||||
}
|
||||
|
||||
static VALUE
|
||||
find_i_fast(RB_BLOCK_CALL_FUNC_ARGLIST(i, memop))
|
||||
{
|
||||
if (RTEST(rb_yield_values2(argc, argv))) {
|
||||
ENUM_WANT_SVALUE();
|
||||
found(i, memop);
|
||||
}
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
find_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, memop))
|
||||
{
|
||||
ENUM_WANT_SVALUE();
|
||||
|
||||
if (RTEST(enum_yield(argc, i))) {
|
||||
struct MEMO *memo = MEMO_CAST(memop);
|
||||
MEMO_V1_SET(memo, i);
|
||||
memo->u3.cnt = 1;
|
||||
rb_iter_break();
|
||||
found(i, memop);
|
||||
}
|
||||
return Qnil;
|
||||
}
|
||||
|
@ -366,7 +382,10 @@ enum_find(int argc, VALUE *argv, VALUE obj)
|
|||
if_none = rb_check_arity(argc, 0, 1) ? argv[0] : Qnil;
|
||||
RETURN_ENUMERATOR(obj, argc, argv);
|
||||
memo = MEMO_NEW(Qundef, 0, 0);
|
||||
rb_block_call(obj, id_each, 0, 0, find_i, (VALUE)memo);
|
||||
if (rb_block_pair_yield_optimizable())
|
||||
rb_block_call2(obj, id_each, 0, 0, find_i_fast, (VALUE)memo, RB_BLOCK_NO_USE_PACKED_ARGS);
|
||||
else
|
||||
rb_block_call2(obj, id_each, 0, 0, find_i, (VALUE)memo, RB_BLOCK_NO_USE_PACKED_ARGS);
|
||||
if (memo->u3.cnt) {
|
||||
return memo->v1;
|
||||
}
|
||||
|
@ -1817,7 +1836,7 @@ enum_all(int argc, VALUE *argv, VALUE obj)
|
|||
{
|
||||
struct MEMO *memo = MEMO_ENUM_NEW(Qtrue);
|
||||
WARN_UNUSED_BLOCK(argc);
|
||||
rb_block_call(obj, id_each, 0, 0, ENUMFUNC(all), (VALUE)memo);
|
||||
rb_block_call2(obj, id_each, 0, 0, ENUMFUNC(all), (VALUE)memo, RB_BLOCK_NO_USE_PACKED_ARGS);
|
||||
return memo->v1;
|
||||
}
|
||||
|
||||
|
@ -1879,7 +1898,7 @@ enum_any(int argc, VALUE *argv, VALUE obj)
|
|||
{
|
||||
struct MEMO *memo = MEMO_ENUM_NEW(Qfalse);
|
||||
WARN_UNUSED_BLOCK(argc);
|
||||
rb_block_call(obj, id_each, 0, 0, ENUMFUNC(any), (VALUE)memo);
|
||||
rb_block_call2(obj, id_each, 0, 0, ENUMFUNC(any), (VALUE)memo, RB_BLOCK_NO_USE_PACKED_ARGS);
|
||||
return memo->v1;
|
||||
}
|
||||
|
||||
|
@ -2168,7 +2187,7 @@ enum_one(int argc, VALUE *argv, VALUE obj)
|
|||
VALUE result;
|
||||
|
||||
WARN_UNUSED_BLOCK(argc);
|
||||
rb_block_call(obj, id_each, 0, 0, ENUMFUNC(one), (VALUE)memo);
|
||||
rb_block_call2(obj, id_each, 0, 0, ENUMFUNC(one), (VALUE)memo, RB_BLOCK_NO_USE_PACKED_ARGS);
|
||||
result = memo->v1;
|
||||
if (UNDEF_P(result)) return Qfalse;
|
||||
return result;
|
||||
|
@ -2229,7 +2248,7 @@ enum_none(int argc, VALUE *argv, VALUE obj)
|
|||
struct MEMO *memo = MEMO_ENUM_NEW(Qtrue);
|
||||
|
||||
WARN_UNUSED_BLOCK(argc);
|
||||
rb_block_call(obj, id_each, 0, 0, ENUMFUNC(none), (VALUE)memo);
|
||||
rb_block_call2(obj, id_each, 0, 0, ENUMFUNC(none), (VALUE)memo, RB_BLOCK_NO_USE_PACKED_ARGS);
|
||||
return memo->v1;
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче