1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 00:02:20 +01:00

array_unshift: Add fast optimized case for packed arrays (#20353)

Packed arrays are likely common in this case, as with array_shift which
already has a similar optimization.

For the following benchmark:
```php
<?php

for ($i = 0; $i < 10000000; $i++) {
    $a = [0, 1, 2, 3, 4, 5];
    array_unshift($a, -3, -2, -1);
}
```

On an i7-4790:
```
Benchmark 1: ./sapi/cli/php x.php
  Time (mean ± σ):     753.8 ms ±  23.8 ms    [User: 749.8 ms, System: 2.1 ms]
  Range (min … max):   734.3 ms … 818.6 ms    10 runs

Benchmark 2: ./sapi/cli/php_old x.php
  Time (mean ± σ):     972.5 ms ±   5.0 ms    [User: 968.8 ms, System: 1.4 ms]
  Range (min … max):   967.8 ms … 984.3 ms    10 runs

Summary
  ./sapi/cli/php x.php  ran
    1.29 ± 0.04 times faster than ./sapi/cli/php_old x.php
```
This commit is contained in:
Niels Dossche
2025-11-06 18:49:23 +01:00
committed by GitHub
parent 4a98fa19ac
commit db8c331d07
2 changed files with 27 additions and 10 deletions

View File

@@ -125,4 +125,5 @@ PHP 8.6 UPGRADE NOTES
- Standard:
. Improved performance of array_fill_keys().
. Improved performance of array_unshift().
. Improved performance of array_walk().

View File

@@ -3743,18 +3743,34 @@ PHP_FUNCTION(array_unshift)
ZEND_PARSE_PARAMETERS_END();
zend_hash_init(&new_hash, zend_hash_num_elements(Z_ARRVAL_P(stack)) + argc, NULL, ZVAL_PTR_DTOR, 0);
for (uint32_t i = 0; i < argc; i++) {
Z_TRY_ADDREF(args[i]);
zend_hash_next_index_insert_new(&new_hash, &args[i]);
}
ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(stack), key, value) {
if (key) {
zend_hash_add_new(&new_hash, key, value);
} else {
zend_hash_next_index_insert_new(&new_hash, value);
if (HT_IS_PACKED(Z_ARRVAL_P(stack))) {
zend_hash_real_init_packed(&new_hash);
ZEND_HASH_FILL_PACKED(&new_hash) {
for (uint32_t i = 0; i < argc; i++) {
Z_TRY_ADDREF(args[i]);
ZEND_HASH_FILL_ADD(&args[i]);
}
ZEND_HASH_PACKED_FOREACH_VAL(Z_ARRVAL_P(stack), value) {
ZEND_HASH_FILL_ADD(value);
} ZEND_HASH_FOREACH_END();
} ZEND_HASH_FILL_END();
} else {
for (uint32_t i = 0; i < argc; i++) {
Z_TRY_ADDREF(args[i]);
zend_hash_next_index_insert_new(&new_hash, &args[i]);
}
} ZEND_HASH_FOREACH_END();
ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(stack), key, value) {
if (key) {
zend_hash_add_new(&new_hash, key, value);
} else {
zend_hash_next_index_insert_new(&new_hash, value);
}
} ZEND_HASH_FOREACH_END();
}
if (UNEXPECTED(HT_HAS_ITERATORS(Z_ARRVAL_P(stack)))) {
zend_hash_iterators_advance(Z_ARRVAL_P(stack), argc);