blob: a856901af9b9325f3fd1c753bcb38f81708d1268 [file] [log] [blame]
Fred Drake41deb1e2001-02-01 05:27:45 +00001#include "Python.h"
2#include "structmember.h"
3
4
5typedef struct _PyWeakReference PyWeakReference;
6
7struct _PyWeakReference {
8 PyObject_HEAD
9 PyObject *wr_object;
10 PyObject *wr_callback;
11 PyWeakReference *wr_prev;
12 PyWeakReference *wr_next;
13};
14
15
16#define GET_WEAKREFS_LISTPTR(o) \
17 ((PyWeakReference **) PyObject_GET_WEAKREFS_LISTPTR(o))
18
19static PyObject *
20ReferenceError;
21
22static PyWeakReference *
23free_list = NULL;
24
25staticforward PyTypeObject
26PyWeakReference_Type;
27
28static PyWeakReference *
29new_weakref(void)
30{
31 PyWeakReference *result;
32
33 if (free_list != NULL) {
34 result = free_list;
35 free_list = result->wr_next;
36 result->ob_type = &PyWeakReference_Type;
Tim Peters231e22f2001-02-02 21:10:53 +000037 _Py_NewReference((PyObject *)result);
Fred Drake41deb1e2001-02-01 05:27:45 +000038 }
39 else {
40 result = PyObject_NEW(PyWeakReference, &PyWeakReference_Type);
41 }
42 return result;
43}
44
45
46/* This function clears the passed-in reference and removes it from the
47 * list of weak references for the referent. This is the only code that
48 * removes an item from the doubly-linked list of weak references for an
49 * object; it is also responsible for clearing the callback slot.
50 */
51static void
52clear_weakref(PyWeakReference *self)
53{
54 PyObject *callback = self->wr_callback;
55
56 if (self->wr_object != Py_None) {
57 PyWeakReference **list = GET_WEAKREFS_LISTPTR(self->wr_object);
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 clear_weakref(self);
78 PyObject_GC_Fini((PyObject *)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 = self->wr_object;
108 Py_INCREF(object);
109 return (object);
110 }
111 return NULL;
112}
113
114
115static PyObject *
116weakref_repr(PyWeakReference *self)
117{
118 char buffer[256];
119 if (self->wr_object == Py_None) {
120 sprintf(buffer, "<weakref at %lx; dead>",
121 (long)(self));
122 }
123 else {
124 sprintf(buffer, "<weakref at %#lx; to '%s' at %#lx>",
125 (long)(self), self->wr_object->ob_type->tp_name,
126 (long)(self->wr_object));
127 }
128 return PyString_FromString(buffer);
129}
130
131
132statichere PyTypeObject
133PyWeakReference_Type = {
134 PyObject_HEAD_INIT(NULL)
135 0,
136 "weakref",
137 sizeof(PyWeakReference) + PyGC_HEAD_SIZE,
138 0,
139 (destructor)weakref_dealloc,/*tp_dealloc*/
140 0, /*tp_print*/
141 0, /*tp_getattr*/
142 0, /*tp_setattr*/
143 0, /*tp_compare*/
144 (reprfunc)weakref_repr, /*tp_repr*/
145 0, /*tp_as_number*/
146 0, /*tp_as_sequence*/
147 0, /*tp_as_mapping*/
148 0, /*tp_hash*/
149 (ternaryfunc)weakref_call, /*tp_call*/
150 0, /*tp_str*/
151 0, /*tp_getattro*/
152 0, /*tp_setattro*/
153 0, /*tp_as_buffer*/
154 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC,
155 0, /*tp_doc*/
156 (traverseproc)gc_traverse, /*tp_traverse*/
157 (inquiry)gc_clear, /*tp_clear*/
158};
159
160
161static int
162proxy_checkref(PyWeakReference *proxy)
163{
164 if (proxy->wr_object == Py_None) {
165 PyErr_SetString(ReferenceError,
166 "weakly-referenced object no longer exists");
167 return 0;
168 }
169 return 1;
170}
171
172
173#define WRAP_UNARY(method, generic) \
174 static PyObject * \
175 method(PyWeakReference *proxy) { \
176 if (!proxy_checkref(proxy)) { \
177 return NULL; \
178 } \
179 return generic(proxy->wr_object); \
180 }
181
182#define WRAP_BINARY(method, generic) \
183 static PyObject * \
184 method(PyWeakReference *proxy, PyObject *v) { \
185 if (!proxy_checkref(proxy)) { \
186 return NULL; \
187 } \
188 return generic(proxy->wr_object, v); \
189 }
190
191#define WRAP_TERNARY(method, generic) \
192 static PyObject * \
193 method(PyWeakReference *proxy, PyObject *v, PyObject *w) { \
194 if (!proxy_checkref(proxy)) { \
195 return NULL; \
196 } \
197 return generic(proxy->wr_object, v, w); \
198 }
199
200
201/* direct slots */
202
203WRAP_BINARY(proxy_getattr, PyObject_GetAttr)
204WRAP_UNARY(proxy_str, PyObject_Str)
205WRAP_TERNARY(proxy_call, PyEval_CallObjectWithKeywords)
206
207static int
208proxy_print(PyWeakReference *proxy, FILE *fp, int flags)
209{
210 if (!proxy_checkref(proxy))
211 return -1;
212 return PyObject_Print(proxy->wr_object, fp, flags);
213}
214
215static PyObject *
216proxy_repr(PyWeakReference *proxy)
217{
218 char buf[160];
219 sprintf(buf, "<weakref at %p to %.100s at %p>", proxy,
220 proxy->wr_object->ob_type->tp_name, proxy->wr_object);
221 return PyString_FromString(buf);
222}
223
224
225static int
226proxy_setattr(PyWeakReference *proxy, PyObject *name, PyObject *value)
227{
228 if (!proxy_checkref(proxy))
229 return -1;
230 return PyObject_SetAttr(proxy->wr_object, name, value);
231}
232
233static int
234proxy_compare(PyWeakReference *proxy, PyObject *v)
235{
236 if (!proxy_checkref(proxy))
237 return -1;
238 return PyObject_Compare(proxy->wr_object, v);
239}
240
241/* number slots */
242WRAP_BINARY(proxy_add, PyNumber_Add)
243WRAP_BINARY(proxy_sub, PyNumber_Subtract)
244WRAP_BINARY(proxy_mul, PyNumber_Multiply)
245WRAP_BINARY(proxy_div, PyNumber_Divide)
246WRAP_BINARY(proxy_mod, PyNumber_Remainder)
247WRAP_BINARY(proxy_divmod, PyNumber_Divmod)
248WRAP_TERNARY(proxy_pow, PyNumber_Power)
249WRAP_UNARY(proxy_neg, PyNumber_Negative)
250WRAP_UNARY(proxy_pos, PyNumber_Positive)
251WRAP_UNARY(proxy_abs, PyNumber_Absolute)
252WRAP_UNARY(proxy_invert, PyNumber_Invert)
253WRAP_BINARY(proxy_lshift, PyNumber_Lshift)
254WRAP_BINARY(proxy_rshift, PyNumber_Rshift)
255WRAP_BINARY(proxy_and, PyNumber_And)
256WRAP_BINARY(proxy_xor, PyNumber_Xor)
257WRAP_BINARY(proxy_or, PyNumber_Or)
258WRAP_UNARY(proxy_int, PyNumber_Int)
259WRAP_UNARY(proxy_long, PyNumber_Long)
260WRAP_UNARY(proxy_float, PyNumber_Float)
261WRAP_BINARY(proxy_iadd, PyNumber_InPlaceAdd)
262WRAP_BINARY(proxy_isub, PyNumber_InPlaceSubtract)
263WRAP_BINARY(proxy_imul, PyNumber_InPlaceMultiply)
264WRAP_BINARY(proxy_idiv, PyNumber_InPlaceDivide)
265WRAP_BINARY(proxy_imod, PyNumber_InPlaceRemainder)
266WRAP_TERNARY(proxy_ipow, PyNumber_InPlacePower)
267WRAP_BINARY(proxy_ilshift, PyNumber_InPlaceLshift)
268WRAP_BINARY(proxy_irshift, PyNumber_InPlaceRshift)
269WRAP_BINARY(proxy_iand, PyNumber_InPlaceAnd)
270WRAP_BINARY(proxy_ixor, PyNumber_InPlaceXor)
271WRAP_BINARY(proxy_ior, PyNumber_InPlaceOr)
272
273static int
274proxy_nonzero(PyWeakReference *proxy)
275{
276 PyObject *o = proxy->wr_object;
277 if (!proxy_checkref(proxy))
278 return 1;
279 if (o->ob_type->tp_as_number &&
280 o->ob_type->tp_as_number->nb_nonzero)
281 return (*o->ob_type->tp_as_number->nb_nonzero)(o);
282 else
283 return 1;
284}
285
286/* sequence slots */
287
288static PyObject *
289proxy_slice(PyWeakReference *proxy, int i, int j)
290{
291 if (!proxy_checkref(proxy))
292 return NULL;
293 return PySequence_GetSlice(proxy->wr_object, i, j);
294}
295
296static int
297proxy_ass_slice(PyWeakReference *proxy, int i, int j, PyObject *value)
298{
299 if (!proxy_checkref(proxy))
300 return -1;
301 return PySequence_SetSlice(proxy->wr_object, i, j, value);
302}
303
304static int
305proxy_contains(PyWeakReference *proxy, PyObject *value)
306{
307 if (!proxy_checkref(proxy))
308 return -1;
309 return PySequence_Contains(proxy->wr_object, value);
310}
311
312
313/* mapping slots */
314
315static int
316proxy_length(PyWeakReference *proxy)
317{
318 if (!proxy_checkref(proxy))
319 return -1;
320 return PyObject_Length(proxy->wr_object);
321}
322
323WRAP_BINARY(proxy_getitem, PyObject_GetItem)
324
325static int
326proxy_setitem(PyWeakReference *proxy, PyObject *key, PyObject *value)
327{
328 if (!proxy_checkref(proxy))
329 return -1;
330 return PyObject_SetItem(proxy->wr_object, key, value);
331}
332
333
334static PyNumberMethods proxy_as_number = {
335 (binaryfunc)proxy_add, /*nb_add*/
336 (binaryfunc)proxy_sub, /*nb_subtract*/
337 (binaryfunc)proxy_mul, /*nb_multiply*/
338 (binaryfunc)proxy_div, /*nb_divide*/
339 (binaryfunc)proxy_mod, /*nb_remainder*/
340 (binaryfunc)proxy_divmod, /*nb_divmod*/
341 (ternaryfunc)proxy_pow, /*nb_power*/
342 (unaryfunc)proxy_neg, /*nb_negative*/
343 (unaryfunc)proxy_pos, /*nb_positive*/
344 (unaryfunc)proxy_abs, /*nb_absolute*/
345 (inquiry)proxy_nonzero, /*nb_nonzero*/
346 (unaryfunc)proxy_invert, /*nb_invert*/
347 (binaryfunc)proxy_lshift, /*nb_lshift*/
348 (binaryfunc)proxy_rshift, /*nb_rshift*/
349 (binaryfunc)proxy_and, /*nb_and*/
350 (binaryfunc)proxy_xor, /*nb_xor*/
351 (binaryfunc)proxy_or, /*nb_or*/
352 (coercion)0, /*nb_coerce*/
353 (unaryfunc)proxy_int, /*nb_int*/
354 (unaryfunc)proxy_long, /*nb_long*/
355 (unaryfunc)proxy_float, /*nb_float*/
356 (unaryfunc)0, /*nb_oct*/
357 (unaryfunc)0, /*nb_hex*/
358 (binaryfunc)proxy_iadd, /*nb_inplace_add*/
359 (binaryfunc)proxy_isub, /*nb_inplace_subtract*/
360 (binaryfunc)proxy_imul, /*nb_inplace_multiply*/
361 (binaryfunc)proxy_idiv, /*nb_inplace_divide*/
362 (binaryfunc)proxy_imod, /*nb_inplace_remainder*/
363 (ternaryfunc)proxy_ipow, /*nb_inplace_power*/
364 (binaryfunc)proxy_ilshift, /*nb_inplace_lshift*/
365 (binaryfunc)proxy_irshift, /*nb_inplace_rshift*/
366 (binaryfunc)proxy_iand, /*nb_inplace_and*/
367 (binaryfunc)proxy_ixor, /*nb_inplace_xor*/
368 (binaryfunc)proxy_ior, /*nb_inplace_or*/
369};
370
371static PySequenceMethods proxy_as_sequence = {
372 (inquiry)proxy_length, /*sq_length*/
373 0, /*sq_concat*/
374 0, /*sq_repeat*/
375 0, /*sq_item*/
376 (intintargfunc)proxy_slice, /*sq_slice*/
377 0, /*sq_ass_item*/
378 (intintobjargproc)proxy_ass_slice, /*sq_ass_slice*/
379 (objobjproc)proxy_contains, /* sq_contains */
380};
381
382static PyMappingMethods proxy_as_mapping = {
383 (inquiry)proxy_length, /*mp_length*/
384 (binaryfunc)proxy_getitem, /*mp_subscript*/
385 (objobjargproc)proxy_setitem, /*mp_ass_subscript*/
386};
387
388
389static PyTypeObject
390PyWeakProxy_Type = {
391 PyObject_HEAD_INIT(NULL)
392 0,
393 "weakproxy",
394 sizeof(PyWeakReference) + PyGC_HEAD_SIZE,
395 0,
396 /* methods */
397 (destructor)weakref_dealloc,/*tp_dealloc*/
398 (printfunc)proxy_print, /*tp_print*/
399 0, /*tp_getattr*/
400 0, /*tp_setattr*/
401 (cmpfunc)proxy_compare, /*tp_compare*/
402 (unaryfunc)proxy_repr, /*tp_repr*/
403 &proxy_as_number, /*tp_as_number*/
404 &proxy_as_sequence, /*tp_as_sequence*/
405 &proxy_as_mapping, /*tp_as_mapping*/
406 0, /*tp_hash*/
407 (ternaryfunc)0, /*tp_call*/
408 (unaryfunc)proxy_str, /*tp_str*/
409 (getattrofunc)proxy_getattr,/*tp_getattro*/
410 (setattrofunc)proxy_setattr,/*tp_setattro*/
411 0, /*tp_as_buffer*/
412 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC
413 |Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
414 0, /*tp_doc*/
415 (traverseproc)gc_traverse, /*tp_traverse*/
416 (inquiry)gc_clear, /*tp_clear*/
417};
418
419
420static PyTypeObject
421PyWeakCallableProxy_Type = {
422 PyObject_HEAD_INIT(NULL)
423 0,
424 "weakcallableproxy",
425 sizeof(PyWeakReference) + PyGC_HEAD_SIZE,
426 0,
427 /* methods */
428 (destructor)weakref_dealloc,/*tp_dealloc*/
429 (printfunc)proxy_print, /*tp_print*/
430 0, /*tp_getattr*/
431 0, /*tp_setattr*/
432 (cmpfunc)proxy_compare, /*tp_compare*/
433 (unaryfunc)proxy_repr, /*tp_repr*/
434 &proxy_as_number, /*tp_as_number*/
435 &proxy_as_sequence, /*tp_as_sequence*/
436 &proxy_as_mapping, /*tp_as_mapping*/
437 0, /*tp_hash*/
438 (ternaryfunc)proxy_call, /*tp_call*/
439 (unaryfunc)proxy_str, /*tp_str*/
440 (getattrofunc)proxy_getattr,/*tp_getattro*/
441 (setattrofunc)proxy_setattr,/*tp_setattro*/
442 0, /*tp_as_buffer*/
443 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC
444 |Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
445 0, /*tp_doc*/
446 (traverseproc)gc_traverse, /*tp_traverse*/
447 (inquiry)gc_clear, /*tp_clear*/
448};
449
450
451static long
452getweakrefcount(PyWeakReference *head)
453{
454 long count = 0;
455
456 while (head != NULL) {
457 ++count;
458 head = head->wr_next;
459 }
460 return count;
461}
462
463
Fred Drake7855aba2001-02-18 05:20:18 +0000464static char weakref_getweakrefcount__doc__[] =
465"getweakrefcount(object) -- return the number of weak references\n"
466"to 'object'.";
467
Fred Drake41deb1e2001-02-01 05:27:45 +0000468static PyObject *
469weakref_getweakrefcount(PyObject *self, PyObject *args)
470{
471 PyObject *result = NULL;
472 PyObject *object;
473
474 if (PyArg_ParseTuple(args, "O:getweakrefcount", &object)) {
475 if (PyType_SUPPORTS_WEAKREFS(object->ob_type)) {
476 PyWeakReference **list = GET_WEAKREFS_LISTPTR(object);
477
478 result = PyInt_FromLong(getweakrefcount(*list));
479 }
480 else
481 result = PyInt_FromLong(0);
482 }
483 return result;
484}
485
486
Fred Drake7855aba2001-02-18 05:20:18 +0000487static char weakref_getweakrefs__doc__[] =
488"getweakrefs(object) -- return a list of all weak reference objects\n"
489"that point to 'object'.";
490
Fred Drake41deb1e2001-02-01 05:27:45 +0000491static PyObject *
492weakref_getweakrefs(PyObject *self, PyObject *args)
493{
494 PyObject *result = NULL;
495 PyObject *object;
496
497 if (PyArg_ParseTuple(args, "O:getweakrefs", &object)) {
498 if (PyType_SUPPORTS_WEAKREFS(object->ob_type)) {
499 PyWeakReference **list = GET_WEAKREFS_LISTPTR(object);
500 long count = getweakrefcount(*list);
501
502 result = PyList_New(count);
503 if (result != NULL) {
504 PyWeakReference *current = *list;
505 long i;
506 for (i = 0; i < count; ++i) {
507 PyList_SET_ITEM(result, i, (PyObject *) current);
508 Py_INCREF(current);
509 current = current->wr_next;
510 }
511 }
512 }
513 else {
514 result = PyList_New(0);
515 }
516 }
517 return result;
518}
519
520
521/* Given the head of an object's list of weak references, extract the
522 * two callback-less refs (ref and proxy). Used to determine if the
523 * shared references exist and to determine the back link for newly
524 * inserted references.
525 */
526static void
527get_basic_refs(PyWeakReference *head,
528 PyWeakReference **refp, PyWeakReference **proxyp)
529{
530 *refp = NULL;
531 *proxyp = NULL;
532
533 if (head != NULL && head->wr_callback == NULL) {
534 if (head->ob_type == &PyWeakReference_Type) {
535 *refp = head;
536 head = head->wr_next;
537 }
538 if (head != NULL && head->wr_callback == NULL) {
539 *proxyp = head;
540 head = head->wr_next;
541 }
542 }
543}
544
545/* Insert 'newref' in the list after 'prev'. Both must be non-NULL. */
546static void
547insert_after(PyWeakReference *newref, PyWeakReference *prev)
548{
549 newref->wr_prev = prev;
550 newref->wr_next = prev->wr_next;
551 if (prev->wr_next != NULL)
552 prev->wr_next->wr_prev = newref;
553 prev->wr_next = newref;
554}
555
556/* Insert 'newref' at the head of the list; 'list' points to the variable
557 * that stores the head.
558 */
559static void
560insert_head(PyWeakReference *newref, PyWeakReference **list)
561{
562 PyWeakReference *next = *list;
563
564 newref->wr_prev = NULL;
565 newref->wr_next = next;
566 if (next != NULL)
567 next->wr_prev = newref;
568 *list = newref;
569}
570
571
Fred Drake7855aba2001-02-18 05:20:18 +0000572static char weakref_ref__doc__[] =
573"new(object[, callback]) -- create a weak reference to 'object';\n"
574"when 'object' is finalized, 'callback' will be called and passed\n"
575"a reference to 'object'.";
576
Fred Drake41deb1e2001-02-01 05:27:45 +0000577static PyObject *
578weakref_ref(PyObject *self, PyObject *args)
579{
580 PyObject *object;
581 PyObject *callback = NULL;
582 PyWeakReference *result = NULL;
583
584 if (PyArg_ParseTuple(args, "O|O:new", &object, &callback)) {
585 PyWeakReference **list;
586 PyWeakReference *ref, *proxy;
587
588 if (!PyType_SUPPORTS_WEAKREFS(object->ob_type)) {
589 PyErr_Format(PyExc_TypeError,
590 "'%s' objects are not weakly referencable",
591 object->ob_type->tp_name);
592 return NULL;
593 }
594 list = GET_WEAKREFS_LISTPTR(object);
595 get_basic_refs(*list, &ref, &proxy);
596 if (callback == NULL) {
597 /* return existing weak reference if it exists */
598 result = ref;
599 Py_XINCREF(result);
600 }
601 if (result == NULL) {
602 result = new_weakref();
603 if (result != NULL) {
604 Py_XINCREF(callback);
605 result->wr_callback = callback;
606 result->wr_object = object;
607 if (callback == NULL) {
608 insert_head(result, list);
609 }
610 else {
611 PyWeakReference *prev = (proxy == NULL) ? ref : proxy;
612
613 if (prev == NULL)
614 insert_head(result, list);
615 else
616 insert_after(result, prev);
617 }
618 PyObject_GC_Init((PyObject *) result);
619 }
620 }
621 }
622 return (PyObject *) result;
623}
624
625
Fred Drake7855aba2001-02-18 05:20:18 +0000626static char weakref_proxy__doc__[] =
627"proxy(object[, callback]) -- create a proxy object that weakly\n"
628"references 'object'. 'callback', if given, is called with a\n"
629"reference to the proxy when it is about to be finalized.";
630
Fred Drake41deb1e2001-02-01 05:27:45 +0000631static PyObject *
632weakref_proxy(PyObject *self, PyObject *args)
633{
634 PyObject *object;
635 PyObject *callback = NULL;
636 PyWeakReference *result = NULL;
637
638 if (PyArg_ParseTuple(args, "O|O:new", &object, &callback)) {
639 PyWeakReference **list;
640 PyWeakReference *ref, *proxy;
641
642 if (!PyType_SUPPORTS_WEAKREFS(object->ob_type)) {
643 PyErr_Format(PyExc_TypeError,
644 "'%s' objects are not weakly referencable",
645 object->ob_type->tp_name);
646 return NULL;
647 }
648 list = GET_WEAKREFS_LISTPTR(object);
649 get_basic_refs(*list, &ref, &proxy);
650 if (callback == NULL) {
651 /* attempt to return an existing weak reference if it exists */
652 result = proxy;
653 Py_XINCREF(result);
654 }
655 if (result == NULL) {
656 result = new_weakref();
657 if (result != NULL) {
658 PyWeakReference *prev;
659
660 if (PyCallable_Check(object))
661 result->ob_type = &PyWeakCallableProxy_Type;
662 else
663 result->ob_type = &PyWeakProxy_Type;
664 result->wr_object = object;
665 Py_XINCREF(callback);
666 result->wr_callback = callback;
667 if (callback == NULL)
668 prev = ref;
669 else
670 prev = (proxy == NULL) ? ref : proxy;
671
672 if (prev == NULL)
673 insert_head(result, list);
674 else
675 insert_after(result, prev);
676 PyObject_GC_Init((PyObject *) result);
677 }
678 }
679 }
680 return (PyObject *) result;
681}
682
683
684/* This is the implementation of the PyObject_ClearWeakRefs() function; it
685 * is installed in the init_weakref() function. It is called by the
686 * tp_dealloc handler to clear weak references.
687 *
688 * This returns true if the object should be deallocated, and false if the
689 * object is resurrected and deallocation should be aborted.
690 *
691 * This iterates through the weak references for 'object' and calls callbacks
692 * until one resurrects the object, at which point it stops invalidating
693 * weak references and returns false.
694 */
695static int
696cleanup_helper(PyObject *object)
697{
698 PyWeakReference **list;
699
700 if (object == NULL
701 || !PyType_SUPPORTS_WEAKREFS(object->ob_type)
702 || object->ob_refcnt != 0) {
703 PyErr_BadInternalCall();
704 /* not sure what we should return here */
705 return 1;
706 }
707 list = GET_WEAKREFS_LISTPTR(object);
708 while (*list != NULL) {
709 PyWeakReference *current = *list;
710 PyObject *callback = current->wr_callback;
711
712 Py_XINCREF(callback);
713 clear_weakref(current);
714 if (callback != NULL) {
715 PyObject *cbresult;
716
717 cbresult = PyObject_CallFunction(callback, "O", current);
718 if (cbresult == NULL)
719 PyErr_WriteUnraisable(callback);
720 else
721 Py_DECREF(cbresult);
722 Py_DECREF(callback);
723 }
724 }
725 return (object->ob_refcnt > 0 ? 0 : 1);
726}
727
728
729static PyMethodDef
730weakref_functions[] = {
731 {"getweakrefcount", weakref_getweakrefcount, METH_VARARGS,
Fred Drake7855aba2001-02-18 05:20:18 +0000732 weakref_getweakrefcount__doc__},
Fred Drake41deb1e2001-02-01 05:27:45 +0000733 {"getweakrefs", weakref_getweakrefs, METH_VARARGS,
Fred Drake7855aba2001-02-18 05:20:18 +0000734 weakref_getweakrefs__doc__},
735 {"proxy", weakref_proxy, METH_VARARGS,
736 weakref_proxy__doc__},
Fred Drake41deb1e2001-02-01 05:27:45 +0000737 {"ref", weakref_ref, METH_VARARGS,
Fred Drake7855aba2001-02-18 05:20:18 +0000738 weakref_ref__doc__},
Fred Drake41deb1e2001-02-01 05:27:45 +0000739 {NULL, NULL, 0, NULL}
740};
741
742
Tim Peters747d5b62001-02-02 00:07:07 +0000743DL_EXPORT(void)
Fred Drake41deb1e2001-02-01 05:27:45 +0000744init_weakref(void)
745{
746 PyObject *m;
747
748 PyWeakReference_Type.ob_type = &PyType_Type;
749 PyWeakProxy_Type.ob_type = &PyType_Type;
750 PyWeakCallableProxy_Type.ob_type = &PyType_Type;
751 m = Py_InitModule3("_weakref", weakref_functions,
752 "Weak-reference support module.");
753 if (m != NULL) {
754 PyObject_ClearWeakRefs = cleanup_helper;
755 Py_INCREF(&PyWeakReference_Type);
756 PyModule_AddObject(m, "ReferenceType",
757 (PyObject *) &PyWeakReference_Type);
758 Py_INCREF(&PyWeakProxy_Type);
759 PyModule_AddObject(m, "ProxyType",
760 (PyObject *) &PyWeakProxy_Type);
761 Py_INCREF(&PyWeakCallableProxy_Type);
762 PyModule_AddObject(m, "CallableProxyType",
763 (PyObject *) &PyWeakCallableProxy_Type);
764 ReferenceError = PyErr_NewException("weakref.ReferenceError",
765 PyExc_RuntimeError, NULL);
766 if (ReferenceError != NULL)
767 PyModule_AddObject(m, "ReferenceError", ReferenceError);
768 }
769}