Implement `copyOfRange()` and `count()`
This commit is contained in:
parent
a7a39c889a
commit
f7b924801b
|
@ -10,6 +10,7 @@
|
||||||
|
|
||||||
#include <php.h>
|
#include <php.h>
|
||||||
#include <php_ini.h>
|
#include <php_ini.h>
|
||||||
|
#include <zend_interfaces.h>
|
||||||
#include <ext/standard/info.h>
|
#include <ext/standard/info.h>
|
||||||
|
|
||||||
#include "php_collections.h"
|
#include "php_collections.h"
|
||||||
|
@ -18,6 +19,8 @@ zend_string* collection_property_name;
|
||||||
zend_string* pair_first_name;
|
zend_string* pair_first_name;
|
||||||
zend_string* pair_second_name;
|
zend_string* pair_second_name;
|
||||||
|
|
||||||
|
zend_object_handlers* collection_handlers;
|
||||||
|
|
||||||
zend_class_entry* collections_collection_ce;
|
zend_class_entry* collections_collection_ce;
|
||||||
zend_class_entry* collections_pair_ce;
|
zend_class_entry* collections_pair_ce;
|
||||||
|
|
||||||
|
@ -26,7 +29,17 @@ PHP_MINIT_FUNCTION(collections)
|
||||||
zend_class_entry collection_ce;
|
zend_class_entry collection_ce;
|
||||||
INIT_CLASS_ENTRY_EX(collection_ce, "Collection", sizeof "Collection" - 1, collection_methods);
|
INIT_CLASS_ENTRY_EX(collection_ce, "Collection", sizeof "Collection" - 1, collection_methods);
|
||||||
collections_collection_ce = zend_register_internal_class(&collection_ce);
|
collections_collection_ce = zend_register_internal_class(&collection_ce);
|
||||||
|
zend_class_implements(collections_collection_ce,
|
||||||
|
#if PHP_VERSION_ID < 70200
|
||||||
|
1,
|
||||||
|
#else
|
||||||
|
2, zend_ce_countable,
|
||||||
|
#endif
|
||||||
|
zend_ce_arrayaccess);
|
||||||
zend_declare_property_null(collections_collection_ce, "_", sizeof "_" - 1, ZEND_ACC_PRIVATE);
|
zend_declare_property_null(collections_collection_ce, "_", sizeof "_" - 1, ZEND_ACC_PRIVATE);
|
||||||
|
collection_handlers = (zend_object_handlers*)emalloc(sizeof(zend_object_handlers));
|
||||||
|
memcpy(collection_handlers, &std_object_handlers, sizeof(zend_object_handlers));
|
||||||
|
collection_handlers->count_elements = count_collection;
|
||||||
zend_class_entry pair_ce;
|
zend_class_entry pair_ce;
|
||||||
INIT_CLASS_ENTRY_EX(pair_ce, "Pair", sizeof "Pair" - 1, pair_methods);
|
INIT_CLASS_ENTRY_EX(pair_ce, "Pair", sizeof "Pair" - 1, pair_methods);
|
||||||
collections_pair_ce = zend_register_internal_class(&pair_ce);
|
collections_pair_ce = zend_register_internal_class(&pair_ce);
|
||||||
|
|
|
@ -35,11 +35,6 @@ ZEND_BEGIN_ARG_INFO(elements_arginfo, 0)
|
||||||
ZEND_ARG_INFO(0, elements)
|
ZEND_ARG_INFO(0, elements)
|
||||||
ZEND_END_ARG_INFO()
|
ZEND_END_ARG_INFO()
|
||||||
|
|
||||||
ZEND_BEGIN_ARG_INFO(from_to_arginfo, 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(initial_operation_arginfo, 0)
|
ZEND_BEGIN_ARG_INFO(initial_operation_arginfo, 0)
|
||||||
ZEND_ARG_INFO(0, initial)
|
ZEND_ARG_INFO(0, initial)
|
||||||
ZEND_ARG_CALLABLE_INFO(0, operation, 0)
|
ZEND_ARG_CALLABLE_INFO(0, operation, 0)
|
||||||
|
@ -95,6 +90,11 @@ ZEND_BEGIN_ARG_INFO(copy_of_arginfo, 0)
|
||||||
ZEND_ARG_TYPE_INFO(0, new_size, IS_LONG, 0)
|
ZEND_ARG_TYPE_INFO(0, new_size, IS_LONG, 0)
|
||||||
ZEND_END_ARG_INFO()
|
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_END_ARG_INFO()
|
||||||
|
|
||||||
ZEND_BEGIN_ARG_INFO(fill_arginfo, 0)
|
ZEND_BEGIN_ARG_INFO(fill_arginfo, 0)
|
||||||
ZEND_ARG_INFO(0, element)
|
ZEND_ARG_INFO(0, element)
|
||||||
ZEND_ARG_TYPE_INFO(0, from_index, IS_LONG, 0)
|
ZEND_ARG_TYPE_INFO(0, from_index, IS_LONG, 0)
|
||||||
|
@ -135,7 +135,7 @@ const zend_function_entry collection_methods[] = {
|
||||||
PHP_ME(Collection, containsKey, key_arginfo, ZEND_ACC_PUBLIC)
|
PHP_ME(Collection, containsKey, key_arginfo, ZEND_ACC_PUBLIC)
|
||||||
PHP_ME(Collection, containsValue, element_arginfo, ZEND_ACC_PUBLIC)
|
PHP_ME(Collection, containsValue, element_arginfo, ZEND_ACC_PUBLIC)
|
||||||
PHP_ME(Collection, copyOf, copy_of_arginfo, ZEND_ACC_PUBLIC)
|
PHP_ME(Collection, copyOf, copy_of_arginfo, ZEND_ACC_PUBLIC)
|
||||||
PHP_ME(Collection, copyOfRange, from_to_arginfo, ZEND_ACC_PUBLIC)
|
PHP_ME(Collection, copyOfRange, copy_of_range_arginfo, ZEND_ACC_PUBLIC)
|
||||||
PHP_ME(Collection, count, NULL, ZEND_ACC_PUBLIC)
|
PHP_ME(Collection, count, NULL, ZEND_ACC_PUBLIC)
|
||||||
PHP_ME(Collection, distinct, NULL, ZEND_ACC_PUBLIC)
|
PHP_ME(Collection, distinct, NULL, ZEND_ACC_PUBLIC)
|
||||||
PHP_ME(Collection, distinctBy, selector_arginfo, ZEND_ACC_PUBLIC)
|
PHP_ME(Collection, distinctBy, selector_arginfo, ZEND_ACC_PUBLIC)
|
||||||
|
@ -210,7 +210,6 @@ const zend_function_entry collection_methods[] = {
|
||||||
PHP_ME(Collection, shuffle, NULL, ZEND_ACC_PUBLIC)
|
PHP_ME(Collection, shuffle, NULL, ZEND_ACC_PUBLIC)
|
||||||
PHP_ME(Collection, single, predicate_arginfo, ZEND_ACC_PUBLIC)
|
PHP_ME(Collection, single, predicate_arginfo, ZEND_ACC_PUBLIC)
|
||||||
PHP_ME(Collection, slice, keys_arginfo, ZEND_ACC_PUBLIC)
|
PHP_ME(Collection, slice, keys_arginfo, ZEND_ACC_PUBLIC)
|
||||||
PHP_ME(Collection, sliceRange, from_to_arginfo, ZEND_ACC_PUBLIC)
|
|
||||||
PHP_ME(Collection, sort, NULL, ZEND_ACC_PUBLIC)
|
PHP_ME(Collection, sort, NULL, ZEND_ACC_PUBLIC)
|
||||||
PHP_ME(Collection, sortBy, selector_arginfo, ZEND_ACC_PUBLIC)
|
PHP_ME(Collection, sortBy, selector_arginfo, ZEND_ACC_PUBLIC)
|
||||||
PHP_ME(Collection, sortByDescending, selector_arginfo, ZEND_ACC_PUBLIC)
|
PHP_ME(Collection, sortByDescending, selector_arginfo, ZEND_ACC_PUBLIC)
|
||||||
|
|
|
@ -9,14 +9,16 @@
|
||||||
#include "php_collections.h"
|
#include "php_collections.h"
|
||||||
#include "php_collections_me.h"
|
#include "php_collections_me.h"
|
||||||
|
|
||||||
#define NEW_OBJ(name, ce) \
|
#define NEW_OBJ(name, ce, object_handlers) \
|
||||||
zend_object* (name) = (zend_object*)ecalloc(1, sizeof(zend_object) + \
|
zend_object* (name) = (zend_object*)ecalloc(1, sizeof(zend_object) + \
|
||||||
zend_object_properties_size(ce)); \
|
zend_object_properties_size(ce)); \
|
||||||
zend_object_std_init(name, ce); \
|
zend_object_std_init(name, ce); \
|
||||||
object_properties_init(name, ce); \
|
object_properties_init(name, ce); \
|
||||||
(name)->handlers = &std_object_handlers;
|
(name)->handlers = object_handlers;
|
||||||
#define NEW_COLLECTION_OBJ(name) NEW_OBJ(name, collections_collection_ce)
|
#define NEW_COLLECTION_OBJ(name) \
|
||||||
#define NEW_PAIR_OBJ(name) NEW_OBJ(name, collections_pair_ce)
|
NEW_OBJ(name, collections_collection_ce, collection_handlers)
|
||||||
|
#define NEW_PAIR_OBJ(name) \
|
||||||
|
NEW_OBJ(name, collections_pair_ce, &std_object_handlers)
|
||||||
|
|
||||||
#define IS_COLLECTION_P(zval) \
|
#define IS_COLLECTION_P(zval) \
|
||||||
Z_TYPE_P(zval) == IS_OBJECT && Z_OBJCE_P(zval) == collections_collection_ce
|
Z_TYPE_P(zval) == IS_OBJECT && Z_OBJCE_P(zval) == collections_collection_ce
|
||||||
|
@ -58,12 +60,12 @@
|
||||||
else \
|
else \
|
||||||
equal_check_func = fast_equal_check_function;
|
equal_check_func = fast_equal_check_function;
|
||||||
|
|
||||||
|
|
||||||
#define PHP_COLLECTIONS_ERROR(type, msg) php_error_docref(NULL, type, msg)
|
#define PHP_COLLECTIONS_ERROR(type, msg) php_error_docref(NULL, type, msg)
|
||||||
#define ERR_BAD_ARGUMENT_TYPE() PHP_COLLECTIONS_ERROR(E_WARNING, "Bad argument type")
|
#define ERR_BAD_ARGUMENT_TYPE() PHP_COLLECTIONS_ERROR(E_WARNING, "Bad argument type")
|
||||||
#define ERR_BAD_KEY_TYPE() PHP_COLLECTIONS_ERROR(E_WARNING, "Key must be integer or string")
|
#define ERR_BAD_KEY_TYPE() PHP_COLLECTIONS_ERROR(E_WARNING, "Key must be integer or string")
|
||||||
#define ERR_BAD_CALLBACK_RETVAL() PHP_COLLECTIONS_ERROR(E_WARNING, "Bad callback return value")
|
#define ERR_BAD_CALLBACK_RETVAL() PHP_COLLECTIONS_ERROR(E_WARNING, "Bad callback return value")
|
||||||
#define ERR_BAD_SIZE() PHP_COLLECTIONS_ERROR(E_WARNING, "Size must be non-negative")
|
#define ERR_BAD_SIZE() PHP_COLLECTIONS_ERROR(E_WARNING, "Size must be non-negative")
|
||||||
|
#define ERR_BAD_INDEX() PHP_COLLECTIONS_ERROR(E_WARNING, "Index must be non-negative")
|
||||||
#define ERR_NOT_ARITHMETIC() PHP_COLLECTIONS_ERROR(E_WARNING, "Elements should be int or double")
|
#define ERR_NOT_ARITHMETIC() PHP_COLLECTIONS_ERROR(E_WARNING, "Elements should be int or double")
|
||||||
|
|
||||||
#define ELEMENTS_VALIDATE(elements) \
|
#define ELEMENTS_VALIDATE(elements) \
|
||||||
|
@ -101,6 +103,14 @@
|
||||||
return; \
|
return; \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int count_collection(zval* obj, zend_long* count)
|
||||||
|
{
|
||||||
|
zval rv;
|
||||||
|
zval* current = COLLECTION_FETCH(obj);
|
||||||
|
*count = zend_hash_num_elements(Z_ARRVAL_P(current));
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
PHP_METHOD(Collection, __construct) {}
|
PHP_METHOD(Collection, __construct) {}
|
||||||
|
|
||||||
PHP_METHOD(Collection, addAll)
|
PHP_METHOD(Collection, addAll)
|
||||||
|
@ -387,12 +397,38 @@ PHP_METHOD(Collection, copyOf)
|
||||||
|
|
||||||
PHP_METHOD(Collection, copyOfRange)
|
PHP_METHOD(Collection, copyOfRange)
|
||||||
{
|
{
|
||||||
|
zend_long from_idx, num_elements;
|
||||||
|
ZEND_PARSE_PARAMETERS_START(2, 2)
|
||||||
|
Z_PARAM_LONG(from_idx)
|
||||||
|
Z_PARAM_LONG(num_elements)
|
||||||
|
ZEND_PARSE_PARAMETERS_END();
|
||||||
|
if (from_idx < 0) {
|
||||||
|
ERR_BAD_INDEX();
|
||||||
|
RETURN_NULL();
|
||||||
|
}
|
||||||
|
if (num_elements < 0) {
|
||||||
|
ERR_BAD_SIZE();
|
||||||
|
RETURN_NULL();
|
||||||
|
}
|
||||||
|
zval rv;
|
||||||
|
zval* current = COLLECTION_FETCH_EX();
|
||||||
|
ARRAY_NEW(new_collection, num_elements);
|
||||||
|
Bucket* bucket = Z_ARRVAL_P(current)->arData;
|
||||||
|
Bucket* end = bucket + Z_ARRVAL_P(current)->nNumUsed;
|
||||||
|
for (bucket += from_idx; num_elements > 0 && bucket < end; ++bucket, --num_elements) {
|
||||||
|
if (bucket->key)
|
||||||
|
zend_hash_add(new_collection, bucket->key, &bucket->val);
|
||||||
|
else
|
||||||
|
zend_hash_next_index_insert(new_collection, &bucket->val);
|
||||||
|
}
|
||||||
|
RETVAL_NEW_COLLECTION(new_collection);
|
||||||
}
|
}
|
||||||
|
|
||||||
PHP_METHOD(Collection, count)
|
PHP_METHOD(Collection, count)
|
||||||
{
|
{
|
||||||
|
zend_long count;
|
||||||
|
count_collection(getThis(), &count);
|
||||||
|
RETVAL_LONG(count);
|
||||||
}
|
}
|
||||||
|
|
||||||
PHP_METHOD(Collection, distinct)
|
PHP_METHOD(Collection, distinct)
|
||||||
|
@ -783,11 +819,6 @@ PHP_METHOD(Collection, slice)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PHP_METHOD(Collection, sliceRange)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
PHP_METHOD(Collection, sort)
|
PHP_METHOD(Collection, sort)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,10 @@ extern zend_string* pair_second_name;
|
||||||
extern PHP_COLLECTIONS_API zend_class_entry* collections_collection_ce;
|
extern PHP_COLLECTIONS_API zend_class_entry* collections_collection_ce;
|
||||||
extern PHP_COLLECTIONS_API zend_class_entry* collections_pair_ce;
|
extern PHP_COLLECTIONS_API zend_class_entry* collections_pair_ce;
|
||||||
|
|
||||||
|
extern zend_object_handlers* collection_handlers;
|
||||||
|
|
||||||
|
int count_collection(zval* obj, zend_long* count);
|
||||||
|
|
||||||
extern const zend_function_entry collection_methods[];
|
extern const zend_function_entry collection_methods[];
|
||||||
extern const zend_function_entry pair_methods[];
|
extern const zend_function_entry pair_methods[];
|
||||||
|
|
||||||
|
|
|
@ -96,7 +96,6 @@ PHP_METHOD(Collection, reversed);
|
||||||
PHP_METHOD(Collection, shuffle);
|
PHP_METHOD(Collection, shuffle);
|
||||||
PHP_METHOD(Collection, single);
|
PHP_METHOD(Collection, single);
|
||||||
PHP_METHOD(Collection, slice);
|
PHP_METHOD(Collection, slice);
|
||||||
PHP_METHOD(Collection, sliceRange);
|
|
||||||
PHP_METHOD(Collection, sort);
|
PHP_METHOD(Collection, sort);
|
||||||
PHP_METHOD(Collection, sortBy);
|
PHP_METHOD(Collection, sortBy);
|
||||||
PHP_METHOD(Collection, sortByDescending);
|
PHP_METHOD(Collection, sortByDescending);
|
||||||
|
|
|
@ -117,10 +117,10 @@ class Collection implements ArrayAccess, Countable
|
||||||
* Returns new collection which is a copy of range of original collection.
|
* Returns new collection which is a copy of range of original collection.
|
||||||
*
|
*
|
||||||
* @param int $from_index
|
* @param int $from_index
|
||||||
* @param int $to_index
|
* @param int $num_elements
|
||||||
* @return Collection
|
* @return Collection
|
||||||
*/
|
*/
|
||||||
function copyOfRange($from_index, $to_index) {}
|
function copyOfRange($from_index, $num_elements) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the number of elements in this collection.
|
* Returns the number of elements in this collection.
|
||||||
|
@ -746,14 +746,6 @@ class Collection implements ArrayAccess, Countable
|
||||||
*/
|
*/
|
||||||
function slice($keys) {}
|
function slice($keys) {}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a collection containing elements at indices in the specified indices range.
|
|
||||||
*
|
|
||||||
* @param int $from_index
|
|
||||||
* @param int $to_index[optional]
|
|
||||||
*/
|
|
||||||
function sliceRange($from_index, $to_index) {}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sorts the collection in-place according to the natural order of its elements.
|
* Sorts the collection in-place according to the natural order of its elements.
|
||||||
*
|
*
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
--TEST--
|
||||||
|
Test Collection::copyOfRange();
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
// An ordinary array.
|
||||||
|
$array = [3, 7, 6, 9, 2];
|
||||||
|
// An associative array, however, Collection::copyOfRange() still works,
|
||||||
|
// and string keys will be preserved.
|
||||||
|
// Note that zend_array is ordered and random access has constant time complexity.
|
||||||
|
$array1 = ['a' => 'b', 'c', 'd' => 'e'];
|
||||||
|
$array2 = Collection::init($array)->copyOfRange(2, 4)->toArray();
|
||||||
|
$array3 = Collection::init($array1)->copyOfRange(1, 2)->toArray();
|
||||||
|
if ($array2 != array_slice($array, 2, 4) || $array3 != array_slice($array1, 1, 2))
|
||||||
|
echo 'Collection::copyOfRange() failed.', PHP_EOL;
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
|
@ -0,0 +1,12 @@
|
||||||
|
--TEST--
|
||||||
|
Test Collection::count() and countable interface.
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
$array = [1, 2, 3, 4, 5, 6];
|
||||||
|
$collection = Collection::init($array);
|
||||||
|
if ($collection->count() != count($array))
|
||||||
|
echo 'Collection::count() failed.', PHP_EOL;
|
||||||
|
if (count($collection) != count($array))
|
||||||
|
echo 'Test for countable interface failed.', PHP_EOL;
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
Reference in New Issue