• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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