1 /*
2 +----------------------------------------------------------------------+
3 | Zend Engine |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 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@php.net> |
16 | Zeev Suraski <zeev@php.net> |
17 | Dmitry Stogov <dmitry@php.net> |
18 +----------------------------------------------------------------------+
19 */
20
21 #ifndef ZEND_HASH_H
22 #define ZEND_HASH_H
23
24 #include "zend.h"
25 #include "zend_sort.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 #define HASH_LOOKUP (1<<5)
37
38 #define HASH_FLAG_CONSISTENCY ((1<<0) | (1<<1))
39 #define HASH_FLAG_PACKED (1<<2)
40 #define HASH_FLAG_UNINITIALIZED (1<<3)
41 #define HASH_FLAG_STATIC_KEYS (1<<4) /* long and interned strings */
42 #define HASH_FLAG_HAS_EMPTY_IND (1<<5)
43 #define HASH_FLAG_ALLOW_COW_VIOLATION (1<<6)
44
45 /* Only the low byte are real flags */
46 #define HASH_FLAG_MASK 0xff
47
48 #define HT_FLAGS(ht) (ht)->u.flags
49
50 #define HT_INVALIDATE(ht) do { \
51 HT_FLAGS(ht) = HASH_FLAG_UNINITIALIZED; \
52 } while (0)
53
54 #define HT_IS_INITIALIZED(ht) \
55 ((HT_FLAGS(ht) & HASH_FLAG_UNINITIALIZED) == 0)
56
57 #define HT_IS_PACKED(ht) \
58 ((HT_FLAGS(ht) & HASH_FLAG_PACKED) != 0)
59
60 #define HT_IS_WITHOUT_HOLES(ht) \
61 ((ht)->nNumUsed == (ht)->nNumOfElements)
62
63 #define HT_HAS_STATIC_KEYS_ONLY(ht) \
64 ((HT_FLAGS(ht) & (HASH_FLAG_PACKED|HASH_FLAG_STATIC_KEYS)) != 0)
65
66 #if ZEND_DEBUG
67 # define HT_ALLOW_COW_VIOLATION(ht) HT_FLAGS(ht) |= HASH_FLAG_ALLOW_COW_VIOLATION
68 #else
69 # define HT_ALLOW_COW_VIOLATION(ht)
70 #endif
71
72 #define HT_ITERATORS_COUNT(ht) (ht)->u.v.nIteratorsCount
73 #define HT_ITERATORS_OVERFLOW(ht) (HT_ITERATORS_COUNT(ht) == 0xff)
74 #define HT_HAS_ITERATORS(ht) (HT_ITERATORS_COUNT(ht) != 0)
75
76 #define HT_SET_ITERATORS_COUNT(ht, iters) \
77 do { HT_ITERATORS_COUNT(ht) = (iters); } while (0)
78 #define HT_INC_ITERATORS_COUNT(ht) \
79 HT_SET_ITERATORS_COUNT(ht, HT_ITERATORS_COUNT(ht) + 1)
80 #define HT_DEC_ITERATORS_COUNT(ht) \
81 HT_SET_ITERATORS_COUNT(ht, HT_ITERATORS_COUNT(ht) - 1)
82
83 extern ZEND_API const HashTable zend_empty_array;
84
85 #define ZVAL_EMPTY_ARRAY(z) do { \
86 zval *__z = (z); \
87 Z_ARR_P(__z) = (zend_array*)&zend_empty_array; \
88 Z_TYPE_INFO_P(__z) = IS_ARRAY; \
89 } while (0)
90
91
92 typedef struct _zend_hash_key {
93 zend_ulong h;
94 zend_string *key;
95 } zend_hash_key;
96
97 typedef bool (*merge_checker_func_t)(HashTable *target_ht, zval *source_data, zend_hash_key *hash_key, void *pParam);
98
99 BEGIN_EXTERN_C()
100
101 /* startup/shutdown */
102 ZEND_API void ZEND_FASTCALL _zend_hash_init(HashTable *ht, uint32_t nSize, dtor_func_t pDestructor, bool persistent);
103 ZEND_API void ZEND_FASTCALL zend_hash_destroy(HashTable *ht);
104 ZEND_API void ZEND_FASTCALL zend_hash_clean(HashTable *ht);
105
106 #define zend_hash_init(ht, nSize, pHashFunction, pDestructor, persistent) \
107 _zend_hash_init((ht), (nSize), (pDestructor), (persistent))
108
109 ZEND_API void ZEND_FASTCALL zend_hash_real_init(HashTable *ht, bool packed);
110 ZEND_API void ZEND_FASTCALL zend_hash_real_init_packed(HashTable *ht);
111 ZEND_API void ZEND_FASTCALL zend_hash_real_init_mixed(HashTable *ht);
112 ZEND_API void ZEND_FASTCALL zend_hash_packed_to_hash(HashTable *ht);
113 ZEND_API void ZEND_FASTCALL zend_hash_to_packed(HashTable *ht);
114 ZEND_API void ZEND_FASTCALL zend_hash_extend(HashTable *ht, uint32_t nSize, bool packed);
115 ZEND_API void ZEND_FASTCALL zend_hash_discard(HashTable *ht, uint32_t nNumUsed);
116 ZEND_API void ZEND_FASTCALL zend_hash_packed_grow(HashTable *ht);
117
118 /* additions/updates/changes */
119 ZEND_API zval* ZEND_FASTCALL zend_hash_add_or_update(HashTable *ht, zend_string *key, zval *pData, uint32_t flag);
120 ZEND_API zval* ZEND_FASTCALL zend_hash_update(HashTable *ht, zend_string *key,zval *pData);
121 ZEND_API zval* ZEND_FASTCALL zend_hash_update_ind(HashTable *ht, zend_string *key,zval *pData);
122 ZEND_API zval* ZEND_FASTCALL zend_hash_add(HashTable *ht, zend_string *key,zval *pData);
123 ZEND_API zval* ZEND_FASTCALL zend_hash_add_new(HashTable *ht, zend_string *key,zval *pData);
124
125 ZEND_API zval* ZEND_FASTCALL zend_hash_str_add_or_update(HashTable *ht, const char *key, size_t len, zval *pData, uint32_t flag);
126 ZEND_API zval* ZEND_FASTCALL zend_hash_str_update(HashTable *ht, const char *key, size_t len, zval *pData);
127 ZEND_API zval* ZEND_FASTCALL zend_hash_str_update_ind(HashTable *ht, const char *key, size_t len, zval *pData);
128 ZEND_API zval* ZEND_FASTCALL zend_hash_str_add(HashTable *ht, const char *key, size_t len, zval *pData);
129 ZEND_API zval* ZEND_FASTCALL zend_hash_str_add_new(HashTable *ht, const char *key, size_t len, zval *pData);
130
131 ZEND_API zval* ZEND_FASTCALL zend_hash_index_add_or_update(HashTable *ht, zend_ulong h, zval *pData, uint32_t flag);
132 ZEND_API zval* ZEND_FASTCALL zend_hash_index_add(HashTable *ht, zend_ulong h, zval *pData);
133 ZEND_API zval* ZEND_FASTCALL zend_hash_index_add_new(HashTable *ht, zend_ulong h, zval *pData);
134 ZEND_API zval* ZEND_FASTCALL zend_hash_index_update(HashTable *ht, zend_ulong h, zval *pData);
135 ZEND_API zval* ZEND_FASTCALL zend_hash_next_index_insert(HashTable *ht, zval *pData);
136 ZEND_API zval* ZEND_FASTCALL zend_hash_next_index_insert_new(HashTable *ht, zval *pData);
137
138 ZEND_API zval* ZEND_FASTCALL zend_hash_index_add_empty_element(HashTable *ht, zend_ulong h);
139 ZEND_API zval* ZEND_FASTCALL zend_hash_add_empty_element(HashTable *ht, zend_string *key);
140 ZEND_API zval* ZEND_FASTCALL zend_hash_str_add_empty_element(HashTable *ht, const char *key, size_t len);
141
142 ZEND_API zval* ZEND_FASTCALL zend_hash_set_bucket_key(HashTable *ht, Bucket *p, zend_string *key);
143
144 #define ZEND_HASH_APPLY_KEEP 0
145 #define ZEND_HASH_APPLY_REMOVE 1<<0
146 #define ZEND_HASH_APPLY_STOP 1<<1
147
148 typedef int (*apply_func_t)(zval *pDest);
149 typedef int (*apply_func_arg_t)(zval *pDest, void *argument);
150 typedef int (*apply_func_args_t)(zval *pDest, int num_args, va_list args, zend_hash_key *hash_key);
151
152 ZEND_API void ZEND_FASTCALL zend_hash_graceful_destroy(HashTable *ht);
153 ZEND_API void ZEND_FASTCALL zend_hash_graceful_reverse_destroy(HashTable *ht);
154 ZEND_API void ZEND_FASTCALL zend_hash_apply(HashTable *ht, apply_func_t apply_func);
155 ZEND_API void ZEND_FASTCALL zend_hash_apply_with_argument(HashTable *ht, apply_func_arg_t apply_func, void *);
156 ZEND_API void zend_hash_apply_with_arguments(HashTable *ht, apply_func_args_t apply_func, int, ...);
157
158 /* This function should be used with special care (in other words,
159 * it should usually not be used). When used with the ZEND_HASH_APPLY_STOP
160 * return value, it assumes things about the order of the elements in the hash.
161 * Also, it does not provide the same kind of reentrancy protection that
162 * the standard apply functions do.
163 */
164 ZEND_API void ZEND_FASTCALL zend_hash_reverse_apply(HashTable *ht, apply_func_t apply_func);
165
166
167 /* Deletes */
168 ZEND_API zend_result ZEND_FASTCALL zend_hash_del(HashTable *ht, zend_string *key);
169 ZEND_API zend_result ZEND_FASTCALL zend_hash_del_ind(HashTable *ht, zend_string *key);
170 ZEND_API zend_result ZEND_FASTCALL zend_hash_str_del(HashTable *ht, const char *key, size_t len);
171 ZEND_API zend_result ZEND_FASTCALL zend_hash_str_del_ind(HashTable *ht, const char *key, size_t len);
172 ZEND_API zend_result ZEND_FASTCALL zend_hash_index_del(HashTable *ht, zend_ulong h);
173 ZEND_API void ZEND_FASTCALL zend_hash_del_bucket(HashTable *ht, Bucket *p);
174 ZEND_API void ZEND_FASTCALL zend_hash_packed_del_val(HashTable *ht, zval *zv);
175
176 /* Data retrieval */
177 ZEND_API zval* ZEND_FASTCALL zend_hash_find(const HashTable *ht, zend_string *key);
178 ZEND_API zval* ZEND_FASTCALL zend_hash_str_find(const HashTable *ht, const char *key, size_t len);
179 ZEND_API zval* ZEND_FASTCALL zend_hash_index_find(const HashTable *ht, zend_ulong h);
180 ZEND_API zval* ZEND_FASTCALL _zend_hash_index_find(const HashTable *ht, zend_ulong h);
181
182 /* The same as zend_hash_find(), but hash value of the key must be already calculated. */
183 ZEND_API zval* ZEND_FASTCALL zend_hash_find_known_hash(const HashTable *ht, const zend_string *key);
184
zend_hash_find_ex(const HashTable * ht,zend_string * key,bool known_hash)185 static zend_always_inline zval *zend_hash_find_ex(const HashTable *ht, zend_string *key, bool known_hash)
186 {
187 if (known_hash) {
188 return zend_hash_find_known_hash(ht, key);
189 } else {
190 return zend_hash_find(ht, key);
191 }
192 }
193
194 #define ZEND_HASH_INDEX_FIND(_ht, _h, _ret, _not_found) do { \
195 if (EXPECTED(HT_IS_PACKED(_ht))) { \
196 if (EXPECTED((zend_ulong)(_h) < (zend_ulong)(_ht)->nNumUsed)) { \
197 _ret = &_ht->arPacked[_h]; \
198 if (UNEXPECTED(Z_TYPE_P(_ret) == IS_UNDEF)) { \
199 goto _not_found; \
200 } \
201 } else { \
202 goto _not_found; \
203 } \
204 } else { \
205 _ret = _zend_hash_index_find(_ht, _h); \
206 if (UNEXPECTED(_ret == NULL)) { \
207 goto _not_found; \
208 } \
209 } \
210 } while (0)
211
212
213 /* Find or add NULL, if doesn't exist */
214 ZEND_API zval* ZEND_FASTCALL zend_hash_lookup(HashTable *ht, zend_string *key);
215 ZEND_API zval* ZEND_FASTCALL zend_hash_index_lookup(HashTable *ht, zend_ulong h);
216
217 #define ZEND_HASH_INDEX_LOOKUP(_ht, _h, _ret) do { \
218 if (EXPECTED(HT_IS_PACKED(_ht))) { \
219 if (EXPECTED((zend_ulong)(_h) < (zend_ulong)(_ht)->nNumUsed)) { \
220 _ret = &_ht->arPacked[_h]; \
221 if (EXPECTED(Z_TYPE_P(_ret) != IS_UNDEF)) { \
222 break; \
223 } \
224 } \
225 } \
226 _ret = zend_hash_index_lookup(_ht, _h); \
227 } while (0)
228
229 /* Misc */
zend_hash_exists(const HashTable * ht,zend_string * key)230 static zend_always_inline bool zend_hash_exists(const HashTable *ht, zend_string *key)
231 {
232 return zend_hash_find(ht, key) != NULL;
233 }
234
zend_hash_str_exists(const HashTable * ht,const char * str,size_t len)235 static zend_always_inline bool zend_hash_str_exists(const HashTable *ht, const char *str, size_t len)
236 {
237 return zend_hash_str_find(ht, str, len) != NULL;
238 }
239
zend_hash_index_exists(const HashTable * ht,zend_ulong h)240 static zend_always_inline bool zend_hash_index_exists(const HashTable *ht, zend_ulong h)
241 {
242 return zend_hash_index_find(ht, h) != NULL;
243 }
244
245 /* traversing */
246 ZEND_API HashPosition ZEND_FASTCALL zend_hash_get_current_pos(const HashTable *ht);
247
248 ZEND_API zend_result ZEND_FASTCALL zend_hash_move_forward_ex(HashTable *ht, HashPosition *pos);
249 ZEND_API zend_result ZEND_FASTCALL zend_hash_move_backwards_ex(HashTable *ht, HashPosition *pos);
250 ZEND_API int ZEND_FASTCALL zend_hash_get_current_key_ex(const HashTable *ht, zend_string **str_index, zend_ulong *num_index, const HashPosition *pos);
251 ZEND_API void ZEND_FASTCALL zend_hash_get_current_key_zval_ex(const HashTable *ht, zval *key, const HashPosition *pos);
252 ZEND_API int ZEND_FASTCALL zend_hash_get_current_key_type_ex(HashTable *ht, HashPosition *pos);
253 ZEND_API zval* ZEND_FASTCALL zend_hash_get_current_data_ex(HashTable *ht, HashPosition *pos);
254 ZEND_API void ZEND_FASTCALL zend_hash_internal_pointer_reset_ex(HashTable *ht, HashPosition *pos);
255 ZEND_API void ZEND_FASTCALL zend_hash_internal_pointer_end_ex(HashTable *ht, HashPosition *pos);
256
zend_hash_has_more_elements_ex(HashTable * ht,HashPosition * pos)257 static zend_always_inline zend_result zend_hash_has_more_elements_ex(HashTable *ht, HashPosition *pos) {
258 return (zend_hash_get_current_key_type_ex(ht, pos) == HASH_KEY_NON_EXISTENT ? FAILURE : SUCCESS);
259 }
zend_hash_has_more_elements(HashTable * ht)260 static zend_always_inline zend_result zend_hash_has_more_elements(HashTable *ht) {
261 return zend_hash_has_more_elements_ex(ht, &ht->nInternalPointer);
262 }
zend_hash_move_forward(HashTable * ht)263 static zend_always_inline zend_result zend_hash_move_forward(HashTable *ht) {
264 return zend_hash_move_forward_ex(ht, &ht->nInternalPointer);
265 }
zend_hash_move_backwards(HashTable * ht)266 static zend_always_inline zend_result zend_hash_move_backwards(HashTable *ht) {
267 return zend_hash_move_backwards_ex(ht, &ht->nInternalPointer);
268 }
zend_hash_get_current_key(const HashTable * ht,zend_string ** str_index,zend_ulong * num_index)269 static zend_always_inline int zend_hash_get_current_key(const HashTable *ht, zend_string **str_index, zend_ulong *num_index) {
270 return zend_hash_get_current_key_ex(ht, str_index, num_index, &ht->nInternalPointer);
271 }
zend_hash_get_current_key_zval(const HashTable * ht,zval * key)272 static zend_always_inline void zend_hash_get_current_key_zval(const HashTable *ht, zval *key) {
273 zend_hash_get_current_key_zval_ex(ht, key, &ht->nInternalPointer);
274 }
zend_hash_get_current_key_type(HashTable * ht)275 static zend_always_inline int zend_hash_get_current_key_type(HashTable *ht) {
276 return zend_hash_get_current_key_type_ex(ht, &ht->nInternalPointer);
277 }
zend_hash_get_current_data(HashTable * ht)278 static zend_always_inline zval* zend_hash_get_current_data(HashTable *ht) {
279 return zend_hash_get_current_data_ex(ht, &ht->nInternalPointer);
280 }
zend_hash_internal_pointer_reset(HashTable * ht)281 static zend_always_inline void zend_hash_internal_pointer_reset(HashTable *ht) {
282 zend_hash_internal_pointer_reset_ex(ht, &ht->nInternalPointer);
283 }
zend_hash_internal_pointer_end(HashTable * ht)284 static zend_always_inline void zend_hash_internal_pointer_end(HashTable *ht) {
285 zend_hash_internal_pointer_end_ex(ht, &ht->nInternalPointer);
286 }
287
288 /* Copying, merging and sorting */
289 ZEND_API void ZEND_FASTCALL zend_hash_copy(HashTable *target, HashTable *source, copy_ctor_func_t pCopyConstructor);
290 ZEND_API void ZEND_FASTCALL zend_hash_merge(HashTable *target, HashTable *source, copy_ctor_func_t pCopyConstructor, bool overwrite);
291 ZEND_API void ZEND_FASTCALL zend_hash_merge_ex(HashTable *target, HashTable *source, copy_ctor_func_t pCopyConstructor, merge_checker_func_t pMergeSource, void *pParam);
292 ZEND_API void zend_hash_bucket_swap(Bucket *p, Bucket *q);
293 ZEND_API void zend_hash_bucket_renum_swap(Bucket *p, Bucket *q);
294 ZEND_API void zend_hash_bucket_packed_swap(Bucket *p, Bucket *q);
295
296 typedef int (*bucket_compare_func_t)(Bucket *a, Bucket *b);
297 ZEND_API int zend_hash_compare(HashTable *ht1, HashTable *ht2, compare_func_t compar, bool ordered);
298 ZEND_API void ZEND_FASTCALL zend_hash_sort_ex(HashTable *ht, sort_func_t sort_func, bucket_compare_func_t compare_func, bool renumber);
299 ZEND_API zval* ZEND_FASTCALL zend_hash_minmax(const HashTable *ht, compare_func_t compar, uint32_t flag);
300
zend_hash_sort(HashTable * ht,bucket_compare_func_t compare_func,bool renumber)301 static zend_always_inline void ZEND_FASTCALL zend_hash_sort(HashTable *ht, bucket_compare_func_t compare_func, bool renumber) {
302 zend_hash_sort_ex(ht, zend_sort, compare_func, renumber);
303 }
304
zend_hash_num_elements(const HashTable * ht)305 static zend_always_inline uint32_t zend_hash_num_elements(const HashTable *ht) {
306 return ht->nNumOfElements;
307 }
308
zend_hash_next_free_element(const HashTable * ht)309 static zend_always_inline zend_long zend_hash_next_free_element(const HashTable *ht) {
310 return ht->nNextFreeElement;
311 }
312
313 ZEND_API void ZEND_FASTCALL zend_hash_rehash(HashTable *ht);
314
315 #if !ZEND_DEBUG && defined(HAVE_BUILTIN_CONSTANT_P)
316 # define zend_new_array(size) \
317 (__builtin_constant_p(size) ? \
318 ((((uint32_t)(size)) <= HT_MIN_SIZE) ? \
319 _zend_new_array_0() \
320 : \
321 _zend_new_array((size)) \
322 ) \
323 : \
324 _zend_new_array((size)) \
325 )
326 #else
327 # define zend_new_array(size) \
328 _zend_new_array(size)
329 #endif
330
331 ZEND_API HashTable* ZEND_FASTCALL _zend_new_array_0(void);
332 ZEND_API HashTable* ZEND_FASTCALL _zend_new_array(uint32_t size);
333 ZEND_API HashTable* ZEND_FASTCALL zend_new_pair(zval *val1, zval *val2);
334 ZEND_API uint32_t zend_array_count(HashTable *ht);
335 ZEND_API HashTable* ZEND_FASTCALL zend_array_dup(HashTable *source);
336 ZEND_API void ZEND_FASTCALL zend_array_destroy(HashTable *ht);
337 ZEND_API HashTable* zend_array_to_list(HashTable *source);
338 ZEND_API void ZEND_FASTCALL zend_symtable_clean(HashTable *ht);
339 ZEND_API HashTable* ZEND_FASTCALL zend_symtable_to_proptable(HashTable *ht);
340 ZEND_API HashTable* ZEND_FASTCALL zend_proptable_to_symtable(HashTable *ht, bool always_duplicate);
341
342 ZEND_API bool ZEND_FASTCALL _zend_handle_numeric_str_ex(const char *key, size_t length, zend_ulong *idx);
343
344 ZEND_API uint32_t ZEND_FASTCALL zend_hash_iterator_add(HashTable *ht, HashPosition pos);
345 ZEND_API HashPosition ZEND_FASTCALL zend_hash_iterator_pos(uint32_t idx, HashTable *ht);
346 ZEND_API HashPosition ZEND_FASTCALL zend_hash_iterator_pos_ex(uint32_t idx, zval *array);
347 ZEND_API void ZEND_FASTCALL zend_hash_iterator_del(uint32_t idx);
348 ZEND_API HashPosition ZEND_FASTCALL zend_hash_iterators_lower_pos(HashTable *ht, HashPosition start);
349 ZEND_API void ZEND_FASTCALL _zend_hash_iterators_update(HashTable *ht, HashPosition from, HashPosition to);
350 ZEND_API void ZEND_FASTCALL zend_hash_iterators_advance(HashTable *ht, HashPosition step);
351
zend_hash_iterators_update(HashTable * ht,HashPosition from,HashPosition to)352 static zend_always_inline void zend_hash_iterators_update(HashTable *ht, HashPosition from, HashPosition to)
353 {
354 if (UNEXPECTED(HT_HAS_ITERATORS(ht))) {
355 _zend_hash_iterators_update(ht, from, to);
356 }
357 }
358
359 /* For regular arrays (non-persistent, storing zvals). */
zend_array_release(zend_array * array)360 static zend_always_inline void zend_array_release(zend_array *array)
361 {
362 if (!(GC_FLAGS(array) & IS_ARRAY_IMMUTABLE)) {
363 if (GC_DELREF(array) == 0) {
364 zend_array_destroy(array);
365 }
366 }
367 }
368
369 /* For general hashes (possibly persistent, storing any kind of value). */
zend_hash_release(zend_array * array)370 static zend_always_inline void zend_hash_release(zend_array *array)
371 {
372 if (!(GC_FLAGS(array) & IS_ARRAY_IMMUTABLE)) {
373 if (GC_DELREF(array) == 0) {
374 zend_hash_destroy(array);
375 pefree(array, GC_FLAGS(array) & IS_ARRAY_PERSISTENT);
376 }
377 }
378 }
379
END_EXTERN_C()380 END_EXTERN_C()
381
382 #define ZEND_INIT_SYMTABLE(ht) \
383 ZEND_INIT_SYMTABLE_EX(ht, 8, 0)
384
385 #define ZEND_INIT_SYMTABLE_EX(ht, n, persistent) \
386 zend_hash_init(ht, n, NULL, ZVAL_PTR_DTOR, persistent)
387
388 static zend_always_inline bool _zend_handle_numeric_str(const char *key, size_t length, zend_ulong *idx)
389 {
390 const char *tmp = key;
391
392 if (EXPECTED(*tmp > '9')) {
393 return 0;
394 } else if (*tmp < '0') {
395 if (*tmp != '-') {
396 return 0;
397 }
398 tmp++;
399 if (*tmp > '9' || *tmp < '0') {
400 return 0;
401 }
402 }
403 return _zend_handle_numeric_str_ex(key, length, idx);
404 }
405
406 #define ZEND_HANDLE_NUMERIC_STR(key, length, idx) \
407 _zend_handle_numeric_str(key, length, &idx)
408
409 #define ZEND_HANDLE_NUMERIC(key, idx) \
410 ZEND_HANDLE_NUMERIC_STR(ZSTR_VAL(key), ZSTR_LEN(key), idx)
411
412
zend_hash_find_ind(const HashTable * ht,zend_string * key)413 static zend_always_inline zval *zend_hash_find_ind(const HashTable *ht, zend_string *key)
414 {
415 zval *zv;
416
417 zv = zend_hash_find(ht, key);
418 return (zv && Z_TYPE_P(zv) == IS_INDIRECT) ?
419 ((Z_TYPE_P(Z_INDIRECT_P(zv)) != IS_UNDEF) ? Z_INDIRECT_P(zv) : NULL) : zv;
420 }
421
422
zend_hash_find_ex_ind(const HashTable * ht,zend_string * key,bool known_hash)423 static zend_always_inline zval *zend_hash_find_ex_ind(const HashTable *ht, zend_string *key, bool known_hash)
424 {
425 zval *zv;
426
427 zv = zend_hash_find_ex(ht, key, known_hash);
428 return (zv && Z_TYPE_P(zv) == IS_INDIRECT) ?
429 ((Z_TYPE_P(Z_INDIRECT_P(zv)) != IS_UNDEF) ? Z_INDIRECT_P(zv) : NULL) : zv;
430 }
431
432
zend_hash_exists_ind(const HashTable * ht,zend_string * key)433 static zend_always_inline bool zend_hash_exists_ind(const HashTable *ht, zend_string *key)
434 {
435 zval *zv;
436
437 zv = zend_hash_find(ht, key);
438 return zv && (Z_TYPE_P(zv) != IS_INDIRECT ||
439 Z_TYPE_P(Z_INDIRECT_P(zv)) != IS_UNDEF);
440 }
441
442
zend_hash_str_find_ind(const HashTable * ht,const char * str,size_t len)443 static zend_always_inline zval *zend_hash_str_find_ind(const HashTable *ht, const char *str, size_t len)
444 {
445 zval *zv;
446
447 zv = zend_hash_str_find(ht, str, len);
448 return (zv && Z_TYPE_P(zv) == IS_INDIRECT) ?
449 ((Z_TYPE_P(Z_INDIRECT_P(zv)) != IS_UNDEF) ? Z_INDIRECT_P(zv) : NULL) : zv;
450 }
451
452
zend_hash_str_exists_ind(const HashTable * ht,const char * str,size_t len)453 static zend_always_inline bool zend_hash_str_exists_ind(const HashTable *ht, const char *str, size_t len)
454 {
455 zval *zv;
456
457 zv = zend_hash_str_find(ht, str, len);
458 return zv && (Z_TYPE_P(zv) != IS_INDIRECT ||
459 Z_TYPE_P(Z_INDIRECT_P(zv)) != IS_UNDEF);
460 }
461
zend_symtable_add_new(HashTable * ht,zend_string * key,zval * pData)462 static zend_always_inline zval *zend_symtable_add_new(HashTable *ht, zend_string *key, zval *pData)
463 {
464 zend_ulong idx;
465
466 if (ZEND_HANDLE_NUMERIC(key, idx)) {
467 return zend_hash_index_add_new(ht, idx, pData);
468 } else {
469 return zend_hash_add_new(ht, key, pData);
470 }
471 }
472
zend_symtable_update(HashTable * ht,zend_string * key,zval * pData)473 static zend_always_inline zval *zend_symtable_update(HashTable *ht, zend_string *key, zval *pData)
474 {
475 zend_ulong idx;
476
477 if (ZEND_HANDLE_NUMERIC(key, idx)) {
478 return zend_hash_index_update(ht, idx, pData);
479 } else {
480 return zend_hash_update(ht, key, pData);
481 }
482 }
483
484
zend_symtable_update_ind(HashTable * ht,zend_string * key,zval * pData)485 static zend_always_inline zval *zend_symtable_update_ind(HashTable *ht, zend_string *key, zval *pData)
486 {
487 zend_ulong idx;
488
489 if (ZEND_HANDLE_NUMERIC(key, idx)) {
490 return zend_hash_index_update(ht, idx, pData);
491 } else {
492 return zend_hash_update_ind(ht, key, pData);
493 }
494 }
495
496
zend_symtable_del(HashTable * ht,zend_string * key)497 static zend_always_inline zend_result zend_symtable_del(HashTable *ht, zend_string *key)
498 {
499 zend_ulong idx;
500
501 if (ZEND_HANDLE_NUMERIC(key, idx)) {
502 return zend_hash_index_del(ht, idx);
503 } else {
504 return zend_hash_del(ht, key);
505 }
506 }
507
508
zend_symtable_del_ind(HashTable * ht,zend_string * key)509 static zend_always_inline zend_result zend_symtable_del_ind(HashTable *ht, zend_string *key)
510 {
511 zend_ulong idx;
512
513 if (ZEND_HANDLE_NUMERIC(key, idx)) {
514 return zend_hash_index_del(ht, idx);
515 } else {
516 return zend_hash_del_ind(ht, key);
517 }
518 }
519
520
zend_symtable_find(const HashTable * ht,zend_string * key)521 static zend_always_inline zval *zend_symtable_find(const HashTable *ht, zend_string *key)
522 {
523 zend_ulong idx;
524
525 if (ZEND_HANDLE_NUMERIC(key, idx)) {
526 return zend_hash_index_find(ht, idx);
527 } else {
528 return zend_hash_find(ht, key);
529 }
530 }
531
532
zend_symtable_find_ind(const HashTable * ht,zend_string * key)533 static zend_always_inline zval *zend_symtable_find_ind(const HashTable *ht, zend_string *key)
534 {
535 zend_ulong idx;
536
537 if (ZEND_HANDLE_NUMERIC(key, idx)) {
538 return zend_hash_index_find(ht, idx);
539 } else {
540 return zend_hash_find_ind(ht, key);
541 }
542 }
543
544
zend_symtable_exists(HashTable * ht,zend_string * key)545 static zend_always_inline bool zend_symtable_exists(HashTable *ht, zend_string *key)
546 {
547 zend_ulong idx;
548
549 if (ZEND_HANDLE_NUMERIC(key, idx)) {
550 return zend_hash_index_exists(ht, idx);
551 } else {
552 return zend_hash_exists(ht, key);
553 }
554 }
555
556
zend_symtable_exists_ind(HashTable * ht,zend_string * key)557 static zend_always_inline bool zend_symtable_exists_ind(HashTable *ht, zend_string *key)
558 {
559 zend_ulong idx;
560
561 if (ZEND_HANDLE_NUMERIC(key, idx)) {
562 return zend_hash_index_exists(ht, idx);
563 } else {
564 return zend_hash_exists_ind(ht, key);
565 }
566 }
567
568
zend_symtable_str_update(HashTable * ht,const char * str,size_t len,zval * pData)569 static zend_always_inline zval *zend_symtable_str_update(HashTable *ht, const char *str, size_t len, zval *pData)
570 {
571 zend_ulong idx;
572
573 if (ZEND_HANDLE_NUMERIC_STR(str, len, idx)) {
574 return zend_hash_index_update(ht, idx, pData);
575 } else {
576 return zend_hash_str_update(ht, str, len, pData);
577 }
578 }
579
580
zend_symtable_str_update_ind(HashTable * ht,const char * str,size_t len,zval * pData)581 static zend_always_inline zval *zend_symtable_str_update_ind(HashTable *ht, const char *str, size_t len, zval *pData)
582 {
583 zend_ulong idx;
584
585 if (ZEND_HANDLE_NUMERIC_STR(str, len, idx)) {
586 return zend_hash_index_update(ht, idx, pData);
587 } else {
588 return zend_hash_str_update_ind(ht, str, len, pData);
589 }
590 }
591
592
zend_symtable_str_del(HashTable * ht,const char * str,size_t len)593 static zend_always_inline zend_result zend_symtable_str_del(HashTable *ht, const char *str, size_t len)
594 {
595 zend_ulong idx;
596
597 if (ZEND_HANDLE_NUMERIC_STR(str, len, idx)) {
598 return zend_hash_index_del(ht, idx);
599 } else {
600 return zend_hash_str_del(ht, str, len);
601 }
602 }
603
604
zend_symtable_str_del_ind(HashTable * ht,const char * str,size_t len)605 static zend_always_inline zend_result zend_symtable_str_del_ind(HashTable *ht, const char *str, size_t len)
606 {
607 zend_ulong idx;
608
609 if (ZEND_HANDLE_NUMERIC_STR(str, len, idx)) {
610 return zend_hash_index_del(ht, idx);
611 } else {
612 return zend_hash_str_del_ind(ht, str, len);
613 }
614 }
615
616
zend_symtable_str_find(HashTable * ht,const char * str,size_t len)617 static zend_always_inline zval *zend_symtable_str_find(HashTable *ht, const char *str, size_t len)
618 {
619 zend_ulong idx;
620
621 if (ZEND_HANDLE_NUMERIC_STR(str, len, idx)) {
622 return zend_hash_index_find(ht, idx);
623 } else {
624 return zend_hash_str_find(ht, str, len);
625 }
626 }
627
628
zend_symtable_str_exists(HashTable * ht,const char * str,size_t len)629 static zend_always_inline bool zend_symtable_str_exists(HashTable *ht, const char *str, size_t len)
630 {
631 zend_ulong idx;
632
633 if (ZEND_HANDLE_NUMERIC_STR(str, len, idx)) {
634 return zend_hash_index_exists(ht, idx);
635 } else {
636 return zend_hash_str_exists(ht, str, len);
637 }
638 }
639
zend_hash_add_ptr(HashTable * ht,zend_string * key,void * pData)640 static zend_always_inline void *zend_hash_add_ptr(HashTable *ht, zend_string *key, void *pData)
641 {
642 zval tmp, *zv;
643
644 ZVAL_PTR(&tmp, pData);
645 zv = zend_hash_add(ht, key, &tmp);
646 if (zv) {
647 ZEND_ASSUME(Z_PTR_P(zv));
648 return Z_PTR_P(zv);
649 } else {
650 return NULL;
651 }
652 }
653
zend_hash_add_new_ptr(HashTable * ht,zend_string * key,void * pData)654 static zend_always_inline void *zend_hash_add_new_ptr(HashTable *ht, zend_string *key, void *pData)
655 {
656 zval tmp, *zv;
657
658 ZVAL_PTR(&tmp, pData);
659 zv = zend_hash_add_new(ht, key, &tmp);
660 if (zv) {
661 ZEND_ASSUME(Z_PTR_P(zv));
662 return Z_PTR_P(zv);
663 } else {
664 return NULL;
665 }
666 }
667
zend_hash_str_add_ptr(HashTable * ht,const char * str,size_t len,void * pData)668 static zend_always_inline void *zend_hash_str_add_ptr(HashTable *ht, const char *str, size_t len, void *pData)
669 {
670 zval tmp, *zv;
671
672 ZVAL_PTR(&tmp, pData);
673 zv = zend_hash_str_add(ht, str, len, &tmp);
674 if (zv) {
675 ZEND_ASSUME(Z_PTR_P(zv));
676 return Z_PTR_P(zv);
677 } else {
678 return NULL;
679 }
680 }
681
zend_hash_str_add_new_ptr(HashTable * ht,const char * str,size_t len,void * pData)682 static zend_always_inline void *zend_hash_str_add_new_ptr(HashTable *ht, const char *str, size_t len, void *pData)
683 {
684 zval tmp, *zv;
685
686 ZVAL_PTR(&tmp, pData);
687 zv = zend_hash_str_add_new(ht, str, len, &tmp);
688 if (zv) {
689 ZEND_ASSUME(Z_PTR_P(zv));
690 return Z_PTR_P(zv);
691 } else {
692 return NULL;
693 }
694 }
695
zend_hash_update_ptr(HashTable * ht,zend_string * key,void * pData)696 static zend_always_inline void *zend_hash_update_ptr(HashTable *ht, zend_string *key, void *pData)
697 {
698 zval tmp, *zv;
699
700 ZVAL_PTR(&tmp, pData);
701 zv = zend_hash_update(ht, key, &tmp);
702 ZEND_ASSUME(Z_PTR_P(zv));
703 return Z_PTR_P(zv);
704 }
705
zend_hash_str_update_ptr(HashTable * ht,const char * str,size_t len,void * pData)706 static zend_always_inline void *zend_hash_str_update_ptr(HashTable *ht, const char *str, size_t len, void *pData)
707 {
708 zval tmp, *zv;
709
710 ZVAL_PTR(&tmp, pData);
711 zv = zend_hash_str_update(ht, str, len, &tmp);
712 ZEND_ASSUME(Z_PTR_P(zv));
713 return Z_PTR_P(zv);
714 }
715
zend_hash_add_mem(HashTable * ht,zend_string * key,void * pData,size_t size)716 static zend_always_inline void *zend_hash_add_mem(HashTable *ht, zend_string *key, void *pData, size_t size)
717 {
718 zval tmp, *zv;
719
720 ZVAL_PTR(&tmp, NULL);
721 if ((zv = zend_hash_add(ht, key, &tmp))) {
722 Z_PTR_P(zv) = pemalloc(size, GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
723 memcpy(Z_PTR_P(zv), pData, size);
724 return Z_PTR_P(zv);
725 }
726 return NULL;
727 }
728
zend_hash_add_new_mem(HashTable * ht,zend_string * key,void * pData,size_t size)729 static zend_always_inline void *zend_hash_add_new_mem(HashTable *ht, zend_string *key, void *pData, size_t size)
730 {
731 zval tmp, *zv;
732
733 ZVAL_PTR(&tmp, NULL);
734 if ((zv = zend_hash_add_new(ht, key, &tmp))) {
735 Z_PTR_P(zv) = pemalloc(size, GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
736 memcpy(Z_PTR_P(zv), pData, size);
737 return Z_PTR_P(zv);
738 }
739 return NULL;
740 }
741
zend_hash_str_add_mem(HashTable * ht,const char * str,size_t len,void * pData,size_t size)742 static zend_always_inline void *zend_hash_str_add_mem(HashTable *ht, const char *str, size_t len, void *pData, size_t size)
743 {
744 zval tmp, *zv;
745
746 ZVAL_PTR(&tmp, NULL);
747 if ((zv = zend_hash_str_add(ht, str, len, &tmp))) {
748 Z_PTR_P(zv) = pemalloc(size, GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
749 memcpy(Z_PTR_P(zv), pData, size);
750 return Z_PTR_P(zv);
751 }
752 return NULL;
753 }
754
zend_hash_str_add_new_mem(HashTable * ht,const char * str,size_t len,void * pData,size_t size)755 static zend_always_inline void *zend_hash_str_add_new_mem(HashTable *ht, const char *str, size_t len, void *pData, size_t size)
756 {
757 zval tmp, *zv;
758
759 ZVAL_PTR(&tmp, NULL);
760 if ((zv = zend_hash_str_add_new(ht, str, len, &tmp))) {
761 Z_PTR_P(zv) = pemalloc(size, GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
762 memcpy(Z_PTR_P(zv), pData, size);
763 return Z_PTR_P(zv);
764 }
765 return NULL;
766 }
767
zend_hash_update_mem(HashTable * ht,zend_string * key,void * pData,size_t size)768 static zend_always_inline void *zend_hash_update_mem(HashTable *ht, zend_string *key, void *pData, size_t size)
769 {
770 void *p;
771
772 p = pemalloc(size, GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
773 memcpy(p, pData, size);
774 return zend_hash_update_ptr(ht, key, p);
775 }
776
zend_hash_str_update_mem(HashTable * ht,const char * str,size_t len,void * pData,size_t size)777 static zend_always_inline void *zend_hash_str_update_mem(HashTable *ht, const char *str, size_t len, void *pData, size_t size)
778 {
779 void *p;
780
781 p = pemalloc(size, GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
782 memcpy(p, pData, size);
783 return zend_hash_str_update_ptr(ht, str, len, p);
784 }
785
zend_hash_index_add_ptr(HashTable * ht,zend_ulong h,void * pData)786 static zend_always_inline void *zend_hash_index_add_ptr(HashTable *ht, zend_ulong h, void *pData)
787 {
788 zval tmp, *zv;
789
790 ZVAL_PTR(&tmp, pData);
791 zv = zend_hash_index_add(ht, h, &tmp);
792 return zv ? Z_PTR_P(zv) : NULL;
793 }
794
zend_hash_index_add_new_ptr(HashTable * ht,zend_ulong h,void * pData)795 static zend_always_inline void *zend_hash_index_add_new_ptr(HashTable *ht, zend_ulong h, void *pData)
796 {
797 zval tmp, *zv;
798
799 ZVAL_PTR(&tmp, pData);
800 zv = zend_hash_index_add_new(ht, h, &tmp);
801 return zv ? Z_PTR_P(zv) : NULL;
802 }
803
zend_hash_index_update_ptr(HashTable * ht,zend_ulong h,void * pData)804 static zend_always_inline void *zend_hash_index_update_ptr(HashTable *ht, zend_ulong h, void *pData)
805 {
806 zval tmp, *zv;
807
808 ZVAL_PTR(&tmp, pData);
809 zv = zend_hash_index_update(ht, h, &tmp);
810 ZEND_ASSUME(Z_PTR_P(zv));
811 return Z_PTR_P(zv);
812 }
813
zend_hash_index_add_mem(HashTable * ht,zend_ulong h,void * pData,size_t size)814 static zend_always_inline void *zend_hash_index_add_mem(HashTable *ht, zend_ulong h, void *pData, size_t size)
815 {
816 zval tmp, *zv;
817
818 ZVAL_PTR(&tmp, NULL);
819 if ((zv = zend_hash_index_add(ht, h, &tmp))) {
820 Z_PTR_P(zv) = pemalloc(size, GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
821 memcpy(Z_PTR_P(zv), pData, size);
822 return Z_PTR_P(zv);
823 }
824 return NULL;
825 }
826
zend_hash_next_index_insert_ptr(HashTable * ht,void * pData)827 static zend_always_inline void *zend_hash_next_index_insert_ptr(HashTable *ht, void *pData)
828 {
829 zval tmp, *zv;
830
831 ZVAL_PTR(&tmp, pData);
832 zv = zend_hash_next_index_insert(ht, &tmp);
833 if (zv) {
834 ZEND_ASSUME(Z_PTR_P(zv));
835 return Z_PTR_P(zv);
836 } else {
837 return NULL;
838 }
839 }
840
zend_hash_index_update_mem(HashTable * ht,zend_ulong h,void * pData,size_t size)841 static zend_always_inline void *zend_hash_index_update_mem(HashTable *ht, zend_ulong h, void *pData, size_t size)
842 {
843 void *p;
844
845 p = pemalloc(size, GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
846 memcpy(p, pData, size);
847 return zend_hash_index_update_ptr(ht, h, p);
848 }
849
zend_hash_next_index_insert_mem(HashTable * ht,void * pData,size_t size)850 static zend_always_inline void *zend_hash_next_index_insert_mem(HashTable *ht, void *pData, size_t size)
851 {
852 zval tmp, *zv;
853
854 ZVAL_PTR(&tmp, NULL);
855 if ((zv = zend_hash_next_index_insert(ht, &tmp))) {
856 Z_PTR_P(zv) = pemalloc(size, GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
857 memcpy(Z_PTR_P(zv), pData, size);
858 return Z_PTR_P(zv);
859 }
860 return NULL;
861 }
862
zend_hash_find_ptr(const HashTable * ht,zend_string * key)863 static zend_always_inline void *zend_hash_find_ptr(const HashTable *ht, zend_string *key)
864 {
865 zval *zv;
866
867 zv = zend_hash_find(ht, key);
868 if (zv) {
869 ZEND_ASSUME(Z_PTR_P(zv));
870 return Z_PTR_P(zv);
871 } else {
872 return NULL;
873 }
874 }
875
zend_hash_find_ex_ptr(const HashTable * ht,zend_string * key,bool known_hash)876 static zend_always_inline void *zend_hash_find_ex_ptr(const HashTable *ht, zend_string *key, bool known_hash)
877 {
878 zval *zv;
879
880 zv = zend_hash_find_ex(ht, key, known_hash);
881 if (zv) {
882 ZEND_ASSUME(Z_PTR_P(zv));
883 return Z_PTR_P(zv);
884 } else {
885 return NULL;
886 }
887 }
888
zend_hash_str_find_ptr(const HashTable * ht,const char * str,size_t len)889 static zend_always_inline void *zend_hash_str_find_ptr(const HashTable *ht, const char *str, size_t len)
890 {
891 zval *zv;
892
893 zv = zend_hash_str_find(ht, str, len);
894 if (zv) {
895 ZEND_ASSUME(Z_PTR_P(zv));
896 return Z_PTR_P(zv);
897 } else {
898 return NULL;
899 }
900 }
901
902 /* Will lowercase the str; use only if you don't need the lowercased string for
903 * anything else. If you have a lowered string, use zend_hash_str_find_ptr. */
904 ZEND_API void *zend_hash_str_find_ptr_lc(const HashTable *ht, const char *str, size_t len);
905
906 /* Will lowercase the str; use only if you don't need the lowercased string for
907 * anything else. If you have a lowered string, use zend_hash_find_ptr. */
908 ZEND_API void *zend_hash_find_ptr_lc(const HashTable *ht, zend_string *key);
909
zend_hash_index_find_ptr(const HashTable * ht,zend_ulong h)910 static zend_always_inline void *zend_hash_index_find_ptr(const HashTable *ht, zend_ulong h)
911 {
912 zval *zv;
913
914 zv = zend_hash_index_find(ht, h);
915 if (zv) {
916 ZEND_ASSUME(Z_PTR_P(zv));
917 return Z_PTR_P(zv);
918 } else {
919 return NULL;
920 }
921 }
922
zend_hash_index_find_deref(HashTable * ht,zend_ulong h)923 static zend_always_inline zval *zend_hash_index_find_deref(HashTable *ht, zend_ulong h)
924 {
925 zval *zv = zend_hash_index_find(ht, h);
926 if (zv) {
927 ZVAL_DEREF(zv);
928 }
929 return zv;
930 }
931
zend_hash_find_deref(HashTable * ht,zend_string * str)932 static zend_always_inline zval *zend_hash_find_deref(HashTable *ht, zend_string *str)
933 {
934 zval *zv = zend_hash_find(ht, str);
935 if (zv) {
936 ZVAL_DEREF(zv);
937 }
938 return zv;
939 }
940
zend_hash_str_find_deref(HashTable * ht,const char * str,size_t len)941 static zend_always_inline zval *zend_hash_str_find_deref(HashTable *ht, const char *str, size_t len)
942 {
943 zval *zv = zend_hash_str_find(ht, str, len);
944 if (zv) {
945 ZVAL_DEREF(zv);
946 }
947 return zv;
948 }
949
zend_symtable_str_find_ptr(HashTable * ht,const char * str,size_t len)950 static zend_always_inline void *zend_symtable_str_find_ptr(HashTable *ht, const char *str, size_t len)
951 {
952 zend_ulong idx;
953
954 if (ZEND_HANDLE_NUMERIC_STR(str, len, idx)) {
955 return zend_hash_index_find_ptr(ht, idx);
956 } else {
957 return zend_hash_str_find_ptr(ht, str, len);
958 }
959 }
960
zend_hash_get_current_data_ptr_ex(HashTable * ht,HashPosition * pos)961 static zend_always_inline void *zend_hash_get_current_data_ptr_ex(HashTable *ht, HashPosition *pos)
962 {
963 zval *zv;
964
965 zv = zend_hash_get_current_data_ex(ht, pos);
966 if (zv) {
967 ZEND_ASSUME(Z_PTR_P(zv));
968 return Z_PTR_P(zv);
969 } else {
970 return NULL;
971 }
972 }
973
974 #define zend_hash_get_current_data_ptr(ht) \
975 zend_hash_get_current_data_ptr_ex(ht, &(ht)->nInternalPointer)
976
977 /* Common hash/packed array iterators */
978 #if 0
979 # define ZEND_HASH_ELEMENT_SIZE(__ht) \
980 (HT_IS_PACKED(__ht) ? sizeof(zval) : sizeof(Bucket))
981 #else /* optimized version */
982 # define ZEND_HASH_ELEMENT_SIZE(__ht) \
983 (sizeof(zval) + (~HT_FLAGS(__ht) & HASH_FLAG_PACKED) * ((sizeof(Bucket)-sizeof(zval))/HASH_FLAG_PACKED))
984 #endif
985
986 #define ZEND_HASH_ELEMENT_EX(__ht, _idx, _size) \
987 ((zval*)(((char*)(__ht)->arPacked) + ((_idx) * (_size))))
988
989 #define ZEND_HASH_ELEMENT(__ht, _idx) \
990 ZEND_HASH_ELEMENT_EX(__ht, _idx, ZEND_HASH_ELEMENT_SIZE(__ht))
991
992 #define ZEND_HASH_NEXT_ELEMENT(_el, _size) \
993 ((zval*)(((char*)(_el)) + (_size)))
994
995 #define ZEND_HASH_PREV_ELEMENT(_el, _size) \
996 ((zval*)(((char*)(_el)) - (_size)))
997
998 #define _ZEND_HASH_FOREACH_VAL(_ht) do { \
999 HashTable *__ht = (_ht); \
1000 uint32_t _count = __ht->nNumUsed; \
1001 size_t _size = ZEND_HASH_ELEMENT_SIZE(__ht); \
1002 zval *_z = __ht->arPacked; \
1003 for (; _count > 0; _z = ZEND_HASH_NEXT_ELEMENT(_z, _size), _count--) { \
1004 if (UNEXPECTED(Z_TYPE_P(_z) == IS_UNDEF)) continue;
1005
1006 #define _ZEND_HASH_REVERSE_FOREACH_VAL(_ht) do { \
1007 HashTable *__ht = (_ht); \
1008 uint32_t _idx = __ht->nNumUsed; \
1009 size_t _size = ZEND_HASH_ELEMENT_SIZE(__ht); \
1010 zval *_z = ZEND_HASH_ELEMENT_EX(__ht, _idx, _size); \
1011 for (;_idx > 0; _idx--) { \
1012 _z = ZEND_HASH_PREV_ELEMENT(_z, _size); \
1013 if (UNEXPECTED(Z_TYPE_P(_z) == IS_UNDEF)) continue;
1014
1015 #define ZEND_HASH_FOREACH_FROM(_ht, indirect, _from) do { \
1016 HashTable *__ht = (_ht); \
1017 zend_ulong __h; \
1018 zend_string *__key = NULL; \
1019 uint32_t _idx = (_from); \
1020 size_t _size = ZEND_HASH_ELEMENT_SIZE(__ht); \
1021 zval *__z = ZEND_HASH_ELEMENT_EX(__ht, _idx, _size); \
1022 uint32_t _count = __ht->nNumUsed - _idx; \
1023 for (;_count > 0; _count--) { \
1024 zval *_z = __z; \
1025 if (HT_IS_PACKED(__ht)) { \
1026 __z++; \
1027 __h = _idx; \
1028 _idx++; \
1029 } else { \
1030 Bucket *_p = (Bucket*)__z; \
1031 __z = &(_p + 1)->val; \
1032 __h = _p->h; \
1033 __key = _p->key; \
1034 if (indirect && Z_TYPE_P(_z) == IS_INDIRECT) { \
1035 _z = Z_INDIRECT_P(_z); \
1036 } \
1037 } \
1038 (void) __h; (void) __key; (void) _idx; \
1039 if (UNEXPECTED(Z_TYPE_P(_z) == IS_UNDEF)) continue;
1040
1041 #define ZEND_HASH_FOREACH(_ht, indirect) ZEND_HASH_FOREACH_FROM(_ht, indirect, 0)
1042
1043 #define ZEND_HASH_REVERSE_FOREACH(_ht, indirect) do { \
1044 HashTable *__ht = (_ht); \
1045 uint32_t _idx = __ht->nNumUsed; \
1046 zval *_z; \
1047 zend_ulong __h; \
1048 zend_string *__key = NULL; \
1049 size_t _size = ZEND_HASH_ELEMENT_SIZE(__ht); \
1050 zval *__z = ZEND_HASH_ELEMENT_EX(__ht, _idx, _size); \
1051 for (;_idx > 0; _idx--) { \
1052 if (HT_IS_PACKED(__ht)) { \
1053 __z--; \
1054 _z = __z; \
1055 __h = _idx - 1; \
1056 } else { \
1057 Bucket *_p = (Bucket*)__z; \
1058 _p--; \
1059 __z = &_p->val; \
1060 _z = __z; \
1061 __h = _p->h; \
1062 __key = _p->key; \
1063 if (indirect && Z_TYPE_P(_z) == IS_INDIRECT) { \
1064 _z = Z_INDIRECT_P(_z); \
1065 } \
1066 } \
1067 (void) __h; (void) __key; (void) __z; \
1068 if (UNEXPECTED(Z_TYPE_P(_z) == IS_UNDEF)) continue;
1069
1070 #define ZEND_HASH_FOREACH_END() \
1071 } \
1072 } while (0)
1073
1074 #define ZEND_HASH_FOREACH_END_DEL() \
1075 ZEND_HASH_MAP_FOREACH_END_DEL()
1076
1077 #define ZEND_HASH_FOREACH_BUCKET(ht, _bucket) \
1078 ZEND_HASH_MAP_FOREACH_BUCKET(ht, _bucket)
1079
1080 #define ZEND_HASH_FOREACH_BUCKET_FROM(ht, _bucket, _from) \
1081 ZEND_HASH_MAP_FOREACH_BUCKET_FROM(ht, _bucket, _from)
1082
1083 #define ZEND_HASH_REVERSE_FOREACH_BUCKET(ht, _bucket) \
1084 ZEND_HASH_MAP_REVERSE_FOREACH_BUCKET(ht, _bucket)
1085
1086 #define ZEND_HASH_FOREACH_VAL(ht, _val) \
1087 _ZEND_HASH_FOREACH_VAL(ht); \
1088 _val = _z;
1089
1090 #define ZEND_HASH_REVERSE_FOREACH_VAL(ht, _val) \
1091 _ZEND_HASH_REVERSE_FOREACH_VAL(ht); \
1092 _val = _z;
1093
1094 #define ZEND_HASH_FOREACH_VAL_IND(ht, _val) \
1095 ZEND_HASH_FOREACH(ht, 1); \
1096 _val = _z;
1097
1098 #define ZEND_HASH_REVERSE_FOREACH_VAL_IND(ht, _val) \
1099 ZEND_HASH_REVERSE_FOREACH(ht, 1); \
1100 _val = _z;
1101
1102 #define ZEND_HASH_FOREACH_PTR(ht, _ptr) \
1103 _ZEND_HASH_FOREACH_VAL(ht); \
1104 _ptr = Z_PTR_P(_z);
1105
1106 #define ZEND_HASH_FOREACH_PTR_FROM(ht, _ptr, _from) \
1107 ZEND_HASH_FOREACH_FROM(ht, 0, _from); \
1108 _ptr = Z_PTR_P(_z);
1109
1110 #define ZEND_HASH_REVERSE_FOREACH_PTR(ht, _ptr) \
1111 _ZEND_HASH_REVERSE_FOREACH_VAL(ht); \
1112 _ptr = Z_PTR_P(_z);
1113
1114 #define ZEND_HASH_FOREACH_NUM_KEY(ht, _h) \
1115 ZEND_HASH_FOREACH(ht, 0); \
1116 _h = __h;
1117
1118 #define ZEND_HASH_REVERSE_FOREACH_NUM_KEY(ht, _h) \
1119 ZEND_HASH_REVERSE_FOREACH(ht, 0); \
1120 _h = __h;
1121
1122 #define ZEND_HASH_FOREACH_STR_KEY(ht, _key) \
1123 ZEND_HASH_FOREACH(ht, 0); \
1124 _key = __key;
1125
1126 #define ZEND_HASH_REVERSE_FOREACH_STR_KEY(ht, _key) \
1127 ZEND_HASH_REVERSE_FOREACH(ht, 0); \
1128 _key = __key;
1129
1130 #define ZEND_HASH_FOREACH_KEY(ht, _h, _key) \
1131 ZEND_HASH_FOREACH(ht, 0); \
1132 _h = __h; \
1133 _key = __key;
1134
1135 #define ZEND_HASH_REVERSE_FOREACH_KEY(ht, _h, _key) \
1136 ZEND_HASH_REVERSE_FOREACH(ht, 0); \
1137 _h = __h; \
1138 _key = __key;
1139
1140 #define ZEND_HASH_FOREACH_NUM_KEY_VAL(ht, _h, _val) \
1141 ZEND_HASH_FOREACH(ht, 0); \
1142 _h = __h; \
1143 _val = _z;
1144
1145 #define ZEND_HASH_REVERSE_FOREACH_NUM_KEY_VAL(ht, _h, _val) \
1146 ZEND_HASH_REVERSE_FOREACH(ht, 0); \
1147 _h = __h; \
1148 _val = _z;
1149
1150 #define ZEND_HASH_FOREACH_STR_KEY_VAL(ht, _key, _val) \
1151 ZEND_HASH_FOREACH(ht, 0); \
1152 _key = __key; \
1153 _val = _z;
1154
1155 #define ZEND_HASH_FOREACH_STR_KEY_VAL_FROM(ht, _key, _val, _from) \
1156 ZEND_HASH_FOREACH_FROM(ht, 0, _from); \
1157 _key = __key; \
1158 _val = _z;
1159
1160 #define ZEND_HASH_REVERSE_FOREACH_STR_KEY_VAL(ht, _key, _val) \
1161 ZEND_HASH_REVERSE_FOREACH(ht, 0); \
1162 _key = __key; \
1163 _val = _z;
1164
1165 #define ZEND_HASH_FOREACH_KEY_VAL(ht, _h, _key, _val) \
1166 ZEND_HASH_FOREACH(ht, 0); \
1167 _h = __h; \
1168 _key = __key; \
1169 _val = _z;
1170
1171 #define ZEND_HASH_REVERSE_FOREACH_KEY_VAL(ht, _h, _key, _val) \
1172 ZEND_HASH_REVERSE_FOREACH(ht, 0); \
1173 _h = __h; \
1174 _key = __key; \
1175 _val = _z;
1176
1177 #define ZEND_HASH_FOREACH_STR_KEY_VAL_IND(ht, _key, _val) \
1178 ZEND_HASH_FOREACH(ht, 1); \
1179 _key = __key; \
1180 _val = _z;
1181
1182 #define ZEND_HASH_REVERSE_FOREACH_STR_KEY_VAL_IND(ht, _key, _val) \
1183 ZEND_HASH_REVERSE_FOREACH(ht, 1); \
1184 _key = __key; \
1185 _val = _z;
1186
1187 #define ZEND_HASH_FOREACH_KEY_VAL_IND(ht, _h, _key, _val) \
1188 ZEND_HASH_FOREACH(ht, 1); \
1189 _h = __h; \
1190 _key = __key; \
1191 _val = _z;
1192
1193 #define ZEND_HASH_REVERSE_FOREACH_KEY_VAL_IND(ht, _h, _key, _val) \
1194 ZEND_HASH_REVERSE_FOREACH(ht, 1); \
1195 _h = __h; \
1196 _key = __key; \
1197 _val = _z;
1198
1199 #define ZEND_HASH_FOREACH_NUM_KEY_PTR(ht, _h, _ptr) \
1200 ZEND_HASH_FOREACH(ht, 0); \
1201 _h = __h; \
1202 _ptr = Z_PTR_P(_z);
1203
1204 #define ZEND_HASH_REVERSE_FOREACH_NUM_KEY_PTR(ht, _h, _ptr) \
1205 ZEND_HASH_REVERSE_FOREACH(ht, 0); \
1206 _h = __h; \
1207 _ptr = Z_PTR_P(_z);
1208
1209 #define ZEND_HASH_FOREACH_STR_KEY_PTR(ht, _key, _ptr) \
1210 ZEND_HASH_FOREACH(ht, 0); \
1211 _key = __key; \
1212 _ptr = Z_PTR_P(_z);
1213
1214 #define ZEND_HASH_REVERSE_FOREACH_STR_KEY_PTR(ht, _key, _ptr) \
1215 ZEND_HASH_REVERSE_FOREACH(ht, 0); \
1216 _key = __key; \
1217 _ptr = Z_PTR_P(_z);
1218
1219 #define ZEND_HASH_FOREACH_KEY_PTR(ht, _h, _key, _ptr) \
1220 ZEND_HASH_FOREACH(ht, 0); \
1221 _h = __h; \
1222 _key = __key; \
1223 _ptr = Z_PTR_P(_z);
1224
1225 #define ZEND_HASH_REVERSE_FOREACH_KEY_PTR(ht, _h, _key, _ptr) \
1226 ZEND_HASH_REVERSE_FOREACH(ht, 0); \
1227 _h = __h; \
1228 _key = __key; \
1229 _ptr = Z_PTR_P(_z);
1230
1231 /* Hash array iterators */
1232 #define ZEND_HASH_MAP_FOREACH_FROM(_ht, indirect, _from) do { \
1233 HashTable *__ht = (_ht); \
1234 Bucket *_p = __ht->arData + (_from); \
1235 Bucket *_end = __ht->arData + __ht->nNumUsed; \
1236 ZEND_ASSERT(!HT_IS_PACKED(__ht)); \
1237 for (; _p != _end; _p++) { \
1238 zval *_z = &_p->val; \
1239 if (indirect && Z_TYPE_P(_z) == IS_INDIRECT) { \
1240 _z = Z_INDIRECT_P(_z); \
1241 } \
1242 if (UNEXPECTED(Z_TYPE_P(_z) == IS_UNDEF)) continue;
1243
1244 #define ZEND_HASH_MAP_FOREACH(_ht, indirect) ZEND_HASH_MAP_FOREACH_FROM(_ht, indirect, 0)
1245
1246 #define ZEND_HASH_MAP_REVERSE_FOREACH(_ht, indirect) do { \
1247 HashTable *__ht = (_ht); \
1248 uint32_t _idx = __ht->nNumUsed; \
1249 Bucket *_p = __ht->arData + _idx; \
1250 zval *_z; \
1251 ZEND_ASSERT(!HT_IS_PACKED(__ht)); \
1252 for (_idx = __ht->nNumUsed; _idx > 0; _idx--) { \
1253 _p--; \
1254 _z = &_p->val; \
1255 if (indirect && Z_TYPE_P(_z) == IS_INDIRECT) { \
1256 _z = Z_INDIRECT_P(_z); \
1257 } \
1258 if (UNEXPECTED(Z_TYPE_P(_z) == IS_UNDEF)) continue;
1259
1260 #define ZEND_HASH_MAP_FOREACH_END_DEL() \
1261 ZEND_ASSERT(!HT_IS_PACKED(__ht)); \
1262 __ht->nNumOfElements--; \
1263 do { \
1264 uint32_t j = HT_IDX_TO_HASH(_idx - 1); \
1265 uint32_t nIndex = _p->h | __ht->nTableMask; \
1266 uint32_t i = HT_HASH(__ht, nIndex); \
1267 if (UNEXPECTED(j != i)) { \
1268 Bucket *prev = HT_HASH_TO_BUCKET(__ht, i); \
1269 while (Z_NEXT(prev->val) != j) { \
1270 i = Z_NEXT(prev->val); \
1271 prev = HT_HASH_TO_BUCKET(__ht, i); \
1272 } \
1273 Z_NEXT(prev->val) = Z_NEXT(_p->val); \
1274 } else { \
1275 HT_HASH(__ht, nIndex) = Z_NEXT(_p->val); \
1276 } \
1277 } while (0); \
1278 } \
1279 __ht->nNumUsed = _idx; \
1280 } while (0)
1281
1282 #define ZEND_HASH_MAP_FOREACH_BUCKET(ht, _bucket) \
1283 ZEND_HASH_MAP_FOREACH(ht, 0); \
1284 _bucket = _p;
1285
1286 #define ZEND_HASH_MAP_FOREACH_BUCKET_FROM(ht, _bucket, _from) \
1287 ZEND_HASH_MAP_FOREACH_FROM(ht, 0, _from); \
1288 _bucket = _p;
1289
1290 #define ZEND_HASH_MAP_REVERSE_FOREACH_BUCKET(ht, _bucket) \
1291 ZEND_HASH_MAP_REVERSE_FOREACH(ht, 0); \
1292 _bucket = _p;
1293
1294 #define ZEND_HASH_MAP_FOREACH_VAL(ht, _val) \
1295 ZEND_HASH_MAP_FOREACH(ht, 0); \
1296 _val = _z;
1297
1298 #define ZEND_HASH_MAP_REVERSE_FOREACH_VAL(ht, _val) \
1299 ZEND_HASH_MAP_REVERSE_FOREACH(ht, 0); \
1300 _val = _z;
1301
1302 #define ZEND_HASH_MAP_FOREACH_VAL_IND(ht, _val) \
1303 ZEND_HASH_MAP_FOREACH(ht, 1); \
1304 _val = _z;
1305
1306 #define ZEND_HASH_MAP_REVERSE_FOREACH_VAL_IND(ht, _val) \
1307 ZEND_HASH_MAP_REVERSE_FOREACH(ht, 1); \
1308 _val = _z;
1309
1310 #define ZEND_HASH_MAP_FOREACH_PTR(ht, _ptr) \
1311 ZEND_HASH_MAP_FOREACH(ht, 0); \
1312 _ptr = Z_PTR_P(_z);
1313
1314 #define ZEND_HASH_MAP_FOREACH_PTR_FROM(ht, _ptr, _from) \
1315 ZEND_HASH_MAP_FOREACH_FROM(ht, 0, _from); \
1316 _ptr = Z_PTR_P(_z);
1317
1318 #define ZEND_HASH_MAP_REVERSE_FOREACH_PTR(ht, _ptr) \
1319 ZEND_HASH_MAP_REVERSE_FOREACH(ht, 0); \
1320 _ptr = Z_PTR_P(_z);
1321
1322 #define ZEND_HASH_MAP_FOREACH_NUM_KEY(ht, _h) \
1323 ZEND_HASH_MAP_FOREACH(ht, 0); \
1324 _h = _p->h;
1325
1326 #define ZEND_HASH_MAP_REVERSE_FOREACH_NUM_KEY(ht, _h) \
1327 ZEND_HASH_MAP_REVERSE_FOREACH(ht, 0); \
1328 _h = _p->h;
1329
1330 #define ZEND_HASH_MAP_FOREACH_STR_KEY(ht, _key) \
1331 ZEND_HASH_MAP_FOREACH(ht, 0); \
1332 _key = _p->key;
1333
1334 #define ZEND_HASH_MAP_REVERSE_FOREACH_STR_KEY(ht, _key) \
1335 ZEND_HASH_MAP_REVERSE_FOREACH(ht, 0); \
1336 _key = _p->key;
1337
1338 #define ZEND_HASH_MAP_FOREACH_KEY(ht, _h, _key) \
1339 ZEND_HASH_MAP_FOREACH(ht, 0); \
1340 _h = _p->h; \
1341 _key = _p->key;
1342
1343 #define ZEND_HASH_MAP_REVERSE_FOREACH_KEY(ht, _h, _key) \
1344 ZEND_HASH_MAP_REVERSE_FOREACH(ht, 0); \
1345 _h = _p->h; \
1346 _key = _p->key;
1347
1348 #define ZEND_HASH_MAP_FOREACH_NUM_KEY_VAL(ht, _h, _val) \
1349 ZEND_HASH_MAP_FOREACH(ht, 0); \
1350 _h = _p->h; \
1351 _val = _z;
1352
1353 #define ZEND_HASH_MAP_REVERSE_FOREACH_NUM_KEY_VAL(ht, _h, _val) \
1354 ZEND_HASH_MAP_REVERSE_FOREACH(ht, 0); \
1355 _h = _p->h; \
1356 _val = _z;
1357
1358 #define ZEND_HASH_MAP_FOREACH_STR_KEY_VAL(ht, _key, _val) \
1359 ZEND_HASH_MAP_FOREACH(ht, 0); \
1360 _key = _p->key; \
1361 _val = _z;
1362
1363 #define ZEND_HASH_MAP_FOREACH_STR_KEY_VAL_FROM(ht, _key, _val, _from) \
1364 ZEND_HASH_MAP_FOREACH_FROM(ht, 0, _from); \
1365 _key = _p->key; \
1366 _val = _z;
1367
1368 #define ZEND_HASH_MAP_REVERSE_FOREACH_STR_KEY_VAL(ht, _key, _val) \
1369 ZEND_HASH_MAP_REVERSE_FOREACH(ht, 0); \
1370 _key = _p->key; \
1371 _val = _z;
1372
1373 #define ZEND_HASH_MAP_FOREACH_KEY_VAL(ht, _h, _key, _val) \
1374 ZEND_HASH_MAP_FOREACH(ht, 0); \
1375 _h = _p->h; \
1376 _key = _p->key; \
1377 _val = _z;
1378
1379 #define ZEND_HASH_MAP_REVERSE_FOREACH_KEY_VAL(ht, _h, _key, _val) \
1380 ZEND_HASH_MAP_REVERSE_FOREACH(ht, 0); \
1381 _h = _p->h; \
1382 _key = _p->key; \
1383 _val = _z;
1384
1385 #define ZEND_HASH_MAP_FOREACH_STR_KEY_VAL_IND(ht, _key, _val) \
1386 ZEND_HASH_MAP_FOREACH(ht, 1); \
1387 _key = _p->key; \
1388 _val = _z;
1389
1390 #define ZEND_HASH_MAP_REVERSE_FOREACH_STR_KEY_VAL_IND(ht, _key, _val) \
1391 ZEND_HASH_MAP_REVERSE_FOREACH(ht, 1); \
1392 _key = _p->key; \
1393 _val = _z;
1394
1395 #define ZEND_HASH_MAP_FOREACH_KEY_VAL_IND(ht, _h, _key, _val) \
1396 ZEND_HASH_MAP_FOREACH(ht, 1); \
1397 _h = _p->h; \
1398 _key = _p->key; \
1399 _val = _z;
1400
1401 #define ZEND_HASH_MAP_REVERSE_FOREACH_KEY_VAL_IND(ht, _h, _key, _val) \
1402 ZEND_HASH_MAP_REVERSE_FOREACH(ht, 1); \
1403 _h = _p->h; \
1404 _key = _p->key; \
1405 _val = _z;
1406
1407 #define ZEND_HASH_MAP_FOREACH_NUM_KEY_PTR(ht, _h, _ptr) \
1408 ZEND_HASH_MAP_FOREACH(ht, 0); \
1409 _h = _p->h; \
1410 _ptr = Z_PTR_P(_z);
1411
1412 #define ZEND_HASH_MAP_REVERSE_FOREACH_NUM_KEY_PTR(ht, _h, _ptr) \
1413 ZEND_HASH_MAP_REVERSE_FOREACH(ht, 0); \
1414 _h = _p->h; \
1415 _ptr = Z_PTR_P(_z);
1416
1417 #define ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(ht, _key, _ptr) \
1418 ZEND_HASH_MAP_FOREACH(ht, 0); \
1419 _key = _p->key; \
1420 _ptr = Z_PTR_P(_z);
1421
1422 #define ZEND_HASH_MAP_REVERSE_FOREACH_STR_KEY_PTR(ht, _key, _ptr) \
1423 ZEND_HASH_MAP_REVERSE_FOREACH(ht, 0); \
1424 _key = _p->key; \
1425 _ptr = Z_PTR_P(_z);
1426
1427 #define ZEND_HASH_MAP_FOREACH_KEY_PTR(ht, _h, _key, _ptr) \
1428 ZEND_HASH_MAP_FOREACH(ht, 0); \
1429 _h = _p->h; \
1430 _key = _p->key; \
1431 _ptr = Z_PTR_P(_z);
1432
1433 #define ZEND_HASH_MAP_REVERSE_FOREACH_KEY_PTR(ht, _h, _key, _ptr) \
1434 ZEND_HASH_MAP_REVERSE_FOREACH(ht, 0); \
1435 _h = _p->h; \
1436 _key = _p->key; \
1437 _ptr = Z_PTR_P(_z);
1438
1439 /* Packed array iterators */
1440 #define ZEND_HASH_PACKED_FOREACH_FROM(_ht, _from) do { \
1441 HashTable *__ht = (_ht); \
1442 zend_ulong _idx = (_from); \
1443 zval *_z = __ht->arPacked + (_from); \
1444 zval *_end = __ht->arPacked + __ht->nNumUsed; \
1445 ZEND_ASSERT(HT_IS_PACKED(__ht)); \
1446 for (;_z != _end; _z++, _idx++) { \
1447 (void) _idx; \
1448 if (UNEXPECTED(Z_TYPE_P(_z) == IS_UNDEF)) continue;
1449
1450 #define ZEND_HASH_PACKED_FOREACH(_ht) ZEND_HASH_PACKED_FOREACH_FROM(_ht, 0)
1451
1452 #define ZEND_HASH_PACKED_REVERSE_FOREACH(_ht) do { \
1453 HashTable *__ht = (_ht); \
1454 zend_ulong _idx = __ht->nNumUsed; \
1455 zval *_z = __ht->arPacked + _idx; \
1456 ZEND_ASSERT(HT_IS_PACKED(__ht)); \
1457 while (_idx > 0) { \
1458 _z--; \
1459 _idx--; \
1460 (void) _idx; \
1461 if (UNEXPECTED(Z_TYPE_P(_z) == IS_UNDEF)) continue;
1462
1463 #define ZEND_HASH_PACKED_FOREACH_VAL(ht, _val) \
1464 ZEND_HASH_PACKED_FOREACH(ht); \
1465 _val = _z;
1466
1467 #define ZEND_HASH_PACKED_REVERSE_FOREACH_VAL(ht, _val) \
1468 ZEND_HASH_PACKED_REVERSE_FOREACH(ht); \
1469 _val = _z;
1470
1471 #define ZEND_HASH_PACKED_FOREACH_PTR(ht, _ptr) \
1472 ZEND_HASH_PACKED_FOREACH(ht); \
1473 _ptr = Z_PTR_P(_z);
1474
1475 #define ZEND_HASH_PACKED_REVERSE_FOREACH_PTR(ht, _ptr) \
1476 ZEND_HASH_PACKED_REVERSE_FOREACH(ht); \
1477 _ptr = Z_PTR_P(_z);
1478
1479 #define ZEND_HASH_PACKED_FOREACH_KEY(ht, _h) \
1480 ZEND_HASH_PACKED_FOREACH(ht); \
1481 _h = _idx;
1482
1483 #define ZEND_HASH_PACKED_REVERSE_FOREACH_KEY(ht, _h) \
1484 ZEND_HASH_PACKED_REVERSE_FOREACH(ht); \
1485 _h = _idx;
1486
1487 #define ZEND_HASH_PACKED_FOREACH_KEY_VAL(ht, _h, _val) \
1488 ZEND_HASH_PACKED_FOREACH(ht); \
1489 _h = _idx; \
1490 _val = _z;
1491
1492 #define ZEND_HASH_PACKED_REVERSE_FOREACH_KEY_VAL(ht, _h, _val) \
1493 ZEND_HASH_PACKED_REVERSE_FOREACH(ht); \
1494 _h = _idx; \
1495 _val = _z;
1496
1497 #define ZEND_HASH_PACKED_FOREACH_KEY_PTR(ht, _h, _ptr) \
1498 ZEND_HASH_PACKED_FOREACH(ht); \
1499 _h = _idx; \
1500 _ptr = Z_PTR_P(_z);
1501
1502 #define ZEND_HASH_PACKED_REVERSE_FOREACH_KEY_PTR(ht, _h, _ptr) \
1503 ZEND_HASH_PACKED_REVERSE_FOREACH(ht); \
1504 _h = _idx; \
1505 _ptr = Z_PTR_P(_z);
1506
1507 /* The following macros are useful to insert a sequence of new elements
1508 * of packed array. They may be used instead of series of
1509 * zend_hash_next_index_insert_new()
1510 * (HashTable must have enough free buckets).
1511 */
1512 #define ZEND_HASH_FILL_PACKED(ht) do { \
1513 HashTable *__fill_ht = (ht); \
1514 zval *__fill_val = __fill_ht->arPacked + __fill_ht->nNumUsed; \
1515 uint32_t __fill_idx = __fill_ht->nNumUsed; \
1516 ZEND_ASSERT(HT_IS_PACKED(__fill_ht));
1517
1518 #define ZEND_HASH_FILL_GROW() do { \
1519 if (UNEXPECTED(__fill_idx >= __fill_ht->nTableSize)) { \
1520 __fill_ht->nNumOfElements += __fill_idx - __fill_ht->nNumUsed; \
1521 __fill_ht->nNumUsed = __fill_idx; \
1522 __fill_ht->nNextFreeElement = __fill_idx; \
1523 zend_hash_packed_grow(__fill_ht); \
1524 __fill_val = __fill_ht->arPacked + __fill_idx; \
1525 } \
1526 } while (0);
1527
1528 #define ZEND_HASH_FILL_SET(_val) \
1529 ZVAL_COPY_VALUE(__fill_val, _val)
1530
1531 #define ZEND_HASH_FILL_SET_NULL() \
1532 ZVAL_NULL(__fill_val)
1533
1534 #define ZEND_HASH_FILL_SET_LONG(_val) \
1535 ZVAL_LONG(__fill_val, _val)
1536
1537 #define ZEND_HASH_FILL_SET_DOUBLE(_val) \
1538 ZVAL_DOUBLE(__fill_val, _val)
1539
1540 #define ZEND_HASH_FILL_SET_STR(_val) \
1541 ZVAL_STR(__fill_val, _val)
1542
1543 #define ZEND_HASH_FILL_SET_STR_COPY(_val) \
1544 ZVAL_STR_COPY(__fill_val, _val)
1545
1546 #define ZEND_HASH_FILL_SET_INTERNED_STR(_val) \
1547 ZVAL_INTERNED_STR(__fill_val, _val)
1548
1549 #define ZEND_HASH_FILL_NEXT() do {\
1550 __fill_val++; \
1551 __fill_idx++; \
1552 } while (0)
1553
1554 #define ZEND_HASH_FILL_ADD(_val) do { \
1555 ZEND_HASH_FILL_SET(_val); \
1556 ZEND_HASH_FILL_NEXT(); \
1557 } while (0)
1558
1559 #define ZEND_HASH_FILL_FINISH() do { \
1560 __fill_ht->nNumOfElements += __fill_idx - __fill_ht->nNumUsed; \
1561 __fill_ht->nNumUsed = __fill_idx; \
1562 __fill_ht->nNextFreeElement = __fill_idx; \
1563 __fill_ht->nInternalPointer = 0; \
1564 } while (0)
1565
1566 #define ZEND_HASH_FILL_END() \
1567 ZEND_HASH_FILL_FINISH(); \
1568 } while (0)
1569
1570 /* Check if an array is a list */
zend_array_is_list(zend_array * array)1571 static zend_always_inline bool zend_array_is_list(zend_array *array)
1572 {
1573 zend_ulong expected_idx = 0;
1574 zend_ulong num_idx;
1575 zend_string* str_idx;
1576 /* Empty arrays are lists */
1577 if (zend_hash_num_elements(array) == 0) {
1578 return 1;
1579 }
1580
1581 /* Packed arrays are lists */
1582 if (HT_IS_PACKED(array)) {
1583 if (HT_IS_WITHOUT_HOLES(array)) {
1584 return 1;
1585 }
1586 /* Check if the list could theoretically be repacked */
1587 ZEND_HASH_PACKED_FOREACH_KEY(array, num_idx) {
1588 if (num_idx != expected_idx++) {
1589 return 0;
1590 }
1591 } ZEND_HASH_FOREACH_END();
1592 } else {
1593 /* Check if the list could theoretically be repacked */
1594 ZEND_HASH_MAP_FOREACH_KEY(array, num_idx, str_idx) {
1595 if (str_idx != NULL || num_idx != expected_idx++) {
1596 return 0;
1597 }
1598 } ZEND_HASH_FOREACH_END();
1599 }
1600
1601 return 1;
1602 }
1603
1604
_zend_hash_append_ex(HashTable * ht,zend_string * key,zval * zv,bool interned)1605 static zend_always_inline zval *_zend_hash_append_ex(HashTable *ht, zend_string *key, zval *zv, bool interned)
1606 {
1607 uint32_t idx = ht->nNumUsed++;
1608 uint32_t nIndex;
1609 Bucket *p = ht->arData + idx;
1610
1611 ZVAL_COPY_VALUE(&p->val, zv);
1612 if (!interned && !ZSTR_IS_INTERNED(key)) {
1613 HT_FLAGS(ht) &= ~HASH_FLAG_STATIC_KEYS;
1614 zend_string_addref(key);
1615 zend_string_hash_val(key);
1616 }
1617 p->key = key;
1618 p->h = ZSTR_H(key);
1619 nIndex = (uint32_t)p->h | ht->nTableMask;
1620 Z_NEXT(p->val) = HT_HASH(ht, nIndex);
1621 HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(idx);
1622 ht->nNumOfElements++;
1623 return &p->val;
1624 }
1625
_zend_hash_append(HashTable * ht,zend_string * key,zval * zv)1626 static zend_always_inline zval *_zend_hash_append(HashTable *ht, zend_string *key, zval *zv)
1627 {
1628 return _zend_hash_append_ex(ht, key, zv, 0);
1629 }
1630
_zend_hash_append_ptr_ex(HashTable * ht,zend_string * key,void * ptr,bool interned)1631 static zend_always_inline zval *_zend_hash_append_ptr_ex(HashTable *ht, zend_string *key, void *ptr, bool interned)
1632 {
1633 uint32_t idx = ht->nNumUsed++;
1634 uint32_t nIndex;
1635 Bucket *p = ht->arData + idx;
1636
1637 ZVAL_PTR(&p->val, ptr);
1638 if (!interned && !ZSTR_IS_INTERNED(key)) {
1639 HT_FLAGS(ht) &= ~HASH_FLAG_STATIC_KEYS;
1640 zend_string_addref(key);
1641 zend_string_hash_val(key);
1642 }
1643 p->key = key;
1644 p->h = ZSTR_H(key);
1645 nIndex = (uint32_t)p->h | ht->nTableMask;
1646 Z_NEXT(p->val) = HT_HASH(ht, nIndex);
1647 HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(idx);
1648 ht->nNumOfElements++;
1649 return &p->val;
1650 }
1651
_zend_hash_append_ptr(HashTable * ht,zend_string * key,void * ptr)1652 static zend_always_inline zval *_zend_hash_append_ptr(HashTable *ht, zend_string *key, void *ptr)
1653 {
1654 return _zend_hash_append_ptr_ex(ht, key, ptr, 0);
1655 }
1656
_zend_hash_append_ind(HashTable * ht,zend_string * key,zval * ptr)1657 static zend_always_inline void _zend_hash_append_ind(HashTable *ht, zend_string *key, zval *ptr)
1658 {
1659 uint32_t idx = ht->nNumUsed++;
1660 uint32_t nIndex;
1661 Bucket *p = ht->arData + idx;
1662
1663 ZVAL_INDIRECT(&p->val, ptr);
1664 if (!ZSTR_IS_INTERNED(key)) {
1665 HT_FLAGS(ht) &= ~HASH_FLAG_STATIC_KEYS;
1666 zend_string_addref(key);
1667 zend_string_hash_val(key);
1668 }
1669 p->key = key;
1670 p->h = ZSTR_H(key);
1671 nIndex = (uint32_t)p->h | ht->nTableMask;
1672 Z_NEXT(p->val) = HT_HASH(ht, nIndex);
1673 HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(idx);
1674 ht->nNumOfElements++;
1675 }
1676
1677 #endif /* ZEND_HASH_H */
1678