]> granicus.if.org Git - php/commitdiff
MFH: Add array_init_size() and use it where array size is known at initialization
authorMatt Wilmas <mattwil@php.net>
Tue, 27 May 2008 10:29:33 +0000 (10:29 +0000)
committerMatt Wilmas <mattwil@php.net>
Tue, 27 May 2008 10:29:33 +0000 (10:29 +0000)
Zend/zend_API.c
Zend/zend_API.h
Zend/zend_builtin_functions.c
Zend/zend_object_handlers.c
ext/standard/array.c
ext/standard/string.c
ext/standard/var_unserializer.re

index a3b2b1e4aee405ee6d55e3d140c574227ebe8012..163ec5411c82e8b784fa752e7f931cfcea631d7f 100644 (file)
@@ -922,11 +922,11 @@ ZEND_API int zend_parse_method_parameters_ex(int flags, int num_args TSRMLS_DC,
 /* }}} */
 
 /* Argument parsing API -- andrei */
-ZEND_API int _array_init(zval *arg ZEND_FILE_LINE_DC) /* {{{ */
+ZEND_API int _array_init(zval *arg, uint size ZEND_FILE_LINE_DC) /* {{{ */
 {
        ALLOC_HASHTABLE_REL(Z_ARRVAL_P(arg));
 
-       _zend_hash_init(Z_ARRVAL_P(arg), 0, NULL, ZVAL_PTR_DTOR, 0 ZEND_FILE_LINE_RELAY_CC);
+       _zend_hash_init(Z_ARRVAL_P(arg), size, NULL, ZVAL_PTR_DTOR, 0 ZEND_FILE_LINE_RELAY_CC);
        Z_TYPE_P(arg) = IS_ARRAY;
        return SUCCESS;
 }
index a71900f51468c08aa799ba25263bee49745d4841..19be6f08a511bb07770cb7922ffc72eec2a4d191 100644 (file)
@@ -316,11 +316,12 @@ ZEND_API char *zend_get_type_by_const(int type);
 #define DLEXPORT
 #endif
 
-#define array_init(arg)                        _array_init((arg) ZEND_FILE_LINE_CC)
+#define array_init(arg)                        _array_init((arg), 0 ZEND_FILE_LINE_CC)
+#define array_init_size(arg, size) _array_init((arg), (size) ZEND_FILE_LINE_CC)
 #define object_init(arg)               _object_init((arg) ZEND_FILE_LINE_CC TSRMLS_CC)
 #define object_init_ex(arg, ce)        _object_init_ex((arg), (ce) ZEND_FILE_LINE_CC TSRMLS_CC)
 #define object_and_properties_init(arg, ce, properties)        _object_and_properties_init((arg), (ce), (properties) ZEND_FILE_LINE_CC TSRMLS_CC)
-ZEND_API int _array_init(zval *arg ZEND_FILE_LINE_DC);
+ZEND_API int _array_init(zval *arg, uint size ZEND_FILE_LINE_DC);
 ZEND_API int _object_init(zval *arg ZEND_FILE_LINE_DC TSRMLS_DC);
 ZEND_API int _object_init_ex(zval *arg, zend_class_entry *ce ZEND_FILE_LINE_DC TSRMLS_DC);
 ZEND_API int _object_and_properties_init(zval *arg, zend_class_entry *ce, HashTable *properties ZEND_FILE_LINE_DC TSRMLS_DC);
index 9006e15fde2482925c0993e776f00c2cf851107b..11447bb6a1150fb63fa7049a00603e13eb124d30 100644 (file)
@@ -285,7 +285,7 @@ ZEND_FUNCTION(func_get_args)
        p = ex->function_state.arguments;
        arg_count = (int)(zend_uintptr_t) *p;           /* this is the amount of arguments passed to func_get_args(); */
 
-       array_init(return_value);
+       array_init_size(return_value, arg_count);
        for (i=0; i<arg_count; i++) {
                zval *element;
 
@@ -1526,16 +1526,14 @@ ZEND_FUNCTION(get_defined_functions)
    Returns an associative array of names and values of all currently defined variable names (variables in the current scope) */
 ZEND_FUNCTION(get_defined_vars)
 {
-       zval *tmp;
-
-       array_init(return_value);
-
        if (!EG(active_symbol_table)) {
                zend_rebuild_symbol_table(TSRMLS_C);
        }
 
+       array_init_size(return_value, zend_hash_num_elements(EG(active_symbol_table)));
+
        zend_hash_copy(Z_ARRVAL_P(return_value), EG(active_symbol_table),
-                                       (copy_ctor_func_t)zval_add_ref, &tmp, sizeof(zval *));
+                                       (copy_ctor_func_t)zval_add_ref, NULL, sizeof(zval *));
 }
 /* }}} */
 
@@ -1764,7 +1762,7 @@ static zval *debug_backtrace_get_args(void **curpos TSRMLS_DC)
        int arg_count = (int)(zend_uintptr_t) *p;
 
        MAKE_STD_ZVAL(arg_array);
-       array_init(arg_array);
+       array_init_size(arg_array, arg_count);
        p -= arg_count;
 
        while (--arg_count >= 0) {
index 20a465dca3dad78adb9217aa01db7795083a746b..71f843b3397e94f21c8957a264387eacb982d8a0 100644 (file)
@@ -654,7 +654,7 @@ ZEND_API void zend_std_call_user_call(INTERNAL_FUNCTION_PARAMETERS) /* {{{ */
 
        ALLOC_ZVAL(method_args_ptr);
        INIT_PZVAL(method_args_ptr);
-       array_init(method_args_ptr);
+       array_init_size(method_args_ptr, ZEND_NUM_ARGS());
 
        if (zend_copy_parameters_array(ZEND_NUM_ARGS(), method_args_ptr TSRMLS_CC) == FAILURE) {
                zval_dtor(method_args_ptr);
@@ -853,7 +853,7 @@ ZEND_API void zend_std_callstatic_user_call(INTERNAL_FUNCTION_PARAMETERS) /* {{{
 
        ALLOC_ZVAL(method_args_ptr);
        INIT_PZVAL(method_args_ptr);
-       array_init(method_args_ptr);
+       array_init_size(method_args_ptr, ZEND_NUM_ARGS());
 
        if (zend_copy_parameters_array(ZEND_NUM_ARGS(), method_args_ptr TSRMLS_CC) == FAILURE) {
                zval_dtor(method_args_ptr);
index 4f6251b91b4304620136339ba3ec03346e034372..7f9a65a70a6f32151fef966cbe58aa2645d87b74 100644 (file)
@@ -1501,7 +1501,14 @@ PHP_FUNCTION(compact)
                zend_rebuild_symbol_table(TSRMLS_C);
        }
 
-       array_init(return_value);
+       /* compact() is probably most used with a single array of var_names
+          or multiple string names, rather than a combination of both.
+          So quickly guess a minimum result size based on that */
+       if (ZEND_NUM_ARGS() == 1 && Z_TYPE_PP(args[0]) == IS_ARRAY) {
+               array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL_PP(args[0])));
+       } else {
+               array_init_size(return_value, ZEND_NUM_ARGS());
+       }
 
        for (i=0; i<ZEND_NUM_ARGS(); i++) {
                php_compact_var(EG(active_symbol_table), return_value, *args[i] TSRMLS_CC);
@@ -1522,15 +1529,15 @@ PHP_FUNCTION(array_fill)
                return;
        }
 
-       num--;
-       if (num < 0) {
+       if (num < 1) {
                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Number of elements must be positive");
                RETURN_FALSE;
        }
 
        /* allocate an array for return */
-       array_init(return_value);
+       array_init_size(return_value, num);
 
+       num--;
        zval_add_ref(&val);
        zend_hash_index_update(Z_ARRVAL_P(return_value), start_key, &val, sizeof(zval *), NULL);
 
@@ -1553,7 +1560,7 @@ PHP_FUNCTION(array_fill_keys)
        }
 
        /* Initialize return array */
-       array_init(return_value);
+       array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL_P(keys)));
 
        zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(keys), &pos);
        while (zend_hash_get_current_data_ex(Z_ARRVAL_P(keys), (void **)&entry, &pos) == SUCCESS) {
@@ -1832,7 +1839,7 @@ PHPAPI HashTable* php_splice(HashTable *in_hash, int offset, int length, zval **
 
        /* Create and initialize output hash */
        ALLOC_HASHTABLE(out_hash);
-       zend_hash_init(out_hash, 0, NULL, ZVAL_PTR_DTOR, 0);
+       zend_hash_init(out_hash, (length > 0 ? num_in - length : 0) + list_count, NULL, ZVAL_PTR_DTOR, 0);
 
        /* Start at the beginning of the input hash and copy entries to output hash until offset is reached */
        for (pos = 0, p = in_hash->pListHead; pos < offset && p ; pos++, p = p->pListNext) {
@@ -2070,19 +2077,23 @@ PHP_FUNCTION(array_splice)
        zval *array,                            /* Input array */
                 *repl_array,                   /* Replacement array */
                 ***repl = NULL;                /* Replacement elements */
-       HashTable *new_hash = NULL;     /* Output array's hash */
+       HashTable *new_hash = NULL,     /* Output array's hash */
+                **rem_hash = NULL;     /* Removed elements' hash */
        Bucket *p;                                      /* Bucket used for traversing hash */
        long    i,
                        offset,
                        length,
                        repl_num = 0;           /* Number of replacement elements */
+       int             num_in;                         /* Number of elements in the input array */
 
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "al|lz/", &array, &offset, &length, &repl_array) == FAILURE) {
                return;
        }
 
+       num_in = zend_hash_num_elements(Z_ARRVAL_P(array));
+
        if (ZEND_NUM_ARGS() < 3) {
-               length = zend_hash_num_elements(Z_ARRVAL_P(array));
+               length = num_in;
        }
 
        if (ZEND_NUM_ARGS() == 4) {
@@ -2097,11 +2108,32 @@ PHP_FUNCTION(array_splice)
                }
        }
 
