Add `containsAllKeys()` and `containsAllValues()`.

This commit is contained in:
CismonX 2018-09-03 21:54:14 +08:00
parent 71d97cf961
commit 24a3b72049
5 changed files with 142 additions and 19 deletions

View File

@ -129,6 +129,8 @@ const zend_function_entry collection_methods[] = {
PHP_ME(Collection, associateByTo, associate_by_to_arginfo, ZEND_ACC_PUBLIC)
PHP_ME(Collection, average, NULL, 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)
PHP_ME(Collection, containsKey, contains_key_arginfo, ZEND_ACC_PUBLIC)
PHP_ME(Collection, containsValue, element_arginfo, ZEND_ACC_PUBLIC)
PHP_ME(Collection, copyOf, copy_of_arginfo, ZEND_ACC_PUBLIC)

View File

@ -738,22 +738,99 @@ PHP_METHOD(Collection, containsAll)
ZEND_PARSE_PARAMETERS_END();
ELEMENTS_VALIDATE(elements, ERR_BAD_ARGUMENT_TYPE, return);
zend_array* current = COLLECTION_FETCH_CURRENT();
ZEND_HASH_FOREACH_VAL(elements_arr, zval* element)
equal_check_func_t eql = equal_check_func_init(element);
int result = 0;
ZEND_HASH_FOREACH_VAL(current, zval* val)
result = eql(element, val);
if (result) {
break;
equal_check_func_t eql = NULL;
ZEND_HASH_FOREACH_BUCKET(elements_arr, Bucket* bucket)
if (UNEXPECTED(eql == NULL)) {
eql = equal_check_func_init(&bucket->val);
}
if (bucket->key) {
zval* result = zend_hash_find(current, bucket->key);
if (!result || !eql(&bucket->val, result)) {
RETURN_FALSE;
}
} else {
zval* result = zend_hash_index_find(current, bucket->h);
if (!result || !eql(&bucket->val, result)) {
RETURN_FALSE;
}
}
ZEND_HASH_FOREACH_END();
RETVAL_TRUE;
}
PHP_METHOD(Collection, containsAllKeys)
{
zval* elements;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_ZVAL(elements)
ZEND_PARSE_PARAMETERS_END();
ELEMENTS_VALIDATE(elements, ERR_BAD_ARGUMENT_TYPE, return);
zend_array* current = COLLECTION_FETCH_CURRENT();
ZEND_HASH_FOREACH_BUCKET(elements_arr, Bucket* bucket)
if (bucket->key) {
if (!zend_hash_exists(current, bucket->key)) {
RETURN_FALSE;
}
} else {
if (!zend_hash_index_exists(current, bucket->h)) {
RETURN_FALSE;
}
ZEND_HASH_FOREACH_END();
if (result == 0) {
RETURN_FALSE;
}
ZEND_HASH_FOREACH_END();
RETURN_TRUE;
}
PHP_METHOD(Collection, containsAllValues)
{
zval* elements;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_ZVAL(elements)
ZEND_PARSE_PARAMETERS_END();
ELEMENTS_VALIDATE(elements, ERR_BAD_ARGUMENT_TYPE, return);
zend_array* current = COLLECTION_FETCH_CURRENT();
compare_func_t cmp = NULL;
equal_check_func_t eql = NULL;
ZEND_HASH_FOREACH_VAL(current, zval* val)
cmp = compare_func_init(val, 0, 0);
eql = equal_check_func_init(val);
break;
ZEND_HASH_FOREACH_END();
ARRAY_CLONE(sorted_current, current);
zend_hash_sort(sorted_current, cmp, 1);
ARRAY_CLONE(sorted_other, elements_arr);
zend_hash_sort(sorted_other, cmp, 1);
Bucket* this = NULL;
Bucket* other = sorted_other->arData;
Bucket* end_other = other + zend_hash_num_elements(sorted_other);
zend_bool result = 1;
ZEND_HASH_FOREACH_BUCKET(sorted_current, Bucket* bucket)
if (EXPECTED(this) && eql(&bucket->val, &this->val)) {
continue;
}
this = bucket;
if (cmp(bucket, other)) {
result = 0;
break;
}
do {
if (UNEXPECTED(++other == end_other)) {
goto end;
}
} while (eql(&(other - 1)->val, &other->val));
ZEND_HASH_FOREACH_END();
result = 0;
do {
if (UNEXPECTED(++other == end_other)) {
result = 1;
break;
}
} while (eql(&(other - 1)->val, &other->val));
end:
zend_array_destroy(sorted_current);
zend_array_destroy(sorted_other);
RETVAL_BOOL(result);
}
PHP_METHOD(Collection, containsKey)
{
zval* key;
@ -1546,18 +1623,18 @@ PHP_METHOD(Collection, intersect)
zend_array* current = COLLECTION_FETCH_CURRENT();
ARRAY_NEW(intersected, 8);
equal_check_func_t eql = NULL;
ZEND_HASH_FOREACH_BUCKET(elements_arr, Bucket* bucket)
ZEND_HASH_FOREACH_BUCKET(current, Bucket* bucket)
if (UNEXPECTED(eql == NULL)) {
eql = equal_check_func_init(&bucket->val);
}
if (bucket->key) {
zval* result = zend_hash_find(current, bucket->key);
zval* result = zend_hash_find(elements_arr, bucket->key);
if (result && eql(&bucket->val, result)) {
zend_hash_add(intersected, bucket->key, result);
Z_TRY_ADDREF_P(result);
}
} else {
zval* result = zend_hash_index_find(current, bucket->h);
zval* result = zend_hash_index_find(elements_arr, bucket->h);
if (result && eql(&bucket->val, result)) {
zend_hash_index_add(intersected, bucket->h, result);
Z_TRY_ADDREF_P(result);

View File

@ -17,6 +17,8 @@ PHP_METHOD(Collection, associateBy);
PHP_METHOD(Collection, associateByTo);
PHP_METHOD(Collection, average);
PHP_METHOD(Collection, containsAll);
PHP_METHOD(Collection, containsAllKeys);
PHP_METHOD(Collection, containsAllValues);
PHP_METHOD(Collection, containsKey);
PHP_METHOD(Collection, containsValue);
PHP_METHOD(Collection, copyOf);

View File

@ -93,13 +93,29 @@ class Collection implements ArrayAccess, Countable
function average() {}
/**
* Checks if all elements in the specified collection are contained in this collection.
* Checks if all key-value pairs in the specified collection are contained in this collection.
*
* @param array|Collection $other
* @return bool
*/
function containsAll($other) {}
/**
* Checks if all keys in the specified collection are contained in this collection.
*
* @param array|Collection $other
* @return bool
*/
function containsAllKeys($other) {}
/**
* Checks if all values in the specified collection are contained in this collection.
*
* @param array|Collection $other
* @return bool
*/
function containsAllValues($other) {}
/**
* Checks if the collection contains the given key.
*

View File

@ -1,12 +1,38 @@
--TEST--
Test Collection::containsAll().
Test Collection::containsAll(), Collection::containsAllKeys(), Collection::containsAllValues().
--FILE--
<?php
$array = [[], 1, 't'];
$array1 = [2, ['t'], 5];
$collection = Collection::init([1, 2, 't', [], 5]);
if (!$collection->containsAll($array) || $collection->containsAll($array1)) {
$collection = Collection::init([
'a' => 'b',
'c' => 'd',
'e' => 'f'
]);
$collection1 = Collection::init([
'a' => 'j',
'c' => 'f',
'e' => 'b'
]);
$collection2 = Collection::init([
'a' => 'b',
'e' => 'f'
]);
if (!$collection->containsAll($collection2) ||
$collection2->containsAll($collection) ||
$collection->containsAll($collection1)
) {
echo 'Collection::containsAll() failed.', PHP_EOL;
}
if (!$collection1->containsAllKeys($collection2) ||
!$collection->containsAllKeys($collection1) ||
$collection2->containsAllKeys($collection1)
) {
echo 'Collection::containsAllKeys() failed.', PHP_EOL;
}
if (!$collection->containsAllValues($collection2) ||
!$collection1->containsAllValues($collection2) ||
$collection->containsAllValues($collection1)
) {
echo 'Collection::containsAllValues() failed.', PHP_EOL;
}
?>
--EXPECT--