blob: f5be759a63f4148baedf702da2bec66d3bfb1b19 [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
Fred Drake8844d522001-10-05 21:52:26 +0000267static PyObject *
268proxy_repr(PyWeakReference *proxy)
269{
270 char buf[160];
Barry Warsawd5867562001-11-28 21:01:56 +0000271 PyOS_snprintf(buf, sizeof(buf),
Guido van Rossumc1f6e8c2003-04-16 21:13:23 +0000272 "<weakproxy at %p to %.100s at %p>", proxy,
Barry Warsawd5867562001-11-28 21:01:56 +0000273 PyWeakref_GET_OBJECT(proxy)->ob_type->tp_name,
274 PyWeakref_GET_OBJECT(proxy));
Fred Drake8844d522001-10-05 21:52:26 +0000275 return PyString_FromString(buf);
276}
277
278
279static int
280proxy_setattr(PyWeakReference *proxy, PyObject *name, PyObject *value)
281{
282 if (!proxy_checkref(proxy))
283 return -1;
284 return PyObject_SetAttr(PyWeakref_GET_OBJECT(proxy), name, value);
285}
286
287static int
Fred Drake2a908f62001-12-19 16:44:30 +0000288proxy_compare(PyObject *proxy, PyObject *v)
Fred Drake8844d522001-10-05 21:52:26 +0000289{
Fred Drake2a908f62001-12-19 16:44:30 +0000290 UNWRAP_I(proxy);
291 UNWRAP_I(v);
292 return PyObject_Compare(proxy, v);
Fred Drake8844d522001-10-05 21:52:26 +0000293}
294
295/* number slots */
296WRAP_BINARY(proxy_add, PyNumber_Add)
297WRAP_BINARY(proxy_sub, PyNumber_Subtract)
298WRAP_BINARY(proxy_mul, PyNumber_Multiply)
299WRAP_BINARY(proxy_div, PyNumber_Divide)
300WRAP_BINARY(proxy_mod, PyNumber_Remainder)
301WRAP_BINARY(proxy_divmod, PyNumber_Divmod)
302WRAP_TERNARY(proxy_pow, PyNumber_Power)
303WRAP_UNARY(proxy_neg, PyNumber_Negative)
304WRAP_UNARY(proxy_pos, PyNumber_Positive)
305WRAP_UNARY(proxy_abs, PyNumber_Absolute)
306WRAP_UNARY(proxy_invert, PyNumber_Invert)
307WRAP_BINARY(proxy_lshift, PyNumber_Lshift)
308WRAP_BINARY(proxy_rshift, PyNumber_Rshift)
309WRAP_BINARY(proxy_and, PyNumber_And)
310WRAP_BINARY(proxy_xor, PyNumber_Xor)
311WRAP_BINARY(proxy_or, PyNumber_Or)
312WRAP_UNARY(proxy_int, PyNumber_Int)
313WRAP_UNARY(proxy_long, PyNumber_Long)
314WRAP_UNARY(proxy_float, PyNumber_Float)
315WRAP_BINARY(proxy_iadd, PyNumber_InPlaceAdd)
316WRAP_BINARY(proxy_isub, PyNumber_InPlaceSubtract)
317WRAP_BINARY(proxy_imul, PyNumber_InPlaceMultiply)
318WRAP_BINARY(proxy_idiv, PyNumber_InPlaceDivide)
319WRAP_BINARY(proxy_imod, PyNumber_InPlaceRemainder)
320WRAP_TERNARY(proxy_ipow, PyNumber_InPlacePower)
321WRAP_BINARY(proxy_ilshift, PyNumber_InPlaceLshift)
322WRAP_BINARY(proxy_irshift, PyNumber_InPlaceRshift)
323WRAP_BINARY(proxy_iand, PyNumber_InPlaceAnd)
324WRAP_BINARY(proxy_ixor, PyNumber_InPlaceXor)
325WRAP_BINARY(proxy_ior, PyNumber_InPlaceOr)
326
327static int
328proxy_nonzero(PyWeakReference *proxy)
329{
330 PyObject *o = PyWeakref_GET_OBJECT(proxy);
331 if (!proxy_checkref(proxy))
332 return 1;
333 if (o->ob_type->tp_as_number &&
334 o->ob_type->tp_as_number->nb_nonzero)
335 return (*o->ob_type->tp_as_number->nb_nonzero)(o);
336 else
337 return 1;
338}
339
340/* sequence slots */
341
342static PyObject *
343proxy_slice(PyWeakReference *proxy, int i, int j)
344{
345 if (!proxy_checkref(proxy))
346 return NULL;
347 return PySequence_GetSlice(PyWeakref_GET_OBJECT(proxy), i, j);
348}
349
350static int
351proxy_ass_slice(PyWeakReference *proxy, int i, int j, PyObject *value)
352{
353 if (!proxy_checkref(proxy))
354 return -1;
355 return PySequence_SetSlice(PyWeakref_GET_OBJECT(proxy), i, j, value);
356}
357
358static int
359proxy_contains(PyWeakReference *proxy, PyObject *value)
360{
361 if (!proxy_checkref(proxy))
362 return -1;
363 return PySequence_Contains(PyWeakref_GET_OBJECT(proxy), value);
364}
365
366
367/* mapping slots */
368
369static int
370proxy_length(PyWeakReference *proxy)
371{
372 if (!proxy_checkref(proxy))
373 return -1;
374 return PyObject_Length(PyWeakref_GET_OBJECT(proxy));
375}
376
377WRAP_BINARY(proxy_getitem, PyObject_GetItem)
378
379static int
380proxy_setitem(PyWeakReference *proxy, PyObject *key, PyObject *value)
381{
382 if (!proxy_checkref(proxy))
383 return -1;
Raymond Hettingerd693a812003-06-30 04:18:48 +0000384
385 if (value == NULL)
386 return PyObject_DelItem(PyWeakref_GET_OBJECT(proxy), key);
387 else
388 return PyObject_SetItem(PyWeakref_GET_OBJECT(proxy), key, value);
Fred Drake8844d522001-10-05 21:52:26 +0000389}
390
Fred Drakef16c3dc2002-08-09 18:34:16 +0000391/* iterator slots */
392
393static PyObject *
394proxy_iter(PyWeakReference *proxy)
395{
396 if (!proxy_checkref(proxy))
397 return NULL;
398 return PyObject_GetIter(PyWeakref_GET_OBJECT(proxy));
399}
400
401static PyObject *
402proxy_iternext(PyWeakReference *proxy)
403{
404 if (!proxy_checkref(proxy))
405 return NULL;
406 return PyIter_Next(PyWeakref_GET_OBJECT(proxy));
407}
408
Fred Drake8844d522001-10-05 21:52:26 +0000409
410static PyNumberMethods proxy_as_number = {
411 (binaryfunc)proxy_add, /*nb_add*/
412 (binaryfunc)proxy_sub, /*nb_subtract*/
413 (binaryfunc)proxy_mul, /*nb_multiply*/
414 (binaryfunc)proxy_div, /*nb_divide*/
415 (binaryfunc)proxy_mod, /*nb_remainder*/
416 (binaryfunc)proxy_divmod, /*nb_divmod*/
417 (ternaryfunc)proxy_pow, /*nb_power*/
418 (unaryfunc)proxy_neg, /*nb_negative*/
419 (unaryfunc)proxy_pos, /*nb_positive*/
420 (unaryfunc)proxy_abs, /*nb_absolute*/
421 (inquiry)proxy_nonzero, /*nb_nonzero*/
422 (unaryfunc)proxy_invert, /*nb_invert*/
423 (binaryfunc)proxy_lshift, /*nb_lshift*/
424 (binaryfunc)proxy_rshift, /*nb_rshift*/
425 (binaryfunc)proxy_and, /*nb_and*/
426 (binaryfunc)proxy_xor, /*nb_xor*/
427 (binaryfunc)proxy_or, /*nb_or*/
428 (coercion)0, /*nb_coerce*/
429 (unaryfunc)proxy_int, /*nb_int*/
430 (unaryfunc)proxy_long, /*nb_long*/
431 (unaryfunc)proxy_float, /*nb_float*/
432 (unaryfunc)0, /*nb_oct*/
433 (unaryfunc)0, /*nb_hex*/
434 (binaryfunc)proxy_iadd, /*nb_inplace_add*/
435 (binaryfunc)proxy_isub, /*nb_inplace_subtract*/
436 (binaryfunc)proxy_imul, /*nb_inplace_multiply*/
437 (binaryfunc)proxy_idiv, /*nb_inplace_divide*/
438 (binaryfunc)proxy_imod, /*nb_inplace_remainder*/
439 (ternaryfunc)proxy_ipow, /*nb_inplace_power*/
440 (binaryfunc)proxy_ilshift, /*nb_inplace_lshift*/
441 (binaryfunc)proxy_irshift, /*nb_inplace_rshift*/
442 (binaryfunc)proxy_iand, /*nb_inplace_and*/
443 (binaryfunc)proxy_ixor, /*nb_inplace_xor*/
444 (binaryfunc)proxy_ior, /*nb_inplace_or*/
445};
446
447static PySequenceMethods proxy_as_sequence = {
448 (inquiry)proxy_length, /*sq_length*/
449 0, /*sq_concat*/
450 0, /*sq_repeat*/
451 0, /*sq_item*/
452 (intintargfunc)proxy_slice, /*sq_slice*/
453 0, /*sq_ass_item*/
454 (intintobjargproc)proxy_ass_slice, /*sq_ass_slice*/
455 (objobjproc)proxy_contains, /* sq_contains */
456};
457
458static PyMappingMethods proxy_as_mapping = {
459 (inquiry)proxy_length, /*mp_length*/
460 (binaryfunc)proxy_getitem, /*mp_subscript*/
461 (objobjargproc)proxy_setitem, /*mp_ass_subscript*/
462};
463
464
465PyTypeObject
466_PyWeakref_ProxyType = {
467 PyObject_HEAD_INIT(&PyType_Type)
468 0,
469 "weakproxy",
470 sizeof(PyWeakReference),
471 0,
472 /* methods */
Fred Drakef16c3dc2002-08-09 18:34:16 +0000473 (destructor)weakref_dealloc, /* tp_dealloc */
Fred Drakefe89cc12003-07-14 21:46:23 +0000474 0, /* tp_print */
Fred Drakef16c3dc2002-08-09 18:34:16 +0000475 0, /* tp_getattr */
476 0, /* tp_setattr */
477 proxy_compare, /* tp_compare */
478 (unaryfunc)proxy_repr, /* tp_repr */
479 &proxy_as_number, /* tp_as_number */
480 &proxy_as_sequence, /* tp_as_sequence */
481 &proxy_as_mapping, /* tp_as_mapping */
482 0, /* tp_hash */
483 (ternaryfunc)0, /* tp_call */
484 (unaryfunc)proxy_str, /* tp_str */
485 (getattrofunc)proxy_getattr, /* tp_getattro */
486 (setattrofunc)proxy_setattr, /* tp_setattro */
487 0, /* tp_as_buffer */
Fred Drake8844d522001-10-05 21:52:26 +0000488 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC
Fred Drakef16c3dc2002-08-09 18:34:16 +0000489 | Py_TPFLAGS_CHECKTYPES, /* tp_flags */
490 0, /* tp_doc */
491 (traverseproc)gc_traverse, /* tp_traverse */
492 (inquiry)gc_clear, /* tp_clear */
493 0, /* tp_richcompare */
494 0, /* tp_weaklistoffset */
495 (getiterfunc)proxy_iter, /* tp_iter */
496 (iternextfunc)proxy_iternext, /* tp_iternext */
Fred Drake8844d522001-10-05 21:52:26 +0000497};
498
499
500PyTypeObject
501_PyWeakref_CallableProxyType = {
502 PyObject_HEAD_INIT(&PyType_Type)
503 0,
504 "weakcallableproxy",
505 sizeof(PyWeakReference),
506 0,
507 /* methods */
Fred Drakef16c3dc2002-08-09 18:34:16 +0000508 (destructor)weakref_dealloc, /* tp_dealloc */
Fred Drakefe89cc12003-07-14 21:46:23 +0000509 0, /* tp_print */
Fred Drakef16c3dc2002-08-09 18:34:16 +0000510 0, /* tp_getattr */
511 0, /* tp_setattr */
512 proxy_compare, /* tp_compare */
513 (unaryfunc)proxy_repr, /* tp_repr */
514 &proxy_as_number, /* tp_as_number */
515 &proxy_as_sequence, /* tp_as_sequence */
516 &proxy_as_mapping, /* tp_as_mapping */
517 0, /* tp_hash */
518 (ternaryfunc)proxy_call, /* tp_call */
519 (unaryfunc)proxy_str, /* tp_str */
520 (getattrofunc)proxy_getattr, /* tp_getattro */
521 (setattrofunc)proxy_setattr, /* tp_setattro */
522 0, /* tp_as_buffer */
Fred Drake8844d522001-10-05 21:52:26 +0000523 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC
Fred Drakef16c3dc2002-08-09 18:34:16 +0000524 | Py_TPFLAGS_CHECKTYPES, /* tp_flags */
525 0, /* tp_doc */
526 (traverseproc)gc_traverse, /* tp_traverse */
527 (inquiry)gc_clear, /* tp_clear */
528 0, /* tp_richcompare */
529 0, /* tp_weaklistoffset */
530 (getiterfunc)proxy_iter, /* tp_iter */
531 (iternextfunc)proxy_iternext, /* tp_iternext */
Fred Drake8844d522001-10-05 21:52:26 +0000532};
533
534
535/* Given the head of an object's list of weak references, extract the
536 * two callback-less refs (ref and proxy). Used to determine if the
537 * shared references exist and to determine the back link for newly
538 * inserted references.
539 */
540static void
541get_basic_refs(PyWeakReference *head,
542 PyWeakReference **refp, PyWeakReference **proxyp)
543{
544 *refp = NULL;
545 *proxyp = NULL;
546
547 if (head != NULL && head->wr_callback == NULL) {
548 if (head->ob_type == &_PyWeakref_RefType) {
549 *refp = head;
550 head = head->wr_next;
551 }
552 if (head != NULL && head->wr_callback == NULL) {
553 *proxyp = head;
554 head = head->wr_next;
555 }
556 }
557}
558
559/* Insert 'newref' in the list after 'prev'. Both must be non-NULL. */
560static void
561insert_after(PyWeakReference *newref, PyWeakReference *prev)
562{
563 newref->wr_prev = prev;
564 newref->wr_next = prev->wr_next;
565 if (prev->wr_next != NULL)
566 prev->wr_next->wr_prev = newref;
567 prev->wr_next = newref;
568}
569
570/* Insert 'newref' at the head of the list; 'list' points to the variable
571 * that stores the head.
572 */
573static void
574insert_head(PyWeakReference *newref, PyWeakReference **list)
575{
576 PyWeakReference *next = *list;
577
578 newref->wr_prev = NULL;
579 newref->wr_next = next;
580 if (next != NULL)
581 next->wr_prev = newref;
582 *list = newref;
583}
584
585
586PyObject *
587PyWeakref_NewRef(PyObject *ob, PyObject *callback)
588{
589 PyWeakReference *result = NULL;
590 PyWeakReference **list;
591 PyWeakReference *ref, *proxy;
592
593 if (!PyType_SUPPORTS_WEAKREFS(ob->ob_type)) {
594 PyErr_Format(PyExc_TypeError,
Jeremy Hylton996fad32001-10-22 16:31:40 +0000595 "cannot create weak reference to '%s' object",
Fred Drake8844d522001-10-05 21:52:26 +0000596 ob->ob_type->tp_name);
597 return NULL;
598 }
599 list = GET_WEAKREFS_LISTPTR(ob);
600 get_basic_refs(*list, &ref, &proxy);
601 if (callback == NULL || callback == Py_None)
602 /* return existing weak reference if it exists */
603 result = ref;
604 if (result != NULL)
605 Py_XINCREF(result);
606 else {
Neil Schemenauer38a89162002-03-27 15:18:21 +0000607 result = new_weakref(ob, callback);
Fred Drake8844d522001-10-05 21:52:26 +0000608 if (result != NULL) {
Fred Drake8844d522001-10-05 21:52:26 +0000609 if (callback == NULL) {
610 insert_head(result, list);
611 }
612 else {
613 PyWeakReference *prev = (proxy == NULL) ? ref : proxy;
614
615 if (prev == NULL)
616 insert_head(result, list);
617 else
618 insert_after(result, prev);
619 }
Fred Drake8844d522001-10-05 21:52:26 +0000620 }
621 }
622 return (PyObject *) result;
623}
624
625
626PyObject *
627PyWeakref_NewProxy(PyObject *ob, PyObject *callback)
628{
629 PyWeakReference *result = NULL;
630 PyWeakReference **list;
631 PyWeakReference *ref, *proxy;
632
633 if (!PyType_SUPPORTS_WEAKREFS(ob->ob_type)) {
634 PyErr_Format(PyExc_TypeError,
Jeremy Hylton996fad32001-10-22 16:31:40 +0000635 "cannot create weak reference to '%s' object",
Fred Drake8844d522001-10-05 21:52:26 +0000636 ob->ob_type->tp_name);
637 return NULL;
638 }
639 list = GET_WEAKREFS_LISTPTR(ob);
640 get_basic_refs(*list, &ref, &proxy);
641 if (callback == NULL)
642 /* attempt to return an existing weak reference if it exists */
643 result = proxy;
644 if (result != NULL)
645 Py_XINCREF(result);
646 else {
Neil Schemenauer38a89162002-03-27 15:18:21 +0000647 result = new_weakref(ob, callback);
Fred Drake8844d522001-10-05 21:52:26 +0000648 if (result != NULL) {
649 PyWeakReference *prev;
650
651 if (PyCallable_Check(ob))
652 result->ob_type = &_PyWeakref_CallableProxyType;
653 else
654 result->ob_type = &_PyWeakref_ProxyType;
Fred Drake8844d522001-10-05 21:52:26 +0000655 if (callback == NULL)
656 prev = ref;
657 else
658 prev = (proxy == NULL) ? ref : proxy;
659
660 if (prev == NULL)
661 insert_head(result, list);
662 else
663 insert_after(result, prev);
Fred Drake8844d522001-10-05 21:52:26 +0000664 }
665 }
666 return (PyObject *) result;
667}
668
669
670PyObject *
671PyWeakref_GetObject(PyObject *ref)
672{
673 if (ref == NULL || !PyWeakref_Check(ref)) {
674 PyErr_BadInternalCall();
675 return NULL;
676 }
677 return PyWeakref_GET_OBJECT(ref);
678}
679
680
Fred Drakeef8ebd12001-12-10 23:44:54 +0000681static void
682handle_callback(PyWeakReference *ref, PyObject *callback)
683{
684 PyObject *cbresult = PyObject_CallFunction(callback, "O", ref);
685
686 if (cbresult == NULL)
687 PyErr_WriteUnraisable(callback);
688 else
689 Py_DECREF(cbresult);
690}
691
692/* This function is called by the tp_dealloc handler to clear weak references.
Fred Drake8844d522001-10-05 21:52:26 +0000693 *
694 * This iterates through the weak references for 'object' and calls callbacks
695 * for those references which have one. It returns when all callbacks have
696 * been attempted.
697 */
698void
699PyObject_ClearWeakRefs(PyObject *object)
700{
701 PyWeakReference **list;
702
703 if (object == NULL
704 || !PyType_SUPPORTS_WEAKREFS(object->ob_type)
705 || object->ob_refcnt != 0) {
706 PyErr_BadInternalCall();
707 return;
708 }
709 list = GET_WEAKREFS_LISTPTR(object);
710 /* Remove the callback-less basic and proxy references */
711 if (*list != NULL && (*list)->wr_callback == NULL) {
712 clear_weakref(*list);
713 if (*list != NULL && (*list)->wr_callback == NULL)
714 clear_weakref(*list);
715 }
716 if (*list != NULL) {
Fred Drakeef8ebd12001-12-10 23:44:54 +0000717 PyWeakReference *current = *list;
718 int count = _PyWeakref_GetWeakrefCount(current);
719 int restore_error = PyErr_Occurred() ? 1 : 0;
720 PyObject *err_type, *err_value, *err_tb;
Fred Drake8844d522001-10-05 21:52:26 +0000721
Fred Drakeef8ebd12001-12-10 23:44:54 +0000722 if (restore_error)
723 PyErr_Fetch(&err_type, &err_value, &err_tb);
Fred Drake8844d522001-10-05 21:52:26 +0000724 if (count == 1) {
Fred Drake8844d522001-10-05 21:52:26 +0000725 PyObject *callback = current->wr_callback;
Fred Drake8844d522001-10-05 21:52:26 +0000726
Fred Drakeef8ebd12001-12-10 23:44:54 +0000727 current->wr_callback = NULL;
Fred Drake8844d522001-10-05 21:52:26 +0000728 clear_weakref(current);
Fred Drakeef8ebd12001-12-10 23:44:54 +0000729 handle_callback(current, callback);
Fred Drake8844d522001-10-05 21:52:26 +0000730 Py_DECREF(callback);
731 }
732 else {
733 PyObject *tuple = PyTuple_New(count * 2);
Fred Drake8844d522001-10-05 21:52:26 +0000734 int i = 0;
735
736 for (i = 0; i < count; ++i) {
737 PyWeakReference *next = current->wr_next;
738
739 Py_INCREF(current);
740 PyTuple_SET_ITEM(tuple, i * 2, (PyObject *) current);
741 PyTuple_SET_ITEM(tuple, i * 2 + 1, current->wr_callback);
742 current->wr_callback = NULL;
Fred Drake8844d522001-10-05 21:52:26 +0000743 clear_weakref(current);
744 current = next;
745 }
746 for (i = 0; i < count; ++i) {
747 PyObject *current = PyTuple_GET_ITEM(tuple, i * 2);
748 PyObject *callback = PyTuple_GET_ITEM(tuple, i * 2 + 1);
Fred Drakeef8ebd12001-12-10 23:44:54 +0000749
750 handle_callback((PyWeakReference *)current, callback);
Fred Drake8844d522001-10-05 21:52:26 +0000751 }
752 Py_DECREF(tuple);
753 }
Fred Drakeef8ebd12001-12-10 23:44:54 +0000754 if (restore_error)
755 PyErr_Restore(err_type, err_value, err_tb);
Fred Drake8844d522001-10-05 21:52:26 +0000756 }
757}