1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 00:02:20 +01:00

ext/standard/array.c: refactor sort functions (#20462)

Consolidate userland functions to rely on a single implementation
Split get_comparison functions into a reverse and a normal one
Use bool type when applicable
This commit is contained in:
Gina Peter Banyard
2025-11-13 01:34:45 +00:00
committed by GitHub
parent 0c97fe082f
commit 31bd92d2dc

View File

@@ -214,7 +214,7 @@ static zend_always_inline int php_array_key_compare_string_unstable_i(Bucket *f,
}
/* }}} */
static int php_array_key_compare_string_natural_general(Bucket *f, Bucket *s, int fold_case) /* {{{ */
static int php_array_key_compare_string_natural_general(Bucket *f, Bucket *s, bool fold_case) /* {{{ */
{
const char *s1, *s2;
size_t l1, l2;
@@ -241,25 +241,25 @@ static int php_array_key_compare_string_natural_general(Bucket *f, Bucket *s, in
static int php_array_key_compare_string_natural_case(Bucket *a, Bucket *b) /* {{{ */
{
RETURN_STABLE_SORT(a, b, php_array_key_compare_string_natural_general(a, b, 1));
RETURN_STABLE_SORT(a, b, php_array_key_compare_string_natural_general(a, b, true));
}
/* }}} */
static int php_array_reverse_key_compare_string_natural_case(Bucket *a, Bucket *b) /* {{{ */
{
RETURN_STABLE_SORT(a, b, php_array_key_compare_string_natural_general(b, a, 1));
RETURN_STABLE_SORT(a, b, php_array_key_compare_string_natural_general(b, a, true));
}
/* }}} */
static int php_array_key_compare_string_natural(Bucket *a, Bucket *b) /* {{{ */
{
RETURN_STABLE_SORT(a, b, php_array_key_compare_string_natural_general(a, b, 0));
RETURN_STABLE_SORT(a, b, php_array_key_compare_string_natural_general(a, b, false));
}
/* }}} */
static int php_array_reverse_key_compare_string_natural(Bucket *a, Bucket *b) /* {{{ */
{
RETURN_STABLE_SORT(a, b, php_array_key_compare_string_natural_general(b, a, 0));
RETURN_STABLE_SORT(a, b, php_array_key_compare_string_natural_general(b, a, false));
}
/* }}} */
@@ -327,7 +327,7 @@ static zend_always_inline int php_array_data_compare_string_unstable_i(Bucket *f
}
/* }}} */
static int php_array_natural_general_compare(Bucket *f, Bucket *s, int fold_case) /* {{{ */
static int php_array_natural_general_compare(Bucket *f, Bucket *s, bool fold_case) /* {{{ */
{
zend_string *tmp_str1, *tmp_str2;
zend_string *str1 = zval_get_tmp_string(&f->val, &tmp_str1);
@@ -343,13 +343,13 @@ static int php_array_natural_general_compare(Bucket *f, Bucket *s, int fold_case
static zend_always_inline int php_array_natural_compare_unstable_i(Bucket *a, Bucket *b) /* {{{ */
{
return php_array_natural_general_compare(a, b, 0);
return php_array_natural_general_compare(a, b, false);
}
/* }}} */
static zend_always_inline int php_array_natural_case_compare_unstable_i(Bucket *a, Bucket *b) /* {{{ */
{
return php_array_natural_general_compare(a, b, 1);
return php_array_natural_general_compare(a, b, true);
}
/* }}} */
@@ -372,135 +372,127 @@ DEFINE_SORT_VARIANTS(data_compare_string_locale);
DEFINE_SORT_VARIANTS(natural_compare);
DEFINE_SORT_VARIANTS(natural_case_compare);
static bucket_compare_func_t php_get_key_compare_func(zend_long sort_type, int reverse) /* {{{ */
static bucket_compare_func_t php_get_key_compare_func(zend_long sort_type)
{
switch (sort_type & ~PHP_SORT_FLAG_CASE) {
case PHP_SORT_NUMERIC:
if (reverse) {
return php_array_reverse_key_compare_numeric;
} else {
return php_array_key_compare_numeric;
}
break;
return php_array_key_compare_numeric;
case PHP_SORT_STRING:
if (sort_type & PHP_SORT_FLAG_CASE) {
if (reverse) {
return php_array_reverse_key_compare_string_case;
} else {
return php_array_key_compare_string_case;
}
return php_array_key_compare_string_case;
} else {
if (reverse) {
return php_array_reverse_key_compare_string;
} else {
return php_array_key_compare_string;
}
return php_array_key_compare_string;
}
break;
case PHP_SORT_NATURAL:
if (sort_type & PHP_SORT_FLAG_CASE) {
if (reverse) {
return php_array_reverse_key_compare_string_natural_case;
} else {
return php_array_key_compare_string_natural_case;
}
return php_array_key_compare_string_natural_case;
} else {
if (reverse) {
return php_array_reverse_key_compare_string_natural;
} else {
return php_array_key_compare_string_natural;
}
return php_array_key_compare_string_natural;
}
break;
case PHP_SORT_LOCALE_STRING:
if (reverse) {
return php_array_reverse_key_compare_string_locale;
} else {
return php_array_key_compare_string_locale;
}
break;
return php_array_key_compare_string_locale;
case PHP_SORT_REGULAR:
default:
if (reverse) {
return php_array_reverse_key_compare;
} else {
return php_array_key_compare;
}
break;
return php_array_key_compare;
}
return NULL;
}
/* }}} */
static bucket_compare_func_t php_get_data_compare_func(zend_long sort_type, int reverse) /* {{{ */
static bucket_compare_func_t php_get_key_reverse_compare_func(zend_long sort_type)
{
switch (sort_type & ~PHP_SORT_FLAG_CASE) {
case PHP_SORT_NUMERIC:
if (reverse) {
return php_array_reverse_data_compare_numeric;
} else {
return php_array_data_compare_numeric;
}
break;
return php_array_reverse_key_compare_numeric;
case PHP_SORT_STRING:
if (sort_type & PHP_SORT_FLAG_CASE) {
if (reverse) {
return php_array_reverse_data_compare_string_case;
} else {
return php_array_data_compare_string_case;
}
return php_array_reverse_key_compare_string_case;
} else {
if (reverse) {
return php_array_reverse_data_compare_string;
} else {
return php_array_data_compare_string;
}
return php_array_reverse_key_compare_string;
}
break;
case PHP_SORT_NATURAL:
if (sort_type & PHP_SORT_FLAG_CASE) {
if (reverse) {
return php_array_reverse_natural_case_compare;
} else {
return php_array_natural_case_compare;
}
return php_array_reverse_key_compare_string_natural_case;
} else {
if (reverse) {
return php_array_reverse_natural_compare;
} else {
return php_array_natural_compare;
}
return php_array_reverse_key_compare_string_natural;
}
break;
case PHP_SORT_LOCALE_STRING:
if (reverse) {
return php_array_reverse_data_compare_string_locale;
} else {
return php_array_data_compare_string_locale;
}
break;
return php_array_reverse_key_compare_string_locale;
case PHP_SORT_REGULAR:
default:
if (reverse) {
return php_array_reverse_data_compare;
} else {
return php_array_data_compare;
}
break;
return php_array_reverse_key_compare;
}
return NULL;
}
/* }}} */
static bucket_compare_func_t php_get_data_compare_func_unstable(zend_long sort_type, int reverse) /* {{{ */
static bucket_compare_func_t php_get_data_compare_func(zend_long sort_type) /* {{{ */
{
switch (sort_type & ~PHP_SORT_FLAG_CASE) {
case PHP_SORT_NUMERIC:
return php_array_data_compare_numeric;
case PHP_SORT_STRING:
if (sort_type & PHP_SORT_FLAG_CASE) {
return php_array_data_compare_string_case;
} else {
return php_array_data_compare_string;
}
case PHP_SORT_NATURAL:
if (sort_type & PHP_SORT_FLAG_CASE) {
return php_array_natural_case_compare;
} else {
return php_array_natural_compare;
}
case PHP_SORT_LOCALE_STRING:
return php_array_data_compare_string_locale;
case PHP_SORT_REGULAR:
default:
return php_array_data_compare;
}
return NULL;
}
static bucket_compare_func_t php_get_data_reverse_compare_func(zend_long sort_type) /* {{{ */
{
switch (sort_type & ~PHP_SORT_FLAG_CASE) {
case PHP_SORT_NUMERIC:
return php_array_reverse_data_compare_numeric;
case PHP_SORT_STRING:
if (sort_type & PHP_SORT_FLAG_CASE) {
return php_array_reverse_data_compare_string_case;
} else {
return php_array_reverse_data_compare_string;
}
case PHP_SORT_NATURAL:
if (sort_type & PHP_SORT_FLAG_CASE) {
return php_array_reverse_natural_case_compare;
} else {
return php_array_reverse_natural_compare;
}
case PHP_SORT_LOCALE_STRING:
return php_array_reverse_data_compare_string_locale;
case PHP_SORT_REGULAR:
default:
return php_array_reverse_data_compare;
}
return NULL;
}
static bucket_compare_func_t php_get_data_compare_func_unstable(zend_long sort_type, bool reverse) /* {{{ */
{
switch (sort_type & ~PHP_SORT_FLAG_CASE) {
case PHP_SORT_NUMERIC:
@@ -564,48 +556,6 @@ static bucket_compare_func_t php_get_data_compare_func_unstable(zend_long sort_t
}
/* }}} */
/* {{{ Sort an array by key value in reverse order */
PHP_FUNCTION(krsort)
{
zval *array;
zend_long sort_type = PHP_SORT_REGULAR;
bucket_compare_func_t cmp;
ZEND_PARSE_PARAMETERS_START(1, 2)
Z_PARAM_ARRAY_EX(array, 0, 1)
Z_PARAM_OPTIONAL
Z_PARAM_LONG(sort_type)
ZEND_PARSE_PARAMETERS_END();
cmp = php_get_key_compare_func(sort_type, 1);
zend_hash_sort(Z_ARRVAL_P(array), cmp, 0);
RETURN_TRUE;
}
/* }}} */
/* {{{ Sort an array by key */
PHP_FUNCTION(ksort)
{
zval *array;
zend_long sort_type = PHP_SORT_REGULAR;
bucket_compare_func_t cmp;
ZEND_PARSE_PARAMETERS_START(1, 2)
Z_PARAM_ARRAY_EX(array, 0, 1)
Z_PARAM_OPTIONAL
Z_PARAM_LONG(sort_type)
ZEND_PARSE_PARAMETERS_END();
cmp = php_get_key_compare_func(sort_type, 0);
zend_hash_sort(Z_ARRVAL_P(array), cmp, 0);
RETURN_TRUE;
}
/* }}} */
PHPAPI zend_long php_count_recursive(HashTable *ht) /* {{{ */
{
zend_long cnt = 0;
@@ -702,119 +652,92 @@ PHP_FUNCTION(count)
}
/* }}} */
static void php_natsort(INTERNAL_FUNCTION_PARAMETERS, int fold_case) /* {{{ */
static void php_natsort(INTERNAL_FUNCTION_PARAMETERS, bucket_compare_func_t sort_fn)
{
zval *array;
HashTable *array;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_ARRAY_EX(array, 0, 1)
Z_PARAM_ARRAY_HT_EX(array, 0, 1)
ZEND_PARSE_PARAMETERS_END();
if (fold_case) {
zend_array_sort(Z_ARRVAL_P(array), php_array_natural_case_compare, 0);
} else {
zend_array_sort(Z_ARRVAL_P(array), php_array_natural_compare, 0);
}
zend_array_sort(array, sort_fn, false);
RETURN_TRUE;
}
/* }}} */
/* {{{ Sort an array using natural sort */
PHP_FUNCTION(natsort)
{
php_natsort(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
php_natsort(INTERNAL_FUNCTION_PARAM_PASSTHRU, php_array_natural_compare);
}
/* }}} */
/* {{{ Sort an array using case-insensitive natural sort */
PHP_FUNCTION(natcasesort)
{
php_natsort(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
php_natsort(INTERNAL_FUNCTION_PARAM_PASSTHRU, php_array_natural_case_compare);
}
/* }}} */
/* {{{ Sort an array and maintain index association */
PHP_FUNCTION(asort)
{
zval *array;
typedef bucket_compare_func_t(*get_compare_function)(zend_long);
static zend_always_inline void php_sort(INTERNAL_FUNCTION_PARAMETERS, get_compare_function get_cmp, bool renumber) {
HashTable *array;
zend_long sort_type = PHP_SORT_REGULAR;
bucket_compare_func_t cmp;
ZEND_PARSE_PARAMETERS_START(1, 2)
Z_PARAM_ARRAY_EX(array, 0, 1)
Z_PARAM_ARRAY_HT_EX(array, 0, 1)
Z_PARAM_OPTIONAL
Z_PARAM_LONG(sort_type)
ZEND_PARSE_PARAMETERS_END();
cmp = php_get_data_compare_func(sort_type, 0);
cmp = get_cmp(sort_type);
zend_array_sort(Z_ARRVAL_P(array), cmp, 0);
zend_array_sort(array, cmp, renumber);
RETURN_TRUE;
}
/* {{{ Sort an array and maintain index association */
PHP_FUNCTION(asort)
{
php_sort(INTERNAL_FUNCTION_PARAM_PASSTHRU, php_get_data_compare_func, false);
}
/* }}} */
/* {{{ Sort an array in reverse order and maintain index association */
PHP_FUNCTION(arsort)
{
zval *array;
zend_long sort_type = PHP_SORT_REGULAR;
bucket_compare_func_t cmp;
ZEND_PARSE_PARAMETERS_START(1, 2)
Z_PARAM_ARRAY_EX(array, 0, 1)
Z_PARAM_OPTIONAL
Z_PARAM_LONG(sort_type)
ZEND_PARSE_PARAMETERS_END();
cmp = php_get_data_compare_func(sort_type, 1);
zend_array_sort(Z_ARRVAL_P(array), cmp, 0);
RETURN_TRUE;
php_sort(INTERNAL_FUNCTION_PARAM_PASSTHRU, php_get_data_reverse_compare_func, false);
}
/* }}} */
/* {{{ Sort an array */
PHP_FUNCTION(sort)
{
zval *array;
zend_long sort_type = PHP_SORT_REGULAR;
bucket_compare_func_t cmp;
ZEND_PARSE_PARAMETERS_START(1, 2)
Z_PARAM_ARRAY_EX(array, 0, 1)
Z_PARAM_OPTIONAL
Z_PARAM_LONG(sort_type)
ZEND_PARSE_PARAMETERS_END();
cmp = php_get_data_compare_func(sort_type, 0);
zend_array_sort(Z_ARRVAL_P(array), cmp, 1);
RETURN_TRUE;
php_sort(INTERNAL_FUNCTION_PARAM_PASSTHRU, php_get_data_compare_func, true);
}
/* }}} */
/* {{{ Sort an array in reverse order */
PHP_FUNCTION(rsort)
{
zval *array;
zend_long sort_type = PHP_SORT_REGULAR;
bucket_compare_func_t cmp;
php_sort(INTERNAL_FUNCTION_PARAM_PASSTHRU, php_get_data_reverse_compare_func, true);
}
/* }}} */
ZEND_PARSE_PARAMETERS_START(1, 2)
Z_PARAM_ARRAY_EX(array, 0, 1)
Z_PARAM_OPTIONAL
Z_PARAM_LONG(sort_type)
ZEND_PARSE_PARAMETERS_END();
/* {{{ Sort an array by key value in reverse order */
PHP_FUNCTION(krsort)
{
php_sort(INTERNAL_FUNCTION_PARAM_PASSTHRU, php_get_key_reverse_compare_func, false);
}
/* }}} */
cmp = php_get_data_compare_func(sort_type, 1);
zend_array_sort(Z_ARRVAL_P(array), cmp, 1);
RETURN_TRUE;
/* {{{ Sort an array by key */
PHP_FUNCTION(ksort)
{
php_sort(INTERNAL_FUNCTION_PARAM_PASSTHRU, php_get_key_compare_func, false);
}
/* }}} */
@@ -912,14 +835,14 @@ static void php_usort(INTERNAL_FUNCTION_PARAMETERS, bucket_compare_func_t compar
/* {{{ Sort an array by values using a user-defined comparison function */
PHP_FUNCTION(usort)
{
php_usort(INTERNAL_FUNCTION_PARAM_PASSTHRU, php_array_user_compare, 1);
php_usort(INTERNAL_FUNCTION_PARAM_PASSTHRU, php_array_user_compare, true);
}
/* }}} */
/* {{{ Sort an array with a user-defined comparison function and maintain index association */
PHP_FUNCTION(uasort)
{
php_usort(INTERNAL_FUNCTION_PARAM_PASSTHRU, php_array_user_compare, 0);
php_usort(INTERNAL_FUNCTION_PARAM_PASSTHRU, php_array_user_compare, false);
}
/* }}} */
@@ -986,7 +909,7 @@ static int php_array_user_key_compare(Bucket *a, Bucket *b) /* {{{ */
/* {{{ Sort an array by keys using a user-defined comparison function */
PHP_FUNCTION(uksort)
{
php_usort(INTERNAL_FUNCTION_PARAM_PASSTHRU, php_array_user_key_compare, 0);
php_usort(INTERNAL_FUNCTION_PARAM_PASSTHRU, php_array_user_key_compare, false);
}
/* }}} */
@@ -5014,7 +4937,7 @@ PHP_FUNCTION(array_unique)
return;
}
cmp = php_get_data_compare_func_unstable(sort_type, 0);
cmp = php_get_data_compare_func_unstable(sort_type, false);
bool in_place = zend_may_modify_arg_in_place(array);
if (in_place) {