blob: b059080ab42ab78fe74f3b71f5d2394a40ed10d5 [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
22static PyWeakReference *
Neil Schemenauer38a89162002-03-27 15:18:21 +000023new_weakref(PyObject *ob, PyObject *callback)
Fred Drake8844d522001-10-05 21:52:26 +000024{
25 PyWeakReference *result;
26
Neil Schemenauer38a89162002-03-27 15:18:21 +000027 result = PyObject_GC_New(PyWeakReference, &_PyWeakref_RefType);
28 if (result) {
Fred Drake8844d522001-10-05 21:52:26 +000029 result->hash = -1;
Neil Schemenauer38a89162002-03-27 15:18:21 +000030 result->wr_object = ob;
31 Py_XINCREF(callback);
32 result->wr_callback = callback;
33 PyObject_GC_Track(result);
34 }
Fred Drake8844d522001-10-05 21:52:26 +000035 return result;
36}
37
38
39/* This function clears the passed-in reference and removes it from the
40 * list of weak references for the referent. This is the only code that
41 * removes an item from the doubly-linked list of weak references for an
42 * object; it is also responsible for clearing the callback slot.
43 */
44static void
45clear_weakref(PyWeakReference *self)
46{
47 PyObject *callback = self->wr_callback;
48
49 if (PyWeakref_GET_OBJECT(self) != Py_None) {
50 PyWeakReference **list = GET_WEAKREFS_LISTPTR(
51 PyWeakref_GET_OBJECT(self));
52
53 if (*list == self)
54 *list = self->wr_next;
55 self->wr_object = Py_None;
56 self->wr_callback = NULL;
57 if (self->wr_prev != NULL)
58 self->wr_prev->wr_next = self->wr_next;
59 if (self->wr_next != NULL)
60 self->wr_next->wr_prev = self->wr_prev;
61 self->wr_prev = NULL;
62 self->wr_next = NULL;
63 Py_XDECREF(callback);
64 }
65}
66
67
68static void
69weakref_dealloc(PyWeakReference *self)
70{
71 PyObject_GC_UnTrack((PyObject *)self);
72 clear_weakref(self);
Neil Schemenauer38a89162002-03-27 15:18:21 +000073 PyObject_GC_Del(self);
Fred Drake8844d522001-10-05 21:52:26 +000074}
75
76
77static int
78gc_traverse(PyWeakReference *self, visitproc visit, void *arg)
79{
80 if (self->wr_callback != NULL)
81 return visit(self->wr_callback, arg);
82 return 0;
83}
84
85
86static int
87gc_clear(PyWeakReference *self)
88{
89 clear_weakref(self);
90 return 0;
91}
92
93
94static PyObject *
95weakref_call(PyWeakReference *self, PyObject *args, PyObject *kw)
96{
97 static char *argnames[] = {NULL};
98
99 if (PyArg_ParseTupleAndKeywords(args, kw, ":__call__", argnames)) {
100 PyObject *object = PyWeakref_GET_OBJECT(self);
101 Py_INCREF(object);
102 return (object);
103 }
104 return NULL;
105}
106
107
108static long
109weakref_hash(PyWeakReference *self)
110{
111 if (self->hash != -1)
112 return self->hash;
113 if (PyWeakref_GET_OBJECT(self) == Py_None) {
114 PyErr_SetString(PyExc_TypeError, "weak object has gone away");
115 return -1;
116 }
117 self->hash = PyObject_Hash(PyWeakref_GET_OBJECT(self));
118 return self->hash;
119}
120
121
122static PyObject *
123weakref_repr(PyWeakReference *self)
124{
125 char buffer[256];
126 if (PyWeakref_GET_OBJECT(self) == Py_None) {
Barry Warsawd5867562001-11-28 21:01:56 +0000127 PyOS_snprintf(buffer, sizeof(buffer), "<weakref at %lx; dead>",
128 (long)(self));
Fred Drake8844d522001-10-05 21:52:26 +0000129 }
130 else {
Barry Warsawd5867562001-11-28 21:01:56 +0000131 PyOS_snprintf(buffer, sizeof(buffer),
132 "<weakref at %#lx; to '%.50s' at %#lx>",
133 (long)(self),
134 PyWeakref_GET_OBJECT(self)->ob_type->tp_name,
135 (long)(PyWeakref_GET_OBJECT(self)));
Fred Drake8844d522001-10-05 21:52:26 +0000136 }
137 return PyString_FromString(buffer);
138}
139
140/* Weak references only support equality, not ordering. Two weak references
141 are equal if the underlying objects are equal. If the underlying object has
142 gone away, they are equal if they are identical. */
143
144static PyObject *
145weakref_richcompare(PyWeakReference* self, PyWeakReference* other, int op)
146{
147 if (op != Py_EQ || self->ob_type != other->ob_type) {
148 Py_INCREF(Py_NotImplemented);
149 return Py_NotImplemented;
150 }
151 if (PyWeakref_GET_OBJECT(self) == Py_None
152 || PyWeakref_GET_OBJECT(other) == Py_None) {
153 PyObject *res = self==other ? Py_True : Py_False;
154 Py_INCREF(res);
155 return res;
156 }
157 return PyObject_RichCompare(PyWeakref_GET_OBJECT(self),
158 PyWeakref_GET_OBJECT(other), op);
159}
160
161
162PyTypeObject
163_PyWeakref_RefType = {
164 PyObject_HEAD_INIT(&PyType_Type)
165 0,
166 "weakref",
167 sizeof(PyWeakReference),
168 0,
169 (destructor)weakref_dealloc,/*tp_dealloc*/
170 0, /*tp_print*/
171 0, /*tp_getattr*/
172 0, /*tp_setattr*/
173 0, /*tp_compare*/
174 (reprfunc)weakref_repr, /*tp_repr*/
175 0, /*tp_as_number*/
176 0, /*tp_as_sequence*/
177 0, /*tp_as_mapping*/
178 (hashfunc)weakref_hash, /*tp_hash*/
179 (ternaryfunc)weakref_call, /*tp_call*/
180 0, /*tp_str*/
181 0, /*tp_getattro*/
182 0, /*tp_setattro*/
183 0, /*tp_as_buffer*/
184 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_RICHCOMPARE,
185 0, /*tp_doc*/
186 (traverseproc)gc_traverse, /*tp_traverse*/
187 (inquiry)gc_clear, /*tp_clear*/
188 (richcmpfunc)weakref_richcompare, /*tp_richcompare*/
189 0, /*tp_weaklistoffset*/
190};
191
192
193static int
194proxy_checkref(PyWeakReference *proxy)
195{
196 if (PyWeakref_GET_OBJECT(proxy) == Py_None) {
197 PyErr_SetString(PyExc_ReferenceError,
198 "weakly-referenced object no longer exists");
199 return 0;
200 }
201 return 1;
202}
203
204
Fred Drake73006d02001-10-18 18:04:18 +0000205/* If a parameter is a proxy, check that it is still "live" and wrap it,
206 * replacing the original value with the raw object. Raises ReferenceError
207 * if the param is a dead proxy.
208 */
209#define UNWRAP(o) \
210 if (PyWeakref_CheckProxy(o)) { \
211 if (!proxy_checkref((PyWeakReference *)o)) \
212 return NULL; \
213 o = PyWeakref_GET_OBJECT(o); \
214 }
215
Fred Drake2a908f62001-12-19 16:44:30 +0000216#define UNWRAP_I(o) \
217 if (PyWeakref_CheckProxy(o)) { \
218 if (!proxy_checkref((PyWeakReference *)o)) \
219 return -1; \
220 o = PyWeakref_GET_OBJECT(o); \
221 }
222
Fred Drake8844d522001-10-05 21:52:26 +0000223#define WRAP_UNARY(method, generic) \
224 static PyObject * \
Fred Drake73006d02001-10-18 18:04:18 +0000225 method(PyObject *proxy) { \
226 UNWRAP(proxy); \
227 return generic(proxy); \
Fred Drake8844d522001-10-05 21:52:26 +0000228 }
229
230#define WRAP_BINARY(method, generic) \
231 static PyObject * \
Fred Drake73006d02001-10-18 18:04:18 +0000232 method(PyObject *x, PyObject *y) { \
233 UNWRAP(x); \
234 UNWRAP(y); \
235 return generic(x, y); \
Fred Drake8844d522001-10-05 21:52:26 +0000236 }
237
Fred Drake31f4d1f2001-10-18 19:21:46 +0000238/* Note that the third arg needs to be checked for NULL since the tp_call
239 * slot can receive NULL for this arg.
Fred Drake73006d02001-10-18 18:04:18 +0000240 */
Fred Drake8844d522001-10-05 21:52:26 +0000241#define WRAP_TERNARY(method, generic) \
242 static PyObject * \
Fred Drake73006d02001-10-18 18:04:18 +0000243 method(PyObject *proxy, PyObject *v, PyObject *w) { \
244 UNWRAP(proxy); \
Fred Drake31f4d1f2001-10-18 19:21:46 +0000245 UNWRAP(v); \
Fred Drake73006d02001-10-18 18:04:18 +0000246 if (w != NULL) \
247 UNWRAP(w); \
248 return generic(proxy, v, w); \
Fred Drake8844d522001-10-05 21:52:26 +0000249 }
250
251
252/* direct slots */
253
254WRAP_BINARY(proxy_getattr, PyObject_GetAttr)
255WRAP_UNARY(proxy_str, PyObject_Str)
256WRAP_TERNARY(proxy_call, PyEval_CallObjectWithKeywords)
257
258static int
259proxy_print(PyWeakReference *proxy, FILE *fp, int flags)
260{
261 if (!proxy_checkref(proxy))
262 return -1;
263 return PyObject_Print(PyWeakref_GET_OBJECT(proxy), fp, flags);
264}
265
266static PyObject *
267proxy_repr(PyWeakReference *proxy)
268{
269 char buf[160];
Barry Warsawd5867562001-11-28 21:01:56 +0000270 PyOS_snprintf(buf, sizeof(buf),
271 "<weakref at %p to %.100s at %p>", proxy,
272 PyWeakref_GET_OBJECT(proxy)->ob_type->tp_name,
273 PyWeakref_GET_OBJECT(proxy));
Fred Drake8844d522001-10-05 21:52:26 +0000274 return PyString_FromString(buf);
275}
276
277
278static int
279proxy_setattr(PyWeakReference *proxy, PyObject *name, PyObject *value)
280{
281 if (!proxy_checkref(proxy))
282 return -1;
283 return PyObject_SetAttr(PyWeakref_GET_OBJECT(proxy), name, value);
284}
285
286static int
Fred Drake2a908f62001-12-19 16:44:30 +0000287proxy_compare(PyObject *proxy, PyObject *v)
Fred Drake8844d522001-10-05 21:52:26 +0000288{
Fred Drake2a908f62001-12-19 16:44:30 +0000289 UNWRAP_I(proxy);
290 UNWRAP_I(v);
291 return PyObject_Compare(proxy, v);
Fred Drake8844d522001-10-05 21:52:26 +0000292}
293
294/* number slots */
295WRAP_BINARY(proxy_add, PyNumber_Add)
296WRAP_BINARY(proxy_sub, PyNumber_Subtract)
297WRAP_BINARY(proxy_mul, PyNumber_Multiply)
298WRAP_BINARY(proxy_div, PyNumber_Divide)
299WRAP_BINARY(proxy_mod, PyNumber_Remainder)
300WRAP_BINARY(proxy_divmod, PyNumber_Divmod)
301WRAP_TERNARY(proxy_pow, PyNumber_Power)
302WRAP_UNARY(proxy_neg, PyNumber_Negative)
303WRAP_UNARY(proxy_pos, PyNumber_Positive)
304WRAP_UNARY(proxy_abs, PyNumber_Absolute)
305WRAP_UNARY(proxy_invert, PyNumber_Invert)
306WRAP_BINARY(proxy_lshift, PyNumber_Lshift)
307WRAP_BINARY(proxy_rshift, PyNumber_Rshift)
308WRAP_BINARY(proxy_and, PyNumber_And)
309WRAP_BINARY(proxy_xor, PyNumber_Xor)
310WRAP_BINARY(proxy_or, PyNumber_Or)
311WRAP_UNARY(proxy_int, PyNumber_Int)
312WRAP_UNARY(proxy_long, PyNumber_Long)
313WRAP_UNARY(proxy_float, PyNumber_Float)
314WRAP_BINARY(proxy_iadd, PyNumber_InPlaceAdd)
315WRAP_BINARY(proxy_isub, PyNumber_InPlaceSubtract)
316WRAP_BINARY(proxy_imul, PyNumber_InPlaceMultiply)
317WRAP_BINARY(proxy_idiv, PyNumber_InPlaceDivide)
318WRAP_BINARY(proxy_imod, PyNumber_InPlaceRemainder)
319WRAP_TERNARY(proxy_ipow, PyNumber_InPlacePower)
320WRAP_BINARY(proxy_ilshift, PyNumber_InPlaceLshift)
321WRAP_BINARY(proxy_irshift, PyNumber_InPlaceRshift)
322WRAP_BINARY(proxy_iand, PyNumber_InPlaceAnd)
323WRAP_BINARY(proxy_ixor, PyNumber_InPlaceXor)
324WRAP_BINARY(proxy_ior, PyNumber_InPlaceOr)
325
326static int
327proxy_nonzero(PyWeakReference *proxy)
328{
329 PyObject *o = PyWeakref_GET_OBJECT(proxy);
330 if (!proxy_checkref(proxy))
331 return 1;
332 if (o->ob_type->tp_as_number &&
333 o->ob_type->tp_as_number->nb_nonzero)
334 return (*o->ob_type->tp_as_number->nb_nonzero)(o);
335 else
336 return 1;
337}
338
339/* sequence slots */
340
341static PyObject *
342proxy_slice(PyWeakReference *proxy, int i, int j)
343{
344 if (!proxy_checkref(proxy))
345 return NULL;
346 return PySequence_GetSlice(PyWeakref_GET_OBJECT(proxy), i, j);
347}
348
349static int
350proxy_ass_slice(PyWeakReference *proxy, int i, int j, PyObject *value)
351{
352 if (!proxy_checkref(proxy))
353 return -1;
354 return PySequence_SetSlice(PyWeakref_GET_OBJECT(proxy), i, j, value);
355}
356
357static int
358proxy_contains(PyWeakReference *proxy, PyObject *value)
359{
360 if (!proxy_checkref(proxy))
361 return -1;
362 return PySequence_Contains(PyWeakref_GET_OBJECT(proxy), value);
363}
364
365
366/* mapping slots */
367
368static int
369proxy_length(PyWeakReference *proxy)
370{
371 if (!proxy_checkref(proxy))
372 return -1;
373 return PyObject_Length(PyWeakref_GET_OBJECT(proxy));
374}
375
376WRAP_BINARY(proxy_getitem, PyObject_GetItem)
377
378static int
379proxy_setitem(PyWeakReference *proxy, PyObject *key, PyObject *value)
380{
381 if (!proxy_checkref(proxy))
382 return -1;
383 return PyObject_SetItem(PyWeakref_GET_OBJECT(proxy), key, value);
384}
385
Fred Drakef16c3dc2002-08-09 18:34:16 +0000386/* iterator slots */
387
388static PyObject *
389proxy_iter(PyWeakReference *proxy)
390{
391 if (!proxy_checkref(proxy))
392 return NULL;
393 return PyObject_GetIter(PyWeakref_GET_OBJECT(proxy));
394}
395
396static PyObject *
397proxy_iternext(PyWeakReference *proxy)
398{
399 if (!proxy_checkref(proxy))
400 return NULL;
401 return PyIter_Next(PyWeakref_GET_OBJECT(proxy));
402}
403
Fred Drake8844d522001-10-05 21:52:26 +0000404
405static PyNumberMethods proxy_as_number = {
406 (binaryfunc)proxy_add, /*nb_add*/
407 (binaryfunc)proxy_sub, /*nb_subtract*/
408 (binaryfunc)proxy_mul, /*nb_multiply*/
409 (binaryfunc)proxy_div, /*nb_divide*/
410 (binaryfunc)proxy_mod, /*nb_remainder*/
411 (binaryfunc)proxy_divmod, /*nb_divmod*/
412 (ternaryfunc)proxy_pow, /*nb_power*/
413 (unaryfunc)proxy_neg, /*nb_negative*/
414 (unaryfunc)proxy_pos, /*nb_positive*/
415 (unaryfunc)proxy_abs, /*nb_absolute*/
416 (inquiry)proxy_nonzero, /*nb_nonzero*/
417 (unaryfunc)proxy_invert, /*nb_invert*/
418 (binaryfunc)proxy_lshift, /*nb_lshift*/
419 (binaryfunc)proxy_rshift, /*nb_rshift*/
420 (binaryfunc)proxy_and, /*nb_and*/
421 (binaryfunc)proxy_xor, /*nb_xor*/
422 (binaryfunc)proxy_or, /*nb_or*/
423 (coercion)0, /*nb_coerce*/
424 (unaryfunc)proxy_int, /*nb_int*/
425 (unaryfunc)proxy_long, /*nb_long*/
426 (unaryfunc)proxy_float, /*nb_float*/
427 (unaryfunc)0, /*nb_oct*/
428 (unaryfunc)0, /*nb_hex*/
429 (binaryfunc)proxy_iadd, /*nb_inplace_add*/
430 (binaryfunc)proxy_isub, /*nb_inplace_subtract*/
431 (binaryfunc)proxy_imul, /*nb_inplace_multiply*/
432 (binaryfunc)proxy_idiv, /*nb_inplace_divide*/
433 (binaryfunc)proxy_imod, /*nb_inplace_remainder*/
434 (ternaryfunc)proxy_ipow, /*nb_inplace_power*/
435 (binaryfunc)proxy_ilshift, /*nb_inplace_lshift*/
436 (binaryfunc)proxy_irshift, /*nb_inplace_rshift*/
437 (binaryfunc)proxy_iand, /*nb_inplace_and*/
438 (binaryfunc)proxy_ixor, /*nb_inplace_xor*/
439 (binaryfunc)proxy_ior, /*nb_inplace_or*/
440};
441
442static PySequenceMethods proxy_as_sequence = {
443 (inquiry)proxy_length, /*sq_length*/
444 0, /*sq_concat*/
445 0, /*sq_repeat*/
446 0, /*sq_item*/
447 (intintargfunc)proxy_slice, /*sq_slice*/
448 0, /*sq_ass_item*/
449 (intintobjargproc)proxy_ass_slice, /*sq_ass_slice*/
450 (objobjproc)proxy_contains, /* sq_contains */
451};
452
453static PyMappingMethods proxy_as_mapping = {
454 (inquiry)proxy_length, /*mp_length*/
455 (binaryfunc)proxy_getitem, /*mp_subscript*/
456 (objobjargproc)proxy_setitem, /*mp_ass_subscript*/
457};
458
459
460PyTypeObject
461_PyWeakref_ProxyType = {
462 PyObject_HEAD_INIT(&PyType_Type)
463 0,
464 "weakproxy",
465 sizeof(PyWeakReference),
466 0,
467 /* methods */
Fred Drakef16c3dc2002-08-09 18:34:16 +0000468 (destructor)weakref_dealloc, /* tp_dealloc */
469 (printfunc)proxy_print, /* tp_print */
470 0, /* tp_getattr */
471 0, /* tp_setattr */
472 proxy_compare, /* tp_compare */
473 (unaryfunc)proxy_repr, /* tp_repr */
474 &proxy_as_number, /* tp_as_number */
475 &proxy_as_sequence, /* tp_as_sequence */
476 &proxy_as_mapping, /* tp_as_mapping */
477 0, /* tp_hash */
478 (ternaryfunc)0, /* tp_call */
479 (unaryfunc)proxy_str, /* tp_str */
480 (getattrofunc)proxy_getattr, /* tp_getattro */
481 (setattrofunc)proxy_setattr, /* tp_setattro */
482 0, /* tp_as_buffer */
Fred Drake8844d522001-10-05 21:52:26 +0000483 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC
Fred Drakef16c3dc2002-08-09 18:34:16 +0000484 | Py_TPFLAGS_CHECKTYPES, /* tp_flags */
485 0, /* tp_doc */
486 (traverseproc)gc_traverse, /* tp_traverse */
487 (inquiry)gc_clear, /* tp_clear */
488 0, /* tp_richcompare */
489 0, /* tp_weaklistoffset */
490 (getiterfunc)proxy_iter, /* tp_iter */
491 (iternextfunc)proxy_iternext, /* tp_iternext */
Fred Drake8844d522001-10-05 21:52:26 +0000492};
493
494
495PyTypeObject
496_PyWeakref_CallableProxyType = {
497 PyObject_HEAD_INIT(&PyType_Type)
498 0,
499 "weakcallableproxy",
500 sizeof(PyWeakReference),
501 0,
502 /* methods */
Fred Drakef16c3dc2002-08-09 18:34:16 +0000503 (destructor)weakref_dealloc, /* tp_dealloc */
504 (printfunc)proxy_print, /* tp_print */
505 0, /* tp_getattr */
506 0, /* tp_setattr */
507 proxy_compare, /* tp_compare */
508 (unaryfunc)proxy_repr, /* tp_repr */
509 &proxy_as_number, /* tp_as_number */
510 &proxy_as_sequence, /* tp_as_sequence */
511 &proxy_as_mapping, /* tp_as_mapping */
512 0, /* tp_hash */
513 (ternaryfunc)proxy_call, /* tp_call */
514 (unaryfunc)proxy_str, /* tp_str */
515 (getattrofunc)proxy_getattr, /* tp_getattro */
516 (setattrofunc)proxy_setattr, /* tp_setattro */
517 0, /* tp_as_buffer */
Fred Drake8844d522001-10-05 21:52:26 +0000518 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC
Fred Drakef16c3dc2002-08-09 18:34:16 +0000519 | Py_TPFLAGS_CHECKTYPES, /* tp_flags */
520 0, /* tp_doc */
521 (traverseproc)gc_traverse, /* tp_traverse */
522 (inquiry)gc_clear, /* tp_clear */
523 0, /* tp_richcompare */
524 0, /* tp_weaklistoffset */
525 (getiterfunc)proxy_iter, /* tp_iter */
526 (iternextfunc)proxy_iternext, /* tp_iternext */
Fred Drake8844d522001-10-05 21:52:26 +0000527};
528
529
530/* Given the head of an object's list of weak references, extract the
531 * two callback-less refs (ref and proxy). Used to determine if the
532 * shared references exist and to determine the back link for newly
533 * inserted references.
534 */
535static void
536get_basic_refs(PyWeakReference *head,
537 PyWeakReference **refp, PyWeakReference **proxyp)
538{
539 *refp = NULL;
540 *proxyp = NULL;
541
542 if (head != NULL && head->wr_callback == NULL) {
543 if (head->ob_type == &_PyWeakref_RefType) {
544 *refp = head;
545 head = head->wr_next;
546 }
547 if (head != NULL && head->wr_callback == NULL) {
548 *proxyp = head;
549 head = head->wr_next;
550 }
551 }
552}
553
554/* Insert 'newref' in the list after 'prev'. Both must be non-NULL. */
555static void
556insert_after(PyWeakReference *newref, PyWeakReference *prev)
557{
558 newref->wr_prev = prev;
559 newref->wr_next = prev->wr_next;
560 if (prev->wr_next != NULL)
561 prev->wr_next->wr_prev = newref;
562 prev->wr_next = newref;
563}
564
565/* Insert 'newref' at the head of the list; 'list' points to the variable
566 * that stores the head.
567 */
568static void
569insert_head(PyWeakReference *newref, PyWeakReference **list)
570{
571 PyWeakReference *next = *list;
572
573 newref->wr_prev = NULL;
574 newref->wr_next = next;
575 if (next != NULL)
576 next->wr_prev = newref;
577 *list = newref;
578}
579
580
581PyObject *
582PyWeakref_NewRef(PyObject *ob, PyObject *callback)
583{
584 PyWeakReference *result = NULL;
585 PyWeakReference **list;
586 PyWeakReference *ref, *proxy;
587
588 if (!PyType_SUPPORTS_WEAKREFS(ob->ob_type)) {
589 PyErr_Format(PyExc_TypeError,
Jeremy Hylton996fad32001-10-22 16:31:40 +0000590 "cannot create weak reference to '%s' object",
Fred Drake8844d522001-10-05 21:52:26 +0000591 ob->ob_type->tp_name);
592 return NULL;
593 }
594 list = GET_WEAKREFS_LISTPTR(ob);
595 get_basic_refs(*list, &ref, &proxy);
596 if (callback == NULL || callback == Py_None)
597 /* return existing weak reference if it exists */
598 result = ref;
599 if (result != NULL)
600 Py_XINCREF(result);
601 else {
Neil Schemenauer38a89162002-03-27 15:18:21 +0000602 result = new_weakref(ob, callback);
Fred Drake8844d522001-10-05 21:52:26 +0000603 if (result != NULL) {
Fred Drake8844d522001-10-05 21:52:26 +0000604 if (callback == NULL) {
605 insert_head(result, list);
606 }
607 else {
608 PyWeakReference *prev = (proxy == NULL) ? ref : proxy;
609
610 if (prev == NULL)
611 insert_head(result, list);
612 else
613 insert_after(result, prev);
614 }
Fred Drake8844d522001-10-05 21:52:26 +0000615 }
616 }
617 return (PyObject *) result;
618}
619
620
621PyObject *
622PyWeakref_NewProxy(PyObject *ob, PyObject *callback)
623{
624 PyWeakReference *result = NULL;
625 PyWeakReference **list;
626 PyWeakReference *ref, *proxy;
627
628 if (!PyType_SUPPORTS_WEAKREFS(ob->ob_type)) {
629 PyErr_Format(PyExc_TypeError,
Jeremy Hylton996fad32001-10-22 16:31:40 +0000630 "cannot create weak reference to '%s' object",
Fred Drake8844d522001-10-05 21:52:26 +0000631 ob->ob_type->tp_name);
632 return NULL;
633 }
634 list = GET_WEAKREFS_LISTPTR(ob);
635 get_basic_refs(*list, &ref, &proxy);
636 if (callback == NULL)
637 /* attempt to return an existing weak reference if it exists */
638 result = proxy;
639 if (result != NULL)
640 Py_XINCREF(result);
641 else {
Neil Schemenauer38a89162002-03-27 15:18:21 +0000642 result = new_weakref(ob, callback);
Fred Drake8844d522001-10-05 21:52:26 +0000643 if (result != NULL) {
644 PyWeakReference *prev;
645
646 if (PyCallable_Check(ob))
647 result->ob_type = &_PyWeakref_CallableProxyType;
648 else
649 result->ob_type = &_PyWeakref_ProxyType;
Fred Drake8844d522001-10-05 21:52:26 +0000650 if (callback == NULL)
651 prev = ref;
652 else
653 prev = (proxy == NULL) ? ref : proxy;
654
655 if (prev == NULL)
656 insert_head(result, list);
657 else
658 insert_after(result, prev);
Fred Drake8844d522001-10-05 21:52:26 +0000659 }
660 }
661 return (PyObject *) result;
662}
663
664
665PyObject *
666PyWeakref_GetObject(PyObject *ref)
667{
668 if (ref == NULL || !PyWeakref_Check(ref)) {
669 PyErr_BadInternalCall();
670 return NULL;
671 }
672 return PyWeakref_GET_OBJECT(ref);
673}
674
675
Fred Drakeef8ebd12001-12-10 23:44:54 +0000676static void
677handle_callback(PyWeakReference *ref, PyObject *callback)
678{
679 PyObject *cbresult = PyObject_CallFunction(callback, "O", ref);
680
681 if (cbresult == NULL)
682 PyErr_WriteUnraisable(callback);
683 else
684 Py_DECREF(cbresult);
685}
686
687/* This function is called by the tp_dealloc handler to clear weak references.
Fred Drake8844d522001-10-05 21:52:26 +0000688 *
689 * This iterates through the weak references for 'object' and calls callbacks
690 * for those references which have one. It returns when all callbacks have
691 * been attempted.
692 */
693void
694PyObject_ClearWeakRefs(PyObject *object)
695{
696 PyWeakReference **list;
697
698 if (object == NULL
699 || !PyType_SUPPORTS_WEAKREFS(object->ob_type)
700 || object->ob_refcnt != 0) {
701 PyErr_BadInternalCall();
702 return;
703 }
704 list = GET_WEAKREFS_LISTPTR(object);
705 /* Remove the callback-less basic and proxy references */
706 if (*list != NULL && (*list)->wr_callback == NULL) {
707 clear_weakref(*list);
708 if (*list != NULL && (*list)->wr_callback == NULL)
709 clear_weakref(*list);
710 }
711 if (*list != NULL) {
Fred Drakeef8ebd12001-12-10 23:44:54 +0000712 PyWeakReference *current = *list;
713 int count = _PyWeakref_GetWeakrefCount(current);
714 int restore_error = PyErr_Occurred() ? 1 : 0;
715 PyObject *err_type, *err_value, *err_tb;
Fred Drake8844d522001-10-05 21:52:26 +0000716
Fred Drakeef8ebd12001-12-10 23:44:54 +0000717 if (restore_error)
718 PyErr_Fetch(&err_type, &err_value, &err_tb);
Fred Drake8844d522001-10-05 21:52:26 +0000719 if (count == 1) {
Fred Drake8844d522001-10-05 21:52:26 +0000720 PyObject *callback = current->wr_callback;
Fred Drake8844d522001-10-05 21:52:26 +0000721
Fred Drakeef8ebd12001-12-10 23:44:54 +0000722 current->wr_callback = NULL;
Fred Drake8844d522001-10-05 21:52:26 +0000723 clear_weakref(current);
Fred Drakeef8ebd12001-12-10 23:44:54 +0000724 handle_callback(current, callback);
Fred Drake8844d522001-10-05 21:52:26 +0000725 Py_DECREF(callback);
726 }
727 else {
728 PyObject *tuple = PyTuple_New(count * 2);
Fred Drake8844d522001-10-05 21:52:26 +0000729 int i = 0;
730
731 for (i = 0; i < count; ++i) {
732 PyWeakReference *next = current->wr_next;
733
734 Py_INCREF(current);
735 PyTuple_SET_ITEM(tuple, i * 2, (PyObject *) current);
736 PyTuple_SET_ITEM(tuple, i * 2 + 1, current->wr_callback);
737 current->wr_callback = NULL;
Fred Drake8844d522001-10-05 21:52:26 +0000738 clear_weakref(current);
739 current = next;
740 }
741 for (i = 0; i < count; ++i) {
742 PyObject *current = PyTuple_GET_ITEM(tuple, i * 2);
743 PyObject *callback = PyTuple_GET_ITEM(tuple, i * 2 + 1);
Fred Drakeef8ebd12001-12-10 23:44:54 +0000744
745 handle_callback((PyWeakReference *)current, callback);
Fred Drake8844d522001-10-05 21:52:26 +0000746 }
747 Py_DECREF(tuple);
748 }
Fred Drakeef8ebd12001-12-10 23:44:54 +0000749 if (restore_error)
750 PyErr_Restore(err_type, err_value, err_tb);
Fred Drake8844d522001-10-05 21:52:26 +0000751 }
752}