diff options
-rw-r--r-- | Zend/zend_hash.c | 154 | ||||
-rw-r--r-- | Zend/zend_hash.h | 5 | ||||
-rw-r--r-- | ext/mysql/php_mysql.c | 21 | ||||
-rw-r--r-- | ext/mysqli/mysqli.c | 21 | ||||
-rw-r--r-- | ext/mysqlnd/mysqlnd_reverse_api.c | 2 | ||||
-rw-r--r-- | ext/mysqlnd/php_mysqlnd.c | 14 | ||||
-rw-r--r-- | ext/pdo/pdo_dbh.c | 18 | ||||
-rw-r--r-- | ext/pdo/pdo_stmt.c | 18 | ||||
-rw-r--r-- | ext/pgsql/pgsql.c | 23 | ||||
-rw-r--r-- | ext/standard/array.c | 218 | ||||
-rw-r--r-- | ext/standard/php_array.h | 2 |
11 files changed, 190 insertions, 306 deletions
diff --git a/Zend/zend_hash.c b/Zend/zend_hash.c index f419e8a571..309631338a 100644 --- a/Zend/zend_hash.c +++ b/Zend/zend_hash.c @@ -29,18 +29,24 @@ (element)->pNext->pLast = (element); \ } -#define CONNECT_TO_GLOBAL_DLLIST(element, ht) \ - (element)->pListLast = (ht)->pListTail; \ - (ht)->pListTail = (element); \ - (element)->pListNext = NULL; \ - if ((element)->pListLast != NULL) { \ - (element)->pListLast->pListNext = (element); \ - } \ - if (!(ht)->pListHead) { \ +#define CONNECT_TO_GLOBAL_DLLIST_EX(element, ht, last, next)\ + (element)->pListLast = (last); \ + (element)->pListNext = (next); \ + if ((last) != NULL) { \ + (last)->pListNext = (element); \ + } else { \ (ht)->pListHead = (element); \ } \ - if ((ht)->pInternalPointer == NULL) { \ - (ht)->pInternalPointer = (element); \ + if ((next) != NULL) { \ + (next)->pListLast = (element); \ + } else { \ + (ht)->pListTail = (element); \ + } \ + +#define CONNECT_TO_GLOBAL_DLLIST(element, ht) \ + CONNECT_TO_GLOBAL_DLLIST_EX(element, ht, (ht)->pListTail, (Bucket *) NULL); \ + if ((ht)->pInternalPointer == NULL) { \ + (ht)->pInternalPointer = (element); \ } #if ZEND_DEBUG @@ -122,13 +128,13 @@ ZEND_API ulong zend_hash_func(const char *arKey, uint nKeyLength) memcpy((p)->pData, pData, nDataSize); \ } -#define INIT_DATA(ht, p, pData, nDataSize); \ +#define INIT_DATA(ht, p, _pData, nDataSize); \ if (nDataSize == sizeof(void*)) { \ - memcpy(&(p)->pDataPtr, pData, sizeof(void *)); \ + memcpy(&(p)->pDataPtr, (_pData), sizeof(void *)); \ (p)->pData = &(p)->pDataPtr; \ } else { \ (p)->pData = (void *) pemalloc_rel(nDataSize, (ht)->persistent);\ - memcpy((p)->pData, pData, nDataSize); \ + memcpy((p)->pData, (_pData), nDataSize); \ (p)->pDataPtr=NULL; \ } @@ -466,16 +472,38 @@ ZEND_API int zend_hash_rehash(HashTable *ht) } memset(ht->arBuckets, 0, ht->nTableSize * sizeof(Bucket *)); - p = ht->pListHead; - while (p != NULL) { + for (p = ht->pListHead; p != NULL; p = p->pListNext) { nIndex = p->h & ht->nTableMask; CONNECT_TO_BUCKET_DLLIST(p, ht->arBuckets[nIndex]); ht->arBuckets[nIndex] = p; - p = p->pListNext; } return SUCCESS; } +ZEND_API void zend_hash_reindex(HashTable *ht, zend_bool only_integer_keys) { + Bucket *p; + uint nIndex; + ulong offset = 0; + + IS_CONSISTENT(ht); + if (UNEXPECTED(ht->nNumOfElements == 0)) { + return; + } + + memset(ht->arBuckets, 0, ht->nTableSize * sizeof(Bucket *)); + for (p = ht->pListHead; p != NULL; p = p->pListNext) { + if (!only_integer_keys || p->nKeyLength == 0) { + p->h = offset++; + p->nKeyLength = 0; + } + + nIndex = p->h & ht->nTableMask; + CONNECT_TO_BUCKET_DLLIST(p, ht->arBuckets[nIndex]); + ht->arBuckets[nIndex] = p; + } + ht->nNextFreeElement = offset; +} + ZEND_API int zend_hash_del_key_or_index(HashTable *ht, const char *arKey, uint nKeyLength, ulong h, int flag) { uint nIndex; @@ -1225,21 +1253,12 @@ ZEND_API int zend_hash_update_current_key_ex(HashTable *ht, int key_type, const q->pData = p->pData; } q->pDataPtr = p->pDataPtr; - q->pListNext = p->pListNext; - q->pListLast = p->pListLast; - if (q->pListNext) { - p->pListNext->pListLast = q; - } else { - ht->pListTail = q; - } - if (q->pListLast) { - p->pListLast->pListNext = q; - } else { - ht->pListHead = q; - } + + CONNECT_TO_GLOBAL_DLLIST_EX(q, ht, p->pListLast, p->pListNext); if (ht->pInternalPointer == p) { ht->pInternalPointer = q; } + if (pos) { *pos = q; } @@ -1270,6 +1289,75 @@ ZEND_API int zend_hash_update_current_key_ex(HashTable *ht, int key_type, const } } +/* Performs an in-place splice operation on a hashtable: + * The elements between offset and offset+length are removed and the elements in list[list_count] + * are inserted in their place. The removed elements can be optionally collected into a hashtable. + * This operation reindexes the hashtable, i.e. integer keys will be zero-based and sequential, + * while string keys stay intact. The same applies to the elements inserted into the removed HT. */ +ZEND_API void _zend_hash_splice(HashTable *ht, uint nDataSize, copy_ctor_func_t pCopyConstructor, uint offset, uint length, void **list, uint list_count, HashTable *removed ZEND_FILE_LINE_DC) /* {{{ */ +{ + int pos; + Bucket *p; + + IS_CONSISTENT(ht); + CHECK_INIT(ht); + + /* Skip all elements until offset */ + for (pos = 0, p = ht->pListHead; pos < offset && p; pos++, p = p->pListNext); + + while (pos < offset + length && p) { + /* Copy removed element into HT, if it was specified */ + if (removed != NULL) { + void *new_entry; + + if (p->nKeyLength == 0) { + zend_hash_next_index_insert(removed, p->pData, sizeof(zval *), &new_entry); + } else { + zend_hash_quick_update(removed, p->arKey, p->nKeyLength, p->h, p->pData, sizeof(zval *), &new_entry); + } + + if (pCopyConstructor) { + pCopyConstructor(new_entry); + } + } + + /* Remove element */ + { + Bucket *p_next = p->pListNext; + zend_hash_bucket_delete(ht, p); + p = p_next; + } + + pos++; + } + + if (list != NULL) { + int i; + for (i = 0; i < list_count; i++) { + /* Add new element only to the global linked list, not the bucket list. + * Also use key 0 for everything, as we'll reindex the hashtable anyways. */ + Bucket *q = pemalloc_rel(sizeof(Bucket), ht->persistent); + q->arKey = NULL; + q->nKeyLength = 0; + q->h = 0; + INIT_DATA(ht, q, list[i], nDataSize); + + CONNECT_TO_GLOBAL_DLLIST_EX(q, ht, p ? p->pListLast : ht->pListTail, p); + + ht->nNumOfElements++; + + if (pCopyConstructor) { + pCopyConstructor(q->pData); + } + } + + ZEND_HASH_IF_FULL_DO_RESIZE(ht); + } + + zend_hash_reindex(ht, 1); +} +/* }}} */ + ZEND_API int zend_hash_sort(HashTable *ht, sort_func_t sort_func, compare_func_t compar, int renumber TSRMLS_DC) { @@ -1316,15 +1404,7 @@ ZEND_API int zend_hash_sort(HashTable *ht, sort_func_t sort_func, HANDLE_UNBLOCK_INTERRUPTIONS(); if (renumber) { - p = ht->pListHead; - i=0; - while (p != NULL) { - p->nKeyLength = 0; - p->h = i++; - p = p->pListNext; - } - ht->nNextFreeElement = i; - zend_hash_rehash(ht); + zend_hash_reindex(ht, 0); } return SUCCESS; } diff --git a/Zend/zend_hash.h b/Zend/zend_hash.h index d990c16674..03f83dfb18 100644 --- a/Zend/zend_hash.h +++ b/Zend/zend_hash.h @@ -227,6 +227,11 @@ ZEND_API int zend_hash_minmax(const HashTable *ht, compare_func_t compar, int fl ZEND_API int zend_hash_num_elements(const HashTable *ht); ZEND_API int zend_hash_rehash(HashTable *ht); +ZEND_API void zend_hash_reindex(HashTable *ht, zend_bool only_integer_keys); + +ZEND_API void _zend_hash_splice(HashTable *ht, uint nDataSize, copy_ctor_func_t pCopyConstructor, uint offset, uint length, void **list, uint list_count, HashTable *removed ZEND_FILE_LINE_DC); +#define zend_hash_splice(ht, nDataSize, pCopyConstructor, offset, length, list, list_count, removed) \ + _zend_hash_splice(ht, nDataSize, pCopyConstructor, offset, length, list, list_count, removed ZEND_FILE_LINE_CC) /* * DJBX33A (Daniel J. Bernstein, Times 33 with Addition) diff --git a/ext/mysql/php_mysql.c b/ext/mysql/php_mysql.c index 3d092b2d6a..daf712cd0d 100644 --- a/ext/mysql/php_mysql.c +++ b/ext/mysql/php_mysql.c @@ -2173,19 +2173,12 @@ static void php_mysql_fetch_hash(INTERNAL_FUNCTION_PARAMETERS, long result_type, fci.symbol_table = NULL; fci.object_ptr = return_value; fci.retval_ptr_ptr = &retval_ptr; + fci.params = NULL; + fci.param_count = 0; + fci.no_separation = 1; + if (ctor_params && Z_TYPE_P(ctor_params) != IS_NULL) { - if (Z_TYPE_P(ctor_params) == IS_ARRAY) { - HashTable *htl = Z_ARRVAL_P(ctor_params); - Bucket *p; - - fci.param_count = 0; - fci.params = safe_emalloc(sizeof(zval*), htl->nNumOfElements, 0); - p = htl->pListHead; - while (p != NULL) { - fci.params[fci.param_count++] = (zval**)p->pData; - p = p->pListNext; - } - } else { + if (zend_fcall_info_args(&fci, ctor_params TSRMLS_CC) == FAILURE) { /* Two problems why we throw exceptions here: PHP is typeless * and hence passing one argument that's not an array could be * by mistake and the other way round is possible, too. The @@ -2195,11 +2188,7 @@ static void php_mysql_fetch_hash(INTERNAL_FUNCTION_PARAMETERS, long result_type, zend_throw_exception(zend_exception_get_default(TSRMLS_C), "Parameter ctor_params must be an array", 0 TSRMLS_CC); return; } - } else { - fci.param_count = 0; - fci.params = NULL; } - fci.no_separation = 1; fcc.initialized = 1; fcc.function_handler = ce->constructor; diff --git a/ext/mysqli/mysqli.c b/ext/mysqli/mysqli.c index 0cea68a33f..c819b976ea 100644 --- a/ext/mysqli/mysqli.c +++ b/ext/mysqli/mysqli.c @@ -1296,19 +1296,12 @@ void php_mysqli_fetch_into_hash(INTERNAL_FUNCTION_PARAMETERS, int override_flags fci.symbol_table = NULL; fci.object_ptr = return_value; fci.retval_ptr_ptr = &retval_ptr; + fci.params = NULL; + fci.param_count = 0; + fci.no_separation = 1; + if (ctor_params && Z_TYPE_P(ctor_params) != IS_NULL) { - if (Z_TYPE_P(ctor_params) == IS_ARRAY) { - HashTable *params_ht = Z_ARRVAL_P(ctor_params); - Bucket *p; - - fci.param_count = 0; - fci.params = safe_emalloc(sizeof(zval*), params_ht->nNumOfElements, 0); - p = params_ht->pListHead; - while (p != NULL) { - fci.params[fci.param_count++] = (zval**)p->pData; - p = p->pListNext; - } - } else { + if (zend_fcall_info_args(&fci, ctor_params TSRMLS_CC) == FAILURE) { /* Two problems why we throw exceptions here: PHP is typeless * and hence passing one argument that's not an array could be * by mistake and the other way round is possible, too. The @@ -1318,11 +1311,7 @@ void php_mysqli_fetch_into_hash(INTERNAL_FUNCTION_PARAMETERS, int override_flags zend_throw_exception(zend_exception_get_default(TSRMLS_C), "Parameter ctor_params must be an array", 0 TSRMLS_CC); return; } - } else { - fci.param_count = 0; - fci.params = NULL; } - fci.no_separation = 1; fcc.initialized = 1; fcc.function_handler = ce->constructor; diff --git a/ext/mysqlnd/mysqlnd_reverse_api.c b/ext/mysqlnd/mysqlnd_reverse_api.c index cd490fa62c..b461b49427 100644 --- a/ext/mysqlnd/mysqlnd_reverse_api.c +++ b/ext/mysqlnd/mysqlnd_reverse_api.c @@ -61,7 +61,7 @@ PHPAPI void mysqlnd_reverse_api_register_api(MYSQLND_REVERSE_API * apiext TSRMLS_DC) { zend_hash_add(&mysqlnd_api_ext_ht, apiext->module->name, strlen(apiext->module->name) + 1, &apiext, - sizeof(MYSQLND_REVERSE_API), NULL); + sizeof(MYSQLND_REVERSE_API *), NULL); } /* }}} */ diff --git a/ext/mysqlnd/php_mysqlnd.c b/ext/mysqlnd/php_mysqlnd.c index 7712f1ecb8..1a4e67f5eb 100644 --- a/ext/mysqlnd/php_mysqlnd.c +++ b/ext/mysqlnd/php_mysqlnd.c @@ -107,17 +107,17 @@ static void mysqlnd_minfo_dump_api_plugins(smart_str * buffer TSRMLS_DC) { HashTable *ht = mysqlnd_reverse_api_get_api_list(TSRMLS_C); - Bucket *p; + HashPosition pos; + MYSQLND_REVERSE_API **ext; - p = ht->pListHead; - while(p != NULL) { - MYSQLND_REVERSE_API * ext = *(MYSQLND_REVERSE_API **) p->pData; + for (zend_hash_internal_pointer_reset_ex(ht, &pos); + zend_hash_get_current_data_ex(ht, (void **) &ext, &pos); + zend_hash_move_forward_ex(ht, &pos) + ) { if (buffer->len) { smart_str_appendc(buffer, ','); } - smart_str_appends(buffer, ext->module->name); - - p = p->pListNext; + smart_str_appends(buffer, (*ext)->module->name); } } /* }}} */ diff --git a/ext/pdo/pdo_dbh.c b/ext/pdo/pdo_dbh.c index d17867d1f9..32e6e1bdd0 100644 --- a/ext/pdo/pdo_dbh.c +++ b/ext/pdo/pdo_dbh.c @@ -468,23 +468,11 @@ static void pdo_stmt_construct(pdo_stmt_t *stmt, zval *object, zend_class_entry fci.object_ptr = object; fci.symbol_table = NULL; fci.retval_ptr_ptr = &retval; - if (ctor_args) { - HashTable *ht = Z_ARRVAL_P(ctor_args); - Bucket *p; - - fci.param_count = 0; - fci.params = safe_emalloc(sizeof(zval*), ht->nNumOfElements, 0); - p = ht->pListHead; - while (p != NULL) { - fci.params[fci.param_count++] = (zval**)p->pData; - p = p->pListNext; - } - } else { - fci.param_count = 0; - fci.params = NULL; - } + fci.params = NULL; fci.no_separation = 1; + zend_fcall_info_args(&fci, ctor_args TSRMLS_CC); + fcc.initialized = 1; fcc.function_handler = dbstmt_ce->constructor; fcc.calling_scope = EG(scope); diff --git a/ext/pdo/pdo_stmt.c b/ext/pdo/pdo_stmt.c index 2735aede41..2593d02e96 100644 --- a/ext/pdo/pdo_stmt.c +++ b/ext/pdo/pdo_stmt.c @@ -757,23 +757,11 @@ static int do_fetch_class_prepare(pdo_stmt_t *stmt TSRMLS_DC) /* {{{ */ fci->function_name = NULL; fci->symbol_table = NULL; fci->retval_ptr_ptr = &stmt->fetch.cls.retval_ptr; - if (stmt->fetch.cls.ctor_args) { - HashTable *ht = Z_ARRVAL_P(stmt->fetch.cls.ctor_args); - Bucket *p; - - fci->param_count = 0; - fci->params = safe_emalloc(sizeof(zval**), ht->nNumOfElements, 0); - p = ht->pListHead; - while (p != NULL) { - fci->params[fci->param_count++] = (zval**)p->pData; - p = p->pListNext; - } - } else { - fci->param_count = 0; - fci->params = NULL; - } + fci->params = NULL; fci->no_separation = 1; + zend_fcall_info_args(fci, stmt->fetch.cls.ctor_args TSRMLS_CC); + fcc->initialized = 1; fcc->function_handler = ce->constructor; fcc->calling_scope = EG(scope); diff --git a/ext/pgsql/pgsql.c b/ext/pgsql/pgsql.c index f5e142a775..d36901d8c1 100644 --- a/ext/pgsql/pgsql.c +++ b/ext/pgsql/pgsql.c @@ -2793,33 +2793,22 @@ static void php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAMETERS, long result_type, fci.symbol_table = NULL; fci.object_ptr = return_value; fci.retval_ptr_ptr = &retval_ptr; + fci.params = NULL; + fci.param_count = 0; + fci.no_separation = 1; + if (ctor_params && Z_TYPE_P(ctor_params) != IS_NULL) { - if (Z_TYPE_P(ctor_params) == IS_ARRAY) { - HashTable *ht = Z_ARRVAL_P(ctor_params); - Bucket *p; - - fci.param_count = 0; - fci.params = safe_emalloc(sizeof(zval***), ht->nNumOfElements, 0); - p = ht->pListHead; - while (p != NULL) { - fci.params[fci.param_count++] = (zval**)p->pData; - p = p->pListNext; - } - } else { + if (zend_fcall_info_args(&fci, ctor_params TSRMLS_CC) == FAILURE) { /* Two problems why we throw exceptions here: PHP is typeless * and hence passing one argument that's not an array could be - * by mistake and the other way round is possible, too. The + * by mistake and the other way round is possible, too. The * single value is an array. Also we'd have to make that one * argument passed by reference. */ zend_throw_exception(zend_exception_get_default(TSRMLS_C), "Parameter ctor_params must be an array", 0 TSRMLS_CC); return; } - } else { - fci.param_count = 0; - fci.params = NULL; } - fci.no_separation = 1; fcc.initialized = 1; fcc.function_handler = ce->constructor; diff --git a/ext/standard/array.c b/ext/standard/array.c index 6642bc2c7b..cfa861e012 100644 --- a/ext/standard/array.c +++ b/ext/standard/array.c @@ -1786,13 +1786,7 @@ static void php_array_data_shuffle(zval *array TSRMLS_DC) /* {{{ */ } temp = hash->pListHead; j = 0; - while (temp != NULL) { - temp->nKeyLength = 0; - temp->h = j++; - temp = temp->pListNext; - } - hash->nNextFreeElement = n_elems; - zend_hash_rehash(hash); + zend_hash_reindex(hash, 0); HANDLE_UNBLOCK_INTERRUPTIONS(); efree(elems); @@ -1815,93 +1809,15 @@ PHP_FUNCTION(shuffle) } /* }}} */ -PHPAPI HashTable* php_splice(HashTable *in_hash, int offset, int length, zval ***list, int list_count, HashTable **removed) /* {{{ */ +PHPAPI void php_splice(HashTable *ht, zend_uint offset, zend_uint length, zval ***list, zend_uint list_count, HashTable *removed TSRMLS_DC) /* {{{ */ { - HashTable *out_hash = NULL; /* Output hashtable */ - int num_in, /* Number of entries in the input hashtable */ - pos, /* Current position in the hashtable */ - i; /* Loop counter */ - Bucket *p; /* Pointer to hash bucket */ - zval *entry; /* Hash entry */ - - /* If input hash doesn't exist, we have nothing to do */ - if (!in_hash) { - return NULL; - } - - /* Get number of entries in the input hash */ - num_in = zend_hash_num_elements(in_hash); + zend_hash_splice(ht, sizeof(zval *), (copy_ctor_func_t) zval_add_ref, offset, length, (void **) list, list_count, removed); - /* Clamp the offset.. */ - if (offset > num_in) { - offset = num_in; - } else if (offset < 0 && (offset = (num_in + offset)) < 0) { - offset = 0; - } - - /* ..and the length */ - if (length < 0) { - length = num_in - offset + length; - } else if (((unsigned)offset + (unsigned)length) > (unsigned)num_in) { - length = num_in - offset; - } - - /* Create and initialize output hash */ - ALLOC_HASHTABLE(out_hash); - zend_hash_init(out_hash, (length > 0 ? num_in - length : 0) + list_count, NULL, ZVAL_PTR_DTOR, 0); - - /* Start at the beginning of the input hash and copy entries to output hash until offset is reached */ - for (pos = 0, p = in_hash->pListHead; pos < offset && p ; pos++, p = p->pListNext) { - /* Get entry and increase reference count */ - entry = *((zval **)p->pData); - Z_ADDREF_P(entry); - - /* Update output hash depending on key type */ - if (p->nKeyLength == 0) { - zend_hash_next_index_insert(out_hash, &entry, sizeof(zval *), NULL); - } else { - zend_hash_quick_update(out_hash, p->arKey, p->nKeyLength, p->h, &entry, sizeof(zval *), NULL); - } - } - - /* If hash for removed entries exists, go until offset+length and copy the entries to it */ - if (removed != NULL) { - for ( ; pos < offset + length && p; pos++, p = p->pListNext) { - entry = *((zval **)p->pData); - Z_ADDREF_P(entry); - if (p->nKeyLength == 0) { - zend_hash_next_index_insert(*removed, &entry, sizeof(zval *), NULL); - } else { - zend_hash_quick_update(*removed, p->arKey, p->nKeyLength, p->h, &entry, sizeof(zval *), NULL); - } - } - } else { /* otherwise just skip those entries */ - for ( ; pos < offset + length && p; pos++, p = p->pListNext); - } - - /* If there are entries to insert.. */ - if (list != NULL) { - /* ..for each one, create a new zval, copy entry into it and copy it into the output hash */ - for (i = 0; i < list_count; i++) { - entry = *list[i]; - Z_ADDREF_P(entry); - zend_hash_next_index_insert(out_hash, &entry, sizeof(zval *), NULL); - } - } + zend_hash_internal_pointer_reset(ht); - /* Copy the remaining input hash entries to the output hash */ - for ( ; p ; p = p->pListNext) { - entry = *((zval **)p->pData); - Z_ADDREF_P(entry); - if (p->nKeyLength == 0) { - zend_hash_next_index_insert(out_hash, &entry, sizeof(zval *), NULL); - } else { - zend_hash_quick_update(out_hash, p->arKey, p->nKeyLength, p->h, &entry, sizeof(zval *), NULL); - } + if (ht == &EG(symbol_table)) { + zend_reset_all_cv(&EG(symbol_table) TSRMLS_CC); } - - zend_hash_internal_pointer_reset(out_hash); - return out_hash; } /* }}} */ @@ -1975,24 +1891,7 @@ static void _phpi_pop(INTERNAL_FUNCTION_PARAMETERS, int off_the_end) /* If we did a shift... re-index like it did before */ if (!off_the_end) { - unsigned int k = 0; - int should_rehash = 0; - Bucket *p = Z_ARRVAL_P(stack)->pListHead; - while (p != NULL) { - if (p->nKeyLength == 0) { - if (p->h != k) { - p->h = k++; - should_rehash = 1; - } else { - k++; - } - } - p = p->pListNext; - } - Z_ARRVAL_P(stack)->nNextFreeElement = k; - if (should_rehash) { - zend_hash_rehash(Z_ARRVAL_P(stack)); - } + zend_hash_reindex(Z_ARRVAL_P(stack), 1); } else if (!key_len && index >= Z_ARRVAL_P(stack)->nNextFreeElement - 1) { Z_ARRVAL_P(stack)->nNextFreeElement = Z_ARRVAL_P(stack)->nNextFreeElement - 1; } @@ -2023,24 +1922,14 @@ PHP_FUNCTION(array_unshift) { zval ***args, /* Function arguments array */ *stack; /* Input stack */ - HashTable *new_hash; /* New hashtable for the stack */ - HashTable old_hash; int argc; /* Number of function arguments */ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a+", &stack, &args, &argc) == FAILURE) { return; } - /* Use splice to insert the elements at the beginning. Destroy old - * hashtable and replace it with new one */ - new_hash = php_splice(Z_ARRVAL_P(stack), 0, 0, &args[0], argc, NULL); - old_hash = *Z_ARRVAL_P(stack); - if (Z_ARRVAL_P(stack) == &EG(symbol_table)) { - zend_reset_all_cv(&EG(symbol_table) TSRMLS_CC); - } - *Z_ARRVAL_P(stack) = *new_hash; - FREE_HASHTABLE(new_hash); - zend_hash_destroy(&old_hash); + /* Use splice to insert the elements at the beginning. */ + php_splice(Z_ARRVAL_P(stack), 0, 0, args, argc, NULL TSRMLS_CC); /* Clean up and return the number of elements in the stack */ efree(args); @@ -2053,11 +1942,9 @@ PHP_FUNCTION(array_unshift) PHP_FUNCTION(array_splice) { zval *array, /* Input array */ - *repl_array = NULL, /* Replacement array */ + **repl_array = NULL, /* Replacement array */ ***repl = NULL; /* Replacement elements */ - HashTable *new_hash = NULL, /* Output array's hash */ - **rem_hash = NULL; /* Removed elements' hash */ - HashTable old_hash; + HashTable *rem_hash = NULL; /* Removed elements' hash */ Bucket *p; /* Bucket used for traversing hash */ long i, offset, @@ -2065,7 +1952,7 @@ PHP_FUNCTION(array_splice) repl_num = 0; /* Number of replacement elements */ int num_in; /* Number of elements in the input array */ - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "al|lz/", &array, &offset, &length, &repl_array) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "al|lZ", &array, &offset, &length, &repl_array) == FAILURE) { return; } @@ -2075,56 +1962,44 @@ PHP_FUNCTION(array_splice) length = num_in; } - if (ZEND_NUM_ARGS() == 4) { + if (repl_array) { /* Make sure the last argument, if passed, is an array */ - convert_to_array(repl_array); + convert_to_array_ex(repl_array); /* Create the array of replacement elements */ - repl_num = zend_hash_num_elements(Z_ARRVAL_P(repl_array)); + repl_num = zend_hash_num_elements(Z_ARRVAL_PP(repl_array)); repl = (zval ***)safe_emalloc(repl_num, sizeof(zval **), 0); - for (p = Z_ARRVAL_P(repl_array)->pListHead, i = 0; p; p = p->pListNext, i++) { + for (p = Z_ARRVAL_PP(repl_array)->pListHead, i = 0; p; p = p->pListNext, i++) { repl[i] = ((zval **)p->pData); } } + /* Clamp the offset */ + if (offset < 0 && (offset = num_in + offset) < 0) { + offset = 0; + } else if (offset > num_in) { + offset = num_in; + } + + /* Clamp the length */ + if (length < 0 && (length = num_in - offset + length) < 0) { + length = 0; + } else if ((unsigned long) offset + (unsigned long) length > (unsigned) num_in) { + length = num_in - offset; + } + /* Don't create the array of removed elements if it's not going * to be used; e.g. only removing and/or replacing elements */ if (return_value_used) { - int size = length; - - /* Clamp the offset.. */ - if (offset > num_in) { - offset = num_in; - } else if (offset < 0 && (offset = (num_in + offset)) < 0) { - offset = 0; - } - - /* ..and the length */ - if (length < 0) { - size = num_in - offset + length; - } else if (((unsigned long) offset + (unsigned long) length) > (unsigned) num_in) { - size = num_in - offset; - } - - /* Initialize return value */ - array_init_size(return_value, size > 0 ? size : 0); - rem_hash = &Z_ARRVAL_P(return_value); + array_init_size(return_value, length); + rem_hash = Z_ARRVAL_P(return_value); } /* Perform splice */ - new_hash = php_splice(Z_ARRVAL_P(array), offset, length, repl, repl_num, rem_hash); - - /* Replace input array's hashtable with the new one */ - old_hash = *Z_ARRVAL_P(array); - if (Z_ARRVAL_P(array) == &EG(symbol_table)) { - zend_reset_all_cv(&EG(symbol_table) TSRMLS_CC); - } - *Z_ARRVAL_P(array) = *new_hash; - FREE_HASHTABLE(new_hash); - zend_hash_destroy(&old_hash); + php_splice(Z_ARRVAL_P(array), offset, length, repl, repl_num, rem_hash TSRMLS_CC); /* Clean up */ - if (ZEND_NUM_ARGS() == 4) { + if (repl) { efree(repl); } } @@ -2686,8 +2561,6 @@ PHP_FUNCTION(array_pad) zval *input; /* Input array */ zval *pad_value; /* Padding value obviously */ zval ***pads; /* Array to pass to splice */ - HashTable *new_hash;/* Return value from splice */ - HashTable old_hash; long pad_size; /* Size to pad to */ long pad_size_abs; /* Absolute value of pad_size */ int input_size; /* Size of the input array */ @@ -2731,19 +2604,10 @@ PHP_FUNCTION(array_pad) /* Pad on the right or on the left */ if (pad_size > 0) { - new_hash = php_splice(Z_ARRVAL_P(return_value), input_size, 0, pads, num_pads, NULL); + php_splice(Z_ARRVAL_P(return_value), input_size, 0, pads, num_pads, NULL TSRMLS_CC); } else { - new_hash = php_splice(Z_ARRVAL_P(return_value), 0, 0, pads, num_pads, NULL); - } - - /* Copy the result hash into return value */ - old_hash = *Z_ARRVAL_P(return_value); - if (Z_ARRVAL_P(return_value) == &EG(symbol_table)) { - zend_reset_all_cv(&EG(symbol_table) TSRMLS_CC); + php_splice(Z_ARRVAL_P(return_value), 0, 0, pads, num_pads, NULL TSRMLS_CC); } - *Z_ARRVAL_P(return_value) = *new_hash; - FREE_HASHTABLE(new_hash); - zend_hash_destroy(&old_hash); /* Clean up */ efree(pads); @@ -3978,15 +3842,7 @@ PHP_FUNCTION(array_multisort) hash->pListTail = indirect[k][i]; } - p = hash->pListHead; - k = 0; - while (p != NULL) { - if (p->nKeyLength == 0) - p->h = k++; - p = p->pListNext; - } - hash->nNextFreeElement = array_size; - zend_hash_rehash(hash); + zend_hash_reindex(hash, 1); } HANDLE_UNBLOCK_INTERRUPTIONS(); diff --git a/ext/standard/php_array.h b/ext/standard/php_array.h index c4389dd92a..deddeb4871 100644 --- a/ext/standard/php_array.h +++ b/ext/standard/php_array.h @@ -103,7 +103,7 @@ PHP_FUNCTION(array_key_exists); PHP_FUNCTION(array_chunk); PHP_FUNCTION(array_combine); -PHPAPI HashTable* php_splice(HashTable *, int, int, zval ***, int, HashTable **); +PHPAPI void php_splice(HashTable *ht, zend_uint offset, zend_uint length, zval ***list, zend_uint list_count, HashTable *removed TSRMLS_DC); PHPAPI int php_array_merge(HashTable *dest, HashTable *src, int recursive TSRMLS_DC); PHPAPI int php_array_replace_recursive(HashTable *dest, HashTable *src TSRMLS_DC); PHPAPI int php_multisort_compare(const void *a, const void *b TSRMLS_DC); |