Skip to content

Commit dfbc874

Browse files
committed
Merge remote-tracking branch 'origin/str_size_and_int64_56_backport' into str_size_and_int64
* origin/str_size_and_int64_56_backport: fix prototype fix typo fix typo fix typo add a NEWS block for beta2 add missing entries to NEWS abstract namespace for unix sockets is a linux only feature Don't test for specific non-zero substr_compare() return value Add only_integer_keys option to zend_hash_reindex Don't always separate splice replacement array Add zend_hash_splice Add zend_hash_reindex Remove some usages of hashtable internals Updated NEWS fixed bug66702 : regexiterator's invert flag doesn't work as expected
2 parents b0ddef8 + 9112c2f commit dfbc874

File tree

15 files changed

+237
-311
lines changed

15 files changed

+237
-311
lines changed

Zend/zend_hash.c

Lines changed: 117 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -29,18 +29,24 @@
2929
(element)->pNext->pLast = (element); \
3030
}
3131

32-
#define CONNECT_TO_GLOBAL_DLLIST(element, ht) \
33-
(element)->pListLast = (ht)->pListTail; \
34-
(ht)->pListTail = (element); \
35-
(element)->pListNext = NULL; \
36-
if ((element)->pListLast != NULL) { \
37-
(element)->pListLast->pListNext = (element); \
38-
} \
39-
if (!(ht)->pListHead) { \
32+
#define CONNECT_TO_GLOBAL_DLLIST_EX(element, ht, last, next)\
33+
(element)->pListLast = (last); \
34+
(element)->pListNext = (next); \
35+
if ((last) != NULL) { \
36+
(last)->pListNext = (element); \
37+
} else { \
4038
(ht)->pListHead = (element); \
4139
} \
42-
if ((ht)->pInternalPointer == NULL) { \
43-
(ht)->pInternalPointer = (element); \
40+
if ((next) != NULL) { \
41+
(next)->pListLast = (element); \
42+
} else { \
43+
(ht)->pListTail = (element); \
44+
} \
45+
46+
#define CONNECT_TO_GLOBAL_DLLIST(element, ht) \
47+
CONNECT_TO_GLOBAL_DLLIST_EX(element, ht, (ht)->pListTail, (Bucket *) NULL); \
48+
if ((ht)->pInternalPointer == NULL) { \
49+
(ht)->pInternalPointer = (element); \
4450
}
4551

4652
#if ZEND_DEBUG
@@ -122,13 +128,13 @@ ZEND_API zend_uint_t zend_hash_func(const char *arKey, zend_size_t nKeyLength)
122128
memcpy((p)->pData, pData, nDataSize); \
123129
}
124130

125-
#define INIT_DATA(ht, p, pData, nDataSize); \
131+
#define INIT_DATA(ht, p, _pData, nDataSize); \
126132
if (nDataSize == sizeof(void*)) { \
127-
memcpy(&(p)->pDataPtr, pData, sizeof(void *)); \
133+
memcpy(&(p)->pDataPtr, (_pData), sizeof(void *)); \
128134
(p)->pData = &(p)->pDataPtr; \
129135
} else { \
130136
(p)->pData = (void *) pemalloc_rel(nDataSize, (ht)->persistent);\
131-
memcpy((p)->pData, pData, nDataSize); \
137+
memcpy((p)->pData, (_pData), nDataSize); \
132138
(p)->pDataPtr=NULL; \
133139
}
134140

@@ -466,16 +472,38 @@ ZEND_API int zend_hash_rehash(HashTable *ht)
466472
}
467473

468474
memset(ht->arBuckets, 0, ht->nTableSize * sizeof(Bucket *));
469-
p = ht->pListHead;
470-
while (p != NULL) {
475+
for (p = ht->pListHead; p != NULL; p = p->pListNext) {
471476
nIndex = p->h & ht->nTableMask;
472477
CONNECT_TO_BUCKET_DLLIST(p, ht->arBuckets[nIndex]);
473478
ht->arBuckets[nIndex] = p;
474-
p = p->pListNext;
475479
}
476480
return SUCCESS;
477481
}
478482

