77 BSD-style license that can be found in the LICENSE file.
88*/
99
10+ #include < pybind11/detail/internals.h>
1011#include < pybind11/pybind11.h>
1112
1213#include " pybind11_tests.h"
1314
15+ #include < vector>
16+
1417namespace py = pybind11;
1518
1619namespace {
20+ struct ContainerOwnsPythonObjects {
21+ std::vector<py::object> list;
1722
18- struct OwnsPythonObjects {
19- py::object value = py::none();
23+ void append (const py::object &obj) { list.emplace_back (obj); }
24+ py::object at (py::ssize_t index) const {
25+ if (index >= size () || index < 0 ) {
26+ throw py::index_error (" Index out of range" );
27+ }
28+ return list.at (py::size_t (index));
29+ }
30+ py::ssize_t size () const { return py::ssize_t_cast (list.size ()); }
31+ void clear () { list.clear (); }
2032};
33+
34+ void add_gc_checkers_with_weakrefs (const py::object &obj) {
35+ py::handle global_capsule = py::detail::get_internals_capsule ();
36+ if (!global_capsule) {
37+ throw std::runtime_error (" No global internals capsule found" );
38+ }
39+ (void ) py::weakref (obj, py::cpp_function ([global_capsule, obj](py::handle weakref) -> void {
40+ py::handle new_global_capsule = py::detail::get_internals_capsule ();
41+ if (!new_global_capsule.is (global_capsule)) {
42+ throw std::runtime_error (
43+ " Global internals capsule was destroyed prematurely" );
44+ }
45+ weakref.dec_ref ();
46+ }))
47+ .release ();
48+
49+ py::handle local_capsule = py::detail::get_local_internals_capsule ();
50+ if (!local_capsule) {
51+ throw std::runtime_error (" No local internals capsule found" );
52+ }
53+ (void ) py::weakref (
54+ obj, py::cpp_function ([local_capsule, obj](py::handle weakref) -> void {
55+ py::handle new_local_capsule = py::detail::get_local_internals_capsule ();
56+ if (!new_local_capsule.is (local_capsule)) {
57+ throw std::runtime_error (" Local internals capsule was destroyed prematurely" );
58+ }
59+ weakref.dec_ref ();
60+ }))
61+ .release ();
62+ }
2163} // namespace
2264
2365TEST_SUBMODULE (custom_type_setup, m) {
24- py::class_<OwnsPythonObjects > cls (
25- m, " OwnsPythonObjects " , py::custom_type_setup ([](PyHeapTypeObject *heap_type) {
66+ py::class_<ContainerOwnsPythonObjects > cls (
67+ m, " ContainerOwnsPythonObjects " , py::custom_type_setup ([](PyHeapTypeObject *heap_type) {
2668 auto *type = &heap_type->ht_type ;
2769 type->tp_flags |= Py_TPFLAGS_HAVE_GC;
2870 type->tp_traverse = [](PyObject *self_base, visitproc visit, void *arg) {
@@ -31,19 +73,29 @@ TEST_SUBMODULE(custom_type_setup, m) {
3173 Py_VISIT (Py_TYPE (self_base));
3274#endif
3375 if (py::detail::is_holder_constructed (self_base)) {
34- auto &self = py::cast<OwnsPythonObjects &>(py::handle (self_base));
35- Py_VISIT (self.value .ptr ());
76+ auto &self = py::cast<ContainerOwnsPythonObjects &>(py::handle (self_base));
77+ for (auto &item : self.list ) {
78+ Py_VISIT (item.ptr ());
79+ }
3680 }
3781 return 0 ;
3882 };
3983 type->tp_clear = [](PyObject *self_base) {
4084 if (py::detail::is_holder_constructed (self_base)) {
41- auto &self = py::cast<OwnsPythonObjects &>(py::handle (self_base));
42- self.value = py::none ();
85+ auto &self = py::cast<ContainerOwnsPythonObjects &>(py::handle (self_base));
86+ for (auto &item : self.list ) {
87+ Py_CLEAR (item.ptr ());
88+ }
89+ self.list .clear ();
4390 }
4491 return 0 ;
4592 };
4693 }));
4794 cls.def (py::init<>());
48- cls.def_readwrite (" value" , &OwnsPythonObjects::value);
95+ cls.def (" append" , &ContainerOwnsPythonObjects::append);
96+ cls.def (" at" , &ContainerOwnsPythonObjects::at);
97+ cls.def (" size" , &ContainerOwnsPythonObjects::size);
98+ cls.def (" clear" , &ContainerOwnsPythonObjects::clear);
99+
100+ m.def (" add_gc_checkers_with_weakrefs" , &add_gc_checkers_with_weakrefs);
49101}
0 commit comments