blob: 886d8742bd2088ed4d383b04d024e4cbdb662e28 [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 Drake73006d02001-10-18 18:04:18 +0000236/* Note that the second and third args need to be checked for NULL since
237 * (at least) the tp_call slot can receive NULL for either of those args.
238 */
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); \
243 if (v != NULL) \
244 UNWRAP(v); \
245 if (w != NULL) \
246 UNWRAP(w); \
247 return generic(proxy, v, w); \
Fred Drake8844d522001-10-05 21:52:26 +0000248 }
249
250
251/* direct slots */
252
253WRAP_BINARY(proxy_getattr, PyObject_GetAttr)
254WRAP_UNARY(proxy_str, PyObject_Str)
255WRAP_TERNARY(proxy_call, PyEval_CallObjectWithKeywords)
256
257static int
258proxy_print(PyWeakReference *proxy, FILE *fp, int flags)
259{
260 if (!proxy_checkref(proxy))
261 return -1;
262 return PyObject_Print(PyWeakref_GET_OBJECT(proxy), fp, flags);
263}
264
265static PyObject *
266proxy_repr(PyWeakReference *proxy)
267{
268 char buf[160];
269 sprintf(buf, "<weakref at %p to %.100s at %p>", proxy,
270 PyWeakref_GET_OBJECT(proxy)->ob_type->tp_name,
271 PyWeakref_GET_OBJECT(proxy));
272 return PyString_FromString(buf);
273}
274
275
276static int
277proxy_setattr(PyWeakReference *proxy, PyObject *name, PyObject *value)
278{
279 if (!proxy_checkref(proxy))
280 return -1;
281 return PyObject_SetAttr(PyWeakref_GET_OBJECT(proxy), name, value);
282}
283
284static int
285proxy_compare(PyWeakReference *proxy, PyObject *v)
286{
287 if (!proxy_checkref(proxy))
288 return -1;
289 return PyObject_Compare(PyWeakref_GET_OBJECT(proxy), v);
290}
291
292/* number slots */
293WRAP_BINARY(proxy_add, PyNumber_Add)
294WRAP_BINARY(proxy_sub, PyNumber_Subtract)
295WRAP_BINARY(proxy_mul, PyNumber_Multiply)
296WRAP_BINARY(proxy_div, PyNumber_Divide)
297WRAP_BINARY(proxy_mod, PyNumber_Remainder)
298WRAP_BINARY(proxy_divmod, PyNumber_Divmod)
299WRAP_TERNARY(proxy_pow, PyNumber_Power)
300WRAP_UNARY(proxy_neg, PyNumber_Negative)
301WRAP_UNARY(proxy_pos, PyNumber_Positive)
302WRAP_UNARY(proxy_abs, PyNumber_Absolute)
303WRAP_UNARY(proxy_invert, PyNumber_Invert)
304WRAP_BINARY(proxy_lshift, PyNumber_Lshift)
305WRAP_BINARY(proxy_rshift, PyNumber_Rshift)
306WRAP_BINARY(proxy_and, PyNumber_And)
307WRAP_BINARY(proxy_xor, PyNumber_Xor)
308WRAP_BINARY(proxy_or, PyNumber_Or)
309WRAP_UNARY(proxy_int, PyNumber_Int)
310WRAP_UNARY(proxy_long, PyNumber_Long)
311WRAP_UNARY(proxy_float, PyNumber_Float)
312WRAP_BINARY(proxy_iadd, PyNumber_InPlaceAdd)
313WRAP_BINARY(proxy_isub, PyNumber_InPlaceSubtract)
314WRAP_BINARY(proxy_imul, PyNumber_InPlaceMultiply)
315WRAP_BINARY(proxy_idiv, PyNumber_InPlaceDivide)
316WRAP_BINARY(proxy_imod, PyNumber_InPlaceRemainder)
317WRAP_TERNARY(proxy_ipow, PyNumber_InPlacePower)
318WRAP_BINARY(proxy_ilshift, PyNumber_InPlaceLshift)
319WRAP_BINARY(proxy_irshift, PyNumber_InPlaceRshift)
320WRAP_BINARY(proxy_iand, PyNumber_InPlaceAnd)
321WRAP_BINARY(proxy_ixor, PyNumber_InPlaceXor)
322WRAP_BINARY(proxy_ior, PyNumber_InPlaceOr)
323
324static int
325proxy_nonzero(PyWeakReference *proxy)
326{
327 PyObject *o = PyWeakref_GET_OBJECT(proxy);
328 if (!proxy_checkref(proxy))
329 return 1;
330 if (o->ob_type->tp_as_number &&
331 o->ob_type->tp_as_number->nb_nonzero)
332 return (*o->ob_type->tp_as_number->nb_nonzero)(o);
333 else
334 return 1;
335}
336
337/* sequence slots */
338
339static PyObject *
340proxy_slice(PyWeakReference *proxy, int i, int j)
341{
342 if (!proxy_checkref(proxy))
343 return NULL;
344 return PySequence_GetSlice(PyWeakref_GET_OBJECT(proxy), i, j);
345}
346
347static int
348proxy_ass_slice(PyWeakReference *proxy, int i, int j, PyObject *value)
349{
350 if (!proxy_checkref(proxy))
351 return -1;
352 return PySequence_SetSlice(PyWeakref_GET_OBJECT(proxy), i, j, value);
353}
354
355static int
356proxy_contains(PyWeakReference *proxy, PyObject *value)
357{
358 if (!proxy_checkref(proxy))
359 return -1;
360 return PySequence_Contains(PyWeakref_GET_OBJECT(proxy), value);
361}
362
363
364/* mapping slots */
365
366static int
367proxy_length(PyWeakReference *proxy)
368{
369 if (!proxy_checkref(proxy))
370 return -1;
371 return PyObject_Length(PyWeakref_GET_OBJECT(proxy));
372}
373
374WRAP_BINARY(proxy_getitem, PyObject_GetItem)
375
376static int
377proxy_setitem(PyWeakReference *proxy, PyObject *key, PyObject *value)
378{
379 if (!proxy_checkref(proxy))
380 return -1;
381 return PyObject_SetItem(PyWeakref_GET_OBJECT(proxy), key, value);
382}
383
384
385static PyNumberMethods proxy_as_number = {
386 (binaryfunc)proxy_add, /*nb_add*/
387 (binaryfunc)proxy_sub, /*nb_subtract*/
388 (binaryfunc)proxy_mul, /*nb_multiply*/
389 (binaryfunc)proxy_div, /*nb_divide*/
390 (binaryfunc)proxy_mod, /*nb_remainder*/
391 (binaryfunc)proxy_divmod, /*nb_divmod*/
392 (ternaryfunc)proxy_pow, /*nb_power*/
393 (unaryfunc)proxy_neg, /*nb_negative*/
394 (unaryfunc)proxy_pos, /*nb_positive*/
395 (unaryfunc)proxy_abs, /*nb_absolute*/
396 (inquiry)proxy_nonzero, /*nb_nonzero*/
397 (unaryfunc)proxy_invert, /*nb_invert*/
398 (binaryfunc)proxy_lshift, /*nb_lshift*/
399 (binaryfunc)proxy_rshift, /*nb_rshift*/
400 (binaryfunc)proxy_and, /*nb_and*/
401 (binaryfunc)proxy_xor, /*nb_xor*/
402 (binaryfunc)proxy_or, /*nb_or*/
403 (coercion)0, /*nb_coerce*/
404 (unaryfunc)proxy_int, /*nb_int*/
405 (unaryfunc)proxy_long, /*nb_long*/
406 (unaryfunc)proxy_float, /*nb_float*/
407 (unaryfunc)0, /*nb_oct*/
408 (unaryfunc)0, /*nb_hex*/
409 (binaryfunc)proxy_iadd, /*nb_inplace_add*/
410 (binaryfunc)proxy_isub, /*nb_inplace_subtract*/
411 (binaryfunc)proxy_imul, /*nb_inplace_multiply*/
412 (binaryfunc)proxy_idiv, /*nb_inplace_divide*/
413 (binaryfunc)proxy_imod, /*nb_inplace_remainder*/
414 (ternaryfunc)proxy_ipow, /*nb_inplace_power*/
415 (binaryfunc)proxy_ilshift, /*nb_inplace_lshift*/
416 (binaryfunc)proxy_irshift, /*nb_inplace_rshift*/
417 (binaryfunc)proxy_iand, /*nb_inplace_and*/
418 (binaryfunc)proxy_ixor, /*nb_inplace_xor*/
419 (binaryfunc)proxy_ior, /*nb_inplace_or*/
420};
421
422static PySequenceMethods proxy_as_sequence = {
423 (inquiry)proxy_length, /*sq_length*/
424 0, /*sq_concat*/
425 0, /*sq_repeat*/
426 0, /*sq_item*/
427 (intintargfunc)proxy_slice, /*sq_slice*/
428 0, /*sq_ass_item*/
429 (intintobjargproc)proxy_ass_slice, /*sq_ass_slice*/
430 (objobjproc)proxy_contains, /* sq_contains */
431};
432
433static PyMappingMethods proxy_as_mapping = {
434 (inquiry)proxy_length, /*mp_length*/
435 (binaryfunc)proxy_getitem, /*mp_subscript*/
436 (objobjargproc)proxy_setitem, /*mp_ass_subscript*/
437};
438
439
440PyTypeObject
441_PyWeakref_ProxyType = {
442 PyObject_HEAD_INIT(&PyType_Type)
443 0,
444 "weakproxy",
445 sizeof(PyWeakReference),
446 0,
447 /* methods */
448 (destructor)weakref_dealloc,/*tp_dealloc*/
449 (printfunc)proxy_print, /*tp_print*/
450 0, /*tp_getattr*/
451 0, /*tp_setattr*/
452 (cmpfunc)proxy_compare, /*tp_compare*/
453 (unaryfunc)proxy_repr, /*tp_repr*/
454 &proxy_as_number, /*tp_as_number*/
455 &proxy_as_sequence, /*tp_as_sequence*/
456 &proxy_as_mapping, /*tp_as_mapping*/
457 0, /*tp_hash*/
458 (ternaryfunc)0, /*tp_call*/
459 (unaryfunc)proxy_str, /*tp_str*/
460 (getattrofunc)proxy_getattr,/*tp_getattro*/
461 (setattrofunc)proxy_setattr,/*tp_setattro*/
462 0, /*tp_as_buffer*/
463 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC
464 |Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
465 0, /*tp_doc*/
466 (traverseproc)gc_traverse, /*tp_traverse*/
467 (inquiry)gc_clear, /*tp_clear*/
468};
469
470
471PyTypeObject
472_PyWeakref_CallableProxyType = {
473 PyObject_HEAD_INIT(&PyType_Type)
474 0,
475 "weakcallableproxy",
476 sizeof(PyWeakReference),
477 0,
478 /* methods */
479 (destructor)weakref_dealloc,/*tp_dealloc*/
480 (printfunc)proxy_print, /*tp_print*/
481 0, /*tp_getattr*/
482 0, /*tp_setattr*/
483 (cmpfunc)proxy_compare, /*tp_compare*/
484 (unaryfunc)proxy_repr, /*tp_repr*/
485 &proxy_as_number, /*tp_as_number*/
486 &proxy_as_sequence, /*tp_as_sequence*/
487 &proxy_as_mapping, /*tp_as_mapping*/
488 0, /*tp_hash*/
489 (ternaryfunc)proxy_call, /*tp_call*/
490 (unaryfunc)proxy_str, /*tp_str*/
491 (getattrofunc)proxy_getattr,/*tp_getattro*/
492 (setattrofunc)proxy_setattr,/*tp_setattro*/
493 0, /*tp_as_buffer*/
494 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC
495 |Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
496 0, /*tp_doc*/
497 (traverseproc)gc_traverse, /*tp_traverse*/
498 (inquiry)gc_clear, /*tp_clear*/
499};
500
501
502/* Given the head of an object's list of weak references, extract the
503 * two callback-less refs (ref and proxy). Used to determine if the
504 * shared references exist and to determine the back link for newly
505 * inserted references.
506 */
507static void
508get_basic_refs(PyWeakReference *head,
509 PyWeakReference **refp, PyWeakReference **proxyp)
510{
511 *refp = NULL;
512 *proxyp = NULL;
513
514 if (head != NULL && head->wr_callback == NULL) {
515 if (head->ob_type == &_PyWeakref_RefType) {
516 *refp = head;
517 head = head->wr_next;
518 }
519 if (head != NULL && head->wr_callback == NULL) {
520 *proxyp = head;
521 head = head->wr_next;
522 }
523 }
524}
525
526/* Insert 'newref' in the list after 'prev'. Both must be non-NULL. */
527static void
528insert_after(PyWeakReference *newref, PyWeakReference *prev)
529{
530 newref->wr_prev = prev;
531 newref->wr_next = prev->wr_next;
532 if (prev->wr_next != NULL)
533 prev->wr_next->wr_prev = newref;
534 prev->wr_next = newref;
535}
536
537/* Insert 'newref' at the head of the list; 'list' points to the variable
538 * that stores the head.
539 */
540static void
541insert_head(PyWeakReference *newref, PyWeakReference **list)
542{
543 PyWeakReference *next = *list;
544
545 newref->wr_prev = NULL;
546 newref->wr_next = next;
547 if (next != NULL)
548 next->wr_prev = newref;
549 *list = newref;
550}
551
552
553PyObject *
554PyWeakref_NewRef(PyObject *ob, PyObject *callback)
555{
556 PyWeakReference *result = NULL;
557 PyWeakReference **list;
558 PyWeakReference *ref, *proxy;
559
560 if (!PyType_SUPPORTS_WEAKREFS(ob->ob_type)) {
561 PyErr_Format(PyExc_TypeError,
562 "'%s' objects are not weakly referencable",
563 ob->ob_type->tp_name);
564 return NULL;
565 }
566 list = GET_WEAKREFS_LISTPTR(ob);
567 get_basic_refs(*list, &ref, &proxy);
568 if (callback == NULL || callback == Py_None)
569 /* return existing weak reference if it exists */
570 result = ref;
571 if (result != NULL)
572 Py_XINCREF(result);
573 else {
574 result = new_weakref();
575 if (result != NULL) {
576 Py_XINCREF(callback);
577 result->wr_callback = callback;
578 result->wr_object = ob;
579 if (callback == NULL) {
580 insert_head(result, list);
581 }
582 else {
583 PyWeakReference *prev = (proxy == NULL) ? ref : proxy;
584
585 if (prev == NULL)
586 insert_head(result, list);
587 else
588 insert_after(result, prev);
589 }
590 PyObject_GC_Track(result);
591 }
592 }
593 return (PyObject *) result;
594}
595
596
597PyObject *
598PyWeakref_NewProxy(PyObject *ob, PyObject *callback)
599{
600 PyWeakReference *result = NULL;
601 PyWeakReference **list;
602 PyWeakReference *ref, *proxy;
603
604 if (!PyType_SUPPORTS_WEAKREFS(ob->ob_type)) {
605 PyErr_Format(PyExc_TypeError,
606 "'%s' objects are not weakly referencable",
607 ob->ob_type->tp_name);
608 return NULL;
609 }
610 list = GET_WEAKREFS_LISTPTR(ob);
611 get_basic_refs(*list, &ref, &proxy);
612 if (callback == NULL)
613 /* attempt to return an existing weak reference if it exists */
614 result = proxy;
615 if (result != NULL)
616 Py_XINCREF(result);
617 else {
618 result = new_weakref();
619 if (result != NULL) {
620 PyWeakReference *prev;
621
622 if (PyCallable_Check(ob))
623 result->ob_type = &_PyWeakref_CallableProxyType;
624 else
625 result->ob_type = &_PyWeakref_ProxyType;
626 result->wr_object = ob;
627 Py_XINCREF(callback);
628 result->wr_callback = callback;
629 if (callback == NULL)
630 prev = ref;
631 else
632 prev = (proxy == NULL) ? ref : proxy;
633
634 if (prev == NULL)
635 insert_head(result, list);
636 else
637 insert_after(result, prev);
638 PyObject_GC_Track(result);
639 }
640 }
641 return (PyObject *) result;
642}
643
644
645PyObject *
646PyWeakref_GetObject(PyObject *ref)
647{
648 if (ref == NULL || !PyWeakref_Check(ref)) {
649 PyErr_BadInternalCall();
650 return NULL;
651 }
652 return PyWeakref_GET_OBJECT(ref);
653}
654
655
656/* This is the implementation of the PyObject_ClearWeakRefs() function; it
657 * is installed in the init_weakref() function. It is called by the
658 * tp_dealloc handler to clear weak references.
659 *
660 * This iterates through the weak references for 'object' and calls callbacks
661 * for those references which have one. It returns when all callbacks have
662 * been attempted.
663 */
664void
665PyObject_ClearWeakRefs(PyObject *object)
666{
667 PyWeakReference **list;
668
669 if (object == NULL
670 || !PyType_SUPPORTS_WEAKREFS(object->ob_type)
671 || object->ob_refcnt != 0) {
672 PyErr_BadInternalCall();
673 return;
674 }
675 list = GET_WEAKREFS_LISTPTR(object);
676 /* Remove the callback-less basic and proxy references */
677 if (*list != NULL && (*list)->wr_callback == NULL) {
678 clear_weakref(*list);
679 if (*list != NULL && (*list)->wr_callback == NULL)
680 clear_weakref(*list);
681 }
682 if (*list != NULL) {
683 int count = _PyWeakref_GetWeakrefCount(*list);
684
685 if (count == 1) {
686 PyWeakReference *current = *list;
687 PyObject *callback = current->wr_callback;
688 PyObject *cbresult;
689
690 Py_INCREF(callback);
691 clear_weakref(current);
692 cbresult = PyObject_CallFunction(callback, "O", current);
693 if (cbresult == NULL)
694 PyErr_WriteUnraisable(callback);
695 else
696 Py_DECREF(cbresult);
697 Py_DECREF(callback);
698 }
699 else {
700 PyObject *tuple = PyTuple_New(count * 2);
701 PyWeakReference *current = *list;
702 int i = 0;
703
704 for (i = 0; i < count; ++i) {
705 PyWeakReference *next = current->wr_next;
706
707 Py_INCREF(current);
708 PyTuple_SET_ITEM(tuple, i * 2, (PyObject *) current);
709 PyTuple_SET_ITEM(tuple, i * 2 + 1, current->wr_callback);
710 current->wr_callback = NULL;
711 next = current->wr_next;
712 clear_weakref(current);
713 current = next;
714 }
715 for (i = 0; i < count; ++i) {
716 PyObject *current = PyTuple_GET_ITEM(tuple, i * 2);
717 PyObject *callback = PyTuple_GET_ITEM(tuple, i * 2 + 1);
718 PyObject *cbresult = PyObject_CallFunction(callback, "O",
719 current);
720 if (cbresult == NULL)
721 PyErr_WriteUnraisable(callback);
722 else
723 Py_DECREF(cbresult);
724 }
725 Py_DECREF(tuple);
726 }
727 }
728}