Skip to content

Allow type_casters to expose temporary dependencies #917

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions include/pybind11/eigen.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<M> 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
Expand Down Expand Up @@ -462,6 +465,7 @@ struct type_caster<
if (!fits || !fits.template stride_compatible<props>())
return false;
copy_or_ref = std::move(copy);
is_copy = true;
}

ref.reset();
Expand All @@ -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 <typename _T> using cast_op_type = pybind11::detail::cast_op_type<_T>;
Expand Down
56 changes: 56 additions & 0 deletions include/pybind11/stl.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,27 @@
NAMESPACE_BEGIN(pybind11)
NAMESPACE_BEGIN(detail)

template <typename caster_t, typename = void>
struct subcaster_keepalive_impl { static handle get(caster_t &) { return {}; } };
template <typename caster_t>
struct subcaster_keepalive_impl<caster_t, void_t<decltype(std::declval<caster_t>().subcaster_keepalive())>> {
static handle get(caster_t &caster) { return caster.subcaster_keepalive(); } };
template <typename caster_t>

// 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<caster_t>::get(caster); }



template <typename caster_t>
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<object>(h));
}
}

template <typename Type, typename Key> struct set_caster {
using type = Type;
using key_conv = make_caster<Key>;
Expand All @@ -62,6 +83,7 @@ template <typename Type, typename Key> struct set_caster {
key_conv conv;
if (!conv.load(entry, convert))
return false;
append_subcaster_keepalive(deps, conv);
value.insert(cast_op<Key &&>(std::move(conv)));
}
return true;
Expand All @@ -78,6 +100,10 @@ template <typename Type, typename Key> struct set_caster {
}

PYBIND11_TYPE_CASTER(type, _("Set[") + key_conv::name() + _("]"));
private:
object deps;
public:
handle dependency() { return deps; }
};

template <typename Type, typename Key, typename Value> struct map_caster {
Expand All @@ -95,6 +121,8 @@ template <typename Type, typename Key, typename Value> 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<Key &&>(std::move(kconv)), cast_op<Value &&>(std::move(vconv)));
}
return true;
Expand All @@ -113,6 +141,10 @@ template <typename Type, typename Key, typename Value> struct map_caster {
}

PYBIND11_TYPE_CASTER(Type, _("Dict[") + key_conv::name() + _(", ") + value_conv::name() + _("]"));
private:
object deps;
public:
handle dependency() { return deps; }
};

template <typename Type, typename Value> struct list_caster {
Expand All @@ -128,6 +160,7 @@ template <typename Type, typename Value> struct list_caster {
value_conv conv;
if (!conv.load(it, convert))
return false;
append_subcaster_keepalive(deps, conv);
value.push_back(cast_op<Value &&>(std::move(conv)));
}
return true;
Expand All @@ -153,6 +186,10 @@ template <typename Type, typename Value> struct list_caster {
}

PYBIND11_TYPE_CASTER(Type, _("List[") + value_conv::name() + _("]"));
private:
object deps;
public:
handle dependency() { return deps; }
};

template <typename Type, typename Alloc> struct type_caster<std::vector<Type, Alloc>>
Expand Down Expand Up @@ -188,6 +225,7 @@ template <typename ArrayType, typename Value, bool Resizable, size_t Size = 0> s
value_conv conv;
if (!conv.load(it, convert))
return false;
append_subcaster_keepalive(deps, conv);
value[ctr++] = cast_op<Value &&>(std::move(conv));
}
return true;
Expand All @@ -206,6 +244,10 @@ template <typename ArrayType, typename Value, bool Resizable, size_t Size = 0> s
}

PYBIND11_TYPE_CASTER(ArrayType, _("List[") + value_conv::name() + _<Resizable>(_(""), _("[") + _<Size>() + _("]")) + _("]"));
private:
object deps;
public:
handle dependency() { return deps; }
};

template <typename Type, size_t Size> struct type_caster<std::array<Type, Size>>
Expand Down Expand Up @@ -246,11 +288,18 @@ template<typename T> struct optional_caster {
if (!inner_caster.load(src, convert))
return false;

if (handle h = subcaster_keepalive(inner_caster))
dep = reinterpret_borrow<object>(h);
value.emplace(cast_op<typename T::value_type &&>(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
Expand Down Expand Up @@ -304,6 +353,8 @@ struct variant_caster<V<Ts...>> {
auto caster = make_caster<U>();
if (caster.load(src, convert)) {
value = cast_op<U>(caster);
if (handle h = subcaster_keepalive(caster))
dep = reinterpret_borrow<object>(h);
return true;
}
return load_alternative(src, convert, type_list<Us...>{});
Expand All @@ -329,6 +380,11 @@ struct variant_caster<V<Ts...>> {

using Type = V<Ts...>;
PYBIND11_TYPE_CASTER(Type, _("Union[") + detail::concat(make_caster<Ts>::name()...) + _("]"));

private:
object dep;
public:
handle dependency() { return dep; }
};

#if PYBIND11_HAS_VARIANT
Expand Down