blob: 206a45512b61bbde66020940642081bf8257ac5b [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)
60 *list = self->wr_next;
61 self->wr_object = Py_None;
Fred Drake8844d522001-10-05 21:52:26 +000062 if (self->wr_prev != NULL)
63 self->wr_prev->wr_next = self->wr_next;
64 if (self->wr_next != NULL)
65 self->wr_next->wr_prev = self->wr_prev;
66 self->wr_prev = NULL;
67 self->wr_next = NULL;
Tim Peters403a2032003-11-20 21:21:46 +000068 }
69 if (callback != NULL) {
70 Py_DECREF(callback);
71 self->wr_callback = NULL;
Fred Drake8844d522001-10-05 21:52:26 +000072 }
73}
74
Tim Peters403a2032003-11-20 21:21:46 +000075/* Cyclic gc uses this to *just* clear the passed-in reference, leaving
76 * the callback intact and uncalled. It must be possible to call self's
77 * tp_dealloc() after calling this, so self has to be left in a sane enough
78 * state for that to work. We expect tp_dealloc to decref the callback
79 * then. The reason for not letting clear_weakref() decref the callback
80 * right now is that if the callback goes away, that may in turn trigger
81 * another callback (if a weak reference to the callback exists) -- running
82 * arbitrary Python code in the middle of gc is a disaster. The convolution
83 * here allows gc to delay triggering such callbacks until the world is in
84 * a sane state again.
85 */
86void
87_PyWeakref_ClearRef(PyWeakReference *self)
88{
89 PyObject *callback;
90
91 assert(self != NULL);
92 assert(PyWeakref_Check(self));
93 /* Preserve and restore the callback around clear_weakref. */
94 callback = self->wr_callback;
95 self->wr_callback = NULL;
96 clear_weakref(self);
97 self->wr_callback = callback;
98}
Fred Drake8844d522001-10-05 21:52:26 +000099
100static void
Fred Drake0a4dd392004-07-02 18:57:45 +0000101weakref_dealloc(PyObject *self)
Fred Drake8844d522001-10-05 21:52:26 +0000102{
Fred Drake0a4dd392004-07-02 18:57:45 +0000103 PyObject_GC_UnTrack(self);
104 clear_weakref((PyWeakReference *) self);
105 self->ob_type->tp_free(self);
Fred Drake8844d522001-10-05 21:52:26 +0000106}
107
108
109static int
110gc_traverse(PyWeakReference *self, visitproc visit, void *arg)
111{
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000112 Py_VISIT(self->wr_callback);
Fred Drake8844d522001-10-05 21:52:26 +0000113 return 0;
114}
115
116
117static int
118gc_clear(PyWeakReference *self)
119{
120 clear_weakref(self);
121 return 0;
122}
123
124
125static PyObject *
126weakref_call(PyWeakReference *self, PyObject *args, PyObject *kw)
127{
Martin v. Löwis15e62742006-02-27 16:46:16 +0000128 static char *kwlist[] = {NULL};
Fred Drake8844d522001-10-05 21:52:26 +0000129
Martin v. Löwis15e62742006-02-27 16:46:16 +0000130 if (PyArg_ParseTupleAndKeywords(args, kw, ":__call__", kwlist)) {
Fred Drake8844d522001-10-05 21:52:26 +0000131 PyObject *object = PyWeakref_GET_OBJECT(self);
132 Py_INCREF(object);
133 return (object);
134 }
135 return NULL;
136}
137
138
139static long
140weakref_hash(PyWeakReference *self)
141{
142 if (self->hash != -1)
143 return self->hash;
144 if (PyWeakref_GET_OBJECT(self) == Py_None) {
145 PyErr_SetString(PyExc_TypeError, "weak object has gone away");
146 return -1;
147 }
148 self->hash = PyObject_Hash(PyWeakref_GET_OBJECT(self));
149 return self->hash;
150}
Tim Peters403a2032003-11-20 21:21:46 +0000151
Fred Drake8844d522001-10-05 21:52:26 +0000152
153static PyObject *
154weakref_repr(PyWeakReference *self)
155{
156 char buffer[256];
157 if (PyWeakref_GET_OBJECT(self) == Py_None) {
Guido van Rossumc1f6e8c2003-04-16 21:13:23 +0000158 PyOS_snprintf(buffer, sizeof(buffer), "<weakref at %p; dead>", self);
Fred Drake8844d522001-10-05 21:52:26 +0000159 }
160 else {
Guido van Rossumc1f6e8c2003-04-16 21:13:23 +0000161 char *name = NULL;
162 PyObject *nameobj = PyObject_GetAttrString(PyWeakref_GET_OBJECT(self),
163 "__name__");
164 if (nameobj == NULL)
165 PyErr_Clear();
166 else if (PyString_Check(nameobj))
167 name = PyString_AS_STRING(nameobj);
Barry Warsawd5867562001-11-28 21:01:56 +0000168 PyOS_snprintf(buffer, sizeof(buffer),
Guido van Rossumc1f6e8c2003-04-16 21:13:23 +0000169 name ? "<weakref at %p; to '%.50s' at %p (%s)>"
170 : "<weakref at %p; to '%.50s' at %p>",
171 self,
Barry Warsawd5867562001-11-28 21:01:56 +0000172 PyWeakref_GET_OBJECT(self)->ob_type->tp_name,
Guido van Rossumc1f6e8c2003-04-16 21:13:23 +0000173 PyWeakref_GET_OBJECT(self),
174 name);
175 Py_XDECREF(nameobj);
Fred Drake8844d522001-10-05 21:52:26 +0000176 }
177 return PyString_FromString(buffer);
178}
179
180/* Weak references only support equality, not ordering. Two weak references
181 are equal if the underlying objects are equal. If the underlying object has
182 gone away, they are equal if they are identical. */
183
184static PyObject *
185weakref_richcompare(PyWeakReference* self, PyWeakReference* other, int op)
186{
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000187 if ((op != Py_EQ && op != Py_NE) ||
188 !PyWeakref_Check(self) ||
189 !PyWeakref_Check(other)) {
Fred Drake8844d522001-10-05 21:52:26 +0000190 Py_INCREF(Py_NotImplemented);
191 return Py_NotImplemented;
192 }
193 if (PyWeakref_GET_OBJECT(self) == Py_None
194 || PyWeakref_GET_OBJECT(other) == Py_None) {
195 PyObject *res = self==other ? Py_True : Py_False;
196 Py_INCREF(res);
197 return res;
198 }
199 return PyObject_RichCompare(PyWeakref_GET_OBJECT(self),
200 PyWeakref_GET_OBJECT(other), op);
201}
202
Fred Drake0a4dd392004-07-02 18:57:45 +0000203/* Given the head of an object's list of weak references, extract the
204 * two callback-less refs (ref and proxy). Used to determine if the
205 * shared references exist and to determine the back link for newly
206 * inserted references.
207 */
208static void
209get_basic_refs(PyWeakReference *head,
210 PyWeakReference **refp, PyWeakReference **proxyp)
211{
212 *refp = NULL;
213 *proxyp = NULL;
214
215 if (head != NULL && head->wr_callback == NULL) {
216 /* We need to be careful that the "basic refs" aren't
217 subclasses of the main types. That complicates this a
218 little. */
219 if (PyWeakref_CheckRefExact(head)) {
220 *refp = head;
221 head = head->wr_next;
222 }
223 if (head != NULL
224 && head->wr_callback == NULL
225 && PyWeakref_CheckProxy(head)) {
226 *proxyp = head;
227 /* head = head->wr_next; */
228 }
229 }
230}
231
232/* Insert 'newref' in the list after 'prev'. Both must be non-NULL. */
233static void
234insert_after(PyWeakReference *newref, PyWeakReference *prev)
235{
236 newref->wr_prev = prev;
237 newref->wr_next = prev->wr_next;
238 if (prev->wr_next != NULL)
239 prev->wr_next->wr_prev = newref;
240 prev->wr_next = newref;
241}
242
243/* Insert 'newref' at the head of the list; 'list' points to the variable
244 * that stores the head.
245 */
246static void
247insert_head(PyWeakReference *newref, PyWeakReference **list)
248{
249 PyWeakReference *next = *list;
250
251 newref->wr_prev = NULL;
252 newref->wr_next = next;
253 if (next != NULL)
254 next->wr_prev = newref;
255 *list = newref;
256}
257
258static int
259parse_weakref_init_args(char *funcname, PyObject *args, PyObject *kwargs,
260 PyObject **obp, PyObject **callbackp)
261{
262 /* XXX Should check that kwargs == NULL or is empty. */
263 return PyArg_UnpackTuple(args, funcname, 1, 2, obp, callbackp);
264}
265
266static PyObject *
267weakref___new__(PyTypeObject *type, PyObject *args, PyObject *kwargs)
268{
269 PyWeakReference *self = NULL;
270 PyObject *ob, *callback = NULL;
271
272 if (parse_weakref_init_args("__new__", args, kwargs, &ob, &callback)) {
273 PyWeakReference *ref, *proxy;
274 PyWeakReference **list;
275
276 if (!PyType_SUPPORTS_WEAKREFS(ob->ob_type)) {
277 PyErr_Format(PyExc_TypeError,
278 "cannot create weak reference to '%s' object",
279 ob->ob_type->tp_name);
280 return NULL;
281 }
282 if (callback == Py_None)
283 callback = NULL;
284 list = GET_WEAKREFS_LISTPTR(ob);
285 get_basic_refs(*list, &ref, &proxy);
286 if (callback == NULL && type == &_PyWeakref_RefType) {
287 if (ref != NULL) {
288 /* We can re-use an existing reference. */
289 Py_INCREF(ref);
290 return (PyObject *)ref;
291 }
292 }
293 /* We have to create a new reference. */
294 /* Note: the tp_alloc() can trigger cyclic GC, so the weakref
295 list on ob can be mutated. This means that the ref and
296 proxy pointers we got back earlier may have been collected,
297 so we need to compute these values again before we use
298 them. */
299 self = (PyWeakReference *) (type->tp_alloc(type, 0));
300 if (self != NULL) {
301 init_weakref(self, ob, callback);
302 if (callback == NULL && type == &_PyWeakref_RefType) {
303 insert_head(self, list);
304 }
305 else {
306 PyWeakReference *prev;
307
308 get_basic_refs(*list, &ref, &proxy);
309 prev = (proxy == NULL) ? ref : proxy;
310 if (prev == NULL)
311 insert_head(self, list);
312 else
313 insert_after(self, prev);
314 }
315 }
316 }
317 return (PyObject *)self;
318}
319
320static int
321weakref___init__(PyObject *self, PyObject *args, PyObject *kwargs)
322{
323 PyObject *tmp;
324
325 if (parse_weakref_init_args("__init__", args, kwargs, &tmp, &tmp))
326 return 0;
327 else
328 return 1;
329}
330
Fred Drake8844d522001-10-05 21:52:26 +0000331
332PyTypeObject
333_PyWeakref_RefType = {
334 PyObject_HEAD_INIT(&PyType_Type)
335 0,
336 "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*/
Guido van Rossum3cf5b1e2006-07-27 21:53:35 +0000354 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC
Fred Drake0a4dd392004-07-02 18:57:45 +0000355 | 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*/
Thomas Wouters49fd7fa2006-04-21 10:40:58 +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,
Barry Warsawd5867562001-11-28 21:01:56 +0000449 PyWeakref_GET_OBJECT(proxy)->ob_type->tp_name,
450 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
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000463static PyObject *
464proxy_richcompare(PyObject *proxy, PyObject *v, int op)
Fred Drake8844d522001-10-05 21:52:26 +0000465{
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000466 UNWRAP(proxy);
467 UNWRAP(v);
468 return PyObject_RichCompare(proxy, v, op);
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)
Fred Drake8844d522001-10-05 21:52:26 +0000475WRAP_BINARY(proxy_mod, PyNumber_Remainder)
476WRAP_BINARY(proxy_divmod, PyNumber_Divmod)
477WRAP_TERNARY(proxy_pow, PyNumber_Power)
478WRAP_UNARY(proxy_neg, PyNumber_Negative)
479WRAP_UNARY(proxy_pos, PyNumber_Positive)
480WRAP_UNARY(proxy_abs, PyNumber_Absolute)
481WRAP_UNARY(proxy_invert, PyNumber_Invert)
482WRAP_BINARY(proxy_lshift, PyNumber_Lshift)
483WRAP_BINARY(proxy_rshift, PyNumber_Rshift)
484WRAP_BINARY(proxy_and, PyNumber_And)
485WRAP_BINARY(proxy_xor, PyNumber_Xor)
486WRAP_BINARY(proxy_or, PyNumber_Or)
487WRAP_UNARY(proxy_int, PyNumber_Int)
488WRAP_UNARY(proxy_long, PyNumber_Long)
489WRAP_UNARY(proxy_float, PyNumber_Float)
490WRAP_BINARY(proxy_iadd, PyNumber_InPlaceAdd)
491WRAP_BINARY(proxy_isub, PyNumber_InPlaceSubtract)
492WRAP_BINARY(proxy_imul, PyNumber_InPlaceMultiply)
Fred Drake8844d522001-10-05 21:52:26 +0000493WRAP_BINARY(proxy_imod, PyNumber_InPlaceRemainder)
494WRAP_TERNARY(proxy_ipow, PyNumber_InPlacePower)
495WRAP_BINARY(proxy_ilshift, PyNumber_InPlaceLshift)
496WRAP_BINARY(proxy_irshift, PyNumber_InPlaceRshift)
497WRAP_BINARY(proxy_iand, PyNumber_InPlaceAnd)
498WRAP_BINARY(proxy_ixor, PyNumber_InPlaceXor)
499WRAP_BINARY(proxy_ior, PyNumber_InPlaceOr)
500
Tim Peters403a2032003-11-20 21:21:46 +0000501static int
Fred Drake8844d522001-10-05 21:52:26 +0000502proxy_nonzero(PyWeakReference *proxy)
503{
504 PyObject *o = PyWeakref_GET_OBJECT(proxy);
505 if (!proxy_checkref(proxy))
Neal Norwitzbdcb9412004-07-08 01:22:31 +0000506 return -1;
Raymond Hettingere6c470f2005-03-27 03:04:54 +0000507 return PyObject_IsTrue(o);
Fred Drake8844d522001-10-05 21:52:26 +0000508}
509
Fred Drake0a4dd392004-07-02 18:57:45 +0000510static void
511proxy_dealloc(PyWeakReference *self)
512{
513 if (self->wr_callback != NULL)
514 PyObject_GC_UnTrack((PyObject *)self);
515 clear_weakref(self);
516 PyObject_GC_Del(self);
517}
518
Fred Drake8844d522001-10-05 21:52:26 +0000519/* sequence slots */
520
521static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000522proxy_slice(PyWeakReference *proxy, Py_ssize_t i, Py_ssize_t j)
Fred Drake8844d522001-10-05 21:52:26 +0000523{
524 if (!proxy_checkref(proxy))
525 return NULL;
526 return PySequence_GetSlice(PyWeakref_GET_OBJECT(proxy), i, j);
527}
528
529static int
Martin v. Löwis18e16552006-02-15 17:27:45 +0000530proxy_ass_slice(PyWeakReference *proxy, Py_ssize_t i, Py_ssize_t j, PyObject *value)
Fred Drake8844d522001-10-05 21:52:26 +0000531{
532 if (!proxy_checkref(proxy))
533 return -1;
534 return PySequence_SetSlice(PyWeakref_GET_OBJECT(proxy), i, j, value);
535}
536
537static int
538proxy_contains(PyWeakReference *proxy, PyObject *value)
539{
540 if (!proxy_checkref(proxy))
541 return -1;
542 return PySequence_Contains(PyWeakref_GET_OBJECT(proxy), value);
543}
544
545
546/* mapping slots */
547
Martin v. Löwis18e16552006-02-15 17:27:45 +0000548static Py_ssize_t
Fred Drake8844d522001-10-05 21:52:26 +0000549proxy_length(PyWeakReference *proxy)
550{
551 if (!proxy_checkref(proxy))
552 return -1;
553 return PyObject_Length(PyWeakref_GET_OBJECT(proxy));
554}
555
556WRAP_BINARY(proxy_getitem, PyObject_GetItem)
557
558static int
559proxy_setitem(PyWeakReference *proxy, PyObject *key, PyObject *value)
560{
561 if (!proxy_checkref(proxy))
562 return -1;
Raymond Hettingerd693a812003-06-30 04:18:48 +0000563
564 if (value == NULL)
565 return PyObject_DelItem(PyWeakref_GET_OBJECT(proxy), key);
566 else
567 return PyObject_SetItem(PyWeakref_GET_OBJECT(proxy), key, value);
Fred Drake8844d522001-10-05 21:52:26 +0000568}
569
Fred Drakef16c3dc2002-08-09 18:34:16 +0000570/* iterator slots */
571
572static PyObject *
573proxy_iter(PyWeakReference *proxy)
574{
575 if (!proxy_checkref(proxy))
576 return NULL;
577 return PyObject_GetIter(PyWeakref_GET_OBJECT(proxy));
578}
579
580static PyObject *
581proxy_iternext(PyWeakReference *proxy)
582{
583 if (!proxy_checkref(proxy))
584 return NULL;
585 return PyIter_Next(PyWeakref_GET_OBJECT(proxy));
586}
587
Fred Drake8844d522001-10-05 21:52:26 +0000588
589static PyNumberMethods proxy_as_number = {
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000590 proxy_add, /*nb_add*/
591 proxy_sub, /*nb_subtract*/
592 proxy_mul, /*nb_multiply*/
593 proxy_mod, /*nb_remainder*/
594 proxy_divmod, /*nb_divmod*/
595 proxy_pow, /*nb_power*/
596 proxy_neg, /*nb_negative*/
597 proxy_pos, /*nb_positive*/
598 proxy_abs, /*nb_absolute*/
599 (inquiry)proxy_nonzero, /*nb_nonzero*/
600 proxy_invert, /*nb_invert*/
601 proxy_lshift, /*nb_lshift*/
602 proxy_rshift, /*nb_rshift*/
603 proxy_and, /*nb_and*/
604 proxy_xor, /*nb_xor*/
605 proxy_or, /*nb_or*/
606 0, /*nb_coerce*/
607 proxy_int, /*nb_int*/
608 proxy_long, /*nb_long*/
609 proxy_float, /*nb_float*/
610 0, /*nb_oct*/
611 0, /*nb_hex*/
612 proxy_iadd, /*nb_inplace_add*/
613 proxy_isub, /*nb_inplace_subtract*/
614 proxy_imul, /*nb_inplace_multiply*/
615 proxy_imod, /*nb_inplace_remainder*/
616 proxy_ipow, /*nb_inplace_power*/
617 proxy_ilshift, /*nb_inplace_lshift*/
618 proxy_irshift, /*nb_inplace_rshift*/
619 proxy_iand, /*nb_inplace_and*/
620 proxy_ixor, /*nb_inplace_xor*/
621 proxy_ior, /*nb_inplace_or*/
Fred Drake8844d522001-10-05 21:52:26 +0000622};
623
624static PySequenceMethods proxy_as_sequence = {
Martin v. Löwis18e16552006-02-15 17:27:45 +0000625 (lenfunc)proxy_length, /*sq_length*/
Fred Drake8844d522001-10-05 21:52:26 +0000626 0, /*sq_concat*/
627 0, /*sq_repeat*/
628 0, /*sq_item*/
Martin v. Löwis18e16552006-02-15 17:27:45 +0000629 (ssizessizeargfunc)proxy_slice, /*sq_slice*/
Fred Drake8844d522001-10-05 21:52:26 +0000630 0, /*sq_ass_item*/
Martin v. Löwis18e16552006-02-15 17:27:45 +0000631 (ssizessizeobjargproc)proxy_ass_slice, /*sq_ass_slice*/
Fred Drake8844d522001-10-05 21:52:26 +0000632 (objobjproc)proxy_contains, /* sq_contains */
633};
634
635static PyMappingMethods proxy_as_mapping = {
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000636 (lenfunc)proxy_length, /*mp_length*/
637 proxy_getitem, /*mp_subscript*/
Fred Drake8844d522001-10-05 21:52:26 +0000638 (objobjargproc)proxy_setitem, /*mp_ass_subscript*/
639};
640
641
642PyTypeObject
643_PyWeakref_ProxyType = {
644 PyObject_HEAD_INIT(&PyType_Type)
645 0,
646 "weakproxy",
647 sizeof(PyWeakReference),
648 0,
649 /* methods */
Fred Drake0a4dd392004-07-02 18:57:45 +0000650 (destructor)proxy_dealloc, /* tp_dealloc */
Fred Drakefe89cc12003-07-14 21:46:23 +0000651 0, /* tp_print */
Fred Drakef16c3dc2002-08-09 18:34:16 +0000652 0, /* tp_getattr */
653 0, /* tp_setattr */
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000654 0, /* tp_compare */
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000655 (reprfunc)proxy_repr, /* tp_repr */
Fred Drakef16c3dc2002-08-09 18:34:16 +0000656 &proxy_as_number, /* tp_as_number */
657 &proxy_as_sequence, /* tp_as_sequence */
658 &proxy_as_mapping, /* tp_as_mapping */
659 0, /* tp_hash */
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000660 0, /* tp_call */
661 proxy_str, /* tp_str */
662 proxy_getattr, /* tp_getattro */
Fred Drakef16c3dc2002-08-09 18:34:16 +0000663 (setattrofunc)proxy_setattr, /* tp_setattro */
664 0, /* tp_as_buffer */
Guido van Rossum3cf5b1e2006-07-27 21:53:35 +0000665 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
Fred Drakef16c3dc2002-08-09 18:34:16 +0000666 0, /* tp_doc */
667 (traverseproc)gc_traverse, /* tp_traverse */
668 (inquiry)gc_clear, /* tp_clear */
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000669 proxy_richcompare, /* tp_richcompare */
Fred Drakef16c3dc2002-08-09 18:34:16 +0000670 0, /* tp_weaklistoffset */
671 (getiterfunc)proxy_iter, /* tp_iter */
672 (iternextfunc)proxy_iternext, /* tp_iternext */
Fred Drake8844d522001-10-05 21:52:26 +0000673};
674
675
676PyTypeObject
677_PyWeakref_CallableProxyType = {
678 PyObject_HEAD_INIT(&PyType_Type)
679 0,
680 "weakcallableproxy",
681 sizeof(PyWeakReference),
682 0,
683 /* methods */
Fred Drake0a4dd392004-07-02 18:57:45 +0000684 (destructor)proxy_dealloc, /* tp_dealloc */
Fred Drakefe89cc12003-07-14 21:46:23 +0000685 0, /* tp_print */
Fred Drakef16c3dc2002-08-09 18:34:16 +0000686 0, /* tp_getattr */
687 0, /* tp_setattr */
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000688 0, /* tp_compare */
Fred Drakef16c3dc2002-08-09 18:34:16 +0000689 (unaryfunc)proxy_repr, /* tp_repr */
690 &proxy_as_number, /* tp_as_number */
691 &proxy_as_sequence, /* tp_as_sequence */
692 &proxy_as_mapping, /* tp_as_mapping */
693 0, /* tp_hash */
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000694 proxy_call, /* tp_call */
695 proxy_str, /* tp_str */
696 proxy_getattr, /* tp_getattro */
Fred Drakef16c3dc2002-08-09 18:34:16 +0000697 (setattrofunc)proxy_setattr, /* tp_setattro */
698 0, /* tp_as_buffer */
Guido van Rossum3cf5b1e2006-07-27 21:53:35 +0000699 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
Fred Drakef16c3dc2002-08-09 18:34:16 +0000700 0, /* tp_doc */
701 (traverseproc)gc_traverse, /* tp_traverse */
702 (inquiry)gc_clear, /* tp_clear */
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000703 proxy_richcompare, /* tp_richcompare */
Fred Drakef16c3dc2002-08-09 18:34:16 +0000704 0, /* tp_weaklistoffset */
705 (getiterfunc)proxy_iter, /* tp_iter */
706 (iternextfunc)proxy_iternext, /* tp_iternext */
Fred Drake8844d522001-10-05 21:52:26 +0000707};
708
709
Fred Drake8844d522001-10-05 21:52:26 +0000710
711PyObject *
712PyWeakref_NewRef(PyObject *ob, PyObject *callback)
713{
714 PyWeakReference *result = NULL;
715 PyWeakReference **list;
716 PyWeakReference *ref, *proxy;
717
718 if (!PyType_SUPPORTS_WEAKREFS(ob->ob_type)) {
719 PyErr_Format(PyExc_TypeError,
Jeremy Hylton996fad32001-10-22 16:31:40 +0000720 "cannot create weak reference to '%s' object",
Fred Drake8844d522001-10-05 21:52:26 +0000721 ob->ob_type->tp_name);
722 return NULL;
723 }
724 list = GET_WEAKREFS_LISTPTR(ob);
725 get_basic_refs(*list, &ref, &proxy);
Fred Drake6a2852c2004-02-03 19:52:56 +0000726 if (callback == Py_None)
727 callback = NULL;
728 if (callback == NULL)
Fred Drake8844d522001-10-05 21:52:26 +0000729 /* return existing weak reference if it exists */
730 result = ref;
731 if (result != NULL)
Fred Drakebc875f52004-02-04 23:14:14 +0000732 Py_INCREF(result);
Fred Drake8844d522001-10-05 21:52:26 +0000733 else {
Fred Drakebc875f52004-02-04 23:14:14 +0000734 /* Note: new_weakref() can trigger cyclic GC, so the weakref
735 list on ob can be mutated. This means that the ref and
736 proxy pointers we got back earlier may have been collected,
737 so we need to compute these values again before we use
738 them. */
Neil Schemenauer38a89162002-03-27 15:18:21 +0000739 result = new_weakref(ob, callback);
Fred Drake8844d522001-10-05 21:52:26 +0000740 if (result != NULL) {
Fred Drake6d3265d2004-08-03 14:47:25 +0000741 get_basic_refs(*list, &ref, &proxy);
Fred Drake8844d522001-10-05 21:52:26 +0000742 if (callback == NULL) {
Fred Drake6d3265d2004-08-03 14:47:25 +0000743 if (ref == NULL)
744 insert_head(result, list);
745 else {
746 /* Someone else added a ref without a callback
747 during GC. Return that one instead of this one
748 to avoid violating the invariants of the list
749 of weakrefs for ob. */
750 Py_DECREF(result);
751 Py_INCREF(ref);
752 result = ref;
753 }
Fred Drake8844d522001-10-05 21:52:26 +0000754 }
755 else {
Fred Drakebc875f52004-02-04 23:14:14 +0000756 PyWeakReference *prev;
Fred Drake8844d522001-10-05 21:52:26 +0000757
Fred Drakebc875f52004-02-04 23:14:14 +0000758 prev = (proxy == NULL) ? ref : proxy;
Fred Drake8844d522001-10-05 21:52:26 +0000759 if (prev == NULL)
760 insert_head(result, list);
761 else
762 insert_after(result, prev);
763 }
Fred Drake8844d522001-10-05 21:52:26 +0000764 }
765 }
766 return (PyObject *) result;
767}
768
769
770PyObject *
771PyWeakref_NewProxy(PyObject *ob, PyObject *callback)
772{
773 PyWeakReference *result = NULL;
774 PyWeakReference **list;
775 PyWeakReference *ref, *proxy;
776
777 if (!PyType_SUPPORTS_WEAKREFS(ob->ob_type)) {
778 PyErr_Format(PyExc_TypeError,
Jeremy Hylton996fad32001-10-22 16:31:40 +0000779 "cannot create weak reference to '%s' object",
Fred Drake8844d522001-10-05 21:52:26 +0000780 ob->ob_type->tp_name);
781 return NULL;
782 }
783 list = GET_WEAKREFS_LISTPTR(ob);
784 get_basic_refs(*list, &ref, &proxy);
Fred Drake6a2852c2004-02-03 19:52:56 +0000785 if (callback == Py_None)
786 callback = NULL;
Fred Drake8844d522001-10-05 21:52:26 +0000787 if (callback == NULL)
788 /* attempt to return an existing weak reference if it exists */
789 result = proxy;
790 if (result != NULL)
Fred Drakebc875f52004-02-04 23:14:14 +0000791 Py_INCREF(result);
Fred Drake8844d522001-10-05 21:52:26 +0000792 else {
Fred Drakebc875f52004-02-04 23:14:14 +0000793 /* Note: new_weakref() can trigger cyclic GC, so the weakref
794 list on ob can be mutated. This means that the ref and
795 proxy pointers we got back earlier may have been collected,
796 so we need to compute these values again before we use
797 them. */
Neil Schemenauer38a89162002-03-27 15:18:21 +0000798 result = new_weakref(ob, callback);
Fred Drake8844d522001-10-05 21:52:26 +0000799 if (result != NULL) {
800 PyWeakReference *prev;
801
802 if (PyCallable_Check(ob))
803 result->ob_type = &_PyWeakref_CallableProxyType;
804 else
805 result->ob_type = &_PyWeakref_ProxyType;
Fred Drakebc875f52004-02-04 23:14:14 +0000806 get_basic_refs(*list, &ref, &proxy);
Fred Drake6d3265d2004-08-03 14:47:25 +0000807 if (callback == NULL) {
808 if (proxy != NULL) {
809 /* Someone else added a proxy without a callback
810 during GC. Return that one instead of this one
811 to avoid violating the invariants of the list
812 of weakrefs for ob. */
813 Py_DECREF(result);
814 Py_INCREF(result = proxy);
815 goto skip_insert;
816 }
Fred Drake8844d522001-10-05 21:52:26 +0000817 prev = ref;
Fred Drake6d3265d2004-08-03 14:47:25 +0000818 }
Fred Drake8844d522001-10-05 21:52:26 +0000819 else
820 prev = (proxy == NULL) ? ref : proxy;
821
822 if (prev == NULL)
823 insert_head(result, list);
824 else
825 insert_after(result, prev);
Fred Drake6d3265d2004-08-03 14:47:25 +0000826 skip_insert:
827 ;
Fred Drake8844d522001-10-05 21:52:26 +0000828 }
829 }
830 return (PyObject *) result;
831}
832
833
834PyObject *
835PyWeakref_GetObject(PyObject *ref)
836{
837 if (ref == NULL || !PyWeakref_Check(ref)) {
838 PyErr_BadInternalCall();
839 return NULL;
840 }
841 return PyWeakref_GET_OBJECT(ref);
842}
843
Tim Petersead8b7a2004-10-30 23:09:22 +0000844/* Note that there's an inlined copy-paste of handle_callback() in gcmodule.c's
845 * handle_weakrefs().
846 */
Fred Drakeef8ebd12001-12-10 23:44:54 +0000847static void
848handle_callback(PyWeakReference *ref, PyObject *callback)
849{
Thomas Wouters477c8d52006-05-27 19:21:47 +0000850 PyObject *cbresult = PyObject_CallFunctionObjArgs(callback, ref, NULL);
Fred Drakeef8ebd12001-12-10 23:44:54 +0000851
852 if (cbresult == NULL)
853 PyErr_WriteUnraisable(callback);
854 else
855 Py_DECREF(cbresult);
856}
857
858/* This function is called by the tp_dealloc handler to clear weak references.
Fred Drake8844d522001-10-05 21:52:26 +0000859 *
860 * This iterates through the weak references for 'object' and calls callbacks
861 * for those references which have one. It returns when all callbacks have
862 * been attempted.
863 */
864void
865PyObject_ClearWeakRefs(PyObject *object)
866{
867 PyWeakReference **list;
868
869 if (object == NULL
870 || !PyType_SUPPORTS_WEAKREFS(object->ob_type)
871 || object->ob_refcnt != 0) {
872 PyErr_BadInternalCall();
873 return;
874 }
875 list = GET_WEAKREFS_LISTPTR(object);
876 /* Remove the callback-less basic and proxy references */
877 if (*list != NULL && (*list)->wr_callback == NULL) {
878 clear_weakref(*list);
879 if (*list != NULL && (*list)->wr_callback == NULL)
880 clear_weakref(*list);
881 }
882 if (*list != NULL) {
Fred Drakeef8ebd12001-12-10 23:44:54 +0000883 PyWeakReference *current = *list;
Martin v. Löwis18e16552006-02-15 17:27:45 +0000884 Py_ssize_t count = _PyWeakref_GetWeakrefCount(current);
Fred Drakeef8ebd12001-12-10 23:44:54 +0000885 int restore_error = PyErr_Occurred() ? 1 : 0;
886 PyObject *err_type, *err_value, *err_tb;
Fred Drake8844d522001-10-05 21:52:26 +0000887
Fred Drakeef8ebd12001-12-10 23:44:54 +0000888 if (restore_error)
889 PyErr_Fetch(&err_type, &err_value, &err_tb);
Fred Drake8844d522001-10-05 21:52:26 +0000890 if (count == 1) {
Fred Drake8844d522001-10-05 21:52:26 +0000891 PyObject *callback = current->wr_callback;
Fred Drake8844d522001-10-05 21:52:26 +0000892
Fred Drakeef8ebd12001-12-10 23:44:54 +0000893 current->wr_callback = NULL;
Fred Drake8844d522001-10-05 21:52:26 +0000894 clear_weakref(current);
Fred Drake0a4dd392004-07-02 18:57:45 +0000895 if (callback != NULL) {
896 handle_callback(current, callback);
897 Py_DECREF(callback);
898 }
Fred Drake8844d522001-10-05 21:52:26 +0000899 }
900 else {
Hye-Shik Chang4af5c8c2006-03-07 15:39:21 +0000901 PyObject *tuple;
Martin v. Löwis18e16552006-02-15 17:27:45 +0000902 Py_ssize_t i = 0;
Hye-Shik Chang4af5c8c2006-03-07 15:39:21 +0000903
904 tuple = PyTuple_New(count * 2);
905 if (tuple == NULL) {
906 if (restore_error)
907 PyErr_Fetch(&err_type, &err_value, &err_tb);
908 return;
909 }
Fred Drake8844d522001-10-05 21:52:26 +0000910
911 for (i = 0; i < count; ++i) {
912 PyWeakReference *next = current->wr_next;
913
914 Py_INCREF(current);
915 PyTuple_SET_ITEM(tuple, i * 2, (PyObject *) current);
916 PyTuple_SET_ITEM(tuple, i * 2 + 1, current->wr_callback);
917 current->wr_callback = NULL;
Fred Drake8844d522001-10-05 21:52:26 +0000918 clear_weakref(current);
919 current = next;
920 }
921 for (i = 0; i < count; ++i) {
Fred Drake8844d522001-10-05 21:52:26 +0000922 PyObject *callback = PyTuple_GET_ITEM(tuple, i * 2 + 1);
Fred Drakeef8ebd12001-12-10 23:44:54 +0000923
Fred Drake0a4dd392004-07-02 18:57:45 +0000924 if (callback != NULL) {
Neal Norwitz0c6e2f12006-01-08 06:13:44 +0000925 PyObject *item = PyTuple_GET_ITEM(tuple, i * 2);
926 handle_callback((PyWeakReference *)item, callback);
Fred Drake0a4dd392004-07-02 18:57:45 +0000927 }
Fred Drake8844d522001-10-05 21:52:26 +0000928 }
929 Py_DECREF(tuple);
930 }
Fred Drakeef8ebd12001-12-10 23:44:54 +0000931 if (restore_error)
932 PyErr_Restore(err_type, err_value, err_tb);
Fred Drake8844d522001-10-05 21:52:26 +0000933 }
934}