-       /* Initialize return value */
-       array_init(return_value);
+       /* Don't create the array of removed elements if it's not going
+        * to be used; e.g. only removing and/or replacing elements */
+       if (return_value_used) {
+               int size;
+
+               /* Clamp the offset.. */
+               if (offset > num_in) {
+                       offset = num_in;
+               } else if (offset < 0 && (offset = (num_in + offset)) < 0) {
+                       offset = 0;
+               }
+
+               /* ..and the length */
+               if (length < 0) {
+                       size = num_in - offset + length;
+               } else if (((unsigned long) offset + (unsigned long) length) > (unsigned) num_in) {
+                       size = num_in - offset;
+               }
+
+               /* Initialize return value */
+               array_init_size(return_value, size > 0 ? size : 0);
+               rem_hash = &Z_ARRVAL_P(return_value);
+       }
 
        /* Perform splice */
-       new_hash = php_splice(Z_ARRVAL_P(array), offset, length, repl, repl_num, &Z_ARRVAL_P(return_value));
+       new_hash = php_splice(Z_ARRVAL_P(array), offset, length, repl, repl_num, rem_hash);
 
        /* Replace input array's hashtable with the new one */
        zend_hash_destroy(Z_ARRVAL_P(array));
@@ -2150,11 +2182,9 @@ PHP_FUNCTION(array_slice)
                length = Z_LVAL_PP(z_length);
        }
 
