commit
f00e72f4ac
|
@ -136,6 +136,18 @@ ZEND_BEGIN_ARG_INFO(to_collection_arginfo, 0)
|
|||
ZEND_ARG_OBJ_INFO(0, destination, Collection, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_INFO(windowed_arginfo, 0)
|
||||
ZEND_ARG_TYPE_INFO(0, size, IS_LONG, 0)
|
||||
ZEND_ARG_TYPE_INFO(0, step, IS_LONG, 0)
|
||||
ZEND_ARG_TYPE_INFO(0, partial_windows, _IS_BOOL, 0)
|
||||
ZEND_ARG_CALLABLE_INFO(0, transform, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_INFO(zip_arginfo, 0)
|
||||
ZEND_ARG_INFO(0, other)
|
||||
ZEND_ARG_CALLABLE_INFO(0, transform, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
const zend_function_entry collection_methods[] = {
|
||||
PHP_ME(Collection, __construct, NULL, ZEND_ACC_PRIVATE | ZEND_ACC_CTOR)
|
||||
PHP_ME(Collection, addAll, elements_arginfo, ZEND_ACC_PUBLIC)
|
||||
|
@ -240,6 +252,9 @@ const zend_function_entry collection_methods[] = {
|
|||
PHP_ME(Collection, toPairs, NULL, ZEND_ACC_PUBLIC)
|
||||
PHP_ME(Collection, union, other_arginfo, ZEND_ACC_PUBLIC)
|
||||
PHP_ME(Collection, values, NULL, ZEND_ACC_PUBLIC)
|
||||
PHP_ME(Collection, windowed, windowed_arginfo, ZEND_ACC_PUBLIC)
|
||||
PHP_ME(Collection, zip, zip_arginfo, ZEND_ACC_PUBLIC)
|
||||
PHP_ME(Collection, zipWithNext, transform_arginfo, ZEND_ACC_PUBLIC)
|
||||
PHP_FE_END
|
||||
};
|
||||
|
||||
|
|
|
@ -2594,7 +2594,7 @@ PHP_METHOD(Collection, shuffle)
|
|||
Z_TRY_ADDREF_P(val);
|
||||
zend_hash_next_index_insert(shuffled, val);
|
||||
ZEND_HASH_FOREACH_END();
|
||||
size_t offset = 0;
|
||||
uint32_t offset = 0;
|
||||
Bucket* bucket = shuffled->arData;
|
||||
for (; offset < num_elements - 1; ++offset) {
|
||||
zend_long rand_idx = php_mt_rand_range(offset, num_elements - 1);
|
||||
|
@ -2613,7 +2613,7 @@ PHP_METHOD(Collection, shuffled)
|
|||
Z_TRY_ADDREF_P(val);
|
||||
zend_hash_next_index_insert(shuffled, val);
|
||||
ZEND_HASH_FOREACH_END();
|
||||
size_t offset = 0;
|
||||
uint32_t offset = 0;
|
||||
Bucket* bucket = shuffled->arData;
|
||||
for (; offset < num_elements - 1; ++offset) {
|
||||
zend_long rand_idx = php_mt_rand_range(offset, num_elements - 1);
|
||||
|
@ -3263,6 +3263,113 @@ PHP_METHOD(Collection, values)
|
|||
RETVAL_NEW_COLLECTION(new_collection);
|
||||
}
|
||||
|
||||
PHP_METHOD(Collection, windowed)
|
||||
{
|
||||
zend_long size;
|
||||
zend_long step = 1;
|
||||
zend_bool partial_windows = 0;
|
||||
zend_fcall_info fci;
|
||||
zend_fcall_info_cache fcc;
|
||||
ZEND_PARSE_PARAMETERS_START(1, 4)
|
||||
Z_PARAM_LONG(size)
|
||||
Z_PARAM_OPTIONAL
|
||||
Z_PARAM_LONG(step)
|
||||
Z_PARAM_BOOL(partial_windows)
|
||||
Z_PARAM_FUNC(fci, fcc)
|
||||
ZEND_PARSE_PARAMETERS_END();
|
||||
zend_array* current = THIS_COLLECTION;
|
||||
if (size < 1 || step < 1) {
|
||||
ERR_BAD_SIZE();
|
||||
RETURN_NULL();
|
||||
}
|
||||
if (!HT_IS_PACKED(current)) {
|
||||
ERR_NOT_PACKED();
|
||||
RETURN_NULL();
|
||||
}
|
||||
zend_bool has_transform = EX_NUM_ARGS() == 4;
|
||||
INIT_FCI(&fci, 2);
|
||||
uint32_t num_elements = zend_hash_num_elements(current);
|
||||
uint32_t num_ret;
|
||||
if (partial_windows) {
|
||||
num_ret = num_elements / step + (num_elements % step ? 1 : 0);
|
||||
} else {
|
||||
num_ret = num_elements >= size ? (num_elements - size) / step + 1 : 0;
|
||||
}
|
||||
ARRAY_NEW(windowed, num_ret);
|
||||
Bucket* start = current->arData;
|
||||
uint32_t idx;
|
||||
uint32_t pos = 0;
|
||||
for (idx = 0; idx < num_ret; ++idx, pos += step) {
|
||||
ARRAY_NEW(snapshot, size);
|
||||
uint32_t snapshot_idx;
|
||||
for (snapshot_idx = 0; snapshot_idx < size; ++snapshot_idx) {
|
||||
if (partial_windows && UNEXPECTED(pos + snapshot_idx >= num_elements)) {
|
||||
break;
|
||||
}
|
||||
Bucket* bucket = start + pos + snapshot_idx;
|
||||
Z_TRY_ADDREF(bucket->val);
|
||||
zend_hash_next_index_insert(snapshot, &bucket->val);
|
||||
}
|
||||
if (has_transform) {
|
||||
ZVAL_ARR(¶ms[0], snapshot);
|
||||
ZVAL_LONG(¶ms[1], idx);
|
||||
zend_call_function(&fci, &fcc);
|
||||
array_release(snapshot);
|
||||
} else {
|
||||
ZVAL_ARR(&retval, snapshot);
|
||||
}
|
||||
zend_hash_next_index_insert(windowed, &retval);
|
||||
}
|
||||
RETVAL_NEW_COLLECTION(windowed);
|
||||
}
|
||||
|
||||
PHP_METHOD(Collection, zip)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
PHP_METHOD(Collection, zipWithNext)
|
||||
{
|
||||
zend_fcall_info fci;
|
||||
zend_fcall_info_cache fcc;
|
||||
ZEND_PARSE_PARAMETERS_START(0, 1)
|
||||
Z_PARAM_OPTIONAL
|
||||
Z_PARAM_FUNC(fci, fcc)
|
||||
ZEND_PARSE_PARAMETERS_END();
|
||||
zend_array* current = THIS_COLLECTION;
|
||||
if (!HT_IS_PACKED(current)) {
|
||||
ERR_NOT_PACKED();
|
||||
RETURN_NULL();
|
||||
}
|
||||
zend_bool has_transform = EX_NUM_ARGS() == 1;
|
||||
INIT_FCI(&fci, 2);
|
||||
uint32_t num_elements = zend_hash_num_elements(current);
|
||||
ARRAY_NEW(zipped, num_elements);
|
||||
if (num_elements > 1) {
|
||||
Bucket* start = current->arData;
|
||||
uint32_t idx;
|
||||
for (idx = 0; idx < num_elements - 1; ++idx) {
|
||||
Bucket* bucket = start + idx;
|
||||
if (has_transform) {
|
||||
ZVAL_COPY_VALUE(¶ms[0], &bucket->val);
|
||||
ZVAL_COPY_VALUE(¶ms[1], &(bucket + 1)->val);
|
||||
zend_call_function(&fci, &fcc);
|
||||
} else {
|
||||
zend_object* obj = create_pair_obj();
|
||||
Z_TRY_ADDREF(bucket->val);
|
||||
Z_TRY_ADDREF((bucket + 1)->val);
|
||||
pair_update_first(obj, &bucket->val);
|
||||
pair_update_second(obj, &(bucket + 1)->val);
|
||||
zval pair;
|
||||
ZVAL_OBJ(&pair, obj);
|
||||
ZVAL_COPY_VALUE(&retval, &pair);
|
||||
}
|
||||
zend_hash_next_index_insert(zipped, &retval);
|
||||
}
|
||||
}
|
||||
RETVAL_NEW_COLLECTION(zipped);
|
||||
}
|
||||
|
||||
PHP_METHOD(Pair, __construct)
|
||||
{
|
||||
zval* first;
|
||||
|
|
|
@ -112,6 +112,9 @@ PHP_METHOD(Collection, toCollection);
|
|||
PHP_METHOD(Collection, toPairs);
|
||||
PHP_METHOD(Collection, union);
|
||||
PHP_METHOD(Collection, values);
|
||||
PHP_METHOD(Collection, windowed);
|
||||
PHP_METHOD(Collection, zip);
|
||||
PHP_METHOD(Collection, zipWithNext);
|
||||
|
||||
PHP_METHOD(Pair, __construct);
|
||||
|
||||
|
|
|
@ -923,4 +923,48 @@ class Collection implements ArrayAccess, Countable
|
|||
* @return Collection
|
||||
*/
|
||||
function values() {}
|
||||
|
||||
/**
|
||||
* Returns a collection of snapshots of the window of the given size sliding along this
|
||||
* collection with the given step, where each snapshot is an array.
|
||||
*
|
||||
* If provided, the transform function will be applied to each snapshot.
|
||||
*
|
||||
* The wrapped array must be packed.
|
||||
*
|
||||
* @param int $size
|
||||
* @param int $step[optional] = 1
|
||||
* @param bool $partial_windows[optional] = false
|
||||
* @param callable $transform[optional] ($value, $key) -> $new_value
|
||||
* @return Collection
|
||||
*/
|
||||
function windowed($size, $step, $partial_windows, $transform) {}
|
||||
|
||||
/**
|
||||
* Returns a collection of pairs built from the elements of this array and other array
|
||||
* with the same index. The returned collection has length of the shortest array.
|
||||
*
|
||||
* If the transform function is provided, return a collection of the return values of
|
||||
* the transform function applied to each pair of elements.
|
||||
*
|
||||
* Both arrays must be packed.
|
||||
*
|
||||
* @param array|Collection $other
|
||||
* @param callable $transform[optional] ($v1, $v2) -> $new_value
|
||||
* @return Collection
|
||||
*/
|
||||
function zip($other, $transform) {}
|
||||
|
||||
/**
|
||||
* Returns a list of pairs of each two adjacent elements in this collection.
|
||||
*
|
||||
* If the transform function is provided, return a collection of the return values of
|
||||
* the transform function applied to each pair of elements.
|
||||
*
|
||||
* The wrapped array must be packed.
|
||||
*
|
||||
* @param callable $transform[optional] ($v1, $v2) -> $new_value
|
||||
* @return Collection
|
||||
*/
|
||||
function zipWithNext($transform) {}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
--TEST--
|
||||
Test Collection::windowed().
|
||||
--FILE--
|
||||
<?php
|
||||
$array = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'];
|
||||
$collection = Collection::init($array);
|
||||
|
||||
$array1 = [
|
||||
['a', 'b', 'c'],
|
||||
['c', 'd', 'e'],
|
||||
['e', 'f', 'g']
|
||||
];
|
||||
if ($collection->windowed(3, 2, false)->toArray() != $array1) {
|
||||
echo 'Collection::windowed() failed.', PHP_EOL;
|
||||
}
|
||||
|
||||
$array1 = [
|
||||
['a', 'b', 'c', 'd', 4],
|
||||
['d', 'e', 'f', 'g', 4],
|
||||
['g', 'h', 2]
|
||||
];
|
||||
$transform = function ($snapshot) {
|
||||
$snapshot[] = count($snapshot);
|
||||
return $snapshot;
|
||||
};
|
||||
if ($collection->windowed(4, 3, true, $transform)->toArray() != $array1) {
|
||||
echo 'Collection::windowed() failed.', PHP_EOL;
|
||||
}
|
||||
?>
|
||||
--EXPECT--
|
|
@ -0,0 +1,29 @@
|
|||
--TEST--
|
||||
Test Collection::zipWithNext().
|
||||
--FILE--
|
||||
<?php
|
||||
$array = ['foo'];
|
||||
if (Collection::init($array)->zipWithNext()->toArray() != []) {
|
||||
echo 'Collection::zipWithNext() failed.', PHP_EOL;
|
||||
}
|
||||
|
||||
$array = ['a', 'b', 'c', 'd'];
|
||||
$collection = Collection::init($array);
|
||||
$array1 = [
|
||||
new Pair('a', 'b'),
|
||||
new Pair('b', 'c'),
|
||||
new Pair('c', 'd')
|
||||
];
|
||||
if ($collection->zipWithNext()->toArray() != $array1) {
|
||||
echo 'Collection::zipWithNext() failed.', PHP_EOL;
|
||||
}
|
||||
|
||||
$transform = function ($v1, $v2) {
|
||||
return $v1.$v2;
|
||||
};
|
||||
$array1 = ['ab', 'bc', 'cd'];
|
||||
if ($collection->zipWithNext($transform)->toArray() != $array1) {
|
||||
echo 'Collection::zipWithNext() failed.', PHP_EOL;
|
||||
}
|
||||
?>
|
||||
--EXPECT--
|
Reference in New Issue