blob: 71fe5a3ac4b8506de1ab562c3f779346a2b04974 [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;
Martin v. Löwis5e163332001-02-27 18:36:56 +000011 long hash;
Fred Drake41deb1e2001-02-01 05:27:45 +000012 PyWeakReference *wr_prev;
13 PyWeakReference *wr_next;
14};
15
16
17#define GET_WEAKREFS_LISTPTR(o) \
18 ((PyWeakReference **) PyObject_GET_WEAKREFS_LISTPTR(o))
19
20static PyObject *
21ReferenceError;
22
23static PyWeakReference *
24free_list = NULL;
25
26staticforward PyTypeObject
27PyWeakReference_Type;
28
29static PyWeakReference *
30new_weakref(void)
31{
32 PyWeakReference *result;
33
34 if (free_list != NULL) {
35 result = free_list;
36 free_list = result->wr_next;
37 result->ob_type = &PyWeakReference_Type;
Tim Peters231e22f2001-02-02 21:10:53 +000038 _Py_NewReference((PyObject *)result);
Fred Drake41deb1e2001-02-01 05:27:45 +000039 }
40 else {
41 result = PyObject_NEW(PyWeakReference, &PyWeakReference_Type);
42 }
Martin v. Löwis5e163332001-02-27 18:36:56 +000043 if (result)
44 result->hash = -1;
Fred Drake41deb1e2001-02-01 05:27:45 +000045 return result;
46}
47
48
49/* This function clears the passed-in reference and removes it from the
50 * list of weak references for the referent. This is the only code that
51 * removes an item from the doubly-linked list of weak references for an
52 * object; it is also responsible for clearing the callback slot.
53 */
54static void
55clear_weakref(PyWeakReference *self)
56{
57 PyObject *callback = self->wr_callback;
58
59 if (self->wr_object != Py_None) {
60 PyWeakReference **list = GET_WEAKREFS_LISTPTR(self->wr_object);
61
62 if (*list == self)
63 *list = self->wr_next;
64 self->wr_object = Py_None;
65 self->wr_callback = NULL;
66 if (self->wr_prev != NULL)
67 self->wr_prev->wr_next = self->wr_next;
68 if (self->wr_next != NULL)
69 self->wr_next->wr_prev = self->wr_prev;
70 self->wr_prev = NULL;
71 self->wr_next = NULL;
72 Py_XDECREF(callback);
73 }
74}
75
76
77static void
78weakref_dealloc(PyWeakReference *self)
79{
80 clear_weakref(self);
Tim Petersa5d7b742001-03-23 06:14:28 +000081 PyObject_GC_Fini((PyObject *)self);
Fred Drake41deb1e2001-02-01 05:27:45 +000082 self->wr_next = free_list;
83 free_list = self;
84}
85
86
87static int
88gc_traverse(PyWeakReference *self, visitproc visit, void *arg)
89{
90 if (self->wr_callback != NULL)
91 return visit(self->wr_callback, arg);
92 return 0;
93}
94
95
96static int
97gc_clear(PyWeakReference *self)
98{
99 clear_weakref(self);
100 return 0;
101}
102
103
104static PyObject *
105weakref_call(PyWeakReference *self, PyObject *args, PyObject *kw)
106{
107 static char *argnames[] = {NULL};
108
109 if (PyArg_ParseTupleAndKeywords(args, kw, ":__call__", argnames)) {
110 PyObject *object = self->wr_object;
111 Py_INCREF(object);
112 return (object);
113 }
114 return NULL;
115}
116
117
Martin v. Löwis5e163332001-02-27 18:36:56 +0000118static long
119weakref_hash(PyWeakReference *self)
120{
121 if (self->hash != -1)
122 return self->hash;
123 if (self->wr_object == Py_None) {
124 PyErr_SetString(PyExc_TypeError, "weak object has gone away");
125 return -1;
126 }
127 self->hash = PyObject_Hash(self->wr_object);
128 return self->hash;
129}
130
131
Fred Drake41deb1e2001-02-01 05:27:45 +0000132static PyObject *
133weakref_repr(PyWeakReference *self)
134{
135 char buffer[256];
136 if (self->wr_object == Py_None) {
137 sprintf(buffer, "<weakref at %lx; dead>",
138 (long)(self));
139 }
140 else {
141 sprintf(buffer, "<weakref at %#lx; to '%s' at %#lx>",
142 (long)(self), self->wr_object->ob_type->tp_name,
143 (long)(self->wr_object));
144 }
145 return PyString_FromString(buffer);
146}
147
Martin v. Löwis5e163332001-02-27 18:36:56 +0000148/* Weak references only support equality, not ordering. Two weak references
149 are equal if the underlying objects are equal. If the underlying object has
150 gone away, they are equal if they are identical. */
151
152static PyObject *
153weakref_richcompare(PyWeakReference* self, PyWeakReference* other, int op)
154{
155 if (op != Py_EQ || self->ob_type != other->ob_type) {
156 Py_INCREF(Py_NotImplemented);
157 return Py_NotImplemented;
158 }
159 if (self->wr_object == Py_None || other->wr_object == Py_None) {
160 PyObject *res = self==other ? Py_True : Py_False;
161 Py_INCREF(res);
162 return res;
163 }
164 return PyObject_RichCompare(self->wr_object, other->wr_object, op);
165}
166
Fred Drake41deb1e2001-02-01 05:27:45 +0000167
168statichere PyTypeObject
169PyWeakReference_Type = {
170 PyObject_HEAD_INIT(NULL)
171 0,
172 "weakref",
173 sizeof(PyWeakReference) + PyGC_HEAD_SIZE,
174 0,
175 (destructor)weakref_dealloc,/*tp_dealloc*/
176 0, /*tp_print*/
177 0, /*tp_getattr*/
178 0, /*tp_setattr*/
179 0, /*tp_compare*/
180 (reprfunc)weakref_repr, /*tp_repr*/
181 0, /*tp_as_number*/
182 0, /*tp_as_sequence*/
183 0, /*tp_as_mapping*/
Martin v. Löwis5e163332001-02-27 18:36:56 +0000184 (hashfunc)weakref_hash, /*tp_hash*/
Fred Drake41deb1e2001-02-01 05:27:45 +0000185 (ternaryfunc)weakref_call, /*tp_call*/
186 0, /*tp_str*/
187 0, /*tp_getattro*/
188 0, /*tp_setattro*/
189 0, /*tp_as_buffer*/
Martin v. Löwis5e163332001-02-27 18:36:56 +0000190 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC | Py_TPFLAGS_HAVE_RICHCOMPARE,
Fred Drake41deb1e2001-02-01 05:27:45 +0000191 0, /*tp_doc*/
192 (traverseproc)gc_traverse, /*tp_traverse*/
193 (inquiry)gc_clear, /*tp_clear*/
Martin v. Löwis5e163332001-02-27 18:36:56 +0000194 (richcmpfunc)weakref_richcompare, /*tp_richcompare*/
195 0, /*tp_weaklistoffset*/
Fred Drake41deb1e2001-02-01 05:27:45 +0000196};
197
198
199static int
200proxy_checkref(PyWeakReference *proxy)
201{
202 if (proxy->wr_object == Py_None) {
203 PyErr_SetString(ReferenceError,
204 "weakly-referenced object no longer exists");
205 return 0;
206 }
207 return 1;
208}
209
210
211#define WRAP_UNARY(method, generic) \
212 static PyObject * \
213 method(PyWeakReference *proxy) { \
214 if (!proxy_checkref(proxy)) { \
215 return NULL; \
216 } \
217 return generic(proxy->wr_object); \
218 }
219
220#define WRAP_BINARY(method, generic) \
221 static PyObject * \
222 method(PyWeakReference *proxy, PyObject *v) { \
223 if (!proxy_checkref(proxy)) { \
224 return NULL; \
225 } \
226 return generic(proxy->wr_object, v); \
227 }
228
229#define WRAP_TERNARY(method, generic) \
230 static PyObject * \
231 method(PyWeakReference *proxy, PyObject *v, PyObject *w) { \
232 if (!proxy_checkref(proxy)) { \
233 return NULL; \
234 } \
235 return generic(proxy->wr_object, v, w); \
236 }
237
238
239/* direct slots */
240
241WRAP_BINARY(proxy_getattr, PyObject_GetAttr)
242WRAP_UNARY(proxy_str, PyObject_Str)
243WRAP_TERNARY(proxy_call, PyEval_CallObjectWithKeywords)
244
245static int
246proxy_print(PyWeakReference *proxy, FILE *fp, int flags)
247{
248 if (!proxy_checkref(proxy))
249 return -1;
250 return PyObject_Print(proxy->wr_object, fp, flags);
251}
252
253static PyObject *
254proxy_repr(PyWeakReference *proxy)
255{
256 char buf[160];
257 sprintf(buf, "<weakref at %p to %.100s at %p>", proxy,
258 proxy->wr_object->ob_type->tp_name, proxy->wr_object);
259 return PyString_FromString(buf);
260}
261
262
263static int
264proxy_setattr(PyWeakReference *proxy, PyObject *name, PyObject *value)
265{
266 if (!proxy_checkref(proxy))
267 return -1;
268 return PyObject_SetAttr(proxy->wr_object, name, value);
269}
270
271static int
272proxy_compare(PyWeakReference *proxy, PyObject *v)
273{
274 if (!proxy_checkref(proxy))
275 return -1;
276 return PyObject_Compare(proxy->wr_object, v);
277}
278
279/* number slots */
280WRAP_BINARY(proxy_add, PyNumber_Add)
281WRAP_BINARY(proxy_sub, PyNumber_Subtract)
282WRAP_BINARY(proxy_mul, PyNumber_Multiply)
283WRAP_BINARY(proxy_div, PyNumber_Divide)
284WRAP_BINARY(proxy_mod, PyNumber_Remainder)
285WRAP_BINARY(proxy_divmod, PyNumber_Divmod)
286WRAP_TERNARY(proxy_pow, PyNumber_Power)
287WRAP_UNARY(proxy_neg, PyNumber_Negative)
288WRAP_UNARY(proxy_pos, PyNumber_Positive)
289WRAP_UNARY(proxy_abs, PyNumber_Absolute)
290WRAP_UNARY(proxy_invert, PyNumber_Invert)
291WRAP_BINARY(proxy_lshift, PyNumber_Lshift)
292WRAP_BINARY(proxy_rshift, PyNumber_Rshift)
293WRAP_BINARY(proxy_and, PyNumber_And)
294WRAP_BINARY(proxy_xor, PyNumber_Xor)
295WRAP_BINARY(proxy_or, PyNumber_Or)
296WRAP_UNARY(proxy_int, PyNumber_Int)
297WRAP_UNARY(proxy_long, PyNumber_Long)
298WRAP_UNARY(proxy_float, PyNumber_Float)
299WRAP_BINARY(proxy_iadd, PyNumber_InPlaceAdd)
300WRAP_BINARY(proxy_isub, PyNumber_InPlaceSubtract)
301WRAP_BINARY(proxy_imul, PyNumber_InPlaceMultiply)
302WRAP_BINARY(proxy_idiv, PyNumber_InPlaceDivide)
303WRAP_BINARY(proxy_imod, PyNumber_InPlaceRemainder)
304WRAP_TERNARY(proxy_ipow, PyNumber_InPlacePower)
305WRAP_BINARY(proxy_ilshift, PyNumber_InPlaceLshift)
306WRAP_BINARY(proxy_irshift, PyNumber_InPlaceRshift)
307WRAP_BINARY(proxy_iand, PyNumber_InPlaceAnd)
308WRAP_BINARY(proxy_ixor, PyNumber_InPlaceXor)
309WRAP_BINARY(proxy_ior, PyNumber_InPlaceOr)
310
311static int
312proxy_nonzero(PyWeakReference *proxy)
313{
314 PyObject *o = proxy->wr_object;
315 if (!proxy_checkref(proxy))
316 return 1;
317 if (o->ob_type->tp_as_number &&
318 o->ob_type->tp_as_number->nb_nonzero)
319 return (*o->ob_type->tp_as_number->nb_nonzero)(o);
320 else
321 return 1;
322}
323
324/* sequence slots */
325
326static PyObject *
327proxy_slice(PyWeakReference *proxy, int i, int j)
328{
329 if (!proxy_checkref(proxy))
330 return NULL;
331 return PySequence_GetSlice(proxy->wr_object, i, j);
332}
333
334static int
335proxy_ass_slice(PyWeakReference *proxy, int i, int j, PyObject *value)
336{
337 if (!proxy_checkref(proxy))
338 return -1;
339 return PySequence_SetSlice(proxy->wr_object, i, j, value);
340}
341
342static int
343proxy_contains(PyWeakReference *proxy, PyObject *value)
344{
345 if (!proxy_checkref(proxy))
346 return -1;
347 return PySequence_Contains(proxy->wr_object, value);
348}
349
350
351/* mapping slots */
352
353static int
354proxy_length(PyWeakReference *proxy)
355{
356 if (!proxy_checkref(proxy))
357 return -1;
358 return PyObject_Length(proxy->wr_object);
359}
360
361WRAP_BINARY(proxy_getitem, PyObject_GetItem)
362
363static int
364proxy_setitem(PyWeakReference *proxy, PyObject *key, PyObject *value)
365{
366 if (!proxy_checkref(proxy))
367 return -1;
368 return PyObject_SetItem(proxy->wr_object, key, value);
369}
370
371
372static PyNumberMethods proxy_as_number = {
373 (binaryfunc)proxy_add, /*nb_add*/
374 (binaryfunc)proxy_sub, /*nb_subtract*/
375 (binaryfunc)proxy_mul, /*nb_multiply*/
376 (binaryfunc)proxy_div, /*nb_divide*/
377 (binaryfunc)proxy_mod, /*nb_remainder*/
378 (binaryfunc)proxy_divmod, /*nb_divmod*/
379 (ternaryfunc)proxy_pow, /*nb_power*/
380 (unaryfunc)proxy_neg, /*nb_negative*/
381 (unaryfunc)proxy_pos, /*nb_positive*/
382 (unaryfunc)proxy_abs, /*nb_absolute*/
383 (inquiry)proxy_nonzero, /*nb_nonzero*/
384 (unaryfunc)proxy_invert, /*nb_invert*/
385 (binaryfunc)proxy_lshift, /*nb_lshift*/
386 (binaryfunc)proxy_rshift, /*nb_rshift*/
387 (binaryfunc)proxy_and, /*nb_and*/
388 (binaryfunc)proxy_xor, /*nb_xor*/
389 (binaryfunc)proxy_or, /*nb_or*/
390 (coercion)0, /*nb_coerce*/
391 (unaryfunc)proxy_int, /*nb_int*/
392 (unaryfunc)proxy_long, /*nb_long*/
393 (unaryfunc)proxy_float, /*nb_float*/
394 (unaryfunc)0, /*nb_oct*/
395 (unaryfunc)0, /*nb_hex*/
396 (binaryfunc)proxy_iadd, /*nb_inplace_add*/
397 (binaryfunc)proxy_isub, /*nb_inplace_subtract*/
398 (binaryfunc)proxy_imul, /*nb_inplace_multiply*/
399 (binaryfunc)proxy_idiv, /*nb_inplace_divide*/
400 (binaryfunc)proxy_imod, /*nb_inplace_remainder*/
401 (ternaryfunc)proxy_ipow, /*nb_inplace_power*/
402 (binaryfunc)proxy_ilshift, /*nb_inplace_lshift*/
403 (binaryfunc)proxy_irshift, /*nb_inplace_rshift*/
404 (binaryfunc)proxy_iand, /*nb_inplace_and*/
405 (binaryfunc)proxy_ixor, /*nb_inplace_xor*/
406 (binaryfunc)proxy_ior, /*nb_inplace_or*/
407};
408
409static PySequenceMethods proxy_as_sequence = {
410 (inquiry)proxy_length, /*sq_length*/
411 0, /*sq_concat*/
412 0, /*sq_repeat*/
413 0, /*sq_item*/
414 (intintargfunc)proxy_slice, /*sq_slice*/
415 0, /*sq_ass_item*/
416 (intintobjargproc)proxy_ass_slice, /*sq_ass_slice*/
417 (objobjproc)proxy_contains, /* sq_contains */
418};
419
420static PyMappingMethods proxy_as_mapping = {
421 (inquiry)proxy_length, /*mp_length*/
422 (binaryfunc)proxy_getitem, /*mp_subscript*/
423 (objobjargproc)proxy_setitem, /*mp_ass_subscript*/
424};
425
426
427static PyTypeObject
428PyWeakProxy_Type = {
429 PyObject_HEAD_INIT(NULL)
430 0,
431 "weakproxy",
432 sizeof(PyWeakReference) + PyGC_HEAD_SIZE,
433 0,
434 /* methods */
435 (destructor)weakref_dealloc,/*tp_dealloc*/
436 (printfunc)proxy_print, /*tp_print*/
437 0, /*tp_getattr*/
438 0, /*tp_setattr*/
439 (cmpfunc)proxy_compare, /*tp_compare*/
440 (unaryfunc)proxy_repr, /*tp_repr*/
441 &proxy_as_number, /*tp_as_number*/
442 &proxy_as_sequence, /*tp_as_sequence*/
443 &proxy_as_mapping, /*tp_as_mapping*/
444 0, /*tp_hash*/
445 (ternaryfunc)0, /*tp_call*/
446 (unaryfunc)proxy_str, /*tp_str*/
447 (getattrofunc)proxy_getattr,/*tp_getattro*/
448 (setattrofunc)proxy_setattr,/*tp_setattro*/
449 0, /*tp_as_buffer*/
450 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC
451 |Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
452 0, /*tp_doc*/
453 (traverseproc)gc_traverse, /*tp_traverse*/
454 (inquiry)gc_clear, /*tp_clear*/
455};
456
457
458static PyTypeObject
459PyWeakCallableProxy_Type = {
460 PyObject_HEAD_INIT(NULL)
461 0,
462 "weakcallableproxy",
463 sizeof(PyWeakReference) + PyGC_HEAD_SIZE,
464 0,
465 /* methods */
466 (destructor)weakref_dealloc,/*tp_dealloc*/
467 (printfunc)proxy_print, /*tp_print*/
468 0, /*tp_getattr*/
469 0, /*tp_setattr*/
470 (cmpfunc)proxy_compare, /*tp_compare*/
471 (unaryfunc)proxy_repr, /*tp_repr*/
472 &proxy_as_number, /*tp_as_number*/
473 &proxy_as_sequence, /*tp_as_sequence*/
474 &proxy_as_mapping, /*tp_as_mapping*/
475 0, /*tp_hash*/
476 (ternaryfunc)proxy_call, /*tp_call*/
477 (unaryfunc)proxy_str, /*tp_str*/
478 (getattrofunc)proxy_getattr,/*tp_getattro*/
479 (setattrofunc)proxy_setattr,/*tp_setattro*/
480 0, /*tp_as_buffer*/
481 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC
482 |Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
483 0, /*tp_doc*/
484 (traverseproc)gc_traverse, /*tp_traverse*/
485 (inquiry)gc_clear, /*tp_clear*/
486};
487
488
489static long
490getweakrefcount(PyWeakReference *head)
491{
492 long count = 0;
493
494 while (head != NULL) {
495 ++count;
496 head = head->wr_next;
497 }
498 return count;
499}
500
501
Fred Drake7855aba2001-02-18 05:20:18 +0000502static char weakref_getweakrefcount__doc__[] =
503"getweakrefcount(object) -- return the number of weak references\n"
504"to 'object'.";
505
Fred Drake41deb1e2001-02-01 05:27:45 +0000506static PyObject *
507weakref_getweakrefcount(PyObject *self, PyObject *args)
508{
509 PyObject *result = NULL;
510 PyObject *object;
511
512 if (PyArg_ParseTuple(args, "O:getweakrefcount", &object)) {
513 if (PyType_SUPPORTS_WEAKREFS(object->ob_type)) {
514 PyWeakReference **list = GET_WEAKREFS_LISTPTR(object);
515
516 result = PyInt_FromLong(getweakrefcount(*list));
517 }
518 else
519 result = PyInt_FromLong(0);
520 }
521 return result;
522}
523
524
Fred Drake7855aba2001-02-18 05:20:18 +0000525static char weakref_getweakrefs__doc__[] =
526"getweakrefs(object) -- return a list of all weak reference objects\n"
527"that point to 'object'.";
528
Fred Drake41deb1e2001-02-01 05:27:45 +0000529static PyObject *
530weakref_getweakrefs(PyObject *self, PyObject *args)
531{
532 PyObject *result = NULL;
533 PyObject *object;
534
535 if (PyArg_ParseTuple(args, "O:getweakrefs", &object)) {
536 if (PyType_SUPPORTS_WEAKREFS(object->ob_type)) {
537 PyWeakReference **list = GET_WEAKREFS_LISTPTR(object);
538 long count = getweakrefcount(*list);
539
540 result = PyList_New(count);
541 if (result != NULL) {
542 PyWeakReference *current = *list;
543 long i;
544 for (i = 0; i < count; ++i) {
545 PyList_SET_ITEM(result, i, (PyObject *) current);
546 Py_INCREF(current);
547 current = current->wr_next;
548 }
549 }
550 }
551 else {
552 result = PyList_New(0);
553 }
554 }
555 return result;
556}
557
558
559/* Given the head of an object's list of weak references, extract the
560 * two callback-less refs (ref and proxy). Used to determine if the
561 * shared references exist and to determine the back link for newly
562 * inserted references.
563 */
564static void
565get_basic_refs(PyWeakReference *head,
566 PyWeakReference **refp, PyWeakReference **proxyp)
567{
568 *refp = NULL;
569 *proxyp = NULL;
570
571 if (head != NULL && head->wr_callback == NULL) {
572 if (head->ob_type == &PyWeakReference_Type) {
573 *refp = head;
574 head = head->wr_next;
575 }
576 if (head != NULL && head->wr_callback == NULL) {
577 *proxyp = head;
578 head = head->wr_next;
579 }
580 }
581}
582
583/* Insert 'newref' in the list after 'prev'. Both must be non-NULL. */
584static void
585insert_after(PyWeakReference *newref, PyWeakReference *prev)
586{
587 newref->wr_prev = prev;
588 newref->wr_next = prev->wr_next;
589 if (prev->wr_next != NULL)
590 prev->wr_next->wr_prev = newref;
591 prev->wr_next = newref;
592}
593
594/* Insert 'newref' at the head of the list; 'list' points to the variable
595 * that stores the head.
596 */
597static void
598insert_head(PyWeakReference *newref, PyWeakReference **list)
599{
600 PyWeakReference *next = *list;
601
602 newref->wr_prev = NULL;
603 newref->wr_next = next;
604 if (next != NULL)
605 next->wr_prev = newref;
606 *list = newref;
607}
608
609
Fred Drake7855aba2001-02-18 05:20:18 +0000610static char weakref_ref__doc__[] =
611"new(object[, callback]) -- create a weak reference to 'object';\n"
612"when 'object' is finalized, 'callback' will be called and passed\n"
613"a reference to 'object'.";
614
Fred Drake41deb1e2001-02-01 05:27:45 +0000615static PyObject *
616weakref_ref(PyObject *self, PyObject *args)
617{
618 PyObject *object;
619 PyObject *callback = NULL;
620 PyWeakReference *result = NULL;
621
622 if (PyArg_ParseTuple(args, "O|O:new", &object, &callback)) {
623 PyWeakReference **list;
624 PyWeakReference *ref, *proxy;
625
626 if (!PyType_SUPPORTS_WEAKREFS(object->ob_type)) {
627 PyErr_Format(PyExc_TypeError,
628 "'%s' objects are not weakly referencable",
629 object->ob_type->tp_name);
630 return NULL;
631 }
632 list = GET_WEAKREFS_LISTPTR(object);
633 get_basic_refs(*list, &ref, &proxy);
634 if (callback == NULL) {
635 /* return existing weak reference if it exists */
636 result = ref;
637 Py_XINCREF(result);
638 }
639 if (result == NULL) {
640 result = new_weakref();
641 if (result != NULL) {
642 Py_XINCREF(callback);
643 result->wr_callback = callback;
644 result->wr_object = object;
645 if (callback == NULL) {
646 insert_head(result, list);
647 }
648 else {
649 PyWeakReference *prev = (proxy == NULL) ? ref : proxy;
650
651 if (prev == NULL)
652 insert_head(result, list);
653 else
654 insert_after(result, prev);
655 }
656 PyObject_GC_Init((PyObject *) result);
657 }
658 }
659 }
660 return (PyObject *) result;
661}
662
663
Fred Drake7855aba2001-02-18 05:20:18 +0000664static char weakref_proxy__doc__[] =
665"proxy(object[, callback]) -- create a proxy object that weakly\n"
666"references 'object'. 'callback', if given, is called with a\n"
667"reference to the proxy when it is about to be finalized.";
668
Fred Drake41deb1e2001-02-01 05:27:45 +0000669static PyObject *
670weakref_proxy(PyObject *self, PyObject *args)
671{
672 PyObject *object;
673 PyObject *callback = NULL;
674 PyWeakReference *result = NULL;
675
676 if (PyArg_ParseTuple(args, "O|O:new", &object, &callback)) {
677 PyWeakReference **list;
678 PyWeakReference *ref, *proxy;
679
680 if (!PyType_SUPPORTS_WEAKREFS(object->ob_type)) {
681 PyErr_Format(PyExc_TypeError,
682 "'%s' objects are not weakly referencable",
683 object->ob_type->tp_name);
684 return NULL;
685 }
686 list = GET_WEAKREFS_LISTPTR(object);
687 get_basic_refs(*list, &ref, &proxy);
688 if (callback == NULL) {
689 /* attempt to return an existing weak reference if it exists */
690 result = proxy;
691 Py_XINCREF(result);
692 }
693 if (result == NULL) {
694 result = new_weakref();
695 if (result != NULL) {
696 PyWeakReference *prev;
697
698 if (PyCallable_Check(object))
699 result->ob_type = &PyWeakCallableProxy_Type;
700 else
701 result->ob_type = &PyWeakProxy_Type;
702 result->wr_object = object;
703 Py_XINCREF(callback);
704 result->wr_callback = callback;
705 if (callback == NULL)
706 prev = ref;
707 else
708 prev = (proxy == NULL) ? ref : proxy;
709
710 if (prev == NULL)
711 insert_head(result, list);
712 else
713 insert_after(result, prev);
714 PyObject_GC_Init((PyObject *) result);
715 }
716 }
717 }
718 return (PyObject *) result;
719}
720
721
722/* This is the implementation of the PyObject_ClearWeakRefs() function; it
723 * is installed in the init_weakref() function. It is called by the
724 * tp_dealloc handler to clear weak references.
725 *
Fred Drake41deb1e2001-02-01 05:27:45 +0000726 * This iterates through the weak references for 'object' and calls callbacks
Fred Drake32efcdb2001-02-26 20:10:51 +0000727 * for those references which have one. It returns when all callbacks have
728 * been attempted.
Fred Drake41deb1e2001-02-01 05:27:45 +0000729 */
Fred Drake32efcdb2001-02-26 20:10:51 +0000730static void
Fred Drake41deb1e2001-02-01 05:27:45 +0000731cleanup_helper(PyObject *object)
732{
733 PyWeakReference **list;
734
735 if (object == NULL
736 || !PyType_SUPPORTS_WEAKREFS(object->ob_type)
737 || object->ob_refcnt != 0) {
738 PyErr_BadInternalCall();
739 /* not sure what we should return here */
Fred Drakeb60654b2001-02-26 18:56:37 +0000740 return;
Fred Drake41deb1e2001-02-01 05:27:45 +0000741 }
742 list = GET_WEAKREFS_LISTPTR(object);
Fred Drake2a5a5ca2001-04-13 17:15:47 +0000743 /* Remove the callback-less basic and proxy references */
744 if (*list != NULL && (*list)->wr_callback == NULL) {
745 clear_weakref(*list);
746 if (*list != NULL && (*list)->wr_callback == NULL)
747 clear_weakref(*list);
748 }
749 if (*list != NULL) {
750 int count = getweakrefcount(*list);
Fred Drake41deb1e2001-02-01 05:27:45 +0000751
Fred Drake2a5a5ca2001-04-13 17:15:47 +0000752 if (count == 1) {
753 PyWeakReference *current = *list;
754 PyObject *callback = current->wr_callback;
Fred Drake41deb1e2001-02-01 05:27:45 +0000755 PyObject *cbresult;
756
Fred Drake2a5a5ca2001-04-13 17:15:47 +0000757 Py_INCREF(callback);
758 clear_weakref(current);
Fred Drake41deb1e2001-02-01 05:27:45 +0000759 cbresult = PyObject_CallFunction(callback, "O", current);
760 if (cbresult == NULL)
761 PyErr_WriteUnraisable(callback);
762 else
763 Py_DECREF(cbresult);
764 Py_DECREF(callback);
765 }
Fred Drake2a5a5ca2001-04-13 17:15:47 +0000766 else {
767 PyObject *tuple = PyTuple_New(count * 2);
768 PyWeakReference *current = *list;
769 int i = 0;
770
771 for (i = 0; i < count; ++i) {
772 PyWeakReference *next = current->wr_next;
773
774 Py_INCREF(current);
775 PyTuple_SET_ITEM(tuple, i * 2, (PyObject *) current);
776 PyTuple_SET_ITEM(tuple, i * 2 + 1, current->wr_callback);
777 current->wr_callback = NULL;
778 next = current->wr_next;
779 clear_weakref(current);
780 current = next;
781 }
782 for (i = 0; i < count; ++i) {
783 PyObject *current = PyTuple_GET_ITEM(tuple, i * 2);
784 PyObject *callback = PyTuple_GET_ITEM(tuple, i * 2 + 1);
785 PyObject *cbresult = PyObject_CallFunction(callback, "O",
786 current);
787 if (cbresult == NULL)
788 PyErr_WriteUnraisable(callback);
789 else
790 Py_DECREF(cbresult);
791 }
792 Py_DECREF(tuple);
793 }
Fred Drake41deb1e2001-02-01 05:27:45 +0000794 }
Fred Drakeb60654b2001-02-26 18:56:37 +0000795 return;
Fred Drake41deb1e2001-02-01 05:27:45 +0000796}
797
798
799static PyMethodDef
800weakref_functions[] = {
801 {"getweakrefcount", weakref_getweakrefcount, METH_VARARGS,
Fred Drake7855aba2001-02-18 05:20:18 +0000802 weakref_getweakrefcount__doc__},
Fred Drake41deb1e2001-02-01 05:27:45 +0000803 {"getweakrefs", weakref_getweakrefs, METH_VARARGS,
Fred Drake7855aba2001-02-18 05:20:18 +0000804 weakref_getweakrefs__doc__},
805 {"proxy", weakref_proxy, METH_VARARGS,
806 weakref_proxy__doc__},
Fred Drake41deb1e2001-02-01 05:27:45 +0000807 {"ref", weakref_ref, METH_VARARGS,
Fred Drake7855aba2001-02-18 05:20:18 +0000808 weakref_ref__doc__},
Fred Drake41deb1e2001-02-01 05:27:45 +0000809 {NULL, NULL, 0, NULL}
810};
811
812
Tim Peters747d5b62001-02-02 00:07:07 +0000813DL_EXPORT(void)
Fred Drake41deb1e2001-02-01 05:27:45 +0000814init_weakref(void)
815{
816 PyObject *m;
817
818 PyWeakReference_Type.ob_type = &PyType_Type;
819 PyWeakProxy_Type.ob_type = &PyType_Type;
820 PyWeakCallableProxy_Type.ob_type = &PyType_Type;
821 m = Py_InitModule3("_weakref", weakref_functions,
822 "Weak-reference support module.");
823 if (m != NULL) {
824 PyObject_ClearWeakRefs = cleanup_helper;
825 Py_INCREF(&PyWeakReference_Type);
826 PyModule_AddObject(m, "ReferenceType",
827 (PyObject *) &PyWeakReference_Type);
828 Py_INCREF(&PyWeakProxy_Type);
829 PyModule_AddObject(m, "ProxyType",
830 (PyObject *) &PyWeakProxy_Type);
831 Py_INCREF(&PyWeakCallableProxy_Type);
832 PyModule_AddObject(m, "CallableProxyType",
833 (PyObject *) &PyWeakCallableProxy_Type);
834 ReferenceError = PyErr_NewException("weakref.ReferenceError",
835 PyExc_RuntimeError, NULL);
836 if (ReferenceError != NULL)
837 PyModule_AddObject(m, "ReferenceError", ReferenceError);
838 }
839}