1/*
2   +----------------------------------------------------------------------+
3   | Zend Engine                                                          |
4   +----------------------------------------------------------------------+
5   | Copyright (c) 1998-2014 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$ */
21
22#ifndef ZEND_HASH_H
23#define ZEND_HASH_H
24
25#include "zend.h"
26
27#define HASH_KEY_IS_STRING 1
28#define HASH_KEY_IS_LONG 2
29#define HASH_KEY_NON_EXISTENT 3
30
31#define HASH_UPDATE             (1<<0)
32#define HASH_ADD                (1<<1)
33#define HASH_UPDATE_INDIRECT    (1<<2)
34#define HASH_ADD_NEW            (1<<3)
35
36#define INVALID_IDX ((uint32_t) -1)
37
38#define HASH_FLAG_PERSISTENT       (1<<0)
39#define HASH_FLAG_APPLY_PROTECTION (1<<1)
40#define HASH_FLAG_PACKED           (1<<2)
41
42#define HASH_MASK_CONSISTENCY      0x60
43
44typedef struct _zend_hash_key {
45    zend_ulong h;
46    zend_string *key;
47} zend_hash_key;
48
49typedef zend_bool (*merge_checker_func_t)(HashTable *target_ht, zval *source_data, zend_hash_key *hash_key, void *pParam);
50
51typedef uint32_t HashPosition;
52
53BEGIN_EXTERN_C()
54
55/* startup/shutdown */
56ZEND_API void _zend_hash_init(HashTable *ht, uint32_t nSize, dtor_func_t pDestructor, zend_bool persistent ZEND_FILE_LINE_DC);
57ZEND_API void _zend_hash_init_ex(HashTable *ht, uint32_t nSize, dtor_func_t pDestructor, zend_bool persistent, zend_bool bApplyProtection ZEND_FILE_LINE_DC);
58ZEND_API void zend_hash_destroy(HashTable *ht);
59ZEND_API void zend_hash_clean(HashTable *ht);
60#define zend_hash_init(ht, nSize, pHashFunction, pDestructor, persistent)                       _zend_hash_init((ht), (nSize), (pDestructor), (persistent) ZEND_FILE_LINE_CC)
61#define zend_hash_init_ex(ht, nSize, pHashFunction, pDestructor, persistent, bApplyProtection)      _zend_hash_init_ex((ht), (nSize), (pDestructor), (persistent), (bApplyProtection) ZEND_FILE_LINE_CC)
62
63ZEND_API void zend_hash_real_init(HashTable *ht, zend_bool packed);
64ZEND_API void zend_hash_packed_to_hash(HashTable *ht);
65ZEND_API void zend_hash_to_packed(HashTable *ht);
66
67/* additions/updates/changes */
68ZEND_API zval *_zend_hash_add_or_update(HashTable *ht, zend_string *key, zval *pData, uint32_t flag ZEND_FILE_LINE_DC);
69ZEND_API zval *_zend_hash_update(HashTable *ht, zend_string *key,zval *pData ZEND_FILE_LINE_DC);
70ZEND_API zval *_zend_hash_update_ind(HashTable *ht, zend_string *key,zval *pData ZEND_FILE_LINE_DC);
71ZEND_API zval *_zend_hash_add(HashTable *ht, zend_string *key,zval *pData ZEND_FILE_LINE_DC);
72ZEND_API zval *_zend_hash_add_new(HashTable *ht, zend_string *key,zval *pData ZEND_FILE_LINE_DC);
73
74#define zend_hash_update(ht, key, pData) \
75        _zend_hash_update(ht, key, pData ZEND_FILE_LINE_CC)
76#define zend_hash_update_ind(ht, key, pData) \
77        _zend_hash_update_ind(ht, key, pData ZEND_FILE_LINE_CC)
78#define zend_hash_add(ht, key, pData) \
79        _zend_hash_add(ht, key, pData ZEND_FILE_LINE_CC)
80#define zend_hash_add_new(ht, key, pData) \
81        _zend_hash_add_new(ht, key, pData ZEND_FILE_LINE_CC)
82
83ZEND_API zval *_zend_hash_str_add_or_update(HashTable *ht, const char *key, size_t len, zval *pData, uint32_t flag ZEND_FILE_LINE_DC);
84ZEND_API zval *_zend_hash_str_update(HashTable *ht, const char *key, size_t len, zval *pData ZEND_FILE_LINE_DC);
85ZEND_API zval *_zend_hash_str_update_ind(HashTable *ht, const char *key, size_t len, zval *pData ZEND_FILE_LINE_DC);
86ZEND_API zval *_zend_hash_str_add(HashTable *ht, const char *key, size_t len, zval *pData ZEND_FILE_LINE_DC);
87ZEND_API zval *_zend_hash_str_add_new(HashTable *ht, const char *key, size_t len, zval *pData ZEND_FILE_LINE_DC);
88
89#define zend_hash_str_update(ht, key, len, pData) \
90        _zend_hash_str_update(ht, key, len, pData ZEND_FILE_LINE_CC)
91#define zend_hash_str_update_ind(ht, key, len, pData) \
92        _zend_hash_str_update_ind(ht, key, len, pData ZEND_FILE_LINE_CC)
93#define zend_hash_str_add(ht, key, len, pData) \
94        _zend_hash_str_add(ht, key, len, pData ZEND_FILE_LINE_CC)
95#define zend_hash_str_add_new(ht, key, len, pData) \
96        _zend_hash_str_add_new(ht, key, len, pData ZEND_FILE_LINE_CC)
97
98ZEND_API zval *_zend_hash_index_add_or_update(HashTable *ht, zend_ulong h, zval *pData, uint32_t flag ZEND_FILE_LINE_DC);
99ZEND_API zval *_zend_hash_index_add(HashTable *ht, zend_ulong h, zval *pData ZEND_FILE_LINE_DC);
100ZEND_API zval *_zend_hash_index_add_new(HashTable *ht, zend_ulong h, zval *pData ZEND_FILE_LINE_DC);
101ZEND_API zval *_zend_hash_index_update(HashTable *ht, zend_ulong h, zval *pData ZEND_FILE_LINE_DC);
102ZEND_API zval *_zend_hash_next_index_insert(HashTable *ht, zval *pData ZEND_FILE_LINE_DC);
103ZEND_API zval *_zend_hash_next_index_insert_new(HashTable *ht, zval *pData ZEND_FILE_LINE_DC);
104
105#define zend_hash_index_add(ht, h, pData) \
106        _zend_hash_index_add(ht, h, pData ZEND_FILE_LINE_CC)
107#define zend_hash_index_add_new(ht, h, pData) \
108        _zend_hash_index_add_new(ht, h, pData ZEND_FILE_LINE_CC)
109#define zend_hash_index_update(ht, h, pData) \
110        _zend_hash_index_update(ht, h, pData ZEND_FILE_LINE_CC)
111#define zend_hash_next_index_insert(ht, pData) \
112        _zend_hash_next_index_insert(ht, pData ZEND_FILE_LINE_CC)
113#define zend_hash_next_index_insert_new(ht, pData) \
114        _zend_hash_next_index_insert_new(ht, pData ZEND_FILE_LINE_CC)
115
116ZEND_API zval *zend_hash_index_add_empty_element(HashTable *ht, zend_ulong h);
117ZEND_API zval *zend_hash_add_empty_element(HashTable *ht, zend_string *key);
118ZEND_API zval *zend_hash_str_add_empty_element(HashTable *ht, const char *key, size_t len);
119
120#define ZEND_HASH_APPLY_KEEP                0
121#define ZEND_HASH_APPLY_REMOVE              1<<0
122#define ZEND_HASH_APPLY_STOP                1<<1
123
124typedef int (*apply_func_t)(zval *pDest TSRMLS_DC);
125typedef int (*apply_func_arg_t)(zval *pDest, void *argument TSRMLS_DC);
126typedef int (*apply_func_args_t)(zval *pDest TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key);
127
128ZEND_API void zend_hash_graceful_destroy(HashTable *ht);
129ZEND_API void zend_hash_graceful_reverse_destroy(HashTable *ht);
130ZEND_API void zend_hash_apply(HashTable *ht, apply_func_t apply_func TSRMLS_DC);
131ZEND_API void zend_hash_apply_with_argument(HashTable *ht, apply_func_arg_t apply_func, void * TSRMLS_DC);
132ZEND_API void zend_hash_apply_with_arguments(HashTable *ht TSRMLS_DC, apply_func_args_t apply_func, int, ...);
133
134/* This function should be used with special care (in other words,
135 * it should usually not be used).  When used with the ZEND_HASH_APPLY_STOP
136 * return value, it assumes things about the order of the elements in the hash.
137 * Also, it does not provide the same kind of reentrancy protection that
138 * the standard apply functions do.
139 */
140ZEND_API void zend_hash_reverse_apply(HashTable *ht, apply_func_t apply_func TSRMLS_DC);
141
142
143/* Deletes */
144ZEND_API int zend_hash_del(HashTable *ht, zend_string *key);
145ZEND_API int zend_hash_del_ind(HashTable *ht, zend_string *key);
146ZEND_API int zend_hash_str_del(HashTable *ht, const char *key, size_t len);
147ZEND_API int zend_hash_str_del_ind(HashTable *ht, const char *key, size_t len);
148ZEND_API int zend_hash_index_del(HashTable *ht, zend_ulong h);
149
150/* Data retreival */
151ZEND_API zval *zend_hash_find(const HashTable *ht, zend_string *key);
152ZEND_API zval *zend_hash_str_find(const HashTable *ht, const char *key, size_t len);
153ZEND_API zval *zend_hash_index_find(const HashTable *ht, zend_ulong h);
154
155/* Misc */
156ZEND_API zend_bool zend_hash_exists(const HashTable *ht, zend_string *key);
157ZEND_API zend_bool zend_hash_str_exists(const HashTable *ht, const char *str, size_t len);
158ZEND_API zend_bool zend_hash_index_exists(const HashTable *ht, zend_ulong h);
159
160/* traversing */
161#define zend_hash_has_more_elements_ex(ht, pos) \
162    (zend_hash_get_current_key_type_ex(ht, pos) == HASH_KEY_NON_EXISTENT ? FAILURE : SUCCESS)
163ZEND_API int zend_hash_move_forward_ex(HashTable *ht, HashPosition *pos);
164ZEND_API int zend_hash_move_backwards_ex(HashTable *ht, HashPosition *pos);
165ZEND_API int zend_hash_get_current_key_ex(const HashTable *ht, zend_string **str_index, zend_ulong *num_index, zend_bool duplicate, HashPosition *pos);
166ZEND_API void zend_hash_get_current_key_zval_ex(const HashTable *ht, zval *key, HashPosition *pos);
167ZEND_API int zend_hash_get_current_key_type_ex(HashTable *ht, HashPosition *pos);
168ZEND_API zval *zend_hash_get_current_data_ex(HashTable *ht, HashPosition *pos);
169ZEND_API void zend_hash_internal_pointer_reset_ex(HashTable *ht, HashPosition *pos);
170ZEND_API void zend_hash_internal_pointer_end_ex(HashTable *ht, HashPosition *pos);
171
172typedef struct _HashPointer {
173    HashPosition pos;
174    HashTable *ht;
175    zend_ulong h;
176} HashPointer;
177
178#define zend_hash_has_more_elements(ht) \
179    zend_hash_has_more_elements_ex(ht, &(ht)->nInternalPointer)
180#define zend_hash_move_forward(ht) \
181    zend_hash_move_forward_ex(ht, &(ht)->nInternalPointer)
182#define zend_hash_move_backwards(ht) \
183    zend_hash_move_backwards_ex(ht, &(ht)->nInternalPointer)
184#define zend_hash_get_current_key(ht, str_index, num_index, duplicate) \
185    zend_hash_get_current_key_ex(ht, str_index, num_index, duplicate, &(ht)->nInternalPointer)
186#define zend_hash_get_current_key_zval(ht, key) \
187    zend_hash_get_current_key_zval_ex(ht, key, &(ht)->nInternalPointer)
188#define zend_hash_get_current_key_type(ht) \
189    zend_hash_get_current_key_type_ex(ht, &(ht)->nInternalPointer)
190#define zend_hash_get_current_data(ht) \
191    zend_hash_get_current_data_ex(ht, &(ht)->nInternalPointer)
192#define zend_hash_internal_pointer_reset(ht) \
193    zend_hash_internal_pointer_reset_ex(ht, &(ht)->nInternalPointer)
194#define zend_hash_internal_pointer_end(ht) \
195    zend_hash_internal_pointer_end_ex(ht, &(ht)->nInternalPointer)
196
197/* Copying, merging and sorting */
198ZEND_API void zend_hash_copy(HashTable *target, HashTable *source, copy_ctor_func_t pCopyConstructor);
199ZEND_API void _zend_hash_merge(HashTable *target, HashTable *source, copy_ctor_func_t pCopyConstructor, zend_bool overwrite ZEND_FILE_LINE_DC);
200ZEND_API void zend_hash_merge_ex(HashTable *target, HashTable *source, copy_ctor_func_t pCopyConstructor, merge_checker_func_t pMergeSource, void *pParam);
201ZEND_API int zend_hash_sort(HashTable *ht, sort_func_t sort_func, compare_func_t compare_func, zend_bool renumber TSRMLS_DC);
202ZEND_API int zend_hash_compare(HashTable *ht1, HashTable *ht2, compare_func_t compar, zend_bool ordered TSRMLS_DC);
203ZEND_API zval *zend_hash_minmax(const HashTable *ht, compare_func_t compar, uint32_t flag TSRMLS_DC);
204
205#define zend_hash_merge(target, source, pCopyConstructor, overwrite)                    \
206    _zend_hash_merge(target, source, pCopyConstructor, overwrite ZEND_FILE_LINE_CC)
207
208#define zend_hash_num_elements(ht) \
209    (ht)->nNumOfElements
210
211#define zend_hash_next_free_element(ht) \
212    (ht)->nNextFreeElement
213
214ZEND_API int zend_hash_rehash(HashTable *ht);
215
216ZEND_API void zend_array_dup(HashTable *target, HashTable *source);
217
218#if ZEND_DEBUG
219/* debug */
220void zend_hash_display_pListTail(const HashTable *ht);
221void zend_hash_display(const HashTable *ht);
222#endif
223
224END_EXTERN_C()
225
226#define ZEND_INIT_SYMTABLE(ht)                              \
227    ZEND_INIT_SYMTABLE_EX(ht, 8, 0)
228
229#define ZEND_INIT_SYMTABLE_EX(ht, n, persistent)            \
230    zend_hash_init(ht, n, NULL, ZVAL_PTR_DTOR, persistent)
231
232ZEND_API int _zend_handle_numeric_str_ex(const char *key, size_t length, zend_ulong *idx);
233
234static zend_always_inline int _zend_handle_numeric_str(const char *key, size_t length, zend_ulong *idx)
235{
236    register const char *tmp = key;
237
238    if (*tmp > '9') {
239        return 0;
240    } else if (*tmp < '0') {
241        if (*tmp != '-') {
242            return 0;
243        }
244        tmp++;
245        if (*tmp > '9' || *tmp < '0') {
246            return 0;
247        }
248    }
249    return _zend_handle_numeric_str_ex(key, length, idx);
250}
251
252#define ZEND_HANDLE_NUMERIC_STR(key, length, idx) \
253    _zend_handle_numeric_str(key, length, &idx)
254
255#define ZEND_HANDLE_NUMERIC(key, idx) \
256    ZEND_HANDLE_NUMERIC_STR((key)->val, (key)->len, idx)
257
258
259static zend_always_inline zval *zend_hash_find_ind(const HashTable *ht, zend_string *key)
260{
261    zval *zv;
262
263    zv = zend_hash_find(ht, key);
264    return (zv && Z_TYPE_P(zv) == IS_INDIRECT) ? Z_INDIRECT_P(zv) : zv;
265}
266
267
268static zend_always_inline int zend_hash_exists_ind(const HashTable *ht, zend_string *key)
269{
270    zval *zv;
271
272    zv = zend_hash_find(ht, key);
273    return zv && (Z_TYPE_P(zv) != IS_INDIRECT ||
274            Z_TYPE_P(Z_INDIRECT_P(zv)) != IS_UNDEF);
275}
276
277
278static zend_always_inline zval *zend_hash_str_find_ind(const HashTable *ht, const char *str, int len)
279{
280    zval *zv;
281
282    zv = zend_hash_str_find(ht, str, len);
283    return (zv && Z_TYPE_P(zv) == IS_INDIRECT) ? Z_INDIRECT_P(zv) : zv;
284}
285
286
287static zend_always_inline zval *zend_symtable_update(HashTable *ht, zend_string *key, zval *pData)
288{
289    zend_ulong idx;
290
291    if (ZEND_HANDLE_NUMERIC(key, idx)) {
292        return zend_hash_index_update(ht, idx, pData);
293    } else {
294        return zend_hash_update(ht, key, pData);
295    }
296}
297
298
299static zend_always_inline zval *zend_symtable_update_ind(HashTable *ht, zend_string *key, zval *pData)
300{
301    zend_ulong idx;
302
303    if (ZEND_HANDLE_NUMERIC(key, idx)) {
304        return zend_hash_index_update(ht, idx, pData);
305    } else {
306        return zend_hash_update_ind(ht, key, pData);
307    }
308}
309
310
311static zend_always_inline int zend_symtable_del(HashTable *ht, zend_string *key)
312{
313    zend_ulong idx;
314
315    if (ZEND_HANDLE_NUMERIC(key, idx)) {
316        return zend_hash_index_del(ht, idx);
317    } else {
318        return zend_hash_del(ht, key);
319    }
320}
321
322
323static zend_always_inline int zend_symtable_del_ind(HashTable *ht, zend_string *key)
324{
325    zend_ulong idx;
326
327    if (ZEND_HANDLE_NUMERIC(key, idx)) {
328        return zend_hash_index_del(ht, idx);
329    } else {
330        return zend_hash_del_ind(ht, key);
331    }
332}
333
334
335static zend_always_inline zval *zend_symtable_find(const HashTable *ht, zend_string *key)
336{
337    zend_ulong idx;
338
339    if (ZEND_HANDLE_NUMERIC(key, idx)) {
340        return zend_hash_index_find(ht, idx);
341    } else {
342        return zend_hash_find(ht, key);
343    }
344}
345
346
347static zend_always_inline zval *zend_symtable_find_ind(const HashTable *ht, zend_string *key)
348{
349    zend_ulong idx;
350
351    if (ZEND_HANDLE_NUMERIC(key, idx)) {
352        return zend_hash_index_find(ht, idx);
353    } else {
354        return zend_hash_find_ind(ht, key);
355    }
356}
357
358
359static zend_always_inline int zend_symtable_exists(HashTable *ht, zend_string *key)
360{
361    zend_ulong idx;
362
363    if (ZEND_HANDLE_NUMERIC(key, idx)) {
364        return zend_hash_index_exists(ht, idx);
365    } else {
366        return zend_hash_exists(ht, key);
367    }
368}
369
370
371static zend_always_inline zval *zend_symtable_str_update(HashTable *ht, const char *str, int len, zval *pData)
372{
373    zend_ulong idx;
374
375    if (ZEND_HANDLE_NUMERIC_STR(str, len, idx)) {
376        return zend_hash_index_update(ht, idx, pData);
377    } else {
378        return zend_hash_str_update(ht, str, len, pData);
379    }
380}
381
382
383static zend_always_inline zval *zend_symtable_str_update_ind(HashTable *ht, const char *str, int len, zval *pData)
384{
385    zend_ulong idx;
386
387    if (ZEND_HANDLE_NUMERIC_STR(str, len, idx)) {
388        return zend_hash_index_update(ht, idx, pData);
389    } else {
390        return zend_hash_str_update_ind(ht, str, len, pData);
391    }
392}
393
394
395static zend_always_inline int zend_symtable_str_del(HashTable *ht, const char *str, int len)
396{
397    zend_ulong idx;
398
399    if (ZEND_HANDLE_NUMERIC_STR(str, len, idx)) {
400        return zend_hash_index_del(ht, idx);
401    } else {
402        return zend_hash_str_del(ht, str, len);
403    }
404}
405
406
407static zend_always_inline int zend_symtable_str_del_ind(HashTable *ht, const char *str, int len)
408{
409    zend_ulong idx;
410
411    if (ZEND_HANDLE_NUMERIC_STR(str, len, idx)) {
412        return zend_hash_index_del(ht, idx);
413    } else {
414        return zend_hash_str_del_ind(ht, str, len);
415    }
416}
417
418
419static zend_always_inline zval *zend_symtable_str_find(HashTable *ht, const char *str, int len)
420{
421    zend_ulong idx;
422
423    if (ZEND_HANDLE_NUMERIC_STR(str, len, idx)) {
424        return zend_hash_index_find(ht, idx);
425    } else {
426        return zend_hash_str_find(ht, str, len);
427    }
428}
429
430
431static zend_always_inline int zend_symtable_str_exists(HashTable *ht, const char *str, int len)
432{
433    zend_ulong idx;
434
435    if (ZEND_HANDLE_NUMERIC_STR(str, len, idx)) {
436        return zend_hash_index_exists(ht, idx);
437    } else {
438        return zend_hash_str_exists(ht, str, len);
439    }
440}
441
442static zend_always_inline void *zend_hash_add_ptr(HashTable *ht, zend_string *key, void *pData)
443{
444    zval tmp, *zv;
445
446    ZVAL_PTR(&tmp, pData);
447    zv = zend_hash_add(ht, key, &tmp);
448    return zv ? Z_PTR_P(zv) : NULL;
449}
450
451static zend_always_inline void *zend_hash_add_new_ptr(HashTable *ht, zend_string *key, void *pData)
452{
453    zval tmp, *zv;
454
455    ZVAL_PTR(&tmp, pData);
456    zv = zend_hash_add_new(ht, key, &tmp);
457    return zv ? Z_PTR_P(zv) : NULL;
458}
459
460static zend_always_inline void *zend_hash_str_add_ptr(HashTable *ht, const char *str, int len, void *pData)
461{
462    zval tmp, *zv;
463
464    ZVAL_PTR(&tmp, pData);
465    zv = zend_hash_str_add(ht, str, len, &tmp);
466    return zv ? Z_PTR_P(zv) : NULL;
467}
468
469static zend_always_inline void *zend_hash_update_ptr(HashTable *ht, zend_string *key, void *pData)
470{
471    zval tmp, *zv;
472
473    ZVAL_PTR(&tmp, pData);
474    zv = zend_hash_update(ht, key, &tmp);
475    return zv ? Z_PTR_P(zv) : NULL;
476}
477
478static zend_always_inline void *zend_hash_str_update_ptr(HashTable *ht, const char *str, int len, void *pData)
479{
480    zval tmp, *zv;
481
482    ZVAL_PTR(&tmp, pData);
483    zv = zend_hash_str_update(ht, str, len, &tmp);
484    return zv ? Z_PTR_P(zv) : NULL;
485}
486
487static zend_always_inline void *zend_hash_add_mem(HashTable *ht, zend_string *key, void *pData, size_t size)
488{
489    zval tmp, *zv;
490
491    ZVAL_PTR(&tmp, NULL);
492    if ((zv = zend_hash_add(ht, key, &tmp))) {
493        Z_PTR_P(zv) = pemalloc(size, ht->u.flags & HASH_FLAG_PERSISTENT);
494        memcpy(Z_PTR_P(zv), pData, size);
495        return Z_PTR_P(zv);
496    }
497    return NULL;
498}
499
500static zend_always_inline void *zend_hash_str_add_mem(HashTable *ht, const char *str, int len, void *pData, size_t size)
501{
502    zval tmp, *zv;
503
504    ZVAL_PTR(&tmp, NULL);
505    if ((zv = zend_hash_str_add(ht, str, len, &tmp))) {
506        Z_PTR_P(zv) = pemalloc(size, ht->u.flags & HASH_FLAG_PERSISTENT);
507        memcpy(Z_PTR_P(zv), pData, size);
508        return Z_PTR_P(zv);
509    }
510    return NULL;
511}
512
513static zend_always_inline void *zend_hash_update_mem(HashTable *ht, zend_string *key, void *pData, size_t size)
514{
515    void *p;
516
517    p = pemalloc(size, ht->u.flags & HASH_FLAG_PERSISTENT);
518    memcpy(p, pData, size);
519    return zend_hash_update_ptr(ht, key, p);
520}
521
522static zend_always_inline void *zend_hash_str_update_mem(HashTable *ht, const char *str, int len, void *pData, size_t size)
523{
524    void *p;
525
526    p = pemalloc(size, ht->u.flags & HASH_FLAG_PERSISTENT);
527    memcpy(p, pData, size);
528    return zend_hash_str_update_ptr(ht, str, len, p);
529}
530
531static zend_always_inline void *zend_hash_index_update_ptr(HashTable *ht, zend_ulong h, void *pData)
532{
533    zval tmp, *zv;
534
535    ZVAL_PTR(&tmp, pData);
536    zv = zend_hash_index_update(ht, h, &tmp);
537    return zv ? Z_PTR_P(zv) : NULL;
538}
539
540static zend_always_inline void *zend_hash_next_index_insert_ptr(HashTable *ht, void *pData)
541{
542    zval tmp, *zv;
543
544    ZVAL_PTR(&tmp, pData);
545    zv = zend_hash_next_index_insert(ht, &tmp);
546    return zv ? Z_PTR_P(zv) : NULL;
547}
548
549static zend_always_inline void *zend_hash_index_update_mem(HashTable *ht, zend_ulong h, void *pData, size_t size)
550{
551    void *p;
552
553    p = pemalloc(size, ht->u.flags & HASH_FLAG_PERSISTENT);
554    memcpy(p, pData, size);
555    return zend_hash_index_update_ptr(ht, h, p);
556}
557
558static zend_always_inline void *zend_hash_next_index_insert_mem(HashTable *ht, void *pData, size_t size)
559{
560    zval tmp, *zv;
561
562    ZVAL_PTR(&tmp, NULL);
563    if ((zv = zend_hash_next_index_insert(ht, &tmp))) {
564        Z_PTR_P(zv) = pemalloc(size, ht->u.flags & HASH_FLAG_PERSISTENT);
565        memcpy(Z_PTR_P(zv), pData, size);
566        return Z_PTR_P(zv);
567    }
568    return NULL;
569}
570
571static zend_always_inline void *zend_hash_find_ptr(const HashTable *ht, zend_string *key)
572{
573    zval *zv;
574
575    zv = zend_hash_find(ht, key);
576    return zv ? Z_PTR_P(zv) : NULL;
577}
578
579static zend_always_inline void *zend_hash_str_find_ptr(const HashTable *ht, const char *str, int len)
580{
581    zval *zv;
582
583    zv = zend_hash_str_find(ht, str, len);
584    return zv ? Z_PTR_P(zv) : NULL;
585}
586
587static zend_always_inline void *zend_hash_index_find_ptr(const HashTable *ht, zend_ulong h)
588{
589    zval *zv;
590
591    zv = zend_hash_index_find(ht, h);
592    return zv ? Z_PTR_P(zv) : NULL;
593}
594
595static zend_always_inline void *zend_symtable_str_find_ptr(HashTable *ht, const char *str, int len)
596{
597    zend_ulong idx;
598
599    if (ZEND_HANDLE_NUMERIC_STR(str, len, idx)) {
600        return zend_hash_index_find_ptr(ht, idx);
601    } else {
602        return zend_hash_str_find_ptr(ht, str, len);
603    }
604}
605
606static zend_always_inline void *zend_hash_get_current_data_ptr_ex(HashTable *ht, HashPosition *pos)
607{
608    zval *zv;
609
610    zv = zend_hash_get_current_data_ex(ht, pos);
611    return zv ? Z_PTR_P(zv) : NULL;
612}
613
614#define zend_hash_get_current_data_ptr(ht) \
615    zend_hash_get_current_data_ptr_ex(ht, &(ht)->nInternalPointer)
616
617#define ZEND_HASH_FOREACH(_ht, indirect) do { \
618        uint _idx; \
619        for (_idx = 0; _idx < (_ht)->nNumUsed; _idx++) { \
620            Bucket *_p = (_ht)->arData + _idx; \
621            zval *_z = &_p->val; \
622            if (indirect && Z_TYPE_P(_z) == IS_INDIRECT) { \
623                _z = Z_INDIRECT_P(_z); \
624            } \
625            if (Z_TYPE_P(_z) == IS_UNDEF) continue;
626
627#define ZEND_HASH_REVERSE_FOREACH(_ht, indirect) do { \
628        uint _idx; \
629        for (_idx = (_ht)->nNumUsed; _idx > 0; _idx--) { \
630            Bucket *_p = (_ht)->arData + _idx - 1; \
631            zval *_z = &_p->val; \
632            if (indirect && Z_TYPE_P(_z) == IS_INDIRECT) { \
633                _z = Z_INDIRECT_P(_z); \
634            } \
635            if (Z_TYPE_P(_z) == IS_UNDEF) continue;
636
637#define ZEND_HASH_FOREACH_END() \
638        } \
639    } while (0)
640
641#define ZEND_HASH_FOREACH_BUCKET(ht, _bucket) \
642    ZEND_HASH_FOREACH(ht, 0); \
643    _bucket = _p;
644
645#define ZEND_HASH_FOREACH_VAL(ht, _val) \
646    ZEND_HASH_FOREACH(ht, 0); \
647    _val = _z;
648
649#define ZEND_HASH_FOREACH_VAL_IND(ht, _val) \
650    ZEND_HASH_FOREACH(ht, 1); \
651    _val = _z;
652
653#define ZEND_HASH_FOREACH_PTR(ht, _ptr) \
654    ZEND_HASH_FOREACH(ht, 0); \
655    _ptr = Z_PTR_P(_z);
656
657#define ZEND_HASH_FOREACH_NUM_KEY(ht, _h) \
658    ZEND_HASH_FOREACH(ht, 0); \
659    _h = _p->h;
660
661#define ZEND_HASH_FOREACH_STR_KEY(ht, _key) \
662    ZEND_HASH_FOREACH(ht, 0); \
663    _key = _p->key;
664
665#define ZEND_HASH_FOREACH_KEY(ht, _h, _key) \
666    ZEND_HASH_FOREACH(ht, 0); \
667    _h = _p->h; \
668    _key = _p->key;
669
670#define ZEND_HASH_FOREACH_NUM_KEY_VAL(ht, _h, _val) \
671    ZEND_HASH_FOREACH(ht, 0); \
672    _h = _p->h; \
673    _val = _z;
674
675#define ZEND_HASH_FOREACH_STR_KEY_VAL(ht, _key, _val) \
676    ZEND_HASH_FOREACH(ht, 0); \
677    _key = _p->key; \
678    _val = _z;
679
680#define ZEND_HASH_FOREACH_KEY_VAL(ht, _h, _key, _val) \
681    ZEND_HASH_FOREACH(ht, 0); \
682    _h = _p->h; \
683    _key = _p->key; \
684    _val = _z;
685
686#define ZEND_HASH_FOREACH_STR_KEY_VAL_IND(ht, _key, _val) \
687    ZEND_HASH_FOREACH(ht, 1); \
688    _key = _p->key; \
689    _val = _z;
690
691#define ZEND_HASH_FOREACH_KEY_VAL_IND(ht, _h, _key, _val) \
692    ZEND_HASH_FOREACH(ht, 1); \
693    _h = _p->h; \
694    _key = _p->key; \
695    _val = _z;
696
697#define ZEND_HASH_FOREACH_STR_KEY_PTR(ht, _key, _ptr) \
698    ZEND_HASH_FOREACH(ht, 0); \
699    _key = _p->key; \
700    _ptr = Z_PTR_P(_z);
701
702#define ZEND_HASH_FOREACH_KEY_PTR(ht, _h, _key, _ptr) \
703    ZEND_HASH_FOREACH(ht, 0); \
704    _h = _p->h; \
705    _key = _p->key; \
706    _ptr = Z_PTR_P(_z);
707
708#define ZEND_HASH_REVERSE_FOREACH_VAL(ht, _val) \
709    ZEND_HASH_REVERSE_FOREACH(ht, 0); \
710    _val = _z;
711
712#define ZEND_HASH_REVERSE_FOREACH_PTR(ht, _ptr) \
713    ZEND_HASH_REVERSE_FOREACH(ht, 0); \
714    _ptr = Z_PTR_P(_z);
715
716#define ZEND_HASH_REVERSE_FOREACH_VAL_IND(ht, _val) \
717    ZEND_HASH_REVERSE_FOREACH(ht, 1); \
718    _val = _z;
719
720#define ZEND_HASH_REVERSE_FOREACH_KEY_VAL(ht, _h, _key, _val) \
721    ZEND_HASH_REVERSE_FOREACH(ht, 0); \
722    _h = _p->h; \
723    _key = _p->key; \
724    _val = _z;
725
726#define ZEND_HASH_REVERSE_FOREACH_KEY_VAL_IND(ht, _h, _key, _val) \
727    ZEND_HASH_REVERSE_FOREACH(ht, 1); \
728    _h = _p->h; \
729    _key = _p->key; \
730    _val = _z;
731
732#define ZEND_HASH_APPLY_PROTECTION(ht) \
733    ((ht)->u.flags & HASH_FLAG_APPLY_PROTECTION)
734
735#define ZEND_HASH_APPLY_SHIFT 8
736#define ZEND_HASH_GET_APPLY_COUNT(ht) ((ht)->u.flags >> ZEND_HASH_APPLY_SHIFT)
737#define ZEND_HASH_INC_APPLY_COUNT(ht) ((ht)->u.flags += (1 << ZEND_HASH_APPLY_SHIFT))
738#define ZEND_HASH_DEC_APPLY_COUNT(ht) ((ht)->u.flags -= (1 << ZEND_HASH_APPLY_SHIFT))
739
740#endif                          /* ZEND_HASH_H */
741
742/*
743 * Local variables:
744 * tab-width: 4
745 * c-basic-offset: 4
746 * indent-tabs-mode: t
747 * End:
748 */
749