483+
ZEND_API void zend_hash_reindex(HashTable *ht, zend_bool only_integer_keys) {
484+
Bucket *p;
485+
zend_uint_t nIndex;
486+
zend_uint_t offset = 0;
487+
488+
IS_CONSISTENT(ht);
489+
if (UNEXPECTED(ht->nNumOfElements == 0)) {
490+
return;
491+
}
492+
493+
memset(ht->arBuckets, 0, ht->nTableSize * sizeof(Bucket *));
494+
for (p = ht->pListHead; p != NULL; p = p->pListNext) {
495+
if (!only_integer_keys || p->nKeyLength == 0) {
496+
p->h = offset++;
497+
p->nKeyLength = 0;
498+
}
499+
500+
nIndex = p->h & ht->nTableMask;
501+
CONNECT_TO_BUCKET_DLLIST(p, ht->arBuckets[nIndex]);
502+
ht->arBuckets[nIndex] = p;
503+
}
504+
ht->nNextFreeElement = offset;
505+
}
506+
479507
ZEND_API int zend_hash_del_key_or_index(HashTable *ht, const char *arKey, zend_size_t nKeyLength, zend_uint_t h, int flag)
480508
{
481509
zend_uint_t nIndex;
@@ -1225,21 +1253,12 @@ ZEND_API int zend_hash_update_current_key_ex(HashTable *ht, int key_type, const
12251253
q->pData = p->pData;
12261254
}
12271255
q->pDataPtr = p->pDataPtr;
1228-
q->pListNext = p->pListNext;
1229-
q->pListLast = p->pListLast;
1230-
if (q->pListNext) {
1231-
p->pListNext->pListLast = q;
1232-
} else {
1233-
ht->pListTail = q;
1234-
}
1235-
if (q->pListLast) {
1236-
p->pListLast->pListNext = q;
1237-
} else {
1238-
ht->pListHead = q;
1239-
}
1256+
1257+
CONNECT_TO_GLOBAL_DLLIST_EX(q, ht, p->pListLast, p->pListNext);
12401258
if (ht->pInternalPointer == p) {
12411259
ht->pInternalPointer = q;
12421260
}
1261+
12431262
if (pos) {
12441263
*pos = q;
12451264
}
@@ -1270,6 +1289,75 @@ ZEND_API int zend_hash_update_current_key_ex(HashTable *ht, int key_type, const
12701289
}
12711290
}
12721291

