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