blob: 826f5710dcf37f7a89482a88f79b037887126eaf [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)
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 Woutersc6e55062006-04-15 21:47:09 +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{
187 if (op != Py_EQ || self->ob_type != other->ob_type) {
188 Py_INCREF(Py_NotImplemented);
189 return Py_NotImplemented;
190 }
191 if (PyWeakref_GET_OBJECT(self) == Py_None
192 || PyWeakref_GET_OBJECT(other) == Py_None) {
193 PyObject *res = self==other ? Py_True : Py_False;
194 Py_INCREF(res);
195 return res;
196 }
197 return PyObject_RichCompare(PyWeakref_GET_OBJECT(self),
198 PyWeakref_GET_OBJECT(other), op);
199}
200
Fred Drake0a4dd392004-07-02 18:57:45 +0000201/* Given the head of an object's list of weak references, extract the
202 * two callback-less refs (ref and proxy). Used to determine if the
203 * shared references exist and to determine the back link for newly
204 * inserted references.
205 */
206static void
207get_basic_refs(PyWeakReference *head,
208 PyWeakReference **refp, PyWeakReference **proxyp)
209{
210 *refp = NULL;
211 *proxyp = NULL;
212
213 if (head != NULL && head->wr_callback == NULL) {
214 /* We need to be careful that the "basic refs" aren't
215 subclasses of the main types. That complicates this a
216 little. */
217 if (PyWeakref_CheckRefExact(head)) {
218 *refp = head;
219 head = head->wr_next;
220 }
221 if (head != NULL
222 && head->wr_callback == NULL
223 && PyWeakref_CheckProxy(head)) {
224 *proxyp = head;
225 /* head = head->wr_next; */
226 }
227 }
228}
229
230/* Insert 'newref' in the list after 'prev'. Both must be non-NULL. */
231static void
232insert_after(PyWeakReference *newref, PyWeakReference *prev)
233{
234 newref->wr_prev = prev;
235 newref->wr_next = prev->wr_next;
236 if (prev->wr_next != NULL)
237 prev->wr_next->wr_prev = newref;
238 prev->wr_next = newref;
239}
240
241/* Insert 'newref' at the head of the list; 'list' points to the variable
242 * that stores the head.
243 */
244static void
245insert_head(PyWeakReference *newref, PyWeakReference **list)
246{
247 PyWeakReference *next = *list;
248
249 newref->wr_prev = NULL;
250 newref->wr_next = next;
251 if (next != NULL)
252 next->wr_prev = newref;
253 *list = newref;
254}
255
256static int
257parse_weakref_init_args(char *funcname, PyObject *args, PyObject *kwargs,
258 PyObject **obp, PyObject **callbackp)
259{
260 /* XXX Should check that kwargs == NULL or is empty. */
261 return PyArg_UnpackTuple(args, funcname, 1, 2, obp, callbackp);
262}
263
264static PyObject *
265weakref___new__(PyTypeObject *type, PyObject *args, PyObject *kwargs)
266{
267 PyWeakReference *self = NULL;
268 PyObject *ob, *callback = NULL;
269
270 if (parse_weakref_init_args("__new__", args, kwargs, &ob, &callback)) {
271 PyWeakReference *ref, *proxy;
272 PyWeakReference **list;
273
274 if (!PyType_SUPPORTS_WEAKREFS(ob->ob_type)) {
275 PyErr_Format(PyExc_TypeError,
276 "cannot create weak reference to '%s' object",
277 ob->ob_type->tp_name);
278 return NULL;
279 }
280 if (callback == Py_None)
281 callback = NULL;
282 list = GET_WEAKREFS_LISTPTR(ob);
283 get_basic_refs(*list, &ref, &proxy);
284 if (callback == NULL && type == &_PyWeakref_RefType) {
285 if (ref != NULL) {
286 /* We can re-use an existing reference. */
287 Py_INCREF(ref);
288 return (PyObject *)ref;
289 }
290 }
291 /* We have to create a new reference. */
292 /* Note: the tp_alloc() can trigger cyclic GC, so the weakref
293 list on ob can be mutated. This means that the ref and
294 proxy pointers we got back earlier may have been collected,
295 so we need to compute these values again before we use
296 them. */
297 self = (PyWeakReference *) (type->tp_alloc(type, 0));
298 if (self != NULL) {
299 init_weakref(self, ob, callback);
300 if (callback == NULL && type == &_PyWeakref_RefType) {
301 insert_head(self, list);
302 }
303 else {
304 PyWeakReference *prev;
305
306 get_basic_refs(*list, &ref, &proxy);
307 prev = (proxy == NULL) ? ref : proxy;
308 if (prev == NULL)
309 insert_head(self, list);
310 else
311 insert_after(self, prev);
312 }
313 }
314 }
315 return (PyObject *)self;
316}
317
318static int
319weakref___init__(PyObject *self, PyObject *args, PyObject *kwargs)
320{
321 PyObject *tmp;
322
323 if (parse_weakref_init_args("__init__", args, kwargs, &tmp, &tmp))
324 return 0;
325 else
326 return 1;
327}
328
Fred Drake8844d522001-10-05 21:52:26 +0000329
330PyTypeObject
331_PyWeakref_RefType = {
332 PyObject_HEAD_INIT(&PyType_Type)
333 0,
334 "weakref",
335 sizeof(PyWeakReference),
336 0,
Fred Drake0a4dd392004-07-02 18:57:45 +0000337 weakref_dealloc, /*tp_dealloc*/
Fred Drake8844d522001-10-05 21:52:26 +0000338 0, /*tp_print*/
339 0, /*tp_getattr*/
340 0, /*tp_setattr*/
341 0, /*tp_compare*/
342 (reprfunc)weakref_repr, /*tp_repr*/
343 0, /*tp_as_number*/
344 0, /*tp_as_sequence*/
345 0, /*tp_as_mapping*/
Fred Drake0a4dd392004-07-02 18:57:45 +0000346 (hashfunc)weakref_hash, /*tp_hash*/
Fred Drake8844d522001-10-05 21:52:26 +0000347 (ternaryfunc)weakref_call, /*tp_call*/
348 0, /*tp_str*/
349 0, /*tp_getattro*/
350 0, /*tp_setattro*/
351 0, /*tp_as_buffer*/
Fred Drake0a4dd392004-07-02 18:57:45 +0000352 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_RICHCOMPARE
353 | Py_TPFLAGS_BASETYPE, /*tp_flags*/
Fred Drake8844d522001-10-05 21:52:26 +0000354 0, /*tp_doc*/
355 (traverseproc)gc_traverse, /*tp_traverse*/
356 (inquiry)gc_clear, /*tp_clear*/
357 (richcmpfunc)weakref_richcompare, /*tp_richcompare*/
Fred Drake0a4dd392004-07-02 18:57:45 +0000358 0, /*tp_weaklistoffset*/
359 0, /*tp_iter*/
360 0, /*tp_iternext*/
361 0, /*tp_methods*/
362 0, /*tp_members*/
363 0, /*tp_getset*/
364 0, /*tp_base*/
365 0, /*tp_dict*/
366 0, /*tp_descr_get*/
367 0, /*tp_descr_set*/
368 0, /*tp_dictoffset*/
Georg Brandl347b3002006-03-30 11:57:00 +0000369 weakref___init__, /*tp_init*/
Fred Drake0a4dd392004-07-02 18:57:45 +0000370 PyType_GenericAlloc, /*tp_alloc*/
371 weakref___new__, /*tp_new*/
372 PyObject_GC_Del, /*tp_free*/
Fred Drake8844d522001-10-05 21:52:26 +0000373};
374
375
376static int
377proxy_checkref(PyWeakReference *proxy)
378{
379 if (PyWeakref_GET_OBJECT(proxy) == Py_None) {
380 PyErr_SetString(PyExc_ReferenceError,
381 "weakly-referenced object no longer exists");
382 return 0;
383 }
384 return 1;
385}
386
387
Fred Drake73006d02001-10-18 18:04:18 +0000388/* If a parameter is a proxy, check that it is still "live" and wrap it,
389 * replacing the original value with the raw object. Raises ReferenceError
390 * if the param is a dead proxy.
391 */
392#define UNWRAP(o) \
393 if (PyWeakref_CheckProxy(o)) { \
394 if (!proxy_checkref((PyWeakReference *)o)) \
395 return NULL; \
396 o = PyWeakref_GET_OBJECT(o); \
397 }
398
Fred Drake2a908f62001-12-19 16:44:30 +0000399#define UNWRAP_I(o) \
400 if (PyWeakref_CheckProxy(o)) { \
401 if (!proxy_checkref((PyWeakReference *)o)) \
402 return -1; \
403 o = PyWeakref_GET_OBJECT(o); \
404 }
405
Fred Drake8844d522001-10-05 21:52:26 +0000406#define WRAP_UNARY(method, generic) \
407 static PyObject * \
Fred Drake73006d02001-10-18 18:04:18 +0000408 method(PyObject *proxy) { \
409 UNWRAP(proxy); \
410 return generic(proxy); \
Fred Drake8844d522001-10-05 21:52:26 +0000411 }
412
413#define WRAP_BINARY(method, generic) \
414 static PyObject * \
Fred Drake73006d02001-10-18 18:04:18 +0000415 method(PyObject *x, PyObject *y) { \
416 UNWRAP(x); \
417 UNWRAP(y); \
418 return generic(x, y); \
Fred Drake8844d522001-10-05 21:52:26 +0000419 }
420
Fred Drake31f4d1f2001-10-18 19:21:46 +0000421/* Note that the third arg needs to be checked for NULL since the tp_call
422 * slot can receive NULL for this arg.
Fred Drake73006d02001-10-18 18:04:18 +0000423 */
Fred Drake8844d522001-10-05 21:52:26 +0000424#define WRAP_TERNARY(method, generic) \
425 static PyObject * \
Fred Drake73006d02001-10-18 18:04:18 +0000426 method(PyObject *proxy, PyObject *v, PyObject *w) { \
427 UNWRAP(proxy); \
Fred Drake31f4d1f2001-10-18 19:21:46 +0000428 UNWRAP(v); \
Fred Drake73006d02001-10-18 18:04:18 +0000429 if (w != NULL) \
430 UNWRAP(w); \
431 return generic(proxy, v, w); \
Fred Drake8844d522001-10-05 21:52:26 +0000432 }
433
434
435/* direct slots */
436
437WRAP_BINARY(proxy_getattr, PyObject_GetAttr)
438WRAP_UNARY(proxy_str, PyObject_Str)
439WRAP_TERNARY(proxy_call, PyEval_CallObjectWithKeywords)
440
Fred Drake8844d522001-10-05 21:52:26 +0000441static PyObject *
442proxy_repr(PyWeakReference *proxy)
443{
444 char buf[160];
Barry Warsawd5867562001-11-28 21:01:56 +0000445 PyOS_snprintf(buf, sizeof(buf),
Guido van Rossumc1f6e8c2003-04-16 21:13:23 +0000446 "<weakproxy at %p to %.100s at %p>", proxy,
Barry Warsawd5867562001-11-28 21:01:56 +0000447 PyWeakref_GET_OBJECT(proxy)->ob_type->tp_name,
448 PyWeakref_GET_OBJECT(proxy));
Fred Drake8844d522001-10-05 21:52:26 +0000449 return PyString_FromString(buf);
450}
451
452
453static int
454proxy_setattr(PyWeakReference *proxy, PyObject *name, PyObject *value)
455{
456 if (!proxy_checkref(proxy))
457 return -1;
458 return PyObject_SetAttr(PyWeakref_GET_OBJECT(proxy), name, value);
459}
460
461static int
Fred Drake2a908f62001-12-19 16:44:30 +0000462proxy_compare(PyObject *proxy, PyObject *v)
Fred Drake8844d522001-10-05 21:52:26 +0000463{
Fred Drake2a908f62001-12-19 16:44:30 +0000464 UNWRAP_I(proxy);
465 UNWRAP_I(v);
466 return PyObject_Compare(proxy, v);
Fred Drake8844d522001-10-05 21:52:26 +0000467}
468
469/* number slots */
470WRAP_BINARY(proxy_add, PyNumber_Add)
471WRAP_BINARY(proxy_sub, PyNumber_Subtract)
472WRAP_BINARY(proxy_mul, PyNumber_Multiply)
473WRAP_BINARY(proxy_div, PyNumber_Divide)
474WRAP_BINARY(proxy_mod, PyNumber_Remainder)
475WRAP_BINARY(proxy_divmod, PyNumber_Divmod)
476WRAP_TERNARY(proxy_pow, PyNumber_Power)
477WRAP_UNARY(proxy_neg, PyNumber_Negative)
478WRAP_UNARY(proxy_pos, PyNumber_Positive)
479WRAP_UNARY(proxy_abs, PyNumber_Absolute)
480WRAP_UNARY(proxy_invert, PyNumber_Invert)
481WRAP_BINARY(proxy_lshift, PyNumber_Lshift)
482WRAP_BINARY(proxy_rshift, PyNumber_Rshift)
483WRAP_BINARY(proxy_and, PyNumber_And)
484WRAP_BINARY(proxy_xor, PyNumber_Xor)
485WRAP_BINARY(proxy_or, PyNumber_Or)
486WRAP_UNARY(proxy_int, PyNumber_Int)
487WRAP_UNARY(proxy_long, PyNumber_Long)
488WRAP_UNARY(proxy_float, PyNumber_Float)
489WRAP_BINARY(proxy_iadd, PyNumber_InPlaceAdd)
490WRAP_BINARY(proxy_isub, PyNumber_InPlaceSubtract)
491WRAP_BINARY(proxy_imul, PyNumber_InPlaceMultiply)
492WRAP_BINARY(proxy_idiv, PyNumber_InPlaceDivide)
493WRAP_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 = {
Georg Brandl347b3002006-03-30 11:57:00 +0000590 proxy_add, /*nb_add*/
591 proxy_sub, /*nb_subtract*/
592 proxy_mul, /*nb_multiply*/
593 proxy_div, /*nb_divide*/
594 proxy_mod, /*nb_remainder*/
595 proxy_divmod, /*nb_divmod*/
596 proxy_pow, /*nb_power*/
597 proxy_neg, /*nb_negative*/
598 proxy_pos, /*nb_positive*/
599 proxy_abs, /*nb_absolute*/
600 (inquiry)proxy_nonzero, /*nb_nonzero*/
601 proxy_invert, /*nb_invert*/
602 proxy_lshift, /*nb_lshift*/
603 proxy_rshift, /*nb_rshift*/
604 proxy_and, /*nb_and*/
605 proxy_xor, /*nb_xor*/
606 proxy_or, /*nb_or*/
607 0, /*nb_coerce*/
608 proxy_int, /*nb_int*/
609 proxy_long, /*nb_long*/
610 proxy_float, /*nb_float*/
611 0, /*nb_oct*/
612 0, /*nb_hex*/
613 proxy_iadd, /*nb_inplace_add*/
614 proxy_isub, /*nb_inplace_subtract*/
615 proxy_imul, /*nb_inplace_multiply*/
616 proxy_idiv, /*nb_inplace_divide*/
617 proxy_imod, /*nb_inplace_remainder*/
618 proxy_ipow, /*nb_inplace_power*/
619 proxy_ilshift, /*nb_inplace_lshift*/
620 proxy_irshift, /*nb_inplace_rshift*/
621 proxy_iand, /*nb_inplace_and*/
622 proxy_ixor, /*nb_inplace_xor*/
623 proxy_ior, /*nb_inplace_or*/
Fred Drake8844d522001-10-05 21:52:26 +0000624};
625
626static PySequenceMethods proxy_as_sequence = {
Martin v. Löwis18e16552006-02-15 17:27:45 +0000627 (lenfunc)proxy_length, /*sq_length*/
Fred Drake8844d522001-10-05 21:52:26 +0000628 0, /*sq_concat*/
629 0, /*sq_repeat*/
630 0, /*sq_item*/
Martin v. Löwis18e16552006-02-15 17:27:45 +0000631 (ssizessizeargfunc)proxy_slice, /*sq_slice*/
Fred Drake8844d522001-10-05 21:52:26 +0000632 0, /*sq_ass_item*/
Martin v. Löwis18e16552006-02-15 17:27:45 +0000633 (ssizessizeobjargproc)proxy_ass_slice, /*sq_ass_slice*/
Fred Drake8844d522001-10-05 21:52:26 +0000634 (objobjproc)proxy_contains, /* sq_contains */
635};
636
637static PyMappingMethods proxy_as_mapping = {
Georg Brandl347b3002006-03-30 11:57:00 +0000638 (lenfunc)proxy_length, /*mp_length*/
639 proxy_getitem, /*mp_subscript*/
Fred Drake8844d522001-10-05 21:52:26 +0000640 (objobjargproc)proxy_setitem, /*mp_ass_subscript*/
641};
642
643
644PyTypeObject
645_PyWeakref_ProxyType = {
646 PyObject_HEAD_INIT(&PyType_Type)
647 0,
648 "weakproxy",
649 sizeof(PyWeakReference),
650 0,
651 /* methods */
Fred Drake0a4dd392004-07-02 18:57:45 +0000652 (destructor)proxy_dealloc, /* tp_dealloc */
Fred Drakefe89cc12003-07-14 21:46:23 +0000653 0, /* tp_print */
Fred Drakef16c3dc2002-08-09 18:34:16 +0000654 0, /* tp_getattr */
655 0, /* tp_setattr */
656 proxy_compare, /* tp_compare */
Georg Brandl347b3002006-03-30 11:57:00 +0000657 (reprfunc)proxy_repr, /* tp_repr */
Fred Drakef16c3dc2002-08-09 18:34:16 +0000658 &proxy_as_number, /* tp_as_number */
659 &proxy_as_sequence, /* tp_as_sequence */
660 &proxy_as_mapping, /* tp_as_mapping */
661 0, /* tp_hash */
Georg Brandl347b3002006-03-30 11:57:00 +0000662 0, /* tp_call */
663 proxy_str, /* tp_str */
664 proxy_getattr, /* tp_getattro */
Fred Drakef16c3dc2002-08-09 18:34:16 +0000665 (setattrofunc)proxy_setattr, /* tp_setattro */
666 0, /* tp_as_buffer */
Fred Drake8844d522001-10-05 21:52:26 +0000667 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC
Fred Drakef16c3dc2002-08-09 18:34:16 +0000668 | Py_TPFLAGS_CHECKTYPES, /* tp_flags */
669 0, /* tp_doc */
670 (traverseproc)gc_traverse, /* tp_traverse */
671 (inquiry)gc_clear, /* tp_clear */
672 0, /* tp_richcompare */
673 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 */
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
722 if (!PyType_SUPPORTS_WEAKREFS(ob->ob_type)) {
723 PyErr_Format(PyExc_TypeError,
Jeremy Hylton996fad32001-10-22 16:31:40 +0000724 "cannot create weak reference to '%s' object",
Fred Drake8844d522001-10-05 21:52:26 +0000725 ob->ob_type->tp_name);
726 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
781 if (!PyType_SUPPORTS_WEAKREFS(ob->ob_type)) {
782 PyErr_Format(PyExc_TypeError,
Jeremy Hylton996fad32001-10-22 16:31:40 +0000783 "cannot create weak reference to '%s' object",
Fred Drake8844d522001-10-05 21:52:26 +0000784 ob->ob_type->tp_name);
785 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))
807 result->ob_type = &_PyWeakref_CallableProxyType;
808 else
809 result->ob_type = &_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
874 || !PyType_SUPPORTS_WEAKREFS(object->ob_type)
875 || 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}