Home | History | Annotate | Download | only in Objects
      1 #include "Python.h"
      2 #include "structmember.h"
      3 
      4 
      5 #define GET_WEAKREFS_LISTPTR(o) \
      6         ((PyWeakReference **) PyObject_GET_WEAKREFS_LISTPTR(o))
      7 
      8 
      9 Py_ssize_t
     10 _PyWeakref_GetWeakrefCount(PyWeakReference *head)
     11 {
     12     Py_ssize_t count = 0;
     13 
     14     while (head != NULL) {
     15         ++count;
     16         head = head->wr_next;
     17     }
     18     return count;
     19 }
     20 
     21 
     22 static void
     23 init_weakref(PyWeakReference *self, PyObject *ob, PyObject *callback)
     24 {
     25     self->hash = -1;
     26     self->wr_object = ob;
     27     Py_XINCREF(callback);
     28     self->wr_callback = callback;
     29 }
     30 
     31 static PyWeakReference *
     32 new_weakref(PyObject *ob, PyObject *callback)
     33 {
     34     PyWeakReference *result;
     35 
     36     result = PyObject_GC_New(PyWeakReference, &_PyWeakref_RefType);
     37     if (result) {
     38         init_weakref(result, ob, callback);
     39         PyObject_GC_Track(result);
     40     }
     41     return result;
     42 }
     43 
     44 
     45 /* This function clears the passed-in reference and removes it from the
     46  * list of weak references for the referent.  This is the only code that
     47  * removes an item from the doubly-linked list of weak references for an
     48  * object; it is also responsible for clearing the callback slot.
     49  */
     50 static void
     51 clear_weakref(PyWeakReference *self)
     52 {
     53     PyObject *callback = self->wr_callback;
     54 
     55     if (PyWeakref_GET_OBJECT(self) != Py_None) {
     56         PyWeakReference **list = GET_WEAKREFS_LISTPTR(
     57             PyWeakref_GET_OBJECT(self));
     58 
     59         if (*list == self)
     60             /* If 'self' is the end of the list (and thus self->wr_next == NULL)
     61                then the weakref list itself (and thus the value of *list) will
     62                end up being set to NULL. */
     63             *list = self->wr_next;
     64         self->wr_object = Py_None;
     65         if (self->wr_prev != NULL)
     66             self->wr_prev->wr_next = self->wr_next;
     67         if (self->wr_next != NULL)
     68             self->wr_next->wr_prev = self->wr_prev;
     69         self->wr_prev = NULL;
     70         self->wr_next = NULL;
     71     }
     72     if (callback != NULL) {
     73         Py_DECREF(callback);
     74         self->wr_callback = NULL;
     75     }
     76 }
     77 
     78 /* Cyclic gc uses this to *just* clear the passed-in reference, leaving
     79  * the callback intact and uncalled.  It must be possible to call self's
     80  * tp_dealloc() after calling this, so self has to be left in a sane enough
     81  * state for that to work.  We expect tp_dealloc to decref the callback
     82  * then.  The reason for not letting clear_weakref() decref the callback
     83  * right now is that if the callback goes away, that may in turn trigger
     84  * another callback (if a weak reference to the callback exists) -- running
     85  * arbitrary Python code in the middle of gc is a disaster.  The convolution
     86  * here allows gc to delay triggering such callbacks until the world is in
     87  * a sane state again.
     88  */
     89 void
     90 _PyWeakref_ClearRef(PyWeakReference *self)
     91 {
     92     PyObject *callback;
     93 
     94     assert(self != NULL);
     95     assert(PyWeakref_Check(self));
     96     /* Preserve and restore the callback around clear_weakref. */
     97     callback = self->wr_callback;
     98     self->wr_callback = NULL;
     99     clear_weakref(self);
    100     self->wr_callback = callback;
    101 }
    102 
    103 static void
    104 weakref_dealloc(PyObject *self)
    105 {
    106     PyObject_GC_UnTrack(self);
    107     clear_weakref((PyWeakReference *) self);
    108     Py_TYPE(self)->tp_free(self);
    109 }
    110 
    111 
    112 static int
    113 gc_traverse(PyWeakReference *self, visitproc visit, void *arg)
    114 {
    115     Py_VISIT(self->wr_callback);
    116     return 0;
    117 }
    118 
    119 
    120 static int
    121 gc_clear(PyWeakReference *self)
    122 {
    123     clear_weakref(self);
    124     return 0;
    125 }
    126 
    127 
    128 static PyObject *
    129 weakref_call(PyWeakReference *self, PyObject *args, PyObject *kw)
    130 {
    131     static char *kwlist[] = {NULL};
    132 
    133     if (PyArg_ParseTupleAndKeywords(args, kw, ":__call__", kwlist)) {
    134         PyObject *object = PyWeakref_GET_OBJECT(self);
    135         Py_INCREF(object);
    136         return (object);
    137     }
    138     return NULL;
    139 }
    140 
    141 
    142 static long
    143 weakref_hash(PyWeakReference *self)
    144 {
    145     if (self->hash != -1)
    146         return self->hash;
    147     if (PyWeakref_GET_OBJECT(self) == Py_None) {
    148         PyErr_SetString(PyExc_TypeError, "weak object has gone away");
    149         return -1;
    150     }
    151     self->hash = PyObject_Hash(PyWeakref_GET_OBJECT(self));
    152     return self->hash;
    153 }
    154 
    155 
    156 static PyObject *
    157 weakref_repr(PyWeakReference *self)
    158 {
    159     char buffer[256];
    160     if (PyWeakref_GET_OBJECT(self) == Py_None) {
    161         PyOS_snprintf(buffer, sizeof(buffer), "<weakref at %p; dead>", self);
    162     }
    163     else {
    164         char *name = NULL;
    165         PyObject *nameobj = PyObject_GetAttrString(PyWeakref_GET_OBJECT(self),
    166                                                    "__name__");
    167         if (nameobj == NULL)
    168                 PyErr_Clear();
    169         else if (PyString_Check(nameobj))
    170                 name = PyString_AS_STRING(nameobj);
    171         PyOS_snprintf(buffer, sizeof(buffer),
    172                       name ? "<weakref at %p; to '%.50s' at %p (%s)>"
    173                            : "<weakref at %p; to '%.50s' at %p>",
    174                       self,
    175                       Py_TYPE(PyWeakref_GET_OBJECT(self))->tp_name,
    176                       PyWeakref_GET_OBJECT(self),
    177                       name);
    178         Py_XDECREF(nameobj);
    179     }
    180     return PyString_FromString(buffer);
    181 }
    182 
    183 /* Weak references only support equality, not ordering. Two weak references
    184    are equal if the underlying objects are equal. If the underlying object has
    185    gone away, they are equal if they are identical. */
    186 
    187 static PyObject *
    188 weakref_richcompare(PyWeakReference* self, PyWeakReference* other, int op)
    189 {
    190     if (op != Py_EQ || self->ob_type != other->ob_type) {
    191         Py_INCREF(Py_NotImplemented);
    192         return Py_NotImplemented;
    193     }
    194     if (PyWeakref_GET_OBJECT(self) == Py_None
    195         || PyWeakref_GET_OBJECT(other) == Py_None) {
    196         PyObject *res = self==other ? Py_True : Py_False;
    197         Py_INCREF(res);
    198         return res;
    199     }
    200     return PyObject_RichCompare(PyWeakref_GET_OBJECT(self),
    201                                 PyWeakref_GET_OBJECT(other), op);
    202 }
    203 
    204 /* Given the head of an object's list of weak references, extract the
    205  * two callback-less refs (ref and proxy).  Used to determine if the
    206  * shared references exist and to determine the back link for newly
    207  * inserted references.
    208  */
    209 static void
    210 get_basic_refs(PyWeakReference *head,
    211                PyWeakReference **refp, PyWeakReference **proxyp)
    212 {
    213     *refp = NULL;
    214     *proxyp = NULL;
    215 
    216     if (head != NULL && head->wr_callback == NULL) {
    217         /* We need to be careful that the "basic refs" aren't
    218            subclasses of the main types.  That complicates this a
    219            little. */
    220         if (PyWeakref_CheckRefExact(head)) {
    221             *refp = head;
    222             head = head->wr_next;
    223         }
    224         if (head != NULL
    225             && head->wr_callback == NULL
    226             && PyWeakref_CheckProxy(head)) {
    227             *proxyp = head;
    228             /* head = head->wr_next; */
    229         }
    230     }
    231 }
    232 
    233 /* Insert 'newref' in the list after 'prev'.  Both must be non-NULL. */
    234 static void
    235 insert_after(PyWeakReference *newref, PyWeakReference *prev)
    236 {
    237     newref->wr_prev = prev;
    238     newref->wr_next = prev->wr_next;
    239     if (prev->wr_next != NULL)
    240         prev->wr_next->wr_prev = newref;
    241     prev->wr_next = newref;
    242 }
    243 
    244 /* Insert 'newref' at the head of the list; 'list' points to the variable
    245  * that stores the head.
    246  */
    247 static void
    248 insert_head(PyWeakReference *newref, PyWeakReference **list)
    249 {
    250     PyWeakReference *next = *list;
    251 
    252     newref->wr_prev = NULL;
    253     newref->wr_next = next;
    254     if (next != NULL)
    255         next->wr_prev = newref;
    256     *list = newref;
    257 }
    258 
    259 static int
    260 parse_weakref_init_args(char *funcname, PyObject *args, PyObject *kwargs,
    261                         PyObject **obp, PyObject **callbackp)
    262 {
    263     /* XXX Should check that kwargs == NULL or is empty. */
    264     return PyArg_UnpackTuple(args, funcname, 1, 2, obp, callbackp);
    265 }
    266 
    267 static PyObject *
    268 weakref___new__(PyTypeObject *type, PyObject *args, PyObject *kwargs)
    269 {
    270     PyWeakReference *self = NULL;
    271     PyObject *ob, *callback = NULL;
    272 
    273     if (parse_weakref_init_args("__new__", args, kwargs, &ob, &callback)) {
    274         PyWeakReference *ref, *proxy;
    275         PyWeakReference **list;
    276 
    277         if (!PyType_SUPPORTS_WEAKREFS(Py_TYPE(ob))) {
    278             PyErr_Format(PyExc_TypeError,
    279                          "cannot create weak reference to '%s' object",
    280                          Py_TYPE(ob)->tp_name);
    281             return NULL;
    282         }
    283         if (callback == Py_None)
    284             callback = NULL;
    285         list = GET_WEAKREFS_LISTPTR(ob);
    286         get_basic_refs(*list, &ref, &proxy);
    287         if (callback == NULL && type == &_PyWeakref_RefType) {
    288             if (ref != NULL) {
    289                 /* We can re-use an existing reference. */
    290                 Py_INCREF(ref);
    291                 return (PyObject *)ref;
    292             }
    293         }
    294         /* We have to create a new reference. */
    295         /* Note: the tp_alloc() can trigger cyclic GC, so the weakref
    296            list on ob can be mutated.  This means that the ref and
    297            proxy pointers we got back earlier may have been collected,
    298            so we need to compute these values again before we use
    299            them. */
    300         self = (PyWeakReference *) (type->tp_alloc(type, 0));
    301         if (self != NULL) {
    302             init_weakref(self, ob, callback);
    303             if (callback == NULL && type == &_PyWeakref_RefType) {
    304                 insert_head(self, list);
    305             }
    306             else {
    307                 PyWeakReference *prev;
    308 
    309                 get_basic_refs(*list, &ref, &proxy);
    310                 prev = (proxy == NULL) ? ref : proxy;
    311                 if (prev == NULL)
    312                     insert_head(self, list);
    313                 else
    314                     insert_after(self, prev);
    315             }
    316         }
    317     }
    318     return (PyObject *)self;
    319 }
    320 
    321 static int
    322 weakref___init__(PyObject *self, PyObject *args, PyObject *kwargs)
    323 {
    324     PyObject *tmp;
    325 
    326     if (parse_weakref_init_args("__init__", args, kwargs, &tmp, &tmp))
    327         return 0;
    328     else
    329         return -1;
    330 }
    331 
    332 
    333 PyTypeObject
    334 _PyWeakref_RefType = {
    335     PyVarObject_HEAD_INIT(&PyType_Type, 0)
    336     "weakref",
    337     sizeof(PyWeakReference),
    338     0,
    339     weakref_dealloc,            /*tp_dealloc*/
    340     0,                          /*tp_print*/
    341     0,                          /*tp_getattr*/
    342     0,                          /*tp_setattr*/
    343     0,                          /*tp_compare*/
    344     (reprfunc)weakref_repr,     /*tp_repr*/
    345     0,                          /*tp_as_number*/
    346     0,                          /*tp_as_sequence*/
    347     0,                          /*tp_as_mapping*/
    348     (hashfunc)weakref_hash,     /*tp_hash*/
    349     (ternaryfunc)weakref_call,  /*tp_call*/
    350     0,                          /*tp_str*/
    351     0,                          /*tp_getattro*/
    352     0,                          /*tp_setattro*/
    353     0,                          /*tp_as_buffer*/
    354     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_RICHCOMPARE
    355         | Py_TPFLAGS_BASETYPE,  /*tp_flags*/
    356     0,                          /*tp_doc*/
    357     (traverseproc)gc_traverse,  /*tp_traverse*/
    358     (inquiry)gc_clear,          /*tp_clear*/
    359     (richcmpfunc)weakref_richcompare,   /*tp_richcompare*/
    360     0,                          /*tp_weaklistoffset*/
    361     0,                          /*tp_iter*/
    362     0,                          /*tp_iternext*/
    363     0,                          /*tp_methods*/
    364     0,                          /*tp_members*/
    365     0,                          /*tp_getset*/
    366     0,                          /*tp_base*/
    367     0,                          /*tp_dict*/
    368     0,                          /*tp_descr_get*/
    369     0,                          /*tp_descr_set*/
    370     0,                          /*tp_dictoffset*/
    371     weakref___init__,           /*tp_init*/
    372     PyType_GenericAlloc,        /*tp_alloc*/
    373     weakref___new__,            /*tp_new*/
    374     PyObject_GC_Del,            /*tp_free*/
    375 };
    376 
    377 
    378 static int
    379 proxy_checkref(PyWeakReference *proxy)
    380 {
    381     if (PyWeakref_GET_OBJECT(proxy) == Py_None) {
    382         PyErr_SetString(PyExc_ReferenceError,
    383                         "weakly-referenced object no longer exists");
    384         return 0;
    385     }
    386     return 1;
    387 }
    388 
    389 
    390 /* If a parameter is a proxy, check that it is still "live" and wrap it,
    391  * replacing the original value with the raw object.  Raises ReferenceError
    392  * if the param is a dead proxy.
    393  */
    394 #define UNWRAP(o) \
    395         if (PyWeakref_CheckProxy(o)) { \
    396             if (!proxy_checkref((PyWeakReference *)o)) \
    397                 return NULL; \
    398             o = PyWeakref_GET_OBJECT(o); \
    399         }
    400 
    401 #define UNWRAP_I(o) \
    402         if (PyWeakref_CheckProxy(o)) { \
    403             if (!proxy_checkref((PyWeakReference *)o)) \
    404                 return -1; \
    405             o = PyWeakref_GET_OBJECT(o); \
    406         }
    407 
    408 #define WRAP_UNARY(method, generic) \
    409     static PyObject * \
    410     method(PyObject *proxy) { \
    411         UNWRAP(proxy); \
    412         return generic(proxy); \
    413     }
    414 
    415 #define WRAP_BINARY(method, generic) \
    416     static PyObject * \
    417     method(PyObject *x, PyObject *y) { \
    418         UNWRAP(x); \
    419         UNWRAP(y); \
    420         return generic(x, y); \
    421     }
    422 
    423 /* Note that the third arg needs to be checked for NULL since the tp_call
    424  * slot can receive NULL for this arg.
    425  */
    426 #define WRAP_TERNARY(method, generic) \
    427     static PyObject * \
    428     method(PyObject *proxy, PyObject *v, PyObject *w) { \
    429         UNWRAP(proxy); \
    430         UNWRAP(v); \
    431         if (w != NULL) \
    432             UNWRAP(w); \
    433         return generic(proxy, v, w); \
    434     }
    435 
    436 #define WRAP_METHOD(method, special) \
    437     static PyObject * \
    438     method(PyObject *proxy) { \
    439             UNWRAP(proxy); \
    440                 return PyObject_CallMethod(proxy, special, ""); \
    441         }
    442 
    443 
    444 /* direct slots */
    445 
    446 WRAP_BINARY(proxy_getattr, PyObject_GetAttr)
    447 WRAP_UNARY(proxy_str, PyObject_Str)
    448 WRAP_TERNARY(proxy_call, PyEval_CallObjectWithKeywords)
    449 
    450 static PyObject *
    451 proxy_repr(PyWeakReference *proxy)
    452 {
    453     char buf[160];
    454     PyOS_snprintf(buf, sizeof(buf),
    455                   "<weakproxy at %p to %.100s at %p>", proxy,
    456                   Py_TYPE(PyWeakref_GET_OBJECT(proxy))->tp_name,
    457                   PyWeakref_GET_OBJECT(proxy));
    458     return PyString_FromString(buf);
    459 }
    460 
    461 
    462 static int
    463 proxy_setattr(PyWeakReference *proxy, PyObject *name, PyObject *value)
    464 {
    465     if (!proxy_checkref(proxy))
    466         return -1;
    467     return PyObject_SetAttr(PyWeakref_GET_OBJECT(proxy), name, value);
    468 }
    469 
    470 static int
    471 proxy_compare(PyObject *proxy, PyObject *v)
    472 {
    473     UNWRAP_I(proxy);
    474     UNWRAP_I(v);
    475     return PyObject_Compare(proxy, v);
    476 }
    477 
    478 /* number slots */
    479 WRAP_BINARY(proxy_add, PyNumber_Add)
    480 WRAP_BINARY(proxy_sub, PyNumber_Subtract)
    481 WRAP_BINARY(proxy_mul, PyNumber_Multiply)
    482 WRAP_BINARY(proxy_div, PyNumber_Divide)
    483 WRAP_BINARY(proxy_floor_div, PyNumber_FloorDivide)
    484 WRAP_BINARY(proxy_true_div, PyNumber_TrueDivide)
    485 WRAP_BINARY(proxy_mod, PyNumber_Remainder)
    486 WRAP_BINARY(proxy_divmod, PyNumber_Divmod)
    487 WRAP_TERNARY(proxy_pow, PyNumber_Power)
    488 WRAP_UNARY(proxy_neg, PyNumber_Negative)
    489 WRAP_UNARY(proxy_pos, PyNumber_Positive)
    490 WRAP_UNARY(proxy_abs, PyNumber_Absolute)
    491 WRAP_UNARY(proxy_invert, PyNumber_Invert)
    492 WRAP_BINARY(proxy_lshift, PyNumber_Lshift)
    493 WRAP_BINARY(proxy_rshift, PyNumber_Rshift)
    494 WRAP_BINARY(proxy_and, PyNumber_And)
    495 WRAP_BINARY(proxy_xor, PyNumber_Xor)
    496 WRAP_BINARY(proxy_or, PyNumber_Or)
    497 WRAP_UNARY(proxy_int, PyNumber_Int)
    498 WRAP_UNARY(proxy_long, PyNumber_Long)
    499 WRAP_UNARY(proxy_float, PyNumber_Float)
    500 WRAP_BINARY(proxy_iadd, PyNumber_InPlaceAdd)
    501 WRAP_BINARY(proxy_isub, PyNumber_InPlaceSubtract)
    502 WRAP_BINARY(proxy_imul, PyNumber_InPlaceMultiply)
    503 WRAP_BINARY(proxy_idiv, PyNumber_InPlaceDivide)
    504 WRAP_BINARY(proxy_ifloor_div, PyNumber_InPlaceFloorDivide)
    505 WRAP_BINARY(proxy_itrue_div, PyNumber_InPlaceTrueDivide)
    506 WRAP_BINARY(proxy_imod, PyNumber_InPlaceRemainder)
    507 WRAP_TERNARY(proxy_ipow, PyNumber_InPlacePower)
    508 WRAP_BINARY(proxy_ilshift, PyNumber_InPlaceLshift)
    509 WRAP_BINARY(proxy_irshift, PyNumber_InPlaceRshift)
    510 WRAP_BINARY(proxy_iand, PyNumber_InPlaceAnd)
    511 WRAP_BINARY(proxy_ixor, PyNumber_InPlaceXor)
    512 WRAP_BINARY(proxy_ior, PyNumber_InPlaceOr)
    513 WRAP_UNARY(proxy_index, PyNumber_Index)
    514 
    515 static int
    516 proxy_nonzero(PyWeakReference *proxy)
    517 {
    518     PyObject *o = PyWeakref_GET_OBJECT(proxy);
    519     if (!proxy_checkref(proxy))
    520         return -1;
    521     return PyObject_IsTrue(o);
    522 }
    523 
    524 static void
    525 proxy_dealloc(PyWeakReference *self)
    526 {
    527     if (self->wr_callback != NULL)
    528         PyObject_GC_UnTrack((PyObject *)self);
    529     clear_weakref(self);
    530     PyObject_GC_Del(self);
    531 }
    532 
    533 /* sequence slots */
    534 
    535 static PyObject *
    536 proxy_slice(PyWeakReference *proxy, Py_ssize_t i, Py_ssize_t j)
    537 {
    538     if (!proxy_checkref(proxy))
    539         return NULL;
    540     return PySequence_GetSlice(PyWeakref_GET_OBJECT(proxy), i, j);
    541 }
    542 
    543 static int
    544 proxy_ass_slice(PyWeakReference *proxy, Py_ssize_t i, Py_ssize_t j, PyObject *value)
    545 {
    546     if (!proxy_checkref(proxy))
    547         return -1;
    548     return PySequence_SetSlice(PyWeakref_GET_OBJECT(proxy), i, j, value);
    549 }
    550 
    551 static int
    552 proxy_contains(PyWeakReference *proxy, PyObject *value)
    553 {
    554     if (!proxy_checkref(proxy))
    555         return -1;
    556     return PySequence_Contains(PyWeakref_GET_OBJECT(proxy), value);
    557 }
    558 
    559 
    560 /* mapping slots */
    561 
    562 static Py_ssize_t
    563 proxy_length(PyWeakReference *proxy)
    564 {
    565     if (!proxy_checkref(proxy))
    566         return -1;
    567     return PyObject_Length(PyWeakref_GET_OBJECT(proxy));
    568 }
    569 
    570 WRAP_BINARY(proxy_getitem, PyObject_GetItem)
    571 
    572 static int
    573 proxy_setitem(PyWeakReference *proxy, PyObject *key, PyObject *value)
    574 {
    575     if (!proxy_checkref(proxy))
    576         return -1;
    577 
    578     if (value == NULL)
    579         return PyObject_DelItem(PyWeakref_GET_OBJECT(proxy), key);
    580     else
    581         return PyObject_SetItem(PyWeakref_GET_OBJECT(proxy), key, value);
    582 }
    583 
    584 /* iterator slots */
    585 
    586 static PyObject *
    587 proxy_iter(PyWeakReference *proxy)
    588 {
    589     if (!proxy_checkref(proxy))
    590         return NULL;
    591     return PyObject_GetIter(PyWeakref_GET_OBJECT(proxy));
    592 }
    593 
    594 static PyObject *
    595 proxy_iternext(PyWeakReference *proxy)
    596 {
    597     if (!proxy_checkref(proxy))
    598         return NULL;
    599     return PyIter_Next(PyWeakref_GET_OBJECT(proxy));
    600 }
    601 
    602 
    603 WRAP_METHOD(proxy_unicode, "__unicode__");
    604 
    605 
    606 static PyMethodDef proxy_methods[] = {
    607         {"__unicode__", (PyCFunction)proxy_unicode, METH_NOARGS},
    608         {NULL, NULL}
    609 };
    610 
    611 
    612 static PyNumberMethods proxy_as_number = {
    613     proxy_add,              /*nb_add*/
    614     proxy_sub,              /*nb_subtract*/
    615     proxy_mul,              /*nb_multiply*/
    616     proxy_div,              /*nb_divide*/
    617     proxy_mod,              /*nb_remainder*/
    618     proxy_divmod,           /*nb_divmod*/
    619     proxy_pow,              /*nb_power*/
    620     proxy_neg,              /*nb_negative*/
    621     proxy_pos,              /*nb_positive*/
    622     proxy_abs,              /*nb_absolute*/
    623     (inquiry)proxy_nonzero, /*nb_nonzero*/
    624     proxy_invert,           /*nb_invert*/
    625     proxy_lshift,           /*nb_lshift*/
    626     proxy_rshift,           /*nb_rshift*/
    627     proxy_and,              /*nb_and*/
    628     proxy_xor,              /*nb_xor*/
    629     proxy_or,               /*nb_or*/
    630     0,                      /*nb_coerce*/
    631     proxy_int,              /*nb_int*/
    632     proxy_long,             /*nb_long*/
    633     proxy_float,            /*nb_float*/
    634     0,                      /*nb_oct*/
    635     0,                      /*nb_hex*/
    636     proxy_iadd,             /*nb_inplace_add*/
    637     proxy_isub,             /*nb_inplace_subtract*/
    638     proxy_imul,             /*nb_inplace_multiply*/
    639     proxy_idiv,             /*nb_inplace_divide*/
    640     proxy_imod,             /*nb_inplace_remainder*/
    641     proxy_ipow,             /*nb_inplace_power*/
    642     proxy_ilshift,          /*nb_inplace_lshift*/
    643     proxy_irshift,          /*nb_inplace_rshift*/
    644     proxy_iand,             /*nb_inplace_and*/
    645     proxy_ixor,             /*nb_inplace_xor*/
    646     proxy_ior,              /*nb_inplace_or*/
    647     proxy_floor_div,        /*nb_floor_divide*/
    648     proxy_true_div,         /*nb_true_divide*/
    649     proxy_ifloor_div,       /*nb_inplace_floor_divide*/
    650     proxy_itrue_div,        /*nb_inplace_true_divide*/
    651     proxy_index,            /*nb_index*/
    652 };
    653 
    654 static PySequenceMethods proxy_as_sequence = {
    655     (lenfunc)proxy_length,      /*sq_length*/
    656     0,                          /*sq_concat*/
    657     0,                          /*sq_repeat*/
    658     0,                          /*sq_item*/
    659     (ssizessizeargfunc)proxy_slice, /*sq_slice*/
    660     0,                          /*sq_ass_item*/
    661     (ssizessizeobjargproc)proxy_ass_slice, /*sq_ass_slice*/
    662     (objobjproc)proxy_contains, /* sq_contains */
    663 };
    664 
    665 static PyMappingMethods proxy_as_mapping = {
    666     (lenfunc)proxy_length,        /*mp_length*/
    667     proxy_getitem,                /*mp_subscript*/
    668     (objobjargproc)proxy_setitem, /*mp_ass_subscript*/
    669 };
    670 
    671 
    672 PyTypeObject
    673 _PyWeakref_ProxyType = {
    674     PyVarObject_HEAD_INIT(&PyType_Type, 0)
    675     "weakproxy",
    676     sizeof(PyWeakReference),
    677     0,
    678     /* methods */
    679     (destructor)proxy_dealloc,          /* tp_dealloc */
    680     0,                                  /* tp_print */
    681     0,                                  /* tp_getattr */
    682     0,                                  /* tp_setattr */
    683     proxy_compare,                      /* tp_compare */
    684     (reprfunc)proxy_repr,               /* tp_repr */
    685     &proxy_as_number,                   /* tp_as_number */
    686     &proxy_as_sequence,                 /* tp_as_sequence */
    687     &proxy_as_mapping,                  /* tp_as_mapping */
    688     0,                                  /* tp_hash */
    689     0,                                  /* tp_call */
    690     proxy_str,                          /* tp_str */
    691     proxy_getattr,                      /* tp_getattro */
    692     (setattrofunc)proxy_setattr,        /* tp_setattro */
    693     0,                                  /* tp_as_buffer */
    694     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC
    695     | Py_TPFLAGS_CHECKTYPES,            /* tp_flags */
    696     0,                                  /* tp_doc */
    697     (traverseproc)gc_traverse,          /* tp_traverse */
    698     (inquiry)gc_clear,                  /* tp_clear */
    699     0,                                  /* tp_richcompare */
    700     0,                                  /* tp_weaklistoffset */
    701     (getiterfunc)proxy_iter,            /* tp_iter */
    702     (iternextfunc)proxy_iternext,       /* tp_iternext */
    703         proxy_methods,                      /* tp_methods */
    704 };
    705 
    706 
    707 PyTypeObject
    708 _PyWeakref_CallableProxyType = {
    709     PyVarObject_HEAD_INIT(&PyType_Type, 0)
    710     "weakcallableproxy",
    711     sizeof(PyWeakReference),
    712     0,
    713     /* methods */
    714     (destructor)proxy_dealloc,          /* tp_dealloc */
    715     0,                                  /* tp_print */
    716     0,                                  /* tp_getattr */
    717     0,                                  /* tp_setattr */
    718     proxy_compare,                      /* tp_compare */
    719     (unaryfunc)proxy_repr,              /* tp_repr */
    720     &proxy_as_number,                   /* tp_as_number */
    721     &proxy_as_sequence,                 /* tp_as_sequence */
    722     &proxy_as_mapping,                  /* tp_as_mapping */
    723     0,                                  /* tp_hash */
    724     proxy_call,                         /* tp_call */
    725     proxy_str,                          /* tp_str */
    726     proxy_getattr,                      /* tp_getattro */
    727     (setattrofunc)proxy_setattr,        /* tp_setattro */
    728     0,                                  /* tp_as_buffer */
    729     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC
    730     | Py_TPFLAGS_CHECKTYPES,            /* tp_flags */
    731     0,                                  /* tp_doc */
    732     (traverseproc)gc_traverse,          /* tp_traverse */
    733     (inquiry)gc_clear,                  /* tp_clear */
    734     0,                                  /* tp_richcompare */
    735     0,                                  /* tp_weaklistoffset */
    736     (getiterfunc)proxy_iter,            /* tp_iter */
    737     (iternextfunc)proxy_iternext,       /* tp_iternext */
    738 };
    739 
    740 
    741 
    742 PyObject *
    743 PyWeakref_NewRef(PyObject *ob, PyObject *callback)
    744 {
    745     PyWeakReference *result = NULL;
    746     PyWeakReference **list;
    747     PyWeakReference *ref, *proxy;
    748 
    749     if (!PyType_SUPPORTS_WEAKREFS(Py_TYPE(ob))) {
    750         PyErr_Format(PyExc_TypeError,
    751                      "cannot create weak reference to '%s' object",
    752                      Py_TYPE(ob)->tp_name);
    753         return NULL;
    754     }
    755     list = GET_WEAKREFS_LISTPTR(ob);
    756     get_basic_refs(*list, &ref, &proxy);
    757     if (callback == Py_None)
    758         callback = NULL;
    759     if (callback == NULL)
    760         /* return existing weak reference if it exists */
    761         result = ref;
    762     if (result != NULL)
    763         Py_INCREF(result);
    764     else {
    765         /* Note: new_weakref() can trigger cyclic GC, so the weakref
    766            list on ob can be mutated.  This means that the ref and
    767            proxy pointers we got back earlier may have been collected,
    768            so we need to compute these values again before we use
    769            them. */
    770         result = new_weakref(ob, callback);
    771         if (result != NULL) {
    772             get_basic_refs(*list, &ref, &proxy);
    773             if (callback == NULL) {
    774                 if (ref == NULL)
    775                     insert_head(result, list);
    776                 else {
    777                     /* Someone else added a ref without a callback
    778                        during GC.  Return that one instead of this one
    779                        to avoid violating the invariants of the list
    780                        of weakrefs for ob. */
    781                     Py_DECREF(result);
    782                     Py_INCREF(ref);
    783                     result = ref;
    784                 }
    785             }
    786             else {
    787                 PyWeakReference *prev;
    788 
    789                 prev = (proxy == NULL) ? ref : proxy;
    790                 if (prev == NULL)
    791                     insert_head(result, list);
    792                 else
    793                     insert_after(result, prev);
    794             }
    795         }
    796     }
    797     return (PyObject *) result;
    798 }
    799 
    800 
    801 PyObject *
    802 PyWeakref_NewProxy(PyObject *ob, PyObject *callback)
    803 {
    804     PyWeakReference *result = NULL;
    805     PyWeakReference **list;
    806     PyWeakReference *ref, *proxy;
    807 
    808     if (!PyType_SUPPORTS_WEAKREFS(Py_TYPE(ob))) {
    809         PyErr_Format(PyExc_TypeError,
    810                      "cannot create weak reference to '%s' object",
    811                      Py_TYPE(ob)->tp_name);
    812         return NULL;
    813     }
    814     list = GET_WEAKREFS_LISTPTR(ob);
    815     get_basic_refs(*list, &ref, &proxy);
    816     if (callback == Py_None)
    817         callback = NULL;
    818     if (callback == NULL)
    819         /* attempt to return an existing weak reference if it exists */
    820         result = proxy;
    821     if (result != NULL)
    822         Py_INCREF(result);
    823     else {
    824         /* Note: new_weakref() can trigger cyclic GC, so the weakref
    825            list on ob can be mutated.  This means that the ref and
    826            proxy pointers we got back earlier may have been collected,
    827            so we need to compute these values again before we use
    828            them. */
    829         result = new_weakref(ob, callback);
    830         if (result != NULL) {
    831             PyWeakReference *prev;
    832 
    833             if (PyCallable_Check(ob))
    834                 Py_TYPE(result) = &_PyWeakref_CallableProxyType;
    835             else
    836                 Py_TYPE(result) = &_PyWeakref_ProxyType;
    837             get_basic_refs(*list, &ref, &proxy);
    838             if (callback == NULL) {
    839                 if (proxy != NULL) {
    840                     /* Someone else added a proxy without a callback
    841                        during GC.  Return that one instead of this one
    842                        to avoid violating the invariants of the list
    843                        of weakrefs for ob. */
    844                     Py_DECREF(result);
    845                     Py_INCREF(result = proxy);
    846                     goto skip_insert;
    847                 }
    848                 prev = ref;
    849             }
    850             else
    851                 prev = (proxy == NULL) ? ref : proxy;
    852 
    853             if (prev == NULL)
    854                 insert_head(result, list);
    855             else
    856                 insert_after(result, prev);
    857         skip_insert:
    858             ;
    859         }
    860     }
    861     return (PyObject *) result;
    862 }
    863 
    864 
    865 PyObject *
    866 PyWeakref_GetObject(PyObject *ref)
    867 {
    868     if (ref == NULL || !PyWeakref_Check(ref)) {
    869         PyErr_BadInternalCall();
    870         return NULL;
    871     }
    872     return PyWeakref_GET_OBJECT(ref);
    873 }
    874 
    875 /* Note that there's an inlined copy-paste of handle_callback() in gcmodule.c's
    876  * handle_weakrefs().
    877  */
    878 static void
    879 handle_callback(PyWeakReference *ref, PyObject *callback)
    880 {
    881     PyObject *cbresult = PyObject_CallFunctionObjArgs(callback, ref, NULL);
    882 
    883     if (cbresult == NULL)
    884         PyErr_WriteUnraisable(callback);
    885     else
    886         Py_DECREF(cbresult);
    887 }
    888 
    889 /* This function is called by the tp_dealloc handler to clear weak references.
    890  *
    891  * This iterates through the weak references for 'object' and calls callbacks
    892  * for those references which have one.  It returns when all callbacks have
    893  * been attempted.
    894  */
    895 void
    896 PyObject_ClearWeakRefs(PyObject *object)
    897 {
    898     PyWeakReference **list;
    899 
    900     if (object == NULL
    901         || !PyType_SUPPORTS_WEAKREFS(Py_TYPE(object))
    902         || object->ob_refcnt != 0) {
    903         PyErr_BadInternalCall();
    904         return;
    905     }
    906     list = GET_WEAKREFS_LISTPTR(object);
    907     /* Remove the callback-less basic and proxy references */
    908     if (*list != NULL && (*list)->wr_callback == NULL) {
    909         clear_weakref(*list);
    910         if (*list != NULL && (*list)->wr_callback == NULL)
    911             clear_weakref(*list);
    912     }
    913     if (*list != NULL) {
    914         PyWeakReference *current = *list;
    915         Py_ssize_t count = _PyWeakref_GetWeakrefCount(current);
    916         int restore_error = PyErr_Occurred() ? 1 : 0;
    917         PyObject *err_type    = NULL,
    918                  *err_value   = NULL,
    919                  *err_tb      = NULL;
    920 
    921         if (restore_error)
    922             PyErr_Fetch(&err_type, &err_value, &err_tb);
    923         if (count == 1) {
    924             PyObject *callback = current->wr_callback;
    925 
    926             current->wr_callback = NULL;
    927             clear_weakref(current);
    928             if (callback != NULL) {
    929                 if (current->ob_refcnt > 0)
    930                     handle_callback(current, callback);
    931                 Py_DECREF(callback);
    932             }
    933         }
    934         else {
    935             PyObject *tuple;
    936             Py_ssize_t i = 0;
    937 
    938             tuple = PyTuple_New(count * 2);
    939             if (tuple == NULL) {
    940                 if (restore_error)
    941                     PyErr_Fetch(&err_type, &err_value, &err_tb);
    942                 return;
    943             }
    944 
    945             for (i = 0; i < count; ++i) {
    946                 PyWeakReference *next = current->wr_next;
    947 
    948                 if (current->ob_refcnt > 0)
    949                 {
    950                     Py_INCREF(current);
    951                     PyTuple_SET_ITEM(tuple, i * 2, (PyObject *) current);
    952                     PyTuple_SET_ITEM(tuple, i * 2 + 1, current->wr_callback);
    953                 }
    954                 else {
    955                     Py_DECREF(current->wr_callback);
    956                 }
    957                 current->wr_callback = NULL;
    958                 clear_weakref(current);
    959                 current = next;
    960             }
    961             for (i = 0; i < count; ++i) {
    962                 PyObject *callback = PyTuple_GET_ITEM(tuple, i * 2 + 1);
    963 
    964                 /* The tuple may have slots left to NULL */
    965                 if (callback != NULL) {
    966                     PyObject *item = PyTuple_GET_ITEM(tuple, i * 2);
    967                     handle_callback((PyWeakReference *)item, callback);
    968                 }
    969             }
    970             Py_DECREF(tuple);
    971         }
    972         if (restore_error)
    973             PyErr_Restore(err_type, err_value, err_tb);
    974     }
    975 }
    976