-       /* Initialize returned array */
-       array_init(return_value);
-
        /* Clamp the offset.. */
        if (offset > num_in) {
+               array_init(return_value);
                return;
        } else if (offset < 0 && (offset = (num_in + offset)) < 0) {
                offset = 0;
@@ -2167,7 +2197,10 @@ PHP_FUNCTION(array_slice)
                length = num_in - offset;
        }
 
-       if (length == 0) {
+       /* Initialize returned array */
+       array_init_size(return_value, length > 0 ? length : 0);
+
+       if (length <= 0) {
                return;
        }
 
@@ -2349,7 +2382,11 @@ PHP_FUNCTION(array_keys)
        }
 
        /* Initialize return array */
-       array_init(return_value);
+       if (search_value != NULL) {
+               array_init(return_value);
+       } else {
+               array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL_P(input)));
+       }
        add_key = 1;
 
        /* Go through input array and add keys to the return array */
@@ -2395,7 +2432,7 @@ PHP_FUNCTION(array_values)
        }
 
        /* Initialize return array */
-       array_init(return_value);
+       array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL_P(input)));
 
        /* Go through input array and add values to the return array */
        zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(input), &pos);
@@ -2472,7 +2509,7 @@ PHP_FUNCTION(array_reverse)
        }
 
        /* Initialize return array */
-       array_init(return_value);
+       array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL_P(input)));
 
        zend_hash_internal_pointer_end_ex(Z_ARRVAL_P(input), &pos);
        while (zend_hash_get_current_data_ex(Z_ARRVAL_P(input), (void **)&entry, &pos) == SUCCESS) {
@@ -2582,7 +2619,7 @@ PHP_FUNCTION(array_flip)
        }
 
        target_hash = HASH_OF(array);
-       array_init(return_value);
+       array_init_size(return_value, zend_hash_num_elements(target_hash));
 
        zend_hash_internal_pointer_reset_ex(target_hash, &pos);
        while (zend_hash_get_current_data_ex(target_hash, (void **)&entry, &pos) == SUCCESS) {
@@ -2627,7 +2664,7 @@ PHP_FUNCTION(array_change_key_case)
                return;
        }
 
-       array_init(return_value);
+       array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL_P(array)));
 
        zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(array), &pos);
        while (zend_hash_get_current_data_ex(Z_ARRVAL_P(array), (void **)&entry, &pos) == SUCCESS) {
@@ -2678,7 +2715,7 @@ PHP_FUNCTION(array_unique)
                RETURN_FALSE;
        }
 
