Home | History | Annotate | Download | only in Modules
      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
     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
     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 *
     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 *
     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 *
    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
    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