symbian-qemu-0.9.1-12/python-2.6.1/Objects/weakrefobject.c
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     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 
       
   437 /* direct slots */
       
   438 
       
   439 WRAP_BINARY(proxy_getattr, PyObject_GetAttr)
       
   440 WRAP_UNARY(proxy_str, PyObject_Str)
       
   441 WRAP_TERNARY(proxy_call, PyEval_CallObjectWithKeywords)
       
   442 
       
   443 static PyObject *
       
   444 proxy_repr(PyWeakReference *proxy)
       
   445 {
       
   446     char buf[160];
       
   447     PyOS_snprintf(buf, sizeof(buf),
       
   448 		  "<weakproxy at %p to %.100s at %p>", proxy,
       
   449 		  Py_TYPE(PyWeakref_GET_OBJECT(proxy))->tp_name,
       
   450 		  PyWeakref_GET_OBJECT(proxy));
       
   451     return PyString_FromString(buf);
       
   452 }
       
   453 
       
   454 
       
   455 static int
       
   456 proxy_setattr(PyWeakReference *proxy, PyObject *name, PyObject *value)
       
   457 {
       
   458     if (!proxy_checkref(proxy))
       
   459         return -1;
       
   460     return PyObject_SetAttr(PyWeakref_GET_OBJECT(proxy), name, value);
       
   461 }
       
   462 
       
   463 static int
       
   464 proxy_compare(PyObject *proxy, PyObject *v)
       
   465 {
       
   466     UNWRAP_I(proxy);
       
   467     UNWRAP_I(v);
       
   468     return PyObject_Compare(proxy, v);
       
   469 }
       
   470 
       
   471 /* number slots */
       
   472 WRAP_BINARY(proxy_add, PyNumber_Add)
       
   473 WRAP_BINARY(proxy_sub, PyNumber_Subtract)
       
   474 WRAP_BINARY(proxy_mul, PyNumber_Multiply)
       
   475 WRAP_BINARY(proxy_div, PyNumber_Divide)
       
   476 WRAP_BINARY(proxy_floor_div, PyNumber_FloorDivide)
       
   477 WRAP_BINARY(proxy_true_div, PyNumber_TrueDivide)
       
   478 WRAP_BINARY(proxy_mod, PyNumber_Remainder)
       
   479 WRAP_BINARY(proxy_divmod, PyNumber_Divmod)
       
   480 WRAP_TERNARY(proxy_pow, PyNumber_Power)
       
   481 WRAP_UNARY(proxy_neg, PyNumber_Negative)
       
   482 WRAP_UNARY(proxy_pos, PyNumber_Positive)
       
   483 WRAP_UNARY(proxy_abs, PyNumber_Absolute)
       
   484 WRAP_UNARY(proxy_invert, PyNumber_Invert)
       
   485 WRAP_BINARY(proxy_lshift, PyNumber_Lshift)
       
   486 WRAP_BINARY(proxy_rshift, PyNumber_Rshift)
       
   487 WRAP_BINARY(proxy_and, PyNumber_And)
       
   488 WRAP_BINARY(proxy_xor, PyNumber_Xor)
       
   489 WRAP_BINARY(proxy_or, PyNumber_Or)
       
   490 WRAP_UNARY(proxy_int, PyNumber_Int)
       
   491 WRAP_UNARY(proxy_long, PyNumber_Long)
       
   492 WRAP_UNARY(proxy_float, PyNumber_Float)
       
   493 WRAP_BINARY(proxy_iadd, PyNumber_InPlaceAdd)
       
   494 WRAP_BINARY(proxy_isub, PyNumber_InPlaceSubtract)
       
   495 WRAP_BINARY(proxy_imul, PyNumber_InPlaceMultiply)
       
   496 WRAP_BINARY(proxy_idiv, PyNumber_InPlaceDivide)
       
   497 WRAP_BINARY(proxy_ifloor_div, PyNumber_InPlaceFloorDivide)
       
   498 WRAP_BINARY(proxy_itrue_div, PyNumber_InPlaceTrueDivide)
       
   499 WRAP_BINARY(proxy_imod, PyNumber_InPlaceRemainder)
       
   500 WRAP_TERNARY(proxy_ipow, PyNumber_InPlacePower)
       
   501 WRAP_BINARY(proxy_ilshift, PyNumber_InPlaceLshift)
       
   502 WRAP_BINARY(proxy_irshift, PyNumber_InPlaceRshift)
       
   503 WRAP_BINARY(proxy_iand, PyNumber_InPlaceAnd)
       
   504 WRAP_BINARY(proxy_ixor, PyNumber_InPlaceXor)
       
   505 WRAP_BINARY(proxy_ior, PyNumber_InPlaceOr)
       
   506 WRAP_UNARY(proxy_index, PyNumber_Index)
       
   507 
       
   508 static int
       
   509 proxy_nonzero(PyWeakReference *proxy)
       
   510 {
       
   511     PyObject *o = PyWeakref_GET_OBJECT(proxy);
       
   512     if (!proxy_checkref(proxy))
       
   513         return -1;
       
   514     return PyObject_IsTrue(o);
       
   515 }
       
   516 
       
   517 static void
       
   518 proxy_dealloc(PyWeakReference *self)
       
   519 {
       
   520     if (self->wr_callback != NULL)
       
   521         PyObject_GC_UnTrack((PyObject *)self);
       
   522     clear_weakref(self);
       
   523     PyObject_GC_Del(self);
       
   524 }
       
   525 
       
   526 /* sequence slots */
       
   527 
       
   528 static PyObject *
       
   529 proxy_slice(PyWeakReference *proxy, Py_ssize_t i, Py_ssize_t j)
       
   530 {
       
   531     if (!proxy_checkref(proxy))
       
   532         return NULL;
       
   533     return PySequence_GetSlice(PyWeakref_GET_OBJECT(proxy), i, j);
       
   534 }
       
   535 
       
   536 static int
       
   537 proxy_ass_slice(PyWeakReference *proxy, Py_ssize_t i, Py_ssize_t j, PyObject *value)
       
   538 {
       
   539     if (!proxy_checkref(proxy))
       
   540         return -1;
       
   541     return PySequence_SetSlice(PyWeakref_GET_OBJECT(proxy), i, j, value);
       
   542 }
       
   543 
       
   544 static int
       
   545 proxy_contains(PyWeakReference *proxy, PyObject *value)
       
   546 {
       
   547     if (!proxy_checkref(proxy))
       
   548         return -1;
       
   549     return PySequence_Contains(PyWeakref_GET_OBJECT(proxy), value);
       
   550 }
       
   551 
       
   552 
       
   553 /* mapping slots */
       
   554 
       
   555 static Py_ssize_t
       
   556 proxy_length(PyWeakReference *proxy)
       
   557 {
       
   558     if (!proxy_checkref(proxy))
       
   559         return -1;
       
   560     return PyObject_Length(PyWeakref_GET_OBJECT(proxy));
       
   561 }
       
   562 
       
   563 WRAP_BINARY(proxy_getitem, PyObject_GetItem)
       
   564 
       
   565 static int
       
   566 proxy_setitem(PyWeakReference *proxy, PyObject *key, PyObject *value)
       
   567 {
       
   568     if (!proxy_checkref(proxy))
       
   569         return -1;
       
   570 
       
   571     if (value == NULL)
       
   572         return PyObject_DelItem(PyWeakref_GET_OBJECT(proxy), key);
       
   573     else
       
   574         return PyObject_SetItem(PyWeakref_GET_OBJECT(proxy), key, value);
       
   575 }
       
   576 
       
   577 /* iterator slots */
       
   578 
       
   579 static PyObject *
       
   580 proxy_iter(PyWeakReference *proxy)
       
   581 {
       
   582     if (!proxy_checkref(proxy))
       
   583         return NULL;
       
   584     return PyObject_GetIter(PyWeakref_GET_OBJECT(proxy));
       
   585 }
       
   586 
       
   587 static PyObject *
       
   588 proxy_iternext(PyWeakReference *proxy)
       
   589 {
       
   590     if (!proxy_checkref(proxy))
       
   591         return NULL;
       
   592     return PyIter_Next(PyWeakref_GET_OBJECT(proxy));
       
   593 }
       
   594 
       
   595 
       
   596 static PyNumberMethods proxy_as_number = {
       
   597     proxy_add,              /*nb_add*/
       
   598     proxy_sub,              /*nb_subtract*/
       
   599     proxy_mul,              /*nb_multiply*/
       
   600     proxy_div,              /*nb_divide*/
       
   601     proxy_mod,              /*nb_remainder*/
       
   602     proxy_divmod,           /*nb_divmod*/
       
   603     proxy_pow,              /*nb_power*/
       
   604     proxy_neg,              /*nb_negative*/
       
   605     proxy_pos,              /*nb_positive*/
       
   606     proxy_abs,              /*nb_absolute*/
       
   607     (inquiry)proxy_nonzero, /*nb_nonzero*/
       
   608     proxy_invert,           /*nb_invert*/
       
   609     proxy_lshift,           /*nb_lshift*/
       
   610     proxy_rshift,           /*nb_rshift*/
       
   611     proxy_and,              /*nb_and*/
       
   612     proxy_xor,              /*nb_xor*/
       
   613     proxy_or,               /*nb_or*/
       
   614     0,                      /*nb_coerce*/
       
   615     proxy_int,              /*nb_int*/
       
   616     proxy_long,             /*nb_long*/
       
   617     proxy_float,            /*nb_float*/
       
   618     0,                      /*nb_oct*/
       
   619     0,                      /*nb_hex*/
       
   620     proxy_iadd,             /*nb_inplace_add*/
       
   621     proxy_isub,             /*nb_inplace_subtract*/
       
   622     proxy_imul,             /*nb_inplace_multiply*/
       
   623     proxy_idiv,             /*nb_inplace_divide*/
       
   624     proxy_imod,             /*nb_inplace_remainder*/
       
   625     proxy_ipow,             /*nb_inplace_power*/
       
   626     proxy_ilshift,          /*nb_inplace_lshift*/
       
   627     proxy_irshift,          /*nb_inplace_rshift*/
       
   628     proxy_iand,             /*nb_inplace_and*/
       
   629     proxy_ixor,             /*nb_inplace_xor*/
       
   630     proxy_ior,              /*nb_inplace_or*/
       
   631     proxy_floor_div,        /*nb_floor_divide*/
       
   632     proxy_true_div,         /*nb_true_divide*/
       
   633     proxy_ifloor_div,       /*nb_inplace_floor_divide*/
       
   634     proxy_itrue_div,        /*nb_inplace_true_divide*/
       
   635     proxy_index,            /*nb_index*/
       
   636 };
       
   637 
       
   638 static PySequenceMethods proxy_as_sequence = {
       
   639     (lenfunc)proxy_length,      /*sq_length*/
       
   640     0,                          /*sq_concat*/
       
   641     0,                          /*sq_repeat*/
       
   642     0,                          /*sq_item*/
       
   643     (ssizessizeargfunc)proxy_slice, /*sq_slice*/
       
   644     0,                          /*sq_ass_item*/
       
   645     (ssizessizeobjargproc)proxy_ass_slice, /*sq_ass_slice*/
       
   646     (objobjproc)proxy_contains, /* sq_contains */
       
   647 };
       
   648 
       
   649 static PyMappingMethods proxy_as_mapping = {
       
   650     (lenfunc)proxy_length,        /*mp_length*/
       
   651     proxy_getitem,                /*mp_subscript*/
       
   652     (objobjargproc)proxy_setitem, /*mp_ass_subscript*/
       
   653 };
       
   654 
       
   655 
       
   656 PyTypeObject
       
   657 _PyWeakref_ProxyType = {
       
   658     PyVarObject_HEAD_INIT(&PyType_Type, 0)
       
   659     "weakproxy",
       
   660     sizeof(PyWeakReference),
       
   661     0,
       
   662     /* methods */
       
   663     (destructor)proxy_dealloc,          /* tp_dealloc */
       
   664     0,				        /* tp_print */
       
   665     0,				        /* tp_getattr */
       
   666     0, 				        /* tp_setattr */
       
   667     proxy_compare,		        /* tp_compare */
       
   668     (reprfunc)proxy_repr,	        /* tp_repr */
       
   669     &proxy_as_number,		        /* tp_as_number */
       
   670     &proxy_as_sequence,		        /* tp_as_sequence */
       
   671     &proxy_as_mapping,		        /* tp_as_mapping */
       
   672     0,	                                /* tp_hash */
       
   673     0,	                                /* tp_call */
       
   674     proxy_str,                          /* tp_str */
       
   675     proxy_getattr,                      /* tp_getattro */
       
   676     (setattrofunc)proxy_setattr,        /* tp_setattro */
       
   677     0,				        /* tp_as_buffer */
       
   678     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC
       
   679     | Py_TPFLAGS_CHECKTYPES,            /* tp_flags */
       
   680     0,                                  /* tp_doc */
       
   681     (traverseproc)gc_traverse,          /* tp_traverse */
       
   682     (inquiry)gc_clear,                  /* tp_clear */
       
   683     0,                                  /* tp_richcompare */
       
   684     0,                                  /* tp_weaklistoffset */
       
   685     (getiterfunc)proxy_iter,            /* tp_iter */
       
   686     (iternextfunc)proxy_iternext,       /* tp_iternext */
       
   687 };
       
   688 
       
   689 
       
   690 PyTypeObject
       
   691 _PyWeakref_CallableProxyType = {
       
   692     PyVarObject_HEAD_INIT(&PyType_Type, 0)
       
   693     "weakcallableproxy",
       
   694     sizeof(PyWeakReference),
       
   695     0,
       
   696     /* methods */
       
   697     (destructor)proxy_dealloc,          /* tp_dealloc */
       
   698     0,				        /* tp_print */
       
   699     0,				        /* tp_getattr */
       
   700     0, 				        /* tp_setattr */
       
   701     proxy_compare,		        /* tp_compare */
       
   702     (unaryfunc)proxy_repr,	        /* tp_repr */
       
   703     &proxy_as_number,		        /* tp_as_number */
       
   704     &proxy_as_sequence,		        /* tp_as_sequence */
       
   705     &proxy_as_mapping,		        /* tp_as_mapping */
       
   706     0,	                                /* tp_hash */
       
   707     proxy_call,	                        /* tp_call */
       
   708     proxy_str,	                        /* tp_str */
       
   709     proxy_getattr,                      /* tp_getattro */
       
   710     (setattrofunc)proxy_setattr,        /* tp_setattro */
       
   711     0,				        /* tp_as_buffer */
       
   712     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC
       
   713     | Py_TPFLAGS_CHECKTYPES,            /* tp_flags */
       
   714     0,                                  /* tp_doc */
       
   715     (traverseproc)gc_traverse,          /* tp_traverse */
       
   716     (inquiry)gc_clear,                  /* tp_clear */
       
   717     0,                                  /* tp_richcompare */
       
   718     0,                                  /* tp_weaklistoffset */
       
   719     (getiterfunc)proxy_iter,            /* tp_iter */
       
   720     (iternextfunc)proxy_iternext,       /* tp_iternext */
       
   721 };
       
   722 
       
   723 
       
   724 
       
   725 PyObject *
       
   726 PyWeakref_NewRef(PyObject *ob, PyObject *callback)
       
   727 {
       
   728     PyWeakReference *result = NULL;
       
   729     PyWeakReference **list;
       
   730     PyWeakReference *ref, *proxy;
       
   731 
       
   732     if (!PyType_SUPPORTS_WEAKREFS(Py_TYPE(ob))) {
       
   733         PyErr_Format(PyExc_TypeError,
       
   734 		     "cannot create weak reference to '%s' object",
       
   735                      Py_TYPE(ob)->tp_name);
       
   736         return NULL;
       
   737     }
       
   738     list = GET_WEAKREFS_LISTPTR(ob);
       
   739     get_basic_refs(*list, &ref, &proxy);
       
   740     if (callback == Py_None)
       
   741         callback = NULL;
       
   742     if (callback == NULL)
       
   743         /* return existing weak reference if it exists */
       
   744         result = ref;
       
   745     if (result != NULL)
       
   746         Py_INCREF(result);
       
   747     else {
       
   748         /* Note: new_weakref() can trigger cyclic GC, so the weakref
       
   749            list on ob can be mutated.  This means that the ref and
       
   750            proxy pointers we got back earlier may have been collected,
       
   751            so we need to compute these values again before we use
       
   752            them. */
       
   753         result = new_weakref(ob, callback);
       
   754         if (result != NULL) {
       
   755             get_basic_refs(*list, &ref, &proxy);
       
   756             if (callback == NULL) {
       
   757                 if (ref == NULL)
       
   758                     insert_head(result, list);
       
   759                 else {
       
   760                     /* Someone else added a ref without a callback
       
   761                        during GC.  Return that one instead of this one
       
   762                        to avoid violating the invariants of the list
       
   763                        of weakrefs for ob. */
       
   764                     Py_DECREF(result);
       
   765                     Py_INCREF(ref);
       
   766                     result = ref;
       
   767                 }
       
   768             }
       
   769             else {
       
   770                 PyWeakReference *prev;
       
   771 
       
   772                 prev = (proxy == NULL) ? ref : proxy;
       
   773                 if (prev == NULL)
       
   774                     insert_head(result, list);
       
   775                 else
       
   776                     insert_after(result, prev);
       
   777             }
       
   778         }
       
   779     }
       
   780     return (PyObject *) result;
       
   781 }
       
   782 
       
   783 
       
   784 PyObject *
       
   785 PyWeakref_NewProxy(PyObject *ob, PyObject *callback)
       
   786 {
       
   787     PyWeakReference *result = NULL;
       
   788     PyWeakReference **list;
       
   789     PyWeakReference *ref, *proxy;
       
   790 
       
   791     if (!PyType_SUPPORTS_WEAKREFS(Py_TYPE(ob))) {
       
   792         PyErr_Format(PyExc_TypeError,
       
   793 		     "cannot create weak reference to '%s' object",
       
   794                      Py_TYPE(ob)->tp_name);
       
   795         return NULL;
       
   796     }
       
   797     list = GET_WEAKREFS_LISTPTR(ob);
       
   798     get_basic_refs(*list, &ref, &proxy);
       
   799     if (callback == Py_None)
       
   800         callback = NULL;
       
   801     if (callback == NULL)
       
   802         /* attempt to return an existing weak reference if it exists */
       
   803         result = proxy;
       
   804     if (result != NULL)
       
   805         Py_INCREF(result);
       
   806     else {
       
   807         /* Note: new_weakref() can trigger cyclic GC, so the weakref
       
   808            list on ob can be mutated.  This means that the ref and
       
   809            proxy pointers we got back earlier may have been collected,
       
   810            so we need to compute these values again before we use
       
   811            them. */
       
   812         result = new_weakref(ob, callback);
       
   813         if (result != NULL) {
       
   814             PyWeakReference *prev;
       
   815 
       
   816             if (PyCallable_Check(ob))
       
   817                 Py_TYPE(result) = &_PyWeakref_CallableProxyType;
       
   818             else
       
   819                 Py_TYPE(result) = &_PyWeakref_ProxyType;
       
   820             get_basic_refs(*list, &ref, &proxy);
       
   821             if (callback == NULL) {
       
   822                 if (proxy != NULL) {
       
   823                     /* Someone else added a proxy without a callback
       
   824                        during GC.  Return that one instead of this one
       
   825                        to avoid violating the invariants of the list
       
   826                        of weakrefs for ob. */
       
   827                     Py_DECREF(result);
       
   828                     Py_INCREF(result = proxy);
       
   829                     goto skip_insert;
       
   830                 }
       
   831                 prev = ref;
       
   832             }
       
   833             else
       
   834                 prev = (proxy == NULL) ? ref : proxy;
       
   835 
       
   836             if (prev == NULL)
       
   837                 insert_head(result, list);
       
   838             else
       
   839                 insert_after(result, prev);
       
   840         skip_insert:
       
   841             ;
       
   842         }
       
   843     }
       
   844     return (PyObject *) result;
       
   845 }
       
   846 
       
   847 
       
   848 PyObject *
       
   849 PyWeakref_GetObject(PyObject *ref)
       
   850 {
       
   851     if (ref == NULL || !PyWeakref_Check(ref)) {
       
   852         PyErr_BadInternalCall();
       
   853         return NULL;
       
   854     }
       
   855     return PyWeakref_GET_OBJECT(ref);
       
   856 }
       
   857 
       
   858 /* Note that there's an inlined copy-paste of handle_callback() in gcmodule.c's
       
   859  * handle_weakrefs().
       
   860  */
       
   861 static void
       
   862 handle_callback(PyWeakReference *ref, PyObject *callback)
       
   863 {
       
   864     PyObject *cbresult = PyObject_CallFunctionObjArgs(callback, ref, NULL);
       
   865 
       
   866     if (cbresult == NULL)
       
   867         PyErr_WriteUnraisable(callback);
       
   868     else
       
   869         Py_DECREF(cbresult);
       
   870 }
       
   871 
       
   872 /* This function is called by the tp_dealloc handler to clear weak references.
       
   873  *
       
   874  * This iterates through the weak references for 'object' and calls callbacks
       
   875  * for those references which have one.  It returns when all callbacks have
       
   876  * been attempted.
       
   877  */
       
   878 void
       
   879 PyObject_ClearWeakRefs(PyObject *object)
       
   880 {
       
   881     PyWeakReference **list;
       
   882 
       
   883     if (object == NULL
       
   884         || !PyType_SUPPORTS_WEAKREFS(Py_TYPE(object))
       
   885         || object->ob_refcnt != 0) {
       
   886         PyErr_BadInternalCall();
       
   887         return;
       
   888     }
       
   889     list = GET_WEAKREFS_LISTPTR(object);
       
   890     /* Remove the callback-less basic and proxy references */
       
   891     if (*list != NULL && (*list)->wr_callback == NULL) {
       
   892         clear_weakref(*list);
       
   893         if (*list != NULL && (*list)->wr_callback == NULL)
       
   894             clear_weakref(*list);
       
   895     }
       
   896     if (*list != NULL) {
       
   897         PyWeakReference *current = *list;
       
   898         Py_ssize_t count = _PyWeakref_GetWeakrefCount(current);
       
   899         int restore_error = PyErr_Occurred() ? 1 : 0;
       
   900         PyObject *err_type, *err_value, *err_tb;
       
   901 
       
   902         if (restore_error)
       
   903             PyErr_Fetch(&err_type, &err_value, &err_tb);
       
   904         if (count == 1) {
       
   905             PyObject *callback = current->wr_callback;
       
   906 
       
   907             current->wr_callback = NULL;
       
   908             clear_weakref(current);
       
   909             if (callback != NULL) {
       
   910                 if (current->ob_refcnt > 0)
       
   911                     handle_callback(current, callback);
       
   912                 Py_DECREF(callback);
       
   913             }
       
   914         }
       
   915         else {
       
   916             PyObject *tuple;
       
   917             Py_ssize_t i = 0;
       
   918     
       
   919             tuple = PyTuple_New(count * 2);
       
   920             if (tuple == NULL) {
       
   921                 if (restore_error)
       
   922                     PyErr_Fetch(&err_type, &err_value, &err_tb);
       
   923                 return;
       
   924             }
       
   925 
       
   926             for (i = 0; i < count; ++i) {
       
   927                 PyWeakReference *next = current->wr_next;
       
   928 
       
   929                 if (current->ob_refcnt > 0)
       
   930                 {
       
   931                     Py_INCREF(current);
       
   932                     PyTuple_SET_ITEM(tuple, i * 2, (PyObject *) current);
       
   933                     PyTuple_SET_ITEM(tuple, i * 2 + 1, current->wr_callback);
       
   934                 }
       
   935                 else {
       
   936                     Py_DECREF(current->wr_callback);
       
   937                 }
       
   938                 current->wr_callback = NULL;
       
   939                 clear_weakref(current);
       
   940                 current = next;
       
   941             }
       
   942             for (i = 0; i < count; ++i) {
       
   943                 PyObject *callback = PyTuple_GET_ITEM(tuple, i * 2 + 1);
       
   944 
       
   945                 /* The tuple may have slots left to NULL */
       
   946                 if (callback != NULL) {
       
   947                     PyObject *item = PyTuple_GET_ITEM(tuple, i * 2);
       
   948                     handle_callback((PyWeakReference *)item, callback);
       
   949                 }
       
   950             }
       
   951             Py_DECREF(tuple);
       
   952         }
       
   953         if (restore_error)
       
   954             PyErr_Restore(err_type, err_value, err_tb);
       
   955     }
       
   956 }