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