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 %lx; dead>",
131 PyOS_snprintf(buffer
, sizeof(buffer
),
132 "<weakref at %#lx; to '%.50s' at %#lx>",
134 PyWeakref_GET_OBJECT(self
)->ob_type
->tp_name
,
135 (long)(PyWeakref_GET_OBJECT(self
)));
137 return PyString_FromString(buffer
);
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. */
145 weakref_richcompare(PyWeakReference
* self
, PyWeakReference
* other
, int op
)
147 if (op
!= Py_EQ
|| self
->ob_type
!= other
->ob_type
) {
148 Py_INCREF(Py_NotImplemented
);
149 return Py_NotImplemented
;
151 if (PyWeakref_GET_OBJECT(self
) == Py_None
152 || PyWeakref_GET_OBJECT(other
) == Py_None
) {
153 PyObject
*res
= self
==other
? Py_True
: Py_False
;
157 return PyObject_RichCompare(PyWeakref_GET_OBJECT(self
),
158 PyWeakref_GET_OBJECT(other
), op
);
163 _PyWeakref_RefType
= {
164 PyObject_HEAD_INIT(&PyType_Type
)
167 sizeof(PyWeakReference
),
169 (destructor
)weakref_dealloc
,/*tp_dealloc*/
174 (reprfunc
)weakref_repr
, /*tp_repr*/
176 0, /*tp_as_sequence*/
178 (hashfunc
)weakref_hash
, /*tp_hash*/
179 (ternaryfunc
)weakref_call
, /*tp_call*/
184 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_HAVE_GC
| Py_TPFLAGS_HAVE_RICHCOMPARE
,
186 (traverseproc
)gc_traverse
, /*tp_traverse*/
187 (inquiry
)gc_clear
, /*tp_clear*/
188 (richcmpfunc
)weakref_richcompare
, /*tp_richcompare*/
189 0, /*tp_weaklistoffset*/
194 proxy_checkref(PyWeakReference
*proxy
)
196 if (PyWeakref_GET_OBJECT(proxy
) == Py_None
) {
197 PyErr_SetString(PyExc_ReferenceError
,
198 "weakly-referenced object no longer exists");
205 /* 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.
210 if (PyWeakref_CheckProxy(o)) { \
211 if (!proxy_checkref((PyWeakReference *)o)) \
213 o = PyWeakref_GET_OBJECT(o); \
216 #define UNWRAP_I(o) \
217 if (PyWeakref_CheckProxy(o)) { \
218 if (!proxy_checkref((PyWeakReference *)o)) \
220 o = PyWeakref_GET_OBJECT(o); \
223 #define WRAP_UNARY(method, generic) \
225 method(PyObject *proxy) { \
227 return generic(proxy); \
230 #define WRAP_BINARY(method, generic) \
232 method(PyObject *x, PyObject *y) { \
235 return generic(x, y); \
238 /* Note that the third arg needs to be checked for NULL since the tp_call
239 * slot can receive NULL for this arg.
241 #define WRAP_TERNARY(method, generic) \
243 method(PyObject *proxy, PyObject *v, PyObject *w) { \
248 return generic(proxy, v, w); \
254 WRAP_BINARY(proxy_getattr
, PyObject_GetAttr
)
255 WRAP_UNARY(proxy_str
, PyObject_Str
)
256 WRAP_TERNARY(proxy_call
, PyEval_CallObjectWithKeywords
)
259 proxy_print(PyWeakReference
*proxy
, FILE *fp
, int flags
)
261 if (!proxy_checkref(proxy
))
263 return PyObject_Print(PyWeakref_GET_OBJECT(proxy
), fp
, flags
);
267 proxy_repr(PyWeakReference
*proxy
)
270 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
));
274 return PyString_FromString(buf
);
279 proxy_setattr(PyWeakReference
*proxy
, PyObject
*name
, PyObject
*value
)
281 if (!proxy_checkref(proxy
))
283 return PyObject_SetAttr(PyWeakref_GET_OBJECT(proxy
), name
, value
);
287 proxy_compare(PyObject
*proxy
, PyObject
*v
)
291 return PyObject_Compare(proxy
, v
);
295 WRAP_BINARY(proxy_add
, PyNumber_Add
)
296 WRAP_BINARY(proxy_sub
, PyNumber_Subtract
)
297 WRAP_BINARY(proxy_mul
, PyNumber_Multiply
)
298 WRAP_BINARY(proxy_div
, PyNumber_Divide
)
299 WRAP_BINARY(proxy_mod
, PyNumber_Remainder
)
300 WRAP_BINARY(proxy_divmod
, PyNumber_Divmod
)
301 WRAP_TERNARY(proxy_pow
, PyNumber_Power
)
302 WRAP_UNARY(proxy_neg
, PyNumber_Negative
)
303 WRAP_UNARY(proxy_pos
, PyNumber_Positive
)
304 WRAP_UNARY(proxy_abs
, PyNumber_Absolute
)
305 WRAP_UNARY(proxy_invert
, PyNumber_Invert
)
306 WRAP_BINARY(proxy_lshift
, PyNumber_Lshift
)
307 WRAP_BINARY(proxy_rshift
, PyNumber_Rshift
)
308 WRAP_BINARY(proxy_and
, PyNumber_And
)
309 WRAP_BINARY(proxy_xor
, PyNumber_Xor
)
310 WRAP_BINARY(proxy_or
, PyNumber_Or
)
311 WRAP_UNARY(proxy_int
, PyNumber_Int
)
312 WRAP_UNARY(proxy_long
, PyNumber_Long
)
313 WRAP_UNARY(proxy_float
, PyNumber_Float
)
314 WRAP_BINARY(proxy_iadd
, PyNumber_InPlaceAdd
)
315 WRAP_BINARY(proxy_isub
, PyNumber_InPlaceSubtract
)
316 WRAP_BINARY(proxy_imul
, PyNumber_InPlaceMultiply
)
317 WRAP_BINARY(proxy_idiv
, PyNumber_InPlaceDivide
)
318 WRAP_BINARY(proxy_imod
, PyNumber_InPlaceRemainder
)
319 WRAP_TERNARY(proxy_ipow
, PyNumber_InPlacePower
)
320 WRAP_BINARY(proxy_ilshift
, PyNumber_InPlaceLshift
)
321 WRAP_BINARY(proxy_irshift
, PyNumber_InPlaceRshift
)
322 WRAP_BINARY(proxy_iand
, PyNumber_InPlaceAnd
)
323 WRAP_BINARY(proxy_ixor
, PyNumber_InPlaceXor
)
324 WRAP_BINARY(proxy_ior
, PyNumber_InPlaceOr
)
327 proxy_nonzero(PyWeakReference
*proxy
)
329 PyObject
*o
= PyWeakref_GET_OBJECT(proxy
);
330 if (!proxy_checkref(proxy
))
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
);
342 proxy_slice(PyWeakReference
*proxy
, int i
, int j
)
344 if (!proxy_checkref(proxy
))
346 return PySequence_GetSlice(PyWeakref_GET_OBJECT(proxy
), i
, j
);
350 proxy_ass_slice(PyWeakReference
*proxy
, int i
, int j
, PyObject
*value
)
352 if (!proxy_checkref(proxy
))
354 return PySequence_SetSlice(PyWeakref_GET_OBJECT(proxy
), i
, j
, value
);
358 proxy_contains(PyWeakReference
*proxy
, PyObject
*value
)
360 if (!proxy_checkref(proxy
))
362 return PySequence_Contains(PyWeakref_GET_OBJECT(proxy
), value
);
369 proxy_length(PyWeakReference
*proxy
)
371 if (!proxy_checkref(proxy
))
373 return PyObject_Length(PyWeakref_GET_OBJECT(proxy
));
376 WRAP_BINARY(proxy_getitem
, PyObject_GetItem
)
379 proxy_setitem(PyWeakReference
*proxy
, PyObject
*key
, PyObject
*value
)
381 if (!proxy_checkref(proxy
))
383 return PyObject_SetItem(PyWeakref_GET_OBJECT(proxy
), key
, value
);
389 proxy_iter(PyWeakReference
*proxy
)
391 if (!proxy_checkref(proxy
))
393 return PyObject_GetIter(PyWeakref_GET_OBJECT(proxy
));
397 proxy_iternext(PyWeakReference
*proxy
)
399 if (!proxy_checkref(proxy
))
401 return PyIter_Next(PyWeakref_GET_OBJECT(proxy
));
405 static 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*/
442 static PySequenceMethods proxy_as_sequence
= {
443 (inquiry
)proxy_length
, /*sq_length*/
447 (intintargfunc
)proxy_slice
, /*sq_slice*/
449 (intintobjargproc
)proxy_ass_slice
, /*sq_ass_slice*/
450 (objobjproc
)proxy_contains
, /* sq_contains */
453 static PyMappingMethods proxy_as_mapping
= {
454 (inquiry
)proxy_length
, /*mp_length*/
455 (binaryfunc
)proxy_getitem
, /*mp_subscript*/
456 (objobjargproc
)proxy_setitem
, /*mp_ass_subscript*/
461 _PyWeakref_ProxyType
= {
462 PyObject_HEAD_INIT(&PyType_Type
)
465 sizeof(PyWeakReference
),
468 (destructor
)weakref_dealloc
, /* tp_dealloc */
469 (printfunc
)proxy_print
, /* tp_print */
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 */
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 */
483 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_HAVE_GC
484 | Py_TPFLAGS_CHECKTYPES
, /* tp_flags */
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 */
496 _PyWeakref_CallableProxyType
= {
497 PyObject_HEAD_INIT(&PyType_Type
)
500 sizeof(PyWeakReference
),
503 (destructor
)weakref_dealloc
, /* tp_dealloc */
504 (printfunc
)proxy_print
, /* tp_print */
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 */
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 */
518 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_HAVE_GC
519 | Py_TPFLAGS_CHECKTYPES
, /* tp_flags */
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 */
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.
536 get_basic_refs(PyWeakReference
*head
,
537 PyWeakReference
**refp
, PyWeakReference
**proxyp
)
542 if (head
!= NULL
&& head
->wr_callback
== NULL
) {
543 if (head
->ob_type
== &_PyWeakref_RefType
) {
545 head
= head
->wr_next
;
547 if (head
!= NULL
&& head
->wr_callback
== NULL
) {
549 head
= head
->wr_next
;
554 /* Insert 'newref' in the list after 'prev'. Both must be non-NULL. */
556 insert_after(PyWeakReference
*newref
, PyWeakReference
*prev
)
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
;
565 /* Insert 'newref' at the head of the list; 'list' points to the variable
566 * that stores the head.
569 insert_head(PyWeakReference
*newref
, PyWeakReference
**list
)
571 PyWeakReference
*next
= *list
;
573 newref
->wr_prev
= NULL
;
574 newref
->wr_next
= next
;
576 next
->wr_prev
= newref
;
582 PyWeakref_NewRef(PyObject
*ob
, PyObject
*callback
)
584 PyWeakReference
*result
= NULL
;
585 PyWeakReference
**list
;
586 PyWeakReference
*ref
, *proxy
;
588 if (!PyType_SUPPORTS_WEAKREFS(ob
->ob_type
)) {
589 PyErr_Format(PyExc_TypeError
,
590 "cannot create weak reference to '%s' object",
591 ob
->ob_type
->tp_name
);
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 */
602 result
= new_weakref(ob
, callback
);
603 if (result
!= NULL
) {
604 if (callback
== NULL
) {
605 insert_head(result
, list
);
608 PyWeakReference
*prev
= (proxy
== NULL
) ? ref
: proxy
;
611 insert_head(result
, list
);
613 insert_after(result
, prev
);
617 return (PyObject
*) result
;
622 PyWeakref_NewProxy(PyObject
*ob
, PyObject
*callback
)
624 PyWeakReference
*result
= NULL
;
625 PyWeakReference
**list
;
626 PyWeakReference
*ref
, *proxy
;
628 if (!PyType_SUPPORTS_WEAKREFS(ob
->ob_type
)) {
629 PyErr_Format(PyExc_TypeError
,
630 "cannot create weak reference to '%s' object",
631 ob
->ob_type
->tp_name
);
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 */
642 result
= new_weakref(ob
, callback
);
643 if (result
!= NULL
) {
644 PyWeakReference
*prev
;
646 if (PyCallable_Check(ob
))
647 result
->ob_type
= &_PyWeakref_CallableProxyType
;
649 result
->ob_type
= &_PyWeakref_ProxyType
;
650 if (callback
== NULL
)
653 prev
= (proxy
== NULL
) ? ref
: proxy
;
656 insert_head(result
, list
);
658 insert_after(result
, prev
);
661 return (PyObject
*) result
;
666 PyWeakref_GetObject(PyObject
*ref
)
668 if (ref
== NULL
|| !PyWeakref_Check(ref
)) {
669 PyErr_BadInternalCall();
672 return PyWeakref_GET_OBJECT(ref
);
677 handle_callback(PyWeakReference
*ref
, PyObject
*callback
)
679 PyObject
*cbresult
= PyObject_CallFunction(callback
, "O", ref
);
681 if (cbresult
== NULL
)
682 PyErr_WriteUnraisable(callback
);
687 /* This function is called by the tp_dealloc handler to clear weak references.
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
694 PyObject_ClearWeakRefs(PyObject
*object
)
696 PyWeakReference
**list
;
699 || !PyType_SUPPORTS_WEAKREFS(object
->ob_type
)
700 || object
->ob_refcnt
!= 0) {
701 PyErr_BadInternalCall();
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
);
712 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
;
718 PyErr_Fetch(&err_type
, &err_value
, &err_tb
);
720 PyObject
*callback
= current
->wr_callback
;
722 current
->wr_callback
= NULL
;
723 clear_weakref(current
);
724 handle_callback(current
, callback
);
728 PyObject
*tuple
= PyTuple_New(count
* 2);
731 for (i
= 0; i
< count
; ++i
) {
732 PyWeakReference
*next
= current
->wr_next
;
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
;
738 clear_weakref(current
);
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);
745 handle_callback((PyWeakReference
*)current
, callback
);
750 PyErr_Restore(err_type
, err_value
, err_tb
);