#include "Python.h" #define GET_WEAKREFS_LISTPTR(o) \ ((PyWeakReference **) PyObject_GET_WEAKREFS_LISTPTR(o)) static int is_dead_weakref(PyObject *value) { if (!PyWeakref_Check(value)) { PyErr_SetString(PyExc_TypeError, "not a weakref"); return -1; } return PyWeakref_GET_OBJECT(value) == Py_None; } PyDoc_STRVAR(remove_dead_weakref__doc__, "_remove_dead_weakref(dict, key) -- atomically remove key from dict\n" "if it points to a dead weakref."); static PyObject * remove_dead_weakref(PyObject *self, PyObject *args) { PyObject *dct, *key; if (!PyArg_ParseTuple(args, "O!O:_remove_dead_weakref", &PyDict_Type, &dct, &key)) { return NULL; } if (_PyDict_DelItemIf(dct, key, is_dead_weakref) < 0) { if (PyErr_ExceptionMatches(PyExc_KeyError)) /* This function is meant to allow safe weak-value dicts with GC in another thread (see issue #28427), so it's ok if the key doesn't exist anymore. */ PyErr_Clear(); else return NULL; } Py_RETURN_NONE; } PyDoc_STRVAR(weakref_getweakrefcount__doc__, "getweakrefcount(object) -- return the number of weak references\n" "to 'object'."); static PyObject * weakref_getweakrefcount(PyObject *self, PyObject *object) { PyObject *result = NULL; if (PyType_SUPPORTS_WEAKREFS(Py_TYPE(object))) { PyWeakReference **list = GET_WEAKREFS_LISTPTR(object); result = PyInt_FromSsize_t(_PyWeakref_GetWeakrefCount(*list)); } else result = PyInt_FromLong(0); return result; } PyDoc_STRVAR(weakref_getweakrefs__doc__, "getweakrefs(object) -- return a list of all weak reference objects\n" "that point to 'object'."); static PyObject * weakref_getweakrefs(PyObject *self, PyObject *object) { PyObject *result = NULL; if (PyType_SUPPORTS_WEAKREFS(Py_TYPE(object))) { PyWeakReference **list = GET_WEAKREFS_LISTPTR(object); Py_ssize_t count = _PyWeakref_GetWeakrefCount(*list); result = PyList_New(count); if (result != NULL) { PyWeakReference *current = *list; Py_ssize_t i; for (i = 0; i < count; ++i) { PyList_SET_ITEM(result, i, (PyObject *) current); Py_INCREF(current); current = current->wr_next; } } } else { result = PyList_New(0); } return result; } PyDoc_STRVAR(weakref_proxy__doc__, "proxy(object[, callback]) -- create a proxy object that weakly\n" "references 'object'. 'callback', if given, is called with a\n" "reference to the proxy when 'object' is about to be finalized."); static PyObject * weakref_proxy(PyObject *self, PyObject *args) { PyObject *object; PyObject *callback = NULL; PyObject *result = NULL; if (PyArg_UnpackTuple(args, "proxy", 1, 2, &object, &callback)) { result = PyWeakref_NewProxy(object, callback); } return result; } static PyMethodDef weakref_functions[] = { {"getweakrefcount", weakref_getweakrefcount, METH_O, weakref_getweakrefcount__doc__}, {"getweakrefs", weakref_getweakrefs, METH_O, weakref_getweakrefs__doc__}, {"proxy", weakref_proxy, METH_VARARGS, weakref_proxy__doc__}, {"_remove_dead_weakref", remove_dead_weakref, METH_VARARGS, remove_dead_weakref__doc__}, {NULL, NULL, 0, NULL} }; PyMODINIT_FUNC init_weakref(void) { PyObject *m; m = Py_InitModule3("_weakref", weakref_functions, "Weak-reference support module."); if (m != NULL) { Py_INCREF(&_PyWeakref_RefType); PyModule_AddObject(m, "ref", (PyObject *) &_PyWeakref_RefType); Py_INCREF(&_PyWeakref_RefType); PyModule_AddObject(m, "ReferenceType", (PyObject *) &_PyWeakref_RefType); Py_INCREF(&_PyWeakref_ProxyType); PyModule_AddObject(m, "ProxyType", (PyObject *) &_PyWeakref_ProxyType); Py_INCREF(&_PyWeakref_CallableProxyType); PyModule_AddObject(m, "CallableProxyType", (PyObject *) &_PyWeakref_CallableProxyType); } }