2 #include "structmember.h"
5 #define GET_WEAKREFS_LISTPTR(o) \
6 ((PyWeakReference **) PyObject_GET_WEAKREFS_LISTPTR(o))
10 _PyWeakref_GetWeakrefCount(PyWeakReference
*head
)
14 while (head
!= NULL
) {
22 static PyWeakReference
*
23 new_weakref(PyObject
*ob
, PyObject
*callback
)
25 PyWeakReference
*result
;
27 result
= PyObject_GC_New(PyWeakReference
, &_PyWeakref_RefType
);
30 result
->wr_object
= ob
;
32 result
->wr_callback
= callback
;
33 PyObject_GC_Track(result
);
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.
45 clear_weakref(PyWeakReference
*self
)
47 PyObject
*callback
= self
->wr_callback
;
49 if (PyWeakref_GET_OBJECT(self
) != Py_None
) {
50 PyWeakReference
**list
= GET_WEAKREFS_LISTPTR(
51 PyWeakref_GET_OBJECT(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
;
69 weakref_dealloc(PyWeakReference
*self
)
71 PyObject_GC_UnTrack((PyObject
*)self
);
73 PyObject_GC_Del(self
);
78 gc_traverse(PyWeakReference
*self
, visitproc visit
, void *arg
)
80 if (self
->wr_callback
!= NULL
)
81 return visit(self
->wr_callback
, arg
);
87 gc_clear(PyWeakReference
*self
)
95 weakref_call(PyWeakReference
*self
, PyObject
*args
, PyObject
*kw
)
97 static char *argnames
[] = {NULL
};
99 if (PyArg_ParseTupleAndKeywords(args
, kw
, ":__call__", argnames
)) {
100 PyObject
*object
= PyWeakref_GET_OBJECT(self
);
109 weakref_hash(PyWeakReference
*self
)
111 if (self
->hash
!= -1)
113 if (PyWeakref_GET_OBJECT(self
) == Py_None
) {
114 PyErr_SetString(PyExc_TypeError
, "weak object has gone away");
117 self
->hash
= PyObject_Hash(PyWeakref_GET_OBJECT(self
));
123 weakref_repr(PyWeakReference
*self
)
126 if (PyWeakref_GET_OBJECT(self
) == Py_None
) {
127 PyOS_snprintf(buffer
, sizeof(buffer
), "<weakref at %p; dead>", self
);
131 PyObject
*nameobj
= PyObject_GetAttrString(PyWeakref_GET_OBJECT(self
),
135 else if (PyString_Check(nameobj
))
136 name
= PyString_AS_STRING(nameobj
);
137 PyOS_snprintf(buffer
, sizeof(buffer
),
138 name
? "<weakref at %p; to '%.50s' at %p (%s)>"
139 : "<weakref at %p; to '%.50s' at %p>",
141 PyWeakref_GET_OBJECT(self
)->ob_type
->tp_name
,
142 PyWeakref_GET_OBJECT(self
),
146 return PyString_FromString(buffer
);
149 /* Weak references only support equality, not ordering. Two weak references
150 are equal if the underlying objects are equal. If the underlying object has
151 gone away, they are equal if they are identical. */
154 weakref_richcompare(PyWeakReference
* self
, PyWeakReference
* other
, int op
)
156 if (op
!= Py_EQ
|| self
->ob_type
!= other
->ob_type
) {
157 Py_INCREF(Py_NotImplemented
);
158 return Py_NotImplemented
;
160 if (PyWeakref_GET_OBJECT(self
) == Py_None
161 || PyWeakref_GET_OBJECT(other
) == Py_None
) {
162 PyObject
*res
= self
==other
? Py_True
: Py_False
;
166 return PyObject_RichCompare(PyWeakref_GET_OBJECT(self
),
167 PyWeakref_GET_OBJECT(other
), op
);
172 _PyWeakref_RefType
= {
173 PyObject_HEAD_INIT(&PyType_Type
)
176 sizeof(PyWeakReference
),
178 (destructor
)weakref_dealloc
,/*tp_dealloc*/
183 (reprfunc
)weakref_repr
, /*tp_repr*/
185 0, /*tp_as_sequence*/
187 (hashfunc
)weakref_hash
, /*tp_hash*/
188 (ternaryfunc
)weakref_call
, /*tp_call*/
193 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_HAVE_GC
| Py_TPFLAGS_HAVE_RICHCOMPARE
,
195 (traverseproc
)gc_traverse
, /*tp_traverse*/
196 (inquiry
)gc_clear
, /*tp_clear*/
197 (richcmpfunc
)weakref_richcompare
, /*tp_richcompare*/
198 0, /*tp_weaklistoffset*/
203 proxy_checkref(PyWeakReference
*proxy
)
205 if (PyWeakref_GET_OBJECT(proxy
) == Py_None
) {
206 PyErr_SetString(PyExc_ReferenceError
,
207 "weakly-referenced object no longer exists");
214 /* If a parameter is a proxy, check that it is still "live" and wrap it,
215 * replacing the original value with the raw object. Raises ReferenceError
216 * if the param is a dead proxy.
219 if (PyWeakref_CheckProxy(o)) { \
220 if (!proxy_checkref((PyWeakReference *)o)) \
222 o = PyWeakref_GET_OBJECT(o); \
225 #define UNWRAP_I(o) \
226 if (PyWeakref_CheckProxy(o)) { \
227 if (!proxy_checkref((PyWeakReference *)o)) \
229 o = PyWeakref_GET_OBJECT(o); \
232 #define WRAP_UNARY(method, generic) \
234 method(PyObject *proxy) { \
236 return generic(proxy); \
239 #define WRAP_BINARY(method, generic) \
241 method(PyObject *x, PyObject *y) { \
244 return generic(x, y); \
247 /* Note that the third arg needs to be checked for NULL since the tp_call
248 * slot can receive NULL for this arg.
250 #define WRAP_TERNARY(method, generic) \
252 method(PyObject *proxy, PyObject *v, PyObject *w) { \
257 return generic(proxy, v, w); \
263 WRAP_BINARY(proxy_getattr
, PyObject_GetAttr
)
264 WRAP_UNARY(proxy_str
, PyObject_Str
)
265 WRAP_TERNARY(proxy_call
, PyEval_CallObjectWithKeywords
)
268 proxy_print(PyWeakReference
*proxy
, FILE *fp
, int flags
)
270 if (!proxy_checkref(proxy
))
272 return PyObject_Print(PyWeakref_GET_OBJECT(proxy
), fp
, flags
);
276 proxy_repr(PyWeakReference
*proxy
)
279 PyOS_snprintf(buf
, sizeof(buf
),
280 "<weakproxy at %p to %.100s at %p>", proxy
,
281 PyWeakref_GET_OBJECT(proxy
)->ob_type
->tp_name
,
282 PyWeakref_GET_OBJECT(proxy
));
283 return PyString_FromString(buf
);
288 proxy_setattr(PyWeakReference
*proxy
, PyObject
*name
, PyObject
*value
)
290 if (!proxy_checkref(proxy
))
292 return PyObject_SetAttr(PyWeakref_GET_OBJECT(proxy
), name
, value
);
296 proxy_compare(PyObject
*proxy
, PyObject
*v
)
300 return PyObject_Compare(proxy
, v
);
304 WRAP_BINARY(proxy_add
, PyNumber_Add
)
305 WRAP_BINARY(proxy_sub
, PyNumber_Subtract
)
306 WRAP_BINARY(proxy_mul
, PyNumber_Multiply
)
307 WRAP_BINARY(proxy_div
, PyNumber_Divide
)
308 WRAP_BINARY(proxy_mod
, PyNumber_Remainder
)
309 WRAP_BINARY(proxy_divmod
, PyNumber_Divmod
)
310 WRAP_TERNARY(proxy_pow
, PyNumber_Power
)
311 WRAP_UNARY(proxy_neg
, PyNumber_Negative
)
312 WRAP_UNARY(proxy_pos
, PyNumber_Positive
)
313 WRAP_UNARY(proxy_abs
, PyNumber_Absolute
)
314 WRAP_UNARY(proxy_invert
, PyNumber_Invert
)
315 WRAP_BINARY(proxy_lshift
, PyNumber_Lshift
)
316 WRAP_BINARY(proxy_rshift
, PyNumber_Rshift
)
317 WRAP_BINARY(proxy_and
, PyNumber_And
)
318 WRAP_BINARY(proxy_xor
, PyNumber_Xor
)
319 WRAP_BINARY(proxy_or
, PyNumber_Or
)
320 WRAP_UNARY(proxy_int
, PyNumber_Int
)
321 WRAP_UNARY(proxy_long
, PyNumber_Long
)
322 WRAP_UNARY(proxy_float
, PyNumber_Float
)
323 WRAP_BINARY(proxy_iadd
, PyNumber_InPlaceAdd
)
324 WRAP_BINARY(proxy_isub
, PyNumber_InPlaceSubtract
)
325 WRAP_BINARY(proxy_imul
, PyNumber_InPlaceMultiply
)
326 WRAP_BINARY(proxy_idiv
, PyNumber_InPlaceDivide
)
327 WRAP_BINARY(proxy_imod
, PyNumber_InPlaceRemainder
)
328 WRAP_TERNARY(proxy_ipow
, PyNumber_InPlacePower
)
329 WRAP_BINARY(proxy_ilshift
, PyNumber_InPlaceLshift
)
330 WRAP_BINARY(proxy_irshift
, PyNumber_InPlaceRshift
)
331 WRAP_BINARY(proxy_iand
, PyNumber_InPlaceAnd
)
332 WRAP_BINARY(proxy_ixor
, PyNumber_InPlaceXor
)
333 WRAP_BINARY(proxy_ior
, PyNumber_InPlaceOr
)
336 proxy_nonzero(PyWeakReference
*proxy
)
338 PyObject
*o
= PyWeakref_GET_OBJECT(proxy
);
339 if (!proxy_checkref(proxy
))
341 if (o
->ob_type
->tp_as_number
&&
342 o
->ob_type
->tp_as_number
->nb_nonzero
)
343 return (*o
->ob_type
->tp_as_number
->nb_nonzero
)(o
);
351 proxy_slice(PyWeakReference
*proxy
, int i
, int j
)
353 if (!proxy_checkref(proxy
))
355 return PySequence_GetSlice(PyWeakref_GET_OBJECT(proxy
), i
, j
);
359 proxy_ass_slice(PyWeakReference
*proxy
, int i
, int j
, PyObject
*value
)
361 if (!proxy_checkref(proxy
))
363 return PySequence_SetSlice(PyWeakref_GET_OBJECT(proxy
), i
, j
, value
);
367 proxy_contains(PyWeakReference
*proxy
, PyObject
*value
)
369 if (!proxy_checkref(proxy
))
371 return PySequence_Contains(PyWeakref_GET_OBJECT(proxy
), value
);
378 proxy_length(PyWeakReference
*proxy
)
380 if (!proxy_checkref(proxy
))
382 return PyObject_Length(PyWeakref_GET_OBJECT(proxy
));
385 WRAP_BINARY(proxy_getitem
, PyObject_GetItem
)
388 proxy_setitem(PyWeakReference
*proxy
, PyObject
*key
, PyObject
*value
)
390 if (!proxy_checkref(proxy
))
392 return PyObject_SetItem(PyWeakref_GET_OBJECT(proxy
), key
, value
);
398 proxy_iter(PyWeakReference
*proxy
)
400 if (!proxy_checkref(proxy
))
402 return PyObject_GetIter(PyWeakref_GET_OBJECT(proxy
));
406 proxy_iternext(PyWeakReference
*proxy
)
408 if (!proxy_checkref(proxy
))
410 return PyIter_Next(PyWeakref_GET_OBJECT(proxy
));
414 static PyNumberMethods proxy_as_number
= {
415 (binaryfunc
)proxy_add
, /*nb_add*/
416 (binaryfunc
)proxy_sub
, /*nb_subtract*/
417 (binaryfunc
)proxy_mul
, /*nb_multiply*/
418 (binaryfunc
)proxy_div
, /*nb_divide*/
419 (binaryfunc
)proxy_mod
, /*nb_remainder*/
420 (binaryfunc
)proxy_divmod
, /*nb_divmod*/
421 (ternaryfunc
)proxy_pow
, /*nb_power*/
422 (unaryfunc
)proxy_neg
, /*nb_negative*/
423 (unaryfunc
)proxy_pos
, /*nb_positive*/
424 (unaryfunc
)proxy_abs
, /*nb_absolute*/
425 (inquiry
)proxy_nonzero
, /*nb_nonzero*/
426 (unaryfunc
)proxy_invert
, /*nb_invert*/
427 (binaryfunc
)proxy_lshift
, /*nb_lshift*/
428 (binaryfunc
)proxy_rshift
, /*nb_rshift*/
429 (binaryfunc
)proxy_and
, /*nb_and*/
430 (binaryfunc
)proxy_xor
, /*nb_xor*/
431 (binaryfunc
)proxy_or
, /*nb_or*/
432 (coercion
)0, /*nb_coerce*/
433 (unaryfunc
)proxy_int
, /*nb_int*/
434 (unaryfunc
)proxy_long
, /*nb_long*/
435 (unaryfunc
)proxy_float
, /*nb_float*/
436 (unaryfunc
)0, /*nb_oct*/
437 (unaryfunc
)0, /*nb_hex*/
438 (binaryfunc
)proxy_iadd
, /*nb_inplace_add*/
439 (binaryfunc
)proxy_isub
, /*nb_inplace_subtract*/
440 (binaryfunc
)proxy_imul
, /*nb_inplace_multiply*/
441 (binaryfunc
)proxy_idiv
, /*nb_inplace_divide*/
442 (binaryfunc
)proxy_imod
, /*nb_inplace_remainder*/
443 (ternaryfunc
)proxy_ipow
, /*nb_inplace_power*/
444 (binaryfunc
)proxy_ilshift
, /*nb_inplace_lshift*/
445 (binaryfunc
)proxy_irshift
, /*nb_inplace_rshift*/
446 (binaryfunc
)proxy_iand
, /*nb_inplace_and*/
447 (binaryfunc
)proxy_ixor
, /*nb_inplace_xor*/
448 (binaryfunc
)proxy_ior
, /*nb_inplace_or*/
451 static PySequenceMethods proxy_as_sequence
= {
452 (inquiry
)proxy_length
, /*sq_length*/
456 (intintargfunc
)proxy_slice
, /*sq_slice*/
458 (intintobjargproc
)proxy_ass_slice
, /*sq_ass_slice*/
459 (objobjproc
)proxy_contains
, /* sq_contains */
462 static PyMappingMethods proxy_as_mapping
= {
463 (inquiry
)proxy_length
, /*mp_length*/
464 (binaryfunc
)proxy_getitem
, /*mp_subscript*/
465 (objobjargproc
)proxy_setitem
, /*mp_ass_subscript*/
470 _PyWeakref_ProxyType
= {
471 PyObject_HEAD_INIT(&PyType_Type
)
474 sizeof(PyWeakReference
),
477 (destructor
)weakref_dealloc
, /* tp_dealloc */
478 (printfunc
)proxy_print
, /* tp_print */
481 proxy_compare
, /* tp_compare */
482 (unaryfunc
)proxy_repr
, /* tp_repr */
483 &proxy_as_number
, /* tp_as_number */
484 &proxy_as_sequence
, /* tp_as_sequence */
485 &proxy_as_mapping
, /* tp_as_mapping */
487 (ternaryfunc
)0, /* tp_call */
488 (unaryfunc
)proxy_str
, /* tp_str */
489 (getattrofunc
)proxy_getattr
, /* tp_getattro */
490 (setattrofunc
)proxy_setattr
, /* tp_setattro */
491 0, /* tp_as_buffer */
492 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_HAVE_GC
493 | Py_TPFLAGS_CHECKTYPES
, /* tp_flags */
495 (traverseproc
)gc_traverse
, /* tp_traverse */
496 (inquiry
)gc_clear
, /* tp_clear */
497 0, /* tp_richcompare */
498 0, /* tp_weaklistoffset */
499 (getiterfunc
)proxy_iter
, /* tp_iter */
500 (iternextfunc
)proxy_iternext
, /* tp_iternext */
505 _PyWeakref_CallableProxyType
= {
506 PyObject_HEAD_INIT(&PyType_Type
)
509 sizeof(PyWeakReference
),
512 (destructor
)weakref_dealloc
, /* tp_dealloc */
513 (printfunc
)proxy_print
, /* tp_print */
516 proxy_compare
, /* tp_compare */
517 (unaryfunc
)proxy_repr
, /* tp_repr */
518 &proxy_as_number
, /* tp_as_number */
519 &proxy_as_sequence
, /* tp_as_sequence */
520 &proxy_as_mapping
, /* tp_as_mapping */
522 (ternaryfunc
)proxy_call
, /* tp_call */
523 (unaryfunc
)proxy_str
, /* tp_str */
524 (getattrofunc
)proxy_getattr
, /* tp_getattro */
525 (setattrofunc
)proxy_setattr
, /* tp_setattro */
526 0, /* tp_as_buffer */
527 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_HAVE_GC
528 | Py_TPFLAGS_CHECKTYPES
, /* tp_flags */
530 (traverseproc
)gc_traverse
, /* tp_traverse */
531 (inquiry
)gc_clear
, /* tp_clear */
532 0, /* tp_richcompare */
533 0, /* tp_weaklistoffset */
534 (getiterfunc
)proxy_iter
, /* tp_iter */
535 (iternextfunc
)proxy_iternext
, /* tp_iternext */
539 /* Given the head of an object's list of weak references, extract the
540 * two callback-less refs (ref and proxy). Used to determine if the
541 * shared references exist and to determine the back link for newly
542 * inserted references.
545 get_basic_refs(PyWeakReference
*head
,
546 PyWeakReference
**refp
, PyWeakReference
**proxyp
)
551 if (head
!= NULL
&& head
->wr_callback
== NULL
) {
552 if (head
->ob_type
== &_PyWeakref_RefType
) {
554 head
= head
->wr_next
;
556 if (head
!= NULL
&& head
->wr_callback
== NULL
) {
558 head
= head
->wr_next
;
563 /* Insert 'newref' in the list after 'prev'. Both must be non-NULL. */
565 insert_after(PyWeakReference
*newref
, PyWeakReference
*prev
)
567 newref
->wr_prev
= prev
;
568 newref
->wr_next
= prev
->wr_next
;
569 if (prev
->wr_next
!= NULL
)
570 prev
->wr_next
->wr_prev
= newref
;
571 prev
->wr_next
= newref
;
574 /* Insert 'newref' at the head of the list; 'list' points to the variable
575 * that stores the head.
578 insert_head(PyWeakReference
*newref
, PyWeakReference
**list
)
580 PyWeakReference
*next
= *list
;
582 newref
->wr_prev
= NULL
;
583 newref
->wr_next
= next
;
585 next
->wr_prev
= newref
;
591 PyWeakref_NewRef(PyObject
*ob
, PyObject
*callback
)
593 PyWeakReference
*result
= NULL
;
594 PyWeakReference
**list
;
595 PyWeakReference
*ref
, *proxy
;
597 if (!PyType_SUPPORTS_WEAKREFS(ob
->ob_type
)) {
598 PyErr_Format(PyExc_TypeError
,
599 "cannot create weak reference to '%s' object",
600 ob
->ob_type
->tp_name
);
603 list
= GET_WEAKREFS_LISTPTR(ob
);
604 get_basic_refs(*list
, &ref
, &proxy
);
605 if (callback
== NULL
|| callback
== Py_None
)
606 /* return existing weak reference if it exists */
611 result
= new_weakref(ob
, callback
);
612 if (result
!= NULL
) {
613 if (callback
== NULL
) {
614 insert_head(result
, list
);
617 PyWeakReference
*prev
= (proxy
== NULL
) ? ref
: proxy
;
620 insert_head(result
, list
);
622 insert_after(result
, prev
);
626 return (PyObject
*) result
;
631 PyWeakref_NewProxy(PyObject
*ob
, PyObject
*callback
)
633 PyWeakReference
*result
= NULL
;
634 PyWeakReference
**list
;
635 PyWeakReference
*ref
, *proxy
;
637 if (!PyType_SUPPORTS_WEAKREFS(ob
->ob_type
)) {
638 PyErr_Format(PyExc_TypeError
,
639 "cannot create weak reference to '%s' object",
640 ob
->ob_type
->tp_name
);
643 list
= GET_WEAKREFS_LISTPTR(ob
);
644 get_basic_refs(*list
, &ref
, &proxy
);
645 if (callback
== NULL
)
646 /* attempt to return an existing weak reference if it exists */
651 result
= new_weakref(ob
, callback
);
652 if (result
!= NULL
) {
653 PyWeakReference
*prev
;
655 if (PyCallable_Check(ob
))
656 result
->ob_type
= &_PyWeakref_CallableProxyType
;
658 result
->ob_type
= &_PyWeakref_ProxyType
;
659 if (callback
== NULL
)
662 prev
= (proxy
== NULL
) ? ref
: proxy
;
665 insert_head(result
, list
);
667 insert_after(result
, prev
);
670 return (PyObject
*) result
;
675 PyWeakref_GetObject(PyObject
*ref
)
677 if (ref
== NULL
|| !PyWeakref_Check(ref
)) {
678 PyErr_BadInternalCall();
681 return PyWeakref_GET_OBJECT(ref
);
686 handle_callback(PyWeakReference
*ref
, PyObject
*callback
)
688 PyObject
*cbresult
= PyObject_CallFunction(callback
, "O", ref
);
690 if (cbresult
== NULL
)
691 PyErr_WriteUnraisable(callback
);
696 /* This function is called by the tp_dealloc handler to clear weak references.
698 * This iterates through the weak references for 'object' and calls callbacks
699 * for those references which have one. It returns when all callbacks have
703 PyObject_ClearWeakRefs(PyObject
*object
)
705 PyWeakReference
**list
;
708 || !PyType_SUPPORTS_WEAKREFS(object
->ob_type
)
709 || object
->ob_refcnt
!= 0) {
710 PyErr_BadInternalCall();
713 list
= GET_WEAKREFS_LISTPTR(object
);
714 /* Remove the callback-less basic and proxy references */
715 if (*list
!= NULL
&& (*list
)->wr_callback
== NULL
) {
716 clear_weakref(*list
);
717 if (*list
!= NULL
&& (*list
)->wr_callback
== NULL
)
718 clear_weakref(*list
);
721 PyWeakReference
*current
= *list
;
722 int count
= _PyWeakref_GetWeakrefCount(current
);
723 int restore_error
= PyErr_Occurred() ? 1 : 0;
724 PyObject
*err_type
, *err_value
, *err_tb
;
727 PyErr_Fetch(&err_type
, &err_value
, &err_tb
);
729 PyObject
*callback
= current
->wr_callback
;
731 current
->wr_callback
= NULL
;
732 clear_weakref(current
);
733 handle_callback(current
, callback
);
737 PyObject
*tuple
= PyTuple_New(count
* 2);
740 for (i
= 0; i
< count
; ++i
) {
741 PyWeakReference
*next
= current
->wr_next
;
744 PyTuple_SET_ITEM(tuple
, i
* 2, (PyObject
*) current
);
745 PyTuple_SET_ITEM(tuple
, i
* 2 + 1, current
->wr_callback
);
746 current
->wr_callback
= NULL
;
747 clear_weakref(current
);
750 for (i
= 0; i
< count
; ++i
) {
751 PyObject
*current
= PyTuple_GET_ITEM(tuple
, i
* 2);
752 PyObject
*callback
= PyTuple_GET_ITEM(tuple
, i
* 2 + 1);
754 handle_callback((PyWeakReference
*)current
, callback
);
759 PyErr_Restore(err_type
, err_value
, err_tb
);