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