From 16bb1838ac59066a1e674844ed5e81c9ccc099a6 Mon Sep 17 00:00:00 2001 From: Robert Haschke Date: Mon, 30 Dec 2019 11:55:23 +0100 Subject: [PATCH] new move_only_holder_caster --- include/pybind11/cast.h | 83 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 77 insertions(+), 6 deletions(-) diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index 605acb3668..3decc49b8c 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -1515,15 +1515,86 @@ template class type_caster> : public copyable_holder_caster> { }; template -struct move_only_holder_caster { - static_assert(std::is_base_of, type_caster>::value, +struct move_only_holder_caster : public type_caster_base { +public: + using base = type_caster_base; + static_assert(std::is_base_of>::value, "Holder classes are only supported for custom types"); + using base::base; + using base::cast; + using base::typeinfo; + using base::value; + + bool load(handle& src, bool convert) { + bool success = base::template load_impl>(src, convert); + if (success) // if loading was successful, the instance needs to be withdrawn from src + // However, setting the src pointer to None is not sufficient. + src.ptr() = none().release().ptr(); + return success; + } + + template using cast_op_type = detail::movable_cast_op_type; + + explicit operator type*() { return this->value; } + explicit operator type&() { return *(this->value); } + explicit operator holder_type*() { return std::addressof(holder); } + + // Workaround for Intel compiler bug + // see pybind11 issue 94 + #if defined(__ICC) || defined(__INTEL_COMPILER) + operator holder_type&() { return holder; } + #else + explicit operator holder_type&() { return holder; } + #endif + explicit operator holder_type&&() { value = nullptr; return std::move(holder); } + + static handle cast(const holder_type &src, return_value_policy, handle) { + const auto *ptr = holder_helper::get(src); + return type_caster_base::cast_holder(ptr, &src); + } + +protected: + friend class type_caster_generic; + void check_holder_compat() { +// if (typeinfo->default_holder) +// throw cast_error("Unable to load a custom holder type from a default-holder instance"); + } - static handle cast(holder_type &&src, return_value_policy, handle) { - auto *ptr = holder_helper::get(src); - return type_caster_base::cast_holder(ptr, std::addressof(src)); + bool load_value(value_and_holder &&v_h) { + if (v_h.holder_constructed()) { + value = v_h.value_ptr(); + holder = std::move(v_h.template holder()); + return true; + } else { + throw cast_error("Unable to cast from non-held to held instance (T& to Holder) " +#if defined(NDEBUG) + "(compile in debug mode for type information)"); +#else + "of type '" + type_id() + "''"); +#endif + } + } + + template ::value, int> = 0> + bool try_implicit_casts(handle, bool) { return false; } + + template ::value, int> = 0> + bool try_implicit_casts(handle src, bool convert) { + for (auto &cast : typeinfo->implicit_casts) { + move_only_holder_caster sub_caster(*cast.first); + if (sub_caster.load(src, convert)) { + value = cast.second(sub_caster.value); + holder = holder_type(sub_caster.holder, (type *) value); + return true; + } + } + return false; } - static constexpr auto name = type_caster_base::name; + + static bool try_direct_conversions(handle) { return false; } + + + holder_type holder; }; template