blob: 575a928f7528f2c538e12210b264e3315e2af957 [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)
Fred Drakebc875f52004-02-04 23:14:14 +0000633 Py_INCREF(result);
Fred Drake8844d522001-10-05 21:52:26 +0000634 else {
Fred Drakebc875f52004-02-04 23:14:14 +0000635 /* Note: new_weakref() can trigger cyclic GC, so the weakref
636 list on ob can be mutated. This means that the ref and
637 proxy pointers we got back earlier may have been collected,
638 so we need to compute these values again before we use
639 them. */
Neil Schemenauer38a89162002-03-27 15:18:21 +0000640 result = new_weakref(ob, callback);
Fred Drake8844d522001-10-05 21:52:26 +0000641 if (result != NULL) {
Fred Drake8844d522001-10-05 21:52:26 +0000642 if (callback == NULL) {
643 insert_head(result, list);
644 }
645 else {
Fred Drakebc875f52004-02-04 23:14:14 +0000646 PyWeakReference *prev;
Fred Drake8844d522001-10-05 21:52:26 +0000647
Fred Drakebc875f52004-02-04 23:14:14 +0000648 get_basic_refs(*list, &ref, &proxy);
649 prev = (proxy == NULL) ? ref : proxy;
Fred Drake8844d522001-10-05 21:52:26 +0000650 if (prev == NULL)
651 insert_head(result, list);
652 else
653 insert_after(result, prev);
654 }
Fred Drake8844d522001-10-05 21:52:26 +0000655 }
656 }
657 return (PyObject *) result;
658}
659
660
661PyObject *
662PyWeakref_NewProxy(PyObject *ob, PyObject *callback)
663{
664 PyWeakReference *result = NULL;
665 PyWeakReference **list;
666 PyWeakReference *ref, *proxy;
667
668 if (!PyType_SUPPORTS_WEAKREFS(ob->ob_type)) {
669 PyErr_Format(PyExc_TypeError,
Jeremy Hylton996fad32001-10-22 16:31:40 +0000670 "cannot create weak reference to '%s' object",
Fred Drake8844d522001-10-05 21:52:26 +0000671 ob->ob_type->tp_name);
672 return NULL;
673 }
674 list = GET_WEAKREFS_LISTPTR(ob);
675 get_basic_refs(*list, &ref, &proxy);
Fred Drake6a2852c2004-02-03 19:52:56 +0000676 if (callback == Py_None)
677 callback = NULL;
Fred Drake8844d522001-10-05 21:52:26 +0000678 if (callback == NULL)
679 /* attempt to return an existing weak reference if it exists */
680 result = proxy;
681 if (result != NULL)
Fred Drakebc875f52004-02-04 23:14:14 +0000682 Py_INCREF(result);
Fred Drake8844d522001-10-05 21:52:26 +0000683 else {
Fred Drakebc875f52004-02-04 23:14:14 +0000684 /* Note: new_weakref() can trigger cyclic GC, so the weakref
685 list on ob can be mutated. This means that the ref and
686 proxy pointers we got back earlier may have been collected,
687 so we need to compute these values again before we use
688 them. */
Neil Schemenauer38a89162002-03-27 15:18:21 +0000689 result = new_weakref(ob, callback);
Fred Drake8844d522001-10-05 21:52:26 +0000690 if (result != NULL) {
691 PyWeakReference *prev;
692
693 if (PyCallable_Check(ob))
694 result->ob_type = &_PyWeakref_CallableProxyType;
695 else
696 result->ob_type = &_PyWeakref_ProxyType;
Fred Drakebc875f52004-02-04 23:14:14 +0000697 get_basic_refs(*list, &ref, &proxy);
Fred Drake8844d522001-10-05 21:52:26 +0000698 if (callback == NULL)
699 prev = ref;
700 else
701 prev = (proxy == NULL) ? ref : proxy;
702
703 if (prev == NULL)
704 insert_head(result, list);
705 else
706 insert_after(result, prev);
Fred Drake8844d522001-10-05 21:52:26 +0000707 }
708 }
709 return (PyObject *) result;
710}
711
712
713PyObject *
714PyWeakref_GetObject(PyObject *ref)
715{
716 if (ref == NULL || !PyWeakref_Check(ref)) {
717 PyErr_BadInternalCall();
718 return NULL;
719 }
720 return PyWeakref_GET_OBJECT(ref);
721}
722
723
Fred Drakeef8ebd12001-12-10 23:44:54 +0000724static void
725handle_callback(PyWeakReference *ref, PyObject *callback)
726{
727 PyObject *cbresult = PyObject_CallFunction(callback, "O", ref);
728
729 if (cbresult == NULL)
730 PyErr_WriteUnraisable(callback);
731 else
732 Py_DECREF(cbresult);
733}
734
735/* This function is called by the tp_dealloc handler to clear weak references.
Fred Drake8844d522001-10-05 21:52:26 +0000736 *
737 * This iterates through the weak references for 'object' and calls callbacks
738 * for those references which have one. It returns when all callbacks have
739 * been attempted.
740 */
741void
742PyObject_ClearWeakRefs(PyObject *object)
743{
744 PyWeakReference **list;
745
746 if (object == NULL
747 || !PyType_SUPPORTS_WEAKREFS(object->ob_type)
748 || object->ob_refcnt != 0) {
749 PyErr_BadInternalCall();
750 return;
751 }
752 list = GET_WEAKREFS_LISTPTR(object);
753 /* Remove the callback-less basic and proxy references */
754 if (*list != NULL && (*list)->wr_callback == NULL) {
755 clear_weakref(*list);
756 if (*list != NULL && (*list)->wr_callback == NULL)
757 clear_weakref(*list);
758 }
759 if (*list != NULL) {
Fred Drakeef8ebd12001-12-10 23:44:54 +0000760 PyWeakReference *current = *list;
761 int count = _PyWeakref_GetWeakrefCount(current);
762 int restore_error = PyErr_Occurred() ? 1 : 0;
763 PyObject *err_type, *err_value, *err_tb;
Fred Drake8844d522001-10-05 21:52:26 +0000764
Fred Drakeef8ebd12001-12-10 23:44:54 +0000765 if (restore_error)
766 PyErr_Fetch(&err_type, &err_value, &err_tb);
Fred Drake8844d522001-10-05 21:52:26 +0000767 if (count == 1) {
Fred Drake8844d522001-10-05 21:52:26 +0000768 PyObject *callback = current->wr_callback;
Fred Drake8844d522001-10-05 21:52:26 +0000769
Fred Drakeef8ebd12001-12-10 23:44:54 +0000770 current->wr_callback = NULL;
Fred Drake8844d522001-10-05 21:52:26 +0000771 clear_weakref(current);
Fred Drakeef8ebd12001-12-10 23:44:54 +0000772 handle_callback(current, callback);
Fred Drake8844d522001-10-05 21:52:26 +0000773 Py_DECREF(callback);
774 }
775 else {
776 PyObject *tuple = PyTuple_New(count * 2);
Fred Drake8844d522001-10-05 21:52:26 +0000777 int i = 0;
778
779 for (i = 0; i < count; ++i) {
780 PyWeakReference *next = current->wr_next;
781
782 Py_INCREF(current);
783 PyTuple_SET_ITEM(tuple, i * 2, (PyObject *) current);
784 PyTuple_SET_ITEM(tuple, i * 2 + 1, current->wr_callback);
785 current->wr_callback = NULL;
Fred Drake8844d522001-10-05 21:52:26 +0000786 clear_weakref(current);
787 current = next;
788 }
789 for (i = 0; i < count; ++i) {
790 PyObject *current = PyTuple_GET_ITEM(tuple, i * 2);
791 PyObject *callback = PyTuple_GET_ITEM(tuple, i * 2 + 1);
Fred Drakeef8ebd12001-12-10 23:44:54 +0000792
793 handle_callback((PyWeakReference *)current, callback);
Fred Drake8844d522001-10-05 21:52:26 +0000794 }
795 Py_DECREF(tuple);
796 }
Fred Drakeef8ebd12001-12-10 23:44:54 +0000797 if (restore_error)
798 PyErr_Restore(err_type, err_value, err_tb);
Fred Drake8844d522001-10-05 21:52:26 +0000799 }
800}