diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index 392f297e70c..055813f5805 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -890,52 +890,45 @@ template class type_caster> { std::tuple...> value; }; +template struct py3_enum_info { handle type = {}; - std::unordered_map values = {}; + std::unordered_map values = {}; py3_enum_info() = default; py3_enum_info(handle type, const dict& values) : type(type) { - for (auto item : values) - this->values[static_cast(item.second.cast())] = type.attr(item.first); - } - - static std::unordered_map& registry() { - static std::unordered_map map = {}; - return map; - } - - template - static void bind(handle type, const dict& values) { - registry()[typeid(T)] = py3_enum_info(type, values); - } - - template - static const py3_enum_info* get() { - auto it = registry().find(typeid(T)); - return it == registry().end() ? nullptr : &it->second; + for (auto item : values) { + this->values[item.second.cast()] = type.attr(item.first); + } } }; template struct type_caster::value>> { + using underlying_type = typename std::underlying_type::type; + private: using base_caster = type_caster_base; + + static std::unique_ptr>& py3_info() { + static std::unique_ptr> info; + return info; + } + base_caster caster; - bool py3 = false; T value; public: template using cast_op_type = pybind11::detail::cast_op_type; - operator T*() { return py3 ? &value : static_cast(caster); } - operator T&() { return py3 ? value : static_cast(caster); } + operator T*() { return py3_info() ? &value : static_cast(caster); } + operator T&() { return py3_info() ? value : static_cast(caster); } static handle cast(const T& src, return_value_policy rvp, handle parent) { - if (auto info = py3_enum_info::get()) { - auto it = info->values.find(static_cast(src)); - if (it == info->values.end()) + if (py3_info()) { + auto it = py3_info()->values.find(static_cast(src)); + if (it == py3_info()->values.end()) return {}; return it->second.inc_ref(); } @@ -945,20 +938,22 @@ struct type_caster::value>> { bool load(handle src, bool convert) { if (!src) return false; - if (auto info = py3_enum_info::get()) { - py3 = true; - if (!isinstance(src, info->type)) + if (py3_info()) { + if (!isinstance(src, py3_info()->type)) return false; - value = static_cast(src.cast()); + value = static_cast(src.cast()); return true; } - py3 = false; return caster.load(src, convert); } static PYBIND11_DESCR name() { return base_caster::name(); } + + static void bind(handle type, const dict& values) { + py3_info().reset(new py3_enum_info(type, values)); + } }; /// Helper class which abstracts away certain actions. Users can provide specializations for diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index d8c3cc2e556..ef3b6c26970 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -1243,8 +1243,8 @@ class py3_enum { public: using underlying_type = typename std::underlying_type::type; - py3_enum(handle scope, const char* name) - : name(name), + py3_enum(handle scope, const char* enum_name) + : name(enum_name), parent(scope), ctor(module::import("enum").attr("IntEnum")), unique(module::import("enum").attr("unique")) { @@ -1267,7 +1267,7 @@ class py3_enum { void update() { object type = unique(ctor(name, entries)); setattr(parent, name, type); - detail::py3_enum_info::bind(type, entries); + detail::type_caster::bind(type, entries); } };