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:
parent
114e32b357
commit
182822683f
37
enum.c
37
enum.c
@ -322,16 +322,32 @@ enum_count(int argc, VALUE *argv, VALUE obj)
|
|||||||
return imemo_count_value(memo);
|
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
|
static VALUE
|
||||||
find_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, memop))
|
find_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, memop))
|
||||||
{
|
{
|
||||||
ENUM_WANT_SVALUE();
|
ENUM_WANT_SVALUE();
|
||||||
|
|
||||||
if (RTEST(enum_yield(argc, i))) {
|
if (RTEST(enum_yield(argc, i))) {
|
||||||
struct MEMO *memo = MEMO_CAST(memop);
|
found(i, memop);
|
||||||
MEMO_V1_SET(memo, i);
|
|
||||||
memo->u3.cnt = 1;
|
|
||||||
rb_iter_break();
|
|
||||||
}
|
}
|
||||||
return Qnil;
|
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;
|
if_none = rb_check_arity(argc, 0, 1) ? argv[0] : Qnil;
|
||||||
RETURN_ENUMERATOR(obj, argc, argv);
|
RETURN_ENUMERATOR(obj, argc, argv);
|
||||||
memo = MEMO_NEW(Qundef, 0, 0);
|
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) {
|
if (memo->u3.cnt) {
|
||||||
return memo->v1;
|
return memo->v1;
|
||||||
}
|
}
|
||||||
@ -1817,7 +1836,7 @@ enum_all(int argc, VALUE *argv, VALUE obj)
|
|||||||
{
|
{
|
||||||
struct MEMO *memo = MEMO_ENUM_NEW(Qtrue);
|
struct MEMO *memo = MEMO_ENUM_NEW(Qtrue);
|
||||||
WARN_UNUSED_BLOCK(argc);
|
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;
|
return memo->v1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1879,7 +1898,7 @@ enum_any(int argc, VALUE *argv, VALUE obj)
|
|||||||
{
|
{
|
||||||
struct MEMO *memo = MEMO_ENUM_NEW(Qfalse);
|
struct MEMO *memo = MEMO_ENUM_NEW(Qfalse);
|
||||||
WARN_UNUSED_BLOCK(argc);
|
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;
|
return memo->v1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2168,7 +2187,7 @@ enum_one(int argc, VALUE *argv, VALUE obj)
|
|||||||
VALUE result;
|
VALUE result;
|
||||||
|
|
||||||
WARN_UNUSED_BLOCK(argc);
|
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;
|
result = memo->v1;
|
||||||
if (UNDEF_P(result)) return Qfalse;
|
if (UNDEF_P(result)) return Qfalse;
|
||||||
return result;
|
return result;
|
||||||
@ -2229,7 +2248,7 @@ enum_none(int argc, VALUE *argv, VALUE obj)
|
|||||||
struct MEMO *memo = MEMO_ENUM_NEW(Qtrue);
|
struct MEMO *memo = MEMO_ENUM_NEW(Qtrue);
|
||||||
|
|
||||||
WARN_UNUSED_BLOCK(argc);
|
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;
|
return memo->v1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user