Skip to content

Commit b6becad

Browse files
committed
Implement packed fast-path for array_map()
1 parent fca3651 commit b6becad

File tree

1 file changed

+53
-21
lines changed

1 file changed

+53
-21
lines changed

ext/standard/array.c

Lines changed: 53 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6747,41 +6747,73 @@ PHP_FUNCTION(array_map)
67476747
ZEND_PARSE_PARAMETERS_END();
67486748

67496749
if (n_arrays == 1) {
6750-
zend_ulong num_key;
6751-
zend_string *str_key;
6752-
67536750
if (Z_TYPE(arrays[0]) != IS_ARRAY) {
67546751
zend_argument_type_error(2, "must be of type array, %s given", zend_zval_value_name(&arrays[0]));
67556752
RETURN_THROWS();
67566753
}
6757-
maxlen = zend_hash_num_elements(Z_ARRVAL(arrays[0]));
6754+
const HashTable *input = Z_ARRVAL(arrays[0]);
6755+
maxlen = zend_hash_num_elements(input);
67586756

67596757
/* Short-circuit: if no callback and only one array, just return it. */
67606758
if (!ZEND_FCI_INITIALIZED(fci) || !maxlen) {
67616759
ZVAL_COPY(return_value, &arrays[0]);
67626760
return;
67636761
}
67646762

6765-
array_init_size(return_value, maxlen);
6766-
zend_hash_real_init(Z_ARRVAL_P(return_value), HT_IS_PACKED(Z_ARRVAL(arrays[0])));
6767-
67686763
fci.retval = &result;
67696764
fci.param_count = 1;
67706765

6771-
ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL(arrays[0]), num_key, str_key, fci.params) {
6772-
zend_result ret = zend_call_function(&fci, &fci_cache);
6773-
ZEND_ASSERT(ret == SUCCESS);
6774-
ZEND_IGNORE_VALUE(ret);
6775-
if (Z_TYPE(result) == IS_UNDEF) {
6776-
zend_array_destroy(Z_ARR_P(return_value));
6777-
RETURN_NULL();
6778-
}
6779-
if (str_key) {
6780-
_zend_hash_append(Z_ARRVAL_P(return_value), str_key, &result);
6781-
} else {
6782-
zend_hash_index_add_new(Z_ARRVAL_P(return_value), num_key, &result);
6783-
}
6784-
} ZEND_HASH_FOREACH_END();
6766+
if (HT_IS_PACKED(input)) {
6767+
array_init_size(return_value, input->nNumUsed);
6768+
HashTable *output = Z_ARRVAL_P(return_value);
6769+
zend_hash_real_init_packed(output);
6770+
6771+
uint32_t undefs = 0;
6772+
ZEND_HASH_FILL_PACKED(output) {
6773+
/* Can't use ZEND_HASH_PACKED_FOREACH_VAL() because we need to also account for the UNDEF values
6774+
* so the keys in the output array will match those of the input array. */
6775+
for (zval *cur = input->arPacked, *end = input->arPacked + input->nNumUsed; cur != end; cur++) {
6776+
if (EXPECTED(!Z_ISUNDEF_P(cur))) {
6777+
fci.params = cur;
6778+
zend_result ret = zend_call_function(&fci, &fci_cache);
6779+
ZEND_ASSERT(ret == SUCCESS);
6780+
ZEND_IGNORE_VALUE(ret);
6781+
if (UNEXPECTED(Z_ISUNDEF(result))) {
6782+
ZEND_HASH_FILL_FINISH();
6783+
zend_array_destroy(output);
6784+
RETURN_NULL();
6785+
}
6786+
} else {
6787+
ZVAL_UNDEF(&result);
6788+
undefs++;
6789+
}
6790+
ZEND_HASH_FILL_ADD(&result);
6791+
}
6792+
} ZEND_HASH_FILL_END();
6793+
output->nNumOfElements -= undefs;
6794+
} else {
6795+
zend_ulong num_key;
6796+
zend_string *str_key;
6797+
6798+
array_init_size(return_value, maxlen);
6799+
HashTable *output = Z_ARRVAL_P(return_value);
6800+
zend_hash_real_init_mixed(output);
6801+
6802+
ZEND_HASH_MAP_FOREACH_KEY_VAL(input, num_key, str_key, fci.params) {
6803+
zend_result ret = zend_call_function(&fci, &fci_cache);
6804+
ZEND_ASSERT(ret == SUCCESS);
6805+
ZEND_IGNORE_VALUE(ret);
6806+
if (UNEXPECTED(Z_ISUNDEF(result))) {
6807+
zend_array_destroy(output);
6808+
RETURN_NULL();
6809+
}
6810+
if (str_key) {
6811+
_zend_hash_append(output, str_key, &result);
6812+
} else {
6813+
zend_hash_index_add_new(output, num_key, &result);
6814+
}
6815+
} ZEND_HASH_FOREACH_END();
6816+
}
67856817
} else {
67866818
uint32_t *array_pos = (HashPosition *)ecalloc(n_arrays, sizeof(HashPosition));
67876819

0 commit comments

Comments
 (0)