This commit was manufactured by cvs2svn to create tag 'r23b1-mac'.
[python/dscho.git] / Objects / weakrefobject.c
blobe26cb65b13041c4916c7cc0394e14f0de509fe57
1 #include "Python.h"
2 #include "structmember.h"
5 #define GET_WEAKREFS_LISTPTR(o) \
6 ((PyWeakReference **) PyObject_GET_WEAKREFS_LISTPTR(o))
9 long
10 _PyWeakref_GetWeakrefCount(PyWeakReference *head)
12 long count = 0;
14 while (head != NULL) {
15 ++count;
16 head = head->wr_next;
18 return count;
22 static PyWeakReference *
23 new_weakref(PyObject *ob, PyObject *callback)
25 PyWeakReference *result;
27 result = PyObject_GC_New(PyWeakReference, &_PyWeakref_RefType);
28 if (result) {
29 result->hash = -1;
30 result->wr_object = ob;
31 Py_XINCREF(callback);
32 result->wr_callback = callback;
33 PyObject_GC_Track(result);
35 return result;
39 /* This function clears the passed-in reference and removes it from the
40 * list of weak references for the referent. This is the only code that
41 * removes an item from the doubly-linked list of weak references for an
42 * object; it is also responsible for clearing the callback slot.
44 static void
45 clear_weakref(PyWeakReference *self)
47 PyObject *callback = self->wr_callback;
49 if (PyWeakref_GET_OBJECT(self) != Py_None) {
50 PyWeakReference **list = GET_WEAKREFS_LISTPTR(
51 PyWeakref_GET_OBJECT(self));
53 if (*list == self)
54 *list = self->wr_next;
55 self->wr_object = Py_None;
56 self->wr_callback = NULL;
57 if (self->wr_prev != NULL)
58 self->wr_prev->wr_next = self->wr_next;
59 if (self->wr_next != NULL)
60 self->wr_next->wr_prev = self->wr_prev;
61 self->wr_prev = NULL;
62 self->wr_next = NULL;
63 Py_XDECREF(callback);
68 static void
69 weakref_dealloc(PyWeakReference *self)
71 PyObject_GC_UnTrack((PyObject *)self);
72 clear_weakref(self);
73 PyObject_GC_Del(self);
77 static int
78 gc_traverse(PyWeakReference *self, visitproc visit, void *arg)
80 if (self->wr_callback != NULL)
81 return visit(self->wr_callback, arg);
82 return 0;
86 static int
87 gc_clear(PyWeakReference *self)
89 clear_weakref(self);
90 return 0;
94 static PyObject *
95 weakref_call(PyWeakReference *self, PyObject *args, PyObject *kw)
97 static char *argnames[] = {NULL};
99 if (PyArg_ParseTupleAndKeywords(args, kw, ":__call__", argnames)) {
100 PyObject *object = PyWeakref_GET_OBJECT(self);
101 Py_INCREF(object);
102 return (object);
104 return NULL;
108 static long
109 weakref_hash(PyWeakReference *self)
111 if (self->hash != -1)
112 return self->hash;
113 if (PyWeakref_GET_OBJECT(self) == Py_None) {
114 PyErr_SetString(PyExc_TypeError, "weak object has gone away");
115 return -1;
117 self->hash = PyObject_Hash(PyWeakref_GET_OBJECT(self));
118 return self->hash;
122 static PyObject *
123 weakref_repr(PyWeakReference *self)
125 char buffer[256];
126 if (PyWeakref_GET_OBJECT(self) == Py_None) {
127 PyOS_snprintf(buffer, sizeof(buffer), "<weakref at %p; dead>", self);
129 else {
130 char *name = NULL;
131 PyObject *nameobj = PyObject_GetAttrString(PyWeakref_GET_OBJECT(self),
132 "__name__");
133 if (nameobj == NULL)
134 PyErr_Clear();
135 else if (PyString_Check(nameobj))
136 name = PyString_AS_STRING(nameobj);
137 PyOS_snprintf(buffer, sizeof(buffer),
138 name ? "<weakref at %p; to '%.50s' at %p (%s)>"
139 : "<weakref at %p; to '%.50s' at %p>",
140 self,
141 PyWeakref_GET_OBJECT(self)->ob_type->tp_name,
142 PyWeakref_GET_OBJECT(self),
143 name);
144 Py_XDECREF(nameobj);
146 return PyString_FromString(buffer);
149 /* Weak references only support equality, not ordering. Two weak references
150 are equal if the underlying objects are equal. If the underlying object has
151 gone away, they are equal if they are identical. */
153 static PyObject *
154 weakref_richcompare(PyWeakReference* self, PyWeakReference* other, int op)
156 if (op != Py_EQ || self->ob_type != other->ob_type) {
157 Py_INCREF(Py_NotImplemented);
158 return Py_NotImplemented;
160 if (PyWeakref_GET_OBJECT(self) == Py_None
161 || PyWeakref_GET_OBJECT(other) == Py_None) {
162 PyObject *res = self==other ? Py_True : Py_False;
163 Py_INCREF(res);
164 return res;
166 return PyObject_RichCompare(PyWeakref_GET_OBJECT(self),
167 PyWeakref_GET_OBJECT(other), op);
171 PyTypeObject
172 _PyWeakref_RefType = {
173 PyObject_HEAD_INIT(&PyType_Type)
175 "weakref",
176 sizeof(PyWeakReference),
178 (destructor)weakref_dealloc,/*tp_dealloc*/
179 0, /*tp_print*/
180 0, /*tp_getattr*/
181 0, /*tp_setattr*/
182 0, /*tp_compare*/
183 (reprfunc)weakref_repr, /*tp_repr*/
184 0, /*tp_as_number*/
185 0, /*tp_as_sequence*/
186 0, /*tp_as_mapping*/
187 (hashfunc)weakref_hash, /*tp_hash*/
188 (ternaryfunc)weakref_call, /*tp_call*/
189 0, /*tp_str*/
190 0, /*tp_getattro*/
191 0, /*tp_setattro*/
192 0, /*tp_as_buffer*/
193 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_RICHCOMPARE,
194 0, /*tp_doc*/
195 (traverseproc)gc_traverse, /*tp_traverse*/
196 (inquiry)gc_clear, /*tp_clear*/
197 (richcmpfunc)weakref_richcompare, /*tp_richcompare*/
198 0, /*tp_weaklistoffset*/
202 static int
203 proxy_checkref(PyWeakReference *proxy)
205 if (PyWeakref_GET_OBJECT(proxy) == Py_None) {
206 PyErr_SetString(PyExc_ReferenceError,
207 "weakly-referenced object no longer exists");
208 return 0;
210 return 1;
214 /* If a parameter is a proxy, check that it is still "live" and wrap it,
215 * replacing the original value with the raw object. Raises ReferenceError
216 * if the param is a dead proxy.
218 #define UNWRAP(o) \
219 if (PyWeakref_CheckProxy(o)) { \
220 if (!proxy_checkref((PyWeakReference *)o)) \
221 return NULL; \
222 o = PyWeakref_GET_OBJECT(o); \
225 #define UNWRAP_I(o) \
226 if (PyWeakref_CheckProxy(o)) { \
227 if (!proxy_checkref((PyWeakReference *)o)) \
228 return -1; \
229 o = PyWeakref_GET_OBJECT(o); \
232 #define WRAP_UNARY(method, generic) \
233 static PyObject * \
234 method(PyObject *proxy) { \
235 UNWRAP(proxy); \
236 return generic(proxy); \
239 #define WRAP_BINARY(method, generic) \
240 static PyObject * \
241 method(PyObject *x, PyObject *y) { \
242 UNWRAP(x); \
243 UNWRAP(y); \
244 return generic(x, y); \
247 /* Note that the third arg needs to be checked for NULL since the tp_call
248 * slot can receive NULL for this arg.
250 #define WRAP_TERNARY(method, generic) \
251 static PyObject * \
252 method(PyObject *proxy, PyObject *v, PyObject *w) { \
253 UNWRAP(proxy); \
254 UNWRAP(v); \
255 if (w != NULL) \
256 UNWRAP(w); \
257 return generic(proxy, v, w); \
261 /* direct slots */
263 WRAP_BINARY(proxy_getattr, PyObject_GetAttr)
264 WRAP_UNARY(proxy_str, PyObject_Str)
265 WRAP_TERNARY(proxy_call, PyEval_CallObjectWithKeywords)
267 static int
268 proxy_print(PyWeakReference *proxy, FILE *fp, int flags)
270 if (!proxy_checkref(proxy))
271 return -1;
272 return PyObject_Print(PyWeakref_GET_OBJECT(proxy), fp, flags);
275 static PyObject *
276 proxy_repr(PyWeakReference *proxy)
278 char buf[160];
279 PyOS_snprintf(buf, sizeof(buf),
280 "<weakproxy at %p to %.100s at %p>", proxy,
281 PyWeakref_GET_OBJECT(proxy)->ob_type->tp_name,
282 PyWeakref_GET_OBJECT(proxy));
283 return PyString_FromString(buf);
287 static int
288 proxy_setattr(PyWeakReference *proxy, PyObject *name, PyObject *value)
290 if (!proxy_checkref(proxy))
291 return -1;
292 return PyObject_SetAttr(PyWeakref_GET_OBJECT(proxy), name, value);
295 static int
296 proxy_compare(PyObject *proxy, PyObject *v)
298 UNWRAP_I(proxy);
299 UNWRAP_I(v);
300 return PyObject_Compare(proxy, v);
303 /* number slots */
304 WRAP_BINARY(proxy_add, PyNumber_Add)
305 WRAP_BINARY(proxy_sub, PyNumber_Subtract)
306 WRAP_BINARY(proxy_mul, PyNumber_Multiply)
307 WRAP_BINARY(proxy_div, PyNumber_Divide)
308 WRAP_BINARY(proxy_mod, PyNumber_Remainder)
309 WRAP_BINARY(proxy_divmod, PyNumber_Divmod)
310 WRAP_TERNARY(proxy_pow, PyNumber_Power)
311 WRAP_UNARY(proxy_neg, PyNumber_Negative)
312 WRAP_UNARY(proxy_pos, PyNumber_Positive)
313 WRAP_UNARY(proxy_abs, PyNumber_Absolute)
314 WRAP_UNARY(proxy_invert, PyNumber_Invert)
315 WRAP_BINARY(proxy_lshift, PyNumber_Lshift)
316 WRAP_BINARY(proxy_rshift, PyNumber_Rshift)
317 WRAP_BINARY(proxy_and, PyNumber_And)
318 WRAP_BINARY(proxy_xor, PyNumber_Xor)
319 WRAP_BINARY(proxy_or, PyNumber_Or)
320 WRAP_UNARY(proxy_int, PyNumber_Int)
321 WRAP_UNARY(proxy_long, PyNumber_Long)
322 WRAP_UNARY(proxy_float, PyNumber_Float)
323 WRAP_BINARY(proxy_iadd, PyNumber_InPlaceAdd)
324 WRAP_BINARY(proxy_isub, PyNumber_InPlaceSubtract)
325 WRAP_BINARY(proxy_imul, PyNumber_InPlaceMultiply)
326 WRAP_BINARY(proxy_idiv, PyNumber_InPlaceDivide)
327 WRAP_BINARY(proxy_imod, PyNumber_InPlaceRemainder)
328 WRAP_TERNARY(proxy_ipow, PyNumber_InPlacePower)
329 WRAP_BINARY(proxy_ilshift, PyNumber_InPlaceLshift)
330 WRAP_BINARY(proxy_irshift, PyNumber_InPlaceRshift)
331 WRAP_BINARY(proxy_iand, PyNumber_InPlaceAnd)
332 WRAP_BINARY(proxy_ixor, PyNumber_InPlaceXor)
333 WRAP_BINARY(proxy_ior, PyNumber_InPlaceOr)
335 static int
336 proxy_nonzero(PyWeakReference *proxy)
338 PyObject *o = PyWeakref_GET_OBJECT(proxy);
339 if (!proxy_checkref(proxy))
340 return 1;
341 if (o->ob_type->tp_as_number &&
342 o->ob_type->tp_as_number->nb_nonzero)
343 return (*o->ob_type->tp_as_number->nb_nonzero)(o);
344 else
345 return 1;
348 /* sequence slots */
350 static PyObject *
351 proxy_slice(PyWeakReference *proxy, int i, int j)
353 if (!proxy_checkref(proxy))
354 return NULL;
355 return PySequence_GetSlice(PyWeakref_GET_OBJECT(proxy), i, j);
358 static int
359 proxy_ass_slice(PyWeakReference *proxy, int i, int j, PyObject *value)
361 if (!proxy_checkref(proxy))
362 return -1;
363 return PySequence_SetSlice(PyWeakref_GET_OBJECT(proxy), i, j, value);
366 static int
367 proxy_contains(PyWeakReference *proxy, PyObject *value)
369 if (!proxy_checkref(proxy))
370 return -1;
371 return PySequence_Contains(PyWeakref_GET_OBJECT(proxy), value);
375 /* mapping slots */
377 static int
378 proxy_length(PyWeakReference *proxy)
380 if (!proxy_checkref(proxy))
381 return -1;
382 return PyObject_Length(PyWeakref_GET_OBJECT(proxy));
385 WRAP_BINARY(proxy_getitem, PyObject_GetItem)
387 static int
388 proxy_setitem(PyWeakReference *proxy, PyObject *key, PyObject *value)
390 if (!proxy_checkref(proxy))
391 return -1;
392 return PyObject_SetItem(PyWeakref_GET_OBJECT(proxy), key, value);
395 /* iterator slots */
397 static PyObject *
398 proxy_iter(PyWeakReference *proxy)
400 if (!proxy_checkref(proxy))
401 return NULL;
402 return PyObject_GetIter(PyWeakref_GET_OBJECT(proxy));
405 static PyObject *
406 proxy_iternext(PyWeakReference *proxy)
408 if (!proxy_checkref(proxy))
409 return NULL;
410 return PyIter_Next(PyWeakref_GET_OBJECT(proxy));
414 static PyNumberMethods proxy_as_number = {
415 (binaryfunc)proxy_add, /*nb_add*/
416 (binaryfunc)proxy_sub, /*nb_subtract*/
417 (binaryfunc)proxy_mul, /*nb_multiply*/
418 (binaryfunc)proxy_div, /*nb_divide*/
419 (binaryfunc)proxy_mod, /*nb_remainder*/
420 (binaryfunc)proxy_divmod, /*nb_divmod*/
421 (ternaryfunc)proxy_pow, /*nb_power*/
422 (unaryfunc)proxy_neg, /*nb_negative*/
423 (unaryfunc)proxy_pos, /*nb_positive*/
424 (unaryfunc)proxy_abs, /*nb_absolute*/
425 (inquiry)proxy_nonzero, /*nb_nonzero*/
426 (unaryfunc)proxy_invert, /*nb_invert*/
427 (binaryfunc)proxy_lshift, /*nb_lshift*/
428 (binaryfunc)proxy_rshift, /*nb_rshift*/
429 (binaryfunc)proxy_and, /*nb_and*/
430 (binaryfunc)proxy_xor, /*nb_xor*/
431 (binaryfunc)proxy_or, /*nb_or*/
432 (coercion)0, /*nb_coerce*/
433 (unaryfunc)proxy_int, /*nb_int*/
434 (unaryfunc)proxy_long, /*nb_long*/
435 (unaryfunc)proxy_float, /*nb_float*/
436 (unaryfunc)0, /*nb_oct*/
437 (unaryfunc)0, /*nb_hex*/
438 (binaryfunc)proxy_iadd, /*nb_inplace_add*/
439 (binaryfunc)proxy_isub, /*nb_inplace_subtract*/
440 (binaryfunc)proxy_imul, /*nb_inplace_multiply*/
441 (binaryfunc)proxy_idiv, /*nb_inplace_divide*/
442 (binaryfunc)proxy_imod, /*nb_inplace_remainder*/
443 (ternaryfunc)proxy_ipow, /*nb_inplace_power*/
444 (binaryfunc)proxy_ilshift, /*nb_inplace_lshift*/
445 (binaryfunc)proxy_irshift, /*nb_inplace_rshift*/
446 (binaryfunc)proxy_iand, /*nb_inplace_and*/
447 (binaryfunc)proxy_ixor, /*nb_inplace_xor*/
448 (binaryfunc)proxy_ior, /*nb_inplace_or*/
451 static PySequenceMethods proxy_as_sequence = {
452 (inquiry)proxy_length, /*sq_length*/
453 0, /*sq_concat*/
454 0, /*sq_repeat*/
455 0, /*sq_item*/
456 (intintargfunc)proxy_slice, /*sq_slice*/
457 0, /*sq_ass_item*/
458 (intintobjargproc)proxy_ass_slice, /*sq_ass_slice*/
459 (objobjproc)proxy_contains, /* sq_contains */
462 static PyMappingMethods proxy_as_mapping = {
463 (inquiry)proxy_length, /*mp_length*/
464 (binaryfunc)proxy_getitem, /*mp_subscript*/
465 (objobjargproc)proxy_setitem, /*mp_ass_subscript*/
469 PyTypeObject
470 _PyWeakref_ProxyType = {
471 PyObject_HEAD_INIT(&PyType_Type)
473 "weakproxy",
474 sizeof(PyWeakReference),
476 /* methods */
477 (destructor)weakref_dealloc, /* tp_dealloc */
478 (printfunc)proxy_print, /* tp_print */
479 0, /* tp_getattr */
480 0, /* tp_setattr */
481 proxy_compare, /* tp_compare */
482 (unaryfunc)proxy_repr, /* tp_repr */
483 &proxy_as_number, /* tp_as_number */
484 &proxy_as_sequence, /* tp_as_sequence */
485 &proxy_as_mapping, /* tp_as_mapping */
486 0, /* tp_hash */
487 (ternaryfunc)0, /* tp_call */
488 (unaryfunc)proxy_str, /* tp_str */
489 (getattrofunc)proxy_getattr, /* tp_getattro */
490 (setattrofunc)proxy_setattr, /* tp_setattro */
491 0, /* tp_as_buffer */
492 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC
493 | Py_TPFLAGS_CHECKTYPES, /* tp_flags */
494 0, /* tp_doc */
495 (traverseproc)gc_traverse, /* tp_traverse */
496 (inquiry)gc_clear, /* tp_clear */
497 0, /* tp_richcompare */
498 0, /* tp_weaklistoffset */
499 (getiterfunc)proxy_iter, /* tp_iter */
500 (iternextfunc)proxy_iternext, /* tp_iternext */
504 PyTypeObject
505 _PyWeakref_CallableProxyType = {
506 PyObject_HEAD_INIT(&PyType_Type)
508 "weakcallableproxy",
509 sizeof(PyWeakReference),
511 /* methods */
512 (destructor)weakref_dealloc, /* tp_dealloc */
513 (printfunc)proxy_print, /* tp_print */
514 0, /* tp_getattr */
515 0, /* tp_setattr */
516 proxy_compare, /* tp_compare */
517 (unaryfunc)proxy_repr, /* tp_repr */
518 &proxy_as_number, /* tp_as_number */
519 &proxy_as_sequence, /* tp_as_sequence */
520 &proxy_as_mapping, /* tp_as_mapping */
521 0, /* tp_hash */
522 (ternaryfunc)proxy_call, /* tp_call */
523 (unaryfunc)proxy_str, /* tp_str */
524 (getattrofunc)proxy_getattr, /* tp_getattro */
525 (setattrofunc)proxy_setattr, /* tp_setattro */
526 0, /* tp_as_buffer */
527 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC
528 | Py_TPFLAGS_CHECKTYPES, /* tp_flags */
529 0, /* tp_doc */
530 (traverseproc)gc_traverse, /* tp_traverse */
531 (inquiry)gc_clear, /* tp_clear */
532 0, /* tp_richcompare */
533 0, /* tp_weaklistoffset */
534 (getiterfunc)proxy_iter, /* tp_iter */
535 (iternextfunc)proxy_iternext, /* tp_iternext */
539 /* Given the head of an object's list of weak references, extract the
540 * two callback-less refs (ref and proxy). Used to determine if the
541 * shared references exist and to determine the back link for newly
542 * inserted references.
544 static void
545 get_basic_refs(PyWeakReference *head,
546 PyWeakReference **refp, PyWeakReference **proxyp)
548 *refp = NULL;
549 *proxyp = NULL;
551 if (head != NULL && head->wr_callback == NULL) {
552 if (head->ob_type == &_PyWeakref_RefType) {
553 *refp = head;
554 head = head->wr_next;
556 if (head != NULL && head->wr_callback == NULL) {
557 *proxyp = head;
558 head = head->wr_next;
563 /* Insert 'newref' in the list after 'prev'. Both must be non-NULL. */
564 static void
565 insert_after(PyWeakReference *newref, PyWeakReference *prev)
567 newref->wr_prev = prev;
568 newref->wr_next = prev->wr_next;
569 if (prev->wr_next != NULL)
570 prev->wr_next->wr_prev = newref;
571 prev->wr_next = newref;
574 /* Insert 'newref' at the head of the list; 'list' points to the variable
575 * that stores the head.
577 static void
578 insert_head(PyWeakReference *newref, PyWeakReference **list)
580 PyWeakReference *next = *list;
582 newref->wr_prev = NULL;
583 newref->wr_next = next;
584 if (next != NULL)
585 next->wr_prev = newref;
586 *list = newref;
590 PyObject *
591 PyWeakref_NewRef(PyObject *ob, PyObject *callback)
593 PyWeakReference *result = NULL;
594 PyWeakReference **list;
595 PyWeakReference *ref, *proxy;
597 if (!PyType_SUPPORTS_WEAKREFS(ob->ob_type)) {
598 PyErr_Format(PyExc_TypeError,
599 "cannot create weak reference to '%s' object",
600 ob->ob_type->tp_name);
601 return NULL;
603 list = GET_WEAKREFS_LISTPTR(ob);
604 get_basic_refs(*list, &ref, &proxy);
605 if (callback == NULL || callback == Py_None)
606 /* return existing weak reference if it exists */
607 result = ref;
608 if (result != NULL)
609 Py_XINCREF(result);
610 else {
611 result = new_weakref(ob, callback);
612 if (result != NULL) {
613 if (callback == NULL) {
614 insert_head(result, list);
616 else {
617 PyWeakReference *prev = (proxy == NULL) ? ref : proxy;
619 if (prev == NULL)
620 insert_head(result, list);
621 else
622 insert_after(result, prev);
626 return (PyObject *) result;
630 PyObject *
631 PyWeakref_NewProxy(PyObject *ob, PyObject *callback)
633 PyWeakReference *result = NULL;
634 PyWeakReference **list;
635 PyWeakReference *ref, *proxy;
637 if (!PyType_SUPPORTS_WEAKREFS(ob->ob_type)) {
638 PyErr_Format(PyExc_TypeError,
639 "cannot create weak reference to '%s' object",
640 ob->ob_type->tp_name);
641 return NULL;
643 list = GET_WEAKREFS_LISTPTR(ob);
644 get_basic_refs(*list, &ref, &proxy);
645 if (callback == NULL)
646 /* attempt to return an existing weak reference if it exists */
647 result = proxy;
648 if (result != NULL)
649 Py_XINCREF(result);
650 else {
651 result = new_weakref(ob, callback);
652 if (result != NULL) {
653 PyWeakReference *prev;
655 if (PyCallable_Check(ob))
656 result->ob_type = &_PyWeakref_CallableProxyType;
657 else
658 result->ob_type = &_PyWeakref_ProxyType;
659 if (callback == NULL)
660 prev = ref;
661 else
662 prev = (proxy == NULL) ? ref : proxy;
664 if (prev == NULL)
665 insert_head(result, list);
666 else
667 insert_after(result, prev);
670 return (PyObject *) result;
674 PyObject *
675 PyWeakref_GetObject(PyObject *ref)
677 if (ref == NULL || !PyWeakref_Check(ref)) {
678 PyErr_BadInternalCall();
679 return NULL;
681 return PyWeakref_GET_OBJECT(ref);
685 static void
686 handle_callback(PyWeakReference *ref, PyObject *callback)
688 PyObject *cbresult = PyObject_CallFunction(callback, "O", ref);
690 if (cbresult == NULL)
691 PyErr_WriteUnraisable(callback);
692 else
693 Py_DECREF(cbresult);
696 /* This function is called by the tp_dealloc handler to clear weak references.
698 * This iterates through the weak references for 'object' and calls callbacks
699 * for those references which have one. It returns when all callbacks have
700 * been attempted.
702 void
703 PyObject_ClearWeakRefs(PyObject *object)
705 PyWeakReference **list;
707 if (object == NULL
708 || !PyType_SUPPORTS_WEAKREFS(object->ob_type)
709 || object->ob_refcnt != 0) {
710 PyErr_BadInternalCall();
711 return;
713 list = GET_WEAKREFS_LISTPTR(object);
714 /* Remove the callback-less basic and proxy references */
715 if (*list != NULL && (*list)->wr_callback == NULL) {
716 clear_weakref(*list);
717 if (*list != NULL && (*list)->wr_callback == NULL)
718 clear_weakref(*list);
720 if (*list != NULL) {
721 PyWeakReference *current = *list;
722 int count = _PyWeakref_GetWeakrefCount(current);
723 int restore_error = PyErr_Occurred() ? 1 : 0;
724 PyObject *err_type, *err_value, *err_tb;
726 if (restore_error)
727 PyErr_Fetch(&err_type, &err_value, &err_tb);
728 if (count == 1) {
729 PyObject *callback = current->wr_callback;
731 current->wr_callback = NULL;
732 clear_weakref(current);
733 handle_callback(current, callback);
734 Py_DECREF(callback);
736 else {
737 PyObject *tuple = PyTuple_New(count * 2);
738 int i = 0;
740 for (i = 0; i < count; ++i) {
741 PyWeakReference *next = current->wr_next;
743 Py_INCREF(current);
744 PyTuple_SET_ITEM(tuple, i * 2, (PyObject *) current);
745 PyTuple_SET_ITEM(tuple, i * 2 + 1, current->wr_callback);
746 current->wr_callback = NULL;
747 clear_weakref(current);
748 current = next;
750 for (i = 0; i < count; ++i) {
751 PyObject *current = PyTuple_GET_ITEM(tuple, i * 2);
752 PyObject *callback = PyTuple_GET_ITEM(tuple, i * 2 + 1);
754 handle_callback((PyWeakReference *)current, callback);
756 Py_DECREF(tuple);
758 if (restore_error)
759 PyErr_Restore(err_type, err_value, err_tb);