From 7f19d34ca690b4efadf3cfd010e3ee7885be83ac Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Wed, 21 Jun 2017 22:11:37 -0400 Subject: [PATCH] Allow type_casters to expose temporary dependencies The Eigen::Ref caster, in particular, requires that a temporary array be kept alive in some cases. This allows a type_caster to expose a keep-alive dependency by providing a `handle subcaster_keepalive()` method so that stl.h casters (which employ temporary subcasters during loading) can hold onto any required extra dependencies. --- include/pybind11/eigen.h | 6 +++++ include/pybind11/stl.h | 56 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/include/pybind11/eigen.h b/include/pybind11/eigen.h index 53d4dab08f..aa342f267a 100644 --- a/include/pybind11/eigen.h +++ b/include/pybind11/eigen.h @@ -425,6 +425,9 @@ struct type_caster< // storage order conversion. (Note that we refuse to use this temporary copy when loading an // argument for a Ref with M non-const, i.e. a read-write reference). Array copy_or_ref; + // Set when copy_or_ref is a copy, in which case subcaster_keepalive() returns it to keep the + // temporary copy alive when this caster is invoked by a subcaster. + bool is_copy; public: bool load(handle src, bool convert) { // First check whether what we have is already an array of the right type. If not, we can't @@ -462,6 +465,7 @@ struct type_caster< if (!fits || !fits.template stride_compatible()) return false; copy_or_ref = std::move(copy); + is_copy = true; } ref.reset(); @@ -471,6 +475,8 @@ struct type_caster< return true; } + handle subcaster_keepalive() { return is_copy ? (handle) copy_or_ref : handle(); } + operator Type*() { return ref.get(); } operator Type&() { return *ref; } template using cast_op_type = pybind11::detail::cast_op_type<_T>; diff --git a/include/pybind11/stl.h b/include/pybind11/stl.h index 535eb49512..400dd09f5a 100644 --- a/include/pybind11/stl.h +++ b/include/pybind11/stl.h @@ -49,6 +49,27 @@ NAMESPACE_BEGIN(pybind11) NAMESPACE_BEGIN(detail) +template +struct subcaster_keepalive_impl { static handle get(caster_t &) { return {}; } }; +template +struct subcaster_keepalive_impl().subcaster_keepalive())>> { + static handle get(caster_t &caster) { return caster.subcaster_keepalive(); } }; +template + +// Calls caster.subcaster_keepalive() if the caster has it, otherwise returns an empty handle +inline handle subcaster_keepalive(caster_t &caster) { return subcaster_keepalive_impl::get(caster); } + + + +template +void append_subcaster_keepalive(object &deps, caster_t &caster) { + if (handle h = subcaster_keepalive(caster)) { + if (!deps) deps = list{}; + list deplist(deps); + deplist.append(reinterpret_borrow(h)); + } +} + template struct set_caster { using type = Type; using key_conv = make_caster; @@ -62,6 +83,7 @@ template struct set_caster { key_conv conv; if (!conv.load(entry, convert)) return false; + append_subcaster_keepalive(deps, conv); value.insert(cast_op(std::move(conv))); } return true; @@ -78,6 +100,10 @@ template struct set_caster { } PYBIND11_TYPE_CASTER(type, _("Set[") + key_conv::name() + _("]")); +private: + object deps; +public: + handle dependency() { return deps; } }; template struct map_caster { @@ -95,6 +121,8 @@ template struct map_caster { if (!kconv.load(it.first.ptr(), convert) || !vconv.load(it.second.ptr(), convert)) return false; + append_subcaster_keepalive(deps, kconv); + append_subcaster_keepalive(deps, vconv); value.emplace(cast_op(std::move(kconv)), cast_op(std::move(vconv))); } return true; @@ -113,6 +141,10 @@ template struct map_caster { } PYBIND11_TYPE_CASTER(Type, _("Dict[") + key_conv::name() + _(", ") + value_conv::name() + _("]")); +private: + object deps; +public: + handle dependency() { return deps; } }; template struct list_caster { @@ -128,6 +160,7 @@ template struct list_caster { value_conv conv; if (!conv.load(it, convert)) return false; + append_subcaster_keepalive(deps, conv); value.push_back(cast_op(std::move(conv))); } return true; @@ -153,6 +186,10 @@ template struct list_caster { } PYBIND11_TYPE_CASTER(Type, _("List[") + value_conv::name() + _("]")); +private: + object deps; +public: + handle dependency() { return deps; } }; template struct type_caster> @@ -188,6 +225,7 @@ template s value_conv conv; if (!conv.load(it, convert)) return false; + append_subcaster_keepalive(deps, conv); value[ctr++] = cast_op(std::move(conv)); } return true; @@ -206,6 +244,10 @@ template s } PYBIND11_TYPE_CASTER(ArrayType, _("List[") + value_conv::name() + _(_(""), _("[") + _() + _("]")) + _("]")); +private: + object deps; +public: + handle dependency() { return deps; } }; template struct type_caster> @@ -246,11 +288,18 @@ template struct optional_caster { if (!inner_caster.load(src, convert)) return false; + if (handle h = subcaster_keepalive(inner_caster)) + dep = reinterpret_borrow(h); value.emplace(cast_op(std::move(inner_caster))); return true; } PYBIND11_TYPE_CASTER(T, _("Optional[") + value_conv::name() + _("]")); + +private: + object dep; +public: + handle dependency() { return dep; } }; #if PYBIND11_HAS_OPTIONAL @@ -304,6 +353,8 @@ struct variant_caster> { auto caster = make_caster(); if (caster.load(src, convert)) { value = cast_op(caster); + if (handle h = subcaster_keepalive(caster)) + dep = reinterpret_borrow(h); return true; } return load_alternative(src, convert, type_list{}); @@ -329,6 +380,11 @@ struct variant_caster> { using Type = V; PYBIND11_TYPE_CASTER(Type, _("Union[") + detail::concat(make_caster::name()...) + _("]")); + +private: + object dep; +public: + handle dependency() { return dep; } }; #if PYBIND11_HAS_VARIANT