• Home
  • History
  • Annotate
  • 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 
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