blob: 7b5b56183c3fb219a0e773b5d5cc77b11aab2cdd [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
Thomas Wouters0e3f5912006-08-11 14:57:12 +00009Py_ssize_t
Fred Drake8844d522001-10-05 21:52:26 +000010_PyWeakref_GetWeakrefCount(PyWeakReference *head)
11{
Thomas Wouters0e3f5912006-08-11 14:57:12 +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)
Thomas Woutersb2137042007-02-01 18:02:27 +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 Wouters49fd7fa2006-04-21 10:40:58 +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{
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000190 if ((op != Py_EQ && op != Py_NE) ||
191 !PyWeakref_Check(self) ||
192 !PyWeakref_Check(other)) {
Fred Drake8844d522001-10-05 21:52:26 +0000193 Py_INCREF(Py_NotImplemented);
194 return Py_NotImplemented;
195 }
196 if (PyWeakref_GET_OBJECT(self) == Py_None
197 || PyWeakref_GET_OBJECT(other) == Py_None) {
198 PyObject *res = self==other ? Py_True : Py_False;
199 Py_INCREF(res);
200 return res;
201 }
202 return PyObject_RichCompare(PyWeakref_GET_OBJECT(self),
203 PyWeakref_GET_OBJECT(other), op);
204}
205
Fred Drake0a4dd392004-07-02 18:57:45 +0000206/* Given the head of an object's list of weak references, extract the
207 * two callback-less refs (ref and proxy). Used to determine if the
208 * shared references exist and to determine the back link for newly
209 * inserted references.
210 */
211static void
212get_basic_refs(PyWeakReference *head,
213 PyWeakReference **refp, PyWeakReference **proxyp)
214{
215 *refp = NULL;
216 *proxyp = NULL;
217
218 if (head != NULL && head->wr_callback == NULL) {
219 /* We need to be careful that the "basic refs" aren't
220 subclasses of the main types. That complicates this a
221 little. */
222 if (PyWeakref_CheckRefExact(head)) {
223 *refp = head;
224 head = head->wr_next;
225 }
226 if (head != NULL
227 && head->wr_callback == NULL
228 && PyWeakref_CheckProxy(head)) {
229 *proxyp = head;
230 /* head = head->wr_next; */
231 }
232 }
233}
234
235/* Insert 'newref' in the list after 'prev'. Both must be non-NULL. */
236static void
237insert_after(PyWeakReference *newref, PyWeakReference *prev)
238{
239 newref->wr_prev = prev;
240 newref->wr_next = prev->wr_next;
241 if (prev->wr_next != NULL)
242 prev->wr_next->wr_prev = newref;
243 prev->wr_next = newref;
244}
245
246/* Insert 'newref' at the head of the list; 'list' points to the variable
247 * that stores the head.
248 */
249static void
250insert_head(PyWeakReference *newref, PyWeakReference **list)
251{
252 PyWeakReference *next = *list;
253
254 newref->wr_prev = NULL;
255 newref->wr_next = next;
256 if (next != NULL)
257 next->wr_prev = newref;
258 *list = newref;
259}
260
261static int
262parse_weakref_init_args(char *funcname, PyObject *args, PyObject *kwargs,
263 PyObject **obp, PyObject **callbackp)
264{
265 /* XXX Should check that kwargs == NULL or is empty. */
266 return PyArg_UnpackTuple(args, funcname, 1, 2, obp, callbackp);
267}
268
269static PyObject *
270weakref___new__(PyTypeObject *type, PyObject *args, PyObject *kwargs)
271{
272 PyWeakReference *self = NULL;
273 PyObject *ob, *callback = NULL;
274
275 if (parse_weakref_init_args("__new__", args, kwargs, &ob, &callback)) {
276 PyWeakReference *ref, *proxy;
277 PyWeakReference **list;
278
279 if (!PyType_SUPPORTS_WEAKREFS(ob->ob_type)) {
280 PyErr_Format(PyExc_TypeError,
281 "cannot create weak reference to '%s' object",
282 ob->ob_type->tp_name);
283 return NULL;
284 }
285 if (callback == Py_None)
286 callback = NULL;
287 list = GET_WEAKREFS_LISTPTR(ob);
288 get_basic_refs(*list, &ref, &proxy);
289 if (callback == NULL && type == &_PyWeakref_RefType) {
290 if (ref != NULL) {
291 /* We can re-use an existing reference. */
292 Py_INCREF(ref);
293 return (PyObject *)ref;
294 }
295 }
296 /* We have to create a new reference. */
297 /* Note: the tp_alloc() can trigger cyclic GC, so the weakref
298 list on ob can be mutated. This means that the ref and
299 proxy pointers we got back earlier may have been collected,
300 so we need to compute these values again before we use
301 them. */
302 self = (PyWeakReference *) (type->tp_alloc(type, 0));
303 if (self != NULL) {
304 init_weakref(self, ob, callback);
305 if (callback == NULL && type == &_PyWeakref_RefType) {
306 insert_head(self, list);
307 }
308 else {
309 PyWeakReference *prev;
310
311 get_basic_refs(*list, &ref, &proxy);
312 prev = (proxy == NULL) ? ref : proxy;
313 if (prev == NULL)
314 insert_head(self, list);
315 else
316 insert_after(self, prev);
317 }
318 }
319 }
320 return (PyObject *)self;
321}
322
323static int
324weakref___init__(PyObject *self, PyObject *args, PyObject *kwargs)
325{
326 PyObject *tmp;
327
328 if (parse_weakref_init_args("__init__", args, kwargs, &tmp, &tmp))
329 return 0;
330 else
331 return 1;
332}
333
Fred Drake8844d522001-10-05 21:52:26 +0000334
335PyTypeObject
336_PyWeakref_RefType = {
337 PyObject_HEAD_INIT(&PyType_Type)
338 0,
339 "weakref",
340 sizeof(PyWeakReference),
341 0,
Fred Drake0a4dd392004-07-02 18:57:45 +0000342 weakref_dealloc, /*tp_dealloc*/
Fred Drake8844d522001-10-05 21:52:26 +0000343 0, /*tp_print*/
344 0, /*tp_getattr*/
345 0, /*tp_setattr*/
346 0, /*tp_compare*/
347 (reprfunc)weakref_repr, /*tp_repr*/
348 0, /*tp_as_number*/
349 0, /*tp_as_sequence*/
350 0, /*tp_as_mapping*/
Fred Drake0a4dd392004-07-02 18:57:45 +0000351 (hashfunc)weakref_hash, /*tp_hash*/
Fred Drake8844d522001-10-05 21:52:26 +0000352 (ternaryfunc)weakref_call, /*tp_call*/
353 0, /*tp_str*/
354 0, /*tp_getattro*/
355 0, /*tp_setattro*/
356 0, /*tp_as_buffer*/
Guido van Rossum3cf5b1e2006-07-27 21:53:35 +0000357 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC
Fred Drake0a4dd392004-07-02 18:57:45 +0000358 | Py_TPFLAGS_BASETYPE, /*tp_flags*/
Fred Drake8844d522001-10-05 21:52:26 +0000359 0, /*tp_doc*/
360 (traverseproc)gc_traverse, /*tp_traverse*/
361 (inquiry)gc_clear, /*tp_clear*/
362 (richcmpfunc)weakref_richcompare, /*tp_richcompare*/
Fred Drake0a4dd392004-07-02 18:57:45 +0000363 0, /*tp_weaklistoffset*/
364 0, /*tp_iter*/
365 0, /*tp_iternext*/
366 0, /*tp_methods*/
367 0, /*tp_members*/
368 0, /*tp_getset*/
369 0, /*tp_base*/
370 0, /*tp_dict*/
371 0, /*tp_descr_get*/
372 0, /*tp_descr_set*/
373 0, /*tp_dictoffset*/
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000374 weakref___init__, /*tp_init*/
Fred Drake0a4dd392004-07-02 18:57:45 +0000375 PyType_GenericAlloc, /*tp_alloc*/
376 weakref___new__, /*tp_new*/
377 PyObject_GC_Del, /*tp_free*/
Fred Drake8844d522001-10-05 21:52:26 +0000378};
379
380
381static int
382proxy_checkref(PyWeakReference *proxy)
383{
384 if (PyWeakref_GET_OBJECT(proxy) == Py_None) {
385 PyErr_SetString(PyExc_ReferenceError,
386 "weakly-referenced object no longer exists");
387 return 0;
388 }
389 return 1;
390}
391
392
Fred Drake73006d02001-10-18 18:04:18 +0000393/* If a parameter is a proxy, check that it is still "live" and wrap it,
394 * replacing the original value with the raw object. Raises ReferenceError
395 * if the param is a dead proxy.
396 */
397#define UNWRAP(o) \
398 if (PyWeakref_CheckProxy(o)) { \
399 if (!proxy_checkref((PyWeakReference *)o)) \
400 return NULL; \
401 o = PyWeakref_GET_OBJECT(o); \
402 }
403
Fred Drake2a908f62001-12-19 16:44:30 +0000404#define UNWRAP_I(o) \
405 if (PyWeakref_CheckProxy(o)) { \
406 if (!proxy_checkref((PyWeakReference *)o)) \
407 return -1; \
408 o = PyWeakref_GET_OBJECT(o); \
409 }
410
Fred Drake8844d522001-10-05 21:52:26 +0000411#define WRAP_UNARY(method, generic) \
412 static PyObject * \
Fred Drake73006d02001-10-18 18:04:18 +0000413 method(PyObject *proxy) { \
414 UNWRAP(proxy); \
415 return generic(proxy); \
Fred Drake8844d522001-10-05 21:52:26 +0000416 }
417
418#define WRAP_BINARY(method, generic) \
419 static PyObject * \
Fred Drake73006d02001-10-18 18:04:18 +0000420 method(PyObject *x, PyObject *y) { \
421 UNWRAP(x); \
422 UNWRAP(y); \
423 return generic(x, y); \
Fred Drake8844d522001-10-05 21:52:26 +0000424 }
425
Fred Drake31f4d1f2001-10-18 19:21:46 +0000426/* Note that the third arg needs to be checked for NULL since the tp_call
427 * slot can receive NULL for this arg.
Fred Drake73006d02001-10-18 18:04:18 +0000428 */
Fred Drake8844d522001-10-05 21:52:26 +0000429#define WRAP_TERNARY(method, generic) \
430 static PyObject * \
Fred Drake73006d02001-10-18 18:04:18 +0000431 method(PyObject *proxy, PyObject *v, PyObject *w) { \
432 UNWRAP(proxy); \
Fred Drake31f4d1f2001-10-18 19:21:46 +0000433 UNWRAP(v); \
Fred Drake73006d02001-10-18 18:04:18 +0000434 if (w != NULL) \
435 UNWRAP(w); \
436 return generic(proxy, v, w); \
Fred Drake8844d522001-10-05 21:52:26 +0000437 }
438
439
440/* direct slots */
441
442WRAP_BINARY(proxy_getattr, PyObject_GetAttr)
443WRAP_UNARY(proxy_str, PyObject_Str)
444WRAP_TERNARY(proxy_call, PyEval_CallObjectWithKeywords)
445
Fred Drake8844d522001-10-05 21:52:26 +0000446static PyObject *
447proxy_repr(PyWeakReference *proxy)
448{
449 char buf[160];
Barry Warsawd5867562001-11-28 21:01:56 +0000450 PyOS_snprintf(buf, sizeof(buf),
Guido van Rossumc1f6e8c2003-04-16 21:13:23 +0000451 "<weakproxy at %p to %.100s at %p>", proxy,
Barry Warsawd5867562001-11-28 21:01:56 +0000452 PyWeakref_GET_OBJECT(proxy)->ob_type->tp_name,
453 PyWeakref_GET_OBJECT(proxy));
Fred Drake8844d522001-10-05 21:52:26 +0000454 return PyString_FromString(buf);
455}
456
457
458static int
459proxy_setattr(PyWeakReference *proxy, PyObject *name, PyObject *value)
460{
461 if (!proxy_checkref(proxy))
462 return -1;
463 return PyObject_SetAttr(PyWeakref_GET_OBJECT(proxy), name, value);
464}
465
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000466static PyObject *
467proxy_richcompare(PyObject *proxy, PyObject *v, int op)
Fred Drake8844d522001-10-05 21:52:26 +0000468{
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000469 UNWRAP(proxy);
470 UNWRAP(v);
471 return PyObject_RichCompare(proxy, v, op);
Fred Drake8844d522001-10-05 21:52:26 +0000472}
473
474/* number slots */
475WRAP_BINARY(proxy_add, PyNumber_Add)
476WRAP_BINARY(proxy_sub, PyNumber_Subtract)
477WRAP_BINARY(proxy_mul, PyNumber_Multiply)
Fred Drake8844d522001-10-05 21:52:26 +0000478WRAP_BINARY(proxy_mod, PyNumber_Remainder)
479WRAP_BINARY(proxy_divmod, PyNumber_Divmod)
480WRAP_TERNARY(proxy_pow, PyNumber_Power)
481WRAP_UNARY(proxy_neg, PyNumber_Negative)
482WRAP_UNARY(proxy_pos, PyNumber_Positive)
483WRAP_UNARY(proxy_abs, PyNumber_Absolute)
484WRAP_UNARY(proxy_invert, PyNumber_Invert)
485WRAP_BINARY(proxy_lshift, PyNumber_Lshift)
486WRAP_BINARY(proxy_rshift, PyNumber_Rshift)
487WRAP_BINARY(proxy_and, PyNumber_And)
488WRAP_BINARY(proxy_xor, PyNumber_Xor)
489WRAP_BINARY(proxy_or, PyNumber_Or)
490WRAP_UNARY(proxy_int, PyNumber_Int)
491WRAP_UNARY(proxy_long, PyNumber_Long)
492WRAP_UNARY(proxy_float, PyNumber_Float)
493WRAP_BINARY(proxy_iadd, PyNumber_InPlaceAdd)
494WRAP_BINARY(proxy_isub, PyNumber_InPlaceSubtract)
495WRAP_BINARY(proxy_imul, PyNumber_InPlaceMultiply)
Fred Drake8844d522001-10-05 21:52:26 +0000496WRAP_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
Jack Diederich4dafcc42006-11-28 19:15:13 +0000505proxy_bool(PyWeakReference *proxy)
Fred Drake8844d522001-10-05 21:52:26 +0000506{
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 = {
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000593 proxy_add, /*nb_add*/
594 proxy_sub, /*nb_subtract*/
595 proxy_mul, /*nb_multiply*/
596 proxy_mod, /*nb_remainder*/
597 proxy_divmod, /*nb_divmod*/
598 proxy_pow, /*nb_power*/
599 proxy_neg, /*nb_negative*/
600 proxy_pos, /*nb_positive*/
601 proxy_abs, /*nb_absolute*/
Jack Diederich4dafcc42006-11-28 19:15:13 +0000602 (inquiry)proxy_bool, /*nb_bool*/
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000603 proxy_invert, /*nb_invert*/
604 proxy_lshift, /*nb_lshift*/
605 proxy_rshift, /*nb_rshift*/
606 proxy_and, /*nb_and*/
607 proxy_xor, /*nb_xor*/
608 proxy_or, /*nb_or*/
609 0, /*nb_coerce*/
610 proxy_int, /*nb_int*/
611 proxy_long, /*nb_long*/
612 proxy_float, /*nb_float*/
613 0, /*nb_oct*/
614 0, /*nb_hex*/
615 proxy_iadd, /*nb_inplace_add*/
616 proxy_isub, /*nb_inplace_subtract*/
617 proxy_imul, /*nb_inplace_multiply*/
618 proxy_imod, /*nb_inplace_remainder*/
619 proxy_ipow, /*nb_inplace_power*/
620 proxy_ilshift, /*nb_inplace_lshift*/
621 proxy_irshift, /*nb_inplace_rshift*/
622 proxy_iand, /*nb_inplace_and*/
623 proxy_ixor, /*nb_inplace_xor*/
624 proxy_ior, /*nb_inplace_or*/
Fred Drake8844d522001-10-05 21:52:26 +0000625};
626
627static PySequenceMethods proxy_as_sequence = {
Martin v. Löwis18e16552006-02-15 17:27:45 +0000628 (lenfunc)proxy_length, /*sq_length*/
Fred Drake8844d522001-10-05 21:52:26 +0000629 0, /*sq_concat*/
630 0, /*sq_repeat*/
631 0, /*sq_item*/
Martin v. Löwis18e16552006-02-15 17:27:45 +0000632 (ssizessizeargfunc)proxy_slice, /*sq_slice*/
Fred Drake8844d522001-10-05 21:52:26 +0000633 0, /*sq_ass_item*/
Martin v. Löwis18e16552006-02-15 17:27:45 +0000634 (ssizessizeobjargproc)proxy_ass_slice, /*sq_ass_slice*/
Fred Drake8844d522001-10-05 21:52:26 +0000635 (objobjproc)proxy_contains, /* sq_contains */
636};
637
638static PyMappingMethods proxy_as_mapping = {
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000639 (lenfunc)proxy_length, /*mp_length*/
640 proxy_getitem, /*mp_subscript*/
Fred Drake8844d522001-10-05 21:52:26 +0000641 (objobjargproc)proxy_setitem, /*mp_ass_subscript*/
642};
643
644
645PyTypeObject
646_PyWeakref_ProxyType = {
647 PyObject_HEAD_INIT(&PyType_Type)
648 0,
649 "weakproxy",
650 sizeof(PyWeakReference),
651 0,
652 /* methods */
Fred Drake0a4dd392004-07-02 18:57:45 +0000653 (destructor)proxy_dealloc, /* tp_dealloc */
Fred Drakefe89cc12003-07-14 21:46:23 +0000654 0, /* tp_print */
Fred Drakef16c3dc2002-08-09 18:34:16 +0000655 0, /* tp_getattr */
656 0, /* tp_setattr */
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000657 0, /* tp_compare */
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000658 (reprfunc)proxy_repr, /* tp_repr */
Fred Drakef16c3dc2002-08-09 18:34:16 +0000659 &proxy_as_number, /* tp_as_number */
660 &proxy_as_sequence, /* tp_as_sequence */
661 &proxy_as_mapping, /* tp_as_mapping */
662 0, /* tp_hash */
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000663 0, /* tp_call */
664 proxy_str, /* tp_str */
665 proxy_getattr, /* tp_getattro */
Fred Drakef16c3dc2002-08-09 18:34:16 +0000666 (setattrofunc)proxy_setattr, /* tp_setattro */
667 0, /* tp_as_buffer */
Guido van Rossum3cf5b1e2006-07-27 21:53:35 +0000668 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
Fred Drakef16c3dc2002-08-09 18:34:16 +0000669 0, /* tp_doc */
670 (traverseproc)gc_traverse, /* tp_traverse */
671 (inquiry)gc_clear, /* tp_clear */
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000672 proxy_richcompare, /* tp_richcompare */
Fred Drakef16c3dc2002-08-09 18:34:16 +0000673 0, /* tp_weaklistoffset */
674 (getiterfunc)proxy_iter, /* tp_iter */
675 (iternextfunc)proxy_iternext, /* tp_iternext */
Fred Drake8844d522001-10-05 21:52:26 +0000676};
677
678
679PyTypeObject
680_PyWeakref_CallableProxyType = {
681 PyObject_HEAD_INIT(&PyType_Type)
682 0,
683 "weakcallableproxy",
684 sizeof(PyWeakReference),
685 0,
686 /* methods */
Fred Drake0a4dd392004-07-02 18:57:45 +0000687 (destructor)proxy_dealloc, /* tp_dealloc */
Fred Drakefe89cc12003-07-14 21:46:23 +0000688 0, /* tp_print */
Fred Drakef16c3dc2002-08-09 18:34:16 +0000689 0, /* tp_getattr */
690 0, /* tp_setattr */
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000691 0, /* tp_compare */
Fred Drakef16c3dc2002-08-09 18:34:16 +0000692 (unaryfunc)proxy_repr, /* tp_repr */
693 &proxy_as_number, /* tp_as_number */
694 &proxy_as_sequence, /* tp_as_sequence */
695 &proxy_as_mapping, /* tp_as_mapping */
696 0, /* tp_hash */
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000697 proxy_call, /* tp_call */
698 proxy_str, /* tp_str */
699 proxy_getattr, /* tp_getattro */
Fred Drakef16c3dc2002-08-09 18:34:16 +0000700 (setattrofunc)proxy_setattr, /* tp_setattro */
701 0, /* tp_as_buffer */
Guido van Rossum3cf5b1e2006-07-27 21:53:35 +0000702 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
Fred Drakef16c3dc2002-08-09 18:34:16 +0000703 0, /* tp_doc */
704 (traverseproc)gc_traverse, /* tp_traverse */
705 (inquiry)gc_clear, /* tp_clear */
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000706 proxy_richcompare, /* tp_richcompare */
Fred Drakef16c3dc2002-08-09 18:34:16 +0000707 0, /* tp_weaklistoffset */
708 (getiterfunc)proxy_iter, /* tp_iter */
709 (iternextfunc)proxy_iternext, /* tp_iternext */
Fred Drake8844d522001-10-05 21:52:26 +0000710};
711
712
Fred Drake8844d522001-10-05 21:52:26 +0000713
714PyObject *
715PyWeakref_NewRef(PyObject *ob, PyObject *callback)
716{
717 PyWeakReference *result = NULL;
718 PyWeakReference **list;
719 PyWeakReference *ref, *proxy;
720
721 if (!PyType_SUPPORTS_WEAKREFS(ob->ob_type)) {
722 PyErr_Format(PyExc_TypeError,
Jeremy Hylton996fad32001-10-22 16:31:40 +0000723 "cannot create weak reference to '%s' object",
Fred Drake8844d522001-10-05 21:52:26 +0000724 ob->ob_type->tp_name);
725 return NULL;
726 }
727 list = GET_WEAKREFS_LISTPTR(ob);
728 get_basic_refs(*list, &ref, &proxy);
Fred Drake6a2852c2004-02-03 19:52:56 +0000729 if (callback == Py_None)
730 callback = NULL;
731 if (callback == NULL)
Fred Drake8844d522001-10-05 21:52:26 +0000732 /* return existing weak reference if it exists */
733 result = ref;
734 if (result != NULL)
Fred Drakebc875f52004-02-04 23:14:14 +0000735 Py_INCREF(result);
Fred Drake8844d522001-10-05 21:52:26 +0000736 else {
Fred Drakebc875f52004-02-04 23:14:14 +0000737 /* Note: new_weakref() can trigger cyclic GC, so the weakref
738 list on ob can be mutated. This means that the ref and
739 proxy pointers we got back earlier may have been collected,
740 so we need to compute these values again before we use
741 them. */
Neil Schemenauer38a89162002-03-27 15:18:21 +0000742 result = new_weakref(ob, callback);
Fred Drake8844d522001-10-05 21:52:26 +0000743 if (result != NULL) {
Fred Drake6d3265d2004-08-03 14:47:25 +0000744 get_basic_refs(*list, &ref, &proxy);
Fred Drake8844d522001-10-05 21:52:26 +0000745 if (callback == NULL) {
Fred Drake6d3265d2004-08-03 14:47:25 +0000746 if (ref == NULL)
747 insert_head(result, list);
748 else {
749 /* Someone else added a ref without a callback
750 during GC. Return that one instead of this one
751 to avoid violating the invariants of the list
752 of weakrefs for ob. */
753 Py_DECREF(result);
754 Py_INCREF(ref);
755 result = ref;
756 }
Fred Drake8844d522001-10-05 21:52:26 +0000757 }
758 else {
Fred Drakebc875f52004-02-04 23:14:14 +0000759 PyWeakReference *prev;
Fred Drake8844d522001-10-05 21:52:26 +0000760
Fred Drakebc875f52004-02-04 23:14:14 +0000761 prev = (proxy == NULL) ? ref : proxy;
Fred Drake8844d522001-10-05 21:52:26 +0000762 if (prev == NULL)
763 insert_head(result, list);
764 else
765 insert_after(result, prev);
766 }
Fred Drake8844d522001-10-05 21:52:26 +0000767 }
768 }
769 return (PyObject *) result;
770}
771
772
773PyObject *
774PyWeakref_NewProxy(PyObject *ob, PyObject *callback)
775{
776 PyWeakReference *result = NULL;
777 PyWeakReference **list;
778 PyWeakReference *ref, *proxy;
779
780 if (!PyType_SUPPORTS_WEAKREFS(ob->ob_type)) {
781 PyErr_Format(PyExc_TypeError,
Jeremy Hylton996fad32001-10-22 16:31:40 +0000782 "cannot create weak reference to '%s' object",
Fred Drake8844d522001-10-05 21:52:26 +0000783 ob->ob_type->tp_name);
784 return NULL;
785 }
786 list = GET_WEAKREFS_LISTPTR(ob);
787 get_basic_refs(*list, &ref, &proxy);
Fred Drake6a2852c2004-02-03 19:52:56 +0000788 if (callback == Py_None)
789 callback = NULL;
Fred Drake8844d522001-10-05 21:52:26 +0000790 if (callback == NULL)
791 /* attempt to return an existing weak reference if it exists */
792 result = proxy;
793 if (result != NULL)
Fred Drakebc875f52004-02-04 23:14:14 +0000794 Py_INCREF(result);
Fred Drake8844d522001-10-05 21:52:26 +0000795 else {
Fred Drakebc875f52004-02-04 23:14:14 +0000796 /* Note: new_weakref() can trigger cyclic GC, so the weakref
797 list on ob can be mutated. This means that the ref and
798 proxy pointers we got back earlier may have been collected,
799 so we need to compute these values again before we use
800 them. */
Neil Schemenauer38a89162002-03-27 15:18:21 +0000801 result = new_weakref(ob, callback);
Fred Drake8844d522001-10-05 21:52:26 +0000802 if (result != NULL) {
803 PyWeakReference *prev;
804
805 if (PyCallable_Check(ob))
806 result->ob_type = &_PyWeakref_CallableProxyType;
807 else
808 result->ob_type = &_PyWeakref_ProxyType;
Fred Drakebc875f52004-02-04 23:14:14 +0000809 get_basic_refs(*list, &ref, &proxy);
Fred Drake6d3265d2004-08-03 14:47:25 +0000810 if (callback == NULL) {
811 if (proxy != NULL) {
812 /* Someone else added a proxy without a callback
813 during GC. Return that one instead of this one
814 to avoid violating the invariants of the list
815 of weakrefs for ob. */
816 Py_DECREF(result);
817 Py_INCREF(result = proxy);
818 goto skip_insert;
819 }
Fred Drake8844d522001-10-05 21:52:26 +0000820 prev = ref;
Fred Drake6d3265d2004-08-03 14:47:25 +0000821 }
Fred Drake8844d522001-10-05 21:52:26 +0000822 else
823 prev = (proxy == NULL) ? ref : proxy;
824
825 if (prev == NULL)
826 insert_head(result, list);
827 else
828 insert_after(result, prev);
Fred Drake6d3265d2004-08-03 14:47:25 +0000829 skip_insert:
830 ;
Fred Drake8844d522001-10-05 21:52:26 +0000831 }
832 }
833 return (PyObject *) result;
834}
835
836
837PyObject *
838PyWeakref_GetObject(PyObject *ref)
839{
840 if (ref == NULL || !PyWeakref_Check(ref)) {
841 PyErr_BadInternalCall();
842 return NULL;
843 }
844 return PyWeakref_GET_OBJECT(ref);
845}
846
Tim Petersead8b7a2004-10-30 23:09:22 +0000847/* Note that there's an inlined copy-paste of handle_callback() in gcmodule.c's
848 * handle_weakrefs().
849 */
Fred Drakeef8ebd12001-12-10 23:44:54 +0000850static void
851handle_callback(PyWeakReference *ref, PyObject *callback)
852{
Thomas Wouters477c8d52006-05-27 19:21:47 +0000853 PyObject *cbresult = PyObject_CallFunctionObjArgs(callback, ref, NULL);
Fred Drakeef8ebd12001-12-10 23:44:54 +0000854
855 if (cbresult == NULL)
856 PyErr_WriteUnraisable(callback);
857 else
858 Py_DECREF(cbresult);
859}
860
861/* This function is called by the tp_dealloc handler to clear weak references.
Fred Drake8844d522001-10-05 21:52:26 +0000862 *
863 * This iterates through the weak references for 'object' and calls callbacks
864 * for those references which have one. It returns when all callbacks have
865 * been attempted.
866 */
867void
868PyObject_ClearWeakRefs(PyObject *object)
869{
870 PyWeakReference **list;
871
872 if (object == NULL
873 || !PyType_SUPPORTS_WEAKREFS(object->ob_type)
874 || object->ob_refcnt != 0) {
875 PyErr_BadInternalCall();
876 return;
877 }
878 list = GET_WEAKREFS_LISTPTR(object);
879 /* Remove the callback-less basic and proxy references */
880 if (*list != NULL && (*list)->wr_callback == NULL) {
881 clear_weakref(*list);
882 if (*list != NULL && (*list)->wr_callback == NULL)
883 clear_weakref(*list);
884 }
885 if (*list != NULL) {
Fred Drakeef8ebd12001-12-10 23:44:54 +0000886 PyWeakReference *current = *list;
Martin v. Löwis18e16552006-02-15 17:27:45 +0000887 Py_ssize_t count = _PyWeakref_GetWeakrefCount(current);
Fred Drakeef8ebd12001-12-10 23:44:54 +0000888 int restore_error = PyErr_Occurred() ? 1 : 0;
889 PyObject *err_type, *err_value, *err_tb;
Fred Drake8844d522001-10-05 21:52:26 +0000890
Fred Drakeef8ebd12001-12-10 23:44:54 +0000891 if (restore_error)
892 PyErr_Fetch(&err_type, &err_value, &err_tb);
Fred Drake8844d522001-10-05 21:52:26 +0000893 if (count == 1) {
Fred Drake8844d522001-10-05 21:52:26 +0000894 PyObject *callback = current->wr_callback;
Fred Drake8844d522001-10-05 21:52:26 +0000895
Fred Drakeef8ebd12001-12-10 23:44:54 +0000896 current->wr_callback = NULL;
Fred Drake8844d522001-10-05 21:52:26 +0000897 clear_weakref(current);
Fred Drake0a4dd392004-07-02 18:57:45 +0000898 if (callback != NULL) {
899 handle_callback(current, callback);
900 Py_DECREF(callback);
901 }
Fred Drake8844d522001-10-05 21:52:26 +0000902 }
903 else {
Hye-Shik Chang4af5c8c2006-03-07 15:39:21 +0000904 PyObject *tuple;
Martin v. Löwis18e16552006-02-15 17:27:45 +0000905 Py_ssize_t i = 0;
Hye-Shik Chang4af5c8c2006-03-07 15:39:21 +0000906
907 tuple = PyTuple_New(count * 2);
908 if (tuple == NULL) {
909 if (restore_error)
910 PyErr_Fetch(&err_type, &err_value, &err_tb);
911 return;
912 }
Fred Drake8844d522001-10-05 21:52:26 +0000913
914 for (i = 0; i < count; ++i) {
915 PyWeakReference *next = current->wr_next;
916
917 Py_INCREF(current);
918 PyTuple_SET_ITEM(tuple, i * 2, (PyObject *) current);
919 PyTuple_SET_ITEM(tuple, i * 2 + 1, current->wr_callback);
920 current->wr_callback = NULL;
Fred Drake8844d522001-10-05 21:52:26 +0000921 clear_weakref(current);
922 current = next;
923 }
924 for (i = 0; i < count; ++i) {
Fred Drake8844d522001-10-05 21:52:26 +0000925 PyObject *callback = PyTuple_GET_ITEM(tuple, i * 2 + 1);
Fred Drakeef8ebd12001-12-10 23:44:54 +0000926
Fred Drake0a4dd392004-07-02 18:57:45 +0000927 if (callback != NULL) {
Neal Norwitz0c6e2f12006-01-08 06:13:44 +0000928 PyObject *item = PyTuple_GET_ITEM(tuple, i * 2);
929 handle_callback((PyWeakReference *)item, callback);
Fred Drake0a4dd392004-07-02 18:57:45 +0000930 }
Fred Drake8844d522001-10-05 21:52:26 +0000931 }
932 Py_DECREF(tuple);
933 }
Fred Drakeef8ebd12001-12-10 23:44:54 +0000934 if (restore_error)
935 PyErr_Restore(err_type, err_value, err_tb);
Fred Drake8844d522001-10-05 21:52:26 +0000936 }
937}