From 6c2c7a023da4223e41fea0225c51a417fc8eb10d Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Tue, 1 Aug 2017 18:07:26 +0200 Subject: [PATCH] Optimize array_unique() In SORT_STRING mode, instead of sorting the array, build a hash of seen elements. --- ext/standard/array.c | 43 +++++++++++++++++-- .../tests/array/array_unique_variation8.phpt | 16 ------- 2 files changed, 40 insertions(+), 19 deletions(-) diff --git a/ext/standard/array.c b/ext/standard/array.c index d6ea5c481b..9ddbf1f3bf 100644 --- a/ext/standard/array.c +++ b/ext/standard/array.c @@ -4477,14 +4477,51 @@ PHP_FUNCTION(array_unique) Z_PARAM_LONG(sort_type) ZEND_PARSE_PARAMETERS_END(); - cmp = php_get_data_compare_func(sort_type, 0); - - if (Z_ARRVAL_P(array)->nNumOfElements <= 1) { /* nothing to do */ ZVAL_COPY(return_value, array); return; } + if (sort_type == PHP_SORT_STRING) { + HashTable seen; + zend_long num_key; + zend_string *str_key; + zval *val; + + zend_hash_init(&seen, zend_hash_num_elements(Z_ARRVAL_P(array)), NULL, NULL, 0); + array_init(return_value); + + ZEND_HASH_FOREACH_KEY_VAL_IND(Z_ARRVAL_P(array), num_key, str_key, val) { + zval *retval; + if (Z_TYPE_P(val) == IS_STRING) { + retval = zend_hash_add_empty_element(&seen, Z_STR_P(val)); + } else { + zend_string *str_val = zval_get_string(val); + retval = zend_hash_add_empty_element(&seen, str_val); + zend_string_release(str_val); + } + + if (retval) { + /* First occurrence of the value */ + if (UNEXPECTED(Z_ISREF_P(val) && Z_REFCOUNT_P(val) == 1)) { + ZVAL_DEREF(val); + } + Z_TRY_ADDREF_P(val); + + if (str_key) { + zend_hash_add_new(Z_ARRVAL_P(return_value), str_key, val); + } else { + zend_hash_index_add_new(Z_ARRVAL_P(return_value), num_key, val); + } + } + } ZEND_HASH_FOREACH_END(); + + zend_hash_destroy(&seen); + return; + } + + cmp = php_get_data_compare_func(sort_type, 0); + RETVAL_ARR(zend_array_dup(Z_ARRVAL_P(array))); /* create and sort array with pointers to the target_hash buckets */ diff --git a/ext/standard/tests/array/array_unique_variation8.phpt b/ext/standard/tests/array/array_unique_variation8.phpt index 3b4eac9f75..8b67adfbab 100644 --- a/ext/standard/tests/array/array_unique_variation8.phpt +++ b/ext/standard/tests/array/array_unique_variation8.phpt @@ -35,22 +35,6 @@ Notice: Array to string conversion in %sarray_unique_variation8.php on line %d Notice: Array to string conversion in %sarray_unique_variation8.php on line %d -Notice: Array to string conversion in %sarray_unique_variation8.php on line %d - -Notice: Array to string conversion in %sarray_unique_variation8.php on line %d - -Notice: Array to string conversion in %sarray_unique_variation8.php on line %d - -Notice: Array to string conversion in %sarray_unique_variation8.php on line %d - -Notice: Array to string conversion in %sarray_unique_variation8.php on line %d - -Notice: Array to string conversion in %sarray_unique_variation8.php on line %d - -Notice: Array to string conversion in %sarray_unique_variation8.php on line %d - -Notice: Array to string conversion in %sarray_unique_variation8.php on line %d - Notice: Array to string conversion in %sarray_unique_variation8.php on line %d array(1) { [0]=> -- 2.50.1