]> granicus.if.org Git - php/commitdiff
Optimized array_fill(). This is a perfect function for fast creation of packed arrays.
authorDmitry Stogov <dmitry@zend.com>
Wed, 6 Apr 2016 22:01:11 +0000 (01:01 +0300)
committerDmitry Stogov <dmitry@zend.com>
Wed, 6 Apr 2016 22:01:11 +0000 (01:01 +0300)
ext/standard/array.c

index 289870ac1f2b323a2e36485071c7ce6752369e28..a0cdd91d855b8d7ad226d6e1bed2dbc22f786e4e 100644 (file)
@@ -2000,34 +2000,72 @@ PHP_FUNCTION(array_fill)
        zval *val;
        zend_long start_key, num;
 
+#ifndef FAST_ZPP
        if (zend_parse_parameters(ZEND_NUM_ARGS(), "llz", &start_key, &num, &val) == FAILURE) {
                return;
        }
+#else
+       ZEND_PARSE_PARAMETERS_START(3, 3)
+               Z_PARAM_LONG(start_key)
+               Z_PARAM_LONG(num)
+               Z_PARAM_ZVAL(val)
+       ZEND_PARSE_PARAMETERS_END();
+#endif
 
-       if (num < 0) {
-               php_error_docref(NULL, E_WARNING, "Number of elements can't be negative");
-               RETURN_FALSE;
-       }
+       if (EXPECTED(num > 0)) {
+               if (sizeof(num) > 4 && UNEXPECTED(EXPECTED(num > 0x7fffffff))) {
+                       php_error_docref(NULL, E_WARNING, "Too many elements");
+                       RETURN_FALSE;
+               } else if (UNEXPECTED(start_key > ZEND_LONG_MAX - num + 1)) {
+                       php_error_docref(NULL, E_WARNING, "Cannot add element to the array as the next element is already occupied");
+                       RETURN_FALSE;
+               } else if (EXPECTED(start_key >= 0) && EXPECTED(start_key < num)) {
+                       /* create packed array */
+                       Bucket *p;
+                       zend_long n;
 
-       /* allocate an array for return */
-       array_init_size(return_value, (uint32_t)num);
+                       array_init_size(return_value, (uint32_t)(start_key + num));
+                       zend_hash_real_init(Z_ARRVAL_P(return_value), 1);
+                       Z_ARRVAL_P(return_value)->nNumUsed = start_key + num;
+                       Z_ARRVAL_P(return_value)->nNumOfElements = num;
+                       Z_ARRVAL_P(return_value)->nInternalPointer = start_key;
 
-       if (num == 0) {
-               return;
-       }
+                       if (Z_REFCOUNTED_P(val)) {
+                               GC_REFCOUNT(Z_COUNTED_P(val)) += num;
+                       }
 
-       num--;
-       zend_hash_index_update(Z_ARRVAL_P(return_value), start_key, val);
-       Z_TRY_ADDREF_P(val);
+                       p = Z_ARRVAL_P(return_value)->arData;
+                       n = start_key;
 
-       while (num--) {
-               if (zend_hash_next_index_insert(Z_ARRVAL_P(return_value), val) != NULL) {
-                       Z_TRY_ADDREF_P(val);
+                       while (start_key--) {
+                               ZVAL_UNDEF(&p->val);
+                               p++;
+                       }
+                       while (num--) {
+                               ZVAL_COPY_VALUE(&p->val, val);
+                               p->h = n++;
+                               p->key = NULL;
+                               p++;
+                       }
                } else {
-                       zval_dtor(return_value);
-                       php_error_docref(NULL, E_WARNING, "Cannot add element to the array as the next element is already occupied");
-                       RETURN_FALSE;
+                       /* create hash */
+                       array_init_size(return_value, (uint32_t)num);
+                       zend_hash_real_init(Z_ARRVAL_P(return_value), 0);
+                       if (Z_REFCOUNTED_P(val)) {
+                               GC_REFCOUNT(Z_COUNTED_P(val)) += num;
+                       }
+                       zend_hash_index_add_new(Z_ARRVAL_P(return_value), start_key, val);
+                       while (--num) {
+                               zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), val);
+                               start_key++;
+                       }
                }
+       } else if (EXPECTED(num == 0)) {
+               array_init(return_value);
+               return;
+       } else {
+               php_error_docref(NULL, E_WARNING, "Number of elements can't be negative");
+               RETURN_FALSE;
        }
 }
 /* }}} */