1 #include "Python.h"
2
3
4 #define GET_WEAKREFS_LISTPTR(o) \
5 ((PyWeakReference **) PyObject_GET_WEAKREFS_LISTPTR(o))
6
7
8 static int
is_dead_weakref(PyObject * value)9 is_dead_weakref(PyObject *value)
10 {
11 if (!PyWeakref_Check(value)) {
12 PyErr_SetString(PyExc_TypeError, "not a weakref");
13 return -1;
14 }
15 return PyWeakref_GET_OBJECT(value) == Py_None;
16 }
17
18 PyDoc_STRVAR(remove_dead_weakref__doc__,
19 "_remove_dead_weakref(dict, key) -- atomically remove key from dict\n"
20 "if it points to a dead weakref.");
21
22 static PyObject *
remove_dead_weakref(PyObject * self,PyObject * args)23 remove_dead_weakref(PyObject *self, PyObject *args)
24 {
25 PyObject *dct, *key;
26
27 if (!PyArg_ParseTuple(args, "O!O:_remove_dead_weakref",
28 &PyDict_Type, &dct, &key)) {
29 return NULL;
30 }
31 if (_PyDict_DelItemIf(dct, key, is_dead_weakref) < 0) {
32 if (PyErr_ExceptionMatches(PyExc_KeyError))
33 /* This function is meant to allow safe weak-value dicts
34 with GC in another thread (see issue #28427), so it's
35 ok if the key doesn't exist anymore.
36 */
37 PyErr_Clear();
38 else
39 return NULL;
40 }
41 Py_RETURN_NONE;
42 }
43
44
45 PyDoc_STRVAR(weakref_getweakrefcount__doc__,
46 "getweakrefcount(object) -- return the number of weak references\n"
47 "to 'object'.");
48
49 static PyObject *
weakref_getweakrefcount(PyObject * self,PyObject * object)50 weakref_getweakrefcount(PyObject *self, PyObject *object)
51 {
52 PyObject *result = NULL;
53
54 if (PyType_SUPPORTS_WEAKREFS(Py_TYPE(object))) {
55 PyWeakReference **list = GET_WEAKREFS_LISTPTR(object);
56
57 result = PyInt_FromSsize_t(_PyWeakref_GetWeakrefCount(*list));
58 }
59 else
60 result = PyInt_FromLong(0);
61
62 return result;
63 }
64
65
66 PyDoc_STRVAR(weakref_getweakrefs__doc__,
67 "getweakrefs(object) -- return a list of all weak reference objects\n"
68 "that point to 'object'.");
69
70 static PyObject *
weakref_getweakrefs(PyObject * self,PyObject * object)71 weakref_getweakrefs(PyObject *self, PyObject *object)
72 {
73 PyObject *result = NULL;
74
75 if (PyType_SUPPORTS_WEAKREFS(Py_TYPE(object))) {
76 PyWeakReference **list = GET_WEAKREFS_LISTPTR(object);
77 Py_ssize_t count = _PyWeakref_GetWeakrefCount(*list);
78
79 result = PyList_New(count);
80 if (result != NULL) {
81 PyWeakReference *current = *list;
82 Py_ssize_t i;
83 for (i = 0; i < count; ++i) {
84 PyList_SET_ITEM(result, i, (PyObject *) current);
85 Py_INCREF(current);
86 current = current->wr_next;
87 }
88 }
89 }
90 else {
91 result = PyList_New(0);
92 }
93 return result;
94 }
95
96
97 PyDoc_STRVAR(weakref_proxy__doc__,
98 "proxy(object[, callback]) -- create a proxy object that weakly\n"
99 "references 'object'. 'callback', if given, is called with a\n"
100 "reference to the proxy when 'object' is about to be finalized.");
101
102 static PyObject *
weakref_proxy(PyObject * self,PyObject * args)103 weakref_proxy(PyObject *self, PyObject *args)
104 {
105 PyObject *object;
106 PyObject *callback = NULL;
107 PyObject *result = NULL;
108
109 if (PyArg_UnpackTuple(args, "proxy", 1, 2, &object, &callback)) {
110 result = PyWeakref_NewProxy(object, callback);
111 }
112 return result;
113 }
114
115
116 static PyMethodDef
117 weakref_functions[] = {
118 {"getweakrefcount", weakref_getweakrefcount, METH_O,
119 weakref_getweakrefcount__doc__},
120 {"getweakrefs", weakref_getweakrefs, METH_O,
121 weakref_getweakrefs__doc__},
122 {"proxy", weakref_proxy, METH_VARARGS,
123 weakref_proxy__doc__},
124 {"_remove_dead_weakref", remove_dead_weakref, METH_VARARGS,
125 remove_dead_weakref__doc__},
126 {NULL, NULL, 0, NULL}
127 };
128
129
130 PyMODINIT_FUNC
init_weakref(void)131 init_weakref(void)
132 {
133 PyObject *m;
134
135 m = Py_InitModule3("_weakref", weakref_functions,
136 "Weak-reference support module.");
137 if (m != NULL) {
138 Py_INCREF(&_PyWeakref_RefType);
139 PyModule_AddObject(m, "ref",
140 (PyObject *) &_PyWeakref_RefType);
141 Py_INCREF(&_PyWeakref_RefType);
142 PyModule_AddObject(m, "ReferenceType",
143 (PyObject *) &_PyWeakref_RefType);
144 Py_INCREF(&_PyWeakref_ProxyType);
145 PyModule_AddObject(m, "ProxyType",
146 (PyObject *) &_PyWeakref_ProxyType);
147 Py_INCREF(&_PyWeakref_CallableProxyType);
148 PyModule_AddObject(m, "CallableProxyType",
149 (PyObject *) &_PyWeakref_CallableProxyType);
150 }
151 }
152