Implement `windowed()`.
This commit is contained in:
parent
db7b116481
commit
f419ce8c2a
|
@ -3265,7 +3265,61 @@ PHP_METHOD(Collection, values)
|
||||||
|
|
||||||
PHP_METHOD(Collection, windowed)
|
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;
|
||||||
|
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, zip)
|
||||||
|
|
|
@ -930,6 +930,8 @@ class Collection implements ArrayAccess, Countable
|
||||||
*
|
*
|
||||||
* If provided, the transform function will be applied to each snapshot.
|
* If provided, the transform function will be applied to each snapshot.
|
||||||
*
|
*
|
||||||
|
* The wrapped array must be packed.
|
||||||
|
*
|
||||||
* @param int $size
|
* @param int $size
|
||||||
* @param int $step[optional] = 1
|
* @param int $step[optional] = 1
|
||||||
* @param bool $partial_windows[optional] = false
|
* @param bool $partial_windows[optional] = false
|
||||||
|
|
|
@ -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--
|
Reference in New Issue