diff --git a/ext/standard/array.c b/ext/standard/array.c index c1cae18f58783..3d9a52724c580 100644 --- a/ext/standard/array.c +++ b/ext/standard/array.c @@ -119,6 +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_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; } /* }}} */ @@ -4071,6 +4073,78 @@ PHP_FUNCTION(array_values) } /* }}} */ +/* {{{ 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 855bdacd95783..6f76c7591d789 100644 --- a/ext/standard/basic_functions.c +++ b/ext/standard/basic_functions.c @@ -416,11 +416,15 @@ 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(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() + ZEND_BEGIN_ARG_INFO(arginfo_array_count_values, 0) ZEND_ARG_INFO(0, arg) /* ARRAY_INFO(0, arg, 0) */ ZEND_END_ARG_INFO() @@ -3370,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 e15b116802bc2..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,6 +125,9 @@ PHPAPI zend_long php_count_recursive(HashTable *ht); #define ARRAY_FILTER_USE_BOTH 1 #define ARRAY_FILTER_USE_KEY 2 +#define ARRAY_REINDEX_SKIP_NULL 1<<1 +#define ARRAY_REINDEX_SKIP_EMPTY 1<<2 + ZEND_BEGIN_MODULE_GLOBALS(array) compare_func_t *multisort_func; ZEND_END_MODULE_GLOBALS(array)