Skip to content

Commit 6c2c7a0

Browse files
committed
Optimize array_unique()
In SORT_STRING mode, instead of sorting the array, build a hash of seen elements.
1 parent 5069d52 commit 6c2c7a0

File tree

2 files changed

+40
-19
lines changed

2 files changed

+40
-19
lines changed

ext/standard/array.c

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4477,14 +4477,51 @@ PHP_FUNCTION(array_unique)
44774477
Z_PARAM_LONG(sort_type)
44784478
ZEND_PARSE_PARAMETERS_END();
44794479

4480-
cmp = php_get_data_compare_func(sort_type, 0);
4481-
4482-
44834480
if (Z_ARRVAL_P(array)->nNumOfElements <= 1) { /* nothing to do */
44844481
ZVAL_COPY(return_value, array);
44854482
return;
44864483
}
44874484

4485+
if (sort_type == PHP_SORT_STRING) {
4486+
HashTable seen;
4487+
zend_long num_key;
4488+
zend_string *str_key;
4489+
zval *val;
4490+
4491+
zend_hash_init(&seen, zend_hash_num_elements(Z_ARRVAL_P(array)), NULL, NULL, 0);
4492+
array_init(return_value);
4493+
4494+
ZEND_HASH_FOREACH_KEY_VAL_IND(Z_ARRVAL_P(array), num_key, str_key, val) {
4495+
zval *retval;
4496+
if (Z_TYPE_P(val) == IS_STRING) {
4497+
retval = zend_hash_add_empty_element(&seen, Z_STR_P(val));
4498+
} else {
4499+
zend_string *str_val = zval_get_string(val);
4500+
retval = zend_hash_add_empty_element(&seen, str_val);
4501+
zend_string_release(str_val);
4502+
}
4503+
4504+
if (retval) {
4505+
/* First occurrence of the value */
4506+
if (UNEXPECTED(Z_ISREF_P(val) && Z_REFCOUNT_P(val) == 1)) {
4507+
ZVAL_DEREF(val);
4508+
}
4509+
Z_TRY_ADDREF_P(val);
4510+
4511+
if (str_key) {
4512+
zend_hash_add_new(Z_ARRVAL_P(return_value), str_key, val);
4513+
} else {
4514+
zend_hash_index_add_new(Z_ARRVAL_P(return_value), num_key, val);
4515+
}
4516+
}
4517+
} ZEND_HASH_FOREACH_END();
4518+
4519+
zend_hash_destroy(&seen);
4520+
return;
4521+
}
4522+
4523+
cmp = php_get_data_compare_func(sort_type, 0);
4524+
44884525
RETVAL_ARR(zend_array_dup(Z_ARRVAL_P(array)));
44894526

44904527
/* create and sort array with pointers to the target_hash buckets */

ext/standard/tests/array/array_unique_variation8.phpt

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -35,22 +35,6 @@ Notice: Array to string conversion in %sarray_unique_variation8.php on line %d
3535

3636
Notice: Array to string conversion in %sarray_unique_variation8.php on line %d
3737

38-
Notice: Array to string conversion in %sarray_unique_variation8.php on line %d
39-
40-
Notice: Array to string conversion in %sarray_unique_variation8.php on line %d
41-
42-
Notice: Array to string conversion in %sarray_unique_variation8.php on line %d
43-
44-
Notice: Array to string conversion in %sarray_unique_variation8.php on line %d
45-
46-
Notice: Array to string conversion in %sarray_unique_variation8.php on line %d
47-
48-
Notice: Array to string conversion in %sarray_unique_variation8.php on line %d
49-
50-
Notice: Array to string conversion in %sarray_unique_variation8.php on line %d
51-
52-
Notice: Array to string conversion in %sarray_unique_variation8.php on line %d
53-
5438
Notice: Array to string conversion in %sarray_unique_variation8.php on line %d
5539
array(1) {
5640
[0]=>

0 commit comments

Comments
 (0)