diff options
Diffstat (limited to 'ext/standard/array.c')
-rw-r--r-- | ext/standard/array.c | 218 |
1 files changed, 37 insertions, 181 deletions
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(); |