Bug fix. Performance boost.

This commit is contained in:
CismonX 2018-04-17 23:17:30 +08:00
parent f2402b9f67
commit b5c3a0b4ad
2 changed files with 33 additions and 42 deletions

View File

@ -31,7 +31,6 @@ PHP_MINIT_FUNCTION(collections)
2, zend_ce_countable, 2, zend_ce_countable,
#endif #endif
zend_ce_arrayaccess); zend_ce_arrayaccess);
zend_declare_property_null(collections_collection_ce, "_", sizeof "_" - 1, ZEND_ACC_PRIVATE);
collection_handlers = (zend_object_handlers*)emalloc(sizeof(zend_object_handlers)); collection_handlers = (zend_object_handlers*)emalloc(sizeof(zend_object_handlers));
memcpy(collection_handlers, &std_object_handlers, sizeof(zend_object_handlers)); memcpy(collection_handlers, &std_object_handlers, sizeof(zend_object_handlers));
collection_handlers->count_elements = count_collection; collection_handlers->count_elements = count_collection;

View File

@ -13,8 +13,7 @@
zend_object* (name) = (zend_object*)ecalloc(1, sizeof(zend_object) + \ zend_object* (name) = (zend_object*)ecalloc(1, sizeof(zend_object) + \
zend_object_properties_size(ce)); \ zend_object_properties_size(ce)); \
zend_object_std_init(name, ce); \ zend_object_std_init(name, ce); \
object_properties_init(name, ce); \ (name)->handlers = object_handlers
(name)->handlers = object_handlers;
#define NEW_COLLECTION_OBJ(name) \ #define NEW_COLLECTION_OBJ(name) \
NEW_OBJ(name, collections_collection_ce, collection_handlers) NEW_OBJ(name, collections_collection_ce, collection_handlers)
#define NEW_PAIR_OBJ(name) \ #define NEW_PAIR_OBJ(name) \
@ -29,15 +28,14 @@
zend_update_property(ce, obj, #property_name, sizeof #property_name - 1, value) zend_update_property(ce, obj, #property_name, sizeof #property_name - 1, value)
#define OBJ_PROPERTY_FETCH(ce, obj, property_name) \ #define OBJ_PROPERTY_FETCH(ce, obj, property_name) \
zend_read_property(ce, obj, #property_name, sizeof #property_name - 1, 1, &rv) zend_read_property(ce, obj, #property_name, sizeof #property_name - 1, 1, &rv)
#define COLLECTION_UPDATE(obj, value) OBJ_PROPERTY_UPDATE(collections_collection_ce, obj, _, value)
#define COLLECTION_UPDATE_EX(value) COLLECTION_UPDATE(getThis(), value)
#define COLLECTION_FETCH(obj) OBJ_PROPERTY_FETCH(collections_collection_ce, obj, _)
#define COLLECTION_FETCH_EX() Z_ARRVAL_P(COLLECTION_FETCH(getThis()))
#define PAIR_UPDATE_FIRST(obj, value) OBJ_PROPERTY_UPDATE(collections_pair_ce, obj, first, value) #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_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_FIRST(obj) OBJ_PROPERTY_FETCH(collections_pair_ce, obj, first)
#define PAIR_FETCH_SECOND(obj) OBJ_PROPERTY_FETCH(collections_pair_ce, obj, second) #define PAIR_FETCH_SECOND(obj) OBJ_PROPERTY_FETCH(collections_pair_ce, obj, second)
#define COLLECTION_FETCH(obj) Z_OBJPROP_P(obj)
#define COLLECTION_FETCH_EX() COLLECTION_FETCH(getThis())
#define INIT_FCI() \ #define INIT_FCI() \
zval params[2], retval; \ zval params[2], retval; \
fci.param_count = 2; \ fci.param_count = 2; \
@ -46,7 +44,6 @@
#define CALLBACK_KEYVAL_INVOKE(params, bucket) \ #define CALLBACK_KEYVAL_INVOKE(params, bucket) \
ZVAL_COPY_VALUE(&params[0], &bucket->val); \ ZVAL_COPY_VALUE(&params[0], &bucket->val); \
ZVAL_COPY(&params[0], &(bucket)->val); \
if ((bucket)->key) \ if ((bucket)->key) \
ZVAL_STR(&params[1], (bucket)->key); \ ZVAL_STR(&params[1], (bucket)->key); \
else \ else \
@ -71,9 +68,12 @@
#define ERR_NOT_ARITHMETIC() PHP_COLLECTIONS_ERROR(E_WARNING, "Elements should be int or double") #define ERR_NOT_ARITHMETIC() PHP_COLLECTIONS_ERROR(E_WARNING, "Elements should be int or double")
#define ELEMENTS_VALIDATE(elements) \ #define ELEMENTS_VALIDATE(elements) \
zend_array* elements##_arr; \
if (IS_COLLECTION_P(elements)) \ if (IS_COLLECTION_P(elements)) \
(elements) = COLLECTION_FETCH(elements); \ (elements##_arr) = COLLECTION_FETCH(elements); \
else if (UNEXPECTED(Z_TYPE_P(elements) != IS_ARRAY)) { \ else if (UNEXPECTED(Z_TYPE_P(elements) == IS_ARRAY))\
(elements##_arr) = Z_ARRVAL_P(elements); \
else { \
ERR_BAD_ARGUMENT_TYPE(); \ ERR_BAD_ARGUMENT_TYPE(); \
return; \ return; \
} }
@ -96,14 +96,11 @@
#define RETVAL_NEW_COLLECTION(collection) \ #define RETVAL_NEW_COLLECTION(collection) \
do { \ do { \
ALLOW_COW_VIOLATION(collection); \
NEW_COLLECTION_OBJ(obj); \ NEW_COLLECTION_OBJ(obj); \
zval _retval; \ zend_array* new_arr = collection; \
ZVAL_OBJ(&_retval, obj); \ if (GC_REFCOUNT(new_arr) > 1) \
zval _property; \ new_arr = zend_array_dup(new_arr) \
ZVAL_ARR(&_property, collection); \ object_properties_init_ex(obj, new_arr); \
COLLECTION_UPDATE(&_retval, &_property); \
zval_ptr_dtor(&_property); \
RETVAL_OBJ(obj); \ RETVAL_OBJ(obj); \
} while (0) } while (0)
@ -117,14 +114,14 @@ zval rv;
int count_collection(zval* obj, zend_long* count) int count_collection(zval* obj, zend_long* count)
{ {
zend_array* current = Z_ARRVAL_P(COLLECTION_FETCH(obj)); zend_array* current = COLLECTION_FETCH(obj);
*count = zend_hash_num_elements(current); *count = zend_hash_num_elements(current);
return SUCCESS; return SUCCESS;
} }
int collection_offset_exists(zval* object, zval* offset, int check_empty) int collection_offset_exists(zval* object, zval* offset, int check_empty)
{ {
zend_array* current = Z_ARRVAL_P(COLLECTION_FETCH(object)); zend_array* current = COLLECTION_FETCH(object);
if (check_empty) if (check_empty)
return zend_hash_num_elements(current) == 0; return zend_hash_num_elements(current) == 0;
if (Z_TYPE_P(offset) == IS_LONG) if (Z_TYPE_P(offset) == IS_LONG)
@ -136,7 +133,7 @@ int collection_offset_exists(zval* object, zval* offset, int check_empty)
void collection_offset_set(zval* object, zval* offset, zval* value) void collection_offset_set(zval* object, zval* offset, zval* value)
{ {
zend_array* current = Z_ARRVAL_P(COLLECTION_FETCH(object)); zend_array* current = COLLECTION_FETCH(object);
if (Z_TYPE_P(offset) == IS_LONG) if (Z_TYPE_P(offset) == IS_LONG)
zend_hash_index_update(current, Z_LVAL_P(offset), value); zend_hash_index_update(current, Z_LVAL_P(offset), value);
else if (Z_TYPE_P(offset) == IS_STRING) else if (Z_TYPE_P(offset) == IS_STRING)
@ -147,7 +144,7 @@ zval* collection_offset_get(zval* object, zval* offset, int type, zval* retval)
{ {
// Note that we don't handle type. So don't do any fancy things with Collection // Note that we don't handle type. So don't do any fancy things with Collection
// such as fetching a reference of a value, etc. // such as fetching a reference of a value, etc.
zend_array* current = Z_ARRVAL_P(COLLECTION_FETCH(object)); zend_array* current = COLLECTION_FETCH(object);
zval* found = NULL; zval* found = NULL;
if (Z_TYPE_P(offset) == IS_LONG) if (Z_TYPE_P(offset) == IS_LONG)
found = zend_hash_index_find(current, Z_LVAL_P(offset)); found = zend_hash_index_find(current, Z_LVAL_P(offset));
@ -159,7 +156,7 @@ zval* collection_offset_get(zval* object, zval* offset, int type, zval* retval)
void collection_offset_unset(zval* object, zval* offset) void collection_offset_unset(zval* object, zval* offset)
{ {
zend_array* current = Z_ARRVAL_P(COLLECTION_FETCH(object)); zend_array* current = COLLECTION_FETCH(object);
if (Z_TYPE_P(offset) == IS_LONG) if (Z_TYPE_P(offset) == IS_LONG)
zend_hash_index_del(current, Z_LVAL_P(offset)); zend_hash_index_del(current, Z_LVAL_P(offset));
else if (Z_TYPE_P(offset) == IS_STRING) else if (Z_TYPE_P(offset) == IS_STRING)
@ -177,7 +174,7 @@ PHP_METHOD(Collection, addAll)
ELEMENTS_VALIDATE(elements); ELEMENTS_VALIDATE(elements);
zend_array* current = COLLECTION_FETCH_EX(); zend_array* current = COLLECTION_FETCH_EX();
ZEND_HASH_FILL_PACKED(current) ZEND_HASH_FILL_PACKED(current)
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(elements), zval* val) ZEND_HASH_FOREACH_VAL(elements_arr, zval* val)
ZEND_HASH_FILL_ADD(val); ZEND_HASH_FILL_ADD(val);
ZEND_HASH_FOREACH_END(); ZEND_HASH_FOREACH_END();
ZEND_HASH_FILL_END(); ZEND_HASH_FILL_END();
@ -258,7 +255,7 @@ PHP_METHOD(Collection, associateTo)
ZEND_PARSE_PARAMETERS_END(); ZEND_PARSE_PARAMETERS_END();
INIT_FCI(); INIT_FCI();
zend_array* current = COLLECTION_FETCH_EX(); zend_array* current = COLLECTION_FETCH_EX();
zend_array* dest_arr = Z_ARRVAL_P(COLLECTION_FETCH(dest)); zend_array* dest_arr = COLLECTION_FETCH(dest);
ZEND_HASH_FOREACH_BUCKET(current, Bucket* bucket) ZEND_HASH_FOREACH_BUCKET(current, Bucket* bucket)
CALLBACK_KEYVAL_INVOKE(params, bucket); CALLBACK_KEYVAL_INVOKE(params, bucket);
if (IS_PAIR(retval)) { if (IS_PAIR(retval)) {
@ -312,7 +309,7 @@ PHP_METHOD(Collection, associateByTo)
ZEND_PARSE_PARAMETERS_END(); ZEND_PARSE_PARAMETERS_END();
INIT_FCI(); INIT_FCI();
zend_array* current = COLLECTION_FETCH_EX(); zend_array* current = COLLECTION_FETCH_EX();
zend_array* dest_arr = Z_ARRVAL_P(COLLECTION_FETCH(dest)); zend_array* dest_arr = COLLECTION_FETCH(dest);
ZEND_HASH_FOREACH_BUCKET(current, Bucket* bucket) ZEND_HASH_FOREACH_BUCKET(current, Bucket* bucket)
CALLBACK_KEYVAL_INVOKE(params, bucket); CALLBACK_KEYVAL_INVOKE(params, bucket);
if (Z_TYPE(retval) == IS_LONG) if (Z_TYPE(retval) == IS_LONG)
@ -351,7 +348,7 @@ PHP_METHOD(Collection, containsAll)
ELEMENTS_VALIDATE(elements); ELEMENTS_VALIDATE(elements);
zval rv; zval rv;
zend_array* current = COLLECTION_FETCH_EX(); zend_array* current = COLLECTION_FETCH_EX();
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(elements), zval* element) ZEND_HASH_FOREACH_VAL(elements_arr, zval* element)
INIT_EQUAL_CHECK_FUNC(element); INIT_EQUAL_CHECK_FUNC(element);
int result = 0; int result = 0;
ZEND_HASH_FOREACH_VAL(current, zval* val) ZEND_HASH_FOREACH_VAL(current, zval* val)
@ -479,7 +476,7 @@ PHP_METHOD(Collection, drop)
ZEND_PARSE_PARAMETERS_END(); ZEND_PARSE_PARAMETERS_END();
if (n < 0) { if (n < 0) {
ERR_BAD_SIZE(); ERR_BAD_SIZE();
RETURN_NULL(); return;
} }
zend_array* current = COLLECTION_FETCH_EX(); zend_array* current = COLLECTION_FETCH_EX();
ARRAY_CLONE(new_collection, current); ARRAY_CLONE(new_collection, current);
@ -501,9 +498,8 @@ PHP_METHOD(Collection, dropLast)
ZEND_PARSE_PARAMETERS_END(); ZEND_PARSE_PARAMETERS_END();
if (n < 0) { if (n < 0) {
ERR_BAD_SIZE(); ERR_BAD_SIZE();
RETURN_NULL(); return;
} }
zval rv;
zend_array* current = COLLECTION_FETCH_EX(); zend_array* current = COLLECTION_FETCH_EX();
ARRAY_CLONE(new_collection, current); ARRAY_CLONE(new_collection, current);
unsigned idx = new_collection->nNumUsed; unsigned idx = new_collection->nNumUsed;
@ -572,8 +568,6 @@ PHP_METHOD(Collection, fill)
Bucket* bucket = current->arData; Bucket* bucket = current->arData;
Bucket* end = bucket + current->nNumUsed; Bucket* end = bucket + current->nNumUsed;
for (bucket += from_idx; num_elements > 0 && bucket < end; ++bucket, --num_elements) { for (bucket += from_idx; num_elements > 0 && bucket < end; ++bucket, --num_elements) {
if (Z_REFCOUNTED(bucket->val))
GC_ADDREF(Z_COUNTED(bucket->val));
if (bucket->key) if (bucket->key)
zend_hash_update(current, bucket->key, element); zend_hash_update(current, bucket->key, element);
else else
@ -634,7 +628,7 @@ PHP_METHOD(Collection, filterNotTo)
ZEND_PARSE_PARAMETERS_END(); ZEND_PARSE_PARAMETERS_END();
INIT_FCI(); INIT_FCI();
zend_array* current = COLLECTION_FETCH_EX(); zend_array* current = COLLECTION_FETCH_EX();
zend_array* dest_arr = Z_ARRVAL_P(COLLECTION_FETCH(dest)); zend_array* dest_arr = COLLECTION_FETCH(dest);
ZEND_HASH_FOREACH_BUCKET(current, Bucket* bucket) ZEND_HASH_FOREACH_BUCKET(current, Bucket* bucket)
CALLBACK_KEYVAL_INVOKE(params, bucket); CALLBACK_KEYVAL_INVOKE(params, bucket);
if (!zend_is_true(&retval)) if (!zend_is_true(&retval))
@ -657,7 +651,7 @@ PHP_METHOD(Collection, filterTo)
ZEND_PARSE_PARAMETERS_END(); ZEND_PARSE_PARAMETERS_END();
INIT_FCI(); INIT_FCI();
zend_array* current = COLLECTION_FETCH_EX(); zend_array* current = COLLECTION_FETCH_EX();
zend_array* dest_arr = Z_ARRVAL_P(COLLECTION_FETCH(dest)); zend_array* dest_arr = COLLECTION_FETCH(dest);
ZEND_HASH_FOREACH_BUCKET(current, Bucket* bucket) ZEND_HASH_FOREACH_BUCKET(current, Bucket* bucket)
CALLBACK_KEYVAL_INVOKE(params, bucket); CALLBACK_KEYVAL_INVOKE(params, bucket);
if (zend_is_true(&retval)) if (zend_is_true(&retval))
@ -707,7 +701,7 @@ PHP_METHOD(Collection, flatMap)
CALLBACK_KEYVAL_INVOKE(params, bucket); CALLBACK_KEYVAL_INVOKE(params, bucket);
zval* retval_p = &retval; zval* retval_p = &retval;
ELEMENTS_VALIDATE(retval_p); ELEMENTS_VALIDATE(retval_p);
ZEND_HASH_FOREACH_BUCKET(Z_ARRVAL_P(retval_p), Bucket* bucket) ZEND_HASH_FOREACH_BUCKET(retval_p_arr, Bucket* bucket)
if (Z_REFCOUNTED(bucket->val)) if (Z_REFCOUNTED(bucket->val))
GC_ADDREF(Z_COUNTED(bucket->val)); GC_ADDREF(Z_COUNTED(bucket->val));
if (bucket->key) if (bucket->key)
@ -731,12 +725,12 @@ PHP_METHOD(Collection, flatMapTo)
ZEND_PARSE_PARAMETERS_END(); ZEND_PARSE_PARAMETERS_END();
INIT_FCI(); INIT_FCI();
zend_array* current = COLLECTION_FETCH_EX(); zend_array* current = COLLECTION_FETCH_EX();
zend_array* dest_arr = Z_ARRVAL_P(COLLECTION_FETCH(dest)); zend_array* dest_arr = COLLECTION_FETCH(dest);
ZEND_HASH_FOREACH_BUCKET(current, Bucket* bucket) ZEND_HASH_FOREACH_BUCKET(current, Bucket* bucket)
CALLBACK_KEYVAL_INVOKE(params, bucket); CALLBACK_KEYVAL_INVOKE(params, bucket);
zval* retval_p = &retval; zval* retval_p = &retval;
ELEMENTS_VALIDATE(retval_p); ELEMENTS_VALIDATE(retval_p);
ZEND_HASH_FOREACH_BUCKET(Z_ARRVAL_P(retval_p), Bucket* bucket) ZEND_HASH_FOREACH_BUCKET(retval_p_arr, Bucket* bucket)
if (Z_REFCOUNTED(bucket->val)) if (Z_REFCOUNTED(bucket->val))
GC_ADDREF(Z_COUNTED(bucket->val)); GC_ADDREF(Z_COUNTED(bucket->val));
if (bucket->key) if (bucket->key)
@ -808,8 +802,7 @@ PHP_METHOD(Collection, init)
ZEND_PARSE_PARAMETERS_END(); ZEND_PARSE_PARAMETERS_END();
if (elements) { if (elements) {
ELEMENTS_VALIDATE(elements); ELEMENTS_VALIDATE(elements);
ARRAY_CLONE(new_collection, Z_ARRVAL_P(elements)); RETURN_NEW_COLLECTION(elements_arr);
RETURN_NEW_COLLECTION(new_collection);
} }
ARRAY_NEW(collection, 0); ARRAY_NEW(collection, 0);
RETVAL_NEW_COLLECTION(collection); RETVAL_NEW_COLLECTION(collection);
@ -1123,10 +1116,9 @@ PHP_METHOD(Collection, takeWhile)
PHP_METHOD(Collection, toArray) PHP_METHOD(Collection, toArray)
{ {
zval rv; zend_array* retval = COLLECTION_FETCH_EX();
zend_array* data = COLLECTION_FETCH_EX(); GC_ADDREF(retval);
GC_ADDREF(data); RETVAL_ARR(retval);
RETVAL_ARR(data);
} }
PHP_METHOD(Collection, toCollection) PHP_METHOD(Collection, toCollection)