1292+
/* Performs an in-place splice operation on a hashtable:
1293+
* The elements between offset and offset+length are removed and the elements in list[list_count]
1294+
* are inserted in their place. The removed elements can be optionally collected into a hashtable.
1295+
* This operation reindexes the hashtable, i.e. integer keys will be zero-based and sequential,
1296+
* while string keys stay intact. The same applies to the elements inserted into the removed HT. */
1297+
ZEND_API void _zend_hash_splice(HashTable *ht, zend_uint_t nDataSize, copy_ctor_func_t pCopyConstructor, zend_uint_t offset, zend_size_t length, void **list, zend_size_t list_count, HashTable *removed ZEND_FILE_LINE_DC) /* {{{ */
1298+
{
1299+
zend_size_t pos;
1300+
Bucket *p;
1301+
1302+
IS_CONSISTENT(ht);
1303+
CHECK_INIT(ht);
1304+
1305+
/* Skip all elements until offset */
1306+
for (pos = 0, p = ht->pListHead; pos < offset && p; pos++, p = p->pListNext);
1307+
1308+
while (pos < offset + length && p) {
1309+
/* Copy removed element into HT, if it was specified */
1310+
if (removed != NULL) {
1311+
void *new_entry;
1312+
1313+
if (p->nKeyLength == 0) {
1314+
zend_hash_next_index_insert(removed, p->pData, sizeof(zval *), &new_entry);
1315+
} else {
1316+
zend_hash_quick_update(removed, p->arKey, p->nKeyLength, p->h, p->pData, sizeof(zval *), &new_entry);
1317+
}
1318+
1319+
if (pCopyConstructor) {
1320+
pCopyConstructor(new_entry);
1321+
}
1322+
}
1323+
1324+
/* Remove element */
1325+
{
1326+
Bucket *p_next = p->pListNext;
1327+
zend_hash_bucket_delete(ht, p);
1328+
p = p_next;
1329+
}
1330+
1331+
pos++;
1332+
}
1333+
1334+
if (list != NULL) {
1335+
zend_size_t i;
1336+
for (i = 0; i < list_count; i++) {
1337+
/* Add new element only to the global linked list, not the bucket list.
1338+
* Also use key 0 for everything, as we'll reindex the hashtable anyways. */
1339+
Bucket *q = pemalloc_rel(sizeof(Bucket), ht->persistent);
1340+
q->arKey = NULL;
1341+
q->nKeyLength = 0;
1342+
q->h = 0;
1343+
INIT_DATA(ht, q, list[i], nDataSize);
1344+
1345+
CONNECT_TO_GLOBAL_DLLIST_EX(q, ht, p ? p->pListLast : ht->pListTail, p);
1346+
1347+
ht->nNumOfElements++;
1348+
1349+
if (pCopyConstructor) {
1350+
pCopyConstructor(q->pData);
1351+
}
1352+
}
1353+
1354+
ZEND_HASH_IF_FULL_DO_RESIZE(ht);
1355+
}
1356+
1357+
zend_hash_reindex(ht, 1);
1358+
}
1359+
/* }}} */
1360+
12731361
ZEND_API int zend_hash_sort(HashTable *ht, sort_func_t sort_func,
12741362
compare_func_t compar, int renumber TSRMLS_DC)
12751363
{
@@ -1316,15 +1404,7 @@ ZEND_API int zend_hash_sort(HashTable *ht, sort_func_t sort_func,
13161404
HANDLE_UNBLOCK_INTERRUPTIONS();
13171405

13181406
if (renumber) {
1319-
p = ht->pListHead;
1320-
i=0;
1321-
while (p != NULL) {
1322-
p->nKeyLength = 0;
1323-
p->h = i++;
1324-
p = p->pListNext;
1325-
}
1326-
ht->nNextFreeElement = i;
1327-
zend_hash_rehash(ht);
1407+
zend_hash_reindex(ht, 0);
13281408
}
13291409
return SUCCESS;
13301410
}

Zend/zend_hash.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,11 @@ ZEND_API int zend_hash_minmax(const HashTable *ht, compare_func_t compar, int fl
227227
ZEND_API zend_uint_t zend_hash_num_elements(const HashTable *ht);
228228

229229
ZEND_API int zend_hash_rehash(HashTable *ht);
230+
ZEND_API void zend_hash_reindex(HashTable *ht, zend_bool only_integer_keys);
231+
232+
ZEND_API void _zend_hash_splice(HashTable *ht, zend_uint_t nDataSize, copy_ctor_func_t pCopyConstructor, zend_uint_t offset, zend_size_t length, void **list, zend_size_t list_count, HashTable *removed ZEND_FILE_LINE_DC);
233+
#define zend_hash_splice(ht, nDataSize, pCopyConstructor, offset, length, list, list_count, removed) \
234+
_zend_hash_splice(ht, nDataSize, pCopyConstructor, offset, length, list, list_count, removed ZEND_FILE_LINE_CC)
230235

231236
/*
232237
* DJBX33A (Daniel J. Bernstein, Times 33 with Addition)

ext/mysql/php_mysql.c

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2176,19 +2176,12 @@ static void php_mysql_fetch_hash(INTERNAL_FUNCTION_PARAMETERS, php_int_t result_
21762176
fci.symbol_table = NULL;
21772177
fci.object_ptr = return_value;
21782178
fci.retval_ptr_ptr = &retval_ptr;
2179+
fci.params = NULL;
2180+
fci.param_count = 0;
2181+
fci.no_separation = 1;
2182+
21792183
if (ctor_params && Z_TYPE_P(ctor_params) != IS_NULL) {
2180-
if (Z_TYPE_P(ctor_params) == IS_ARRAY) {
2181-
HashTable *htl = Z_ARRVAL_P(ctor_params);
2182-
Bucket *p;
2183-
2184-
fci.param_count = 0;
2185-
fci.params = safe_emalloc(sizeof(zval*), htl->nNumOfElements, 0);
2186-
p = htl->pListHead;
2187-
while (p != NULL) {
2188-
fci.params[fci.param_count++] = (zval**)p->pData;
2189-
p = p->pListNext;
2190-
}
2191-
} else {
2184+
if (zend_fcall_info_args(&fci, ctor_params TSRMLS_CC) == FAILURE) {
21922185
/* Two problems why we throw exceptions here: PHP is typeless
21932186
* and hence passing one argument that's not an array could be
21942187
* by mistake and the other way round is possible, too. The
@@ -2198,11 +2191,7 @@ static void php_mysql_fetch_hash(INTERNAL_FUNCTION_PARAMETERS, php_int_t result_
21982191
zend_throw_exception(zend_exception_get_default(TSRMLS_C), "Parameter ctor_params must be an array", 0 TSRMLS_CC);
21992192
return;
22002193
}
2201-
} else {
2202-
fci.param_count = 0;
2203-
fci.params = NULL;
22042194
}
2205-
fci.no_separation = 1;
22062195

22072196
fcc.initialized = 1;
22082197
fcc.function_handler = ce->constructor;

ext/mysqli/mysqli.c

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1296,19 +1296,12 @@ void php_mysqli_fetch_into_hash(INTERNAL_FUNCTION_PARAMETERS, int override_flags
12961296
fci.symbol_table = NULL;
12971297
fci.object_ptr = return_value;
12981298
fci.retval_ptr_ptr = &retval_ptr;
1299+
fci.params = NULL;
1300+
fci.param_count = 0;
1301+
fci.no_separation = 1;
1302+
12991303
if (ctor_params && Z_TYPE_P(ctor_params) != IS_NULL) {
1300-
if (Z_TYPE_P(ctor_params) == IS_ARRAY) {
1301-
HashTable *params_ht = Z_ARRVAL_P(ctor_params);
1302-
Bucket *p;
1303-
1304-
fci.param_count = 0;
1305-
fci.params = safe_emalloc(sizeof(zval*), params_ht->nNumOfElements, 0);
1306-
p = params_ht->pListHead;
1307-
while (p != NULL) {
1308-
fci.params[fci.param_count++] = (zval**)p->pData;
1309-
p = p->pListNext;
1310-
}
1311-
} else {
1304+
if (zend_fcall_info_args(&fci, ctor_params TSRMLS_CC) == FAILURE) {
13121305
/* Two problems why we throw exceptions here: PHP is typeless
13131306
* and hence passing one argument that's not an array could be
13141307
* 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
13181311
zend_throw_exception(zend_exception_get_default(TSRMLS_C), "Parameter ctor_params must be an array", 0 TSRMLS_CC);
13191312
return;
13201313
}
1321-
} else {
1322-
fci.param_count = 0;
1323-
fci.params = NULL;
13241314
}
1325-
fci.no_separation = 1;
13261315

13271316
fcc.initialized = 1;
13281317
fcc.function_handler = ce->constructor;

ext/mysqlnd/mysqlnd_reverse_api.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ PHPAPI void
6161
mysqlnd_reverse_api_register_api(MYSQLND_REVERSE_API * apiext TSRMLS_DC)
6262
{
6363
zend_hash_add(&mysqlnd_api_ext_ht, apiext->module->name, strlen(apiext->module->name) + 1, &apiext,
64-
sizeof(MYSQLND_REVERSE_API), NULL);
64+
sizeof(MYSQLND_REVERSE_API *), NULL);
6565
}
6666
/* }}} */
6767

ext/mysqlnd/php_mysqlnd.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -107,17 +107,17 @@ static void
107107
mysqlnd_minfo_dump_api_plugins(smart_str * buffer TSRMLS_DC)
108108
{
109109
HashTable *ht = mysqlnd_reverse_api_get_api_list(TSRMLS_C);
110-
Bucket *p;
110+
HashPosition pos;
111+
MYSQLND_REVERSE_API **ext;
111112

112-
p = ht->pListHead;
113-
while(p != NULL) {
114-
MYSQLND_REVERSE_API * ext = *(MYSQLND_REVERSE_API **) p->pData;
113+
for (zend_hash_internal_pointer_reset_ex(ht, &pos);
114+
zend_hash_get_current_data_ex(ht, (void **) &ext, &pos);
115+
zend_hash_move_forward_ex(ht, &pos)
116+
) {
115117
if (buffer->len) {
116118
smart_str_appendc(buffer, ',');
117119
}
118-
smart_str_appends(buffer, ext->module->name);
119-
120-
p = p->pListNext;
120+
smart_str_appends(buffer, (*ext)->module->name);
121121
}
122122
}
123123
/* }}} */

ext/pdo/pdo_dbh.c

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -470,23 +470,11 @@ static void pdo_stmt_construct(pdo_stmt_t *stmt, zval *object, zend_class_entry
470470
fci.object_ptr = object;
471471
fci.symbol_table = NULL;
472472
fci.retval_ptr_ptr = &retval;
473-
if (ctor_args) {
474-
HashTable *ht = Z_ARRVAL_P(ctor_args);
475-
Bucket *p;
476-
477-
fci.param_count = 0;
478-
fci.params = safe_emalloc(sizeof(zval*), ht->nNumOfElements, 0);
479-
p = ht->pListHead;
480-
while (p != NULL) {
481-
fci.params[fci.param_count++] = (zval**)p->pData;
482-
p = p->pListNext;
483-
}
484-
} else {
485-
fci.param_count = 0;
486-
fci.params = NULL;
487-
}
473+
fci.params = NULL;
488474
fci.no_separation = 1;
489475

476+
zend_fcall_info_args(&fci, ctor_args TSRMLS_CC);
477+
490478
fcc.initialized = 1;
491479
fcc.function_handler = dbstmt_ce->constructor;
492480
fcc.calling_scope = EG(scope);

ext/pdo/pdo_stmt.c

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -753,23 +753,11 @@ static int do_fetch_class_prepare(pdo_stmt_t *stmt TSRMLS_DC) /* {{{ */
753753
fci->function_name = NULL;
754754
fci->symbol_table = NULL;
755755
fci->retval_ptr_ptr = &stmt->fetch.cls.retval_ptr;
756-
if (stmt->fetch.cls.ctor_args) {
757-
HashTable *ht = Z_ARRVAL_P(stmt->fetch.cls.ctor_args);
758-
Bucket *p;
759-
760-
fci->param_count = 0;
761-
fci->params = safe_emalloc(sizeof(zval**), ht->nNumOfElements, 0);
762-
p = ht->pListHead;
763-
while (p != NULL) {
764-
fci->params[fci->param_count++] = (zval**)p->pData;
765-
p = p->pListNext;
766-
}
767-
} else {
768-
fci->param_count = 0;
769-
fci->params = NULL;
770-
}
756+
fci->params = NULL;
771757
fci->no_separation = 1;
772758

759+
zend_fcall_info_args(fci, stmt->fetch.cls.ctor_args TSRMLS_CC);
760+
773761
fcc->initialized = 1;
774762
fcc->function_handler = ce->constructor;
775763
fcc->calling_scope = EG(scope);

0 commit comments

Comments
 (0)