blob: d26d5d1180867578e48085734ce97b7f9b08003c [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);
Martin v. Löwis68192102007-07-21 06:55:02 +0000108 Py_Type(self)->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,
Martin v. Löwis68192102007-07-21 06:55:02 +0000175 Py_Type(PyWeakref_GET_OBJECT(self))->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
Martin v. Löwis68192102007-07-21 06:55:02 +0000277 if (!PyType_SUPPORTS_WEAKREFS(Py_Type(ob))) {
Fred Drake0a4dd392004-07-02 18:57:45 +0000278 PyErr_Format(PyExc_TypeError,
279 "cannot create weak reference to '%s' object",
Martin v. Löwis68192102007-07-21 06:55:02 +0000280 Py_Type(ob)->tp_name);
Fred Drake0a4dd392004-07-02 18:57:45 +0000281 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 = {
Martin v. Löwis68192102007-07-21 06:55:02 +0000335 PyVarObject_HEAD_INIT(&PyType_Type, 0)
Fred Drake8844d522001-10-05 21:52:26 +0000336 "weakref",
337 sizeof(PyWeakReference),
338 0,
Fred Drake0a4dd392004-07-02 18:57:45 +0000339 weakref_dealloc, /*tp_dealloc*/
Fred Drake8844d522001-10-05 21:52:26 +0000340 0, /*tp_print*/
341 0, /*tp_getattr*/
342 0, /*tp_setattr*/
343 0, /*tp_compare*/
344 (reprfunc)weakref_repr, /*tp_repr*/
345 0, /*tp_as_number*/
346 0, /*tp_as_sequence*/
347 0, /*tp_as_mapping*/
Fred Drake0a4dd392004-07-02 18:57:45 +0000348 (hashfunc)weakref_hash, /*tp_hash*/
Fred Drake8844d522001-10-05 21:52:26 +0000349 (ternaryfunc)weakref_call, /*tp_call*/
350 0, /*tp_str*/
351 0, /*tp_getattro*/
352 0, /*tp_setattro*/
353 0, /*tp_as_buffer*/
Fred Drake0a4dd392004-07-02 18:57:45 +0000354 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_RICHCOMPARE
355 | Py_TPFLAGS_BASETYPE, /*tp_flags*/
Fred Drake8844d522001-10-05 21:52:26 +0000356 0, /*tp_doc*/
357 (traverseproc)gc_traverse, /*tp_traverse*/
358 (inquiry)gc_clear, /*tp_clear*/
359 (richcmpfunc)weakref_richcompare, /*tp_richcompare*/
Fred Drake0a4dd392004-07-02 18:57:45 +0000360 0, /*tp_weaklistoffset*/
361 0, /*tp_iter*/
362 0, /*tp_iternext*/
363 0, /*tp_methods*/
364 0, /*tp_members*/
365 0, /*tp_getset*/
366 0, /*tp_base*/
367 0, /*tp_dict*/
368 0, /*tp_descr_get*/
369 0, /*tp_descr_set*/
370 0, /*tp_dictoffset*/
Georg Brandl347b3002006-03-30 11:57:00 +0000371 weakref___init__, /*tp_init*/
Fred Drake0a4dd392004-07-02 18:57:45 +0000372 PyType_GenericAlloc, /*tp_alloc*/
373 weakref___new__, /*tp_new*/
374 PyObject_GC_Del, /*tp_free*/
Fred Drake8844d522001-10-05 21:52:26 +0000375};
376
377
378static int
379proxy_checkref(PyWeakReference *proxy)
380{
381 if (PyWeakref_GET_OBJECT(proxy) == Py_None) {
382 PyErr_SetString(PyExc_ReferenceError,
383 "weakly-referenced object no longer exists");
384 return 0;
385 }
386 return 1;
387}
388
389
Fred Drake73006d02001-10-18 18:04:18 +0000390/* If a parameter is a proxy, check that it is still "live" and wrap it,
391 * replacing the original value with the raw object. Raises ReferenceError
392 * if the param is a dead proxy.
393 */
394#define UNWRAP(o) \
395 if (PyWeakref_CheckProxy(o)) { \
396 if (!proxy_checkref((PyWeakReference *)o)) \
397 return NULL; \
398 o = PyWeakref_GET_OBJECT(o); \
399 }
400
Fred Drake2a908f62001-12-19 16:44:30 +0000401#define UNWRAP_I(o) \
402 if (PyWeakref_CheckProxy(o)) { \
403 if (!proxy_checkref((PyWeakReference *)o)) \
404 return -1; \
405 o = PyWeakref_GET_OBJECT(o); \
406 }
407
Fred Drake8844d522001-10-05 21:52:26 +0000408#define WRAP_UNARY(method, generic) \
409 static PyObject * \
Fred Drake73006d02001-10-18 18:04:18 +0000410 method(PyObject *proxy) { \
411 UNWRAP(proxy); \
412 return generic(proxy); \
Fred Drake8844d522001-10-05 21:52:26 +0000413 }
414
415#define WRAP_BINARY(method, generic) \
416 static PyObject * \
Fred Drake73006d02001-10-18 18:04:18 +0000417 method(PyObject *x, PyObject *y) { \
418 UNWRAP(x); \
419 UNWRAP(y); \
420 return generic(x, y); \
Fred Drake8844d522001-10-05 21:52:26 +0000421 }
422
Fred Drake31f4d1f2001-10-18 19:21:46 +0000423/* Note that the third arg needs to be checked for NULL since the tp_call
424 * slot can receive NULL for this arg.
Fred Drake73006d02001-10-18 18:04:18 +0000425 */
Fred Drake8844d522001-10-05 21:52:26 +0000426#define WRAP_TERNARY(method, generic) \
427 static PyObject * \
Fred Drake73006d02001-10-18 18:04:18 +0000428 method(PyObject *proxy, PyObject *v, PyObject *w) { \
429 UNWRAP(proxy); \
Fred Drake31f4d1f2001-10-18 19:21:46 +0000430 UNWRAP(v); \
Fred Drake73006d02001-10-18 18:04:18 +0000431 if (w != NULL) \
432 UNWRAP(w); \
433 return generic(proxy, v, w); \
Fred Drake8844d522001-10-05 21:52:26 +0000434 }
435
436
437/* direct slots */
438
439WRAP_BINARY(proxy_getattr, PyObject_GetAttr)
440WRAP_UNARY(proxy_str, PyObject_Str)
441WRAP_TERNARY(proxy_call, PyEval_CallObjectWithKeywords)
442
Fred Drake8844d522001-10-05 21:52:26 +0000443static PyObject *
444proxy_repr(PyWeakReference *proxy)
445{
446 char buf[160];
Barry Warsawd5867562001-11-28 21:01:56 +0000447 PyOS_snprintf(buf, sizeof(buf),
Guido van Rossumc1f6e8c2003-04-16 21:13:23 +0000448 "<weakproxy at %p to %.100s at %p>", proxy,
Martin v. Löwis68192102007-07-21 06:55:02 +0000449 Py_Type(PyWeakref_GET_OBJECT(proxy))->tp_name,
Barry Warsawd5867562001-11-28 21:01:56 +0000450 PyWeakref_GET_OBJECT(proxy));
Fred Drake8844d522001-10-05 21:52:26 +0000451 return PyString_FromString(buf);
452}
453
454
455static int
456proxy_setattr(PyWeakReference *proxy, PyObject *name, PyObject *value)
457{
458 if (!proxy_checkref(proxy))
459 return -1;
460 return PyObject_SetAttr(PyWeakref_GET_OBJECT(proxy), name, value);
461}
462
463static int
Fred Drake2a908f62001-12-19 16:44:30 +0000464proxy_compare(PyObject *proxy, PyObject *v)
Fred Drake8844d522001-10-05 21:52:26 +0000465{
Fred Drake2a908f62001-12-19 16:44:30 +0000466 UNWRAP_I(proxy);
467 UNWRAP_I(v);
468 return PyObject_Compare(proxy, v);
Fred Drake8844d522001-10-05 21:52:26 +0000469}
470
471/* number slots */
472WRAP_BINARY(proxy_add, PyNumber_Add)
473WRAP_BINARY(proxy_sub, PyNumber_Subtract)
474WRAP_BINARY(proxy_mul, PyNumber_Multiply)
475WRAP_BINARY(proxy_div, PyNumber_Divide)
476WRAP_BINARY(proxy_mod, PyNumber_Remainder)
477WRAP_BINARY(proxy_divmod, PyNumber_Divmod)
478WRAP_TERNARY(proxy_pow, PyNumber_Power)
479WRAP_UNARY(proxy_neg, PyNumber_Negative)
480WRAP_UNARY(proxy_pos, PyNumber_Positive)
481WRAP_UNARY(proxy_abs, PyNumber_Absolute)
482WRAP_UNARY(proxy_invert, PyNumber_Invert)
483WRAP_BINARY(proxy_lshift, PyNumber_Lshift)
484WRAP_BINARY(proxy_rshift, PyNumber_Rshift)
485WRAP_BINARY(proxy_and, PyNumber_And)
486WRAP_BINARY(proxy_xor, PyNumber_Xor)
487WRAP_BINARY(proxy_or, PyNumber_Or)
488WRAP_UNARY(proxy_int, PyNumber_Int)
489WRAP_UNARY(proxy_long, PyNumber_Long)
490WRAP_UNARY(proxy_float, PyNumber_Float)
491WRAP_BINARY(proxy_iadd, PyNumber_InPlaceAdd)
492WRAP_BINARY(proxy_isub, PyNumber_InPlaceSubtract)
493WRAP_BINARY(proxy_imul, PyNumber_InPlaceMultiply)
494WRAP_BINARY(proxy_idiv, PyNumber_InPlaceDivide)
495WRAP_BINARY(proxy_imod, PyNumber_InPlaceRemainder)
496WRAP_TERNARY(proxy_ipow, PyNumber_InPlacePower)
497WRAP_BINARY(proxy_ilshift, PyNumber_InPlaceLshift)
498WRAP_BINARY(proxy_irshift, PyNumber_InPlaceRshift)
499WRAP_BINARY(proxy_iand, PyNumber_InPlaceAnd)
500WRAP_BINARY(proxy_ixor, PyNumber_InPlaceXor)
501WRAP_BINARY(proxy_ior, PyNumber_InPlaceOr)
502
Tim Peters403a2032003-11-20 21:21:46 +0000503static int
Fred Drake8844d522001-10-05 21:52:26 +0000504proxy_nonzero(PyWeakReference *proxy)
505{
506 PyObject *o = PyWeakref_GET_OBJECT(proxy);
507 if (!proxy_checkref(proxy))
Neal Norwitzbdcb9412004-07-08 01:22:31 +0000508 return -1;
Raymond Hettingere6c470f2005-03-27 03:04:54 +0000509 return PyObject_IsTrue(o);
Fred Drake8844d522001-10-05 21:52:26 +0000510}
511
Fred Drake0a4dd392004-07-02 18:57:45 +0000512static void
513proxy_dealloc(PyWeakReference *self)
514{
515 if (self->wr_callback != NULL)
516 PyObject_GC_UnTrack((PyObject *)self);
517 clear_weakref(self);
518 PyObject_GC_Del(self);
519}
520
Fred Drake8844d522001-10-05 21:52:26 +0000521/* sequence slots */
522
523static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000524proxy_slice(PyWeakReference *proxy, Py_ssize_t i, Py_ssize_t j)
Fred Drake8844d522001-10-05 21:52:26 +0000525{
526 if (!proxy_checkref(proxy))
527 return NULL;
528 return PySequence_GetSlice(PyWeakref_GET_OBJECT(proxy), i, j);
529}
530
531static int
Martin v. Löwis18e16552006-02-15 17:27:45 +0000532proxy_ass_slice(PyWeakReference *proxy, Py_ssize_t i, Py_ssize_t j, PyObject *value)
Fred Drake8844d522001-10-05 21:52:26 +0000533{
534 if (!proxy_checkref(proxy))
535 return -1;
536 return PySequence_SetSlice(PyWeakref_GET_OBJECT(proxy), i, j, value);
537}
538
539static int
540proxy_contains(PyWeakReference *proxy, PyObject *value)
541{
542 if (!proxy_checkref(proxy))
543 return -1;
544 return PySequence_Contains(PyWeakref_GET_OBJECT(proxy), value);
545}
546
547
548/* mapping slots */
549
Martin v. Löwis18e16552006-02-15 17:27:45 +0000550static Py_ssize_t
Fred Drake8844d522001-10-05 21:52:26 +0000551proxy_length(PyWeakReference *proxy)
552{
553 if (!proxy_checkref(proxy))
554 return -1;
555 return PyObject_Length(PyWeakref_GET_OBJECT(proxy));
556}
557
558WRAP_BINARY(proxy_getitem, PyObject_GetItem)
559
560static int
561proxy_setitem(PyWeakReference *proxy, PyObject *key, PyObject *value)
562{
563 if (!proxy_checkref(proxy))
564 return -1;
Raymond Hettingerd693a812003-06-30 04:18:48 +0000565
566 if (value == NULL)
567 return PyObject_DelItem(PyWeakref_GET_OBJECT(proxy), key);
568 else
569 return PyObject_SetItem(PyWeakref_GET_OBJECT(proxy), key, value);
Fred Drake8844d522001-10-05 21:52:26 +0000570}
571
Fred Drakef16c3dc2002-08-09 18:34:16 +0000572/* iterator slots */
573
574static PyObject *
575proxy_iter(PyWeakReference *proxy)
576{
577 if (!proxy_checkref(proxy))
578 return NULL;
579 return PyObject_GetIter(PyWeakref_GET_OBJECT(proxy));
580}
581
582static PyObject *
583proxy_iternext(PyWeakReference *proxy)
584{
585 if (!proxy_checkref(proxy))
586 return NULL;
587 return PyIter_Next(PyWeakref_GET_OBJECT(proxy));
588}
589
Fred Drake8844d522001-10-05 21:52:26 +0000590
591static PyNumberMethods proxy_as_number = {
Georg Brandl347b3002006-03-30 11:57:00 +0000592 proxy_add, /*nb_add*/
593 proxy_sub, /*nb_subtract*/
594 proxy_mul, /*nb_multiply*/
595 proxy_div, /*nb_divide*/
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*/
602 (inquiry)proxy_nonzero, /*nb_nonzero*/
603 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_idiv, /*nb_inplace_divide*/
619 proxy_imod, /*nb_inplace_remainder*/
620 proxy_ipow, /*nb_inplace_power*/
621 proxy_ilshift, /*nb_inplace_lshift*/
622 proxy_irshift, /*nb_inplace_rshift*/
623 proxy_iand, /*nb_inplace_and*/
624 proxy_ixor, /*nb_inplace_xor*/
625 proxy_ior, /*nb_inplace_or*/
Fred Drake8844d522001-10-05 21:52:26 +0000626};
627
628static PySequenceMethods proxy_as_sequence = {
Martin v. Löwis18e16552006-02-15 17:27:45 +0000629 (lenfunc)proxy_length, /*sq_length*/
Fred Drake8844d522001-10-05 21:52:26 +0000630 0, /*sq_concat*/
631 0, /*sq_repeat*/
632 0, /*sq_item*/
Martin v. Löwis18e16552006-02-15 17:27:45 +0000633 (ssizessizeargfunc)proxy_slice, /*sq_slice*/
Fred Drake8844d522001-10-05 21:52:26 +0000634 0, /*sq_ass_item*/
Martin v. Löwis18e16552006-02-15 17:27:45 +0000635 (ssizessizeobjargproc)proxy_ass_slice, /*sq_ass_slice*/
Fred Drake8844d522001-10-05 21:52:26 +0000636 (objobjproc)proxy_contains, /* sq_contains */
637};
638
639static PyMappingMethods proxy_as_mapping = {
Georg Brandl347b3002006-03-30 11:57:00 +0000640 (lenfunc)proxy_length, /*mp_length*/
641 proxy_getitem, /*mp_subscript*/
Fred Drake8844d522001-10-05 21:52:26 +0000642 (objobjargproc)proxy_setitem, /*mp_ass_subscript*/
643};
644
645
646PyTypeObject
647_PyWeakref_ProxyType = {
Martin v. Löwis68192102007-07-21 06:55:02 +0000648 PyVarObject_HEAD_INIT(&PyType_Type, 0)
Fred Drake8844d522001-10-05 21:52:26 +0000649 "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 */
657 proxy_compare, /* tp_compare */
Georg Brandl347b3002006-03-30 11:57:00 +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 */
Georg Brandl347b3002006-03-30 11:57:00 +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 */
Fred Drake8844d522001-10-05 21:52:26 +0000668 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC
Fred Drakef16c3dc2002-08-09 18:34:16 +0000669 | Py_TPFLAGS_CHECKTYPES, /* tp_flags */
670 0, /* tp_doc */
671 (traverseproc)gc_traverse, /* tp_traverse */
672 (inquiry)gc_clear, /* tp_clear */
673 0, /* tp_richcompare */
674 0, /* tp_weaklistoffset */
675 (getiterfunc)proxy_iter, /* tp_iter */
676 (iternextfunc)proxy_iternext, /* tp_iternext */
Fred Drake8844d522001-10-05 21:52:26 +0000677};
678
679
680PyTypeObject
681_PyWeakref_CallableProxyType = {
Martin v. Löwis68192102007-07-21 06:55:02 +0000682 PyVarObject_HEAD_INIT(&PyType_Type, 0)
Fred Drake8844d522001-10-05 21:52:26 +0000683 "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 */
691 proxy_compare, /* tp_compare */
692 (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 */
Georg Brandl347b3002006-03-30 11:57:00 +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 */
Fred Drake8844d522001-10-05 21:52:26 +0000702 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC
Fred Drakef16c3dc2002-08-09 18:34:16 +0000703 | Py_TPFLAGS_CHECKTYPES, /* tp_flags */
704 0, /* tp_doc */
705 (traverseproc)gc_traverse, /* tp_traverse */
706 (inquiry)gc_clear, /* tp_clear */
707 0, /* tp_richcompare */
708 0, /* tp_weaklistoffset */
709 (getiterfunc)proxy_iter, /* tp_iter */
710 (iternextfunc)proxy_iternext, /* tp_iternext */
Fred Drake8844d522001-10-05 21:52:26 +0000711};
712
713
Fred Drake8844d522001-10-05 21:52:26 +0000714
715PyObject *
716PyWeakref_NewRef(PyObject *ob, PyObject *callback)
717{
718 PyWeakReference *result = NULL;
719 PyWeakReference **list;
720 PyWeakReference *ref, *proxy;
721
Martin v. Löwis68192102007-07-21 06:55:02 +0000722 if (!PyType_SUPPORTS_WEAKREFS(Py_Type(ob))) {
Fred Drake8844d522001-10-05 21:52:26 +0000723 PyErr_Format(PyExc_TypeError,
Jeremy Hylton996fad32001-10-22 16:31:40 +0000724 "cannot create weak reference to '%s' object",
Martin v. Löwis68192102007-07-21 06:55:02 +0000725 Py_Type(ob)->tp_name);
Fred Drake8844d522001-10-05 21:52:26 +0000726 return NULL;
727 }
728 list = GET_WEAKREFS_LISTPTR(ob);
729 get_basic_refs(*list, &ref, &proxy);
Fred Drake6a2852c2004-02-03 19:52:56 +0000730 if (callback == Py_None)
731 callback = NULL;
732 if (callback == NULL)
Fred Drake8844d522001-10-05 21:52:26 +0000733 /* return existing weak reference if it exists */
734 result = ref;
735 if (result != NULL)
Fred Drakebc875f52004-02-04 23:14:14 +0000736 Py_INCREF(result);
Fred Drake8844d522001-10-05 21:52:26 +0000737 else {
Fred Drakebc875f52004-02-04 23:14:14 +0000738 /* Note: new_weakref() can trigger cyclic GC, so the weakref
739 list on ob can be mutated. This means that the ref and
740 proxy pointers we got back earlier may have been collected,
741 so we need to compute these values again before we use
742 them. */
Neil Schemenauer38a89162002-03-27 15:18:21 +0000743 result = new_weakref(ob, callback);
Fred Drake8844d522001-10-05 21:52:26 +0000744 if (result != NULL) {
Fred Drake6d3265d2004-08-03 14:47:25 +0000745 get_basic_refs(*list, &ref, &proxy);
Fred Drake8844d522001-10-05 21:52:26 +0000746 if (callback == NULL) {
Fred Drake6d3265d2004-08-03 14:47:25 +0000747 if (ref == NULL)
748 insert_head(result, list);
749 else {
750 /* Someone else added a ref without a callback
751 during GC. Return that one instead of this one
752 to avoid violating the invariants of the list
753 of weakrefs for ob. */
754 Py_DECREF(result);
755 Py_INCREF(ref);
756 result = ref;
757 }
Fred Drake8844d522001-10-05 21:52:26 +0000758 }
759 else {
Fred Drakebc875f52004-02-04 23:14:14 +0000760 PyWeakReference *prev;
Fred Drake8844d522001-10-05 21:52:26 +0000761
Fred Drakebc875f52004-02-04 23:14:14 +0000762 prev = (proxy == NULL) ? ref : proxy;
Fred Drake8844d522001-10-05 21:52:26 +0000763 if (prev == NULL)
764 insert_head(result, list);
765 else
766 insert_after(result, prev);
767 }
Fred Drake8844d522001-10-05 21:52:26 +0000768 }
769 }
770 return (PyObject *) result;
771}
772
773
774PyObject *
775PyWeakref_NewProxy(PyObject *ob, PyObject *callback)
776{
777 PyWeakReference *result = NULL;
778 PyWeakReference **list;
779 PyWeakReference *ref, *proxy;
780
Martin v. Löwis68192102007-07-21 06:55:02 +0000781 if (!PyType_SUPPORTS_WEAKREFS(Py_Type(ob))) {
Fred Drake8844d522001-10-05 21:52:26 +0000782 PyErr_Format(PyExc_TypeError,
Jeremy Hylton996fad32001-10-22 16:31:40 +0000783 "cannot create weak reference to '%s' object",
Martin v. Löwis68192102007-07-21 06:55:02 +0000784 Py_Type(ob)->tp_name);
Fred Drake8844d522001-10-05 21:52:26 +0000785 return NULL;
786 }
787 list = GET_WEAKREFS_LISTPTR(ob);
788 get_basic_refs(*list, &ref, &proxy);
Fred Drake6a2852c2004-02-03 19:52:56 +0000789 if (callback == Py_None)
790 callback = NULL;
Fred Drake8844d522001-10-05 21:52:26 +0000791 if (callback == NULL)
792 /* attempt to return an existing weak reference if it exists */
793 result = proxy;
794 if (result != NULL)
Fred Drakebc875f52004-02-04 23:14:14 +0000795 Py_INCREF(result);
Fred Drake8844d522001-10-05 21:52:26 +0000796 else {
Fred Drakebc875f52004-02-04 23:14:14 +0000797 /* Note: new_weakref() can trigger cyclic GC, so the weakref
798 list on ob can be mutated. This means that the ref and
799 proxy pointers we got back earlier may have been collected,
800 so we need to compute these values again before we use
801 them. */
Neil Schemenauer38a89162002-03-27 15:18:21 +0000802 result = new_weakref(ob, callback);
Fred Drake8844d522001-10-05 21:52:26 +0000803 if (result != NULL) {
804 PyWeakReference *prev;
805
806 if (PyCallable_Check(ob))
Martin v. Löwis68192102007-07-21 06:55:02 +0000807 Py_Type(result) = &_PyWeakref_CallableProxyType;
Fred Drake8844d522001-10-05 21:52:26 +0000808 else
Martin v. Löwis68192102007-07-21 06:55:02 +0000809 Py_Type(result) = &_PyWeakref_ProxyType;
Fred Drakebc875f52004-02-04 23:14:14 +0000810 get_basic_refs(*list, &ref, &proxy);
Fred Drake6d3265d2004-08-03 14:47:25 +0000811 if (callback == NULL) {
812 if (proxy != NULL) {
813 /* Someone else added a proxy without a callback
814 during GC. Return that one instead of this one
815 to avoid violating the invariants of the list
816 of weakrefs for ob. */
817 Py_DECREF(result);
818 Py_INCREF(result = proxy);
819 goto skip_insert;
820 }
Fred Drake8844d522001-10-05 21:52:26 +0000821 prev = ref;
Fred Drake6d3265d2004-08-03 14:47:25 +0000822 }
Fred Drake8844d522001-10-05 21:52:26 +0000823 else
824 prev = (proxy == NULL) ? ref : proxy;
825
826 if (prev == NULL)
827 insert_head(result, list);
828 else
829 insert_after(result, prev);
Fred Drake6d3265d2004-08-03 14:47:25 +0000830 skip_insert:
831 ;
Fred Drake8844d522001-10-05 21:52:26 +0000832 }
833 }
834 return (PyObject *) result;
835}
836
837
838PyObject *
839PyWeakref_GetObject(PyObject *ref)
840{
841 if (ref == NULL || !PyWeakref_Check(ref)) {
842 PyErr_BadInternalCall();
843 return NULL;
844 }
845 return PyWeakref_GET_OBJECT(ref);
846}
847
Tim Petersead8b7a2004-10-30 23:09:22 +0000848/* Note that there's an inlined copy-paste of handle_callback() in gcmodule.c's
849 * handle_weakrefs().
850 */
Fred Drakeef8ebd12001-12-10 23:44:54 +0000851static void
852handle_callback(PyWeakReference *ref, PyObject *callback)
853{
Georg Brandl684fd0c2006-05-25 19:15:31 +0000854 PyObject *cbresult = PyObject_CallFunctionObjArgs(callback, ref, NULL);
Fred Drakeef8ebd12001-12-10 23:44:54 +0000855
856 if (cbresult == NULL)
857 PyErr_WriteUnraisable(callback);
858 else
859 Py_DECREF(cbresult);
860}
861
862/* This function is called by the tp_dealloc handler to clear weak references.
Fred Drake8844d522001-10-05 21:52:26 +0000863 *
864 * This iterates through the weak references for 'object' and calls callbacks
865 * for those references which have one. It returns when all callbacks have
866 * been attempted.
867 */
868void
869PyObject_ClearWeakRefs(PyObject *object)
870{
871 PyWeakReference **list;
872
873 if (object == NULL
Martin v. Löwis68192102007-07-21 06:55:02 +0000874 || !PyType_SUPPORTS_WEAKREFS(Py_Type(object))
Fred Drake8844d522001-10-05 21:52:26 +0000875 || object->ob_refcnt != 0) {
876 PyErr_BadInternalCall();
877 return;
878 }
879 list = GET_WEAKREFS_LISTPTR(object);
880 /* Remove the callback-less basic and proxy references */
881 if (*list != NULL && (*list)->wr_callback == NULL) {
882 clear_weakref(*list);
883 if (*list != NULL && (*list)->wr_callback == NULL)
884 clear_weakref(*list);
885 }
886 if (*list != NULL) {
Fred Drakeef8ebd12001-12-10 23:44:54 +0000887 PyWeakReference *current = *list;
Martin v. Löwis18e16552006-02-15 17:27:45 +0000888 Py_ssize_t count = _PyWeakref_GetWeakrefCount(current);
Fred Drakeef8ebd12001-12-10 23:44:54 +0000889 int restore_error = PyErr_Occurred() ? 1 : 0;
890 PyObject *err_type, *err_value, *err_tb;
Fred Drake8844d522001-10-05 21:52:26 +0000891
Fred Drakeef8ebd12001-12-10 23:44:54 +0000892 if (restore_error)
893 PyErr_Fetch(&err_type, &err_value, &err_tb);
Fred Drake8844d522001-10-05 21:52:26 +0000894 if (count == 1) {
Fred Drake8844d522001-10-05 21:52:26 +0000895 PyObject *callback = current->wr_callback;
Fred Drake8844d522001-10-05 21:52:26 +0000896
Fred Drakeef8ebd12001-12-10 23:44:54 +0000897 current->wr_callback = NULL;
Fred Drake8844d522001-10-05 21:52:26 +0000898 clear_weakref(current);
Fred Drake0a4dd392004-07-02 18:57:45 +0000899 if (callback != NULL) {
900 handle_callback(current, callback);
901 Py_DECREF(callback);
902 }
Fred Drake8844d522001-10-05 21:52:26 +0000903 }
904 else {
Hye-Shik Chang4af5c8c2006-03-07 15:39:21 +0000905 PyObject *tuple;
Martin v. Löwis18e16552006-02-15 17:27:45 +0000906 Py_ssize_t i = 0;
Hye-Shik Chang4af5c8c2006-03-07 15:39:21 +0000907
908 tuple = PyTuple_New(count * 2);
909 if (tuple == NULL) {
910 if (restore_error)
911 PyErr_Fetch(&err_type, &err_value, &err_tb);
912 return;
913 }
Fred Drake8844d522001-10-05 21:52:26 +0000914
915 for (i = 0; i < count; ++i) {
916 PyWeakReference *next = current->wr_next;
917
918 Py_INCREF(current);
919 PyTuple_SET_ITEM(tuple, i * 2, (PyObject *) current);
920 PyTuple_SET_ITEM(tuple, i * 2 + 1, current->wr_callback);
921 current->wr_callback = NULL;
Fred Drake8844d522001-10-05 21:52:26 +0000922 clear_weakref(current);
923 current = next;
924 }
925 for (i = 0; i < count; ++i) {
Fred Drake8844d522001-10-05 21:52:26 +0000926 PyObject *callback = PyTuple_GET_ITEM(tuple, i * 2 + 1);
Fred Drakeef8ebd12001-12-10 23:44:54 +0000927
Fred Drake0a4dd392004-07-02 18:57:45 +0000928 if (callback != NULL) {
Neal Norwitz0c6e2f12006-01-08 06:13:44 +0000929 PyObject *item = PyTuple_GET_ITEM(tuple, i * 2);
930 handle_callback((PyWeakReference *)item, callback);
Fred Drake0a4dd392004-07-02 18:57:45 +0000931 }
Fred Drake8844d522001-10-05 21:52:26 +0000932 }
933 Py_DECREF(tuple);
934 }
Fred Drakeef8ebd12001-12-10 23:44:54 +0000935 if (restore_error)
936 PyErr_Restore(err_type, err_value, err_tb);
Fred Drake8844d522001-10-05 21:52:26 +0000937 }
938}