зеркало из https://github.com/github/ruby.git
Move Array#select to Ruby
This speeds up the mail benchmark by about 7% on the interpreter: ``` before: ruby 3.4.0dev (2024-07-03T17:01:41Z masterf4b313f733
) [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 masterf4b313f733
) +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:
Родитель
7fe5f0a1d0
Коммит
4c9134d2b2
44
array.c
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);
|
||||
|
|
35
array.rb
35
array.rb
|
@ -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
|
||||
#
|
||||
|
|
Загрузка…
Ссылка в новой задаче