blob: a404f29ade2b0bdeb00b4f3abaa32384806b3437 [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
Neal Norwitzc5e060d2006-08-02 06:14:22 +00009Py_ssize_t
Fred Drake8844d522001-10-05 21:52:26 +000010_PyWeakref_GetWeakrefCount(PyWeakReference *head)
11{
Neal Norwitzc5e060d2006-08-02 06:14:22 +000012 Py_ssize_t count = 0;
Fred Drake8844d522001-10-05 21:52:26 +000013
14 while (head != NULL) {
15 ++count;
16 head = head->wr_next;
17 }
18 return count;
19}
20
21
Fred Drake0a4dd392004-07-02 18:57:45 +000022static void
23init_weakref(PyWeakReference *self, PyObject *ob, PyObject *callback)
24{
25 self->hash = -1;
26 self->wr_object = ob;
27 Py_XINCREF(callback);
28 self->wr_callback = callback;
29}
30
Fred Drake8844d522001-10-05 21:52:26 +000031static PyWeakReference *
Neil Schemenauer38a89162002-03-27 15:18:21 +000032new_weakref(PyObject *ob, PyObject *callback)
Fred Drake8844d522001-10-05 21:52:26 +000033{
34 PyWeakReference *result;
35
Neil Schemenauer38a89162002-03-27 15:18:21 +000036 result = PyObject_GC_New(PyWeakReference, &_PyWeakref_RefType);
37 if (result) {
Fred Drake0a4dd392004-07-02 18:57:45 +000038 init_weakref(result, ob, callback);
Neil Schemenauer38a89162002-03-27 15:18:21 +000039 PyObject_GC_Track(result);
40 }
Fred Drake8844d522001-10-05 21:52:26 +000041 return result;
42}
43
44
45/* This function clears the passed-in reference and removes it from the
46 * list of weak references for the referent. This is the only code that
47 * removes an item from the doubly-linked list of weak references for an
48 * object; it is also responsible for clearing the callback slot.
49 */
50static void
51clear_weakref(PyWeakReference *self)
52{
53 PyObject *callback = self->wr_callback;
54
55 if (PyWeakref_GET_OBJECT(self) != Py_None) {
56 PyWeakReference **list = GET_WEAKREFS_LISTPTR(
57 PyWeakref_GET_OBJECT(self));
58
59 if (*list == self)
Brett Cannonf5bee302007-01-23 23:21:22 +000060 /* If 'self' is the end of the list (and thus self->wr_next == NULL)
61 then the weakref list itself (and thus the value of *list) will
62 end up being set to NULL. */
Fred Drake8844d522001-10-05 21:52:26 +000063 *list = self->wr_next;
64 self->wr_object = Py_None;
Fred Drake8844d522001-10-05 21:52:26 +000065 if (self->wr_prev != NULL)
66 self->wr_prev->wr_next = self->wr_next;
67 if (self->wr_next != NULL)
68 self->wr_next->wr_prev = self->wr_prev;
69 self->wr_prev = NULL;
70 self->wr_next = NULL;
Tim Peters403a2032003-11-20 21:21:46 +000071 }
72 if (callback != NULL) {
73 Py_DECREF(callback);
74 self->wr_callback = NULL;
Fred Drake8844d522001-10-05 21:52:26 +000075 }
76}
77
Tim Peters403a2032003-11-20 21:21:46 +000078/* Cyclic gc uses this to *just* clear the passed-in reference, leaving
79 * the callback intact and uncalled. It must be possible to call self's
80 * tp_dealloc() after calling this, so self has to be left in a sane enough
81 * state for that to work. We expect tp_dealloc to decref the callback
82 * then. The reason for not letting clear_weakref() decref the callback
83 * right now is that if the callback goes away, that may in turn trigger
84 * another callback (if a weak reference to the callback exists) -- running
85 * arbitrary Python code in the middle of gc is a disaster. The convolution
86 * here allows gc to delay triggering such callbacks until the world is in
87 * a sane state again.
88 */
89void
90_PyWeakref_ClearRef(PyWeakReference *self)
91{
92 PyObject *callback;
93
94 assert(self != NULL);
95 assert(PyWeakref_Check(self));
96 /* Preserve and restore the callback around clear_weakref. */
97 callback = self->wr_callback;
98 self->wr_callback = NULL;
99 clear_weakref(self);
100 self->wr_callback = callback;
101}
Fred Drake8844d522001-10-05 21:52:26 +0000102
103static void
Fred Drake0a4dd392004-07-02 18:57:45 +0000104weakref_dealloc(PyObject *self)
Fred Drake8844d522001-10-05 21:52:26 +0000105{
Fred Drake0a4dd392004-07-02 18:57:45 +0000106 PyObject_GC_UnTrack(self);
107 clear_weakref((PyWeakReference *) self);
108 self->ob_type->tp_free(self);
Fred Drake8844d522001-10-05 21:52:26 +0000109}
110
111
112static int
113gc_traverse(PyWeakReference *self, visitproc visit, void *arg)
114{
Thomas Woutersc6e55062006-04-15 21:47:09 +0000115 Py_VISIT(self->wr_callback);
Fred Drake8844d522001-10-05 21:52:26 +0000116 return 0;
117}
118
119
120static int
121gc_clear(PyWeakReference *self)
122{
123 clear_weakref(self);
124 return 0;
125}
126
127
128static PyObject *
129weakref_call(PyWeakReference *self, PyObject *args, PyObject *kw)
130{
Martin v. Löwis15e62742006-02-27 16:46:16 +0000131 static char *kwlist[] = {NULL};
Fred Drake8844d522001-10-05 21:52:26 +0000132
Martin v. Löwis15e62742006-02-27 16:46:16 +0000133 if (PyArg_ParseTupleAndKeywords(args, kw, ":__call__", kwlist)) {
Fred Drake8844d522001-10-05 21:52:26 +0000134 PyObject *object = PyWeakref_GET_OBJECT(self);
135 Py_INCREF(object);
136 return (object);
137 }
138 return NULL;
139}
140
141
142static long
143weakref_hash(PyWeakReference *self)
144{
145 if (self->hash != -1)
146 return self->hash;
147 if (PyWeakref_GET_OBJECT(self) == Py_None) {
148 PyErr_SetString(PyExc_TypeError, "weak object has gone away");
149 return -1;
150 }
151 self->hash = PyObject_Hash(PyWeakref_GET_OBJECT(self));
152 return self->hash;
153}
Tim Peters403a2032003-11-20 21:21:46 +0000154
Fred Drake8844d522001-10-05 21:52:26 +0000155
156static PyObject *
157weakref_repr(PyWeakReference *self)
158{
159 char buffer[256];
160 if (PyWeakref_GET_OBJECT(self) == Py_None) {
Guido van Rossumc1f6e8c2003-04-16 21:13:23 +0000161 PyOS_snprintf(buffer, sizeof(buffer), "<weakref at %p; dead>", self);
Fred Drake8844d522001-10-05 21:52:26 +0000162 }
163 else {
Guido van Rossumc1f6e8c2003-04-16 21:13:23 +0000164 char *name = NULL;
165 PyObject *nameobj = PyObject_GetAttrString(PyWeakref_GET_OBJECT(self),
166 "__name__");
167 if (nameobj == NULL)
168 PyErr_Clear();
169 else if (PyString_Check(nameobj))
170 name = PyString_AS_STRING(nameobj);
Barry Warsawd5867562001-11-28 21:01:56 +0000171 PyOS_snprintf(buffer, sizeof(buffer),
Guido van Rossumc1f6e8c2003-04-16 21:13:23 +0000172 name ? "<weakref at %p; to '%.50s' at %p (%s)>"
173 : "<weakref at %p; to '%.50s' at %p>",
174 self,
Barry Warsawd5867562001-11-28 21:01:56 +0000175 PyWeakref_GET_OBJECT(self)->ob_type->tp_name,
Guido van Rossumc1f6e8c2003-04-16 21:13:23 +0000176 PyWeakref_GET_OBJECT(self),
177 name);
178 Py_XDECREF(nameobj);
Fred Drake8844d522001-10-05 21:52:26 +0000179 }
180 return PyString_FromString(buffer);
181}
182
183/* Weak references only support equality, not ordering. Two weak references
184 are equal if the underlying objects are equal. If the underlying object has
185 gone away, they are equal if they are identical. */
186
187static PyObject *
188weakref_richcompare(PyWeakReference* self, PyWeakReference* other, int op)
189{
190 if (op != Py_EQ || self->ob_type != other->ob_type) {
191 Py_INCREF(Py_NotImplemented);
192 return Py_NotImplemented;
193 }
194 if (PyWeakref_GET_OBJECT(self) == Py_None
195 || PyWeakref_GET_OBJECT(other) == Py_None) {
196 PyObject *res = self==other ? Py_True : Py_False;
197 Py_INCREF(res);
198 return res;
199 }
200 return PyObject_RichCompare(PyWeakref_GET_OBJECT(self),
201 PyWeakref_GET_OBJECT(other), op);
202}
203
Fred Drake0a4dd392004-07-02 18:57:45 +0000204/* Given the head of an object's list of weak references, extract the
205 * two callback-less refs (ref and proxy). Used to determine if the
206 * shared references exist and to determine the back link for newly
207 * inserted references.
208 */
209static void
210get_basic_refs(PyWeakReference *head,
211 PyWeakReference **refp, PyWeakReference **proxyp)
212{
213 *refp = NULL;
214 *proxyp = NULL;
215
216 if (head != NULL && head->wr_callback == NULL) {
217 /* We need to be careful that the "basic refs" aren't
218 subclasses of the main types. That complicates this a
219 little. */
220 if (PyWeakref_CheckRefExact(head)) {
221 *refp = head;
222 head = head->wr_next;
223 }
224 if (head != NULL
225 && head->wr_callback == NULL
226 && PyWeakref_CheckProxy(head)) {
227 *proxyp = head;
228 /* head = head->wr_next; */
229 }
230 }
231}
232
233/* Insert 'newref' in the list after 'prev'. Both must be non-NULL. */
234static void
235insert_after(PyWeakReference *newref, PyWeakReference *prev)
236{
237 newref->wr_prev = prev;
238 newref->wr_next = prev->wr_next;
239 if (prev->wr_next != NULL)
240 prev->wr_next->wr_prev = newref;
241 prev->wr_next = newref;
242}
243
244/* Insert 'newref' at the head of the list; 'list' points to the variable
245 * that stores the head.
246 */
247static void
248insert_head(PyWeakReference *newref, PyWeakReference **list)
249{
250 PyWeakReference *next = *list;
251
252 newref->wr_prev = NULL;
253 newref->wr_next = next;
254 if (next != NULL)
255 next->wr_prev = newref;
256 *list = newref;
257}
258
259static int
260parse_weakref_init_args(char *funcname, PyObject *args, PyObject *kwargs,
261 PyObject **obp, PyObject **callbackp)
262{
263 /* XXX Should check that kwargs == NULL or is empty. */
264 return PyArg_UnpackTuple(args, funcname, 1, 2, obp, callbackp);
265}
266
267static PyObject *
268weakref___new__(PyTypeObject *type, PyObject *args, PyObject *kwargs)
269{
270 PyWeakReference *self = NULL;
271 PyObject *ob, *callback = NULL;
272
273 if (parse_weakref_init_args("__new__", args, kwargs, &ob, &callback)) {
274 PyWeakReference *ref, *proxy;
275 PyWeakReference **list;
276
277 if (!PyType_SUPPORTS_WEAKREFS(ob->ob_type)) {
278 PyErr_Format(PyExc_TypeError,
279 "cannot create weak reference to '%s' object",
280 ob->ob_type->tp_name);
281 return NULL;
282 }
283 if (callback == Py_None)
284 callback = NULL;
285 list = GET_WEAKREFS_LISTPTR(ob);
286 get_basic_refs(*list, &ref, &proxy);
287 if (callback == NULL && type == &_PyWeakref_RefType) {
288 if (ref != NULL) {
289 /* We can re-use an existing reference. */
290 Py_INCREF(ref);
291 return (PyObject *)ref;
292 }
293 }
294 /* We have to create a new reference. */
295 /* Note: the tp_alloc() can trigger cyclic GC, so the weakref
296 list on ob can be mutated. This means that the ref and
297 proxy pointers we got back earlier may have been collected,
298 so we need to compute these values again before we use
299 them. */
300 self = (PyWeakReference *) (type->tp_alloc(type, 0));
301 if (self != NULL) {
302 init_weakref(self, ob, callback);
303 if (callback == NULL && type == &_PyWeakref_RefType) {
304 insert_head(self, list);
305 }
306 else {
307 PyWeakReference *prev;
308
309 get_basic_refs(*list, &ref, &proxy);
310 prev = (proxy == NULL) ? ref : proxy;
311 if (prev == NULL)
312 insert_head(self, list);
313 else
314 insert_after(self, prev);
315 }
316 }
317 }
318 return (PyObject *)self;
319}
320
321static int
322weakref___init__(PyObject *self, PyObject *args, PyObject *kwargs)
323{
324 PyObject *tmp;
325
326 if (parse_weakref_init_args("__init__", args, kwargs, &tmp, &tmp))
327 return 0;
328 else
329 return 1;
330}
331
Fred Drake8844d522001-10-05 21:52:26 +0000332
333PyTypeObject
334_PyWeakref_RefType = {
335 PyObject_HEAD_INIT(&PyType_Type)
336 0,
337 "weakref",
338 sizeof(PyWeakReference),
339 0,
Fred Drake0a4dd392004-07-02 18:57:45 +0000340 weakref_dealloc, /*tp_dealloc*/
Fred Drake8844d522001-10-05 21:52:26 +0000341 0, /*tp_print*/
342 0, /*tp_getattr*/
343 0, /*tp_setattr*/
344 0, /*tp_compare*/
345 (reprfunc)weakref_repr, /*tp_repr*/
346 0, /*tp_as_number*/
347 0, /*tp_as_sequence*/
348 0, /*tp_as_mapping*/
Fred Drake0a4dd392004-07-02 18:57:45 +0000349 (hashfunc)weakref_hash, /*tp_hash*/
Fred Drake8844d522001-10-05 21:52:26 +0000350 (ternaryfunc)weakref_call, /*tp_call*/
351 0, /*tp_str*/
352 0, /*tp_getattro*/
353 0, /*tp_setattro*/
354 0, /*tp_as_buffer*/
Fred Drake0a4dd392004-07-02 18:57:45 +0000355 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_RICHCOMPARE
356 | Py_TPFLAGS_BASETYPE, /*tp_flags*/
Fred Drake8844d522001-10-05 21:52:26 +0000357 0, /*tp_doc*/
358 (traverseproc)gc_traverse, /*tp_traverse*/
359 (inquiry)gc_clear, /*tp_clear*/
360 (richcmpfunc)weakref_richcompare, /*tp_richcompare*/
Fred Drake0a4dd392004-07-02 18:57:45 +0000361 0, /*tp_weaklistoffset*/
362 0, /*tp_iter*/
363 0, /*tp_iternext*/
364 0, /*tp_methods*/
365 0, /*tp_members*/
366 0, /*tp_getset*/
367 0, /*tp_base*/
368 0, /*tp_dict*/
369 0, /*tp_descr_get*/
370 0, /*tp_descr_set*/
371 0, /*tp_dictoffset*/
Georg Brandl347b3002006-03-30 11:57:00 +0000372 weakref___init__, /*tp_init*/
Fred Drake0a4dd392004-07-02 18:57:45 +0000373 PyType_GenericAlloc, /*tp_alloc*/
374 weakref___new__, /*tp_new*/
375 PyObject_GC_Del, /*tp_free*/
Fred Drake8844d522001-10-05 21:52:26 +0000376};
377
378
379static int
380proxy_checkref(PyWeakReference *proxy)
381{
382 if (PyWeakref_GET_OBJECT(proxy) == Py_None) {
383 PyErr_SetString(PyExc_ReferenceError,
384 "weakly-referenced object no longer exists");
385 return 0;
386 }
387 return 1;
388}
389
390
Fred Drake73006d02001-10-18 18:04:18 +0000391/* If a parameter is a proxy, check that it is still "live" and wrap it,
392 * replacing the original value with the raw object. Raises ReferenceError
393 * if the param is a dead proxy.
394 */
395#define UNWRAP(o) \
396 if (PyWeakref_CheckProxy(o)) { \
397 if (!proxy_checkref((PyWeakReference *)o)) \
398 return NULL; \
399 o = PyWeakref_GET_OBJECT(o); \
400 }
401
Fred Drake2a908f62001-12-19 16:44:30 +0000402#define UNWRAP_I(o) \
403 if (PyWeakref_CheckProxy(o)) { \
404 if (!proxy_checkref((PyWeakReference *)o)) \
405 return -1; \
406 o = PyWeakref_GET_OBJECT(o); \
407 }
408
Fred Drake8844d522001-10-05 21:52:26 +0000409#define WRAP_UNARY(method, generic) \
410 static PyObject * \
Fred Drake73006d02001-10-18 18:04:18 +0000411 method(PyObject *proxy) { \
412 UNWRAP(proxy); \
413 return generic(proxy); \
Fred Drake8844d522001-10-05 21:52:26 +0000414 }
415
416#define WRAP_BINARY(method, generic) \
417 static PyObject * \
Fred Drake73006d02001-10-18 18:04:18 +0000418 method(PyObject *x, PyObject *y) { \
419 UNWRAP(x); \
420 UNWRAP(y); \
421 return generic(x, y); \
Fred Drake8844d522001-10-05 21:52:26 +0000422 }
423
Fred Drake31f4d1f2001-10-18 19:21:46 +0000424/* Note that the third arg needs to be checked for NULL since the tp_call
425 * slot can receive NULL for this arg.
Fred Drake73006d02001-10-18 18:04:18 +0000426 */
Fred Drake8844d522001-10-05 21:52:26 +0000427#define WRAP_TERNARY(method, generic) \
428 static PyObject * \
Fred Drake73006d02001-10-18 18:04:18 +0000429 method(PyObject *proxy, PyObject *v, PyObject *w) { \
430 UNWRAP(proxy); \
Fred Drake31f4d1f2001-10-18 19:21:46 +0000431 UNWRAP(v); \
Fred Drake73006d02001-10-18 18:04:18 +0000432 if (w != NULL) \
433 UNWRAP(w); \
434 return generic(proxy, v, w); \
Fred Drake8844d522001-10-05 21:52:26 +0000435 }
436
437
438/* direct slots */
439
440WRAP_BINARY(proxy_getattr, PyObject_GetAttr)
441WRAP_UNARY(proxy_str, PyObject_Str)
442WRAP_TERNARY(proxy_call, PyEval_CallObjectWithKeywords)
443
Fred Drake8844d522001-10-05 21:52:26 +0000444static PyObject *
445proxy_repr(PyWeakReference *proxy)
446{
447 char buf[160];
Barry Warsawd5867562001-11-28 21:01:56 +0000448 PyOS_snprintf(buf, sizeof(buf),
Guido van Rossumc1f6e8c2003-04-16 21:13:23 +0000449 "<weakproxy at %p to %.100s at %p>", proxy,
Barry Warsawd5867562001-11-28 21:01:56 +0000450 PyWeakref_GET_OBJECT(proxy)->ob_type->tp_name,
451 PyWeakref_GET_OBJECT(proxy));
Fred Drake8844d522001-10-05 21:52:26 +0000452 return PyString_FromString(buf);
453}
454
455
456static int
457proxy_setattr(PyWeakReference *proxy, PyObject *name, PyObject *value)
458{
459 if (!proxy_checkref(proxy))
460 return -1;
461 return PyObject_SetAttr(PyWeakref_GET_OBJECT(proxy), name, value);
462}
463
464static int
Fred Drake2a908f62001-12-19 16:44:30 +0000465proxy_compare(PyObject *proxy, PyObject *v)
Fred Drake8844d522001-10-05 21:52:26 +0000466{
Fred Drake2a908f62001-12-19 16:44:30 +0000467 UNWRAP_I(proxy);
468 UNWRAP_I(v);
469 return PyObject_Compare(proxy, v);
Fred Drake8844d522001-10-05 21:52:26 +0000470}
471
472/* number slots */
473WRAP_BINARY(proxy_add, PyNumber_Add)
474WRAP_BINARY(proxy_sub, PyNumber_Subtract)
475WRAP_BINARY(proxy_mul, PyNumber_Multiply)
476WRAP_BINARY(proxy_div, PyNumber_Divide)
477WRAP_BINARY(proxy_mod, PyNumber_Remainder)
478WRAP_BINARY(proxy_divmod, PyNumber_Divmod)
479WRAP_TERNARY(proxy_pow, PyNumber_Power)
480WRAP_UNARY(proxy_neg, PyNumber_Negative)
481WRAP_UNARY(proxy_pos, PyNumber_Positive)
482WRAP_UNARY(proxy_abs, PyNumber_Absolute)
483WRAP_UNARY(proxy_invert, PyNumber_Invert)
484WRAP_BINARY(proxy_lshift, PyNumber_Lshift)
485WRAP_BINARY(proxy_rshift, PyNumber_Rshift)
486WRAP_BINARY(proxy_and, PyNumber_And)
487WRAP_BINARY(proxy_xor, PyNumber_Xor)
488WRAP_BINARY(proxy_or, PyNumber_Or)
489WRAP_UNARY(proxy_int, PyNumber_Int)
490WRAP_UNARY(proxy_long, PyNumber_Long)
491WRAP_UNARY(proxy_float, PyNumber_Float)
492WRAP_BINARY(proxy_iadd, PyNumber_InPlaceAdd)
493WRAP_BINARY(proxy_isub, PyNumber_InPlaceSubtract)
494WRAP_BINARY(proxy_imul, PyNumber_InPlaceMultiply)
495WRAP_BINARY(proxy_idiv, PyNumber_InPlaceDivide)
496WRAP_BINARY(proxy_imod, PyNumber_InPlaceRemainder)
497WRAP_TERNARY(proxy_ipow, PyNumber_InPlacePower)
498WRAP_BINARY(proxy_ilshift, PyNumber_InPlaceLshift)
499WRAP_BINARY(proxy_irshift, PyNumber_InPlaceRshift)
500WRAP_BINARY(proxy_iand, PyNumber_InPlaceAnd)
501WRAP_BINARY(proxy_ixor, PyNumber_InPlaceXor)
502WRAP_BINARY(proxy_ior, PyNumber_InPlaceOr)
503
Tim Peters403a2032003-11-20 21:21:46 +0000504static int
Fred Drake8844d522001-10-05 21:52:26 +0000505proxy_nonzero(PyWeakReference *proxy)
506{
507 PyObject *o = PyWeakref_GET_OBJECT(proxy);
508 if (!proxy_checkref(proxy))
Neal Norwitzbdcb9412004-07-08 01:22:31 +0000509 return -1;
Raymond Hettingere6c470f2005-03-27 03:04:54 +0000510 return PyObject_IsTrue(o);
Fred Drake8844d522001-10-05 21:52:26 +0000511}
512
Fred Drake0a4dd392004-07-02 18:57:45 +0000513static void
514proxy_dealloc(PyWeakReference *self)
515{
516 if (self->wr_callback != NULL)
517 PyObject_GC_UnTrack((PyObject *)self);
518 clear_weakref(self);
519 PyObject_GC_Del(self);
520}
521
Fred Drake8844d522001-10-05 21:52:26 +0000522/* sequence slots */
523
524static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000525proxy_slice(PyWeakReference *proxy, Py_ssize_t i, Py_ssize_t j)
Fred Drake8844d522001-10-05 21:52:26 +0000526{
527 if (!proxy_checkref(proxy))
528 return NULL;
529 return PySequence_GetSlice(PyWeakref_GET_OBJECT(proxy), i, j);
530}
531
532static int
Martin v. Löwis18e16552006-02-15 17:27:45 +0000533proxy_ass_slice(PyWeakReference *proxy, Py_ssize_t i, Py_ssize_t j, PyObject *value)
Fred Drake8844d522001-10-05 21:52:26 +0000534{
535 if (!proxy_checkref(proxy))
536 return -1;
537 return PySequence_SetSlice(PyWeakref_GET_OBJECT(proxy), i, j, value);
538}
539
540static int
541proxy_contains(PyWeakReference *proxy, PyObject *value)
542{
543 if (!proxy_checkref(proxy))
544 return -1;
545 return PySequence_Contains(PyWeakref_GET_OBJECT(proxy), value);
546}
547
548
549/* mapping slots */
550
Martin v. Löwis18e16552006-02-15 17:27:45 +0000551static Py_ssize_t
Fred Drake8844d522001-10-05 21:52:26 +0000552proxy_length(PyWeakReference *proxy)
553{
554 if (!proxy_checkref(proxy))
555 return -1;
556 return PyObject_Length(PyWeakref_GET_OBJECT(proxy));
557}
558
559WRAP_BINARY(proxy_getitem, PyObject_GetItem)
560
561static int
562proxy_setitem(PyWeakReference *proxy, PyObject *key, PyObject *value)
563{
564 if (!proxy_checkref(proxy))
565 return -1;
Raymond Hettingerd693a812003-06-30 04:18:48 +0000566
567 if (value == NULL)
568 return PyObject_DelItem(PyWeakref_GET_OBJECT(proxy), key);
569 else
570 return PyObject_SetItem(PyWeakref_GET_OBJECT(proxy), key, value);
Fred Drake8844d522001-10-05 21:52:26 +0000571}
572
Fred Drakef16c3dc2002-08-09 18:34:16 +0000573/* iterator slots */
574
575static PyObject *
576proxy_iter(PyWeakReference *proxy)
577{
578 if (!proxy_checkref(proxy))
579 return NULL;
580 return PyObject_GetIter(PyWeakref_GET_OBJECT(proxy));
581}
582
583static PyObject *
584proxy_iternext(PyWeakReference *proxy)
585{
586 if (!proxy_checkref(proxy))
587 return NULL;
588 return PyIter_Next(PyWeakref_GET_OBJECT(proxy));
589}
590
Fred Drake8844d522001-10-05 21:52:26 +0000591
592static PyNumberMethods proxy_as_number = {
Georg Brandl347b3002006-03-30 11:57:00 +0000593 proxy_add, /*nb_add*/
594 proxy_sub, /*nb_subtract*/
595 proxy_mul, /*nb_multiply*/
596 proxy_div, /*nb_divide*/
597 proxy_mod, /*nb_remainder*/
598 proxy_divmod, /*nb_divmod*/
599 proxy_pow, /*nb_power*/
600 proxy_neg, /*nb_negative*/
601 proxy_pos, /*nb_positive*/
602 proxy_abs, /*nb_absolute*/
603 (inquiry)proxy_nonzero, /*nb_nonzero*/
604 proxy_invert, /*nb_invert*/
605 proxy_lshift, /*nb_lshift*/
606 proxy_rshift, /*nb_rshift*/
607 proxy_and, /*nb_and*/
608 proxy_xor, /*nb_xor*/
609 proxy_or, /*nb_or*/
610 0, /*nb_coerce*/
611 proxy_int, /*nb_int*/
612 proxy_long, /*nb_long*/
613 proxy_float, /*nb_float*/
614 0, /*nb_oct*/
615 0, /*nb_hex*/
616 proxy_iadd, /*nb_inplace_add*/
617 proxy_isub, /*nb_inplace_subtract*/
618 proxy_imul, /*nb_inplace_multiply*/
619 proxy_idiv, /*nb_inplace_divide*/
620 proxy_imod, /*nb_inplace_remainder*/
621 proxy_ipow, /*nb_inplace_power*/
622 proxy_ilshift, /*nb_inplace_lshift*/
623 proxy_irshift, /*nb_inplace_rshift*/
624 proxy_iand, /*nb_inplace_and*/
625 proxy_ixor, /*nb_inplace_xor*/
626 proxy_ior, /*nb_inplace_or*/
Fred Drake8844d522001-10-05 21:52:26 +0000627};
628
629static PySequenceMethods proxy_as_sequence = {
Martin v. Löwis18e16552006-02-15 17:27:45 +0000630 (lenfunc)proxy_length, /*sq_length*/
Fred Drake8844d522001-10-05 21:52:26 +0000631 0, /*sq_concat*/
632 0, /*sq_repeat*/
633 0, /*sq_item*/
Martin v. Löwis18e16552006-02-15 17:27:45 +0000634 (ssizessizeargfunc)proxy_slice, /*sq_slice*/
Fred Drake8844d522001-10-05 21:52:26 +0000635 0, /*sq_ass_item*/
Martin v. Löwis18e16552006-02-15 17:27:45 +0000636 (ssizessizeobjargproc)proxy_ass_slice, /*sq_ass_slice*/
Fred Drake8844d522001-10-05 21:52:26 +0000637 (objobjproc)proxy_contains, /* sq_contains */
638};
639
640static PyMappingMethods proxy_as_mapping = {
Georg Brandl347b3002006-03-30 11:57:00 +0000641 (lenfunc)proxy_length, /*mp_length*/
642 proxy_getitem, /*mp_subscript*/
Fred Drake8844d522001-10-05 21:52:26 +0000643 (objobjargproc)proxy_setitem, /*mp_ass_subscript*/
644};
645
646
647PyTypeObject
648_PyWeakref_ProxyType = {
649 PyObject_HEAD_INIT(&PyType_Type)
650 0,
651 "weakproxy",
652 sizeof(PyWeakReference),
653 0,
654 /* methods */
Fred Drake0a4dd392004-07-02 18:57:45 +0000655 (destructor)proxy_dealloc, /* tp_dealloc */
Fred Drakefe89cc12003-07-14 21:46:23 +0000656 0, /* tp_print */
Fred Drakef16c3dc2002-08-09 18:34:16 +0000657 0, /* tp_getattr */
658 0, /* tp_setattr */
659 proxy_compare, /* tp_compare */
Georg Brandl347b3002006-03-30 11:57:00 +0000660 (reprfunc)proxy_repr, /* tp_repr */
Fred Drakef16c3dc2002-08-09 18:34:16 +0000661 &proxy_as_number, /* tp_as_number */
662 &proxy_as_sequence, /* tp_as_sequence */
663 &proxy_as_mapping, /* tp_as_mapping */
664 0, /* tp_hash */
Georg Brandl347b3002006-03-30 11:57:00 +0000665 0, /* tp_call */
666 proxy_str, /* tp_str */
667 proxy_getattr, /* tp_getattro */
Fred Drakef16c3dc2002-08-09 18:34:16 +0000668 (setattrofunc)proxy_setattr, /* tp_setattro */
669 0, /* tp_as_buffer */
Fred Drake8844d522001-10-05 21:52:26 +0000670 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC
Fred Drakef16c3dc2002-08-09 18:34:16 +0000671 | Py_TPFLAGS_CHECKTYPES, /* tp_flags */
672 0, /* tp_doc */
673 (traverseproc)gc_traverse, /* tp_traverse */
674 (inquiry)gc_clear, /* tp_clear */
675 0, /* tp_richcompare */
676 0, /* tp_weaklistoffset */
677 (getiterfunc)proxy_iter, /* tp_iter */
678 (iternextfunc)proxy_iternext, /* tp_iternext */
Fred Drake8844d522001-10-05 21:52:26 +0000679};
680
681
682PyTypeObject
683_PyWeakref_CallableProxyType = {
684 PyObject_HEAD_INIT(&PyType_Type)
685 0,
686 "weakcallableproxy",
687 sizeof(PyWeakReference),
688 0,
689 /* methods */
Fred Drake0a4dd392004-07-02 18:57:45 +0000690 (destructor)proxy_dealloc, /* tp_dealloc */
Fred Drakefe89cc12003-07-14 21:46:23 +0000691 0, /* tp_print */
Fred Drakef16c3dc2002-08-09 18:34:16 +0000692 0, /* tp_getattr */
693 0, /* tp_setattr */
694 proxy_compare, /* tp_compare */
695 (unaryfunc)proxy_repr, /* tp_repr */
696 &proxy_as_number, /* tp_as_number */
697 &proxy_as_sequence, /* tp_as_sequence */
698 &proxy_as_mapping, /* tp_as_mapping */
699 0, /* tp_hash */
Georg Brandl347b3002006-03-30 11:57:00 +0000700 proxy_call, /* tp_call */
701 proxy_str, /* tp_str */
702 proxy_getattr, /* tp_getattro */
Fred Drakef16c3dc2002-08-09 18:34:16 +0000703 (setattrofunc)proxy_setattr, /* tp_setattro */
704 0, /* tp_as_buffer */
Fred Drake8844d522001-10-05 21:52:26 +0000705 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC
Fred Drakef16c3dc2002-08-09 18:34:16 +0000706 | Py_TPFLAGS_CHECKTYPES, /* tp_flags */
707 0, /* tp_doc */
708 (traverseproc)gc_traverse, /* tp_traverse */
709 (inquiry)gc_clear, /* tp_clear */
710 0, /* tp_richcompare */
711 0, /* tp_weaklistoffset */
712 (getiterfunc)proxy_iter, /* tp_iter */
713 (iternextfunc)proxy_iternext, /* tp_iternext */
Fred Drake8844d522001-10-05 21:52:26 +0000714};
715
716
Fred Drake8844d522001-10-05 21:52:26 +0000717
718PyObject *
719PyWeakref_NewRef(PyObject *ob, PyObject *callback)
720{
721 PyWeakReference *result = NULL;
722 PyWeakReference **list;
723 PyWeakReference *ref, *proxy;
724
725 if (!PyType_SUPPORTS_WEAKREFS(ob->ob_type)) {
726 PyErr_Format(PyExc_TypeError,
Jeremy Hylton996fad32001-10-22 16:31:40 +0000727 "cannot create weak reference to '%s' object",
Fred Drake8844d522001-10-05 21:52:26 +0000728 ob->ob_type->tp_name);
729 return NULL;
730 }
731 list = GET_WEAKREFS_LISTPTR(ob);
732 get_basic_refs(*list, &ref, &proxy);
Fred Drake6a2852c2004-02-03 19:52:56 +0000733 if (callback == Py_None)
734 callback = NULL;
735 if (callback == NULL)
Fred Drake8844d522001-10-05 21:52:26 +0000736 /* return existing weak reference if it exists */
737 result = ref;
738 if (result != NULL)
Fred Drakebc875f52004-02-04 23:14:14 +0000739 Py_INCREF(result);
Fred Drake8844d522001-10-05 21:52:26 +0000740 else {
Fred Drakebc875f52004-02-04 23:14:14 +0000741 /* Note: new_weakref() can trigger cyclic GC, so the weakref
742 list on ob can be mutated. This means that the ref and
743 proxy pointers we got back earlier may have been collected,
744 so we need to compute these values again before we use
745 them. */
Neil Schemenauer38a89162002-03-27 15:18:21 +0000746 result = new_weakref(ob, callback);
Fred Drake8844d522001-10-05 21:52:26 +0000747 if (result != NULL) {
Fred Drake6d3265d2004-08-03 14:47:25 +0000748 get_basic_refs(*list, &ref, &proxy);
Fred Drake8844d522001-10-05 21:52:26 +0000749 if (callback == NULL) {
Fred Drake6d3265d2004-08-03 14:47:25 +0000750 if (ref == NULL)
751 insert_head(result, list);
752 else {
753 /* Someone else added a ref without a callback
754 during GC. Return that one instead of this one
755 to avoid violating the invariants of the list
756 of weakrefs for ob. */
757 Py_DECREF(result);
758 Py_INCREF(ref);
759 result = ref;
760 }
Fred Drake8844d522001-10-05 21:52:26 +0000761 }
762 else {
Fred Drakebc875f52004-02-04 23:14:14 +0000763 PyWeakReference *prev;
Fred Drake8844d522001-10-05 21:52:26 +0000764
Fred Drakebc875f52004-02-04 23:14:14 +0000765 prev = (proxy == NULL) ? ref : proxy;
Fred Drake8844d522001-10-05 21:52:26 +0000766 if (prev == NULL)
767 insert_head(result, list);
768 else
769 insert_after(result, prev);
770 }
Fred Drake8844d522001-10-05 21:52:26 +0000771 }
772 }
773 return (PyObject *) result;
774}
775
776
777PyObject *
778PyWeakref_NewProxy(PyObject *ob, PyObject *callback)
779{
780 PyWeakReference *result = NULL;
781 PyWeakReference **list;
782 PyWeakReference *ref, *proxy;
783
784 if (!PyType_SUPPORTS_WEAKREFS(ob->ob_type)) {
785 PyErr_Format(PyExc_TypeError,
Jeremy Hylton996fad32001-10-22 16:31:40 +0000786 "cannot create weak reference to '%s' object",
Fred Drake8844d522001-10-05 21:52:26 +0000787 ob->ob_type->tp_name);
788 return NULL;
789 }
790 list = GET_WEAKREFS_LISTPTR(ob);
791 get_basic_refs(*list, &ref, &proxy);
Fred Drake6a2852c2004-02-03 19:52:56 +0000792 if (callback == Py_None)
793 callback = NULL;
Fred Drake8844d522001-10-05 21:52:26 +0000794 if (callback == NULL)
795 /* attempt to return an existing weak reference if it exists */
796 result = proxy;
797 if (result != NULL)
Fred Drakebc875f52004-02-04 23:14:14 +0000798 Py_INCREF(result);
Fred Drake8844d522001-10-05 21:52:26 +0000799 else {
Fred Drakebc875f52004-02-04 23:14:14 +0000800 /* Note: new_weakref() can trigger cyclic GC, so the weakref
801 list on ob can be mutated. This means that the ref and
802 proxy pointers we got back earlier may have been collected,
803 so we need to compute these values again before we use
804 them. */
Neil Schemenauer38a89162002-03-27 15:18:21 +0000805 result = new_weakref(ob, callback);
Fred Drake8844d522001-10-05 21:52:26 +0000806 if (result != NULL) {
807 PyWeakReference *prev;
808
809 if (PyCallable_Check(ob))
810 result->ob_type = &_PyWeakref_CallableProxyType;
811 else
812 result->ob_type = &_PyWeakref_ProxyType;
Fred Drakebc875f52004-02-04 23:14:14 +0000813 get_basic_refs(*list, &ref, &proxy);
Fred Drake6d3265d2004-08-03 14:47:25 +0000814 if (callback == NULL) {
815 if (proxy != NULL) {
816 /* Someone else added a proxy without a callback
817 during GC. Return that one instead of this one
818 to avoid violating the invariants of the list
819 of weakrefs for ob. */
820 Py_DECREF(result);
821 Py_INCREF(result = proxy);
822 goto skip_insert;
823 }
Fred Drake8844d522001-10-05 21:52:26 +0000824 prev = ref;
Fred Drake6d3265d2004-08-03 14:47:25 +0000825 }
Fred Drake8844d522001-10-05 21:52:26 +0000826 else
827 prev = (proxy == NULL) ? ref : proxy;
828
829 if (prev == NULL)
830 insert_head(result, list);
831 else
832 insert_after(result, prev);
Fred Drake6d3265d2004-08-03 14:47:25 +0000833 skip_insert:
834 ;
Fred Drake8844d522001-10-05 21:52:26 +0000835 }
836 }
837 return (PyObject *) result;
838}
839
840
841PyObject *
842PyWeakref_GetObject(PyObject *ref)
843{
844 if (ref == NULL || !PyWeakref_Check(ref)) {
845 PyErr_BadInternalCall();
846 return NULL;
847 }
848 return PyWeakref_GET_OBJECT(ref);
849}
850
Tim Petersead8b7a2004-10-30 23:09:22 +0000851/* Note that there's an inlined copy-paste of handle_callback() in gcmodule.c's
852 * handle_weakrefs().
853 */
Fred Drakeef8ebd12001-12-10 23:44:54 +0000854static void
855handle_callback(PyWeakReference *ref, PyObject *callback)
856{
Georg Brandl684fd0c2006-05-25 19:15:31 +0000857 PyObject *cbresult = PyObject_CallFunctionObjArgs(callback, ref, NULL);
Fred Drakeef8ebd12001-12-10 23:44:54 +0000858
859 if (cbresult == NULL)
860 PyErr_WriteUnraisable(callback);
861 else
862 Py_DECREF(cbresult);
863}
864
865/* This function is called by the tp_dealloc handler to clear weak references.
Fred Drake8844d522001-10-05 21:52:26 +0000866 *
867 * This iterates through the weak references for 'object' and calls callbacks
868 * for those references which have one. It returns when all callbacks have
869 * been attempted.
870 */
871void
872PyObject_ClearWeakRefs(PyObject *object)
873{
874 PyWeakReference **list;
875
876 if (object == NULL
877 || !PyType_SUPPORTS_WEAKREFS(object->ob_type)
878 || object->ob_refcnt != 0) {
879 PyErr_BadInternalCall();
880 return;
881 }
882 list = GET_WEAKREFS_LISTPTR(object);
883 /* Remove the callback-less basic and proxy references */
884 if (*list != NULL && (*list)->wr_callback == NULL) {
885 clear_weakref(*list);
886 if (*list != NULL && (*list)->wr_callback == NULL)
887 clear_weakref(*list);
888 }
889 if (*list != NULL) {
Fred Drakeef8ebd12001-12-10 23:44:54 +0000890 PyWeakReference *current = *list;
Martin v. Löwis18e16552006-02-15 17:27:45 +0000891 Py_ssize_t count = _PyWeakref_GetWeakrefCount(current);
Fred Drakeef8ebd12001-12-10 23:44:54 +0000892 int restore_error = PyErr_Occurred() ? 1 : 0;
893 PyObject *err_type, *err_value, *err_tb;
Fred Drake8844d522001-10-05 21:52:26 +0000894
Fred Drakeef8ebd12001-12-10 23:44:54 +0000895 if (restore_error)
896 PyErr_Fetch(&err_type, &err_value, &err_tb);
Fred Drake8844d522001-10-05 21:52:26 +0000897 if (count == 1) {
Fred Drake8844d522001-10-05 21:52:26 +0000898 PyObject *callback = current->wr_callback;
Fred Drake8844d522001-10-05 21:52:26 +0000899
Fred Drakeef8ebd12001-12-10 23:44:54 +0000900 current->wr_callback = NULL;
Fred Drake8844d522001-10-05 21:52:26 +0000901 clear_weakref(current);
Fred Drake0a4dd392004-07-02 18:57:45 +0000902 if (callback != NULL) {
903 handle_callback(current, callback);
904 Py_DECREF(callback);
905 }
Fred Drake8844d522001-10-05 21:52:26 +0000906 }
907 else {
Hye-Shik Chang4af5c8c2006-03-07 15:39:21 +0000908 PyObject *tuple;
Martin v. Löwis18e16552006-02-15 17:27:45 +0000909 Py_ssize_t i = 0;
Hye-Shik Chang4af5c8c2006-03-07 15:39:21 +0000910
911 tuple = PyTuple_New(count * 2);
912 if (tuple == NULL) {
913 if (restore_error)
914 PyErr_Fetch(&err_type, &err_value, &err_tb);
915 return;
916 }
Fred Drake8844d522001-10-05 21:52:26 +0000917
918 for (i = 0; i < count; ++i) {
919 PyWeakReference *next = current->wr_next;
920
921 Py_INCREF(current);
922 PyTuple_SET_ITEM(tuple, i * 2, (PyObject *) current);
923 PyTuple_SET_ITEM(tuple, i * 2 + 1, current->wr_callback);
924 current->wr_callback = NULL;
Fred Drake8844d522001-10-05 21:52:26 +0000925 clear_weakref(current);
926 current = next;
927 }
928 for (i = 0; i < count; ++i) {
Fred Drake8844d522001-10-05 21:52:26 +0000929 PyObject *callback = PyTuple_GET_ITEM(tuple, i * 2 + 1);
Fred Drakeef8ebd12001-12-10 23:44:54 +0000930
Fred Drake0a4dd392004-07-02 18:57:45 +0000931 if (callback != NULL) {
Neal Norwitz0c6e2f12006-01-08 06:13:44 +0000932 PyObject *item = PyTuple_GET_ITEM(tuple, i * 2);
933 handle_callback((PyWeakReference *)item, callback);
Fred Drake0a4dd392004-07-02 18:57:45 +0000934 }
Fred Drake8844d522001-10-05 21:52:26 +0000935 }
936 Py_DECREF(tuple);
937 }
Fred Drakeef8ebd12001-12-10 23:44:54 +0000938 if (restore_error)
939 PyErr_Restore(err_type, err_value, err_tb);
Fred Drake8844d522001-10-05 21:52:26 +0000940 }
941}