mirror of
https://github.com/pybind/pybind11.git
synced 2024-11-25 22:52:01 +00:00
Use static_assert()
!std::is_pointer<>
to replace runtime guards.
This commit is contained in:
parent
20b9baf270
commit
0640eb3359
@ -1034,6 +1034,11 @@ struct format_descriptor<
|
||||
static std::string format() { return std::string(1, c); }
|
||||
};
|
||||
|
||||
// Common message for `static_assert()`s, which are useful to easily preempt much less obvious
|
||||
// errors in code that does not support `format_descriptor<PyObject *>`.
|
||||
#define PYBIND11_MESSAGE_POINTER_TYPES_ARE_NOT_SUPPORTED \
|
||||
"Pointer types (in particular `PyObject *`) are not supported."
|
||||
|
||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||
// Returns the index of the given type in the type char array below, and in the list in numpy.h
|
||||
// The order here is: bool; 8 ints ((signed,unsigned)x(8,16,32,64)bits); float,double,long double;
|
||||
|
@ -287,14 +287,11 @@ handle eigen_encapsulate(Type *src) {
|
||||
template <typename Type>
|
||||
struct type_caster<Type, enable_if_t<is_eigen_dense_plain<Type>::value>> {
|
||||
using Scalar = typename Type::Scalar;
|
||||
static_assert(!std::is_pointer<Scalar>::value,
|
||||
PYBIND11_MESSAGE_POINTER_TYPES_ARE_NOT_SUPPORTED);
|
||||
using props = EigenProps<Type>;
|
||||
|
||||
bool load(handle src, bool convert) {
|
||||
// dtype=object is not supported. See #1152 & #2259 for related experiments.
|
||||
if (is_same_ignoring_cvref<Scalar, PyObject *>::value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If we're in no-convert mode, only load if given an array of the correct type
|
||||
if (!convert && !isinstance<array_t<Scalar>>(src)) {
|
||||
return false;
|
||||
@ -410,6 +407,9 @@ private:
|
||||
// Base class for casting reference/map/block/etc. objects back to python.
|
||||
template <typename MapType>
|
||||
struct eigen_map_caster {
|
||||
static_assert(!std::is_pointer<typename MapType::Scalar>::value,
|
||||
PYBIND11_MESSAGE_POINTER_TYPES_ARE_NOT_SUPPORTED);
|
||||
|
||||
private:
|
||||
using props = EigenProps<MapType>;
|
||||
|
||||
@ -462,6 +462,8 @@ private:
|
||||
using Type = Eigen::Ref<PlainObjectType, 0, StrideType>;
|
||||
using props = EigenProps<Type>;
|
||||
using Scalar = typename props::Scalar;
|
||||
static_assert(!std::is_pointer<Scalar>::value,
|
||||
PYBIND11_MESSAGE_POINTER_TYPES_ARE_NOT_SUPPORTED);
|
||||
using MapType = Eigen::Map<PlainObjectType, 0, StrideType>;
|
||||
using Array
|
||||
= array_t<Scalar,
|
||||
@ -485,11 +487,6 @@ private:
|
||||
|
||||
public:
|
||||
bool load(handle src, bool convert) {
|
||||
// dtype=object is not supported. See #1152 & #2259 for related experiments.
|
||||
if (is_same_ignoring_cvref<Scalar, PyObject *>::value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// First check whether what we have is already an array of the right type. If not, we
|
||||
// can't avoid a copy (because the copy is also going to do type conversion).
|
||||
bool need_copy = !isinstance<Array>(src);
|
||||
@ -614,6 +611,9 @@ private:
|
||||
// regular Eigen::Matrix, then casting that.
|
||||
template <typename Type>
|
||||
struct type_caster<Type, enable_if_t<is_eigen_other<Type>::value>> {
|
||||
static_assert(!std::is_pointer<typename Type::Scalar>::value,
|
||||
PYBIND11_MESSAGE_POINTER_TYPES_ARE_NOT_SUPPORTED);
|
||||
|
||||
protected:
|
||||
using Matrix
|
||||
= Eigen::Matrix<typename Type::Scalar, Type::RowsAtCompileTime, Type::ColsAtCompileTime>;
|
||||
@ -642,16 +642,13 @@ public:
|
||||
template <typename Type>
|
||||
struct type_caster<Type, enable_if_t<is_eigen_sparse<Type>::value>> {
|
||||
using Scalar = typename Type::Scalar;
|
||||
static_assert(!std::is_pointer<Scalar>::value,
|
||||
PYBIND11_MESSAGE_POINTER_TYPES_ARE_NOT_SUPPORTED);
|
||||
using StorageIndex = remove_reference_t<decltype(*std::declval<Type>().outerIndexPtr())>;
|
||||
using Index = typename Type::Index;
|
||||
static constexpr bool rowMajor = Type::IsRowMajor;
|
||||
|
||||
bool load(handle src, bool) {
|
||||
// dtype=object is not supported. See #1152 & #2259 for related experiments.
|
||||
if (is_same_ignoring_cvref<Scalar, PyObject *>::value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!src) {
|
||||
return false;
|
||||
}
|
||||
|
@ -164,16 +164,13 @@ PYBIND11_WARNING_POP
|
||||
|
||||
template <typename Type>
|
||||
struct type_caster<Type, typename eigen_tensor_helper<Type>::ValidType> {
|
||||
static_assert(!std::is_pointer<typename Type::Scalar>::value,
|
||||
PYBIND11_MESSAGE_POINTER_TYPES_ARE_NOT_SUPPORTED);
|
||||
using Helper = eigen_tensor_helper<Type>;
|
||||
static constexpr auto temp_name = get_tensor_descriptor<Type, false>::value;
|
||||
PYBIND11_TYPE_CASTER(Type, temp_name);
|
||||
|
||||
bool load(handle src, bool convert) {
|
||||
// dtype=object is not supported. See #1152 & #2259 for related experiments.
|
||||
if (is_same_ignoring_cvref<typename Type::Scalar, PyObject *>::value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!convert) {
|
||||
if (!isinstance<array>(src)) {
|
||||
return false;
|
||||
@ -364,15 +361,12 @@ struct get_storage_pointer_type<MapType, void_t<typename MapType::PointerArgType
|
||||
template <typename Type, int Options>
|
||||
struct type_caster<Eigen::TensorMap<Type, Options>,
|
||||
typename eigen_tensor_helper<remove_cv_t<Type>>::ValidType> {
|
||||
static_assert(!std::is_pointer<typename Type::Scalar>::value,
|
||||
PYBIND11_MESSAGE_POINTER_TYPES_ARE_NOT_SUPPORTED);
|
||||
using MapType = Eigen::TensorMap<Type, Options>;
|
||||
using Helper = eigen_tensor_helper<remove_cv_t<Type>>;
|
||||
|
||||
bool load(handle src, bool /*convert*/) {
|
||||
// dtype=object is not supported. See #1152 & #2259 for related experiments.
|
||||
if (is_same_ignoring_cvref<typename Type::Scalar, PyObject *>::value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Note that we have a lot more checks here as we want to make sure to avoid copies
|
||||
if (!isinstance<array>(src)) {
|
||||
return false;
|
||||
|
@ -425,10 +425,4 @@ TEST_SUBMODULE(eigen_matrix, m) {
|
||||
py::module_::import("numpy").attr("ones")(10);
|
||||
return v[0](5);
|
||||
});
|
||||
|
||||
m.def("pass_eigen_matrix_dtype_object",
|
||||
[](const Eigen::Matrix<PyObject *, Eigen::Dynamic, Eigen::Dynamic> &) {});
|
||||
m.def("pass_eigen_ref_matrix_dtype_object",
|
||||
[](const Eigen::Ref<Eigen::Matrix<PyObject *, Eigen::Dynamic, Eigen::Dynamic>> &) {});
|
||||
m.def("pass_eigen_sparse_matrix_dtype_object", [](const Eigen::SparseMatrix<PyObject *> &) {});
|
||||
}
|
||||
|
@ -805,20 +805,3 @@ def test_custom_operator_new():
|
||||
o = m.CustomOperatorNew()
|
||||
np.testing.assert_allclose(o.a, 0.0)
|
||||
np.testing.assert_allclose(o.b.diagonal(), 1.0)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"pass_eigen_type_dtype_object",
|
||||
[
|
||||
m.pass_eigen_matrix_dtype_object,
|
||||
m.pass_eigen_ref_matrix_dtype_object,
|
||||
m.pass_eigen_sparse_matrix_dtype_object,
|
||||
],
|
||||
)
|
||||
def test_pass_array_with_dtype_object(pass_eigen_type_dtype_object):
|
||||
# Only the dtype matters (not shape etc.): dtype=object is (should be) the
|
||||
# first check in the type_caster load() implementations.
|
||||
obj = np.array([], dtype=object)
|
||||
with pytest.raises(TypeError) as excinfo:
|
||||
pass_eigen_type_dtype_object(obj)
|
||||
assert "incompatible function arguments" in str(excinfo.value)
|
||||
|
@ -320,10 +320,6 @@ void init_tensor_module(pybind11::module &m) {
|
||||
"round_trip_rank_0_view",
|
||||
[](Eigen::TensorMap<Eigen::Tensor<double, 0, Options>> &tensor) { return tensor; },
|
||||
py::return_value_policy::reference);
|
||||
|
||||
m.def("pass_eigen_tensor_dtype_object", [](const Eigen::Tensor<PyObject *, 0, Options> &) {});
|
||||
m.def("pass_eigen_tensor_map_dtype_object",
|
||||
[](Eigen::TensorMap<Eigen::Tensor<PyObject *, 0, Options>> &) {});
|
||||
}
|
||||
|
||||
void test_module(py::module_ &m) {
|
||||
|
@ -286,20 +286,3 @@ def test_doc_string(m, doc):
|
||||
f"round_trip_const_view_tensor(arg0: numpy.ndarray[numpy.float64[?, ?, ?], {order_flag}])"
|
||||
" -> numpy.ndarray[numpy.float64[?, ?, ?]]"
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("m", submodules)
|
||||
@pytest.mark.parametrize(
|
||||
"func_name",
|
||||
[
|
||||
"pass_eigen_tensor_dtype_object",
|
||||
"pass_eigen_tensor_map_dtype_object",
|
||||
],
|
||||
)
|
||||
def test_pass_array_with_dtype_object(m, func_name):
|
||||
# Only the dtype matters (not shape etc.): dtype=object is (should be) the
|
||||
# first check in the type_caster load() implementations.
|
||||
obj = np.array([], dtype=object)
|
||||
with pytest.raises(TypeError) as excinfo:
|
||||
getattr(m, func_name)(obj)
|
||||
assert "incompatible function arguments" in str(excinfo.value)
|
||||
|
Loading…
Reference in New Issue
Block a user