Skip to content

Commit 4b74fba

Browse files
committed
Issue 21101: Internal API for dict getitem and setitem where the hash value is known.
1 parent 1b5eebc commit 4b74fba

2 files changed

Lines changed: 60 additions & 0 deletions

File tree

Include/dictobject.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ PyAPI_DATA(PyTypeObject) PyDictValues_Type;
5050

5151
PyAPI_FUNC(PyObject *) PyDict_New(void);
5252
PyAPI_FUNC(PyObject *) PyDict_GetItem(PyObject *mp, PyObject *key);
53+
PyAPI_FUNC(PyObject *) _PyDict_GetItem_KnownHash(PyObject *mp, PyObject *key,
54+
Py_hash_t hash);
5355
PyAPI_FUNC(PyObject *) PyDict_GetItemWithError(PyObject *mp, PyObject *key);
5456
PyAPI_FUNC(PyObject *) _PyDict_GetItemIdWithError(PyObject *dp,
5557
struct _Py_Identifier *key);
@@ -58,6 +60,8 @@ PyAPI_FUNC(PyObject *) PyDict_SetDefault(
5860
PyObject *mp, PyObject *key, PyObject *defaultobj);
5961
#endif
6062
PyAPI_FUNC(int) PyDict_SetItem(PyObject *mp, PyObject *key, PyObject *item);
63+
PyAPI_FUNC(int) _PyDict_SetItem_KnownHash(PyObject *mp, PyObject *key,
64+
PyObject *item, Py_hash_t hash);
6165
PyAPI_FUNC(int) PyDict_DelItem(PyObject *mp, PyObject *key);
6266
PyAPI_FUNC(void) PyDict_Clear(PyObject *mp);
6367
PyAPI_FUNC(int) PyDict_Next(

Objects/dictobject.c

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1101,6 +1101,44 @@ PyDict_GetItem(PyObject *op, PyObject *key)
11011101
return *value_addr;
11021102
}
11031103

1104+
PyObject *
1105+
_PyDict_GetItem_KnownHash(PyObject *op, PyObject *key, Py_hash_t hash)
1106+
{
1107+
PyDictObject *mp = (PyDictObject *)op;
1108+
PyDictKeyEntry *ep;
1109+
PyThreadState *tstate;
1110+
PyObject **value_addr;
1111+
1112+
if (!PyDict_Check(op))
1113+
return NULL;
1114+
1115+
/* We can arrive here with a NULL tstate during initialization: try
1116+
running "python -Wi" for an example related to string interning.
1117+
Let's just hope that no exception occurs then... This must be
1118+
_PyThreadState_Current and not PyThreadState_GET() because in debug
1119+
mode, the latter complains if tstate is NULL. */
1120+
tstate = (PyThreadState*)_Py_atomic_load_relaxed(
1121+
&_PyThreadState_Current);
1122+
if (tstate != NULL && tstate->curexc_type != NULL) {
1123+
/* preserve the existing exception */
1124+
PyObject *err_type, *err_value, *err_tb;
1125+
PyErr_Fetch(&err_type, &err_value, &err_tb);
1126+
ep = (mp->ma_keys->dk_lookup)(mp, key, hash, &value_addr);
1127+
/* ignore errors */
1128+
PyErr_Restore(err_type, err_value, err_tb);
1129+
if (ep == NULL)
1130+
return NULL;
1131+
}
1132+
else {
1133+
ep = (mp->ma_keys->dk_lookup)(mp, key, hash, &value_addr);
1134+
if (ep == NULL) {
1135+
PyErr_Clear();
1136+
return NULL;
1137+
}
1138+
}
1139+
return *value_addr;
1140+
}
1141+
11041142
/* Variant of PyDict_GetItem() that doesn't suppress exceptions.
11051143
This returns NULL *with* an exception set if an exception occurred.
11061144
It returns NULL *without* an exception set if the key wasn't present.
@@ -1207,6 +1245,24 @@ PyDict_SetItem(PyObject *op, PyObject *key, PyObject *value)
12071245
return insertdict(mp, key, hash, value);
12081246
}
12091247

1248+
int
1249+
_PyDict_SetItem_KnownHash(PyObject *op, PyObject *key, PyObject *value,
1250+
Py_hash_t hash)
1251+
{
1252+
PyDictObject *mp;
1253+
1254+
if (!PyDict_Check(op)) {
1255+
PyErr_BadInternalCall();
1256+
return -1;
1257+
}
1258+
assert(key);
1259+
assert(value);
1260+
mp = (PyDictObject *)op;
1261+
1262+
/* insertdict() handles any resizing that might be necessary */
1263+
return insertdict(mp, key, hash, value);
1264+
}
1265+
12101266
int
12111267
PyDict_DelItem(PyObject *op, PyObject *key)
12121268
{

0 commit comments

Comments
 (0)