xref: /PHP-8.1/Zend/zend_hash.h (revision 8356da60)
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