blob: 39595ae6bc97c8d690ad8184dcac1eadc92b4575 [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
9long
10_PyWeakref_GetWeakrefCount(PyWeakReference *head)
11{
12 long count = 0;
13
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{
112 if (self->wr_callback != NULL)
113 return visit(self->wr_callback, arg);
114 return 0;
115}
116
117
118static int
119gc_clear(PyWeakReference *self)
120{
121 clear_weakref(self);
122 return 0;
123}
124
125
126static PyObject *
127weakref_call(PyWeakReference *self, PyObject *args, PyObject *kw)
128{
Martin v. Löwis15e62742006-02-27 16:46:16 +0000129 static char *kwlist[] = {NULL};
Fred Drake8844d522001-10-05 21:52:26 +0000130
Martin v. Löwis15e62742006-02-27 16:46:16 +0000131 if (PyArg_ParseTupleAndKeywords(args, kw, ":__call__", kwlist)) {
Fred Drake8844d522001-10-05 21:52:26 +0000132 PyObject *object = PyWeakref_GET_OBJECT(self);
133 Py_INCREF(object);
134 return (object);
135 }
136 return NULL;
137}
138
139
140static long
141weakref_hash(PyWeakReference *self)
142{
143 if (self->hash != -1)
144 return self->hash;
145 if (PyWeakref_GET_OBJECT(self) == Py_None) {
146 PyErr_SetString(PyExc_TypeError, "weak object has gone away");
147 return -1;
148 }
149 self->hash = PyObject_Hash(PyWeakref_GET_OBJECT(self));
150 return self->hash;
151}
Tim Peters403a2032003-11-20 21:21:46 +0000152
Fred Drake8844d522001-10-05 21:52:26 +0000153
154static PyObject *
155weakref_repr(PyWeakReference *self)
156{
157 char buffer[256];
158 if (PyWeakref_GET_OBJECT(self) == Py_None) {
Guido van Rossumc1f6e8c2003-04-16 21:13:23 +0000159 PyOS_snprintf(buffer, sizeof(buffer), "<weakref at %p; dead>", self);
Fred Drake8844d522001-10-05 21:52:26 +0000160 }
161 else {
Guido van Rossumc1f6e8c2003-04-16 21:13:23 +0000162 char *name = NULL;
163 PyObject *nameobj = PyObject_GetAttrString(PyWeakref_GET_OBJECT(self),
164 "__name__");
165 if (nameobj == NULL)
166 PyErr_Clear();
167 else if (PyString_Check(nameobj))
168 name = PyString_AS_STRING(nameobj);
Barry Warsawd5867562001-11-28 21:01:56 +0000169 PyOS_snprintf(buffer, sizeof(buffer),
Guido van Rossumc1f6e8c2003-04-16 21:13:23 +0000170 name ? "<weakref at %p; to '%.50s' at %p (%s)>"
171 : "<weakref at %p; to '%.50s' at %p>",
172 self,
Barry Warsawd5867562001-11-28 21:01:56 +0000173 PyWeakref_GET_OBJECT(self)->ob_type->tp_name,
Guido van Rossumc1f6e8c2003-04-16 21:13:23 +0000174 PyWeakref_GET_OBJECT(self),
175 name);
176 Py_XDECREF(nameobj);
Fred Drake8844d522001-10-05 21:52:26 +0000177 }
178 return PyString_FromString(buffer);
179}
180
181/* Weak references only support equality, not ordering. Two weak references
182 are equal if the underlying objects are equal. If the underlying object has
183 gone away, they are equal if they are identical. */
184
185static PyObject *
186weakref_richcompare(PyWeakReference* self, PyWeakReference* other, int op)
187{
188 if (op != Py_EQ || self->ob_type != other->ob_type) {
189 Py_INCREF(Py_NotImplemented);
190 return Py_NotImplemented;
191 }
192 if (PyWeakref_GET_OBJECT(self) == Py_None
193 || PyWeakref_GET_OBJECT(other) == Py_None) {
194 PyObject *res = self==other ? Py_True : Py_False;
195 Py_INCREF(res);
196 return res;
197 }
198 return PyObject_RichCompare(PyWeakref_GET_OBJECT(self),
199 PyWeakref_GET_OBJECT(other), op);
200}
201
Fred Drake0a4dd392004-07-02 18:57:45 +0000202/* Given the head of an object's list of weak references, extract the
203 * two callback-less refs (ref and proxy). Used to determine if the
204 * shared references exist and to determine the back link for newly
205 * inserted references.
206 */
207static void
208get_basic_refs(PyWeakReference *head,
209 PyWeakReference **refp, PyWeakReference **proxyp)
210{
211 *refp = NULL;
212 *proxyp = NULL;
213
214 if (head != NULL && head->wr_callback == NULL) {
215 /* We need to be careful that the "basic refs" aren't
216 subclasses of the main types. That complicates this a
217 little. */
218 if (PyWeakref_CheckRefExact(head)) {
219 *refp = head;
220 head = head->wr_next;
221 }
222 if (head != NULL
223 && head->wr_callback == NULL
224 && PyWeakref_CheckProxy(head)) {
225 *proxyp = head;
226 /* head = head->wr_next; */
227 }
228 }
229}
230
231/* Insert 'newref' in the list after 'prev'. Both must be non-NULL. */
232static void
233insert_after(PyWeakReference *newref, PyWeakReference *prev)
234{
235 newref->wr_prev = prev;
236 newref->wr_next = prev->wr_next;
237 if (prev->wr_next != NULL)
238 prev->wr_next->wr_prev = newref;
239 prev->wr_next = newref;
240}
241
242/* Insert 'newref' at the head of the list; 'list' points to the variable
243 * that stores the head.
244 */
245static void
246insert_head(PyWeakReference *newref, PyWeakReference **list)
247{
248 PyWeakReference *next = *list;
249
250 newref->wr_prev = NULL;
251 newref->wr_next = next;
252 if (next != NULL)
253 next->wr_prev = newref;
254 *list = newref;
255}
256
257static int
258parse_weakref_init_args(char *funcname, PyObject *args, PyObject *kwargs,
259 PyObject **obp, PyObject **callbackp)
260{
261 /* XXX Should check that kwargs == NULL or is empty. */
262 return PyArg_UnpackTuple(args, funcname, 1, 2, obp, callbackp);
263}
264
265static PyObject *
266weakref___new__(PyTypeObject *type, PyObject *args, PyObject *kwargs)
267{
268 PyWeakReference *self = NULL;
269 PyObject *ob, *callback = NULL;
270
271 if (parse_weakref_init_args("__new__", args, kwargs, &ob, &callback)) {
272 PyWeakReference *ref, *proxy;
273 PyWeakReference **list;
274
275 if (!PyType_SUPPORTS_WEAKREFS(ob->ob_type)) {
276 PyErr_Format(PyExc_TypeError,
277 "cannot create weak reference to '%s' object",
278 ob->ob_type->tp_name);
279 return NULL;
280 }
281 if (callback == Py_None)
282 callback = NULL;
283 list = GET_WEAKREFS_LISTPTR(ob);
284 get_basic_refs(*list, &ref, &proxy);
285 if (callback == NULL && type == &_PyWeakref_RefType) {
286 if (ref != NULL) {
287 /* We can re-use an existing reference. */
288 Py_INCREF(ref);
289 return (PyObject *)ref;
290 }
291 }
292 /* We have to create a new reference. */
293 /* Note: the tp_alloc() can trigger cyclic GC, so the weakref
294 list on ob can be mutated. This means that the ref and
295 proxy pointers we got back earlier may have been collected,
296 so we need to compute these values again before we use
297 them. */
298 self = (PyWeakReference *) (type->tp_alloc(type, 0));
299 if (self != NULL) {
300 init_weakref(self, ob, callback);
301 if (callback == NULL && type == &_PyWeakref_RefType) {
302 insert_head(self, list);
303 }
304 else {
305 PyWeakReference *prev;
306
307 get_basic_refs(*list, &ref, &proxy);
308 prev = (proxy == NULL) ? ref : proxy;
309 if (prev == NULL)
310 insert_head(self, list);
311 else
312 insert_after(self, prev);
313 }
314 }
315 }
316 return (PyObject *)self;
317}
318
319static int
320weakref___init__(PyObject *self, PyObject *args, PyObject *kwargs)
321{
322 PyObject *tmp;
323
324 if (parse_weakref_init_args("__init__", args, kwargs, &tmp, &tmp))
325 return 0;
326 else
327 return 1;
328}
329
Fred Drake8844d522001-10-05 21:52:26 +0000330
331PyTypeObject
332_PyWeakref_RefType = {
333 PyObject_HEAD_INIT(&PyType_Type)
334 0,
335 "weakref",
336 sizeof(PyWeakReference),
337 0,
Fred Drake0a4dd392004-07-02 18:57:45 +0000338 weakref_dealloc, /*tp_dealloc*/
Fred Drake8844d522001-10-05 21:52:26 +0000339 0, /*tp_print*/
340 0, /*tp_getattr*/
341 0, /*tp_setattr*/
342 0, /*tp_compare*/
343 (reprfunc)weakref_repr, /*tp_repr*/
344 0, /*tp_as_number*/
345 0, /*tp_as_sequence*/
346 0, /*tp_as_mapping*/
Fred Drake0a4dd392004-07-02 18:57:45 +0000347 (hashfunc)weakref_hash, /*tp_hash*/
Fred Drake8844d522001-10-05 21:52:26 +0000348 (ternaryfunc)weakref_call, /*tp_call*/
349 0, /*tp_str*/
350 0, /*tp_getattro*/
351 0, /*tp_setattro*/
352 0, /*tp_as_buffer*/
Fred Drake0a4dd392004-07-02 18:57:45 +0000353 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_RICHCOMPARE
354 | Py_TPFLAGS_BASETYPE, /*tp_flags*/
Fred Drake8844d522001-10-05 21:52:26 +0000355 0, /*tp_doc*/
356 (traverseproc)gc_traverse, /*tp_traverse*/
357 (inquiry)gc_clear, /*tp_clear*/
358 (richcmpfunc)weakref_richcompare, /*tp_richcompare*/
Fred Drake0a4dd392004-07-02 18:57:45 +0000359 0, /*tp_weaklistoffset*/
360 0, /*tp_iter*/
361 0, /*tp_iternext*/
362 0, /*tp_methods*/
363 0, /*tp_members*/
364 0, /*tp_getset*/
365 0, /*tp_base*/
366 0, /*tp_dict*/
367 0, /*tp_descr_get*/
368 0, /*tp_descr_set*/
369 0, /*tp_dictoffset*/
370 (initproc)weakref___init__, /*tp_init*/
371 PyType_GenericAlloc, /*tp_alloc*/
372 weakref___new__, /*tp_new*/
373 PyObject_GC_Del, /*tp_free*/
Fred Drake8844d522001-10-05 21:52:26 +0000374};
375
376
377static int
378proxy_checkref(PyWeakReference *proxy)
379{
380 if (PyWeakref_GET_OBJECT(proxy) == Py_None) {
381 PyErr_SetString(PyExc_ReferenceError,
382 "weakly-referenced object no longer exists");
383 return 0;
384 }
385 return 1;
386}
387
388
Fred Drake73006d02001-10-18 18:04:18 +0000389/* If a parameter is a proxy, check that it is still "live" and wrap it,
390 * replacing the original value with the raw object. Raises ReferenceError
391 * if the param is a dead proxy.
392 */
393#define UNWRAP(o) \
394 if (PyWeakref_CheckProxy(o)) { \
395 if (!proxy_checkref((PyWeakReference *)o)) \
396 return NULL; \
397 o = PyWeakref_GET_OBJECT(o); \
398 }
399
Fred Drake2a908f62001-12-19 16:44:30 +0000400#define UNWRAP_I(o) \
401 if (PyWeakref_CheckProxy(o)) { \
402 if (!proxy_checkref((PyWeakReference *)o)) \
403 return -1; \
404 o = PyWeakref_GET_OBJECT(o); \
405 }
406
Fred Drake8844d522001-10-05 21:52:26 +0000407#define WRAP_UNARY(method, generic) \
408 static PyObject * \
Fred Drake73006d02001-10-18 18:04:18 +0000409 method(PyObject *proxy) { \
410 UNWRAP(proxy); \
411 return generic(proxy); \
Fred Drake8844d522001-10-05 21:52:26 +0000412 }
413
414#define WRAP_BINARY(method, generic) \
415 static PyObject * \
Fred Drake73006d02001-10-18 18:04:18 +0000416 method(PyObject *x, PyObject *y) { \
417 UNWRAP(x); \
418 UNWRAP(y); \
419 return generic(x, y); \
Fred Drake8844d522001-10-05 21:52:26 +0000420 }
421
Fred Drake31f4d1f2001-10-18 19:21:46 +0000422/* Note that the third arg needs to be checked for NULL since the tp_call
423 * slot can receive NULL for this arg.
Fred Drake73006d02001-10-18 18:04:18 +0000424 */
Fred Drake8844d522001-10-05 21:52:26 +0000425#define WRAP_TERNARY(method, generic) \
426 static PyObject * \
Fred Drake73006d02001-10-18 18:04:18 +0000427 method(PyObject *proxy, PyObject *v, PyObject *w) { \
428 UNWRAP(proxy); \
Fred Drake31f4d1f2001-10-18 19:21:46 +0000429 UNWRAP(v); \
Fred Drake73006d02001-10-18 18:04:18 +0000430 if (w != NULL) \
431 UNWRAP(w); \
432 return generic(proxy, v, w); \
Fred Drake8844d522001-10-05 21:52:26 +0000433 }
434
435
436/* direct slots */
437
438WRAP_BINARY(proxy_getattr, PyObject_GetAttr)
439WRAP_UNARY(proxy_str, PyObject_Str)
440WRAP_TERNARY(proxy_call, PyEval_CallObjectWithKeywords)
441
Fred Drake8844d522001-10-05 21:52:26 +0000442static PyObject *
443proxy_repr(PyWeakReference *proxy)
444{
445 char buf[160];
Barry Warsawd5867562001-11-28 21:01:56 +0000446 PyOS_snprintf(buf, sizeof(buf),
Guido van Rossumc1f6e8c2003-04-16 21:13:23 +0000447 "<weakproxy at %p to %.100s at %p>", proxy,
Barry Warsawd5867562001-11-28 21:01:56 +0000448 PyWeakref_GET_OBJECT(proxy)->ob_type->tp_name,
449 PyWeakref_GET_OBJECT(proxy));
Fred Drake8844d522001-10-05 21:52:26 +0000450 return PyString_FromString(buf);
451}
452
453
454static int
455proxy_setattr(PyWeakReference *proxy, PyObject *name, PyObject *value)
456{
457 if (!proxy_checkref(proxy))
458 return -1;
459 return PyObject_SetAttr(PyWeakref_GET_OBJECT(proxy), name, value);
460}
461
462static int
Fred Drake2a908f62001-12-19 16:44:30 +0000463proxy_compare(PyObject *proxy, PyObject *v)
Fred Drake8844d522001-10-05 21:52:26 +0000464{
Fred Drake2a908f62001-12-19 16:44:30 +0000465 UNWRAP_I(proxy);
466 UNWRAP_I(v);
467 return PyObject_Compare(proxy, v);
Fred Drake8844d522001-10-05 21:52:26 +0000468}
469
470/* number slots */
471WRAP_BINARY(proxy_add, PyNumber_Add)
472WRAP_BINARY(proxy_sub, PyNumber_Subtract)
473WRAP_BINARY(proxy_mul, PyNumber_Multiply)
Fred Drake8844d522001-10-05 21:52:26 +0000474WRAP_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)
Fred Drake8844d522001-10-05 21:52:26 +0000492WRAP_BINARY(proxy_imod, PyNumber_InPlaceRemainder)
493WRAP_TERNARY(proxy_ipow, PyNumber_InPlacePower)
494WRAP_BINARY(proxy_ilshift, PyNumber_InPlaceLshift)
495WRAP_BINARY(proxy_irshift, PyNumber_InPlaceRshift)
496WRAP_BINARY(proxy_iand, PyNumber_InPlaceAnd)
497WRAP_BINARY(proxy_ixor, PyNumber_InPlaceXor)
498WRAP_BINARY(proxy_ior, PyNumber_InPlaceOr)
499
Tim Peters403a2032003-11-20 21:21:46 +0000500static int
Fred Drake8844d522001-10-05 21:52:26 +0000501proxy_nonzero(PyWeakReference *proxy)
502{
503 PyObject *o = PyWeakref_GET_OBJECT(proxy);
504 if (!proxy_checkref(proxy))
Neal Norwitzbdcb9412004-07-08 01:22:31 +0000505 return -1;
Raymond Hettingere6c470f2005-03-27 03:04:54 +0000506 return PyObject_IsTrue(o);
Fred Drake8844d522001-10-05 21:52:26 +0000507}
508
Fred Drake0a4dd392004-07-02 18:57:45 +0000509static void
510proxy_dealloc(PyWeakReference *self)
511{
512 if (self->wr_callback != NULL)
513 PyObject_GC_UnTrack((PyObject *)self);
514 clear_weakref(self);
515 PyObject_GC_Del(self);
516}
517
Fred Drake8844d522001-10-05 21:52:26 +0000518/* sequence slots */
519
520static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000521proxy_slice(PyWeakReference *proxy, Py_ssize_t i, Py_ssize_t j)
Fred Drake8844d522001-10-05 21:52:26 +0000522{
523 if (!proxy_checkref(proxy))
524 return NULL;
525 return PySequence_GetSlice(PyWeakref_GET_OBJECT(proxy), i, j);
526}
527
528static int
Martin v. Löwis18e16552006-02-15 17:27:45 +0000529proxy_ass_slice(PyWeakReference *proxy, Py_ssize_t i, Py_ssize_t j, PyObject *value)
Fred Drake8844d522001-10-05 21:52:26 +0000530{
531 if (!proxy_checkref(proxy))
532 return -1;
533 return PySequence_SetSlice(PyWeakref_GET_OBJECT(proxy), i, j, value);
534}
535
536static int
537proxy_contains(PyWeakReference *proxy, PyObject *value)
538{
539 if (!proxy_checkref(proxy))
540 return -1;
541 return PySequence_Contains(PyWeakref_GET_OBJECT(proxy), value);
542}
543
544
545/* mapping slots */
546
Martin v. Löwis18e16552006-02-15 17:27:45 +0000547static Py_ssize_t
Fred Drake8844d522001-10-05 21:52:26 +0000548proxy_length(PyWeakReference *proxy)
549{
550 if (!proxy_checkref(proxy))
551 return -1;
552 return PyObject_Length(PyWeakref_GET_OBJECT(proxy));
553}
554
555WRAP_BINARY(proxy_getitem, PyObject_GetItem)
556
557static int
558proxy_setitem(PyWeakReference *proxy, PyObject *key, PyObject *value)
559{
560 if (!proxy_checkref(proxy))
561 return -1;
Raymond Hettingerd693a812003-06-30 04:18:48 +0000562
563 if (value == NULL)
564 return PyObject_DelItem(PyWeakref_GET_OBJECT(proxy), key);
565 else
566 return PyObject_SetItem(PyWeakref_GET_OBJECT(proxy), key, value);
Fred Drake8844d522001-10-05 21:52:26 +0000567}
568
Fred Drakef16c3dc2002-08-09 18:34:16 +0000569/* iterator slots */
570
571static PyObject *
572proxy_iter(PyWeakReference *proxy)
573{
574 if (!proxy_checkref(proxy))
575 return NULL;
576 return PyObject_GetIter(PyWeakref_GET_OBJECT(proxy));
577}
578
579static PyObject *
580proxy_iternext(PyWeakReference *proxy)
581{
582 if (!proxy_checkref(proxy))
583 return NULL;
584 return PyIter_Next(PyWeakref_GET_OBJECT(proxy));
585}
586
Fred Drake8844d522001-10-05 21:52:26 +0000587
588static PyNumberMethods proxy_as_number = {
589 (binaryfunc)proxy_add, /*nb_add*/
590 (binaryfunc)proxy_sub, /*nb_subtract*/
591 (binaryfunc)proxy_mul, /*nb_multiply*/
Fred Drake8844d522001-10-05 21:52:26 +0000592 (binaryfunc)proxy_mod, /*nb_remainder*/
593 (binaryfunc)proxy_divmod, /*nb_divmod*/
594 (ternaryfunc)proxy_pow, /*nb_power*/
595 (unaryfunc)proxy_neg, /*nb_negative*/
596 (unaryfunc)proxy_pos, /*nb_positive*/
597 (unaryfunc)proxy_abs, /*nb_absolute*/
598 (inquiry)proxy_nonzero, /*nb_nonzero*/
599 (unaryfunc)proxy_invert, /*nb_invert*/
600 (binaryfunc)proxy_lshift, /*nb_lshift*/
601 (binaryfunc)proxy_rshift, /*nb_rshift*/
602 (binaryfunc)proxy_and, /*nb_and*/
603 (binaryfunc)proxy_xor, /*nb_xor*/
604 (binaryfunc)proxy_or, /*nb_or*/
605 (coercion)0, /*nb_coerce*/
606 (unaryfunc)proxy_int, /*nb_int*/
607 (unaryfunc)proxy_long, /*nb_long*/
608 (unaryfunc)proxy_float, /*nb_float*/
609 (unaryfunc)0, /*nb_oct*/
610 (unaryfunc)0, /*nb_hex*/
611 (binaryfunc)proxy_iadd, /*nb_inplace_add*/
612 (binaryfunc)proxy_isub, /*nb_inplace_subtract*/
613 (binaryfunc)proxy_imul, /*nb_inplace_multiply*/
Fred Drake8844d522001-10-05 21:52:26 +0000614 (binaryfunc)proxy_imod, /*nb_inplace_remainder*/
615 (ternaryfunc)proxy_ipow, /*nb_inplace_power*/
616 (binaryfunc)proxy_ilshift, /*nb_inplace_lshift*/
617 (binaryfunc)proxy_irshift, /*nb_inplace_rshift*/
618 (binaryfunc)proxy_iand, /*nb_inplace_and*/
619 (binaryfunc)proxy_ixor, /*nb_inplace_xor*/
620 (binaryfunc)proxy_ior, /*nb_inplace_or*/
621};
622
623static PySequenceMethods proxy_as_sequence = {
Martin v. Löwis18e16552006-02-15 17:27:45 +0000624 (lenfunc)proxy_length, /*sq_length*/
Fred Drake8844d522001-10-05 21:52:26 +0000625 0, /*sq_concat*/
626 0, /*sq_repeat*/
627 0, /*sq_item*/
Martin v. Löwis18e16552006-02-15 17:27:45 +0000628 (ssizessizeargfunc)proxy_slice, /*sq_slice*/
Fred Drake8844d522001-10-05 21:52:26 +0000629 0, /*sq_ass_item*/
Martin v. Löwis18e16552006-02-15 17:27:45 +0000630 (ssizessizeobjargproc)proxy_ass_slice, /*sq_ass_slice*/
Fred Drake8844d522001-10-05 21:52:26 +0000631 (objobjproc)proxy_contains, /* sq_contains */
632};
633
634static PyMappingMethods proxy_as_mapping = {
Martin v. Löwis18e16552006-02-15 17:27:45 +0000635 (lenfunc)proxy_length, /*mp_length*/
Fred Drake8844d522001-10-05 21:52:26 +0000636 (binaryfunc)proxy_getitem, /*mp_subscript*/
637 (objobjargproc)proxy_setitem, /*mp_ass_subscript*/
638};
639
640
641PyTypeObject
642_PyWeakref_ProxyType = {
643 PyObject_HEAD_INIT(&PyType_Type)
644 0,
645 "weakproxy",
646 sizeof(PyWeakReference),
647 0,
648 /* methods */
Fred Drake0a4dd392004-07-02 18:57:45 +0000649 (destructor)proxy_dealloc, /* tp_dealloc */
Fred Drakefe89cc12003-07-14 21:46:23 +0000650 0, /* tp_print */
Fred Drakef16c3dc2002-08-09 18:34:16 +0000651 0, /* tp_getattr */
652 0, /* tp_setattr */
653 proxy_compare, /* tp_compare */
654 (unaryfunc)proxy_repr, /* tp_repr */
655 &proxy_as_number, /* tp_as_number */
656 &proxy_as_sequence, /* tp_as_sequence */
657 &proxy_as_mapping, /* tp_as_mapping */
658 0, /* tp_hash */
659 (ternaryfunc)0, /* tp_call */
660 (unaryfunc)proxy_str, /* tp_str */
661 (getattrofunc)proxy_getattr, /* tp_getattro */
662 (setattrofunc)proxy_setattr, /* tp_setattro */
663 0, /* tp_as_buffer */
Fred Drake8844d522001-10-05 21:52:26 +0000664 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC
Fred Drakef16c3dc2002-08-09 18:34:16 +0000665 | Py_TPFLAGS_CHECKTYPES, /* tp_flags */
666 0, /* tp_doc */
667 (traverseproc)gc_traverse, /* tp_traverse */
668 (inquiry)gc_clear, /* tp_clear */
669 0, /* tp_richcompare */
670 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 */
688 proxy_compare, /* tp_compare */
689 (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 */
694 (ternaryfunc)proxy_call, /* tp_call */
695 (unaryfunc)proxy_str, /* tp_str */
696 (getattrofunc)proxy_getattr, /* tp_getattro */
697 (setattrofunc)proxy_setattr, /* tp_setattro */
698 0, /* tp_as_buffer */
Fred Drake8844d522001-10-05 21:52:26 +0000699 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC
Fred Drakef16c3dc2002-08-09 18:34:16 +0000700 | Py_TPFLAGS_CHECKTYPES, /* tp_flags */
701 0, /* tp_doc */
702 (traverseproc)gc_traverse, /* tp_traverse */
703 (inquiry)gc_clear, /* tp_clear */
704 0, /* tp_richcompare */
705 0, /* tp_weaklistoffset */
706 (getiterfunc)proxy_iter, /* tp_iter */
707 (iternextfunc)proxy_iternext, /* tp_iternext */
Fred Drake8844d522001-10-05 21:52:26 +0000708};
709
710
Fred Drake8844d522001-10-05 21:52:26 +0000711
712PyObject *
713PyWeakref_NewRef(PyObject *ob, PyObject *callback)
714{
715 PyWeakReference *result = NULL;
716 PyWeakReference **list;
717 PyWeakReference *ref, *proxy;
718
719 if (!PyType_SUPPORTS_WEAKREFS(ob->ob_type)) {
720 PyErr_Format(PyExc_TypeError,
Jeremy Hylton996fad32001-10-22 16:31:40 +0000721 "cannot create weak reference to '%s' object",
Fred Drake8844d522001-10-05 21:52:26 +0000722 ob->ob_type->tp_name);
723 return NULL;
724 }
725 list = GET_WEAKREFS_LISTPTR(ob);
726 get_basic_refs(*list, &ref, &proxy);
Fred Drake6a2852c2004-02-03 19:52:56 +0000727 if (callback == Py_None)
728 callback = NULL;
729 if (callback == NULL)
Fred Drake8844d522001-10-05 21:52:26 +0000730 /* return existing weak reference if it exists */
731 result = ref;
732 if (result != NULL)
Fred Drakebc875f52004-02-04 23:14:14 +0000733 Py_INCREF(result);
Fred Drake8844d522001-10-05 21:52:26 +0000734 else {
Fred Drakebc875f52004-02-04 23:14:14 +0000735 /* Note: new_weakref() can trigger cyclic GC, so the weakref
736 list on ob can be mutated. This means that the ref and
737 proxy pointers we got back earlier may have been collected,
738 so we need to compute these values again before we use
739 them. */
Neil Schemenauer38a89162002-03-27 15:18:21 +0000740 result = new_weakref(ob, callback);
Fred Drake8844d522001-10-05 21:52:26 +0000741 if (result != NULL) {
Fred Drake6d3265d2004-08-03 14:47:25 +0000742 get_basic_refs(*list, &ref, &proxy);
Fred Drake8844d522001-10-05 21:52:26 +0000743 if (callback == NULL) {
Fred Drake6d3265d2004-08-03 14:47:25 +0000744 if (ref == NULL)
745 insert_head(result, list);
746 else {
747 /* Someone else added a ref without a callback
748 during GC. Return that one instead of this one
749 to avoid violating the invariants of the list
750 of weakrefs for ob. */
751 Py_DECREF(result);
752 Py_INCREF(ref);
753 result = ref;
754 }
Fred Drake8844d522001-10-05 21:52:26 +0000755 }
756 else {
Fred Drakebc875f52004-02-04 23:14:14 +0000757 PyWeakReference *prev;
Fred Drake8844d522001-10-05 21:52:26 +0000758
Fred Drakebc875f52004-02-04 23:14:14 +0000759 prev = (proxy == NULL) ? ref : proxy;
Fred Drake8844d522001-10-05 21:52:26 +0000760 if (prev == NULL)
761 insert_head(result, list);
762 else
763 insert_after(result, prev);
764 }
Fred Drake8844d522001-10-05 21:52:26 +0000765 }
766 }
767 return (PyObject *) result;
768}
769
770
771PyObject *
772PyWeakref_NewProxy(PyObject *ob, PyObject *callback)
773{
774 PyWeakReference *result = NULL;
775 PyWeakReference **list;
776 PyWeakReference *ref, *proxy;
777
778 if (!PyType_SUPPORTS_WEAKREFS(ob->ob_type)) {
779 PyErr_Format(PyExc_TypeError,
Jeremy Hylton996fad32001-10-22 16:31:40 +0000780 "cannot create weak reference to '%s' object",
Fred Drake8844d522001-10-05 21:52:26 +0000781 ob->ob_type->tp_name);
782 return NULL;
783 }
784 list = GET_WEAKREFS_LISTPTR(ob);
785 get_basic_refs(*list, &ref, &proxy);
Fred Drake6a2852c2004-02-03 19:52:56 +0000786 if (callback == Py_None)
787 callback = NULL;
Fred Drake8844d522001-10-05 21:52:26 +0000788 if (callback == NULL)
789 /* attempt to return an existing weak reference if it exists */
790 result = proxy;
791 if (result != NULL)
Fred Drakebc875f52004-02-04 23:14:14 +0000792 Py_INCREF(result);
Fred Drake8844d522001-10-05 21:52:26 +0000793 else {
Fred Drakebc875f52004-02-04 23:14:14 +0000794 /* Note: new_weakref() can trigger cyclic GC, so the weakref
795 list on ob can be mutated. This means that the ref and
796 proxy pointers we got back earlier may have been collected,
797 so we need to compute these values again before we use
798 them. */
Neil Schemenauer38a89162002-03-27 15:18:21 +0000799 result = new_weakref(ob, callback);
Fred Drake8844d522001-10-05 21:52:26 +0000800 if (result != NULL) {
801 PyWeakReference *prev;
802
803 if (PyCallable_Check(ob))
804 result->ob_type = &_PyWeakref_CallableProxyType;
805 else
806 result->ob_type = &_PyWeakref_ProxyType;
Fred Drakebc875f52004-02-04 23:14:14 +0000807 get_basic_refs(*list, &ref, &proxy);
Fred Drake6d3265d2004-08-03 14:47:25 +0000808 if (callback == NULL) {
809 if (proxy != NULL) {
810 /* Someone else added a proxy without a callback
811 during GC. Return that one instead of this one
812 to avoid violating the invariants of the list
813 of weakrefs for ob. */
814 Py_DECREF(result);
815 Py_INCREF(result = proxy);
816 goto skip_insert;
817 }
Fred Drake8844d522001-10-05 21:52:26 +0000818 prev = ref;
Fred Drake6d3265d2004-08-03 14:47:25 +0000819 }
Fred Drake8844d522001-10-05 21:52:26 +0000820 else
821 prev = (proxy == NULL) ? ref : proxy;
822
823 if (prev == NULL)
824 insert_head(result, list);
825 else
826 insert_after(result, prev);
Fred Drake6d3265d2004-08-03 14:47:25 +0000827 skip_insert:
828 ;
Fred Drake8844d522001-10-05 21:52:26 +0000829 }
830 }
831 return (PyObject *) result;
832}
833
834
835PyObject *
836PyWeakref_GetObject(PyObject *ref)
837{
838 if (ref == NULL || !PyWeakref_Check(ref)) {
839 PyErr_BadInternalCall();
840 return NULL;
841 }
842 return PyWeakref_GET_OBJECT(ref);
843}
844
Tim Petersead8b7a2004-10-30 23:09:22 +0000845/* Note that there's an inlined copy-paste of handle_callback() in gcmodule.c's
846 * handle_weakrefs().
847 */
Fred Drakeef8ebd12001-12-10 23:44:54 +0000848static void
849handle_callback(PyWeakReference *ref, PyObject *callback)
850{
851 PyObject *cbresult = PyObject_CallFunction(callback, "O", ref);
852
853 if (cbresult == NULL)
854 PyErr_WriteUnraisable(callback);
855 else
856 Py_DECREF(cbresult);
857}
858
859/* This function is called by the tp_dealloc handler to clear weak references.
Fred Drake8844d522001-10-05 21:52:26 +0000860 *
861 * This iterates through the weak references for 'object' and calls callbacks
862 * for those references which have one. It returns when all callbacks have
863 * been attempted.
864 */
865void
866PyObject_ClearWeakRefs(PyObject *object)
867{
868 PyWeakReference **list;
869
870 if (object == NULL
871 || !PyType_SUPPORTS_WEAKREFS(object->ob_type)
872 || object->ob_refcnt != 0) {
873 PyErr_BadInternalCall();
874 return;
875 }
876 list = GET_WEAKREFS_LISTPTR(object);
877 /* Remove the callback-less basic and proxy references */
878 if (*list != NULL && (*list)->wr_callback == NULL) {
879 clear_weakref(*list);
880 if (*list != NULL && (*list)->wr_callback == NULL)
881 clear_weakref(*list);
882 }
883 if (*list != NULL) {
Fred Drakeef8ebd12001-12-10 23:44:54 +0000884 PyWeakReference *current = *list;
Martin v. Löwis18e16552006-02-15 17:27:45 +0000885 Py_ssize_t count = _PyWeakref_GetWeakrefCount(current);
Fred Drakeef8ebd12001-12-10 23:44:54 +0000886 int restore_error = PyErr_Occurred() ? 1 : 0;
887 PyObject *err_type, *err_value, *err_tb;
Fred Drake8844d522001-10-05 21:52:26 +0000888
Fred Drakeef8ebd12001-12-10 23:44:54 +0000889 if (restore_error)
890 PyErr_Fetch(&err_type, &err_value, &err_tb);
Fred Drake8844d522001-10-05 21:52:26 +0000891 if (count == 1) {
Fred Drake8844d522001-10-05 21:52:26 +0000892 PyObject *callback = current->wr_callback;
Fred Drake8844d522001-10-05 21:52:26 +0000893
Fred Drakeef8ebd12001-12-10 23:44:54 +0000894 current->wr_callback = NULL;
Fred Drake8844d522001-10-05 21:52:26 +0000895 clear_weakref(current);
Fred Drake0a4dd392004-07-02 18:57:45 +0000896 if (callback != NULL) {
897 handle_callback(current, callback);
898 Py_DECREF(callback);
899 }
Fred Drake8844d522001-10-05 21:52:26 +0000900 }
901 else {
Hye-Shik Chang4af5c8c2006-03-07 15:39:21 +0000902 PyObject *tuple;
Martin v. Löwis18e16552006-02-15 17:27:45 +0000903 Py_ssize_t i = 0;
Hye-Shik Chang4af5c8c2006-03-07 15:39:21 +0000904
905 tuple = PyTuple_New(count * 2);
906 if (tuple == NULL) {
907 if (restore_error)
908 PyErr_Fetch(&err_type, &err_value, &err_tb);
909 return;
910 }
Fred Drake8844d522001-10-05 21:52:26 +0000911
912 for (i = 0; i < count; ++i) {
913 PyWeakReference *next = current->wr_next;
914
915 Py_INCREF(current);
916 PyTuple_SET_ITEM(tuple, i * 2, (PyObject *) current);
917 PyTuple_SET_ITEM(tuple, i * 2 + 1, current->wr_callback);
918 current->wr_callback = NULL;
Fred Drake8844d522001-10-05 21:52:26 +0000919 clear_weakref(current);
920 current = next;
921 }
922 for (i = 0; i < count; ++i) {
Fred Drake8844d522001-10-05 21:52:26 +0000923 PyObject *callback = PyTuple_GET_ITEM(tuple, i * 2 + 1);
Fred Drakeef8ebd12001-12-10 23:44:54 +0000924
Fred Drake0a4dd392004-07-02 18:57:45 +0000925 if (callback != NULL) {
Neal Norwitz0c6e2f12006-01-08 06:13:44 +0000926 PyObject *item = PyTuple_GET_ITEM(tuple, i * 2);
927 handle_callback((PyWeakReference *)item, callback);
Fred Drake0a4dd392004-07-02 18:57:45 +0000928 }
Fred Drake8844d522001-10-05 21:52:26 +0000929 }
930 Py_DECREF(tuple);
931 }
Fred Drakeef8ebd12001-12-10 23:44:54 +0000932 if (restore_error)
933 PyErr_Restore(err_type, err_value, err_tb);
Fred Drake8844d522001-10-05 21:52:26 +0000934 }
935}