Add `reduce()` and `reduceRight()`. Update signatures. Fix bugs. Update README.
This commit is contained in:
parent
ecfee75fbe
commit
440d3fdb63
|
@ -17,7 +17,7 @@ Method names and functionalities are inspired by [Kotlin.Collections](https://ko
|
||||||
|
|
||||||
### 2.1 Functionalities
|
### 2.1 Functionalities
|
||||||
|
|
||||||
See [stubs](stubs/) directory for signature of all classes and methods of this extension, with PHPDoc.
|
See [stubs](stubs/) directory for signature of all classes and methods of this extension, with PHPDoc. They can also serve as IDE helper.
|
||||||
|
|
||||||
### 2.2 PHP-style access
|
### 2.2 PHP-style access
|
||||||
|
|
||||||
|
|
|
@ -113,9 +113,28 @@
|
||||||
/// Unused global variable.
|
/// Unused global variable.
|
||||||
zval rv;
|
zval rv;
|
||||||
|
|
||||||
static zend_always_inline int bucket_compare_numeric(Bucket* op1, Bucket* op2)
|
static zend_always_inline int bucket_compare_numeric(const void* op1, const void* op2)
|
||||||
{
|
{
|
||||||
return numeric_compare_function(&op1->val, &op2->val);
|
Bucket* b1 = (Bucket*)op1;
|
||||||
|
Bucket* b2 = (Bucket*)op2;
|
||||||
|
return numeric_compare_function(&b1->val, &b2->val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static zend_always_inline int bucket_compare_string(const void* op1, const void* op2)
|
||||||
|
{
|
||||||
|
Bucket* b1 = (Bucket*)op1;
|
||||||
|
Bucket* b2 = (Bucket*)op2;
|
||||||
|
return string_compare_function(&b1->val, &b2->val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static zend_always_inline int bucket_compare_regular(const void* op1, const void* op2)
|
||||||
|
{
|
||||||
|
Bucket* b1 = (Bucket*)op1;
|
||||||
|
Bucket* b2 = (Bucket*)op2;
|
||||||
|
zval result;
|
||||||
|
if (compare_function(&result, &b1->val, &b2->val) == FAILURE)
|
||||||
|
return 0;
|
||||||
|
return ZEND_NORMALIZE_BOOL(Z_LVAL(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
int count_collection(zval* obj, zend_long* count)
|
int count_collection(zval* obj, zend_long* count)
|
||||||
|
@ -1271,12 +1290,78 @@ PHP_METHOD(Collection, putAll)
|
||||||
|
|
||||||
PHP_METHOD(Collection, reduce)
|
PHP_METHOD(Collection, reduce)
|
||||||
{
|
{
|
||||||
|
zend_fcall_info fci;
|
||||||
|
zend_fcall_info_cache fcc;
|
||||||
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
||||||
|
Z_PARAM_FUNC(fci, fcc)
|
||||||
|
ZEND_PARSE_PARAMETERS_END();
|
||||||
|
zend_array* current = COLLECTION_FETCH_CURRENT();
|
||||||
|
if (zend_hash_num_elements(current) == 0) {
|
||||||
|
ERR_BAD_SIZE();
|
||||||
|
RETURN_NULL();
|
||||||
|
}
|
||||||
|
INIT_FCI(3);
|
||||||
|
zval acc;
|
||||||
|
Bucket* bucket = current->arData;
|
||||||
|
Bucket* end = bucket + current->nNumUsed;
|
||||||
|
for (; bucket < end; ++bucket) {
|
||||||
|
if (Z_ISUNDEF(bucket->val))
|
||||||
|
continue;
|
||||||
|
ZVAL_COPY_VALUE(&acc, &(bucket++)->val);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for (; bucket < end; ++bucket) {
|
||||||
|
if (Z_ISUNDEF(bucket->val))
|
||||||
|
continue;
|
||||||
|
ZVAL_COPY_VALUE(¶ms[0], &acc);
|
||||||
|
ZVAL_COPY_VALUE(¶ms[1], &bucket->val);
|
||||||
|
if (bucket->key)
|
||||||
|
ZVAL_STR(¶ms[2], bucket->key);
|
||||||
|
else
|
||||||
|
ZVAL_LONG(¶ms[2], bucket->h);
|
||||||
|
zend_call_function(&fci, &fcc);
|
||||||
|
zval_ptr_dtor(&acc);
|
||||||
|
ZVAL_COPY_VALUE(&acc, &retval);
|
||||||
|
}
|
||||||
|
RETVAL_ZVAL(&retval, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
PHP_METHOD(Collection, reduceRight)
|
PHP_METHOD(Collection, reduceRight)
|
||||||
{
|
{
|
||||||
|
zend_fcall_info fci;
|
||||||
|
zend_fcall_info_cache fcc;
|
||||||
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
||||||
|
Z_PARAM_FUNC(fci, fcc)
|
||||||
|
ZEND_PARSE_PARAMETERS_END();
|
||||||
|
zend_array* current = COLLECTION_FETCH_CURRENT();
|
||||||
|
if (zend_hash_num_elements(current) == 0) {
|
||||||
|
ERR_BAD_SIZE();
|
||||||
|
RETURN_NULL();
|
||||||
|
}
|
||||||
|
INIT_FCI(3);
|
||||||
|
zval acc;
|
||||||
|
Bucket* start = current->arData;
|
||||||
|
Bucket* bucket = start + current->nNumUsed - 1;
|
||||||
|
for (; bucket >= start; --bucket) {
|
||||||
|
if (Z_ISUNDEF(bucket->val))
|
||||||
|
continue;
|
||||||
|
ZVAL_COPY_VALUE(&acc, &(bucket--)->val);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for (; bucket >= start; --bucket) {
|
||||||
|
if (Z_ISUNDEF(bucket->val))
|
||||||
|
continue;
|
||||||
|
ZVAL_COPY_VALUE(¶ms[0], &acc);
|
||||||
|
ZVAL_COPY_VALUE(¶ms[1], &bucket->val);
|
||||||
|
if (bucket->key)
|
||||||
|
ZVAL_STR(¶ms[2], bucket->key);
|
||||||
|
else
|
||||||
|
ZVAL_LONG(¶ms[2], bucket->h);
|
||||||
|
zend_call_function(&fci, &fcc);
|
||||||
|
zval_ptr_dtor(&acc);
|
||||||
|
ZVAL_COPY_VALUE(&acc, &retval);
|
||||||
|
}
|
||||||
|
RETVAL_ZVAL(&retval, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
PHP_METHOD(Collection, remove)
|
PHP_METHOD(Collection, remove)
|
||||||
|
@ -1365,7 +1450,7 @@ PHP_METHOD(Collection, reverse)
|
||||||
else if (HT_IS_PACKED(current))
|
else if (HT_IS_PACKED(current))
|
||||||
zend_hash_next_index_insert(reversed, &bucket->val);
|
zend_hash_next_index_insert(reversed, &bucket->val);
|
||||||
else
|
else
|
||||||
zend_hash_index_add(reversed, &bucket->h, &bucket->val);
|
zend_hash_index_add(reversed, bucket->h, &bucket->val);
|
||||||
ZEND_HASH_FOREACH_END();
|
ZEND_HASH_FOREACH_END();
|
||||||
if (GC_REFCOUNT(current) > 1)
|
if (GC_REFCOUNT(current) > 1)
|
||||||
GC_DELREF(current);
|
GC_DELREF(current);
|
||||||
|
@ -1385,7 +1470,7 @@ PHP_METHOD(Collection, reversed)
|
||||||
else if (HT_IS_PACKED(current))
|
else if (HT_IS_PACKED(current))
|
||||||
zend_hash_next_index_insert(reversed, &bucket->val);
|
zend_hash_next_index_insert(reversed, &bucket->val);
|
||||||
else
|
else
|
||||||
zend_hash_index_add(reversed, &bucket->h, &bucket->val);
|
zend_hash_index_add(reversed, bucket->h, &bucket->val);
|
||||||
ZEND_HASH_FOREACH_END();
|
ZEND_HASH_FOREACH_END();
|
||||||
RETVAL_NEW_COLLECTION(reversed);
|
RETVAL_NEW_COLLECTION(reversed);
|
||||||
}
|
}
|
||||||
|
@ -1571,7 +1656,7 @@ PHP_METHOD(Collection, takeLast)
|
||||||
continue;
|
continue;
|
||||||
taken[--num_taken] = bucket;
|
taken[--num_taken] = bucket;
|
||||||
}
|
}
|
||||||
memset(&taken[0], NULL, num_taken * sizeof(Bucket*));
|
memset(&taken[0], 0, num_taken * sizeof(Bucket*));
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (; i < n; ++i) {
|
for (; i < n; ++i) {
|
||||||
Bucket* bucket = taken[i];
|
Bucket* bucket = taken[i];
|
||||||
|
@ -1607,7 +1692,7 @@ PHP_METHOD(Collection, takeLastWhile)
|
||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
ZEND_HASH_FOREACH_END();
|
ZEND_HASH_FOREACH_END();
|
||||||
memset(&taken[0], NULL, num_elements * sizeof(Bucket*));
|
memset(&taken[0], 0, num_elements * sizeof(Bucket*));
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (; i < zend_hash_num_elements(current); ++i) {
|
for (; i < zend_hash_num_elements(current); ++i) {
|
||||||
Bucket* bucket = taken[i];
|
Bucket* bucket = taken[i];
|
||||||
|
|
|
@ -624,7 +624,7 @@ class Collection implements ArrayAccess, Countable
|
||||||
* Accumulates value starting with the first element and applying operation from left to right to
|
* Accumulates value starting with the first element and applying operation from left to right to
|
||||||
* current accumulator value and each element.
|
* current accumulator value and each element.
|
||||||
*
|
*
|
||||||
* @param $operation ($acc, $value, $key) -> $new_acc
|
* @param callable $operation ($acc, $value, $key) -> $new_acc
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
function reduce($operation) {}
|
function reduce($operation) {}
|
||||||
|
@ -633,7 +633,7 @@ class Collection implements ArrayAccess, Countable
|
||||||
* Accumulates value starting with the last element and applying operation from right to left to
|
* Accumulates value starting with the last element and applying operation from right to left to
|
||||||
* each element and current accumulator value.
|
* each element and current accumulator value.
|
||||||
*
|
*
|
||||||
* @param $operation ($acc, $value, $key) -> $new_acc
|
* @param callable $operation ($acc, $value, $key) -> $new_acc
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
function reduceRight($operation) {}
|
function reduceRight($operation) {}
|
||||||
|
@ -712,82 +712,90 @@ class Collection implements ArrayAccess, Countable
|
||||||
function slice($keys) {}
|
function slice($keys) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sorts the collection in-place according to the natural order of its elements.
|
* Sorts the collection in-place according to the specified order of its elements.
|
||||||
*
|
*
|
||||||
|
* @param int $order[optional]
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
function sort() {}
|
function sort($order = SORT_REGULAR) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sorts elements in the collection in-place according to natural sort order of the value returned
|
* Sorts elements in the collection in-place according to the specified order of the value returned
|
||||||
* by specified selector function.
|
* by specified selector function.
|
||||||
*
|
*
|
||||||
* @param callable $selector ($value, $key) -> $new_value
|
* @param callable $selector ($value, $key) -> $new_value
|
||||||
|
* @param int $flags[optional]
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
function sortBy($selector) {}
|
function sortBy($selector, $flags = SORT_REGULAR) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sorts elements in the collection in-place descending according to natural sort order of the
|
* Sorts elements in the collection in-place descending according to the specified order of the
|
||||||
* value returned by specified selector function.
|
* value returned by specified selector function.
|
||||||
*
|
*
|
||||||
* @param callable $selector ($value, $key) -> $new_value
|
* @param callable $selector ($value, $key) -> $new_value
|
||||||
|
* @param int $flags[optional]
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
function sortByDescending($selector) {}
|
function sortByDescending($selector, $flags = SORT_REGULAR) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sorts elements in the collection in-place descending according to their natural sort order.
|
* Sorts elements in the collection in-place descending according to the specified order.
|
||||||
*
|
*
|
||||||
|
* @param int $flags[optional]
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
function sortDescending() {}
|
function sortDescending($flags = SORT_REGULAR) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sorts elements in the collection in-place according to the order specified with comparator.
|
* Sorts elements in the collection in-place according to the order specified with comparator.
|
||||||
*
|
*
|
||||||
* @param callable $comparator ($value_1, $value_2, $key_1, $key_2) -> int
|
* @param callable $comparator (Pair($key, $value), Pair($key, $value)) -> int
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
function sortWith($comparator) {}
|
function sortWith($comparator) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a collection of all elements sorted according to their natural sort order.
|
* Returns a collection of all elements sorted according to the specified order.
|
||||||
*
|
*
|
||||||
|
* @param int $flags[optional]
|
||||||
* @return Collection
|
* @return Collection
|
||||||
*/
|
*/
|
||||||
function sorted() {}
|
function sorted($flags = SORT_REGULAR) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a collection of all elements sorted according to natural sort order of the
|
* Returns a collection of all elements sorted according to the specified order of the
|
||||||
* value returned by specified selector function.
|
* value returned by specified selector function.
|
||||||
*
|
*
|
||||||
* @param callable $selector ($value, $key) -> $new_value
|
* @param callable $selector ($value, $key) -> $new_value
|
||||||
|
* @param int $flags[optional]
|
||||||
* @return Collection
|
* @return Collection
|
||||||
*/
|
*/
|
||||||
function sortedBy($selector) {}
|
function sortedBy($selector, $flags = SORT_REGULAR) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a collection of all elements sorted descending according to natural sort order
|
* Returns a collection of all elements sorted descending according to the specified order
|
||||||
* of the value returned by specified selector function.
|
* of the value returned by specified selector function.
|
||||||
*
|
*
|
||||||
* @param callable $selector ($value, $key) -> $new_value
|
* @param callable $selector ($value, $key) -> $new_value
|
||||||
|
* @param int $flags[optional]
|
||||||
* @return Collection
|
* @return Collection
|
||||||
*/
|
*/
|
||||||
function sortedByDescending($selector) {}
|
function sortedByDescending($selector, $flags = SORT_REGULAR) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a collection of all elements sorted descending according to their natural sort order.
|
* Returns a collection of all elements sorted descending according to the specified order.
|
||||||
*
|
*
|
||||||
* @param callable $selector ($value, $key) -> $new_value
|
* @param callable $selector ($value, $key) -> $new_value
|
||||||
|
* @param int $flags[optional]
|
||||||
* @return Collection
|
* @return Collection
|
||||||
*/
|
*/
|
||||||
function sortedDescending($selector) {}
|
function sortedDescending($selector, $flags = SORT_REGULAR) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a collection of all elements sorted according to the specified comparator.
|
* Returns a collection of all elements sorted according to the specified comparator.
|
||||||
*
|
*
|
||||||
* @param callable $comparator ($value_1, $value_2, $key_1, $key_2) -> int
|
* @param callable $comparator (Pair($key, $value), Pair($key, $value)) -> int
|
||||||
* @return Collection
|
* @return Collection
|
||||||
*/
|
*/
|
||||||
function sortedWith($comparator) {}
|
function sortedWith($comparator) {}
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
--TEST--
|
||||||
|
Test Collection::reduce() and Collection::reduceRight().
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
$collection = Collection::init(['a', 'b', 'c', 'd', 'e']);
|
||||||
|
$reduce_cb = function ($acc, $value, $key) {
|
||||||
|
return $acc.$value.strval($key);
|
||||||
|
};
|
||||||
|
if ($collection->reduce($reduce_cb) != 'ab1c2d3e4')
|
||||||
|
echo 'Collection::reduce() failed.', PHP_EOL;
|
||||||
|
if ($collection->reduceRight($reduce_cb) != 'ed3c2b1a0')
|
||||||
|
echo 'Collection::reduceRight() failed.', PHP_EOL;
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
Reference in New Issue