|
|
|
@ -223,18 +223,14 @@ equally good collision statistics, needed less code & used less memory. |
|
|
|
|
|
|
|
/* forward declarations */ |
|
|
|
static Py_ssize_t lookdict(PyDictObject *mp, PyObject *key, |
|
|
|
Py_hash_t hash, PyObject **value_addr, |
|
|
|
Py_ssize_t *hashpos); |
|
|
|
Py_hash_t hash, PyObject **value_addr); |
|
|
|
static Py_ssize_t lookdict_unicode(PyDictObject *mp, PyObject *key, |
|
|
|
Py_hash_t hash, PyObject **value_addr, |
|
|
|
Py_ssize_t *hashpos); |
|
|
|
Py_hash_t hash, PyObject **value_addr); |
|
|
|
static Py_ssize_t |
|
|
|
lookdict_unicode_nodummy(PyDictObject *mp, PyObject *key, |
|
|
|
Py_hash_t hash, PyObject **value_addr, |
|
|
|
Py_ssize_t *hashpos); |
|
|
|
Py_hash_t hash, PyObject **value_addr); |
|
|
|
static Py_ssize_t lookdict_split(PyDictObject *mp, PyObject *key, |
|
|
|
Py_hash_t hash, PyObject **value_addr, |
|
|
|
Py_ssize_t *hashpos); |
|
|
|
Py_hash_t hash, PyObject **value_addr); |
|
|
|
|
|
|
|
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 |
|
|
|
is string. Otherwise, it falls back to lookdict(). |
|
|
|
lookdict_unicode_nodummy is further specialized for string keys that cannot be |
|
|
|
the <dummy> value. |
|
|
|
For both, when the key isn't found a DKIX_EMPTY is returned. hashpos returns |
|
|
|
where the key index should be inserted. |
|
|
|
For both, when the key isn't found a DKIX_EMPTY is returned. |
|
|
|
*/ |
|
|
|
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) |
|
|
|
{ |
|
|
|
size_t i, mask; |
|
|
|
Py_ssize_t ix, freeslot; |
|
|
|
int cmp; |
|
|
|
size_t i, mask, perturb; |
|
|
|
PyDictKeysObject *dk; |
|
|
|
PyDictKeyEntry *ep0, *ep; |
|
|
|
PyObject *startkey; |
|
|
|
PyDictKeyEntry *ep0; |
|
|
|
|
|
|
|
top: |
|
|
|
dk = mp->ma_keys; |
|
|
|
mask = DK_MASK(dk); |
|
|
|
ep0 = DK_ENTRIES(dk); |
|
|
|
mask = DK_MASK(dk); |
|
|
|
perturb = hash; |
|
|
|
i = (size_t)hash & mask; |
|
|
|
|
|
|
|
ix = dk_get_index(dk, 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) { |
|
|
|
*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); |
|
|
|
for (;;) { |
|
|
|
Py_ssize_t ix = dk_get_index(dk, i); |
|
|
|
if (ix == DKIX_EMPTY) { |
|
|
|
if (hashpos != NULL) { |
|
|
|
*hashpos = (freeslot == -1) ? (Py_ssize_t)i : freeslot; |
|
|
|
} |
|
|
|
*value_addr = NULL; |
|
|
|
return ix; |
|
|
|
} |
|
|
|
if (ix == DKIX_DUMMY) { |
|
|
|
if (freeslot == -1) |
|
|
|
freeslot = i; |
|
|
|
continue; |
|
|
|
} |
|
|
|
ep = &ep0[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 (ix >= 0) { |
|
|
|
PyDictKeyEntry *ep = &ep0[ix]; |
|
|
|
assert(ep->me_key != NULL); |
|
|
|
if (ep->me_key == key) { |
|
|
|
*value_addr = ep->me_value; |
|
|
|
return ix; |
|
|
|
} |
|
|
|
if (dk == mp->ma_keys && ep->me_key == startkey) { |
|
|
|
if (cmp > 0) { |
|
|
|
if (hashpos != NULL) { |
|
|
|
*hashpos = i; |
|
|
|
if (ep->me_hash == hash) { |
|
|
|
PyObject *startkey = ep->me_key; |
|
|
|
Py_INCREF(startkey); |
|
|
|
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 { |
|
|
|
/* The dict was mutated, restart */ |
|
|
|
goto top; |
|
|
|
else { |
|
|
|
/* The dict was mutated, restart */ |
|
|
|
goto top; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
perturb >>= PERTURB_SHIFT; |
|
|
|
i = (i*5 + perturb + 1) & mask; |
|
|
|
} |
|
|
|
assert(0); /* NOT REACHED */ |
|
|
|
return 0; |
|
|
|
@ -792,13 +729,8 @@ top: |
|
|
|
/* 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) |
|
|
|
{ |
|
|
|
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); |
|
|
|
/* Make sure this function doesn't have to handle non-unicode keys, |
|
|
|
including subclasses of str; e.g., one reason to subclass |
|
|
|
@ -806,59 +738,34 @@ lookdict_unicode(PyDictObject *mp, PyObject *key, |
|
|
|
that here. */ |
|
|
|
if (!PyUnicode_CheckExact(key)) { |
|
|
|
mp->ma_keys->dk_lookup = lookdict; |
|
|
|
return lookdict(mp, key, hash, value_addr, hashpos); |
|
|
|
} |
|
|
|
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; |
|
|
|
return lookdict(mp, key, hash, value_addr); |
|
|
|
} |
|
|
|
|
|
|
|
for (size_t perturb = hash;;) { |
|
|
|
perturb >>= PERTURB_SHIFT; |
|
|
|
i = mask & (i*5 + perturb + 1); |
|
|
|
ix = dk_get_index(mp->ma_keys, i); |
|
|
|
PyDictKeyEntry *ep0 = DK_ENTRIES(mp->ma_keys); |
|
|
|
size_t mask = DK_MASK(mp->ma_keys); |
|
|
|
size_t perturb = (size_t)hash; |
|
|
|
size_t i = (size_t)hash & mask; |
|
|
|
|
|
|
|
for (;;) { |
|
|
|
Py_ssize_t ix = dk_get_index(mp->ma_keys, i); |
|
|
|
if (ix == DKIX_EMPTY) { |
|
|
|
if (hashpos != NULL) { |
|
|
|
*hashpos = (freeslot == -1) ? (Py_ssize_t)i : freeslot; |
|
|
|
} |
|
|
|
*value_addr = NULL; |
|
|
|
return DKIX_EMPTY; |
|
|
|
} |
|
|
|
if (ix == DKIX_DUMMY) { |
|
|
|
if (freeslot == -1) |
|
|
|
freeslot = i; |
|
|
|
continue; |
|
|
|
} |
|
|
|
ep = &ep0[ix]; |
|
|
|
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; |
|
|
|
if (hashpos != NULL) { |
|
|
|
*hashpos = i; |
|
|
|
if (ix >= 0) { |
|
|
|
PyDictKeyEntry *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))) { |
|
|
|
*value_addr = ep->me_value; |
|
|
|
return ix; |
|
|
|
} |
|
|
|
return ix; |
|
|
|
} |
|
|
|
perturb >>= PERTURB_SHIFT; |
|
|
|
i = mask & (i*5 + perturb + 1); |
|
|
|
} |
|
|
|
|
|
|
|
assert(0); /* NOT REACHED */ |
|
|
|
return 0; |
|
|
|
} |
|
|
|
@ -867,14 +774,8 @@ lookdict_unicode(PyDictObject *mp, PyObject *key, |
|
|
|
* 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_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); |
|
|
|
|
|
|
|
assert(mp->ma_values == NULL); |
|
|
|
/* Make sure this function doesn't have to handle non-unicode keys, |
|
|
|
including subclasses of str; e.g., one reason to subclass |
|
|
|
@ -882,47 +783,31 @@ lookdict_unicode_nodummy(PyDictObject *mp, PyObject *key, |
|
|
|
that here. */ |
|
|
|
if (!PyUnicode_CheckExact(key)) { |
|
|
|
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); |
|
|
|
assert (ix != DKIX_DUMMY); |
|
|
|
if (ix == DKIX_EMPTY) { |
|
|
|
if (hashpos != NULL) |
|
|
|
*hashpos = i; |
|
|
|
*value_addr = NULL; |
|
|
|
return DKIX_EMPTY; |
|
|
|
} |
|
|
|
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); |
|
|
|
|
|
|
|
PyDictKeyEntry *ep0 = DK_ENTRIES(mp->ma_keys); |
|
|
|
size_t mask = DK_MASK(mp->ma_keys); |
|
|
|
size_t perturb = (size_t)hash; |
|
|
|
size_t i = (size_t)hash & mask; |
|
|
|
|
|
|
|
for (;;) { |
|
|
|
Py_ssize_t ix = dk_get_index(mp->ma_keys, i); |
|
|
|
assert (ix != DKIX_DUMMY); |
|
|
|
if (ix == DKIX_EMPTY) { |
|
|
|
if (hashpos != NULL) |
|
|
|
*hashpos = i; |
|
|
|
*value_addr = NULL; |
|
|
|
return DKIX_EMPTY; |
|
|
|
} |
|
|
|
ep = &ep0[ix]; |
|
|
|
assert(ep->me_key != NULL && PyUnicode_CheckExact(ep->me_key)); |
|
|
|
PyDictKeyEntry *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; |
|
|
|
} |
|
|
|
perturb >>= PERTURB_SHIFT; |
|
|
|
i = mask & (i*5 + perturb + 1); |
|
|
|
} |
|
|
|
assert(0); /* NOT REACHED */ |
|
|
|
return 0; |
|
|
|
@ -935,61 +820,40 @@ lookdict_unicode_nodummy(PyDictObject *mp, PyObject *key, |
|
|
|
*/ |
|
|
|
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) |
|
|
|
{ |
|
|
|
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 */ |
|
|
|
assert(mp->ma_values != NULL); |
|
|
|
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) { |
|
|
|
*value_addr = mp->ma_values[ix]; |
|
|
|
} |
|
|
|
return ix; |
|
|
|
} |
|
|
|
|
|
|
|
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; |
|
|
|
} |
|
|
|
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); |
|
|
|
PyDictKeyEntry *ep0 = DK_ENTRIES(mp->ma_keys); |
|
|
|
size_t mask = DK_MASK(mp->ma_keys); |
|
|
|
size_t perturb = (size_t)hash; |
|
|
|
size_t i = (size_t)hash & mask; |
|
|
|
|
|
|
|
for (;;) { |
|
|
|
Py_ssize_t ix = dk_get_index(mp->ma_keys, i); |
|
|
|
assert (ix != DKIX_DUMMY); |
|
|
|
if (ix == DKIX_EMPTY) { |
|
|
|
if (hashpos != NULL) |
|
|
|
*hashpos = i; |
|
|
|
*value_addr = NULL; |
|
|
|
return DKIX_EMPTY; |
|
|
|
} |
|
|
|
assert(ix >= 0); |
|
|
|
ep = &ep0[ix]; |
|
|
|
assert(ep->me_key != NULL && PyUnicode_CheckExact(ep->me_key)); |
|
|
|
PyDictKeyEntry *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 = mp->ma_values[ix]; |
|
|
|
return ix; |
|
|
|
} |
|
|
|
perturb >>= PERTURB_SHIFT; |
|
|
|
i = mask & (i*5 + perturb + 1); |
|
|
|
} |
|
|
|
assert(0); /* NOT REACHED */ |
|
|
|
return 0; |
|
|
|
@ -1061,23 +925,19 @@ _PyDict_MaybeUntrack(PyObject *op) |
|
|
|
|
|
|
|
The dict must be combined. */ |
|
|
|
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; |
|
|
|
size_t mask = DK_MASK(keys); |
|
|
|
Py_ssize_t ix; |
|
|
|
|
|
|
|
assert(key != NULL); |
|
|
|
assert(keys != NULL); |
|
|
|
|
|
|
|
i = hash & mask; |
|
|
|
ix = dk_get_index(keys, i); |
|
|
|
for (size_t perturb = hash; ix != DKIX_EMPTY;) { |
|
|
|
const size_t mask = DK_MASK(keys); |
|
|
|
size_t i = hash & mask; |
|
|
|
Py_ssize_t ix = dk_get_index(keys, i); |
|
|
|
for (size_t perturb = hash; ix >= 0;) { |
|
|
|
perturb >>= PERTURB_SHIFT; |
|
|
|
i = i*5 + perturb + 1; |
|
|
|
ix = dk_get_index(keys, i & mask); |
|
|
|
i = (i*5 + perturb + 1) & mask; |
|
|
|
ix = dk_get_index(keys, i); |
|
|
|
} |
|
|
|
assert(DK_ENTRIES(keys)[keys->dk_nentries].me_value == NULL); |
|
|
|
return i & mask; |
|
|
|
return i; |
|
|
|
} |
|
|
|
|
|
|
|
static int |
|
|
|
@ -1096,7 +956,6 @@ insertdict(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject *value) |
|
|
|
{ |
|
|
|
PyObject *old_value; |
|
|
|
PyDictKeyEntry *ep; |
|
|
|
Py_ssize_t hashpos, ix; |
|
|
|
|
|
|
|
Py_INCREF(key); |
|
|
|
Py_INCREF(value); |
|
|
|
@ -1105,7 +964,7 @@ insertdict(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject *value) |
|
|
|
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) |
|
|
|
goto Fail; |
|
|
|
|
|
|
|
@ -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))) { |
|
|
|
if (insertion_resize(mp) < 0) |
|
|
|
goto Fail; |
|
|
|
hashpos = find_empty_slot(mp->ma_keys, key, hash); |
|
|
|
ix = DKIX_EMPTY; |
|
|
|
} |
|
|
|
|
|
|
|
@ -1131,8 +989,8 @@ insertdict(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject *value) |
|
|
|
/* Need to resize. */ |
|
|
|
if (insertion_resize(mp) < 0) |
|
|
|
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]; |
|
|
|
dk_set_index(mp->ma_keys, hashpos, mp->ma_keys->dk_nentries); |
|
|
|
ep->me_key = key; |
|
|
|
@ -1411,14 +1269,14 @@ PyDict_GetItem(PyObject *op, PyObject *key) |
|
|
|
/* 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, NULL); |
|
|
|
ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value); |
|
|
|
/* 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, NULL); |
|
|
|
ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value); |
|
|
|
if (ix < 0) { |
|
|
|
PyErr_Clear(); |
|
|
|
return NULL; |
|
|
|
@ -1443,7 +1301,7 @@ _PyDict_GetItem_KnownHash(PyObject *op, PyObject *key, Py_hash_t hash) |
|
|
|
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) { |
|
|
|
return NULL; |
|
|
|
} |
|
|
|
@ -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) |
|
|
|
return NULL; |
|
|
|
return value; |
|
|
|
@ -1514,14 +1372,14 @@ _PyDict_LoadGlobal(PyDictObject *globals, PyDictObject *builtins, PyObject *key) |
|
|
|
} |
|
|
|
|
|
|
|
/* 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) |
|
|
|
return NULL; |
|
|
|
if (ix != DKIX_EMPTY && value != NULL) |
|
|
|
return value; |
|
|
|
|
|
|
|
/* 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) |
|
|
|
return NULL; |
|
|
|
return value; |
|
|
|
@ -1577,12 +1435,15 @@ _PyDict_SetItem_KnownHash(PyObject *op, PyObject *key, PyObject *value, |
|
|
|
} |
|
|
|
|
|
|
|
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_key; |
|
|
|
PyDictKeyEntry *ep; |
|
|
|
|
|
|
|
Py_ssize_t hashpos = lookdict_index(mp->ma_keys, hash, ix); |
|
|
|
assert(hashpos >= 0); |
|
|
|
|
|
|
|
mp->ma_used--; |
|
|
|
mp->ma_version_tag = DICT_NEXT_VERSION(); |
|
|
|
ep = &DK_ENTRIES(mp->ma_keys)[ix]; |
|
|
|
@ -1616,7 +1477,7 @@ PyDict_DelItem(PyObject *op, PyObject *key) |
|
|
|
int |
|
|
|
_PyDict_DelItem_KnownHash(PyObject *op, PyObject *key, Py_hash_t hash) |
|
|
|
{ |
|
|
|
Py_ssize_t hashpos, ix; |
|
|
|
Py_ssize_t ix; |
|
|
|
PyDictObject *mp; |
|
|
|
PyObject *old_value; |
|
|
|
|
|
|
|
@ -1627,25 +1488,24 @@ _PyDict_DelItem_KnownHash(PyObject *op, PyObject *key, Py_hash_t hash) |
|
|
|
assert(key); |
|
|
|
assert(hash != -1); |
|
|
|
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) |
|
|
|
return -1; |
|
|
|
if (ix == DKIX_EMPTY || old_value == NULL) { |
|
|
|
_PyErr_SetKeyError(key); |
|
|
|
return -1; |
|
|
|
} |
|
|
|
assert(dk_get_index(mp->ma_keys, hashpos) == ix); |
|
|
|
|
|
|
|
// Split table doesn't allow deletion. Combine it. |
|
|
|
if (_PyDict_HasSplitTable(mp)) { |
|
|
|
if (dictresize(mp, DK_SIZE(mp->ma_keys))) { |
|
|
|
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); |
|
|
|
} |
|
|
|
|
|
|
|
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 |
|
|
|
@ -1671,27 +1531,30 @@ _PyDict_DelItemIf(PyObject *op, PyObject *key, |
|
|
|
if (hash == -1) |
|
|
|
return -1; |
|
|
|
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) |
|
|
|
return -1; |
|
|
|
if (ix == DKIX_EMPTY || old_value == NULL) { |
|
|
|
_PyErr_SetKeyError(key); |
|
|
|
return -1; |
|
|
|
} |
|
|
|
assert(dk_get_index(mp->ma_keys, hashpos) == ix); |
|
|
|
|
|
|
|
// Split table doesn't allow deletion. Combine it. |
|
|
|
if (_PyDict_HasSplitTable(mp)) { |
|
|
|
if (dictresize(mp, DK_SIZE(mp->ma_keys))) { |
|
|
|
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); |
|
|
|
} |
|
|
|
|
|
|
|
res = predicate(old_value); |
|
|
|
if (res == -1) |
|
|
|
return -1; |
|
|
|
|
|
|
|
hashpos = lookdict_index(mp->ma_keys, hash, ix); |
|
|
|
assert(hashpos >= 0); |
|
|
|
|
|
|
|
if (res > 0) |
|
|
|
return delitem_common(mp, hashpos, ix, old_value); |
|
|
|
else |
|
|
|
@ -1828,7 +1691,7 @@ _PyDict_Pop_KnownHash(PyObject *dict, PyObject *key, Py_hash_t hash, PyObject *d |
|
|
|
_PyErr_SetKeyError(key); |
|
|
|
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) |
|
|
|
return 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 |
|
|
|
if (dictresize(mp, DK_SIZE(mp->ma_keys))) { |
|
|
|
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); |
|
|
|
} |
|
|
|
|
|
|
|
hashpos = lookdict_index(mp->ma_keys, hash, ix); |
|
|
|
assert(hashpos >= 0); |
|
|
|
assert(old_value != NULL); |
|
|
|
mp->ma_used--; |
|
|
|
mp->ma_version_tag = DICT_NEXT_VERSION(); |
|
|
|
@ -2107,7 +1972,7 @@ dict_subscript(PyDictObject *mp, PyObject *key) |
|
|
|
if (hash == -1) |
|
|
|
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) |
|
|
|
return NULL; |
|
|
|
if (ix == DKIX_EMPTY || value == NULL) { |
|
|
|
@ -2718,7 +2583,7 @@ dict_equal(PyDictObject *a, PyDictObject *b) |
|
|
|
/* ditto for key */ |
|
|
|
Py_INCREF(key); |
|
|
|
/* 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) { |
|
|
|
Py_DECREF(key); |
|
|
|
Py_DECREF(aval); |
|
|
|
@ -2783,7 +2648,7 @@ dict___contains__(PyDictObject *self, PyObject *key) |
|
|
|
if (hash == -1) |
|
|
|
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) |
|
|
|
return NULL; |
|
|
|
if (ix == DKIX_EMPTY || value == NULL) |
|
|
|
@ -2815,7 +2680,7 @@ dict_get_impl(PyDictObject *self, PyObject *key, PyObject *default_value) |
|
|
|
if (hash == -1) |
|
|
|
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) |
|
|
|
return NULL; |
|
|
|
if (ix == DKIX_EMPTY || val == NULL) { |
|
|
|
@ -2831,7 +2696,6 @@ PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *defaultobj) |
|
|
|
PyDictObject *mp = (PyDictObject *)d; |
|
|
|
PyObject *value; |
|
|
|
Py_hash_t hash; |
|
|
|
Py_ssize_t hashpos, ix; |
|
|
|
|
|
|
|
if (!PyDict_Check(d)) { |
|
|
|
PyErr_BadInternalCall(); |
|
|
|
@ -2850,7 +2714,7 @@ PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *defaultobj) |
|
|
|
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) |
|
|
|
return NULL; |
|
|
|
|
|
|
|
@ -2860,7 +2724,6 @@ PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *defaultobj) |
|
|
|
if (insertion_resize(mp) < 0) { |
|
|
|
return NULL; |
|
|
|
} |
|
|
|
hashpos = find_empty_slot(mp->ma_keys, key, hash); |
|
|
|
ix = DKIX_EMPTY; |
|
|
|
} |
|
|
|
|
|
|
|
@ -2871,8 +2734,8 @@ PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *defaultobj) |
|
|
|
if (insertion_resize(mp) < 0) { |
|
|
|
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); |
|
|
|
ep = &ep0[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) |
|
|
|
if (hash == -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) |
|
|
|
return -1; |
|
|
|
return (ix != DKIX_EMPTY && value != NULL); |
|
|
|
@ -3181,7 +3044,7 @@ _PyDict_Contains(PyObject *op, PyObject *key, Py_hash_t hash) |
|
|
|
PyObject *value; |
|
|
|
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) |
|
|
|
return -1; |
|
|
|
return (ix != DKIX_EMPTY && value != NULL); |
|
|
|
|