/* forward declarations */
static Py_ssize_t lookdict(PyDictObject *mp, PyObject *key,
- Py_hash_t hash, PyObject ***value_addr,
+ Py_hash_t hash, PyObject **value_addr,
Py_ssize_t *hashpos);
static Py_ssize_t lookdict_unicode(PyDictObject *mp, PyObject *key,
- Py_hash_t hash, PyObject ***value_addr,
+ Py_hash_t hash, PyObject **value_addr,
Py_ssize_t *hashpos);
static Py_ssize_t
lookdict_unicode_nodummy(PyDictObject *mp, PyObject *key,
- Py_hash_t hash, PyObject ***value_addr,
+ Py_hash_t hash, PyObject **value_addr,
Py_ssize_t *hashpos);
static Py_ssize_t lookdict_split(PyDictObject *mp, PyObject *key,
- Py_hash_t hash, PyObject ***value_addr,
+ Py_hash_t hash, PyObject **value_addr,
Py_ssize_t *hashpos);
static int dictresize(PyDictObject *mp, Py_ssize_t minused);
*/
static Py_ssize_t _Py_HOT_FUNCTION
lookdict(PyDictObject *mp, PyObject *key,
- Py_hash_t hash, PyObject ***value_addr, Py_ssize_t *hashpos)
+ Py_hash_t hash, PyObject **value_addr, Py_ssize_t *hashpos)
{
size_t i, mask;
Py_ssize_t ix, freeslot;
ep = &ep0[ix];
assert(ep->me_key != NULL);
if (ep->me_key == key) {
- *value_addr = &ep->me_value;
+ *value_addr = ep->me_value;
if (hashpos != NULL)
*hashpos = i;
return ix;
}
if (dk == mp->ma_keys && ep->me_key == startkey) {
if (cmp > 0) {
- *value_addr = &ep->me_value;
+ *value_addr = ep->me_value;
if (hashpos != NULL)
*hashpos = i;
return ix;
if (hashpos != NULL) {
*hashpos = i;
}
- *value_addr = &ep->me_value;
+ *value_addr = ep->me_value;
return ix;
}
if (ep->me_hash == hash) {
if (hashpos != NULL) {
*hashpos = i;
}
- *value_addr = &ep->me_value;
+ *value_addr = ep->me_value;
return ix;
}
}
/* Specialized version for string-only keys */
static Py_ssize_t _Py_HOT_FUNCTION
lookdict_unicode(PyDictObject *mp, PyObject *key,
- Py_hash_t hash, PyObject ***value_addr, Py_ssize_t *hashpos)
+ Py_hash_t hash, PyObject **value_addr, Py_ssize_t *hashpos)
{
size_t i;
size_t mask = DK_MASK(mp->ma_keys);
|| (ep->me_hash == hash && unicode_eq(ep->me_key, key))) {
if (hashpos != NULL)
*hashpos = i;
- *value_addr = &ep->me_value;
+ *value_addr = ep->me_value;
return ix;
}
freeslot = -1;
assert(ep->me_key != NULL);
if (ep->me_key == key
|| (ep->me_hash == hash && unicode_eq(ep->me_key, key))) {
- *value_addr = &ep->me_value;
+ *value_addr = ep->me_value;
if (hashpos != NULL) {
*hashpos = i;
}
* will be present. */
static Py_ssize_t _Py_HOT_FUNCTION
lookdict_unicode_nodummy(PyDictObject *mp, PyObject *key,
- Py_hash_t hash, PyObject ***value_addr,
+ Py_hash_t hash, PyObject **value_addr,
Py_ssize_t *hashpos)
{
size_t i;
(ep->me_hash == hash && unicode_eq(ep->me_key, key))) {
if (hashpos != NULL)
*hashpos = i;
- *value_addr = &ep->me_value;
+ *value_addr = ep->me_value;
return ix;
}
for (size_t perturb = hash;;) {
(ep->me_hash == hash && unicode_eq(ep->me_key, key))) {
if (hashpos != NULL)
*hashpos = i;
- *value_addr = &ep->me_value;
+ *value_addr = ep->me_value;
return ix;
}
}
*/
static Py_ssize_t _Py_HOT_FUNCTION
lookdict_split(PyDictObject *mp, PyObject *key,
- Py_hash_t hash, PyObject ***value_addr, Py_ssize_t *hashpos)
+ Py_hash_t hash, PyObject **value_addr, Py_ssize_t *hashpos)
{
size_t i;
size_t mask = DK_MASK(mp->ma_keys);
if (!PyUnicode_CheckExact(key)) {
ix = lookdict(mp, key, hash, value_addr, hashpos);
if (ix >= 0) {
- *value_addr = &mp->ma_values[ix];
+ *value_addr = mp->ma_values[ix];
}
return ix;
}
(ep->me_hash == hash && unicode_eq(ep->me_key, key))) {
if (hashpos != NULL)
*hashpos = i;
- *value_addr = &mp->ma_values[ix];
+ *value_addr = mp->ma_values[ix];
return ix;
}
for (size_t perturb = hash;;) {
(ep->me_hash == hash && unicode_eq(ep->me_key, key))) {
if (hashpos != NULL)
*hashpos = i;
- *value_addr = &mp->ma_values[ix];
+ *value_addr = mp->ma_values[ix];
return ix;
}
}
when it is known that the key is not present in the dict.
The dict must be combined. */
-static void
-find_empty_slot(PyDictObject *mp, PyObject *key, Py_hash_t hash,
- PyObject ***value_addr, Py_ssize_t *hashpos)
+static Py_ssize_t
+find_empty_slot(PyDictKeysObject *keys, PyObject *key, Py_hash_t hash)
{
size_t i;
- size_t mask = DK_MASK(mp->ma_keys);
+ size_t mask = DK_MASK(keys);
Py_ssize_t ix;
- PyDictKeyEntry *ep, *ep0 = DK_ENTRIES(mp->ma_keys);
- assert(!_PyDict_HasSplitTable(mp));
- assert(hashpos != NULL);
assert(key != NULL);
- if (!PyUnicode_CheckExact(key))
- mp->ma_keys->dk_lookup = lookdict;
i = hash & mask;
- ix = dk_get_index(mp->ma_keys, i);
+ ix = dk_get_index(keys, i);
for (size_t perturb = hash; ix != DKIX_EMPTY;) {
perturb >>= PERTURB_SHIFT;
i = (i << 2) + i + perturb + 1;
- ix = dk_get_index(mp->ma_keys, i & mask);
+ ix = dk_get_index(keys, i & mask);
}
- ep = &ep0[mp->ma_keys->dk_nentries];
- *hashpos = i & mask;
- assert(ep->me_value == NULL);
- *value_addr = &ep->me_value;
+ assert(DK_ENTRIES(keys)[keys->dk_nentries].me_value == NULL);
+ return i & mask;
}
static int
insertdict(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject *value)
{
PyObject *old_value;
- PyObject **value_addr;
- PyDictKeyEntry *ep, *ep0;
+ PyDictKeyEntry *ep;
Py_ssize_t hashpos, ix;
if (mp->ma_values != NULL && !PyUnicode_CheckExact(key)) {
return -1;
}
- ix = mp->ma_keys->dk_lookup(mp, key, hash, &value_addr, &hashpos);
+ ix = mp->ma_keys->dk_lookup(mp, key, hash, &old_value, &hashpos);
if (ix == DKIX_ERROR) {
return -1;
}
* the key anymore. Convert this instance to combine table.
*/
if (_PyDict_HasSplitTable(mp) &&
- ((ix >= 0 && *value_addr == NULL && mp->ma_used != ix) ||
+ ((ix >= 0 && old_value == NULL && mp->ma_used != ix) ||
(ix == DKIX_EMPTY && mp->ma_used != mp->ma_keys->dk_nentries))) {
if (insertion_resize(mp) < 0) {
Py_DECREF(value);
return -1;
}
- find_empty_slot(mp, key, hash, &value_addr, &hashpos);
+ hashpos = find_empty_slot(mp->ma_keys, key, hash);
ix = DKIX_EMPTY;
}
if (ix == DKIX_EMPTY) {
/* Insert into new slot. */
+ assert(old_value == NULL);
if (mp->ma_keys->dk_usable <= 0) {
/* Need to resize. */
if (insertion_resize(mp) < 0) {
Py_DECREF(value);
return -1;
}
- find_empty_slot(mp, key, hash, &value_addr, &hashpos);
+ hashpos = find_empty_slot(mp->ma_keys, key, hash);
}
- ep0 = DK_ENTRIES(mp->ma_keys);
- ep = &ep0[mp->ma_keys->dk_nentries];
+ ep = &DK_ENTRIES(mp->ma_keys)[mp->ma_keys->dk_nentries];
dk_set_index(mp->ma_keys, hashpos, mp->ma_keys->dk_nentries);
Py_INCREF(key);
ep->me_key = key;
return 0;
}
- assert(value_addr != NULL);
-
- old_value = *value_addr;
- if (old_value != NULL) {
- *value_addr = value;
- mp->ma_version_tag = DICT_NEXT_VERSION();
- assert(_PyDict_CheckConsistency(mp));
-
- Py_DECREF(old_value); /* which **CAN** re-enter (see issue #22653) */
- return 0;
+ if (_PyDict_HasSplitTable(mp)) {
+ mp->ma_values[ix] = value;
+ if (old_value == NULL) {
+ /* pending state */
+ assert(ix == mp->ma_used);
+ mp->ma_used++;
+ }
+ }
+ else {
+ assert(old_value != NULL);
+ DK_ENTRIES(mp->ma_keys)[ix].me_value = value;
}
- /* pending state */
- assert(_PyDict_HasSplitTable(mp));
- assert(ix == mp->ma_used);
- *value_addr = value;
- mp->ma_used++;
mp->ma_version_tag = DICT_NEXT_VERSION();
+ Py_XDECREF(old_value); /* which **CAN** re-enter (see issue #22653) */
assert(_PyDict_CheckConsistency(mp));
return 0;
}
Py_ssize_t ix;
PyDictObject *mp = (PyDictObject *)op;
PyThreadState *tstate;
- PyObject **value_addr;
+ PyObject *value;
if (!PyDict_Check(op))
return NULL;
/* preserve the existing exception */
PyObject *err_type, *err_value, *err_tb;
PyErr_Fetch(&err_type, &err_value, &err_tb);
- ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value_addr, NULL);
+ ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value, NULL);
/* ignore errors */
PyErr_Restore(err_type, err_value, err_tb);
if (ix < 0)
return NULL;
}
else {
- ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value_addr, NULL);
+ ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value, NULL);
if (ix < 0) {
PyErr_Clear();
return NULL;
}
}
- return *value_addr;
+ return value;
}
/* Same as PyDict_GetItemWithError() but with hash supplied by caller.
{
Py_ssize_t ix;
PyDictObject *mp = (PyDictObject *)op;
- PyObject **value_addr;
+ PyObject *value;
if (!PyDict_Check(op)) {
PyErr_BadInternalCall();
return NULL;
}
- ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value_addr, NULL);
+ ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value, NULL);
if (ix < 0) {
return NULL;
}
- return *value_addr;
+ return value;
}
/* Variant of PyDict_GetItem() that doesn't suppress exceptions.
Py_ssize_t ix;
Py_hash_t hash;
PyDictObject*mp = (PyDictObject *)op;
- PyObject **value_addr;
+ PyObject *value;
if (!PyDict_Check(op)) {
PyErr_BadInternalCall();
}
}
- ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value_addr, NULL);
+ ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value, NULL);
if (ix < 0)
return NULL;
- return *value_addr;
+ return value;
}
PyObject *
{
Py_ssize_t ix;
Py_hash_t hash;
- PyObject **value_addr;
+ PyObject *value;
if (!PyUnicode_CheckExact(key) ||
(hash = ((PyASCIIObject *) key)->hash) == -1)
}
/* namespace 1: globals */
- ix = globals->ma_keys->dk_lookup(globals, key, hash, &value_addr, NULL);
+ ix = globals->ma_keys->dk_lookup(globals, key, hash, &value, NULL);
if (ix == DKIX_ERROR)
return NULL;
- if (ix != DKIX_EMPTY && *value_addr != NULL)
- return *value_addr;
+ if (ix != DKIX_EMPTY && value != NULL)
+ return value;
/* namespace 2: builtins */
- ix = builtins->ma_keys->dk_lookup(builtins, key, hash, &value_addr, NULL);
+ ix = builtins->ma_keys->dk_lookup(builtins, key, hash, &value, NULL);
if (ix < 0)
return NULL;
- return *value_addr;
+ return value;
}
/* CAUTION: PyDict_SetItem() must guarantee that it won't resize the
PyDictObject *mp;
PyDictKeyEntry *ep;
PyObject *old_key, *old_value;
- PyObject **value_addr;
if (!PyDict_Check(op)) {
PyErr_BadInternalCall();
assert(key);
assert(hash != -1);
mp = (PyDictObject *)op;
- ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value_addr, &hashpos);
+ ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &old_value, &hashpos);
if (ix == DKIX_ERROR)
return -1;
- if (ix == DKIX_EMPTY || *value_addr == NULL) {
+ if (ix == DKIX_EMPTY || old_value == NULL) {
_PyErr_SetKeyError(key);
return -1;
}
if (dictresize(mp, DK_SIZE(mp->ma_keys))) {
return -1;
}
- ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value_addr, &hashpos);
+ ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &old_value, &hashpos);
assert(ix >= 0);
}
- old_value = *value_addr;
assert(old_value != NULL);
- *value_addr = NULL;
mp->ma_used--;
mp->ma_version_tag = DICT_NEXT_VERSION();
ep = &DK_ENTRIES(mp->ma_keys)[ix];
ENSURE_ALLOWS_DELETIONS(mp);
old_key = ep->me_key;
ep->me_key = NULL;
+ ep->me_value = NULL;
Py_DECREF(old_key);
Py_DECREF(old_value);
Py_ssize_t ix, hashpos;
PyObject *old_value, *old_key;
PyDictKeyEntry *ep;
- PyObject **value_addr;
PyDictObject *mp;
assert(PyDict_Check(dict));
if (hash == -1)
return NULL;
}
- ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value_addr, &hashpos);
+ ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &old_value, &hashpos);
if (ix == DKIX_ERROR)
return NULL;
- if (ix == DKIX_EMPTY || *value_addr == NULL) {
+ if (ix == DKIX_EMPTY || old_value == NULL) {
if (deflt) {
Py_INCREF(deflt);
return deflt;
if (dictresize(mp, DK_SIZE(mp->ma_keys))) {
return NULL;
}
- ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value_addr, &hashpos);
+ ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &old_value, &hashpos);
assert(ix >= 0);
}
- old_value = *value_addr;
assert(old_value != NULL);
- *value_addr = NULL;
mp->ma_used--;
mp->ma_version_tag = DICT_NEXT_VERSION();
dk_set_index(mp->ma_keys, hashpos, DKIX_DUMMY);
ENSURE_ALLOWS_DELETIONS(mp);
old_key = ep->me_key;
ep->me_key = NULL;
+ ep->me_value = NULL;
Py_DECREF(old_key);
assert(_PyDict_CheckConsistency(mp));
static PyObject *
dict_subscript(PyDictObject *mp, PyObject *key)
{
- PyObject *v;
Py_ssize_t ix;
Py_hash_t hash;
- PyObject **value_addr;
+ PyObject *value;
if (!PyUnicode_CheckExact(key) ||
(hash = ((PyASCIIObject *) key)->hash) == -1) {
if (hash == -1)
return NULL;
}
- ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value_addr, NULL);
+ ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value, NULL);
if (ix == DKIX_ERROR)
return NULL;
- if (ix == DKIX_EMPTY || *value_addr == NULL) {
+ if (ix == DKIX_EMPTY || value == NULL) {
if (!PyDict_CheckExact(mp)) {
/* Look up __missing__ method if we're a subclass. */
PyObject *missing, *res;
_PyErr_SetKeyError(key);
return NULL;
}
- v = *value_addr;
- Py_INCREF(v);
- return v;
+ Py_INCREF(value);
+ return value;
}
static int
if (aval != NULL) {
int cmp;
PyObject *bval;
- PyObject **vaddr;
PyObject *key = ep->me_key;
/* temporarily bump aval's refcount to ensure it stays
alive until we're done with it */
/* ditto for key */
Py_INCREF(key);
/* reuse the known hash value */
- if ((b->ma_keys->dk_lookup)(b, key, ep->me_hash, &vaddr, NULL) < 0)
- bval = NULL;
- else
- bval = *vaddr;
+ b->ma_keys->dk_lookup(b, key, ep->me_hash, &bval, NULL);
Py_DECREF(key);
if (bval == NULL) {
Py_DECREF(aval);
register PyDictObject *mp = self;
Py_hash_t hash;
Py_ssize_t ix;
- PyObject **value_addr;
+ PyObject *value;
if (!PyUnicode_CheckExact(key) ||
(hash = ((PyASCIIObject *) key)->hash) == -1) {
if (hash == -1)
return NULL;
}
- ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value_addr, NULL);
+ ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value, NULL);
if (ix == DKIX_ERROR)
return NULL;
- if (ix == DKIX_EMPTY || *value_addr == NULL)
+ if (ix == DKIX_EMPTY || value == NULL)
Py_RETURN_FALSE;
Py_RETURN_TRUE;
}
PyObject *val = NULL;
Py_hash_t hash;
Py_ssize_t ix;
- PyObject **value_addr;
if (!PyArg_UnpackTuple(args, "get", 1, 2, &key, &failobj))
return NULL;
if (hash == -1)
return NULL;
}
- ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value_addr, NULL);
+ ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &val, NULL);
if (ix == DKIX_ERROR)
return NULL;
- if (ix == DKIX_EMPTY || *value_addr == NULL)
+ if (ix == DKIX_EMPTY || val == NULL) {
val = failobj;
- else
- val = *value_addr;
+ }
Py_INCREF(val);
return val;
}
PyObject *value;
Py_hash_t hash;
Py_ssize_t hashpos, ix;
- PyObject **value_addr;
if (!PyDict_Check(d)) {
PyErr_BadInternalCall();
return NULL;
}
- ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value_addr, &hashpos);
+ ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value, &hashpos);
if (ix == DKIX_ERROR)
return NULL;
if (_PyDict_HasSplitTable(mp) &&
- ((ix >= 0 && *value_addr == NULL && mp->ma_used != ix) ||
+ ((ix >= 0 && value == NULL && mp->ma_used != ix) ||
(ix == DKIX_EMPTY && mp->ma_used != mp->ma_keys->dk_nentries))) {
if (insertion_resize(mp) < 0) {
return NULL;
}
- find_empty_slot(mp, key, hash, &value_addr, &hashpos);
+ hashpos = find_empty_slot(mp->ma_keys, key, hash);
ix = DKIX_EMPTY;
}
if (insertion_resize(mp) < 0) {
return NULL;
}
- find_empty_slot(mp, key, hash, &value_addr, &hashpos);
+ hashpos = find_empty_slot(mp->ma_keys, key, hash);
}
ep0 = DK_ENTRIES(mp->ma_keys);
ep = &ep0[mp->ma_keys->dk_nentries];
MAINTAIN_TRACKING(mp, key, value);
ep->me_key = key;
ep->me_hash = hash;
- if (mp->ma_values) {
+ if (_PyDict_HasSplitTable(mp)) {
assert(mp->ma_values[mp->ma_keys->dk_nentries] == NULL);
mp->ma_values[mp->ma_keys->dk_nentries] = value;
}
mp->ma_keys->dk_nentries++;
assert(mp->ma_keys->dk_usable >= 0);
}
- else if (*value_addr == NULL) {
+ else if (value == NULL) {
value = defaultobj;
assert(_PyDict_HasSplitTable(mp));
assert(ix == mp->ma_used);
Py_INCREF(value);
MAINTAIN_TRACKING(mp, key, value);
- *value_addr = value;
+ mp->ma_values[ix] = value;
mp->ma_used++;
mp->ma_version_tag = DICT_NEXT_VERSION();
}
- else {
- value = *value_addr;
- }
assert(_PyDict_CheckConsistency(mp));
return value;
Py_hash_t hash;
Py_ssize_t ix;
PyDictObject *mp = (PyDictObject *)op;
- PyObject **value_addr;
+ PyObject *value;
if (!PyUnicode_CheckExact(key) ||
(hash = ((PyASCIIObject *) key)->hash) == -1) {
if (hash == -1)
return -1;
}
- ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value_addr, NULL);
+ ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value, NULL);
if (ix == DKIX_ERROR)
return -1;
- return (ix != DKIX_EMPTY && *value_addr != NULL);
+ return (ix != DKIX_EMPTY && value != NULL);
}
/* Internal version of PyDict_Contains used when the hash value is already known */
_PyDict_Contains(PyObject *op, PyObject *key, Py_hash_t hash)
{
PyDictObject *mp = (PyDictObject *)op;
- PyObject **value_addr;
+ PyObject *value;
Py_ssize_t ix;
- ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value_addr, NULL);
+ ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value, NULL);
if (ix == DKIX_ERROR)
return -1;
- return (ix != DKIX_EMPTY && *value_addr != NULL);
+ return (ix != DKIX_EMPTY && value != NULL);
}
/* Hack to implement "key in dict" */