Add zend_hash_lookup() and zend_hash_index_lookup() functions.

Thet search for an element with given key/index and add an empty one (NULL), if no found.
This commit is contained in:
Dmitry Stogov 2021-03-19 22:36:24 +03:00
parent 64e589cab6
commit 340013ad01
3 changed files with 96 additions and 44 deletions

View file

@ -2121,25 +2121,27 @@ try_again:
if (EXPECTED(Z_TYPE_P(dim) == IS_LONG)) {
hval = Z_LVAL_P(dim);
num_index:
ZEND_HASH_INDEX_FIND(ht, hval, retval, num_undef);
return retval;
if (type != BP_VAR_W) {
ZEND_HASH_INDEX_FIND(ht, hval, retval, num_undef);
return retval;
num_undef:
switch (type) {
case BP_VAR_R:
zend_undefined_offset(hval);
/* break missing intentionally */
case BP_VAR_UNSET:
case BP_VAR_IS:
retval = &EG(uninitialized_zval);
break;
case BP_VAR_RW:
if (UNEXPECTED(zend_undefined_offset_write(ht, hval) == FAILURE)) {
return NULL;
switch (type) {
case BP_VAR_R:
zend_undefined_offset(hval);
/* break missing intentionally */
case BP_VAR_UNSET:
case BP_VAR_IS:
retval = &EG(uninitialized_zval);
break;
case BP_VAR_RW:
if (UNEXPECTED(zend_undefined_offset_write(ht, hval) == FAILURE)) {
return NULL;
}
retval = zend_hash_index_add_new(ht, hval, &EG(uninitialized_zval));
break;
}
/* break missing intentionally */
case BP_VAR_W:
retval = zend_hash_index_add_new(ht, hval, &EG(uninitialized_zval));
break;
} else {
ZEND_HASH_INDEX_LOOKUP(ht, hval, retval);
}
} else if (EXPECTED(Z_TYPE_P(dim) == IS_STRING)) {
offset_key = Z_STR_P(dim);
@ -2149,30 +2151,31 @@ num_undef:
}
}
str_index:
retval = zend_hash_find_ex(ht, offset_key, ZEND_CONST_COND(dim_type == IS_CONST, 0));
if (!retval) {
switch (type) {
case BP_VAR_R:
zend_undefined_index(offset_key);
/* break missing intentionally */
case BP_VAR_UNSET:
case BP_VAR_IS:
retval = &EG(uninitialized_zval);
break;
case BP_VAR_RW:
/* Key may be released while throwing the undefined index warning. */
zend_string_addref(offset_key);
if (UNEXPECTED(zend_undefined_index_write(ht, offset_key) == FAILURE)) {
if (type != BP_VAR_W) {
retval = zend_hash_find_ex(ht, offset_key, ZEND_CONST_COND(dim_type == IS_CONST, 0));
if (!retval) {
switch (type) {
case BP_VAR_R:
zend_undefined_index(offset_key);
/* break missing intentionally */
case BP_VAR_UNSET:
case BP_VAR_IS:
retval = &EG(uninitialized_zval);
break;
case BP_VAR_RW:
/* Key may be released while throwing the undefined index warning. */
zend_string_addref(offset_key);
if (UNEXPECTED(zend_undefined_index_write(ht, offset_key) == FAILURE)) {
zend_string_release(offset_key);
return NULL;
}
retval = zend_hash_add_new(ht, offset_key, &EG(uninitialized_zval));
zend_string_release(offset_key);
return NULL;
}
retval = zend_hash_add_new(ht, offset_key, &EG(uninitialized_zval));
zend_string_release(offset_key);
break;
case BP_VAR_W:
retval = zend_hash_add_new(ht, offset_key, &EG(uninitialized_zval));
break;
break;
}
}
} else {
retval = zend_hash_lookup(ht, offset_key);
}
} else if (EXPECTED(Z_TYPE_P(dim) == IS_REFERENCE)) {
dim = Z_REFVAL_P(dim);

View file

@ -748,7 +748,9 @@ static zend_always_inline zval *_zend_hash_add_or_update_i(HashTable *ht, zend_s
zval *data;
ZEND_ASSERT((flag & HASH_ADD_NEW) == 0);
if (flag & HASH_ADD) {
if (flag & HASH_LOOKUP) {
return &p->val;
} else if (flag & HASH_ADD) {
if (!(flag & HASH_UPDATE_INDIRECT)) {
return NULL;
}
@ -793,7 +795,11 @@ add_to_hash:
nIndex = h | ht->nTableMask;
Z_NEXT(p->val) = HT_HASH_EX(arData, nIndex);
HT_HASH_EX(arData, nIndex) = HT_IDX_TO_HASH(idx);
ZVAL_COPY_VALUE(&p->val, pData);
if (flag & HASH_LOOKUP) {
ZVAL_NULL(&p->val);
} else {
ZVAL_COPY_VALUE(&p->val, pData);
}
return &p->val;
}
@ -821,7 +827,9 @@ static zend_always_inline zval *_zend_hash_str_add_or_update_i(HashTable *ht, co
if (p) {
zval *data;
if (flag & HASH_ADD) {
if (flag & HASH_LOOKUP) {
return &p->val;
} else if (flag & HASH_ADD) {
if (!(flag & HASH_UPDATE_INDIRECT)) {
return NULL;
}
@ -859,7 +867,11 @@ add_to_hash:
p->key = key = zend_string_init(str, len, GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
p->h = ZSTR_H(key) = h;
HT_FLAGS(ht) &= ~HASH_FLAG_STATIC_KEYS;
ZVAL_COPY_VALUE(&p->val, pData);
if (flag & HASH_LOOKUP) {
ZVAL_NULL(&p->val);
} else {
ZVAL_COPY_VALUE(&p->val, pData);
}
nIndex = h | ht->nTableMask;
Z_NEXT(p->val) = HT_HASH(ht, nIndex);
HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(idx);
@ -901,6 +913,11 @@ ZEND_API zval* ZEND_FASTCALL zend_hash_add_new(HashTable *ht, zend_string *key,
return _zend_hash_add_or_update_i(ht, key, pData, HASH_ADD_NEW);
}
ZEND_API zval* ZEND_FASTCALL zend_hash_lookup(HashTable *ht, zend_string *key)
{
return _zend_hash_add_or_update_i(ht, key, NULL, HASH_LOOKUP);
}
ZEND_API zval* ZEND_FASTCALL zend_hash_str_add_or_update(HashTable *ht, const char *str, size_t len, zval *pData, uint32_t flag)
{
if (flag == HASH_ADD) {
@ -984,6 +1001,9 @@ static zend_always_inline zval *_zend_hash_index_add_or_update_i(HashTable *ht,
if (h < ht->nNumUsed) {
p = ht->arData + h;
if (Z_TYPE(p->val) != IS_UNDEF) {
if (flag & HASH_LOOKUP) {
return &p->val;
}
replace:
if (flag & HASH_ADD) {
return NULL;
@ -1032,6 +1052,9 @@ convert_to_hash:
if ((flag & HASH_ADD_NEW) == 0 || ZEND_DEBUG) {
p = zend_hash_index_find_bucket(ht, h);
if (p) {
if (flag & HASH_LOOKUP) {
return &p->val;
}
ZEND_ASSERT((flag & HASH_ADD_NEW) == 0);
goto replace;
}
@ -1051,7 +1074,11 @@ add:
ht->nNumOfElements++;
p->h = h;
p->key = NULL;
ZVAL_COPY_VALUE(&p->val, pData);
if (flag & HASH_LOOKUP) {
ZVAL_NULL(&p->val);
} else {
ZVAL_COPY_VALUE(&p->val, pData);
}
return &p->val;
}
@ -1099,6 +1126,11 @@ ZEND_API zval* ZEND_FASTCALL zend_hash_next_index_insert_new(HashTable *ht, zval
return _zend_hash_index_add_or_update_i(ht, ht->nNextFreeElement, pData, HASH_ADD | HASH_ADD_NEW | HASH_ADD_NEXT);
}
ZEND_API zval* ZEND_FASTCALL zend_hash_index_lookup(HashTable *ht, zend_ulong h)
{
return _zend_hash_index_add_or_update_i(ht, h, NULL, HASH_LOOKUP);
}
ZEND_API zval* ZEND_FASTCALL zend_hash_set_bucket_key(HashTable *ht, Bucket *b, zend_string *key)
{
uint32_t nIndex;

View file

@ -32,6 +32,7 @@
#define HASH_UPDATE_INDIRECT (1<<2)
#define HASH_ADD_NEW (1<<3)
#define HASH_ADD_NEXT (1<<4)
#define HASH_LOOKUP (1<<5)
#define HASH_FLAG_CONSISTENCY ((1<<0) | (1<<1))
#define HASH_FLAG_PACKED (1<<2)
@ -206,6 +207,22 @@ static zend_always_inline zval *zend_hash_find_ex(const HashTable *ht, zend_stri
} while (0)
/* 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_FLAGS(_ht) & HASH_FLAG_PACKED)) { \
if (EXPECTED((zend_ulong)(_h) < (zend_ulong)(_ht)->nNumUsed)) { \
_ret = &_ht->arData[_h].val; \
if (EXPECTED(Z_TYPE_P(_ret) != IS_UNDEF)) { \
break; \
} \
} \
} \
_ret = zend_hash_index_lookup(_ht, _h); \
} while (0)
/* Misc */
static zend_always_inline bool zend_hash_exists(const HashTable *ht, zend_string *key)
{