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