blob: f5afb53627734fe530c9d1fb07aa1082ca0bc3e0 [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;
Raymond Hettingerd693a812003-06-30 04:18:48 +0000392
393 if (value == NULL)
394 return PyObject_DelItem(PyWeakref_GET_OBJECT(proxy), key);
395 else
396 return PyObject_SetItem(PyWeakref_GET_OBJECT(proxy), key, value);
Fred Drake8844d522001-10-05 21:52:26 +0000397}
398
Fred Drakef16c3dc2002-08-09 18:34:16 +0000399/* iterator slots */
400
401static PyObject *
402proxy_iter(PyWeakReference *proxy)
403{
404 if (!proxy_checkref(proxy))
405 return NULL;
406 return PyObject_GetIter(PyWeakref_GET_OBJECT(proxy));
407}
408
409static PyObject *
410proxy_iternext(PyWeakReference *proxy)
411{
412 if (!proxy_checkref(proxy))
413 return NULL;
414 return PyIter_Next(PyWeakref_GET_OBJECT(proxy));
415}
416
Fred Drake8844d522001-10-05 21:52:26 +0000417
418static PyNumberMethods proxy_as_number = {
419 (binaryfunc)proxy_add, /*nb_add*/
420 (binaryfunc)proxy_sub, /*nb_subtract*/
421 (binaryfunc)proxy_mul, /*nb_multiply*/
422 (binaryfunc)proxy_div, /*nb_divide*/
423 (binaryfunc)proxy_mod, /*nb_remainder*/
424 (binaryfunc)proxy_divmod, /*nb_divmod*/
425 (ternaryfunc)proxy_pow, /*nb_power*/
426 (unaryfunc)proxy_neg, /*nb_negative*/
427 (unaryfunc)proxy_pos, /*nb_positive*/
428 (unaryfunc)proxy_abs, /*nb_absolute*/
429 (inquiry)proxy_nonzero, /*nb_nonzero*/
430 (unaryfunc)proxy_invert, /*nb_invert*/
431 (binaryfunc)proxy_lshift, /*nb_lshift*/
432 (binaryfunc)proxy_rshift, /*nb_rshift*/
433 (binaryfunc)proxy_and, /*nb_and*/
434 (binaryfunc)proxy_xor, /*nb_xor*/
435 (binaryfunc)proxy_or, /*nb_or*/
436 (coercion)0, /*nb_coerce*/
437 (unaryfunc)proxy_int, /*nb_int*/
438 (unaryfunc)proxy_long, /*nb_long*/
439 (unaryfunc)proxy_float, /*nb_float*/
440 (unaryfunc)0, /*nb_oct*/
441 (unaryfunc)0, /*nb_hex*/
442 (binaryfunc)proxy_iadd, /*nb_inplace_add*/
443 (binaryfunc)proxy_isub, /*nb_inplace_subtract*/
444 (binaryfunc)proxy_imul, /*nb_inplace_multiply*/
445 (binaryfunc)proxy_idiv, /*nb_inplace_divide*/
446 (binaryfunc)proxy_imod, /*nb_inplace_remainder*/
447 (ternaryfunc)proxy_ipow, /*nb_inplace_power*/
448 (binaryfunc)proxy_ilshift, /*nb_inplace_lshift*/
449 (binaryfunc)proxy_irshift, /*nb_inplace_rshift*/
450 (binaryfunc)proxy_iand, /*nb_inplace_and*/
451 (binaryfunc)proxy_ixor, /*nb_inplace_xor*/
452 (binaryfunc)proxy_ior, /*nb_inplace_or*/
453};
454
455static PySequenceMethods proxy_as_sequence = {
456 (inquiry)proxy_length, /*sq_length*/
457 0, /*sq_concat*/
458 0, /*sq_repeat*/
459 0, /*sq_item*/
460 (intintargfunc)proxy_slice, /*sq_slice*/
461 0, /*sq_ass_item*/
462 (intintobjargproc)proxy_ass_slice, /*sq_ass_slice*/
463 (objobjproc)proxy_contains, /* sq_contains */
464};
465
466static PyMappingMethods proxy_as_mapping = {
467 (inquiry)proxy_length, /*mp_length*/
468 (binaryfunc)proxy_getitem, /*mp_subscript*/
469 (objobjargproc)proxy_setitem, /*mp_ass_subscript*/
470};
471
472
473PyTypeObject
474_PyWeakref_ProxyType = {
475 PyObject_HEAD_INIT(&PyType_Type)
476 0,
477 "weakproxy",
478 sizeof(PyWeakReference),
479 0,
480 /* methods */
Fred Drakef16c3dc2002-08-09 18:34:16 +0000481 (destructor)weakref_dealloc, /* tp_dealloc */
482 (printfunc)proxy_print, /* tp_print */
483 0, /* tp_getattr */
484 0, /* tp_setattr */
485 proxy_compare, /* tp_compare */
486 (unaryfunc)proxy_repr, /* tp_repr */
487 &proxy_as_number, /* tp_as_number */
488 &proxy_as_sequence, /* tp_as_sequence */
489 &proxy_as_mapping, /* tp_as_mapping */
490 0, /* tp_hash */
491 (ternaryfunc)0, /* tp_call */
492 (unaryfunc)proxy_str, /* tp_str */
493 (getattrofunc)proxy_getattr, /* tp_getattro */
494 (setattrofunc)proxy_setattr, /* tp_setattro */
495 0, /* tp_as_buffer */
Fred Drake8844d522001-10-05 21:52:26 +0000496 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC
Fred Drakef16c3dc2002-08-09 18:34:16 +0000497 | Py_TPFLAGS_CHECKTYPES, /* tp_flags */
498 0, /* tp_doc */
499 (traverseproc)gc_traverse, /* tp_traverse */
500 (inquiry)gc_clear, /* tp_clear */
501 0, /* tp_richcompare */
502 0, /* tp_weaklistoffset */
503 (getiterfunc)proxy_iter, /* tp_iter */
504 (iternextfunc)proxy_iternext, /* tp_iternext */
Fred Drake8844d522001-10-05 21:52:26 +0000505};
506
507
508PyTypeObject
509_PyWeakref_CallableProxyType = {
510 PyObject_HEAD_INIT(&PyType_Type)
511 0,
512 "weakcallableproxy",
513 sizeof(PyWeakReference),
514 0,
515 /* methods */
Fred Drakef16c3dc2002-08-09 18:34:16 +0000516 (destructor)weakref_dealloc, /* tp_dealloc */
517 (printfunc)proxy_print, /* tp_print */
518 0, /* tp_getattr */
519 0, /* tp_setattr */
520 proxy_compare, /* tp_compare */
521 (unaryfunc)proxy_repr, /* tp_repr */
522 &proxy_as_number, /* tp_as_number */
523 &proxy_as_sequence, /* tp_as_sequence */
524 &proxy_as_mapping, /* tp_as_mapping */
525 0, /* tp_hash */
526 (ternaryfunc)proxy_call, /* tp_call */
527 (unaryfunc)proxy_str, /* tp_str */
528 (getattrofunc)proxy_getattr, /* tp_getattro */
529 (setattrofunc)proxy_setattr, /* tp_setattro */
530 0, /* tp_as_buffer */
Fred Drake8844d522001-10-05 21:52:26 +0000531 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC
Fred Drakef16c3dc2002-08-09 18:34:16 +0000532 | Py_TPFLAGS_CHECKTYPES, /* tp_flags */
533 0, /* tp_doc */
534 (traverseproc)gc_traverse, /* tp_traverse */
535 (inquiry)gc_clear, /* tp_clear */
536 0, /* tp_richcompare */
537 0, /* tp_weaklistoffset */
538 (getiterfunc)proxy_iter, /* tp_iter */
539 (iternextfunc)proxy_iternext, /* tp_iternext */
Fred Drake8844d522001-10-05 21:52:26 +0000540};
541
542
543/* Given the head of an object's list of weak references, extract the
544 * two callback-less refs (ref and proxy). Used to determine if the
545 * shared references exist and to determine the back link for newly
546 * inserted references.
547 */
548static void
549get_basic_refs(PyWeakReference *head,
550 PyWeakReference **refp, PyWeakReference **proxyp)
551{
552 *refp = NULL;
553 *proxyp = NULL;
554
555 if (head != NULL && head->wr_callback == NULL) {
556 if (head->ob_type == &_PyWeakref_RefType) {
557 *refp = head;
558 head = head->wr_next;
559 }
560 if (head != NULL && head->wr_callback == NULL) {
561 *proxyp = head;
562 head = head->wr_next;
563 }
564 }
565}
566
567/* Insert 'newref' in the list after 'prev'. Both must be non-NULL. */
568static void
569insert_after(PyWeakReference *newref, PyWeakReference *prev)
570{
571 newref->wr_prev = prev;
572 newref->wr_next = prev->wr_next;
573 if (prev->wr_next != NULL)
574 prev->wr_next->wr_prev = newref;
575 prev->wr_next = newref;
576}
577
578/* Insert 'newref' at the head of the list; 'list' points to the variable
579 * that stores the head.
580 */
581static void
582insert_head(PyWeakReference *newref, PyWeakReference **list)
583{
584 PyWeakReference *next = *list;
585
586 newref->wr_prev = NULL;
587 newref->wr_next = next;
588 if (next != NULL)
589 next->wr_prev = newref;
590 *list = newref;
591}
592
593
594PyObject *
595PyWeakref_NewRef(PyObject *ob, PyObject *callback)
596{
597 PyWeakReference *result = NULL;
598 PyWeakReference **list;
599 PyWeakReference *ref, *proxy;
600
601 if (!PyType_SUPPORTS_WEAKREFS(ob->ob_type)) {
602 PyErr_Format(PyExc_TypeError,
Jeremy Hylton996fad32001-10-22 16:31:40 +0000603 "cannot create weak reference to '%s' object",
Fred Drake8844d522001-10-05 21:52:26 +0000604 ob->ob_type->tp_name);
605 return NULL;
606 }
607 list = GET_WEAKREFS_LISTPTR(ob);
608 get_basic_refs(*list, &ref, &proxy);
609 if (callback == NULL || callback == Py_None)
610 /* return existing weak reference if it exists */
611 result = ref;
612 if (result != NULL)
613 Py_XINCREF(result);
614 else {
Neil Schemenauer38a89162002-03-27 15:18:21 +0000615 result = new_weakref(ob, callback);
Fred Drake8844d522001-10-05 21:52:26 +0000616 if (result != NULL) {
Fred Drake8844d522001-10-05 21:52:26 +0000617 if (callback == NULL) {
618 insert_head(result, list);
619 }
620 else {
621 PyWeakReference *prev = (proxy == NULL) ? ref : proxy;
622
623 if (prev == NULL)
624 insert_head(result, list);
625 else
626 insert_after(result, prev);
627 }
Fred Drake8844d522001-10-05 21:52:26 +0000628 }
629 }
630 return (PyObject *) result;
631}
632
633
634PyObject *
635PyWeakref_NewProxy(PyObject *ob, PyObject *callback)
636{
637 PyWeakReference *result = NULL;
638 PyWeakReference **list;
639 PyWeakReference *ref, *proxy;
640
641 if (!PyType_SUPPORTS_WEAKREFS(ob->ob_type)) {
642 PyErr_Format(PyExc_TypeError,
Jeremy Hylton996fad32001-10-22 16:31:40 +0000643 "cannot create weak reference to '%s' object",
Fred Drake8844d522001-10-05 21:52:26 +0000644 ob->ob_type->tp_name);
645 return NULL;
646 }
647 list = GET_WEAKREFS_LISTPTR(ob);
648 get_basic_refs(*list, &ref, &proxy);
649 if (callback == NULL)
650 /* attempt to return an existing weak reference if it exists */
651 result = proxy;
652 if (result != NULL)
653 Py_XINCREF(result);
654 else {
Neil Schemenauer38a89162002-03-27 15:18:21 +0000655 result = new_weakref(ob, callback);
Fred Drake8844d522001-10-05 21:52:26 +0000656 if (result != NULL) {
657 PyWeakReference *prev;
658
659 if (PyCallable_Check(ob))
660 result->ob_type = &_PyWeakref_CallableProxyType;
661 else
662 result->ob_type = &_PyWeakref_ProxyType;
Fred Drake8844d522001-10-05 21:52:26 +0000663 if (callback == NULL)
664 prev = ref;
665 else
666 prev = (proxy == NULL) ? ref : proxy;
667
668 if (prev == NULL)
669 insert_head(result, list);
670 else
671 insert_after(result, prev);
Fred Drake8844d522001-10-05 21:52:26 +0000672 }
673 }
674 return (PyObject *) result;
675}
676
677
678PyObject *
679PyWeakref_GetObject(PyObject *ref)
680{
681 if (ref == NULL || !PyWeakref_Check(ref)) {
682 PyErr_BadInternalCall();
683 return NULL;
684 }
685 return PyWeakref_GET_OBJECT(ref);
686}
687
688
Fred Drakeef8ebd12001-12-10 23:44:54 +0000689static void
690handle_callback(PyWeakReference *ref, PyObject *callback)
691{
692 PyObject *cbresult = PyObject_CallFunction(callback, "O", ref);
693
694 if (cbresult == NULL)
695 PyErr_WriteUnraisable(callback);
696 else
697 Py_DECREF(cbresult);
698}
699
700/* This function is called by the tp_dealloc handler to clear weak references.
Fred Drake8844d522001-10-05 21:52:26 +0000701 *
702 * This iterates through the weak references for 'object' and calls callbacks
703 * for those references which have one. It returns when all callbacks have
704 * been attempted.
705 */
706void
707PyObject_ClearWeakRefs(PyObject *object)
708{
709 PyWeakReference **list;
710
711 if (object == NULL
712 || !PyType_SUPPORTS_WEAKREFS(object->ob_type)
713 || object->ob_refcnt != 0) {
714 PyErr_BadInternalCall();
715 return;
716 }
717 list = GET_WEAKREFS_LISTPTR(object);
718 /* Remove the callback-less basic and proxy references */
719 if (*list != NULL && (*list)->wr_callback == NULL) {
720 clear_weakref(*list);
721 if (*list != NULL && (*list)->wr_callback == NULL)
722 clear_weakref(*list);
723 }
724 if (*list != NULL) {
Fred Drakeef8ebd12001-12-10 23:44:54 +0000725 PyWeakReference *current = *list;
726 int count = _PyWeakref_GetWeakrefCount(current);
727 int restore_error = PyErr_Occurred() ? 1 : 0;
728 PyObject *err_type, *err_value, *err_tb;
Fred Drake8844d522001-10-05 21:52:26 +0000729
Fred Drakeef8ebd12001-12-10 23:44:54 +0000730 if (restore_error)
731 PyErr_Fetch(&err_type, &err_value, &err_tb);
Fred Drake8844d522001-10-05 21:52:26 +0000732 if (count == 1) {
Fred Drake8844d522001-10-05 21:52:26 +0000733 PyObject *callback = current->wr_callback;
Fred Drake8844d522001-10-05 21:52:26 +0000734
Fred Drakeef8ebd12001-12-10 23:44:54 +0000735 current->wr_callback = NULL;
Fred Drake8844d522001-10-05 21:52:26 +0000736 clear_weakref(current);
Fred Drakeef8ebd12001-12-10 23:44:54 +0000737 handle_callback(current, callback);
Fred Drake8844d522001-10-05 21:52:26 +0000738 Py_DECREF(callback);
739 }
740 else {
741 PyObject *tuple = PyTuple_New(count * 2);
Fred Drake8844d522001-10-05 21:52:26 +0000742 int i = 0;
743
744 for (i = 0; i < count; ++i) {
745 PyWeakReference *next = current->wr_next;
746
747 Py_INCREF(current);
748 PyTuple_SET_ITEM(tuple, i * 2, (PyObject *) current);
749 PyTuple_SET_ITEM(tuple, i * 2 + 1, current->wr_callback);
750 current->wr_callback = NULL;
Fred Drake8844d522001-10-05 21:52:26 +0000751 clear_weakref(current);
752 current = next;
753 }
754 for (i = 0; i < count; ++i) {
755 PyObject *current = PyTuple_GET_ITEM(tuple, i * 2);
756 PyObject *callback = PyTuple_GET_ITEM(tuple, i * 2 + 1);
Fred Drakeef8ebd12001-12-10 23:44:54 +0000757
758 handle_callback((PyWeakReference *)current, callback);
Fred Drake8844d522001-10-05 21:52:26 +0000759 }
760 Py_DECREF(tuple);
761 }
Fred Drakeef8ebd12001-12-10 23:44:54 +0000762 if (restore_error)
763 PyErr_Restore(err_type, err_value, err_tb);
Fred Drake8844d522001-10-05 21:52:26 +0000764 }
765}