blob: cab64a39f28b630925d38d5716528dca8c4c5417 [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 *
Fred Drake7fdc0a12001-08-16 14:11:30 +0000507weakref_getweakrefcount(PyObject *self, PyObject *object)
Fred Drake41deb1e2001-02-01 05:27:45 +0000508{
509 PyObject *result = NULL;
Fred Drake41deb1e2001-02-01 05:27:45 +0000510
Fred Drake7fdc0a12001-08-16 14:11:30 +0000511 if (PyType_SUPPORTS_WEAKREFS(object->ob_type)) {
512 PyWeakReference **list = GET_WEAKREFS_LISTPTR(object);
Fred Drake41deb1e2001-02-01 05:27:45 +0000513
Fred Drake7fdc0a12001-08-16 14:11:30 +0000514 result = PyInt_FromLong(getweakrefcount(*list));
Fred Drake41deb1e2001-02-01 05:27:45 +0000515 }
Fred Drake7fdc0a12001-08-16 14:11:30 +0000516 else
517 result = PyInt_FromLong(0);
518
Fred Drake41deb1e2001-02-01 05:27:45 +0000519 return result;
520}
521
522
Fred Drake7855aba2001-02-18 05:20:18 +0000523static char weakref_getweakrefs__doc__[] =
524"getweakrefs(object) -- return a list of all weak reference objects\n"
525"that point to 'object'.";
526
Fred Drake41deb1e2001-02-01 05:27:45 +0000527static PyObject *
Fred Drake7fdc0a12001-08-16 14:11:30 +0000528weakref_getweakrefs(PyObject *self, PyObject *object)
Fred Drake41deb1e2001-02-01 05:27:45 +0000529{
530 PyObject *result = NULL;
Fred Drake41deb1e2001-02-01 05:27:45 +0000531
Fred Drake7fdc0a12001-08-16 14:11:30 +0000532 if (PyType_SUPPORTS_WEAKREFS(object->ob_type)) {
533 PyWeakReference **list = GET_WEAKREFS_LISTPTR(object);
534 long count = getweakrefcount(*list);
Fred Drake41deb1e2001-02-01 05:27:45 +0000535
Fred Drake7fdc0a12001-08-16 14:11:30 +0000536 result = PyList_New(count);
537 if (result != NULL) {
538 PyWeakReference *current = *list;
539 long i;
540 for (i = 0; i < count; ++i) {
541 PyList_SET_ITEM(result, i, (PyObject *) current);
542 Py_INCREF(current);
543 current = current->wr_next;
Fred Drake41deb1e2001-02-01 05:27:45 +0000544 }
545 }
Fred Drake7fdc0a12001-08-16 14:11:30 +0000546 }
547 else {
548 result = PyList_New(0);
Fred Drake41deb1e2001-02-01 05:27:45 +0000549 }
550 return result;
551}
552
553
554/* Given the head of an object's list of weak references, extract the
555 * two callback-less refs (ref and proxy). Used to determine if the
556 * shared references exist and to determine the back link for newly
557 * inserted references.
558 */
559static void
560get_basic_refs(PyWeakReference *head,
561 PyWeakReference **refp, PyWeakReference **proxyp)
562{
563 *refp = NULL;
564 *proxyp = NULL;
565
566 if (head != NULL && head->wr_callback == NULL) {
567 if (head->ob_type == &PyWeakReference_Type) {
568 *refp = head;
569 head = head->wr_next;
570 }
571 if (head != NULL && head->wr_callback == NULL) {
572 *proxyp = head;
573 head = head->wr_next;
574 }
575 }
576}
577
578/* Insert 'newref' in the list after 'prev'. Both must be non-NULL. */
579static void
580insert_after(PyWeakReference *newref, PyWeakReference *prev)
581{
582 newref->wr_prev = prev;
583 newref->wr_next = prev->wr_next;
584 if (prev->wr_next != NULL)
585 prev->wr_next->wr_prev = newref;
586 prev->wr_next = newref;
587}
588
589/* Insert 'newref' at the head of the list; 'list' points to the variable
590 * that stores the head.
591 */
592static void
593insert_head(PyWeakReference *newref, PyWeakReference **list)
594{
595 PyWeakReference *next = *list;
596
597 newref->wr_prev = NULL;
598 newref->wr_next = next;
599 if (next != NULL)
600 next->wr_prev = newref;
601 *list = newref;
602}
603
604
Fred Drake7855aba2001-02-18 05:20:18 +0000605static char weakref_ref__doc__[] =
606"new(object[, callback]) -- create a weak reference to 'object';\n"
607"when 'object' is finalized, 'callback' will be called and passed\n"
608"a reference to 'object'.";
609
Fred Drake41deb1e2001-02-01 05:27:45 +0000610static PyObject *
611weakref_ref(PyObject *self, PyObject *args)
612{
613 PyObject *object;
614 PyObject *callback = NULL;
615 PyWeakReference *result = NULL;
616
617 if (PyArg_ParseTuple(args, "O|O:new", &object, &callback)) {
618 PyWeakReference **list;
619 PyWeakReference *ref, *proxy;
620
621 if (!PyType_SUPPORTS_WEAKREFS(object->ob_type)) {
622 PyErr_Format(PyExc_TypeError,
623 "'%s' objects are not weakly referencable",
624 object->ob_type->tp_name);
625 return NULL;
626 }
627 list = GET_WEAKREFS_LISTPTR(object);
628 get_basic_refs(*list, &ref, &proxy);
629 if (callback == NULL) {
630 /* return existing weak reference if it exists */
631 result = ref;
632 Py_XINCREF(result);
633 }
634 if (result == NULL) {
635 result = new_weakref();
636 if (result != NULL) {
637 Py_XINCREF(callback);
638 result->wr_callback = callback;
639 result->wr_object = object;
640 if (callback == NULL) {
641 insert_head(result, list);
642 }
643 else {
644 PyWeakReference *prev = (proxy == NULL) ? ref : proxy;
645
646 if (prev == NULL)
647 insert_head(result, list);
648 else
649 insert_after(result, prev);
650 }
651 PyObject_GC_Init((PyObject *) result);
652 }
653 }
654 }
655 return (PyObject *) result;
656}
657
658
Fred Drake7855aba2001-02-18 05:20:18 +0000659static char weakref_proxy__doc__[] =
660"proxy(object[, callback]) -- create a proxy object that weakly\n"
661"references 'object'. 'callback', if given, is called with a\n"
662"reference to the proxy when it is about to be finalized.";
663
Fred Drake41deb1e2001-02-01 05:27:45 +0000664static PyObject *
665weakref_proxy(PyObject *self, PyObject *args)
666{
667 PyObject *object;
668 PyObject *callback = NULL;
669 PyWeakReference *result = NULL;
670
671 if (PyArg_ParseTuple(args, "O|O:new", &object, &callback)) {
672 PyWeakReference **list;
673 PyWeakReference *ref, *proxy;
674
675 if (!PyType_SUPPORTS_WEAKREFS(object->ob_type)) {
676 PyErr_Format(PyExc_TypeError,
677 "'%s' objects are not weakly referencable",
678 object->ob_type->tp_name);
679 return NULL;
680 }
681 list = GET_WEAKREFS_LISTPTR(object);
682 get_basic_refs(*list, &ref, &proxy);
683 if (callback == NULL) {
684 /* attempt to return an existing weak reference if it exists */
685 result = proxy;
686 Py_XINCREF(result);
687 }
688 if (result == NULL) {
689 result = new_weakref();
690 if (result != NULL) {
691 PyWeakReference *prev;
692
693 if (PyCallable_Check(object))
694 result->ob_type = &PyWeakCallableProxy_Type;
695 else
696 result->ob_type = &PyWeakProxy_Type;
697 result->wr_object = object;
698 Py_XINCREF(callback);
699 result->wr_callback = callback;
700 if (callback == NULL)
701 prev = ref;
702 else
703 prev = (proxy == NULL) ? ref : proxy;
704
705 if (prev == NULL)
706 insert_head(result, list);
707 else
708 insert_after(result, prev);
709 PyObject_GC_Init((PyObject *) result);
710 }
711 }
712 }
713 return (PyObject *) result;
714}
715
716
717/* This is the implementation of the PyObject_ClearWeakRefs() function; it
718 * is installed in the init_weakref() function. It is called by the
719 * tp_dealloc handler to clear weak references.
720 *
Fred Drake41deb1e2001-02-01 05:27:45 +0000721 * This iterates through the weak references for 'object' and calls callbacks
Fred Drake32efcdb2001-02-26 20:10:51 +0000722 * for those references which have one. It returns when all callbacks have
723 * been attempted.
Fred Drake41deb1e2001-02-01 05:27:45 +0000724 */
Fred Drake32efcdb2001-02-26 20:10:51 +0000725static void
Fred Drake41deb1e2001-02-01 05:27:45 +0000726cleanup_helper(PyObject *object)
727{
728 PyWeakReference **list;
729
730 if (object == NULL
731 || !PyType_SUPPORTS_WEAKREFS(object->ob_type)
732 || object->ob_refcnt != 0) {
733 PyErr_BadInternalCall();
Fred Drakeb60654b2001-02-26 18:56:37 +0000734 return;
Fred Drake41deb1e2001-02-01 05:27:45 +0000735 }
736 list = GET_WEAKREFS_LISTPTR(object);
Fred Drake2a5a5ca2001-04-13 17:15:47 +0000737 /* Remove the callback-less basic and proxy references */
738 if (*list != NULL && (*list)->wr_callback == NULL) {
739 clear_weakref(*list);
740 if (*list != NULL && (*list)->wr_callback == NULL)
741 clear_weakref(*list);
742 }
743 if (*list != NULL) {
744 int count = getweakrefcount(*list);
Fred Drake41deb1e2001-02-01 05:27:45 +0000745
Fred Drake2a5a5ca2001-04-13 17:15:47 +0000746 if (count == 1) {
747 PyWeakReference *current = *list;
748 PyObject *callback = current->wr_callback;
Fred Drake41deb1e2001-02-01 05:27:45 +0000749 PyObject *cbresult;
750
Fred Drake2a5a5ca2001-04-13 17:15:47 +0000751 Py_INCREF(callback);
752 clear_weakref(current);
Fred Drake41deb1e2001-02-01 05:27:45 +0000753 cbresult = PyObject_CallFunction(callback, "O", current);
754 if (cbresult == NULL)
755 PyErr_WriteUnraisable(callback);
756 else
757 Py_DECREF(cbresult);
758 Py_DECREF(callback);
759 }
Fred Drake2a5a5ca2001-04-13 17:15:47 +0000760 else {
761 PyObject *tuple = PyTuple_New(count * 2);
762 PyWeakReference *current = *list;
763 int i = 0;
764
765 for (i = 0; i < count; ++i) {
766 PyWeakReference *next = current->wr_next;
767
768 Py_INCREF(current);
769 PyTuple_SET_ITEM(tuple, i * 2, (PyObject *) current);
770 PyTuple_SET_ITEM(tuple, i * 2 + 1, current->wr_callback);
771 current->wr_callback = NULL;
772 next = current->wr_next;
773 clear_weakref(current);
774 current = next;
775 }
776 for (i = 0; i < count; ++i) {
777 PyObject *current = PyTuple_GET_ITEM(tuple, i * 2);
778 PyObject *callback = PyTuple_GET_ITEM(tuple, i * 2 + 1);
779 PyObject *cbresult = PyObject_CallFunction(callback, "O",
780 current);
781 if (cbresult == NULL)
782 PyErr_WriteUnraisable(callback);
783 else
784 Py_DECREF(cbresult);
785 }
786 Py_DECREF(tuple);
787 }
Fred Drake41deb1e2001-02-01 05:27:45 +0000788 }
Fred Drake41deb1e2001-02-01 05:27:45 +0000789}
790
791
792static PyMethodDef
793weakref_functions[] = {
Fred Drake7fdc0a12001-08-16 14:11:30 +0000794 {"getweakrefcount", weakref_getweakrefcount, METH_O,
Fred Drake7855aba2001-02-18 05:20:18 +0000795 weakref_getweakrefcount__doc__},
Fred Drake7fdc0a12001-08-16 14:11:30 +0000796 {"getweakrefs", weakref_getweakrefs, METH_O,
Fred Drake7855aba2001-02-18 05:20:18 +0000797 weakref_getweakrefs__doc__},
798 {"proxy", weakref_proxy, METH_VARARGS,
799 weakref_proxy__doc__},
Fred Drake41deb1e2001-02-01 05:27:45 +0000800 {"ref", weakref_ref, METH_VARARGS,
Fred Drake7855aba2001-02-18 05:20:18 +0000801 weakref_ref__doc__},
Fred Drake41deb1e2001-02-01 05:27:45 +0000802 {NULL, NULL, 0, NULL}
803};
804
805
Tim Peters747d5b62001-02-02 00:07:07 +0000806DL_EXPORT(void)
Fred Drake41deb1e2001-02-01 05:27:45 +0000807init_weakref(void)
808{
809 PyObject *m;
810
811 PyWeakReference_Type.ob_type = &PyType_Type;
812 PyWeakProxy_Type.ob_type = &PyType_Type;
813 PyWeakCallableProxy_Type.ob_type = &PyType_Type;
814 m = Py_InitModule3("_weakref", weakref_functions,
815 "Weak-reference support module.");
816 if (m != NULL) {
817 PyObject_ClearWeakRefs = cleanup_helper;
818 Py_INCREF(&PyWeakReference_Type);
819 PyModule_AddObject(m, "ReferenceType",
820 (PyObject *) &PyWeakReference_Type);
821 Py_INCREF(&PyWeakProxy_Type);
822 PyModule_AddObject(m, "ProxyType",
823 (PyObject *) &PyWeakProxy_Type);
824 Py_INCREF(&PyWeakCallableProxy_Type);
825 PyModule_AddObject(m, "CallableProxyType",
826 (PyObject *) &PyWeakCallableProxy_Type);
827 ReferenceError = PyErr_NewException("weakref.ReferenceError",
828 PyExc_RuntimeError, NULL);
829 if (ReferenceError != NULL)
830 PyModule_AddObject(m, "ReferenceError", ReferenceError);
831 }
832}