gh-91052: Add PyDict_Unwatch for unwatching a dictionary (#98055)

This commit is contained in:
Carl Meyer 2022-10-07 17:37:46 -07:00 committed by GitHub
parent 8ba9378b16
commit e82d977eb0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 116 additions and 29 deletions

View file

@ -5720,6 +5720,20 @@ uint32_t _PyDictKeys_GetVersionForCurrentState(PyDictKeysObject *dictkeys)
return v;
}
static inline int
validate_watcher_id(PyInterpreterState *interp, int watcher_id)
{
if (watcher_id < 0 || watcher_id >= DICT_MAX_WATCHERS) {
PyErr_Format(PyExc_ValueError, "Invalid dict watcher ID %d", watcher_id);
return -1;
}
if (!interp->dict_watchers[watcher_id]) {
PyErr_Format(PyExc_ValueError, "No dict watcher set for ID %d", watcher_id);
return -1;
}
return 0;
}
int
PyDict_Watch(int watcher_id, PyObject* dict)
{
@ -5727,19 +5741,29 @@ PyDict_Watch(int watcher_id, PyObject* dict)
PyErr_SetString(PyExc_ValueError, "Cannot watch non-dictionary");
return -1;
}
if (watcher_id < 0 || watcher_id >= DICT_MAX_WATCHERS) {
PyErr_Format(PyExc_ValueError, "Invalid dict watcher ID %d", watcher_id);
return -1;
}
PyInterpreterState *interp = _PyInterpreterState_GET();
if (!interp->dict_watchers[watcher_id]) {
PyErr_Format(PyExc_ValueError, "No dict watcher set for ID %d", watcher_id);
if (validate_watcher_id(interp, watcher_id)) {
return -1;
}
((PyDictObject*)dict)->ma_version_tag |= (1LL << watcher_id);
return 0;
}
int
PyDict_Unwatch(int watcher_id, PyObject* dict)
{
if (!PyDict_Check(dict)) {
PyErr_SetString(PyExc_ValueError, "Cannot watch non-dictionary");
return -1;
}
PyInterpreterState *interp = _PyInterpreterState_GET();
if (validate_watcher_id(interp, watcher_id)) {
return -1;
}
((PyDictObject*)dict)->ma_version_tag &= ~(1LL << watcher_id);
return 0;
}
int
PyDict_AddWatcher(PyDict_WatchCallback callback)
{
@ -5759,13 +5783,8 @@ PyDict_AddWatcher(PyDict_WatchCallback callback)
int
PyDict_ClearWatcher(int watcher_id)
{
if (watcher_id < 0 || watcher_id >= DICT_MAX_WATCHERS) {
PyErr_Format(PyExc_ValueError, "Invalid dict watcher ID %d", watcher_id);
return -1;
}
PyInterpreterState *interp = _PyInterpreterState_GET();
if (!interp->dict_watchers[watcher_id]) {
PyErr_Format(PyExc_ValueError, "No dict watcher set for ID %d", watcher_id);
if (validate_watcher_id(interp, watcher_id)) {
return -1;
}
interp->dict_watchers[watcher_id] = NULL;