Skip to content

Commit a70b65e

Browse files
committed
standard: Optimize str_split()
Three optimizations: - If the entire string is returned, we don't need to duplicate it. - Use packed filling logic. - Use fast construction of strings. This is useful when splitting strings on length=1. In that case I get a 6x speedup in the code below. Bench: ```php $x = str_repeat('A', 100); for ($i = 0; $i < 1000000; $i++) str_split($x, 10); ``` On an i7-4790: ``` Benchmark 1: ./sapi/cli/php x.php Time (mean ± σ): 160.1 ms ± 6.4 ms [User: 157.3 ms, System: 1.8 ms] Range (min … max): 155.6 ms … 184.7 ms 18 runs Benchmark 2: ./sapi/cli/php_old x.php Time (mean ± σ): 202.6 ms ± 4.0 ms [User: 199.1 ms, System: 1.9 ms] Range (min … max): 197.4 ms … 209.2 ms 14 runs Summary ./sapi/cli/php x.php ran 1.27 ± 0.06 times faster than ./sapi/cli/php_old x.php ``` The performance gain increases with smaller lengths.
1 parent 376fdd7 commit a70b65e

File tree

1 file changed

+16
-8
lines changed

1 file changed

+16
-8
lines changed

ext/standard/string.c

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6152,23 +6152,31 @@ PHP_FUNCTION(str_split)
61526152
}
61536153

61546154
array_init_size(return_value, 1);
6155-
add_next_index_stringl(return_value, ZSTR_VAL(str), ZSTR_LEN(str));
6155+
GC_TRY_ADDREF(str);
6156+
add_next_index_str(return_value, str);
61566157
return;
61576158
}
61586159

61596160
array_init_size(return_value, (uint32_t)(((ZSTR_LEN(str) - 1) / split_length) + 1));
6161+
zend_hash_real_init_packed(Z_ARRVAL_P(return_value));
61606162

61616163
n_reg_segments = ZSTR_LEN(str) / split_length;
61626164
p = ZSTR_VAL(str);
61636165

6164-
while (n_reg_segments-- > 0) {
6165-
add_next_index_stringl(return_value, p, split_length);
6166-
p += split_length;
6167-
}
6166+
ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
6167+
zval zv;
6168+
while (n_reg_segments-- > 0) {
6169+
ZEND_ASSERT(split_length > 0);
6170+
ZVAL_STRINGL_FAST(&zv, p, split_length);
6171+
ZEND_HASH_FILL_ADD(&zv);
6172+
p += split_length;
6173+
}
61686174

6169-
if (p != (ZSTR_VAL(str) + ZSTR_LEN(str))) {
6170-
add_next_index_stringl(return_value, p, (ZSTR_VAL(str) + ZSTR_LEN(str) - p));
6171-
}
6175+
if (p != (ZSTR_VAL(str) + ZSTR_LEN(str))) {
6176+
ZVAL_STRINGL_FAST(&zv, p, (ZSTR_VAL(str) + ZSTR_LEN(str) - p));
6177+
ZEND_HASH_FILL_ADD(&zv);
6178+
}
6179+
} ZEND_HASH_FILL_END();
61726180
}
61736181
/* }}} */
61746182

0 commit comments

Comments
 (0)