-       array_init(return_value);
+       array_init_size(return_value, zend_hash_num_elements(target_hash));
        zend_hash_copy(Z_ARRVAL_P(return_value), target_hash, (copy_ctor_func_t) zval_add_ref, (void *)&tmp, sizeof(zval*));
 
        if (target_hash->nNumOfElements <= 1) { /* nothing to do */
@@ -3879,7 +3916,7 @@ PHP_FUNCTION(array_rand)
 
        /* Make the return value an array only if we need to pass back more than one result. */
        if (num_req > 1) {
-               array_init(return_value);
+               array_init_size(return_value, num_req);
        }
 
        /* We can't use zend_hash_index_find() because the array may have string keys or gaps. */
@@ -4193,7 +4230,7 @@ PHP_FUNCTION(array_map)
                return;
        }
 
-       array_init(return_value);
+       array_init_size(return_value, maxlen);
        params = (zval ***)safe_emalloc(n_arrays, sizeof(zval **), 0);
        MAKE_STD_ZVAL(null);
        ZVAL_NULL(null);
@@ -4209,7 +4246,7 @@ PHP_FUNCTION(array_map)
                 * entries from all arrays. */
                if (!ZEND_FCI_INITIALIZED(fci)) {
                        MAKE_STD_ZVAL(result);
-                       array_init(result);
+                       array_init_size(result, n_arrays);
                }
 
                for (i = 0; i < n_arrays; i++) {
@@ -4315,7 +4352,7 @@ PHP_FUNCTION(array_key_exists)
    Split array into chunks */
 PHP_FUNCTION(array_chunk)
 {
-       int argc = ZEND_NUM_ARGS(), key_type;
+       int argc = ZEND_NUM_ARGS(), key_type, num_in;
        long size, current = 0;
        char *str_key;
        uint str_key_len;
@@ -4335,14 +4372,20 @@ PHP_FUNCTION(array_chunk)
                return;
        }
 
-       array_init(return_value);
+       num_in = zend_hash_num_elements(Z_ARRVAL_P(input));
+
+       if (size > num_in) {
+               size = num_in > 0 ? num_in : 1;
+       }
+
+       array_init_size(return_value, ((num_in - 1) / size) + 1);
 
        zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(input), &pos);
        while (zend_hash_get_current_data_ex(Z_ARRVAL_P(input), (void**)&entry, &pos) == SUCCESS) {
                /* If new chunk, create and initialize it. */
                if (!chunk) {
                        MAKE_STD_ZVAL(chunk);
-                       array_init(chunk);
+                       array_init_size(chunk, size);
                }
 
                /* Add entry to the chunk, preserving keys if necessary. */
@@ -4405,7 +4448,7 @@ PHP_FUNCTION(array_combine)
                RETURN_FALSE;
        }
 
-       array_init(return_value);
+       array_init_size(return_value, num_keys);
 
        zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(keys), &pos_keys);
        zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(values), &pos_values);
index 46cd46c90a4ba09042fa09f8eeace1ee742bbeef..b3288882ee77aec3cf85cda586081b542f58da96 100644 (file)
@@ -40,8 +40,6 @@
 # include <libintl.h> /* For LC_MESSAGES */
 #endif
 
-#include <math.h>
-
 #include "scanf.h"
 #include "zend_API.h"
 #include "zend_execute.h"
@@ -5178,14 +5176,14 @@ PHP_FUNCTION(str_split)
                RETURN_FALSE;
        }
 
-       array_init(return_value);
+       array_init_size(return_value, ((str_len - 1) / split_length) + 1);
 
        if (split_length >= str_len) {
                add_next_index_stringl(return_value, str, str_len, 1);
                return;
        }
 
-       n_reg_segments = floor(str_len / split_length);
+       n_reg_segments = str_len / split_length;
        p = str;
 
        while (n_reg_segments-- > 0) {
index c68c748d75918a183bd9123f14e05b36ab02de31..d46812c6ad446fba9e61085b31c7da8058faae93 100644 (file)
@@ -557,10 +557,8 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER)
        }
 
        INIT_PZVAL(*rval);
-       Z_TYPE_PP(rval) = IS_ARRAY;
-       ALLOC_HASHTABLE(Z_ARRVAL_PP(rval));
 
-       zend_hash_init(Z_ARRVAL_PP(rval), elements + 1, NULL, ZVAL_PTR_DTOR, 0);
+       array_init_size(*rval, elements);
 
        if (!process_nested_data(UNSERIALIZE_PASSTHRU, Z_ARRVAL_PP(rval), elements)) {
                return 0;