This commit was manufactured by cvs2svn to create tag 'r22a4-fork'.
[python/dscho.git] / Modules / _weakref.c
blob695ffda9fa7dae19ac2bee460c89d10db6b26f1c
1 #include "Python.h"
2 #include "structmember.h"
5 typedef struct _PyWeakReference PyWeakReference;
7 struct _PyWeakReference {
8 PyObject_HEAD
9 PyObject *wr_object;
10 PyObject *wr_callback;
11 long hash;
12 PyWeakReference *wr_prev;
13 PyWeakReference *wr_next;
17 #define GET_WEAKREFS_LISTPTR(o) \
18 ((PyWeakReference **) PyObject_GET_WEAKREFS_LISTPTR(o))
20 static PyObject *
21 ReferenceError;
23 static PyWeakReference *
24 free_list = NULL;
26 staticforward PyTypeObject
27 PyWeakReference_Type;
29 static PyWeakReference *
30 new_weakref(void)
32 PyWeakReference *result;
34 if (free_list != NULL) {
35 result = free_list;
36 free_list = result->wr_next;
37 result->ob_type = &PyWeakReference_Type;
38 _Py_NewReference((PyObject *)result);
40 else {
41 result = PyObject_GC_New(PyWeakReference, &PyWeakReference_Type);
43 if (result)
44 result->hash = -1;
45 return result;
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.
54 static void
55 clear_weakref(PyWeakReference *self)
57 PyObject *callback = self->wr_callback;
59 if (self->wr_object != Py_None) {
60 PyWeakReference **list = GET_WEAKREFS_LISTPTR(self->wr_object);
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);
77 static void
78 weakref_dealloc(PyWeakReference *self)
80 PyObject_GC_UnTrack((PyObject *)self);
81 clear_weakref(self);
82 self->wr_next = free_list;
83 free_list = self;
87 static int
88 gc_traverse(PyWeakReference *self, visitproc visit, void *arg)
90 if (self->wr_callback != NULL)
91 return visit(self->wr_callback, arg);
92 return 0;
96 static int
97 gc_clear(PyWeakReference *self)
99 clear_weakref(self);
100 return 0;
104 static PyObject *
105 weakref_call(PyWeakReference *self, PyObject *args, PyObject *kw)
107 static char *argnames[] = {NULL};
109 if (PyArg_ParseTupleAndKeywords(args, kw, ":__call__", argnames)) {
110 PyObject *object = self->wr_object;
111 Py_INCREF(object);
112 return (object);
114 return NULL;
118 static long
119 weakref_hash(PyWeakReference *self)
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;
127 self->hash = PyObject_Hash(self->wr_object);
128 return self->hash;
132 static PyObject *
133 weakref_repr(PyWeakReference *self)
135 char buffer[256];
136 if (self->wr_object == Py_None) {
137 sprintf(buffer, "<weakref at %lx; dead>",
138 (long)(self));
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));
145 return PyString_FromString(buffer);
148 /* 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. */
152 static PyObject *
153 weakref_richcompare(PyWeakReference* self, PyWeakReference* other, int op)
155 if (op != Py_EQ || self->ob_type != other->ob_type) {
156 Py_INCREF(Py_NotImplemented);
157 return Py_NotImplemented;
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;
164 return PyObject_RichCompare(self->wr_object, other->wr_object, op);
168 statichere PyTypeObject
169 PyWeakReference_Type = {
170 PyObject_HEAD_INIT(NULL)
172 "weakref",
173 sizeof(PyWeakReference),
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*/
184 (hashfunc)weakref_hash, /*tp_hash*/
185 (ternaryfunc)weakref_call, /*tp_call*/
186 0, /*tp_str*/
187 0, /*tp_getattro*/
188 0, /*tp_setattro*/
189 0, /*tp_as_buffer*/
190 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_RICHCOMPARE,
191 0, /*tp_doc*/
192 (traverseproc)gc_traverse, /*tp_traverse*/
193 (inquiry)gc_clear, /*tp_clear*/
194 (richcmpfunc)weakref_richcompare, /*tp_richcompare*/
195 0, /*tp_weaklistoffset*/
199 static int
200 proxy_checkref(PyWeakReference *proxy)
202 if (proxy->wr_object == Py_None) {
203 PyErr_SetString(ReferenceError,
204 "weakly-referenced object no longer exists");
205 return 0;
207 return 1;
211 #define WRAP_UNARY(method, generic) \
212 static PyObject * \
213 method(PyWeakReference *proxy) { \
214 if (!proxy_checkref(proxy)) { \
215 return NULL; \
217 return generic(proxy->wr_object); \
220 #define WRAP_BINARY(method, generic) \
221 static PyObject * \
222 method(PyWeakReference *proxy, PyObject *v) { \
223 if (!proxy_checkref(proxy)) { \
224 return NULL; \
226 return generic(proxy->wr_object, v); \
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; \
235 return generic(proxy->wr_object, v, w); \
239 /* direct slots */
241 WRAP_BINARY(proxy_getattr, PyObject_GetAttr)
242 WRAP_UNARY(proxy_str, PyObject_Str)
243 WRAP_TERNARY(proxy_call, PyEval_CallObjectWithKeywords)
245 static int
246 proxy_print(PyWeakReference *proxy, FILE *fp, int flags)
248 if (!proxy_checkref(proxy))
249 return -1;
250 return PyObject_Print(proxy->wr_object, fp, flags);
253 static PyObject *
254 proxy_repr(PyWeakReference *proxy)
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);
263 static int
264 proxy_setattr(PyWeakReference *proxy, PyObject *name, PyObject *value)
266 if (!proxy_checkref(proxy))
267 return -1;
268 return PyObject_SetAttr(proxy->wr_object, name, value);
271 static int
272 proxy_compare(PyWeakReference *proxy, PyObject *v)
274 if (!proxy_checkref(proxy))
275 return -1;
276 return PyObject_Compare(proxy->wr_object, v);
279 /* number slots */
280 WRAP_BINARY(proxy_add, PyNumber_Add)
281 WRAP_BINARY(proxy_sub, PyNumber_Subtract)
282 WRAP_BINARY(proxy_mul, PyNumber_Multiply)
283 WRAP_BINARY(proxy_div, PyNumber_Divide)
284 WRAP_BINARY(proxy_mod, PyNumber_Remainder)
285 WRAP_BINARY(proxy_divmod, PyNumber_Divmod)
286 WRAP_TERNARY(proxy_pow, PyNumber_Power)
287 WRAP_UNARY(proxy_neg, PyNumber_Negative)
288 WRAP_UNARY(proxy_pos, PyNumber_Positive)
289 WRAP_UNARY(proxy_abs, PyNumber_Absolute)
290 WRAP_UNARY(proxy_invert, PyNumber_Invert)
291 WRAP_BINARY(proxy_lshift, PyNumber_Lshift)
292 WRAP_BINARY(proxy_rshift, PyNumber_Rshift)
293 WRAP_BINARY(proxy_and, PyNumber_And)
294 WRAP_BINARY(proxy_xor, PyNumber_Xor)
295 WRAP_BINARY(proxy_or, PyNumber_Or)
296 WRAP_UNARY(proxy_int, PyNumber_Int)
297 WRAP_UNARY(proxy_long, PyNumber_Long)
298 WRAP_UNARY(proxy_float, PyNumber_Float)
299 WRAP_BINARY(proxy_iadd, PyNumber_InPlaceAdd)
300 WRAP_BINARY(proxy_isub, PyNumber_InPlaceSubtract)
301 WRAP_BINARY(proxy_imul, PyNumber_InPlaceMultiply)
302 WRAP_BINARY(proxy_idiv, PyNumber_InPlaceDivide)
303 WRAP_BINARY(proxy_imod, PyNumber_InPlaceRemainder)
304 WRAP_TERNARY(proxy_ipow, PyNumber_InPlacePower)
305 WRAP_BINARY(proxy_ilshift, PyNumber_InPlaceLshift)
306 WRAP_BINARY(proxy_irshift, PyNumber_InPlaceRshift)
307 WRAP_BINARY(proxy_iand, PyNumber_InPlaceAnd)
308 WRAP_BINARY(proxy_ixor, PyNumber_InPlaceXor)
309 WRAP_BINARY(proxy_ior, PyNumber_InPlaceOr)
311 static int
312 proxy_nonzero(PyWeakReference *proxy)
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;
324 /* sequence slots */
326 static PyObject *
327 proxy_slice(PyWeakReference *proxy, int i, int j)
329 if (!proxy_checkref(proxy))
330 return NULL;
331 return PySequence_GetSlice(proxy->wr_object, i, j);
334 static int
335 proxy_ass_slice(PyWeakReference *proxy, int i, int j, PyObject *value)
337 if (!proxy_checkref(proxy))
338 return -1;
339 return PySequence_SetSlice(proxy->wr_object, i, j, value);
342 static int
343 proxy_contains(PyWeakReference *proxy, PyObject *value)
345 if (!proxy_checkref(proxy))
346 return -1;
347 return PySequence_Contains(proxy->wr_object, value);
351 /* mapping slots */
353 static int
354 proxy_length(PyWeakReference *proxy)
356 if (!proxy_checkref(proxy))
357 return -1;
358 return PyObject_Length(proxy->wr_object);
361 WRAP_BINARY(proxy_getitem, PyObject_GetItem)
363 static int
364 proxy_setitem(PyWeakReference *proxy, PyObject *key, PyObject *value)
366 if (!proxy_checkref(proxy))
367 return -1;
368 return PyObject_SetItem(proxy->wr_object, key, value);
372 static 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*/
409 static 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 */
420 static PyMappingMethods proxy_as_mapping = {
421 (inquiry)proxy_length, /*mp_length*/
422 (binaryfunc)proxy_getitem, /*mp_subscript*/
423 (objobjargproc)proxy_setitem, /*mp_ass_subscript*/
427 static PyTypeObject
428 PyWeakProxy_Type = {
429 PyObject_HEAD_INIT(NULL)
431 "weakproxy",
432 sizeof(PyWeakReference),
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_HAVE_GC
451 |Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
452 0, /*tp_doc*/
453 (traverseproc)gc_traverse, /*tp_traverse*/
454 (inquiry)gc_clear, /*tp_clear*/
458 static PyTypeObject
459 PyWeakCallableProxy_Type = {
460 PyObject_HEAD_INIT(NULL)
462 "weakcallableproxy",
463 sizeof(PyWeakReference),
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_HAVE_GC
482 |Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
483 0, /*tp_doc*/
484 (traverseproc)gc_traverse, /*tp_traverse*/
485 (inquiry)gc_clear, /*tp_clear*/
489 static long
490 getweakrefcount(PyWeakReference *head)
492 long count = 0;
494 while (head != NULL) {
495 ++count;
496 head = head->wr_next;
498 return count;
502 static char weakref_getweakrefcount__doc__[] =
503 "getweakrefcount(object) -- return the number of weak references\n"
504 "to 'object'.";
506 static PyObject *
507 weakref_getweakrefcount(PyObject *self, PyObject *object)
509 PyObject *result = NULL;
511 if (PyType_SUPPORTS_WEAKREFS(object->ob_type)) {
512 PyWeakReference **list = GET_WEAKREFS_LISTPTR(object);
514 result = PyInt_FromLong(getweakrefcount(*list));
516 else
517 result = PyInt_FromLong(0);
519 return result;
523 static char weakref_getweakrefs__doc__[] =
524 "getweakrefs(object) -- return a list of all weak reference objects\n"
525 "that point to 'object'.";
527 static PyObject *
528 weakref_getweakrefs(PyObject *self, PyObject *object)
530 PyObject *result = NULL;
532 if (PyType_SUPPORTS_WEAKREFS(object->ob_type)) {
533 PyWeakReference **list = GET_WEAKREFS_LISTPTR(object);
534 long count = getweakrefcount(*list);
536 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;
547 else {
548 result = PyList_New(0);
550 return result;
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.
559 static void
560 get_basic_refs(PyWeakReference *head,
561 PyWeakReference **refp, PyWeakReference **proxyp)
563 *refp = NULL;
564 *proxyp = NULL;
566 if (head != NULL && head->wr_callback == NULL) {
567 if (head->ob_type == &PyWeakReference_Type) {
568 *refp = head;
569 head = head->wr_next;
571 if (head != NULL && head->wr_callback == NULL) {
572 *proxyp = head;
573 head = head->wr_next;
578 /* Insert 'newref' in the list after 'prev'. Both must be non-NULL. */
579 static void
580 insert_after(PyWeakReference *newref, PyWeakReference *prev)
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;
589 /* Insert 'newref' at the head of the list; 'list' points to the variable
590 * that stores the head.
592 static void
593 insert_head(PyWeakReference *newref, PyWeakReference **list)
595 PyWeakReference *next = *list;
597 newref->wr_prev = NULL;
598 newref->wr_next = next;
599 if (next != NULL)
600 next->wr_prev = newref;
601 *list = newref;
605 static 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'.";
610 static PyObject *
611 weakref_ref(PyObject *self, PyObject *args)
613 PyObject *object;
614 PyObject *callback = NULL;
615 PyWeakReference *result = NULL;
617 if (PyArg_ParseTuple(args, "O|O:new", &object, &callback)) {
618 PyWeakReference **list;
619 PyWeakReference *ref, *proxy;
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;
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);
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);
643 else {
644 PyWeakReference *prev = (proxy == NULL) ? ref : proxy;
646 if (prev == NULL)
647 insert_head(result, list);
648 else
649 insert_after(result, prev);
651 PyObject_GC_Track(result);
655 return (PyObject *) result;
659 static 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.";
664 static PyObject *
665 weakref_proxy(PyObject *self, PyObject *args)
667 PyObject *object;
668 PyObject *callback = NULL;
669 PyWeakReference *result = NULL;
671 if (PyArg_ParseTuple(args, "O|O:new", &object, &callback)) {
672 PyWeakReference **list;
673 PyWeakReference *ref, *proxy;
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;
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);
688 if (result == NULL) {
689 result = new_weakref();
690 if (result != NULL) {
691 PyWeakReference *prev;
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;
705 if (prev == NULL)
706 insert_head(result, list);
707 else
708 insert_after(result, prev);
709 PyObject_GC_Track(result);
713 return (PyObject *) result;
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.
721 * This iterates through the weak references for 'object' and calls callbacks
722 * for those references which have one. It returns when all callbacks have
723 * been attempted.
725 static void
726 cleanup_helper(PyObject *object)
728 PyWeakReference **list;
730 if (object == NULL
731 || !PyType_SUPPORTS_WEAKREFS(object->ob_type)
732 || object->ob_refcnt != 0) {
733 PyErr_BadInternalCall();
734 return;
736 list = GET_WEAKREFS_LISTPTR(object);
737 /* 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);
743 if (*list != NULL) {
744 int count = getweakrefcount(*list);
746 if (count == 1) {
747 PyWeakReference *current = *list;
748 PyObject *callback = current->wr_callback;
749 PyObject *cbresult;
751 Py_INCREF(callback);
752 clear_weakref(current);
753 cbresult = PyObject_CallFunction(callback, "O", current);
754 if (cbresult == NULL)
755 PyErr_WriteUnraisable(callback);
756 else
757 Py_DECREF(cbresult);
758 Py_DECREF(callback);
760 else {
761 PyObject *tuple = PyTuple_New(count * 2);
762 PyWeakReference *current = *list;
763 int i = 0;
765 for (i = 0; i < count; ++i) {
766 PyWeakReference *next = current->wr_next;
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;
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);
786 Py_DECREF(tuple);
792 static PyMethodDef
793 weakref_functions[] = {
794 {"getweakrefcount", weakref_getweakrefcount, METH_O,
795 weakref_getweakrefcount__doc__},
796 {"getweakrefs", weakref_getweakrefs, METH_O,
797 weakref_getweakrefs__doc__},
798 {"proxy", weakref_proxy, METH_VARARGS,
799 weakref_proxy__doc__},
800 {"ref", weakref_ref, METH_VARARGS,
801 weakref_ref__doc__},
802 {NULL, NULL, 0, NULL}
806 DL_EXPORT(void)
807 init_weakref(void)
809 PyObject *m;
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);