summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSara Golemon <pollita@php.net>2017-03-14 10:30:49 -0700
committerSara Golemon <pollita@php.net>2017-03-14 11:23:02 -0700
commitc74bc87c74f48bc55541b3bf2fc67d595f58a3b5 (patch)
treef6a2a477370122232f54f5e95380c42d5d4b28e9
parent16ae9f82e82e2aea5d7deaf8f9a9c825a56dfcc1 (diff)
downloadphp-git-c74bc87c74f48bc55541b3bf2fc67d595f58a3b5.tar.gz
Minor optimizations to array_keys()/array_values()
array_values(): When the input is an empty array or a packed array with no gaps, return the original array. array_keys(): When the input is an empty array, return the original array. When the input is a packed array with no holes (and no search key specified), populate the return with a simple range(0, count($input) - 1)
-rw-r--r--NEWS1
-rw-r--r--ext/standard/array.c61
-rw-r--r--ext/standard/tests/array/packed_001.phpt84
3 files changed, 127 insertions, 19 deletions
diff --git a/NEWS b/NEWS
index 7aa4ccfe93..84cf31d401 100644
--- a/NEWS
+++ b/NEWS
@@ -22,6 +22,7 @@ PHP NEWS
bugs #53838, #61655, #66173, #70925, #72254, etc. (Andrea)
. Raised minimum supported Windows versions to Windows 7/Server 2008 R2.
(Anatol)
+ . Implemented minor optimization in array_keys/array_values(). (Sara)
. Fixed bug #73969 (segfault in debug_print_backtrace). (andrewnester)
. Added PHP_OS_FAMILY constant to determine on which OS we are. (Jan Altensen)
. Fixed bug #73994 (arginfo incorrect for unpack). (krakjoe)
diff --git a/ext/standard/array.c b/ext/standard/array.c
index 8b9ad196e4..6e94ed6759 100644
--- a/ext/standard/array.c
+++ b/ext/standard/array.c
@@ -3938,6 +3938,8 @@ PHP_FUNCTION(array_keys)
zend_bool strict = 0; /* do strict comparison */
zend_ulong num_idx;
zend_string *str_idx;
+ zend_array *arrval;
+ zend_ulong elem_count;
ZEND_PARSE_PARAMETERS_START(1, 3)
Z_PARAM_ARRAY(input)
@@ -3945,13 +3947,20 @@ PHP_FUNCTION(array_keys)
Z_PARAM_ZVAL(search_value)
Z_PARAM_BOOL(strict)
ZEND_PARSE_PARAMETERS_END();
+ arrval = Z_ARRVAL_P(input);
+ elem_count = zend_hash_num_elements(arrval);
+
+ /* Base case: empty input */
+ if (!elem_count) {
+ RETURN_ZVAL(input, 1, 0)
+ }
/* Initialize return array */
if (search_value != NULL) {
array_init(return_value);
if (strict) {
- ZEND_HASH_FOREACH_KEY_VAL_IND(Z_ARRVAL_P(input), num_idx, str_idx, entry) {
+ ZEND_HASH_FOREACH_KEY_VAL_IND(arrval, num_idx, str_idx, entry) {
ZVAL_DEREF(entry);
if (fast_is_identical_function(search_value, entry)) {
if (str_idx) {
@@ -3963,7 +3972,7 @@ PHP_FUNCTION(array_keys)
}
} ZEND_HASH_FOREACH_END();
} else {
- ZEND_HASH_FOREACH_KEY_VAL_IND(Z_ARRVAL_P(input), num_idx, str_idx, entry) {
+ ZEND_HASH_FOREACH_KEY_VAL_IND(arrval, num_idx, str_idx, entry) {
if (fast_equal_check_function(search_value, entry)) {
if (str_idx) {
ZVAL_STR_COPY(&new_val, str_idx);
@@ -3975,21 +3984,27 @@ PHP_FUNCTION(array_keys)
} ZEND_HASH_FOREACH_END();
}
} else {
- array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL_P(input)));
- if (!zend_hash_num_elements(Z_ARRVAL_P(input))) {
- return;
- }
+ array_init_size(return_value, elem_count);
zend_hash_real_init(Z_ARRVAL_P(return_value), 1);
ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
- /* Go through input array and add keys to the return array */
- ZEND_HASH_FOREACH_KEY_VAL_IND(Z_ARRVAL_P(input), num_idx, str_idx, entry) {
- if (str_idx) {
- ZVAL_STR_COPY(&new_val, str_idx);
- } else {
- ZVAL_LONG(&new_val, num_idx);
+ if (HT_IS_PACKED(arrval) && HT_IS_WITHOUT_HOLES(arrval)) {
+ /* Optimistic case: range(0..n-1) for vector-like packed array */
+ zval new_val;
+ ZVAL_LONG(&new_val, 0);
+ for (; Z_LVAL(new_val) < elem_count; ++Z_LVAL(new_val)) {
+ ZEND_HASH_FILL_ADD(&new_val);
}
- ZEND_HASH_FILL_ADD(&new_val);
- } ZEND_HASH_FOREACH_END();
+ } else {
+ /* Go through input array and add keys to the return array */
+ ZEND_HASH_FOREACH_KEY_VAL_IND(Z_ARRVAL_P(input), num_idx, str_idx, entry) {
+ if (str_idx) {
+ ZVAL_STR_COPY(&new_val, str_idx);
+ } else {
+ ZVAL_LONG(&new_val, num_idx);
+ }
+ ZEND_HASH_FILL_ADD(&new_val);
+ } ZEND_HASH_FOREACH_END();
+ }
} ZEND_HASH_FILL_END();
}
}
@@ -4001,23 +4016,31 @@ PHP_FUNCTION(array_values)
{
zval *input, /* Input array */
*entry; /* An entry in the input array */
+ zend_array *arrval;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_ARRAY(input)
ZEND_PARSE_PARAMETERS_END();
- /* Initialize return array */
- array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL_P(input)));
+ arrval = Z_ARRVAL_P(input);
- if (!zend_hash_num_elements(Z_ARRVAL_P(input))) {
- return;
+ /* Return empty input as is */
+ if (!zend_hash_num_elements(arrval)) {
+ RETURN_ZVAL(input, 1, 0);
}
+ /* Return vector-like packed arrays as-is */
+ if (HT_IS_PACKED(arrval) && HT_IS_WITHOUT_HOLES(arrval)) {
+ RETURN_ZVAL(input, 1, 0);
+ }
+
+ /* Initialize return array */
+ array_init_size(return_value, zend_hash_num_elements(arrval));
zend_hash_real_init(Z_ARRVAL_P(return_value), 1);
/* Go through input array and add values to the return array */
ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
- ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(input), entry) {
+ ZEND_HASH_FOREACH_VAL(arrval, entry) {
if (UNEXPECTED(Z_ISREF_P(entry) && Z_REFCOUNT_P(entry) == 1)) {
entry = Z_REFVAL_P(entry);
}
diff --git a/ext/standard/tests/array/packed_001.phpt b/ext/standard/tests/array/packed_001.phpt
new file mode 100644
index 0000000000..81973c7e0e
--- /dev/null
+++ b/ext/standard/tests/array/packed_001.phpt
@@ -0,0 +1,84 @@
+--TEST--
+array_keys() and array_values() w/ packed optimization
+--FILE--
+<?php
+
+$x = [1,2,3];
+unset($x[1]);
+
+$inputs = [
+ [],
+ [1,2,3],
+ [0=>1, 1=>2, 2=>3],
+ [1=>1, 2=>2, 3=>3],
+ [0=>1, 2=>3],
+ $x,
+];
+
+foreach ($inputs as $input) {
+ print_r(array_keys($input));
+ print_r(array_values($input));
+}
+--EXPECT--
+Array
+(
+)
+Array
+(
+)
+Array
+(
+ [0] => 0
+ [1] => 1
+ [2] => 2
+)
+Array
+(
+ [0] => 1
+ [1] => 2
+ [2] => 3
+)
+Array
+(
+ [0] => 0
+ [1] => 1
+ [2] => 2
+)
+Array
+(
+ [0] => 1
+ [1] => 2
+ [2] => 3
+)
+Array
+(
+ [0] => 1
+ [1] => 2
+ [2] => 3
+)
+Array
+(
+ [0] => 1
+ [1] => 2
+ [2] => 3
+)
+Array
+(
+ [0] => 0
+ [1] => 2
+)
+Array
+(
+ [0] => 1
+ [1] => 3
+)
+Array
+(
+ [0] => 0
+ [1] => 2
+)
+Array
+(
+ [0] => 1
+ [1] => 3
+)