com php-src: Minor optimizations to array_keys()/array_ values(): NEWS ext/standard/array.c ext/standard/ tests/array/packed_001.phpt

[email protected] (Sara Golemon)
Newsgroups php.cvs
Message-ID <[email protected]>
Commit:    c74bc87c74f48bc55541b3bf2fc67d595f58a3b5
Author:    Sara Golemon <[email protected]>         Tue, 14 Mar 2017 10:30:49 -0700
Parents:   16ae9f82e82e2aea5d7deaf8f9a9c825a56dfcc1
Branches:  master

Link:       http://git.php.net/?p=php-src.git;a=commitdiff;h=c74bc87c74f48bc55541b3bf2fc67d595f58a3b5

Log:
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)

Changed paths:
  M  NEWS
  M  ext/standard/array.c
  A  ext/standard/tests/array/packed_001.phpt


Diff:
diff --git a/NEWS b/NEWS
index 7aa4ccf..84cf31d 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 8b9ad19..6e94ed6 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 0000000..81973c7
--- /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
+)
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.