blob: e26cb65b13041c4916c7cc0394e14f0de509fe57 [file] [log] [blame]
Fred Drake8844d522001-10-05 21:52:26 +00001#include "Python.h"
2#include "structmember.h"
3
4
5#define GET_WEAKREFS_LISTPTR(o) \
6 ((PyWeakReference **) PyObject_GET_WEAKREFS_LISTPTR(o))
7
Fred Drake8844d522001-10-05 21:52:26 +00008
9long
10_PyWeakref_GetWeakrefCount(PyWeakReference *head)
11{
12 long count = 0;
13
14 while (head != NULL) {
15 ++count;
16 head = head->wr_next;
17 }
18 return count;
19}
20
21
22static PyWeakReference *
Neil Schemenauer38a89162002-03-27 15:18:21 +000023new_weakref(PyObject *ob, PyObject *callback)
Fred Drake8844d522001-10-05 21:52:26 +000024{
25 PyWeakReference *result;
26
Neil Schemenauer38a89162002-03-27 15:18:21 +000027 result = PyObject_GC_New(PyWeakReference, &_PyWeakref_RefType);
28 if (result) {
Fred Drake8844d522001-10-05 21:52:26 +000029 result->hash = -1;
Neil Schemenauer38a89162002-03-27 15:18:21 +000030 result->wr_object = ob;
31 Py_XINCREF(callback);
32 result->wr_callback = callback;
33 PyObject_GC_Track(result);
34 }
Fred Drake8844d522001-10-05 21:52:26 +000035 return result;
36}
37
38
39/* This function clears the passed-in reference and removes it from the
40 * list of weak references for the referent. This is the only code that
41 * removes an item from the doubly-linked list of weak references for an
42 * object; it is also responsible for clearing the callback slot.
43 */
44static void
45clear_weakref(PyWeakReference *self)
46{
47 PyObject *callback = self->wr_callback;
48
49 if (PyWeakref_GET_OBJECT(self) != Py_None) {
50 PyWeakReference **list = GET_WEAKREFS_LISTPTR(
51 PyWeakref_GET_OBJECT(self));
52
53 if (*list == self)
54 *list = self->wr_next;
55 self->wr_object = Py_None;
56 self->wr_callback = NULL;
57 if (self->wr_prev != NULL)
58 self->wr_prev->wr_next = self->wr_next;
59 if (self->wr_next != NULL)
60 self->wr_next->wr_prev = self->wr_prev;
61 self->wr_prev = NULL;
62 self->wr_next = NULL;
63 Py_XDECREF(callback);
64 }
65}
66
67
68static void
69weakref_dealloc(PyWeakReference *self)
70{
71 PyObject_GC_UnTrack((PyObject *)self);
72 clear_weakref(self);
Neil Schemenauer38a89162002-03-27 15:18:21 +000073 PyObject_GC_Del(self);
Fred Drake8844d522001-10-05 21:52:26 +000074}
75
76
77static int
78gc_traverse(PyWeakReference *self, visitproc visit, void *arg)
79{
80 if (self->wr_callback != NULL)
81 return visit(self->wr_callback, arg);
82 return 0;
83}
84
85
86static int
87gc_clear(PyWeakReference *self)
88{
89 clear_weakref(self);
90 return 0;
91}
92
93
94static PyObject *
95weakref_call(PyWeakReference *self, PyObject *args, PyObject *kw)
96{
97 static char *argnames[] = {NULL};
98
99 if (PyArg_ParseTupleAndKeywords(args, kw, ":__call__", argnames)) {
100 PyObject *object = PyWeakref_GET_OBJECT(self);
101 Py_INCREF(object);
102 return (object);
103 }
104 return NULL;
105}
106
107
108static long
109weakref_hash(PyWeakReference *self)
110{
111 if (self->hash != -1)
112 return self->hash;
113 if (PyWeakref_GET_OBJECT(self) == Py_None) {
114 PyErr_SetString(PyExc_TypeError, "weak object has gone away");
115 return -1;
116 }
117 self->hash = PyObject_Hash(PyWeakref_GET_OBJECT(self));
118 return self->hash;
119}
120
121
122static PyObject *
123weakref_repr(PyWeakReference *self)
124{
125 char buffer[256];
126 if (PyWeakref_GET_OBJECT(self) == Py_None) {
Guido van Rossumc1f6e8c2003-04-16 21:13:23 +0000127 PyOS_snprintf(buffer, sizeof(buffer), "<weakref at %p; dead>", self);
Fred Drake8844d522001-10-05 21:52:26 +0000128 }
129 else {
Guido van Rossumc1f6e8c2003-04-16 21:13:23 +0000130 char *name = NULL;
131 PyObject *nameobj = PyObject_GetAttrString(PyWeakref_GET_OBJECT(self),
132 "__name__");
133 if (nameobj == NULL)
134 PyErr_Clear();
135 else if (PyString_Check(nameobj))
136 name = PyString_AS_STRING(nameobj);
Barry Warsawd5867562001-11-28 21:01:56 +0000137 PyOS_snprintf(buffer, sizeof(buffer),
Guido van Rossumc1f6e8c2003-04-16 21:13:23 +0000138 name ? "<weakref at %p; to '%.50s' at %p (%s)>"
139 : "<weakref at %p; to '%.50s' at %p>",
140 self,
Barry Warsawd5867562001-11-28 21:01:56 +0000141 PyWeakref_GET_OBJECT(self)->ob_type->tp_name,
Guido van Rossumc1f6e8c2003-04-16 21:13:23 +0000142 PyWeakref_GET_OBJECT(self),
143 name);
144 Py_XDECREF(nameobj);
Fred Drake8844d522001-10-05 21:52:26 +0000145 }
146 return PyString_FromString(buffer);
147}
148
149/* Weak references only support equality, not ordering. Two weak references
150 are equal if the underlying objects are equal. If the underlying object has
151 gone away, they are equal if they are identical. */
152
153static PyObject *
154weakref_richcompare(PyWeakReference* self, PyWeakReference* other, int op)
155{
156 if (op != Py_EQ || self->ob_type != other->ob_type) {
157 Py_INCREF(Py_NotImplemented);
158 return Py_NotImplemented;
159 }
160 if (PyWeakref_GET_OBJECT(self) == Py_None
161 || PyWeakref_GET_OBJECT(other) == Py_None) {
162 PyObject *res = self==other ? Py_True : Py_False;
163 Py_INCREF(res);
164 return res;
165 }
166 return PyObject_RichCompare(PyWeakref_GET_OBJECT(self),
167 PyWeakref_GET_OBJECT(other), op);
168}
169
170
171PyTypeObject
172_PyWeakref_RefType = {
173 PyObject_HEAD_INIT(&PyType_Type)
174 0,
175 "weakref",
176 sizeof(PyWeakReference),
177 0,
178 (destructor)weakref_dealloc,/*tp_dealloc*/
179 0, /*tp_print*/
180 0, /*tp_getattr*/
181 0, /*tp_setattr*/
182 0, /*tp_compare*/
183 (reprfunc)weakref_repr, /*tp_repr*/
184 0, /*tp_as_number*/
185 0, /*tp_as_sequence*/
186 0, /*tp_as_mapping*/
187 (hashfunc)weakref_hash, /*tp_hash*/
188 (ternaryfunc)weakref_call, /*tp_call*/
189 0, /*tp_str*/
190 0, /*tp_getattro*/
191 0, /*tp_setattro*/
192 0, /*tp_as_buffer*/
193 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_RICHCOMPARE,
194 0, /*tp_doc*/
195 (traverseproc)gc_traverse, /*tp_traverse*/
196 (inquiry)gc_clear, /*tp_clear*/
197 (richcmpfunc)weakref_richcompare, /*tp_richcompare*/
198 0, /*tp_weaklistoffset*/
199};
200
201
202static int
203proxy_checkref(PyWeakReference *proxy)
204{
205 if (PyWeakref_GET_OBJECT(proxy) == Py_None) {
206 PyErr_SetString(PyExc_ReferenceError,
207 "weakly-referenced object no longer exists");
208 return 0;
209 }
210 return 1;
211}
212
213
Fred Drake73006d02001-10-18 18:04:18 +0000214/* If a parameter is a proxy, check that it is still "live" and wrap it,
215 * replacing the original value with the raw object. Raises ReferenceError
216 * if the param is a dead proxy.
217 */
218#define UNWRAP(o) \
219 if (PyWeakref_CheckProxy(o)) { \
220 if (!proxy_checkref((PyWeakReference *)o)) \
221 return NULL; \
222 o = PyWeakref_GET_OBJECT(o); \
223 }
224
Fred Drake2a908f62001-12-19 16:44:30 +0000225#define UNWRAP_I(o) \
226 if (PyWeakref_CheckProxy(o)) { \
227 if (!proxy_checkref((PyWeakReference *)o)) \
228 return -1; \
229 o = PyWeakref_GET_OBJECT(o); \
230 }
231
Fred Drake8844d522001-10-05 21:52:26 +0000232#define WRAP_UNARY(method, generic) \
233 static PyObject * \
Fred Drake73006d02001-10-18 18:04:18 +0000234 method(PyObject *proxy) { \
235 UNWRAP(proxy); \
236 return generic(proxy); \
Fred Drake8844d522001-10-05 21:52:26 +0000237 }
238
239#define WRAP_BINARY(method, generic) \
240 static PyObject * \
Fred Drake73006d02001-10-18 18:04:18 +0000241 method(PyObject *x, PyObject *y) { \
242 UNWRAP(x); \
243 UNWRAP(y); \
244 return generic(x, y); \
Fred Drake8844d522001-10-05 21:52:26 +0000245 }
246
Fred Drake31f4d1f2001-10-18 19:21:46 +0000247/* Note that the third arg needs to be checked for NULL since the tp_call
248 * slot can receive NULL for this arg.
Fred Drake73006d02001-10-18 18:04:18 +0000249 */
Fred Drake8844d522001-10-05 21:52:26 +0000250#define WRAP_TERNARY(method, generic) \
251 static PyObject * \
Fred Drake73006d02001-10-18 18:04:18 +0000252 method(PyObject *proxy, PyObject *v, PyObject *w) { \
253 UNWRAP(proxy); \
Fred Drake31f4d1f2001-10-18 19:21:46 +0000254 UNWRAP(v); \
Fred Drake73006d02001-10-18 18:04:18 +0000255 if (w != NULL) \
256 UNWRAP(w); \
257 return generic(proxy, v, w); \
Fred Drake8844d522001-10-05 21:52:26 +0000258 }
259
260
261/* direct slots */
262
263WRAP_BINARY(proxy_getattr, PyObject_GetAttr)
264WRAP_UNARY(proxy_str, PyObject_Str)
265WRAP_TERNARY(proxy_call, PyEval_CallObjectWithKeywords)
266
267static int
268proxy_print(PyWeakReference *proxy, FILE *fp, int flags)
269{
270 if (!proxy_checkref(proxy))
271 return -1;
272 return PyObject_Print(PyWeakref_GET_OBJECT(proxy), fp, flags);
273}
274
275static PyObject *
276proxy_repr(PyWeakReference *proxy)
277{
278 char buf[160];
Barry Warsawd5867562001-11-28 21:01:56 +0000279 PyOS_snprintf(buf, sizeof(buf),
Guido van Rossumc1f6e8c2003-04-16 21:13:23 +0000280 "<weakproxy at %p to %.100s at %p>", proxy,
Barry Warsawd5867562001-11-28 21:01:56 +0000281 PyWeakref_GET_OBJECT(proxy)->ob_type->tp_name,
282 PyWeakref_GET_OBJECT(proxy));
Fred Drake8844d522001-10-05 21:52:26 +0000283 return PyString_FromString(buf);
284}
285
286
287static int
288proxy_setattr(PyWeakReference *proxy, PyObject *name, PyObject *value)
289{
290 if (!proxy_checkref(proxy))
291 return -1;
292 return PyObject_SetAttr(PyWeakref_GET_OBJECT(proxy), name, value);
293}
294
295static int
Fred Drake2a908f62001-12-19 16:44:30 +0000296proxy_compare(PyObject *proxy, PyObject *v)
Fred Drake8844d522001-10-05 21:52:26 +0000297{
Fred Drake2a908f62001-12-19 16:44:30 +0000298 UNWRAP_I(proxy);
299 UNWRAP_I(v);
300 return PyObject_Compare(proxy, v);
Fred Drake8844d522001-10-05 21:52:26 +0000301}
302
303/* number slots */
304WRAP_BINARY(proxy_add, PyNumber_Add)
305WRAP_BINARY(proxy_sub, PyNumber_Subtract)
306WRAP_BINARY(proxy_mul, PyNumber_Multiply)
307WRAP_BINARY(proxy_div, PyNumber_Divide)
308WRAP_BINARY(proxy_mod, PyNumber_Remainder)
309WRAP_BINARY(proxy_divmod, PyNumber_Divmod)
310WRAP_TERNARY(proxy_pow, PyNumber_Power)
311WRAP_UNARY(proxy_neg, PyNumber_Negative)
312WRAP_UNARY(proxy_pos, PyNumber_Positive)
313WRAP_UNARY(proxy_abs, PyNumber_Absolute)
314WRAP_UNARY(proxy_invert, PyNumber_Invert)
315WRAP_BINARY(proxy_lshift, PyNumber_Lshift)
316WRAP_BINARY(proxy_rshift, PyNumber_Rshift)
317WRAP_BINARY(proxy_and, PyNumber_And)
318WRAP_BINARY(proxy_xor, PyNumber_Xor)
319WRAP_BINARY(proxy_or, PyNumber_Or)
320WRAP_UNARY(proxy_int, PyNumber_Int)
321WRAP_UNARY(proxy_long, PyNumber_Long)
322WRAP_UNARY(proxy_float, PyNumber_Float)
323WRAP_BINARY(proxy_iadd, PyNumber_InPlaceAdd)
324WRAP_BINARY(proxy_isub, PyNumber_InPlaceSubtract)
325WRAP_BINARY(proxy_imul, PyNumber_InPlaceMultiply)
326WRAP_BINARY(proxy_idiv, PyNumber_InPlaceDivide)
327WRAP_BINARY(proxy_imod, PyNumber_InPlaceRemainder)
328WRAP_TERNARY(proxy_ipow, PyNumber_InPlacePower)
329WRAP_BINARY(proxy_ilshift, PyNumber_InPlaceLshift)
330WRAP_BINARY(proxy_irshift, PyNumber_InPlaceRshift)
331WRAP_BINARY(proxy_iand, PyNumber_InPlaceAnd)
332WRAP_BINARY(proxy_ixor, PyNumber_InPlaceXor)
333WRAP_BINARY(proxy_ior, PyNumber_InPlaceOr)
334
335static int
336proxy_nonzero(PyWeakReference *proxy)
337{
338 PyObject *o = PyWeakref_GET_OBJECT(proxy);
339 if (!proxy_checkref(proxy))
340 return 1;
341 if (o->ob_type->tp_as_number &&
342 o->ob_type->tp_as_number->nb_nonzero)
343 return (*o->ob_type->tp_as_number->nb_nonzero)(o);
344 else
345 return 1;
346}
347
348/* sequence slots */
349
350static PyObject *
351proxy_slice(PyWeakReference *proxy, int i, int j)
352{
353 if (!proxy_checkref(proxy))
354 return NULL;
355 return PySequence_GetSlice(PyWeakref_GET_OBJECT(proxy), i, j);
356}
357
358static int
359proxy_ass_slice(PyWeakReference *proxy, int i, int j, PyObject *value)
360{
361 if (!proxy_checkref(proxy))
362 return -1;
363 return PySequence_SetSlice(PyWeakref_GET_OBJECT(proxy), i, j, value);
364}
365
366static int
367proxy_contains(PyWeakReference *proxy, PyObject *value)
368{
369 if (!proxy_checkref(proxy))
370 return -1;
371 return PySequence_Contains(PyWeakref_GET_OBJECT(proxy), value);
372}
373
374
375/* mapping slots */
376
377static int
378proxy_length(PyWeakReference *proxy)
379{
380 if (!proxy_checkref(proxy))
381 return -1;
382 return PyObject_Length(PyWeakref_GET_OBJECT(proxy));
383}
384
385WRAP_BINARY(proxy_getitem, PyObject_GetItem)
386
387static int
388proxy_setitem(PyWeakReference *proxy, PyObject *key, PyObject *value)
389{
390 if (!proxy_checkref(proxy))
391 return -1;
392 return PyObject_SetItem(PyWeakref_GET_OBJECT(proxy), key, value);
393}
394
Fred Drakef16c3dc2002-08-09 18:34:16 +0000395/* iterator slots */
396
397static PyObject *
398proxy_iter(PyWeakReference *proxy)
399{
400 if (!proxy_checkref(proxy))
401 return NULL;
402 return PyObject_GetIter(PyWeakref_GET_OBJECT(proxy));
403}
404
405static PyObject *
406proxy_iternext(PyWeakReference *proxy)
407{
408 if (!proxy_checkref(proxy))
409 return NULL;
410 return PyIter_Next(PyWeakref_GET_OBJECT(proxy));
411}
412
Fred Drake8844d522001-10-05 21:52:26 +0000413
414static PyNumberMethods proxy_as_number = {
415 (binaryfunc)proxy_add, /*nb_add*/
416 (binaryfunc)proxy_sub, /*nb_subtract*/
417 (binaryfunc)proxy_mul, /*nb_multiply*/
418 (binaryfunc)proxy_div, /*nb_divide*/
419 (binaryfunc)proxy_mod, /*nb_remainder*/
420 (binaryfunc)proxy_divmod, /*nb_divmod*/
421 (ternaryfunc)proxy_pow, /*nb_power*/
422 (unaryfunc)proxy_neg, /*nb_negative*/
423 (unaryfunc)proxy_pos, /*nb_positive*/
424 (unaryfunc)proxy_abs, /*nb_absolute*/
425 (inquiry)proxy_nonzero, /*nb_nonzero*/
426 (unaryfunc)proxy_invert, /*nb_invert*/
427 (binaryfunc)proxy_lshift, /*nb_lshift*/
428 (binaryfunc)proxy_rshift, /*nb_rshift*/
429 (binaryfunc)proxy_and, /*nb_and*/
430 (binaryfunc)proxy_xor, /*nb_xor*/
431 (binaryfunc)proxy_or, /*nb_or*/
432 (coercion)0, /*nb_coerce*/
433 (unaryfunc)proxy_int, /*nb_int*/
434 (unaryfunc)proxy_long, /*nb_long*/
435 (unaryfunc)proxy_float, /*nb_float*/
436 (unaryfunc)0, /*nb_oct*/
437 (unaryfunc)0, /*nb_hex*/
438 (binaryfunc)proxy_iadd, /*nb_inplace_add*/
439 (binaryfunc)proxy_isub, /*nb_inplace_subtract*/
440 (binaryfunc)proxy_imul, /*nb_inplace_multiply*/
441 (binaryfunc)proxy_idiv, /*nb_inplace_divide*/
442 (binaryfunc)proxy_imod, /*nb_inplace_remainder*/
443 (ternaryfunc)proxy_ipow, /*nb_inplace_power*/
444 (binaryfunc)proxy_ilshift, /*nb_inplace_lshift*/
445 (binaryfunc)proxy_irshift, /*nb_inplace_rshift*/
446 (binaryfunc)proxy_iand, /*nb_inplace_and*/
447 (binaryfunc)proxy_ixor, /*nb_inplace_xor*/
448 (binaryfunc)proxy_ior, /*nb_inplace_or*/
449};
450
451static PySequenceMethods proxy_as_sequence = {
452 (inquiry)proxy_length, /*sq_length*/
453 0, /*sq_concat*/
454 0, /*sq_repeat*/
455 0, /*sq_item*/
456 (intintargfunc)proxy_slice, /*sq_slice*/
457 0, /*sq_ass_item*/
458 (intintobjargproc)proxy_ass_slice, /*sq_ass_slice*/
459 (objobjproc)proxy_contains, /* sq_contains */
460};
461
462static PyMappingMethods proxy_as_mapping = {
463 (inquiry)proxy_length, /*mp_length*/
464 (binaryfunc)proxy_getitem, /*mp_subscript*/
465 (objobjargproc)proxy_setitem, /*mp_ass_subscript*/
466};
467
468
469PyTypeObject
470_PyWeakref_ProxyType = {
471 PyObject_HEAD_INIT(&PyType_Type)
472 0,
473 "weakproxy",
474 sizeof(PyWeakReference),
475 0,
476 /* methods */
Fred Drakef16c3dc2002-08-09 18:34:16 +0000477 (destructor)weakref_dealloc, /* tp_dealloc */
478 (printfunc)proxy_print, /* tp_print */
479 0, /* tp_getattr */
480 0, /* tp_setattr */
481 proxy_compare, /* tp_compare */
482 (unaryfunc)proxy_repr, /* tp_repr */
483 &proxy_as_number, /* tp_as_number */
484 &proxy_as_sequence, /* tp_as_sequence */
485 &proxy_as_mapping, /* tp_as_mapping */
486 0, /* tp_hash */
487 (ternaryfunc)0, /* tp_call */
488 (unaryfunc)proxy_str, /* tp_str */
489 (getattrofunc)proxy_getattr, /* tp_getattro */
490 (setattrofunc)proxy_setattr, /* tp_setattro */
491 0, /* tp_as_buffer */
Fred Drake8844d522001-10-05 21:52:26 +0000492 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC
Fred Drakef16c3dc2002-08-09 18:34:16 +0000493 | Py_TPFLAGS_CHECKTYPES, /* tp_flags */
494 0, /* tp_doc */
495 (traverseproc)gc_traverse, /* tp_traverse */
496 (inquiry)gc_clear, /* tp_clear */
497 0, /* tp_richcompare */
498 0, /* tp_weaklistoffset */
499 (getiterfunc)proxy_iter, /* tp_iter */
500 (iternextfunc)proxy_iternext, /* tp_iternext */
Fred Drake8844d522001-10-05 21:52:26 +0000501};
502
503
504PyTypeObject
505_PyWeakref_CallableProxyType = {
506 PyObject_HEAD_INIT(&PyType_Type)
507 0,
508 "weakcallableproxy",
509 sizeof(PyWeakReference),
510 0,
511 /* methods */
Fred Drakef16c3dc2002-08-09 18:34:16 +0000512 (destructor)weakref_dealloc, /* tp_dealloc */
513 (printfunc)proxy_print, /* tp_print */
514 0, /* tp_getattr */
515 0, /* tp_setattr */
516 proxy_compare, /* tp_compare */
517 (unaryfunc)proxy_repr, /* tp_repr */
518 &proxy_as_number, /* tp_as_number */
519 &proxy_as_sequence, /* tp_as_sequence */
520 &proxy_as_mapping, /* tp_as_mapping */
521 0, /* tp_hash */
522 (ternaryfunc)proxy_call, /* tp_call */
523 (unaryfunc)proxy_str, /* tp_str */
524 (getattrofunc)proxy_getattr, /* tp_getattro */
525 (setattrofunc)proxy_setattr, /* tp_setattro */
526 0, /* tp_as_buffer */
Fred Drake8844d522001-10-05 21:52:26 +0000527 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC
Fred Drakef16c3dc2002-08-09 18:34:16 +0000528 | Py_TPFLAGS_CHECKTYPES, /* tp_flags */
529 0, /* tp_doc */
530 (traverseproc)gc_traverse, /* tp_traverse */
531 (inquiry)gc_clear, /* tp_clear */
532 0, /* tp_richcompare */
533 0, /* tp_weaklistoffset */
534 (getiterfunc)proxy_iter, /* tp_iter */
535 (iternextfunc)proxy_iternext, /* tp_iternext */
Fred Drake8844d522001-10-05 21:52:26 +0000536};
537
538
539/* Given the head of an object's list of weak references, extract the
540 * two callback-less refs (ref and proxy). Used to determine if the
541 * shared references exist and to determine the back link for newly
542 * inserted references.
543 */
544static void
545get_basic_refs(PyWeakReference *head,
546 PyWeakReference **refp, PyWeakReference **proxyp)
547{
548 *refp = NULL;
549 *proxyp = NULL;
550
551 if (head != NULL && head->wr_callback == NULL) {
552 if (head->ob_type == &_PyWeakref_RefType) {
553 *refp = head;
554 head = head->wr_next;
555 }
556 if (head != NULL && head->wr_callback == NULL) {
557 *proxyp = head;
558 head = head->wr_next;
559 }
560 }
561}
562
563/* Insert 'newref' in the list after 'prev'. Both must be non-NULL. */
564static void
565insert_after(PyWeakReference *newref, PyWeakReference *prev)
566{
567 newref->wr_prev = prev;
568 newref->wr_next = prev->wr_next;
569 if (prev->wr_next != NULL)
570 prev->wr_next->wr_prev = newref;
571 prev->wr_next = newref;
572}
573
574/* Insert 'newref' at the head of the list; 'list' points to the variable
575 * that stores the head.
576 */
577static void
578insert_head(PyWeakReference *newref, PyWeakReference **list)
579{
580 PyWeakReference *next = *list;
581
582 newref->wr_prev = NULL;
583 newref->wr_next = next;
584 if (next != NULL)
585 next->wr_prev = newref;
586 *list = newref;
587}
588
589
590PyObject *
591PyWeakref_NewRef(PyObject *ob, PyObject *callback)
592{
593 PyWeakReference *result = NULL;
594 PyWeakReference **list;
595 PyWeakReference *ref, *proxy;
596
597 if (!PyType_SUPPORTS_WEAKREFS(ob->ob_type)) {
598 PyErr_Format(PyExc_TypeError,
Jeremy Hylton996fad32001-10-22 16:31:40 +0000599 "cannot create weak reference to '%s' object",
Fred Drake8844d522001-10-05 21:52:26 +0000600 ob->ob_type->tp_name);
601 return NULL;
602 }
603 list = GET_WEAKREFS_LISTPTR(ob);
604 get_basic_refs(*list, &ref, &proxy);
605 if (callback == NULL || callback == Py_None)
606 /* return existing weak reference if it exists */
607 result = ref;
608 if (result != NULL)
609 Py_XINCREF(result);
610 else {
Neil Schemenauer38a89162002-03-27 15:18:21 +0000611 result = new_weakref(ob, callback);
Fred Drake8844d522001-10-05 21:52:26 +0000612 if (result != NULL) {
Fred Drake8844d522001-10-05 21:52:26 +0000613 if (callback == NULL) {
614 insert_head(result, list);
615 }
616 else {
617 PyWeakReference *prev = (proxy == NULL) ? ref : proxy;
618
619 if (prev == NULL)
620 insert_head(result, list);
621 else
622 insert_after(result, prev);
623 }
Fred Drake8844d522001-10-05 21:52:26 +0000624 }
625 }
626 return (PyObject *) result;
627}
628
629
630PyObject *
631PyWeakref_NewProxy(PyObject *ob, PyObject *callback)
632{
633 PyWeakReference *result = NULL;
634 PyWeakReference **list;
635 PyWeakReference *ref, *proxy;
636
637 if (!PyType_SUPPORTS_WEAKREFS(ob->ob_type)) {
638 PyErr_Format(PyExc_TypeError,
Jeremy Hylton996fad32001-10-22 16:31:40 +0000639 "cannot create weak reference to '%s' object",
Fred Drake8844d522001-10-05 21:52:26 +0000640 ob->ob_type->tp_name);
641 return NULL;
642 }
643 list = GET_WEAKREFS_LISTPTR(ob);
644 get_basic_refs(*list, &ref, &proxy);
645 if (callback == NULL)
646 /* attempt to return an existing weak reference if it exists */
647 result = proxy;
648 if (result != NULL)
649 Py_XINCREF(result);
650 else {
Neil Schemenauer38a89162002-03-27 15:18:21 +0000651 result = new_weakref(ob, callback);
Fred Drake8844d522001-10-05 21:52:26 +0000652 if (result != NULL) {
653 PyWeakReference *prev;
654
655 if (PyCallable_Check(ob))
656 result->ob_type = &_PyWeakref_CallableProxyType;
657 else
658 result->ob_type = &_PyWeakref_ProxyType;
Fred Drake8844d522001-10-05 21:52:26 +0000659 if (callback == NULL)
660 prev = ref;
661 else
662 prev = (proxy == NULL) ? ref : proxy;
663
664 if (prev == NULL)
665 insert_head(result, list);
666 else
667 insert_after(result, prev);
Fred Drake8844d522001-10-05 21:52:26 +0000668 }
669 }
670 return (PyObject *) result;
671}
672
673
674PyObject *
675PyWeakref_GetObject(PyObject *ref)
676{
677 if (ref == NULL || !PyWeakref_Check(ref)) {
678 PyErr_BadInternalCall();
679 return NULL;
680 }
681 return PyWeakref_GET_OBJECT(ref);
682}
683
684
Fred Drakeef8ebd12001-12-10 23:44:54 +0000685static void
686handle_callback(PyWeakReference *ref, PyObject *callback)
687{
688 PyObject *cbresult = PyObject_CallFunction(callback, "O", ref);
689
690 if (cbresult == NULL)
691 PyErr_WriteUnraisable(callback);
692 else
693 Py_DECREF(cbresult);
694}
695
696/* This function is called by the tp_dealloc handler to clear weak references.
Fred Drake8844d522001-10-05 21:52:26 +0000697 *
698 * This iterates through the weak references for 'object' and calls callbacks
699 * for those references which have one. It returns when all callbacks have
700 * been attempted.
701 */
702void
703PyObject_ClearWeakRefs(PyObject *object)
704{
705 PyWeakReference **list;
706
707 if (object == NULL
708 || !PyType_SUPPORTS_WEAKREFS(object->ob_type)
709 || object->ob_refcnt != 0) {
710 PyErr_BadInternalCall();
711 return;
712 }
713 list = GET_WEAKREFS_LISTPTR(object);
714 /* Remove the callback-less basic and proxy references */
715 if (*list != NULL && (*list)->wr_callback == NULL) {
716 clear_weakref(*list);
717 if (*list != NULL && (*list)->wr_callback == NULL)
718 clear_weakref(*list);
719 }
720 if (*list != NULL) {
Fred Drakeef8ebd12001-12-10 23:44:54 +0000721 PyWeakReference *current = *list;
722 int count = _PyWeakref_GetWeakrefCount(current);
723 int restore_error = PyErr_Occurred() ? 1 : 0;
724 PyObject *err_type, *err_value, *err_tb;
Fred Drake8844d522001-10-05 21:52:26 +0000725
Fred Drakeef8ebd12001-12-10 23:44:54 +0000726 if (restore_error)
727 PyErr_Fetch(&err_type, &err_value, &err_tb);
Fred Drake8844d522001-10-05 21:52:26 +0000728 if (count == 1) {
Fred Drake8844d522001-10-05 21:52:26 +0000729 PyObject *callback = current->wr_callback;
Fred Drake8844d522001-10-05 21:52:26 +0000730
Fred Drakeef8ebd12001-12-10 23:44:54 +0000731 current->wr_callback = NULL;
Fred Drake8844d522001-10-05 21:52:26 +0000732 clear_weakref(current);
Fred Drakeef8ebd12001-12-10 23:44:54 +0000733 handle_callback(current, callback);
Fred Drake8844d522001-10-05 21:52:26 +0000734 Py_DECREF(callback);
735 }
736 else {
737 PyObject *tuple = PyTuple_New(count * 2);
Fred Drake8844d522001-10-05 21:52:26 +0000738 int i = 0;
739
740 for (i = 0; i < count; ++i) {
741 PyWeakReference *next = current->wr_next;
742
743 Py_INCREF(current);
744 PyTuple_SET_ITEM(tuple, i * 2, (PyObject *) current);
745 PyTuple_SET_ITEM(tuple, i * 2 + 1, current->wr_callback);
746 current->wr_callback = NULL;
Fred Drake8844d522001-10-05 21:52:26 +0000747 clear_weakref(current);
748 current = next;
749 }
750 for (i = 0; i < count; ++i) {
751 PyObject *current = PyTuple_GET_ITEM(tuple, i * 2);
752 PyObject *callback = PyTuple_GET_ITEM(tuple, i * 2 + 1);
Fred Drakeef8ebd12001-12-10 23:44:54 +0000753
754 handle_callback((PyWeakReference *)current, callback);
Fred Drake8844d522001-10-05 21:52:26 +0000755 }
756 Py_DECREF(tuple);
757 }
Fred Drakeef8ebd12001-12-10 23:44:54 +0000758 if (restore_error)
759 PyErr_Restore(err_type, err_value, err_tb);
Fred Drake8844d522001-10-05 21:52:26 +0000760 }
761}