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