From 1bf39a0249bc3a02a990639fcd70be3e62e4c2d5 Mon Sep 17 00:00:00 2001 From: rjhdby Date: Tue, 5 Mar 2019 17:52:04 +0300 Subject: [PATCH 1/2] array_values improvment --- ext/standard/array.c | 82 ++++++++++++++++++++++++++++++---- ext/standard/basic_functions.c | 3 +- ext/standard/php_array.h | 4 ++ 3 files changed, 79 insertions(+), 10 deletions(-) diff --git a/ext/standard/array.c b/ext/standard/array.c index 8c3d5ef20012c..a7445b1800875 100644 --- a/ext/standard/array.c +++ b/ext/standard/array.c @@ -119,6 +119,9 @@ PHP_MINIT_FUNCTION(array) /* {{{ */ REGISTER_LONG_CONSTANT("ARRAY_FILTER_USE_BOTH", ARRAY_FILTER_USE_BOTH, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("ARRAY_FILTER_USE_KEY", ARRAY_FILTER_USE_KEY, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("ARRAY_VALUES_IN_PLACE", ARRAY_VALUES_IN_PLACE, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("ARRAY_VALUES_SKIP_NULL", ARRAY_VALUES_SKIP_NULL, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("ARRAY_VALUES_SKIP_FALSE", ARRAY_VALUES_SKIP_FALSE, CONST_CS | CONST_PERSISTENT); return SUCCESS; } /* }}} */ @@ -4032,40 +4035,101 @@ PHP_FUNCTION(array_values) { zval *input, /* Input array */ *entry; /* An entry in the input array */ + zend_long flags = 0; zend_array *arrval; zend_long arrlen; - ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_ARRAY(input) + ZEND_PARSE_PARAMETERS_START(1, 2) + Z_PARAM_ARRAY_EX(input, 0, 1) + Z_PARAM_OPTIONAL + Z_PARAM_LONG(flags) ZEND_PARSE_PARAMETERS_END(); + zend_bool skip_null = flags & ARRAY_VALUES_SKIP_NULL; + zend_bool skip_false = flags & ARRAY_VALUES_SKIP_FALSE; + zend_bool in_place = flags & ARRAY_VALUES_IN_PLACE; + arrval = Z_ARRVAL_P(input); /* Return empty input as is */ arrlen = zend_hash_num_elements(arrval); if (!arrlen) { - ZVAL_EMPTY_ARRAY(return_value); + if (UNEXPECTED(in_place)) { + RETURN_TRUE; + } else { + ZVAL_EMPTY_ARRAY(return_value); + } return; } /* Return vector-like packed arrays as-is */ if (HT_IS_PACKED(arrval) && HT_IS_WITHOUT_HOLES(arrval) && - arrval->nNextFreeElement == arrlen) { + arrval->nNextFreeElement == arrlen && !(skip_null || skip_false)) { + if (in_place) { + RETURN_TRUE; + } RETURN_ZVAL(input, 1, 0); } + if (in_place) { + uint32_t i = 0, skip = 0; + Bucket *p; + ZEND_HASH_FOREACH_VAL(arrval, entry) { + if (UNEXPECTED((skip_null && Z_TYPE_P(entry) == IS_NULL) + || (skip_false && !zend_is_true(entry))) == 1) { + zval_ptr_dtor(entry); + skip++; + } else if (skip) { + p = arrval->arData + i - skip; + zval *value = &p->val; + ZVAL_COPY_VALUE(value, entry); + zval_copy_ctor(value); + zval_ptr_dtor(entry); + } + p = arrval->arData + i; + p->h = i; + if (p->key) { + zend_string_release(p->key); + p->key = NULL; + } + i++; + } ZEND_HASH_FOREACH_END(); + arrval->nNextFreeElement = i - skip; + arrval->nNumUsed = i - skip; + arrval->nNumOfElements = i - skip; + + if (!HT_IS_PACKED(arrval)) { + zend_hash_to_packed(arrval); + } + RETURN_TRUE; + } + + uint32_t skip = 0; + if (UNEXPECTED(skip_null || skip_false) == 1) { + ZEND_HASH_FOREACH_VAL(arrval, entry) { + if (UNEXPECTED((skip_null && Z_TYPE_P(entry) == IS_NULL) + || (skip_false && !zend_is_true(entry))) == 1) { + skip++; + } + } ZEND_HASH_FOREACH_END(); + } /* Initialize return array */ - array_init_size(return_value, zend_hash_num_elements(arrval)); + array_init_size(return_value, zend_hash_num_elements(arrval) - skip); zend_hash_real_init_packed(Z_ARRVAL_P(return_value)); /* Go through input array and add values to the return array */ ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) { ZEND_HASH_FOREACH_VAL(arrval, entry) { - if (UNEXPECTED(Z_ISREF_P(entry) && Z_REFCOUNT_P(entry) == 1)) { - entry = Z_REFVAL_P(entry); + if (UNEXPECTED((skip_null && Z_TYPE_P(entry) == IS_NULL) + || (skip_false && !zend_is_true(entry))) == 1) { + continue; + } else { + if (UNEXPECTED(Z_ISREF_P(entry) && Z_REFCOUNT_P(entry) == 1)) { + entry = Z_REFVAL_P(entry); + } + Z_TRY_ADDREF_P(entry); + ZEND_HASH_FILL_ADD(entry); } - Z_TRY_ADDREF_P(entry); - ZEND_HASH_FILL_ADD(entry); } ZEND_HASH_FOREACH_END(); } ZEND_HASH_FILL_END(); } diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c index 855bdacd95783..499adeef7d3c9 100644 --- a/ext/standard/basic_functions.c +++ b/ext/standard/basic_functions.c @@ -418,7 +418,8 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO(arginfo_array_values, 0) - ZEND_ARG_INFO(0, arg) /* ARRAY_INFO(0, arg, 0) */ + ZEND_ARG_INFO(1, arg) /* ARRAY_INFO(0, arg, 0) */ + ZEND_ARG_INFO(0, flags) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO(arginfo_array_count_values, 0) diff --git a/ext/standard/php_array.h b/ext/standard/php_array.h index e15b116802bc2..126859aa853d9 100644 --- a/ext/standard/php_array.h +++ b/ext/standard/php_array.h @@ -124,6 +124,10 @@ PHPAPI zend_long php_count_recursive(HashTable *ht); #define ARRAY_FILTER_USE_BOTH 1 #define ARRAY_FILTER_USE_KEY 2 +#define ARRAY_VALUES_IN_PLACE 1<<1 +#define ARRAY_VALUES_SKIP_NULL 1<<2 +#define ARRAY_VALUES_SKIP_FALSE 1<<3 + ZEND_BEGIN_MODULE_GLOBALS(array) compare_func_t *multisort_func; ZEND_END_MODULE_GLOBALS(array) From ab43d3dfe391455814dbe83d9106447b04a36d3a Mon Sep 17 00:00:00 2001 From: rjhdby Date: Thu, 7 Mar 2019 15:17:50 +0300 Subject: [PATCH 2/2] array_reindex --- ext/standard/array.c | 156 ++++++++++++++++++--------------- ext/standard/basic_functions.c | 8 +- ext/standard/php_array.h | 6 +- 3 files changed, 92 insertions(+), 78 deletions(-) diff --git a/ext/standard/array.c b/ext/standard/array.c index dbca5cf91b759..3d9a52724c580 100644 --- a/ext/standard/array.c +++ b/ext/standard/array.c @@ -119,9 +119,8 @@ PHP_MINIT_FUNCTION(array) /* {{{ */ REGISTER_LONG_CONSTANT("ARRAY_FILTER_USE_BOTH", ARRAY_FILTER_USE_BOTH, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("ARRAY_FILTER_USE_KEY", ARRAY_FILTER_USE_KEY, CONST_CS | CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("ARRAY_VALUES_IN_PLACE", ARRAY_VALUES_IN_PLACE, CONST_CS | CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("ARRAY_VALUES_SKIP_NULL", ARRAY_VALUES_SKIP_NULL, CONST_CS | CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("ARRAY_VALUES_SKIP_FALSE", ARRAY_VALUES_SKIP_FALSE, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("ARRAY_REINDEX_SKIP_NULL", ARRAY_REINDEX_SKIP_NULL, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("ARRAY_REINDEX_SKIP_EMPTY", ARRAY_REINDEX_SKIP_EMPTY, CONST_CS | CONST_PERSISTENT); return SUCCESS; } /* }}} */ @@ -4035,106 +4034,117 @@ PHP_FUNCTION(array_values) { zval *input, /* Input array */ *entry; /* An entry in the input array */ - zend_long flags = 0; zend_array *arrval; zend_long arrlen; - ZEND_PARSE_PARAMETERS_START(1, 2) - Z_PARAM_ARRAY_EX(input, 0, 1) - Z_PARAM_OPTIONAL - Z_PARAM_LONG(flags) + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ARRAY(input) ZEND_PARSE_PARAMETERS_END(); - zend_bool skip_null = flags & ARRAY_VALUES_SKIP_NULL; - zend_bool skip_false = flags & ARRAY_VALUES_SKIP_FALSE; - zend_bool in_place = flags & ARRAY_VALUES_IN_PLACE; - arrval = Z_ARRVAL_P(input); /* Return empty input as is */ arrlen = zend_hash_num_elements(arrval); if (!arrlen) { - if (UNEXPECTED(in_place)) { - RETURN_TRUE; - } else { - ZVAL_EMPTY_ARRAY(return_value); - } + ZVAL_EMPTY_ARRAY(return_value); return; } /* Return vector-like packed arrays as-is */ if (HT_IS_PACKED(arrval) && HT_IS_WITHOUT_HOLES(arrval) && - arrval->nNextFreeElement == arrlen && !(skip_null || skip_false)) { - if (in_place) { - RETURN_TRUE; - } + arrval->nNextFreeElement == arrlen) { RETURN_ZVAL(input, 1, 0); } - if (in_place) { - uint32_t i = 0, skip = 0; - Bucket *p; - ZEND_HASH_FOREACH_VAL(arrval, entry) { - if (UNEXPECTED((skip_null && Z_TYPE_P(entry) == IS_NULL) - || (skip_false && !zend_is_true(entry))) == 1) { - zval_ptr_dtor(entry); - skip++; - } else if (skip) { - p = arrval->arData + i - skip; - zval *value = &p->val; - ZVAL_COPY_VALUE(value, entry); - zval_copy_ctor(value); - zval_ptr_dtor(entry); - } - p = arrval->arData + i; - p->h = i; - if (p->key) { - zend_string_release(p->key); - p->key = NULL; - } - i++; - } ZEND_HASH_FOREACH_END(); - arrval->nNextFreeElement = i - skip; - arrval->nNumUsed = i - skip; - arrval->nNumOfElements = i - skip; - - if (!HT_IS_PACKED(arrval)) { - zend_hash_to_packed(arrval); - } - RETURN_TRUE; - } - - uint32_t skip = 0; - if (UNEXPECTED(skip_null || skip_false) == 1) { - ZEND_HASH_FOREACH_VAL(arrval, entry) { - if (UNEXPECTED((skip_null && Z_TYPE_P(entry) == IS_NULL) - || (skip_false && !zend_is_true(entry))) == 1) { - skip++; - } - } ZEND_HASH_FOREACH_END(); - } /* Initialize return array */ - array_init_size(return_value, zend_hash_num_elements(arrval) - skip); + array_init_size(return_value, zend_hash_num_elements(arrval)); zend_hash_real_init_packed(Z_ARRVAL_P(return_value)); /* Go through input array and add values to the return array */ ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) { ZEND_HASH_FOREACH_VAL(arrval, entry) { - if (UNEXPECTED((skip_null && Z_TYPE_P(entry) == IS_NULL) - || (skip_false && !zend_is_true(entry))) == 1) { - continue; - } else { - if (UNEXPECTED(Z_ISREF_P(entry) && Z_REFCOUNT_P(entry) == 1)) { - entry = Z_REFVAL_P(entry); - } - Z_TRY_ADDREF_P(entry); - ZEND_HASH_FILL_ADD(entry); + if (UNEXPECTED(Z_ISREF_P(entry) && Z_REFCOUNT_P(entry) == 1)) { + entry = Z_REFVAL_P(entry); } + Z_TRY_ADDREF_P(entry); + ZEND_HASH_FILL_ADD(entry); } ZEND_HASH_FOREACH_END(); } ZEND_HASH_FILL_END(); } /* }}} */ +/* {{{ proto array array_reindex(array input, int flags) */ +PHP_FUNCTION(array_reindex) +{ + zval *input, /* Input array */ + *entry; /* An entry in the input array */ + zend_long flags = 0; + zend_array *arrval; + zend_long arrlen; + uint32_t i = 0, skip = 0, reindexed = 0; + Bucket *p; + + ZEND_PARSE_PARAMETERS_START(1, 2) + Z_PARAM_ARRAY_EX(input, 0, 1) + Z_PARAM_OPTIONAL + Z_PARAM_LONG(flags) + ZEND_PARSE_PARAMETERS_END(); + + zend_bool skip_null = flags & ARRAY_REINDEX_SKIP_NULL; + zend_bool skip_false = flags & ARRAY_REINDEX_SKIP_EMPTY; + + arrval = Z_ARRVAL_P(input); + + /* Do not reindex empty input */ + arrlen = zend_hash_num_elements(arrval); + if (!arrlen) { + RETURN_FALSE; + } + + /* Do not reindex vector-like packed arrays */ + if (HT_IS_PACKED(arrval) && HT_IS_WITHOUT_HOLES(arrval) && + arrval->nNextFreeElement == arrlen && !(skip_null || skip_false)) { + RETURN_FALSE; + } + + ZEND_HASH_FOREACH_VAL(arrval, entry) { + if (UNEXPECTED((skip_null && Z_TYPE_P(entry) == IS_NULL) + || (skip_false && !zend_is_true(entry))) == 1) { + zval_ptr_dtor(entry); + skip++; + } else if (skip) { + p = arrval->arData + i - skip; + zval *value = &p->val; + ZVAL_COPY_VALUE(value, entry); + zval_copy_ctor(value); + zval_ptr_dtor(entry); + } + p = arrval->arData + i; + if (p->h != i) { + reindexed = 1; + } + p->h = i; + if (p->key) { + zend_string_release(p->key); + p->key = NULL; + } + i++; + } ZEND_HASH_FOREACH_END(); + arrval->nNextFreeElement = i - skip; + arrval->nNumUsed = i - skip; + arrval->nNumOfElements = i - skip; + + if (!HT_IS_PACKED(arrval)) { + zend_hash_to_packed(arrval); + } + + if (skip || reindexed) { + RETURN_TRUE; + } + RETURN_FALSE; +} +/* }}} */ + /* {{{ proto array array_count_values(array input) Return the value as key and the frequency of that value in input as value */ PHP_FUNCTION(array_count_values) diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c index 499adeef7d3c9..6f76c7591d789 100644 --- a/ext/standard/basic_functions.c +++ b/ext/standard/basic_functions.c @@ -416,9 +416,12 @@ ZEND_BEGIN_ARG_INFO(arginfo_array_key_last, 0) ZEND_ARG_INFO(0, arg) /* ARRAY_INFO(0, arg, 0) */ ZEND_END_ARG_INFO() - ZEND_BEGIN_ARG_INFO(arginfo_array_values, 0) - ZEND_ARG_INFO(1, arg) /* ARRAY_INFO(0, arg, 0) */ + ZEND_ARG_INFO(0, arg) /* ARRAY_INFO(0, arg, 0) */ +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO(arginfo_array_reindex, 0) + ZEND_ARG_INFO(1, arg) /* ARRAY_INFO(1, arg, 0) */ ZEND_ARG_INFO(0, flags) ZEND_END_ARG_INFO() @@ -3371,6 +3374,7 @@ static const zend_function_entry basic_functions[] = { /* {{{ */ PHP_FE(array_key_first, arginfo_array_key_first) PHP_FE(array_key_last, arginfo_array_key_last) PHP_FE(array_values, arginfo_array_values) + PHP_FE(array_reindex, arginfo_array_reindex) PHP_FE(array_count_values, arginfo_array_count_values) PHP_FE(array_column, arginfo_array_column) PHP_FE(array_reverse, arginfo_array_reverse) diff --git a/ext/standard/php_array.h b/ext/standard/php_array.h index 126859aa853d9..bcc6294b0db90 100644 --- a/ext/standard/php_array.h +++ b/ext/standard/php_array.h @@ -70,6 +70,7 @@ PHP_FUNCTION(array_keys); PHP_FUNCTION(array_key_first); PHP_FUNCTION(array_key_last); PHP_FUNCTION(array_values); +PHP_FUNCTION(array_reindex); PHP_FUNCTION(array_count_values); PHP_FUNCTION(array_column); PHP_FUNCTION(array_reverse); @@ -124,9 +125,8 @@ PHPAPI zend_long php_count_recursive(HashTable *ht); #define ARRAY_FILTER_USE_BOTH 1 #define ARRAY_FILTER_USE_KEY 2 -#define ARRAY_VALUES_IN_PLACE 1<<1 -#define ARRAY_VALUES_SKIP_NULL 1<<2 -#define ARRAY_VALUES_SKIP_FALSE 1<<3 +#define ARRAY_REINDEX_SKIP_NULL 1<<1 +#define ARRAY_REINDEX_SKIP_EMPTY 1<<2 ZEND_BEGIN_MODULE_GLOBALS(array) compare_func_t *multisort_func;