summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Zend/zend_hash.c154
-rw-r--r--Zend/zend_hash.h5
-rw-r--r--ext/mysql/php_mysql.c21
-rw-r--r--ext/mysqli/mysqli.c21
-rw-r--r--ext/mysqlnd/mysqlnd_reverse_api.c2
-rw-r--r--ext/mysqlnd/php_mysqlnd.c14
-rw-r--r--ext/pdo/pdo_dbh.c18
-rw-r--r--ext/pdo/pdo_stmt.c18
-rw-r--r--ext/pgsql/pgsql.c23
-rw-r--r--ext/standard/array.c218
-rw-r--r--ext/standard/php_array.h2
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);