2018-03-23 09:06:05 +00:00
|
|
|
//
|
|
|
|
// ext-collections/collections_methods.c
|
|
|
|
//
|
|
|
|
// @Author CismonX
|
|
|
|
//
|
|
|
|
|
|
|
|
#include "php_collections.h"
|
2018-03-23 14:17:09 +00:00
|
|
|
#include "php_collections_me.h"
|
2018-03-23 09:06:05 +00:00
|
|
|
|
2018-09-07 08:00:08 +00:00
|
|
|
#include <ext/standard/php_string.h>
|
|
|
|
#include <ext/standard/php_mt_rand.h>
|
|
|
|
|
2018-08-26 12:56:35 +00:00
|
|
|
#if PHP_VERSION_ID < 70300
|
2018-09-07 15:42:36 +00:00
|
|
|
#define GC_ADDREF(p) ++GC_REFCOUNT(p)
|
|
|
|
#define GC_DELREF(p) --GC_REFCOUNT(p)
|
2018-08-26 12:56:35 +00:00
|
|
|
#endif
|
|
|
|
|
2018-09-07 15:42:36 +00:00
|
|
|
#define FCI_G COLLECTIONS_G(fci)
|
|
|
|
#define FCC_G COLLECTIONS_G(fcc)
|
|
|
|
#define REF_G COLLECTIONS_G(ref)
|
|
|
|
#define CMP_G COLLECTIONS_G(cmp)
|
2018-08-30 17:04:46 +00:00
|
|
|
|
2018-09-07 15:42:36 +00:00
|
|
|
#define Z_COLLECTION_P(val) (Z_OBJ_P(val)->properties)
|
|
|
|
#define THIS_COLLECTION Z_COLLECTION_P(getThis())
|
|
|
|
#define PAIR_FIRST(obj) OBJ_PROP_NUM(obj, 0)
|
|
|
|
#define PAIR_SECOND(obj) OBJ_PROP_NUM(obj, 1)
|
2018-03-23 09:06:05 +00:00
|
|
|
|
2018-09-07 19:43:00 +00:00
|
|
|
#define REMOVE_DUPLICATE (1 << 0)
|
|
|
|
#define RETAIN_DUPLICATE (0 << 0)
|
|
|
|
#define ELEMENT_SUBTRACT (1 << 1)
|
|
|
|
#define ELEMENT_INTERSECT (0 << 1)
|
|
|
|
|
2018-09-08 03:42:19 +00:00
|
|
|
#define IS_COLLECTION_P(val) \
|
|
|
|
Z_TYPE_P(val) == IS_OBJECT && Z_OBJCE_P(val) == collections_collection_ce
|
|
|
|
#define IS_PAIR(val) \
|
|
|
|
Z_TYPE(val) == IS_OBJECT && Z_OBJCE(val) == collections_pair_ce
|
2018-03-23 09:06:05 +00:00
|
|
|
|
2018-08-13 13:03:38 +00:00
|
|
|
#define SEPARATE_COLLECTION(ht, obj) \
|
2018-09-03 12:07:08 +00:00
|
|
|
if (GC_REFCOUNT(ht) > 1) { \
|
2018-08-13 13:03:38 +00:00
|
|
|
GC_DELREF(ht); \
|
|
|
|
ht = Z_OBJ_P(obj)->properties = zend_array_dup(ht); \
|
2018-04-18 04:03:27 +00:00
|
|
|
}
|
2018-08-26 12:56:35 +00:00
|
|
|
#define SEPARATE_CURRENT_COLLECTION(ht) \
|
|
|
|
SEPARATE_COLLECTION(ht, getThis())
|
2018-04-18 04:03:27 +00:00
|
|
|
|
2018-08-15 14:37:37 +00:00
|
|
|
#define INIT_FCI(fci, num_args) \
|
2018-08-13 13:03:38 +00:00
|
|
|
zval params[num_args], retval; \
|
2018-08-15 14:37:37 +00:00
|
|
|
(fci)->size = sizeof(zend_fcall_info); \
|
2018-09-08 03:42:19 +00:00
|
|
|
(fci)->param_count = (num_args); \
|
2018-08-15 14:37:37 +00:00
|
|
|
(fci)->retval = &retval; \
|
|
|
|
(fci)->params = params
|
|
|
|
|
2018-08-13 13:03:38 +00:00
|
|
|
#define CALLBACK_KEYVAL_INVOKE(params, bucket) \
|
2018-09-08 03:42:19 +00:00
|
|
|
ZVAL_COPY_VALUE(&(params)[0], &(bucket)->val); \
|
2018-09-03 12:07:08 +00:00
|
|
|
if ((bucket)->key) { \
|
2018-09-08 03:42:19 +00:00
|
|
|
ZVAL_STR(&(params)[1], (bucket)->key); \
|
2018-09-03 12:07:08 +00:00
|
|
|
} else { \
|
2018-09-08 03:42:19 +00:00
|
|
|
ZVAL_LONG(&(params)[1], (bucket)->h); \
|
2018-08-13 13:03:38 +00:00
|
|
|
} \
|
2018-04-16 12:58:38 +00:00
|
|
|
zend_call_function(&fci, &fcc)
|
2018-03-25 07:26:07 +00:00
|
|
|
|
2018-08-26 12:56:35 +00:00
|
|
|
#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_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_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")
|
2018-09-05 16:00:15 +00:00
|
|
|
#define ERR_NOT_NUMERIC() \
|
2018-08-26 12:56:35 +00:00
|
|
|
PHP_COLLECTIONS_ERROR(E_WARNING, "Elements should be int or double")
|
2018-09-05 16:00:15 +00:00
|
|
|
#define ERR_BAD_GROUP() \
|
|
|
|
PHP_COLLECTIONS_ERROR(E_WARNING, "Group value must be array")
|
2018-09-12 05:42:13 +00:00
|
|
|
#define ERR_NOT_PACKED() \
|
|
|
|
PHP_COLLECTIONS_ERROR(E_WARNING, "The array should be packed")
|
2018-04-22 14:47:30 +00:00
|
|
|
#define ERR_SILENCED()
|
2018-03-23 09:06:05 +00:00
|
|
|
|
2018-08-13 13:03:38 +00:00
|
|
|
#define ELEMENTS_VALIDATE(elements, err, err_then) \
|
|
|
|
zend_array* elements##_arr; \
|
2018-09-03 12:07:08 +00:00
|
|
|
if (IS_COLLECTION_P(elements)) { \
|
2018-09-07 19:43:00 +00:00
|
|
|
(elements##_arr) = Z_COLLECTION_P(elements); \
|
2018-09-03 12:07:08 +00:00
|
|
|
} else if (UNEXPECTED(Z_TYPE_P(elements) == IS_ARRAY)) { \
|
2018-08-13 13:03:38 +00:00
|
|
|
(elements##_arr) = Z_ARRVAL_P(elements); \
|
2018-09-03 12:07:08 +00:00
|
|
|
} else { \
|
2018-08-13 13:03:38 +00:00
|
|
|
err(); \
|
|
|
|
err_then; \
|
2018-03-23 13:38:34 +00:00
|
|
|
}
|
|
|
|
|
2018-08-13 13:03:38 +00:00
|
|
|
#define ARRAY_NEW(name, size) \
|
|
|
|
zend_array* (name) = (zend_array*)emalloc(sizeof(zend_array)); \
|
2018-03-25 07:26:07 +00:00
|
|
|
zend_hash_init(name, size, NULL, ZVAL_PTR_DTOR, 0)
|
2018-08-13 13:03:38 +00:00
|
|
|
#define ARRAY_NEW_EX(name, other) \
|
2018-04-15 03:22:10 +00:00
|
|
|
ARRAY_NEW(name, zend_hash_num_elements(other))
|
2018-08-13 13:03:38 +00:00
|
|
|
#define ARRAY_CLONE(dest, src) \
|
2018-08-26 12:23:22 +00:00
|
|
|
zend_array* (dest) = zend_array_dup(src);
|
2018-03-23 13:38:34 +00:00
|
|
|
|
2018-09-08 03:42:19 +00:00
|
|
|
#define RETVAL_NEW_COLLECTION(ht) \
|
2018-08-13 13:03:38 +00:00
|
|
|
{ \
|
2018-09-08 03:42:19 +00:00
|
|
|
zend_object* _obj = create_collection_obj(); \
|
|
|
|
if (GC_REFCOUNT(ht) > 1) { \
|
|
|
|
GC_ADDREF(ht); \
|
|
|
|
} \
|
|
|
|
_obj->properties = ht; \
|
|
|
|
RETVAL_OBJ(_obj); \
|
2018-09-03 12:07:08 +00:00
|
|
|
}
|
2018-03-23 13:38:34 +00:00
|
|
|
|
2018-09-08 03:42:19 +00:00
|
|
|
#define RETURN_NEW_COLLECTION(ht) \
|
2018-08-13 13:03:38 +00:00
|
|
|
{ \
|
2018-09-08 03:42:19 +00:00
|
|
|
RETVAL_NEW_COLLECTION(ht); \
|
2018-08-13 13:03:38 +00:00
|
|
|
return; \
|
2018-03-29 04:33:39 +00:00
|
|
|
}
|
|
|
|
|
2018-08-20 14:47:23 +00:00
|
|
|
typedef int (*equal_check_func_t)(zval*, zval*);
|
|
|
|
|
2018-08-30 17:04:46 +00:00
|
|
|
static zend_always_inline void pair_update_first(zend_object* obj, zval* value)
|
|
|
|
{
|
2018-09-02 13:16:05 +00:00
|
|
|
zval_ptr_dtor(PAIR_FIRST(obj));
|
|
|
|
ZVAL_COPY_VALUE(PAIR_FIRST(obj), value);
|
2018-08-30 17:04:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static zend_always_inline void pair_update_second(zend_object* obj, zval* value)
|
|
|
|
{
|
2018-09-02 13:16:05 +00:00
|
|
|
zval_ptr_dtor(PAIR_SECOND(obj));
|
|
|
|
ZVAL_COPY_VALUE(PAIR_SECOND(obj), value);
|
2018-08-30 17:04:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static zend_always_inline zend_object* create_object(zend_class_entry* ce,
|
|
|
|
zend_object_handlers* handlers)
|
|
|
|
{
|
|
|
|
zend_object* obj = (zend_object*)ecalloc(1, sizeof(zend_object) +
|
|
|
|
zend_object_properties_size(ce));
|
|
|
|
zend_object_std_init(obj, ce);
|
|
|
|
object_properties_init(obj, ce);
|
|
|
|
obj->handlers = handlers;
|
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
|
|
|
|
static zend_always_inline zend_object* create_collection_obj()
|
|
|
|
{
|
|
|
|
return create_object(collections_collection_ce, &collection_handlers);
|
|
|
|
}
|
|
|
|
|
|
|
|
static zend_always_inline zend_object* create_pair_obj()
|
|
|
|
{
|
|
|
|
return create_object(collections_pair_ce, &std_object_handlers);
|
|
|
|
}
|
|
|
|
|
2018-09-12 05:42:13 +00:00
|
|
|
static zend_always_inline void array_release(zend_array* ht)
|
|
|
|
{
|
|
|
|
if (GC_REFCOUNT(ht) > 1) {
|
|
|
|
GC_DELREF(ht);
|
|
|
|
} else {
|
|
|
|
zend_array_destroy(ht);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-02 13:16:05 +00:00
|
|
|
static zend_always_inline zend_array* array_group_fetch(zend_array* ht, zval* key)
|
|
|
|
{
|
2018-09-05 16:00:15 +00:00
|
|
|
zend_array* group = NULL;
|
2018-09-03 12:07:08 +00:00
|
|
|
if (Z_TYPE_P(key) == IS_LONG) {
|
2018-09-02 13:16:05 +00:00
|
|
|
zval* group_val = zend_hash_index_find(ht, Z_LVAL_P(key));
|
2018-09-03 12:07:08 +00:00
|
|
|
if (UNEXPECTED(group_val == NULL)) {
|
2018-09-02 13:16:05 +00:00
|
|
|
zval tmp_val;
|
|
|
|
group = (zend_array*)emalloc(sizeof(zend_array));
|
|
|
|
zend_hash_init(group, 8, NULL, ZVAL_PTR_DTOR, 0);
|
|
|
|
ZVAL_ARR(&tmp_val, group);
|
|
|
|
zend_hash_index_add(ht, Z_LVAL_P(key), &tmp_val);
|
2018-09-05 16:00:15 +00:00
|
|
|
} else if (EXPECTED(Z_TYPE_P(group_val) == IS_ARRAY)) {
|
|
|
|
SEPARATE_ARRAY(group_val);
|
2018-09-02 13:16:05 +00:00
|
|
|
group = Z_ARR_P(group_val);
|
2018-09-05 16:00:15 +00:00
|
|
|
} else {
|
|
|
|
ERR_BAD_GROUP();
|
2018-09-02 13:16:05 +00:00
|
|
|
}
|
2018-09-03 12:07:08 +00:00
|
|
|
} else if (Z_TYPE_P(key) == IS_STRING) {
|
2018-09-02 13:16:05 +00:00
|
|
|
zval* group_val = zend_hash_find(ht, Z_STR_P(key));
|
2018-09-03 12:07:08 +00:00
|
|
|
if (UNEXPECTED(group_val == NULL)) {
|
2018-09-02 13:16:05 +00:00
|
|
|
zval tmp_val;
|
|
|
|
group = (zend_array*)emalloc(sizeof(zend_array));
|
|
|
|
zend_hash_init(group, 8, NULL, ZVAL_PTR_DTOR, 0);
|
|
|
|
ZVAL_ARR(&tmp_val, group);
|
|
|
|
zend_hash_add(ht, Z_STR_P(key), &tmp_val);
|
2018-09-05 16:00:15 +00:00
|
|
|
} else if (EXPECTED(Z_TYPE_P(group_val) == IS_ARRAY)) {
|
|
|
|
SEPARATE_ARRAY(group_val);
|
2018-09-02 13:16:05 +00:00
|
|
|
group = Z_ARR_P(group_val);
|
2018-09-05 16:00:15 +00:00
|
|
|
} else {
|
|
|
|
ERR_BAD_GROUP();
|
2018-09-02 13:16:05 +00:00
|
|
|
}
|
2018-09-03 12:07:08 +00:00
|
|
|
} else {
|
2018-09-02 13:16:05 +00:00
|
|
|
ERR_BAD_KEY_TYPE();
|
|
|
|
}
|
|
|
|
return group;
|
|
|
|
}
|
|
|
|
|
2018-08-20 14:47:23 +00:00
|
|
|
static zend_always_inline void bucket_to_pair(zend_object* pair, Bucket* bucket)
|
|
|
|
{
|
|
|
|
zval key;
|
2018-09-03 12:07:08 +00:00
|
|
|
if (bucket->key) {
|
2018-08-20 14:47:23 +00:00
|
|
|
GC_ADDREF(bucket->key);
|
|
|
|
ZVAL_STR(&key, bucket->key);
|
2018-09-03 12:07:08 +00:00
|
|
|
} else {
|
2018-08-20 14:47:23 +00:00
|
|
|
ZVAL_LONG(&key, bucket->h);
|
|
|
|
}
|
2018-08-30 17:04:46 +00:00
|
|
|
pair_update_first(pair, &key);
|
|
|
|
pair_update_second(pair, &bucket->val);
|
2018-08-20 14:47:23 +00:00
|
|
|
}
|
|
|
|
|
2018-08-23 12:16:44 +00:00
|
|
|
static int bucket_compare_numeric(const void* op1, const void* op2)
|
2018-05-01 09:35:19 +00:00
|
|
|
{
|
2018-08-07 16:43:09 +00:00
|
|
|
Bucket* b1 = (Bucket*)op1;
|
|
|
|
Bucket* b2 = (Bucket*)op2;
|
|
|
|
return numeric_compare_function(&b1->val, &b2->val);
|
|
|
|
}
|
|
|
|
|
2018-08-20 14:47:23 +00:00
|
|
|
static int bucket_reverse_compare_numeric(const void* op1, const void* op2)
|
|
|
|
{
|
2018-08-23 12:16:44 +00:00
|
|
|
Bucket* b1 = (Bucket*)op1;
|
|
|
|
Bucket* b2 = (Bucket*)op2;
|
|
|
|
return numeric_compare_function(&b2->val, &b1->val);
|
2018-08-20 14:47:23 +00:00
|
|
|
}
|
|
|
|
|
2018-08-23 12:16:44 +00:00
|
|
|
static int bucket_compare_string_ci(const void* op1, const void* op2)
|
2018-08-20 14:47:23 +00:00
|
|
|
{
|
|
|
|
Bucket* b1 = (Bucket*)op1;
|
|
|
|
Bucket* b2 = (Bucket*)op2;
|
|
|
|
return string_case_compare_function(&b1->val, &b2->val);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int bucket_reverse_compare_string_ci(const void* op1, const void* op2)
|
|
|
|
{
|
2018-08-23 12:16:44 +00:00
|
|
|
Bucket* b1 = (Bucket*)op1;
|
|
|
|
Bucket* b2 = (Bucket*)op2;
|
|
|
|
return string_case_compare_function(&b2->val, &b1->val);
|
2018-08-20 14:47:23 +00:00
|
|
|
}
|
|
|
|
|
2018-08-23 12:16:44 +00:00
|
|
|
static int bucket_compare_string_cs(const void* op1, const void* op2)
|
2018-08-07 16:43:09 +00:00
|
|
|
{
|
|
|
|
Bucket* b1 = (Bucket*)op1;
|
|
|
|
Bucket* b2 = (Bucket*)op2;
|
|
|
|
return string_compare_function(&b1->val, &b2->val);
|
|
|
|
}
|
|
|
|
|
2018-08-20 14:47:23 +00:00
|
|
|
static int bucket_reverse_compare_string_cs(const void* op1, const void* op2)
|
|
|
|
{
|
2018-08-23 12:16:44 +00:00
|
|
|
Bucket* b1 = (Bucket*)op1;
|
|
|
|
Bucket* b2 = (Bucket*)op2;
|
|
|
|
return string_compare_function(&b2->val, &b1->val);
|
2018-08-20 14:47:23 +00:00
|
|
|
}
|
|
|
|
|
2018-08-23 12:16:44 +00:00
|
|
|
static int bucket_compare_natural_ci(const void* op1, const void* op2)
|
2018-08-20 14:47:23 +00:00
|
|
|
{
|
2018-09-02 13:46:01 +00:00
|
|
|
zend_string* s1 = Z_STR(((Bucket*)op1)->val);
|
|
|
|
zend_string* s2 = Z_STR(((Bucket*)op2)->val);
|
|
|
|
return strnatcmp_ex(ZSTR_VAL(s1), ZSTR_LEN(s1), ZSTR_VAL(s2), ZSTR_LEN(s2), 1);
|
2018-08-20 14:47:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int bucket_reverse_compare_natural_ci(const void* op1, const void* op2)
|
|
|
|
{
|
2018-09-02 13:46:01 +00:00
|
|
|
zend_string* s1 = Z_STR(((Bucket*)op1)->val);
|
|
|
|
zend_string* s2 = Z_STR(((Bucket*)op2)->val);
|
|
|
|
return strnatcmp_ex(ZSTR_VAL(s2), ZSTR_LEN(s2), ZSTR_VAL(s1), ZSTR_LEN(s1), 1);
|
2018-08-20 14:47:23 +00:00
|
|
|
}
|
|
|
|
|
2018-08-23 12:16:44 +00:00
|
|
|
static int bucket_compare_natural_cs(const void* op1, const void* op2)
|
2018-08-20 14:47:23 +00:00
|
|
|
{
|
2018-09-02 13:46:01 +00:00
|
|
|
zend_string* s1 = Z_STR(((Bucket*)op1)->val);
|
|
|
|
zend_string* s2 = Z_STR(((Bucket*)op2)->val);
|
|
|
|
return strnatcmp_ex(ZSTR_VAL(s1), ZSTR_LEN(s1), ZSTR_VAL(s2), ZSTR_LEN(s2), 0);
|
2018-08-20 14:47:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int bucket_reverse_compare_natural_cs(const void* op1, const void* op2)
|
|
|
|
{
|
2018-09-02 13:46:01 +00:00
|
|
|
zend_string* s1 = Z_STR(((Bucket*)op1)->val);
|
|
|
|
zend_string* s2 = Z_STR(((Bucket*)op2)->val);
|
|
|
|
return strnatcmp_ex(ZSTR_VAL(s2), ZSTR_LEN(s2), ZSTR_VAL(s1), ZSTR_LEN(s1), 0);
|
2018-08-20 14:47:23 +00:00
|
|
|
}
|
|
|
|
|
2018-08-23 12:16:44 +00:00
|
|
|
static int bucket_compare_regular(const void* op1, const void* op2)
|
2018-08-07 16:43:09 +00:00
|
|
|
{
|
|
|
|
Bucket* b1 = (Bucket*)op1;
|
|
|
|
Bucket* b2 = (Bucket*)op2;
|
|
|
|
zval result;
|
2018-09-03 12:07:08 +00:00
|
|
|
if (compare_function(&result, &b1->val, &b2->val) == FAILURE) {
|
2018-08-07 16:43:09 +00:00
|
|
|
return 0;
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-08-07 16:43:09 +00:00
|
|
|
return ZEND_NORMALIZE_BOOL(Z_LVAL(result));
|
2018-05-01 09:35:19 +00:00
|
|
|
}
|
|
|
|
|
2018-08-20 14:47:23 +00:00
|
|
|
static int bucket_reverse_compare_regular(const void* op1, const void* op2)
|
|
|
|
{
|
2018-08-23 12:16:44 +00:00
|
|
|
Bucket* b1 = (Bucket*)op1;
|
|
|
|
Bucket* b2 = (Bucket*)op2;
|
|
|
|
zval result;
|
2018-09-03 12:07:08 +00:00
|
|
|
if (compare_function(&result, &b2->val, &b1->val) == FAILURE) {
|
2018-08-23 12:16:44 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return ZEND_NORMALIZE_BOOL(Z_LVAL(result));
|
2018-08-20 14:47:23 +00:00
|
|
|
}
|
|
|
|
|
2018-08-26 12:23:22 +00:00
|
|
|
static int bucket_compare_by(const void* op1, const void* op2)
|
|
|
|
{
|
|
|
|
Bucket* b1 = (Bucket*)op1;
|
|
|
|
Bucket* b2 = (Bucket*)op2;
|
2018-09-07 15:42:36 +00:00
|
|
|
zval* ref = REF_G;
|
|
|
|
return CMP_G(&ref[b1->h], &ref[b2->h]);
|
2018-08-26 12:23:22 +00:00
|
|
|
}
|
|
|
|
|
2018-08-28 16:36:50 +00:00
|
|
|
static int bucket_compare_with_idx(const void* op1, const void* op2)
|
|
|
|
{
|
|
|
|
zend_long h1 = ((Bucket*)op1)->h;
|
|
|
|
zend_long h2 = ((Bucket*)op2)->h;
|
2018-09-07 15:42:36 +00:00
|
|
|
int result = CMP_G(op1, op2);
|
2018-08-28 16:36:50 +00:00
|
|
|
return result ? result : ZEND_NORMALIZE_BOOL(h1 - h2);
|
|
|
|
}
|
|
|
|
|
2018-08-15 17:50:08 +00:00
|
|
|
static int bucket_compare_userland(const void* op1, const void* op2)
|
2018-08-15 14:37:37 +00:00
|
|
|
{
|
|
|
|
Bucket* b1 = (Bucket*)op1;
|
|
|
|
Bucket* b2 = (Bucket*)op2;
|
|
|
|
INIT_FCI(FCI_G, 2);
|
|
|
|
ZVAL_COPY_VALUE(¶ms[0], &b1->val);
|
|
|
|
ZVAL_COPY_VALUE(¶ms[1], &b2->val);
|
|
|
|
zend_call_function(FCI_G, FCC_G);
|
2018-08-16 05:03:56 +00:00
|
|
|
int result = ZEND_NORMALIZE_BOOL(zval_get_long(&retval));
|
|
|
|
zval_ptr_dtor(&retval);
|
|
|
|
return result;
|
2018-08-15 14:37:37 +00:00
|
|
|
}
|
|
|
|
|
2018-08-20 14:47:23 +00:00
|
|
|
static zend_always_inline equal_check_func_t equal_check_func_init(zval* val)
|
|
|
|
{
|
2018-09-03 12:07:08 +00:00
|
|
|
if (Z_TYPE_P(val) == IS_LONG) {
|
2018-08-20 14:47:23 +00:00
|
|
|
return fast_equal_check_long;
|
|
|
|
}
|
2018-09-03 12:07:08 +00:00
|
|
|
if (Z_TYPE_P(val) == IS_STRING) {
|
2018-08-20 14:47:23 +00:00
|
|
|
return fast_equal_check_string;
|
|
|
|
}
|
|
|
|
return fast_equal_check_function;
|
|
|
|
}
|
|
|
|
|
|
|
|
static zend_always_inline compare_func_t compare_func_init(
|
|
|
|
zval* val, zend_bool reverse, zend_long flags)
|
|
|
|
{
|
|
|
|
zend_bool case_insensitive = flags & PHP_COLLECTIONS_FOLD_CASE;
|
2018-09-03 12:07:08 +00:00
|
|
|
if (Z_TYPE_P(val) == IS_LONG || Z_TYPE_P(val) == IS_DOUBLE) {
|
2018-08-20 14:47:23 +00:00
|
|
|
return reverse ? bucket_reverse_compare_numeric : bucket_compare_numeric;
|
|
|
|
}
|
2018-09-03 12:07:08 +00:00
|
|
|
if (Z_TYPE_P(val) == IS_STRING) {
|
|
|
|
if ((flags & ~PHP_COLLECTIONS_FOLD_CASE) == PHP_COLLECTIONS_COMPARE_NATURAL) {
|
|
|
|
if (case_insensitive) {
|
2018-08-20 14:47:23 +00:00
|
|
|
return reverse ? bucket_reverse_compare_natural_ci : bucket_compare_natural_ci;
|
|
|
|
}
|
|
|
|
return reverse ? bucket_reverse_compare_natural_cs : bucket_compare_natural_cs;
|
|
|
|
}
|
2018-09-03 12:07:08 +00:00
|
|
|
if (case_insensitive) {
|
2018-08-20 14:47:23 +00:00
|
|
|
return reverse ? bucket_reverse_compare_string_ci : bucket_compare_string_ci;
|
|
|
|
}
|
|
|
|
return reverse ? bucket_reverse_compare_string_cs : bucket_compare_string_cs;
|
|
|
|
}
|
|
|
|
return reverse ? bucket_reverse_compare_regular : bucket_compare_regular;
|
|
|
|
}
|
|
|
|
|
2018-09-12 05:42:13 +00:00
|
|
|
static zend_always_inline zend_long binary_search(Bucket* ref, zval* val,
|
|
|
|
zend_long from_idx, zend_long to_idx, compare_func_t cmp)
|
|
|
|
{
|
|
|
|
zend_long low = from_idx;
|
|
|
|
zend_long high = to_idx - 1;
|
|
|
|
while (low <= high) {
|
|
|
|
zend_long mid = (low + high) >> 1;
|
|
|
|
int result = cmp(&ref[mid].val, val);
|
|
|
|
if (result == 1) {
|
|
|
|
high = mid - 1;
|
|
|
|
} else if (result == -1) {
|
|
|
|
low = mid + 1;
|
|
|
|
} else {
|
|
|
|
return mid;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -(low + 1);
|
|
|
|
}
|
|
|
|
|
2018-09-07 19:43:00 +00:00
|
|
|
static zend_always_inline void array_sort_by(zend_array* ht)
|
2018-08-26 12:23:22 +00:00
|
|
|
{
|
|
|
|
uint32_t i;
|
2018-09-03 12:07:08 +00:00
|
|
|
if (HT_IS_WITHOUT_HOLES(ht)) {
|
2018-08-26 12:59:47 +00:00
|
|
|
i = ht->nNumUsed;
|
2018-09-03 12:07:08 +00:00
|
|
|
} else {
|
2018-08-26 12:23:22 +00:00
|
|
|
uint32_t j;
|
2018-09-03 12:07:08 +00:00
|
|
|
for (j = 0, i = 0; j < ht->nNumUsed; j++) {
|
2018-08-26 12:59:47 +00:00
|
|
|
Bucket *p = ht->arData + j;
|
2018-09-03 12:07:08 +00:00
|
|
|
if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) {
|
2018-08-26 12:23:22 +00:00
|
|
|
continue;
|
|
|
|
}
|
2018-09-03 12:07:08 +00:00
|
|
|
if (i != j) {
|
2018-08-26 12:59:47 +00:00
|
|
|
ht->arData[i] = *p;
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
}
|
2018-08-26 12:23:22 +00:00
|
|
|
uint32_t num_elements = zend_hash_num_elements(ht);
|
2018-09-03 12:07:08 +00:00
|
|
|
if (num_elements > 1) {
|
2018-08-26 12:59:47 +00:00
|
|
|
zend_sort(ht->arData, i, sizeof(Bucket), bucket_compare_by,
|
2018-08-26 12:23:22 +00:00
|
|
|
(swap_func_t)zend_hash_bucket_packed_swap);
|
|
|
|
ht->nNumUsed = i;
|
2018-08-26 12:59:47 +00:00
|
|
|
}
|
2018-08-28 13:24:26 +00:00
|
|
|
uint32_t idx = 0;
|
2018-08-26 12:23:22 +00:00
|
|
|
ZEND_HASH_FOREACH_BUCKET(ht, Bucket* bucket)
|
|
|
|
bucket->h = idx++;
|
|
|
|
ZEND_HASH_FOREACH_END();
|
2018-09-03 12:07:08 +00:00
|
|
|
if (!HT_IS_PACKED(ht)) {
|
2018-08-28 13:24:26 +00:00
|
|
|
zend_hash_to_packed(ht);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-07 19:43:00 +00:00
|
|
|
static zend_always_inline void array_packed_renumber(zend_array* ht)
|
|
|
|
{
|
|
|
|
Bucket* bucket = ht->arData;
|
|
|
|
Bucket* last = NULL;
|
|
|
|
uint32_t idx;
|
|
|
|
for (idx = 0; bucket < ht->arData + ht->nNumUsed; ++bucket, ++idx) {
|
|
|
|
bucket->h = idx;
|
|
|
|
if (Z_ISUNDEF(bucket->val)) {
|
|
|
|
if (UNEXPECTED(last == NULL)) {
|
|
|
|
last = bucket;
|
|
|
|
}
|
|
|
|
} else if (EXPECTED(last)) {
|
|
|
|
ZVAL_COPY_VALUE(&(last++)->val, &bucket->val);
|
|
|
|
ZVAL_UNDEF(&bucket->val);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ht->nNumUsed = ht->nNumOfElements;
|
|
|
|
zend_hash_to_packed(ht);
|
|
|
|
}
|
|
|
|
|
|
|
|
static zend_always_inline void delete_by_offset(zend_array* ht, uint32_t offset,
|
|
|
|
zend_bool packed)
|
|
|
|
{
|
|
|
|
Bucket* bucket = ht->arData + offset;
|
|
|
|
if (packed) {
|
|
|
|
zval_ptr_dtor(&bucket->val);
|
|
|
|
ZVAL_UNDEF(&bucket->val);
|
|
|
|
--ht->nNumOfElements;
|
|
|
|
} else {
|
|
|
|
zend_hash_del_bucket(ht, bucket);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-28 16:36:50 +00:00
|
|
|
static zend_always_inline void array_distinct(zend_array* ht, Bucket* ref, compare_func_t cmp,
|
2018-08-28 13:24:26 +00:00
|
|
|
equal_check_func_t eql)
|
|
|
|
{
|
|
|
|
uint32_t num_elements = zend_hash_num_elements(ht);
|
|
|
|
zend_bool packed = HT_IS_PACKED(ht);
|
|
|
|
uint32_t idx = 0;
|
2018-08-28 16:36:50 +00:00
|
|
|
zend_sort(ref, num_elements, sizeof(Bucket), packed ? bucket_compare_with_idx : cmp,
|
|
|
|
(swap_func_t)zend_hash_bucket_packed_swap);
|
2018-08-28 13:24:26 +00:00
|
|
|
Bucket* first = &ref[0];
|
2018-09-07 19:43:00 +00:00
|
|
|
for (idx = 1; idx < num_elements; ++idx) {
|
|
|
|
Bucket* bucket = &ref[idx];
|
|
|
|
if (eql(&bucket->val, &first->val)) {
|
|
|
|
delete_by_offset(ht, bucket->h, packed);
|
|
|
|
} else {
|
|
|
|
first = bucket;
|
|
|
|
}
|
|
|
|
}
|
2018-09-03 12:07:08 +00:00
|
|
|
if (packed) {
|
2018-09-07 19:43:00 +00:00
|
|
|
array_packed_renumber(ht);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static zend_always_inline uint32_t advance_idx(zend_array* ht, Bucket* ref,
|
|
|
|
uint32_t offset, uint32_t max_offset, equal_check_func_t eql,
|
|
|
|
zend_bool del_dup, zend_bool packed)
|
|
|
|
{
|
|
|
|
for (++offset; offset < max_offset; ++offset) {
|
|
|
|
if (!eql(&ref[offset].val, &ref[offset - 1].val)) {
|
|
|
|
return offset;
|
2018-08-28 13:24:26 +00:00
|
|
|
}
|
2018-09-07 19:43:00 +00:00
|
|
|
if (del_dup) {
|
|
|
|
delete_by_offset(ht, ref[offset].h, packed);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static zend_always_inline void tail_cleanup(zend_array* ht,
|
|
|
|
Bucket* ref, uint32_t offset, uint32_t max_offset, zend_bool packed,
|
|
|
|
equal_check_func_t eql, zend_bool subtract, zend_bool del_dup)
|
|
|
|
{
|
|
|
|
if (subtract) {
|
|
|
|
if (!del_dup) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
while (offset) {
|
|
|
|
offset = advance_idx(ht, ref, offset, max_offset, eql, 1, packed);
|
2018-08-28 13:24:26 +00:00
|
|
|
}
|
2018-09-03 12:07:08 +00:00
|
|
|
} else {
|
2018-09-07 19:43:00 +00:00
|
|
|
for (; offset < max_offset; ++offset) {
|
|
|
|
delete_by_offset(ht, ref[offset].h, packed);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static zend_always_inline void array_slice_by(zend_array* ht, zend_array* other,
|
|
|
|
zend_long flags)
|
|
|
|
{
|
|
|
|
zend_bool packed = HT_IS_PACKED(ht);
|
|
|
|
uint32_t num_this = zend_hash_num_elements(ht);
|
|
|
|
if (UNEXPECTED(num_this == 0)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
zend_bool del_dup = flags & REMOVE_DUPLICATE;
|
|
|
|
zend_bool subtract = flags & ELEMENT_SUBTRACT;
|
|
|
|
uint32_t num_other = zend_hash_num_elements(other);
|
|
|
|
if (UNEXPECTED(num_other == 0)) {
|
|
|
|
if (!subtract) {
|
|
|
|
zend_hash_clean(ht);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
Bucket* ref_this = (Bucket*)malloc(num_this * sizeof(Bucket));
|
|
|
|
compare_func_t cmp = NULL;
|
|
|
|
equal_check_func_t eql;
|
|
|
|
uint32_t idx = 0;
|
|
|
|
ZEND_HASH_FOREACH_BUCKET(ht, Bucket* bucket)
|
|
|
|
if (UNEXPECTED(cmp == NULL)) {
|
|
|
|
cmp = compare_func_init(&bucket->val, 0, 0);
|
|
|
|
eql = equal_check_func_init(&bucket->val);
|
|
|
|
}
|
|
|
|
Bucket* dest = &ref_this[idx++];
|
|
|
|
dest->key = NULL;
|
|
|
|
dest->h = bucket - ht->arData;
|
|
|
|
memcpy(&dest->val, &bucket->val, sizeof(zval));
|
|
|
|
ZEND_HASH_FOREACH_END();
|
|
|
|
CMP_G = cmp;
|
|
|
|
zend_sort(ref_this, num_this, sizeof(Bucket), packed ? bucket_compare_with_idx : cmp,
|
|
|
|
(swap_func_t)zend_hash_bucket_packed_swap);
|
|
|
|
Bucket* ref_other = (Bucket*)malloc(num_other * sizeof(Bucket));
|
|
|
|
uint32_t idx_other = 0;
|
|
|
|
ZEND_HASH_FOREACH_BUCKET(other, Bucket* bucket)
|
|
|
|
Bucket* dest = &ref_other[idx_other++];
|
|
|
|
dest->key = NULL;
|
|
|
|
dest->h = bucket - other->arData;
|
|
|
|
memcpy(&dest->val, &bucket->val, sizeof(zval));
|
|
|
|
ZEND_HASH_FOREACH_END();
|
|
|
|
zend_sort(ref_other, num_other, sizeof(Bucket), packed ? bucket_compare_with_idx : cmp,
|
|
|
|
(swap_func_t)zend_hash_bucket_packed_swap);
|
|
|
|
idx = idx_other = 0;
|
|
|
|
while (1) {
|
|
|
|
Bucket* this = &ref_this[idx];
|
|
|
|
Bucket* other = &ref_other[idx_other];
|
|
|
|
int result = cmp(&this->val, &other->val);
|
|
|
|
if (result == 0) {
|
|
|
|
// Element exists in both zend_array.
|
|
|
|
if (subtract) {
|
|
|
|
delete_by_offset(ht, ref_this[idx].h, packed);
|
|
|
|
}
|
|
|
|
idx = advance_idx(ht, ref_this, idx, num_this, eql, subtract || del_dup, packed);
|
|
|
|
if (UNEXPECTED(idx == 0)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
idx_other = advance_idx(NULL, ref_other, idx_other, num_other, eql, 0, 0);
|
|
|
|
if (UNEXPECTED(idx_other == 0)) {
|
|
|
|
tail_cleanup(ht, ref_this, idx, num_this, packed, eql, subtract, del_dup);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else if (result == -1) {
|
|
|
|
// Element `ref_this[idx]` exists only in current zend_array.
|
|
|
|
if (!subtract) {
|
|
|
|
delete_by_offset(ht, ref_this[idx].h, packed);
|
|
|
|
}
|
|
|
|
idx = advance_idx(ht, ref_this, idx, num_this, eql, !subtract || del_dup, packed);
|
|
|
|
if (UNEXPECTED(idx == 0)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Element `ref_other[other_idx]` exists only in the other zend_array.
|
|
|
|
idx_other = advance_idx(NULL, ref_other, idx_other, num_other, eql, 0, 0);
|
|
|
|
if (UNEXPECTED(idx_other == 0)) {
|
|
|
|
tail_cleanup(ht, ref_this, idx, num_this, packed, eql, subtract, del_dup);
|
|
|
|
break;
|
2018-08-28 13:24:26 +00:00
|
|
|
}
|
|
|
|
}
|
2018-08-26 12:23:22 +00:00
|
|
|
}
|
2018-09-07 19:43:00 +00:00
|
|
|
if (packed) {
|
|
|
|
array_packed_renumber(ht);
|
|
|
|
}
|
|
|
|
free(ref_this);
|
|
|
|
free(ref_other);
|
2018-08-26 12:23:22 +00:00
|
|
|
}
|
|
|
|
|
2018-03-30 11:06:39 +00:00
|
|
|
int count_collection(zval* obj, zend_long* count)
|
|
|
|
{
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = Z_COLLECTION_P(obj);
|
2018-04-15 03:22:10 +00:00
|
|
|
*count = zend_hash_num_elements(current);
|
2018-03-30 11:06:39 +00:00
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
|
2018-03-31 04:02:13 +00:00
|
|
|
int collection_offset_exists(zval* object, zval* offset, int check_empty)
|
|
|
|
{
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = Z_COLLECTION_P(object);
|
2018-09-03 12:07:08 +00:00
|
|
|
if (check_empty) {
|
2018-08-30 17:27:19 +00:00
|
|
|
zval result;
|
|
|
|
return zend_is_true(collection_offset_get(object, offset, 0, &result));
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-09-03 12:07:08 +00:00
|
|
|
if (Z_TYPE_P(offset) == IS_LONG) {
|
2018-04-15 03:22:10 +00:00
|
|
|
return zend_hash_index_exists(current, Z_LVAL_P(offset));
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-09-03 12:07:08 +00:00
|
|
|
if (Z_TYPE_P(offset) == IS_STRING) {
|
2018-04-15 03:22:10 +00:00
|
|
|
return zend_hash_exists(current, Z_STR_P(offset));
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-03-31 04:02:13 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-08-30 17:04:46 +00:00
|
|
|
int collection_property_exists(zval* object, zval* member, int has_set_exists,
|
|
|
|
void** unused)
|
|
|
|
{
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = Z_COLLECTION_P(object);
|
2018-08-30 17:04:46 +00:00
|
|
|
zval* found = NULL;
|
2018-09-03 12:07:08 +00:00
|
|
|
if (EXPECTED(Z_TYPE_P(member) == IS_STRING)) {
|
2018-08-30 17:04:46 +00:00
|
|
|
found = zend_hash_find(current, Z_STR_P(member));
|
2018-09-03 12:07:08 +00:00
|
|
|
} else if (EXPECTED(Z_TYPE_P(member) == IS_LONG)) {
|
2018-08-30 17:04:46 +00:00
|
|
|
found = zend_hash_index_find(current, Z_LVAL_P(member));
|
|
|
|
}
|
2018-09-03 12:07:08 +00:00
|
|
|
if (found == NULL) {
|
2018-08-30 17:04:46 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2018-09-03 12:07:08 +00:00
|
|
|
if (has_set_exists == 0) {
|
|
|
|
// whether property exists and is not NULL
|
2018-08-30 17:04:46 +00:00
|
|
|
return Z_TYPE_P(found) != IS_NULL;
|
2018-09-03 12:07:08 +00:00
|
|
|
} else if (has_set_exists == 1) {
|
|
|
|
// whether property exists and is true
|
2018-08-30 17:04:46 +00:00
|
|
|
return zend_is_true(found);
|
|
|
|
}
|
|
|
|
// whether property exists
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2018-03-31 04:02:13 +00:00
|
|
|
void collection_offset_set(zval* object, zval* offset, zval* value)
|
|
|
|
{
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = Z_COLLECTION_P(object);
|
2018-04-18 04:03:27 +00:00
|
|
|
SEPARATE_COLLECTION(current, object);
|
2018-09-03 12:07:08 +00:00
|
|
|
if (Z_TYPE_P(offset) == IS_LONG) {
|
2018-04-15 03:22:10 +00:00
|
|
|
zend_hash_index_update(current, Z_LVAL_P(offset), value);
|
2018-09-03 12:07:08 +00:00
|
|
|
} else if (Z_TYPE_P(offset) == IS_STRING) {
|
2018-04-15 03:22:10 +00:00
|
|
|
zend_hash_update(current, Z_STR_P(offset), value);
|
2018-09-03 12:07:08 +00:00
|
|
|
} else {
|
2018-08-22 09:54:21 +00:00
|
|
|
ERR_BAD_KEY_TYPE();
|
|
|
|
return;
|
2018-08-30 17:04:46 +00:00
|
|
|
}
|
2018-08-22 09:54:21 +00:00
|
|
|
Z_TRY_ADDREF_P(value);
|
2018-03-31 04:02:13 +00:00
|
|
|
}
|
|
|
|
|
2018-08-30 17:04:46 +00:00
|
|
|
void collection_property_set(zval* object, zval* member, zval* value, void** unused)
|
|
|
|
{
|
|
|
|
collection_offset_set(object, member, value);
|
|
|
|
}
|
|
|
|
|
2018-03-31 04:02:13 +00:00
|
|
|
zval* collection_offset_get(zval* object, zval* offset, int type, zval* retval)
|
|
|
|
{
|
2018-04-11 07:16:20 +00:00
|
|
|
// Note that we don't handle type. So don't do any fancy things with Collection
|
2018-03-31 04:02:13 +00:00
|
|
|
// such as fetching a reference of a value, etc.
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = Z_COLLECTION_P(object);
|
2018-03-31 04:02:13 +00:00
|
|
|
zval* found = NULL;
|
2018-09-03 12:07:08 +00:00
|
|
|
if (Z_TYPE_P(offset) == IS_LONG) {
|
2018-04-15 03:22:10 +00:00
|
|
|
found = zend_hash_index_find(current, Z_LVAL_P(offset));
|
2018-09-03 12:07:08 +00:00
|
|
|
} else if (Z_TYPE_P(offset) == IS_STRING) {
|
2018-04-15 03:22:10 +00:00
|
|
|
found = zend_hash_find(current, Z_STR_P(offset));
|
2018-09-03 12:07:08 +00:00
|
|
|
} if (found) {
|
2018-08-30 17:04:46 +00:00
|
|
|
ZVAL_COPY_VALUE(retval, found);
|
2018-09-03 12:07:08 +00:00
|
|
|
} else {
|
2018-08-30 17:04:46 +00:00
|
|
|
retval = &EG(uninitialized_zval);
|
|
|
|
}
|
2018-03-31 04:02:13 +00:00
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2018-08-30 17:04:46 +00:00
|
|
|
zval* collection_property_get(zval* object, zval* member, int type, void** unused,
|
|
|
|
zval* retval)
|
|
|
|
{
|
|
|
|
return collection_offset_get(object, member, type, retval);
|
|
|
|
}
|
|
|
|
|
2018-03-31 04:02:13 +00:00
|
|
|
void collection_offset_unset(zval* object, zval* offset)
|
|
|
|
{
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = Z_COLLECTION_P(object);
|
2018-04-18 04:03:27 +00:00
|
|
|
SEPARATE_COLLECTION(current, object);
|
2018-09-03 12:07:08 +00:00
|
|
|
if (Z_TYPE_P(offset) == IS_LONG) {
|
2018-04-15 03:22:10 +00:00
|
|
|
zend_hash_index_del(current, Z_LVAL_P(offset));
|
2018-09-03 12:07:08 +00:00
|
|
|
} else if (Z_TYPE_P(offset) == IS_STRING) {
|
2018-04-15 03:22:10 +00:00
|
|
|
zend_hash_del(current, Z_STR_P(offset));
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-03-31 04:02:13 +00:00
|
|
|
}
|
|
|
|
|
2018-08-30 17:04:46 +00:00
|
|
|
void collection_property_unset(zval* object, zval* member, void** unused)
|
|
|
|
{
|
|
|
|
collection_offset_unset(object, member);
|
|
|
|
}
|
|
|
|
|
2018-03-23 13:38:34 +00:00
|
|
|
PHP_METHOD(Collection, __construct) {}
|
2018-03-23 09:06:05 +00:00
|
|
|
|
|
|
|
PHP_METHOD(Collection, addAll)
|
|
|
|
{
|
2018-03-23 13:38:34 +00:00
|
|
|
zval* elements;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
|
|
Z_PARAM_ZVAL(elements)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-04-22 14:47:30 +00:00
|
|
|
ELEMENTS_VALIDATE(elements, ERR_BAD_ARGUMENT_TYPE, return);
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-09-04 14:11:12 +00:00
|
|
|
zend_bool packed = HT_IS_PACKED(current) && HT_IS_PACKED(elements_arr);
|
2018-04-26 13:52:31 +00:00
|
|
|
SEPARATE_CURRENT_COLLECTION(current);
|
2018-05-26 11:02:32 +00:00
|
|
|
ZEND_HASH_FOREACH_BUCKET(elements_arr, Bucket* bucket)
|
2018-09-05 16:00:15 +00:00
|
|
|
zval* result;
|
2018-09-03 12:07:08 +00:00
|
|
|
if (bucket->key) {
|
2018-09-05 16:00:15 +00:00
|
|
|
result = zend_hash_add(current, bucket->key, &bucket->val);
|
2018-09-03 12:07:08 +00:00
|
|
|
} else if (packed) {
|
2018-09-06 03:33:41 +00:00
|
|
|
result = zend_hash_next_index_insert(current, &bucket->val);
|
2018-09-03 12:07:08 +00:00
|
|
|
} else {
|
2018-09-05 16:00:15 +00:00
|
|
|
result = zend_hash_index_add(current, bucket->h, &bucket->val);
|
|
|
|
}
|
|
|
|
if (result) {
|
|
|
|
Z_TRY_ADDREF(bucket->val);
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-05-26 11:02:32 +00:00
|
|
|
ZEND_HASH_FOREACH_END();
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, all)
|
|
|
|
{
|
2018-03-23 13:38:34 +00:00
|
|
|
zend_fcall_info fci;
|
|
|
|
zend_fcall_info_cache fcc;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
|
|
Z_PARAM_FUNC(fci, fcc)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-08-15 14:37:37 +00:00
|
|
|
INIT_FCI(&fci, 2);
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-04-15 03:22:10 +00:00
|
|
|
ZEND_HASH_FOREACH_BUCKET(current, Bucket* bucket)
|
2018-04-13 11:54:11 +00:00
|
|
|
CALLBACK_KEYVAL_INVOKE(params, bucket);
|
2018-09-03 12:07:08 +00:00
|
|
|
if (!zend_is_true(&retval)) {
|
2018-08-11 18:26:46 +00:00
|
|
|
zval_ptr_dtor(&retval);
|
2018-03-23 13:38:34 +00:00
|
|
|
RETURN_FALSE;
|
2018-08-11 18:26:46 +00:00
|
|
|
}
|
|
|
|
zval_ptr_dtor(&retval);
|
2018-03-23 13:38:34 +00:00
|
|
|
ZEND_HASH_FOREACH_END();
|
|
|
|
RETURN_TRUE;
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, any)
|
|
|
|
{
|
2018-03-24 04:22:00 +00:00
|
|
|
zend_fcall_info fci;
|
|
|
|
zend_fcall_info_cache fcc;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
|
|
Z_PARAM_FUNC(fci, fcc)
|
2018-03-25 07:26:07 +00:00
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-08-15 14:37:37 +00:00
|
|
|
INIT_FCI(&fci, 2);
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-04-15 03:22:10 +00:00
|
|
|
ZEND_HASH_FOREACH_BUCKET(current, Bucket* bucket)
|
2018-04-13 11:54:11 +00:00
|
|
|
CALLBACK_KEYVAL_INVOKE(params, bucket);
|
2018-09-03 12:07:08 +00:00
|
|
|
if (zend_is_true(&retval)) {
|
2018-08-11 18:26:46 +00:00
|
|
|
zval_ptr_dtor(&retval);
|
2018-03-24 04:22:00 +00:00
|
|
|
RETURN_TRUE;
|
2018-08-11 18:26:46 +00:00
|
|
|
}
|
|
|
|
zval_ptr_dtor(&retval);
|
2018-03-24 04:22:00 +00:00
|
|
|
ZEND_HASH_FOREACH_END();
|
|
|
|
RETURN_FALSE;
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, associate)
|
|
|
|
{
|
2018-03-25 07:26:07 +00:00
|
|
|
zend_fcall_info fci;
|
|
|
|
zend_fcall_info_cache fcc;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
|
|
Z_PARAM_FUNC(fci, fcc)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-08-15 14:37:37 +00:00
|
|
|
INIT_FCI(&fci, 2);
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-03-25 07:26:07 +00:00
|
|
|
ARRAY_NEW_EX(new_collection, current);
|
2018-04-15 03:22:10 +00:00
|
|
|
ZEND_HASH_FOREACH_BUCKET(current, Bucket* bucket)
|
2018-04-13 11:54:11 +00:00
|
|
|
CALLBACK_KEYVAL_INVOKE(params, bucket);
|
2018-09-05 10:44:16 +00:00
|
|
|
if (EXPECTED(IS_PAIR(retval))) {
|
2018-09-02 13:16:05 +00:00
|
|
|
zval* key = PAIR_FIRST(Z_OBJ(retval));
|
|
|
|
zval* value = PAIR_SECOND(Z_OBJ(retval));
|
2018-09-03 12:07:08 +00:00
|
|
|
if (Z_TYPE_P(key) == IS_LONG) {
|
2018-09-05 16:00:15 +00:00
|
|
|
Z_TRY_ADDREF_P(value);
|
2018-03-25 07:26:07 +00:00
|
|
|
zend_hash_index_add(new_collection, Z_LVAL_P(key), value);
|
2018-09-03 12:07:08 +00:00
|
|
|
} else if (Z_TYPE_P(key) == IS_STRING) {
|
2018-09-05 16:00:15 +00:00
|
|
|
Z_TRY_ADDREF_P(value);
|
2018-03-25 07:26:07 +00:00
|
|
|
zend_hash_add(new_collection, Z_STR_P(key), value);
|
2018-09-03 12:07:08 +00:00
|
|
|
} else {
|
2018-03-25 07:26:07 +00:00
|
|
|
ERR_BAD_KEY_TYPE();
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-09-03 12:07:08 +00:00
|
|
|
} else {
|
2018-03-25 07:26:07 +00:00
|
|
|
ERR_BAD_CALLBACK_RETVAL();
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-08-11 18:26:46 +00:00
|
|
|
zval_ptr_dtor(&retval);
|
2018-03-25 07:26:07 +00:00
|
|
|
ZEND_HASH_FOREACH_END();
|
|
|
|
RETVAL_NEW_COLLECTION(new_collection);
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, associateTo)
|
|
|
|
{
|
2018-03-26 05:25:00 +00:00
|
|
|
zend_fcall_info fci;
|
|
|
|
zend_fcall_info_cache fcc;
|
|
|
|
zval* dest;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(2, 2)
|
|
|
|
Z_PARAM_OBJECT_OF_CLASS(dest, collections_collection_ce)
|
|
|
|
Z_PARAM_FUNC(fci, fcc)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-08-15 14:37:37 +00:00
|
|
|
INIT_FCI(&fci, 2);
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
|
|
|
zend_array* dest_arr = Z_COLLECTION_P(dest);
|
2018-04-18 04:03:27 +00:00
|
|
|
SEPARATE_COLLECTION(dest_arr, dest);
|
2018-04-15 03:22:10 +00:00
|
|
|
ZEND_HASH_FOREACH_BUCKET(current, Bucket* bucket)
|
2018-04-13 11:54:11 +00:00
|
|
|
CALLBACK_KEYVAL_INVOKE(params, bucket);
|
2018-09-05 10:44:16 +00:00
|
|
|
if (EXPECTED(IS_PAIR(retval))) {
|
2018-09-02 13:16:05 +00:00
|
|
|
zval* key = PAIR_FIRST(Z_OBJ(retval));
|
|
|
|
zval* value = PAIR_SECOND(Z_OBJ(retval));
|
2018-09-03 12:07:08 +00:00
|
|
|
if (Z_TYPE_P(key) == IS_LONG) {
|
2018-09-05 16:00:15 +00:00
|
|
|
value = zend_hash_index_add(dest_arr, Z_LVAL_P(key), value);
|
2018-09-03 12:07:08 +00:00
|
|
|
} else if (Z_TYPE_P(key) == IS_STRING) {
|
2018-09-05 16:00:15 +00:00
|
|
|
value = zend_hash_add(dest_arr, Z_STR_P(key), value);
|
2018-09-03 12:07:08 +00:00
|
|
|
} else {
|
2018-03-26 05:25:00 +00:00
|
|
|
ERR_BAD_KEY_TYPE();
|
2018-09-05 16:00:15 +00:00
|
|
|
value = NULL;
|
|
|
|
}
|
|
|
|
if (value) {
|
|
|
|
Z_TRY_ADDREF_P(value);
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-09-03 12:07:08 +00:00
|
|
|
} else {
|
2018-03-26 05:25:00 +00:00
|
|
|
ERR_BAD_CALLBACK_RETVAL();
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-08-11 18:26:46 +00:00
|
|
|
zval_ptr_dtor(&retval);
|
2018-03-26 05:25:00 +00:00
|
|
|
ZEND_HASH_FOREACH_END();
|
|
|
|
RETVAL_ZVAL(dest, 1, 0);
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, associateBy)
|
|
|
|
{
|
2018-03-26 11:58:40 +00:00
|
|
|
zend_fcall_info fci;
|
|
|
|
zend_fcall_info_cache fcc;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
|
|
Z_PARAM_FUNC(fci, fcc)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-08-15 14:37:37 +00:00
|
|
|
INIT_FCI(&fci, 2);
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-03-26 11:58:40 +00:00
|
|
|
ARRAY_NEW_EX(new_collection, current);
|
2018-04-15 03:22:10 +00:00
|
|
|
ZEND_HASH_FOREACH_BUCKET(current, Bucket* bucket)
|
2018-04-13 11:54:11 +00:00
|
|
|
CALLBACK_KEYVAL_INVOKE(params, bucket);
|
2018-09-03 12:07:08 +00:00
|
|
|
if (Z_TYPE(retval) == IS_LONG) {
|
2018-09-05 16:00:15 +00:00
|
|
|
Z_TRY_ADDREF(bucket->val);
|
2018-03-26 11:58:40 +00:00
|
|
|
zend_hash_index_add(new_collection, Z_LVAL(retval), &bucket->val);
|
2018-09-03 12:07:08 +00:00
|
|
|
} else if (Z_TYPE(retval) == IS_STRING) {
|
2018-09-05 16:00:15 +00:00
|
|
|
Z_TRY_ADDREF(bucket->val);
|
2018-03-26 11:58:40 +00:00
|
|
|
zend_hash_add(new_collection, Z_STR(retval), &bucket->val);
|
2018-09-03 12:07:08 +00:00
|
|
|
} else {
|
2018-03-26 11:58:40 +00:00
|
|
|
ERR_BAD_CALLBACK_RETVAL();
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-08-11 18:26:46 +00:00
|
|
|
zval_ptr_dtor(&retval);
|
2018-03-26 11:58:40 +00:00
|
|
|
ZEND_HASH_FOREACH_END();
|
|
|
|
RETVAL_NEW_COLLECTION(new_collection);
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, associateByTo)
|
|
|
|
{
|
2018-04-14 06:03:47 +00:00
|
|
|
zval* dest;
|
2018-03-26 11:58:40 +00:00
|
|
|
zend_fcall_info fci;
|
|
|
|
zend_fcall_info_cache fcc;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(2, 2)
|
|
|
|
Z_PARAM_OBJECT_OF_CLASS(dest, collections_collection_ce)
|
|
|
|
Z_PARAM_FUNC(fci, fcc)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-08-15 14:37:37 +00:00
|
|
|
INIT_FCI(&fci, 2);
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
|
|
|
zend_array* dest_arr = Z_COLLECTION_P(dest);
|
2018-04-18 04:03:27 +00:00
|
|
|
SEPARATE_COLLECTION(dest_arr, dest);
|
2018-04-15 03:22:10 +00:00
|
|
|
ZEND_HASH_FOREACH_BUCKET(current, Bucket* bucket)
|
2018-04-13 11:54:11 +00:00
|
|
|
CALLBACK_KEYVAL_INVOKE(params, bucket);
|
2018-09-05 16:00:15 +00:00
|
|
|
zval* result = NULL;
|
2018-09-03 12:07:08 +00:00
|
|
|
if (Z_TYPE(retval) == IS_LONG) {
|
2018-09-05 16:00:15 +00:00
|
|
|
result = zend_hash_index_add(dest_arr, Z_LVAL(retval), &bucket->val);
|
2018-09-03 12:07:08 +00:00
|
|
|
} else if (Z_TYPE(retval) == IS_STRING) {
|
2018-09-05 16:00:15 +00:00
|
|
|
result = zend_hash_add(dest_arr, Z_STR(retval), &bucket->val);
|
2018-09-03 12:07:08 +00:00
|
|
|
} else {
|
2018-03-26 11:58:40 +00:00
|
|
|
ERR_BAD_CALLBACK_RETVAL();
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-09-05 16:00:15 +00:00
|
|
|
if (result) {
|
|
|
|
Z_TRY_ADDREF(bucket->val);
|
|
|
|
}
|
2018-08-11 18:26:46 +00:00
|
|
|
zval_ptr_dtor(&retval);
|
2018-03-26 11:58:40 +00:00
|
|
|
ZEND_HASH_FOREACH_END();
|
|
|
|
RETVAL_ZVAL(dest, 1, 0);
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, average)
|
|
|
|
{
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-03-28 05:02:51 +00:00
|
|
|
double sum = 0;
|
2018-04-16 12:58:38 +00:00
|
|
|
ZEND_HASH_FOREACH_VAL(current, zval* val)
|
2018-09-03 12:07:08 +00:00
|
|
|
if (Z_TYPE_P(val) == IS_LONG) {
|
2018-03-28 05:02:51 +00:00
|
|
|
sum += Z_LVAL_P(val);
|
2018-09-03 12:07:08 +00:00
|
|
|
} else if (Z_TYPE_P(val) == IS_DOUBLE) {
|
2018-03-28 05:02:51 +00:00
|
|
|
sum += Z_DVAL_P(val);
|
2018-09-03 12:07:08 +00:00
|
|
|
} else {
|
2018-09-05 16:00:15 +00:00
|
|
|
ERR_NOT_NUMERIC();
|
2018-09-07 08:00:08 +00:00
|
|
|
RETURN_NULL();
|
2018-03-28 05:02:51 +00:00
|
|
|
}
|
|
|
|
ZEND_HASH_FOREACH_END();
|
2018-04-15 03:22:10 +00:00
|
|
|
RETVAL_DOUBLE(sum / zend_hash_num_elements(current));
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
2018-09-09 14:20:39 +00:00
|
|
|
PHP_METHOD(Collection, binarySearch)
|
|
|
|
{
|
2018-09-12 05:42:13 +00:00
|
|
|
zval* element;
|
|
|
|
zend_long flags = 0;
|
|
|
|
zend_long from_idx = 0;
|
|
|
|
zend_array* current = THIS_COLLECTION;
|
|
|
|
uint32_t num_elements = zend_hash_num_elements(current);
|
|
|
|
zend_long to_idx = num_elements;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 4)
|
|
|
|
Z_PARAM_ZVAL(element)
|
|
|
|
Z_PARAM_OPTIONAL
|
|
|
|
Z_PARAM_LONG(flags)
|
|
|
|
Z_PARAM_LONG(from_idx)
|
|
|
|
Z_PARAM_LONG(to_idx)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
|
|
if (UNEXPECTED(!HT_IS_PACKED(current))) {
|
|
|
|
ERR_NOT_PACKED();
|
|
|
|
RETURN_NULL();
|
|
|
|
}
|
|
|
|
if (UNEXPECTED(from_idx < 0)) {
|
|
|
|
ERR_BAD_INDEX();
|
|
|
|
RETURN_NULL();
|
|
|
|
}
|
|
|
|
if (to_idx > num_elements) {
|
|
|
|
to_idx = num_elements;
|
|
|
|
}
|
|
|
|
if (UNEXPECTED(to_idx < from_idx)) {
|
|
|
|
ERR_BAD_SIZE();
|
|
|
|
RETURN_NULL();
|
|
|
|
}
|
|
|
|
compare_func_t cmp;
|
|
|
|
ZEND_HASH_FOREACH_VAL(current, zval* val)
|
|
|
|
cmp = compare_func_init(val, 0, flags);
|
|
|
|
break;
|
|
|
|
ZEND_HASH_FOREACH_END();
|
|
|
|
RETVAL_LONG(binary_search(current->arData, element, from_idx, to_idx, cmp));
|
2018-09-09 14:20:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, binarySearchBy)
|
|
|
|
{
|
2018-09-12 05:42:13 +00:00
|
|
|
zval* element;
|
|
|
|
zend_fcall_info fci;
|
|
|
|
zend_fcall_info_cache fcc;
|
|
|
|
zend_long flags = 0;
|
|
|
|
zend_long from_idx = 0;
|
|
|
|
zend_array* current = THIS_COLLECTION;
|
|
|
|
uint32_t num_elements = zend_hash_num_elements(current);
|
|
|
|
zend_long to_idx = num_elements;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(2, 5)
|
|
|
|
Z_PARAM_ZVAL(element)
|
|
|
|
Z_PARAM_FUNC(fci, fcc)
|
|
|
|
Z_PARAM_OPTIONAL
|
|
|
|
Z_PARAM_LONG(flags)
|
|
|
|
Z_PARAM_LONG(from_idx)
|
|
|
|
Z_PARAM_LONG(to_idx)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
|
|
if (UNEXPECTED(!HT_IS_PACKED(current))) {
|
|
|
|
ERR_NOT_PACKED();
|
|
|
|
RETURN_NULL();
|
|
|
|
}
|
|
|
|
if (UNEXPECTED(from_idx < 0)) {
|
|
|
|
ERR_BAD_INDEX();
|
|
|
|
RETURN_NULL();
|
|
|
|
}
|
|
|
|
if (to_idx > num_elements) {
|
|
|
|
to_idx = num_elements;
|
|
|
|
}
|
|
|
|
if (UNEXPECTED(to_idx < from_idx)) {
|
|
|
|
ERR_BAD_SIZE();
|
|
|
|
RETURN_NULL();
|
|
|
|
}
|
|
|
|
INIT_FCI(&fci, 2);
|
|
|
|
uint32_t range = to_idx - from_idx;
|
|
|
|
Bucket* ref = (Bucket*)malloc(range * sizeof(Bucket));
|
|
|
|
compare_func_t cmp = NULL;
|
|
|
|
uint32_t idx = 0;
|
|
|
|
Bucket* bucket = current->arData + from_idx;
|
|
|
|
Bucket* end = current->arData + to_idx;
|
|
|
|
for (; bucket < end; ++bucket) {
|
|
|
|
CALLBACK_KEYVAL_INVOKE(params, bucket);
|
|
|
|
memcpy(&ref[idx++].val, &bucket->val, sizeof(zval));
|
|
|
|
if (UNEXPECTED(cmp == NULL)) {
|
|
|
|
cmp = compare_func_init(&retval, 0, flags);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
zend_long result = binary_search(ref, element, 0, range, cmp);
|
|
|
|
RETVAL_LONG(result < 0 ? result - from_idx : result + from_idx);
|
|
|
|
for (idx = 0; idx < range; ++idx) {
|
|
|
|
zval_ptr_dtor(&ref[idx].val);
|
|
|
|
}
|
|
|
|
free(ref);
|
2018-09-09 14:20:39 +00:00
|
|
|
}
|
|
|
|
|
2018-09-12 05:50:26 +00:00
|
|
|
PHP_METHOD(Collection, binarySearchWith)
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2018-09-09 14:20:39 +00:00
|
|
|
PHP_METHOD(Collection, chunked)
|
|
|
|
{
|
2018-09-11 03:28:45 +00:00
|
|
|
zend_long size;
|
|
|
|
zend_fcall_info fci;
|
|
|
|
zend_fcall_info_cache fcc;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 2)
|
|
|
|
Z_PARAM_LONG(size)
|
|
|
|
Z_PARAM_OPTIONAL
|
|
|
|
Z_PARAM_FUNC(fci, fcc)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
|
|
if (size <= 0) {
|
|
|
|
ERR_BAD_SIZE();
|
|
|
|
RETURN_NULL();
|
|
|
|
}
|
|
|
|
zend_bool transform = EX_NUM_ARGS() > 1;
|
|
|
|
zend_array* current = THIS_COLLECTION;
|
|
|
|
zend_bool packed = HT_IS_PACKED(current);
|
|
|
|
INIT_FCI(&fci, 2);
|
|
|
|
ARRAY_NEW(chunked, 8);
|
|
|
|
uint32_t num_remaining = 0;
|
|
|
|
uint32_t num_chunks = 0;
|
|
|
|
zend_array* chunk = NULL;
|
|
|
|
ZEND_HASH_FOREACH_BUCKET(current, Bucket* bucket)
|
|
|
|
if (num_remaining == 0) {
|
|
|
|
chunk = (zend_array*)emalloc(sizeof(zend_array));
|
|
|
|
zend_hash_init(chunk, 8, NULL, ZVAL_PTR_DTOR, 0);
|
|
|
|
num_remaining = size;
|
|
|
|
}
|
|
|
|
Z_TRY_ADDREF(bucket->val);
|
|
|
|
if (bucket->key) {
|
|
|
|
zend_hash_add_new(chunk, bucket->key, &bucket->val);
|
|
|
|
} else if (packed) {
|
|
|
|
zend_hash_next_index_insert(chunk, &bucket->val);
|
|
|
|
} else {
|
|
|
|
zend_hash_index_add_new(chunk, bucket->h, &bucket->val);
|
|
|
|
}
|
|
|
|
if (--num_remaining == 0) {
|
|
|
|
ZVAL_ARR(¶ms[0], chunk);
|
|
|
|
if (transform) {
|
|
|
|
ZVAL_LONG(¶ms[1], num_chunks++);
|
|
|
|
zend_call_function(&fci, &fcc);
|
2018-09-12 05:42:13 +00:00
|
|
|
array_release(chunk);
|
2018-09-11 03:28:45 +00:00
|
|
|
zend_hash_next_index_insert(chunked, &retval);
|
|
|
|
} else {
|
|
|
|
zend_hash_next_index_insert(chunked, ¶ms[0]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ZEND_HASH_FOREACH_END();
|
|
|
|
if (num_remaining) {
|
|
|
|
ZVAL_ARR(¶ms[0], chunk);
|
|
|
|
if (transform) {
|
|
|
|
ZVAL_LONG(¶ms[1], num_chunks++);
|
|
|
|
zend_call_function(&fci, &fcc);
|
2018-09-12 05:42:13 +00:00
|
|
|
array_release(chunk);
|
2018-09-11 03:28:45 +00:00
|
|
|
zend_hash_next_index_insert(chunked, &retval);
|
|
|
|
} else {
|
|
|
|
zend_hash_next_index_insert(chunked, ¶ms[0]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
RETVAL_NEW_COLLECTION(chunked);
|
2018-09-09 14:20:39 +00:00
|
|
|
}
|
|
|
|
|
2018-03-23 09:06:05 +00:00
|
|
|
PHP_METHOD(Collection, containsAll)
|
|
|
|
{
|
2018-03-28 05:02:51 +00:00
|
|
|
zval* elements;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
|
|
Z_PARAM_ZVAL(elements)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-04-22 14:47:30 +00:00
|
|
|
ELEMENTS_VALIDATE(elements, ERR_BAD_ARGUMENT_TYPE, return);
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-09-03 13:54:14 +00:00
|
|
|
ZEND_HASH_FOREACH_BUCKET(elements_arr, Bucket* bucket)
|
|
|
|
if (bucket->key) {
|
|
|
|
zval* result = zend_hash_find(current, bucket->key);
|
2018-09-05 10:44:16 +00:00
|
|
|
if (!result || !fast_equal_check_function(&bucket->val, result)) {
|
2018-09-03 13:54:14 +00:00
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
zval* result = zend_hash_index_find(current, bucket->h);
|
2018-09-05 10:44:16 +00:00
|
|
|
if (!result || !fast_equal_check_function(&bucket->val, result)) {
|
2018-09-03 13:54:14 +00:00
|
|
|
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);
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-09-03 13:54:14 +00:00
|
|
|
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;
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
|
|
|
}
|
2018-03-28 05:02:51 +00:00
|
|
|
ZEND_HASH_FOREACH_END();
|
|
|
|
RETURN_TRUE;
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
2018-09-03 13:54:14 +00:00
|
|
|
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);
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-09-03 13:54:14 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2018-03-23 09:06:05 +00:00
|
|
|
PHP_METHOD(Collection, containsKey)
|
|
|
|
{
|
2018-03-29 04:33:39 +00:00
|
|
|
zval* key;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
|
|
Z_PARAM_ZVAL(key)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-09-03 12:07:08 +00:00
|
|
|
if (Z_TYPE_P(key) == IS_LONG) {
|
2018-04-15 03:22:10 +00:00
|
|
|
RETURN_BOOL(zend_hash_index_exists(current, Z_LVAL_P(key)));
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-09-03 12:07:08 +00:00
|
|
|
if (Z_TYPE_P(key) == IS_STRING) {
|
2018-04-15 03:22:10 +00:00
|
|
|
RETURN_BOOL(zend_hash_exists(current, Z_STR_P(key)));
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-03-29 04:33:39 +00:00
|
|
|
ERR_BAD_KEY_TYPE();
|
|
|
|
RETVAL_FALSE;
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, containsValue)
|
|
|
|
{
|
2018-03-29 04:33:39 +00:00
|
|
|
zval* element;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
|
|
Z_PARAM_ZVAL(element)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-08-20 14:47:23 +00:00
|
|
|
equal_check_func_t eql = equal_check_func_init(element);
|
2018-04-16 12:58:38 +00:00
|
|
|
ZEND_HASH_FOREACH_VAL(current, zval* val)
|
2018-09-03 12:07:08 +00:00
|
|
|
if (eql(element, val)) {
|
2018-03-29 04:33:39 +00:00
|
|
|
RETURN_TRUE;
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-03-29 04:33:39 +00:00
|
|
|
ZEND_HASH_FOREACH_END();
|
|
|
|
RETURN_FALSE;
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, copyOf)
|
|
|
|
{
|
2018-03-29 04:33:39 +00:00
|
|
|
zend_long new_size = -1;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(0, 1)
|
|
|
|
Z_PARAM_OPTIONAL
|
|
|
|
Z_PARAM_LONG(new_size);
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-09-03 12:07:08 +00:00
|
|
|
if (EX_NUM_ARGS() == 0) {
|
2018-03-29 04:33:39 +00:00
|
|
|
ARRAY_CLONE(new_collection, current);
|
|
|
|
RETURN_NEW_COLLECTION(new_collection);
|
|
|
|
}
|
2018-09-03 12:07:08 +00:00
|
|
|
if (UNEXPECTED(new_size < 0)) {
|
2018-03-29 04:33:39 +00:00
|
|
|
ERR_BAD_SIZE();
|
|
|
|
RETURN_NULL();
|
|
|
|
}
|
2018-09-03 12:07:08 +00:00
|
|
|
if (new_size == 0) {
|
2018-03-29 04:33:39 +00:00
|
|
|
ARRAY_NEW(new_collection, 0);
|
|
|
|
RETURN_NEW_COLLECTION(new_collection);
|
|
|
|
}
|
2018-09-02 13:46:01 +00:00
|
|
|
uint32_t num_elements = zend_hash_num_elements(current);
|
|
|
|
ARRAY_NEW(new_collection, new_size < num_elements ? new_size : num_elements);
|
2018-04-15 03:22:10 +00:00
|
|
|
ZEND_HASH_FOREACH_BUCKET(current, Bucket* bucket)
|
2018-09-05 16:00:15 +00:00
|
|
|
Z_TRY_ADDREF(bucket->val);
|
2018-09-03 12:07:08 +00:00
|
|
|
if (bucket->key) {
|
2018-05-26 11:02:32 +00:00
|
|
|
zend_hash_add_new(new_collection, bucket->key, &bucket->val);
|
2018-09-03 12:07:08 +00:00
|
|
|
} else {
|
2018-05-26 11:02:32 +00:00
|
|
|
zend_hash_index_add_new(new_collection, bucket->h, &bucket->val);
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-09-03 12:07:08 +00:00
|
|
|
if (--new_size == 0) {
|
2018-03-29 04:33:39 +00:00
|
|
|
break;
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-03-29 04:33:39 +00:00
|
|
|
ZEND_HASH_FOREACH_END();
|
|
|
|
RETVAL_NEW_COLLECTION(new_collection);
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, copyOfRange)
|
|
|
|
{
|
2018-09-12 05:42:13 +00:00
|
|
|
zend_long from_idx, to_idx;
|
2018-03-30 11:06:39 +00:00
|
|
|
ZEND_PARSE_PARAMETERS_START(2, 2)
|
|
|
|
Z_PARAM_LONG(from_idx)
|
2018-09-12 05:42:13 +00:00
|
|
|
Z_PARAM_LONG(to_idx)
|
2018-03-30 11:06:39 +00:00
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-09-12 05:42:13 +00:00
|
|
|
if (UNEXPECTED(from_idx < 0)) {
|
2018-03-30 11:06:39 +00:00
|
|
|
ERR_BAD_INDEX();
|
|
|
|
RETURN_NULL();
|
|
|
|
}
|
2018-09-12 05:42:13 +00:00
|
|
|
if (UNEXPECTED(to_idx < from_idx)) {
|
2018-03-30 11:06:39 +00:00
|
|
|
ERR_BAD_SIZE();
|
|
|
|
RETURN_NULL();
|
|
|
|
}
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-09-12 05:42:13 +00:00
|
|
|
uint32_t num_elements = to_idx - from_idx;
|
2018-03-30 11:06:39 +00:00
|
|
|
ARRAY_NEW(new_collection, num_elements);
|
2018-09-02 13:16:05 +00:00
|
|
|
zend_bool packed = HT_IS_PACKED(current);
|
2018-04-15 03:22:10 +00:00
|
|
|
Bucket* bucket = current->arData;
|
|
|
|
Bucket* end = bucket + current->nNumUsed;
|
2018-04-18 04:03:27 +00:00
|
|
|
for (bucket += from_idx; num_elements > 0 && bucket < end; ++bucket) {
|
2018-09-03 12:07:08 +00:00
|
|
|
if (Z_ISUNDEF(bucket->val)) {
|
2018-04-18 04:03:27 +00:00
|
|
|
continue;
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-04-18 04:03:27 +00:00
|
|
|
--num_elements;
|
2018-09-05 16:00:15 +00:00
|
|
|
Z_TRY_ADDREF(bucket->val);
|
2018-09-03 12:07:08 +00:00
|
|
|
if (bucket->key) {
|
2018-09-06 03:33:41 +00:00
|
|
|
zend_hash_add_new(new_collection, bucket->key, &bucket->val);
|
2018-09-03 12:07:08 +00:00
|
|
|
} else if (packed) {
|
2018-03-30 11:06:39 +00:00
|
|
|
zend_hash_next_index_insert(new_collection, &bucket->val);
|
2018-09-03 12:07:08 +00:00
|
|
|
} else {
|
2018-09-06 03:33:41 +00:00
|
|
|
zend_hash_index_add_new(new_collection, bucket->h, &bucket->val);
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-04-18 04:03:27 +00:00
|
|
|
}
|
2018-03-30 11:06:39 +00:00
|
|
|
RETVAL_NEW_COLLECTION(new_collection);
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, count)
|
|
|
|
{
|
2018-03-30 11:06:39 +00:00
|
|
|
zend_long count;
|
|
|
|
count_collection(getThis(), &count);
|
|
|
|
RETVAL_LONG(count);
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, distinct)
|
|
|
|
{
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-08-28 13:24:26 +00:00
|
|
|
compare_func_t cmp = NULL;
|
|
|
|
equal_check_func_t eql = NULL;
|
2018-09-07 19:43:00 +00:00
|
|
|
uint32_t num_elements = zend_hash_num_elements(current);
|
|
|
|
Bucket* ref = (Bucket*)malloc(num_elements * sizeof(Bucket));
|
2018-08-28 13:24:26 +00:00
|
|
|
ARRAY_CLONE(distinct, current);
|
|
|
|
uint32_t idx = 0;
|
|
|
|
ZEND_HASH_FOREACH_BUCKET(distinct, Bucket* bucket)
|
2018-09-03 12:07:08 +00:00
|
|
|
if (UNEXPECTED(cmp == NULL)) {
|
2018-08-28 13:24:26 +00:00
|
|
|
cmp = compare_func_init(&bucket->val, 0, 0);
|
|
|
|
eql = equal_check_func_init(&bucket->val);
|
|
|
|
}
|
|
|
|
Bucket* dest = &ref[idx++];
|
|
|
|
dest->key = NULL;
|
|
|
|
dest->h = bucket - distinct->arData;
|
|
|
|
memcpy(&dest->val, &bucket->val, sizeof(zval));
|
|
|
|
ZEND_HASH_FOREACH_END();
|
2018-09-07 15:42:36 +00:00
|
|
|
CMP_G = cmp;
|
2018-08-28 16:36:50 +00:00
|
|
|
array_distinct(distinct, ref, cmp, eql);
|
2018-08-28 13:24:26 +00:00
|
|
|
free(ref);
|
|
|
|
RETVAL_NEW_COLLECTION(distinct);
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, distinctBy)
|
|
|
|
{
|
2018-08-29 05:00:15 +00:00
|
|
|
zend_fcall_info fci;
|
|
|
|
zend_fcall_info_cache fcc;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
|
|
Z_PARAM_FUNC(fci, fcc)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-08-29 05:00:15 +00:00
|
|
|
compare_func_t cmp = NULL;
|
|
|
|
equal_check_func_t eql = NULL;
|
|
|
|
uint32_t num_elements = zend_hash_num_elements(current);
|
|
|
|
Bucket* ref = (Bucket*)malloc(num_elements * sizeof(Bucket));
|
|
|
|
ARRAY_CLONE(distinct, current);
|
|
|
|
uint32_t idx = 0;
|
|
|
|
INIT_FCI(&fci, 2);
|
|
|
|
ZEND_HASH_FOREACH_BUCKET(distinct, Bucket* bucket)
|
|
|
|
CALLBACK_KEYVAL_INVOKE(params, bucket);
|
2018-09-03 12:07:08 +00:00
|
|
|
if (UNEXPECTED(cmp == NULL)) {
|
2018-08-29 05:00:15 +00:00
|
|
|
cmp = compare_func_init(&retval, 0, 0);
|
|
|
|
eql = equal_check_func_init(&retval);
|
|
|
|
}
|
|
|
|
Bucket* dest = &ref[idx++];
|
|
|
|
dest->key = NULL;
|
|
|
|
dest->h = bucket - distinct->arData;
|
|
|
|
memcpy(&dest->val, &retval, sizeof(zval));
|
|
|
|
ZEND_HASH_FOREACH_END();
|
2018-09-07 15:42:36 +00:00
|
|
|
CMP_G = cmp;
|
2018-08-29 05:00:15 +00:00
|
|
|
array_distinct(distinct, ref, cmp, eql);
|
2018-09-03 12:07:08 +00:00
|
|
|
for (idx = 0; idx < num_elements; ++idx) {
|
2018-08-29 05:00:15 +00:00
|
|
|
zval_ptr_dtor(&ref[idx].val);
|
|
|
|
}
|
|
|
|
free(ref);
|
|
|
|
RETVAL_NEW_COLLECTION(distinct);
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, drop)
|
|
|
|
{
|
2018-04-11 07:16:20 +00:00
|
|
|
zend_long n;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
|
|
Z_PARAM_LONG(n)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-09-03 12:07:08 +00:00
|
|
|
if (n < 0) {
|
2018-04-11 07:16:20 +00:00
|
|
|
ERR_BAD_SIZE();
|
2018-04-17 15:17:30 +00:00
|
|
|
return;
|
2018-04-11 07:16:20 +00:00
|
|
|
}
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-04-11 07:16:20 +00:00
|
|
|
ARRAY_CLONE(new_collection, current);
|
|
|
|
Bucket* bucket = new_collection->arData;
|
|
|
|
Bucket* end = bucket + new_collection->nNumUsed;
|
2018-09-03 12:07:08 +00:00
|
|
|
for (; n > 0 && bucket < end; ++bucket) {
|
|
|
|
if (Z_ISUNDEF(bucket->val)) {
|
2018-04-18 04:03:27 +00:00
|
|
|
continue;
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-04-18 04:03:27 +00:00
|
|
|
--n;
|
2018-04-11 07:16:20 +00:00
|
|
|
zend_hash_del_bucket(new_collection, bucket);
|
|
|
|
}
|
|
|
|
RETVAL_NEW_COLLECTION(new_collection);
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, dropLast)
|
|
|
|
{
|
2018-04-11 07:16:20 +00:00
|
|
|
zend_long n;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
|
|
Z_PARAM_LONG(n)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-09-03 12:07:08 +00:00
|
|
|
if (n < 0) {
|
2018-04-11 07:16:20 +00:00
|
|
|
ERR_BAD_SIZE();
|
2018-04-17 15:17:30 +00:00
|
|
|
return;
|
2018-04-11 07:16:20 +00:00
|
|
|
}
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-04-11 07:16:20 +00:00
|
|
|
ARRAY_CLONE(new_collection, current);
|
|
|
|
unsigned idx = new_collection->nNumUsed;
|
2018-09-03 12:07:08 +00:00
|
|
|
for (; n > 0 && idx > 0; --idx) {
|
2018-04-11 07:16:20 +00:00
|
|
|
Bucket* bucket = new_collection->arData + idx - 1;
|
2018-09-03 12:07:08 +00:00
|
|
|
if (Z_ISUNDEF(bucket->val)) {
|
2018-04-18 04:03:27 +00:00
|
|
|
continue;
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-04-18 04:03:27 +00:00
|
|
|
--n;
|
2018-04-11 07:16:20 +00:00
|
|
|
zend_hash_del_bucket(new_collection, bucket);
|
|
|
|
}
|
|
|
|
RETVAL_NEW_COLLECTION(new_collection);
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, dropLastWhile)
|
|
|
|
{
|
2018-04-11 13:26:51 +00:00
|
|
|
zend_fcall_info fci;
|
|
|
|
zend_fcall_info_cache fcc;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
|
|
Z_PARAM_FUNC(fci, fcc)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-08-15 14:37:37 +00:00
|
|
|
INIT_FCI(&fci, 2);
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-04-11 13:26:51 +00:00
|
|
|
ARRAY_CLONE(new_collection, current);
|
|
|
|
ZEND_HASH_REVERSE_FOREACH_BUCKET(new_collection, Bucket* bucket)
|
2018-04-13 11:54:11 +00:00
|
|
|
CALLBACK_KEYVAL_INVOKE(params, bucket);
|
2018-09-03 12:07:08 +00:00
|
|
|
if (zend_is_true(&retval)) {
|
2018-08-11 18:26:46 +00:00
|
|
|
zval_ptr_dtor(&retval);
|
2018-04-11 13:26:51 +00:00
|
|
|
zend_hash_del_bucket(new_collection, bucket);
|
2018-09-03 12:07:08 +00:00
|
|
|
} else {
|
2018-08-11 18:26:46 +00:00
|
|
|
zval_ptr_dtor(&retval);
|
2018-04-11 13:26:51 +00:00
|
|
|
break;
|
2018-08-11 18:26:46 +00:00
|
|
|
}
|
2018-04-11 13:26:51 +00:00
|
|
|
ZEND_HASH_FOREACH_END();
|
|
|
|
RETVAL_NEW_COLLECTION(new_collection);
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, dropWhile)
|
|
|
|
{
|
2018-04-11 13:26:51 +00:00
|
|
|
zend_fcall_info fci;
|
|
|
|
zend_fcall_info_cache fcc;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
|
|
Z_PARAM_FUNC(fci, fcc)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-08-15 14:37:37 +00:00
|
|
|
INIT_FCI(&fci, 2);
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-04-11 13:26:51 +00:00
|
|
|
ARRAY_CLONE(new_collection, current);
|
|
|
|
ZEND_HASH_FOREACH_BUCKET(new_collection, Bucket* bucket)
|
2018-04-13 11:54:11 +00:00
|
|
|
CALLBACK_KEYVAL_INVOKE(params, bucket);
|
2018-09-03 12:07:08 +00:00
|
|
|
if (zend_is_true(&retval)) {
|
2018-08-11 18:26:46 +00:00
|
|
|
zval_ptr_dtor(&retval);
|
2018-04-11 13:26:51 +00:00
|
|
|
zend_hash_del_bucket(new_collection, bucket);
|
2018-09-03 12:07:08 +00:00
|
|
|
} else {
|
2018-08-11 18:26:46 +00:00
|
|
|
zval_ptr_dtor(&retval);
|
2018-04-11 13:26:51 +00:00
|
|
|
break;
|
2018-08-11 18:26:46 +00:00
|
|
|
}
|
2018-04-11 13:26:51 +00:00
|
|
|
ZEND_HASH_FOREACH_END();
|
|
|
|
RETVAL_NEW_COLLECTION(new_collection);
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, fill)
|
|
|
|
{
|
2018-04-12 07:24:53 +00:00
|
|
|
zval* element;
|
|
|
|
zend_long from_idx = 0;
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-09-12 05:42:13 +00:00
|
|
|
zend_long to_idx = zend_hash_num_elements(current);
|
2018-04-12 07:24:53 +00:00
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 3)
|
|
|
|
Z_PARAM_ZVAL(element)
|
|
|
|
Z_PARAM_OPTIONAL
|
|
|
|
Z_PARAM_LONG(from_idx)
|
2018-09-12 05:42:13 +00:00
|
|
|
Z_PARAM_LONG(to_idx)
|
2018-04-12 07:24:53 +00:00
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-09-12 05:42:13 +00:00
|
|
|
if (UNEXPECTED(from_idx < 0)) {
|
|
|
|
ERR_BAD_INDEX();
|
|
|
|
RETURN_NULL();
|
|
|
|
}
|
|
|
|
if (UNEXPECTED(to_idx < from_idx)) {
|
|
|
|
ERR_BAD_SIZE();
|
|
|
|
RETURN_NULL();
|
|
|
|
}
|
|
|
|
SEPARATE_CURRENT_COLLECTION(current);
|
|
|
|
uint32_t num_elements = to_idx - from_idx;
|
2018-09-03 12:07:08 +00:00
|
|
|
Bucket* bucket = current->arData + from_idx;
|
2018-04-15 03:22:10 +00:00
|
|
|
Bucket* end = bucket + current->nNumUsed;
|
2018-09-03 12:07:08 +00:00
|
|
|
for (; num_elements > 0 && bucket < end; ++bucket, --num_elements) {
|
|
|
|
if (Z_ISUNDEF(bucket->val)) {
|
2018-04-18 04:03:27 +00:00
|
|
|
continue;
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-09-05 16:00:15 +00:00
|
|
|
Z_TRY_ADDREF_P(element);
|
2018-09-03 12:07:08 +00:00
|
|
|
if (bucket->key) {
|
2018-04-15 03:22:10 +00:00
|
|
|
zend_hash_update(current, bucket->key, element);
|
2018-09-03 12:07:08 +00:00
|
|
|
} else {
|
2018-04-15 03:22:10 +00:00
|
|
|
zend_hash_index_update(current, bucket->h, element);
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-04-12 07:24:53 +00:00
|
|
|
}
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, filter)
|
|
|
|
{
|
2018-04-13 11:54:11 +00:00
|
|
|
zend_fcall_info fci;
|
|
|
|
zend_fcall_info_cache fcc;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
|
|
Z_PARAM_FUNC(fci, fcc)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-08-15 14:37:37 +00:00
|
|
|
INIT_FCI(&fci, 2);
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-09-02 13:46:01 +00:00
|
|
|
ARRAY_NEW(new_collection, 8);
|
2018-09-02 13:16:05 +00:00
|
|
|
zend_bool packed = HT_IS_PACKED(current);
|
2018-04-15 03:22:10 +00:00
|
|
|
ZEND_HASH_FOREACH_BUCKET(current, Bucket* bucket)
|
2018-04-13 11:54:11 +00:00
|
|
|
CALLBACK_KEYVAL_INVOKE(params, bucket);
|
2018-09-03 12:07:08 +00:00
|
|
|
if (zend_is_true(&retval)) {
|
2018-09-05 16:00:15 +00:00
|
|
|
Z_TRY_ADDREF(bucket->val);
|
2018-09-03 12:07:08 +00:00
|
|
|
if (bucket->key) {
|
2018-09-06 03:33:41 +00:00
|
|
|
zend_hash_add_new(new_collection, bucket->key, &bucket->val);
|
2018-09-03 12:07:08 +00:00
|
|
|
} else if (packed) {
|
2018-05-26 11:02:32 +00:00
|
|
|
zend_hash_next_index_insert(new_collection, &bucket->val);
|
2018-09-03 12:07:08 +00:00
|
|
|
} else {
|
2018-09-06 03:33:41 +00:00
|
|
|
zend_hash_index_add_new(new_collection, bucket->h, &bucket->val);
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-05-26 11:02:32 +00:00
|
|
|
}
|
2018-08-11 18:26:46 +00:00
|
|
|
zval_ptr_dtor(&retval);
|
2018-04-13 11:54:11 +00:00
|
|
|
ZEND_HASH_FOREACH_END();
|
|
|
|
RETVAL_NEW_COLLECTION(new_collection);
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, filterNot)
|
|
|
|
{
|
2018-04-13 11:54:11 +00:00
|
|
|
zend_fcall_info fci;
|
|
|
|
zend_fcall_info_cache fcc;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
|
|
Z_PARAM_FUNC(fci, fcc)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-08-15 14:37:37 +00:00
|
|
|
INIT_FCI(&fci, 2);
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-09-02 13:46:01 +00:00
|
|
|
ARRAY_NEW(new_collection, 8);
|
2018-09-02 13:16:05 +00:00
|
|
|
zend_bool packed = HT_IS_PACKED(current);
|
2018-04-15 03:22:10 +00:00
|
|
|
ZEND_HASH_FOREACH_BUCKET(current, Bucket* bucket)
|
2018-04-13 11:54:11 +00:00
|
|
|
CALLBACK_KEYVAL_INVOKE(params, bucket);
|
2018-09-03 12:07:08 +00:00
|
|
|
if (!zend_is_true(&retval)) {
|
2018-09-05 16:00:15 +00:00
|
|
|
Z_TRY_ADDREF(bucket->val);
|
2018-09-03 12:07:08 +00:00
|
|
|
if (bucket->key) {
|
2018-09-06 03:33:41 +00:00
|
|
|
zend_hash_add_new(new_collection, bucket->key, &bucket->val);
|
2018-09-03 12:07:08 +00:00
|
|
|
} else if (packed) {
|
2018-05-26 11:02:32 +00:00
|
|
|
zend_hash_next_index_insert(new_collection, &bucket->val);
|
2018-09-03 12:07:08 +00:00
|
|
|
} else {
|
2018-09-06 03:33:41 +00:00
|
|
|
zend_hash_index_add_new(new_collection, bucket->h, &bucket->val);
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-05-26 11:02:32 +00:00
|
|
|
}
|
2018-08-11 18:26:46 +00:00
|
|
|
zval_ptr_dtor(&retval);
|
2018-04-13 11:54:11 +00:00
|
|
|
ZEND_HASH_FOREACH_END();
|
|
|
|
RETVAL_NEW_COLLECTION(new_collection);
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, filterNotTo)
|
|
|
|
{
|
2018-04-14 06:03:47 +00:00
|
|
|
zval* dest;
|
|
|
|
zend_fcall_info fci;
|
|
|
|
zend_fcall_info_cache fcc;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(2, 2)
|
|
|
|
Z_PARAM_OBJECT_OF_CLASS(dest, collections_collection_ce)
|
|
|
|
Z_PARAM_FUNC(fci, fcc)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-08-15 14:37:37 +00:00
|
|
|
INIT_FCI(&fci, 2);
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
|
|
|
zend_array* dest_arr = Z_COLLECTION_P(dest);
|
2018-04-18 04:03:27 +00:00
|
|
|
SEPARATE_COLLECTION(dest_arr, dest);
|
2018-09-02 13:16:05 +00:00
|
|
|
zend_bool packed = HT_IS_PACKED(current);
|
2018-04-15 03:22:10 +00:00
|
|
|
ZEND_HASH_FOREACH_BUCKET(current, Bucket* bucket)
|
2018-04-14 06:03:47 +00:00
|
|
|
CALLBACK_KEYVAL_INVOKE(params, bucket);
|
2018-09-03 12:07:08 +00:00
|
|
|
if (!zend_is_true(&retval)) {
|
2018-09-06 03:33:41 +00:00
|
|
|
zval* result;
|
2018-09-03 12:07:08 +00:00
|
|
|
if (bucket->key) {
|
2018-09-05 16:00:15 +00:00
|
|
|
result = zend_hash_add(dest_arr, bucket->key, &bucket->val);
|
2018-09-03 12:07:08 +00:00
|
|
|
} else if (packed) {
|
2018-09-06 03:33:41 +00:00
|
|
|
result = zend_hash_next_index_insert(dest_arr, &bucket->val);
|
2018-09-03 12:07:08 +00:00
|
|
|
} else {
|
2018-09-05 16:00:15 +00:00
|
|
|
result = zend_hash_index_add(dest_arr, bucket->h, &bucket->val);
|
|
|
|
}
|
|
|
|
if (result) {
|
|
|
|
Z_TRY_ADDREF(bucket->val);
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-05-26 11:02:32 +00:00
|
|
|
}
|
2018-08-11 18:26:46 +00:00
|
|
|
zval_ptr_dtor(&retval);
|
2018-04-14 06:03:47 +00:00
|
|
|
ZEND_HASH_FOREACH_END();
|
|
|
|
RETVAL_ZVAL(dest, 1, 0);
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, filterTo)
|
|
|
|
{
|
2018-04-14 06:03:47 +00:00
|
|
|
zval* dest;
|
|
|
|
zend_fcall_info fci;
|
|
|
|
zend_fcall_info_cache fcc;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(2, 2)
|
|
|
|
Z_PARAM_OBJECT_OF_CLASS(dest, collections_collection_ce)
|
|
|
|
Z_PARAM_FUNC(fci, fcc)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-08-15 14:37:37 +00:00
|
|
|
INIT_FCI(&fci, 2);
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
|
|
|
zend_array* dest_arr = Z_COLLECTION_P(dest);
|
2018-04-18 04:03:27 +00:00
|
|
|
SEPARATE_COLLECTION(dest_arr, dest);
|
2018-09-02 13:16:05 +00:00
|
|
|
zend_bool packed = HT_IS_PACKED(current);
|
2018-04-15 03:22:10 +00:00
|
|
|
ZEND_HASH_FOREACH_BUCKET(current, Bucket* bucket)
|
2018-04-14 06:03:47 +00:00
|
|
|
CALLBACK_KEYVAL_INVOKE(params, bucket);
|
2018-09-03 12:07:08 +00:00
|
|
|
if (zend_is_true(&retval)) {
|
2018-09-05 16:00:15 +00:00
|
|
|
zval* result;
|
2018-09-03 12:07:08 +00:00
|
|
|
if (bucket->key) {
|
2018-09-05 16:00:15 +00:00
|
|
|
result = zend_hash_add(dest_arr, bucket->key, &bucket->val);
|
2018-09-03 12:07:08 +00:00
|
|
|
} else if (packed) {
|
2018-09-06 03:33:41 +00:00
|
|
|
result = zend_hash_next_index_insert(dest_arr, &bucket->val);
|
2018-09-03 12:07:08 +00:00
|
|
|
} else {
|
2018-09-05 16:00:15 +00:00
|
|
|
result = zend_hash_index_add(dest_arr, bucket->h, &bucket->val);
|
|
|
|
}
|
|
|
|
if (result) {
|
|
|
|
Z_TRY_ADDREF(bucket->val);
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-05-26 11:02:32 +00:00
|
|
|
}
|
2018-08-11 18:26:46 +00:00
|
|
|
zval_ptr_dtor(&retval);
|
2018-04-14 06:03:47 +00:00
|
|
|
ZEND_HASH_FOREACH_END();
|
|
|
|
RETVAL_ZVAL(dest, 1, 0);
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, first)
|
|
|
|
{
|
2018-04-15 03:22:10 +00:00
|
|
|
zend_fcall_info fci;
|
|
|
|
zend_fcall_info_cache fcc;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(0, 1)
|
|
|
|
Z_PARAM_OPTIONAL
|
|
|
|
Z_PARAM_FUNC(fci, fcc)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-09-03 12:07:08 +00:00
|
|
|
if (zend_hash_num_elements(current) == 0) {
|
2018-04-15 03:22:10 +00:00
|
|
|
RETURN_NULL();
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-09-03 12:07:08 +00:00
|
|
|
if (EX_NUM_ARGS() == 0) {
|
2018-08-28 13:24:26 +00:00
|
|
|
uint32_t pos = 0;
|
2018-09-03 12:07:08 +00:00
|
|
|
while (pos < current->nNumUsed && Z_ISUNDEF(current->arData[pos].val)) {
|
2018-04-18 04:03:27 +00:00
|
|
|
++pos;
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-04-18 04:03:27 +00:00
|
|
|
RETURN_ZVAL(¤t->arData[pos].val, 1, 0);
|
2018-04-15 03:22:10 +00:00
|
|
|
}
|
2018-08-15 14:37:37 +00:00
|
|
|
INIT_FCI(&fci, 2);
|
2018-04-15 03:22:10 +00:00
|
|
|
ZEND_HASH_FOREACH_BUCKET(current, Bucket* bucket)
|
|
|
|
CALLBACK_KEYVAL_INVOKE(params, bucket);
|
2018-09-03 12:07:08 +00:00
|
|
|
if (zend_is_true(&retval)) {
|
2018-08-11 18:26:46 +00:00
|
|
|
zval_ptr_dtor(&retval);
|
2018-04-15 03:22:10 +00:00
|
|
|
RETURN_ZVAL(&bucket->val, 1, 0);
|
2018-08-11 18:26:46 +00:00
|
|
|
}
|
|
|
|
zval_ptr_dtor(&retval);
|
2018-04-15 03:22:10 +00:00
|
|
|
ZEND_HASH_FOREACH_END();
|
|
|
|
RETVAL_NULL();
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, flatMap)
|
|
|
|
{
|
2018-04-16 12:58:38 +00:00
|
|
|
zend_fcall_info fci;
|
|
|
|
zend_fcall_info_cache fcc;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
|
|
Z_PARAM_FUNC(fci, fcc)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-08-15 14:37:37 +00:00
|
|
|
INIT_FCI(&fci, 2);
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-04-16 12:58:38 +00:00
|
|
|
ARRAY_NEW_EX(new_collection, current);
|
|
|
|
ZEND_HASH_FOREACH_BUCKET(current, Bucket* bucket)
|
|
|
|
CALLBACK_KEYVAL_INVOKE(params, bucket);
|
|
|
|
zval* retval_p = &retval;
|
2018-04-22 14:47:30 +00:00
|
|
|
ELEMENTS_VALIDATE(retval_p, ERR_BAD_CALLBACK_RETVAL, continue);
|
2018-04-17 15:17:30 +00:00
|
|
|
ZEND_HASH_FOREACH_BUCKET(retval_p_arr, Bucket* bucket)
|
2018-09-06 03:33:41 +00:00
|
|
|
zval* result;
|
2018-09-03 12:07:08 +00:00
|
|
|
if (bucket->key) {
|
2018-09-06 03:33:41 +00:00
|
|
|
result = zend_hash_add(new_collection, bucket->key, &bucket->val);
|
2018-09-03 12:07:08 +00:00
|
|
|
} else {
|
2018-09-06 03:33:41 +00:00
|
|
|
result = zend_hash_next_index_insert(new_collection, &bucket->val);
|
|
|
|
}
|
|
|
|
if (result) {
|
|
|
|
Z_TRY_ADDREF(bucket->val);
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-04-16 12:58:38 +00:00
|
|
|
ZEND_HASH_FOREACH_END();
|
|
|
|
zval_ptr_dtor(&retval);
|
|
|
|
ZEND_HASH_FOREACH_END();
|
|
|
|
RETVAL_NEW_COLLECTION(new_collection);
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, flatMapTo)
|
|
|
|
{
|
2018-04-16 12:58:38 +00:00
|
|
|
zval* dest;
|
|
|
|
zend_fcall_info fci;
|
|
|
|
zend_fcall_info_cache fcc;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(2, 2)
|
|
|
|
Z_PARAM_OBJECT_OF_CLASS(dest, collections_collection_ce)
|
|
|
|
Z_PARAM_FUNC(fci, fcc)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-08-15 14:37:37 +00:00
|
|
|
INIT_FCI(&fci, 2);
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
|
|
|
zend_array* dest_arr = Z_COLLECTION_P(dest);
|
2018-04-18 04:03:27 +00:00
|
|
|
SEPARATE_COLLECTION(dest_arr, dest);
|
2018-04-16 12:58:38 +00:00
|
|
|
ZEND_HASH_FOREACH_BUCKET(current, Bucket* bucket)
|
|
|
|
CALLBACK_KEYVAL_INVOKE(params, bucket);
|
|
|
|
zval* retval_p = &retval;
|
2018-04-22 14:47:30 +00:00
|
|
|
ELEMENTS_VALIDATE(retval_p, ERR_BAD_CALLBACK_RETVAL, continue);
|
2018-04-17 15:17:30 +00:00
|
|
|
ZEND_HASH_FOREACH_BUCKET(retval_p_arr, Bucket* bucket)
|
2018-09-06 03:33:41 +00:00
|
|
|
zval* result;
|
2018-09-03 12:07:08 +00:00
|
|
|
if (bucket->key) {
|
2018-09-06 03:33:41 +00:00
|
|
|
result = zend_hash_add(dest_arr, bucket->key, &bucket->val);
|
2018-09-03 12:07:08 +00:00
|
|
|
} else {
|
2018-09-06 03:33:41 +00:00
|
|
|
result = zend_hash_next_index_insert(dest_arr, &bucket->val);
|
|
|
|
}
|
|
|
|
if (result) {
|
|
|
|
Z_TRY_ADDREF(bucket->val);
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-04-16 12:58:38 +00:00
|
|
|
ZEND_HASH_FOREACH_END();
|
|
|
|
zval_ptr_dtor(&retval);
|
|
|
|
ZEND_HASH_FOREACH_END();
|
|
|
|
RETVAL_ZVAL(dest, 1, 0);
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, flatten)
|
|
|
|
{
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-04-22 14:47:30 +00:00
|
|
|
ARRAY_NEW_EX(new_collection, current);
|
|
|
|
ZEND_HASH_FOREACH_BUCKET(current, Bucket* bucket)
|
|
|
|
zval* val = &bucket->val;
|
2018-09-03 12:07:08 +00:00
|
|
|
ELEMENTS_VALIDATE(val, ERR_SILENCED, {
|
|
|
|
if (bucket->key) {
|
2018-09-06 03:33:41 +00:00
|
|
|
val = zend_hash_add(new_collection, bucket->key, val);
|
2018-09-03 12:07:08 +00:00
|
|
|
} else {
|
2018-09-06 03:33:41 +00:00
|
|
|
val = zend_hash_next_index_insert(new_collection, val);
|
|
|
|
}
|
|
|
|
if (val) {
|
|
|
|
Z_TRY_ADDREF_P(val);
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-04-22 14:47:30 +00:00
|
|
|
continue;
|
|
|
|
});
|
|
|
|
ZEND_HASH_FOREACH_BUCKET(val_arr, Bucket* bucket)
|
2018-09-06 03:33:41 +00:00
|
|
|
zval* result;
|
2018-09-03 12:07:08 +00:00
|
|
|
if (bucket->key) {
|
2018-09-06 03:33:41 +00:00
|
|
|
result = zend_hash_add(new_collection, bucket->key, &bucket->val);
|
2018-09-03 12:07:08 +00:00
|
|
|
} else {
|
2018-09-06 03:33:41 +00:00
|
|
|
result = zend_hash_next_index_insert(new_collection, &bucket->val);
|
|
|
|
}
|
|
|
|
if (result) {
|
|
|
|
Z_TRY_ADDREF(bucket->val);
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-04-22 14:47:30 +00:00
|
|
|
ZEND_HASH_FOREACH_END();
|
|
|
|
ZEND_HASH_FOREACH_END();
|
|
|
|
RETVAL_NEW_COLLECTION(new_collection);
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, fold)
|
|
|
|
{
|
2018-08-11 18:26:46 +00:00
|
|
|
zval* initial;
|
|
|
|
zend_fcall_info fci;
|
|
|
|
zend_fcall_info_cache fcc;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(2, 2)
|
|
|
|
Z_PARAM_ZVAL(initial)
|
|
|
|
Z_PARAM_FUNC(fci, fcc)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-08-15 14:37:37 +00:00
|
|
|
INIT_FCI(&fci, 3);
|
2018-08-11 18:26:46 +00:00
|
|
|
ZVAL_COPY(¶ms[0], initial);
|
|
|
|
ZEND_HASH_FOREACH_BUCKET(current, Bucket* bucket)
|
|
|
|
ZVAL_COPY_VALUE(¶ms[1], &bucket->val);
|
2018-09-03 12:07:08 +00:00
|
|
|
if (bucket->key) {
|
2018-08-11 18:26:46 +00:00
|
|
|
ZVAL_STR(¶ms[2], bucket->key);
|
2018-09-03 12:07:08 +00:00
|
|
|
} else {
|
2018-08-11 18:26:46 +00:00
|
|
|
ZVAL_LONG(¶ms[2], bucket->h);
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-08-11 18:26:46 +00:00
|
|
|
zend_call_function(&fci, &fcc);
|
|
|
|
zval_ptr_dtor(¶ms[0]);
|
|
|
|
ZVAL_COPY_VALUE(¶ms[0], &retval);
|
|
|
|
ZEND_HASH_FOREACH_END();
|
|
|
|
RETVAL_ZVAL(&retval, 0, 0);
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, foldRight)
|
|
|
|
{
|
2018-08-11 18:26:46 +00:00
|
|
|
zval* initial;
|
|
|
|
zend_fcall_info fci;
|
|
|
|
zend_fcall_info_cache fcc;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(2, 2)
|
|
|
|
Z_PARAM_ZVAL(initial)
|
|
|
|
Z_PARAM_FUNC(fci, fcc)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-08-15 14:37:37 +00:00
|
|
|
INIT_FCI(&fci, 3);
|
2018-08-11 18:26:46 +00:00
|
|
|
ZVAL_COPY(¶ms[0], initial);
|
|
|
|
ZEND_HASH_REVERSE_FOREACH_BUCKET(current, Bucket* bucket)
|
|
|
|
ZVAL_COPY_VALUE(¶ms[1], &bucket->val);
|
2018-09-03 12:07:08 +00:00
|
|
|
if (bucket->key) {
|
2018-08-11 18:26:46 +00:00
|
|
|
ZVAL_STR(¶ms[2], bucket->key);
|
2018-09-03 12:07:08 +00:00
|
|
|
} else {
|
2018-08-11 18:26:46 +00:00
|
|
|
ZVAL_LONG(¶ms[2], bucket->h);
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-08-11 18:26:46 +00:00
|
|
|
zend_call_function(&fci, &fcc);
|
|
|
|
zval_ptr_dtor(¶ms[0]);
|
|
|
|
ZVAL_COPY_VALUE(¶ms[0], &retval);
|
|
|
|
ZEND_HASH_FOREACH_END();
|
|
|
|
RETVAL_ZVAL(&retval, 0, 0);
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, forEach)
|
|
|
|
{
|
2018-05-09 13:00:18 +00:00
|
|
|
zend_fcall_info fci;
|
|
|
|
zend_fcall_info_cache fcc;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
|
|
Z_PARAM_FUNC(fci, fcc)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-08-15 14:37:37 +00:00
|
|
|
INIT_FCI(&fci, 2);
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-05-09 13:00:18 +00:00
|
|
|
ZEND_HASH_FOREACH_BUCKET(current, Bucket* bucket)
|
|
|
|
CALLBACK_KEYVAL_INVOKE(params, bucket);
|
2018-08-11 18:26:46 +00:00
|
|
|
zval_ptr_dtor(&retval);
|
2018-05-09 13:00:18 +00:00
|
|
|
ZEND_HASH_FOREACH_END();
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, get)
|
|
|
|
{
|
2018-04-26 13:52:31 +00:00
|
|
|
zval* key;
|
|
|
|
zend_fcall_info fci;
|
|
|
|
zend_fcall_info_cache fcc;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 2)
|
|
|
|
Z_PARAM_ZVAL(key)
|
|
|
|
Z_PARAM_OPTIONAL
|
|
|
|
Z_PARAM_FUNC(fci, fcc)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-04-26 13:52:31 +00:00
|
|
|
zval* found = NULL;
|
2018-09-03 12:07:08 +00:00
|
|
|
if (Z_TYPE_P(key) == IS_STRING) {
|
2018-04-26 13:52:31 +00:00
|
|
|
found = zend_hash_find(current, Z_STR_P(key));
|
2018-09-03 12:07:08 +00:00
|
|
|
} else if (Z_TYPE_P(key) == IS_LONG) {
|
2018-04-26 13:52:31 +00:00
|
|
|
found = zend_hash_index_find(current, Z_LVAL_P(key));
|
2018-09-03 12:07:08 +00:00
|
|
|
} else {
|
2018-04-26 13:52:31 +00:00
|
|
|
ERR_BAD_KEY_TYPE();
|
2018-04-26 14:05:26 +00:00
|
|
|
RETURN_NULL();
|
2018-04-26 13:52:31 +00:00
|
|
|
}
|
2018-09-03 12:07:08 +00:00
|
|
|
if (found) {
|
2018-04-26 13:52:31 +00:00
|
|
|
RETURN_ZVAL(found, 1, 0);
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-09-03 12:07:08 +00:00
|
|
|
if (EX_NUM_ARGS() < 2) {
|
2018-04-26 13:52:31 +00:00
|
|
|
RETURN_NULL();
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-08-15 14:37:37 +00:00
|
|
|
INIT_FCI(&fci, 1);
|
2018-04-26 13:52:31 +00:00
|
|
|
ZVAL_COPY_VALUE(¶ms[0], key);
|
|
|
|
zend_call_function(&fci, &fcc);
|
2018-08-11 18:26:46 +00:00
|
|
|
RETVAL_ZVAL(&retval, 0, 0);
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, groupBy)
|
|
|
|
{
|
2018-09-02 13:16:05 +00:00
|
|
|
zend_fcall_info fci;
|
|
|
|
zend_fcall_info_cache fcc;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
|
|
Z_PARAM_FUNC(fci, fcc)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-09-02 13:16:05 +00:00
|
|
|
ARRAY_NEW(new_collection, 8);
|
|
|
|
zend_bool packed = HT_IS_PACKED(current);
|
|
|
|
INIT_FCI(&fci, 2);
|
|
|
|
ZEND_HASH_FOREACH_BUCKET(current, Bucket* bucket)
|
|
|
|
CALLBACK_KEYVAL_INVOKE(params, bucket);
|
|
|
|
zval* key;
|
|
|
|
zval* value;
|
2018-09-05 10:44:16 +00:00
|
|
|
if (EXPECTED(IS_PAIR(retval))) {
|
2018-09-02 13:16:05 +00:00
|
|
|
key = PAIR_FIRST(Z_OBJ(retval));
|
|
|
|
value = PAIR_SECOND(Z_OBJ(retval));
|
2018-09-03 12:07:08 +00:00
|
|
|
} else {
|
2018-09-02 13:16:05 +00:00
|
|
|
key = &retval;
|
|
|
|
value = &bucket->val;
|
|
|
|
}
|
|
|
|
zend_array* group = array_group_fetch(new_collection, key);
|
2018-09-03 12:07:08 +00:00
|
|
|
if (UNEXPECTED(group == NULL)) {
|
2018-09-02 13:16:05 +00:00
|
|
|
continue;
|
|
|
|
}
|
2018-09-05 16:00:15 +00:00
|
|
|
Z_TRY_ADDREF_P(value);
|
2018-09-03 12:07:08 +00:00
|
|
|
if (bucket->key) {
|
2018-09-06 03:33:41 +00:00
|
|
|
zend_hash_add_new(group, bucket->key, value);
|
2018-09-03 12:07:08 +00:00
|
|
|
} else if (packed) {
|
2018-09-02 13:16:05 +00:00
|
|
|
zend_hash_next_index_insert(group, value);
|
2018-09-03 12:07:08 +00:00
|
|
|
} else {
|
2018-09-06 03:33:41 +00:00
|
|
|
zend_hash_index_add_new(group, bucket->h, value);
|
2018-09-02 13:16:05 +00:00
|
|
|
}
|
|
|
|
zval_ptr_dtor(&retval);
|
|
|
|
ZEND_HASH_FOREACH_END();
|
|
|
|
RETVAL_NEW_COLLECTION(new_collection);
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, groupByTo)
|
|
|
|
{
|
2018-09-03 05:19:07 +00:00
|
|
|
zval* dest;
|
|
|
|
zend_fcall_info fci;
|
|
|
|
zend_fcall_info_cache fcc;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(2, 2)
|
|
|
|
Z_PARAM_OBJECT_OF_CLASS(dest, collections_collection_ce)
|
|
|
|
Z_PARAM_FUNC(fci, fcc)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
|
|
|
zend_array* dest_arr = Z_COLLECTION_P(dest);
|
2018-09-03 05:19:07 +00:00
|
|
|
SEPARATE_COLLECTION(dest_arr, dest);
|
|
|
|
zend_bool packed = HT_IS_PACKED(current);
|
|
|
|
INIT_FCI(&fci, 2);
|
|
|
|
ZEND_HASH_FOREACH_BUCKET(current, Bucket* bucket)
|
|
|
|
CALLBACK_KEYVAL_INVOKE(params, bucket);
|
|
|
|
zval* key;
|
|
|
|
zval* value;
|
2018-09-05 10:44:16 +00:00
|
|
|
if (EXPECTED(IS_PAIR(retval))) {
|
2018-09-03 05:19:07 +00:00
|
|
|
key = PAIR_FIRST(Z_OBJ(retval));
|
|
|
|
value = PAIR_SECOND(Z_OBJ(retval));
|
2018-09-03 12:07:08 +00:00
|
|
|
} else {
|
2018-09-03 05:19:07 +00:00
|
|
|
key = &retval;
|
|
|
|
value = &bucket->val;
|
|
|
|
}
|
|
|
|
zend_array* group = array_group_fetch(dest_arr, key);
|
2018-09-03 12:07:08 +00:00
|
|
|
if (UNEXPECTED(group == NULL)) {
|
2018-09-03 05:19:07 +00:00
|
|
|
continue;
|
|
|
|
}
|
2018-09-03 12:07:08 +00:00
|
|
|
if (bucket->key) {
|
2018-09-05 16:00:15 +00:00
|
|
|
value = zend_hash_add(group, bucket->key, value);
|
2018-09-03 12:07:08 +00:00
|
|
|
} else if (packed) {
|
2018-09-06 03:33:41 +00:00
|
|
|
value = zend_hash_next_index_insert(group, value);
|
2018-09-03 12:07:08 +00:00
|
|
|
} else {
|
2018-09-05 16:00:15 +00:00
|
|
|
value = zend_hash_index_add(group, bucket->h, value);
|
|
|
|
}
|
|
|
|
if (value) {
|
|
|
|
Z_TRY_ADDREF_P(value);
|
2018-09-03 05:19:07 +00:00
|
|
|
}
|
|
|
|
zval_ptr_dtor(&retval);
|
|
|
|
ZEND_HASH_FOREACH_END();
|
|
|
|
RETVAL_NEW_COLLECTION(dest_arr);
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, indexOf)
|
|
|
|
{
|
2018-07-14 16:11:02 +00:00
|
|
|
zval* element;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
|
|
Z_PARAM_ZVAL(element)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-08-20 14:47:23 +00:00
|
|
|
equal_check_func_t eql = equal_check_func_init(element);
|
2018-07-14 16:11:02 +00:00
|
|
|
ZEND_HASH_FOREACH_BUCKET(current, Bucket* bucket)
|
2018-09-03 12:07:08 +00:00
|
|
|
if (eql(element, &bucket->val)) {
|
|
|
|
if (bucket->key) {
|
2018-07-14 16:11:02 +00:00
|
|
|
RETURN_STR(bucket->key);
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-07-14 16:11:02 +00:00
|
|
|
RETURN_LONG(bucket->h);
|
|
|
|
}
|
|
|
|
ZEND_HASH_FOREACH_END();
|
|
|
|
RETVAL_NULL();
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, indexOfFirst)
|
|
|
|
{
|
2018-07-14 16:11:02 +00:00
|
|
|
zend_fcall_info fci;
|
|
|
|
zend_fcall_info_cache fcc;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
|
|
Z_PARAM_FUNC(fci, fcc)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-08-15 14:37:37 +00:00
|
|
|
INIT_FCI(&fci, 1);
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-07-14 16:11:02 +00:00
|
|
|
ZEND_HASH_FOREACH_BUCKET(current, Bucket* bucket)
|
|
|
|
ZVAL_COPY_VALUE(¶ms[0], &bucket->val);
|
|
|
|
zend_call_function(&fci, &fcc);
|
2018-09-03 12:07:08 +00:00
|
|
|
if (zend_is_true(&retval)) {
|
2018-08-11 18:26:46 +00:00
|
|
|
zval_ptr_dtor(&retval);
|
2018-09-03 12:07:08 +00:00
|
|
|
if (bucket->key) {
|
2018-07-14 16:11:02 +00:00
|
|
|
RETURN_STR(bucket->key);
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-07-14 16:11:02 +00:00
|
|
|
RETURN_LONG(bucket->h);
|
|
|
|
}
|
2018-08-11 18:26:46 +00:00
|
|
|
zval_ptr_dtor(&retval);
|
2018-07-14 16:11:02 +00:00
|
|
|
ZEND_HASH_FOREACH_END();
|
|
|
|
RETVAL_NULL();
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, indexOfLast)
|
|
|
|
{
|
2018-07-14 16:11:02 +00:00
|
|
|
zend_fcall_info fci;
|
|
|
|
zend_fcall_info_cache fcc;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
|
|
Z_PARAM_FUNC(fci, fcc)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-08-15 14:37:37 +00:00
|
|
|
INIT_FCI(&fci, 1);
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-07-14 16:11:02 +00:00
|
|
|
ZEND_HASH_REVERSE_FOREACH_BUCKET(current, Bucket* bucket)
|
|
|
|
ZVAL_COPY_VALUE(¶ms[0], &bucket->val);
|
|
|
|
zend_call_function(&fci, &fcc);
|
2018-09-03 12:07:08 +00:00
|
|
|
if (zend_is_true(&retval)) {
|
2018-08-11 18:26:46 +00:00
|
|
|
zval_ptr_dtor(&retval);
|
2018-09-03 12:07:08 +00:00
|
|
|
if (bucket->key) {
|
2018-07-14 16:11:02 +00:00
|
|
|
RETURN_STR(bucket->key);
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-07-14 16:11:02 +00:00
|
|
|
RETURN_LONG(bucket->h);
|
|
|
|
}
|
2018-08-11 18:26:46 +00:00
|
|
|
zval_ptr_dtor(&retval);
|
2018-07-14 16:11:02 +00:00
|
|
|
ZEND_HASH_FOREACH_END();
|
|
|
|
RETVAL_NULL();
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, init)
|
|
|
|
{
|
|
|
|
zval* elements = NULL;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(0, 1)
|
|
|
|
Z_PARAM_OPTIONAL
|
|
|
|
Z_PARAM_ZVAL(elements)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-09-03 12:07:08 +00:00
|
|
|
if (EXPECTED(elements)) {
|
2018-04-22 14:47:30 +00:00
|
|
|
ELEMENTS_VALIDATE(elements, ERR_BAD_ARGUMENT_TYPE, return);
|
2018-04-17 15:17:30 +00:00
|
|
|
RETURN_NEW_COLLECTION(elements_arr);
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
2018-03-30 14:20:58 +00:00
|
|
|
ARRAY_NEW(collection, 0);
|
|
|
|
RETVAL_NEW_COLLECTION(collection);
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, intersect)
|
|
|
|
{
|
2018-09-03 11:34:58 +00:00
|
|
|
zval* elements;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
|
|
Z_PARAM_ZVAL(elements)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
|
|
ELEMENTS_VALIDATE(elements, ERR_BAD_ARGUMENT_TYPE, return);
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-09-03 11:34:58 +00:00
|
|
|
ARRAY_NEW(intersected, 8);
|
|
|
|
equal_check_func_t eql = NULL;
|
2018-09-03 13:54:14 +00:00
|
|
|
ZEND_HASH_FOREACH_BUCKET(current, Bucket* bucket)
|
2018-09-03 12:07:08 +00:00
|
|
|
if (UNEXPECTED(eql == NULL)) {
|
2018-09-03 11:34:58 +00:00
|
|
|
eql = equal_check_func_init(&bucket->val);
|
|
|
|
}
|
2018-09-03 12:07:08 +00:00
|
|
|
if (bucket->key) {
|
2018-09-03 13:54:14 +00:00
|
|
|
zval* result = zend_hash_find(elements_arr, bucket->key);
|
2018-09-03 12:07:08 +00:00
|
|
|
if (result && eql(&bucket->val, result)) {
|
2018-09-03 11:34:58 +00:00
|
|
|
Z_TRY_ADDREF_P(result);
|
2018-09-06 03:33:41 +00:00
|
|
|
zend_hash_add_new(intersected, bucket->key, result);
|
2018-09-03 11:34:58 +00:00
|
|
|
}
|
2018-09-03 12:07:08 +00:00
|
|
|
} else {
|
2018-09-03 13:54:14 +00:00
|
|
|
zval* result = zend_hash_index_find(elements_arr, bucket->h);
|
2018-09-03 12:07:08 +00:00
|
|
|
if (result && eql(&bucket->val, result)) {
|
2018-09-03 11:34:58 +00:00
|
|
|
Z_TRY_ADDREF_P(result);
|
2018-09-06 03:33:41 +00:00
|
|
|
zend_hash_index_add_new(intersected, bucket->h, result);
|
2018-09-03 11:34:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
ZEND_HASH_FOREACH_END();
|
|
|
|
RETVAL_NEW_COLLECTION(intersected);
|
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, intersectKeys)
|
|
|
|
{
|
|
|
|
zval* elements;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
|
|
Z_PARAM_ZVAL(elements)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
|
|
ELEMENTS_VALIDATE(elements, ERR_BAD_ARGUMENT_TYPE, return);
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-09-03 11:34:58 +00:00
|
|
|
ARRAY_NEW(intersected, 8);
|
|
|
|
ZEND_HASH_FOREACH_BUCKET(current, Bucket* bucket)
|
2018-09-03 12:07:08 +00:00
|
|
|
if (bucket->key) {
|
|
|
|
if (zend_hash_exists(elements_arr, bucket->key)) {
|
2018-09-03 11:34:58 +00:00
|
|
|
Z_TRY_ADDREF(bucket->val);
|
2018-09-06 03:33:41 +00:00
|
|
|
zend_hash_add_new(intersected, bucket->key, &bucket->val);
|
2018-09-03 11:34:58 +00:00
|
|
|
}
|
2018-09-03 12:07:08 +00:00
|
|
|
} else {
|
|
|
|
if (zend_hash_index_exists(elements_arr, bucket->h)) {
|
2018-09-03 11:34:58 +00:00
|
|
|
Z_TRY_ADDREF(bucket->val);
|
2018-09-06 03:33:41 +00:00
|
|
|
zend_hash_index_add_new(intersected, bucket->h, &bucket->val);
|
2018-09-03 11:34:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
ZEND_HASH_FOREACH_END();
|
|
|
|
RETVAL_NEW_COLLECTION(intersected);
|
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, intersectValues)
|
|
|
|
{
|
2018-09-07 19:43:00 +00:00
|
|
|
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 = THIS_COLLECTION;
|
|
|
|
ARRAY_CLONE(intersected, current);
|
|
|
|
array_slice_by(intersected, elements_arr, REMOVE_DUPLICATE | ELEMENT_INTERSECT);
|
|
|
|
RETVAL_NEW_COLLECTION(intersected);
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, isEmpty)
|
|
|
|
{
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-04-26 13:52:31 +00:00
|
|
|
RETVAL_BOOL(zend_hash_num_elements(current) == 0);
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
2018-09-05 10:44:16 +00:00
|
|
|
PHP_METHOD(Collection, isPacked)
|
2018-03-23 09:06:05 +00:00
|
|
|
{
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-09-05 10:44:16 +00:00
|
|
|
RETVAL_BOOL(HT_IS_PACKED(current));
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, keys)
|
|
|
|
{
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-04-24 09:22:43 +00:00
|
|
|
ARRAY_NEW_EX(new_collection, current);
|
|
|
|
ZEND_HASH_FOREACH_BUCKET(current, Bucket* bucket)
|
|
|
|
zval val;
|
2018-09-03 12:07:08 +00:00
|
|
|
if (bucket->key) {
|
2018-09-05 16:00:15 +00:00
|
|
|
GC_ADDREF(bucket->key);
|
2018-04-24 09:22:43 +00:00
|
|
|
ZVAL_STR(&val, bucket->key);
|
2018-09-03 12:07:08 +00:00
|
|
|
} else {
|
2018-04-24 09:22:43 +00:00
|
|
|
ZVAL_LONG(&val, bucket->h);
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-04-24 09:22:43 +00:00
|
|
|
zend_hash_next_index_insert(new_collection, &val);
|
|
|
|
ZEND_HASH_FOREACH_END();
|
|
|
|
RETVAL_NEW_COLLECTION(new_collection);
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, last)
|
|
|
|
{
|
2018-04-15 03:22:10 +00:00
|
|
|
zend_fcall_info fci;
|
|
|
|
zend_fcall_info_cache fcc;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(0, 1)
|
|
|
|
Z_PARAM_OPTIONAL
|
|
|
|
Z_PARAM_FUNC(fci, fcc)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-09-03 12:07:08 +00:00
|
|
|
if (zend_hash_num_elements(current) == 0) {
|
2018-04-15 03:22:10 +00:00
|
|
|
RETURN_NULL();
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-09-03 12:07:08 +00:00
|
|
|
if (EX_NUM_ARGS() == 0) {
|
2018-08-28 13:24:26 +00:00
|
|
|
uint32_t pos = current->nNumUsed;
|
2018-09-03 12:07:08 +00:00
|
|
|
while (pos <= current->nNumUsed && Z_ISUNDEF(current->arData[pos].val)) {
|
2018-04-18 04:03:27 +00:00
|
|
|
--pos;
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-04-18 04:03:27 +00:00
|
|
|
RETURN_ZVAL(¤t->arData[pos].val, 1, 0);
|
2018-04-15 03:22:10 +00:00
|
|
|
}
|
2018-08-15 14:37:37 +00:00
|
|
|
INIT_FCI(&fci, 2);
|
2018-04-15 03:22:10 +00:00
|
|
|
ZEND_HASH_REVERSE_FOREACH_BUCKET(current, Bucket* bucket)
|
|
|
|
CALLBACK_KEYVAL_INVOKE(params, bucket);
|
2018-09-03 12:07:08 +00:00
|
|
|
if (zend_is_true(&retval)) {
|
2018-08-11 18:26:46 +00:00
|
|
|
zval_ptr_dtor(&retval);
|
2018-04-15 03:22:10 +00:00
|
|
|
RETURN_ZVAL(&bucket->val, 1, 0);
|
2018-08-11 18:26:46 +00:00
|
|
|
}
|
|
|
|
zval_ptr_dtor(&retval);
|
2018-04-15 03:22:10 +00:00
|
|
|
ZEND_HASH_FOREACH_END();
|
|
|
|
RETVAL_NULL();
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
2018-07-14 16:11:02 +00:00
|
|
|
PHP_METHOD(Collection, lastIndexOf)
|
|
|
|
{
|
|
|
|
zval* element;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
|
|
Z_PARAM_ZVAL(element)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-08-20 14:47:23 +00:00
|
|
|
equal_check_func_t eql = equal_check_func_init(element);
|
2018-07-14 16:11:02 +00:00
|
|
|
ZEND_HASH_REVERSE_FOREACH_BUCKET(current, Bucket* bucket)
|
2018-09-03 12:07:08 +00:00
|
|
|
if (eql(element, &bucket->val)) {
|
|
|
|
if (bucket->key) {
|
2018-07-14 16:11:02 +00:00
|
|
|
RETURN_STR(bucket->key);
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-07-14 16:11:02 +00:00
|
|
|
RETURN_LONG(bucket->h);
|
|
|
|
}
|
|
|
|
ZEND_HASH_FOREACH_END();
|
|
|
|
RETVAL_NULL();
|
|
|
|
}
|
|
|
|
|
2018-03-23 09:06:05 +00:00
|
|
|
PHP_METHOD(Collection, map)
|
|
|
|
{
|
2018-07-23 17:24:00 +00:00
|
|
|
zend_fcall_info fci;
|
|
|
|
zend_fcall_info_cache fcc;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
|
|
Z_PARAM_FUNC(fci, fcc)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-08-15 14:37:37 +00:00
|
|
|
INIT_FCI(&fci, 2);
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-07-23 17:24:00 +00:00
|
|
|
ARRAY_NEW_EX(new_collection, current);
|
|
|
|
ZEND_HASH_FOREACH_BUCKET(current, Bucket* bucket)
|
|
|
|
CALLBACK_KEYVAL_INVOKE(params, bucket);
|
|
|
|
zend_hash_next_index_insert(new_collection, &retval);
|
|
|
|
ZEND_HASH_FOREACH_END();
|
|
|
|
RETVAL_NEW_COLLECTION(new_collection);
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, mapTo)
|
|
|
|
{
|
2018-07-23 17:24:00 +00:00
|
|
|
zend_fcall_info fci;
|
|
|
|
zend_fcall_info_cache fcc;
|
|
|
|
zval* dest;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(2, 2)
|
|
|
|
Z_PARAM_OBJECT_OF_CLASS(dest, collections_collection_ce)
|
|
|
|
Z_PARAM_FUNC(fci, fcc)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-08-15 14:37:37 +00:00
|
|
|
INIT_FCI(&fci, 2);
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
|
|
|
zend_array* dest_arr = Z_COLLECTION_P(dest);
|
2018-07-23 17:24:00 +00:00
|
|
|
SEPARATE_COLLECTION(dest_arr, dest);
|
|
|
|
ZEND_HASH_FOREACH_BUCKET(current, Bucket* bucket)
|
|
|
|
CALLBACK_KEYVAL_INVOKE(params, bucket);
|
|
|
|
zend_hash_next_index_insert(dest_arr, &retval);
|
|
|
|
ZEND_HASH_FOREACH_END();
|
|
|
|
RETVAL_ZVAL(dest, 1, 0);
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, max)
|
|
|
|
{
|
2018-08-20 14:47:23 +00:00
|
|
|
zend_long flags = 0;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(0, 1)
|
|
|
|
Z_PARAM_OPTIONAL
|
|
|
|
Z_PARAM_LONG(flags)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-08-20 14:47:23 +00:00
|
|
|
compare_func_t cmp;
|
|
|
|
ZEND_HASH_FOREACH_VAL(current, zval* val)
|
|
|
|
cmp = compare_func_init(val, 0, flags);
|
|
|
|
break;
|
|
|
|
ZEND_HASH_FOREACH_END();
|
|
|
|
zval* max = zend_hash_minmax(current, cmp, 1);
|
2018-09-06 01:29:38 +00:00
|
|
|
if (EXPECTED(max)) {
|
|
|
|
RETURN_ZVAL(max, 1, 0);
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-04-24 09:22:43 +00:00
|
|
|
RETVAL_NULL();
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, maxBy)
|
|
|
|
{
|
2018-05-01 09:35:19 +00:00
|
|
|
zend_fcall_info fci;
|
|
|
|
zend_fcall_info_cache fcc;
|
2018-08-20 14:47:23 +00:00
|
|
|
zend_long flags = 0;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 2)
|
2018-05-01 09:35:19 +00:00
|
|
|
Z_PARAM_FUNC(fci, fcc)
|
2018-08-20 14:47:23 +00:00
|
|
|
Z_PARAM_OPTIONAL
|
|
|
|
Z_PARAM_LONG(flags)
|
2018-05-01 09:35:19 +00:00
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-05-01 09:35:19 +00:00
|
|
|
ARRAY_NEW_EX(max_by, current);
|
2018-08-20 14:47:23 +00:00
|
|
|
compare_func_t cmp = NULL;
|
2018-08-15 14:37:37 +00:00
|
|
|
INIT_FCI(&fci, 2);
|
2018-05-01 09:35:19 +00:00
|
|
|
ZEND_HASH_FOREACH_BUCKET(current, Bucket* bucket)
|
|
|
|
CALLBACK_KEYVAL_INVOKE(params, bucket);
|
2018-09-03 12:07:08 +00:00
|
|
|
if (UNEXPECTED(cmp == NULL)) {
|
2018-08-20 14:47:23 +00:00
|
|
|
cmp = compare_func_init(&retval, 0, flags);
|
|
|
|
}
|
2018-05-01 09:35:19 +00:00
|
|
|
zend_hash_index_add(max_by, bucket - current->arData, &retval);
|
|
|
|
ZEND_HASH_FOREACH_END();
|
2018-08-20 14:47:23 +00:00
|
|
|
zval* max = zend_hash_minmax(max_by, cmp, 1);
|
2018-09-06 01:29:38 +00:00
|
|
|
if (EXPECTED(max)) {
|
2018-05-01 09:35:19 +00:00
|
|
|
zend_ulong offset = *(zend_ulong*)(max + 1);
|
|
|
|
zval* ret = &(current->arData + offset)->val;
|
|
|
|
RETVAL_ZVAL(ret, 1, 0);
|
2018-09-03 12:07:08 +00:00
|
|
|
} else {
|
2018-05-01 09:35:19 +00:00
|
|
|
RETVAL_NULL();
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-05-01 09:35:19 +00:00
|
|
|
zend_hash_destroy(max_by);
|
|
|
|
efree(max_by);
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, maxWith)
|
|
|
|
{
|
2018-08-15 14:37:37 +00:00
|
|
|
zend_fcall_info fci;
|
|
|
|
zend_fcall_info_cache fcc;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
|
|
Z_PARAM_FUNC(fci, fcc)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-08-15 14:37:37 +00:00
|
|
|
FCI_G = &fci;
|
|
|
|
FCC_G = &fcc;
|
2018-08-26 12:23:22 +00:00
|
|
|
ARRAY_CLONE(max_with, current);
|
2018-08-15 14:37:37 +00:00
|
|
|
ZEND_HASH_FOREACH_BUCKET(max_with, Bucket* bucket)
|
2018-08-30 17:04:46 +00:00
|
|
|
zend_object* obj = create_pair_obj();
|
2018-08-20 14:47:23 +00:00
|
|
|
bucket_to_pair(obj, bucket);
|
2018-08-15 14:37:37 +00:00
|
|
|
ZVAL_OBJ(&bucket->val, obj);
|
|
|
|
ZEND_HASH_FOREACH_END();
|
2018-09-06 01:29:38 +00:00
|
|
|
zval* result = zend_hash_minmax(max_with, bucket_compare_userland, 1);
|
|
|
|
if (EXPECTED(result)) {
|
|
|
|
RETVAL_ZVAL(PAIR_SECOND(Z_OBJ_P(result)), 1, 0);
|
|
|
|
} else {
|
|
|
|
RETVAL_NULL();
|
2018-08-15 14:37:37 +00:00
|
|
|
}
|
2018-09-06 01:29:38 +00:00
|
|
|
zend_array_destroy(max_with);
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, min)
|
|
|
|
{
|
2018-08-20 14:47:23 +00:00
|
|
|
zend_long flags = 0;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(0, 1)
|
|
|
|
Z_PARAM_OPTIONAL
|
|
|
|
Z_PARAM_LONG(flags)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-08-20 14:47:23 +00:00
|
|
|
compare_func_t cmp;
|
|
|
|
ZEND_HASH_FOREACH_VAL(current, zval* val)
|
|
|
|
cmp = compare_func_init(val, 0, flags);
|
|
|
|
break;
|
|
|
|
ZEND_HASH_FOREACH_END();
|
|
|
|
zval* min = zend_hash_minmax(current, cmp, 0);
|
2018-09-06 01:29:38 +00:00
|
|
|
if (EXPECTED(min)) {
|
|
|
|
RETURN_ZVAL(min, 1, 0);
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-04-24 09:22:43 +00:00
|
|
|
RETVAL_NULL();
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, minBy)
|
|
|
|
{
|
2018-05-01 09:35:19 +00:00
|
|
|
zend_fcall_info fci;
|
|
|
|
zend_fcall_info_cache fcc;
|
2018-08-20 14:47:23 +00:00
|
|
|
zend_long flags = 0;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 2)
|
2018-05-01 09:35:19 +00:00
|
|
|
Z_PARAM_FUNC(fci, fcc)
|
2018-08-20 14:47:23 +00:00
|
|
|
Z_PARAM_OPTIONAL
|
|
|
|
Z_PARAM_LONG(flags)
|
2018-05-01 09:35:19 +00:00
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-05-01 09:35:19 +00:00
|
|
|
ARRAY_NEW_EX(min_by, current);
|
2018-08-20 14:47:23 +00:00
|
|
|
compare_func_t cmp = NULL;
|
2018-08-15 14:37:37 +00:00
|
|
|
INIT_FCI(&fci, 2);
|
2018-05-01 09:35:19 +00:00
|
|
|
ZEND_HASH_FOREACH_BUCKET(current, Bucket* bucket)
|
|
|
|
CALLBACK_KEYVAL_INVOKE(params, bucket);
|
2018-09-03 12:07:08 +00:00
|
|
|
if (UNEXPECTED(cmp == NULL)) {
|
2018-08-20 14:47:23 +00:00
|
|
|
cmp = compare_func_init(&retval, 0, flags);
|
|
|
|
}
|
2018-05-01 09:35:19 +00:00
|
|
|
zend_hash_index_add(min_by, bucket - current->arData, &retval);
|
|
|
|
ZEND_HASH_FOREACH_END();
|
2018-08-20 14:47:23 +00:00
|
|
|
zval* min = zend_hash_minmax(min_by, cmp, 0);
|
2018-09-06 01:29:38 +00:00
|
|
|
if (EXPECTED(min)) {
|
2018-05-01 09:35:19 +00:00
|
|
|
zend_ulong offset = *(zend_ulong*)(min + 1);
|
|
|
|
zval* ret = &(current->arData + offset)->val;
|
|
|
|
RETVAL_ZVAL(ret, 1, 0);
|
2018-09-03 12:07:08 +00:00
|
|
|
} else {
|
2018-05-01 09:35:19 +00:00
|
|
|
RETVAL_NULL();
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-05-01 09:35:19 +00:00
|
|
|
zend_hash_destroy(min_by);
|
|
|
|
efree(min_by);
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, minWith)
|
|
|
|
{
|
2018-08-15 14:37:37 +00:00
|
|
|
zend_fcall_info fci;
|
|
|
|
zend_fcall_info_cache fcc;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
|
|
Z_PARAM_FUNC(fci, fcc)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-08-15 14:37:37 +00:00
|
|
|
FCI_G = &fci;
|
|
|
|
FCC_G = &fcc;
|
2018-08-26 12:23:22 +00:00
|
|
|
ARRAY_CLONE(min_with, current);
|
2018-08-15 14:37:37 +00:00
|
|
|
ZEND_HASH_FOREACH_BUCKET(min_with, Bucket* bucket)
|
2018-08-30 17:04:46 +00:00
|
|
|
zend_object* obj = create_pair_obj();
|
2018-08-20 14:47:23 +00:00
|
|
|
bucket_to_pair(obj, bucket);
|
2018-08-15 14:37:37 +00:00
|
|
|
ZVAL_OBJ(&bucket->val, obj);
|
|
|
|
ZEND_HASH_FOREACH_END();
|
2018-09-06 01:29:38 +00:00
|
|
|
zval* result = zend_hash_minmax(min_with, bucket_compare_userland, 0);
|
|
|
|
if (EXPECTED(result)) {
|
|
|
|
RETVAL_ZVAL(PAIR_SECOND(Z_OBJ_P(result)), 1, 0);
|
|
|
|
} else {
|
|
|
|
RETVAL_NULL();
|
2018-08-15 14:37:37 +00:00
|
|
|
}
|
2018-09-06 01:29:38 +00:00
|
|
|
zend_array_destroy(min_with);
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, minus)
|
|
|
|
{
|
2018-09-05 10:44:16 +00:00
|
|
|
zval* elements;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
|
|
Z_PARAM_ZVAL(elements)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
|
|
ELEMENTS_VALIDATE(elements, ERR_BAD_ARGUMENT_TYPE, return);
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-09-05 10:44:16 +00:00
|
|
|
ARRAY_NEW(new_collection, 8);
|
|
|
|
ZEND_HASH_FOREACH_BUCKET(current, Bucket* bucket)
|
|
|
|
zval* result;
|
|
|
|
if (bucket->key) {
|
|
|
|
result = zend_hash_find(elements_arr, bucket->key);
|
|
|
|
} else {
|
|
|
|
result = zend_hash_index_find(elements_arr, bucket->h);
|
|
|
|
}
|
|
|
|
if (result && fast_equal_check_function(result, &bucket->val)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
Z_TRY_ADDREF(bucket->val);
|
|
|
|
if (bucket->key) {
|
2018-09-06 03:33:41 +00:00
|
|
|
zend_hash_add_new(new_collection, bucket->key, &bucket->val);
|
2018-09-05 10:44:16 +00:00
|
|
|
} else {
|
2018-09-06 03:33:41 +00:00
|
|
|
zend_hash_index_add_new(new_collection, bucket->h, &bucket->val);
|
2018-09-05 10:44:16 +00:00
|
|
|
}
|
|
|
|
ZEND_HASH_FOREACH_END();
|
|
|
|
RETVAL_NEW_COLLECTION(new_collection);
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, none)
|
|
|
|
{
|
2018-04-24 09:22:43 +00:00
|
|
|
zend_fcall_info fci;
|
|
|
|
zend_fcall_info_cache fcc;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
|
|
Z_PARAM_FUNC(fci, fcc)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-08-15 14:37:37 +00:00
|
|
|
INIT_FCI(&fci, 2);
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-04-24 09:22:43 +00:00
|
|
|
ZEND_HASH_FOREACH_BUCKET(current, Bucket* bucket)
|
|
|
|
CALLBACK_KEYVAL_INVOKE(params, bucket);
|
2018-09-03 12:07:08 +00:00
|
|
|
if (zend_is_true(&retval)) {
|
2018-08-11 18:26:46 +00:00
|
|
|
zval_ptr_dtor(&retval);
|
2018-04-24 09:22:43 +00:00
|
|
|
RETURN_FALSE;
|
2018-08-11 18:26:46 +00:00
|
|
|
}
|
|
|
|
zval_ptr_dtor(&retval);
|
2018-04-24 09:22:43 +00:00
|
|
|
ZEND_HASH_FOREACH_END();
|
|
|
|
RETURN_TRUE;
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, onEach)
|
|
|
|
{
|
2018-05-09 13:00:18 +00:00
|
|
|
zend_fcall_info fci;
|
|
|
|
zend_fcall_info_cache fcc;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
|
|
Z_PARAM_FUNC(fci, fcc)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-08-15 14:37:37 +00:00
|
|
|
INIT_FCI(&fci, 2);
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-05-09 13:00:18 +00:00
|
|
|
ZEND_HASH_FOREACH_BUCKET(current, Bucket* bucket)
|
|
|
|
CALLBACK_KEYVAL_INVOKE(params, bucket);
|
2018-08-11 18:26:46 +00:00
|
|
|
zval_ptr_dtor(&retval);
|
2018-05-09 13:00:18 +00:00
|
|
|
ZEND_HASH_FOREACH_END();
|
|
|
|
RETVAL_ZVAL(getThis(), 1, 0);
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, partition)
|
|
|
|
{
|
2018-05-12 14:10:59 +00:00
|
|
|
zend_fcall_info fci;
|
|
|
|
zend_fcall_info_cache fcc;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
|
|
Z_PARAM_FUNC(fci, fcc)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-08-15 14:37:37 +00:00
|
|
|
INIT_FCI(&fci, 2);
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-08-30 17:04:46 +00:00
|
|
|
zend_object* pair = create_pair_obj();
|
2018-09-02 13:46:01 +00:00
|
|
|
ARRAY_NEW(first_arr, 8);
|
|
|
|
ARRAY_NEW(second_arr, 8);
|
2018-09-02 13:16:05 +00:00
|
|
|
zend_bool packed = HT_IS_PACKED(current);
|
2018-05-12 14:10:59 +00:00
|
|
|
ZEND_HASH_FOREACH_BUCKET(current, Bucket* bucket)
|
|
|
|
CALLBACK_KEYVAL_INVOKE(params, bucket);
|
|
|
|
zend_array* which = zend_is_true(&retval) ? first_arr : second_arr;
|
2018-05-26 11:02:32 +00:00
|
|
|
Z_TRY_ADDREF(bucket->val);
|
2018-09-03 12:07:08 +00:00
|
|
|
if (bucket->key) {
|
2018-09-06 03:33:41 +00:00
|
|
|
zend_hash_add_new(which, bucket->key, &bucket->val);
|
2018-09-03 12:07:08 +00:00
|
|
|
} else if (packed) {
|
2018-05-26 11:02:32 +00:00
|
|
|
zend_hash_next_index_insert(which, &bucket->val);
|
2018-09-03 12:07:08 +00:00
|
|
|
} else {
|
2018-09-06 03:33:41 +00:00
|
|
|
zend_hash_index_add_new(which, bucket->h, &bucket->val);
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-08-11 18:26:46 +00:00
|
|
|
zval_ptr_dtor(&retval);
|
2018-05-12 14:10:59 +00:00
|
|
|
ZEND_HASH_FOREACH_END();
|
|
|
|
zval first, second;
|
|
|
|
ZVAL_ARR(&first, first_arr);
|
|
|
|
ZVAL_ARR(&second, second_arr);
|
2018-08-30 17:04:46 +00:00
|
|
|
pair_update_first(pair, &first);
|
|
|
|
pair_update_second(pair, &second);
|
2018-05-12 14:10:59 +00:00
|
|
|
RETVAL_OBJ(pair);
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, plus)
|
|
|
|
{
|
2018-09-04 14:11:12 +00:00
|
|
|
zval* elements;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
|
|
Z_PARAM_ZVAL(elements)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
|
|
ELEMENTS_VALIDATE(elements, ERR_BAD_ARGUMENT_TYPE, return);
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-09-04 14:11:12 +00:00
|
|
|
ARRAY_CLONE(new_collection, current);
|
|
|
|
zend_bool packed = HT_IS_PACKED(current) && HT_IS_PACKED(elements_arr);
|
|
|
|
ZEND_HASH_FOREACH_BUCKET(elements_arr, Bucket* bucket)
|
|
|
|
Z_TRY_ADDREF(bucket->val);
|
|
|
|
if (bucket->key) {
|
|
|
|
zend_hash_update(new_collection, bucket->key, &bucket->val);
|
|
|
|
} else if (packed) {
|
|
|
|
zend_hash_next_index_insert(new_collection, &bucket->val);
|
|
|
|
} else {
|
|
|
|
zend_hash_index_update(new_collection, bucket->h, &bucket->val);
|
|
|
|
}
|
|
|
|
ZEND_HASH_FOREACH_END();
|
|
|
|
RETVAL_NEW_COLLECTION(new_collection);
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, putAll)
|
|
|
|
{
|
2018-07-29 17:53:05 +00:00
|
|
|
zval* elements;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
|
|
Z_PARAM_ZVAL(elements)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
|
|
ELEMENTS_VALIDATE(elements, ERR_BAD_ARGUMENT_TYPE, return);
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-07-29 17:53:05 +00:00
|
|
|
SEPARATE_CURRENT_COLLECTION(current);
|
2018-09-04 14:11:12 +00:00
|
|
|
zend_bool packed = HT_IS_PACKED(current) && HT_IS_PACKED(elements_arr);
|
2018-07-29 17:53:05 +00:00
|
|
|
ZEND_HASH_FOREACH_BUCKET(elements_arr, Bucket* bucket)
|
|
|
|
Z_TRY_ADDREF(bucket->val);
|
2018-09-03 12:07:08 +00:00
|
|
|
if (bucket->key) {
|
2018-07-29 17:53:05 +00:00
|
|
|
zend_hash_update(current, bucket->key, &bucket->val);
|
2018-09-03 12:07:08 +00:00
|
|
|
} else if (packed) {
|
2018-07-29 17:53:05 +00:00
|
|
|
zend_hash_next_index_insert(current, &bucket->val);
|
2018-09-03 12:07:08 +00:00
|
|
|
} else {
|
2018-07-29 17:53:05 +00:00
|
|
|
zend_hash_index_update(current, bucket->h, &bucket->val);
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-07-29 17:53:05 +00:00
|
|
|
ZEND_HASH_FOREACH_END();
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, reduce)
|
|
|
|
{
|
2018-08-07 16:43:09 +00:00
|
|
|
zend_fcall_info fci;
|
|
|
|
zend_fcall_info_cache fcc;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
|
|
Z_PARAM_FUNC(fci, fcc)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-09-03 12:07:08 +00:00
|
|
|
if (zend_hash_num_elements(current) == 0) {
|
2018-08-07 16:43:09 +00:00
|
|
|
ERR_BAD_SIZE();
|
|
|
|
RETURN_NULL();
|
|
|
|
}
|
2018-08-15 14:37:37 +00:00
|
|
|
INIT_FCI(&fci, 3);
|
2018-08-07 16:43:09 +00:00
|
|
|
Bucket* bucket = current->arData;
|
|
|
|
Bucket* end = bucket + current->nNumUsed;
|
2018-09-03 12:07:08 +00:00
|
|
|
for (; bucket < end; ++bucket) {
|
|
|
|
if (Z_ISUNDEF(bucket->val)) {
|
2018-08-07 16:43:09 +00:00
|
|
|
continue;
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-08-07 17:34:09 +00:00
|
|
|
ZVAL_COPY(&retval, &(bucket++)->val);
|
2018-08-07 16:43:09 +00:00
|
|
|
break;
|
|
|
|
}
|
2018-09-03 12:07:08 +00:00
|
|
|
for (; bucket < end; ++bucket) {
|
|
|
|
if (Z_ISUNDEF(bucket->val)) {
|
2018-08-07 16:43:09 +00:00
|
|
|
continue;
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-08-07 17:34:09 +00:00
|
|
|
ZVAL_COPY_VALUE(¶ms[0], &retval);
|
2018-08-07 16:43:09 +00:00
|
|
|
ZVAL_COPY_VALUE(¶ms[1], &bucket->val);
|
2018-09-03 12:07:08 +00:00
|
|
|
if (bucket->key) {
|
2018-08-07 16:43:09 +00:00
|
|
|
ZVAL_STR(¶ms[2], bucket->key);
|
2018-09-03 12:07:08 +00:00
|
|
|
} else {
|
2018-08-07 16:43:09 +00:00
|
|
|
ZVAL_LONG(¶ms[2], bucket->h);
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-08-07 16:43:09 +00:00
|
|
|
zend_call_function(&fci, &fcc);
|
2018-08-07 17:34:09 +00:00
|
|
|
zval_ptr_dtor(¶ms[0]);
|
2018-08-07 16:43:09 +00:00
|
|
|
}
|
|
|
|
RETVAL_ZVAL(&retval, 0, 0);
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, reduceRight)
|
|
|
|
{
|
2018-08-07 16:43:09 +00:00
|
|
|
zend_fcall_info fci;
|
|
|
|
zend_fcall_info_cache fcc;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
|
|
Z_PARAM_FUNC(fci, fcc)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-09-03 12:07:08 +00:00
|
|
|
if (zend_hash_num_elements(current) == 0) {
|
2018-08-07 16:43:09 +00:00
|
|
|
ERR_BAD_SIZE();
|
|
|
|
RETURN_NULL();
|
|
|
|
}
|
2018-08-15 14:37:37 +00:00
|
|
|
INIT_FCI(&fci, 3);
|
2018-08-07 16:43:09 +00:00
|
|
|
Bucket* start = current->arData;
|
|
|
|
Bucket* bucket = start + current->nNumUsed - 1;
|
2018-09-03 12:07:08 +00:00
|
|
|
for (; bucket >= start; --bucket) {
|
|
|
|
if (Z_ISUNDEF(bucket->val)) {
|
2018-08-07 16:43:09 +00:00
|
|
|
continue;
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-08-07 17:34:09 +00:00
|
|
|
ZVAL_COPY(&retval, &(bucket--)->val);
|
2018-08-07 16:43:09 +00:00
|
|
|
break;
|
|
|
|
}
|
2018-09-03 12:07:08 +00:00
|
|
|
for (; bucket >= start; --bucket) {
|
|
|
|
if (Z_ISUNDEF(bucket->val)) {
|
2018-08-07 16:43:09 +00:00
|
|
|
continue;
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-08-07 17:34:09 +00:00
|
|
|
ZVAL_COPY_VALUE(¶ms[0], &retval);
|
2018-08-07 16:43:09 +00:00
|
|
|
ZVAL_COPY_VALUE(¶ms[1], &bucket->val);
|
2018-09-03 12:07:08 +00:00
|
|
|
if (bucket->key) {
|
2018-08-07 16:43:09 +00:00
|
|
|
ZVAL_STR(¶ms[2], bucket->key);
|
2018-09-03 12:07:08 +00:00
|
|
|
} else {
|
2018-08-07 16:43:09 +00:00
|
|
|
ZVAL_LONG(¶ms[2], bucket->h);
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-08-07 16:43:09 +00:00
|
|
|
zend_call_function(&fci, &fcc);
|
2018-08-07 17:34:09 +00:00
|
|
|
zval_ptr_dtor(¶ms[0]);
|
2018-08-07 16:43:09 +00:00
|
|
|
}
|
|
|
|
RETVAL_ZVAL(&retval, 0, 0);
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, remove)
|
|
|
|
{
|
2018-05-05 10:29:14 +00:00
|
|
|
zval* key;
|
|
|
|
zval* value = NULL;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 2)
|
|
|
|
Z_PARAM_ZVAL(key)
|
|
|
|
Z_PARAM_OPTIONAL
|
|
|
|
Z_PARAM_ZVAL(value)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-05-05 10:29:14 +00:00
|
|
|
zval* found;
|
2018-09-03 12:07:08 +00:00
|
|
|
if (Z_TYPE_P(key) == IS_LONG) {
|
|
|
|
if (value == NULL) {
|
2018-05-05 10:29:14 +00:00
|
|
|
RETURN_BOOL(zend_hash_index_del(current, Z_LVAL_P(key)) == SUCCESS);
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-05-05 10:29:14 +00:00
|
|
|
found = zend_hash_index_find(current, Z_LVAL_P(key));
|
2018-09-03 12:07:08 +00:00
|
|
|
if (found == NULL || fast_equal_check_function(found, value) == 0) {
|
2018-05-05 10:29:14 +00:00
|
|
|
RETURN_FALSE;
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-05-05 10:29:14 +00:00
|
|
|
RETURN_BOOL(zend_hash_index_del(current, Z_LVAL_P(key)) == SUCCESS);
|
|
|
|
}
|
2018-09-03 12:07:08 +00:00
|
|
|
if (Z_TYPE_P(key) == IS_STRING) {
|
|
|
|
if (value == NULL) {
|
2018-05-05 10:29:14 +00:00
|
|
|
RETURN_BOOL(zend_hash_del(current, Z_STR_P(key)) == SUCCESS);
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-05-05 10:29:14 +00:00
|
|
|
found = zend_hash_find(current, Z_STR_P(key));
|
2018-09-03 12:07:08 +00:00
|
|
|
if (found == NULL || fast_equal_check_function(found, value) == 0) {
|
2018-05-05 10:29:14 +00:00
|
|
|
RETURN_FALSE;
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-05-05 10:29:14 +00:00
|
|
|
RETURN_BOOL(zend_hash_del(current, Z_STR_P(key)) == SUCCESS);
|
|
|
|
}
|
|
|
|
ERR_BAD_KEY_TYPE();
|
|
|
|
RETVAL_FALSE;
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, removeAll)
|
2018-09-04 12:52:40 +00:00
|
|
|
{
|
2018-09-07 19:43:00 +00:00
|
|
|
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 = THIS_COLLECTION;
|
|
|
|
SEPARATE_CURRENT_COLLECTION(current);
|
|
|
|
array_slice_by(current, elements_arr, RETAIN_DUPLICATE | ELEMENT_SUBTRACT);
|
2018-09-04 12:52:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, removeWhile)
|
2018-03-23 09:06:05 +00:00
|
|
|
{
|
2018-05-05 10:29:14 +00:00
|
|
|
zend_fcall_info fci;
|
|
|
|
zend_fcall_info_cache fcc;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(0, 1)
|
|
|
|
Z_PARAM_OPTIONAL
|
|
|
|
Z_PARAM_FUNC(fci, fcc)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-05-05 10:29:14 +00:00
|
|
|
SEPARATE_CURRENT_COLLECTION(current);
|
2018-08-15 14:37:37 +00:00
|
|
|
INIT_FCI(&fci, 2);
|
2018-05-05 10:29:14 +00:00
|
|
|
ZEND_HASH_FOREACH_BUCKET(current, Bucket* bucket)
|
|
|
|
CALLBACK_KEYVAL_INVOKE(params, bucket);
|
2018-09-03 12:07:08 +00:00
|
|
|
if (zend_is_true(&retval)) {
|
2018-05-05 10:29:14 +00:00
|
|
|
zend_hash_del_bucket(current, bucket);
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-08-11 18:26:46 +00:00
|
|
|
zval_ptr_dtor(&retval);
|
2018-05-05 10:29:14 +00:00
|
|
|
ZEND_HASH_FOREACH_END();
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, retainAll)
|
|
|
|
{
|
2018-09-07 19:43:00 +00:00
|
|
|
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 = THIS_COLLECTION;
|
|
|
|
SEPARATE_CURRENT_COLLECTION(current);
|
|
|
|
array_slice_by(current, elements_arr, RETAIN_DUPLICATE | ELEMENT_INTERSECT);
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
2018-09-07 08:00:08 +00:00
|
|
|
PHP_METHOD(Collection, retainWhile)
|
|
|
|
{
|
|
|
|
zend_fcall_info fci;
|
|
|
|
zend_fcall_info_cache fcc;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(0, 1)
|
|
|
|
Z_PARAM_OPTIONAL
|
|
|
|
Z_PARAM_FUNC(fci, fcc)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-09-07 08:00:08 +00:00
|
|
|
SEPARATE_CURRENT_COLLECTION(current);
|
|
|
|
INIT_FCI(&fci, 2);
|
|
|
|
ZEND_HASH_FOREACH_BUCKET(current, Bucket* bucket)
|
|
|
|
CALLBACK_KEYVAL_INVOKE(params, bucket);
|
|
|
|
if (!zend_is_true(&retval)) {
|
|
|
|
zend_hash_del_bucket(current, bucket);
|
|
|
|
}
|
|
|
|
zval_ptr_dtor(&retval);
|
|
|
|
ZEND_HASH_FOREACH_END();
|
|
|
|
}
|
|
|
|
|
2018-03-23 09:06:05 +00:00
|
|
|
PHP_METHOD(Collection, reverse)
|
|
|
|
{
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-05-14 08:20:07 +00:00
|
|
|
ARRAY_NEW_EX(reversed, current);
|
2018-09-02 13:16:05 +00:00
|
|
|
zend_bool packed = HT_IS_PACKED(current);
|
2018-05-14 08:20:07 +00:00
|
|
|
ZEND_HASH_REVERSE_FOREACH_BUCKET(current, Bucket* bucket)
|
2018-05-26 11:02:32 +00:00
|
|
|
Z_TRY_ADDREF(bucket->val);
|
2018-09-03 12:07:08 +00:00
|
|
|
if (bucket->key) {
|
2018-05-14 08:20:07 +00:00
|
|
|
zend_hash_add(reversed, bucket->key, &bucket->val);
|
2018-09-03 12:07:08 +00:00
|
|
|
} else if (packed) {
|
2018-05-14 08:20:07 +00:00
|
|
|
zend_hash_next_index_insert(reversed, &bucket->val);
|
2018-09-03 12:07:08 +00:00
|
|
|
} else {
|
2018-08-07 16:43:09 +00:00
|
|
|
zend_hash_index_add(reversed, bucket->h, &bucket->val);
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-05-14 08:20:07 +00:00
|
|
|
ZEND_HASH_FOREACH_END();
|
2018-09-12 05:50:26 +00:00
|
|
|
array_release(current);
|
2018-09-07 15:42:36 +00:00
|
|
|
THIS_COLLECTION = reversed;
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, reversed)
|
|
|
|
{
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-05-14 08:20:07 +00:00
|
|
|
ARRAY_NEW_EX(reversed, current);
|
2018-09-02 13:16:05 +00:00
|
|
|
zend_bool packed = HT_IS_PACKED(current);
|
2018-05-14 08:20:07 +00:00
|
|
|
ZEND_HASH_REVERSE_FOREACH_BUCKET(current, Bucket* bucket)
|
2018-05-26 11:02:32 +00:00
|
|
|
Z_TRY_ADDREF(bucket->val);
|
2018-09-03 12:07:08 +00:00
|
|
|
if (bucket->key) {
|
2018-05-14 08:20:07 +00:00
|
|
|
zend_hash_add(reversed, bucket->key, &bucket->val);
|
2018-09-03 12:07:08 +00:00
|
|
|
} else if (packed) {
|
2018-05-14 08:20:07 +00:00
|
|
|
zend_hash_next_index_insert(reversed, &bucket->val);
|
2018-09-03 12:07:08 +00:00
|
|
|
} else {
|
2018-08-07 16:43:09 +00:00
|
|
|
zend_hash_index_add(reversed, bucket->h, &bucket->val);
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-05-14 08:20:07 +00:00
|
|
|
ZEND_HASH_FOREACH_END();
|
|
|
|
RETVAL_NEW_COLLECTION(reversed);
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, shuffle)
|
|
|
|
{
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-08-13 11:35:34 +00:00
|
|
|
uint32_t num_elements = zend_hash_num_elements(current);
|
|
|
|
ARRAY_NEW(shuffled, num_elements);
|
|
|
|
ZEND_HASH_FOREACH_VAL(current, zval* val)
|
2018-09-05 16:00:15 +00:00
|
|
|
Z_TRY_ADDREF_P(val);
|
2018-08-13 11:35:34 +00:00
|
|
|
zend_hash_next_index_insert(shuffled, val);
|
|
|
|
ZEND_HASH_FOREACH_END();
|
|
|
|
size_t offset = 0;
|
|
|
|
Bucket* bucket = shuffled->arData;
|
2018-09-03 12:07:08 +00:00
|
|
|
for (; offset < num_elements - 1; ++offset) {
|
2018-08-13 11:35:34 +00:00
|
|
|
zend_long rand_idx = php_mt_rand_range(offset, num_elements - 1);
|
|
|
|
zend_hash_bucket_renum_swap(&bucket[offset], &bucket[rand_idx]);
|
|
|
|
}
|
2018-09-12 05:50:26 +00:00
|
|
|
array_release(current);
|
2018-09-07 15:42:36 +00:00
|
|
|
THIS_COLLECTION = shuffled;
|
2018-08-13 11:35:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, shuffled)
|
|
|
|
{
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-08-13 11:35:34 +00:00
|
|
|
uint32_t num_elements = zend_hash_num_elements(current);
|
|
|
|
ARRAY_NEW(shuffled, num_elements);
|
|
|
|
ZEND_HASH_FOREACH_VAL(current, zval* val)
|
2018-09-05 16:00:15 +00:00
|
|
|
Z_TRY_ADDREF_P(val);
|
2018-08-13 11:35:34 +00:00
|
|
|
zend_hash_next_index_insert(shuffled, val);
|
|
|
|
ZEND_HASH_FOREACH_END();
|
|
|
|
size_t offset = 0;
|
|
|
|
Bucket* bucket = shuffled->arData;
|
2018-09-03 12:07:08 +00:00
|
|
|
for (; offset < num_elements - 1; ++offset) {
|
2018-08-13 11:35:34 +00:00
|
|
|
zend_long rand_idx = php_mt_rand_range(offset, num_elements - 1);
|
|
|
|
zend_hash_bucket_renum_swap(&bucket[offset], &bucket[rand_idx]);
|
|
|
|
}
|
|
|
|
RETVAL_NEW_COLLECTION(shuffled);
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
2018-04-26 13:52:31 +00:00
|
|
|
PHP_METHOD(Collection, set)
|
|
|
|
{
|
|
|
|
zval* key;
|
|
|
|
zval* value;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(2, 2)
|
|
|
|
Z_PARAM_ZVAL(key)
|
|
|
|
Z_PARAM_ZVAL(value)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-09-03 12:07:08 +00:00
|
|
|
if (Z_TYPE_P(key) == IS_STRING) {
|
2018-05-05 10:29:14 +00:00
|
|
|
SEPARATE_CURRENT_COLLECTION(current);
|
2018-09-06 03:46:53 +00:00
|
|
|
Z_TRY_ADDREF_P(value);
|
2018-04-26 13:52:31 +00:00
|
|
|
zend_hash_update(current, Z_STR_P(key), value);
|
2018-09-03 12:07:08 +00:00
|
|
|
} else if (Z_TYPE_P(key) == IS_LONG) {
|
2018-05-05 10:29:14 +00:00
|
|
|
SEPARATE_CURRENT_COLLECTION(current);
|
2018-09-06 03:46:53 +00:00
|
|
|
Z_TRY_ADDREF_P(value);
|
2018-04-26 13:52:31 +00:00
|
|
|
zend_hash_index_update(current, Z_LVAL_P(key), value);
|
2018-09-03 12:07:08 +00:00
|
|
|
} else {
|
2018-04-26 13:52:31 +00:00
|
|
|
ERR_BAD_KEY_TYPE();
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-04-26 13:52:31 +00:00
|
|
|
}
|
|
|
|
|
2018-03-23 09:06:05 +00:00
|
|
|
PHP_METHOD(Collection, single)
|
|
|
|
{
|
2018-04-26 13:52:31 +00:00
|
|
|
zend_fcall_info fci;
|
|
|
|
zend_fcall_info_cache fcc;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
|
|
Z_PARAM_FUNC(fci, fcc)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-08-15 14:37:37 +00:00
|
|
|
INIT_FCI(&fci, 2);
|
2018-04-26 13:52:31 +00:00
|
|
|
zval single;
|
|
|
|
ZVAL_UNDEF(&single);
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-04-26 13:52:31 +00:00
|
|
|
ZEND_HASH_FOREACH_BUCKET(current, Bucket* bucket)
|
|
|
|
CALLBACK_KEYVAL_INVOKE(params, bucket);
|
2018-09-03 12:07:08 +00:00
|
|
|
if (zend_is_true(&retval)) {
|
|
|
|
if (Z_TYPE(single) == IS_UNDEF) {
|
2018-04-26 13:52:31 +00:00
|
|
|
ZVAL_COPY_VALUE(&single, &bucket->val);
|
2018-09-03 12:07:08 +00:00
|
|
|
} else {
|
2018-04-26 13:52:31 +00:00
|
|
|
RETURN_NULL();
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-04-26 13:52:31 +00:00
|
|
|
}
|
2018-08-11 18:26:46 +00:00
|
|
|
zval_ptr_dtor(&retval);
|
2018-04-26 13:52:31 +00:00
|
|
|
ZEND_HASH_FOREACH_END();
|
2018-09-03 12:07:08 +00:00
|
|
|
if (Z_TYPE(single) == IS_UNDEF) {
|
2018-08-13 13:03:38 +00:00
|
|
|
RETURN_NULL();
|
|
|
|
}
|
2018-04-26 13:52:31 +00:00
|
|
|
RETVAL_ZVAL(&single, 1, 0);
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, slice)
|
|
|
|
{
|
2018-07-22 16:23:46 +00:00
|
|
|
zval* elements;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
|
|
Z_PARAM_ZVAL(elements)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
|
|
ELEMENTS_VALIDATE(elements, ERR_BAD_ARGUMENT_TYPE, return);
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-09-02 13:46:01 +00:00
|
|
|
ARRAY_NEW_EX(sliced, elements_arr);
|
2018-07-22 16:23:46 +00:00
|
|
|
ZEND_HASH_FOREACH_VAL(elements_arr, zval* val)
|
2018-09-03 12:07:08 +00:00
|
|
|
if (Z_TYPE_P(val) == IS_LONG) {
|
2018-07-22 16:23:46 +00:00
|
|
|
zval* found = zend_hash_index_find(current, Z_LVAL_P(val));
|
2018-09-03 12:07:08 +00:00
|
|
|
if (found) {
|
2018-07-22 16:23:46 +00:00
|
|
|
Z_TRY_ADDREF_P(found);
|
|
|
|
zend_hash_next_index_insert(sliced, found);
|
|
|
|
}
|
2018-09-03 12:07:08 +00:00
|
|
|
} else if (Z_TYPE_P(val) == IS_STRING) {
|
2018-07-22 16:23:46 +00:00
|
|
|
zval* found = zend_hash_find(current, Z_STR_P(val));
|
2018-09-03 12:07:08 +00:00
|
|
|
if (found) {
|
2018-07-22 16:23:46 +00:00
|
|
|
Z_TRY_ADDREF_P(found);
|
|
|
|
zend_hash_add(sliced, Z_STR_P(val), found);
|
|
|
|
}
|
2018-09-03 12:07:08 +00:00
|
|
|
} else {
|
2018-09-02 13:46:01 +00:00
|
|
|
ERR_BAD_KEY_TYPE();
|
|
|
|
}
|
2018-07-22 16:23:46 +00:00
|
|
|
ZEND_HASH_FOREACH_END();
|
|
|
|
RETVAL_NEW_COLLECTION(sliced);
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, sort)
|
|
|
|
{
|
2018-08-23 12:16:44 +00:00
|
|
|
zend_long flags = 0;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(0, 1)
|
|
|
|
Z_PARAM_OPTIONAL
|
|
|
|
Z_PARAM_LONG(flags)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-08-23 12:16:44 +00:00
|
|
|
SEPARATE_CURRENT_COLLECTION(current);
|
|
|
|
compare_func_t cmp;
|
|
|
|
ZEND_HASH_FOREACH_VAL(current, zval* val)
|
|
|
|
cmp = compare_func_init(val, 0, flags);
|
|
|
|
break;
|
|
|
|
ZEND_HASH_FOREACH_END();
|
|
|
|
zend_hash_sort(current, cmp, 1);
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, sortBy)
|
|
|
|
{
|
2018-08-26 12:23:22 +00:00
|
|
|
zend_fcall_info fci;
|
|
|
|
zend_fcall_info_cache fcc;
|
|
|
|
zend_long flags = 0;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 2)
|
|
|
|
Z_PARAM_FUNC(fci, fcc)
|
|
|
|
Z_PARAM_OPTIONAL
|
|
|
|
Z_PARAM_LONG(flags)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-08-26 12:23:22 +00:00
|
|
|
SEPARATE_CURRENT_COLLECTION(current);
|
|
|
|
uint32_t num_elements = zend_hash_num_elements(current);
|
|
|
|
zval* sort_by = (zval*)malloc(num_elements * sizeof(zval));
|
|
|
|
INIT_FCI(&fci, 2);
|
|
|
|
compare_func_t cmp = NULL;
|
2018-08-28 13:24:26 +00:00
|
|
|
uint32_t idx = 0;
|
2018-08-26 12:23:22 +00:00
|
|
|
ZEND_HASH_FOREACH_BUCKET(current, Bucket* bucket)
|
|
|
|
CALLBACK_KEYVAL_INVOKE(params, bucket);
|
2018-09-03 12:07:08 +00:00
|
|
|
if (UNEXPECTED(cmp == NULL)) {
|
2018-08-26 12:23:22 +00:00
|
|
|
cmp = compare_func_init(&retval, 0, flags);
|
|
|
|
}
|
2018-09-03 12:07:08 +00:00
|
|
|
if (bucket->key) {
|
2018-08-26 12:23:22 +00:00
|
|
|
zend_string_release(bucket->key);
|
|
|
|
bucket->key = NULL;
|
|
|
|
}
|
|
|
|
bucket->h = idx;
|
|
|
|
ZVAL_COPY_VALUE(&sort_by[idx++], &retval);
|
|
|
|
ZEND_HASH_FOREACH_END();
|
2018-09-07 15:42:36 +00:00
|
|
|
REF_G = sort_by;
|
|
|
|
CMP_G = cmp;
|
2018-09-07 19:43:00 +00:00
|
|
|
array_sort_by(current);
|
2018-09-03 12:07:08 +00:00
|
|
|
for (idx = 0; idx < num_elements; ++idx) {
|
2018-08-26 12:23:22 +00:00
|
|
|
zval_ptr_dtor(&sort_by[idx]);
|
|
|
|
}
|
|
|
|
free(sort_by);
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, sortByDescending)
|
|
|
|
{
|
2018-08-26 12:23:22 +00:00
|
|
|
zend_fcall_info fci;
|
|
|
|
zend_fcall_info_cache fcc;
|
|
|
|
zend_long flags = 0;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 2)
|
|
|
|
Z_PARAM_FUNC(fci, fcc)
|
|
|
|
Z_PARAM_OPTIONAL
|
|
|
|
Z_PARAM_LONG(flags)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-08-26 12:23:22 +00:00
|
|
|
SEPARATE_CURRENT_COLLECTION(current);
|
|
|
|
uint32_t num_elements = zend_hash_num_elements(current);
|
|
|
|
zval* sort_by = (zval*)malloc(num_elements * sizeof(zval));
|
|
|
|
INIT_FCI(&fci, 2);
|
|
|
|
compare_func_t cmp = NULL;
|
2018-08-28 13:24:26 +00:00
|
|
|
uint32_t idx = 0;
|
2018-08-26 12:23:22 +00:00
|
|
|
ZEND_HASH_FOREACH_BUCKET(current, Bucket* bucket)
|
|
|
|
CALLBACK_KEYVAL_INVOKE(params, bucket);
|
2018-09-03 12:07:08 +00:00
|
|
|
if (UNEXPECTED(cmp == NULL)) {
|
2018-08-26 12:23:22 +00:00
|
|
|
cmp = compare_func_init(&retval, 1, flags);
|
|
|
|
}
|
2018-09-03 12:07:08 +00:00
|
|
|
if (bucket->key) {
|
2018-08-26 12:23:22 +00:00
|
|
|
zend_string_release(bucket->key);
|
|
|
|
bucket->key = NULL;
|
|
|
|
}
|
|
|
|
bucket->h = idx;
|
|
|
|
ZVAL_COPY_VALUE(&sort_by[idx++], &retval);
|
|
|
|
ZEND_HASH_FOREACH_END();
|
2018-09-07 15:42:36 +00:00
|
|
|
REF_G = sort_by;
|
|
|
|
CMP_G = cmp;
|
2018-09-07 19:43:00 +00:00
|
|
|
array_sort_by(current);
|
2018-09-03 12:07:08 +00:00
|
|
|
for (idx = 0; idx < num_elements; ++idx) {
|
2018-08-26 12:23:22 +00:00
|
|
|
zval_ptr_dtor(&sort_by[idx]);
|
|
|
|
}
|
|
|
|
free(sort_by);
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, sortDescending)
|
|
|
|
{
|
2018-08-23 12:16:44 +00:00
|
|
|
zend_long flags = 0;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(0, 1)
|
|
|
|
Z_PARAM_OPTIONAL
|
|
|
|
Z_PARAM_LONG(flags)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-08-23 12:16:44 +00:00
|
|
|
SEPARATE_CURRENT_COLLECTION(current);
|
|
|
|
compare_func_t cmp;
|
|
|
|
ZEND_HASH_FOREACH_VAL(current, zval* val)
|
|
|
|
cmp = compare_func_init(val, 1, flags);
|
|
|
|
break;
|
|
|
|
ZEND_HASH_FOREACH_END();
|
|
|
|
zend_hash_sort(current, cmp, 1);
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, sortWith)
|
|
|
|
{
|
2018-08-18 06:54:26 +00:00
|
|
|
zend_fcall_info fci;
|
|
|
|
zend_fcall_info_cache fcc;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
|
|
Z_PARAM_FUNC(fci, fcc)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
|
|
FCI_G = &fci;
|
|
|
|
FCC_G = &fcc;
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-08-26 12:23:22 +00:00
|
|
|
ARRAY_CLONE(sorted_with, current);
|
2018-08-18 06:54:26 +00:00
|
|
|
ZEND_HASH_FOREACH_BUCKET(sorted_with, Bucket* bucket)
|
2018-08-30 17:04:46 +00:00
|
|
|
zend_object* obj = create_pair_obj();
|
2018-08-20 14:47:23 +00:00
|
|
|
bucket_to_pair(obj, bucket);
|
2018-08-18 06:54:26 +00:00
|
|
|
ZVAL_OBJ(&bucket->val, obj);
|
|
|
|
ZEND_HASH_FOREACH_END();
|
|
|
|
zend_hash_sort(sorted_with, bucket_compare_userland, 1);
|
|
|
|
ZEND_HASH_FOREACH_VAL(sorted_with, zval* val)
|
|
|
|
zend_object* pair = Z_OBJ_P(val);
|
2018-09-02 13:16:05 +00:00
|
|
|
ZVAL_COPY_VALUE(val, PAIR_SECOND(pair));
|
2018-08-18 06:54:26 +00:00
|
|
|
GC_DELREF(pair);
|
|
|
|
ZEND_HASH_FOREACH_END();
|
2018-09-12 05:50:26 +00:00
|
|
|
array_release(current);
|
2018-09-07 15:42:36 +00:00
|
|
|
THIS_COLLECTION = sorted_with;
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, sorted)
|
|
|
|
{
|
2018-08-23 12:16:44 +00:00
|
|
|
zend_long flags = 0;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(0, 1)
|
|
|
|
Z_PARAM_OPTIONAL
|
|
|
|
Z_PARAM_LONG(flags)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-08-23 12:16:44 +00:00
|
|
|
ARRAY_CLONE(sorted, current);
|
|
|
|
compare_func_t cmp;
|
|
|
|
ZEND_HASH_FOREACH_VAL(sorted, zval* val)
|
|
|
|
cmp = compare_func_init(val, 0, flags);
|
|
|
|
break;
|
|
|
|
ZEND_HASH_FOREACH_END();
|
|
|
|
zend_hash_sort(sorted, cmp, 1);
|
|
|
|
RETVAL_NEW_COLLECTION(sorted);
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, sortedBy)
|
|
|
|
{
|
2018-08-26 12:23:22 +00:00
|
|
|
zend_fcall_info fci;
|
|
|
|
zend_fcall_info_cache fcc;
|
|
|
|
zend_long flags = 0;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 2)
|
|
|
|
Z_PARAM_FUNC(fci, fcc)
|
|
|
|
Z_PARAM_OPTIONAL
|
|
|
|
Z_PARAM_LONG(flags)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-08-26 12:23:22 +00:00
|
|
|
ARRAY_CLONE(sorted, current);
|
|
|
|
uint32_t num_elements = zend_hash_num_elements(current);
|
|
|
|
zval* sort_by = (zval*)malloc(num_elements * sizeof(zval));
|
|
|
|
INIT_FCI(&fci, 2);
|
|
|
|
compare_func_t cmp = NULL;
|
2018-08-28 13:24:26 +00:00
|
|
|
uint32_t idx = 0;
|
2018-08-26 12:23:22 +00:00
|
|
|
ZEND_HASH_FOREACH_BUCKET(sorted, Bucket* bucket)
|
|
|
|
CALLBACK_KEYVAL_INVOKE(params, bucket);
|
2018-09-03 12:07:08 +00:00
|
|
|
if (UNEXPECTED(cmp == NULL)) {
|
2018-08-26 12:23:22 +00:00
|
|
|
cmp = compare_func_init(&retval, 0, flags);
|
|
|
|
}
|
2018-09-03 12:07:08 +00:00
|
|
|
if (bucket->key) {
|
2018-08-26 12:23:22 +00:00
|
|
|
zend_string_release(bucket->key);
|
|
|
|
bucket->key = NULL;
|
|
|
|
}
|
|
|
|
bucket->h = idx;
|
|
|
|
ZVAL_COPY_VALUE(&sort_by[idx++], &retval);
|
|
|
|
ZEND_HASH_FOREACH_END();
|
2018-09-07 15:42:36 +00:00
|
|
|
REF_G = sort_by;
|
|
|
|
CMP_G = cmp;
|
2018-09-07 19:43:00 +00:00
|
|
|
array_sort_by(sorted);
|
2018-09-03 12:07:08 +00:00
|
|
|
for (idx = 0; idx < num_elements; ++idx) {
|
2018-08-26 12:23:22 +00:00
|
|
|
zval_ptr_dtor(&sort_by[idx]);
|
|
|
|
}
|
|
|
|
free(sort_by);
|
|
|
|
RETVAL_NEW_COLLECTION(sorted);
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, sortedByDescending)
|
|
|
|
{
|
2018-08-26 12:23:22 +00:00
|
|
|
zend_fcall_info fci;
|
|
|
|
zend_fcall_info_cache fcc;
|
|
|
|
zend_long flags = 0;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 2)
|
|
|
|
Z_PARAM_FUNC(fci, fcc)
|
|
|
|
Z_PARAM_OPTIONAL
|
|
|
|
Z_PARAM_LONG(flags)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-08-26 12:23:22 +00:00
|
|
|
ARRAY_CLONE(sorted, current);
|
|
|
|
uint32_t num_elements = zend_hash_num_elements(current);
|
|
|
|
zval* sort_by = (zval*)malloc(num_elements * sizeof(zval));
|
|
|
|
INIT_FCI(&fci, 2);
|
|
|
|
compare_func_t cmp = NULL;
|
2018-08-28 13:24:26 +00:00
|
|
|
uint32_t idx = 0;
|
2018-08-26 12:23:22 +00:00
|
|
|
ZEND_HASH_FOREACH_BUCKET(sorted, Bucket* bucket)
|
|
|
|
CALLBACK_KEYVAL_INVOKE(params, bucket);
|
2018-09-03 12:07:08 +00:00
|
|
|
if (UNEXPECTED(cmp == NULL)) {
|
2018-08-26 12:23:22 +00:00
|
|
|
cmp = compare_func_init(&retval, 1, flags);
|
|
|
|
}
|
2018-09-03 12:07:08 +00:00
|
|
|
if (bucket->key) {
|
2018-08-26 12:23:22 +00:00
|
|
|
zend_string_release(bucket->key);
|
|
|
|
bucket->key = NULL;
|
|
|
|
}
|
|
|
|
bucket->h = idx;
|
|
|
|
ZVAL_COPY_VALUE(&sort_by[idx++], &retval);
|
|
|
|
ZEND_HASH_FOREACH_END();
|
2018-09-07 15:42:36 +00:00
|
|
|
REF_G = sort_by;
|
|
|
|
CMP_G = cmp;
|
2018-09-07 19:43:00 +00:00
|
|
|
array_sort_by(sorted);
|
2018-09-03 12:07:08 +00:00
|
|
|
for (idx = 0; idx < num_elements; ++idx) {
|
2018-08-26 12:23:22 +00:00
|
|
|
zval_ptr_dtor(&sort_by[idx]);
|
|
|
|
}
|
|
|
|
free(sort_by);
|
|
|
|
RETVAL_NEW_COLLECTION(sorted);
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, sortedDescending)
|
|
|
|
{
|
2018-08-23 12:16:44 +00:00
|
|
|
zend_long flags = 0;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(0, 1)
|
|
|
|
Z_PARAM_OPTIONAL
|
|
|
|
Z_PARAM_LONG(flags)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-08-23 12:16:44 +00:00
|
|
|
ARRAY_CLONE(sorted, current);
|
|
|
|
compare_func_t cmp;
|
|
|
|
ZEND_HASH_FOREACH_VAL(sorted, zval* val)
|
|
|
|
cmp = compare_func_init(val, 1, flags);
|
|
|
|
break;
|
|
|
|
ZEND_HASH_FOREACH_END();
|
|
|
|
zend_hash_sort(sorted, cmp, 1);
|
|
|
|
RETVAL_NEW_COLLECTION(sorted);
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, sortedWith)
|
|
|
|
{
|
2018-08-18 06:54:26 +00:00
|
|
|
zend_fcall_info fci;
|
|
|
|
zend_fcall_info_cache fcc;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
|
|
Z_PARAM_FUNC(fci, fcc)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
|
|
FCI_G = &fci;
|
|
|
|
FCC_G = &fcc;
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-08-26 12:23:22 +00:00
|
|
|
ARRAY_CLONE(sorted_with, current);
|
2018-08-18 06:54:26 +00:00
|
|
|
ZEND_HASH_FOREACH_BUCKET(sorted_with, Bucket* bucket)
|
2018-08-30 17:04:46 +00:00
|
|
|
zend_object* obj = create_pair_obj();
|
2018-08-20 14:47:23 +00:00
|
|
|
bucket_to_pair(obj, bucket);
|
2018-08-18 06:54:26 +00:00
|
|
|
ZVAL_OBJ(&bucket->val, obj);
|
|
|
|
ZEND_HASH_FOREACH_END();
|
|
|
|
zend_hash_sort(sorted_with, bucket_compare_userland, 1);
|
|
|
|
ZEND_HASH_FOREACH_VAL(sorted_with, zval* val)
|
|
|
|
zend_object* pair = Z_OBJ_P(val);
|
2018-09-02 13:16:05 +00:00
|
|
|
ZVAL_COPY_VALUE(val, PAIR_SECOND(pair));
|
2018-08-18 06:54:26 +00:00
|
|
|
GC_DELREF(pair);
|
|
|
|
ZEND_HASH_FOREACH_END();
|
|
|
|
RETVAL_NEW_COLLECTION(sorted_with);
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
2018-09-07 15:42:36 +00:00
|
|
|
PHP_METHOD(Collection, subtract)
|
|
|
|
{
|
2018-09-07 19:43:00 +00:00
|
|
|
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 = THIS_COLLECTION;
|
|
|
|
ARRAY_CLONE(subtracted, current);
|
|
|
|
array_slice_by(subtracted, elements_arr, REMOVE_DUPLICATE | ELEMENT_SUBTRACT);
|
|
|
|
RETVAL_NEW_COLLECTION(subtracted);
|
2018-09-07 15:42:36 +00:00
|
|
|
}
|
|
|
|
|
2018-09-06 02:30:18 +00:00
|
|
|
PHP_METHOD(Collection, sum)
|
|
|
|
{
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-09-06 02:30:18 +00:00
|
|
|
zval sum;
|
|
|
|
ZVAL_NULL(&sum);
|
|
|
|
ZEND_HASH_FOREACH_VAL(current, zval* val)
|
|
|
|
if (UNEXPECTED(ZVAL_IS_NULL(&sum))) {
|
|
|
|
if (Z_TYPE_P(val) == IS_LONG) {
|
|
|
|
ZVAL_LONG(&sum, 0);
|
|
|
|
} else if (EXPECTED(Z_TYPE_P(val) == IS_DOUBLE)) {
|
|
|
|
ZVAL_DOUBLE(&sum, 0.0);
|
|
|
|
} else {
|
|
|
|
ERR_NOT_NUMERIC();
|
2018-09-07 08:00:08 +00:00
|
|
|
RETURN_NULL();
|
2018-09-06 02:30:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (Z_TYPE_P(val) == IS_LONG) {
|
|
|
|
Z_LVAL(sum) += Z_LVAL_P(val);
|
|
|
|
} else if (EXPECTED(Z_TYPE_P(val) == IS_DOUBLE)) {
|
|
|
|
Z_DVAL(sum) += Z_DVAL_P(val);
|
|
|
|
} else {
|
|
|
|
ERR_NOT_NUMERIC();
|
2018-09-07 08:00:08 +00:00
|
|
|
RETURN_NULL();
|
2018-09-06 02:30:18 +00:00
|
|
|
}
|
|
|
|
ZEND_HASH_FOREACH_END();
|
|
|
|
RETVAL_ZVAL(&sum, 0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, sumBy)
|
|
|
|
{
|
|
|
|
zend_fcall_info fci;
|
|
|
|
zend_fcall_info_cache fcc;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
|
|
Z_PARAM_FUNC(fci, fcc)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-09-06 02:30:18 +00:00
|
|
|
zval sum;
|
|
|
|
ZVAL_NULL(&sum);
|
|
|
|
INIT_FCI(&fci, 2);
|
|
|
|
ZEND_HASH_FOREACH_BUCKET(current, Bucket* bucket)
|
|
|
|
CALLBACK_KEYVAL_INVOKE(params, bucket);
|
|
|
|
if (UNEXPECTED(ZVAL_IS_NULL(&sum))) {
|
|
|
|
if (Z_TYPE(retval) == IS_LONG) {
|
|
|
|
ZVAL_LONG(&sum, 0);
|
|
|
|
} else if (EXPECTED(Z_TYPE(retval) == IS_DOUBLE)) {
|
|
|
|
ZVAL_DOUBLE(&sum, 0.0);
|
|
|
|
} else {
|
|
|
|
ERR_NOT_NUMERIC();
|
|
|
|
zval_ptr_dtor(&retval);
|
2018-09-07 08:00:08 +00:00
|
|
|
RETURN_NULL();
|
2018-09-06 02:30:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (Z_TYPE(retval) == IS_LONG) {
|
|
|
|
Z_LVAL(sum) += Z_LVAL(retval);
|
|
|
|
} else if (EXPECTED(Z_TYPE(retval) == IS_DOUBLE)) {
|
|
|
|
Z_DVAL(sum) += Z_DVAL(retval);
|
|
|
|
} else {
|
|
|
|
ERR_NOT_NUMERIC();
|
|
|
|
zval_ptr_dtor(&retval);
|
2018-09-07 08:00:08 +00:00
|
|
|
RETURN_NULL();
|
2018-09-06 02:30:18 +00:00
|
|
|
}
|
|
|
|
ZEND_HASH_FOREACH_END();
|
|
|
|
RETVAL_ZVAL(&sum, 0, 0);
|
|
|
|
}
|
|
|
|
|
2018-03-23 09:06:05 +00:00
|
|
|
PHP_METHOD(Collection, take)
|
|
|
|
{
|
2018-05-26 11:02:32 +00:00
|
|
|
zend_long n;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
|
|
Z_PARAM_LONG(n)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-09-03 12:07:08 +00:00
|
|
|
if (n < 0) {
|
2018-05-26 11:02:32 +00:00
|
|
|
ERR_BAD_SIZE();
|
|
|
|
return;
|
|
|
|
}
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-05-26 11:02:32 +00:00
|
|
|
zend_long num_elements = zend_hash_num_elements(current);
|
|
|
|
ARRAY_NEW(new_collection, n > num_elements ? num_elements : n);
|
2018-09-02 13:16:05 +00:00
|
|
|
zend_bool packed = HT_IS_PACKED(current);
|
2018-05-26 11:02:32 +00:00
|
|
|
Bucket* bucket = current->arData;
|
|
|
|
Bucket* end = bucket + current->nNumUsed;
|
2018-09-03 12:07:08 +00:00
|
|
|
for (; n > 0 && bucket < end; ++bucket) {
|
|
|
|
if (Z_ISUNDEF(bucket->val)) {
|
2018-05-26 11:02:32 +00:00
|
|
|
continue;
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-05-26 11:02:32 +00:00
|
|
|
--n;
|
|
|
|
Z_TRY_ADDREF(bucket->val);
|
2018-09-06 03:33:41 +00:00
|
|
|
// Works for any zend_array, however, it doesn't make sense if you use any of
|
|
|
|
// these methods on non-packed zend_arrays.
|
2018-09-03 12:07:08 +00:00
|
|
|
if (bucket->key) {
|
2018-05-26 11:02:32 +00:00
|
|
|
zend_hash_add_new(new_collection, bucket->key, &bucket->val);
|
2018-09-03 12:07:08 +00:00
|
|
|
} else if (packed) {
|
2018-05-26 11:02:32 +00:00
|
|
|
zend_hash_next_index_insert(new_collection, &bucket->val);
|
2018-09-03 12:07:08 +00:00
|
|
|
} else {
|
2018-05-26 11:02:32 +00:00
|
|
|
zend_hash_index_add_new(new_collection, bucket->h, &bucket->val);
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-05-26 11:02:32 +00:00
|
|
|
}
|
|
|
|
RETVAL_NEW_COLLECTION(new_collection);
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, takeLast)
|
|
|
|
{
|
2018-05-26 11:02:32 +00:00
|
|
|
zend_long n;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
|
|
Z_PARAM_LONG(n)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-09-03 12:07:08 +00:00
|
|
|
if (n < 0) {
|
2018-05-26 11:02:32 +00:00
|
|
|
ERR_BAD_SIZE();
|
|
|
|
return;
|
|
|
|
}
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-05-26 11:02:32 +00:00
|
|
|
zend_long num_elements = zend_hash_num_elements(current);
|
|
|
|
ARRAY_NEW(new_collection, n > num_elements ? num_elements : n);
|
2018-09-02 13:16:05 +00:00
|
|
|
zend_bool packed = HT_IS_PACKED(current);
|
2018-05-26 11:02:32 +00:00
|
|
|
uint32_t idx = current->nNumUsed;
|
|
|
|
zend_long num_taken = n;
|
2018-08-13 18:30:48 +00:00
|
|
|
Bucket** taken = (Bucket**)malloc(num_taken * sizeof(Bucket*));
|
2018-05-26 11:02:32 +00:00
|
|
|
// Note that the original element orders should be preserved as in kotlin.
|
2018-09-03 12:07:08 +00:00
|
|
|
for (; num_taken > 0 && idx > 0; --idx) {
|
2018-05-26 11:02:32 +00:00
|
|
|
Bucket* bucket = current->arData + idx - 1;
|
2018-09-03 12:07:08 +00:00
|
|
|
if (Z_ISUNDEF(bucket->val)) {
|
2018-05-26 11:02:32 +00:00
|
|
|
continue;
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-05-26 11:02:32 +00:00
|
|
|
taken[--num_taken] = bucket;
|
|
|
|
}
|
2018-08-07 16:43:09 +00:00
|
|
|
memset(&taken[0], 0, num_taken * sizeof(Bucket*));
|
2018-05-26 11:05:59 +00:00
|
|
|
int i = 0;
|
2018-09-03 12:07:08 +00:00
|
|
|
for (; i < n; ++i) {
|
2018-05-26 11:02:32 +00:00
|
|
|
Bucket* bucket = taken[i];
|
2018-09-03 12:07:08 +00:00
|
|
|
if (bucket == NULL) {
|
2018-05-26 11:02:32 +00:00
|
|
|
continue;
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-05-26 11:02:32 +00:00
|
|
|
Z_TRY_ADDREF(bucket->val);
|
2018-09-03 12:07:08 +00:00
|
|
|
if (bucket->key) {
|
2018-05-26 11:02:32 +00:00
|
|
|
zend_hash_add_new(new_collection, bucket->key, &bucket->val);
|
2018-09-03 12:07:08 +00:00
|
|
|
} else if (packed) {
|
2018-05-26 11:02:32 +00:00
|
|
|
zend_hash_next_index_insert(new_collection, &bucket->val);
|
2018-09-03 12:07:08 +00:00
|
|
|
} else {
|
2018-05-26 11:02:32 +00:00
|
|
|
zend_hash_index_add_new(new_collection, bucket->h, &bucket->val);
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-05-26 11:02:32 +00:00
|
|
|
}
|
2018-08-13 18:30:48 +00:00
|
|
|
free(taken);
|
2018-05-26 11:02:32 +00:00
|
|
|
RETVAL_NEW_COLLECTION(new_collection);
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, takeLastWhile)
|
|
|
|
{
|
2018-06-03 11:18:40 +00:00
|
|
|
zend_fcall_info fci;
|
|
|
|
zend_fcall_info_cache fcc;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
|
|
Z_PARAM_FUNC(fci, fcc)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-08-15 14:37:37 +00:00
|
|
|
INIT_FCI(&fci, 2);
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-09-02 13:46:01 +00:00
|
|
|
ARRAY_NEW(new_collection, 8);
|
2018-09-02 13:16:05 +00:00
|
|
|
zend_bool packed = HT_IS_PACKED(current);
|
2018-06-03 11:18:40 +00:00
|
|
|
uint32_t num_elements = zend_hash_num_elements(current);
|
2018-08-13 18:30:48 +00:00
|
|
|
Bucket** taken = (Bucket**)malloc(num_elements * sizeof(Bucket*));
|
2018-06-03 11:18:40 +00:00
|
|
|
ZEND_HASH_REVERSE_FOREACH_BUCKET(current, Bucket* bucket)
|
|
|
|
CALLBACK_KEYVAL_INVOKE(params, bucket);
|
2018-09-03 12:07:08 +00:00
|
|
|
if (zend_is_true(&retval)) {
|
2018-08-11 18:26:46 +00:00
|
|
|
zval_ptr_dtor(&retval);
|
2018-06-03 11:18:40 +00:00
|
|
|
taken[--num_elements] = bucket;
|
2018-09-03 12:07:08 +00:00
|
|
|
} else {
|
2018-08-11 18:26:46 +00:00
|
|
|
zval_ptr_dtor(&retval);
|
2018-06-03 11:18:40 +00:00
|
|
|
break;
|
2018-08-11 18:26:46 +00:00
|
|
|
}
|
2018-06-03 11:18:40 +00:00
|
|
|
ZEND_HASH_FOREACH_END();
|
2018-08-07 16:43:09 +00:00
|
|
|
memset(&taken[0], 0, num_elements * sizeof(Bucket*));
|
2018-06-03 11:18:40 +00:00
|
|
|
int i = 0;
|
|
|
|
for (; i < zend_hash_num_elements(current); ++i) {
|
|
|
|
Bucket* bucket = taken[i];
|
2018-09-03 12:07:08 +00:00
|
|
|
if (bucket == NULL) {
|
2018-06-03 11:18:40 +00:00
|
|
|
continue;
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-06-03 11:18:40 +00:00
|
|
|
Z_TRY_ADDREF(bucket->val);
|
2018-09-03 12:07:08 +00:00
|
|
|
if (bucket->key) {
|
2018-06-03 11:18:40 +00:00
|
|
|
zend_hash_add_new(new_collection, bucket->key, &bucket->val);
|
2018-09-03 12:07:08 +00:00
|
|
|
} else if (packed) {
|
2018-06-03 11:18:40 +00:00
|
|
|
zend_hash_next_index_insert(new_collection, &bucket->val);
|
2018-09-03 12:07:08 +00:00
|
|
|
} else {
|
2018-06-03 11:18:40 +00:00
|
|
|
zend_hash_index_add_new(new_collection, bucket->h, &bucket->val);
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-06-03 11:18:40 +00:00
|
|
|
}
|
2018-08-13 18:30:48 +00:00
|
|
|
free(taken);
|
2018-06-03 11:18:40 +00:00
|
|
|
RETVAL_NEW_COLLECTION(new_collection);
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, takeWhile)
|
|
|
|
{
|
2018-06-03 11:18:40 +00:00
|
|
|
zend_fcall_info fci;
|
|
|
|
zend_fcall_info_cache fcc;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
|
|
Z_PARAM_FUNC(fci, fcc)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-08-15 14:37:37 +00:00
|
|
|
INIT_FCI(&fci, 2);
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-09-02 13:46:01 +00:00
|
|
|
ARRAY_NEW(new_collection, 8);
|
2018-09-02 13:16:05 +00:00
|
|
|
zend_bool packed = HT_IS_PACKED(current);
|
2018-06-03 11:18:40 +00:00
|
|
|
ZEND_HASH_FOREACH_BUCKET(current, Bucket* bucket)
|
|
|
|
CALLBACK_KEYVAL_INVOKE(params, bucket);
|
2018-09-03 12:07:08 +00:00
|
|
|
if (zend_is_true(&retval)) {
|
2018-08-11 18:26:46 +00:00
|
|
|
zval_ptr_dtor(&retval);
|
2018-09-03 12:07:08 +00:00
|
|
|
if (bucket->key) {
|
2018-06-03 11:18:40 +00:00
|
|
|
zend_hash_add_new(new_collection, bucket->key, &bucket->val);
|
2018-09-03 12:07:08 +00:00
|
|
|
} else if (packed) {
|
2018-06-03 11:18:40 +00:00
|
|
|
zend_hash_next_index_insert(new_collection, &bucket->val);
|
2018-09-03 12:07:08 +00:00
|
|
|
} else {
|
2018-06-03 11:18:40 +00:00
|
|
|
zend_hash_index_add_new(new_collection, bucket->h, &bucket->val);
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-09-03 12:07:08 +00:00
|
|
|
} else {
|
2018-08-11 18:26:46 +00:00
|
|
|
zval_ptr_dtor(&retval);
|
2018-06-03 11:18:40 +00:00
|
|
|
break;
|
2018-08-11 18:26:46 +00:00
|
|
|
}
|
2018-06-03 11:18:40 +00:00
|
|
|
ZEND_HASH_FOREACH_END();
|
|
|
|
RETVAL_NEW_COLLECTION(new_collection);
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, toArray)
|
|
|
|
{
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* retval = THIS_COLLECTION;
|
2018-04-17 15:17:30 +00:00
|
|
|
GC_ADDREF(retval);
|
|
|
|
RETVAL_ARR(retval);
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, toCollection)
|
|
|
|
{
|
2018-04-20 12:59:21 +00:00
|
|
|
zval* dest;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
|
|
Z_PARAM_OBJECT_OF_CLASS(dest, collections_collection_ce)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
|
|
|
zend_array* dest_arr = Z_COLLECTION_P(dest);
|
2018-04-20 12:59:21 +00:00
|
|
|
SEPARATE_COLLECTION(dest_arr, dest);
|
2018-09-05 16:00:15 +00:00
|
|
|
zend_bool packed = HT_IS_PACKED(current) && HT_IS_PACKED(dest_arr);
|
2018-04-20 12:59:21 +00:00
|
|
|
ZEND_HASH_FOREACH_BUCKET(current, Bucket* bucket)
|
2018-09-05 16:00:15 +00:00
|
|
|
zval* result;
|
2018-09-03 12:07:08 +00:00
|
|
|
if (bucket->key) {
|
2018-09-05 16:00:15 +00:00
|
|
|
result = zend_hash_add(dest_arr, bucket->key, &bucket->val);
|
|
|
|
} else if (packed) {
|
2018-09-06 03:33:41 +00:00
|
|
|
result = zend_hash_next_index_insert(dest_arr, &bucket->val);
|
2018-09-05 16:00:15 +00:00
|
|
|
} else {
|
|
|
|
result = zend_hash_index_add(dest_arr, bucket->h, &bucket->val);
|
|
|
|
}
|
|
|
|
if (result) {
|
|
|
|
Z_TRY_ADDREF(bucket->val);
|
2018-08-13 13:03:38 +00:00
|
|
|
}
|
2018-04-20 12:59:21 +00:00
|
|
|
ZEND_HASH_FOREACH_END();
|
|
|
|
RETVAL_ZVAL(dest, 1, 0);
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, toPairs)
|
|
|
|
{
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-04-20 12:59:21 +00:00
|
|
|
ARRAY_NEW_EX(new_collection, current);
|
|
|
|
ZEND_HASH_FOREACH_BUCKET(current, Bucket* bucket)
|
2018-08-30 17:04:46 +00:00
|
|
|
zend_object* obj = create_pair_obj();
|
2018-09-05 16:00:15 +00:00
|
|
|
Z_TRY_ADDREF(bucket->val);
|
2018-08-20 14:47:23 +00:00
|
|
|
bucket_to_pair(obj, bucket);
|
2018-08-15 14:37:37 +00:00
|
|
|
zval pair;
|
2018-04-20 12:59:21 +00:00
|
|
|
ZVAL_OBJ(&pair, obj);
|
|
|
|
zend_hash_next_index_insert(new_collection, &pair);
|
|
|
|
ZEND_HASH_FOREACH_END();
|
|
|
|
RETVAL_NEW_COLLECTION(new_collection);
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, union)
|
|
|
|
{
|
2018-09-04 14:11:12 +00:00
|
|
|
zval* elements;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
|
|
Z_PARAM_ZVAL(elements)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
|
|
ELEMENTS_VALIDATE(elements, ERR_BAD_ARGUMENT_TYPE, return);
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-09-04 14:11:12 +00:00
|
|
|
zend_bool packed = HT_IS_PACKED(current) && HT_IS_PACKED(elements_arr);
|
|
|
|
ARRAY_CLONE(new_collection, current);
|
|
|
|
ZEND_HASH_FOREACH_BUCKET(elements_arr, Bucket* bucket)
|
2018-09-06 03:33:41 +00:00
|
|
|
zval* result;
|
2018-09-04 14:11:12 +00:00
|
|
|
if (bucket->key) {
|
2018-09-06 03:33:41 +00:00
|
|
|
result = zend_hash_add(new_collection, bucket->key, &bucket->val);
|
2018-09-04 14:11:12 +00:00
|
|
|
} else if (packed) {
|
2018-09-06 03:33:41 +00:00
|
|
|
result = zend_hash_next_index_insert(new_collection, &bucket->val);
|
2018-09-04 14:11:12 +00:00
|
|
|
} else {
|
2018-09-06 03:33:41 +00:00
|
|
|
result = zend_hash_index_add(new_collection, bucket->h, &bucket->val);
|
|
|
|
}
|
|
|
|
if (result) {
|
|
|
|
Z_TRY_ADDREF(bucket->val);
|
2018-09-04 14:11:12 +00:00
|
|
|
}
|
|
|
|
ZEND_HASH_FOREACH_END();
|
|
|
|
uint32_t num_elements = zend_hash_num_elements(new_collection);
|
|
|
|
compare_func_t cmp = NULL;
|
|
|
|
equal_check_func_t eql = NULL;
|
|
|
|
Bucket* ref = (Bucket*)malloc(num_elements * sizeof(Bucket));
|
|
|
|
uint32_t idx = 0;
|
|
|
|
ZEND_HASH_FOREACH_BUCKET(new_collection, Bucket* bucket)
|
|
|
|
if (UNEXPECTED(cmp == NULL)) {
|
|
|
|
cmp = compare_func_init(&bucket->val, 0, 0);
|
|
|
|
eql = equal_check_func_init(&bucket->val);
|
|
|
|
}
|
|
|
|
Bucket* dest = &ref[idx++];
|
|
|
|
dest->key = NULL;
|
|
|
|
dest->h = bucket - new_collection->arData;
|
|
|
|
memcpy(&dest->val, &bucket->val, sizeof(zval));
|
|
|
|
ZEND_HASH_FOREACH_END();
|
2018-09-07 15:42:36 +00:00
|
|
|
CMP_G = cmp;
|
2018-09-04 14:11:12 +00:00
|
|
|
array_distinct(new_collection, ref, cmp, eql);
|
|
|
|
free(ref);
|
|
|
|
RETVAL_NEW_COLLECTION(new_collection);
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Collection, values)
|
|
|
|
{
|
2018-09-07 15:42:36 +00:00
|
|
|
zend_array* current = THIS_COLLECTION;
|
2018-04-24 09:22:43 +00:00
|
|
|
ARRAY_NEW_EX(new_collection, current);
|
|
|
|
ZEND_HASH_FOREACH_VAL(current, zval* val)
|
2018-09-05 16:00:15 +00:00
|
|
|
Z_TRY_ADDREF_P(val);
|
2018-04-24 09:22:43 +00:00
|
|
|
zend_hash_next_index_insert(new_collection, val);
|
|
|
|
ZEND_HASH_FOREACH_END();
|
|
|
|
RETVAL_NEW_COLLECTION(new_collection);
|
2018-03-23 09:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_METHOD(Pair, __construct)
|
|
|
|
{
|
2018-03-24 04:22:00 +00:00
|
|
|
zval* first;
|
|
|
|
zval* second;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(2, 2)
|
|
|
|
Z_PARAM_ZVAL(first)
|
|
|
|
Z_PARAM_ZVAL(second)
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-08-30 17:04:46 +00:00
|
|
|
Z_TRY_ADDREF_P(first);
|
|
|
|
Z_TRY_ADDREF_P(second);
|
|
|
|
pair_update_first(Z_OBJ_P(getThis()), first);
|
|
|
|
pair_update_second(Z_OBJ_P(getThis()), second);
|
2018-04-16 12:58:38 +00:00
|
|
|
}
|