Skip to content

Commit 05f3706

Browse files
committed
Split php_array_merge_or_replace_wrapper() into php_array_merge_wrapper() and php_array_replace_wrapper().
Avoid array duplication when merging with an empty array.
1 parent b380483 commit 05f3706

File tree

1 file changed

+113
-73
lines changed

1 file changed

+113
-73
lines changed

ext/standard/array.c

Lines changed: 113 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -3730,102 +3730,142 @@ PHPAPI int php_array_replace_recursive(HashTable *dest, HashTable *src) /* {{{ *
37303730
}
37313731
/* }}} */
37323732

3733-
static inline void php_array_merge_or_replace_wrapper(INTERNAL_FUNCTION_PARAMETERS, int recursive, int replace) /* {{{ */
3733+
static zend_always_inline void php_array_replace_wrapper(INTERNAL_FUNCTION_PARAMETERS, int recursive) /* {{{ */
37343734
{
37353735
zval *args = NULL;
37363736
zval *arg;
37373737
int argc, i;
3738+
HashTable *dest;
37383739

37393740
ZEND_PARSE_PARAMETERS_START(1, -1)
37403741
Z_PARAM_VARIADIC('+', args, argc)
37413742
ZEND_PARSE_PARAMETERS_END();
37423743

37433744

3744-
if (replace) {
3745-
HashTable *dest;
3746-
3747-
for (i = 0; i < argc; i++) {
3748-
zval *arg = args + i;
3745+
for (i = 0; i < argc; i++) {
3746+
zval *arg = args + i;
37493747

3750-
if (Z_TYPE_P(arg) != IS_ARRAY) {
3751-
php_error_docref(NULL, E_WARNING, "Expected parameter %d to be an array, %s given", i + 1, zend_zval_type_name(arg));
3752-
RETURN_NULL();
3753-
}
3748+
if (Z_TYPE_P(arg) != IS_ARRAY) {
3749+
php_error_docref(NULL, E_WARNING, "Expected parameter %d to be an array, %s given", i + 1, zend_zval_type_name(arg));
3750+
RETURN_NULL();
37543751
}
3752+
}
37553753

3756-
/* copy first array */
3757-
arg = args;
3758-
dest = zend_array_dup(Z_ARRVAL_P(arg));
3759-
ZVAL_ARR(return_value, dest);
3760-
if (recursive) {
3761-
for (i = 1; i < argc; i++) {
3762-
arg = args + i;
3763-
php_array_replace_recursive(dest, Z_ARRVAL_P(arg));
3764-
}
3765-
} else {
3766-
for (i = 1; i < argc; i++) {
3767-
arg = args + i;
3768-
zend_hash_merge(dest, Z_ARRVAL_P(arg), zval_add_ref, 1);
3769-
}
3754+
/* copy first array */
3755+
arg = args;
3756+
dest = zend_array_dup(Z_ARRVAL_P(arg));
3757+
ZVAL_ARR(return_value, dest);
3758+
if (recursive) {
3759+
for (i = 1; i < argc; i++) {
3760+
arg = args + i;
3761+
php_array_replace_recursive(dest, Z_ARRVAL_P(arg));
37703762
}
37713763
} else {
3772-
zval *src_entry;
3773-
HashTable *src, *dest;
3774-
uint32_t count = 0;
3764+
for (i = 1; i < argc; i++) {
3765+
arg = args + i;
3766+
zend_hash_merge(dest, Z_ARRVAL_P(arg), zval_add_ref, 1);
3767+
}
3768+
}
3769+
}
3770+
/* }}} */
3771+
3772+
static zend_always_inline void php_array_merge_wrapper(INTERNAL_FUNCTION_PARAMETERS, int recursive) /* {{{ */
3773+
{
3774+
zval *args = NULL;
3775+
zval *arg;
3776+
int argc, i;
3777+
zval *src_entry;
3778+
HashTable *src, *dest;
3779+
uint32_t count = 0;
37753780

3776-
for (i = 0; i < argc; i++) {
3777-
zval *arg = args + i;
3781+
ZEND_PARSE_PARAMETERS_START(1, -1)
3782+
Z_PARAM_VARIADIC('+', args, argc)
3783+
ZEND_PARSE_PARAMETERS_END();
37783784

3779-
if (Z_TYPE_P(arg) != IS_ARRAY) {
3780-
php_error_docref(NULL, E_WARNING, "Expected parameter %d to be an array, %s given", i + 1, zend_zval_type_name(arg));
3781-
RETURN_NULL();
3782-
}
3783-
count += zend_hash_num_elements(Z_ARRVAL_P(arg));
3784-
}
3785-
3786-
arg = args;
3787-
src = Z_ARRVAL_P(arg);
3788-
/* copy first array */
3789-
array_init_size(return_value, count);
3790-
dest = Z_ARRVAL_P(return_value);
3791-
if (HT_FLAGS(src) & HASH_FLAG_PACKED) {
3792-
zend_hash_real_init_packed(dest);
3793-
ZEND_HASH_FILL_PACKED(dest) {
3794-
ZEND_HASH_FOREACH_VAL(src, src_entry) {
3795-
if (UNEXPECTED(Z_ISREF_P(src_entry) &&
3796-
Z_REFCOUNT_P(src_entry) == 1)) {
3797-
src_entry = Z_REFVAL_P(src_entry);
3785+
for (i = 0; i < argc; i++) {
3786+
zval *arg = args + i;
3787+
3788+
if (Z_TYPE_P(arg) != IS_ARRAY) {
3789+
php_error_docref(NULL, E_WARNING, "Expected parameter %d to be an array, %s given", i + 1, zend_zval_type_name(arg));
3790+
RETURN_NULL();
3791+
}
3792+
count += zend_hash_num_elements(Z_ARRVAL_P(arg));
3793+
}
3794+
3795+
if (argc == 2) {
3796+
zval *ret = NULL;
3797+
3798+
if (zend_hash_num_elements(Z_ARRVAL(args[0])) == 0) {
3799+
ret = &args[1];
3800+
} else if (zend_hash_num_elements(Z_ARRVAL(args[1])) == 0) {
3801+
ret = &args[0];
3802+
}
3803+
if (ret) {
3804+
if (HT_FLAGS(Z_ARRVAL_P(ret)) & HASH_FLAG_PACKED) {
3805+
if (HT_IS_WITHOUT_HOLES(Z_ARRVAL_P(ret))) {
3806+
ZVAL_COPY(return_value, ret);
3807+
return;
3808+
}
3809+
} else {
3810+
zend_bool copy = 1;
3811+
zend_string *string_key;
3812+
3813+
ZEND_HASH_FOREACH_STR_KEY(Z_ARRVAL_P(ret), string_key) {
3814+
if (!string_key) {
3815+
copy = 0;
3816+
break;
37983817
}
3799-
Z_TRY_ADDREF_P(src_entry);
3800-
ZEND_HASH_FILL_ADD(src_entry);
38013818
} ZEND_HASH_FOREACH_END();
3802-
} ZEND_HASH_FILL_END();
3803-
} else {
3804-
zend_string *string_key;
3805-
zend_hash_real_init_mixed(dest);
3806-
ZEND_HASH_FOREACH_STR_KEY_VAL(src, string_key, src_entry) {
3819+
if (copy) {
3820+
ZVAL_COPY(return_value, ret);
3821+
return;
3822+
}
3823+
}
3824+
}
3825+
}
3826+
3827+
arg = args;
3828+
src = Z_ARRVAL_P(arg);
3829+
/* copy first array */
3830+
array_init_size(return_value, count);
3831+
dest = Z_ARRVAL_P(return_value);
3832+
if (HT_FLAGS(src) & HASH_FLAG_PACKED) {
3833+
zend_hash_real_init_packed(dest);
3834+
ZEND_HASH_FILL_PACKED(dest) {
3835+
ZEND_HASH_FOREACH_VAL(src, src_entry) {
38073836
if (UNEXPECTED(Z_ISREF_P(src_entry) &&
38083837
Z_REFCOUNT_P(src_entry) == 1)) {
38093838
src_entry = Z_REFVAL_P(src_entry);
38103839
}
38113840
Z_TRY_ADDREF_P(src_entry);
3812-
if (EXPECTED(string_key)) {
3813-
_zend_hash_append(dest, string_key, src_entry);
3814-
} else {
3815-
zend_hash_next_index_insert_new(dest, src_entry);
3816-
}
3841+
ZEND_HASH_FILL_ADD(src_entry);
38173842
} ZEND_HASH_FOREACH_END();
3818-
}
3819-
if (recursive) {
3820-
for (i = 1; i < argc; i++) {
3821-
arg = args + i;
3822-
php_array_merge_recursive(dest, Z_ARRVAL_P(arg));
3843+
} ZEND_HASH_FILL_END();
3844+
} else {
3845+
zend_string *string_key;
3846+
zend_hash_real_init_mixed(dest);
3847+
ZEND_HASH_FOREACH_STR_KEY_VAL(src, string_key, src_entry) {
3848+
if (UNEXPECTED(Z_ISREF_P(src_entry) &&
3849+
Z_REFCOUNT_P(src_entry) == 1)) {
3850+
src_entry = Z_REFVAL_P(src_entry);
38233851
}
3824-
} else {
3825-
for (i = 1; i < argc; i++) {
3826-
arg = args + i;
3827-
php_array_merge(dest, Z_ARRVAL_P(arg));
3852+
Z_TRY_ADDREF_P(src_entry);
3853+
if (EXPECTED(string_key)) {
3854+
_zend_hash_append(dest, string_key, src_entry);
3855+
} else {
3856+
zend_hash_next_index_insert_new(dest, src_entry);
38283857
}
3858+
} ZEND_HASH_FOREACH_END();
3859+
}
3860+
if (recursive) {
3861+
for (i = 1; i < argc; i++) {
3862+
arg = args + i;
3863+
php_array_merge_recursive(dest, Z_ARRVAL_P(arg));
3864+
}
3865+
} else {
3866+
for (i = 1; i < argc; i++) {
3867+
arg = args + i;
3868+
php_array_merge(dest, Z_ARRVAL_P(arg));
38293869
}
38303870
}
38313871
}
@@ -3835,31 +3875,31 @@ static inline void php_array_merge_or_replace_wrapper(INTERNAL_FUNCTION_PARAMETE
38353875
Merges elements from passed arrays into one array */
38363876
PHP_FUNCTION(array_merge)
38373877
{
3838-
php_array_merge_or_replace_wrapper(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, 0);
3878+
php_array_merge_wrapper(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
38393879
}
38403880
/* }}} */
38413881

38423882
/* {{{ proto array array_merge_recursive(array arr1 [, array ...])
38433883
Recursively merges elements from passed arrays into one array */
38443884
PHP_FUNCTION(array_merge_recursive)
38453885
{
3846-
php_array_merge_or_replace_wrapper(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1, 0);
3886+
php_array_merge_wrapper(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
38473887
}
38483888
/* }}} */
38493889

38503890
/* {{{ proto array array_replace(array arr1 [, array ...])
38513891
Replaces elements from passed arrays into one array */
38523892
PHP_FUNCTION(array_replace)
38533893
{
3854-
php_array_merge_or_replace_wrapper(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, 1);
3894+
php_array_replace_wrapper(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
38553895
}
38563896
/* }}} */
38573897

38583898
/* {{{ proto array array_replace_recursive(array arr1 [, array ...])
38593899
Recursively replaces elements from passed arrays into one array */
38603900
PHP_FUNCTION(array_replace_recursive)
38613901
{
3862-
php_array_merge_or_replace_wrapper(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1, 1);
3902+
php_array_replace_wrapper(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
38633903
}
38643904
/* }}} */
38653905

0 commit comments

Comments
 (0)