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