Skip to content

Commit 8eeb4fe

Browse files
committed
Add _PyDictKeys_StringLookupAndVersion
Look up a unicode key in an all unicode keys object along with the keys version, assigning one if not present. We need a keys version that is consistent with presence of the key for use in the guards.
1 parent f802c8b commit 8eeb4fe

File tree

2 files changed

+45
-9
lines changed

2 files changed

+45
-9
lines changed

Include/internal/pycore_dict.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,18 @@ extern Py_ssize_t _Py_dict_lookup_threadsafe(PyDictObject *mp, PyObject *key, Py
113113
extern Py_ssize_t _Py_dict_lookup_threadsafe_stackref(PyDictObject *mp, PyObject *key, Py_hash_t hash, _PyStackRef *value_addr);
114114

115115
extern Py_ssize_t _PyDict_LookupIndex(PyDictObject *, PyObject *);
116+
116117
extern Py_ssize_t _PyDictKeys_StringLookup(PyDictKeysObject* dictkeys, PyObject *key);
118+
119+
/* Look up a string key in an all unicode dict keys, assign the keys object a version, and
120+
* stored it in version.
121+
*
122+
* Returns DKIX_ERROR if key is not a string or if the keys object is not all
123+
* strings.
124+
*
125+
* Returns DKIX_EMPTY if the key is not present.
126+
*/
127+
extern Py_ssize_t _PyDictKeys_StringLookupAndVersion(PyDictKeysObject* dictkeys, PyObject *key, uint32_t *version);
117128
PyAPI_FUNC(PyObject *)_PyDict_LoadGlobal(PyDictObject *, PyDictObject *, PyObject *);
118129
PyAPI_FUNC(void) _PyDict_LoadGlobalStackRef(PyDictObject *, PyDictObject *, PyObject *, _PyStackRef *);
119130

Objects/dictobject.c

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1129,6 +1129,23 @@ dictkeys_generic_lookup(PyDictObject *mp, PyDictKeysObject* dk, PyObject *key, P
11291129
return do_lookup(mp, dk, key, hash, compare_generic);
11301130
}
11311131

1132+
static Py_hash_t
1133+
check_keys_and_hash(PyDictKeysObject *dk, PyObject *key) {
1134+
DictKeysKind kind = dk->dk_kind;
1135+
if (!PyUnicode_CheckExact(key) || kind == DICT_KEYS_GENERAL) {
1136+
return -1;
1137+
}
1138+
Py_hash_t hash = unicode_get_hash(key);
1139+
if (hash == -1) {
1140+
hash = PyUnicode_Type.tp_hash(key);
1141+
if (hash == -1) {
1142+
PyErr_Clear();
1143+
return -1;
1144+
}
1145+
}
1146+
return hash;
1147+
}
1148+
11321149
/* Lookup a string in a (all unicode) dict keys.
11331150
* Returns DKIX_ERROR if key is not a string,
11341151
* or if the dict keys is not all strings.
@@ -1138,19 +1155,27 @@ dictkeys_generic_lookup(PyDictObject *mp, PyDictKeysObject* dk, PyObject *key, P
11381155
Py_ssize_t
11391156
_PyDictKeys_StringLookup(PyDictKeysObject* dk, PyObject *key)
11401157
{
1141-
DictKeysKind kind = dk->dk_kind;
1142-
if (!PyUnicode_CheckExact(key) || kind == DICT_KEYS_GENERAL) {
1158+
Py_hash_t hash = check_keys_and_hash(dk, key);
1159+
if (hash == -1) {
11431160
return DKIX_ERROR;
11441161
}
1145-
Py_hash_t hash = unicode_get_hash(key);
1162+
return unicodekeys_lookup_unicode(dk, key, hash);
1163+
}
1164+
1165+
Py_ssize_t
1166+
_PyDictKeys_StringLookupAndVersion(PyDictKeysObject* dk, PyObject *key, uint32_t *version)
1167+
{
1168+
Py_hash_t hash = check_keys_and_hash(dk, key);
11461169
if (hash == -1) {
1147-
hash = PyUnicode_Type.tp_hash(key);
1148-
if (hash == -1) {
1149-
PyErr_Clear();
1150-
return DKIX_ERROR;
1151-
}
1170+
return DKIX_ERROR;
11521171
}
1153-
return unicodekeys_lookup_unicode(dk, key, hash);
1172+
1173+
Py_ssize_t ix;
1174+
LOCK_KEYS(dk);
1175+
ix = unicodekeys_lookup_unicode(dk, key, hash);
1176+
*version = _PyDictKeys_GetVersionForCurrentState(_PyInterpreterState_GET(), dk);
1177+
UNLOCK_KEYS(dk);
1178+
return ix;
11541179
}
11551180

11561181
#ifdef Py_GIL_DISABLED

0 commit comments

Comments
 (0)