mirror of
https://github.com/php/php-src.git
synced 2026-03-24 08:12:21 +01:00
standard: Optimize str_split() (#20419)
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.
This commit is contained in:
@@ -128,3 +128,4 @@ PHP 8.6 UPGRADE NOTES
|
||||
. Improved performance of array_unshift().
|
||||
. Improved performance of array_walk().
|
||||
. Improved performance of intval('+0b...', 2) and intval('0b...', 2).
|
||||
. Improved performance of str_split().
|
||||
|
||||
@@ -6152,23 +6152,31 @@ PHP_FUNCTION(str_split)
|
||||
}
|
||||
|
||||
array_init_size(return_value, 1);
|
||||
add_next_index_stringl(return_value, ZSTR_VAL(str), ZSTR_LEN(str));
|
||||
GC_TRY_ADDREF(str);
|
||||
add_next_index_str(return_value, str);
|
||||
return;
|
||||
}
|
||||
|
||||
array_init_size(return_value, (uint32_t)(((ZSTR_LEN(str) - 1) / split_length) + 1));
|
||||
zend_hash_real_init_packed(Z_ARRVAL_P(return_value));
|
||||
|
||||
n_reg_segments = ZSTR_LEN(str) / split_length;
|
||||
p = ZSTR_VAL(str);
|
||||
|
||||
while (n_reg_segments-- > 0) {
|
||||
add_next_index_stringl(return_value, p, split_length);
|
||||
p += split_length;
|
||||
}
|
||||
ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
|
||||
zval zv;
|
||||
while (n_reg_segments-- > 0) {
|
||||
ZEND_ASSERT(split_length > 0);
|
||||
ZVAL_STRINGL_FAST(&zv, p, split_length);
|
||||
ZEND_HASH_FILL_ADD(&zv);
|
||||
p += split_length;
|
||||
}
|
||||
|
||||
if (p != (ZSTR_VAL(str) + ZSTR_LEN(str))) {
|
||||
add_next_index_stringl(return_value, p, (ZSTR_VAL(str) + ZSTR_LEN(str) - p));
|
||||
}
|
||||
if (p != (ZSTR_VAL(str) + ZSTR_LEN(str))) {
|
||||
ZVAL_STRINGL_FAST(&zv, p, (ZSTR_VAL(str) + ZSTR_LEN(str) - p));
|
||||
ZEND_HASH_FILL_ADD(&zv);
|
||||
}
|
||||
} ZEND_HASH_FILL_END();
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
|
||||
Reference in New Issue
Block a user