blob: db1f8d190659f2230d7a0f41d6e61fdaafb74658 [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);
627 if (callback == NULL || callback == Py_None)
628 /* return existing weak reference if it exists */
629 result = ref;
630 if (result != NULL)
631 Py_XINCREF(result);
632 else {
Neil Schemenauer38a89162002-03-27 15:18:21 +0000633 result = new_weakref(ob, callback);
Fred Drake8844d522001-10-05 21:52:26 +0000634 if (result != NULL) {
Fred Drake8844d522001-10-05 21:52:26 +0000635 if (callback == NULL) {
636 insert_head(result, list);
637 }
638 else {
639 PyWeakReference *prev = (proxy == NULL) ? ref : proxy;
640
641 if (prev == NULL)
642 insert_head(result, list);
643 else
644 insert_after(result, prev);
645 }
Fred Drake8844d522001-10-05 21:52:26 +0000646 }
647 }
648 return (PyObject *) result;
649}
650
651
652PyObject *
653PyWeakref_NewProxy(PyObject *ob, PyObject *callback)
654{
655 PyWeakReference *result = NULL;
656 PyWeakReference **list;
657 PyWeakReference *ref, *proxy;
658
659 if (!PyType_SUPPORTS_WEAKREFS(ob->ob_type)) {
660 PyErr_Format(PyExc_TypeError,
Jeremy Hylton996fad32001-10-22 16:31:40 +0000661 "cannot create weak reference to '%s' object",
Fred Drake8844d522001-10-05 21:52:26 +0000662 ob->ob_type->tp_name);
663 return NULL;
664 }
665 list = GET_WEAKREFS_LISTPTR(ob);
666 get_basic_refs(*list, &ref, &proxy);
667 if (callback == NULL)
668 /* attempt to return an existing weak reference if it exists */
669 result = proxy;
670 if (result != NULL)
671 Py_XINCREF(result);
672 else {
Neil Schemenauer38a89162002-03-27 15:18:21 +0000673 result = new_weakref(ob, callback);
Fred Drake8844d522001-10-05 21:52:26 +0000674 if (result != NULL) {
675 PyWeakReference *prev;
676
677 if (PyCallable_Check(ob))
678 result->ob_type = &_PyWeakref_CallableProxyType;
679 else
680 result->ob_type = &_PyWeakref_ProxyType;
Fred Drake8844d522001-10-05 21:52:26 +0000681 if (callback == NULL)
682 prev = ref;
683 else
684 prev = (proxy == NULL) ? ref : proxy;
685
686 if (prev == NULL)
687 insert_head(result, list);
688 else
689 insert_after(result, prev);
Fred Drake8844d522001-10-05 21:52:26 +0000690 }
691 }
692 return (PyObject *) result;
693}
694
695
696PyObject *
697PyWeakref_GetObject(PyObject *ref)
698{
699 if (ref == NULL || !PyWeakref_Check(ref)) {
700 PyErr_BadInternalCall();
701 return NULL;
702 }
703 return PyWeakref_GET_OBJECT(ref);
704}
705
706
Fred Drakeef8ebd12001-12-10 23:44:54 +0000707static void
708handle_callback(PyWeakReference *ref, PyObject *callback)
709{
710 PyObject *cbresult = PyObject_CallFunction(callback, "O", ref);
711
712 if (cbresult == NULL)
713 PyErr_WriteUnraisable(callback);
714 else
715 Py_DECREF(cbresult);
716}
717
718/* This function is called by the tp_dealloc handler to clear weak references.
Fred Drake8844d522001-10-05 21:52:26 +0000719 *
720 * This iterates through the weak references for 'object' and calls callbacks
721 * for those references which have one. It returns when all callbacks have
722 * been attempted.
723 */
724void
725PyObject_ClearWeakRefs(PyObject *object)
726{
727 PyWeakReference **list;
728
729 if (object == NULL
730 || !PyType_SUPPORTS_WEAKREFS(object->ob_type)
731 || object->ob_refcnt != 0) {
732 PyErr_BadInternalCall();
733 return;
734 }
735 list = GET_WEAKREFS_LISTPTR(object);
736 /* Remove the callback-less basic and proxy references */
737 if (*list != NULL && (*list)->wr_callback == NULL) {
738 clear_weakref(*list);
739 if (*list != NULL && (*list)->wr_callback == NULL)
740 clear_weakref(*list);
741 }
742 if (*list != NULL) {
Fred Drakeef8ebd12001-12-10 23:44:54 +0000743 PyWeakReference *current = *list;
744 int count = _PyWeakref_GetWeakrefCount(current);
745 int restore_error = PyErr_Occurred() ? 1 : 0;
746 PyObject *err_type, *err_value, *err_tb;
Fred Drake8844d522001-10-05 21:52:26 +0000747
Fred Drakeef8ebd12001-12-10 23:44:54 +0000748 if (restore_error)
749 PyErr_Fetch(&err_type, &err_value, &err_tb);
Fred Drake8844d522001-10-05 21:52:26 +0000750 if (count == 1) {
Fred Drake8844d522001-10-05 21:52:26 +0000751 PyObject *callback = current->wr_callback;
Fred Drake8844d522001-10-05 21:52:26 +0000752
Fred Drakeef8ebd12001-12-10 23:44:54 +0000753 current->wr_callback = NULL;
Fred Drake8844d522001-10-05 21:52:26 +0000754 clear_weakref(current);
Fred Drakeef8ebd12001-12-10 23:44:54 +0000755 handle_callback(current, callback);
Fred Drake8844d522001-10-05 21:52:26 +0000756 Py_DECREF(callback);
757 }
758 else {
759 PyObject *tuple = PyTuple_New(count * 2);
Fred Drake8844d522001-10-05 21:52:26 +0000760 int i = 0;
761
762 for (i = 0; i < count; ++i) {
763 PyWeakReference *next = current->wr_next;
764
765 Py_INCREF(current);
766 PyTuple_SET_ITEM(tuple, i * 2, (PyObject *) current);
767 PyTuple_SET_ITEM(tuple, i * 2 + 1, current->wr_callback);
768 current->wr_callback = NULL;
Fred Drake8844d522001-10-05 21:52:26 +0000769 clear_weakref(current);
770 current = next;
771 }
772 for (i = 0; i < count; ++i) {
773 PyObject *current = PyTuple_GET_ITEM(tuple, i * 2);
774 PyObject *callback = PyTuple_GET_ITEM(tuple, i * 2 + 1);
Fred Drakeef8ebd12001-12-10 23:44:54 +0000775
776 handle_callback((PyWeakReference *)current, callback);
Fred Drake8844d522001-10-05 21:52:26 +0000777 }
778 Py_DECREF(tuple);
779 }
Fred Drakeef8ebd12001-12-10 23:44:54 +0000780 if (restore_error)
781 PyErr_Restore(err_type, err_value, err_tb);
Fred Drake8844d522001-10-05 21:52:26 +0000782 }
783}