blob: 399b4fe67b55da0646c6446ebf90391b8fe35633 [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);
743 while (*list != NULL) {
744 PyWeakReference *current = *list;
745 PyObject *callback = current->wr_callback;
746
747 Py_XINCREF(callback);
748 clear_weakref(current);
749 if (callback != NULL) {
750 PyObject *cbresult;
751
752 cbresult = PyObject_CallFunction(callback, "O", current);
753 if (cbresult == NULL)
754 PyErr_WriteUnraisable(callback);
755 else
756 Py_DECREF(cbresult);
757 Py_DECREF(callback);
758 }
759 }
Fred Drakeb60654b2001-02-26 18:56:37 +0000760 return;
Fred Drake41deb1e2001-02-01 05:27:45 +0000761}
762
763
764static PyMethodDef
765weakref_functions[] = {
766 {"getweakrefcount", weakref_getweakrefcount, METH_VARARGS,
Fred Drake7855aba2001-02-18 05:20:18 +0000767 weakref_getweakrefcount__doc__},
Fred Drake41deb1e2001-02-01 05:27:45 +0000768 {"getweakrefs", weakref_getweakrefs, METH_VARARGS,
Fred Drake7855aba2001-02-18 05:20:18 +0000769 weakref_getweakrefs__doc__},
770 {"proxy", weakref_proxy, METH_VARARGS,
771 weakref_proxy__doc__},
Fred Drake41deb1e2001-02-01 05:27:45 +0000772 {"ref", weakref_ref, METH_VARARGS,
Fred Drake7855aba2001-02-18 05:20:18 +0000773 weakref_ref__doc__},
Fred Drake41deb1e2001-02-01 05:27:45 +0000774 {NULL, NULL, 0, NULL}
775};
776
777
Tim Peters747d5b62001-02-02 00:07:07 +0000778DL_EXPORT(void)
Fred Drake41deb1e2001-02-01 05:27:45 +0000779init_weakref(void)
780{
781 PyObject *m;
782
783 PyWeakReference_Type.ob_type = &PyType_Type;
784 PyWeakProxy_Type.ob_type = &PyType_Type;
785 PyWeakCallableProxy_Type.ob_type = &PyType_Type;
786 m = Py_InitModule3("_weakref", weakref_functions,
787 "Weak-reference support module.");
788 if (m != NULL) {
789 PyObject_ClearWeakRefs = cleanup_helper;
790 Py_INCREF(&PyWeakReference_Type);
791 PyModule_AddObject(m, "ReferenceType",
792 (PyObject *) &PyWeakReference_Type);
793 Py_INCREF(&PyWeakProxy_Type);
794 PyModule_AddObject(m, "ProxyType",
795 (PyObject *) &PyWeakProxy_Type);
796 Py_INCREF(&PyWeakCallableProxy_Type);
797 PyModule_AddObject(m, "CallableProxyType",
798 (PyObject *) &PyWeakCallableProxy_Type);
799 ReferenceError = PyErr_NewException("weakref.ReferenceError",
800 PyExc_RuntimeError, NULL);
801 if (ReferenceError != NULL)
802 PyModule_AddObject(m, "ReferenceError", ReferenceError);
803 }
804}