Commit 778928b0 authored by INADA Naoki's avatar INADA Naoki Committed by GitHub

bpo-29304: Simplify dict lookup functions (GH-2407)

* remove hashpos parameter from lookdict functions.
* remove many duplicated code from lookdict functions.
parent 87c3c5de
...@@ -12,8 +12,7 @@ typedef struct { ...@@ -12,8 +12,7 @@ typedef struct {
* -1 when no entry found, -3 when compare raises error. * -1 when no entry found, -3 when compare raises error.
*/ */
typedef Py_ssize_t (*dict_lookup_func) typedef Py_ssize_t (*dict_lookup_func)
(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject **value_addr, (PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject **value_addr);
Py_ssize_t *hashpos);
#define DKIX_EMPTY (-1) #define DKIX_EMPTY (-1)
#define DKIX_DUMMY (-2) /* Used internally */ #define DKIX_DUMMY (-2) /* Used internally */
......
...@@ -223,18 +223,14 @@ equally good collision statistics, needed less code & used less memory. ...@@ -223,18 +223,14 @@ equally good collision statistics, needed less code & used less memory.
/* forward declarations */ /* forward declarations */
static Py_ssize_t lookdict(PyDictObject *mp, PyObject *key, 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, 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 static Py_ssize_t
lookdict_unicode_nodummy(PyDictObject *mp, PyObject *key, 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, 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 int dictresize(PyDictObject *mp, Py_ssize_t minused);
...@@ -672,118 +668,59 @@ never raise an exception; that function can never return DKIX_ERROR when key ...@@ -672,118 +668,59 @@ never raise an exception; that function can never return DKIX_ERROR when key
is string. Otherwise, it falls back to lookdict(). is string. Otherwise, it falls back to lookdict().
lookdict_unicode_nodummy is further specialized for string keys that cannot be lookdict_unicode_nodummy is further specialized for string keys that cannot be
the <dummy> value. the <dummy> value.
For both, when the key isn't found a DKIX_EMPTY is returned. hashpos returns For both, when the key isn't found a DKIX_EMPTY is returned.
where the key index should be inserted.
*/ */
static Py_ssize_t _Py_HOT_FUNCTION static Py_ssize_t _Py_HOT_FUNCTION
lookdict(PyDictObject *mp, PyObject *key, lookdict(PyDictObject *mp, PyObject *key,
Py_hash_t hash, PyObject **value_addr, Py_ssize_t *hashpos) Py_hash_t hash, PyObject **value_addr)
{ {
size_t i, mask; size_t i, mask, perturb;
Py_ssize_t ix, freeslot;
int cmp;
PyDictKeysObject *dk; PyDictKeysObject *dk;
PyDictKeyEntry *ep0, *ep; PyDictKeyEntry *ep0;
PyObject *startkey;
top: top:
dk = mp->ma_keys; dk = mp->ma_keys;
mask = DK_MASK(dk);
ep0 = DK_ENTRIES(dk); ep0 = DK_ENTRIES(dk);
mask = DK_MASK(dk);
perturb = hash;
i = (size_t)hash & mask; i = (size_t)hash & mask;
ix = dk_get_index(dk, i); for (;;) {
if (ix == DKIX_EMPTY) { Py_ssize_t ix = dk_get_index(dk, i);
if (hashpos != NULL)
*hashpos = i;
*value_addr = NULL;
return DKIX_EMPTY;
}
if (ix == DKIX_DUMMY) {
freeslot = i;
}
else {
ep = &ep0[ix];
assert(ep->me_key != NULL);
if (ep->me_key == key) {
*value_addr = ep->me_value;
if (hashpos != NULL)
*hashpos = i;
return ix;
}
if (ep->me_hash == hash) {
startkey = ep->me_key;
Py_INCREF(startkey);
cmp = PyObject_RichCompareBool(startkey, key, Py_EQ);
Py_DECREF(startkey);
if (cmp < 0) {
*value_addr = NULL;
return DKIX_ERROR;
}
if (dk == mp->ma_keys && ep->me_key == startkey) {
if (cmp > 0) {
*value_addr = ep->me_value;
if (hashpos != NULL)
*hashpos = i;
return ix;
}
}
else {
/* The dict was mutated, restart */
goto top;
}
}
freeslot = -1;
}
for (size_t perturb = hash;;) {
perturb >>= PERTURB_SHIFT;
i = (i*5 + perturb + 1) & mask;
ix = dk_get_index(dk, i);
if (ix == DKIX_EMPTY) { if (ix == DKIX_EMPTY) {
if (hashpos != NULL) {
*hashpos = (freeslot == -1) ? (Py_ssize_t)i : freeslot;
}
*value_addr = NULL; *value_addr = NULL;
return ix; return ix;
} }
if (ix == DKIX_DUMMY) { if (ix >= 0) {
if (freeslot == -1) PyDictKeyEntry *ep = &ep0[ix];
freeslot = i; assert(ep->me_key != NULL);
continue; if (ep->me_key == key) {
} *value_addr = ep->me_value;
ep = &ep0[ix]; return ix;
assert(ep->me_key != NULL);
if (ep->me_key == key) {
if (hashpos != NULL) {
*hashpos = i;
}
*value_addr = ep->me_value;
return ix;
}
if (ep->me_hash == hash) {
startkey = ep->me_key;
Py_INCREF(startkey);
cmp = PyObject_RichCompareBool(startkey, key, Py_EQ);
Py_DECREF(startkey);
if (cmp < 0) {
*value_addr = NULL;
return DKIX_ERROR;
} }
if (dk == mp->ma_keys && ep->me_key == startkey) { if (ep->me_hash == hash) {
if (cmp > 0) { PyObject *startkey = ep->me_key;
if (hashpos != NULL) { Py_INCREF(startkey);
*hashpos = i; int cmp = PyObject_RichCompareBool(startkey, key, Py_EQ);
Py_DECREF(startkey);
if (cmp < 0) {
*value_addr = NULL;
return DKIX_ERROR;
}
if (dk == mp->ma_keys && ep->me_key == startkey) {
if (cmp > 0) {
*value_addr = ep->me_value;
return ix;
} }
*value_addr = ep->me_value;
return ix;
} }
} else {
else { /* The dict was mutated, restart */
/* The dict was mutated, restart */ goto top;
goto top; }
} }
} }
perturb >>= PERTURB_SHIFT;
i = (i*5 + perturb + 1) & mask;
} }
assert(0); /* NOT REACHED */ assert(0); /* NOT REACHED */
return 0; return 0;
...@@ -792,13 +729,8 @@ top: ...@@ -792,13 +729,8 @@ top:
/* Specialized version for string-only keys */ /* Specialized version for string-only keys */
static Py_ssize_t _Py_HOT_FUNCTION static Py_ssize_t _Py_HOT_FUNCTION
lookdict_unicode(PyDictObject *mp, PyObject *key, lookdict_unicode(PyDictObject *mp, PyObject *key,
Py_hash_t hash, PyObject **value_addr, Py_ssize_t *hashpos) Py_hash_t hash, PyObject **value_addr)
{ {
size_t i;
size_t mask = DK_MASK(mp->ma_keys);
Py_ssize_t ix, freeslot;
PyDictKeyEntry *ep, *ep0 = DK_ENTRIES(mp->ma_keys);
assert(mp->ma_values == NULL); assert(mp->ma_values == NULL);
/* Make sure this function doesn't have to handle non-unicode keys, /* Make sure this function doesn't have to handle non-unicode keys,
including subclasses of str; e.g., one reason to subclass including subclasses of str; e.g., one reason to subclass
...@@ -806,59 +738,34 @@ lookdict_unicode(PyDictObject *mp, PyObject *key, ...@@ -806,59 +738,34 @@ lookdict_unicode(PyDictObject *mp, PyObject *key,
that here. */ that here. */
if (!PyUnicode_CheckExact(key)) { if (!PyUnicode_CheckExact(key)) {
mp->ma_keys->dk_lookup = lookdict; mp->ma_keys->dk_lookup = lookdict;
return lookdict(mp, key, hash, value_addr, hashpos); return lookdict(mp, key, hash, value_addr);
}
i = (size_t)hash & mask;
ix = dk_get_index(mp->ma_keys, i);
if (ix == DKIX_EMPTY) {
if (hashpos != NULL)
*hashpos = i;
*value_addr = NULL;
return DKIX_EMPTY;
}
if (ix == DKIX_DUMMY) {
freeslot = i;
}
else {
ep = &ep0[ix];
assert(ep->me_key != NULL);
if (ep->me_key == key
|| (ep->me_hash == hash && unicode_eq(ep->me_key, key))) {
if (hashpos != NULL)
*hashpos = i;
*value_addr = ep->me_value;
return ix;
}
freeslot = -1;
} }
for (size_t perturb = hash;;) { PyDictKeyEntry *ep0 = DK_ENTRIES(mp->ma_keys);
perturb >>= PERTURB_SHIFT; size_t mask = DK_MASK(mp->ma_keys);
i = mask & (i*5 + perturb + 1); size_t perturb = (size_t)hash;
ix = dk_get_index(mp->ma_keys, i); size_t i = (size_t)hash & mask;
for (;;) {
Py_ssize_t ix = dk_get_index(mp->ma_keys, i);
if (ix == DKIX_EMPTY) { if (ix == DKIX_EMPTY) {
if (hashpos != NULL) {
*hashpos = (freeslot == -1) ? (Py_ssize_t)i : freeslot;
}
*value_addr = NULL; *value_addr = NULL;
return DKIX_EMPTY; return DKIX_EMPTY;
} }
if (ix == DKIX_DUMMY) { if (ix >= 0) {
if (freeslot == -1) PyDictKeyEntry *ep = &ep0[ix];
freeslot = i; assert(ep->me_key != NULL);
continue; assert(PyUnicode_CheckExact(ep->me_key));
} if (ep->me_key == key ||
ep = &ep0[ix]; (ep->me_hash == hash && unicode_eq(ep->me_key, key))) {
assert(ep->me_key != NULL); *value_addr = ep->me_value;
if (ep->me_key == key return ix;
|| (ep->me_hash == hash && unicode_eq(ep->me_key, key))) {
*value_addr = ep->me_value;
if (hashpos != NULL) {
*hashpos = i;
} }
return ix;
} }
perturb >>= PERTURB_SHIFT;
i = mask & (i*5 + perturb + 1);
} }
assert(0); /* NOT REACHED */ assert(0); /* NOT REACHED */
return 0; return 0;
} }
...@@ -867,14 +774,8 @@ lookdict_unicode(PyDictObject *mp, PyObject *key, ...@@ -867,14 +774,8 @@ lookdict_unicode(PyDictObject *mp, PyObject *key,
* will be present. */ * will be present. */
static Py_ssize_t _Py_HOT_FUNCTION static Py_ssize_t _Py_HOT_FUNCTION
lookdict_unicode_nodummy(PyDictObject *mp, PyObject *key, 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;
size_t mask = DK_MASK(mp->ma_keys);
Py_ssize_t ix;
PyDictKeyEntry *ep, *ep0 = DK_ENTRIES(mp->ma_keys);
assert(mp->ma_values == NULL); assert(mp->ma_values == NULL);
/* Make sure this function doesn't have to handle non-unicode keys, /* Make sure this function doesn't have to handle non-unicode keys,
including subclasses of str; e.g., one reason to subclass including subclasses of str; e.g., one reason to subclass
...@@ -882,47 +783,31 @@ lookdict_unicode_nodummy(PyDictObject *mp, PyObject *key, ...@@ -882,47 +783,31 @@ lookdict_unicode_nodummy(PyDictObject *mp, PyObject *key,
that here. */ that here. */
if (!PyUnicode_CheckExact(key)) { if (!PyUnicode_CheckExact(key)) {
mp->ma_keys->dk_lookup = lookdict; mp->ma_keys->dk_lookup = lookdict;
return lookdict(mp, key, hash, value_addr, hashpos); return lookdict(mp, key, hash, value_addr);
} }
i = (size_t)hash & mask;
ix = dk_get_index(mp->ma_keys, i); PyDictKeyEntry *ep0 = DK_ENTRIES(mp->ma_keys);
assert (ix != DKIX_DUMMY); size_t mask = DK_MASK(mp->ma_keys);
if (ix == DKIX_EMPTY) { size_t perturb = (size_t)hash;
if (hashpos != NULL) size_t i = (size_t)hash & mask;
*hashpos = i;
*value_addr = NULL; for (;;) {
return DKIX_EMPTY; Py_ssize_t ix = dk_get_index(mp->ma_keys, i);
}
ep = &ep0[ix];
assert(ep->me_key != NULL);
assert(PyUnicode_CheckExact(ep->me_key));
if (ep->me_key == key ||
(ep->me_hash == hash && unicode_eq(ep->me_key, key))) {
if (hashpos != NULL)
*hashpos = i;
*value_addr = ep->me_value;
return ix;
}
for (size_t perturb = hash;;) {
perturb >>= PERTURB_SHIFT;
i = mask & (i*5 + perturb + 1);
ix = dk_get_index(mp->ma_keys, i);
assert (ix != DKIX_DUMMY); assert (ix != DKIX_DUMMY);
if (ix == DKIX_EMPTY) { if (ix == DKIX_EMPTY) {
if (hashpos != NULL)
*hashpos = i;
*value_addr = NULL; *value_addr = NULL;
return DKIX_EMPTY; return DKIX_EMPTY;
} }
ep = &ep0[ix]; PyDictKeyEntry *ep = &ep0[ix];
assert(ep->me_key != NULL && PyUnicode_CheckExact(ep->me_key)); assert(ep->me_key != NULL);
assert(PyUnicode_CheckExact(ep->me_key));
if (ep->me_key == key || if (ep->me_key == key ||
(ep->me_hash == hash && unicode_eq(ep->me_key, key))) { (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; return ix;
} }
perturb >>= PERTURB_SHIFT;
i = mask & (i*5 + perturb + 1);
} }
assert(0); /* NOT REACHED */ assert(0); /* NOT REACHED */
return 0; return 0;
...@@ -935,61 +820,40 @@ lookdict_unicode_nodummy(PyDictObject *mp, PyObject *key, ...@@ -935,61 +820,40 @@ lookdict_unicode_nodummy(PyDictObject *mp, PyObject *key,
*/ */
static Py_ssize_t _Py_HOT_FUNCTION static Py_ssize_t _Py_HOT_FUNCTION
lookdict_split(PyDictObject *mp, PyObject *key, lookdict_split(PyDictObject *mp, PyObject *key,
Py_hash_t hash, PyObject **value_addr, Py_ssize_t *hashpos) Py_hash_t hash, PyObject **value_addr)
{ {
size_t i;
size_t mask = DK_MASK(mp->ma_keys);
Py_ssize_t ix;
PyDictKeyEntry *ep, *ep0 = DK_ENTRIES(mp->ma_keys);
/* mp must split table */ /* mp must split table */
assert(mp->ma_values != NULL); assert(mp->ma_values != NULL);
if (!PyUnicode_CheckExact(key)) { if (!PyUnicode_CheckExact(key)) {
ix = lookdict(mp, key, hash, value_addr, hashpos); Py_ssize_t ix = lookdict(mp, key, hash, value_addr);
if (ix >= 0) { if (ix >= 0) {
*value_addr = mp->ma_values[ix]; *value_addr = mp->ma_values[ix];
} }
return ix; return ix;
} }
i = (size_t)hash & mask; PyDictKeyEntry *ep0 = DK_ENTRIES(mp->ma_keys);
ix = dk_get_index(mp->ma_keys, i); size_t mask = DK_MASK(mp->ma_keys);
if (ix == DKIX_EMPTY) { size_t perturb = (size_t)hash;
if (hashpos != NULL) size_t i = (size_t)hash & mask;
*hashpos = i;
*value_addr = NULL; for (;;) {
return DKIX_EMPTY; Py_ssize_t ix = dk_get_index(mp->ma_keys, i);
} assert (ix != DKIX_DUMMY);
assert(ix >= 0);
ep = &ep0[ix];
assert(ep->me_key != NULL && PyUnicode_CheckExact(ep->me_key));
if (ep->me_key == key ||
(ep->me_hash == hash && unicode_eq(ep->me_key, key))) {
if (hashpos != NULL)
*hashpos = i;
*value_addr = mp->ma_values[ix];
return ix;
}
for (size_t perturb = hash;;) {
perturb >>= PERTURB_SHIFT;
i = mask & (i*5 + perturb + 1);
ix = dk_get_index(mp->ma_keys, i);
if (ix == DKIX_EMPTY) { if (ix == DKIX_EMPTY) {
if (hashpos != NULL)
*hashpos = i;
*value_addr = NULL; *value_addr = NULL;
return DKIX_EMPTY; return DKIX_EMPTY;
} }
assert(ix >= 0); PyDictKeyEntry *ep = &ep0[ix];
ep = &ep0[ix]; assert(ep->me_key != NULL);
assert(ep->me_key != NULL && PyUnicode_CheckExact(ep->me_key)); assert(PyUnicode_CheckExact(ep->me_key));
if (ep->me_key == key || if (ep->me_key == key ||
(ep->me_hash == hash && unicode_eq(ep->me_key, key))) { (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; return ix;
} }
perturb >>= PERTURB_SHIFT;
i = mask & (i*5 + perturb + 1);
} }
assert(0); /* NOT REACHED */ assert(0); /* NOT REACHED */
return 0; return 0;
...@@ -1061,23 +925,19 @@ _PyDict_MaybeUntrack(PyObject *op) ...@@ -1061,23 +925,19 @@ _PyDict_MaybeUntrack(PyObject *op)
The dict must be combined. */ The dict must be combined. */
static Py_ssize_t static Py_ssize_t
find_empty_slot(PyDictKeysObject *keys, PyObject *key, Py_hash_t hash) find_empty_slot(PyDictKeysObject *keys, Py_hash_t hash)
{ {
size_t i; assert(keys != NULL);
size_t mask = DK_MASK(keys);
Py_ssize_t ix;
assert(key != NULL);
i = hash & mask; const size_t mask = DK_MASK(keys);
ix = dk_get_index(keys, i); size_t i = hash & mask;
for (size_t perturb = hash; ix != DKIX_EMPTY;) { Py_ssize_t ix = dk_get_index(keys, i);
for (size_t perturb = hash; ix >= 0;) {
perturb >>= PERTURB_SHIFT; perturb >>= PERTURB_SHIFT;
i = i*5 + perturb + 1; i = (i*5 + perturb + 1) & mask;
ix = dk_get_index(keys, i & mask); ix = dk_get_index(keys, i);
} }
assert(DK_ENTRIES(keys)[keys->dk_nentries].me_value == NULL); return i;
return i & mask;
} }
static int static int
...@@ -1096,7 +956,6 @@ insertdict(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject *value) ...@@ -1096,7 +956,6 @@ insertdict(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject *value)
{ {
PyObject *old_value; PyObject *old_value;
PyDictKeyEntry *ep; PyDictKeyEntry *ep;
Py_ssize_t hashpos, ix;
Py_INCREF(key); Py_INCREF(key);
Py_INCREF(value); Py_INCREF(value);
...@@ -1105,7 +964,7 @@ insertdict(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject *value) ...@@ -1105,7 +964,7 @@ insertdict(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject *value)
goto Fail; goto Fail;
} }
ix = mp->ma_keys->dk_lookup(mp, key, hash, &old_value, &hashpos); Py_ssize_t ix = mp->ma_keys->dk_lookup(mp, key, hash, &old_value);
if (ix == DKIX_ERROR) if (ix == DKIX_ERROR)
goto Fail; goto Fail;
...@@ -1120,7 +979,6 @@ insertdict(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject *value) ...@@ -1120,7 +979,6 @@ insertdict(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject *value)
(ix == DKIX_EMPTY && mp->ma_used != mp->ma_keys->dk_nentries))) { (ix == DKIX_EMPTY && mp->ma_used != mp->ma_keys->dk_nentries))) {
if (insertion_resize(mp) < 0) if (insertion_resize(mp) < 0)
goto Fail; goto Fail;
hashpos = find_empty_slot(mp->ma_keys, key, hash);
ix = DKIX_EMPTY; ix = DKIX_EMPTY;
} }
...@@ -1131,8 +989,8 @@ insertdict(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject *value) ...@@ -1131,8 +989,8 @@ insertdict(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject *value)
/* Need to resize. */ /* Need to resize. */
if (insertion_resize(mp) < 0) if (insertion_resize(mp) < 0)
goto Fail; goto Fail;
hashpos = find_empty_slot(mp->ma_keys, key, hash);
} }
Py_ssize_t hashpos = find_empty_slot(mp->ma_keys, hash);
ep = &DK_ENTRIES(mp->ma_keys)[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); dk_set_index(mp->ma_keys, hashpos, mp->ma_keys->dk_nentries);
ep->me_key = key; ep->me_key = key;
...@@ -1411,14 +1269,14 @@ PyDict_GetItem(PyObject *op, PyObject *key) ...@@ -1411,14 +1269,14 @@ PyDict_GetItem(PyObject *op, PyObject *key)
/* preserve the existing exception */ /* preserve the existing exception */
PyObject *err_type, *err_value, *err_tb; PyObject *err_type, *err_value, *err_tb;
PyErr_Fetch(&err_type, &err_value, &err_tb); PyErr_Fetch(&err_type, &err_value, &err_tb);
ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value, NULL); ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value);
/* ignore errors */ /* ignore errors */
PyErr_Restore(err_type, err_value, err_tb); PyErr_Restore(err_type, err_value, err_tb);
if (ix < 0) if (ix < 0)
return NULL; return NULL;
} }
else { else {
ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value, NULL); ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value);
if (ix < 0) { if (ix < 0) {
PyErr_Clear(); PyErr_Clear();
return NULL; return NULL;
...@@ -1443,7 +1301,7 @@ _PyDict_GetItem_KnownHash(PyObject *op, PyObject *key, Py_hash_t hash) ...@@ -1443,7 +1301,7 @@ _PyDict_GetItem_KnownHash(PyObject *op, PyObject *key, Py_hash_t hash)
return NULL; return NULL;
} }
ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value, NULL); ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value);
if (ix < 0) { if (ix < 0) {
return NULL; return NULL;
} }
...@@ -1475,7 +1333,7 @@ PyDict_GetItemWithError(PyObject *op, PyObject *key) ...@@ -1475,7 +1333,7 @@ PyDict_GetItemWithError(PyObject *op, PyObject *key)
} }
} }
ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value, NULL); ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value);
if (ix < 0) if (ix < 0)
return NULL; return NULL;
return value; return value;
...@@ -1514,14 +1372,14 @@ _PyDict_LoadGlobal(PyDictObject *globals, PyDictObject *builtins, PyObject *key) ...@@ -1514,14 +1372,14 @@ _PyDict_LoadGlobal(PyDictObject *globals, PyDictObject *builtins, PyObject *key)
} }
/* namespace 1: globals */ /* namespace 1: globals */
ix = globals->ma_keys->dk_lookup(globals, key, hash, &value, NULL); ix = globals->ma_keys->dk_lookup(globals, key, hash, &value);
if (ix == DKIX_ERROR) if (ix == DKIX_ERROR)
return NULL; return NULL;
if (ix != DKIX_EMPTY && value != NULL) if (ix != DKIX_EMPTY && value != NULL)
return value; return value;
/* namespace 2: builtins */ /* namespace 2: builtins */
ix = builtins->ma_keys->dk_lookup(builtins, key, hash, &value, NULL); ix = builtins->ma_keys->dk_lookup(builtins, key, hash, &value);
if (ix < 0) if (ix < 0)
return NULL; return NULL;
return value; return value;
...@@ -1577,12 +1435,15 @@ _PyDict_SetItem_KnownHash(PyObject *op, PyObject *key, PyObject *value, ...@@ -1577,12 +1435,15 @@ _PyDict_SetItem_KnownHash(PyObject *op, PyObject *key, PyObject *value,
} }
static int static int
delitem_common(PyDictObject *mp, Py_ssize_t hashpos, Py_ssize_t ix, delitem_common(PyDictObject *mp, Py_hash_t hash, Py_ssize_t ix,
PyObject *old_value) PyObject *old_value)
{ {
PyObject *old_key; PyObject *old_key;
PyDictKeyEntry *ep; PyDictKeyEntry *ep;
Py_ssize_t hashpos = lookdict_index(mp->ma_keys, hash, ix);
assert(hashpos >= 0);
mp->ma_used--; mp->ma_used--;
mp->ma_version_tag = DICT_NEXT_VERSION(); mp->ma_version_tag = DICT_NEXT_VERSION();
ep = &DK_ENTRIES(mp->ma_keys)[ix]; ep = &DK_ENTRIES(mp->ma_keys)[ix];
...@@ -1616,7 +1477,7 @@ PyDict_DelItem(PyObject *op, PyObject *key) ...@@ -1616,7 +1477,7 @@ PyDict_DelItem(PyObject *op, PyObject *key)
int int
_PyDict_DelItem_KnownHash(PyObject *op, PyObject *key, Py_hash_t hash) _PyDict_DelItem_KnownHash(PyObject *op, PyObject *key, Py_hash_t hash)
{ {
Py_ssize_t hashpos, ix; Py_ssize_t ix;
PyDictObject *mp; PyDictObject *mp;
PyObject *old_value; PyObject *old_value;
...@@ -1627,25 +1488,24 @@ _PyDict_DelItem_KnownHash(PyObject *op, PyObject *key, Py_hash_t hash) ...@@ -1627,25 +1488,24 @@ _PyDict_DelItem_KnownHash(PyObject *op, PyObject *key, Py_hash_t hash)
assert(key); assert(key);
assert(hash != -1); assert(hash != -1);
mp = (PyDictObject *)op; mp = (PyDictObject *)op;
ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &old_value, &hashpos); ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &old_value);
if (ix == DKIX_ERROR) if (ix == DKIX_ERROR)
return -1; return -1;
if (ix == DKIX_EMPTY || old_value == NULL) { if (ix == DKIX_EMPTY || old_value == NULL) {
_PyErr_SetKeyError(key); _PyErr_SetKeyError(key);
return -1; return -1;
} }
assert(dk_get_index(mp->ma_keys, hashpos) == ix);
// Split table doesn't allow deletion. Combine it. // Split table doesn't allow deletion. Combine it.
if (_PyDict_HasSplitTable(mp)) { if (_PyDict_HasSplitTable(mp)) {
if (dictresize(mp, DK_SIZE(mp->ma_keys))) { if (dictresize(mp, DK_SIZE(mp->ma_keys))) {
return -1; return -1;
} }
ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &old_value, &hashpos); ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &old_value);
assert(ix >= 0); assert(ix >= 0);
} }
return delitem_common(mp, hashpos, ix, old_value); return delitem_common(mp, hash, ix, old_value);
} }
/* This function promises that the predicate -> deletion sequence is atomic /* This function promises that the predicate -> deletion sequence is atomic
...@@ -1671,27 +1531,30 @@ _PyDict_DelItemIf(PyObject *op, PyObject *key, ...@@ -1671,27 +1531,30 @@ _PyDict_DelItemIf(PyObject *op, PyObject *key,
if (hash == -1) if (hash == -1)
return -1; return -1;
mp = (PyDictObject *)op; mp = (PyDictObject *)op;
ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &old_value, &hashpos); ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &old_value);
if (ix == DKIX_ERROR) if (ix == DKIX_ERROR)
return -1; return -1;
if (ix == DKIX_EMPTY || old_value == NULL) { if (ix == DKIX_EMPTY || old_value == NULL) {
_PyErr_SetKeyError(key); _PyErr_SetKeyError(key);
return -1; return -1;
} }
assert(dk_get_index(mp->ma_keys, hashpos) == ix);
// Split table doesn't allow deletion. Combine it. // Split table doesn't allow deletion. Combine it.
if (_PyDict_HasSplitTable(mp)) { if (_PyDict_HasSplitTable(mp)) {
if (dictresize(mp, DK_SIZE(mp->ma_keys))) { if (dictresize(mp, DK_SIZE(mp->ma_keys))) {
return -1; return -1;
} }
ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &old_value, &hashpos); ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &old_value);
assert(ix >= 0); assert(ix >= 0);
} }
res = predicate(old_value); res = predicate(old_value);
if (res == -1) if (res == -1)
return -1; return -1;
hashpos = lookdict_index(mp->ma_keys, hash, ix);
assert(hashpos >= 0);
if (res > 0) if (res > 0)
return delitem_common(mp, hashpos, ix, old_value); return delitem_common(mp, hashpos, ix, old_value);
else else
...@@ -1828,7 +1691,7 @@ _PyDict_Pop_KnownHash(PyObject *dict, PyObject *key, Py_hash_t hash, PyObject *d ...@@ -1828,7 +1691,7 @@ _PyDict_Pop_KnownHash(PyObject *dict, PyObject *key, Py_hash_t hash, PyObject *d
_PyErr_SetKeyError(key); _PyErr_SetKeyError(key);
return NULL; return NULL;
} }
ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &old_value, &hashpos); ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &old_value);
if (ix == DKIX_ERROR) if (ix == DKIX_ERROR)
return NULL; return NULL;
if (ix == DKIX_EMPTY || old_value == NULL) { if (ix == DKIX_EMPTY || old_value == NULL) {
...@@ -1845,10 +1708,12 @@ _PyDict_Pop_KnownHash(PyObject *dict, PyObject *key, Py_hash_t hash, PyObject *d ...@@ -1845,10 +1708,12 @@ _PyDict_Pop_KnownHash(PyObject *dict, PyObject *key, Py_hash_t hash, PyObject *d
if (dictresize(mp, DK_SIZE(mp->ma_keys))) { if (dictresize(mp, DK_SIZE(mp->ma_keys))) {
return NULL; return NULL;
} }
ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &old_value, &hashpos); ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &old_value);
assert(ix >= 0); assert(ix >= 0);
} }
hashpos = lookdict_index(mp->ma_keys, hash, ix);
assert(hashpos >= 0);
assert(old_value != NULL); assert(old_value != NULL);
mp->ma_used--; mp->ma_used--;
mp->ma_version_tag = DICT_NEXT_VERSION(); mp->ma_version_tag = DICT_NEXT_VERSION();
...@@ -2107,7 +1972,7 @@ dict_subscript(PyDictObject *mp, PyObject *key) ...@@ -2107,7 +1972,7 @@ dict_subscript(PyDictObject *mp, PyObject *key)
if (hash == -1) if (hash == -1)
return NULL; return NULL;
} }
ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value, NULL); ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value);
if (ix == DKIX_ERROR) if (ix == DKIX_ERROR)
return NULL; return NULL;
if (ix == DKIX_EMPTY || value == NULL) { if (ix == DKIX_EMPTY || value == NULL) {
...@@ -2718,7 +2583,7 @@ dict_equal(PyDictObject *a, PyDictObject *b) ...@@ -2718,7 +2583,7 @@ dict_equal(PyDictObject *a, PyDictObject *b)
/* ditto for key */ /* ditto for key */
Py_INCREF(key); Py_INCREF(key);
/* reuse the known hash value */ /* reuse the known hash value */
b->ma_keys->dk_lookup(b, key, ep->me_hash, &bval, NULL); b->ma_keys->dk_lookup(b, key, ep->me_hash, &bval);
if (bval == NULL) { if (bval == NULL) {
Py_DECREF(key); Py_DECREF(key);
Py_DECREF(aval); Py_DECREF(aval);
...@@ -2783,7 +2648,7 @@ dict___contains__(PyDictObject *self, PyObject *key) ...@@ -2783,7 +2648,7 @@ dict___contains__(PyDictObject *self, PyObject *key)
if (hash == -1) if (hash == -1)
return NULL; return NULL;
} }
ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value, NULL); ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value);
if (ix == DKIX_ERROR) if (ix == DKIX_ERROR)
return NULL; return NULL;
if (ix == DKIX_EMPTY || value == NULL) if (ix == DKIX_EMPTY || value == NULL)
...@@ -2815,7 +2680,7 @@ dict_get_impl(PyDictObject *self, PyObject *key, PyObject *default_value) ...@@ -2815,7 +2680,7 @@ dict_get_impl(PyDictObject *self, PyObject *key, PyObject *default_value)
if (hash == -1) if (hash == -1)
return NULL; return NULL;
} }
ix = (self->ma_keys->dk_lookup) (self, key, hash, &val, NULL); ix = (self->ma_keys->dk_lookup) (self, key, hash, &val);
if (ix == DKIX_ERROR) if (ix == DKIX_ERROR)
return NULL; return NULL;
if (ix == DKIX_EMPTY || val == NULL) { if (ix == DKIX_EMPTY || val == NULL) {
...@@ -2831,7 +2696,6 @@ PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *defaultobj) ...@@ -2831,7 +2696,6 @@ PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *defaultobj)
PyDictObject *mp = (PyDictObject *)d; PyDictObject *mp = (PyDictObject *)d;
PyObject *value; PyObject *value;
Py_hash_t hash; Py_hash_t hash;
Py_ssize_t hashpos, ix;
if (!PyDict_Check(d)) { if (!PyDict_Check(d)) {
PyErr_BadInternalCall(); PyErr_BadInternalCall();
...@@ -2850,7 +2714,7 @@ PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *defaultobj) ...@@ -2850,7 +2714,7 @@ PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *defaultobj)
return NULL; return NULL;
} }
ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value, &hashpos); Py_ssize_t ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value);
if (ix == DKIX_ERROR) if (ix == DKIX_ERROR)
return NULL; return NULL;
...@@ -2860,7 +2724,6 @@ PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *defaultobj) ...@@ -2860,7 +2724,6 @@ PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *defaultobj)
if (insertion_resize(mp) < 0) { if (insertion_resize(mp) < 0) {
return NULL; return NULL;
} }
hashpos = find_empty_slot(mp->ma_keys, key, hash);
ix = DKIX_EMPTY; ix = DKIX_EMPTY;
} }
...@@ -2871,8 +2734,8 @@ PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *defaultobj) ...@@ -2871,8 +2734,8 @@ PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *defaultobj)
if (insertion_resize(mp) < 0) { if (insertion_resize(mp) < 0) {
return NULL; return NULL;
} }
hashpos = find_empty_slot(mp->ma_keys, key, hash);
} }
Py_ssize_t hashpos = find_empty_slot(mp->ma_keys, hash);
ep0 = DK_ENTRIES(mp->ma_keys); ep0 = DK_ENTRIES(mp->ma_keys);
ep = &ep0[mp->ma_keys->dk_nentries]; ep = &ep0[mp->ma_keys->dk_nentries];
dk_set_index(mp->ma_keys, hashpos, mp->ma_keys->dk_nentries); dk_set_index(mp->ma_keys, hashpos, mp->ma_keys->dk_nentries);
...@@ -3167,7 +3030,7 @@ PyDict_Contains(PyObject *op, PyObject *key) ...@@ -3167,7 +3030,7 @@ PyDict_Contains(PyObject *op, PyObject *key)
if (hash == -1) if (hash == -1)
return -1; return -1;
} }
ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value, NULL); ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value);
if (ix == DKIX_ERROR) if (ix == DKIX_ERROR)
return -1; return -1;
return (ix != DKIX_EMPTY && value != NULL); return (ix != DKIX_EMPTY && value != NULL);
...@@ -3181,7 +3044,7 @@ _PyDict_Contains(PyObject *op, PyObject *key, Py_hash_t hash) ...@@ -3181,7 +3044,7 @@ _PyDict_Contains(PyObject *op, PyObject *key, Py_hash_t hash)
PyObject *value; PyObject *value;
Py_ssize_t ix; Py_ssize_t ix;
ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value, NULL); ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value);
if (ix == DKIX_ERROR) if (ix == DKIX_ERROR)
return -1; return -1;
return (ix != DKIX_EMPTY && value != NULL); return (ix != DKIX_EMPTY && value != NULL);
......
...@@ -546,7 +546,7 @@ _odict_get_index_raw(PyODictObject *od, PyObject *key, Py_hash_t hash) ...@@ -546,7 +546,7 @@ _odict_get_index_raw(PyODictObject *od, PyObject *key, Py_hash_t hash)
PyDictKeysObject *keys = ((PyDictObject *)od)->ma_keys; PyDictKeysObject *keys = ((PyDictObject *)od)->ma_keys;
Py_ssize_t ix; Py_ssize_t ix;
ix = (keys->dk_lookup)((PyDictObject *)od, key, hash, &value, NULL); ix = (keys->dk_lookup)((PyDictObject *)od, key, hash, &value);
if (ix == DKIX_EMPTY) { if (ix == DKIX_EMPTY) {
return keys->dk_nentries; /* index of new entry */ return keys->dk_nentries; /* index of new entry */
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment