Skip to content

Faster phalcon_array_merge_recursive_n() #830

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from Jul 12, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 3 additions & 35 deletions ext/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -292,38 +292,6 @@ PHP_METHOD(Phalcon_Config, offsetUnset){
RETURN_TRUE;
}

static void array_merge_recursive_n(zval **a1, zval *a2 TSRMLS_DC)
{
HashTable *ah2;
HashPosition hp2;
zval **hd;
zval *key = NULL, *value = NULL;
zval *tmp1 = NULL, *tmp2 = NULL;

PHALCON_MM_GROW();

phalcon_is_iterable(a2, &ah2, &hp2, 0, 0);
while (zend_hash_get_current_data_ex(ah2, (void**) &hd, &hp2) == SUCCESS) {
PHALCON_GET_HKEY(key, ah2, hp2);
PHALCON_GET_HVALUE(value);

if (!phalcon_array_isset(*a1, key) || Z_TYPE_P(value) != IS_ARRAY) {
phalcon_array_update_zval(a1, key, &value, PH_COPY | PH_SEPARATE);
}
else {
PHALCON_INIT_NVAR(tmp1);
PHALCON_INIT_NVAR(tmp2);
phalcon_array_fetch(&tmp1, *a1, key, PH_NOISY);
phalcon_array_fetch(&tmp2, a2, key, PH_NOISY);
array_merge_recursive_n(&tmp1, tmp2 TSRMLS_CC);
}

zend_hash_move_forward_ex(ah2, &hp2);
}

PHALCON_MM_RESTORE();
}

/**
* Merges a configuration into the current one
*
Expand Down Expand Up @@ -380,17 +348,17 @@ PHP_METHOD(Phalcon_Config, merge){
else if (Z_TYPE_P(value) == IS_OBJECT && Z_TYPE_P(active_value) == IS_ARRAY) { /* Path AB in the test */
PHALCON_INIT_NVAR(other_array);
phalcon_call_func_p1(other_array, "get_object_vars", value);
array_merge_recursive_n(&active_value, other_array TSRMLS_CC);
phalcon_array_merge_recursive_n(&active_value, other_array);
phalcon_update_property_zval_zval(this_ptr, key, active_value TSRMLS_CC);
}
else if (Z_TYPE_P(value) == IS_ARRAY && Z_TYPE_P(active_value) == IS_OBJECT) { /* Path AC in the test */
PHALCON_INIT_NVAR(other_array);
phalcon_call_func_p1(other_array, "get_object_vars", active_value);
array_merge_recursive_n(&other_array, value TSRMLS_CC);
phalcon_array_merge_recursive_n(&other_array, value);
phalcon_update_property_zval_zval(this_ptr, key, other_array TSRMLS_CC);
}
else if (Z_TYPE_P(value) == IS_ARRAY && Z_TYPE_P(active_value) == IS_ARRAY) { /* Path AD in the test */
array_merge_recursive_n(&active_value, value TSRMLS_CC);
phalcon_array_merge_recursive_n(&active_value, value);
phalcon_update_property_zval_zval(this_ptr, key, active_value TSRMLS_CC);
}
else { /* Path AE in the test */
Expand Down
19 changes: 8 additions & 11 deletions ext/kernel/array.c
Original file line number Diff line number Diff line change
Expand Up @@ -1362,30 +1362,27 @@ void phalcon_fast_array_merge(zval *return_value, zval **array1, zval **array2 T
*
* Equivalent to <tt>$a1 = array_merge_recursive($a1, $a2)</tt> in PHP with the only exception
* that Phalcon's version preserves numeric keys
*
* @todo @c PHALCON_GET_HVALUE() calls @c PHALCON_OBSERVE_VAR; does it mean that the calling function needs a memory frame? Are there any limitations?
*/
void phalcon_array_merge_recursive_n(zval **a1, zval *a2 TSRMLS_DC)
void phalcon_array_merge_recursive_n(zval **a1, zval *a2)
{
HashTable *ah2;
HashPosition hp2;
zval **hd;
zval *key = NULL, *value = NULL;
zval key;
zval *tmp1 = NULL, *tmp2 = NULL;

phalcon_is_iterable(a2, &ah2, &hp2, 0, 0);

while (zend_hash_get_current_data_ex(ah2, (void**) &hd, &hp2) == SUCCESS) {

PHALCON_GET_HKEY(key, ah2, hp2);
PHALCON_GET_HVALUE(value);
key = phalcon_get_current_key_w(ah2, &hp2);

if (!phalcon_array_isset(*a1, key) || Z_TYPE_P(value) != IS_ARRAY) {
phalcon_array_update_zval(a1, key, &value, PH_COPY | PH_SEPARATE);
if (!phalcon_array_isset(*a1, &key) || Z_TYPE_PP(hd) != IS_ARRAY) {
phalcon_array_update_zval(a1, &key, hd, PH_COPY | PH_SEPARATE);
} else {
phalcon_array_fetch(&tmp1, *a1, key, PH_NOISY);
phalcon_array_fetch(&tmp2, a2, key, PH_NOISY);
phalcon_array_merge_recursive_n(&tmp1, tmp2 TSRMLS_CC);
phalcon_array_fetch(&tmp1, *a1, &key, PH_NOISY);
phalcon_array_fetch(&tmp2, a2, &key, PH_NOISY);
phalcon_array_merge_recursive_n(&tmp1, tmp2);
zval_ptr_dtor(&tmp1);
zval_ptr_dtor(&tmp2);
tmp1 = NULL;
Expand Down
2 changes: 1 addition & 1 deletion ext/kernel/array.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,4 @@ extern int phalcon_fast_in_array(zval *needle, zval *haystack TSRMLS_DC);
extern void phalcon_fast_array_merge(zval *return_value, zval **array1, zval **array2 TSRMLS_DC);

/** Recursive merge */
extern void phalcon_array_merge_recursive_n(zval **a1, zval *a2 TSRMLS_DC);
extern void phalcon_array_merge_recursive_n(zval **a1, zval *a2);
21 changes: 20 additions & 1 deletion ext/kernel/hash.c
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,25 @@ void phalcon_get_current_key(zval **key, const HashTable *hash_table, HashPositi

}

zval phalcon_get_current_key_w(const HashTable *hash_table, HashPosition *hash_position)
{
Bucket *p;
zval result;

INIT_ZVAL(result);
p = hash_position ? (*hash_position) : hash_table->pInternalPointer;

if (p) {
if (p->nKeyLength) {
ZVAL_STRINGL(&result, (char *) p->arKey, p->nKeyLength - 1, 0);
} else {
ZVAL_LONG(&result, p->h);
}
}

return result;
}

/**
* Traverses the hash checking if at least one of the keys is numeric
*/
Expand All @@ -159,4 +178,4 @@ int phalcon_has_numeric_keys(const zval *data)
}

return 0;
}
}
1 change: 1 addition & 0 deletions ext/kernel/hash.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,5 @@ int phalcon_hash_quick_exists(const HashTable *ht, const char *arKey, uint nKeyL
int phalcon_hash_find(const HashTable *ht, const char *arKey, uint nKeyLength, void **pData);
int phalcon_hash_quick_find(const HashTable *ht, const char *arKey, uint nKeyLength, ulong h, void **pData);
void phalcon_get_current_key(zval **key, const HashTable *hash_table, HashPosition *hash_position TSRMLS_DC);
zval phalcon_get_current_key_w(const HashTable *hash_table, HashPosition *hash_position);
int phalcon_has_numeric_keys(const zval *data);