Add `Collection::flatMap()` and `Collection::flatMapTo()`. Fix bugs.
This commit is contained in:
parent
70588073a6
commit
f2402b9f67
|
@ -229,4 +229,4 @@ const zend_function_entry collection_methods[] = {
|
||||||
const zend_function_entry pair_methods[] = {
|
const zend_function_entry pair_methods[] = {
|
||||||
PHP_ME(Pair, __construct, key_value_arginfo, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
|
PHP_ME(Pair, __construct, key_value_arginfo, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
|
||||||
PHP_FE_END
|
PHP_FE_END
|
||||||
};
|
};
|
||||||
|
|
|
@ -39,7 +39,7 @@
|
||||||
#define PAIR_FETCH_SECOND(obj) OBJ_PROPERTY_FETCH(collections_pair_ce, obj, second)
|
#define PAIR_FETCH_SECOND(obj) OBJ_PROPERTY_FETCH(collections_pair_ce, obj, second)
|
||||||
|
|
||||||
#define INIT_FCI() \
|
#define INIT_FCI() \
|
||||||
zval params[2], rv, retval; \
|
zval params[2], retval; \
|
||||||
fci.param_count = 2; \
|
fci.param_count = 2; \
|
||||||
fci.retval = &retval; \
|
fci.retval = &retval; \
|
||||||
fci.params = params;
|
fci.params = params;
|
||||||
|
@ -51,8 +51,7 @@
|
||||||
ZVAL_STR(¶ms[1], (bucket)->key); \
|
ZVAL_STR(¶ms[1], (bucket)->key); \
|
||||||
else \
|
else \
|
||||||
ZVAL_LONG(¶ms[1], (bucket)->h); \
|
ZVAL_LONG(¶ms[1], (bucket)->h); \
|
||||||
zend_call_function(&fci, &fcc); \
|
zend_call_function(&fci, &fcc)
|
||||||
zval_ptr_dtor(¶ms[0])
|
|
||||||
|
|
||||||
#define INIT_EQUAL_CHECK_FUNC(val) \
|
#define INIT_EQUAL_CHECK_FUNC(val) \
|
||||||
int (*equal_check_func)(zval*, zval*); \
|
int (*equal_check_func)(zval*, zval*); \
|
||||||
|
@ -72,12 +71,11 @@
|
||||||
#define ERR_NOT_ARITHMETIC() PHP_COLLECTIONS_ERROR(E_WARNING, "Elements should be int or double")
|
#define ERR_NOT_ARITHMETIC() PHP_COLLECTIONS_ERROR(E_WARNING, "Elements should be int or double")
|
||||||
|
|
||||||
#define ELEMENTS_VALIDATE(elements) \
|
#define ELEMENTS_VALIDATE(elements) \
|
||||||
if (IS_COLLECTION_P(elements)) { \
|
if (IS_COLLECTION_P(elements)) \
|
||||||
zval rv; \
|
|
||||||
(elements) = COLLECTION_FETCH(elements); \
|
(elements) = COLLECTION_FETCH(elements); \
|
||||||
} else if (UNEXPECTED(Z_TYPE_P(elements) != IS_ARRAY)) { \
|
else if (UNEXPECTED(Z_TYPE_P(elements) != IS_ARRAY)) { \
|
||||||
ERR_BAD_ARGUMENT_TYPE(); \
|
ERR_BAD_ARGUMENT_TYPE(); \
|
||||||
RETVAL_NULL(); \
|
return; \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define ARRAY_NEW(name, size) \
|
#define ARRAY_NEW(name, size) \
|
||||||
|
@ -114,9 +112,11 @@
|
||||||
return; \
|
return; \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Unused global variable.
|
||||||
|
zval rv;
|
||||||
|
|
||||||
int count_collection(zval* obj, zend_long* count)
|
int count_collection(zval* obj, zend_long* count)
|
||||||
{
|
{
|
||||||
zval rv;
|
|
||||||
zend_array* current = Z_ARRVAL_P(COLLECTION_FETCH(obj));
|
zend_array* current = Z_ARRVAL_P(COLLECTION_FETCH(obj));
|
||||||
*count = zend_hash_num_elements(current);
|
*count = zend_hash_num_elements(current);
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
|
@ -124,7 +124,6 @@ int count_collection(zval* obj, zend_long* count)
|
||||||
|
|
||||||
int collection_offset_exists(zval* object, zval* offset, int check_empty)
|
int collection_offset_exists(zval* object, zval* offset, int check_empty)
|
||||||
{
|
{
|
||||||
zval rv;
|
|
||||||
zend_array* current = Z_ARRVAL_P(COLLECTION_FETCH(object));
|
zend_array* current = Z_ARRVAL_P(COLLECTION_FETCH(object));
|
||||||
if (check_empty)
|
if (check_empty)
|
||||||
return zend_hash_num_elements(current) == 0;
|
return zend_hash_num_elements(current) == 0;
|
||||||
|
@ -137,7 +136,6 @@ int collection_offset_exists(zval* object, zval* offset, int check_empty)
|
||||||
|
|
||||||
void collection_offset_set(zval* object, zval* offset, zval* value)
|
void collection_offset_set(zval* object, zval* offset, zval* value)
|
||||||
{
|
{
|
||||||
zval rv;
|
|
||||||
zend_array* current = Z_ARRVAL_P(COLLECTION_FETCH(object));
|
zend_array* current = Z_ARRVAL_P(COLLECTION_FETCH(object));
|
||||||
if (Z_TYPE_P(offset) == IS_LONG)
|
if (Z_TYPE_P(offset) == IS_LONG)
|
||||||
zend_hash_index_update(current, Z_LVAL_P(offset), value);
|
zend_hash_index_update(current, Z_LVAL_P(offset), value);
|
||||||
|
@ -149,7 +147,6 @@ zval* collection_offset_get(zval* object, zval* offset, int type, zval* retval)
|
||||||
{
|
{
|
||||||
// Note that we don't handle type. So don't do any fancy things with Collection
|
// Note that we don't handle type. So don't do any fancy things with Collection
|
||||||
// such as fetching a reference of a value, etc.
|
// such as fetching a reference of a value, etc.
|
||||||
zval rv;
|
|
||||||
zend_array* current = Z_ARRVAL_P(COLLECTION_FETCH(object));
|
zend_array* current = Z_ARRVAL_P(COLLECTION_FETCH(object));
|
||||||
zval* found = NULL;
|
zval* found = NULL;
|
||||||
if (Z_TYPE_P(offset) == IS_LONG)
|
if (Z_TYPE_P(offset) == IS_LONG)
|
||||||
|
@ -162,7 +159,6 @@ zval* collection_offset_get(zval* object, zval* offset, int type, zval* retval)
|
||||||
|
|
||||||
void collection_offset_unset(zval* object, zval* offset)
|
void collection_offset_unset(zval* object, zval* offset)
|
||||||
{
|
{
|
||||||
zval rv;
|
|
||||||
zend_array* current = Z_ARRVAL_P(COLLECTION_FETCH(object));
|
zend_array* current = Z_ARRVAL_P(COLLECTION_FETCH(object));
|
||||||
if (Z_TYPE_P(offset) == IS_LONG)
|
if (Z_TYPE_P(offset) == IS_LONG)
|
||||||
zend_hash_index_del(current, Z_LVAL_P(offset));
|
zend_hash_index_del(current, Z_LVAL_P(offset));
|
||||||
|
@ -179,10 +175,9 @@ PHP_METHOD(Collection, addAll)
|
||||||
Z_PARAM_ZVAL(elements)
|
Z_PARAM_ZVAL(elements)
|
||||||
ZEND_PARSE_PARAMETERS_END();
|
ZEND_PARSE_PARAMETERS_END();
|
||||||
ELEMENTS_VALIDATE(elements);
|
ELEMENTS_VALIDATE(elements);
|
||||||
zval rv;
|
|
||||||
zend_array* current = COLLECTION_FETCH_EX();
|
zend_array* current = COLLECTION_FETCH_EX();
|
||||||
ZEND_HASH_FILL_PACKED(current)
|
ZEND_HASH_FILL_PACKED(current)
|
||||||
ZEND_HASH_FOREACH_VAL_IND(Z_ARRVAL_P(elements), zval* val)
|
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(elements), zval* val)
|
||||||
ZEND_HASH_FILL_ADD(val);
|
ZEND_HASH_FILL_ADD(val);
|
||||||
ZEND_HASH_FOREACH_END();
|
ZEND_HASH_FOREACH_END();
|
||||||
ZEND_HASH_FILL_END();
|
ZEND_HASH_FILL_END();
|
||||||
|
@ -332,10 +327,9 @@ PHP_METHOD(Collection, associateByTo)
|
||||||
|
|
||||||
PHP_METHOD(Collection, average)
|
PHP_METHOD(Collection, average)
|
||||||
{
|
{
|
||||||
zval rv;
|
|
||||||
zend_array* current = COLLECTION_FETCH_EX();
|
zend_array* current = COLLECTION_FETCH_EX();
|
||||||
double sum = 0;
|
double sum = 0;
|
||||||
ZEND_HASH_FOREACH_VAL_IND(current, zval* val)
|
ZEND_HASH_FOREACH_VAL(current, zval* val)
|
||||||
if (Z_TYPE_P(val) == IS_LONG)
|
if (Z_TYPE_P(val) == IS_LONG)
|
||||||
sum += Z_LVAL_P(val);
|
sum += Z_LVAL_P(val);
|
||||||
else if (Z_TYPE_P(val) == IS_DOUBLE)
|
else if (Z_TYPE_P(val) == IS_DOUBLE)
|
||||||
|
@ -357,10 +351,10 @@ PHP_METHOD(Collection, containsAll)
|
||||||
ELEMENTS_VALIDATE(elements);
|
ELEMENTS_VALIDATE(elements);
|
||||||
zval rv;
|
zval rv;
|
||||||
zend_array* current = COLLECTION_FETCH_EX();
|
zend_array* current = COLLECTION_FETCH_EX();
|
||||||
ZEND_HASH_FOREACH_VAL_IND(Z_ARRVAL_P(elements), zval* element)
|
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(elements), zval* element)
|
||||||
INIT_EQUAL_CHECK_FUNC(element);
|
INIT_EQUAL_CHECK_FUNC(element);
|
||||||
int result = 0;
|
int result = 0;
|
||||||
ZEND_HASH_FOREACH_VAL_IND(current, zval* val)
|
ZEND_HASH_FOREACH_VAL(current, zval* val)
|
||||||
if (result = equal_check_func(element, val))
|
if (result = equal_check_func(element, val))
|
||||||
break;
|
break;
|
||||||
ZEND_HASH_FOREACH_END();
|
ZEND_HASH_FOREACH_END();
|
||||||
|
@ -376,7 +370,6 @@ PHP_METHOD(Collection, containsKey)
|
||||||
ZEND_PARSE_PARAMETERS_START(1, 1)
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
||||||
Z_PARAM_ZVAL(key)
|
Z_PARAM_ZVAL(key)
|
||||||
ZEND_PARSE_PARAMETERS_END();
|
ZEND_PARSE_PARAMETERS_END();
|
||||||
zval rv;
|
|
||||||
zend_array* current = COLLECTION_FETCH_EX();
|
zend_array* current = COLLECTION_FETCH_EX();
|
||||||
if (Z_TYPE_P(key) == IS_LONG)
|
if (Z_TYPE_P(key) == IS_LONG)
|
||||||
RETURN_BOOL(zend_hash_index_exists(current, Z_LVAL_P(key)));
|
RETURN_BOOL(zend_hash_index_exists(current, Z_LVAL_P(key)));
|
||||||
|
@ -395,7 +388,7 @@ PHP_METHOD(Collection, containsValue)
|
||||||
zval rv;
|
zval rv;
|
||||||
zend_array* current = COLLECTION_FETCH_EX();
|
zend_array* current = COLLECTION_FETCH_EX();
|
||||||
INIT_EQUAL_CHECK_FUNC(element);
|
INIT_EQUAL_CHECK_FUNC(element);
|
||||||
ZEND_HASH_FOREACH_VAL_IND(current, zval* val)
|
ZEND_HASH_FOREACH_VAL(current, zval* val)
|
||||||
if (equal_check_func(element, val))
|
if (equal_check_func(element, val))
|
||||||
RETURN_TRUE;
|
RETURN_TRUE;
|
||||||
ZEND_HASH_FOREACH_END();
|
ZEND_HASH_FOREACH_END();
|
||||||
|
@ -409,7 +402,6 @@ PHP_METHOD(Collection, copyOf)
|
||||||
Z_PARAM_OPTIONAL
|
Z_PARAM_OPTIONAL
|
||||||
Z_PARAM_LONG(new_size);
|
Z_PARAM_LONG(new_size);
|
||||||
ZEND_PARSE_PARAMETERS_END();
|
ZEND_PARSE_PARAMETERS_END();
|
||||||
zval rv;
|
|
||||||
zend_array* current = COLLECTION_FETCH_EX();
|
zend_array* current = COLLECTION_FETCH_EX();
|
||||||
if (EX_NUM_ARGS() == 0) {
|
if (EX_NUM_ARGS() == 0) {
|
||||||
ARRAY_CLONE(new_collection, current);
|
ARRAY_CLONE(new_collection, current);
|
||||||
|
@ -450,7 +442,6 @@ PHP_METHOD(Collection, copyOfRange)
|
||||||
ERR_BAD_SIZE();
|
ERR_BAD_SIZE();
|
||||||
RETURN_NULL();
|
RETURN_NULL();
|
||||||
}
|
}
|
||||||
zval rv;
|
|
||||||
zend_array* current = COLLECTION_FETCH_EX();
|
zend_array* current = COLLECTION_FETCH_EX();
|
||||||
ARRAY_NEW(new_collection, num_elements);
|
ARRAY_NEW(new_collection, num_elements);
|
||||||
Bucket* bucket = current->arData;
|
Bucket* bucket = current->arData;
|
||||||
|
@ -490,7 +481,6 @@ PHP_METHOD(Collection, drop)
|
||||||
ERR_BAD_SIZE();
|
ERR_BAD_SIZE();
|
||||||
RETURN_NULL();
|
RETURN_NULL();
|
||||||
}
|
}
|
||||||
zval rv;
|
|
||||||
zend_array* current = COLLECTION_FETCH_EX();
|
zend_array* current = COLLECTION_FETCH_EX();
|
||||||
ARRAY_CLONE(new_collection, current);
|
ARRAY_CLONE(new_collection, current);
|
||||||
Bucket* bucket = new_collection->arData;
|
Bucket* bucket = new_collection->arData;
|
||||||
|
@ -687,7 +677,6 @@ PHP_METHOD(Collection, first)
|
||||||
Z_PARAM_OPTIONAL
|
Z_PARAM_OPTIONAL
|
||||||
Z_PARAM_FUNC(fci, fcc)
|
Z_PARAM_FUNC(fci, fcc)
|
||||||
ZEND_PARSE_PARAMETERS_END();
|
ZEND_PARSE_PARAMETERS_END();
|
||||||
INIT_FCI();
|
|
||||||
zend_array* current = COLLECTION_FETCH_EX();
|
zend_array* current = COLLECTION_FETCH_EX();
|
||||||
if (zend_hash_num_elements(current) == 0)
|
if (zend_hash_num_elements(current) == 0)
|
||||||
RETURN_NULL();
|
RETURN_NULL();
|
||||||
|
@ -695,6 +684,7 @@ PHP_METHOD(Collection, first)
|
||||||
zend_hash_internal_pointer_reset(current);
|
zend_hash_internal_pointer_reset(current);
|
||||||
RETURN_ZVAL(zend_hash_get_current_data(current), 1, 0);
|
RETURN_ZVAL(zend_hash_get_current_data(current), 1, 0);
|
||||||
}
|
}
|
||||||
|
INIT_FCI();
|
||||||
ZEND_HASH_FOREACH_BUCKET(current, Bucket* bucket)
|
ZEND_HASH_FOREACH_BUCKET(current, Bucket* bucket)
|
||||||
CALLBACK_KEYVAL_INVOKE(params, bucket);
|
CALLBACK_KEYVAL_INVOKE(params, bucket);
|
||||||
if (zend_is_true(&retval))
|
if (zend_is_true(&retval))
|
||||||
|
@ -705,12 +695,58 @@ PHP_METHOD(Collection, first)
|
||||||
|
|
||||||
PHP_METHOD(Collection, flatMap)
|
PHP_METHOD(Collection, flatMap)
|
||||||
{
|
{
|
||||||
|
zend_fcall_info fci;
|
||||||
|
zend_fcall_info_cache fcc;
|
||||||
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
||||||
|
Z_PARAM_FUNC(fci, fcc)
|
||||||
|
ZEND_PARSE_PARAMETERS_END();
|
||||||
|
INIT_FCI();
|
||||||
|
zend_array* current = COLLECTION_FETCH_EX();
|
||||||
|
ARRAY_NEW_EX(new_collection, current);
|
||||||
|
ZEND_HASH_FOREACH_BUCKET(current, Bucket* bucket)
|
||||||
|
CALLBACK_KEYVAL_INVOKE(params, bucket);
|
||||||
|
zval* retval_p = &retval;
|
||||||
|
ELEMENTS_VALIDATE(retval_p);
|
||||||
|
ZEND_HASH_FOREACH_BUCKET(Z_ARRVAL_P(retval_p), Bucket* bucket)
|
||||||
|
if (Z_REFCOUNTED(bucket->val))
|
||||||
|
GC_ADDREF(Z_COUNTED(bucket->val));
|
||||||
|
if (bucket->key)
|
||||||
|
zend_hash_add(new_collection, bucket->key, &bucket->val);
|
||||||
|
else
|
||||||
|
zend_hash_next_index_insert(new_collection, &bucket->val);
|
||||||
|
ZEND_HASH_FOREACH_END();
|
||||||
|
zval_ptr_dtor(&retval);
|
||||||
|
ZEND_HASH_FOREACH_END();
|
||||||
|
RETVAL_NEW_COLLECTION(new_collection);
|
||||||
}
|
}
|
||||||
|
|
||||||
PHP_METHOD(Collection, flatMapTo)
|
PHP_METHOD(Collection, flatMapTo)
|
||||||
{
|
{
|
||||||
|
zval* dest;
|
||||||
|
zend_fcall_info fci;
|
||||||
|
zend_fcall_info_cache fcc;
|
||||||
|
ZEND_PARSE_PARAMETERS_START(2, 2)
|
||||||
|
Z_PARAM_OBJECT_OF_CLASS(dest, collections_collection_ce)
|
||||||
|
Z_PARAM_FUNC(fci, fcc)
|
||||||
|
ZEND_PARSE_PARAMETERS_END();
|
||||||
|
INIT_FCI();
|
||||||
|
zend_array* current = COLLECTION_FETCH_EX();
|
||||||
|
zend_array* dest_arr = Z_ARRVAL_P(COLLECTION_FETCH(dest));
|
||||||
|
ZEND_HASH_FOREACH_BUCKET(current, Bucket* bucket)
|
||||||
|
CALLBACK_KEYVAL_INVOKE(params, bucket);
|
||||||
|
zval* retval_p = &retval;
|
||||||
|
ELEMENTS_VALIDATE(retval_p);
|
||||||
|
ZEND_HASH_FOREACH_BUCKET(Z_ARRVAL_P(retval_p), Bucket* bucket)
|
||||||
|
if (Z_REFCOUNTED(bucket->val))
|
||||||
|
GC_ADDREF(Z_COUNTED(bucket->val));
|
||||||
|
if (bucket->key)
|
||||||
|
zend_hash_add(dest_arr, bucket->key, &bucket->val);
|
||||||
|
else
|
||||||
|
zend_hash_next_index_insert(dest_arr, &bucket->val);
|
||||||
|
ZEND_HASH_FOREACH_END();
|
||||||
|
zval_ptr_dtor(&retval);
|
||||||
|
ZEND_HASH_FOREACH_END();
|
||||||
|
RETVAL_ZVAL(dest, 1, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
PHP_METHOD(Collection, flatten)
|
PHP_METHOD(Collection, flatten)
|
||||||
|
@ -807,7 +843,6 @@ PHP_METHOD(Collection, last)
|
||||||
Z_PARAM_OPTIONAL
|
Z_PARAM_OPTIONAL
|
||||||
Z_PARAM_FUNC(fci, fcc)
|
Z_PARAM_FUNC(fci, fcc)
|
||||||
ZEND_PARSE_PARAMETERS_END();
|
ZEND_PARSE_PARAMETERS_END();
|
||||||
INIT_FCI();
|
|
||||||
zend_array* current = COLLECTION_FETCH_EX();
|
zend_array* current = COLLECTION_FETCH_EX();
|
||||||
if (zend_hash_num_elements(current) == 0)
|
if (zend_hash_num_elements(current) == 0)
|
||||||
RETURN_NULL();
|
RETURN_NULL();
|
||||||
|
@ -817,6 +852,7 @@ PHP_METHOD(Collection, last)
|
||||||
zend_hash_internal_pointer_reset(current);
|
zend_hash_internal_pointer_reset(current);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
INIT_FCI();
|
||||||
ZEND_HASH_REVERSE_FOREACH_BUCKET(current, Bucket* bucket)
|
ZEND_HASH_REVERSE_FOREACH_BUCKET(current, Bucket* bucket)
|
||||||
CALLBACK_KEYVAL_INVOKE(params, bucket);
|
CALLBACK_KEYVAL_INVOKE(params, bucket);
|
||||||
if (zend_is_true(&retval))
|
if (zend_is_true(&retval))
|
||||||
|
@ -1123,4 +1159,4 @@ PHP_METHOD(Pair, __construct)
|
||||||
ZEND_PARSE_PARAMETERS_END();
|
ZEND_PARSE_PARAMETERS_END();
|
||||||
PAIR_UPDATE_FIRST(getThis(), first);
|
PAIR_UPDATE_FIRST(getThis(), first);
|
||||||
PAIR_UPDATE_SECOND(getThis(), second);
|
PAIR_UPDATE_SECOND(getThis(), second);
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,4 +47,4 @@ extern const zend_function_entry pair_methods[];
|
||||||
ZEND_TSRMLS_CACHE_EXTERN()
|
ZEND_TSRMLS_CACHE_EXTERN()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif // !PHP_COLLECTIONS_FE_H
|
#endif // !PHP_COLLECTIONS_FE_H
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
--TEST--
|
||||||
|
Test Collection::flatMap() and Collection::flatMapTo().
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
$array = [['a' => ['b', 'c'], 'd' => ['e', 'f']], ['a' => ['g', 'h'], 'd' => ['i', 'j']]];
|
||||||
|
$collection = Collection::init($array)->flatMap(function ($value) {
|
||||||
|
return $value['a'];
|
||||||
|
});
|
||||||
|
if ($collection->toArray() != ['b', 'c', 'g', 'h'])
|
||||||
|
echo 'Collection::flatMap() failed.', PHP_EOL;
|
||||||
|
$collection1 = Collection::init(['k', 'l']);
|
||||||
|
$collection2 = Collection::init($array)->flatMapTo($collection1, function ($value) {
|
||||||
|
return Collection::init($value['d']);
|
||||||
|
});
|
||||||
|
if ($collection2->toArray() != ['k', 'l', 'e', 'f', 'i', 'j'])
|
||||||
|
echo 'Collection::flatMap() failed.', PHP_EOL;
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
Reference in New Issue