blob: 021670a9936a74b3f1e104c6a15fdd8dd8b1e24d [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
386
387static PyNumberMethods proxy_as_number = {
388 (binaryfunc)proxy_add, /*nb_add*/
389 (binaryfunc)proxy_sub, /*nb_subtract*/
390 (binaryfunc)proxy_mul, /*nb_multiply*/
391 (binaryfunc)proxy_div, /*nb_divide*/
392 (binaryfunc)proxy_mod, /*nb_remainder*/
393 (binaryfunc)proxy_divmod, /*nb_divmod*/
394 (ternaryfunc)proxy_pow, /*nb_power*/
395 (unaryfunc)proxy_neg, /*nb_negative*/
396 (unaryfunc)proxy_pos, /*nb_positive*/
397 (unaryfunc)proxy_abs, /*nb_absolute*/
398 (inquiry)proxy_nonzero, /*nb_nonzero*/
399 (unaryfunc)proxy_invert, /*nb_invert*/
400 (binaryfunc)proxy_lshift, /*nb_lshift*/
401 (binaryfunc)proxy_rshift, /*nb_rshift*/
402 (binaryfunc)proxy_and, /*nb_and*/
403 (binaryfunc)proxy_xor, /*nb_xor*/
404 (binaryfunc)proxy_or, /*nb_or*/
405 (coercion)0, /*nb_coerce*/
406 (unaryfunc)proxy_int, /*nb_int*/
407 (unaryfunc)proxy_long, /*nb_long*/
408 (unaryfunc)proxy_float, /*nb_float*/
409 (unaryfunc)0, /*nb_oct*/
410 (unaryfunc)0, /*nb_hex*/
411 (binaryfunc)proxy_iadd, /*nb_inplace_add*/
412 (binaryfunc)proxy_isub, /*nb_inplace_subtract*/
413 (binaryfunc)proxy_imul, /*nb_inplace_multiply*/
414 (binaryfunc)proxy_idiv, /*nb_inplace_divide*/
415 (binaryfunc)proxy_imod, /*nb_inplace_remainder*/
416 (ternaryfunc)proxy_ipow, /*nb_inplace_power*/
417 (binaryfunc)proxy_ilshift, /*nb_inplace_lshift*/
418 (binaryfunc)proxy_irshift, /*nb_inplace_rshift*/
419 (binaryfunc)proxy_iand, /*nb_inplace_and*/
420 (binaryfunc)proxy_ixor, /*nb_inplace_xor*/
421 (binaryfunc)proxy_ior, /*nb_inplace_or*/
422};
423
424static PySequenceMethods proxy_as_sequence = {
425 (inquiry)proxy_length, /*sq_length*/
426 0, /*sq_concat*/
427 0, /*sq_repeat*/
428 0, /*sq_item*/
429 (intintargfunc)proxy_slice, /*sq_slice*/
430 0, /*sq_ass_item*/
431 (intintobjargproc)proxy_ass_slice, /*sq_ass_slice*/
432 (objobjproc)proxy_contains, /* sq_contains */
433};
434
435static PyMappingMethods proxy_as_mapping = {
436 (inquiry)proxy_length, /*mp_length*/
437 (binaryfunc)proxy_getitem, /*mp_subscript*/
438 (objobjargproc)proxy_setitem, /*mp_ass_subscript*/
439};
440
441
442PyTypeObject
443_PyWeakref_ProxyType = {
444 PyObject_HEAD_INIT(&PyType_Type)
445 0,
446 "weakproxy",
447 sizeof(PyWeakReference),
448 0,
449 /* methods */
450 (destructor)weakref_dealloc,/*tp_dealloc*/
451 (printfunc)proxy_print, /*tp_print*/
452 0, /*tp_getattr*/
453 0, /*tp_setattr*/
Fred Drake2a908f62001-12-19 16:44:30 +0000454 proxy_compare, /*tp_compare*/
Fred Drake8844d522001-10-05 21:52:26 +0000455 (unaryfunc)proxy_repr, /*tp_repr*/
456 &proxy_as_number, /*tp_as_number*/
457 &proxy_as_sequence, /*tp_as_sequence*/
458 &proxy_as_mapping, /*tp_as_mapping*/
459 0, /*tp_hash*/
460 (ternaryfunc)0, /*tp_call*/
461 (unaryfunc)proxy_str, /*tp_str*/
462 (getattrofunc)proxy_getattr,/*tp_getattro*/
463 (setattrofunc)proxy_setattr,/*tp_setattro*/
464 0, /*tp_as_buffer*/
465 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC
466 |Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
467 0, /*tp_doc*/
468 (traverseproc)gc_traverse, /*tp_traverse*/
469 (inquiry)gc_clear, /*tp_clear*/
470};
471
472
473PyTypeObject
474_PyWeakref_CallableProxyType = {
475 PyObject_HEAD_INIT(&PyType_Type)
476 0,
477 "weakcallableproxy",
478 sizeof(PyWeakReference),
479 0,
480 /* methods */
481 (destructor)weakref_dealloc,/*tp_dealloc*/
482 (printfunc)proxy_print, /*tp_print*/
483 0, /*tp_getattr*/
484 0, /*tp_setattr*/
Fred Drake2a908f62001-12-19 16:44:30 +0000485 proxy_compare, /*tp_compare*/
Fred Drake8844d522001-10-05 21:52:26 +0000486 (unaryfunc)proxy_repr, /*tp_repr*/
487 &proxy_as_number, /*tp_as_number*/
488 &proxy_as_sequence, /*tp_as_sequence*/
489 &proxy_as_mapping, /*tp_as_mapping*/
490 0, /*tp_hash*/
491 (ternaryfunc)proxy_call, /*tp_call*/
492 (unaryfunc)proxy_str, /*tp_str*/
493 (getattrofunc)proxy_getattr,/*tp_getattro*/
494 (setattrofunc)proxy_setattr,/*tp_setattro*/
495 0, /*tp_as_buffer*/
496 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC
497 |Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
498 0, /*tp_doc*/
499 (traverseproc)gc_traverse, /*tp_traverse*/
500 (inquiry)gc_clear, /*tp_clear*/
501};
502
503
504/* Given the head of an object's list of weak references, extract the
505 * two callback-less refs (ref and proxy). Used to determine if the
506 * shared references exist and to determine the back link for newly
507 * inserted references.
508 */
509static void
510get_basic_refs(PyWeakReference *head,
511 PyWeakReference **refp, PyWeakReference **proxyp)
512{
513 *refp = NULL;
514 *proxyp = NULL;
515
516 if (head != NULL && head->wr_callback == NULL) {
517 if (head->ob_type == &_PyWeakref_RefType) {
518 *refp = head;
519 head = head->wr_next;
520 }
521 if (head != NULL && head->wr_callback == NULL) {
522 *proxyp = head;
523 head = head->wr_next;
524 }
525 }
526}
527
528/* Insert 'newref' in the list after 'prev'. Both must be non-NULL. */
529static void
530insert_after(PyWeakReference *newref, PyWeakReference *prev)
531{
532 newref->wr_prev = prev;
533 newref->wr_next = prev->wr_next;
534 if (prev->wr_next != NULL)
535 prev->wr_next->wr_prev = newref;
536 prev->wr_next = newref;
537}
538
539/* Insert 'newref' at the head of the list; 'list' points to the variable
540 * that stores the head.
541 */
542static void
543insert_head(PyWeakReference *newref, PyWeakReference **list)
544{
545 PyWeakReference *next = *list;
546
547 newref->wr_prev = NULL;
548 newref->wr_next = next;
549 if (next != NULL)
550 next->wr_prev = newref;
551 *list = newref;
552}
553
554
555PyObject *
556PyWeakref_NewRef(PyObject *ob, PyObject *callback)
557{
558 PyWeakReference *result = NULL;
559 PyWeakReference **list;
560 PyWeakReference *ref, *proxy;
561
562 if (!PyType_SUPPORTS_WEAKREFS(ob->ob_type)) {
563 PyErr_Format(PyExc_TypeError,
Jeremy Hylton996fad32001-10-22 16:31:40 +0000564 "cannot create weak reference to '%s' object",
Fred Drake8844d522001-10-05 21:52:26 +0000565 ob->ob_type->tp_name);
566 return NULL;
567 }
568 list = GET_WEAKREFS_LISTPTR(ob);
569 get_basic_refs(*list, &ref, &proxy);
570 if (callback == NULL || callback == Py_None)
571 /* return existing weak reference if it exists */
572 result = ref;
573 if (result != NULL)
574 Py_XINCREF(result);
575 else {
Neil Schemenauer38a89162002-03-27 15:18:21 +0000576 result = new_weakref(ob, callback);
Fred Drake8844d522001-10-05 21:52:26 +0000577 if (result != NULL) {
Fred Drake8844d522001-10-05 21:52:26 +0000578 if (callback == NULL) {
579 insert_head(result, list);
580 }
581 else {
582 PyWeakReference *prev = (proxy == NULL) ? ref : proxy;
583
584 if (prev == NULL)
585 insert_head(result, list);
586 else
587 insert_after(result, prev);
588 }
Fred Drake8844d522001-10-05 21:52:26 +0000589 }
590 }
591 return (PyObject *) result;
592}
593
594
595PyObject *
596PyWeakref_NewProxy(PyObject *ob, PyObject *callback)
597{
598 PyWeakReference *result = NULL;
599 PyWeakReference **list;
600 PyWeakReference *ref, *proxy;
601
602 if (!PyType_SUPPORTS_WEAKREFS(ob->ob_type)) {
603 PyErr_Format(PyExc_TypeError,
Jeremy Hylton996fad32001-10-22 16:31:40 +0000604 "cannot create weak reference to '%s' object",
Fred Drake8844d522001-10-05 21:52:26 +0000605 ob->ob_type->tp_name);
606 return NULL;
607 }
608 list = GET_WEAKREFS_LISTPTR(ob);
609 get_basic_refs(*list, &ref, &proxy);
610 if (callback == NULL)
611 /* attempt to return an existing weak reference if it exists */
612 result = proxy;
613 if (result != NULL)
614 Py_XINCREF(result);
615 else {
Neil Schemenauer38a89162002-03-27 15:18:21 +0000616 result = new_weakref(ob, callback);
Fred Drake8844d522001-10-05 21:52:26 +0000617 if (result != NULL) {
618 PyWeakReference *prev;
619
620 if (PyCallable_Check(ob))
621 result->ob_type = &_PyWeakref_CallableProxyType;
622 else
623 result->ob_type = &_PyWeakref_ProxyType;
Fred Drake8844d522001-10-05 21:52:26 +0000624 if (callback == NULL)
625 prev = ref;
626 else
627 prev = (proxy == NULL) ? ref : proxy;
628
629 if (prev == NULL)
630 insert_head(result, list);
631 else
632 insert_after(result, prev);
Fred Drake8844d522001-10-05 21:52:26 +0000633 }
634 }
635 return (PyObject *) result;
636}
637
638
639PyObject *
640PyWeakref_GetObject(PyObject *ref)
641{
642 if (ref == NULL || !PyWeakref_Check(ref)) {
643 PyErr_BadInternalCall();
644 return NULL;
645 }
646 return PyWeakref_GET_OBJECT(ref);
647}
648
649
Fred Drakeef8ebd12001-12-10 23:44:54 +0000650static void
651handle_callback(PyWeakReference *ref, PyObject *callback)
652{
653 PyObject *cbresult = PyObject_CallFunction(callback, "O", ref);
654
655 if (cbresult == NULL)
656 PyErr_WriteUnraisable(callback);
657 else
658 Py_DECREF(cbresult);
659}
660
661/* This function is called by the tp_dealloc handler to clear weak references.
Fred Drake8844d522001-10-05 21:52:26 +0000662 *
663 * This iterates through the weak references for 'object' and calls callbacks
664 * for those references which have one. It returns when all callbacks have
665 * been attempted.
666 */
667void
668PyObject_ClearWeakRefs(PyObject *object)
669{
670 PyWeakReference **list;
671
672 if (object == NULL
673 || !PyType_SUPPORTS_WEAKREFS(object->ob_type)
674 || object->ob_refcnt != 0) {
675 PyErr_BadInternalCall();
676 return;
677 }
678 list = GET_WEAKREFS_LISTPTR(object);
679 /* Remove the callback-less basic and proxy references */
680 if (*list != NULL && (*list)->wr_callback == NULL) {
681 clear_weakref(*list);
682 if (*list != NULL && (*list)->wr_callback == NULL)
683 clear_weakref(*list);
684 }
685 if (*list != NULL) {
Fred Drakeef8ebd12001-12-10 23:44:54 +0000686 PyWeakReference *current = *list;
687 int count = _PyWeakref_GetWeakrefCount(current);
688 int restore_error = PyErr_Occurred() ? 1 : 0;
689 PyObject *err_type, *err_value, *err_tb;
Fred Drake8844d522001-10-05 21:52:26 +0000690
Fred Drakeef8ebd12001-12-10 23:44:54 +0000691 if (restore_error)
692 PyErr_Fetch(&err_type, &err_value, &err_tb);
Fred Drake8844d522001-10-05 21:52:26 +0000693 if (count == 1) {
Fred Drake8844d522001-10-05 21:52:26 +0000694 PyObject *callback = current->wr_callback;
Fred Drake8844d522001-10-05 21:52:26 +0000695
Fred Drakeef8ebd12001-12-10 23:44:54 +0000696 current->wr_callback = NULL;
Fred Drake8844d522001-10-05 21:52:26 +0000697 clear_weakref(current);
Fred Drakeef8ebd12001-12-10 23:44:54 +0000698 handle_callback(current, callback);
Fred Drake8844d522001-10-05 21:52:26 +0000699 Py_DECREF(callback);
700 }
701 else {
702 PyObject *tuple = PyTuple_New(count * 2);
Fred Drake8844d522001-10-05 21:52:26 +0000703 int i = 0;
704
705 for (i = 0; i < count; ++i) {
706 PyWeakReference *next = current->wr_next;
707
708 Py_INCREF(current);
709 PyTuple_SET_ITEM(tuple, i * 2, (PyObject *) current);
710 PyTuple_SET_ITEM(tuple, i * 2 + 1, current->wr_callback);
711 current->wr_callback = NULL;
Fred Drake8844d522001-10-05 21:52:26 +0000712 clear_weakref(current);
713 current = next;
714 }
715 for (i = 0; i < count; ++i) {
716 PyObject *current = PyTuple_GET_ITEM(tuple, i * 2);
717 PyObject *callback = PyTuple_GET_ITEM(tuple, i * 2 + 1);
Fred Drakeef8ebd12001-12-10 23:44:54 +0000718
719 handle_callback((PyWeakReference *)current, callback);
Fred Drake8844d522001-10-05 21:52:26 +0000720 }
721 Py_DECREF(tuple);
722 }
Fred Drakeef8ebd12001-12-10 23:44:54 +0000723 if (restore_error)
724 PyErr_Restore(err_type, err_value, err_tb);
Fred Drake8844d522001-10-05 21:52:26 +0000725 }
726}