Compare commits
40 Commits
v0.1.0-bet
...
master
Author | SHA1 | Date |
---|---|---|
CismonX | 9a7a72dd29 | |
CismonX | 66934839e8 | |
CismonX | 96a7c69edd | |
CismonX | f4b5e60ba9 | |
CismonX | 9cd6222d39 | |
CismonX | d7f2835fc0 | |
CismonX | eeb0b4e809 | |
CismonX | 368a49271a | |
CismonX | 1baf525cd7 | |
CismonX | 426d80e5b1 | |
CismonX | 8d9f4d773b | |
CismonX | 394fdbf5f0 | |
CismonX | da855f8844 | |
CismonX | 5f3f4f1d96 | |
CismonX | 28c9cbb2f1 | |
CismonX | fea371d6b2 | |
CismonX | cbc03da7fb | |
CismonX | fddc87e95d | |
CismonX | 14c4c57736 | |
CismonX | f00e72f4ac | |
CismonX | 98b01ef3e2 | |
CismonX | cf09a314b2 | |
CismonX | e4a0cc2df8 | |
CismonX | dfde697222 | |
CismonX | f419ce8c2a | |
CismonX | db7b116481 | |
CismonX | 9b8df0bf01 | |
CismonX | c480413b1e | |
CismonX | 60ae083093 | |
CismonX | c9f785935a | |
CismonX | 28e2cef92c | |
CismonX | 8af47a3960 | |
CismonX | e2b2fc0150 | |
CismonX | db57bc126d | |
CismonX | 3245047186 | |
CismonX | 4eba5b27b7 | |
CismonX | 1b2d443697 | |
CismonX | 7c9fda5c64 | |
CismonX | 693e404667 | |
CismonX | d39b273251 |
|
@ -1 +1,3 @@
|
|||
*.h linguist-language=C
|
||||
*.h linguist-language=C
|
||||
stubs/* linguist-documentation
|
||||
config.m4 linguist-detectable=false
|
||||
|
|
|
@ -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
|
||||
|
|
14
.travis.yml
14
.travis.yml
|
@ -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)
|
||||
|
|
4
LICENSE
4
LICENSE
|
@ -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
|
||||
|
@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
THE SOFTWARE.
|
||||
|
|
101
README.md
101
README.md
|
@ -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
|
||||
```
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
ignore:
|
||||
- "src/collections.c"
|
|
@ -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()
|
||||
|
|
|
@ -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
|
@ -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[];
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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) {}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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))) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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--
|
|
@ -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--
|
|
@ -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--
|
|
@ -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--
|
Reference in New Issue