blob: cf0316a50fd943dec296a7ceee117ebb985e56b6 [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;
Fred Drake8844d522001-10-05 21:52:26 +000056 if (self->wr_prev != NULL)
57 self->wr_prev->wr_next = self->wr_next;
58 if (self->wr_next != NULL)
59 self->wr_next->wr_prev = self->wr_prev;
60 self->wr_prev = NULL;
61 self->wr_next = NULL;
Tim Peters403a2032003-11-20 21:21:46 +000062 }
63 if (callback != NULL) {
64 Py_DECREF(callback);
65 self->wr_callback = NULL;
Fred Drake8844d522001-10-05 21:52:26 +000066 }
67}
68
Tim Peters403a2032003-11-20 21:21:46 +000069/* Cyclic gc uses this to *just* clear the passed-in reference, leaving
70 * the callback intact and uncalled. It must be possible to call self's
71 * tp_dealloc() after calling this, so self has to be left in a sane enough
72 * state for that to work. We expect tp_dealloc to decref the callback
73 * then. The reason for not letting clear_weakref() decref the callback
74 * right now is that if the callback goes away, that may in turn trigger
75 * another callback (if a weak reference to the callback exists) -- running
76 * arbitrary Python code in the middle of gc is a disaster. The convolution
77 * here allows gc to delay triggering such callbacks until the world is in
78 * a sane state again.
79 */
80void
81_PyWeakref_ClearRef(PyWeakReference *self)
82{
83 PyObject *callback;
84
85 assert(self != NULL);
86 assert(PyWeakref_Check(self));
87 /* Preserve and restore the callback around clear_weakref. */
88 callback = self->wr_callback;
89 self->wr_callback = NULL;
90 clear_weakref(self);
91 self->wr_callback = callback;
92}
Fred Drake8844d522001-10-05 21:52:26 +000093
94static void
95weakref_dealloc(PyWeakReference *self)
96{
97 PyObject_GC_UnTrack((PyObject *)self);
98 clear_weakref(self);
Neil Schemenauer38a89162002-03-27 15:18:21 +000099 PyObject_GC_Del(self);
Fred Drake8844d522001-10-05 21:52:26 +0000100}
101
102
103static int
104gc_traverse(PyWeakReference *self, visitproc visit, void *arg)
105{
106 if (self->wr_callback != NULL)
107 return visit(self->wr_callback, arg);
108 return 0;
109}
110
111
112static int
113gc_clear(PyWeakReference *self)
114{
115 clear_weakref(self);
116 return 0;
117}
118
119
120static PyObject *
121weakref_call(PyWeakReference *self, PyObject *args, PyObject *kw)
122{
123 static char *argnames[] = {NULL};
124
125 if (PyArg_ParseTupleAndKeywords(args, kw, ":__call__", argnames)) {
126 PyObject *object = PyWeakref_GET_OBJECT(self);
127 Py_INCREF(object);
128 return (object);
129 }
130 return NULL;
131}
132
133
134static long
135weakref_hash(PyWeakReference *self)
136{
137 if (self->hash != -1)
138 return self->hash;
139 if (PyWeakref_GET_OBJECT(self) == Py_None) {
140 PyErr_SetString(PyExc_TypeError, "weak object has gone away");
141 return -1;
142 }
143 self->hash = PyObject_Hash(PyWeakref_GET_OBJECT(self));
144 return self->hash;
145}
Tim Peters403a2032003-11-20 21:21:46 +0000146
Fred Drake8844d522001-10-05 21:52:26 +0000147
148static PyObject *
149weakref_repr(PyWeakReference *self)
150{
151 char buffer[256];
152 if (PyWeakref_GET_OBJECT(self) == Py_None) {
Guido van Rossumc1f6e8c2003-04-16 21:13:23 +0000153 PyOS_snprintf(buffer, sizeof(buffer), "<weakref at %p; dead>", self);
Fred Drake8844d522001-10-05 21:52:26 +0000154 }
155 else {
Guido van Rossumc1f6e8c2003-04-16 21:13:23 +0000156 char *name = NULL;
157 PyObject *nameobj = PyObject_GetAttrString(PyWeakref_GET_OBJECT(self),
158 "__name__");
159 if (nameobj == NULL)
160 PyErr_Clear();
161 else if (PyString_Check(nameobj))
162 name = PyString_AS_STRING(nameobj);
Barry Warsawd5867562001-11-28 21:01:56 +0000163 PyOS_snprintf(buffer, sizeof(buffer),
Guido van Rossumc1f6e8c2003-04-16 21:13:23 +0000164 name ? "<weakref at %p; to '%.50s' at %p (%s)>"
165 : "<weakref at %p; to '%.50s' at %p>",
166 self,
Barry Warsawd5867562001-11-28 21:01:56 +0000167 PyWeakref_GET_OBJECT(self)->ob_type->tp_name,
Guido van Rossumc1f6e8c2003-04-16 21:13:23 +0000168 PyWeakref_GET_OBJECT(self),
169 name);
170 Py_XDECREF(nameobj);
Fred Drake8844d522001-10-05 21:52:26 +0000171 }
172 return PyString_FromString(buffer);
173}
174
175/* Weak references only support equality, not ordering. Two weak references
176 are equal if the underlying objects are equal. If the underlying object has
177 gone away, they are equal if they are identical. */
178
179static PyObject *
180weakref_richcompare(PyWeakReference* self, PyWeakReference* other, int op)
181{
182 if (op != Py_EQ || self->ob_type != other->ob_type) {
183 Py_INCREF(Py_NotImplemented);
184 return Py_NotImplemented;
185 }
186 if (PyWeakref_GET_OBJECT(self) == Py_None
187 || PyWeakref_GET_OBJECT(other) == Py_None) {
188 PyObject *res = self==other ? Py_True : Py_False;
189 Py_INCREF(res);
190 return res;
191 }
192 return PyObject_RichCompare(PyWeakref_GET_OBJECT(self),
193 PyWeakref_GET_OBJECT(other), op);
194}
195
196
197PyTypeObject
198_PyWeakref_RefType = {
199 PyObject_HEAD_INIT(&PyType_Type)
200 0,
201 "weakref",
202 sizeof(PyWeakReference),
203 0,
204 (destructor)weakref_dealloc,/*tp_dealloc*/
205 0, /*tp_print*/
206 0, /*tp_getattr*/
207 0, /*tp_setattr*/
208 0, /*tp_compare*/
209 (reprfunc)weakref_repr, /*tp_repr*/
210 0, /*tp_as_number*/
211 0, /*tp_as_sequence*/
212 0, /*tp_as_mapping*/
213 (hashfunc)weakref_hash, /*tp_hash*/
214 (ternaryfunc)weakref_call, /*tp_call*/
215 0, /*tp_str*/
216 0, /*tp_getattro*/
217 0, /*tp_setattro*/
218 0, /*tp_as_buffer*/
219 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_RICHCOMPARE,
220 0, /*tp_doc*/
221 (traverseproc)gc_traverse, /*tp_traverse*/
222 (inquiry)gc_clear, /*tp_clear*/
223 (richcmpfunc)weakref_richcompare, /*tp_richcompare*/
224 0, /*tp_weaklistoffset*/
225};
226
227
228static int
229proxy_checkref(PyWeakReference *proxy)
230{
231 if (PyWeakref_GET_OBJECT(proxy) == Py_None) {
232 PyErr_SetString(PyExc_ReferenceError,
233 "weakly-referenced object no longer exists");
234 return 0;
235 }
236 return 1;
237}
238
239
Fred Drake73006d02001-10-18 18:04:18 +0000240/* If a parameter is a proxy, check that it is still "live" and wrap it,
241 * replacing the original value with the raw object. Raises ReferenceError
242 * if the param is a dead proxy.
243 */
244#define UNWRAP(o) \
245 if (PyWeakref_CheckProxy(o)) { \
246 if (!proxy_checkref((PyWeakReference *)o)) \
247 return NULL; \
248 o = PyWeakref_GET_OBJECT(o); \
249 }
250
Fred Drake2a908f62001-12-19 16:44:30 +0000251#define UNWRAP_I(o) \
252 if (PyWeakref_CheckProxy(o)) { \
253 if (!proxy_checkref((PyWeakReference *)o)) \
254 return -1; \
255 o = PyWeakref_GET_OBJECT(o); \
256 }
257
Fred Drake8844d522001-10-05 21:52:26 +0000258#define WRAP_UNARY(method, generic) \
259 static PyObject * \
Fred Drake73006d02001-10-18 18:04:18 +0000260 method(PyObject *proxy) { \
261 UNWRAP(proxy); \
262 return generic(proxy); \
Fred Drake8844d522001-10-05 21:52:26 +0000263 }
264
265#define WRAP_BINARY(method, generic) \
266 static PyObject * \
Fred Drake73006d02001-10-18 18:04:18 +0000267 method(PyObject *x, PyObject *y) { \
268 UNWRAP(x); \
269 UNWRAP(y); \
270 return generic(x, y); \
Fred Drake8844d522001-10-05 21:52:26 +0000271 }
272
Fred Drake31f4d1f2001-10-18 19:21:46 +0000273/* Note that the third arg needs to be checked for NULL since the tp_call
274 * slot can receive NULL for this arg.
Fred Drake73006d02001-10-18 18:04:18 +0000275 */
Fred Drake8844d522001-10-05 21:52:26 +0000276#define WRAP_TERNARY(method, generic) \
277 static PyObject * \
Fred Drake73006d02001-10-18 18:04:18 +0000278 method(PyObject *proxy, PyObject *v, PyObject *w) { \
279 UNWRAP(proxy); \
Fred Drake31f4d1f2001-10-18 19:21:46 +0000280 UNWRAP(v); \
Fred Drake73006d02001-10-18 18:04:18 +0000281 if (w != NULL) \
282 UNWRAP(w); \
283 return generic(proxy, v, w); \
Fred Drake8844d522001-10-05 21:52:26 +0000284 }
285
286
287/* direct slots */
288
289WRAP_BINARY(proxy_getattr, PyObject_GetAttr)
290WRAP_UNARY(proxy_str, PyObject_Str)
291WRAP_TERNARY(proxy_call, PyEval_CallObjectWithKeywords)
292
Fred Drake8844d522001-10-05 21:52:26 +0000293static PyObject *
294proxy_repr(PyWeakReference *proxy)
295{
296 char buf[160];
Barry Warsawd5867562001-11-28 21:01:56 +0000297 PyOS_snprintf(buf, sizeof(buf),
Guido van Rossumc1f6e8c2003-04-16 21:13:23 +0000298 "<weakproxy at %p to %.100s at %p>", proxy,
Barry Warsawd5867562001-11-28 21:01:56 +0000299 PyWeakref_GET_OBJECT(proxy)->ob_type->tp_name,
300 PyWeakref_GET_OBJECT(proxy));
Fred Drake8844d522001-10-05 21:52:26 +0000301 return PyString_FromString(buf);
302}
303
304
305static int
306proxy_setattr(PyWeakReference *proxy, PyObject *name, PyObject *value)
307{
308 if (!proxy_checkref(proxy))
309 return -1;
310 return PyObject_SetAttr(PyWeakref_GET_OBJECT(proxy), name, value);
311}
312
313static int
Fred Drake2a908f62001-12-19 16:44:30 +0000314proxy_compare(PyObject *proxy, PyObject *v)
Fred Drake8844d522001-10-05 21:52:26 +0000315{
Fred Drake2a908f62001-12-19 16:44:30 +0000316 UNWRAP_I(proxy);
317 UNWRAP_I(v);
318 return PyObject_Compare(proxy, v);
Fred Drake8844d522001-10-05 21:52:26 +0000319}
320
321/* number slots */
322WRAP_BINARY(proxy_add, PyNumber_Add)
323WRAP_BINARY(proxy_sub, PyNumber_Subtract)
324WRAP_BINARY(proxy_mul, PyNumber_Multiply)
325WRAP_BINARY(proxy_div, PyNumber_Divide)
326WRAP_BINARY(proxy_mod, PyNumber_Remainder)
327WRAP_BINARY(proxy_divmod, PyNumber_Divmod)
328WRAP_TERNARY(proxy_pow, PyNumber_Power)
329WRAP_UNARY(proxy_neg, PyNumber_Negative)
330WRAP_UNARY(proxy_pos, PyNumber_Positive)
331WRAP_UNARY(proxy_abs, PyNumber_Absolute)
332WRAP_UNARY(proxy_invert, PyNumber_Invert)
333WRAP_BINARY(proxy_lshift, PyNumber_Lshift)
334WRAP_BINARY(proxy_rshift, PyNumber_Rshift)
335WRAP_BINARY(proxy_and, PyNumber_And)
336WRAP_BINARY(proxy_xor, PyNumber_Xor)
337WRAP_BINARY(proxy_or, PyNumber_Or)
338WRAP_UNARY(proxy_int, PyNumber_Int)
339WRAP_UNARY(proxy_long, PyNumber_Long)
340WRAP_UNARY(proxy_float, PyNumber_Float)
341WRAP_BINARY(proxy_iadd, PyNumber_InPlaceAdd)
342WRAP_BINARY(proxy_isub, PyNumber_InPlaceSubtract)
343WRAP_BINARY(proxy_imul, PyNumber_InPlaceMultiply)
344WRAP_BINARY(proxy_idiv, PyNumber_InPlaceDivide)
345WRAP_BINARY(proxy_imod, PyNumber_InPlaceRemainder)
346WRAP_TERNARY(proxy_ipow, PyNumber_InPlacePower)
347WRAP_BINARY(proxy_ilshift, PyNumber_InPlaceLshift)
348WRAP_BINARY(proxy_irshift, PyNumber_InPlaceRshift)
349WRAP_BINARY(proxy_iand, PyNumber_InPlaceAnd)
350WRAP_BINARY(proxy_ixor, PyNumber_InPlaceXor)
351WRAP_BINARY(proxy_ior, PyNumber_InPlaceOr)
352
Tim Peters403a2032003-11-20 21:21:46 +0000353static int
Fred Drake8844d522001-10-05 21:52:26 +0000354proxy_nonzero(PyWeakReference *proxy)
355{
356 PyObject *o = PyWeakref_GET_OBJECT(proxy);
357 if (!proxy_checkref(proxy))
358 return 1;
359 if (o->ob_type->tp_as_number &&
360 o->ob_type->tp_as_number->nb_nonzero)
361 return (*o->ob_type->tp_as_number->nb_nonzero)(o);
362 else
363 return 1;
364}
365
366/* sequence slots */
367
368static PyObject *
369proxy_slice(PyWeakReference *proxy, int i, int j)
370{
371 if (!proxy_checkref(proxy))
372 return NULL;
373 return PySequence_GetSlice(PyWeakref_GET_OBJECT(proxy), i, j);
374}
375
376static int
377proxy_ass_slice(PyWeakReference *proxy, int i, int j, PyObject *value)
378{
379 if (!proxy_checkref(proxy))
380 return -1;
381 return PySequence_SetSlice(PyWeakref_GET_OBJECT(proxy), i, j, value);
382}
383
384static int
385proxy_contains(PyWeakReference *proxy, PyObject *value)
386{
387 if (!proxy_checkref(proxy))
388 return -1;
389 return PySequence_Contains(PyWeakref_GET_OBJECT(proxy), value);
390}
391
392
393/* mapping slots */
394
395static int
396proxy_length(PyWeakReference *proxy)
397{
398 if (!proxy_checkref(proxy))
399 return -1;
400 return PyObject_Length(PyWeakref_GET_OBJECT(proxy));
401}
402
403WRAP_BINARY(proxy_getitem, PyObject_GetItem)
404
405static int
406proxy_setitem(PyWeakReference *proxy, PyObject *key, PyObject *value)
407{
408 if (!proxy_checkref(proxy))
409 return -1;
Raymond Hettingerd693a812003-06-30 04:18:48 +0000410
411 if (value == NULL)
412 return PyObject_DelItem(PyWeakref_GET_OBJECT(proxy), key);
413 else
414 return PyObject_SetItem(PyWeakref_GET_OBJECT(proxy), key, value);
Fred Drake8844d522001-10-05 21:52:26 +0000415}
416
Fred Drakef16c3dc2002-08-09 18:34:16 +0000417/* iterator slots */
418
419static PyObject *
420proxy_iter(PyWeakReference *proxy)
421{
422 if (!proxy_checkref(proxy))
423 return NULL;
424 return PyObject_GetIter(PyWeakref_GET_OBJECT(proxy));
425}
426
427static PyObject *
428proxy_iternext(PyWeakReference *proxy)
429{
430 if (!proxy_checkref(proxy))
431 return NULL;
432 return PyIter_Next(PyWeakref_GET_OBJECT(proxy));
433}
434
Fred Drake8844d522001-10-05 21:52:26 +0000435
436static PyNumberMethods proxy_as_number = {
437 (binaryfunc)proxy_add, /*nb_add*/
438 (binaryfunc)proxy_sub, /*nb_subtract*/
439 (binaryfunc)proxy_mul, /*nb_multiply*/
440 (binaryfunc)proxy_div, /*nb_divide*/
441 (binaryfunc)proxy_mod, /*nb_remainder*/
442 (binaryfunc)proxy_divmod, /*nb_divmod*/
443 (ternaryfunc)proxy_pow, /*nb_power*/
444 (unaryfunc)proxy_neg, /*nb_negative*/
445 (unaryfunc)proxy_pos, /*nb_positive*/
446 (unaryfunc)proxy_abs, /*nb_absolute*/
447 (inquiry)proxy_nonzero, /*nb_nonzero*/
448 (unaryfunc)proxy_invert, /*nb_invert*/
449 (binaryfunc)proxy_lshift, /*nb_lshift*/
450 (binaryfunc)proxy_rshift, /*nb_rshift*/
451 (binaryfunc)proxy_and, /*nb_and*/
452 (binaryfunc)proxy_xor, /*nb_xor*/
453 (binaryfunc)proxy_or, /*nb_or*/
454 (coercion)0, /*nb_coerce*/
455 (unaryfunc)proxy_int, /*nb_int*/
456 (unaryfunc)proxy_long, /*nb_long*/
457 (unaryfunc)proxy_float, /*nb_float*/
458 (unaryfunc)0, /*nb_oct*/
459 (unaryfunc)0, /*nb_hex*/
460 (binaryfunc)proxy_iadd, /*nb_inplace_add*/
461 (binaryfunc)proxy_isub, /*nb_inplace_subtract*/
462 (binaryfunc)proxy_imul, /*nb_inplace_multiply*/
463 (binaryfunc)proxy_idiv, /*nb_inplace_divide*/
464 (binaryfunc)proxy_imod, /*nb_inplace_remainder*/
465 (ternaryfunc)proxy_ipow, /*nb_inplace_power*/
466 (binaryfunc)proxy_ilshift, /*nb_inplace_lshift*/
467 (binaryfunc)proxy_irshift, /*nb_inplace_rshift*/
468 (binaryfunc)proxy_iand, /*nb_inplace_and*/
469 (binaryfunc)proxy_ixor, /*nb_inplace_xor*/
470 (binaryfunc)proxy_ior, /*nb_inplace_or*/
471};
472
473static PySequenceMethods proxy_as_sequence = {
474 (inquiry)proxy_length, /*sq_length*/
475 0, /*sq_concat*/
476 0, /*sq_repeat*/
477 0, /*sq_item*/
478 (intintargfunc)proxy_slice, /*sq_slice*/
479 0, /*sq_ass_item*/
480 (intintobjargproc)proxy_ass_slice, /*sq_ass_slice*/
481 (objobjproc)proxy_contains, /* sq_contains */
482};
483
484static PyMappingMethods proxy_as_mapping = {
485 (inquiry)proxy_length, /*mp_length*/
486 (binaryfunc)proxy_getitem, /*mp_subscript*/
487 (objobjargproc)proxy_setitem, /*mp_ass_subscript*/
488};
489
490
491PyTypeObject
492_PyWeakref_ProxyType = {
493 PyObject_HEAD_INIT(&PyType_Type)
494 0,
495 "weakproxy",
496 sizeof(PyWeakReference),
497 0,
498 /* methods */
Fred Drakef16c3dc2002-08-09 18:34:16 +0000499 (destructor)weakref_dealloc, /* tp_dealloc */
Fred Drakefe89cc12003-07-14 21:46:23 +0000500 0, /* tp_print */
Fred Drakef16c3dc2002-08-09 18:34:16 +0000501 0, /* tp_getattr */
502 0, /* tp_setattr */
503 proxy_compare, /* tp_compare */
504 (unaryfunc)proxy_repr, /* tp_repr */
505 &proxy_as_number, /* tp_as_number */
506 &proxy_as_sequence, /* tp_as_sequence */
507 &proxy_as_mapping, /* tp_as_mapping */
508 0, /* tp_hash */
509 (ternaryfunc)0, /* tp_call */
510 (unaryfunc)proxy_str, /* tp_str */
511 (getattrofunc)proxy_getattr, /* tp_getattro */
512 (setattrofunc)proxy_setattr, /* tp_setattro */
513 0, /* tp_as_buffer */
Fred Drake8844d522001-10-05 21:52:26 +0000514 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC
Fred Drakef16c3dc2002-08-09 18:34:16 +0000515 | Py_TPFLAGS_CHECKTYPES, /* tp_flags */
516 0, /* tp_doc */
517 (traverseproc)gc_traverse, /* tp_traverse */
518 (inquiry)gc_clear, /* tp_clear */
519 0, /* tp_richcompare */
520 0, /* tp_weaklistoffset */
521 (getiterfunc)proxy_iter, /* tp_iter */
522 (iternextfunc)proxy_iternext, /* tp_iternext */
Fred Drake8844d522001-10-05 21:52:26 +0000523};
524
525
526PyTypeObject
527_PyWeakref_CallableProxyType = {
528 PyObject_HEAD_INIT(&PyType_Type)
529 0,
530 "weakcallableproxy",
531 sizeof(PyWeakReference),
532 0,
533 /* methods */
Fred Drakef16c3dc2002-08-09 18:34:16 +0000534 (destructor)weakref_dealloc, /* tp_dealloc */
Fred Drakefe89cc12003-07-14 21:46:23 +0000535 0, /* tp_print */
Fred Drakef16c3dc2002-08-09 18:34:16 +0000536 0, /* tp_getattr */
537 0, /* tp_setattr */
538 proxy_compare, /* tp_compare */
539 (unaryfunc)proxy_repr, /* tp_repr */
540 &proxy_as_number, /* tp_as_number */
541 &proxy_as_sequence, /* tp_as_sequence */
542 &proxy_as_mapping, /* tp_as_mapping */
543 0, /* tp_hash */
544 (ternaryfunc)proxy_call, /* tp_call */
545 (unaryfunc)proxy_str, /* tp_str */
546 (getattrofunc)proxy_getattr, /* tp_getattro */
547 (setattrofunc)proxy_setattr, /* tp_setattro */
548 0, /* tp_as_buffer */
Fred Drake8844d522001-10-05 21:52:26 +0000549 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC
Fred Drakef16c3dc2002-08-09 18:34:16 +0000550 | Py_TPFLAGS_CHECKTYPES, /* tp_flags */
551 0, /* tp_doc */
552 (traverseproc)gc_traverse, /* tp_traverse */
553 (inquiry)gc_clear, /* tp_clear */
554 0, /* tp_richcompare */
555 0, /* tp_weaklistoffset */
556 (getiterfunc)proxy_iter, /* tp_iter */
557 (iternextfunc)proxy_iternext, /* tp_iternext */
Fred Drake8844d522001-10-05 21:52:26 +0000558};
559
560
561/* Given the head of an object's list of weak references, extract the
562 * two callback-less refs (ref and proxy). Used to determine if the
563 * shared references exist and to determine the back link for newly
564 * inserted references.
565 */
566static void
567get_basic_refs(PyWeakReference *head,
568 PyWeakReference **refp, PyWeakReference **proxyp)
569{
570 *refp = NULL;
571 *proxyp = NULL;
572
573 if (head != NULL && head->wr_callback == NULL) {
574 if (head->ob_type == &_PyWeakref_RefType) {
575 *refp = head;
576 head = head->wr_next;
577 }
578 if (head != NULL && head->wr_callback == NULL) {
579 *proxyp = head;
580 head = head->wr_next;
581 }
582 }
583}
584
585/* Insert 'newref' in the list after 'prev'. Both must be non-NULL. */
586static void
587insert_after(PyWeakReference *newref, PyWeakReference *prev)
588{
589 newref->wr_prev = prev;
590 newref->wr_next = prev->wr_next;
591 if (prev->wr_next != NULL)
592 prev->wr_next->wr_prev = newref;
593 prev->wr_next = newref;
594}
595
596/* Insert 'newref' at the head of the list; 'list' points to the variable
597 * that stores the head.
598 */
599static void
600insert_head(PyWeakReference *newref, PyWeakReference **list)
601{
602 PyWeakReference *next = *list;
603
604 newref->wr_prev = NULL;
605 newref->wr_next = next;
606 if (next != NULL)
607 next->wr_prev = newref;
608 *list = newref;
609}
610
611
612PyObject *
613PyWeakref_NewRef(PyObject *ob, PyObject *callback)
614{
615 PyWeakReference *result = NULL;
616 PyWeakReference **list;
617 PyWeakReference *ref, *proxy;
618
619 if (!PyType_SUPPORTS_WEAKREFS(ob->ob_type)) {
620 PyErr_Format(PyExc_TypeError,
Jeremy Hylton996fad32001-10-22 16:31:40 +0000621 "cannot create weak reference to '%s' object",
Fred Drake8844d522001-10-05 21:52:26 +0000622 ob->ob_type->tp_name);
623 return NULL;
624 }
625 list = GET_WEAKREFS_LISTPTR(ob);
626 get_basic_refs(*list, &ref, &proxy);
Fred Drake6a2852c2004-02-03 19:52:56 +0000627 if (callback == Py_None)
628 callback = NULL;
629 if (callback == NULL)
Fred Drake8844d522001-10-05 21:52:26 +0000630 /* return existing weak reference if it exists */
631 result = ref;
632 if (result != NULL)
633 Py_XINCREF(result);
634 else {
Neil Schemenauer38a89162002-03-27 15:18:21 +0000635 result = new_weakref(ob, callback);
Fred Drake8844d522001-10-05 21:52:26 +0000636 if (result != NULL) {
Fred Drake8844d522001-10-05 21:52:26 +0000637 if (callback == NULL) {
638 insert_head(result, list);
639 }
640 else {
641 PyWeakReference *prev = (proxy == NULL) ? ref : proxy;
642
643 if (prev == NULL)
644 insert_head(result, list);
645 else
646 insert_after(result, prev);
647 }
Fred Drake8844d522001-10-05 21:52:26 +0000648 }
649 }
650 return (PyObject *) result;
651}
652
653
654PyObject *
655PyWeakref_NewProxy(PyObject *ob, PyObject *callback)
656{
657 PyWeakReference *result = NULL;
658 PyWeakReference **list;
659 PyWeakReference *ref, *proxy;
660
661 if (!PyType_SUPPORTS_WEAKREFS(ob->ob_type)) {
662 PyErr_Format(PyExc_TypeError,
Jeremy Hylton996fad32001-10-22 16:31:40 +0000663 "cannot create weak reference to '%s' object",
Fred Drake8844d522001-10-05 21:52:26 +0000664 ob->ob_type->tp_name);
665 return NULL;
666 }
667 list = GET_WEAKREFS_LISTPTR(ob);
668 get_basic_refs(*list, &ref, &proxy);
Fred Drake6a2852c2004-02-03 19:52:56 +0000669 if (callback == Py_None)
670 callback = NULL;
Fred Drake8844d522001-10-05 21:52:26 +0000671 if (callback == NULL)
672 /* attempt to return an existing weak reference if it exists */
673 result = proxy;
674 if (result != NULL)
675 Py_XINCREF(result);
676 else {
Neil Schemenauer38a89162002-03-27 15:18:21 +0000677 result = new_weakref(ob, callback);
Fred Drake8844d522001-10-05 21:52:26 +0000678 if (result != NULL) {
679 PyWeakReference *prev;
680
681 if (PyCallable_Check(ob))
682 result->ob_type = &_PyWeakref_CallableProxyType;
683 else
684 result->ob_type = &_PyWeakref_ProxyType;
Fred Drake8844d522001-10-05 21:52:26 +0000685 if (callback == NULL)
686 prev = ref;
687 else
688 prev = (proxy == NULL) ? ref : proxy;
689
690 if (prev == NULL)
691 insert_head(result, list);
692 else
693 insert_after(result, prev);
Fred Drake8844d522001-10-05 21:52:26 +0000694 }
695 }
696 return (PyObject *) result;
697}
698
699
700PyObject *
701PyWeakref_GetObject(PyObject *ref)
702{
703 if (ref == NULL || !PyWeakref_Check(ref)) {
704 PyErr_BadInternalCall();
705 return NULL;
706 }
707 return PyWeakref_GET_OBJECT(ref);
708}
709
710
Fred Drakeef8ebd12001-12-10 23:44:54 +0000711static void
712handle_callback(PyWeakReference *ref, PyObject *callback)
713{
714 PyObject *cbresult = PyObject_CallFunction(callback, "O", ref);
715
716 if (cbresult == NULL)
717 PyErr_WriteUnraisable(callback);
718 else
719 Py_DECREF(cbresult);
720}
721
722/* This function is called by the tp_dealloc handler to clear weak references.
Fred Drake8844d522001-10-05 21:52:26 +0000723 *
724 * This iterates through the weak references for 'object' and calls callbacks
725 * for those references which have one. It returns when all callbacks have
726 * been attempted.
727 */
728void
729PyObject_ClearWeakRefs(PyObject *object)
730{
731 PyWeakReference **list;
732
733 if (object == NULL
734 || !PyType_SUPPORTS_WEAKREFS(object->ob_type)
735 || object->ob_refcnt != 0) {
736 PyErr_BadInternalCall();
737 return;
738 }
739 list = GET_WEAKREFS_LISTPTR(object);
740 /* Remove the callback-less basic and proxy references */
741 if (*list != NULL && (*list)->wr_callback == NULL) {
742 clear_weakref(*list);
743 if (*list != NULL && (*list)->wr_callback == NULL)
744 clear_weakref(*list);
745 }
746 if (*list != NULL) {
Fred Drakeef8ebd12001-12-10 23:44:54 +0000747 PyWeakReference *current = *list;
748 int count = _PyWeakref_GetWeakrefCount(current);
749 int restore_error = PyErr_Occurred() ? 1 : 0;
750 PyObject *err_type, *err_value, *err_tb;
Fred Drake8844d522001-10-05 21:52:26 +0000751
Fred Drakeef8ebd12001-12-10 23:44:54 +0000752 if (restore_error)
753 PyErr_Fetch(&err_type, &err_value, &err_tb);
Fred Drake8844d522001-10-05 21:52:26 +0000754 if (count == 1) {
Fred Drake8844d522001-10-05 21:52:26 +0000755 PyObject *callback = current->wr_callback;
Fred Drake8844d522001-10-05 21:52:26 +0000756
Fred Drakeef8ebd12001-12-10 23:44:54 +0000757 current->wr_callback = NULL;
Fred Drake8844d522001-10-05 21:52:26 +0000758 clear_weakref(current);
Fred Drakeef8ebd12001-12-10 23:44:54 +0000759 handle_callback(current, callback);
Fred Drake8844d522001-10-05 21:52:26 +0000760 Py_DECREF(callback);
761 }
762 else {
763 PyObject *tuple = PyTuple_New(count * 2);
Fred Drake8844d522001-10-05 21:52:26 +0000764 int i = 0;
765
766 for (i = 0; i < count; ++i) {
767 PyWeakReference *next = current->wr_next;
768
769 Py_INCREF(current);
770 PyTuple_SET_ITEM(tuple, i * 2, (PyObject *) current);
771 PyTuple_SET_ITEM(tuple, i * 2 + 1, current->wr_callback);
772 current->wr_callback = NULL;
Fred Drake8844d522001-10-05 21:52:26 +0000773 clear_weakref(current);
774 current = next;
775 }
776 for (i = 0; i < count; ++i) {
777 PyObject *current = PyTuple_GET_ITEM(tuple, i * 2);
778 PyObject *callback = PyTuple_GET_ITEM(tuple, i * 2 + 1);
Fred Drakeef8ebd12001-12-10 23:44:54 +0000779
780 handle_callback((PyWeakReference *)current, callback);
Fred Drake8844d522001-10-05 21:52:26 +0000781 }
782 Py_DECREF(tuple);
783 }
Fred Drakeef8ebd12001-12-10 23:44:54 +0000784 if (restore_error)
785 PyErr_Restore(err_type, err_value, err_tb);
Fred Drake8844d522001-10-05 21:52:26 +0000786 }
787}