@@ -311,6 +311,8 @@ struct type_info {
311311// / Each module locally stores a pointer to the `internals` data. The data
312312// / itself is shared among modules with the same `PYBIND11_INTERNALS_ID`.
313313inline internals **&get_internals_pp () {
314+ // The reason for the double-indirection is documented here:
315+ // https://github.com/pybind/pybind11/pull/1092
314316 static internals **internals_pp = nullptr ;
315317 return internals_pp;
316318}
@@ -647,52 +649,81 @@ T &get_or_create_shared_data(const std::string &name) {
647649
648650PYBIND11_NAMESPACE_BEGIN (detail)
649651
650- #define PYBIND11_NATIVE_ENUM_TYPE_MAP_ABI_ID \
651- " __pybind11_native_enum_type_map_v1" PYBIND11_ABI_ID " __"
652+ struct native_enum_type_map_v1 {
653+ static constexpr const char *abi_id_c_str
654+ = " __pybind11_native_enum_type_map_v1" PYBIND11_ABI_ID " __" ;
652655
653- using native_enum_type_map = type_map<PyObject *>;
656+ using native_enum_type_map = type_map<PyObject *>;
654657
655- inline native_enum_type_map **&get_native_enum_types_pp () {
656- static native_enum_type_map **native_enum_types_pp = nullptr ;
657- return native_enum_types_pp;
658- }
659-
660- PYBIND11_NOINLINE native_enum_type_map &get_native_enum_type_map () {
661- native_enum_type_map **&native_enum_type_map_pp = get_native_enum_types_pp ();
662- if (native_enum_type_map_pp && *native_enum_type_map_pp) {
663- return **native_enum_type_map_pp;
658+ static native_enum_type_map **&native_enum_type_map_pp () {
659+ static native_enum_type_map **pp;
660+ return pp;
664661 }
665662
666- gil_scoped_acquire_simple gil;
667- error_scope err_scope;
663+ static native_enum_type_map *get_existing () {
664+ if (native_enum_type_map_pp () && *native_enum_type_map_pp ()) {
665+ return *native_enum_type_map_pp ();
666+ }
668667
669- constexpr const char *id_cstr = PYBIND11_NATIVE_ENUM_TYPE_MAP_ABI_ID ;
670- str id (id_cstr) ;
668+ gil_scoped_acquire_simple gil ;
669+ error_scope err_scope ;
671670
672- dict state_dict = get_python_state_dict ();
671+ str abi_id_str (abi_id_c_str);
672+ dict state_dict = get_python_state_dict ();
673+ if (!state_dict.contains (abi_id_str)) {
674+ return nullptr ;
675+ }
673676
674- if (state_dict.contains (id_cstr)) {
675- void *raw_ptr = PyCapsule_GetPointer (state_dict[id].ptr (), id_cstr);
677+ void *raw_ptr = PyCapsule_GetPointer (state_dict[abi_id_str].ptr (), abi_id_c_str);
676678 if (raw_ptr == nullptr ) {
677679 raise_from (PyExc_SystemError,
678- " pybind11::detail::get_native_enum_type_map (): Retrieve "
679- " native_enum_type_map** from capsule FAILED" );
680+ " pybind11::detail::native_enum_type_map::get_existing ():"
681+ " Retrieve native_enum_type_map** from capsule FAILED" );
680682 }
681- native_enum_type_map_pp = static_cast <native_enum_type_map **>(raw_ptr);
683+ native_enum_type_map_pp () = static_cast <native_enum_type_map **>(raw_ptr);
684+ return *native_enum_type_map_pp ();
682685 }
683686
684- if (native_enum_type_map_pp && *native_enum_type_map_pp) {
685- return **native_enum_type_map_pp;
687+ static native_enum_type_map &get () {
688+ if (get_existing () != nullptr ) {
689+ return **native_enum_type_map_pp ();
690+ }
691+ if (native_enum_type_map_pp () == nullptr ) {
692+ native_enum_type_map_pp () = new native_enum_type_map *();
693+ }
694+ *native_enum_type_map_pp () = new native_enum_type_map ();
695+ get_python_state_dict ()[abi_id_c_str] = capsule (native_enum_type_map_pp (), abi_id_c_str);
696+ return **native_enum_type_map_pp ();
686697 }
687698
688- if (!native_enum_type_map_pp) {
689- native_enum_type_map_pp = new native_enum_type_map *();
690- }
691- auto *&native_enum_type_map_ptr = *native_enum_type_map_pp;
692- native_enum_type_map_ptr = new native_enum_type_map ();
693- state_dict[id] = capsule (native_enum_type_map_pp, id_cstr);
694- return **native_enum_type_map_pp;
695- }
699+ struct scoped_clear {
700+ // To be called BEFORE Py_Finalize().
701+ scoped_clear () {
702+ if (get_existing () != nullptr ) {
703+ for (auto it : **native_enum_type_map_pp ()) {
704+ Py_DECREF (it.second );
705+ }
706+ (*native_enum_type_map_pp ())->clear ();
707+ arm_dtor = true ;
708+ }
709+ }
710+
711+ // To be called AFTER Py_Finalize().
712+ ~scoped_clear () {
713+ if (arm_dtor) {
714+ delete *native_enum_type_map_pp ();
715+ *native_enum_type_map_pp () = nullptr ;
716+ }
717+ }
718+
719+ scoped_clear (const scoped_clear &) = delete ;
720+ scoped_clear &operator =(const scoped_clear &) = delete ;
721+
722+ bool arm_dtor = false ;
723+ };
724+ };
725+
726+ using native_enum_type_map = native_enum_type_map_v1;
696727
697728PYBIND11_NAMESPACE_END (detail)
698729
0 commit comments