]> granicus.if.org Git - php/commitdiff
Optimized array_merge and cleanup
authorXinchen Hui <laruence@gmail.com>
Tue, 2 Aug 2016 12:02:23 +0000 (20:02 +0800)
committerXinchen Hui <laruence@gmail.com>
Tue, 2 Aug 2016 12:02:23 +0000 (20:02 +0800)
ext/standard/array.c

index 4ad3b68962bdaee97ef512afd80bd1b1538d0cf5..b24c4d4eb2b4b5cba3e248389ab1f6665a0901ed 100644 (file)
@@ -3011,8 +3011,8 @@ PHP_FUNCTION(array_slice)
                                if (pos > offset + length) {
                                        break;
                                }
-                               if (UNEXPECTED(Z_ISREF_P(entry))
-                                       && UNEXPECTED(Z_REFCOUNT_P(entry) == 1)) {
+                               if (UNEXPECTED(Z_ISREF_P(entry)) &&
+                                       UNEXPECTED(Z_REFCOUNT_P(entry) == 1)) {
                                        ZVAL_UNREF(entry);
                                }
                                Z_TRY_ADDREF_P(entry);
@@ -3143,8 +3143,8 @@ PHPAPI int php_array_merge(HashTable *dest, HashTable *src) /* {{{ */
                } ZEND_HASH_FILL_END();
        } else {
                ZEND_HASH_FOREACH_STR_KEY_VAL(src, string_key, src_entry) {
-                       if (UNEXPECTED(Z_ISREF_P(src_entry)) &&
-                               UNEXPECTED(Z_REFCOUNT_P(src_entry) == 1)) {
+                       if (UNEXPECTED(Z_ISREF_P(src_entry) &&
+                               Z_REFCOUNT_P(src_entry) == 1)) {
                                ZVAL_UNREF(src_entry);
                        }
                        Z_TRY_ADDREF_P(src_entry);
@@ -3230,7 +3230,7 @@ static inline void php_array_merge_or_replace_wrapper(INTERNAL_FUNCTION_PARAMETE
 {
        zval *args = NULL;
        zval *arg;
-       int argc, i, init_size = 0;
+       int argc, i;
 
 #ifndef FAST_ZPP
        if (zend_parse_parameters(ZEND_NUM_ARGS(), "+", &args, &argc) == FAILURE) {
@@ -3249,98 +3249,79 @@ static inline void php_array_merge_or_replace_wrapper(INTERNAL_FUNCTION_PARAMETE
                if (Z_TYPE_P(arg) != IS_ARRAY) {
                        php_error_docref(NULL, E_WARNING, "Argument #%d is not an array", i + 1);
                        RETURN_NULL();
-               } else {
-                       int num = zend_hash_num_elements(Z_ARRVAL_P(arg));
-
-                       if (num > init_size) {
-                               init_size = num;
-                       }
                }
        }
 
-       array_init_size(return_value, init_size);
 
        if (replace) {
-               zend_string *string_key;
-               zval *src_entry;
-               zend_ulong idx;
-               HashTable *src, *dest;
+               HashTable *dest;
 
                /* copy first array */
                arg = args;
                ZVAL_DEREF(arg);
-               src  = Z_ARRVAL_P(arg);
-               dest = Z_ARRVAL_P(return_value);
-               ZEND_HASH_FOREACH_KEY_VAL(src, idx, string_key, src_entry) {
-                       if (Z_REFCOUNTED_P(src_entry)) {
-                               if (UNEXPECTED(Z_ISREF_P(src_entry) && Z_REFCOUNT_P(src_entry) == 1)) {
-                                       src_entry = Z_REFVAL_P(src_entry);
-                                       if (Z_REFCOUNTED_P(src_entry)) {
-                                               Z_ADDREF_P(src_entry);
-                                       }
-                               } else {
-                                       Z_ADDREF_P(src_entry);
-                               }
-                       }
-                       if (string_key) {
-                               zend_hash_add_new(dest, string_key, src_entry);
-                       } else {
-                               zend_hash_index_add_new(dest, idx, src_entry);
-                       }
-               } ZEND_HASH_FOREACH_END();
-
+               dest = zend_array_dup(Z_ARRVAL_P(arg));
+               ZVAL_ARR(return_value, dest);
                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));
+                               php_array_replace_recursive(dest, Z_ARRVAL_P(arg));
                        }
                } else {
                        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);
+                               zend_hash_merge(dest, 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);
+               /* copy first array */
+               array_init_size(return_value, zend_hash_num_elements(src));
                dest = Z_ARRVAL_P(return_value);
-               ZEND_HASH_FOREACH_STR_KEY_VAL(src, string_key, src_entry) {
-                       if (Z_REFCOUNTED_P(src_entry)) {
-                               if (UNEXPECTED(Z_ISREF_P(src_entry) && Z_REFCOUNT_P(src_entry) == 1)) {
-                                       src_entry = Z_REFVAL_P(src_entry);
-                                       if (Z_REFCOUNTED_P(src_entry)) {
-                                               Z_ADDREF_P(src_entry);
+               if (src->u.flags & HASH_FLAG_PACKED) {
+                       zend_hash_real_init(dest, 1);
+                       ZEND_HASH_FILL_PACKED(dest) {
+                               ZEND_HASH_FOREACH_VAL(src, src_entry) {
+                                       if (UNEXPECTED(Z_ISREF_P(src_entry) &&
+                                               Z_REFCOUNT_P(src_entry) == 1)) {
+                                               ZVAL_UNREF(src_entry);
                                        }
+                                       Z_TRY_ADDREF_P(src_entry);
+                                       ZEND_HASH_FILL_ADD(src_entry);
+                               } ZEND_HASH_FOREACH_END();
+                       } ZEND_HASH_FILL_END();
+               } else {
+                       zend_string *string_key;
+                       ZEND_HASH_FOREACH_STR_KEY_VAL(src, string_key, src_entry) {
+                               if (UNEXPECTED(Z_ISREF_P(src_entry) &&
+                                       Z_REFCOUNT_P(src_entry) == 1)) {
+                                       ZVAL_UNREF(src_entry);
+                               }
+                               Z_TRY_ADDREF_P(src_entry);
+                               if (string_key) {
+                                       zend_hash_add_new(dest, string_key, src_entry);
                                } else {
-                                       Z_ADDREF_P(src_entry);
+                                       zend_hash_next_index_insert_new(dest, src_entry);
                                }
-                       }
-                       if (string_key) {
-                               zend_hash_add_new(dest, string_key, src_entry);
-                       } else {
-                               zend_hash_next_index_insert_new(dest, src_entry);
-                       }
-               } ZEND_HASH_FOREACH_END();
-
+                       } 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));
+                               php_array_merge_recursive(dest, Z_ARRVAL_P(arg));
                        }
                } 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));
+                               php_array_merge(dest, Z_ARRVAL_P(arg));
                        }
                }
        }
@@ -3689,8 +3670,8 @@ PHP_FUNCTION(array_reverse)
                zend_hash_real_init(Z_ARRVAL_P(return_value), 1);
                ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
                        ZEND_HASH_REVERSE_FOREACH_VAL(Z_ARRVAL_P(input), entry) {
-                               if (UNEXPECTED(Z_ISREF_P(entry))
-                                       && UNEXPECTED(Z_REFCOUNT_P(entry) == 1)) {
+                               if (UNEXPECTED(Z_ISREF_P(entry) &&
+                                       Z_REFCOUNT_P(entry) == 1)) {
                                        ZVAL_UNREF(entry);
                                }
                                Z_TRY_ADDREF_P(entry);