From 3b168358b7ede1ccf63145c760564887f9657987 Mon Sep 17 00:00:00 2001 From: CismonX Date: Sat, 12 May 2018 22:10:59 +0800 Subject: [PATCH] Add `partition()`. Manually init properties for `Pair`. --- src/collections.c | 7 +++-- src/collections_methods.c | 64 +++++++++++++++++++++++++++------------ src/php_collections.h | 3 ++ tests/031-partition.phpt | 12 ++++++++ 4 files changed, 65 insertions(+), 21 deletions(-) create mode 100644 tests/031-partition.phpt diff --git a/src/collections.c b/src/collections.c index 8ceee3e..8e33721 100644 --- a/src/collections.c +++ b/src/collections.c @@ -19,8 +19,13 @@ zend_object_handlers* collection_handlers; zend_class_entry* collections_collection_ce; zend_class_entry* collections_pair_ce; +zend_string* collections_pair_first; +zend_string* collections_pair_second; + PHP_MINIT_FUNCTION(collections) { + collections_pair_first = zend_string_init("first", sizeof "first" - 1, 1); + collections_pair_second = zend_string_init("second", sizeof "second" - 1, 1); zend_class_entry collection_ce; INIT_CLASS_ENTRY_EX(collection_ce, "Collection", sizeof "Collection" - 1, collection_methods); collections_collection_ce = zend_register_internal_class(&collection_ce); @@ -41,8 +46,6 @@ PHP_MINIT_FUNCTION(collections) zend_class_entry pair_ce; INIT_CLASS_ENTRY_EX(pair_ce, "Pair", sizeof "Pair" - 1, pair_methods); collections_pair_ce = zend_register_internal_class(&pair_ce); - zend_declare_property_null(collections_pair_ce, "first", sizeof "first" - 1, ZEND_ACC_PUBLIC); - zend_declare_property_null(collections_pair_ce, "second", sizeof "second" - 1, ZEND_ACC_PUBLIC); return SUCCESS; } diff --git a/src/collections_methods.c b/src/collections_methods.c index 8a394b8..5753d30 100644 --- a/src/collections_methods.c +++ b/src/collections_methods.c @@ -18,22 +18,22 @@ NEW_OBJ(name, collections_collection_ce, collection_handlers) #define NEW_PAIR_OBJ(name) \ NEW_OBJ(name, collections_pair_ce, &std_object_handlers); \ - object_properties_init(name, collections_pair_ce) + name->properties = (zend_array*)emalloc(sizeof(zend_array)); \ + zend_hash_init(name->properties, 2, NULL, ZVAL_PTR_DTOR, 0) #define IS_COLLECTION_P(zval) \ Z_TYPE_P(zval) == IS_OBJECT && Z_OBJCE_P(zval) == collections_collection_ce #define IS_PAIR(zval) \ EXPECTED(Z_TYPE(zval) == IS_OBJECT) && EXPECTED(Z_OBJCE(zval) == collections_pair_ce) -#define OBJ_PROPERTY_UPDATE(ce, obj, property_name, value) \ - zend_update_property(ce, obj, #property_name, sizeof #property_name - 1, value) -#define OBJ_PROPERTY_FETCH(ce, obj, property_name) \ - zend_read_property(ce, obj, #property_name, sizeof #property_name - 1, 1, &rv) -#define PAIR_UPDATE_FIRST(obj, value) OBJ_PROPERTY_UPDATE(collections_pair_ce, obj, first, value) -#define PAIR_UPDATE_SECOND(obj, value) OBJ_PROPERTY_UPDATE(collections_pair_ce, obj, second, value) -#define PAIR_FETCH_FIRST(obj) OBJ_PROPERTY_FETCH(collections_pair_ce, obj, first) -#define PAIR_FETCH_SECOND(obj) OBJ_PROPERTY_FETCH(collections_pair_ce, obj, second) - +#define OBJ_PROPERTY_UPDATE(obj, property_name, value) \ + zend_hash_update((obj)->properties, property_name, value) +#define OBJ_PROPERTY_FETCH(obj, property_name) \ + zend_hash_find((obj)->properties, property_name) +#define PAIR_UPDATE_FIRST(obj, value) OBJ_PROPERTY_UPDATE(obj, collections_pair_first, value) +#define PAIR_UPDATE_SECOND(obj, value) OBJ_PROPERTY_UPDATE(obj, collections_pair_second, value) +#define PAIR_FETCH_FIRST(obj) OBJ_PROPERTY_FETCH(obj, collections_pair_first) +#define PAIR_FETCH_SECOND(obj) OBJ_PROPERTY_FETCH(obj, collections_pair_second) #define COLLECTION_FETCH(obj) Z_OBJ_P(obj)->properties #define COLLECTION_FETCH_CURRENT() COLLECTION_FETCH(getThis()) @@ -240,8 +240,8 @@ PHP_METHOD(Collection, associate) ZEND_HASH_FOREACH_BUCKET(current, Bucket* bucket) CALLBACK_KEYVAL_INVOKE(params, bucket); if (IS_PAIR(retval)) { - zval* key = PAIR_FETCH_FIRST(&retval); - zval* value = PAIR_FETCH_SECOND(&retval); + zval* key = PAIR_FETCH_FIRST(Z_OBJ(retval)); + zval* value = PAIR_FETCH_SECOND(Z_OBJ(retval)); if (Z_TYPE_P(key) == IS_LONG) zend_hash_index_add(new_collection, Z_LVAL_P(key), value); else if (Z_TYPE_P(key) == IS_STRING) @@ -273,8 +273,8 @@ PHP_METHOD(Collection, associateTo) ZEND_HASH_FOREACH_BUCKET(current, Bucket* bucket) CALLBACK_KEYVAL_INVOKE(params, bucket); if (IS_PAIR(retval)) { - zval* key = PAIR_FETCH_FIRST(&retval); - zval* value = PAIR_FETCH_SECOND(&retval); + zval* key = PAIR_FETCH_FIRST(Z_OBJ(retval)); + zval* value = PAIR_FETCH_SECOND(Z_OBJ(retval)); if (Z_TYPE_P(key) == IS_LONG) zend_hash_index_add(dest_arr, Z_LVAL_P(key), value); else if (Z_TYPE_P(key) == IS_STRING) @@ -1116,7 +1116,31 @@ PHP_METHOD(Collection, onEach) PHP_METHOD(Collection, partition) { - + zend_fcall_info fci; + zend_fcall_info_cache fcc; + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_FUNC(fci, fcc) + ZEND_PARSE_PARAMETERS_END(); + INIT_FCI(2); + zend_array* current = COLLECTION_FETCH_CURRENT(); + NEW_PAIR_OBJ(pair); + ARRAY_NEW_EX(first_arr, current); + ARRAY_NEW_EX(second_arr, current); + ZEND_HASH_FOREACH_BUCKET(current, Bucket* bucket) + CALLBACK_KEYVAL_INVOKE(params, bucket); + zend_array* which = zend_is_true(&retval) ? first_arr : second_arr; + ADDREF_IF_REFCOUNTED(bucket->val); + if (bucket->key) + zend_hash_add(which, bucket->key, &bucket->val); + else + zend_hash_index_add(which, bucket->h, &bucket->val); + ZEND_HASH_FOREACH_END(); + zval first, second; + ZVAL_ARR(&first, first_arr); + ZVAL_ARR(&second, second_arr); + PAIR_UPDATE_FIRST(pair, &first); + PAIR_UPDATE_SECOND(pair, &second); + RETVAL_OBJ(pair); } PHP_METHOD(Collection, plus) @@ -1400,8 +1424,8 @@ PHP_METHOD(Collection, toPairs) ZVAL_STR(&key, bucket->key); else ZVAL_LONG(&key, bucket->h); - PAIR_UPDATE_FIRST(&pair, &key); - PAIR_UPDATE_SECOND(&pair, &bucket->val); + PAIR_UPDATE_FIRST(obj, &key); + PAIR_UPDATE_SECOND(obj, &bucket->val); zend_hash_next_index_insert(new_collection, &pair); ZEND_HASH_FOREACH_END(); RETVAL_NEW_COLLECTION(new_collection); @@ -1430,6 +1454,8 @@ PHP_METHOD(Pair, __construct) Z_PARAM_ZVAL(first) Z_PARAM_ZVAL(second) ZEND_PARSE_PARAMETERS_END(); - PAIR_UPDATE_FIRST(getThis(), first); - PAIR_UPDATE_SECOND(getThis(), second); + zend_array* properties = Z_OBJ_P(getThis())->properties = (zend_array*)emalloc(sizeof(zend_array)); + zend_hash_init(properties, 2, NULL, ZVAL_PTR_DTOR, 0); + PAIR_UPDATE_FIRST(Z_OBJ_P(getThis()), first); + PAIR_UPDATE_SECOND(Z_OBJ_P(getThis()), second); } diff --git a/src/php_collections.h b/src/php_collections.h index 2e17bc8..9bf89b5 100644 --- a/src/php_collections.h +++ b/src/php_collections.h @@ -28,6 +28,9 @@ extern zend_module_entry collections_module_entry; extern PHP_COLLECTIONS_API zend_class_entry* collections_collection_ce; extern PHP_COLLECTIONS_API zend_class_entry* collections_pair_ce; +extern zend_string* collections_pair_first; +extern zend_string* collections_pair_second; + extern zend_object_handlers* collection_handlers; int count_collection(zval* obj, zend_long* count); diff --git a/tests/031-partition.phpt b/tests/031-partition.phpt new file mode 100644 index 0000000..9bde76c --- /dev/null +++ b/tests/031-partition.phpt @@ -0,0 +1,12 @@ +--TEST-- +Test Collection::partition(). +--FILE-- +partition(function ($value) { + return strlen($value) % 2; +}); +if ($pair->first != ['abc', 'd'] || $pair->second != [2 => 'ef', 3 => 'ghij']) + echo 'Collection::partition() failed.', PHP_EOL; +?> +--EXPECT--