зеркало из https://github.com/github/ruby.git
Move Array#map to Ruby
Improves activerecord by about 1% on the interpreter: ``` before: ruby 3.4.0dev (2024-07-03T18:40:10Z masterf88841b8f3
) [arm64-darwin23] after: ruby 3.4.0dev (2024-07-03T18:41:14Z ruby-map 6c0df4eb32) [arm64-darwin23] ------------ ----------- ---------- ---------- ---------- ------------- ------------ bench before (ms) stddev (%) after (ms) stddev (%) after 1st itr before/after activerecord 235.2 0.8 233.6 0.7 1.01 1.01 ------------ ----------- ---------- ---------- ---------- ------------- ------------ 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. ``` Improves YJIT by about 4%: ``` before: ruby 3.4.0dev (2024-07-03T18:40:10Z masterf88841b8f3
) +YJIT [arm64-darwin23] after: ruby 3.4.0dev (2024-07-03T18:41:14Z ruby-map 6c0df4eb32) +YJIT [arm64-darwin23] ------------ ----------- ---------- ---------- ---------- ------------- ------------ bench before (ms) stddev (%) after (ms) stddev (%) after 1st itr before/after activerecord 142.1 1.2 137.0 0.6 1.00 1.04 ------------ ----------- ---------- ---------- ---------- ------------- ------------ 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:
Родитель
6ac05ddb8a
Коммит
b974c84606
37
array.c
37
array.c
|
@ -3630,41 +3630,6 @@ rb_ary_sort_by_bang(VALUE ary)
|
|||
return ary;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* array.map {|element| ... } -> new_array
|
||||
* array.map -> new_enumerator
|
||||
*
|
||||
* Calls the block, if given, with each element of +self+;
|
||||
* returns a new +Array+ whose elements are the return values from the block:
|
||||
*
|
||||
* a = [:foo, 'bar', 2]
|
||||
* a1 = a.map {|element| element.class }
|
||||
* a1 # => [Symbol, String, Integer]
|
||||
*
|
||||
* Returns a new Enumerator if no block given:
|
||||
* a = [:foo, 'bar', 2]
|
||||
* a1 = a.map
|
||||
* a1 # => #<Enumerator: [:foo, "bar", 2]:map>
|
||||
*
|
||||
*/
|
||||
|
||||
static VALUE
|
||||
rb_ary_collect(VALUE ary)
|
||||
{
|
||||
long i;
|
||||
VALUE collect;
|
||||
|
||||
RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length);
|
||||
collect = rb_ary_new2(RARRAY_LEN(ary));
|
||||
for (i = 0; i < RARRAY_LEN(ary); i++) {
|
||||
rb_ary_push(collect, rb_yield(RARRAY_AREF(ary, i)));
|
||||
}
|
||||
return collect;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* array.map! {|element| ... } -> self
|
||||
|
@ -8668,9 +8633,7 @@ Init_Array(void)
|
|||
rb_define_method(rb_cArray, "sort", rb_ary_sort, 0);
|
||||
rb_define_method(rb_cArray, "sort!", rb_ary_sort_bang, 0);
|
||||
rb_define_method(rb_cArray, "sort_by!", rb_ary_sort_by_bang, 0);
|
||||
rb_define_method(rb_cArray, "collect", rb_ary_collect, 0);
|
||||
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_bang, 0);
|
||||
rb_define_method(rb_cArray, "filter!", rb_ary_select_bang, 0);
|
||||
|
|
34
array.rb
34
array.rb
|
@ -56,6 +56,40 @@ class Array
|
|||
self
|
||||
end
|
||||
|
||||
# call-seq:
|
||||
# array.map {|element| ... } -> new_array
|
||||
# array.map -> new_enumerator
|
||||
#
|
||||
# Calls the block, if given, with each element of +self+;
|
||||
# returns a new +Array+ whose elements are the return values from the block:
|
||||
#
|
||||
# a = [:foo, 'bar', 2]
|
||||
# a1 = a.map {|element| element.class }
|
||||
# a1 # => [Symbol, String, Integer]
|
||||
#
|
||||
# Returns a new Enumerator if no block given:
|
||||
# a = [:foo, 'bar', 2]
|
||||
# a1 = a.map
|
||||
# a1 # => #<Enumerator: [:foo, "bar", 2]:map>
|
||||
def map
|
||||
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 << yield(value)
|
||||
end
|
||||
result
|
||||
end
|
||||
|
||||
alias collect map
|
||||
|
||||
# call-seq:
|
||||
# array.select {|element| ... } -> new_array
|
||||
# array.select -> new_enumerator
|
||||
|
|
|
@ -223,15 +223,15 @@ class TestBacktrace < Test::Unit::TestCase
|
|||
@res = caller_locations(2, 1).inspect
|
||||
end
|
||||
@line = __LINE__ + 1
|
||||
[1].map.map { [1].map.map { foo } }
|
||||
assert_equal("[\"#{__FILE__}:#{@line}:in 'Array#map'\"]", @res)
|
||||
[1].map!.map { [1].map!.map { foo } }
|
||||
assert_equal("[\"#{__FILE__}:#{@line}:in 'Array#map!'\"]", @res)
|
||||
end
|
||||
|
||||
def test_caller_location_path_cfunc_iseq_no_pc
|
||||
def self.foo
|
||||
@res = caller_locations(2, 1)[0].path
|
||||
end
|
||||
[1].map.map { [1].map.map { foo } }
|
||||
[1].map!.map { [1].map!.map { foo } }
|
||||
assert_equal(__FILE__, @res)
|
||||
end
|
||||
|
||||
|
|
|
@ -680,10 +680,8 @@ CODE
|
|||
#
|
||||
[:c_return, 1, "xyzzy", TracePoint, :trace, TracePoint, nil, nil],
|
||||
[:line, 4, 'xyzzy', self.class, method, self, :outer, :nothing],
|
||||
[:c_call, 4, 'xyzzy', Integer, :times, 1, nil, nil],
|
||||
[:line, 4, 'xyzzy', self.class, method, self, nil, :nothing],
|
||||
[:line, 5, 'xyzzy', self.class, method, self, :inner, :nothing],
|
||||
[:c_return, 4, "xyzzy", Integer, :times, 1, nil, nil],
|
||||
[:line, 7, 'xyzzy', self.class, method, self, :outer, :nothing],
|
||||
[:c_call, 7, "xyzzy", Class, :inherited, Object, nil, nil],
|
||||
[:c_return, 7, "xyzzy", Class, :inherited, Object, nil, nil],
|
||||
|
@ -1069,10 +1067,12 @@ CODE
|
|||
# pp events
|
||||
# expected_events =
|
||||
[[:b_call, :test_tracepoint_block, TestSetTraceFunc, TestSetTraceFunc, nil],
|
||||
[:c_call, :map, Array, Array, nil],
|
||||
[:call, :map, Array, Array, nil],
|
||||
[:b_call, :test_tracepoint_block, TestSetTraceFunc, TestSetTraceFunc, nil],
|
||||
[:b_return, :test_tracepoint_block, TestSetTraceFunc, TestSetTraceFunc, 3],
|
||||
[:c_return, :map, Array, Array, [3]],
|
||||
[:c_call, :<<, Array, Array, nil],
|
||||
[:c_return, :<<, Array, Array, [3]],
|
||||
[:return, :map, Array, Array, [3]],
|
||||
[:call, :method_for_test_tracepoint_block, TestSetTraceFunc, TestSetTraceFunc, nil],
|
||||
[:b_call, :test_tracepoint_block, TestSetTraceFunc, TestSetTraceFunc, nil],
|
||||
[:b_return, :test_tracepoint_block, TestSetTraceFunc, TestSetTraceFunc, 4],
|
||||
|
@ -1386,8 +1386,9 @@ CODE
|
|||
}
|
||||
assert_equal([
|
||||
:b_call,
|
||||
:c_call,
|
||||
:call,
|
||||
:b_call,
|
||||
:c_call,
|
||||
:call,
|
||||
:b_call,
|
||||
], events)
|
||||
|
@ -1409,6 +1410,7 @@ CODE
|
|||
assert_equal([
|
||||
:b_return,
|
||||
:c_return,
|
||||
:return,
|
||||
:b_return,
|
||||
:return,
|
||||
:b_return
|
||||
|
|
Загрузка…
Ссылка в новой задаче