Compare commits

...

40 Commits

Author SHA1 Message Date
9a7a72dd29 Update LICENSE 2020-03-30 13:21:48 +08:00
66934839e8 Update README.md 2020-03-30 13:08:27 +08:00
96a7c69edd Add codecov.yml. Bumping version. 2020-03-30 12:43:03 +08:00
f4b5e60ba9 Update readme and travis config. 2020-03-30 12:28:12 +08:00
9cd6222d39 integrating Codecov 2020-03-24 11:07:16 +08:00
d7f2835fc0 fix travis configuration 2020-03-20 11:34:55 +08:00
eeb0b4e809 update .travis.yml 2020-03-20 11:20:08 +08:00
368a49271a fix bug. refactor code. 2020-03-20 11:15:54 +08:00
1baf525cd7 prepare for 0.1.1 2019-12-10 04:52:49 +08:00
426d80e5b1 compatible to PHP 7.4 2019-12-10 04:50:01 +08:00
8d9f4d773b small refactor && update documentation 2019-07-25 00:09:02 +08:00
394fdbf5f0 Merge pull request #4 from CismonX/dev
merge changes
2019-06-12 11:27:48 +08:00
da855f8844 refactor 2019-06-12 11:20:37 +08:00
5f3f4f1d96 update 2019-06-08 00:18:42 +08:00
28c9cbb2f1 Merge pull request #3 from CismonX/dev
0.1.0 ready
2019-01-18 21:50:18 +08:00
fea371d6b2 Prevent compiler warning for PHP 7.3 and above. 2019-01-18 21:43:49 +08:00
cbc03da7fb Add zip(). 2019-01-18 21:37:42 +08:00
fddc87e95d Compatible for PHP 7.4 2019-01-18 20:58:05 +08:00
14c4c57736 Add PHP 7.3 to travis. 2019-01-18 20:44:05 +08:00
f00e72f4ac Merge pull request #2 from CismonX/dev
Merge dev into master
2018-11-09 12:04:45 +08:00
98b01ef3e2 Implement zipWithNext(). 2018-11-09 11:57:37 +08:00
cf09a314b2 update 2018-11-08 22:49:58 +08:00
e4a0cc2df8 update stub 2018-10-24 13:37:37 +08:00
dfde697222 fix bug 2018-10-22 20:25:54 +08:00
f419ce8c2a Implement windowed(). 2018-10-22 20:14:33 +08:00
db7b116481 Add signature for windowed(), zip(), zipWithNext(). 2018-10-12 14:48:02 +08:00
9b8df0bf01 Update stubs for zip(). Add stubs for windowed(), zipWithNext(). 2018-10-11 20:23:27 +08:00
c480413b1e Merge branch 'master' of https://github.com/CismonX/ext-collections into dev 2018-10-11 18:57:07 +08:00
60ae083093 refactor code 2018-10-11 18:53:39 +08:00
c9f785935a Add stub for zip(). 2018-09-20 15:23:17 +08:00
28e2cef92c Refactor code. 2018-09-16 16:29:55 +08:00
8af47a3960 Fix bug. 2018-09-15 22:42:57 +08:00
e2b2fc0150 Refactor code. Fix test. 2018-09-15 22:34:25 +08:00
db57bc126d Refactor code. 2018-09-12 15:32:32 +08:00
3245047186 Remove binarySearchWith(). Fix bug for binarySearchBy(). 2018-09-12 14:39:18 +08:00
4eba5b27b7 Refactor code. Add signature for binarySearchWith(). 2018-09-12 13:50:26 +08:00
1b2d443697 Add binarySearch() and binarySearchBy(). Refactor code. 2018-09-12 13:42:13 +08:00
7c9fda5c64 Add chunked(). 2018-09-11 11:28:45 +08:00
693e404667 Update signature for binarySearch() and binarySearchBy(). 2018-09-09 23:05:00 +08:00
d39b273251 Add signature for binarySearch(), binarySearchBy(), chunked(). 2018-09-09 22:20:39 +08:00
27 changed files with 885 additions and 400 deletions

2
.gitattributes vendored
View File

