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