A singleton class that holds references to certain Python objects This singleton is per-interpreter using gil_safe_call_once_and_store
| 14 | // A singleton class that holds references to certain Python objects |
| 15 | // This singleton is per-interpreter using gil_safe_call_once_and_store |
| 16 | class MySingleton { |
| 17 | public: |
| 18 | MySingleton() = default; |
| 19 | ~MySingleton() = default; |
| 20 | MySingleton(const MySingleton &) = delete; |
| 21 | MySingleton &operator=(const MySingleton &) = delete; |
| 22 | MySingleton(MySingleton &&) = default; |
| 23 | MySingleton &operator=(MySingleton &&) = default; |
| 24 | |
| 25 | static MySingleton &get_instance() { |
| 26 | PYBIND11_CONSTINIT static py::gil_safe_call_once_and_store<MySingleton> storage; |
| 27 | return storage |
| 28 | .call_once_and_store_result([]() -> MySingleton { |
| 29 | MySingleton instance{}; |
| 30 | |
| 31 | auto emplace = [&instance](const py::handle &obj) -> void { |
| 32 | obj.inc_ref(); // Ensure the object is not GC'd while interpreter is alive |
| 33 | instance.objects.emplace_back(obj); |
| 34 | }; |
| 35 | |
| 36 | // Example objects to store in the singleton |
| 37 | emplace(py::type::handle_of(py::none())); // static type |
| 38 | emplace(py::type::handle_of(py::tuple())); // static type |
| 39 | emplace(py::type::handle_of(py::list())); // static type |
| 40 | emplace(py::type::handle_of(py::dict())); // static type |
| 41 | emplace(py::module_::import("collections").attr("OrderedDict")); // static type |
| 42 | emplace(py::module_::import("collections").attr("defaultdict")); // heap type |
| 43 | emplace(py::module_::import("collections").attr("deque")); // heap type |
| 44 | |
| 45 | assert(instance.objects.size() == 7); |
| 46 | return instance; |
| 47 | }) |
| 48 | .get_stored(); |
| 49 | } |
| 50 | |
| 51 | std::vector<py::handle> &get_objects() { return objects; } |
| 52 | |
| 53 | static void init() { |
| 54 | // Ensure the singleton is created |
| 55 | auto &instance = get_instance(); |
| 56 | (void) instance; // suppress unused variable warning |
| 57 | assert(instance.objects.size() == 7); |
| 58 | // Register cleanup at interpreter exit |
| 59 | py::module_::import("atexit").attr("register")(py::cpp_function(&MySingleton::clear)); |
| 60 | } |
| 61 | |
| 62 | static void clear() { |
| 63 | auto &instance = get_instance(); |
| 64 | (void) instance; // suppress unused variable warning |
| 65 | assert(instance.objects.size() == 7); |
| 66 | for (const auto &obj : instance.objects) { |
| 67 | obj.dec_ref(); |
| 68 | } |
| 69 | instance.objects.clear(); |
| 70 | } |
| 71 | |
| 72 | private: |
| 73 | std::vector<py::handle> objects; |