Skip to content

Commit a211abb

Browse files
authored
Cache array length in rb_ary_join (ruby#15362)
When all elements are strings, we never have to recalculate the length of the array because there are no conversion methods that are called, so the length will never change. This speeds up the fast path by ~10%. ```ruby a = ["1"*10, "2"*10, "3"*10, "4"*10, "5"*10] * 10 10_000_000.times do a.join end ``` ``` hyperfine --warmup 1 'ruby ../ruby2/test.rb' './exe/ruby ../ruby2/test.rb' Benchmark 1: ruby ../ruby2/test.rb Time (mean ± σ): 3.779 s ± 0.053 s [User: 3.754 s, System: 0.017 s] Range (min … max): 3.715 s … 3.874 s 10 runs Benchmark 2: ./exe/ruby ../ruby2/test.rb Time (mean ± σ): 3.411 s ± 0.038 s [User: 3.387 s, System: 0.017 s] Range (min … max): 3.360 s … 3.472 s 10 runs Summary ./exe/ruby ../ruby2/test.rb ran 1.11 ± 0.02 times faster than ruby ../ruby2/test.rb ```
1 parent a63147e commit a211abb

File tree

1 file changed

+20
-15
lines changed

1 file changed

+20
-15
lines changed

array.c

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2917,23 +2917,28 @@ rb_ary_join(VALUE ary, VALUE sep)
29172917
StringValue(sep);
29182918
len += RSTRING_LEN(sep) * (RARRAY_LEN(ary) - 1);
29192919
}
2920-
for (i=0; i<RARRAY_LEN(ary); i++) {
2920+
long len_memo = RARRAY_LEN(ary);
2921+
for (i=0; i < len_memo; i++) {
29212922
val = RARRAY_AREF(ary, i);
2922-
tmp = rb_check_string_type(val);
2923-
2924-
if (NIL_P(tmp) || tmp != val) {
2925-
int first;
2926-
long n = RARRAY_LEN(ary);
2927-
if (i > n) i = n;
2928-
result = rb_str_buf_new(len + (n-i)*10);
2929-
rb_enc_associate(result, rb_usascii_encoding());
2930-
i = ary_join_0(ary, sep, i, result);
2931-
first = i == 0;
2932-
ary_join_1(ary, ary, sep, i, result, &first);
2933-
return result;
2923+
if (RB_UNLIKELY(!RB_TYPE_P(val, T_STRING))) {
2924+
tmp = rb_check_string_type(val);
2925+
if (NIL_P(tmp) || tmp != val) {
2926+
int first;
2927+
long n = RARRAY_LEN(ary);
2928+
if (i > n) i = n;
2929+
result = rb_str_buf_new(len + (n-i)*10);
2930+
rb_enc_associate(result, rb_usascii_encoding());
2931+
i = ary_join_0(ary, sep, i, result);
2932+
first = i == 0;
2933+
ary_join_1(ary, ary, sep, i, result, &first);
2934+
return result;
2935+
}
2936+
len += RSTRING_LEN(tmp);
2937+
len_memo = RARRAY_LEN(ary);
2938+
}
2939+
else {
2940+
len += RSTRING_LEN(val);
29342941
}
2935-
2936-
len += RSTRING_LEN(tmp);
29372942
}
29382943

29392944
result = rb_str_new(0, len);

0 commit comments

Comments
 (0)