mirror of
https://github.com/pybind/pybind11.git
synced 2024-11-25 22:52:01 +00:00
Combine std::tuple/std::pair logic
The std::pair caster can be written as a special case of the std::tuple caster; this combines them via a base `tuple_caster` class (which is essentially identical to the previous std::tuple caster). This also removes the special empty tuple base case: returning an empty tuple is relatively rare, and the base case still works perfectly well even when the tuple types is an empty list.
This commit is contained in:
parent
23bf894590
commit
897d71687e
@ -1255,50 +1255,13 @@ public:
|
|||||||
template <typename _T> using cast_op_type = remove_reference_t<pybind11::detail::cast_op_type<_T>>;
|
template <typename _T> using cast_op_type = remove_reference_t<pybind11::detail::cast_op_type<_T>>;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T1, typename T2> class type_caster<std::pair<T1, T2>> {
|
// Base implementation for std::tuple and std::pair
|
||||||
typedef std::pair<T1, T2> type;
|
template <template<typename...> class TupleType, typename... Tuple> class tuple_caster {
|
||||||
public:
|
using type = TupleType<Tuple...>;
|
||||||
bool load(handle src, bool convert) {
|
|
||||||
if (!isinstance<sequence>(src))
|
|
||||||
return false;
|
|
||||||
const auto seq = reinterpret_borrow<sequence>(src);
|
|
||||||
if (seq.size() != 2)
|
|
||||||
return false;
|
|
||||||
return first.load(seq[0], convert) && second.load(seq[1], convert);
|
|
||||||
}
|
|
||||||
|
|
||||||
static handle cast(const type &src, return_value_policy policy, handle parent) {
|
|
||||||
auto o1 = reinterpret_steal<object>(make_caster<T1>::cast(src.first, policy, parent));
|
|
||||||
auto o2 = reinterpret_steal<object>(make_caster<T2>::cast(src.second, policy, parent));
|
|
||||||
if (!o1 || !o2)
|
|
||||||
return handle();
|
|
||||||
tuple result(2);
|
|
||||||
PyTuple_SET_ITEM(result.ptr(), 0, o1.release().ptr());
|
|
||||||
PyTuple_SET_ITEM(result.ptr(), 1, o2.release().ptr());
|
|
||||||
return result.release();
|
|
||||||
}
|
|
||||||
|
|
||||||
static PYBIND11_DESCR name() {
|
|
||||||
return type_descr(
|
|
||||||
_("Tuple[") + make_caster<T1>::name() + _(", ") + make_caster<T2>::name() + _("]")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T> using cast_op_type = type;
|
|
||||||
|
|
||||||
operator type() & { return type(cast_op<T1>(first), cast_op<T2>(second)); }
|
|
||||||
operator type() && { return type(cast_op<T1>(std::move(first)), cast_op<T2>(std::move(second))); }
|
|
||||||
protected:
|
|
||||||
make_caster<T1> first;
|
|
||||||
make_caster<T2> second;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename... Tuple> class type_caster<std::tuple<Tuple...>> {
|
|
||||||
using type = std::tuple<Tuple...>;
|
|
||||||
using indices = make_index_sequence<sizeof...(Tuple)>;
|
|
||||||
static constexpr auto size = sizeof...(Tuple);
|
static constexpr auto size = sizeof...(Tuple);
|
||||||
|
using indices = make_index_sequence<size>;
|
||||||
public:
|
public:
|
||||||
|
|
||||||
bool load(handle src, bool convert) {
|
bool load(handle src, bool convert) {
|
||||||
if (!isinstance<sequence>(src))
|
if (!isinstance<sequence>(src))
|
||||||
return false;
|
return false;
|
||||||
@ -1327,7 +1290,6 @@ protected:
|
|||||||
template <size_t... Is>
|
template <size_t... Is>
|
||||||
type implicit_cast(index_sequence<Is...>) && { return type(cast_op<Tuple>(std::move(std::get<Is>(subcasters)))...); }
|
type implicit_cast(index_sequence<Is...>) && { return type(cast_op<Tuple>(std::move(std::get<Is>(subcasters)))...); }
|
||||||
|
|
||||||
|
|
||||||
static constexpr bool load_impl(const sequence &, bool, index_sequence<>) { return true; }
|
static constexpr bool load_impl(const sequence &, bool, index_sequence<>) { return true; }
|
||||||
|
|
||||||
template <size_t... Is>
|
template <size_t... Is>
|
||||||
@ -1338,9 +1300,6 @@ protected:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static handle cast_impl(const type &, return_value_policy, handle,
|
|
||||||
index_sequence<>) { return tuple().release(); }
|
|
||||||
|
|
||||||
/* Implementation: Convert a C++ tuple into a Python tuple */
|
/* Implementation: Convert a C++ tuple into a Python tuple */
|
||||||
template <size_t... Is>
|
template <size_t... Is>
|
||||||
static handle cast_impl(const type &src, return_value_policy policy, handle parent, index_sequence<Is...>) {
|
static handle cast_impl(const type &src, return_value_policy policy, handle parent, index_sequence<Is...>) {
|
||||||
@ -1357,9 +1316,15 @@ protected:
|
|||||||
return result.release();
|
return result.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::tuple<make_caster<Tuple>...> subcasters;
|
TupleType<make_caster<Tuple>...> subcasters;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename T1, typename T2> class type_caster<std::pair<T1, T2>>
|
||||||
|
: public tuple_caster<std::pair, T1, T2> {};
|
||||||
|
|
||||||
|
template <typename... Tuple> class type_caster<std::tuple<Tuple...>>
|
||||||
|
: public tuple_caster<std::tuple, Tuple...> {};
|
||||||
|
|
||||||
/// Helper class which abstracts away certain actions. Users can provide specializations for
|
/// Helper class which abstracts away certain actions. Users can provide specializations for
|
||||||
/// custom holders, but it's only necessary if the type has a non-standard interface.
|
/// custom holders, but it's only necessary if the type has a non-standard interface.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
@ -85,7 +85,7 @@ TEST_SUBMODULE(builtin_casters, m) {
|
|||||||
m.def("tuple_passthrough", [](std::tuple<bool, std::string, int> input) {
|
m.def("tuple_passthrough", [](std::tuple<bool, std::string, int> input) {
|
||||||
return std::make_tuple(std::get<2>(input), std::get<1>(input), std::get<0>(input));
|
return std::make_tuple(std::get<2>(input), std::get<1>(input), std::get<0>(input));
|
||||||
}, "Return a triple in reversed order");
|
}, "Return a triple in reversed order");
|
||||||
|
m.def("empty_tuple", []() { return std::tuple<>(); });
|
||||||
|
|
||||||
// test_builtins_cast_return_none
|
// test_builtins_cast_return_none
|
||||||
m.def("return_none_string", []() -> std::string * { return nullptr; });
|
m.def("return_none_string", []() -> std::string * { return nullptr; });
|
||||||
|
@ -188,6 +188,7 @@ def test_tuple(doc):
|
|||||||
# Any sequence can be cast to a std::pair or std::tuple
|
# Any sequence can be cast to a std::pair or std::tuple
|
||||||
assert m.pair_passthrough([True, "test"]) == ("test", True)
|
assert m.pair_passthrough([True, "test"]) == ("test", True)
|
||||||
assert m.tuple_passthrough([True, "test", 5]) == (5, "test", True)
|
assert m.tuple_passthrough([True, "test", 5]) == (5, "test", True)
|
||||||
|
assert m.empty_tuple() == ()
|
||||||
|
|
||||||
assert doc(m.pair_passthrough) == """
|
assert doc(m.pair_passthrough) == """
|
||||||
pair_passthrough(arg0: Tuple[bool, str]) -> Tuple[str, bool]
|
pair_passthrough(arg0: Tuple[bool, str]) -> Tuple[str, bool]
|
||||||
|
Loading…
Reference in New Issue
Block a user