summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Stogov <dmitry@zend.com>2014-12-11 19:18:31 +0300
committerDmitry Stogov <dmitry@zend.com>2014-12-11 19:18:31 +0300
commit381438e5df4534d5b2f0d5c7008289d35d4c372a (patch)
treef11d3a777165c184ee5e4306733d71e8527f97bd
parent73458e8f19525c7814482161e86ab8bc266633fe (diff)
downloadphp-git-381438e5df4534d5b2f0d5c7008289d35d4c372a.tar.gz
Improved array_merge() and array_replace() (1-st array may be added using simple procedure).
-rw-r--r--ext/standard/array.c228
-rw-r--r--ext/standard/php_array.h3
2 files changed, 151 insertions, 80 deletions
diff --git a/ext/standard/array.c b/ext/standard/array.c
index bacd98cf30..1f03e5acb8 100644
--- a/ext/standard/array.c
+++ b/ext/standard/array.c
@@ -2348,99 +2348,104 @@ PHP_FUNCTION(array_slice)
}
/* }}} */
-PHPAPI int php_array_merge(HashTable *dest, HashTable *src, int recursive TSRMLS_DC) /* {{{ */
+PHPAPI int php_array_merge_recursive(HashTable *dest, HashTable *src TSRMLS_DC) /* {{{ */
{
zval *src_entry, *dest_entry;
zend_string *string_key;
- if (recursive) {
- ZEND_HASH_FOREACH_STR_KEY_VAL(src, string_key, src_entry) {
- if (string_key) {
- if ((dest_entry = zend_hash_find(dest, string_key)) != NULL) {
- zval *src_zval = src_entry;
- zval *dest_zval = dest_entry;
- HashTable *thash;
- zval tmp;
- int ret;
-
- ZVAL_DEREF(src_zval);
- ZVAL_DEREF(dest_zval);
- thash = Z_TYPE_P(dest_zval) == IS_ARRAY ? Z_ARRVAL_P(dest_zval) : NULL;
- if ((thash && thash->u.v.nApplyCount > 1) || (src_entry == dest_entry && Z_ISREF_P(dest_entry) && (Z_REFCOUNT_P(dest_entry) % 2))) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "recursion detected");
- return 0;
- }
+ ZEND_HASH_FOREACH_STR_KEY_VAL(src, string_key, src_entry) {
+ if (string_key) {
+ if ((dest_entry = zend_hash_find(dest, string_key)) != NULL) {
+ zval *src_zval = src_entry;
+ zval *dest_zval = dest_entry;
+ HashTable *thash;
+ zval tmp;
+ int ret;
- if (Z_ISREF_P(dest_entry)) {
- if (Z_REFCOUNT_P(dest_entry) == 1) {
- ZVAL_UNREF(dest_entry);
- } else {
- Z_DELREF_P(dest_entry);
- ZVAL_DUP(dest_entry, dest_zval);
- }
- dest_zval = dest_entry;
- } else {
- SEPARATE_ZVAL(dest_zval);
- }
+ ZVAL_DEREF(src_zval);
+ ZVAL_DEREF(dest_zval);
+ thash = Z_TYPE_P(dest_zval) == IS_ARRAY ? Z_ARRVAL_P(dest_zval) : NULL;
+ if ((thash && thash->u.v.nApplyCount > 1) || (src_entry == dest_entry && Z_ISREF_P(dest_entry) && (Z_REFCOUNT_P(dest_entry) % 2))) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "recursion detected");
+ return 0;
+ }
- if (Z_TYPE_P(dest_zval) == IS_NULL) {
- convert_to_array_ex(dest_zval);
- add_next_index_null(dest_zval);
+ if (Z_ISREF_P(dest_entry)) {
+ if (Z_REFCOUNT_P(dest_entry) == 1) {
+ ZVAL_UNREF(dest_entry);
} else {
- convert_to_array_ex(dest_zval);
+ Z_DELREF_P(dest_entry);
+ ZVAL_DUP(dest_entry, dest_zval);
+ }
+ dest_zval = dest_entry;
+ } else {
+ SEPARATE_ZVAL(dest_zval);
+ }
+ if (Z_TYPE_P(dest_zval) == IS_NULL) {
+ convert_to_array_ex(dest_zval);
+ add_next_index_null(dest_zval);
+ } else {
+ convert_to_array_ex(dest_zval);
+ }
+ ZVAL_UNDEF(&tmp);
+ if (Z_TYPE_P(src_zval) == IS_OBJECT) {
+ ZVAL_DUP(&tmp, src_zval);
+ convert_to_array(&tmp);
+ src_zval = &tmp;
+ }
+ if (Z_TYPE_P(src_zval) == IS_ARRAY) {
+ if (thash && ZEND_HASH_APPLY_PROTECTION(thash)) {
+ thash->u.v.nApplyCount++;
}
- ZVAL_UNDEF(&tmp);
- if (Z_TYPE_P(src_zval) == IS_OBJECT) {
- ZVAL_DUP(&tmp, src_zval);
- convert_to_array(&tmp);
- src_zval = &tmp;
+ ret = php_array_merge_recursive(Z_ARRVAL_P(dest_zval), Z_ARRVAL_P(src_zval) TSRMLS_CC);
+ if (thash && ZEND_HASH_APPLY_PROTECTION(thash)) {
+ thash->u.v.nApplyCount--;
}
- if (Z_TYPE_P(src_zval) == IS_ARRAY) {
- if (thash && ZEND_HASH_APPLY_PROTECTION(thash)) {
- thash->u.v.nApplyCount++;
- }
- ret = php_array_merge(Z_ARRVAL_P(dest_zval), Z_ARRVAL_P(src_zval), 1 TSRMLS_CC);
- if (thash && ZEND_HASH_APPLY_PROTECTION(thash)) {
- thash->u.v.nApplyCount--;
- }
- if (!ret) {
- return 0;
- }
- } else {
- if (Z_REFCOUNTED_P(src_entry)) {
- Z_ADDREF_P(src_entry);
- }
- zend_hash_next_index_insert(Z_ARRVAL_P(dest_zval), src_zval);
+ if (!ret) {
+ return 0;
}
- zval_ptr_dtor(&tmp);
} else {
if (Z_REFCOUNTED_P(src_entry)) {
Z_ADDREF_P(src_entry);
}
- zend_hash_add_new(dest, string_key, src_entry);
+ zend_hash_next_index_insert(Z_ARRVAL_P(dest_zval), src_zval);
}
+ zval_ptr_dtor(&tmp);
} else {
if (Z_REFCOUNTED_P(src_entry)) {
Z_ADDREF_P(src_entry);
}
- zend_hash_next_index_insert_new(dest, src_entry);
+ zend_hash_add_new(dest, string_key, src_entry);
}
- } ZEND_HASH_FOREACH_END();
- } else {
- ZEND_HASH_FOREACH_STR_KEY_VAL(src, string_key, src_entry) {
- if (string_key) {
- if (Z_REFCOUNTED_P(src_entry)) {
- Z_ADDREF_P(src_entry);
- }
- zend_hash_update(dest, string_key, src_entry);
- } else {
- if (Z_REFCOUNTED_P(src_entry)) {
- Z_ADDREF_P(src_entry);
- }
- zend_hash_next_index_insert_new(dest, src_entry);
+ } else {
+ if (Z_REFCOUNTED_P(src_entry)) {
+ Z_ADDREF_P(src_entry);
}
- } ZEND_HASH_FOREACH_END();
- }
+ zend_hash_next_index_insert_new(dest, src_entry);
+ }
+ } ZEND_HASH_FOREACH_END();
+ return 1;
+}
+/* }}} */
+
+PHPAPI int php_array_merge(HashTable *dest, HashTable *src TSRMLS_DC) /* {{{ */
+{
+ zval *src_entry;
+ zend_string *string_key;
+
+ ZEND_HASH_FOREACH_STR_KEY_VAL(src, string_key, src_entry) {
+ if (string_key) {
+ if (Z_REFCOUNTED_P(src_entry)) {
+ Z_ADDREF_P(src_entry);
+ }
+ zend_hash_update(dest, string_key, src_entry);
+ } else {
+ if (Z_REFCOUNTED_P(src_entry)) {
+ Z_ADDREF_P(src_entry);
+ }
+ zend_hash_next_index_insert_new(dest, src_entry);
+ }
+ } ZEND_HASH_FOREACH_END();
return 1;
}
/* }}} */
@@ -2521,6 +2526,7 @@ PHPAPI int php_array_replace_recursive(HashTable *dest, HashTable *src TSRMLS_DC
static void php_array_merge_or_replace_wrapper(INTERNAL_FUNCTION_PARAMETERS, int recursive, int replace) /* {{{ */
{
zval *args = NULL;
+ zval *arg;
int argc, i, init_size = 0;
#ifndef FAST_ZPP
@@ -2551,16 +2557,80 @@ static void php_array_merge_or_replace_wrapper(INTERNAL_FUNCTION_PARAMETERS, int
array_init_size(return_value, init_size);
- for (i = 0; i < argc; i++) {
- zval *arg = args + i;
+ if (replace) {
+ zend_string *string_key;
+ zval *src_entry;
+ zend_ulong idx;
+ HashTable *src, *dest;
+ /* copy first array */
+ arg = args;
ZVAL_DEREF(arg);
- if (!replace) {
- php_array_merge(Z_ARRVAL_P(return_value), Z_ARRVAL_P(arg), recursive TSRMLS_CC);
- } else if (recursive && i > 0) { /* First array will be copied directly instead */
- php_array_replace_recursive(Z_ARRVAL_P(return_value), Z_ARRVAL_P(arg) TSRMLS_CC);
+ src = Z_ARRVAL_P(arg);
+ dest = Z_ARRVAL_P(return_value);
+ ZEND_HASH_FOREACH_KEY_VAL(src, idx, string_key, src_entry) {
+ if (string_key) {
+ if (Z_REFCOUNTED_P(src_entry)) {
+ Z_ADDREF_P(src_entry);
+ }
+ zend_hash_add_new(dest, string_key, src_entry);
+ } else {
+ if (Z_REFCOUNTED_P(src_entry)) {
+ Z_ADDREF_P(src_entry);
+ }
+ zend_hash_index_add_new(dest, idx, src_entry);
+ }
+ } ZEND_HASH_FOREACH_END();
+
+ if (recursive) {
+ for (i = 1; i < argc; i++) {
+ arg = args + i;
+ ZVAL_DEREF(arg);
+ php_array_replace_recursive(Z_ARRVAL_P(return_value), Z_ARRVAL_P(arg) TSRMLS_CC);
+ }
} else {
- zend_hash_merge(Z_ARRVAL_P(return_value), Z_ARRVAL_P(arg), zval_add_ref, 1);
+ for (i = 1; i < argc; i++) {
+ arg = args + i;
+ ZVAL_DEREF(arg);
+ zend_hash_merge(Z_ARRVAL_P(return_value), Z_ARRVAL_P(arg), zval_add_ref, 1);
+ }
+ }
+ } else {
+ zend_string *string_key;
+ zval *src_entry;
+ HashTable *src, *dest;
+
+ /* copy first array */
+ arg = args;
+ ZVAL_DEREF(arg);
+ src = Z_ARRVAL_P(arg);
+ dest = Z_ARRVAL_P(return_value);
+ ZEND_HASH_FOREACH_STR_KEY_VAL(src, string_key, src_entry) {
+ if (string_key) {
+ if (Z_REFCOUNTED_P(src_entry)) {
+ Z_ADDREF_P(src_entry);
+ }
+ zend_hash_add_new(dest, string_key, src_entry);
+ } else {
+ if (Z_REFCOUNTED_P(src_entry)) {
+ Z_ADDREF_P(src_entry);
+ }
+ zend_hash_next_index_insert_new(dest, src_entry);
+ }
+ } ZEND_HASH_FOREACH_END();
+
+ if (recursive) {
+ for (i = 1; i < argc; i++) {
+ arg = args + i;
+ ZVAL_DEREF(arg);
+ php_array_merge_recursive(Z_ARRVAL_P(return_value), Z_ARRVAL_P(arg) TSRMLS_CC);
+ }
+ } else {
+ for (i = 1; i < argc; i++) {
+ arg = args + i;
+ ZVAL_DEREF(arg);
+ php_array_merge(Z_ARRVAL_P(return_value), Z_ARRVAL_P(arg) TSRMLS_CC);
+ }
}
}
}
diff --git a/ext/standard/php_array.h b/ext/standard/php_array.h
index d86121b277..31955042eb 100644
--- a/ext/standard/php_array.h
+++ b/ext/standard/php_array.h
@@ -104,7 +104,8 @@ PHP_FUNCTION(array_chunk);
PHP_FUNCTION(array_combine);
PHPAPI HashTable* php_splice(HashTable *, int, int, zval *, int, HashTable *);
-PHPAPI int php_array_merge(HashTable *dest, HashTable *src, int recursive TSRMLS_DC);
+PHPAPI int php_array_merge(HashTable *dest, HashTable *src TSRMLS_DC);
+PHPAPI int php_array_merge_recursive(HashTable *dest, HashTable *src TSRMLS_DC);
PHPAPI int php_array_replace_recursive(HashTable *dest, HashTable *src TSRMLS_DC);
PHPAPI int php_multisort_compare(const void *a, const void *b TSRMLS_DC);
PHPAPI zend_long php_count_recursive(zval *array, zend_long mode TSRMLS_DC);