blob: e8211543452ee8e3c1d2ec6084e835daf9d06ba5 [file] [log] [blame]
Fred Drake8844d522001-10-05 21:52:26 +00001#include "Python.h"
2#include "structmember.h"
3
4
5#define GET_WEAKREFS_LISTPTR(o) \
6 ((PyWeakReference **) PyObject_GET_WEAKREFS_LISTPTR(o))
7
8static PyWeakReference *
9free_list = NULL;
10
11
12long
13_PyWeakref_GetWeakrefCount(PyWeakReference *head)
14{
15 long count = 0;
16
17 while (head != NULL) {
18 ++count;
19 head = head->wr_next;
20 }
21 return count;
22}
23
24
25static PyWeakReference *
26new_weakref(void)
27{
28 PyWeakReference *result;
29
30 if (free_list != NULL) {
31 result = free_list;
32 free_list = result->wr_next;
33 result->ob_type = &_PyWeakref_RefType;
34 _Py_NewReference((PyObject *)result);
35 }
36 else {
37 result = PyObject_GC_New(PyWeakReference, &_PyWeakref_RefType);
38 }
39 if (result)
40 result->hash = -1;
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 */
50static void
51clear_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 *list = self->wr_next;
61 self->wr_object = Py_None;
62 self->wr_callback = NULL;
63 if (self->wr_prev != NULL)
64 self->wr_prev->wr_next = self->wr_next;
65 if (self->wr_next != NULL)
66 self->wr_next->wr_prev = self->wr_prev;
67 self->wr_prev = NULL;
68 self->wr_next = NULL;
69 Py_XDECREF(callback);
70 }
71}
72
73
74static void
75weakref_dealloc(PyWeakReference *self)
76{
77 PyObject_GC_UnTrack((PyObject *)self);
78 clear_weakref(self);
79 self->wr_next = free_list;
80 free_list = self;
81}
82
83
84static int
85gc_traverse(PyWeakReference *self, visitproc visit, void *arg)
86{
87 if (self->wr_callback != NULL)
88 return visit(self->wr_callback, arg);
89 return 0;
90}
91
92
93static int
94gc_clear(PyWeakReference *self)
95{
96 clear_weakref(self);
97 return 0;
98}
99
100
101static PyObject *
102weakref_call(PyWeakReference *self, PyObject *args, PyObject *kw)
103{
104 static char *argnames[] = {NULL};
105
106 if (PyArg_ParseTupleAndKeywords(args, kw, ":__call__", argnames)) {
107 PyObject *object = PyWeakref_GET_OBJECT(self);
108 Py_INCREF(object);
109 return (object);
110 }
111 return NULL;
112}
113
114
115static long
116weakref_hash(PyWeakReference *self)
117{
118 if (self->hash != -1)
119 return self->hash;
120 if (PyWeakref_GET_OBJECT(self) == Py_None) {
121 PyErr_SetString(PyExc_TypeError, "weak object has gone away");
122 return -1;
123 }
124 self->hash = PyObject_Hash(PyWeakref_GET_OBJECT(self));
125 return self->hash;
126}
127
128
129static PyObject *
130weakref_repr(PyWeakReference *self)
131{
132 char buffer[256];
133 if (PyWeakref_GET_OBJECT(self) == Py_None) {
134 sprintf(buffer, "<weakref at %lx; dead>",
135 (long)(self));
136 }
137 else {
138 sprintf(buffer, "<weakref at %#lx; to '%s' at %#lx>",
139 (long)(self), PyWeakref_GET_OBJECT(self)->ob_type->tp_name,
140 (long)(PyWeakref_GET_OBJECT(self)));
141 }
142 return PyString_FromString(buffer);
143}
144
145/* Weak references only support equality, not ordering. Two weak references
146 are equal if the underlying objects are equal. If the underlying object has
147 gone away, they are equal if they are identical. */
148
149static PyObject *
150weakref_richcompare(PyWeakReference* self, PyWeakReference* other, int op)
151{
152 if (op != Py_EQ || self->ob_type != other->ob_type) {
153 Py_INCREF(Py_NotImplemented);
154 return Py_NotImplemented;
155 }
156 if (PyWeakref_GET_OBJECT(self) == Py_None
157 || PyWeakref_GET_OBJECT(other) == Py_None) {
158 PyObject *res = self==other ? Py_True : Py_False;
159 Py_INCREF(res);
160 return res;
161 }
162 return PyObject_RichCompare(PyWeakref_GET_OBJECT(self),
163 PyWeakref_GET_OBJECT(other), op);
164}
165
166
167PyTypeObject
168_PyWeakref_RefType = {
169 PyObject_HEAD_INIT(&PyType_Type)
170 0,
171 "weakref",
172 sizeof(PyWeakReference),
173 0,
174 (destructor)weakref_dealloc,/*tp_dealloc*/
175 0, /*tp_print*/
176 0, /*tp_getattr*/
177 0, /*tp_setattr*/
178 0, /*tp_compare*/
179 (reprfunc)weakref_repr, /*tp_repr*/
180 0, /*tp_as_number*/
181 0, /*tp_as_sequence*/
182 0, /*tp_as_mapping*/
183 (hashfunc)weakref_hash, /*tp_hash*/
184 (ternaryfunc)weakref_call, /*tp_call*/
185 0, /*tp_str*/
186 0, /*tp_getattro*/
187 0, /*tp_setattro*/
188 0, /*tp_as_buffer*/
189 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_RICHCOMPARE,
190 0, /*tp_doc*/
191 (traverseproc)gc_traverse, /*tp_traverse*/
192 (inquiry)gc_clear, /*tp_clear*/
193 (richcmpfunc)weakref_richcompare, /*tp_richcompare*/
194 0, /*tp_weaklistoffset*/
195};
196
197
198static int
199proxy_checkref(PyWeakReference *proxy)
200{
201 if (PyWeakref_GET_OBJECT(proxy) == Py_None) {
202 PyErr_SetString(PyExc_ReferenceError,
203 "weakly-referenced object no longer exists");
204 return 0;
205 }
206 return 1;
207}
208
209
Fred Drake73006d02001-10-18 18:04:18 +0000210/* If a parameter is a proxy, check that it is still "live" and wrap it,
211 * replacing the original value with the raw object. Raises ReferenceError
212 * if the param is a dead proxy.
213 */
214#define UNWRAP(o) \
215 if (PyWeakref_CheckProxy(o)) { \
216 if (!proxy_checkref((PyWeakReference *)o)) \
217 return NULL; \
218 o = PyWeakref_GET_OBJECT(o); \
219 }
220
Fred Drake8844d522001-10-05 21:52:26 +0000221#define WRAP_UNARY(method, generic) \
222 static PyObject * \
Fred Drake73006d02001-10-18 18:04:18 +0000223 method(PyObject *proxy) { \
224 UNWRAP(proxy); \
225 return generic(proxy); \
Fred Drake8844d522001-10-05 21:52:26 +0000226 }
227
228#define WRAP_BINARY(method, generic) \
229 static PyObject * \
Fred Drake73006d02001-10-18 18:04:18 +0000230 method(PyObject *x, PyObject *y) { \
231 UNWRAP(x); \
232 UNWRAP(y); \
233 return generic(x, y); \
Fred Drake8844d522001-10-05 21:52:26 +0000234 }
235
Fred Drake31f4d1f2001-10-18 19:21:46 +0000236/* Note that the third arg needs to be checked for NULL since the tp_call
237 * slot can receive NULL for this arg.
Fred Drake73006d02001-10-18 18:04:18 +0000238 */
Fred Drake8844d522001-10-05 21:52:26 +0000239#define WRAP_TERNARY(method, generic) \
240 static PyObject * \
Fred Drake73006d02001-10-18 18:04:18 +0000241 method(PyObject *proxy, PyObject *v, PyObject *w) { \
242 UNWRAP(proxy); \
Fred Drake31f4d1f2001-10-18 19:21:46 +0000243 UNWRAP(v); \
Fred Drake73006d02001-10-18 18:04:18 +0000244 if (w != NULL) \
245 UNWRAP(w); \
246 return generic(proxy, v, w); \
Fred Drake8844d522001-10-05 21:52:26 +0000247 }
248
249
250/* direct slots */
251
252WRAP_BINARY(proxy_getattr, PyObject_GetAttr)
253WRAP_UNARY(proxy_str, PyObject_Str)
254WRAP_TERNARY(proxy_call, PyEval_CallObjectWithKeywords)
255
256static int
257proxy_print(PyWeakReference *proxy, FILE *fp, int flags)
258{
259 if (!proxy_checkref(proxy))
260 return -1;
261 return PyObject_Print(PyWeakref_GET_OBJECT(proxy), fp, flags);
262}
263
264static PyObject *
265proxy_repr(PyWeakReference *proxy)
266{
267 char buf[160];
268 sprintf(buf, "<weakref at %p to %.100s at %p>", proxy,
269 PyWeakref_GET_OBJECT(proxy)->ob_type->tp_name,
270 PyWeakref_GET_OBJECT(proxy));
271 return PyString_FromString(buf);
272}
273
274
275static int
276proxy_setattr(PyWeakReference *proxy, PyObject *name, PyObject *value)
277{
278 if (!proxy_checkref(proxy))
279 return -1;
280 return PyObject_SetAttr(PyWeakref_GET_OBJECT(proxy), name, value);
281}
282
283static int
284proxy_compare(PyWeakReference *proxy, PyObject *v)
285{
286 if (!proxy_checkref(proxy))
287 return -1;
288 return PyObject_Compare(PyWeakref_GET_OBJECT(proxy), v);
289}
290
291/* number slots */
292WRAP_BINARY(proxy_add, PyNumber_Add)
293WRAP_BINARY(proxy_sub, PyNumber_Subtract)
294WRAP_BINARY(proxy_mul, PyNumber_Multiply)
295WRAP_BINARY(proxy_div, PyNumber_Divide)
296WRAP_BINARY(proxy_mod, PyNumber_Remainder)
297WRAP_BINARY(proxy_divmod, PyNumber_Divmod)
298WRAP_TERNARY(proxy_pow, PyNumber_Power)
299WRAP_UNARY(proxy_neg, PyNumber_Negative)
300WRAP_UNARY(proxy_pos, PyNumber_Positive)
301WRAP_UNARY(proxy_abs, PyNumber_Absolute)
302WRAP_UNARY(proxy_invert, PyNumber_Invert)
303WRAP_BINARY(proxy_lshift, PyNumber_Lshift)
304WRAP_BINARY(proxy_rshift, PyNumber_Rshift)
305WRAP_BINARY(proxy_and, PyNumber_And)
306WRAP_BINARY(proxy_xor, PyNumber_Xor)
307WRAP_BINARY(proxy_or, PyNumber_Or)
308WRAP_UNARY(proxy_int, PyNumber_Int)
309WRAP_UNARY(proxy_long, PyNumber_Long)
310WRAP_UNARY(proxy_float, PyNumber_Float)
311WRAP_BINARY(proxy_iadd, PyNumber_InPlaceAdd)
312WRAP_BINARY(proxy_isub, PyNumber_InPlaceSubtract)
313WRAP_BINARY(proxy_imul, PyNumber_InPlaceMultiply)
314WRAP_BINARY(proxy_idiv, PyNumber_InPlaceDivide)
315WRAP_BINARY(proxy_imod, PyNumber_InPlaceRemainder)
316WRAP_TERNARY(proxy_ipow, PyNumber_InPlacePower)
317WRAP_BINARY(proxy_ilshift, PyNumber_InPlaceLshift)
318WRAP_BINARY(proxy_irshift, PyNumber_InPlaceRshift)
319WRAP_BINARY(proxy_iand, PyNumber_InPlaceAnd)
320WRAP_BINARY(proxy_ixor, PyNumber_InPlaceXor)
321WRAP_BINARY(proxy_ior, PyNumber_InPlaceOr)
322
323static int
324proxy_nonzero(PyWeakReference *proxy)
325{
326 PyObject *o = PyWeakref_GET_OBJECT(proxy);
327 if (!proxy_checkref(proxy))
328 return 1;
329 if (o->ob_type->tp_as_number &&
330 o->ob_type->tp_as_number->nb_nonzero)
331 return (*o->ob_type->tp_as_number->nb_nonzero)(o);
332 else
333 return 1;
334}
335
336/* sequence slots */
337
338static PyObject *
339proxy_slice(PyWeakReference *proxy, int i, int j)
340{
341 if (!proxy_checkref(proxy))
342 return NULL;
343 return PySequence_GetSlice(PyWeakref_GET_OBJECT(proxy), i, j);
344}
345
346static int
347proxy_ass_slice(PyWeakReference *proxy, int i, int j, PyObject *value)
348{
349 if (!proxy_checkref(proxy))
350 return -1;
351 return PySequence_SetSlice(PyWeakref_GET_OBJECT(proxy), i, j, value);
352}
353
354static int
355proxy_contains(PyWeakReference *proxy, PyObject *value)
356{
357 if (!proxy_checkref(proxy))
358 return -1;
359 return PySequence_Contains(PyWeakref_GET_OBJECT(proxy), value);
360}
361
362
363/* mapping slots */
364
365static int
366proxy_length(PyWeakReference *proxy)
367{
368 if (!proxy_checkref(proxy))
369 return -1;
370 return PyObject_Length(PyWeakref_GET_OBJECT(proxy));
371}
372
373WRAP_BINARY(proxy_getitem, PyObject_GetItem)
374
375static int
376proxy_setitem(PyWeakReference *proxy, PyObject *key, PyObject *value)
377{
378 if (!proxy_checkref(proxy))
379 return -1;
380 return PyObject_SetItem(PyWeakref_GET_OBJECT(proxy), key, value);
381}
382
383
384static PyNumberMethods proxy_as_number = {
385 (binaryfunc)proxy_add, /*nb_add*/
386 (binaryfunc)proxy_sub, /*nb_subtract*/
387 (binaryfunc)proxy_mul, /*nb_multiply*/
388 (binaryfunc)proxy_div, /*nb_divide*/
389 (binaryfunc)proxy_mod, /*nb_remainder*/
390 (binaryfunc)proxy_divmod, /*nb_divmod*/
391 (ternaryfunc)proxy_pow, /*nb_power*/
392 (unaryfunc)proxy_neg, /*nb_negative*/
393 (unaryfunc)proxy_pos, /*nb_positive*/
394 (unaryfunc)proxy_abs, /*nb_absolute*/
395 (inquiry)proxy_nonzero, /*nb_nonzero*/
396 (unaryfunc)proxy_invert, /*nb_invert*/
397 (binaryfunc)proxy_lshift, /*nb_lshift*/
398 (binaryfunc)proxy_rshift, /*nb_rshift*/
399 (binaryfunc)proxy_and, /*nb_and*/
400 (binaryfunc)proxy_xor, /*nb_xor*/
401 (binaryfunc)proxy_or, /*nb_or*/
402 (coercion)0, /*nb_coerce*/
403 (unaryfunc)proxy_int, /*nb_int*/
404 (unaryfunc)proxy_long, /*nb_long*/
405 (unaryfunc)proxy_float, /*nb_float*/
406 (unaryfunc)0, /*nb_oct*/
407 (unaryfunc)0, /*nb_hex*/
408 (binaryfunc)proxy_iadd, /*nb_inplace_add*/
409 (binaryfunc)proxy_isub, /*nb_inplace_subtract*/
410 (binaryfunc)proxy_imul, /*nb_inplace_multiply*/
411 (binaryfunc)proxy_idiv, /*nb_inplace_divide*/
412 (binaryfunc)proxy_imod, /*nb_inplace_remainder*/
413 (ternaryfunc)proxy_ipow, /*nb_inplace_power*/
414 (binaryfunc)proxy_ilshift, /*nb_inplace_lshift*/
415 (binaryfunc)proxy_irshift, /*nb_inplace_rshift*/
416 (binaryfunc)proxy_iand, /*nb_inplace_and*/
417 (binaryfunc)proxy_ixor, /*nb_inplace_xor*/
418 (binaryfunc)proxy_ior, /*nb_inplace_or*/
419};
420
421static PySequenceMethods proxy_as_sequence = {
422 (inquiry)proxy_length, /*sq_length*/
423 0, /*sq_concat*/
424 0, /*sq_repeat*/
425 0, /*sq_item*/
426 (intintargfunc)proxy_slice, /*sq_slice*/
427 0, /*sq_ass_item*/
428 (intintobjargproc)proxy_ass_slice, /*sq_ass_slice*/
429 (objobjproc)proxy_contains, /* sq_contains */
430};
431
432static PyMappingMethods proxy_as_mapping = {
433 (inquiry)proxy_length, /*mp_length*/
434 (binaryfunc)proxy_getitem, /*mp_subscript*/
435 (objobjargproc)proxy_setitem, /*mp_ass_subscript*/
436};
437
438
439PyTypeObject
440_PyWeakref_ProxyType = {
441 PyObject_HEAD_INIT(&PyType_Type)
442 0,
443 "weakproxy",
444 sizeof(PyWeakReference),
445 0,
446 /* methods */
447 (destructor)weakref_dealloc,/*tp_dealloc*/
448 (printfunc)proxy_print, /*tp_print*/
449 0, /*tp_getattr*/
450 0, /*tp_setattr*/
451 (cmpfunc)proxy_compare, /*tp_compare*/
452 (unaryfunc)proxy_repr, /*tp_repr*/
453 &proxy_as_number, /*tp_as_number*/
454 &proxy_as_sequence, /*tp_as_sequence*/
455 &proxy_as_mapping, /*tp_as_mapping*/
456 0, /*tp_hash*/
457 (ternaryfunc)0, /*tp_call*/
458 (unaryfunc)proxy_str, /*tp_str*/
459 (getattrofunc)proxy_getattr,/*tp_getattro*/
460 (setattrofunc)proxy_setattr,/*tp_setattro*/
461 0, /*tp_as_buffer*/
462 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC
463 |Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
464 0, /*tp_doc*/
465 (traverseproc)gc_traverse, /*tp_traverse*/
466 (inquiry)gc_clear, /*tp_clear*/
467};
468
469
470PyTypeObject
471_PyWeakref_CallableProxyType = {
472 PyObject_HEAD_INIT(&PyType_Type)
473 0,
474 "weakcallableproxy",
475 sizeof(PyWeakReference),
476 0,
477 /* methods */
478 (destructor)weakref_dealloc,/*tp_dealloc*/
479 (printfunc)proxy_print, /*tp_print*/
480 0, /*tp_getattr*/
481 0, /*tp_setattr*/
482 (cmpfunc)proxy_compare, /*tp_compare*/
483 (unaryfunc)proxy_repr, /*tp_repr*/
484 &proxy_as_number, /*tp_as_number*/
485 &proxy_as_sequence, /*tp_as_sequence*/
486 &proxy_as_mapping, /*tp_as_mapping*/
487 0, /*tp_hash*/
488 (ternaryfunc)proxy_call, /*tp_call*/
489 (unaryfunc)proxy_str, /*tp_str*/
490 (getattrofunc)proxy_getattr,/*tp_getattro*/
491 (setattrofunc)proxy_setattr,/*tp_setattro*/
492 0, /*tp_as_buffer*/
493 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC
494 |Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
495 0, /*tp_doc*/
496 (traverseproc)gc_traverse, /*tp_traverse*/
497 (inquiry)gc_clear, /*tp_clear*/
498};
499
500
501/* Given the head of an object's list of weak references, extract the
502 * two callback-less refs (ref and proxy). Used to determine if the
503 * shared references exist and to determine the back link for newly
504 * inserted references.
505 */
506static void
507get_basic_refs(PyWeakReference *head,
508 PyWeakReference **refp, PyWeakReference **proxyp)
509{
510 *refp = NULL;
511 *proxyp = NULL;
512
513 if (head != NULL && head->wr_callback == NULL) {
514 if (head->ob_type == &_PyWeakref_RefType) {
515 *refp = head;
516 head = head->wr_next;
517 }
518 if (head != NULL && head->wr_callback == NULL) {
519 *proxyp = head;
520 head = head->wr_next;
521 }
522 }
523}
524
525/* Insert 'newref' in the list after 'prev'. Both must be non-NULL. */
526static void
527insert_after(PyWeakReference *newref, PyWeakReference *prev)
528{
529 newref->wr_prev = prev;
530 newref->wr_next = prev->wr_next;
531 if (prev->wr_next != NULL)
532 prev->wr_next->wr_prev = newref;
533 prev->wr_next = newref;
534}
535
536/* Insert 'newref' at the head of the list; 'list' points to the variable
537 * that stores the head.
538 */
539static void
540insert_head(PyWeakReference *newref, PyWeakReference **list)
541{
542 PyWeakReference *next = *list;
543
544 newref->wr_prev = NULL;
545 newref->wr_next = next;
546 if (next != NULL)
547 next->wr_prev = newref;
548 *list = newref;
549}
550
551
552PyObject *
553PyWeakref_NewRef(PyObject *ob, PyObject *callback)
554{
555 PyWeakReference *result = NULL;
556 PyWeakReference **list;
557 PyWeakReference *ref, *proxy;
558
559 if (!PyType_SUPPORTS_WEAKREFS(ob->ob_type)) {
560 PyErr_Format(PyExc_TypeError,
561 "'%s' objects are not weakly referencable",
562 ob->ob_type->tp_name);
563 return NULL;
564 }
565 list = GET_WEAKREFS_LISTPTR(ob);
566 get_basic_refs(*list, &ref, &proxy);
567 if (callback == NULL || callback == Py_None)
568 /* return existing weak reference if it exists */
569 result = ref;
570 if (result != NULL)
571 Py_XINCREF(result);
572 else {
573 result = new_weakref();
574 if (result != NULL) {
575 Py_XINCREF(callback);
576 result->wr_callback = callback;
577 result->wr_object = ob;
578 if (callback == NULL) {
579 insert_head(result, list);
580 }
581 else {
582 PyWeakReference *prev = (proxy == NULL) ? ref : proxy;
583
584 if (prev == NULL)
585 insert_head(result, list);
586 else
587 insert_after(result, prev);
588 }
589 PyObject_GC_Track(result);
590 }
591 }
592 return (PyObject *) result;
593}
594
595
596PyObject *
597PyWeakref_NewProxy(PyObject *ob, PyObject *callback)
598{
599 PyWeakReference *result = NULL;
600 PyWeakReference **list;
601 PyWeakReference *ref, *proxy;
602
603 if (!PyType_SUPPORTS_WEAKREFS(ob->ob_type)) {
604 PyErr_Format(PyExc_TypeError,
605 "'%s' objects are not weakly referencable",
606 ob->ob_type->tp_name);
607 return NULL;
608 }
609 list = GET_WEAKREFS_LISTPTR(ob);
610 get_basic_refs(*list, &ref, &proxy);
611 if (callback == NULL)
612 /* attempt to return an existing weak reference if it exists */
613 result = proxy;
614 if (result != NULL)
615 Py_XINCREF(result);
616 else {
617 result = new_weakref();
618 if (result != NULL) {
619 PyWeakReference *prev;
620
621 if (PyCallable_Check(ob))
622 result->ob_type = &_PyWeakref_CallableProxyType;
623 else
624 result->ob_type = &_PyWeakref_ProxyType;
625 result->wr_object = ob;
626 Py_XINCREF(callback);
627 result->wr_callback = callback;
628 if (callback == NULL)
629 prev = ref;
630 else
631 prev = (proxy == NULL) ? ref : proxy;
632
633 if (prev == NULL)
634 insert_head(result, list);
635 else
636 insert_after(result, prev);
637 PyObject_GC_Track(result);
638 }
639 }
640 return (PyObject *) result;
641}
642
643
644PyObject *
645PyWeakref_GetObject(PyObject *ref)
646{
647 if (ref == NULL || !PyWeakref_Check(ref)) {
648 PyErr_BadInternalCall();
649 return NULL;
650 }
651 return PyWeakref_GET_OBJECT(ref);
652}
653
654
655/* This is the implementation of the PyObject_ClearWeakRefs() function; it
656 * is installed in the init_weakref() function. It is called by the
657 * tp_dealloc handler to clear weak references.
658 *
659 * This iterates through the weak references for 'object' and calls callbacks
660 * for those references which have one. It returns when all callbacks have
661 * been attempted.
662 */
663void
664PyObject_ClearWeakRefs(PyObject *object)
665{
666 PyWeakReference **list;
667
668 if (object == NULL
669 || !PyType_SUPPORTS_WEAKREFS(object->ob_type)
670 || object->ob_refcnt != 0) {
671 PyErr_BadInternalCall();
672 return;
673 }
674 list = GET_WEAKREFS_LISTPTR(object);
675 /* Remove the callback-less basic and proxy references */
676 if (*list != NULL && (*list)->wr_callback == NULL) {
677 clear_weakref(*list);
678 if (*list != NULL && (*list)->wr_callback == NULL)
679 clear_weakref(*list);
680 }
681 if (*list != NULL) {
682 int count = _PyWeakref_GetWeakrefCount(*list);
683
684 if (count == 1) {
685 PyWeakReference *current = *list;
686 PyObject *callback = current->wr_callback;
687 PyObject *cbresult;
688
689 Py_INCREF(callback);
690 clear_weakref(current);
691 cbresult = PyObject_CallFunction(callback, "O", current);
692 if (cbresult == NULL)
693 PyErr_WriteUnraisable(callback);
694 else
695 Py_DECREF(cbresult);
696 Py_DECREF(callback);
697 }
698 else {
699 PyObject *tuple = PyTuple_New(count * 2);
700 PyWeakReference *current = *list;
701 int i = 0;
702
703 for (i = 0; i < count; ++i) {
704 PyWeakReference *next = current->wr_next;
705
706 Py_INCREF(current);
707 PyTuple_SET_ITEM(tuple, i * 2, (PyObject *) current);
708 PyTuple_SET_ITEM(tuple, i * 2 + 1, current->wr_callback);
709 current->wr_callback = NULL;
710 next = current->wr_next;
711 clear_weakref(current);
712 current = next;
713 }
714 for (i = 0; i < count; ++i) {
715 PyObject *current = PyTuple_GET_ITEM(tuple, i * 2);
716 PyObject *callback = PyTuple_GET_ITEM(tuple, i * 2 + 1);
717 PyObject *cbresult = PyObject_CallFunction(callback, "O",
718 current);
719 if (cbresult == NULL)
720 PyErr_WriteUnraisable(callback);
721 else
722 Py_DECREF(cbresult);
723 }
724 Py_DECREF(tuple);
725 }
726 }
727}