Skip to content

Commit aa8ecbe

Browse files
committed
Simplify array_splice()
1 parent c6bc209 commit aa8ecbe

File tree

2 files changed

+49
-68
lines changed

2 files changed

+49
-68
lines changed

ext/standard/array.c

Lines changed: 49 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1907,21 +1907,15 @@ PHP_FUNCTION(shuffle)
19071907
}
19081908
/* }}} */
19091909

1910-
PHPAPI HashTable* php_splice(HashTable *in_hash, int offset, int length, zval *list, int list_count, HashTable *removed) /* {{{ */
1910+
static void php_splice(HashTable *in_hash, int offset, int length, HashTable *replace, HashTable *removed) /* {{{ */
19111911
{
1912-
HashTable *out_hash = NULL; /* Output hashtable */
1912+
HashTable out_hash; /* Output hashtable */
19131913
int num_in, /* Number of entries in the input hashtable */
1914-
pos, /* Current position in the hashtable */
1915-
i; /* Loop counter */
1914+
pos; /* Current position in the hashtable */
19161915
uint idx;
19171916
Bucket *p; /* Pointer to hash bucket */
19181917
zval *entry; /* Hash entry */
19191918

1920-
/* If input hash doesn't exist, we have nothing to do */
1921-
if (!in_hash) {
1922-
return NULL;
1923-
}
1924-
19251919
/* Get number of entries in the input hash */
19261920
num_in = zend_hash_num_elements(in_hash);
19271921

@@ -1940,8 +1934,7 @@ PHPAPI HashTable* php_splice(HashTable *in_hash, int offset, int length, zval *l
19401934
}
19411935

19421936
/* Create and initialize output hash */
1943-
ALLOC_HASHTABLE(out_hash);
1944-
zend_hash_init(out_hash, (length > 0 ? num_in - length : 0) + list_count, NULL, ZVAL_PTR_DTOR, 0);
1937+
zend_hash_init(&out_hash, (length > 0 ? num_in - length : 0) + (replace ? zend_hash_num_elements(replace) : 0), NULL, ZVAL_PTR_DTOR, 0);
19451938

19461939
/* Start at the beginning of the input hash and copy entries to output hash until offset is reached */
19471940
for (pos = 0, idx = 0; pos < offset && idx < in_hash->nNumUsed; idx++) {
@@ -1950,15 +1943,12 @@ PHPAPI HashTable* php_splice(HashTable *in_hash, int offset, int length, zval *l
19501943
pos++;
19511944
/* Get entry and increase reference count */
19521945
entry = &p->val;
1953-
if (Z_REFCOUNTED_P(entry)) {
1954-
Z_ADDREF_P(entry);
1955-
}
19561946

19571947
/* Update output hash depending on key type */
19581948
if (p->key == NULL) {
1959-
zend_hash_next_index_insert(out_hash, entry);
1949+
zend_hash_next_index_insert_new(&out_hash, entry);
19601950
} else {
1961-
zend_hash_update(out_hash, p->key, entry);
1951+
zend_hash_add_new(&out_hash, p->key, entry);
19621952
}
19631953
}
19641954

@@ -1973,42 +1963,59 @@ PHPAPI HashTable* php_splice(HashTable *in_hash, int offset, int length, zval *l
19731963
Z_ADDREF_P(entry);
19741964
}
19751965
if (p->key == NULL) {
1976-
zend_hash_next_index_insert(removed, entry);
1966+
zend_hash_next_index_insert_new(removed, entry);
1967+
zend_hash_index_del(in_hash, p->h);
19771968
} else {
1978-
zend_hash_update(removed, p->key, entry);
1969+
zend_hash_add_new(removed, p->key, entry);
1970+
if (in_hash == &EG(symbol_table).ht) {
1971+
zend_delete_global_variable(p->key);
1972+
} else {
1973+
zend_hash_del(in_hash, p->key);
1974+
}
19791975
}
19801976
}
19811977
} else { /* otherwise just skip those entries */
1982-
for ( ; pos < offset + length && idx < in_hash->nNumUsed; pos++, idx++);
1978+
for ( ; pos < offset + length && idx < in_hash->nNumUsed; idx++) {
1979+
p = in_hash->arData + idx;
1980+
if (Z_TYPE(p->val) == IS_UNDEF) continue;
1981+
pos++;
1982+
if (p->key == NULL) {
1983+
zend_hash_index_del(in_hash, p->h);
1984+
} else {
1985+
if (in_hash == &EG(symbol_table).ht) {
1986+
zend_delete_global_variable(p->key);
1987+
} else {
1988+
zend_hash_del(in_hash, p->key);
1989+
}
1990+
}
1991+
}
19831992
}
19841993

19851994
/* If there are entries to insert.. */
1986-
if (list != NULL) {
1987-
/* ..for each one, create a new zval, copy entry into it and copy it into the output hash */
1988-
for (i = 0; i < list_count; i++) {
1989-
entry = &list[i];
1995+
if (replace) {
1996+
ZEND_HASH_FOREACH_VAL_IND(replace, entry) {
19901997
if (Z_REFCOUNTED_P(entry)) Z_ADDREF_P(entry);
1991-
zend_hash_next_index_insert(out_hash, entry);
1992-
}
1998+
zend_hash_next_index_insert_new(&out_hash, entry);
1999+
} ZEND_HASH_FOREACH_END();
19932000
}
19942001

19952002
/* Copy the remaining input hash entries to the output hash */
19962003
for ( ; idx < in_hash->nNumUsed ; idx++) {
19972004
p = in_hash->arData + idx;
19982005
if (Z_TYPE(p->val) == IS_UNDEF) continue;
19992006
entry = &p->val;
2000-
if (Z_REFCOUNTED_P(entry)) {
2001-
Z_ADDREF_P(entry);
2002-
}
20032007
if (p->key == NULL) {
2004-
zend_hash_next_index_insert(out_hash, entry);
2008+
zend_hash_next_index_insert_new(&out_hash, entry);
20052009
} else {
2006-
zend_hash_update(out_hash, p->key, entry);
2010+
zend_hash_add_new(&out_hash, p->key, entry);
20072011
}
20082012
}
20092013

2010-
zend_hash_internal_pointer_reset(out_hash);
2011-
return out_hash;
2014+
zend_hash_internal_pointer_reset(&out_hash);
2015+
2016+
in_hash->pDestructor = NULL;
2017+
zend_hash_destroy(in_hash);
2018+
*in_hash = out_hash;
20122019
}
20132020
/* }}} */
20142021

