mirror of
https://github.com/pybind/pybind11.git
synced 2024-11-30 17:07:12 +00:00
Backport of https://github.com/google/pywrapcc/pull/30034 (#5305)
This commit is contained in:
parent
bd5951b691
commit
a1d00916b2
@ -11,11 +11,14 @@
|
|||||||
|
|
||||||
#include "pybind11.h"
|
#include "pybind11.h"
|
||||||
#include "detail/common.h"
|
#include "detail/common.h"
|
||||||
|
#include "detail/descr.h"
|
||||||
|
#include "detail/type_caster_base.h"
|
||||||
|
|
||||||
#include <deque>
|
#include <deque>
|
||||||
#include <initializer_list>
|
#include <initializer_list>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
@ -349,39 +352,68 @@ struct type_caster<std::deque<Type, Alloc>> : list_caster<std::deque<Type, Alloc
|
|||||||
template <typename Type, typename Alloc>
|
template <typename Type, typename Alloc>
|
||||||
struct type_caster<std::list<Type, Alloc>> : list_caster<std::list<Type, Alloc>, Type> {};
|
struct type_caster<std::list<Type, Alloc>> : list_caster<std::list<Type, Alloc>, Type> {};
|
||||||
|
|
||||||
|
template <typename ArrayType, typename V, size_t... I>
|
||||||
|
ArrayType vector_to_array_impl(V &&v, index_sequence<I...>) {
|
||||||
|
return {{std::move(v[I])...}};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Based on https://en.cppreference.com/w/cpp/container/array/to_array
|
||||||
|
template <typename ArrayType, size_t N, typename V>
|
||||||
|
ArrayType vector_to_array(V &&v) {
|
||||||
|
return vector_to_array_impl<ArrayType, V>(std::forward<V>(v), make_index_sequence<N>{});
|
||||||
|
}
|
||||||
|
|
||||||
template <typename ArrayType, typename Value, bool Resizable, size_t Size = 0>
|
template <typename ArrayType, typename Value, bool Resizable, size_t Size = 0>
|
||||||
struct array_caster {
|
struct array_caster {
|
||||||
using value_conv = make_caster<Value>;
|
using value_conv = make_caster<Value>;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template <bool R = Resizable>
|
std::unique_ptr<ArrayType> value;
|
||||||
bool require_size(enable_if_t<R, size_t> size) {
|
|
||||||
if (value.size() != size) {
|
|
||||||
value.resize(size);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
template <bool R = Resizable>
|
|
||||||
bool require_size(enable_if_t<!R, size_t> size) {
|
|
||||||
return size == Size;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
template <bool R = Resizable, enable_if_t<R, int> = 0>
|
||||||
bool convert_elements(handle seq, bool convert) {
|
bool convert_elements(handle seq, bool convert) {
|
||||||
auto l = reinterpret_borrow<sequence>(seq);
|
auto l = reinterpret_borrow<sequence>(seq);
|
||||||
if (!require_size(l.size())) {
|
value.reset(new ArrayType{});
|
||||||
return false;
|
// Using `resize` to preserve the behavior exactly as it was before PR #5305
|
||||||
}
|
// For the `resize` to work, `Value` must be default constructible.
|
||||||
|
// For `std::valarray`, this is a requirement:
|
||||||
|
// https://en.cppreference.com/w/cpp/named_req/NumericType
|
||||||
|
value->resize(l.size());
|
||||||
size_t ctr = 0;
|
size_t ctr = 0;
|
||||||
for (const auto &it : l) {
|
for (const auto &it : l) {
|
||||||
value_conv conv;
|
value_conv conv;
|
||||||
if (!conv.load(it, convert)) {
|
if (!conv.load(it, convert)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
value[ctr++] = cast_op<Value &&>(std::move(conv));
|
(*value)[ctr++] = cast_op<Value &&>(std::move(conv));
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <bool R = Resizable, enable_if_t<!R, int> = 0>
|
||||||
|
bool convert_elements(handle seq, bool convert) {
|
||||||
|
auto l = reinterpret_borrow<sequence>(seq);
|
||||||
|
if (l.size() != Size) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// The `temp` storage is needed to support `Value` types that are not
|
||||||
|
// default-constructible.
|
||||||
|
// Deliberate choice: no template specializations, for simplicity, and
|
||||||
|
// because the compile time overhead for the specializations is deemed
|
||||||
|
// more significant than the runtime overhead for the `temp` storage.
|
||||||
|
std::vector<Value> temp;
|
||||||
|
temp.reserve(l.size());
|
||||||
|
for (auto it : l) {
|
||||||
|
value_conv conv;
|
||||||
|
if (!conv.load(it, convert)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
temp.emplace_back(cast_op<Value &&>(std::move(conv)));
|
||||||
|
}
|
||||||
|
value.reset(new ArrayType(vector_to_array<ArrayType, Size>(std::move(temp))));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool load(handle src, bool convert) {
|
bool load(handle src, bool convert) {
|
||||||
if (!PyObjectTypeIsConvertibleToStdVector(src.ptr())) {
|
if (!PyObjectTypeIsConvertibleToStdVector(src.ptr())) {
|
||||||
@ -416,12 +448,36 @@ public:
|
|||||||
return l.release();
|
return l.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
PYBIND11_TYPE_CASTER(ArrayType,
|
// Code copied from PYBIND11_TYPE_CASTER macro.
|
||||||
const_name<Resizable>(const_name(""), const_name("Annotated["))
|
// Intentionally preserving the behavior exactly as it was before PR #5305
|
||||||
+ const_name("list[") + value_conv::name + const_name("]")
|
template <typename T_, enable_if_t<std::is_same<ArrayType, remove_cv_t<T_>>::value, int> = 0>
|
||||||
+ const_name<Resizable>(const_name(""),
|
static handle cast(T_ *src, return_value_policy policy, handle parent) {
|
||||||
const_name(", FixedSize(")
|
if (!src) {
|
||||||
+ const_name<Size>() + const_name(")]")));
|
return none().release();
|
||||||
|
}
|
||||||
|
if (policy == return_value_policy::take_ownership) {
|
||||||
|
auto h = cast(std::move(*src), policy, parent);
|
||||||
|
delete src; // WARNING: Assumes `src` was allocated with `new`.
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
return cast(*src, policy, parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOLINTNEXTLINE(google-explicit-constructor)
|
||||||
|
operator ArrayType *() { return &(*value); }
|
||||||
|
// NOLINTNEXTLINE(google-explicit-constructor)
|
||||||
|
operator ArrayType &() { return *value; }
|
||||||
|
// NOLINTNEXTLINE(google-explicit-constructor)
|
||||||
|
operator ArrayType &&() && { return std::move(*value); }
|
||||||
|
|
||||||
|
template <typename T_>
|
||||||
|
using cast_op_type = movable_cast_op_type<T_>;
|
||||||
|
|
||||||
|
static constexpr auto name
|
||||||
|
= const_name<Resizable>(const_name(""), const_name("Annotated[")) + const_name("list[")
|
||||||
|
+ value_conv::name + const_name("]")
|
||||||
|
+ const_name<Resizable>(
|
||||||
|
const_name(""), const_name(", FixedSize(") + const_name<Size>() + const_name(")]"));
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Type, size_t Size>
|
template <typename Type, size_t Size>
|
||||||
|
@ -201,6 +201,23 @@ TEST_SUBMODULE(stl, m) {
|
|||||||
m.def("cast_array", []() { return std::array<int, 2>{{1, 2}}; });
|
m.def("cast_array", []() { return std::array<int, 2>{{1, 2}}; });
|
||||||
m.def("load_array", [](const std::array<int, 2> &a) { return a[0] == 1 && a[1] == 2; });
|
m.def("load_array", [](const std::array<int, 2> &a) { return a[0] == 1 && a[1] == 2; });
|
||||||
|
|
||||||
|
struct NoDefaultCtor {
|
||||||
|
explicit constexpr NoDefaultCtor(int val) : val{val} {}
|
||||||
|
int val;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NoDefaultCtorArray {
|
||||||
|
explicit constexpr NoDefaultCtorArray(int i)
|
||||||
|
: arr{{NoDefaultCtor(10 + i), NoDefaultCtor(20 + i)}} {}
|
||||||
|
std::array<NoDefaultCtor, 2> arr;
|
||||||
|
};
|
||||||
|
|
||||||
|
// test_array_no_default_ctor
|
||||||
|
py::class_<NoDefaultCtor>(m, "NoDefaultCtor").def_readonly("val", &NoDefaultCtor::val);
|
||||||
|
py::class_<NoDefaultCtorArray>(m, "NoDefaultCtorArray")
|
||||||
|
.def(py::init<int>())
|
||||||
|
.def_readwrite("arr", &NoDefaultCtorArray::arr);
|
||||||
|
|
||||||
// test_valarray
|
// test_valarray
|
||||||
m.def("cast_valarray", []() { return std::valarray<int>{1, 4, 9}; });
|
m.def("cast_valarray", []() { return std::valarray<int>{1, 4, 9}; });
|
||||||
m.def("load_valarray", [](const std::valarray<int> &v) {
|
m.def("load_valarray", [](const std::valarray<int> &v) {
|
||||||
|
@ -48,6 +48,13 @@ def test_array(doc):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_array_no_default_ctor():
|
||||||
|
lst = m.NoDefaultCtorArray(3)
|
||||||
|
assert [e.val for e in lst.arr] == [13, 23]
|
||||||
|
lst.arr = m.NoDefaultCtorArray(4).arr
|
||||||
|
assert [e.val for e in lst.arr] == [14, 24]
|
||||||
|
|
||||||
|
|
||||||
def test_valarray(doc):
|
def test_valarray(doc):
|
||||||
"""std::valarray <-> list"""
|
"""std::valarray <-> list"""
|
||||||
lst = m.cast_valarray()
|
lst = m.cast_valarray()
|
||||||
|
Loading…
Reference in New Issue
Block a user