1 : /*
2 : +----------------------------------------------------------------------+
3 : | Zend Engine |
4 : +----------------------------------------------------------------------+
5 : | Copyright (c) 1998-2009 Zend Technologies Ltd. (http://www.zend.com) |
6 : +----------------------------------------------------------------------+
7 : | This source file is subject to version 2.00 of the Zend license, |
8 : | that is bundled with this package in the file LICENSE, and is |
9 : | available through the world-wide-web at the following url: |
10 : | http://www.zend.com/license/2_00.txt. |
11 : | If you did not receive a copy of the Zend license and are unable to |
12 : | obtain it through the world-wide-web, please send a note to |
13 : | license@zend.com so we can mail you a copy immediately. |
14 : +----------------------------------------------------------------------+
15 : | Authors: Andi Gutmans <andi@zend.com> |
16 : | Zeev Suraski <zeev@zend.com> |
17 : +----------------------------------------------------------------------+
18 : */
19 :
20 : /* $Id: zend_hash.c 281777 2009-06-07 19:28:02Z mattwil $ */
21 :
22 : #include "zend.h"
23 : #include "zend_operators.h"
24 : #include "zend_globals.h"
25 :
26 : #include <unicode/utypes.h>
27 : #include <unicode/uchar.h>
28 :
29 : #define CONNECT_TO_BUCKET_DLLIST(element, list_head) \
30 : (element)->pNext = (list_head); \
31 : (element)->pLast = NULL; \
32 : if ((element)->pNext) { \
33 : (element)->pNext->pLast = (element); \
34 : }
35 :
36 : #define CONNECT_TO_GLOBAL_DLLIST(element, ht) \
37 : (element)->pListLast = (ht)->pListTail; \
38 : (ht)->pListTail = (element); \
39 : (element)->pListNext = NULL; \
40 : if ((element)->pListLast != NULL) { \
41 : (element)->pListLast->pListNext = (element); \
42 : } \
43 : if (!(ht)->pListHead) { \
44 : (ht)->pListHead = (element); \
45 : } \
46 : if ((ht)->pInternalPointer == NULL) { \
47 : (ht)->pInternalPointer = (element); \
48 : }
49 :
50 : #define ZEND_HASH_CVT_ERROR() zend_error(E_WARNING, "Could not convert String to Unicode")
51 :
52 : #define UNICODE_KEY(ht, type, arKey, nKeyLength, tmp) \
53 : if (ht->unicode && type == IS_STRING) { \
54 : UErrorCode status = U_ZERO_ERROR; \
55 : UChar *u = NULL; \
56 : int u_len; \
57 : TSRMLS_FETCH(); \
58 : zend_string_to_unicode_ex(ZEND_U_CONVERTER(UG(runtime_encoding_conv)), &u, &u_len, arKey.s, nKeyLength-1, &status); \
59 : if (U_FAILURE(status)) { \
60 : ZEND_HASH_CVT_ERROR(); \
61 : } else { \
62 : type = IS_UNICODE; \
63 : tmp = arKey.u = u; \
64 : nKeyLength = u_len + 1; \
65 : } \
66 : }
67 :
68 :
69 : #if ZEND_DEBUG
70 : #define HT_OK 0
71 : #define HT_IS_DESTROYING 1
72 : #define HT_DESTROYED 2
73 : #define HT_CLEANING 3
74 :
75 : static void _zend_is_inconsistent(const HashTable *ht, const char *file, int line) /* {{{ */
76 : {
77 : if (ht->inconsistent==HT_OK) {
78 : return;
79 : }
80 : switch (ht->inconsistent) {
81 : case HT_IS_DESTROYING:
82 : zend_output_debug_string(1, "%s(%d) : ht=%p is being destroyed", file, line, ht);
83 : break;
84 : case HT_DESTROYED:
85 : zend_output_debug_string(1, "%s(%d) : ht=%p is already destroyed", file, line, ht);
86 : break;
87 : case HT_CLEANING:
88 : zend_output_debug_string(1, "%s(%d) : ht=%p is being cleaned", file, line, ht);
89 : break;
90 : }
91 : zend_bailout();
92 : }
93 : /* }}} */
94 :
95 : #define IS_CONSISTENT(a) _zend_is_inconsistent(a, __FILE__, __LINE__);
96 : #define SET_INCONSISTENT(n) ht->inconsistent = n;
97 : #else
98 : #define IS_CONSISTENT(a)
99 : #define SET_INCONSISTENT(n)
100 : #endif
101 :
102 : #define HASH_PROTECT_RECURSION(ht) \
103 : if ((ht)->bApplyProtection) { \
104 : if ((ht)->nApplyCount++ >= 3) { \
105 : zend_error(E_ERROR, "Nesting level too deep - recursive dependency?"); \
106 : } \
107 : }
108 :
109 :
110 : #define HASH_UNPROTECT_RECURSION(ht) \
111 : if ((ht)->bApplyProtection) { \
112 : (ht)->nApplyCount--; \
113 : }
114 :
115 :
116 : #define ZEND_HASH_IF_FULL_DO_RESIZE(ht) \
117 : if ((ht)->nNumOfElements > (ht)->nTableSize) { \
118 : zend_hash_do_resize(ht); \
119 : }
120 :
121 : static int zend_hash_do_resize(HashTable *ht);
122 :
123 : #define UPDATE_DATA(ht, p, pData, nDataSize) \
124 : if (nDataSize == sizeof(void*)) { \
125 : if ((p)->pData != &(p)->pDataPtr) { \
126 : pefree_rel(p->pData, ht->persistent); \
127 : } \
128 : memcpy(&(p)->pDataPtr, pData, sizeof(void *)); \
129 : (p)->pData = &(p)->pDataPtr; \
130 : } else { \
131 : if ((p)->pData == &(p)->pDataPtr) { \
132 : (p)->pData = (void *) pemalloc_rel(nDataSize, (ht)->persistent); \
133 : } else { \
134 : (p)->pData = (void *) perealloc_rel((p)->pData, nDataSize, (ht)->persistent); \
135 : } \
136 : memcpy((p)->pData, pData, nDataSize); \
137 : }
138 :
139 : #define INIT_DATA(ht, p, pData, nDataSize); \
140 : if (nDataSize == sizeof(void*)) { \
141 : memcpy(&(p)->pDataPtr, pData, sizeof(void *)); \
142 : (p)->pData = &(p)->pDataPtr; \
143 : } else { \
144 : (p)->pData = (void *) pemalloc_rel(nDataSize, (ht)->persistent); \
145 : if (!(p)->pData) { \
146 : pefree_rel(p, (ht)->persistent); \
147 : return FAILURE; \
148 : } \
149 : memcpy((p)->pData, pData, nDataSize); \
150 : }
151 : /* }}} */
152 :
153 : ZEND_API int _zend_u_hash_init(HashTable *ht, uint nSize, hash_func_t pHashFunction, dtor_func_t pDestructor, zend_bool persistent, zend_bool unicode ZEND_FILE_LINE_DC) /* {{{ */
154 20465145 : {
155 20465145 : uint i = 3;
156 : Bucket **tmp;
157 :
158 : SET_INCONSISTENT(HT_OK);
159 :
160 20465145 : if (nSize >= 0x80000000) {
161 : /* prevent overflow */
162 0 : ht->nTableSize = 0x80000000;
163 : } else {
164 41664384 : while ((1U << i) < nSize) {
165 734094 : i++;
166 : }
167 20465145 : ht->nTableSize = 1 << i;
168 : }
169 :
170 20465145 : ht->nTableMask = ht->nTableSize - 1;
171 20465145 : ht->pDestructor = pDestructor;
172 20465145 : ht->arBuckets = NULL;
173 20465145 : ht->pListHead = NULL;
174 20465145 : ht->pListTail = NULL;
175 20465145 : ht->nNumOfElements = 0;
176 20465145 : ht->nNextFreeElement = 0;
177 20465145 : ht->pInternalPointer = NULL;
178 20465145 : ht->persistent = persistent;
179 20465145 : ht->unicode = unicode;
180 20465145 : ht->nApplyCount = 0;
181 20465145 : ht->bApplyProtection = 1;
182 :
183 : /* Uses ecalloc() so that Bucket* == NULL */
184 20465145 : if (persistent) {
185 14408374 : tmp = (Bucket **) calloc(ht->nTableSize, sizeof(Bucket *));
186 14408374 : if (!tmp) {
187 0 : return FAILURE;
188 : }
189 14408374 : ht->arBuckets = tmp;
190 : } else {
191 6056771 : tmp = (Bucket **) ecalloc_rel(ht->nTableSize, sizeof(Bucket *));
192 6056771 : if (tmp) {
193 6056771 : ht->arBuckets = tmp;
194 : }
195 : }
196 :
197 20465145 : return SUCCESS;
198 : }
199 : /* }}} */
200 :
201 : ZEND_API int _zend_hash_init(HashTable *ht, uint nSize, hash_func_t pHashFunction, dtor_func_t pDestructor, zend_bool persistent ZEND_FILE_LINE_DC) /* {{{ */
202 2809764 : {
203 2809764 : return _zend_u_hash_init(ht, nSize, pHashFunction, pDestructor, persistent, 0 ZEND_FILE_LINE_CC);
204 : }
205 : /* }}} */
206 :
207 : ZEND_API int _zend_hash_init_ex(HashTable *ht, uint nSize, hash_func_t pHashFunction, dtor_func_t pDestructor, zend_bool persistent, zend_bool bApplyProtection ZEND_FILE_LINE_DC) /* {{{ */
208 170079 : {
209 170079 : int retval = _zend_hash_init(ht, nSize, pHashFunction, pDestructor, persistent ZEND_FILE_LINE_CC);
210 :
211 170079 : ht->bApplyProtection = bApplyProtection;
212 170079 : return retval;
213 : }
214 : /* }}} */
215 :
216 : ZEND_API int _zend_u_hash_init_ex(HashTable *ht, uint nSize, hash_func_t pHashFunction, dtor_func_t pDestructor, zend_bool persistent, zend_bool unicode, zend_bool bApplyProtection ZEND_FILE_LINE_DC) /* {{{ */
217 13295740 : {
218 13295740 : int retval = _zend_u_hash_init(ht, nSize, pHashFunction, pDestructor, persistent, unicode ZEND_FILE_LINE_CC);
219 :
220 13295740 : ht->bApplyProtection = bApplyProtection;
221 13295740 : return retval;
222 : }
223 : /* }}} */
224 :
225 : ZEND_API void zend_hash_set_apply_protection(HashTable *ht, zend_bool bApplyProtection) /* {{{ */
226 0 : {
227 0 : ht->bApplyProtection = bApplyProtection;
228 0 : }
229 : /* }}} */
230 :
231 : ZEND_API int _zend_u_hash_add_or_update(HashTable *ht, zend_uchar type, zstr arKey, uint nKeyLength, void *pData, uint nDataSize, void **pDest, int flag ZEND_FILE_LINE_DC) /* {{{ */
232 128143295 : {
233 : ulong h;
234 : uint nIndex;
235 : Bucket *p;
236 128143295 : void *tmp = NULL;
237 : uint realKeyLength;
238 :
239 : IS_CONSISTENT(ht);
240 :
241 128143295 : if (nKeyLength <= 0) {
242 : #if ZEND_DEBUG
243 : ZEND_PUTS("zend_hash_update: Can't put in empty key\n");
244 : #endif
245 0 : return FAILURE;
246 : }
247 :
248 128143295 : UNICODE_KEY(ht, type, arKey, nKeyLength, tmp);
249 128143295 : realKeyLength = USTR_BYTES(type, nKeyLength);
250 :
251 128143295 : h = zend_u_inline_hash_func(type, arKey, nKeyLength);
252 128143295 : nIndex = h & ht->nTableMask;
253 :
254 128143295 : p = ht->arBuckets[nIndex];
255 336516561 : while (p != NULL) {
256 80762971 : if ((p->h == h) &&
257 : (p->key.type == type) &&
258 : (p->nKeyLength == nKeyLength) &&
259 : !memcmp(p->key.arKey.s, arKey.s, realKeyLength)) {
260 533000 : if (flag & HASH_ADD) {
261 240090 : if (tmp) efree(tmp);
262 240090 : return FAILURE;
263 : }
264 292910 : HANDLE_BLOCK_INTERRUPTIONS();
265 : #if ZEND_DEBUG
266 : if (p->pData == pData) {
267 : ZEND_PUTS("Fatal error in zend_hash_update: p->pData == pData\n");
268 : HANDLE_UNBLOCK_INTERRUPTIONS();
269 : if (tmp) efree(tmp);
270 : return FAILURE;
271 : }
272 : #endif
273 292910 : if (ht->pDestructor) {
274 258618 : ht->pDestructor(p->pData);
275 : }
276 292910 : UPDATE_DATA(ht, p, pData, nDataSize);
277 292910 : if (pDest) {
278 86906 : *pDest = p->pData;
279 : }
280 292910 : HANDLE_UNBLOCK_INTERRUPTIONS();
281 292910 : if (tmp) efree(tmp);
282 292910 : return SUCCESS;
283 : }
284 80229971 : p = p->pNext;
285 : }
286 :
287 127610295 : p = (Bucket *) pemalloc(sizeof(Bucket)-sizeof(p->key.arKey)+realKeyLength, ht->persistent);
288 127610295 : if (!p) {
289 0 : if (tmp) efree(tmp);
290 0 : return FAILURE;
291 : }
292 127610295 : p->key.type = type;
293 127610295 : memcpy(p->key.arKey.s, arKey.s, realKeyLength);
294 127610295 : p->nKeyLength = nKeyLength;
295 127610295 : INIT_DATA(ht, p, pData, nDataSize);
296 127610295 : p->h = h;
297 127610295 : CONNECT_TO_BUCKET_DLLIST(p, ht->arBuckets[nIndex]);
298 127610295 : if (pDest) {
299 63707588 : *pDest = p->pData;
300 : }
301 :
302 127610295 : HANDLE_BLOCK_INTERRUPTIONS();
303 127610295 : CONNECT_TO_GLOBAL_DLLIST(p, ht);
304 127610295 : ht->arBuckets[nIndex] = p;
305 127610295 : HANDLE_UNBLOCK_INTERRUPTIONS();
306 :
307 127610295 : ht->nNumOfElements++;
308 127610295 : ZEND_HASH_IF_FULL_DO_RESIZE(ht); /* If the Hash table is full, resize it */
309 127610295 : if (tmp) efree(tmp);
310 127610295 : return SUCCESS;
311 : }
312 : /* }}} */
313 :
314 : ZEND_API int _zend_hash_add_or_update(HashTable *ht, const char *arKey, uint nKeyLength, void *pData, uint nDataSize, void **pDest, int flag ZEND_FILE_LINE_DC) /* {{{ */
315 15660807 : {
316 15660807 : return _zend_u_hash_add_or_update(ht, IS_STRING, ZSTR(arKey), nKeyLength, pData, nDataSize, pDest, flag ZEND_FILE_LINE_CC);
317 : }
318 : /* }}} */
319 :
320 : ZEND_API int _zend_ascii_hash_add_or_update(HashTable *ht, const char *arKey, uint nKeyLength, void *pData, uint nDataSize, void **pDest, int flag ZEND_FILE_LINE_DC) /* {{{ */
321 71111320 : {
322 : zstr key;
323 : int ret;
324 :
325 71111320 : key.u = zend_ascii_to_unicode(arKey, nKeyLength ZEND_FILE_LINE_CC);
326 71111320 : ret = _zend_u_hash_add_or_update(ht, IS_UNICODE, key, nKeyLength, pData, nDataSize, pDest, flag ZEND_FILE_LINE_CC);
327 71111320 : efree(key.u);
328 71111320 : return ret;
329 : }
330 : /* }}} */
331 :
332 : ZEND_API int _zend_rt_hash_add_or_update(HashTable *ht, const char *arKey, uint nKeyLength, void *pData, uint nDataSize, void **pDest, int flag ZEND_FILE_LINE_DC) /* {{{ */
333 1281 : {
334 : zstr key;
335 : int ret;
336 1281 : UErrorCode status = U_ZERO_ERROR;
337 : int u_len;
338 : TSRMLS_FETCH();
339 :
340 1281 : zend_string_to_unicode_ex(ZEND_U_CONVERTER(UG(runtime_encoding_conv)), &key.u, &u_len, arKey, nKeyLength-1, &status);
341 1281 : if (U_FAILURE(status)) {
342 0 : ZEND_HASH_CVT_ERROR();
343 0 : return _zend_u_hash_add_or_update(ht, IS_STRING, ZSTR(arKey), nKeyLength, pData, nDataSize, pDest, flag ZEND_FILE_LINE_CC);
344 : }
345 :
346 1281 : ret = _zend_u_hash_add_or_update(ht, IS_UNICODE, key, u_len+1, pData, nDataSize, pDest, flag ZEND_FILE_LINE_CC);
347 1281 : efree(key.u);
348 1281 : return ret;
349 : }
350 : /* }}} */
351 :
352 : ZEND_API int _zend_utf8_hash_add_or_update(HashTable *ht, const char *arKey, uint nKeyLength, void *pData, uint nDataSize, void **pDest, int flag ZEND_FILE_LINE_DC) /* {{{ */
353 308 : {
354 : zstr key;
355 : int ret;
356 308 : UErrorCode status = U_ZERO_ERROR;
357 : int u_len;
358 : TSRMLS_FETCH();
359 :
360 308 : zend_string_to_unicode_ex(ZEND_U_CONVERTER(UG(utf8_conv)), &key.u, &u_len, arKey, nKeyLength-1, &status);
361 308 : if (U_FAILURE(status)) {
362 0 : ZEND_HASH_CVT_ERROR();
363 0 : return _zend_u_hash_add_or_update(ht, IS_STRING, ZSTR(arKey), nKeyLength, pData, nDataSize, pDest, flag ZEND_FILE_LINE_CC);
364 : }
365 :
366 308 : ret = _zend_u_hash_add_or_update(ht, IS_UNICODE, key, u_len+1, pData, nDataSize, pDest, flag ZEND_FILE_LINE_CC);
367 308 : efree(key.u);
368 308 : return ret;
369 : }
370 : /* }}} */
371 :
372 : ZEND_API int _zend_u_hash_quick_add_or_update(HashTable *ht, zend_uchar type, zstr arKey, uint nKeyLength, ulong h, void *pData, uint nDataSize, void **pDest, int flag ZEND_FILE_LINE_DC) /* {{{ */
373 31369592 : {
374 : uint nIndex;
375 : Bucket *p;
376 31369592 : void *tmp = NULL;
377 : uint realKeyLength;
378 :
379 : IS_CONSISTENT(ht);
380 :
381 31369592 : if (nKeyLength == 0) {
382 0 : return zend_hash_index_update(ht, h, pData, nDataSize, pDest);
383 : }
384 :
385 31369592 : if (ht->unicode && type == IS_STRING) {
386 18207 : UNICODE_KEY(ht, type, arKey, nKeyLength, tmp);
387 18207 : h = zend_u_inline_hash_func(IS_UNICODE, arKey, nKeyLength);
388 : }
389 31369592 : realKeyLength = USTR_BYTES(type, nKeyLength);
390 :
391 31369592 : nIndex = h & ht->nTableMask;
392 :
393 31369592 : p = ht->arBuckets[nIndex];
394 79871985 : while (p != NULL) {
395 17135935 : if ((p->h == h) &&
396 : (p->key.type == type) &&
397 : (p->nKeyLength == nKeyLength) &&
398 : !memcmp(p->key.arKey.s, arKey.s, realKeyLength)) {
399 3134 : if (flag & HASH_ADD) {
400 641 : if (tmp) efree(tmp);
401 641 : return FAILURE;
402 : }
403 2493 : HANDLE_BLOCK_INTERRUPTIONS();
404 : #if ZEND_DEBUG
405 : if (p->pData == pData) {
406 : ZEND_PUTS("Fatal error in zend_hash_update: p->pData == pData\n");
407 : HANDLE_UNBLOCK_INTERRUPTIONS();
408 : if (tmp) efree(tmp);
409 : return FAILURE;
410 : }
411 : #endif
412 2493 : if (ht->pDestructor) {
413 2493 : ht->pDestructor(p->pData);
414 : }
415 2493 : UPDATE_DATA(ht, p, pData, nDataSize);
416 2493 : if (pDest) {
417 478 : *pDest = p->pData;
418 : }
419 2493 : HANDLE_UNBLOCK_INTERRUPTIONS();
420 2493 : if (tmp) efree(tmp);
421 2493 : return SUCCESS;
422 : }
423 17132801 : p = p->pNext;
424 : }
425 :
426 31366458 : p = (Bucket *) pemalloc(sizeof(Bucket)-sizeof(p->key.arKey)+realKeyLength, ht->persistent);
427 31366458 : if (!p) {
428 0 : if (tmp) efree(tmp);
429 0 : return FAILURE;
430 : }
431 :
432 31366458 : p->key.type = type;
433 31366458 : memcpy(p->key.arKey.s, arKey.s, realKeyLength);
434 31366458 : p->nKeyLength = nKeyLength;
435 31366458 : INIT_DATA(ht, p, pData, nDataSize);
436 31366458 : p->h = h;
437 :
438 31366458 : CONNECT_TO_BUCKET_DLLIST(p, ht->arBuckets[nIndex]);
439 :
440 31366458 : if (pDest) {
441 31316754 : *pDest = p->pData;
442 : }
443 :
444 31366458 : HANDLE_BLOCK_INTERRUPTIONS();
445 31366458 : ht->arBuckets[nIndex] = p;
446 31366458 : CONNECT_TO_GLOBAL_DLLIST(p, ht);
447 31366458 : HANDLE_UNBLOCK_INTERRUPTIONS();
448 :
449 31366458 : ht->nNumOfElements++;
450 31366458 : ZEND_HASH_IF_FULL_DO_RESIZE(ht); /* If the Hash table is full, resize it */
451 31366458 : if (tmp) efree(tmp);
452 31366458 : return SUCCESS;
453 : }
454 : /* }}} */
455 :
456 : ZEND_API int _zend_hash_quick_add_or_update(HashTable *ht, const char *arKey, uint nKeyLength, ulong h, void *pData, uint nDataSize, void **pDest, int flag ZEND_FILE_LINE_DC) /* {{{ */
457 18246 : {
458 18246 : return _zend_u_hash_quick_add_or_update(ht, IS_STRING, ZSTR(arKey), nKeyLength, h, pData, nDataSize, pDest, flag ZEND_FILE_LINE_CC);
459 : }
460 : /* }}} */
461 :
462 : ZEND_API int zend_u_hash_add_empty_element(HashTable *ht, zend_uchar type, zstr arKey, uint nKeyLength) /* {{{ */
463 0 : {
464 0 : void *dummy = (void *) 1;
465 :
466 0 : return zend_u_hash_add(ht, type, arKey, nKeyLength, &dummy, sizeof(void *), NULL);
467 : }
468 : /* }}} */
469 :
470 : ZEND_API int zend_hash_add_empty_element(HashTable *ht, const char *arKey, uint nKeyLength) /* {{{ */
471 26968 : {
472 26968 : void *dummy = (void *) 1;
473 :
474 26968 : return zend_u_hash_add(ht, IS_STRING, ZSTR(arKey), nKeyLength, &dummy, sizeof(void *), NULL);
475 : }
476 : /* }}} */
477 :
478 : ZEND_API int _zend_hash_index_update_or_next_insert(HashTable *ht, ulong h, void *pData, uint nDataSize, void **pDest, int flag ZEND_FILE_LINE_DC) /* {{{ */
479 10242172 : {
480 : uint nIndex;
481 : Bucket *p;
482 :
483 : IS_CONSISTENT(ht);
484 :
485 10242172 : if (flag & HASH_NEXT_INSERT) {
486 4432034 : h = ht->nNextFreeElement;
487 : }
488 10242172 : nIndex = h & ht->nTableMask;
489 :
490 10242172 : p = ht->arBuckets[nIndex];
491 21160607 : while (p != NULL) {
492 685957 : if ((p->nKeyLength == 0) && (p->h == h)) {
493 9694 : if (flag & HASH_NEXT_INSERT || flag & HASH_ADD) {
494 2 : return FAILURE;
495 : }
496 9692 : HANDLE_BLOCK_INTERRUPTIONS();
497 : #if ZEND_DEBUG
498 : if (p->pData == pData) {
499 : ZEND_PUTS("Fatal error in zend_hash_index_update: p->pData == pData\n");
500 : HANDLE_UNBLOCK_INTERRUPTIONS();
501 : return FAILURE;
502 : }
503 : #endif
504 9692 : if (ht->pDestructor) {
505 9692 : ht->pDestructor(p->pData);
506 : }
507 9692 : UPDATE_DATA(ht, p, pData, nDataSize);
508 9692 : HANDLE_UNBLOCK_INTERRUPTIONS();
509 9692 : if ((long)h >= (long)ht->nNextFreeElement) {
510 2 : ht->nNextFreeElement = h < LONG_MAX ? h + 1 : LONG_MAX;
511 : }
512 9692 : if (pDest) {
513 4931 : *pDest = p->pData;
514 : }
515 9692 : return SUCCESS;
516 : }
517 676263 : p = p->pNext;
518 : }
519 10232478 : p = (Bucket *) pemalloc_rel(sizeof(Bucket) - sizeof(p->key.arKey), ht->persistent);
520 10232478 : if (!p) {
521 0 : return FAILURE;
522 : }
523 10232478 : p->nKeyLength = 0; /* Numeric indices are marked by making the nKeyLength == 0 */
524 10232478 : p->h = h;
525 10232478 : INIT_DATA(ht, p, pData, nDataSize);
526 10232478 : if (pDest) {
527 5238622 : *pDest = p->pData;
528 : }
529 :
530 10232478 : p->key.type = IS_LONG;
531 :
532 10232478 : CONNECT_TO_BUCKET_DLLIST(p, ht->arBuckets[nIndex]);
533 :
534 10232478 : HANDLE_BLOCK_INTERRUPTIONS();
535 10232478 : ht->arBuckets[nIndex] = p;
536 10232478 : CONNECT_TO_GLOBAL_DLLIST(p, ht);
537 10232478 : HANDLE_UNBLOCK_INTERRUPTIONS();
538 :
539 10232478 : if ((long)h >= (long)ht->nNextFreeElement) {
540 9191105 : ht->nNextFreeElement = h < LONG_MAX ? h + 1 : LONG_MAX;
541 : }
542 10232478 : ht->nNumOfElements++;
543 10232478 : ZEND_HASH_IF_FULL_DO_RESIZE(ht);
544 10232478 : return SUCCESS;
545 : }
546 : /* }}} */
547 :
548 : static int zend_hash_do_resize(HashTable *ht) /* {{{ */
549 4716207 : {
550 : Bucket **t;
551 :
552 : IS_CONSISTENT(ht);
553 :
554 4716207 : if ((ht->nTableSize << 1) > 0) { /* Let's double the table size */
555 4716207 : t = (Bucket **) perealloc_recoverable(ht->arBuckets, (ht->nTableSize << 1) * sizeof(Bucket *), ht->persistent);
556 4716207 : if (t) {
557 4716207 : HANDLE_BLOCK_INTERRUPTIONS();
558 4716207 : ht->arBuckets = t;
559 4716207 : ht->nTableSize = (ht->nTableSize << 1);
560 4716207 : ht->nTableMask = ht->nTableSize - 1;
561 4716207 : zend_hash_rehash(ht);
562 4716207 : HANDLE_UNBLOCK_INTERRUPTIONS();
563 4716207 : return SUCCESS;
564 : }
565 0 : return FAILURE;
566 : }
567 0 : return SUCCESS;
568 : }
569 : /* }}} */
570 :
571 : ZEND_API int zend_hash_rehash(HashTable *ht) /* {{{ */
572 4806601 : {
573 : Bucket *p;
574 : uint nIndex;
575 :
576 : IS_CONSISTENT(ht);
577 :
578 4806601 : memset(ht->arBuckets, 0, ht->nTableSize * sizeof(Bucket *));
579 4806601 : p = ht->pListHead;
580 157553625 : while (p != NULL) {
581 147940423 : nIndex = p->h & ht->nTableMask;
582 147940423 : CONNECT_TO_BUCKET_DLLIST(p, ht->arBuckets[nIndex]);
583 147940423 : ht->arBuckets[nIndex] = p;
584 147940423 : p = p->pListNext;
585 : }
586 4806601 : return SUCCESS;
587 : }
588 : /* }}} */
589 :
590 : ZEND_API int zend_u_hash_del_key_or_index(HashTable *ht, zend_uchar type, zstr arKey, uint nKeyLength, ulong h, int flag) /* {{{ */
591 35753281 : {
592 : uint nIndex;
593 : Bucket *p;
594 35753281 : void *tmp = NULL;
595 :
596 : IS_CONSISTENT(ht);
597 :
598 35753281 : if (flag == HASH_DEL_KEY) {
599 35241538 : UNICODE_KEY(ht, type, arKey, nKeyLength, tmp);
600 35241538 : h = zend_u_inline_hash_func(type, arKey, nKeyLength);
601 : }
602 35753281 : nIndex = h & ht->nTableMask;
603 :
604 35753281 : p = ht->arBuckets[nIndex];
605 77080123 : while (p != NULL) {
606 41097372 : if ((p->h == h)
607 : && (p->nKeyLength == nKeyLength)
608 : && ((p->nKeyLength == 0) /* Numeric index (short circuits the memcmp()) */
609 : || ((p->key.type == type)
610 : && !memcmp(p->key.arKey.s, arKey.s, USTR_BYTES(type, nKeyLength))))) {
611 35523811 : HANDLE_BLOCK_INTERRUPTIONS();
612 35523811 : if (p == ht->arBuckets[nIndex]) {
613 30581664 : ht->arBuckets[nIndex] = p->pNext;
614 : } else {
615 4942147 : p->pLast->pNext = p->pNext;
616 : }
617 35523811 : if (p->pNext) {
618 9139657 : p->pNext->pLast = p->pLast;
619 : }
620 35523811 : if (p->pListLast != NULL) {
621 34567468 : p->pListLast->pListNext = p->pListNext;
622 : } else {
623 : /* Deleting the head of the list */
624 956343 : ht->pListHead = p->pListNext;
625 : }
626 35523811 : if (p->pListNext != NULL) {
627 35045569 : p->pListNext->pListLast = p->pListLast;
628 : } else {
629 478242 : ht->pListTail = p->pListLast;
630 : }
631 35523811 : if (ht->pInternalPointer == p) {
632 956296 : ht->pInternalPointer = p->pListNext;
633 : }
634 35523811 : if (ht->pDestructor) {
635 34995211 : ht->pDestructor(p->pData);
636 : }
637 35523809 : if (p->pData != &p->pDataPtr) {
638 34970245 : pefree(p->pData, ht->persistent);
639 : }
640 35523809 : pefree(p, ht->persistent);
641 35523809 : HANDLE_UNBLOCK_INTERRUPTIONS();
642 35523809 : ht->nNumOfElements--;
643 35523809 : if (tmp) efree(tmp);
644 35523809 : return SUCCESS;
645 : }
646 5573561 : p = p->pNext;
647 : }
648 229470 : if (tmp) efree(tmp);
649 229470 : return FAILURE;
650 : }
651 : /* }}} */
652 :
653 : ZEND_API int zend_hash_del_key_or_index(HashTable *ht, const char *arKey, uint nKeyLength, ulong h, int flag) /* {{{ */
654 1173662 : {
655 1173662 : return zend_u_hash_del_key_or_index(ht, IS_STRING, ZSTR(arKey), nKeyLength, h, flag);
656 : }
657 : /* }}} */
658 :
659 : ZEND_API int zend_ascii_hash_del(HashTable *ht, const char *arKey, uint nKeyLength) /* {{{ */
660 34384943 : {
661 : zstr key;
662 : int ret;
663 :
664 34384943 : key.u = zend_ascii_to_unicode(arKey, nKeyLength ZEND_FILE_LINE_CC);
665 34384943 : ret = zend_u_hash_del_key_or_index(ht, IS_UNICODE, key, nKeyLength, 0, HASH_DEL_KEY);
666 34384943 : efree(key.u);
667 34384943 : return ret;
668 : }
669 : /* }}} */
670 :
671 : ZEND_API int zend_rt_hash_del(HashTable *ht, const char *arKey, uint nKeyLength) /* {{{ */
672 0 : {
673 : zstr key;
674 : int ret;
675 0 : UErrorCode status = U_ZERO_ERROR;
676 : int u_len;
677 : TSRMLS_FETCH();
678 :
679 0 : zend_string_to_unicode_ex(ZEND_U_CONVERTER(UG(runtime_encoding_conv)), &key.u, &u_len, arKey, nKeyLength-1, &status);
680 0 : if (U_FAILURE(status)) {
681 0 : ZEND_HASH_CVT_ERROR();
682 0 : return zend_u_hash_del_key_or_index(ht, IS_STRING, ZSTR(arKey), nKeyLength, 0, HASH_DEL_KEY);
683 : }
684 0 : ret = zend_u_hash_del_key_or_index(ht, IS_UNICODE, key, u_len+1, 0, HASH_DEL_KEY);
685 0 : efree(key.u);
686 0 : return ret;
687 :
688 : }
689 : /* }}} */
690 :
691 : ZEND_API int zend_utf8_hash_del(HashTable *ht, const char *arKey, uint nKeyLength) /* {{{ */
692 0 : {
693 : zstr key;
694 : int ret;
695 0 : UErrorCode status = U_ZERO_ERROR;
696 : int u_len;
697 : TSRMLS_FETCH();
698 :
699 0 : zend_string_to_unicode_ex(ZEND_U_CONVERTER(UG(utf8_conv)), &key.u, &u_len, arKey, nKeyLength-1, &status);
700 0 : if (U_FAILURE(status)) {
701 0 : ZEND_HASH_CVT_ERROR();
702 0 : return zend_u_hash_del_key_or_index(ht, IS_STRING, ZSTR(arKey), nKeyLength, 0, HASH_DEL_KEY);
703 : }
704 0 : ret = zend_u_hash_del_key_or_index(ht, IS_UNICODE, key, u_len+1, 0, HASH_DEL_KEY);
705 0 : efree(key.u);
706 0 : return ret;
707 : }
708 : /* }}} */
709 :
710 : ZEND_API void zend_hash_destroy(HashTable *ht) /* {{{ */
711 20423819 : {
712 : Bucket *p, *q;
713 :
714 : IS_CONSISTENT(ht);
715 :
716 : SET_INCONSISTENT(HT_IS_DESTROYING);
717 :
718 20423819 : p = ht->pListHead;
719 168486867 : while (p != NULL) {
720 127639229 : q = p;
721 127639229 : p = p->pListNext;
722 127639229 : if (ht->pDestructor) {
723 111768642 : ht->pDestructor(q->pData);
724 : }
725 127639229 : if (q->pData != &q->pDataPtr) {
726 87557040 : pefree(q->pData, ht->persistent);
727 : }
728 127639229 : pefree(q, ht->persistent);
729 : }
730 20423819 : pefree(ht->arBuckets, ht->persistent);
731 :
732 : SET_INCONSISTENT(HT_DESTROYED);
733 20423819 : }
734 : /* }}} */
735 :
736 : ZEND_API void zend_hash_clean(HashTable *ht) /* {{{ */
737 57100 : {
738 : Bucket *p, *q;
739 :
740 : IS_CONSISTENT(ht);
741 :
742 : SET_INCONSISTENT(HT_CLEANING);
743 :
744 57100 : p = ht->pListHead;
745 1222406 : while (p != NULL) {
746 1108206 : q = p;
747 1108206 : p = p->pListNext;
748 1108206 : if (ht->pDestructor) {
749 1087193 : ht->pDestructor(q->pData);
750 : }
751 1108206 : if (q->pData != &q->pDataPtr) {
752 0 : pefree(q->pData, ht->persistent);
753 : }
754 1108206 : pefree(q, ht->persistent);
755 : }
756 57100 : memset(ht->arBuckets, 0, ht->nTableSize*sizeof(Bucket *));
757 57100 : ht->pListHead = NULL;
758 57100 : ht->pListTail = NULL;
759 57100 : ht->nNumOfElements = 0;
760 57100 : ht->nNextFreeElement = 0;
761 57100 : ht->pInternalPointer = NULL;
762 :
763 : SET_INCONSISTENT(HT_OK);
764 57100 : }
765 : /* }}} */
766 :
767 : /* This function is used by the various apply() functions.
768 : * It deletes the passed bucket, and returns the address of the
769 : * next bucket. The hash *may* be altered during that time, the
770 : * returned value will still be valid.
771 : */
772 : static Bucket *zend_hash_apply_deleter(HashTable *ht, Bucket *p) /* {{{ */
773 5230582 : {
774 : Bucket *retval;
775 :
776 5230582 : HANDLE_BLOCK_INTERRUPTIONS();
777 5230582 : if (p->pLast) {
778 361147 : p->pLast->pNext = p->pNext;
779 : } else {
780 : uint nIndex;
781 :
782 4869435 : nIndex = p->h & ht->nTableMask;
783 4869435 : ht->arBuckets[nIndex] = p->pNext;
784 : }
785 5230582 : if (p->pNext) {
786 1257494 : p->pNext->pLast = p->pLast;
787 : } else {
788 : /* Nothing to do as this list doesn't have a tail */
789 : }
790 :
791 5230582 : if (p->pListLast != NULL) {
792 3555191 : p->pListLast->pListNext = p->pListNext;
793 : } else {
794 : /* Deleting the head of the list */
795 1675391 : ht->pListHead = p->pListNext;
796 : }
797 5230582 : if (p->pListNext != NULL) {
798 3754199 : p->pListNext->pListLast = p->pListLast;
799 : } else {
800 1476383 : ht->pListTail = p->pListLast;
801 : }
802 5230582 : if (ht->pInternalPointer == p) {
803 1675386 : ht->pInternalPointer = p->pListNext;
804 : }
805 5230582 : ht->nNumOfElements--;
806 5230582 : HANDLE_UNBLOCK_INTERRUPTIONS();
807 :
808 5230582 : if (ht->pDestructor) {
809 1561156 : ht->pDestructor(p->pData);
810 : }
811 5230582 : if (p->pData != &p->pDataPtr) {
812 4855458 : pefree(p->pData, ht->persistent);
813 : }
814 5230582 : retval = p->pListNext;
815 5230582 : pefree(p, ht->persistent);
816 :
817 5230582 : return retval;
818 : }
819 : /* }}} */
820 :
821 : ZEND_API void zend_hash_graceful_destroy(HashTable *ht) /* {{{ */
822 0 : {
823 : Bucket *p;
824 :
825 : IS_CONSISTENT(ht);
826 :
827 0 : p = ht->pListHead;
828 0 : while (p != NULL) {
829 0 : p = zend_hash_apply_deleter(ht, p);
830 : }
831 0 : pefree(ht->arBuckets, ht->persistent);
832 :
833 : SET_INCONSISTENT(HT_DESTROYED);
834 0 : }
835 : /* }}} */
836 :
837 : ZEND_API void zend_hash_graceful_reverse_destroy(HashTable *ht) /* {{{ */
838 68250 : {
839 : Bucket *p;
840 :
841 : IS_CONSISTENT(ht);
842 :
843 68250 : p = ht->pListTail;
844 1508895 : while (p != NULL) {
845 1372395 : zend_hash_apply_deleter(ht, p);
846 1372395 : p = ht->pListTail;
847 : }
848 :
849 68250 : pefree(ht->arBuckets, ht->persistent);
850 :
851 : SET_INCONSISTENT(HT_DESTROYED);
852 68250 : }
853 : /* }}} */
854 :
855 : /* This is used to recurse elements and selectively delete certain entries
856 : * from a hashtable. apply_func() receives the data and decides if the entry
857 : * should be deleted or recursion should be stopped. The following three
858 : * return codes are possible:
859 : * ZEND_HASH_APPLY_KEEP - continue
860 : * ZEND_HASH_APPLY_STOP - stop iteration
861 : * ZEND_HASH_APPLY_REMOVE - delete the element, combineable with the former
862 : */
863 :
864 : ZEND_API void zend_hash_apply(HashTable *ht, apply_func_t apply_func TSRMLS_DC) /* {{{ */
865 202855 : {
866 : Bucket *p;
867 :
868 : IS_CONSISTENT(ht);
869 :
870 202855 : HASH_PROTECT_RECURSION(ht);
871 202855 : p = ht->pListHead;
872 6860154 : while (p != NULL) {
873 6454445 : int result = apply_func(p->pData TSRMLS_CC);
874 :
875 6454444 : if (result & ZEND_HASH_APPLY_REMOVE) {
876 3465 : p = zend_hash_apply_deleter(ht, p);
877 : } else {
878 6450979 : p = p->pListNext;
879 : }
880 6454444 : if (result & ZEND_HASH_APPLY_STOP) {
881 0 : break;
882 : }
883 : }
884 202854 : HASH_UNPROTECT_RECURSION(ht);
885 202854 : }
886 : /* }}} */
887 :
888 : ZEND_API void zend_hash_apply_with_argument(HashTable *ht, apply_func_arg_t apply_func, void *argument TSRMLS_DC) /* {{{ */
889 672600 : {
890 : Bucket *p;
891 :
892 : IS_CONSISTENT(ht);
893 :
894 672600 : HASH_PROTECT_RECURSION(ht);
895 672600 : p = ht->pListHead;
896 70202477 : while (p != NULL) {
897 68858368 : int result = apply_func(p->pData, argument TSRMLS_CC);
898 :
899 68858358 : if (result & ZEND_HASH_APPLY_REMOVE) {
900 3854722 : p = zend_hash_apply_deleter(ht, p);
901 : } else {
902 65003636 : p = p->pListNext;
903 : }
904 68858358 : if (result & ZEND_HASH_APPLY_STOP) {
905 1081 : break;
906 : }
907 : }
908 672590 : HASH_UNPROTECT_RECURSION(ht);
909 672590 : }
910 : /* }}} */
911 :
912 : ZEND_API void zend_hash_apply_with_arguments(HashTable *ht TSRMLS_DC, apply_func_args_t apply_func, int num_args, ...) /* {{{ */
913 1117419 : {
914 : Bucket *p;
915 : va_list args;
916 : zend_hash_key hash_key;
917 :
918 : IS_CONSISTENT(ht);
919 :
920 1117419 : HASH_PROTECT_RECURSION(ht);
921 :
922 1117417 : p = ht->pListHead;
923 2455041 : while (p != NULL) {
924 : int result;
925 220214 : va_start(args, num_args);
926 220214 : hash_key.nKeyLength = p->nKeyLength;
927 220214 : hash_key.h = p->h;
928 220214 : hash_key.type = p->key.type;
929 220214 : hash_key.arKey.s = p->key.arKey.s;
930 220214 : result = apply_func(p->pData TSRMLS_CC, num_args, args, &hash_key);
931 :
932 220207 : if (result & ZEND_HASH_APPLY_REMOVE) {
933 0 : p = zend_hash_apply_deleter(ht, p);
934 : } else {
935 220207 : p = p->pListNext;
936 : }
937 220207 : if (result & ZEND_HASH_APPLY_STOP) {
938 0 : break;
939 : }
940 220207 : va_end(args);
941 : }
942 :
943 1117410 : HASH_UNPROTECT_RECURSION(ht);
944 1117410 : }
945 : /* }}} */
946 :
947 : ZEND_API void zend_hash_reverse_apply(HashTable *ht, apply_func_t apply_func TSRMLS_DC) /* {{{ */
948 123114 : {
949 : Bucket *p, *q;
950 :
951 : IS_CONSISTENT(ht);
952 :
953 123114 : HASH_PROTECT_RECURSION(ht);
954 123114 : p = ht->pListTail;
955 1748894 : while (p != NULL) {
956 1587791 : int result = apply_func(p->pData TSRMLS_CC);
957 :
958 1587791 : q = p;
959 1587791 : p = p->pListLast;
960 1587791 : if (result & ZEND_HASH_APPLY_REMOVE) {
961 77354 : if (q->nKeyLength==0) {
962 0 : zend_hash_index_del(ht, q->h);
963 : } else {
964 77354 : zend_u_hash_del(ht, q->key.type, ZSTR(q->key.arKey.s), q->nKeyLength);
965 : }
966 : }
967 1587791 : if (result & ZEND_HASH_APPLY_STOP) {
968 85125 : break;
969 : }
970 : }
971 123114 : HASH_UNPROTECT_RECURSION(ht);
972 123114 : }
973 : /* }}} */
974 :
975 : ZEND_API void zend_hash_copy(HashTable *target, HashTable *source, copy_ctor_func_t pCopyConstructor, void *tmp, uint size) /* {{{ */
976 1521376 : {
977 : Bucket *p;
978 : void *new_entry;
979 : zend_bool setTargetPointer;
980 :
981 : IS_CONSISTENT(source);
982 : IS_CONSISTENT(target);
983 :
984 1521376 : setTargetPointer = !target->pInternalPointer;
985 1521376 : p = source->pListHead;
986 9462541 : while (p) {
987 6419789 : if (setTargetPointer && source->pInternalPointer == p) {
988 1060556 : target->pInternalPointer = NULL;
989 : }
990 6419789 : if (p->nKeyLength == 0) {
991 3743275 : zend_hash_index_update(target, p->h, p->pData, size, &new_entry);
992 : } else {
993 2676514 : zend_u_hash_quick_update(target, p->key.type, ZSTR(p->key.arKey.s), p->nKeyLength, p->h, p->pData, size, &new_entry);
994 : }
995 6419789 : if (pCopyConstructor) {
996 5242768 : pCopyConstructor(new_entry);
997 : }
998 6419789 : p = p->pListNext;
999 : }
1000 1521376 : if (!target->pInternalPointer) {
1001 460616 : target->pInternalPointer = target->pListHead;
1002 : }
1003 1521376 : }
1004 : /* }}} */
1005 :
1006 : ZEND_API void _zend_hash_merge(HashTable *target, HashTable *source, copy_ctor_func_t pCopyConstructor, void *tmp, uint size, int overwrite ZEND_FILE_LINE_DC) /* {{{ */
1007 2316893 : {
1008 : Bucket *p;
1009 : void *t;
1010 2316893 : int mode = (overwrite?HASH_UPDATE:HASH_ADD);
1011 :
1012 : IS_CONSISTENT(source);
1013 : IS_CONSISTENT(target);
1014 :
1015 2316893 : p = source->pListHead;
1016 10827660 : while (p) {
1017 6193874 : if (p->nKeyLength==0) {
1018 16 : if ((mode==HASH_UPDATE || !zend_hash_index_exists(target, p->h)) && zend_hash_index_update(target, p->h, p->pData, size, &t)==SUCCESS && pCopyConstructor) {
1019 6 : pCopyConstructor(t);
1020 : }
1021 : } else {
1022 6193858 : if (_zend_u_hash_quick_add_or_update(target, p->key.type, ZSTR(p->key.arKey.s), p->nKeyLength, p->h, p->pData, size, &t, mode ZEND_FILE_LINE_RELAY_CC)==SUCCESS && pCopyConstructor) {
1023 3982311 : pCopyConstructor(t);
1024 : }
1025 : }
1026 6193874 : p = p->pListNext;
1027 : }
1028 2316893 : target->pInternalPointer = target->pListHead;
1029 2316893 : }
1030 : /* }}} */
1031 :
1032 : static zend_bool zend_hash_replace_checker_wrapper(HashTable *target, void *source_data, Bucket *p, void *pParam, merge_checker_func_t merge_checker_func) /* {{{ */
1033 25855404 : {
1034 : zend_hash_key hash_key;
1035 :
1036 25855404 : hash_key.nKeyLength = p->nKeyLength;
1037 25855404 : hash_key.h = p->h;
1038 25855404 : hash_key.type = p->key.type;
1039 25855404 : hash_key.arKey.s = p->key.arKey.s;
1040 25855404 : return merge_checker_func(target, source_data, &hash_key, pParam);
1041 : }
1042 : /* }}} */
1043 :
1044 : ZEND_API void zend_hash_merge_ex(HashTable *target, HashTable *source, copy_ctor_func_t pCopyConstructor, uint size, merge_checker_func_t pMergeSource, void *pParam) /* {{{ */
1045 4188166 : {
1046 : Bucket *p;
1047 : void *t;
1048 :
1049 : IS_CONSISTENT(source);
1050 : IS_CONSISTENT(target);
1051 :
1052 4188166 : p = source->pListHead;
1053 34231693 : while (p) {
1054 25855404 : if (zend_hash_replace_checker_wrapper(target, p->pData, p, pParam, pMergeSource)) {
1055 19815978 : if (zend_u_hash_quick_update(target, p->key.type, ZSTR(p->key.arKey.s), p->nKeyLength, p->h, p->pData, size, &t)==SUCCESS && pCopyConstructor) {
1056 19815978 : pCopyConstructor(t);
1057 : }
1058 : }
1059 25855361 : p = p->pListNext;
1060 : }
1061 4188123 : target->pInternalPointer = target->pListHead;
1062 4188123 : }
1063 : /* }}} */
1064 :
1065 : ZEND_API ulong zend_u_get_hash_value(zend_uchar type, zstr arKey, uint nKeyLength) /* {{{ */
1066 1806717 : {
1067 1806717 : return zend_u_inline_hash_func(type, arKey, nKeyLength);
1068 : }
1069 : /* }}} */
1070 :
1071 : ZEND_API ulong zend_get_hash_value(const char *arKey, uint nKeyLength) /* {{{ */
1072 29598 : {
1073 29598 : return zend_u_get_hash_value(IS_STRING, ZSTR(arKey), nKeyLength);
1074 : }
1075 : /* }}} */
1076 :
1077 : /* Returns SUCCESS if found and FAILURE if not. The pointer to the
1078 : * data is returned in pData. The reason is that there's no reason
1079 : * someone using the hash table might not want to have NULL data
1080 : */
1081 : ZEND_API int zend_u_hash_find(const HashTable *ht, zend_uchar type, zstr arKey, uint nKeyLength, void **pData) /* {{{ */
1082 18539285 : {
1083 : ulong h;
1084 : uint nIndex;
1085 : Bucket *p;
1086 18539285 : void *tmp = NULL;
1087 : uint realKeyLength;
1088 :
1089 : IS_CONSISTENT(ht);
1090 :
1091 18539285 : UNICODE_KEY(ht, type, arKey, nKeyLength, tmp);
1092 18539285 : realKeyLength = USTR_BYTES(type, nKeyLength);
1093 :
1094 18539285 : h = zend_u_inline_hash_func(type, arKey, nKeyLength);
1095 18539285 : nIndex = h & ht->nTableMask;
1096 :
1097 18539285 : p = ht->arBuckets[nIndex];
1098 48080152 : while (p != NULL) {
1099 23754926 : if ((p->h == h) &&
1100 : (p->key.type == type) &&
1101 : (p->nKeyLength == nKeyLength) &&
1102 : !memcmp(p->key.arKey.s, arKey.s, realKeyLength)) {
1103 12753344 : *pData = p->pData;
1104 12753344 : if (tmp) efree(tmp);
1105 12753344 : return SUCCESS;
1106 : }
1107 11001582 : p = p->pNext;
1108 : }
1109 5785941 : if (tmp) efree(tmp);
1110 5785941 : return FAILURE;
1111 : }
1112 : /* }}} */
1113 :
1114 : ZEND_API int zend_hash_find(const HashTable *ht, const char *arKey, uint nKeyLength, void **pData) /* {{{ */
1115 11918164 : {
1116 11918164 : return zend_u_hash_find(ht, IS_STRING, ZSTR(arKey), nKeyLength, pData);
1117 : }
1118 : /* }}} */
1119 :
1120 : ZEND_API int zend_ascii_hash_find(const HashTable *ht, const char *arKey, uint nKeyLength, void **pData) /* {{{ */
1121 125593 : {
1122 : zstr key;
1123 : int ret;
1124 :
1125 125593 : key.u = zend_ascii_to_unicode(arKey, nKeyLength ZEND_FILE_LINE_CC);
1126 125593 : ret = zend_u_hash_find(ht, IS_UNICODE, key, nKeyLength, pData);
1127 125593 : efree(key.u);
1128 125593 : return ret;
1129 : }
1130 : /* }}} */
1131 :
1132 : ZEND_API int zend_rt_hash_find(const HashTable *ht, const char *arKey, uint nKeyLength, void **pData) /* {{{ */
1133 2118 : {
1134 : zstr key;
1135 : int ret;
1136 2118 : UErrorCode status = U_ZERO_ERROR;
1137 : int u_len;
1138 : TSRMLS_FETCH();
1139 :
1140 2118 : zend_string_to_unicode_ex(ZEND_U_CONVERTER(UG(runtime_encoding_conv)), &key.u, &u_len, arKey, nKeyLength-1, &status);
1141 2118 : if (U_FAILURE(status)) {
1142 0 : ZEND_HASH_CVT_ERROR();
1143 0 : return zend_u_hash_find(ht, IS_STRING, ZSTR(arKey), nKeyLength, pData);
1144 : }
1145 2118 : ret = zend_u_hash_find(ht, IS_UNICODE, key, u_len+1, pData);
1146 2118 : efree(key.u);
1147 2118 : return ret;
1148 : }
1149 : /* }}} */
1150 :
1151 : ZEND_API int zend_utf8_hash_find(const HashTable *ht, const char *arKey, uint nKeyLength, void **pData) /* {{{ */
1152 43 : {
1153 : zstr key;
1154 : int ret;
1155 43 : UErrorCode status = U_ZERO_ERROR;
1156 : int u_len;
1157 : TSRMLS_FETCH();
1158 :
1159 43 : zend_string_to_unicode_ex(ZEND_U_CONVERTER(UG(utf8_conv)), &key.u, &u_len, arKey, nKeyLength-1, &status);
1160 43 : if (U_FAILURE(status)) {
1161 0 : ZEND_HASH_CVT_ERROR();
1162 0 : return zend_u_hash_find(ht, IS_STRING, ZSTR(arKey), nKeyLength, pData);
1163 : }
1164 43 : ret = zend_u_hash_find(ht, IS_UNICODE, key, u_len+1, pData);
1165 43 : efree(key.u);
1166 43 : return ret;
1167 : }
1168 : /* }}} */
1169 :
1170 : ZEND_API int zend_u_hash_quick_find(const HashTable *ht, zend_uchar type, zstr arKey, uint nKeyLength, ulong h, void **pData) /* {{{ */
1171 62827461 : {
1172 : uint nIndex;
1173 : Bucket *p;
1174 62827461 : void *tmp = NULL;
1175 : uint realKeyLength;
1176 :
1177 62827461 : if (nKeyLength==0) {
1178 0 : return zend_hash_index_find(ht, h, pData);
1179 : }
1180 :
1181 : IS_CONSISTENT(ht);
1182 :
1183 62827461 : if (ht->unicode && type == IS_STRING) {
1184 28790 : UNICODE_KEY(ht, type, arKey, nKeyLength, tmp);
1185 28790 : h = zend_u_inline_hash_func(IS_UNICODE, arKey, nKeyLength);
1186 : }
1187 62827461 : realKeyLength = USTR_BYTES(type, nKeyLength);
1188 :
1189 62827461 : nIndex = h & ht->nTableMask;
1190 :
1191 62827461 : p = ht->arBuckets[nIndex];
1192 143464427 : while (p != NULL) {
1193 58380351 : if ((p->h == h) &&
1194 : (p->key.type == type) &&
1195 : (p->nKeyLength == nKeyLength) &&
1196 : !memcmp(p->key.arKey.s, arKey.s, realKeyLength)) {
1197 40570846 : *pData = p->pData;
1198 40570846 : if (tmp) efree(tmp);
1199 40570846 : return SUCCESS;
1200 : }
1201 17809505 : p = p->pNext;
1202 : }
1203 22256615 : if (tmp) efree(tmp);
1204 22256615 : return FAILURE;
1205 : }
1206 : /* }}} */
1207 :
1208 : ZEND_API int zend_hash_quick_find(const HashTable *ht, char *arKey, uint nKeyLength, ulong h, void **pData) /* {{{ */
1209 32005 : {
1210 32005 : return zend_u_hash_quick_find(ht, IS_STRING, ZSTR(arKey), nKeyLength, h, pData);
1211 : }
1212 : /* }}} */
1213 :
1214 : ZEND_API int zend_u_hash_exists(const HashTable *ht, zend_uchar type, zstr arKey, uint nKeyLength) /* {{{ */
1215 685290 : {
1216 : ulong h;
1217 : uint nIndex;
1218 : Bucket *p;
1219 685290 : void *tmp = NULL;
1220 : uint realKeyLength;
1221 :
1222 : IS_CONSISTENT(ht);
1223 :
1224 685290 : UNICODE_KEY(ht, type, arKey, nKeyLength, tmp);
1225 685290 : realKeyLength = USTR_BYTES(type, nKeyLength);
1226 :
1227 685290 : h = zend_u_inline_hash_func(type, arKey, nKeyLength);
1228 685290 : nIndex = h & ht->nTableMask;
1229 :
1230 685290 : p = ht->arBuckets[nIndex];
1231 1463528 : while (p != NULL) {
1232 688540 : if ((p->h == h) &&
1233 : (p->key.type == type) &&
1234 : (p->nKeyLength == nKeyLength) &&
1235 : !memcmp(p->key.arKey.s, arKey.s, realKeyLength)) {
1236 595592 : if (tmp) efree(tmp);
1237 595592 : return 1;
1238 : }
1239 92948 : p = p->pNext;
1240 : }
1241 89698 : if (tmp) efree(tmp);
1242 89698 : return 0;
1243 : }
1244 : /* }}} */
1245 :
1246 : ZEND_API int zend_hash_exists(const HashTable *ht, const char *arKey, uint nKeyLength) /* {{{ */
1247 236700 : {
1248 236700 : return zend_u_hash_exists(ht, IS_STRING, ZSTR(arKey), nKeyLength);
1249 : }
1250 : /* }}} */
1251 :
1252 : ZEND_API int zend_ascii_hash_exists(HashTable *ht, const char *arKey, uint nKeyLength) /* {{{ */
1253 374401 : {
1254 : zstr key;
1255 : int ret;
1256 :
1257 374401 : key.u = zend_ascii_to_unicode(arKey, nKeyLength ZEND_FILE_LINE_CC);
1258 374401 : ret = zend_u_hash_exists(ht, IS_UNICODE, key, nKeyLength);
1259 374401 : efree(key.u);
1260 374401 : return ret;
1261 : }
1262 : /* }}} */
1263 :
1264 : ZEND_API int zend_rt_hash_exists(HashTable *ht, const char *arKey, uint nKeyLength) /* {{{ */
1265 0 : {
1266 : zstr key;
1267 : int ret;
1268 0 : UErrorCode status = U_ZERO_ERROR;
1269 : int u_len;
1270 : TSRMLS_FETCH();
1271 :
1272 0 : zend_string_to_unicode_ex(ZEND_U_CONVERTER(UG(runtime_encoding_conv)), &key.u, &u_len, arKey, nKeyLength-1, &status);
1273 0 : if (U_FAILURE(status)) {
1274 0 : ZEND_HASH_CVT_ERROR();
1275 0 : return zend_u_hash_exists(ht, IS_STRING, ZSTR(arKey), nKeyLength);
1276 : }
1277 0 : ret = zend_u_hash_exists(ht, IS_UNICODE, key, u_len+1);
1278 0 : efree(key.u);
1279 0 : return ret;
1280 : }
1281 : /* }}} */
1282 :
1283 : ZEND_API int zend_utf8_hash_exists(HashTable *ht, const char *arKey, uint nKeyLength) /* {{{ */
1284 0 : {
1285 : zstr key;
1286 : int ret;
1287 0 : UErrorCode status = U_ZERO_ERROR;
1288 : int u_len;
1289 : TSRMLS_FETCH();
1290 :
1291 0 : zend_string_to_unicode_ex(ZEND_U_CONVERTER(UG(utf8_conv)), &key.u, &u_len, arKey, nKeyLength-1, &status);
1292 0 : if (U_FAILURE(status)) {
1293 0 : ZEND_HASH_CVT_ERROR();
1294 0 : return zend_u_hash_exists(ht, IS_STRING, ZSTR(arKey), nKeyLength);
1295 : }
1296 0 : ret = zend_u_hash_exists(ht, IS_UNICODE, key, u_len+1);
1297 0 : efree(key.u);
1298 0 : return ret;
1299 : }
1300 : /* }}} */
1301 :
1302 : ZEND_API int zend_u_hash_quick_exists(const HashTable *ht, zend_uchar type, zstr arKey, uint nKeyLength, ulong h) /* {{{ */
1303 501 : {
1304 : uint nIndex;
1305 : Bucket *p;
1306 501 : void *tmp = NULL;
1307 : uint realKeyLength;
1308 :
1309 501 : if (nKeyLength==0) {
1310 0 : return zend_hash_index_exists(ht, h);
1311 : }
1312 :
1313 : IS_CONSISTENT(ht);
1314 :
1315 501 : if (ht->unicode && type == IS_STRING) {
1316 352 : UNICODE_KEY(ht, type, arKey, nKeyLength, tmp);
1317 352 : h = zend_u_inline_hash_func(type, arKey, nKeyLength);
1318 : }
1319 501 : realKeyLength = USTR_BYTES(type, nKeyLength);
1320 :
1321 501 : nIndex = h & ht->nTableMask;
1322 :
1323 501 : p = ht->arBuckets[nIndex];
1324 1042 : while (p != NULL) {
1325 180 : if ((p->h == h) &&
1326 : (p->key.type == type) &&
1327 : (p->nKeyLength == nKeyLength) &&
1328 : !memcmp(p->key.arKey.s, arKey.s, realKeyLength)) {
1329 140 : if (tmp) efree(tmp);
1330 140 : return 1;
1331 : }
1332 40 : p = p->pNext;
1333 : }
1334 361 : if (tmp) efree(tmp);
1335 361 : return 0;
1336 : }
1337 : /* }}} */
1338 :
1339 : ZEND_API int zend_hash_quick_exists(const HashTable *ht, const char *arKey, uint nKeyLength, ulong h) /* {{{ */
1340 119 : {
1341 119 : return zend_u_hash_quick_exists(ht, IS_STRING, ZSTR(arKey), nKeyLength, h);
1342 : }
1343 : /* }}} */
1344 :
1345 : ZEND_API int zend_hash_index_find(const HashTable *ht, ulong h, void **pData) /* {{{ */
1346 30758717 : {
1347 : uint nIndex;
1348 : Bucket *p;
1349 :
1350 : IS_CONSISTENT(ht);
1351 :
1352 30758717 : nIndex = h & ht->nTableMask;
1353 :
1354 30758717 : p = ht->arBuckets[nIndex];
1355 62313128 : while (p != NULL) {
1356 28618901 : if ((p->h == h) && (p->nKeyLength == 0)) {
1357 27823207 : *pData = p->pData;
1358 27823207 : return SUCCESS;
1359 : }
1360 795694 : p = p->pNext;
1361 : }
1362 2935510 : return FAILURE;
1363 : }
1364 : /* }}} */
1365 :
1366 : ZEND_API int zend_hash_index_exists(const HashTable *ht, ulong h) /* {{{ */
1367 1292904 : {
1368 : uint nIndex;
1369 : Bucket *p;
1370 :
1371 : IS_CONSISTENT(ht);
1372 :
1373 1292904 : nIndex = h & ht->nTableMask;
1374 :
1375 1292904 : p = ht->arBuckets[nIndex];
1376 3096037 : while (p != NULL) {
1377 748548 : if ((p->h == h) && (p->nKeyLength == 0)) {
1378 238319 : return 1;
1379 : }
1380 510229 : p = p->pNext;
1381 : }
1382 1054585 : return 0;
1383 : }
1384 : /* }}} */
1385 :
1386 : ZEND_API int zend_hash_num_elements(const HashTable *ht) /* {{{ */
1387 3714160 : {
1388 : IS_CONSISTENT(ht);
1389 :
1390 3714160 : return ht->nNumOfElements;
1391 : }
1392 : /* }}} */
1393 :
1394 : ZEND_API int zend_hash_get_pointer(const HashTable *ht, HashPointer *ptr) /* {{{ */
1395 1839038 : {
1396 1839038 : ptr->pos = ht->pInternalPointer;
1397 1839038 : if (ht->pInternalPointer) {
1398 1786660 : ptr->h = ht->pInternalPointer->h;
1399 1786660 : return 1;
1400 : } else {
1401 52378 : ptr->h = 0;
1402 52378 : return 0;
1403 : }
1404 : }
1405 : /* }}} */
1406 :
1407 : ZEND_API int zend_hash_set_pointer(HashTable *ht, const HashPointer *ptr) /* {{{ */
1408 1838709 : {
1409 1838709 : if (ptr->pos == NULL) {
1410 52317 : ht->pInternalPointer = NULL;
1411 1786392 : } else if (ht->pInternalPointer != ptr->pos) {
1412 : Bucket *p;
1413 :
1414 : IS_CONSISTENT(ht);
1415 69 : p = ht->arBuckets[ptr->h & ht->nTableMask];
1416 186 : while (p != NULL) {
1417 58 : if (p == ptr->pos) {
1418 10 : ht->pInternalPointer = p;
1419 10 : return 1;
1420 : }
1421 48 : p = p->pNext;
1422 : }
1423 59 : return 0;
1424 : }
1425 1838640 : return 1;
1426 : }
1427 : /* }}} */
1428 :
1429 : ZEND_API void zend_hash_internal_pointer_reset_ex(HashTable *ht, HashPosition *pos) /* {{{ */
1430 3588187 : {
1431 : IS_CONSISTENT(ht);
1432 :
1433 3588187 : if (pos)
1434 203691 : *pos = ht->pListHead;
1435 : else
1436 3384496 : ht->pInternalPointer = ht->pListHead;
1437 3588187 : }
1438 : /* }}} */
1439 :
1440 : /* This function will be extremely optimized by remembering
1441 : * the end of the list
1442 : */
1443 : ZEND_API void zend_hash_internal_pointer_end_ex(HashTable *ht, HashPosition *pos) /* {{{ */
1444 270 : {
1445 : IS_CONSISTENT(ht);
1446 :
1447 270 : if (pos)
1448 155 : *pos = ht->pListTail;
1449 : else
1450 115 : ht->pInternalPointer = ht->pListTail;
1451 270 : }
1452 : /* }}} */
1453 :
1454 : ZEND_API int zend_hash_move_forward_ex(HashTable *ht, HashPosition *pos) /* {{{ */
1455 12195991 : {
1456 12195991 : HashPosition *current = pos ? pos : &ht->pInternalPointer;
1457 :
1458 : IS_CONSISTENT(ht);
1459 :
1460 12195991 : if (*current) {
1461 12195968 : *current = (*current)->pListNext;
1462 12195968 : return SUCCESS;
1463 : } else
1464 23 : return FAILURE;
1465 : }
1466 : /* }}} */
1467 :
1468 : ZEND_API int zend_hash_move_backwards_ex(HashTable *ht, HashPosition *pos) /* {{{ */
1469 530 : {
1470 530 : HashPosition *current = pos ? pos : &ht->pInternalPointer;
1471 :
1472 : IS_CONSISTENT(ht);
1473 :
1474 530 : if (*current) {
1475 528 : *current = (*current)->pListLast;
1476 528 : return SUCCESS;
1477 : } else
1478 2 : return FAILURE;
1479 : }
1480 : /* }}} */
1481 :
1482 : /* This function should be made binary safe */
1483 : ZEND_API int zend_hash_get_current_key_ex(const HashTable *ht, zstr *str_index, uint *str_length, ulong *num_index, zend_bool duplicate, HashPosition *pos) /* {{{ */
1484 3013319 : {
1485 : Bucket *p;
1486 :
1487 3013319 : p = pos ? (*pos) : ht->pInternalPointer;
1488 :
1489 : IS_CONSISTENT(ht);
1490 :
1491 3013319 : if (p) {
1492 3003865 : if (p->nKeyLength) {
1493 2881035 : if (p->key.type == IS_STRING) {
1494 2257102 : if (duplicate) {
1495 731033 : str_index->s = estrndup(p->key.arKey.s, p->nKeyLength-1);
1496 : } else {
1497 1526069 : str_index->s = p->key.arKey.s;
1498 : }
1499 2257102 : if (str_length) {
1500 2255294 : *str_length = p->nKeyLength;
1501 : }
1502 2257102 : return HASH_KEY_IS_STRING;
1503 623933 : } else if (p->key.type == IS_UNICODE) {
1504 623933 : if (duplicate) {
1505 573321 : str_index->u = eustrndup(p->key.arKey.u, p->nKeyLength-1);
1506 : } else {
1507 50612 : str_index->u = p->key.arKey.u;
1508 : }
1509 623933 : if (str_length) {
1510 619623 : *str_length = p->nKeyLength;
1511 : }
1512 623933 : return HASH_KEY_IS_UNICODE;
1513 : }
1514 : } else {
1515 122830 : *num_index = p->h;
1516 122830 : return HASH_KEY_IS_LONG;
1517 : }
1518 : }
1519 9454 : return HASH_KEY_NON_EXISTANT;
1520 : }
1521 : /* }}} */
1522 :
1523 : ZEND_API int zend_hash_get_current_key_type_ex(HashTable *ht, HashPosition *pos) /* {{{ */
1524 105723 : {
1525 : Bucket *p;
1526 :
1527 105723 : p = pos ? (*pos) : ht->pInternalPointer;
1528 :
1529 : IS_CONSISTENT(ht);
1530 :
1531 105723 : if (p) {
1532 90569 : if (p->nKeyLength) {
1533 65973 : if (p->key.type == IS_UNICODE) {
1534 17885 : return HASH_KEY_IS_UNICODE;
1535 : } else {
1536 48088 : return HASH_KEY_IS_STRING;
1537 : }
1538 : } else {
1539 24596 : return HASH_KEY_IS_LONG;
1540 : }
1541 : }
1542 15154 : return HASH_KEY_NON_EXISTANT;
1543 : }
1544 : /* }}} */
1545 :
1546 : ZEND_API int zend_hash_get_current_data_ex(HashTable *ht, void **pData, HashPosition *pos) /* {{{ */
1547 14957477 : {
1548 : Bucket *p;
1549 :
1550 14957477 : p = pos ? (*pos) : ht->pInternalPointer;
1551 :
1552 : IS_CONSISTENT(ht);
1553 :
1554 14957477 : if (p) {
1555 12224863 : *pData = p->pData;
1556 12224863 : return SUCCESS;
1557 : } else {
1558 2732614 : return FAILURE;
1559 : }
1560 : }
1561 : /* }}} */
1562 :
1563 : /* This function changes key of currevt element without changing elements'
1564 : * order. If element with target key already exists, it will be deleted first.
1565 : */
1566 : ZEND_API int zend_hash_update_current_key_ex(HashTable *ht, int key_type, zstr str_index, uint str_length, ulong num_index, int mode, HashPosition *pos) /* {{{ */
1567 88 : {
1568 : Bucket *p;
1569 : uint real_length;
1570 :
1571 88 : p = pos ? (*pos) : ht->pInternalPointer;
1572 :
1573 : IS_CONSISTENT(ht);
1574 :
1575 88 : if (p) {
1576 88 : if (key_type == HASH_KEY_IS_LONG) {
1577 49 : real_length = str_length = 0;
1578 49 : if (!p->nKeyLength && p->h == num_index) {
1579 0 : return SUCCESS;
1580 : }
1581 :
1582 49 : if (mode != HASH_UPDATE_KEY_ANYWAY) {
1583 49 : Bucket *q = ht->arBuckets[num_index & ht->nTableMask];
1584 49 : int found = 0;
1585 :
1586 103 : while (q != NULL) {
1587 6 : if (q == p) {
1588 5 : found = 1;
1589 1 : } else if (!q->nKeyLength && q->h == num_index) {
1590 1 : if (found) {
1591 0 : if (mode & HASH_UPDATE_KEY_IF_BEFORE) {
1592 0 : break;
1593 : } else {
1594 0 : if (p->nKeyLength) {
1595 0 : zend_u_hash_del(ht, p->key.type, ZSTR(p->key.arKey.s), p->nKeyLength);
1596 : } else {
1597 0 : zend_hash_index_del(ht, p->h);
1598 : }
1599 0 : return FAILURE;
1600 : }
1601 : } else {
1602 1 : if (mode & HASH_UPDATE_KEY_IF_AFTER) {
1603 0 : break;
1604 : } else {
1605 1 : if (p->nKeyLength) {
1606 1 : zend_u_hash_del(ht, p->key.type, ZSTR(p->key.arKey.s), p->nKeyLength);
1607 : } else {
1608 0 : zend_hash_index_del(ht, p->h);
1609 : }
1610 1 : return FAILURE;
1611 : }
1612 : }
1613 : }
1614 5 : q = q->pNext;
1615 : }
1616 : }
1617 :
1618 48 : zend_hash_index_del(ht, num_index);
1619 75 : } else if (key_type == HASH_KEY_IS_STRING ||
1620 : key_type == HASH_KEY_IS_UNICODE) {
1621 39 : real_length = key_type == HASH_KEY_IS_STRING ? str_length : str_length * sizeof(UChar);
1622 39 : if (p->nKeyLength == str_length &&
1623 : p->key.type == key_type &&
1624 : memcmp(p->key.arKey.s, str_index.v, real_length) == 0) {
1625 0 : return SUCCESS;
1626 : }
1627 :
1628 39 : if (mode != HASH_UPDATE_KEY_ANYWAY) {
1629 26 : ulong h = zend_u_inline_hash_func(key_type, str_index, str_length);
1630 26 : Bucket *q = ht->arBuckets[h & ht->nTableMask];
1631 26 : int found = 0;
1632 :
1633 56 : while (q != NULL) {
1634 8 : if (q == p) {
1635 4 : found = 1;
1636 4 : } else if (q->h == h && q->nKeyLength == str_length &&
1637 : q->key.type == key_type &&
1638 : memcmp(q->key.arKey.s, str_index.v, real_length) == 0) {
1639 4 : if (found) {
1640 1 : if (mode & HASH_UPDATE_KEY_IF_BEFORE) {
1641 1 : break;
1642 : } else {
1643 0 : if (p->nKeyLength) {
1644 0 : zend_u_hash_del(ht, p->key.type, ZSTR(p->key.arKey.s), p->nKeyLength);
1645 : } else {
1646 0 : zend_hash_index_del(ht, p->h);
1647 : }
1648 0 : return FAILURE;
1649 : }
1650 : } else {
1651 3 : if (mode & HASH_UPDATE_KEY_IF_AFTER) {
1652 0 : break;
1653 : } else {
1654 3 : if (p->nKeyLength) {
1655 3 : zend_u_hash_del(ht, p->key.type, ZSTR(p->key.arKey.s), p->nKeyLength);
1656 : } else {
1657 0 : zend_hash_index_del(ht, p->h);
1658 : }
1659 3 : return FAILURE;
1660 : }
1661 : }
1662 : }
1663 4 : q = q->pNext;
1664 : }
1665 : }
1666 :
1667 36 : zend_u_hash_del(ht, key_type, str_index, str_length);
1668 : } else {
1669 0 : return FAILURE;
1670 : }
1671 :
1672 84 : HANDLE_BLOCK_INTERRUPTIONS();
1673 :
1674 84 : if (p->pNext) {
1675 2 : p->pNext->pLast = p->pLast;
1676 : }
1677 84 : if (p->pLast) {
1678 3 : p->pLast->pNext = p->pNext;
1679 : } else{
1680 81 : ht->arBuckets[p->h & ht->nTableMask] = p->pNext;
1681 : }
1682 :
1683 84 : if (p->nKeyLength != str_length) {
1684 71 : Bucket *q = (Bucket *) pemalloc(sizeof(Bucket) - 1 + real_length, ht->persistent);
1685 :
1686 71 : q->nKeyLength = str_length;
1687 71 : if (p->pData == &p->pDataPtr) {
1688 71 : q->pData = &q->pDataPtr;
1689 : } else {
1690 0 : q->pData = p->pData;
1691 : }
1692 71 : q->pDataPtr = p->pDataPtr;
1693 71 : q->pListNext = p->pListNext;
1694 71 : q->pListLast = p->pListLast;
1695 71 : if (q->pListNext) {
1696 9 : p->pListNext->pListLast = q;
1697 : } else {
1698 62 : ht->pListTail = q;
1699 : }
1700 71 : if (q->pListLast) {
1701 8 : p->pListLast->pListNext = q;
1702 : } else {
1703 63 : ht->pListHead = q;
1704 : }
1705 71 : if (ht->pInternalPointer == p) {
1706 71 : ht->pInternalPointer = q;
1707 : }
1708 71 : if (pos) {
1709 0 : *pos = q;
1710 : }
1711 71 : pefree(p, ht->persistent);
1712 71 : p = q;
1713 : }
1714 :
1715 84 : if (key_type == HASH_KEY_IS_LONG) {
1716 48 : p->h = num_index;
1717 36 : } else if (key_type == HASH_KEY_IS_UNICODE) {
1718 23 : memcpy(p->key.arKey.u, str_index.u, real_length);
1719 23 : p->key.type = IS_UNICODE;
1720 23 : p->h = zend_u_inline_hash_func(IS_UNICODE, str_index, str_length);
1721 : } else {
1722 13 : memcpy(p->key.arKey.s, str_index.s, real_length);
1723 13 : p->key.type = IS_STRING;
1724 13 : p->h = zend_u_inline_hash_func(p->key.type, str_index, str_length);
1725 : }
1726 :
1727 84 : CONNECT_TO_BUCKET_DLLIST(p, ht->arBuckets[p->h & ht->nTableMask]);
1728 84 : ht->arBuckets[p->h & ht->nTableMask] = p;
1729 84 : HANDLE_UNBLOCK_INTERRUPTIONS();
1730 :
1731 84 : return SUCCESS;
1732 : } else {
1733 0 : return FAILURE;
1734 : }
1735 : }
1736 : /* }}} */
1737 :
1738 : ZEND_API int zend_hash_sort(HashTable *ht, sort_func_t sort_func, compare_func_t compar, int renumber TSRMLS_DC) /* {{{ */
1739 18292 : {
1740 : Bucket **arTmp;
1741 : Bucket *p;
1742 : int i, j;
1743 :
1744 : IS_CONSISTENT(ht);
1745 :
1746 18292 : if (!(ht->nNumOfElements>1) && !(renumber && ht->nNumOfElements>0)) { /* Doesn't require sorting */
1747 268 : return SUCCESS;
1748 : }
1749 18024 : arTmp = (Bucket **) pemalloc(ht->nNumOfElements * sizeof(Bucket *), ht->persistent);
1750 18024 : if (!arTmp) {
1751 0 : return FAILURE;
1752 : }
1753 18024 : p = ht->pListHead;
1754 18024 : i = 0;
1755 1224082 : while (p) {
1756 1188034 : arTmp[i] = p;
1757 1188034 : p = p->pListNext;
1758 1188034 : i++;
1759 : }
1760 :
1761 18024 : (*sort_func)((void *) arTmp, i, sizeof(Bucket *), compar TSRMLS_CC);
1762 :
1763 18024 : HANDLE_BLOCK_INTERRUPTIONS();
1764 18024 : ht->pListHead = arTmp[0];
1765 18024 : ht->pListTail = NULL;
1766 18024 : ht->pInternalPointer = ht->pListHead;
1767 :
1768 18024 : arTmp[0]->pListLast = NULL;
1769 18024 : if (i > 1) {
1770 18015 : arTmp[0]->pListNext = arTmp[1];
1771 1170010 : for (j = 1; j < i-1; j++) {
1772 1151995 : arTmp[j]->pListLast = arTmp[j-1];
1773 1151995 : arTmp[j]->pListNext = arTmp[j+1];
1774 : }
1775 18015 : arTmp[j]->pListLast = arTmp[j-1];
1776 18015 : arTmp[j]->pListNext = NULL;
1777 : } else {
1778 9 : arTmp[0]->pListNext = NULL;
1779 : }
1780 18024 : ht->pListTail = arTmp[i-1];
1781 :
1782 18024 : pefree(arTmp, ht->persistent);
1783 18024 : HANDLE_UNBLOCK_INTERRUPTIONS();
1784 :
1785 18024 : if (renumber) {
1786 236 : p = ht->pListHead;
1787 236 : i=0;
1788 13043 : while (p != NULL) {
1789 12571 : p->nKeyLength = 0;
1790 12571 : p->h = i++;
1791 12571 : p = p->pListNext;
1792 : }
1793 236 : ht->nNextFreeElement = i;
1794 236 : zend_hash_rehash(ht);
1795 : }
1796 18024 : return SUCCESS;
1797 : }
1798 : /* }}} */
1799 :
1800 : ZEND_API int zend_hash_compare(HashTable *ht1, HashTable *ht2, compare_func_t compar, zend_bool ordered TSRMLS_DC) /* {{{ */
1801 1218 : {
1802 1218 : Bucket *p1, *p2 = NULL;
1803 : int result;
1804 : void *pData2;
1805 :
1806 : IS_CONSISTENT(ht1);
1807 : IS_CONSISTENT(ht2);
1808 :
1809 1218 : HASH_PROTECT_RECURSION(ht1);
1810 1218 : HASH_PROTECT_RECURSION(ht2);
1811 :
1812 1218 : result = ht1->nNumOfElements - ht2->nNumOfElements;
1813 1218 : if (result!=0) {
1814 463 : HASH_UNPROTECT_RECURSION(ht1);
1815 463 : HASH_UNPROTECT_RECURSION(ht2);
1816 463 : return result;
1817 : }
1818 :
1819 755 : p1 = ht1->pListHead;
1820 755 : if (ordered) {
1821 59 : p2 = ht2->pListHead;
1822 : }
1823 :
1824 4556 : while (p1) {
1825 3382 : if (ordered && !p2) {
1826 0 : HASH_UNPROTECT_RECURSION(ht1);
1827 0 : HASH_UNPROTECT_RECURSION(ht2);
1828 0 : return 1; /* That's not supposed to happen */
1829 : }
1830 3382 : if (ordered) {
1831 1445 : if (p1->nKeyLength==0 && p2->nKeyLength==0) { /* numeric indices */
1832 363 : result = p1->h - p2->h;
1833 363 : if (result!=0) {
1834 1 : HASH_UNPROTECT_RECURSION(ht1);
1835 1 : HASH_UNPROTECT_RECURSION(ht2);
1836 1 : return result;
1837 : }
1838 : } else { /* string indices */
1839 720 : result = p1->key.type - p2->key.type;
1840 720 : if (result==0) {
1841 714 : result = p1->nKeyLength - p2->nKeyLength;
1842 : }
1843 720 : if (result==0) {
1844 714 : result = memcmp(p1->key.arKey.s, p2->key.arKey.s, USTR_BYTES(p1->key.type, p1->nKeyLength));
1845 : }
1846 720 : if (result!=0) {
1847 6 : HASH_UNPROTECT_RECURSION(ht1);
1848 6 : HASH_UNPROTECT_RECURSION(ht2);
1849 6 : return result;
1850 : }
1851 : }
1852 1076 : pData2 = p2->pData;
1853 : } else {
1854 2299 : if (p1->nKeyLength==0) { /* numeric index */
1855 212 : if (zend_hash_index_find(ht2, p1->h, &pData2)==FAILURE) {
1856 4 : HASH_UNPROTECT_RECURSION(ht1);
1857 4 : HASH_UNPROTECT_RECURSION(ht2);
1858 4 : return 1;
1859 : }
1860 : } else { /* string, binary or unicode index */
1861 2087 : if (zend_u_hash_find(ht2, p1->key.type, ZSTR(p1->key.arKey.s), p1->nKeyLength, &pData2)==FAILURE) {
1862 18 : HASH_UNPROTECT_RECURSION(ht1);
1863 18 : HASH_UNPROTECT_RECURSION(ht2);
1864 18 : return 1;
1865 : }
1866 : }
1867 : }
1868 3353 : result = compar(p1->pData, pData2 TSRMLS_CC);
1869 3353 : if (result!=0) {
1870 307 : HASH_UNPROTECT_RECURSION(ht1);
1871 307 : HASH_UNPROTECT_RECURSION(ht2);
1872 307 : return result;
1873 : }
1874 3046 : p1 = p1->pListNext;
1875 3046 : if (ordered) {
1876 1070 : p2 = p2->pListNext;
1877 : }
1878 : }
1879 :
1880 419 : HASH_UNPROTECT_RECURSION(ht1);
1881 419 : HASH_UNPROTECT_RECURSION(ht2);
1882 419 : return 0;
1883 : }
1884 : /* }}} */
1885 :
1886 : ZEND_API int zend_hash_minmax(const HashTable *ht, compare_func_t compar, int flag, void **pData TSRMLS_DC) /* {{{ */
1887 34 : {
1888 : Bucket *p, *res;
1889 :
1890 : IS_CONSISTENT(ht);
1891 :
1892 34 : if (ht->nNumOfElements == 0 ) {
1893 4 : *pData=NULL;
1894 4 : return FAILURE;
1895 : }
1896 :
1897 30 : res = p = ht->pListHead;
1898 112 : while ((p = p->pListNext)) {
1899 52 : if (flag) {
1900 26 : if (compar(&res, &p TSRMLS_CC) < 0) { /* max */
1901 14 : res = p;
1902 : }
1903 : } else {
1904 26 : if (compar(&res, &p TSRMLS_CC) > 0) { /* min */
1905 4 : res = p;
1906 : }
1907 : }
1908 : }
1909 30 : *pData = res->pData;
1910 30 : return SUCCESS;
1911 : }
1912 : /* }}} */
1913 :
1914 : ZEND_API ulong zend_hash_next_free_element(const HashTable *ht) /* {{{ */
1915 505658 : {
1916 : IS_CONSISTENT(ht);
1917 :
1918 505658 : return ht->nNextFreeElement;
1919 :
1920 : }
1921 : /* }}} */
1922 :
1923 : ZEND_API int zend_u_symtable_update(HashTable *ht, zend_uchar type, zstr arKey, uint nKeyLength, void *pData, uint nDataSize, void **pDest) /* {{{ */
1924 1731252 : {
1925 1731252 : if (type == IS_STRING) {
1926 892925 : ZEND_HANDLE_NUMERIC(arKey.s, nKeyLength, zend_hash_index_update(ht, idx, pData, nDataSize, pDest));
1927 838327 : } else if (type == IS_UNICODE) {
1928 838327 : ZEND_HANDLE_U_NUMERIC(arKey.u, nKeyLength, zend_hash_index_update(ht, idx, pData, nDataSize, pDest));
1929 : }
1930 1729944 : return zend_u_hash_update(ht, type, arKey, nKeyLength, pData, nDataSize, pDest);
1931 : }
1932 : /* }}} */
1933 :
1934 : ZEND_API int zend_u_symtable_del(HashTable *ht, zend_uchar type, zstr arKey, uint nKeyLength) /* {{{ */
1935 527 : {
1936 527 : if (type == IS_STRING) {
1937 0 : ZEND_HANDLE_NUMERIC(arKey.s, nKeyLength, zend_hash_index_del(ht, idx));
1938 527 : } else if (type == IS_UNICODE) {
1939 527 : ZEND_HANDLE_U_NUMERIC(arKey.u, nKeyLength, zend_hash_index_del(ht, idx));
1940 : }
1941 520 : return zend_u_hash_del(ht, type, arKey, nKeyLength);
1942 : }
1943 : /* }}} */
1944 :
1945 : ZEND_API int zend_u_symtable_find(HashTable *ht, zend_uchar type, zstr arKey, uint nKeyLength, void **pData) /* {{{ */
1946 3589240 : {
1947 3589240 : if (type == IS_STRING) {
1948 919397 : ZEND_HANDLE_NUMERIC(arKey.s, nKeyLength, zend_hash_index_find(ht, idx, pData));
1949 2669843 : } else if (type == IS_UNICODE) {
1950 2669843 : ZEND_HANDLE_U_NUMERIC(arKey.u, nKeyLength, zend_hash_index_find(ht, idx, pData));
1951 : }
1952 3229120 : return zend_u_hash_find(ht, type, arKey, nKeyLength, pData);
1953 : }
1954 : /* }}} */
1955 :
1956 : ZEND_API int zend_u_symtable_exists(HashTable *ht, zend_uchar type, zstr arKey, uint nKeyLength) /* {{{ */
1957 73626 : {
1958 73626 : if (type == IS_STRING) {
1959 0 : ZEND_HANDLE_NUMERIC(arKey.s, nKeyLength, zend_hash_index_exists(ht, idx));
1960 73626 : } else if (type == IS_UNICODE) {
1961 73626 : ZEND_HANDLE_U_NUMERIC(arKey.u, nKeyLength, zend_hash_index_exists(ht, idx));
1962 : }
1963 73595 : return zend_u_hash_exists(ht, type, arKey, nKeyLength);
1964 : }
1965 : /* }}} */
1966 :
1967 : ZEND_API int zend_u_symtable_update_current_key_ex(HashTable *ht, zend_uchar type, zstr arKey, uint nKeyLength, int mode, HashPosition *pos) /* {{{ */
1968 27 : {
1969 : zend_uchar key_type;
1970 :
1971 27 : if (type == IS_STRING) {
1972 0 : key_type = HASH_KEY_IS_STRING;
1973 0 : ZEND_HANDLE_NUMERIC(arKey.s, nKeyLength, zend_hash_update_current_key_ex(ht, HASH_KEY_IS_LONG, NULL_ZSTR, 0, idx, mode, pos));
1974 : } else {
1975 27 : key_type = HASH_KEY_IS_UNICODE;
1976 27 : ZEND_HANDLE_U_NUMERIC(arKey.u, nKeyLength, zend_hash_update_current_key_ex(ht, HASH_KEY_IS_LONG, NULL_ZSTR, 0, idx, mode, pos));
1977 : }
1978 26 : return zend_hash_update_current_key_ex(ht, key_type, arKey, nKeyLength, 0, mode, pos);
1979 : }
1980 : /* }}} */
1981 :
1982 : ZEND_API int zend_symtable_update(HashTable *ht, const char *arKey, uint nKeyLength, void *pData, uint nDataSize, void **pDest) /* {{{ */
1983 1005943 : {
1984 1005943 : ZEND_HANDLE_NUMERIC(arKey, nKeyLength, zend_hash_index_update(ht, idx, pData, nDataSize, pDest));
1985 1005805 : return zend_hash_update(ht, arKey, nKeyLength, pData, nDataSize, pDest);
1986 : }
1987 : /* }}} */
1988 :
1989 : ZEND_API int zend_symtable_del(HashTable *ht, const char *arKey, uint nKeyLength) /* {{{ */
1990 0 : {
1991 0 : ZEND_HANDLE_NUMERIC(arKey, nKeyLength, zend_hash_index_del(ht, idx));
1992 0 : return zend_hash_del(ht, arKey, nKeyLength);
1993 : }
1994 : /* }}} */
1995 :
1996 : ZEND_API int zend_symtable_find(HashTable *ht, const char *arKey, uint nKeyLength, void **pData) /* {{{ */
1997 93 : {
1998 93 : ZEND_HANDLE_NUMERIC(arKey, nKeyLength, zend_hash_index_find(ht, idx, pData));
1999 79 : return zend_hash_find(ht, arKey, nKeyLength, pData);
2000 : }
2001 : /* }}} */
2002 :
2003 : ZEND_API int zend_symtable_exists(HashTable *ht, const char *arKey, uint nKeyLength) /* {{{ */
2004 0 : {
2005 0 : ZEND_HANDLE_NUMERIC(arKey, nKeyLength, zend_hash_index_exists(ht, idx));
2006 0 : return zend_hash_exists(ht, arKey, nKeyLength);
2007 : }
2008 : /* }}} */
2009 :
2010 : ZEND_API int zend_symtable_update_current_key_ex(HashTable *ht, const char *arKey, uint nKeyLength, int mode, HashPosition *pos) /* {{{ */
2011 0 : {
2012 0 : ZEND_HANDLE_NUMERIC(arKey, nKeyLength, zend_hash_update_current_key_ex(ht, HASH_KEY_IS_LONG, NULL_ZSTR, 0, idx, mode, pos));
2013 0 : return zend_hash_update_current_key_ex(ht, HASH_KEY_IS_STRING, ZSTR(arKey), nKeyLength, 0, mode, pos);
2014 : }
2015 : /* }}} */
2016 :
2017 : ZEND_API int zend_ascii_symtable_update(HashTable *ht, const char *arKey, uint nKeyLength, void *pData, uint nDataSize, void **pDest) /* {{{ */
2018 212212 : {
2019 212212 : ZEND_HANDLE_NUMERIC(arKey, nKeyLength, zend_hash_index_update(ht, idx, pData, nDataSize, pDest));
2020 212212 : return zend_ascii_hash_update(ht, arKey, nKeyLength, pData, nDataSize, pDest);
2021 : }
2022 : /* }}} */
2023 :
2024 : ZEND_API int zend_ascii_symtable_del(HashTable *ht, const char *arKey, uint nKeyLength) /* {{{ */
2025 0 : {
2026 0 : ZEND_HANDLE_NUMERIC(arKey, nKeyLength, zend_hash_index_del(ht, idx));
2027 0 : return zend_ascii_hash_del(ht, arKey, nKeyLength);
2028 : }
2029 : /* }}} */
2030 :
2031 : ZEND_API int zend_ascii_symtable_find(HashTable *ht, const char *arKey, uint nKeyLength, void **pData) /* {{{ */
2032 0 : {
2033 0 : ZEND_HANDLE_NUMERIC(arKey, nKeyLength, zend_hash_index_find(ht, idx, pData));
2034 0 : return zend_ascii_hash_find(ht, arKey, nKeyLength, pData);
2035 : }
2036 : /* }}} */
2037 :
2038 : ZEND_API int zend_ascii_symtable_exists(HashTable *ht, const char *arKey, uint nKeyLength) /* {{{ */
2039 0 : {
2040 0 : ZEND_HANDLE_NUMERIC(arKey, nKeyLength, zend_hash_index_exists(ht, idx));
2041 0 : return zend_ascii_hash_exists(ht, arKey, nKeyLength);
2042 : }
2043 : /* }}} */
2044 :
2045 : ZEND_API int zend_rt_symtable_update(HashTable *ht, const char *arKey, uint nKeyLength, void *pData, uint nDataSize, void **pDest) /* {{{ */
2046 99 : {
2047 99 : ZEND_HANDLE_NUMERIC(arKey, nKeyLength, zend_hash_index_update(ht, idx, pData, nDataSize, pDest));
2048 19 : return zend_rt_hash_update(ht, arKey, nKeyLength, pData, nDataSize, pDest);
2049 : }
2050 : /* }}} */
2051 :
2052 : ZEND_API int zend_rt_symtable_del(HashTable *ht, const char *arKey, uint nKeyLength) /* {{{ */
2053 0 : {
2054 0 : ZEND_HANDLE_NUMERIC(arKey, nKeyLength, zend_hash_index_del(ht, idx));
2055 0 : return zend_rt_hash_del(ht, arKey, nKeyLength);
2056 : }
2057 : /* }}} */
2058 :
2059 : ZEND_API int zend_rt_symtable_find(HashTable *ht, const char *arKey, uint nKeyLength, void **pData) /* {{{ */
2060 0 : {
2061 0 : ZEND_HANDLE_NUMERIC(arKey, nKeyLength, zend_hash_index_find(ht, idx, pData));
2062 0 : return zend_rt_hash_find(ht, arKey, nKeyLength, pData);
2063 : }
2064 : /* }}} */
2065 :
2066 : ZEND_API int zend_rt_symtable_exists(HashTable *ht, const char *arKey, uint nKeyLength) /* {{{ */
2067 0 : {
2068 0 : ZEND_HANDLE_NUMERIC(arKey, nKeyLength, zend_hash_index_exists(ht, idx));
2069 0 : return zend_rt_hash_exists(ht, arKey, nKeyLength);
2070 : }
2071 : /* }}} */
2072 :
2073 : ZEND_API int zend_utf8_symtable_update(HashTable *ht, const char *arKey, uint nKeyLength, void *pData, uint nDataSize, void **pDest) /* {{{ */
2074 203 : {
2075 203 : ZEND_HANDLE_NUMERIC(arKey, nKeyLength, zend_hash_index_update(ht, idx, pData, nDataSize, pDest));
2076 197 : return zend_utf8_hash_update(ht, arKey, nKeyLength, pData, nDataSize, pDest);
2077 : }
2078 : /* }}} */
2079 :
2080 : ZEND_API int zend_utf8_symtable_del(HashTable *ht, const char *arKey, uint nKeyLength) /* {{{ */
2081 0 : {
2082 0 : ZEND_HANDLE_NUMERIC(arKey, nKeyLength, zend_hash_index_del(ht, idx));
2083 0 : return zend_utf8_hash_del(ht, arKey, nKeyLength);
2084 : }
2085 : /* }}} */
2086 :
2087 : ZEND_API int zend_utf8_symtable_find(HashTable *ht, const char *arKey, uint nKeyLength, void **pData) /* {{{ */
2088 0 : {
2089 0 : ZEND_HANDLE_NUMERIC(arKey, nKeyLength, zend_hash_index_find(ht, idx, pData));
2090 0 : return zend_utf8_hash_find(ht, arKey, nKeyLength, pData);
2091 : }
2092 : /* }}} */
2093 :
2094 : ZEND_API int zend_utf8_symtable_exists(HashTable *ht, const char *arKey, uint nKeyLength) /* {{{ */
2095 0 : {
2096 0 : ZEND_HANDLE_NUMERIC(arKey, nKeyLength, zend_hash_index_exists(ht, idx));
2097 0 : return zend_utf8_hash_exists(ht, arKey, nKeyLength);
2098 : }
2099 : /* }}} */
2100 :
2101 : ZEND_API void zend_hash_to_unicode(HashTable *ht, apply_func_t apply_func TSRMLS_DC) /* {{{ */
2102 68028 : {
2103 : Bucket **p;
2104 : uint nIndex;
2105 :
2106 : IS_CONSISTENT(ht);
2107 68028 : if (ht->unicode) {
2108 0 : return;
2109 : }
2110 :
2111 68028 : ht->unicode = 1;
2112 68028 : memset(ht->arBuckets, 0, ht->nTableSize * sizeof(Bucket *));
2113 68028 : p = &ht->pListHead;
2114 1462602 : while ((*p) != NULL) {
2115 1326546 : if ((*p)->key.type == IS_STRING) {
2116 17007 : UErrorCode status = U_ZERO_ERROR;
2117 17007 : UChar *u = NULL;
2118 : int u_len;
2119 : Bucket *q;
2120 :
2121 17007 : zend_string_to_unicode_ex(ZEND_U_CONVERTER(UG(runtime_encoding_conv)), &u, &u_len, (*p)->key.arKey.s, (*p)->nKeyLength-1, &status);
2122 17007 : if (U_FAILURE(status)) {
2123 0 : zend_error(E_ERROR, "Cannot convert HashTable to Unicode");
2124 : }
2125 :
2126 17007 : q = (Bucket *) pemalloc(sizeof(Bucket)-sizeof(q->key.arKey)+((u_len+1)*2), ht->persistent);
2127 17007 : memcpy(q, *p, sizeof(Bucket)-sizeof(q->key.arKey));
2128 17007 : memcpy(q->key.arKey.u, u, (u_len+1)*2);
2129 17007 : q->key.type = IS_UNICODE;
2130 17007 : q->nKeyLength = u_len+1;
2131 17007 : q->h = zend_u_inline_hash_func(IS_UNICODE, q->key.arKey, q->nKeyLength);
2132 17007 : if ((*p)->pData == &(*p)->pDataPtr) {
2133 0 : q->pData = &q->pDataPtr;
2134 : }
2135 17007 : efree(u);
2136 17007 : pefree(*p, ht->persistent);
2137 17007 : *p = q;
2138 17007 : if (q->pListNext) {
2139 0 : q->pListNext->pListLast = q;
2140 : } else {
2141 17007 : ht->pListTail = q;
2142 : }
2143 : }
2144 1326546 : nIndex = (*p)->h & ht->nTableMask;
2145 1326546 : CONNECT_TO_BUCKET_DLLIST(*p, ht->arBuckets[nIndex]);
2146 1326546 : ht->arBuckets[nIndex] = *p;
2147 1326546 : if (apply_func) {
2148 1309539 : apply_func((*p)->pData TSRMLS_CC);
2149 : }
2150 1326546 : p = &(*p)->pListNext;
2151 : }
2152 : }
2153 : /* }}} */
2154 :
2155 : #if ZEND_DEBUG
2156 : void zend_hash_display_pListTail(const HashTable *ht) /* {{{ */
2157 : {
2158 : Bucket *p;
2159 :
2160 : p = ht->pListTail;
2161 : while (p != NULL) {
2162 : if (p->key.type == IS_UNICODE) {
2163 : /* FIXME: Unicode support??? */
2164 : } else {
2165 : zend_output_debug_string(0, "pListTail has key %s\n", p->key.arKey.s);
2166 : }
2167 : p = p->pListLast;
2168 : }
2169 : }
2170 : /* }}} */
2171 :
2172 : void zend_hash_display(const HashTable *ht) /* {{{ */
2173 : {
2174 : Bucket *p;
2175 : uint i;
2176 :
2177 : for (i = 0; i < ht->nTableSize; i++) {
2178 : p = ht->arBuckets[i];
2179 : while (p != NULL) {
2180 : if (p->key.type == IS_UNICODE) {
2181 : /* FIXME: Unicode support??? */
2182 : } else {
2183 : zend_output_debug_string(0, "%s <==> 0x%lX\n", p->key.arKey.s, p->h);
2184 : }
2185 : p = p->pNext;
2186 : }
2187 : }
2188 :
2189 : p = ht->pListTail;
2190 : while (p != NULL) {
2191 : if (p->key.type == IS_UNICODE) {
2192 : /* FIXME: Unicode support??? */
2193 : } else {
2194 : zend_output_debug_string(0, "%s <==> 0x%lX\n", p->key.arKey.s, p->h);
2195 : }
2196 : p = p->pListLast;
2197 : }
2198 : }
2199 : /* }}} */
2200 :
2201 : #endif
2202 :
2203 : /*
2204 : * Local variables:
2205 : * tab-width: 4
2206 : * c-basic-offset: 4
2207 : * indent-tabs-mode: t
2208 : * End:
2209 : */
|