@@ -2224,7 +2231,7 @@ PHP_FUNCTION(array_unshift)
22242231
}
22252232
zend_hash_next_index_insert_new(&new_hash, &args[i]);
22262233
}
2227-
ZEND_HASH_FOREACH_STR_KEY_VAL_IND(Z_ARRVAL_P(stack), key, value) {
2234+
ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(stack), key, value) {
22282235
if (key) {
22292236
zend_hash_add_new(&new_hash, key, value);
22302237
} else {
@@ -2246,17 +2253,10 @@ PHP_FUNCTION(array_unshift)
22462253
PHP_FUNCTION(array_splice)
22472254
{
22482255
zval *array, /* Input array */
2249-
*repl_array = NULL, /* Replacement array */
2250-
*repl = NULL; /* Replacement elements */
2251-
HashTable *new_hash = NULL, /* Output array's hash */
2252-
*rem_hash = NULL; /* Removed elements' hash */
2253-
HashTable old_hash;
2254-
uint idx;
2255-
Bucket *p; /* Bucket used for traversing hash */
2256-
zend_long i,
2257-
offset,
2258-
length = 0,
2259-
repl_num = 0; /* Number of replacement elements */
2256+
*repl_array = NULL; /* Replacement array */
2257+
HashTable *rem_hash = NULL;
2258+
zend_long offset,
2259+
length = 0;
22602260
int num_in; /* Number of elements in the input array */
22612261

22622262
if (zend_parse_parameters(ZEND_NUM_ARGS(), "a/l|lz/", &array, &offset, &length, &repl_array) == FAILURE) {
@@ -2271,16 +2271,7 @@ PHP_FUNCTION(array_splice)
22712271

22722272
if (ZEND_NUM_ARGS() == 4) {
22732273
/* Make sure the last argument, if passed, is an array */
2274-
convert_to_array(repl_array);
2275-
2276-
/* Create the array of replacement elements */
2277-
repl_num = zend_hash_num_elements(Z_ARRVAL_P(repl_array));
2278-
repl = (zval *)safe_emalloc(repl_num, sizeof(zval), 0);
2279-
for (idx = 0, i = 0; idx < Z_ARRVAL_P(repl_array)->nNumUsed; idx++) {
2280-
p = Z_ARRVAL_P(repl_array)->arData + idx;
2281-
if (Z_TYPE(p->val) == IS_UNDEF) continue;
2282-
ZVAL_COPY_VALUE(&repl[i++], &p->val);
2283-
}
2274+
convert_to_array_ex(repl_array);
22842275
}
22852276

22862277
/* Don't create the array of removed elements if it's not going
@@ -2308,18 +2299,7 @@ PHP_FUNCTION(array_splice)
23082299
}
23092300

23102301
/* Perform splice */
2311-
new_hash = php_splice(Z_ARRVAL_P(array), (int)offset, (int)length, repl, (int)repl_num, rem_hash);
2312-
2313-
/* Replace input array's hashtable with the new one */
2314-
old_hash = *Z_ARRVAL_P(array);
2315-
*Z_ARRVAL_P(array) = *new_hash;
2316-
FREE_HASHTABLE(new_hash);
2317-
zend_hash_destroy(&old_hash);
2318-
2319-
/* Clean up */
2320-
if (ZEND_NUM_ARGS() == 4) {
2321-
efree(repl);
2322-
}
2302+
php_splice(Z_ARRVAL_P(array), (int)offset, (int)length, repl_array ? Z_ARRVAL_P(repl_array) : NULL, rem_hash);
23232303
}
23242304
/* }}} */
23252305

@@ -3041,7 +3021,9 @@ PHP_FUNCTION(array_pad)
30413021
}
30423022

30433023
ZEND_HASH_FOREACH_STR_KEY_VAL_IND(Z_ARRVAL_P(input), key, value) {
3044-
zval_add_ref(value);
3024+
if (Z_REFCOUNTED_P(value)) {
3025+
Z_ADDREF_P(value);
3026+
}
30453027
if (key) {
30463028
zend_hash_add_new(Z_ARRVAL_P(return_value), key, value);
30473029
} else {

ext/standard/php_array.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,6 @@ PHP_FUNCTION(array_key_exists);
103103
PHP_FUNCTION(array_chunk);
104104
PHP_FUNCTION(array_combine);
105105

106-
PHPAPI HashTable* php_splice(HashTable *, int, int, zval *, int, HashTable *);
107106
PHPAPI int php_array_merge(HashTable *dest, HashTable *src);
108107
PHPAPI int php_array_merge_recursive(HashTable *dest, HashTable *src);
109108
PHPAPI int php_array_replace_recursive(HashTable *dest, HashTable *src);

0 commit comments

Comments
 (0)