@ -1 +1,3 @@
*.h linguist-language=C
stubs/* linguist-documentation
config.m4 linguist-detectable=false

15
.gitignore vendored
View File

@ -28,11 +28,14 @@ missing
mkinstalldirs
modules
run-tests.php
tests/*/*.diff
tests/*/*.out
tests/*/*.php
tests/*/*.exp
tests/*/*.log
tests/*/*.sh
tests/*.diff
tests/*.out
tests/*.php
tests/*.exp
tests/*.log
tests/*.sh
.idea/
.vscode/
*.gcov
*.gcda
*.gcno

View File

@ -1,15 +1,19 @@
dist: xenial
group: edge
language: php
dist: bionic
php:
- 7.1
- 7.2
- nightly
- 7.3
- 7.4
script:
- phpize
- ./configure
- make
- make EXTRA_CFLAGS='-coverage' EXTRA_LDFLAGS='-fprofile-arcs'
- make test
- gcov --object-directory=src/.libs src/collections_methods.c
after_success:
- bash <(curl -s https://codecov.io/bash)

View File

@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2018 CismonX
Copyright (c) 2018-2020 CismonX<admin@cismon.net>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

101
README.md
View File

@ -1,57 +1,33 @@
# ext-collections
[![Travis-CI](https://travis-ci.org/CismonX/ext-collections.svg?branch=master)](https://travis-ci.org/CismonX/ext-collections)
[![MIT license](https://img.shields.io/badge/licence-MIT-blue.svg)](https://opensource.org/licenses/MIT)
[![Travis-CI](https://travis-ci.com/CismonX/ext-collections.svg?branch=master)](https://travis-ci.com/CismonX/ext-collections)
[![Codecov](https://codecov.io/gh/CismonX/ext-collections/branch/master/graphs/badge.svg)](https://codecov.io/gh/CismonX/ext-collections)
[![MIT license](https://img.shields.io/badge/licence-MIT-blue.svg)](LICENSE)
## 1. Introduction
This PHP extension provides a set of useful functional-style operations on PHP arrays, which makes array manipulation simple and scalable.
This PHP extension provides a set of useful and convenient operations on PHP arrays, which makes working with arrays simple and scalable.
Method names and functionalities are inspired by [Kotlin.Collections](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/).
Method names and functionalities are inspired by [Kotlin.Collections](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/), having a slightly different style than that of [Laravel Collections](https://laravel.com/docs/5.8/collections).
### 1.1 Notes
Requires PHP version >= 7.1 and < 8.0 (master branch).
* Requires PHP 7.1 and above.
* Thread safety:
* Distinct objects: **safe**.
* Shared objects: **unsafe**.
### 1.1 Example
## 2. Documentation
### 2.1 Functionalities
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
The `Collection` class implements `ArrayAccess` and `Countable` interface internally, you can treat an instance of `Collection` as an `ArrayObject`.
* The `isset()`, `unset()` keywords can be used on elements of `Collection`.
* Elements can be accessed via property and bracket expression.
* `empty()`, `count()` can be used on instance of `Collection`.
* Elements can be traversed via `foreach()` keyword.
### 2.4 Notes
* The `Collection::xxxTo()` methods will preserve the original key-value pairs of destination `Collection` when keys collide.
* Some methods of `Collection` involves comparing two of its elements, which accepts `$flags` as one of its arguments. When these methods are being invoked, make sure all elements are of the same type (numeric/string/others), otherwise you're likely to get a segfault.
## 3. Example
Here is a simple example for how to work with arrays gracefully using this extension.
Here is a simple example on how to work with arrays gracefully using this extension.
```php
$employees = [
['name' => 'Alice', 'sex' => 'female', 'age' => 35],
['name' => 'Bob', 'sex' => 'male', 'age' => 29],
['name' => 'David', 'sex' => 'male', 'age' => 40],
['name' => 'Benjamin', 'sex' => 'male', 'age' => 32]
['name' => 'Alice', 'gender' => 'female', 'age' => 35],
['name' => 'Bob', 'gender' => 'male', 'age' => 29],
['name' => 'David', 'gender' => 'male', 'age' => 40],
['name' => 'Benjamin', 'gender' => 'male', 'age' => 32]
];
// Trying to get an array of names of male employees,
// sorted by the descending order of their age.
$names = Collection::init($employees)
->filter(function ($value) {
return $value['sex'] == 'male';
return $value['gender'] == 'male';
})
->sortedByDescending(function ($value) {
return $value['age'];
@ -62,3 +38,54 @@ $names = Collection::init($employees)
->toArray();
// You got $names == ['David', 'Benjamin', 'Bob'].
```
## 2. Getting Started
### 2.1 Installation
Like other PHP extensions, ext-collections can be built and installed with a few commands:
```bash
phpize
./configure
make
sudo make install
```
Include it in your PHP configuration file to enable this extension:
```php.ini
extension=collections.so
```
Building on Windows is not as convenient, however, pre-built binaries for Windows are provided in the [releases](https://github.com/CismonX/ext-collections/releases). If you want to build it yourself, follow the [official PHP wiki](https://wiki.php.net/internals/windows/stepbystepbuild_sdk_2).
### 2.2 API Reference
See [stubs](stubs/) directory for signatures of all classes and methods of this extension, with PHPDoc. They can also serve as IDE helper.
### 2.3 PHP-style Access
The `Collection` class implements `ArrayAccess` and `Countable` interface internally, you can treat an instance of `Collection` as an `ArrayObject`.
* The `isset()`, `unset()` keywords can be used on elements of `Collection`.
* Elements can be accessed via property or bracket expression.
* `empty()`, `count()` can be used on instance of `Collection`.
* Elements can be traversed via `foreach()` keyword.
## 3. Notes
* The `Collection::xxxTo()` methods will preserve the original key-value pairs of destination `Collection` when keys collide.
* Some methods of `Collection` involves comparing two of its elements, which accepts `$flags` as one of its arguments. When these methods are being invoked, make sure all elements are of the same type (numeric/string/others), otherwise you're likely to get a segfault.
### 3.1 Copy-on-write Mechanism
Class `Collection` does not introduce new data structures internally. Instead, it only holds a pointer to a `zend_array`, and all its methods works directly on top of `zend_array`. Which means conversion between `Collection` and `array` does not involve copying, until write operation is performed on one of the duplicates.
```php
$foo = ['a', 'b']; // arr0: refcount = 1
$bar = Collection::init($foo); // arr0: refcount = 2, no copying of either `zend_array` or its elements
echo $bar->containsValue('a'); // arr0: refcount = 2, read operation, no copying
$bar->shuffle(); // arr0: refcount = 1, arr1: refcount = 1, write operation, `zend_array` is separated
$baz = $bar->toArray(); // arr0: refcount = 1, arr1: refcount = 2, no copying
```

2
codecov.yml Normal file
View File

@ -0,0 +1,2 @@
ignore:
- "src/collections.c"

View File

@ -17,6 +17,10 @@
zend_declare_class_constant_long(collections_##cls##_ce, name, sizeof(name) - 1, val)
#define COLLECTIONS_PROP_DECLARE(cls, name, flags) \
zend_declare_property_null(collections_##cls##_ce, name, sizeof(name) - 1, flags)
#define COLLECTIONS_HANDLERS_INIT(cls) \
memcpy(&cls##_handlers, &std_object_handlers, sizeof(zend_object_handlers))
#define COLLECTIONS_HANDLER_SET(cls, name) \
cls##_handlers.name = cls##_##name
zend_object_handlers collection_handlers;
@ -41,16 +45,16 @@ static zend_always_inline void collection_ce_init()
2, zend_ce_countable,
#endif
zend_ce_arrayaccess);
memcpy(&collection_handlers, &std_object_handlers, sizeof(zend_object_handlers));
collection_handlers.unset_dimension = collection_offset_unset;
collection_handlers.unset_property = collection_property_unset;
collection_handlers.write_dimension = collection_offset_set;
collection_handlers.write_property = collection_property_set;
collection_handlers.read_dimension = collection_offset_get;
collection_handlers.read_property = collection_property_get;
collection_handlers.has_dimension = collection_offset_exists;
collection_handlers.has_property = collection_property_exists;
collection_handlers.count_elements = count_collection;
COLLECTIONS_HANDLERS_INIT(collection);
COLLECTIONS_HANDLER_SET(collection, count_elements);
COLLECTIONS_HANDLER_SET(collection, has_dimension);
COLLECTIONS_HANDLER_SET(collection, write_dimension);
COLLECTIONS_HANDLER_SET(collection, read_dimension);
COLLECTIONS_HANDLER_SET(collection, unset_dimension);
COLLECTIONS_HANDLER_SET(collection, has_property);
COLLECTIONS_HANDLER_SET(collection, write_property);
COLLECTIONS_HANDLER_SET(collection, read_property);
COLLECTIONS_HANDLER_SET(collection, unset_property);
}
static zend_always_inline void pair_ce_init()

View File

@ -97,14 +97,34 @@ ZEND_BEGIN_ARG_INFO(copy_of_arginfo, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO(copy_of_range_arginfo, 0)
ZEND_ARG_TYPE_INFO(0, from_idx, IS_LONG, 0)
ZEND_ARG_TYPE_INFO(0, num_elements, IS_LONG, 0)
ZEND_ARG_TYPE_INFO(0, from_index, IS_LONG, 0)
ZEND_ARG_TYPE_INFO(0, to_index, IS_LONG, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO(fill_arginfo, 0)
ZEND_ARG_INFO(0, element)
ZEND_ARG_TYPE_INFO(0, from_index, IS_LONG, 0)
ZEND_ARG_TYPE_INFO(0, num_elements, IS_LONG, 0)
ZEND_ARG_TYPE_INFO(0, to_index, IS_LONG, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO(binary_search_arginfo, 0)
ZEND_ARG_INFO(0, element)
ZEND_ARG_TYPE_INFO(0, flags, IS_LONG, 0)
ZEND_ARG_TYPE_INFO(0, from_index, IS_LONG, 0)
ZEND_ARG_TYPE_INFO(0, to_index, IS_LONG, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO(binary_search_by_arginfo, 0)
ZEND_ARG_INFO(0, element)
ZEND_ARG_CALLABLE_INFO(0, selector, 0)
ZEND_ARG_TYPE_INFO(0, flags, IS_LONG, 0)
ZEND_ARG_TYPE_INFO(0, from_index, IS_LONG, 0)
ZEND_ARG_TYPE_INFO(0, to_index, IS_LONG, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO(chuncked_arginfo, 0)
ZEND_ARG_TYPE_INFO(0, size, IS_LONG, 0)
ZEND_ARG_CALLABLE_INFO(0, transform, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO(get_arginfo, 0)
@ -116,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)
@ -126,6 +158,9 @@ const zend_function_entry collection_methods[] = {
PHP_ME(Collection, associateBy, associate_by_arginfo, ZEND_ACC_PUBLIC)
PHP_ME(Collection, associateByTo, associate_by_to_arginfo, ZEND_ACC_PUBLIC)
PHP_ME(Collection, average, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Collection, binarySearch, binary_search_arginfo, ZEND_ACC_PUBLIC)
PHP_ME(Collection, binarySearchBy, binary_search_by_arginfo, ZEND_ACC_PUBLIC)
PHP_ME(Collection, chunked, chuncked_arginfo, ZEND_ACC_PUBLIC)
PHP_ME(Collection, containsAll, other_arginfo, ZEND_ACC_PUBLIC)
PHP_ME(Collection, containsAllKeys, other_arginfo, ZEND_ACC_PUBLIC)
PHP_ME(Collection, containsAllValues, other_arginfo, ZEND_ACC_PUBLIC)
@ -217,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
};

File diff suppressed because it is too large Load Diff

View File

@ -16,7 +16,7 @@
extern zend_module_entry collections_module_entry;
#define phpext_collections_ptr &collections_module_entry
#define PHP_COLLECTIONS_VERSION "0.1.0"
#define PHP_COLLECTIONS_VERSION "0.1.2"
#ifdef PHP_WIN32
#define PHP_COLLECTIONS_API __declspec(dllexport)
@ -28,6 +28,14 @@ extern zend_module_entry collections_module_entry;
#if PHP_VERSION_ID < 70100
#error "This extension requires PHP 7.1 and above."
#elif PHP_VERSION_ID >= 80000
#error "This extension does not yet support PHP 8.0 (which is under development)."
#endif
#if PHP_VERSION_ID >= 70400
typedef zval* zobj_write_prop_ret_t;
#else
typedef void zobj_write_prop_ret_t;
#endif
#define PHP_COLLECTIONS_COMPARE_NATURAL (1 << 0)
@ -56,15 +64,15 @@ extern PHP_COLLECTIONS_API zend_class_entry* collections_pair_ce;
extern zend_object_handlers collection_handlers;
int count_collection(zval* obj, zend_long* count);
int collection_offset_exists(zval* object, zval* offset, int check_empty);
void collection_offset_set(zval* object, zval* offset, zval* value);
zval* collection_offset_get(zval* object, zval* offset, int type, zval* retval);
void collection_offset_unset(zval* object, zval* offset);
int collection_property_exists(zval* object, zval* member, int has_set_exists, void**);
void collection_property_set(zval* object, zval* member, zval* value, void**);
zval* collection_property_get(zval* object, zval* member, int type, void**, zval* retval);
void collection_property_unset(zval* object, zval* member, void**);
int collection_count_elements(zval* obj, zend_long* count);
int collection_has_dimension(zval* object, zval* offset, int check_empty);
void collection_write_dimension(zval* object, zval* offset, zval* value);
zval* collection_read_dimension(zval* object, zval* offset, int type, zval* rv);
void collection_unset_dimension(zval* object, zval* offset);
int collection_has_property(zval* object, zval* member, int has_set_exists, void**);
zobj_write_prop_ret_t collection_write_property(zval* object, zval* member, zval* value, void**);
zval* collection_read_property(zval* object, zval* member, int type, void**, zval* rv);
void collection_unset_property(zval* object, zval* member, void**);
extern const zend_function_entry collection_methods[];
extern const zend_function_entry pair_methods[];

View File

@ -18,6 +18,9 @@ PHP_METHOD(Collection, associateTo);
PHP_METHOD(Collection, associateBy);
PHP_METHOD(Collection, associateByTo);
PHP_METHOD(Collection, average);
PHP_METHOD(Collection, binarySearch);
PHP_METHOD(Collection, binarySearchBy);
PHP_METHOD(Collection, chunked);
PHP_METHOD(Collection, containsAll);
PHP_METHOD(Collection, containsAllKeys);
PHP_METHOD(Collection, containsAllValues);
@ -109,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);

View File

@ -92,6 +92,49 @@ class Collection implements ArrayAccess, Countable
*/
function average() {}
/**
* Searches the array or the range of the array for the provided element using the
* binary search algorithm.
*
* The array is expected to be packed and sorted into ascending order, otherwise the
* result is undefined.
*
* @param mixed $element
* @param int $flags[optional]
* @param int $from_index[optional]
* @param int $to_index[optional]
* @return int|null
*/
function binarySearch($element, $flags, $from_index, $to_index) {}
/**
* Searches the array or the range of the array for the provided element using the
* binary search algorithm, where the element equals to the one returned by the
* corresponding selector function.
*
* The array is expected to be packed and sorted into ascending order, otherwise the
* result is undefined.
*
* @param mixed $element
* @param callable $selector ($value, $key) -> $new_value
* @param int $flags[optional]
* @param int $from_index[optional]
* @param int $to_index[optional]
* @return int|null
*/
function binarySearchBy($element, $selector, $flags, $from_index, $to_index) {}
/**
* Splits this collection into a collection of arrays each not exceeding the given size.
*
* If the transform function is provided, apply it on each array.
*
* @param int $size
* @param callable $transform[optional] ($value, $key) -> $new_value
* @return Collection
*/
function chunked($size, $transform) {}
/**
* Checks if all key-value pairs in the specified collection are contained in this collection.
*
@ -144,10 +187,10 @@ class Collection implements ArrayAccess, Countable
* Returns new collection which is a copy of range of original collection.
*
* @param int $from_index
* @param int $num_elements
* @param int $to_index
* @return Collection
*/
function copyOfRange($from_index, $num_elements) {}
function copyOfRange($from_index, $to_index) {}
/**
* Returns the number of elements in this collection.
@ -217,10 +260,10 @@ class Collection implements ArrayAccess, Countable
*
* @param mixed $element
* @param int $from_index[optional]
* @param int $num_elements[optional]
* @param int $to_index[optional]
* @return void
*/
function fill($element, $from_index, $num_elements) {}
function fill($element, $from_index, $to_index) {}
/**
* Returns a collection containing only elements matching the given predicate.
@ -547,38 +590,6 @@ class Collection implements ArrayAccess, Countable
*/
function none($predicate) {}
/**
* This method is implemented in handlers.unset_dimension.
* There's no method with name 'offsetUnset'.
*
* @internal
*/
function offsetUnset($key) {}
/**
* This method is implemented in handlers.write_dimension.
* There's no method with name 'offsetSet'.
*
* @internal
*/
function offsetSet($key, $value) {}
/**
* This method is implemented in handlers.read_dimension.
* There's no method with name 'offsetGet'.
*
* @internal
*/
function offsetGet($key) {}
/**
* This method is implemented in handlers.has_dimension.
* There's no method with name 'offsetExists'.
*
* @internal
*/
function offsetExists($key) {}
/**
* Performs the given action on each element and returns the collection itself afterwards.
*
@ -912,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) {}
}

View File

@ -7,8 +7,8 @@ $array = [3, 7, 6, 9, 2];
// An associative array, however, Collection::copyOfRange() still works,
// and string keys will be preserved.
$array1 = ['a' => 'b', 'c', 'd' => 'e'];
$array2 = Collection::init($array)->copyOfRange(2, 4)->toArray();
$array3 = Collection::init($array1)->copyOfRange(1, 2)->toArray();
$array2 = Collection::init($array)->copyOfRange(2, 6)->toArray();
$array3 = Collection::init($array1)->copyOfRange(1, 3)->toArray();
if ($array2 != array_slice($array, 2, 4) || $array3 != array_slice($array1, 1, 2)) {
echo 'Collection::copyOfRange() failed.', PHP_EOL;
}

View File

@ -4,7 +4,7 @@ Test Collection::fill().
<?php
$array = ['foo', 'bar' => 'baz', 1, 2, 3];
$collection = Collection::init($array);
$collection->fill('t', 1, 3);
$collection->fill('t', 1, 4);
$array1 = ['foo', 'bar' => 't', 't', 't', 3];
$collection1 = Collection::init($array);
$collection1->fill(0);

View File

@ -4,7 +4,7 @@ Test Collection::sort(), Collection::sortDescending(), Collection::sorted(), Col
<?php
$array = [];
for ($i = 0; $i < 100; ++$i) {
$array[] = random_int(-200, 200);
$array[] = mt_rand(-200, 200);
}
$collection = Collection::init($array);

View File

@ -4,7 +4,7 @@ Test Collection::sortBy(), Collection::sortByDescending(), Collection::sortedBy(
<?php
$array = [];
for ($i = 0; $i < 4; ++$i) {
$array[random_bytes(2)] = [random_int(10, 99)];
$array[random_bytes(2)] = [mt_rand(10, 99)];
}
$sort_by = function ($value) {

View File

@ -4,7 +4,7 @@ Test Collection::distinct().
<?php
$array = [];
for ($i = 0; $i < 100; ++$i) {
$array[] = random_int(1, 10);
$array[] = mt_rand(1, 10);
}
$collection = Collection::init($array)->distinct();
if ($collection->toArray() != array_values(array_unique($array))) {

View File

@ -4,7 +4,7 @@ Test Collection::distinctBy().
<?php
$array = [];
for ($i = 0; $i < 100; ++$i) {
$array[] = random_bytes(random_int(1, 10));
$array[] = random_bytes(mt_rand(1, 10));
}
$get_len = function ($value) {
return strlen($value);

View File

@ -4,11 +4,11 @@ Test Collection::union().
<?php
$array = [];
for ($i = 0; $i < 50; ++$i) {
$array[] = random_int(1, 50);
$array[] = mt_rand(1, 50);
}
$array1 = [];
for ($i = 0; $i < 50; ++$i) {
$array1[] = random_int(1, 50);
$array1[] = mt_rand(1, 50);
}
$union = array_values(array_unique(array_merge($array, $array1)));
$collection = Collection::init($array);

View File

@ -4,7 +4,7 @@ Test Collection::sum() and Collection::sumBy().
<?php
$array = [];
for ($i = 0; $i < 50; ++$i) {
$array[] = random_int(1, 50);
$array[] = mt_rand(1, 50);
}
$collection = Collection::init($array);
$sum = array_sum($array);
@ -12,7 +12,7 @@ if ($collection->sum() != $sum) {
echo 'Collection::sum() failed.', PHP_EOL;
}
$array = array_map(function ($value) {
return [$value, floatval($value / random_int(3, 7))];
return [$value, floatval($value / mt_rand(3, 7))];
}, $array);
$collection = Collection::init($array);
$sum = array_sum(array_column($array, 1));

View File

@ -4,11 +4,11 @@ Test Collection::intersectValues() and Collection::subtract().
<?php
$array = [];
for ($i = 0; $i < 50; ++$i) {
$array[] = random_int(1, 50);
$array[] = mt_rand(1, 50);
}
$array1 = [];
for ($i = 0; $i < 50; ++$i) {
$array1[] = random_int(1, 50);
$array1[] = mt_rand(1, 50);
}
$collection = Collection::init($array);
$collection1 = Collection::init($array1);

View File

@ -4,11 +4,11 @@ Test Collection::removeAll() and Collection::retainAll().
<?php
$array = [];
for ($i = 0; $i < 50; ++$i) {
$array[] = random_int(1, 50);
$array[] = mt_rand(1, 50);
}
$array1 = [];
for ($i = 0; $i < 50; ++$i) {
$array1[] = random_int(1, 50);
$array1[] = mt_rand(1, 50);
}
$collection = Collection::init($array);

27
tests/057-chunked.phpt Normal file
View File

@ -0,0 +1,27 @@
--TEST--
Test Collection::chunked().
--FILE--
<?php
$array = [];
$size = mt_rand(20, 30);
for ($i = 0; $i < 50; ++$i) {
$array[] = mt_rand(100, 200);
}
$chunk_size = mt_rand(4, 9);
$chunked = array_chunk($array, $chunk_size, false);
$collection = Collection::init($array);
if ($collection->chunked($chunk_size)->toArray() != $chunked) {
echo 'Collection::chunked() failed.', PHP_EOL;
}
$transform = function ($value) use ($chunk_size) {
if (count($value) < $chunk_size) {
return [];
}
return $value;
};
$chunked = array_map($transform, $chunked);
if ($collection->chunked($chunk_size, $transform)->toArray() != $chunked) {
echo 'Collection::chunked() failed.', PHP_EOL;
}
?>
--EXPECT--

View File

@ -0,0 +1,31 @@
--TEST--
Test Collection::binarySearch() and Collection::binarySearchBy().
--FILE--
<?php
$array = [];
$size = mt_rand(20, 30);
for ($i = 0; $i < 50; ++$i) {
$array[] = mt_rand(100, 200);
}
$array = array_unique($array);
sort($array);
$idx = mt_rand(0, count($array) - 1);
$which = $array[$idx];
$from = mt_rand(0, $idx);
$to = mt_rand($idx + 1, count($array));
$collection = Collection::init($array);
if ($collection->binarySearch($which, 0, $from, $to) != $idx) {
echo 'Collection::binarySearch() failed.', PHP_EOL;
}
$array = array_map(function ($value) {
return [$value];
}, $array);
$selector = function ($value) {
return $value[0];
};
$collection = Collection::init($array);
if ($collection->binarySearchBy($which, $selector, 0, $from, $to) != $idx) {
echo 'Collection::binarySearchBy() failed.', PHP_EOL;
}
?>
--EXPECT--

30
tests/059-windowed.phpt Normal file
View File

@ -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--

View File

@ -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--

20
tests/061-zip.phpt Normal file
View File

@ -0,0 +1,20 @@
--TEST--
Test Collection::zip().
--FILE--
<?php
$array = ['a', 'b', 'c'];
$array1 = ['d', 'e'];
$zipped = Collection::init($array)->zip($array1)->toArray();
if ($zipped != [new Pair('a', 'd'), new Pair('b', 'e')]) {
echo 'Collection::zip() failed.', PHP_EOL;
}
$transform = function ($v1, $v2) {
return $v1.$v2;
};
$zipped = Collection::init($array1)->zip($array, $transform)->toArray();
if ($zipped != ['da', 'eb']) {
echo 'Collection::zip() failed.', PHP_EOL;
}
?>
--EXPECT--