This speeds up the mail benchmark by about 7% on the interpreter:

```
before: ruby 3.4.0dev (2024-07-03T17:01:41Z master f4b313f733) [arm64-darwin23]
after: ruby 3.4.0dev (2024-07-03T17:45:50Z ruby-select de282cacd5) [arm64-darwin23]

-----  -----------  ----------  ----------  ----------  -------------  ------------
bench  before (ms)  stddev (%)  after (ms)  stddev (%)  after 1st itr  before/after
mail   72.9         0.8         68.2        1.0         1.02           1.07
-----  -----------  ----------  ----------  ----------  -------------  ------------
Legend:
- after 1st itr: ratio of before/after time for the first benchmarking iteration.
- before/after: ratio of before/after time. Higher is better for after. Above 1 represents a speedup.
```

YJIT is about 13% faster:

```
before: ruby 3.4.0dev (2024-07-03T17:01:41Z master f4b313f733) +YJIT [arm64-darwin23]
after: ruby 3.4.0dev (2024-07-03T17:45:50Z ruby-select de282cacd5) +YJIT [arm64-darwin23]

-----  -----------  ----------  ----------  ----------  -------------  ------------
bench  before (ms)  stddev (%)  after (ms)  stddev (%)  after 1st itr  before/after
mail   51.0         0.8         45.2        0.6         1.00           1.13
-----  -----------  ----------  ----------  ----------  -------------  ------------
Legend:
- after 1st itr: ratio of before/after time for the first benchmarking iteration.
- before/after: ratio of before/after time. Higher is better for after. Above 1 represents a speedup.
```
This commit is contained in:
Aaron Patterson 2024-07-03 09:45:29 -07:00 коммит произвёл Aaron Patterson
Родитель 7fe5f0a1d0
Коммит 4c9134d2b2
2 изменённых файлов: 41 добавлений и 38 удалений

44
array.c
Просмотреть файл

@ -3807,42 +3807,6 @@ rb_ary_values_at(int argc, VALUE *argv, VALUE ary)
}
/*
* call-seq:
* array.select {|element| ... } -> new_array
* array.select -> new_enumerator
*
* Calls the block, if given, with each element of +self+;
* returns a new +Array+ containing those elements of +self+
* for which the block returns a truthy value:
*
* a = [:foo, 'bar', 2, :bam]
* a1 = a.select {|element| element.to_s.start_with?('b') }
* a1 # => ["bar", :bam]
*
* Returns a new Enumerator if no block given:
*
* a = [:foo, 'bar', 2, :bam]
* a.select # => #<Enumerator: [:foo, "bar", 2, :bam]:select>
*
*/
static VALUE
rb_ary_select(VALUE ary)
{
VALUE result;
long i;
RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length);
result = rb_ary_new2(RARRAY_LEN(ary));
for (i = 0; i < RARRAY_LEN(ary); i++) {
if (RTEST(rb_yield(RARRAY_AREF(ary, i)))) {
rb_ary_push(result, rb_ary_elt(ary, i));
}
}
return result;
}
struct select_bang_arg {
VALUE ary;
long len[2];
@ -6696,6 +6660,12 @@ ary_sample(rb_execution_context_t *ec, VALUE ary, VALUE randgen, VALUE nv, VALUE
return result;
}
static VALUE
ary_sized_alloc(rb_execution_context_t *ec, VALUE self)
{
return rb_ary_new2(RARRAY_LEN(self));
}
static VALUE
ary_sample0(rb_execution_context_t *ec, VALUE ary)
{
@ -8702,9 +8672,7 @@ Init_Array(void)
rb_define_method(rb_cArray, "collect!", rb_ary_collect_bang, 0);
rb_define_method(rb_cArray, "map", rb_ary_collect, 0);
rb_define_method(rb_cArray, "map!", rb_ary_collect_bang, 0);
rb_define_method(rb_cArray, "select", rb_ary_select, 0);
rb_define_method(rb_cArray, "select!", rb_ary_select_bang, 0);
rb_define_method(rb_cArray, "filter", rb_ary_select, 0);
rb_define_method(rb_cArray, "filter!", rb_ary_select_bang, 0);
rb_define_method(rb_cArray, "keep_if", rb_ary_keep_if, 0);
rb_define_method(rb_cArray, "values_at", rb_ary_values_at, -1);

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

@ -56,6 +56,41 @@ class Array
self
end
# call-seq:
# array.select {|element| ... } -> new_array
# array.select -> new_enumerator
#
# Calls the block, if given, with each element of +self+;
# returns a new +Array+ containing those elements of +self+
# for which the block returns a truthy value:
#
# a = [:foo, 'bar', 2, :bam]
# a1 = a.select {|element| element.to_s.start_with?('b') }
# a1 # => ["bar", :bam]
#
# Returns a new Enumerator if no block given:
#
# a = [:foo, 'bar', 2, :bam]
# a.select # => #<Enumerator: [:foo, "bar", 2, :bam]:select>
def select
Primitive.attr! :inline_block
Primitive.attr! :use_block
unless defined?(yield)
return Primitive.cexpr! 'SIZED_ENUMERATOR(self, 0, 0, ary_enum_length)'
end
_i = 0
value = nil
result = Primitive.ary_sized_alloc
while Primitive.cexpr!(%q{ ary_fetch_next(self, LOCAL_PTR(_i), LOCAL_PTR(value)) })
result << value if yield value
end
result
end
alias filter select
# call-seq:
# array.shuffle!(random: Random) -> array
#