diff --git a/CMakeLists.txt b/CMakeLists.txt index 39cea8e5..fb82639d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -147,10 +147,8 @@ endif() # NB: when adding a header don't forget to also add it to setup.py set(PYBIND11_HEADERS - include/pybind11/detail/abi_platform_id.h include/pybind11/detail/class.h include/pybind11/detail/common.h - include/pybind11/detail/cross_extension_shared_state.h include/pybind11/detail/descr.h include/pybind11/detail/dynamic_raw_ptr_cast_if_possible.h include/pybind11/detail/function_record_pyobject.h @@ -162,7 +160,6 @@ set(PYBIND11_HEADERS include/pybind11/detail/smart_holder_type_casters.h include/pybind11/detail/type_caster_base.h include/pybind11/detail/type_caster_odr_guard.h - include/pybind11/detail/type_map.h include/pybind11/detail/typeid.h include/pybind11/detail/value_and_holder.h include/pybind11/attr.h diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index e53c4d09..4c97515f 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -88,10 +88,10 @@ class type_caster_enum_type { template static handle cast(SrcType &&src, return_value_policy, handle parent) { - auto const &natives = cross_extension_shared_states::native_enum_type_map::get(); - auto found = natives.find(std::type_index(typeid(EnumType))); - if (found != natives.end()) { - return handle(found->second)(static_cast(src)).release(); + handle native_enum + = global_internals_native_enum_type_map_get_item(std::type_index(typeid(EnumType))); + if (native_enum) { + return native_enum(static_cast(src)).release(); } return type_caster_for_class_::cast( std::forward(src), @@ -101,10 +101,10 @@ class type_caster_enum_type { } bool load(handle src, bool convert) { - auto const &natives = cross_extension_shared_states::native_enum_type_map::get(); - auto found = natives.find(std::type_index(typeid(EnumType))); - if (found != natives.end()) { - if (!isinstance(src, found->second)) { + handle native_enum + = global_internals_native_enum_type_map_get_item(std::type_index(typeid(EnumType))); + if (native_enum) { + if (!isinstance(src, native_enum)) { return false; } type_caster underlying_caster; @@ -180,12 +180,11 @@ struct type_caster_classh_enum_aware< template ::value, int> = 0> bool isinstance_native_enum_impl(handle obj, const std::type_info &tp) { - auto const &natives = cross_extension_shared_states::native_enum_type_map::get(); - auto found = natives.find(tp); - if (found == natives.end()) { + handle native_enum = global_internals_native_enum_type_map_get_item(tp); + if (!native_enum) { return false; } - return isinstance(obj, found->second); + return isinstance(obj, native_enum); } template ::value, int> = 0> @@ -1351,9 +1350,8 @@ T cast(const handle &handle) { "Unable to cast type to reference: value is local to type caster"); #ifndef NDEBUG if (is_enum_cast && cast_is_temporary_value_reference::value) { - if (cross_extension_shared_states::native_enum_type_map::get().count( - std::type_index(typeid(intrinsic_t))) - != 0) { + if (detail::global_internals_native_enum_type_map_contains( + std::type_index(typeid(intrinsic_t)))) { pybind11_fail("Unable to cast native enum type to reference"); } } diff --git a/include/pybind11/detail/abi_platform_id.h b/include/pybind11/detail/abi_platform_id.h deleted file mode 100644 index 57e30d22..00000000 --- a/include/pybind11/detail/abi_platform_id.h +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright (c) 2022 The pybind Community. -// All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -#pragma once - -#include "common.h" - -/// On MSVC, debug and release builds are not ABI-compatible! -#if defined(_MSC_VER) && defined(_DEBUG) -# define PYBIND11_BUILD_TYPE "_debug" -#else -# define PYBIND11_BUILD_TYPE "" -#endif - -/// Let's assume that different compilers are ABI-incompatible. -/// A user can manually set this string if they know their -/// compiler is compatible. -#ifndef PYBIND11_COMPILER_TYPE -# if defined(_MSC_VER) -# define PYBIND11_COMPILER_TYPE "_msvc" -# elif defined(__INTEL_COMPILER) -# define PYBIND11_COMPILER_TYPE "_icc" -# elif defined(__clang__) -# define PYBIND11_COMPILER_TYPE "_clang" -# elif defined(__PGI) -# define PYBIND11_COMPILER_TYPE "_pgi" -# elif defined(__MINGW32__) -# define PYBIND11_COMPILER_TYPE "_mingw" -# elif defined(__CYGWIN__) -# define PYBIND11_COMPILER_TYPE "_gcc_cygwin" -# elif defined(__GNUC__) -# define PYBIND11_COMPILER_TYPE "_gcc" -# else -# define PYBIND11_COMPILER_TYPE "_unknown" -# endif -#endif - -/// Also standard libs -#ifndef PYBIND11_STDLIB -# if defined(_LIBCPP_VERSION) -# define PYBIND11_STDLIB "_libcpp" -# elif defined(__GLIBCXX__) || defined(__GLIBCPP__) -# define PYBIND11_STDLIB "_libstdcpp" -# else -# define PYBIND11_STDLIB "" -# endif -#endif - -/// On Linux/OSX, changes in __GXX_ABI_VERSION__ indicate ABI incompatibility. -/// On MSVC, changes in _MSC_VER may indicate ABI incompatibility (#2898). -#ifndef PYBIND11_BUILD_ABI -# if defined(__GXX_ABI_VERSION) -# define PYBIND11_BUILD_ABI "_cxxabi" PYBIND11_TOSTRING(__GXX_ABI_VERSION) -# elif defined(_MSC_VER) -# define PYBIND11_BUILD_ABI "_mscver" -# else -# define PYBIND11_BUILD_ABI "" -# endif -#endif - -#ifndef PYBIND11_INTERNALS_KIND -# define PYBIND11_INTERNALS_KIND "" -#endif - -/// See README_smart_holder.rst: -/// Classic / Conservative / Progressive cross-module compatibility -#ifndef PYBIND11_INTERNALS_SH_DEF -# if defined(PYBIND11_USE_SMART_HOLDER_AS_DEFAULT) -# define PYBIND11_INTERNALS_SH_DEF "_sh_def" -# else -# define PYBIND11_INTERNALS_SH_DEF "" -# endif -#endif - -/* NOTE - ATTENTION - WARNING - EXTREME CAUTION - Changing this will break compatibility with `PYBIND11_INTERNALS_VERSION 4` - See pybind11/detail/type_map.h for more information. - */ -#define PYBIND11_PLATFORM_ABI_ID_V4 \ - PYBIND11_INTERNALS_KIND PYBIND11_COMPILER_TYPE PYBIND11_STDLIB PYBIND11_BUILD_ABI \ - PYBIND11_BUILD_TYPE PYBIND11_INTERNALS_SH_DEF - -/// LEGACY "ABI-breaking" APPROACH, ORIGINAL COMMENT -/// ------------------------------------------------ -/// Tracks the `internals` and `type_info` ABI version independent of the main library version. -/// -/// Some portions of the code use an ABI that is conditional depending on this -/// version number. That allows ABI-breaking changes to be "pre-implemented". -/// Once the default version number is incremented, the conditional logic that -/// no longer applies can be removed. Additionally, users that need not -/// maintain ABI compatibility can increase the version number in order to take -/// advantage of any functionality/efficiency improvements that depend on the -/// newer ABI. -/// -/// WARNING: If you choose to manually increase the ABI version, note that -/// pybind11 may not be tested as thoroughly with a non-default ABI version, and -/// further ABI-incompatible changes may be made before the ABI is officially -/// changed to the new version. -#ifndef PYBIND11_INTERNALS_VERSION -# if PY_VERSION_HEX >= 0x030C0000 || defined(_MSC_VER) -// Version bump for Python 3.12+, before first 3.12 beta release. -// Version bump for MSVC piggy-backed on PR #4779. See comments there. -# define PYBIND11_INTERNALS_VERSION 5 -# else -# define PYBIND11_INTERNALS_VERSION 4 -# endif -#endif - -// This requirement is mainly to reduce the support burden (see PR #4570). -static_assert(PY_VERSION_HEX < 0x030C0000 || PYBIND11_INTERNALS_VERSION >= 5, - "pybind11 ABI version 5 is the minimum for Python 3.12+"); diff --git a/include/pybind11/detail/cross_extension_shared_state.h b/include/pybind11/detail/cross_extension_shared_state.h deleted file mode 100644 index 69b6ad01..00000000 --- a/include/pybind11/detail/cross_extension_shared_state.h +++ /dev/null @@ -1,143 +0,0 @@ -// Copyright (c) 2022 The pybind Community. -// All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -#pragma once - -#define PYBIND11_HAS_CROSS_EXTENSION_SHARED_STATE - -#include "common.h" - -#if defined(PYBIND11_SIMPLE_GIL_MANAGEMENT) -# include "../gil.h" -#endif - -#include "../pytypes.h" -#include "abi_platform_id.h" - -#include - -PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) -PYBIND11_NAMESPACE_BEGIN(detail) - -inline object get_python_state_dict() { - object state_dict; -#if PYBIND11_INTERNALS_VERSION <= 4 || PY_VERSION_HEX < 0x03080000 || defined(PYPY_VERSION) - state_dict = reinterpret_borrow(PyEval_GetBuiltins()); -#else -# if PY_VERSION_HEX < 0x03090000 - PyInterpreterState *istate = _PyInterpreterState_Get(); -# else - PyInterpreterState *istate = PyInterpreterState_Get(); -# endif - if (istate) { - state_dict = reinterpret_borrow(PyInterpreterState_GetDict(istate)); - } -#endif - if (!state_dict) { - raise_from(PyExc_SystemError, "pybind11::detail::get_python_state_dict() FAILED"); - throw error_already_set(); - } - return state_dict; -} - -#if defined(PYBIND11_SIMPLE_GIL_MANAGEMENT) -using gil_scoped_acquire_simple = gil_scoped_acquire; -#else -// Cannot use py::gil_scoped_acquire here since that constructor calls get_internals. -struct gil_scoped_acquire_simple { - gil_scoped_acquire_simple() : state(PyGILState_Ensure()) {} - gil_scoped_acquire_simple(const gil_scoped_acquire_simple &) = delete; - gil_scoped_acquire_simple &operator=(const gil_scoped_acquire_simple &) = delete; - ~gil_scoped_acquire_simple() { PyGILState_Release(state); } - const PyGILState_STATE state; -}; -#endif - -/* NOTE: struct cross_extension_shared_state is in - namespace pybind11::detail - but all types using this struct are meant to live in - namespace pybind11::cross_extension_shared_states - to make them easy to discover and reason about. - */ -template -struct cross_extension_shared_state { - static constexpr const char *abi_id() { return AdapterType::abi_id(); } - - using payload_type = typename AdapterType::payload_type; - - static payload_type **&payload_pp() { - // The reason for the double-indirection is documented here: - // https://github.com/pybind/pybind11/pull/1092 - static payload_type **pp; - return pp; - } - - static payload_type *get_existing() { - if (payload_pp() && *payload_pp()) { - return *payload_pp(); - } - - gil_scoped_acquire_simple gil; - error_scope err_scope; - - str abi_id_str(AdapterType::abi_id()); - dict state_dict = get_python_state_dict(); - if (!state_dict.contains(abi_id_str)) { - return nullptr; - } - - void *raw_ptr = PyCapsule_GetPointer(state_dict[abi_id_str].ptr(), AdapterType::abi_id()); - if (raw_ptr == nullptr) { - raise_from(PyExc_SystemError, - ("pybind11::detail::cross_extension_shared_state::get_existing():" - " Retrieve payload_type** from capsule FAILED for ABI ID \"" - + std::string(AdapterType::abi_id()) + "\"") - .c_str()); - throw error_already_set(); - } - payload_pp() = static_cast(raw_ptr); - return *payload_pp(); - } - - static payload_type &get() { - payload_type *existing = get_existing(); - if (existing != nullptr) { - return *existing; - } - if (payload_pp() == nullptr) { - payload_pp() = new payload_type *(); - } - *payload_pp() = new payload_type(); - get_python_state_dict()[AdapterType::abi_id()] - = capsule(reinterpret_cast(payload_pp()), AdapterType::abi_id()); - return **payload_pp(); - } - - struct scoped_clear { - // To be called BEFORE Py_Finalize(). - scoped_clear() { - payload_type *existing = get_existing(); - if (existing != nullptr) { - AdapterType::payload_clear(*existing); - arm_dtor = true; - } - } - - // To be called AFTER Py_Finalize(). - ~scoped_clear() { - if (arm_dtor) { - delete *payload_pp(); - *payload_pp() = nullptr; - } - } - - scoped_clear(const scoped_clear &) = delete; - scoped_clear &operator=(const scoped_clear &) = delete; - - bool arm_dtor = false; - }; -}; - -PYBIND11_NAMESPACE_END(detail) -PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/include/pybind11/detail/function_record_pyobject.h b/include/pybind11/detail/function_record_pyobject.h index 92875b99..be434112 100644 --- a/include/pybind11/detail/function_record_pyobject.h +++ b/include/pybind11/detail/function_record_pyobject.h @@ -9,6 +9,7 @@ #include "../attr.h" #include "../pytypes.h" #include "common.h" +#include "internals.h" #include @@ -45,7 +46,7 @@ PYBIND11_WARNING_POP // Note that this name is versioned. constexpr char tp_name_impl[] = "pybind11_detail_function_record_" PYBIND11_DETAIL_FUNCTION_RECORD_ABI_ID - "_" PYBIND11_PLATFORM_ABI_ID_V4; + PYBIND11_INTERNALS_ID; PYBIND11_NAMESPACE_END(function_record_PyTypeObject_methods) diff --git a/include/pybind11/detail/internals.h b/include/pybind11/detail/internals.h index b3777412..b4da3ced 100644 --- a/include/pybind11/detail/internals.h +++ b/include/pybind11/detail/internals.h @@ -9,26 +9,53 @@ #pragma once -#include "../pytypes.h" -#include "abi_platform_id.h" #include "common.h" -#include "cross_extension_shared_state.h" + +#if defined(PYBIND11_SIMPLE_GIL_MANAGEMENT) +# include "../gil.h" +#endif + +#include "../pytypes.h" #include "smart_holder_sfinae_hooks_only.h" -#include "type_map.h" #include -#include #include -#include -#include -#include #include -#include -#include -#include -#include -#include -#include + +/// Tracks the `internals` and `type_info` ABI version independent of the main library version. +/// +/// Some portions of the code use an ABI that is conditional depending on this +/// version number. That allows ABI-breaking changes to be "pre-implemented". +/// Once the default version number is incremented, the conditional logic that +/// no longer applies can be removed. Additionally, users that need not +/// maintain ABI compatibility can increase the version number in order to take +/// advantage of any functionality/efficiency improvements that depend on the +/// newer ABI. +/// +/// WARNING: If you choose to manually increase the ABI version, note that +/// pybind11 may not be tested as thoroughly with a non-default ABI version, and +/// further ABI-incompatible changes may be made before the ABI is officially +/// changed to the new version. +// NATIVE_ENUM_IN_INTERNALS_WIP: +#if defined(PYBIND11_INTERNALS_VERSION) && PYBIND11_INTERNALS_VERSION < 6 +# undef PYBIND11_INTERNALS_VERSION +#endif +#ifndef PYBIND11_INTERNALS_VERSION +# define PYBIND11_INTERNALS_VERSION 6 +#endif +#ifndef PYBIND11_INTERNALS_VERSION +# if PY_VERSION_HEX >= 0x030C0000 || defined(_MSC_VER) +// Version bump for Python 3.12+, before first 3.12 beta release. +// Version bump for MSVC piggy-backed on PR #4779. See comments there. +# define PYBIND11_INTERNALS_VERSION 5 +# else +# define PYBIND11_INTERNALS_VERSION 4 +# endif +#endif + +// This requirement is mainly to reduce the support burden (see PR #4570). +static_assert(PY_VERSION_HEX < 0x030C0000 || PYBIND11_INTERNALS_VERSION >= 5, + "pybind11 ABI version 5 is the minimum for Python 3.12+"); PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) @@ -82,6 +109,43 @@ inline PyObject *make_object_base_type(PyTypeObject *metaclass); # define PYBIND11_TLS_FREE(key) PyThread_tss_free(key) #endif +// Python loads modules by default with dlopen with the RTLD_LOCAL flag; under libc++ and possibly +// other STLs, this means `typeid(A)` from one module won't equal `typeid(A)` from another module +// even when `A` is the same, non-hidden-visibility type (e.g. from a common include). Under +// libstdc++, this doesn't happen: equality and the type_index hash are based on the type name, +// which works. If not under a known-good stl, provide our own name-based hash and equality +// functions that use the type name. +#if (PYBIND11_INTERNALS_VERSION <= 4 && defined(__GLIBCXX__)) \ + || (PYBIND11_INTERNALS_VERSION >= 5 && !defined(_LIBCPP_VERSION)) +inline bool same_type(const std::type_info &lhs, const std::type_info &rhs) { return lhs == rhs; } +using type_hash = std::hash; +using type_equal_to = std::equal_to; +#else +inline bool same_type(const std::type_info &lhs, const std::type_info &rhs) { + return lhs.name() == rhs.name() || std::strcmp(lhs.name(), rhs.name()) == 0; +} + +struct type_hash { + size_t operator()(const std::type_index &t) const { + size_t hash = 5381; + const char *ptr = t.name(); + while (auto c = static_cast(*ptr++)) { + hash = (hash * 33) ^ c; + } + return hash; + } +}; + +struct type_equal_to { + bool operator()(const std::type_index &lhs, const std::type_index &rhs) const { + return lhs.name() == rhs.name() || std::strcmp(lhs.name(), rhs.name()) == 0; + } +}; +#endif + +template +using type_map = std::unordered_map; + struct override_hash { inline size_t operator()(const std::pair &v) const { size_t value = std::hash()(v.first); @@ -158,10 +222,13 @@ struct internals { #if PYBIND11_INTERNALS_VERSION > 4 // Note that we have to use a std::string to allocate memory to ensure a unique address // We want unique addresses since we use pointer equality to compare function records - // OBSOLETE: google/pybind11k#30099 std::string function_record_capsule_name = internals_function_record_capsule_name; #endif +#if PYBIND11_INTERNALS_VERSION >= 6 + type_map native_enum_type_map; +#endif + internals() = default; internals(const internals &other) = delete; internals &operator=(const internals &other) = delete; @@ -209,13 +276,82 @@ struct type_info { bool module_local : 1; }; +/// On MSVC, debug and release builds are not ABI-compatible! +#if defined(_MSC_VER) && defined(_DEBUG) +# define PYBIND11_BUILD_TYPE "_debug" +#else +# define PYBIND11_BUILD_TYPE "" +#endif + +/// Let's assume that different compilers are ABI-incompatible. +/// A user can manually set this string if they know their +/// compiler is compatible. +#ifndef PYBIND11_COMPILER_TYPE +# if defined(_MSC_VER) +# define PYBIND11_COMPILER_TYPE "_msvc" +# elif defined(__INTEL_COMPILER) +# define PYBIND11_COMPILER_TYPE "_icc" +# elif defined(__clang__) +# define PYBIND11_COMPILER_TYPE "_clang" +# elif defined(__PGI) +# define PYBIND11_COMPILER_TYPE "_pgi" +# elif defined(__MINGW32__) +# define PYBIND11_COMPILER_TYPE "_mingw" +# elif defined(__CYGWIN__) +# define PYBIND11_COMPILER_TYPE "_gcc_cygwin" +# elif defined(__GNUC__) +# define PYBIND11_COMPILER_TYPE "_gcc" +# else +# define PYBIND11_COMPILER_TYPE "_unknown" +# endif +#endif + +/// Also standard libs +#ifndef PYBIND11_STDLIB +# if defined(_LIBCPP_VERSION) +# define PYBIND11_STDLIB "_libcpp" +# elif defined(__GLIBCXX__) || defined(__GLIBCPP__) +# define PYBIND11_STDLIB "_libstdcpp" +# else +# define PYBIND11_STDLIB "" +# endif +#endif + +/// On Linux/OSX, changes in __GXX_ABI_VERSION__ indicate ABI incompatibility. +/// On MSVC, changes in _MSC_VER may indicate ABI incompatibility (#2898). +#ifndef PYBIND11_BUILD_ABI +# if defined(__GXX_ABI_VERSION) +# define PYBIND11_BUILD_ABI "_cxxabi" PYBIND11_TOSTRING(__GXX_ABI_VERSION) +# elif defined(_MSC_VER) +# define PYBIND11_BUILD_ABI "_mscver" PYBIND11_TOSTRING(_MSC_VER) +# else +# define PYBIND11_BUILD_ABI "" +# endif +#endif + +#ifndef PYBIND11_INTERNALS_KIND +# define PYBIND11_INTERNALS_KIND "" +#endif + +/// See README_smart_holder.rst: +/// Classic / Conservative / Progressive cross-module compatibility +#ifndef PYBIND11_INTERNALS_SH_DEF +# if defined(PYBIND11_USE_SMART_HOLDER_AS_DEFAULT) +# define PYBIND11_INTERNALS_SH_DEF "_sh_def" +# else +# define PYBIND11_INTERNALS_SH_DEF "" +# endif +#endif + #define PYBIND11_INTERNALS_ID \ "__pybind11_internals_v" PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) \ - PYBIND11_PLATFORM_ABI_ID_V4 "__" + PYBIND11_INTERNALS_KIND PYBIND11_COMPILER_TYPE PYBIND11_STDLIB PYBIND11_BUILD_ABI \ + PYBIND11_BUILD_TYPE PYBIND11_INTERNALS_SH_DEF "__" #define PYBIND11_MODULE_LOCAL_ID \ "__pybind11_module_local_v" PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) \ - PYBIND11_PLATFORM_ABI_ID_V4 "__" + PYBIND11_INTERNALS_KIND PYBIND11_COMPILER_TYPE PYBIND11_STDLIB PYBIND11_BUILD_ABI \ + PYBIND11_BUILD_TYPE PYBIND11_INTERNALS_SH_DEF "__" /// Each module locally stores a pointer to the `internals` data. The data /// itself is shared among modules with the same `PYBIND11_INTERNALS_ID`. @@ -331,6 +467,27 @@ inline void translate_local_exception(std::exception_ptr p) { } #endif +inline object get_python_state_dict() { + object state_dict; +#if PYBIND11_INTERNALS_VERSION <= 4 || PY_VERSION_HEX < 0x03080000 || defined(PYPY_VERSION) + state_dict = reinterpret_borrow(PyEval_GetBuiltins()); +#else +# if PY_VERSION_HEX < 0x03090000 + PyInterpreterState *istate = _PyInterpreterState_Get(); +# else + PyInterpreterState *istate = PyInterpreterState_Get(); +# endif + if (istate) { + state_dict = reinterpret_borrow(PyInterpreterState_GetDict(istate)); + } +#endif + if (!state_dict) { + raise_from(PyExc_SystemError, "pybind11::detail::get_python_state_dict() FAILED"); + throw error_already_set(); + } + return state_dict; +} + inline object get_internals_obj_from_state_dict(handle state_dict) { return reinterpret_steal( dict_getitemstringref(state_dict.ptr(), PYBIND11_INTERNALS_ID)); @@ -366,7 +523,19 @@ PYBIND11_NOINLINE internals &get_internals() { return **internals_pp; } - gil_scoped_acquire_simple gil; +#if defined(PYBIND11_SIMPLE_GIL_MANAGEMENT) + gil_scoped_acquire gil; +#else + // Ensure that the GIL is held since we will need to make Python calls. + // Cannot use py::gil_scoped_acquire here since that constructor calls get_internals. + struct gil_scoped_acquire_local { + gil_scoped_acquire_local() : state(PyGILState_Ensure()) {} + gil_scoped_acquire_local(const gil_scoped_acquire_local &) = delete; + gil_scoped_acquire_local &operator=(const gil_scoped_acquire_local &) = delete; + ~gil_scoped_acquire_local() { PyGILState_Release(state); } + const PyGILState_STATE state; + } gil; +#endif error_scope err_scope; dict state_dict = get_python_state_dict(); diff --git a/include/pybind11/detail/native_enum_data.h b/include/pybind11/detail/native_enum_data.h index fc60f127..5895dc6c 100644 --- a/include/pybind11/detail/native_enum_data.h +++ b/include/pybind11/detail/native_enum_data.h @@ -7,10 +7,8 @@ #define PYBIND11_HAS_NATIVE_ENUM #include "../pytypes.h" -#include "abi_platform_id.h" #include "common.h" -#include "cross_extension_shared_state.h" -#include "type_map.h" +#include "internals.h" #include #include @@ -61,32 +59,29 @@ class native_enum_data { list docs; }; -PYBIND11_NAMESPACE_END(detail) - -PYBIND11_NAMESPACE_BEGIN(cross_extension_shared_states) - -struct native_enum_type_map_v1_adapter { - static constexpr const char *abi_id() { - return "__pybind11_native_enum_type_map_v1" PYBIND11_PLATFORM_ABI_ID_V4 "__"; - } - - using payload_type = detail::type_map; +inline void global_internals_native_enum_type_map_set_item(const std::type_index &enum_type_index, + PyObject *py_enum) { + with_internals( + [&](internals &internals) { internals.native_enum_type_map[enum_type_index] = py_enum; }); +} - static void payload_clear(payload_type &payload) { - for (auto it : payload) { - Py_DECREF(it.second); +inline handle +global_internals_native_enum_type_map_get_item(const std::type_index &enum_type_index) { + return with_internals([&](internals &internals) { + auto found = internals.native_enum_type_map.find(enum_type_index); + if (found != internals.native_enum_type_map.end()) { + return handle(found->second); } - payload.clear(); - } -}; - -using native_enum_type_map_v1 - = detail::cross_extension_shared_state; -using native_enum_type_map = native_enum_type_map_v1; - -PYBIND11_NAMESPACE_END(cross_extension_shared_states) + return handle(); + }); +} -PYBIND11_NAMESPACE_BEGIN(detail) +inline bool +global_internals_native_enum_type_map_contains(const std::type_index &enum_type_index) { + return with_internals([&](internals &internals) { + return internals.native_enum_type_map.count(enum_type_index) != 0; + }); +} inline void native_enum_add_to_parent(const object &parent, const detail::native_enum_data &data) { data.disarm_correct_use_check(); @@ -121,10 +116,8 @@ inline void native_enum_add_to_parent(const object &parent, const detail::native for (auto doc : data.docs) { py_enum[doc[int_(0)]].attr("__doc__") = doc[int_(1)]; } - cross_extension_shared_states::native_enum_type_map::get()[data.enum_type_index] - = py_enum.release().ptr(); + global_internals_native_enum_type_map_set_item(data.enum_type_index, py_enum.release().ptr()); } PYBIND11_NAMESPACE_END(detail) - PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/include/pybind11/detail/type_map.h b/include/pybind11/detail/type_map.h deleted file mode 100644 index 74ca7bfe..00000000 --- a/include/pybind11/detail/type_map.h +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright (c) 2022 The pybind Community. -// All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -#pragma once - -#include "common.h" - -#include -#include -#include -#include - -/* NOTE - ATTENTION - WARNING - EXTREME CAUTION - - Almost any changes here will break compatibility with `PYBIND11_INTERNALS_VERSION 4` - - Recommendation: - To not break compatibility with many existing PyPI wheels (https://pypi.org/), - DO NOT MAKE CHANGES HERE - until Python 3.11 (at least) has reached EOL. Then remove this file entirely. - - To evolve this code, start with a copy of this file and move the code to - namespace pybind11::cross_extension_shared_states - with new, versioned names, e.g. type_map_v2. - */ - -PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) -PYBIND11_NAMESPACE_BEGIN(detail) - -// Python loads modules by default with dlopen with the RTLD_LOCAL flag; under libc++ and possibly -// other STLs, this means `typeid(A)` from one module won't equal `typeid(A)` from another module -// even when `A` is the same, non-hidden-visibility type (e.g. from a common include). Under -// libstdc++, this doesn't happen: equality and the type_index hash are based on the type name, -// which works. If not under a known-good stl, provide our own name-based hash and equality -// functions that use the type name. -#if (PYBIND11_INTERNALS_VERSION <= 4 && defined(__GLIBCXX__)) \ - || (PYBIND11_INTERNALS_VERSION >= 5 && !defined(_LIBCPP_VERSION)) - -inline bool same_type(const std::type_info &lhs, const std::type_info &rhs) { return lhs == rhs; } -using type_hash = std::hash; -using type_equal_to = std::equal_to; - -#else - -inline bool same_type(const std::type_info &lhs, const std::type_info &rhs) { - return lhs.name() == rhs.name() || std::strcmp(lhs.name(), rhs.name()) == 0; -} - -struct type_hash { - size_t operator()(const std::type_index &t) const { - size_t hash = 5381; - const char *ptr = t.name(); - while (auto c = static_cast(*ptr++)) { - hash = (hash * 33) ^ c; - } - return hash; - } -}; - -struct type_equal_to { - bool operator()(const std::type_index &lhs, const std::type_index &rhs) const { - return lhs.name() == rhs.name() || std::strcmp(lhs.name(), rhs.name()) == 0; - } -}; - -#endif - -template -using type_map = std::unordered_map; - -PYBIND11_NAMESPACE_END(detail) -PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/include/pybind11/embed.h b/include/pybind11/embed.h index b249b401..9d29eb82 100644 --- a/include/pybind11/embed.h +++ b/include/pybind11/embed.h @@ -240,8 +240,6 @@ inline void initialize_interpreter(bool init_signal_handlers = true, \endrst */ inline void finalize_interpreter() { - cross_extension_shared_states::native_enum_type_map::scoped_clear native_enum_type_map_clear; - // Get the internals pointer (without creating it if it doesn't exist). It's possible for the // internals to be created during Py_Finalize() (e.g. if a py::capsule calls `get_internals()` // during destruction), so we get the pointer-pointer here and check it after Py_Finalize(). diff --git a/include/pybind11/native_enum.h b/include/pybind11/native_enum.h index 00a317e5..a4120a2c 100644 --- a/include/pybind11/native_enum.h +++ b/include/pybind11/native_enum.h @@ -32,7 +32,7 @@ class native_enum : public detail::native_enum_data { "pybind11::native_enum<...>(\"" + enum_name_encoded + "\") is already registered as a `pybind11::enum_` or `pybind11::class_`!"); } - if (cross_extension_shared_states::native_enum_type_map::get().count(enum_type_index)) { + if (detail::global_internals_native_enum_type_map_contains(enum_type_index)) { pybind11_fail("pybind11::native_enum<...>(\"" + enum_name_encoded + "\") is already registered!"); } diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index b48ed521..32f82fe5 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -2614,9 +2614,8 @@ class enum_ : public class_ { enum_(const handle &scope, const char *name, const Extra &...extra) : class_(scope, name, extra...), m_base(*this, scope) { { - if (cross_extension_shared_states::native_enum_type_map::get().count( - std::type_index(typeid(Type))) - != 0) { + if (detail::global_internals_native_enum_type_map_contains( + std::type_index(typeid(Type)))) { pybind11_fail("pybind11::enum_ \"" + std::string(name) + "\" is already registered as a pybind11::native_enum!"); } diff --git a/tests/extra_python_package/test_files.py b/tests/extra_python_package/test_files.py index 6eea457e..cd6fc088 100644 --- a/tests/extra_python_package/test_files.py +++ b/tests/extra_python_package/test_files.py @@ -54,10 +54,8 @@ } detail_headers = { - "include/pybind11/detail/abi_platform_id.h", "include/pybind11/detail/class.h", "include/pybind11/detail/common.h", - "include/pybind11/detail/cross_extension_shared_state.h", "include/pybind11/detail/descr.h", "include/pybind11/detail/dynamic_raw_ptr_cast_if_possible.h", "include/pybind11/detail/function_record_pyobject.h", @@ -69,7 +67,6 @@ "include/pybind11/detail/smart_holder_type_casters.h", "include/pybind11/detail/type_caster_base.h", "include/pybind11/detail/type_caster_odr_guard.h", - "include/pybind11/detail/type_map.h", "include/pybind11/detail/typeid.h", "include/pybind11/detail/value_and_holder.h", } diff --git a/tests/test_native_enum.cpp b/tests/test_native_enum.cpp index 385c3a42..39ce62b1 100644 --- a/tests/test_native_enum.cpp +++ b/tests/test_native_enum.cpp @@ -71,9 +71,6 @@ PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) TEST_SUBMODULE(native_enum, m) { using namespace test_native_enum; - m.attr("native_enum_type_map_abi_id_c_str") - = py::cross_extension_shared_states::native_enum_type_map::abi_id(); - m += py::native_enum("smallenum", py::native_enum_kind::IntEnum) .value("a", smallenum::a) .value("b", smallenum::b) diff --git a/tests/test_native_enum.py b/tests/test_native_enum.py index 26b920de..3d702530 100644 --- a/tests/test_native_enum.py +++ b/tests/test_native_enum.py @@ -2,19 +2,11 @@ import enum import pickle -import re import pytest from pybind11_tests import native_enum as m - -def test_abi_id(): - assert re.match( - "__pybind11_native_enum_type_map_v1_.*__$", m.native_enum_type_map_abi_id_c_str - ) - - SMALLENUM_MEMBERS = ( ("a", 0), ("b", 1),