php-src/Zend/zend_hash.h

1695 lines
51 KiB
C
Raw Permalink Normal View History

1999-04-08 02:10:10 +08:00
/*
+----------------------------------------------------------------------+
| Zend Engine |
+----------------------------------------------------------------------+
2019-01-30 17:23:29 +08:00
| Copyright (c) Zend Technologies Ltd. (http://www.zend.com) |
1999-04-08 02:10:10 +08:00
+----------------------------------------------------------------------+
2001-12-11 23:16:21 +08:00
| This source file is subject to version 2.00 of the Zend license, |
2015-01-03 17:22:58 +08:00
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
2001-12-11 23:16:21 +08:00
| http://www.zend.com/license/2_00.txt. |
1999-07-16 22:58:16 +08:00
| If you did not receive a copy of the Zend license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@zend.com so we can mail you a copy immediately. |
1999-04-08 02:10:10 +08:00
+----------------------------------------------------------------------+
| Authors: Andi Gutmans <andi@php.net> |
| Zeev Suraski <zeev@php.net> |
| Dmitry Stogov <dmitry@php.net> |
1999-04-08 02:10:10 +08:00
+----------------------------------------------------------------------+
*/
#ifndef ZEND_HASH_H
#define ZEND_HASH_H
1999-04-08 02:10:10 +08:00
#include "zend_types.h"
#include "zend_gc.h"
#include "zend_string.h"
#include "zend_sort.h"
1999-04-08 02:10:10 +08:00
#define HASH_KEY_IS_STRING 1
2014-08-26 01:24:55 +08:00
#define HASH_KEY_IS_LONG 2
2013-07-09 05:09:06 +08:00
#define HASH_KEY_NON_EXISTENT 3
1999-04-08 02:10:10 +08:00
#define HASH_UPDATE (1<<0) /* Create new entry, or update the existing one. */
#define HASH_ADD (1<<1) /* Create new entry, or fail if it exists. */
#define HASH_UPDATE_INDIRECT (1<<2) /* If the given ht entry is an indirect zval, unwrap it before writing to it. \
* When used with HASH_ADD, writing is allowed if the target zval is IS_UNDEF. */
#define HASH_ADD_NEW (1<<3) /* Used when the offset is known not to exist. */
#define HASH_ADD_NEXT (1<<4) /* Append to an array. (e.g. $array[] = 42;) */
#define HASH_LOOKUP (1<<5) /* Look up an existing entry, or create one with a NULL value. */
1999-04-08 02:10:10 +08:00
#define HASH_FLAG_CONSISTENCY ((1<<0) | (1<<1))
#define HASH_FLAG_PACKED (1<<2)
#define HASH_FLAG_UNINITIALIZED (1<<3)
#define HASH_FLAG_STATIC_KEYS (1<<4) /* long and interned strings */
#define HASH_FLAG_HAS_EMPTY_IND (1<<5)
#define HASH_FLAG_ALLOW_COW_VIOLATION (1<<6)
/* Only the low byte are real flags */
#define HASH_FLAG_MASK 0xff
#define HT_FLAGS(ht) (ht)->u.flags
#define HT_INVALIDATE(ht) do { \
HT_FLAGS(ht) = HASH_FLAG_UNINITIALIZED; \
} while (0)
#define HT_IS_INITIALIZED(ht) \
((HT_FLAGS(ht) & HASH_FLAG_UNINITIALIZED) == 0)
#define HT_IS_PACKED(ht) \
((HT_FLAGS(ht) & HASH_FLAG_PACKED) != 0)
#define HT_IS_WITHOUT_HOLES(ht) \
((ht)->nNumUsed == (ht)->nNumOfElements)
#define HT_HAS_STATIC_KEYS_ONLY(ht) \
((HT_FLAGS(ht) & (HASH_FLAG_PACKED|HASH_FLAG_STATIC_KEYS)) != 0)
#if ZEND_DEBUG
# define HT_ALLOW_COW_VIOLATION(ht) HT_FLAGS(ht) |= HASH_FLAG_ALLOW_COW_VIOLATION
#else
# define HT_ALLOW_COW_VIOLATION(ht)
#endif
#define HT_ITERATORS_COUNT(ht) (ht)->u.v.nIteratorsCount
#define HT_ITERATORS_OVERFLOW(ht) (HT_ITERATORS_COUNT(ht) == 0xff)
#define HT_HAS_ITERATORS(ht) (HT_ITERATORS_COUNT(ht) != 0)
#define HT_SET_ITERATORS_COUNT(ht, iters) \
do { HT_ITERATORS_COUNT(ht) = (iters); } while (0)
#define HT_INC_ITERATORS_COUNT(ht) \
HT_SET_ITERATORS_COUNT(ht, HT_ITERATORS_COUNT(ht) + 1)
#define HT_DEC_ITERATORS_COUNT(ht) \
HT_SET_ITERATORS_COUNT(ht, HT_ITERATORS_COUNT(ht) - 1)
extern ZEND_API const HashTable zend_empty_array;
#define ZVAL_EMPTY_ARRAY(z) do { \
zval *__z = (z); \
Z_ARR_P(__z) = (zend_array*)&zend_empty_array; \
2018-01-19 22:47:26 +08:00
Z_TYPE_INFO_P(__z) = IS_ARRAY; \
} while (0)
2003-02-04 20:12:34 +08:00
typedef struct _zend_hash_key {
zend_ulong h;
zend_string *key;
2003-02-04 20:12:34 +08:00
} zend_hash_key;
typedef bool (*merge_checker_func_t)(HashTable *target_ht, zval *source_data, zend_hash_key *hash_key, void *pParam);
2003-02-04 20:12:34 +08:00
1999-06-08 06:49:33 +08:00
BEGIN_EXTERN_C()
1999-04-08 02:10:10 +08:00
/* startup/shutdown */
ZEND_API void ZEND_FASTCALL _zend_hash_init(HashTable *ht, uint32_t nSize, dtor_func_t pDestructor, bool persistent);
ZEND_API void ZEND_FASTCALL zend_hash_destroy(HashTable *ht);
ZEND_API void ZEND_FASTCALL zend_hash_clean(HashTable *ht);
#define zend_hash_init(ht, nSize, pHashFunction, pDestructor, persistent) \
_zend_hash_init((ht), (nSize), (pDestructor), (persistent))
1999-04-08 02:10:10 +08:00
ZEND_API void ZEND_FASTCALL zend_hash_real_init(HashTable *ht, bool packed);
2018-03-23 05:13:45 +08:00
ZEND_API void ZEND_FASTCALL zend_hash_real_init_packed(HashTable *ht);
ZEND_API void ZEND_FASTCALL zend_hash_real_init_mixed(HashTable *ht);
ZEND_API void ZEND_FASTCALL zend_hash_packed_to_hash(HashTable *ht);
ZEND_API void ZEND_FASTCALL zend_hash_to_packed(HashTable *ht);
ZEND_API void ZEND_FASTCALL zend_hash_extend(HashTable *ht, uint32_t nSize, bool packed);
2018-07-17 22:31:04 +08:00
ZEND_API void ZEND_FASTCALL zend_hash_discard(HashTable *ht, uint32_t nNumUsed);
ZEND_API void ZEND_FASTCALL zend_hash_packed_grow(HashTable *ht);
/* additions/updates/changes */
ZEND_API zval* ZEND_FASTCALL zend_hash_add_or_update(HashTable *ht, zend_string *key, zval *pData, uint32_t flag);
ZEND_API zval* ZEND_FASTCALL zend_hash_update(HashTable *ht, zend_string *key,zval *pData);
ZEND_API zval* ZEND_FASTCALL zend_hash_update_ind(HashTable *ht, zend_string *key,zval *pData);
ZEND_API zval* ZEND_FASTCALL zend_hash_add(HashTable *ht, zend_string *key,zval *pData);
ZEND_API zval* ZEND_FASTCALL zend_hash_add_new(HashTable *ht, zend_string *key,zval *pData);
ZEND_API zval* ZEND_FASTCALL zend_hash_str_add_or_update(HashTable *ht, const char *key, size_t len, zval *pData, uint32_t flag);
ZEND_API zval* ZEND_FASTCALL zend_hash_str_update(HashTable *ht, const char *key, size_t len, zval *pData);
ZEND_API zval* ZEND_FASTCALL zend_hash_str_update_ind(HashTable *ht, const char *key, size_t len, zval *pData);
ZEND_API zval* ZEND_FASTCALL zend_hash_str_add(HashTable *ht, const char *key, size_t len, zval *pData);
ZEND_API zval* ZEND_FASTCALL zend_hash_str_add_new(HashTable *ht, const char *key, size_t len, zval *pData);
ZEND_API zval* ZEND_FASTCALL zend_hash_index_add_or_update(HashTable *ht, zend_ulong h, zval *pData, uint32_t flag);
ZEND_API zval* ZEND_FASTCALL zend_hash_index_add(HashTable *ht, zend_ulong h, zval *pData);
ZEND_API zval* ZEND_FASTCALL zend_hash_index_add_new(HashTable *ht, zend_ulong h, zval *pData);
ZEND_API zval* ZEND_FASTCALL zend_hash_index_update(HashTable *ht, zend_ulong h, zval *pData);
ZEND_API zval* ZEND_FASTCALL zend_hash_next_index_insert(HashTable *ht, zval *pData);
ZEND_API zval* ZEND_FASTCALL zend_hash_next_index_insert_new(HashTable *ht, zval *pData);
ZEND_API zval* ZEND_FASTCALL zend_hash_index_add_empty_element(HashTable *ht, zend_ulong h);
ZEND_API zval* ZEND_FASTCALL zend_hash_add_empty_element(HashTable *ht, zend_string *key);
ZEND_API zval* ZEND_FASTCALL zend_hash_str_add_empty_element(HashTable *ht, const char *key, size_t len);
ZEND_API zval* ZEND_FASTCALL zend_hash_set_bucket_key(HashTable *ht, Bucket *p, zend_string *key);
#define ZEND_HASH_APPLY_KEEP 0
#define ZEND_HASH_APPLY_REMOVE 1<<0
#define ZEND_HASH_APPLY_STOP 1<<1
2014-12-14 06:06:14 +08:00
typedef int (*apply_func_t)(zval *pDest);
typedef int (*apply_func_arg_t)(zval *pDest, void *argument);
typedef int (*apply_func_args_t)(zval *pDest, int num_args, va_list args, zend_hash_key *hash_key);
ZEND_API void ZEND_FASTCALL zend_hash_graceful_destroy(HashTable *ht);
ZEND_API void ZEND_FASTCALL zend_hash_graceful_reverse_destroy(HashTable *ht);
ZEND_API void ZEND_FASTCALL zend_hash_apply(HashTable *ht, apply_func_t apply_func);
ZEND_API void ZEND_FASTCALL zend_hash_apply_with_argument(HashTable *ht, apply_func_arg_t apply_func, void *);
ZEND_API void zend_hash_apply_with_arguments(HashTable *ht, apply_func_args_t apply_func, int, ...);
1999-08-26 03:02:13 +08:00
/* This function should be used with special care (in other words,
* it should usually not be used). When used with the ZEND_HASH_APPLY_STOP
* return value, it assumes things about the order of the elements in the hash.
* Also, it does not provide the same kind of reentrancy protection that
* the standard apply functions do.
*/
ZEND_API void ZEND_FASTCALL zend_hash_reverse_apply(HashTable *ht, apply_func_t apply_func);
1999-04-08 02:10:10 +08:00
/* Deletes */
ZEND_API zend_result ZEND_FASTCALL zend_hash_del(HashTable *ht, zend_string *key);
ZEND_API zend_result ZEND_FASTCALL zend_hash_del_ind(HashTable *ht, zend_string *key);
ZEND_API zend_result ZEND_FASTCALL zend_hash_str_del(HashTable *ht, const char *key, size_t len);
ZEND_API zend_result ZEND_FASTCALL zend_hash_str_del_ind(HashTable *ht, const char *key, size_t len);
ZEND_API zend_result ZEND_FASTCALL zend_hash_index_del(HashTable *ht, zend_ulong h);
ZEND_API void ZEND_FASTCALL zend_hash_del_bucket(HashTable *ht, Bucket *p);
ZEND_API void ZEND_FASTCALL zend_hash_packed_del_val(HashTable *ht, zval *zv);
1999-04-08 02:10:10 +08:00
/* Data retrieval */
ZEND_API zval* ZEND_FASTCALL zend_hash_find(const HashTable *ht, zend_string *key);
ZEND_API zval* ZEND_FASTCALL zend_hash_str_find(const HashTable *ht, const char *key, size_t len);
ZEND_API zval* ZEND_FASTCALL zend_hash_index_find(const HashTable *ht, zend_ulong h);
2016-05-04 22:33:35 +08:00
ZEND_API zval* ZEND_FASTCALL _zend_hash_index_find(const HashTable *ht, zend_ulong h);
/* The same as zend_hash_find(), but hash value of the key must be already calculated. */
ZEND_API zval* ZEND_FASTCALL zend_hash_find_known_hash(const HashTable *ht, const zend_string *key);
static zend_always_inline zval *zend_hash_find_ex(const HashTable *ht, zend_string *key, bool known_hash)
{
if (known_hash) {
return zend_hash_find_known_hash(ht, key);
} else {
return zend_hash_find(ht, key);
}
}
2016-05-04 22:33:35 +08:00
#define ZEND_HASH_INDEX_FIND(_ht, _h, _ret, _not_found) do { \
if (EXPECTED(HT_IS_PACKED(_ht))) { \
2016-06-21 21:55:17 +08:00
if (EXPECTED((zend_ulong)(_h) < (zend_ulong)(_ht)->nNumUsed)) { \
_ret = &_ht->arPacked[_h]; \
2016-05-04 22:33:35 +08:00
if (UNEXPECTED(Z_TYPE_P(_ret) == IS_UNDEF)) { \
goto _not_found; \
} \
} else { \
goto _not_found; \
} \
} else { \
_ret = _zend_hash_index_find(_ht, _h); \
if (UNEXPECTED(_ret == NULL)) { \
goto _not_found; \
} \
} \
} while (0)
1999-04-08 02:10:10 +08:00
/* Find or add NULL, if doesn't exist */
ZEND_API zval* ZEND_FASTCALL zend_hash_lookup(HashTable *ht, zend_string *key);
ZEND_API zval* ZEND_FASTCALL zend_hash_index_lookup(HashTable *ht, zend_ulong h);
#define ZEND_HASH_INDEX_LOOKUP(_ht, _h, _ret) do { \
if (EXPECTED(HT_IS_PACKED(_ht))) { \
if (EXPECTED((zend_ulong)(_h) < (zend_ulong)(_ht)->nNumUsed)) { \
_ret = &_ht->arPacked[_h]; \
if (EXPECTED(Z_TYPE_P(_ret) != IS_UNDEF)) { \
break; \
} \
} \
} \
_ret = zend_hash_index_lookup(_ht, _h); \
} while (0)
1999-04-08 02:10:10 +08:00
/* Misc */
static zend_always_inline bool zend_hash_exists(const HashTable *ht, zend_string *key)
{
return zend_hash_find(ht, key) != NULL;
}
static zend_always_inline bool zend_hash_str_exists(const HashTable *ht, const char *str, size_t len)
{
return zend_hash_str_find(ht, str, len) != NULL;
}
static zend_always_inline bool zend_hash_index_exists(const HashTable *ht, zend_ulong h)
{
return zend_hash_index_find(ht, h) != NULL;
}
1999-04-08 02:10:10 +08:00
/* traversing */
ZEND_API HashPosition ZEND_FASTCALL zend_hash_get_current_pos_ex(const HashTable *ht, HashPosition pos);
ZEND_API HashPosition ZEND_FASTCALL zend_hash_get_current_pos(const HashTable *ht);
ZEND_API zend_result ZEND_FASTCALL zend_hash_move_forward_ex(const HashTable *ht, HashPosition *pos);
ZEND_API zend_result ZEND_FASTCALL zend_hash_move_backwards_ex(const HashTable *ht, HashPosition *pos);
ZEND_API int ZEND_FASTCALL zend_hash_get_current_key_ex(const HashTable *ht, zend_string **str_index, zend_ulong *num_index, const HashPosition *pos);
ZEND_API void ZEND_FASTCALL zend_hash_get_current_key_zval_ex(const HashTable *ht, zval *key, const HashPosition *pos);
ZEND_API int ZEND_FASTCALL zend_hash_get_current_key_type_ex(const HashTable *ht, const HashPosition *pos);
ZEND_API zval* ZEND_FASTCALL zend_hash_get_current_data_ex(const HashTable *ht, const HashPosition *pos);
ZEND_API void ZEND_FASTCALL zend_hash_internal_pointer_reset_ex(const HashTable *ht, HashPosition *pos);
ZEND_API void ZEND_FASTCALL zend_hash_internal_pointer_end_ex(const HashTable *ht, HashPosition *pos);
static zend_always_inline zend_result zend_hash_has_more_elements_ex(const HashTable *ht, const HashPosition *pos) {
return (zend_hash_get_current_key_type_ex(ht, pos) == HASH_KEY_NON_EXISTENT ? FAILURE : SUCCESS);
}
static zend_always_inline zend_result zend_hash_has_more_elements(HashTable *ht) {
return zend_hash_has_more_elements_ex(ht, &ht->nInternalPointer);
}
static zend_always_inline zend_result zend_hash_move_forward(HashTable *ht) {
return zend_hash_move_forward_ex(ht, &ht->nInternalPointer);
}
static zend_always_inline zend_result zend_hash_move_backwards(HashTable *ht) {
return zend_hash_move_backwards_ex(ht, &ht->nInternalPointer);
}
static zend_always_inline int zend_hash_get_current_key(const HashTable *ht, zend_string **str_index, zend_ulong *num_index) {
return zend_hash_get_current_key_ex(ht, str_index, num_index, &ht->nInternalPointer);
}
static zend_always_inline void zend_hash_get_current_key_zval(const HashTable *ht, zval *key) {
zend_hash_get_current_key_zval_ex(ht, key, &ht->nInternalPointer);
}
static zend_always_inline int zend_hash_get_current_key_type(const HashTable *ht) {
return zend_hash_get_current_key_type_ex(ht, &ht->nInternalPointer);
}
static zend_always_inline zval* zend_hash_get_current_data(const HashTable *ht) {
return zend_hash_get_current_data_ex(ht, &ht->nInternalPointer);
}
static zend_always_inline void zend_hash_internal_pointer_reset(HashTable *ht) {
zend_hash_internal_pointer_reset_ex(ht, &ht->nInternalPointer);
}
static zend_always_inline void zend_hash_internal_pointer_end(HashTable *ht) {
zend_hash_internal_pointer_end_ex(ht, &ht->nInternalPointer);
}
1999-04-08 02:10:10 +08:00
/* Copying, merging and sorting */
ZEND_API void ZEND_FASTCALL zend_hash_copy(HashTable *target, const HashTable *source, copy_ctor_func_t pCopyConstructor);
ZEND_API void ZEND_FASTCALL zend_hash_merge(HashTable *target, const HashTable *source, copy_ctor_func_t pCopyConstructor, bool overwrite);
ZEND_API void ZEND_FASTCALL zend_hash_merge_ex(HashTable *target, const HashTable *source, copy_ctor_func_t pCopyConstructor, merge_checker_func_t pMergeSource, void *pParam);
ZEND_API void zend_hash_bucket_swap(Bucket *p, Bucket *q);
ZEND_API void zend_hash_bucket_renum_swap(Bucket *p, Bucket *q);
ZEND_API void zend_hash_bucket_packed_swap(Bucket *p, Bucket *q);
typedef int (*bucket_compare_func_t)(Bucket *a, Bucket *b);
ZEND_API int zend_hash_compare(HashTable *ht1, HashTable *ht2, compare_func_t compar, bool ordered);
ZEND_API void ZEND_FASTCALL zend_hash_sort_ex(HashTable *ht, sort_func_t sort_func, bucket_compare_func_t compare_func, bool renumber);
ZEND_API void ZEND_FASTCALL zend_array_sort_ex(HashTable *ht, sort_func_t sort_func, bucket_compare_func_t compare_func, bool renumber);
ZEND_API zval* ZEND_FASTCALL zend_hash_minmax(const HashTable *ht, compare_func_t compar, uint32_t flag);
1999-04-08 02:10:10 +08:00
static zend_always_inline void ZEND_FASTCALL zend_hash_sort(HashTable *ht, bucket_compare_func_t compare_func, bool renumber) {
zend_hash_sort_ex(ht, zend_sort, compare_func, renumber);
}
2015-01-14 17:22:58 +08:00
/* Use this variant over zend_hash_sort() when sorting user arrays that may
* trigger user code. It will ensure the user code cannot free the array during
* sorting. */
static zend_always_inline void zend_array_sort(HashTable *ht, bucket_compare_func_t compare_func, bool renumber) {
zend_array_sort_ex(ht, zend_sort, compare_func, renumber);
}
static zend_always_inline uint32_t zend_hash_num_elements(const HashTable *ht) {
return ht->nNumOfElements;
}
static zend_always_inline zend_long zend_hash_next_free_element(const HashTable *ht) {
return ht->nNextFreeElement;
}
1999-04-08 02:10:10 +08:00
ZEND_API void ZEND_FASTCALL zend_hash_rehash(HashTable *ht);
1999-04-08 02:10:10 +08:00
#if !ZEND_DEBUG && defined(HAVE_BUILTIN_CONSTANT_P)
# define zend_new_array(size) \
(__builtin_constant_p(size) ? \
((((uint32_t)(size)) <= HT_MIN_SIZE) ? \
_zend_new_array_0() \
: \
_zend_new_array((size)) \
) \
: \
_zend_new_array((size)) \
)
#else
# define zend_new_array(size) \
_zend_new_array(size)
#endif
ZEND_API HashTable* ZEND_FASTCALL _zend_new_array_0(void);
ZEND_API HashTable* ZEND_FASTCALL _zend_new_array(uint32_t size);
ZEND_API HashTable* ZEND_FASTCALL zend_new_pair(const zval *val1, const zval *val2);
ZEND_API uint32_t zend_array_count(HashTable *ht);
ZEND_API HashTable* ZEND_FASTCALL zend_array_dup(const HashTable *source);
ZEND_API void ZEND_FASTCALL zend_array_destroy(HashTable *ht);
ZEND_API HashTable* zend_array_to_list(const HashTable *source);
ZEND_API void ZEND_FASTCALL zend_symtable_clean(HashTable *ht);
ZEND_API HashTable* ZEND_FASTCALL zend_symtable_to_proptable(HashTable *ht);
ZEND_API HashTable* ZEND_FASTCALL zend_proptable_to_symtable(HashTable *ht, bool always_duplicate);
ZEND_API bool ZEND_FASTCALL _zend_handle_numeric_str_ex(const char *key, size_t length, zend_ulong *idx);
1999-04-08 02:10:10 +08:00
ZEND_API uint32_t ZEND_FASTCALL zend_hash_iterator_add(HashTable *ht, HashPosition pos);
ZEND_API HashPosition ZEND_FASTCALL zend_hash_iterator_pos(uint32_t idx, HashTable *ht);
ZEND_API HashPosition ZEND_FASTCALL zend_hash_iterator_pos_ex(uint32_t idx, zval *array);
ZEND_API void ZEND_FASTCALL zend_hash_iterator_del(uint32_t idx);
ZEND_API HashPosition ZEND_FASTCALL zend_hash_iterators_lower_pos(const HashTable *ht, HashPosition start);
ZEND_API void ZEND_FASTCALL _zend_hash_iterators_update(const HashTable *ht, HashPosition from, HashPosition to);
ZEND_API void ZEND_FASTCALL zend_hash_iterators_advance(const HashTable *ht, HashPosition step);
Fix "forech" statemt behaviour according to https://wiki.php.net/rfc/php7_foreach Squashed commit of the following: commit 1e41295097576dbce6c197ddb7507c07ccae3cbe Author: Dmitry Stogov <dmitry@zend.com> Date: Sat Jan 31 07:28:58 2015 +0300 Generalize HashTableIterator API to allows its usage without involvement of HashTable.nInternalPonter commit 5406f21b11e563069d64045e599693b51c444b63 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jan 30 18:08:43 2015 +0300 Reduced alghorithms complexity commit b37f1d58d2a141b6e1d980a461ccb588d4317d2e Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jan 30 18:08:30 2015 +0300 Fixed test name commit fb2d079645829b12ed4e55a461034df6400bc430 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jan 30 18:08:05 2015 +0300 API cleanup commit 08302c0d6d1cab279b9f2129df03a057baddf2ff Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jan 30 14:20:46 2015 +0300 Make array_splice() to preserve foreach hash position commit cc4b7be41e2e2b9b0d7a3c8e98466b8886692e6e Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jan 30 12:24:31 2015 +0300 Make internal function, operation on array passed by reference, to preserve foreach hash position commit 5aa9712b0a30303aadfe3bdd8ae1f072ca3e6ba1 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jan 30 09:49:35 2015 +0300 Implement consistent behavior for foreach by value over plain object commit 4c5b385ff53ae9f0b52572e98c4db801f56603b0 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jan 30 07:56:37 2015 +0300 More careful iterators update. commit 721fc9e80d2ee8f2cd79c8c3cdceffae2c72de92 Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Jan 29 21:43:28 2015 +0300 Added new test commit 15a23b1218b3e38630d677751a975907daa2cd54 Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Jan 29 21:05:02 2015 +0300 Reimplement iteration magic with HashTableIterators (see https://wiki.php.net/rfc/php7_foreach#implementation_details) commit 10a3260b1f16b6075fd8140f673dfef4d5efea91 Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Jan 29 21:04:44 2015 +0300 New test commit eef80c583762d1e98d177cdbb27e3a8a6b0c4539 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jan 28 16:52:21 2015 +0300 Fixed foreach by reference iteration over constant array commit 61e739187391661e2d541947bec25d7dcc4479f3 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jan 28 14:59:54 2015 +0300 Fixed temporary variable re-allocation pass commit 92e90c09f085c22707ff4a59201f016f56e0ef8b Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jan 28 12:44:57 2015 +0300 Fixed operand destruction in case of exceptions in iterator commit dd2a36a2074bbb0cb31de00b66dcf2812d6d753f Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jan 28 10:02:34 2015 +0300 Use GET_OP1_ZVAL_PTR_DEREF() (IS_TMP_VAR and IS_CONST can't be IS_REFERENCE) commit 4638f7b91407c48710007af82a68da0007c820f2 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jan 28 07:43:28 2015 +0300 Change "foreach" statement behavior (this is just a PoC yet) - "foreach by value" don't relay on internal array/object pointer and doesnt perform array duplication. It just locks it incrementing reference counter. If the original array is modified by some code, the copy on write is performed and "foreach" still work with the old copy. - it makes no difference if array given to "foreach by value" is reference itself - "foreach by reference" still use internal array/object pointer and should work similar to PHP-5. (This id not completely implemented)
2015-02-12 18:57:12 +08:00
static zend_always_inline void zend_hash_iterators_update(const HashTable *ht, HashPosition from, HashPosition to)
Fix "forech" statemt behaviour according to https://wiki.php.net/rfc/php7_foreach Squashed commit of the following: commit 1e41295097576dbce6c197ddb7507c07ccae3cbe Author: Dmitry Stogov <dmitry@zend.com> Date: Sat Jan 31 07:28:58 2015 +0300 Generalize HashTableIterator API to allows its usage without involvement of HashTable.nInternalPonter commit 5406f21b11e563069d64045e599693b51c444b63 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jan 30 18:08:43 2015 +0300 Reduced alghorithms complexity commit b37f1d58d2a141b6e1d980a461ccb588d4317d2e Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jan 30 18:08:30 2015 +0300 Fixed test name commit fb2d079645829b12ed4e55a461034df6400bc430 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jan 30 18:08:05 2015 +0300 API cleanup commit 08302c0d6d1cab279b9f2129df03a057baddf2ff Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jan 30 14:20:46 2015 +0300 Make array_splice() to preserve foreach hash position commit cc4b7be41e2e2b9b0d7a3c8e98466b8886692e6e Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jan 30 12:24:31 2015 +0300 Make internal function, operation on array passed by reference, to preserve foreach hash position commit 5aa9712b0a30303aadfe3bdd8ae1f072ca3e6ba1 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jan 30 09:49:35 2015 +0300 Implement consistent behavior for foreach by value over plain object commit 4c5b385ff53ae9f0b52572e98c4db801f56603b0 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jan 30 07:56:37 2015 +0300 More careful iterators update. commit 721fc9e80d2ee8f2cd79c8c3cdceffae2c72de92 Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Jan 29 21:43:28 2015 +0300 Added new test commit 15a23b1218b3e38630d677751a975907daa2cd54 Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Jan 29 21:05:02 2015 +0300 Reimplement iteration magic with HashTableIterators (see https://wiki.php.net/rfc/php7_foreach#implementation_details) commit 10a3260b1f16b6075fd8140f673dfef4d5efea91 Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Jan 29 21:04:44 2015 +0300 New test commit eef80c583762d1e98d177cdbb27e3a8a6b0c4539 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jan 28 16:52:21 2015 +0300 Fixed foreach by reference iteration over constant array commit 61e739187391661e2d541947bec25d7dcc4479f3 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jan 28 14:59:54 2015 +0300 Fixed temporary variable re-allocation pass commit 92e90c09f085c22707ff4a59201f016f56e0ef8b Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jan 28 12:44:57 2015 +0300 Fixed operand destruction in case of exceptions in iterator commit dd2a36a2074bbb0cb31de00b66dcf2812d6d753f Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jan 28 10:02:34 2015 +0300 Use GET_OP1_ZVAL_PTR_DEREF() (IS_TMP_VAR and IS_CONST can't be IS_REFERENCE) commit 4638f7b91407c48710007af82a68da0007c820f2 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jan 28 07:43:28 2015 +0300 Change "foreach" statement behavior (this is just a PoC yet) - "foreach by value" don't relay on internal array/object pointer and doesnt perform array duplication. It just locks it incrementing reference counter. If the original array is modified by some code, the copy on write is performed and "foreach" still work with the old copy. - it makes no difference if array given to "foreach by value" is reference itself - "foreach by reference" still use internal array/object pointer and should work similar to PHP-5. (This id not completely implemented)
2015-02-12 18:57:12 +08:00
{
if (UNEXPECTED(HT_HAS_ITERATORS(ht))) {
Fix "forech" statemt behaviour according to https://wiki.php.net/rfc/php7_foreach Squashed commit of the following: commit 1e41295097576dbce6c197ddb7507c07ccae3cbe Author: Dmitry Stogov <dmitry@zend.com> Date: Sat Jan 31 07:28:58 2015 +0300 Generalize HashTableIterator API to allows its usage without involvement of HashTable.nInternalPonter commit 5406f21b11e563069d64045e599693b51c444b63 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jan 30 18:08:43 2015 +0300 Reduced alghorithms complexity commit b37f1d58d2a141b6e1d980a461ccb588d4317d2e Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jan 30 18:08:30 2015 +0300 Fixed test name commit fb2d079645829b12ed4e55a461034df6400bc430 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jan 30 18:08:05 2015 +0300 API cleanup commit 08302c0d6d1cab279b9f2129df03a057baddf2ff Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jan 30 14:20:46 2015 +0300 Make array_splice() to preserve foreach hash position commit cc4b7be41e2e2b9b0d7a3c8e98466b8886692e6e Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jan 30 12:24:31 2015 +0300 Make internal function, operation on array passed by reference, to preserve foreach hash position commit 5aa9712b0a30303aadfe3bdd8ae1f072ca3e6ba1 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jan 30 09:49:35 2015 +0300 Implement consistent behavior for foreach by value over plain object commit 4c5b385ff53ae9f0b52572e98c4db801f56603b0 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jan 30 07:56:37 2015 +0300 More careful iterators update. commit 721fc9e80d2ee8f2cd79c8c3cdceffae2c72de92 Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Jan 29 21:43:28 2015 +0300 Added new test commit 15a23b1218b3e38630d677751a975907daa2cd54 Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Jan 29 21:05:02 2015 +0300 Reimplement iteration magic with HashTableIterators (see https://wiki.php.net/rfc/php7_foreach#implementation_details) commit 10a3260b1f16b6075fd8140f673dfef4d5efea91 Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Jan 29 21:04:44 2015 +0300 New test commit eef80c583762d1e98d177cdbb27e3a8a6b0c4539 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jan 28 16:52:21 2015 +0300 Fixed foreach by reference iteration over constant array commit 61e739187391661e2d541947bec25d7dcc4479f3 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jan 28 14:59:54 2015 +0300 Fixed temporary variable re-allocation pass commit 92e90c09f085c22707ff4a59201f016f56e0ef8b Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jan 28 12:44:57 2015 +0300 Fixed operand destruction in case of exceptions in iterator commit dd2a36a2074bbb0cb31de00b66dcf2812d6d753f Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jan 28 10:02:34 2015 +0300 Use GET_OP1_ZVAL_PTR_DEREF() (IS_TMP_VAR and IS_CONST can't be IS_REFERENCE) commit 4638f7b91407c48710007af82a68da0007c820f2 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jan 28 07:43:28 2015 +0300 Change "foreach" statement behavior (this is just a PoC yet) - "foreach by value" don't relay on internal array/object pointer and doesnt perform array duplication. It just locks it incrementing reference counter. If the original array is modified by some code, the copy on write is performed and "foreach" still work with the old copy. - it makes no difference if array given to "foreach by value" is reference itself - "foreach by reference" still use internal array/object pointer and should work similar to PHP-5. (This id not completely implemented)
2015-02-12 18:57:12 +08:00
_zend_hash_iterators_update(ht, from, to);
}
}
/* For regular arrays (non-persistent, storing zvals). */
static zend_always_inline void zend_array_release(zend_array *array)
{
if (!(GC_FLAGS(array) & IS_ARRAY_IMMUTABLE)) {
if (GC_DELREF(array) == 0) {
zend_array_destroy(array);
}
}
}
Fix "forech" statemt behaviour according to https://wiki.php.net/rfc/php7_foreach Squashed commit of the following: commit 1e41295097576dbce6c197ddb7507c07ccae3cbe Author: Dmitry Stogov <dmitry@zend.com> Date: Sat Jan 31 07:28:58 2015 +0300 Generalize HashTableIterator API to allows its usage without involvement of HashTable.nInternalPonter commit 5406f21b11e563069d64045e599693b51c444b63 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jan 30 18:08:43 2015 +0300 Reduced alghorithms complexity commit b37f1d58d2a141b6e1d980a461ccb588d4317d2e Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jan 30 18:08:30 2015 +0300 Fixed test name commit fb2d079645829b12ed4e55a461034df6400bc430 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jan 30 18:08:05 2015 +0300 API cleanup commit 08302c0d6d1cab279b9f2129df03a057baddf2ff Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jan 30 14:20:46 2015 +0300 Make array_splice() to preserve foreach hash position commit cc4b7be41e2e2b9b0d7a3c8e98466b8886692e6e Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jan 30 12:24:31 2015 +0300 Make internal function, operation on array passed by reference, to preserve foreach hash position commit 5aa9712b0a30303aadfe3bdd8ae1f072ca3e6ba1 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jan 30 09:49:35 2015 +0300 Implement consistent behavior for foreach by value over plain object commit 4c5b385ff53ae9f0b52572e98c4db801f56603b0 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jan 30 07:56:37 2015 +0300 More careful iterators update. commit 721fc9e80d2ee8f2cd79c8c3cdceffae2c72de92 Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Jan 29 21:43:28 2015 +0300 Added new test commit 15a23b1218b3e38630d677751a975907daa2cd54 Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Jan 29 21:05:02 2015 +0300 Reimplement iteration magic with HashTableIterators (see https://wiki.php.net/rfc/php7_foreach#implementation_details) commit 10a3260b1f16b6075fd8140f673dfef4d5efea91 Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Jan 29 21:04:44 2015 +0300 New test commit eef80c583762d1e98d177cdbb27e3a8a6b0c4539 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jan 28 16:52:21 2015 +0300 Fixed foreach by reference iteration over constant array commit 61e739187391661e2d541947bec25d7dcc4479f3 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jan 28 14:59:54 2015 +0300 Fixed temporary variable re-allocation pass commit 92e90c09f085c22707ff4a59201f016f56e0ef8b Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jan 28 12:44:57 2015 +0300 Fixed operand destruction in case of exceptions in iterator commit dd2a36a2074bbb0cb31de00b66dcf2812d6d753f Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jan 28 10:02:34 2015 +0300 Use GET_OP1_ZVAL_PTR_DEREF() (IS_TMP_VAR and IS_CONST can't be IS_REFERENCE) commit 4638f7b91407c48710007af82a68da0007c820f2 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jan 28 07:43:28 2015 +0300 Change "foreach" statement behavior (this is just a PoC yet) - "foreach by value" don't relay on internal array/object pointer and doesnt perform array duplication. It just locks it incrementing reference counter. If the original array is modified by some code, the copy on write is performed and "foreach" still work with the old copy. - it makes no difference if array given to "foreach by value" is reference itself - "foreach by reference" still use internal array/object pointer and should work similar to PHP-5. (This id not completely implemented)
2015-02-12 18:57:12 +08:00
/* For general hashes (possibly persistent, storing any kind of value). */
static zend_always_inline void zend_hash_release(zend_array *array)
{
if (!(GC_FLAGS(array) & IS_ARRAY_IMMUTABLE)) {
if (GC_DELREF(array) == 0) {
zend_hash_destroy(array);
pefree(array, GC_FLAGS(array) & IS_ARRAY_PERSISTENT);
}
}
}
1999-06-08 06:49:33 +08:00
END_EXTERN_C()
2000-04-25 18:10:44 +08:00
#define ZEND_INIT_SYMTABLE(ht) \
ZEND_INIT_SYMTABLE_EX(ht, 8, 0)
2000-04-25 18:10:44 +08:00
#define ZEND_INIT_SYMTABLE_EX(ht, n, persistent) \
zend_hash_init(ht, n, NULL, ZVAL_PTR_DTOR, persistent)
static zend_always_inline bool _zend_handle_numeric_str(const char *key, size_t length, zend_ulong *idx)
{
const char *tmp = key;
2018-03-07 04:22:01 +08:00
if (EXPECTED(*tmp > '9')) {
return 0;
} else if (*tmp < '0') {
if (*tmp != '-') {
return 0;
}
tmp++;
if (*tmp > '9' || *tmp < '0') {
return 0;
}
}
return _zend_handle_numeric_str_ex(key, length, idx);
}
#define ZEND_HANDLE_NUMERIC_STR(key, length, idx) \
_zend_handle_numeric_str(key, length, &idx)
#define ZEND_HANDLE_NUMERIC(key, idx) \
ZEND_HANDLE_NUMERIC_STR(ZSTR_VAL(key), ZSTR_LEN(key), idx)
static zend_always_inline zval *zend_hash_find_ind(const HashTable *ht, zend_string *key)
{
zval *zv;
zv = zend_hash_find(ht, key);
return (zv && Z_TYPE_P(zv) == IS_INDIRECT) ?
((Z_TYPE_P(Z_INDIRECT_P(zv)) != IS_UNDEF) ? Z_INDIRECT_P(zv) : NULL) : zv;
}
static zend_always_inline zval *zend_hash_find_ex_ind(const HashTable *ht, zend_string *key, bool known_hash)
{
zval *zv;
zv = zend_hash_find_ex(ht, key, known_hash);
return (zv && Z_TYPE_P(zv) == IS_INDIRECT) ?
((Z_TYPE_P(Z_INDIRECT_P(zv)) != IS_UNDEF) ? Z_INDIRECT_P(zv) : NULL) : zv;
}
static zend_always_inline bool zend_hash_exists_ind(const HashTable *ht, zend_string *key)
2014-03-27 02:52:28 +08:00
{
zval *zv;
zv = zend_hash_find(ht, key);
return zv && (Z_TYPE_P(zv) != IS_INDIRECT ||
Z_TYPE_P(Z_INDIRECT_P(zv)) != IS_UNDEF);
}
static zend_always_inline zval *zend_hash_str_find_ind(const HashTable *ht, const char *str, size_t len)
{
zval *zv;
zv = zend_hash_str_find(ht, str, len);
return (zv && Z_TYPE_P(zv) == IS_INDIRECT) ?
((Z_TYPE_P(Z_INDIRECT_P(zv)) != IS_UNDEF) ? Z_INDIRECT_P(zv) : NULL) : zv;
}
static zend_always_inline bool zend_hash_str_exists_ind(const HashTable *ht, const char *str, size_t len)
{
zval *zv;
zv = zend_hash_str_find(ht, str, len);
return zv && (Z_TYPE_P(zv) != IS_INDIRECT ||
Z_TYPE_P(Z_INDIRECT_P(zv)) != IS_UNDEF);
}
static zend_always_inline zval *zend_symtable_add_new(HashTable *ht, zend_string *key, zval *pData)
{
zend_ulong idx;
if (ZEND_HANDLE_NUMERIC(key, idx)) {
return zend_hash_index_add_new(ht, idx, pData);
} else {
return zend_hash_add_new(ht, key, pData);
}
}
static zend_always_inline zval *zend_symtable_update(HashTable *ht, zend_string *key, zval *pData)
{
2014-08-26 01:24:55 +08:00
zend_ulong idx;
if (ZEND_HANDLE_NUMERIC(key, idx)) {
return zend_hash_index_update(ht, idx, pData);
} else {
return zend_hash_update(ht, key, pData);
}
}
static zend_always_inline zval *zend_symtable_update_ind(HashTable *ht, zend_string *key, zval *pData)
{
2014-08-26 01:24:55 +08:00
zend_ulong idx;
if (ZEND_HANDLE_NUMERIC(key, idx)) {
return zend_hash_index_update(ht, idx, pData);
} else {
return zend_hash_update_ind(ht, key, pData);
}
}
static zend_always_inline zend_result zend_symtable_del(HashTable *ht, zend_string *key)
{
2014-08-26 01:24:55 +08:00
zend_ulong idx;
if (ZEND_HANDLE_NUMERIC(key, idx)) {
return zend_hash_index_del(ht, idx);
} else {
return zend_hash_del(ht, key);
}
}
static zend_always_inline zend_result zend_symtable_del_ind(HashTable *ht, zend_string *key)
{
2014-08-26 01:24:55 +08:00
zend_ulong idx;
if (ZEND_HANDLE_NUMERIC(key, idx)) {
return zend_hash_index_del(ht, idx);
} else {
return zend_hash_del_ind(ht, key);
}
}
static zend_always_inline zval *zend_symtable_find(const HashTable *ht, zend_string *key)
{
2014-08-26 01:24:55 +08:00
zend_ulong idx;
if (ZEND_HANDLE_NUMERIC(key, idx)) {
return zend_hash_index_find(ht, idx);
} else {
return zend_hash_find(ht, key);
}
}
static zend_always_inline zval *zend_symtable_find_ind(const HashTable *ht, zend_string *key)
{
2014-08-26 01:24:55 +08:00
zend_ulong idx;
if (ZEND_HANDLE_NUMERIC(key, idx)) {
return zend_hash_index_find(ht, idx);
} else {
return zend_hash_find_ind(ht, key);
}
}
static zend_always_inline bool zend_symtable_exists(HashTable *ht, zend_string *key)
{
zend_ulong idx;
if (ZEND_HANDLE_NUMERIC(key, idx)) {
return zend_hash_index_exists(ht, idx);
} else {
return zend_hash_exists(ht, key);
}
}
static zend_always_inline bool zend_symtable_exists_ind(HashTable *ht, zend_string *key)
{
2014-08-26 01:24:55 +08:00
zend_ulong idx;
if (ZEND_HANDLE_NUMERIC(key, idx)) {
return zend_hash_index_exists(ht, idx);
} else {
2016-03-02 12:11:13 +08:00
return zend_hash_exists_ind(ht, key);
}
}
static zend_always_inline zval *zend_symtable_str_update(HashTable *ht, const char *str, size_t len, zval *pData)
{
2014-08-26 01:24:55 +08:00
zend_ulong idx;
if (ZEND_HANDLE_NUMERIC_STR(str, len, idx)) {
return zend_hash_index_update(ht, idx, pData);
} else {
return zend_hash_str_update(ht, str, len, pData);
}
}
static zend_always_inline zval *zend_symtable_str_update_ind(HashTable *ht, const char *str, size_t len, zval *pData)
{
2014-08-26 01:24:55 +08:00
zend_ulong idx;
if (ZEND_HANDLE_NUMERIC_STR(str, len, idx)) {
return zend_hash_index_update(ht, idx, pData);
} else {
return zend_hash_str_update_ind(ht, str, len, pData);
}
}
static zend_always_inline zend_result zend_symtable_str_del(HashTable *ht, const char *str, size_t len)
{
2014-08-26 01:24:55 +08:00
zend_ulong idx;
if (ZEND_HANDLE_NUMERIC_STR(str, len, idx)) {
return zend_hash_index_del(ht, idx);
} else {
return zend_hash_str_del(ht, str, len);
}
}
static zend_always_inline zend_result zend_symtable_str_del_ind(HashTable *ht, const char *str, size_t len)
{
2014-08-26 01:24:55 +08:00
zend_ulong idx;
if (ZEND_HANDLE_NUMERIC_STR(str, len, idx)) {
return zend_hash_index_del(ht, idx);
} else {
return zend_hash_str_del_ind(ht, str, len);
}
}
static zend_always_inline zval *zend_symtable_str_find(HashTable *ht, const char *str, size_t len)
{
2014-08-26 01:24:55 +08:00
zend_ulong idx;
if (ZEND_HANDLE_NUMERIC_STR(str, len, idx)) {
return zend_hash_index_find(ht, idx);
} else {
return zend_hash_str_find(ht, str, len);
}
}
static zend_always_inline bool zend_symtable_str_exists(HashTable *ht, const char *str, size_t len)
{
2014-08-26 01:24:55 +08:00
zend_ulong idx;
if (ZEND_HANDLE_NUMERIC_STR(str, len, idx)) {
return zend_hash_index_exists(ht, idx);
} else {
return zend_hash_str_exists(ht, str, len);
}
}
static zend_always_inline void *zend_hash_add_ptr(HashTable *ht, zend_string *key, void *pData)
{
zval tmp, *zv;
ZVAL_PTR(&tmp, pData);
zv = zend_hash_add(ht, key, &tmp);
2015-03-24 17:22:11 +08:00
if (zv) {
ZEND_ASSERT(Z_PTR_P(zv));
2015-03-24 17:22:11 +08:00
return Z_PTR_P(zv);
} else {
return NULL;
}
}
static zend_always_inline void *zend_hash_add_new_ptr(HashTable *ht, zend_string *key, void *pData)
2014-05-27 01:29:35 +08:00
{
zval tmp, *zv;
ZVAL_PTR(&tmp, pData);
zv = zend_hash_add_new(ht, key, &tmp);
2015-03-24 17:22:11 +08:00
if (zv) {
ZEND_ASSERT(Z_PTR_P(zv));
2015-03-24 17:22:11 +08:00
return Z_PTR_P(zv);
} else {
return NULL;
}
2014-05-27 01:29:35 +08:00
}
static zend_always_inline void *zend_hash_str_add_ptr(HashTable *ht, const char *str, size_t len, void *pData)
{
zval tmp, *zv;
ZVAL_PTR(&tmp, pData);
zv = zend_hash_str_add(ht, str, len, &tmp);
2015-03-24 17:22:11 +08:00
if (zv) {
ZEND_ASSERT(Z_PTR_P(zv));
2015-03-24 17:22:11 +08:00
return Z_PTR_P(zv);
} else {
return NULL;
}
}
static zend_always_inline void *zend_hash_str_add_new_ptr(HashTable *ht, const char *str, size_t len, void *pData)
{
zval tmp, *zv;
ZVAL_PTR(&tmp, pData);
zv = zend_hash_str_add_new(ht, str, len, &tmp);
2015-03-24 17:22:11 +08:00
if (zv) {
ZEND_ASSERT(Z_PTR_P(zv));
2015-03-24 17:22:11 +08:00
return Z_PTR_P(zv);
} else {
return NULL;
}
}
static zend_always_inline void *zend_hash_update_ptr(HashTable *ht, zend_string *key, void *pData)
{
zval tmp, *zv;
ZVAL_PTR(&tmp, pData);
zv = zend_hash_update(ht, key, &tmp);
ZEND_ASSERT(Z_PTR_P(zv));
return Z_PTR_P(zv);
}
static zend_always_inline void *zend_hash_str_update_ptr(HashTable *ht, const char *str, size_t len, void *pData)
{
zval tmp, *zv;
ZVAL_PTR(&tmp, pData);
zv = zend_hash_str_update(ht, str, len, &tmp);
ZEND_ASSERT(Z_PTR_P(zv));
return Z_PTR_P(zv);
}
static zend_always_inline void *zend_hash_add_mem(HashTable *ht, zend_string *key, void *pData, size_t size)
{
2014-04-25 15:29:18 +08:00
zval tmp, *zv;
2014-04-25 15:29:18 +08:00
ZVAL_PTR(&tmp, NULL);
if ((zv = zend_hash_add(ht, key, &tmp))) {
Z_PTR_P(zv) = pemalloc(size, GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
2014-04-25 15:29:18 +08:00
memcpy(Z_PTR_P(zv), pData, size);
return Z_PTR_P(zv);
2014-03-15 19:33:36 +08:00
}
return NULL;
}
static zend_always_inline void *zend_hash_add_new_mem(HashTable *ht, zend_string *key, void *pData, size_t size)
{
zval tmp, *zv;
ZVAL_PTR(&tmp, NULL);
if ((zv = zend_hash_add_new(ht, key, &tmp))) {
Z_PTR_P(zv) = pemalloc(size, GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
memcpy(Z_PTR_P(zv), pData, size);
return Z_PTR_P(zv);
}
return NULL;
}
static zend_always_inline void *zend_hash_str_add_mem(HashTable *ht, const char *str, size_t len, void *pData, size_t size)
{
2014-04-25 15:29:18 +08:00
zval tmp, *zv;
2014-04-25 15:29:18 +08:00
ZVAL_PTR(&tmp, NULL);
if ((zv = zend_hash_str_add(ht, str, len, &tmp))) {
Z_PTR_P(zv) = pemalloc(size, GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
2014-04-25 15:29:18 +08:00
memcpy(Z_PTR_P(zv), pData, size);
return Z_PTR_P(zv);
2014-03-15 19:33:36 +08:00
}
return NULL;
}
static zend_always_inline void *zend_hash_str_add_new_mem(HashTable *ht, const char *str, size_t len, void *pData, size_t size)
{
zval tmp, *zv;
ZVAL_PTR(&tmp, NULL);
if ((zv = zend_hash_str_add_new(ht, str, len, &tmp))) {
Z_PTR_P(zv) = pemalloc(size, GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
memcpy(Z_PTR_P(zv), pData, size);
return Z_PTR_P(zv);
}
return NULL;
}
static zend_always_inline void *zend_hash_update_mem(HashTable *ht, zend_string *key, void *pData, size_t size)
{
void *p;
p = pemalloc(size, GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
memcpy(p, pData, size);
return zend_hash_update_ptr(ht, key, p);
}
static zend_always_inline void *zend_hash_str_update_mem(HashTable *ht, const char *str, size_t len, void *pData, size_t size)
{
void *p;
p = pemalloc(size, GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
memcpy(p, pData, size);
return zend_hash_str_update_ptr(ht, str, len, p);
}
2015-03-07 07:28:12 +08:00
static zend_always_inline void *zend_hash_index_add_ptr(HashTable *ht, zend_ulong h, void *pData)
{
zval tmp, *zv;
ZVAL_PTR(&tmp, pData);
zv = zend_hash_index_add(ht, h, &tmp);
return zv ? Z_PTR_P(zv) : NULL;
}
2015-06-05 18:54:57 +08:00
static zend_always_inline void *zend_hash_index_add_new_ptr(HashTable *ht, zend_ulong h, void *pData)
{
zval tmp, *zv;
ZVAL_PTR(&tmp, pData);
zv = zend_hash_index_add_new(ht, h, &tmp);
return zv ? Z_PTR_P(zv) : NULL;
}
static zend_always_inline void *zend_hash_index_update_ptr(HashTable *ht, zend_ulong h, void *pData)
{
zval tmp, *zv;
ZVAL_PTR(&tmp, pData);
zv = zend_hash_index_update(ht, h, &tmp);
ZEND_ASSERT(Z_PTR_P(zv));
return Z_PTR_P(zv);
}
static zend_always_inline void *zend_hash_index_add_mem(HashTable *ht, zend_ulong h, void *pData, size_t size)
{
zval tmp, *zv;
ZVAL_PTR(&tmp, NULL);
if ((zv = zend_hash_index_add(ht, h, &tmp))) {
Z_PTR_P(zv) = pemalloc(size, GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
memcpy(Z_PTR_P(zv), pData, size);
return Z_PTR_P(zv);
}
return NULL;
}
static zend_always_inline void *zend_hash_next_index_insert_ptr(HashTable *ht, void *pData)
{
zval tmp, *zv;
ZVAL_PTR(&tmp, pData);
zv = zend_hash_next_index_insert(ht, &tmp);
2015-03-24 17:22:11 +08:00
if (zv) {
ZEND_ASSERT(Z_PTR_P(zv));
2015-03-24 17:22:11 +08:00
return Z_PTR_P(zv);
} else {
return NULL;
}
}
static zend_always_inline void *zend_hash_index_update_mem(HashTable *ht, zend_ulong h, void *pData, size_t size)
{
void *p;
p = pemalloc(size, GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
memcpy(p, pData, size);
return zend_hash_index_update_ptr(ht, h, p);
}
static zend_always_inline void *zend_hash_next_index_insert_mem(HashTable *ht, void *pData, size_t size)
{
zval tmp;
void *p = pemalloc(size, GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
memcpy(p, pData, size);
ZVAL_PTR(&tmp, p);
if (!zend_hash_next_index_insert(ht, &tmp)) {
pefree(p, GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
return NULL;
2014-03-15 19:33:36 +08:00
}
return p;
}
static zend_always_inline void *zend_hash_find_ptr(const HashTable *ht, zend_string *key)
{
zval *zv;
zv = zend_hash_find(ht, key);
2015-03-24 17:22:11 +08:00
if (zv) {
ZEND_ASSUME(Z_PTR_P(zv));
return Z_PTR_P(zv);
} else {
return NULL;
}
}
static zend_always_inline void *zend_hash_find_ex_ptr(const HashTable *ht, zend_string *key, bool known_hash)
2017-12-18 11:55:14 +08:00
{
zval *zv;
zv = zend_hash_find_ex(ht, key, known_hash);
if (zv) {
ZEND_ASSUME(Z_PTR_P(zv));
return Z_PTR_P(zv);
} else {
return NULL;
}
}
static zend_always_inline void *zend_hash_str_find_ptr(const HashTable *ht, const char *str, size_t len)
{
zval *zv;
zv = zend_hash_str_find(ht, str, len);
2015-03-24 17:22:11 +08:00
if (zv) {
ZEND_ASSUME(Z_PTR_P(zv));
return Z_PTR_P(zv);
} else {
return NULL;
}
}
BEGIN_EXTERN_C()
/* Will lowercase the str; use only if you don't need the lowercased string for
* anything else. If you have a lowered string, use zend_hash_str_find_ptr. */
ZEND_API void *zend_hash_str_find_ptr_lc(const HashTable *ht, const char *str, size_t len);
/* Will lowercase the str; use only if you don't need the lowercased string for
* anything else. If you have a lowered string, use zend_hash_find_ptr. */
ZEND_API void *zend_hash_find_ptr_lc(const HashTable *ht, zend_string *key);
END_EXTERN_C()
static zend_always_inline void *zend_hash_index_find_ptr(const HashTable *ht, zend_ulong h)
{
zval *zv;
zv = zend_hash_index_find(ht, h);
2015-03-24 17:22:11 +08:00
if (zv) {
ZEND_ASSUME(Z_PTR_P(zv));
return Z_PTR_P(zv);
} else {
return NULL;
}
}
static zend_always_inline zval *zend_hash_index_find_deref(HashTable *ht, zend_ulong h)
{
zval *zv = zend_hash_index_find(ht, h);
if (zv) {
ZVAL_DEREF(zv);
}
return zv;
}
static zend_always_inline zval *zend_hash_find_deref(HashTable *ht, zend_string *str)
{
zval *zv = zend_hash_find(ht, str);
if (zv) {
ZVAL_DEREF(zv);
}
return zv;
}
static zend_always_inline zval *zend_hash_str_find_deref(HashTable *ht, const char *str, size_t len)
{
zval *zv = zend_hash_str_find(ht, str, len);
if (zv) {
ZVAL_DEREF(zv);
}
return zv;
}
static zend_always_inline void *zend_symtable_str_find_ptr(HashTable *ht, const char *str, size_t len)
2014-07-29 14:15:01 +08:00
{
2014-08-26 01:24:55 +08:00
zend_ulong idx;
2014-07-29 14:15:01 +08:00
if (ZEND_HANDLE_NUMERIC_STR(str, len, idx)) {
return zend_hash_index_find_ptr(ht, idx);
} else {
return zend_hash_str_find_ptr(ht, str, len);
}
}
static zend_always_inline void *zend_hash_get_current_data_ptr_ex(HashTable *ht, HashPosition *pos)
{
zval *zv;
zv = zend_hash_get_current_data_ex(ht, pos);
2015-03-24 17:22:11 +08:00
if (zv) {
ZEND_ASSUME(Z_PTR_P(zv));
return Z_PTR_P(zv);
} else {
return NULL;
}
}
#define zend_hash_get_current_data_ptr(ht) \
zend_hash_get_current_data_ptr_ex(ht, &(ht)->nInternalPointer)
/* Common hash/packed array iterators */
#if 0
# define ZEND_HASH_ELEMENT_SIZE(__ht) \
(HT_IS_PACKED(__ht) ? sizeof(zval) : sizeof(Bucket))
#else /* optimized version */
# define ZEND_HASH_ELEMENT_SIZE(__ht) \
(sizeof(zval) + (~HT_FLAGS(__ht) & HASH_FLAG_PACKED) * ((sizeof(Bucket)-sizeof(zval))/HASH_FLAG_PACKED))
#endif
#define ZEND_HASH_ELEMENT_EX(__ht, _idx, _size) \
((zval*)(((char*)(__ht)->arPacked) + ((_idx) * (_size))))
#define ZEND_HASH_ELEMENT(__ht, _idx) \
ZEND_HASH_ELEMENT_EX(__ht, _idx, ZEND_HASH_ELEMENT_SIZE(__ht))
#define ZEND_HASH_NEXT_ELEMENT(_el, _size) \
((zval*)(((char*)(_el)) + (_size)))
#define ZEND_HASH_PREV_ELEMENT(_el, _size) \
((zval*)(((char*)(_el)) - (_size)))
#define _ZEND_HASH_FOREACH_VAL(_ht) do { \
const HashTable *__ht = (_ht); \
uint32_t _count = __ht->nNumUsed; \
size_t _size = ZEND_HASH_ELEMENT_SIZE(__ht); \
zval *_z = __ht->arPacked; \
for (; _count > 0; _z = ZEND_HASH_NEXT_ELEMENT(_z, _size), _count--) { \
if (UNEXPECTED(Z_TYPE_P(_z) == IS_UNDEF)) continue;
#define _ZEND_HASH_REVERSE_FOREACH_VAL(_ht) do { \
const HashTable *__ht = (_ht); \
uint32_t _idx = __ht->nNumUsed; \
size_t _size = ZEND_HASH_ELEMENT_SIZE(__ht); \
zval *_z = ZEND_HASH_ELEMENT_EX(__ht, _idx, _size); \
for (;_idx > 0; _idx--) { \
_z = ZEND_HASH_PREV_ELEMENT(_z, _size); \
if (UNEXPECTED(Z_TYPE_P(_z) == IS_UNDEF)) continue;
#define ZEND_HASH_FOREACH_FROM(_ht, indirect, _from) do { \
const HashTable *__ht = (_ht); \
zend_ulong __h; \
zend_string *__key = NULL; \
uint32_t _idx = (_from); \
size_t _size = ZEND_HASH_ELEMENT_SIZE(__ht); \
zval *__z = ZEND_HASH_ELEMENT_EX(__ht, _idx, _size); \
uint32_t _count = __ht->nNumUsed - _idx; \
for (;_count > 0; _count--) { \
zval *_z = __z; \
if (HT_IS_PACKED(__ht)) { \
__z++; \
__h = _idx; \
_idx++; \
} else { \
Bucket *_p = (Bucket*)__z; \
__z = &(_p + 1)->val; \
__h = _p->h; \
__key = _p->key; \
if (indirect && Z_TYPE_P(_z) == IS_INDIRECT) { \
_z = Z_INDIRECT_P(_z); \
} \
} \
(void) __h; (void) __key; (void) _idx; \
if (UNEXPECTED(Z_TYPE_P(_z) == IS_UNDEF)) continue;
#define ZEND_HASH_FOREACH(_ht, indirect) ZEND_HASH_FOREACH_FROM(_ht, indirect, 0)
#define ZEND_HASH_REVERSE_FOREACH(_ht, indirect) do { \
const HashTable *__ht = (_ht); \
2018-01-10 19:23:43 +08:00
uint32_t _idx = __ht->nNumUsed; \
zval *_z; \
zend_ulong __h; \
zend_string *__key = NULL; \
size_t _size = ZEND_HASH_ELEMENT_SIZE(__ht); \
zval *__z = ZEND_HASH_ELEMENT_EX(__ht, _idx, _size); \
for (;_idx > 0; _idx--) { \
if (HT_IS_PACKED(__ht)) { \
__z--; \
_z = __z; \
__h = _idx - 1; \
} else { \
Bucket *_p = (Bucket*)__z; \
_p--; \
__z = &_p->val; \
_z = __z; \
__h = _p->h; \
__key = _p->key; \
if (indirect && Z_TYPE_P(_z) == IS_INDIRECT) { \
_z = Z_INDIRECT_P(_z); \
} \
} \
(void) __h; (void) __key; (void) __z; \
if (UNEXPECTED(Z_TYPE_P(_z) == IS_UNDEF)) continue;
#define ZEND_HASH_FOREACH_END() \
} \
} while (0)
2015-01-03 17:22:58 +08:00
#define ZEND_HASH_FOREACH_END_DEL() \
ZEND_HASH_MAP_FOREACH_END_DEL()
#define ZEND_HASH_FOREACH_BUCKET(ht, _bucket) \
ZEND_HASH_MAP_FOREACH_BUCKET(ht, _bucket)
#define ZEND_HASH_FOREACH_BUCKET_FROM(ht, _bucket, _from) \
ZEND_HASH_MAP_FOREACH_BUCKET_FROM(ht, _bucket, _from)
#define ZEND_HASH_REVERSE_FOREACH_BUCKET(ht, _bucket) \
ZEND_HASH_MAP_REVERSE_FOREACH_BUCKET(ht, _bucket)
#define ZEND_HASH_FOREACH_VAL(ht, _val) \
_ZEND_HASH_FOREACH_VAL(ht); \
_val = _z;
#define ZEND_HASH_REVERSE_FOREACH_VAL(ht, _val) \
_ZEND_HASH_REVERSE_FOREACH_VAL(ht); \
_val = _z;
#define ZEND_HASH_FOREACH_VAL_IND(ht, _val) \
ZEND_HASH_FOREACH(ht, 1); \
_val = _z;
#define ZEND_HASH_REVERSE_FOREACH_VAL_IND(ht, _val) \
ZEND_HASH_REVERSE_FOREACH(ht, 1); \
_val = _z;
#define ZEND_HASH_FOREACH_PTR(ht, _ptr) \
_ZEND_HASH_FOREACH_VAL(ht); \
_ptr = Z_PTR_P(_z);
#define ZEND_HASH_FOREACH_PTR_FROM(ht, _ptr, _from) \
ZEND_HASH_FOREACH_FROM(ht, 0, _from); \
_ptr = Z_PTR_P(_z);
#define ZEND_HASH_REVERSE_FOREACH_PTR(ht, _ptr) \
_ZEND_HASH_REVERSE_FOREACH_VAL(ht); \
_ptr = Z_PTR_P(_z);
2014-04-24 23:14:29 +08:00
#define ZEND_HASH_FOREACH_NUM_KEY(ht, _h) \
ZEND_HASH_FOREACH(ht, 0); \
_h = __h;
2014-04-24 23:14:29 +08:00
#define ZEND_HASH_REVERSE_FOREACH_NUM_KEY(ht, _h) \
ZEND_HASH_REVERSE_FOREACH(ht, 0); \
_h = __h;
2014-04-22 21:46:34 +08:00
#define ZEND_HASH_FOREACH_STR_KEY(ht, _key) \
ZEND_HASH_FOREACH(ht, 0); \
_key = __key;
2015-01-03 17:22:58 +08:00
#define ZEND_HASH_REVERSE_FOREACH_STR_KEY(ht, _key) \
ZEND_HASH_REVERSE_FOREACH(ht, 0); \
_key = __key;
#define ZEND_HASH_FOREACH_KEY(ht, _h, _key) \
ZEND_HASH_FOREACH(ht, 0); \
_h = __h; \
_key = __key;
2014-08-26 05:05:05 +08:00
#define ZEND_HASH_REVERSE_FOREACH_KEY(ht, _h, _key) \
ZEND_HASH_REVERSE_FOREACH(ht, 0); \
_h = __h; \
_key = __key;
2014-08-26 05:05:05 +08:00
#define ZEND_HASH_FOREACH_NUM_KEY_VAL(ht, _h, _val) \
ZEND_HASH_FOREACH(ht, 0); \
_h = __h; \
2014-08-26 05:05:05 +08:00
_val = _z;
2015-01-03 17:22:58 +08:00
#define ZEND_HASH_REVERSE_FOREACH_NUM_KEY_VAL(ht, _h, _val) \
ZEND_HASH_REVERSE_FOREACH(ht, 0); \
_h = __h; \
_val = _z;
2014-04-22 21:46:34 +08:00
#define ZEND_HASH_FOREACH_STR_KEY_VAL(ht, _key, _val) \
ZEND_HASH_FOREACH(ht, 0); \
_key = __key; \
2014-04-22 21:46:34 +08:00
_val = _z;
#define ZEND_HASH_FOREACH_STR_KEY_VAL_FROM(ht, _key, _val, _from) \
ZEND_HASH_FOREACH_FROM(ht, 0, _from); \
_key = __key; \
_val = _z;
#define ZEND_HASH_REVERSE_FOREACH_STR_KEY_VAL(ht, _key, _val) \
ZEND_HASH_REVERSE_FOREACH(ht, 0); \
_key = __key; \
_val = _z;
#define ZEND_HASH_FOREACH_KEY_VAL(ht, _h, _key, _val) \
ZEND_HASH_FOREACH(ht, 0); \
_h = __h; \
_key = __key; \
_val = _z;
#define ZEND_HASH_REVERSE_FOREACH_KEY_VAL(ht, _h, _key, _val) \
ZEND_HASH_REVERSE_FOREACH(ht, 0); \
_h = __h; \
_key = __key; \
_val = _z;
2014-04-22 21:46:34 +08:00
#define ZEND_HASH_FOREACH_STR_KEY_VAL_IND(ht, _key, _val) \
ZEND_HASH_FOREACH(ht, 1); \
_key = __key; \
2014-04-22 21:46:34 +08:00
_val = _z;
#define ZEND_HASH_REVERSE_FOREACH_STR_KEY_VAL_IND(ht, _key, _val) \
ZEND_HASH_REVERSE_FOREACH(ht, 1); \
_key = __key; \
_val = _z;
#define ZEND_HASH_FOREACH_KEY_VAL_IND(ht, _h, _key, _val) \
ZEND_HASH_FOREACH(ht, 1); \
_h = __h; \
_key = __key; \
_val = _z;
#define ZEND_HASH_REVERSE_FOREACH_KEY_VAL_IND(ht, _h, _key, _val) \
ZEND_HASH_REVERSE_FOREACH(ht, 1); \
_h = __h; \
_key = __key; \
_val = _z;
2014-04-22 21:46:34 +08:00
#define ZEND_HASH_FOREACH_NUM_KEY_PTR(ht, _h, _ptr) \
ZEND_HASH_FOREACH(ht, 0); \
_h = __h; \
_ptr = Z_PTR_P(_z);
#define ZEND_HASH_REVERSE_FOREACH_NUM_KEY_PTR(ht, _h, _ptr) \
ZEND_HASH_REVERSE_FOREACH(ht, 0); \
_h = __h; \
_ptr = Z_PTR_P(_z);
#define ZEND_HASH_FOREACH_STR_KEY_PTR(ht, _key, _ptr) \
ZEND_HASH_FOREACH(ht, 0); \
_key = __key; \
_ptr = Z_PTR_P(_z);
#define ZEND_HASH_REVERSE_FOREACH_STR_KEY_PTR(ht, _key, _ptr) \
ZEND_HASH_REVERSE_FOREACH(ht, 0); \
_key = __key; \
_ptr = Z_PTR_P(_z);
#define ZEND_HASH_FOREACH_KEY_PTR(ht, _h, _key, _ptr) \
ZEND_HASH_FOREACH(ht, 0); \
_h = __h; \
_key = __key; \
_ptr = Z_PTR_P(_z);
#define ZEND_HASH_REVERSE_FOREACH_KEY_PTR(ht, _h, _key, _ptr) \
ZEND_HASH_REVERSE_FOREACH(ht, 0); \
_h = __h; \
_key = __key; \
_ptr = Z_PTR_P(_z);
/* Hash array iterators */
#define ZEND_HASH_MAP_FOREACH_FROM(_ht, indirect, _from) do { \
const HashTable *__ht = (_ht); \
Bucket *_p = __ht->arData + (_from); \
const Bucket *_end = __ht->arData + __ht->nNumUsed; \
ZEND_ASSERT(!HT_IS_PACKED(__ht)); \
for (; _p != _end; _p++) { \
zval *_z = &_p->val; \
if (indirect && Z_TYPE_P(_z) == IS_INDIRECT) { \
_z = Z_INDIRECT_P(_z); \
} \
if (UNEXPECTED(Z_TYPE_P(_z) == IS_UNDEF)) continue;
#define ZEND_HASH_MAP_FOREACH(_ht, indirect) ZEND_HASH_MAP_FOREACH_FROM(_ht, indirect, 0)
#define ZEND_HASH_MAP_REVERSE_FOREACH(_ht, indirect) do { \
/* const */ HashTable *__ht = (_ht); \
uint32_t _idx = __ht->nNumUsed; \
Bucket *_p = __ht->arData + _idx; \
zval *_z; \
ZEND_ASSERT(!HT_IS_PACKED(__ht)); \
for (_idx = __ht->nNumUsed; _idx > 0; _idx--) { \
_p--; \
_z = &_p->val; \
if (indirect && Z_TYPE_P(_z) == IS_INDIRECT) { \
_z = Z_INDIRECT_P(_z); \
} \
if (UNEXPECTED(Z_TYPE_P(_z) == IS_UNDEF)) continue;
#define ZEND_HASH_MAP_FOREACH_END_DEL() \
ZEND_ASSERT(!HT_IS_PACKED(__ht)); \
__ht->nNumOfElements--; \
do { \
uint32_t j = HT_IDX_TO_HASH(_idx - 1); \
uint32_t nIndex = _p->h | __ht->nTableMask; \
uint32_t i = HT_HASH(__ht, nIndex); \
if (UNEXPECTED(j != i)) { \
Bucket *prev = HT_HASH_TO_BUCKET(__ht, i); \
while (Z_NEXT(prev->val) != j) { \
i = Z_NEXT(prev->val); \
prev = HT_HASH_TO_BUCKET(__ht, i); \
} \
Z_NEXT(prev->val) = Z_NEXT(_p->val); \
} else { \
HT_HASH(__ht, nIndex) = Z_NEXT(_p->val); \
} \
} while (0); \
} \
__ht->nNumUsed = _idx; \
} while (0)
#define ZEND_HASH_MAP_FOREACH_BUCKET(ht, _bucket) \
ZEND_HASH_MAP_FOREACH(ht, 0); \
_bucket = _p;
#define ZEND_HASH_MAP_FOREACH_BUCKET_FROM(ht, _bucket, _from) \
ZEND_HASH_MAP_FOREACH_FROM(ht, 0, _from); \
_bucket = _p;
#define ZEND_HASH_MAP_REVERSE_FOREACH_BUCKET(ht, _bucket) \
ZEND_HASH_MAP_REVERSE_FOREACH(ht, 0); \
_bucket = _p;
#define ZEND_HASH_MAP_FOREACH_VAL(ht, _val) \
ZEND_HASH_MAP_FOREACH(ht, 0); \
_val = _z;
#define ZEND_HASH_MAP_REVERSE_FOREACH_VAL(ht, _val) \
ZEND_HASH_MAP_REVERSE_FOREACH(ht, 0); \
_val = _z;
#define ZEND_HASH_MAP_FOREACH_VAL_IND(ht, _val) \
ZEND_HASH_MAP_FOREACH(ht, 1); \
_val = _z;
#define ZEND_HASH_MAP_REVERSE_FOREACH_VAL_IND(ht, _val) \
ZEND_HASH_MAP_REVERSE_FOREACH(ht, 1); \
_val = _z;
#define ZEND_HASH_MAP_FOREACH_PTR(ht, _ptr) \
ZEND_HASH_MAP_FOREACH(ht, 0); \
_ptr = Z_PTR_P(_z);
#define ZEND_HASH_MAP_FOREACH_PTR_FROM(ht, _ptr, _from) \
ZEND_HASH_MAP_FOREACH_FROM(ht, 0, _from); \
_ptr = Z_PTR_P(_z);
#define ZEND_HASH_MAP_REVERSE_FOREACH_PTR(ht, _ptr) \
ZEND_HASH_MAP_REVERSE_FOREACH(ht, 0); \
_ptr = Z_PTR_P(_z);
#define ZEND_HASH_MAP_FOREACH_NUM_KEY(ht, _h) \
ZEND_HASH_MAP_FOREACH(ht, 0); \
_h = _p->h;
#define ZEND_HASH_MAP_REVERSE_FOREACH_NUM_KEY(ht, _h) \
ZEND_HASH_MAP_REVERSE_FOREACH(ht, 0); \
_h = _p->h;
#define ZEND_HASH_MAP_FOREACH_STR_KEY(ht, _key) \
ZEND_HASH_MAP_FOREACH(ht, 0); \
_key = _p->key;
#define ZEND_HASH_MAP_REVERSE_FOREACH_STR_KEY(ht, _key) \
ZEND_HASH_MAP_REVERSE_FOREACH(ht, 0); \
_key = _p->key;
#define ZEND_HASH_MAP_FOREACH_KEY(ht, _h, _key) \
ZEND_HASH_MAP_FOREACH(ht, 0); \
_h = _p->h; \
_key = _p->key;
#define ZEND_HASH_MAP_REVERSE_FOREACH_KEY(ht, _h, _key) \
ZEND_HASH_MAP_REVERSE_FOREACH(ht, 0); \
_h = _p->h; \
_key = _p->key;
#define ZEND_HASH_MAP_FOREACH_NUM_KEY_VAL(ht, _h, _val) \
ZEND_HASH_MAP_FOREACH(ht, 0); \
_h = _p->h; \
_val = _z;
#define ZEND_HASH_MAP_REVERSE_FOREACH_NUM_KEY_VAL(ht, _h, _val) \
ZEND_HASH_MAP_REVERSE_FOREACH(ht, 0); \
_h = _p->h; \
_val = _z;
#define ZEND_HASH_MAP_FOREACH_STR_KEY_VAL(ht, _key, _val) \
ZEND_HASH_MAP_FOREACH(ht, 0); \
_key = _p->key; \
_val = _z;
#define ZEND_HASH_MAP_FOREACH_STR_KEY_VAL_FROM(ht, _key, _val, _from) \
ZEND_HASH_MAP_FOREACH_FROM(ht, 0, _from); \
_key = _p->key; \
_val = _z;
#define ZEND_HASH_MAP_REVERSE_FOREACH_STR_KEY_VAL(ht, _key, _val) \
ZEND_HASH_MAP_REVERSE_FOREACH(ht, 0); \
_key = _p->key; \
_val = _z;
#define ZEND_HASH_MAP_FOREACH_KEY_VAL(ht, _h, _key, _val) \
ZEND_HASH_MAP_FOREACH(ht, 0); \
_h = _p->h; \
_key = _p->key; \
_val = _z;
#define ZEND_HASH_MAP_REVERSE_FOREACH_KEY_VAL(ht, _h, _key, _val) \
ZEND_HASH_MAP_REVERSE_FOREACH(ht, 0); \
_h = _p->h; \
_key = _p->key; \
_val = _z;
#define ZEND_HASH_MAP_FOREACH_STR_KEY_VAL_IND(ht, _key, _val) \
ZEND_HASH_MAP_FOREACH(ht, 1); \
_key = _p->key; \
_val = _z;
#define ZEND_HASH_MAP_REVERSE_FOREACH_STR_KEY_VAL_IND(ht, _key, _val) \
ZEND_HASH_MAP_REVERSE_FOREACH(ht, 1); \
_key = _p->key; \
_val = _z;
#define ZEND_HASH_MAP_FOREACH_KEY_VAL_IND(ht, _h, _key, _val) \
ZEND_HASH_MAP_FOREACH(ht, 1); \
_h = _p->h; \
_key = _p->key; \
_val = _z;
#define ZEND_HASH_MAP_REVERSE_FOREACH_KEY_VAL_IND(ht, _h, _key, _val) \
ZEND_HASH_MAP_REVERSE_FOREACH(ht, 1); \
_h = _p->h; \
_key = _p->key; \
_val = _z;
#define ZEND_HASH_MAP_FOREACH_NUM_KEY_PTR(ht, _h, _ptr) \
ZEND_HASH_MAP_FOREACH(ht, 0); \
_h = _p->h; \
_ptr = Z_PTR_P(_z);
#define ZEND_HASH_MAP_REVERSE_FOREACH_NUM_KEY_PTR(ht, _h, _ptr) \
ZEND_HASH_MAP_REVERSE_FOREACH(ht, 0); \
_h = _p->h; \
_ptr = Z_PTR_P(_z);
#define ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(ht, _key, _ptr) \
ZEND_HASH_MAP_FOREACH(ht, 0); \
_key = _p->key; \
_ptr = Z_PTR_P(_z);
#define ZEND_HASH_MAP_REVERSE_FOREACH_STR_KEY_PTR(ht, _key, _ptr) \
ZEND_HASH_MAP_REVERSE_FOREACH(ht, 0); \
_key = _p->key; \
_ptr = Z_PTR_P(_z);
#define ZEND_HASH_MAP_FOREACH_KEY_PTR(ht, _h, _key, _ptr) \
ZEND_HASH_MAP_FOREACH(ht, 0); \
_h = _p->h; \
_key = _p->key; \
_ptr = Z_PTR_P(_z);
#define ZEND_HASH_MAP_REVERSE_FOREACH_KEY_PTR(ht, _h, _key, _ptr) \
ZEND_HASH_MAP_REVERSE_FOREACH(ht, 0); \
_h = _p->h; \
_key = _p->key; \
_ptr = Z_PTR_P(_z);
/* Packed array iterators */
#define ZEND_HASH_PACKED_FOREACH_FROM(_ht, _from) do { \
const HashTable *__ht = (_ht); \
zend_ulong _idx = (_from); \
zval *_z = __ht->arPacked + (_from); \
zval *_end = __ht->arPacked + __ht->nNumUsed; \
ZEND_ASSERT(HT_IS_PACKED(__ht)); \
for (;_z != _end; _z++, _idx++) { \
(void) _idx; \
if (UNEXPECTED(Z_TYPE_P(_z) == IS_UNDEF)) continue;
#define ZEND_HASH_PACKED_FOREACH(_ht) ZEND_HASH_PACKED_FOREACH_FROM(_ht, 0)
#define ZEND_HASH_PACKED_REVERSE_FOREACH(_ht) do { \
const HashTable *__ht = (_ht); \
zend_ulong _idx = __ht->nNumUsed; \
zval *_z = __ht->arPacked + _idx; \
ZEND_ASSERT(HT_IS_PACKED(__ht)); \
while (_idx > 0) { \
_z--; \
_idx--; \
(void) _idx; \
if (UNEXPECTED(Z_TYPE_P(_z) == IS_UNDEF)) continue;
#define ZEND_HASH_PACKED_FOREACH_VAL(ht, _val) \
ZEND_HASH_PACKED_FOREACH(ht); \
_val = _z;
#define ZEND_HASH_PACKED_REVERSE_FOREACH_VAL(ht, _val) \
ZEND_HASH_PACKED_REVERSE_FOREACH(ht); \
_val = _z;
#define ZEND_HASH_PACKED_FOREACH_PTR(ht, _ptr) \
ZEND_HASH_PACKED_FOREACH(ht); \
_ptr = Z_PTR_P(_z);
#define ZEND_HASH_PACKED_REVERSE_FOREACH_PTR(ht, _ptr) \
ZEND_HASH_PACKED_REVERSE_FOREACH(ht); \
_ptr = Z_PTR_P(_z);
#define ZEND_HASH_PACKED_FOREACH_KEY(ht, _h) \
ZEND_HASH_PACKED_FOREACH(ht); \
_h = _idx;
#define ZEND_HASH_PACKED_REVERSE_FOREACH_KEY(ht, _h) \
ZEND_HASH_PACKED_REVERSE_FOREACH(ht); \
_h = _idx;
#define ZEND_HASH_PACKED_FOREACH_KEY_VAL(ht, _h, _val) \
ZEND_HASH_PACKED_FOREACH(ht); \
_h = _idx; \
_val = _z;
#define ZEND_HASH_PACKED_REVERSE_FOREACH_KEY_VAL(ht, _h, _val) \
ZEND_HASH_PACKED_REVERSE_FOREACH(ht); \
_h = _idx; \
_val = _z;
#define ZEND_HASH_PACKED_FOREACH_KEY_PTR(ht, _h, _ptr) \
ZEND_HASH_PACKED_FOREACH(ht); \
_h = _idx; \
_ptr = Z_PTR_P(_z);
#define ZEND_HASH_PACKED_REVERSE_FOREACH_KEY_PTR(ht, _h, _ptr) \
ZEND_HASH_PACKED_REVERSE_FOREACH(ht); \
_h = _idx; \
_ptr = Z_PTR_P(_z);
2015-01-03 17:22:58 +08:00
/* The following macros are useful to insert a sequence of new elements
* of packed array. They may be used instead of series of
* zend_hash_next_index_insert_new()
* (HashTable must have enough free buckets).
*/
#define ZEND_HASH_FILL_PACKED(ht) do { \
HashTable *__fill_ht = (ht); \
zval *__fill_val = __fill_ht->arPacked + __fill_ht->nNumUsed; \
uint32_t __fill_idx = __fill_ht->nNumUsed; \
ZEND_ASSERT(HT_IS_PACKED(__fill_ht));
#define ZEND_HASH_FILL_GROW() do { \
if (UNEXPECTED(__fill_idx >= __fill_ht->nTableSize)) { \
__fill_ht->nNumOfElements += __fill_idx - __fill_ht->nNumUsed; \
__fill_ht->nNumUsed = __fill_idx; \
__fill_ht->nNextFreeElement = __fill_idx; \
zend_hash_packed_grow(__fill_ht); \
__fill_val = __fill_ht->arPacked + __fill_idx; \
} \
} while (0);
2019-05-28 18:35:00 +08:00
#define ZEND_HASH_FILL_SET(_val) \
ZVAL_COPY_VALUE(__fill_val, _val)
2019-05-28 18:35:00 +08:00
#define ZEND_HASH_FILL_SET_NULL() \
ZVAL_NULL(__fill_val)
2019-05-28 18:35:00 +08:00
#define ZEND_HASH_FILL_SET_LONG(_val) \
ZVAL_LONG(__fill_val, _val)
2019-05-28 18:35:00 +08:00
#define ZEND_HASH_FILL_SET_DOUBLE(_val) \
ZVAL_DOUBLE(__fill_val, _val)
2019-05-28 18:35:00 +08:00
#define ZEND_HASH_FILL_SET_STR(_val) \
ZVAL_STR(__fill_val, _val)
2019-05-28 18:35:00 +08:00
#define ZEND_HASH_FILL_SET_STR_COPY(_val) \
ZVAL_STR_COPY(__fill_val, _val)
2019-05-28 18:35:00 +08:00
#define ZEND_HASH_FILL_SET_INTERNED_STR(_val) \
ZVAL_INTERNED_STR(__fill_val, _val)
2019-05-28 18:35:00 +08:00
#define ZEND_HASH_FILL_NEXT() do {\
__fill_val++; \
__fill_idx++; \
} while (0)
2015-01-03 17:22:58 +08:00
2019-05-28 18:35:00 +08:00
#define ZEND_HASH_FILL_ADD(_val) do { \
ZEND_HASH_FILL_SET(_val); \
ZEND_HASH_FILL_NEXT(); \
} while (0)
#define ZEND_HASH_FILL_FINISH() do { \
__fill_ht->nNumOfElements += __fill_idx - __fill_ht->nNumUsed; \
__fill_ht->nNumUsed = __fill_idx; \
__fill_ht->nNextFreeElement = __fill_idx; \
__fill_ht->nInternalPointer = 0; \
} while (0)
#define ZEND_HASH_FILL_END() \
ZEND_HASH_FILL_FINISH(); \
} while (0)
/* Check if an array is a list */
static zend_always_inline bool zend_array_is_list(const zend_array *array)
{
zend_ulong expected_idx = 0;
zend_ulong num_idx;
zend_string* str_idx;
/* Empty arrays are lists */
if (zend_hash_num_elements(array) == 0) {
return 1;
}
/* Packed arrays are lists */
if (HT_IS_PACKED(array)) {
if (HT_IS_WITHOUT_HOLES(array)) {
return 1;
}
/* Check if the list could theoretically be repacked */
ZEND_HASH_PACKED_FOREACH_KEY(array, num_idx) {
if (num_idx != expected_idx++) {
return 0;
}
} ZEND_HASH_FOREACH_END();
} else {
/* Check if the list could theoretically be repacked */
ZEND_HASH_MAP_FOREACH_KEY(array, num_idx, str_idx) {
if (str_idx != NULL || num_idx != expected_idx++) {
return 0;
}
} ZEND_HASH_FOREACH_END();
}
return 1;
}
static zend_always_inline zval *_zend_hash_append_ex(HashTable *ht, zend_string *key, zval *zv, bool interned)
2015-03-05 04:06:07 +08:00
{
uint32_t idx = ht->nNumUsed++;
uint32_t nIndex;
Bucket *p = ht->arData + idx;
ZVAL_COPY_VALUE(&p->val, zv);
2018-04-04 07:12:26 +08:00
if (!interned && !ZSTR_IS_INTERNED(key)) {
HT_FLAGS(ht) &= ~HASH_FLAG_STATIC_KEYS;
zend_string_addref(key);
zend_string_hash_val(key);
}
p->key = key;
p->h = ZSTR_H(key);
2015-03-19 14:45:10 +08:00
nIndex = (uint32_t)p->h | ht->nTableMask;
Z_NEXT(p->val) = HT_HASH(ht, nIndex);
HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(idx);
2015-03-05 04:06:07 +08:00
ht->nNumOfElements++;
2015-05-19 18:22:58 +08:00
return &p->val;
2015-03-05 04:06:07 +08:00
}
2018-04-04 07:12:26 +08:00
static zend_always_inline zval *_zend_hash_append(HashTable *ht, zend_string *key, zval *zv)
{
return _zend_hash_append_ex(ht, key, zv, 0);
}
static zend_always_inline zval *_zend_hash_append_ptr_ex(HashTable *ht, zend_string *key, void *ptr, bool interned)
{
uint32_t idx = ht->nNumUsed++;
uint32_t nIndex;
Bucket *p = ht->arData + idx;
ZVAL_PTR(&p->val, ptr);
2018-04-04 07:12:26 +08:00
if (!interned && !ZSTR_IS_INTERNED(key)) {
HT_FLAGS(ht) &= ~HASH_FLAG_STATIC_KEYS;
zend_string_addref(key);
zend_string_hash_val(key);
}
p->key = key;
p->h = ZSTR_H(key);
2015-03-19 14:45:10 +08:00
nIndex = (uint32_t)p->h | ht->nTableMask;
Z_NEXT(p->val) = HT_HASH(ht, nIndex);
HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(idx);
ht->nNumOfElements++;
2015-05-19 18:22:58 +08:00
return &p->val;
}
2018-04-04 07:12:26 +08:00
static zend_always_inline zval *_zend_hash_append_ptr(HashTable *ht, zend_string *key, void *ptr)
{
return _zend_hash_append_ptr_ex(ht, key, ptr, 0);
}
2015-03-07 00:23:54 +08:00
static zend_always_inline void _zend_hash_append_ind(HashTable *ht, zend_string *key, zval *ptr)
{
uint32_t idx = ht->nNumUsed++;
uint32_t nIndex;
Bucket *p = ht->arData + idx;
ZVAL_INDIRECT(&p->val, ptr);
if (!ZSTR_IS_INTERNED(key)) {
HT_FLAGS(ht) &= ~HASH_FLAG_STATIC_KEYS;
zend_string_addref(key);
zend_string_hash_val(key);
}
p->key = key;
p->h = ZSTR_H(key);
2015-03-19 14:45:10 +08:00
nIndex = (uint32_t)p->h | ht->nTableMask;
Z_NEXT(p->val) = HT_HASH(ht, nIndex);
HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(idx);
2015-03-07 00:23:54 +08:00
ht->nNumOfElements++;
}
#endif /* ZEND_HASH_H */