diff --git a/docs/advanced/pycpp/numpy.rst b/docs/advanced/pycpp/numpy.rst index 6bcc46719d..42f376c2cc 100644 --- a/docs/advanced/pycpp/numpy.rst +++ b/docs/advanced/pycpp/numpy.rst @@ -41,8 +41,8 @@ completely avoid copy operations with Python expressions like py::format_descriptor::format(), /* Python struct-style format descriptor */ 2, /* Number of dimensions */ { m.rows(), m.cols() }, /* Buffer dimensions */ - { sizeof(float) * m.rows(), /* Strides (in bytes) for each index */ - sizeof(float) } + { (ssize_t)( sizeof(float) * m.rows() ),/* Strides (in bytes) for each index */ + (ssize_t)( sizeof(float) ) } ); }); @@ -61,7 +61,7 @@ specification. std::string format; int ndim; std::vector shape; - std::vector strides; + std::vector strides; }; To create a C++ function that can take a Python buffer object as an argument, @@ -121,8 +121,8 @@ as follows: { (size_t) m.rows(), (size_t) m.cols() }, /* Strides (in bytes) for each index */ - { sizeof(Scalar) * (rowMajor ? m.cols() : 1), - sizeof(Scalar) * (rowMajor ? 1 : m.rows()) } + { (ssize_t)( sizeof(Scalar) * (rowMajor ? m.cols() : 1) ), + (ssize_t)( sizeof(Scalar) * (rowMajor ? 1 : m.rows()) ) } ); }) diff --git a/include/pybind11/numpy.h b/include/pybind11/numpy.h index ba9402b5cd..f86df9c1e0 100644 --- a/include/pybind11/numpy.h +++ b/include/pybind11/numpy.h @@ -265,14 +265,14 @@ class unchecked_reference { const unsigned char *data_; // Storing the shape & strides in local variables (i.e. these arrays) allows the compiler to // make large performance gains on big, nested loops, but requires compile-time dimensions - conditional_t> - shape_, strides_; + conditional_t> shape_; + conditional_t> strides_; const size_t dims_; friend class pybind11::array; // Constructor for compile-time dimensions: template - unchecked_reference(const void *data, const size_t *shape, const size_t *strides, enable_if_t) + unchecked_reference(const void *data, const size_t *shape, const ssize_t *strides, enable_if_t) : data_{reinterpret_cast(data)}, dims_{Dims} { for (size_t i = 0; i < dims_; i++) { shape_[i] = shape[i]; @@ -281,7 +281,7 @@ class unchecked_reference { } // Constructor for runtime dimensions: template - unchecked_reference(const void *data, const size_t *shape, const size_t *strides, enable_if_t dims) + unchecked_reference(const void *data, const size_t *shape, const ssize_t *strides, enable_if_t dims) : data_{reinterpret_cast(data)}, shape_{shape}, strides_{strides}, dims_{dims} {} public: @@ -573,12 +573,12 @@ class array : public buffer { } /// Strides of the array - const size_t* strides() const { - return reinterpret_cast(detail::array_proxy(m_ptr)->strides); + const ssize_t* strides() const { + return reinterpret_cast(detail::array_proxy(m_ptr)->strides); } /// Stride along a given axis - size_t strides(size_t dim) const { + ssize_t strides(size_t dim) const { if (dim >= ndim()) fail_dim_check(dim, "invalid axis"); return strides()[dim]; @@ -702,9 +702,9 @@ class array : public buffer { throw std::domain_error("array is not writeable"); } - static std::vector default_strides(const std::vector& shape, size_t itemsize) { + static std::vector default_strides(const std::vector& shape, size_t itemsize) { auto ndim = shape.size(); - std::vector strides(ndim); + std::vector strides(ndim); if (ndim) { std::fill(strides.begin(), strides.end(), itemsize); for (size_t i = 0; i < ndim - 1; i++) @@ -1133,7 +1133,7 @@ array_iterator array_end(const buffer_info& buffer) { class common_iterator { public: - using container_type = std::vector; + using container_type = std::vector; using value_type = container_type::value_type; using size_type = container_type::size_type; @@ -1175,7 +1175,7 @@ template class multi_array_iterator { for (size_t i = 0; i < shape.size(); ++i) m_shape[i] = static_cast(shape[i]); - container_type strides(shape.size()); + std::vector strides(shape.size()); for (size_t i = 0; i < N; ++i) init_common_iterator(buffers[i], shape, m_common_iterator[i], strides); } @@ -1203,7 +1203,7 @@ template class multi_array_iterator { void init_common_iterator(const buffer_info &buffer, const std::vector &shape, - common_iter &iterator, container_type &strides) { + common_iter &iterator, std::vector &strides) { auto buffer_shape_iter = buffer.shape.rbegin(); auto buffer_strides_iter = buffer.strides.rbegin(); auto shape_iter = shape.rbegin(); @@ -1211,7 +1211,7 @@ template class multi_array_iterator { while (buffer_shape_iter != buffer.shape.rend()) { if (*shape_iter == *buffer_shape_iter) - *strides_iter = static_cast(*buffer_strides_iter); + *strides_iter = *buffer_strides_iter; else *strides_iter = 0; @@ -1283,10 +1283,11 @@ broadcast_trivial broadcast(const std::array &buffers, size_t &n // Check for C contiguity (but only if previous inputs were also C contiguous) if (trivial_broadcast_c) { - size_t expect_stride = buffers[i].itemsize; + ssize_t expect_stride = static_cast(buffers[i].itemsize); auto end = buffers[i].shape.crend(); - for (auto shape_iter = buffers[i].shape.crbegin(), stride_iter = buffers[i].strides.crbegin(); - trivial_broadcast_c && shape_iter != end; ++shape_iter, ++stride_iter) { + auto shape_iter = buffers[i].shape.crbegin(); + auto stride_iter = buffers[i].strides.crbegin(); + for (; trivial_broadcast_c && shape_iter != end; ++shape_iter, ++stride_iter) { if (expect_stride == *stride_iter) expect_stride *= *shape_iter; else @@ -1296,10 +1297,11 @@ broadcast_trivial broadcast(const std::array &buffers, size_t &n // Check for Fortran contiguity (if previous inputs were also F contiguous) if (trivial_broadcast_f) { - size_t expect_stride = buffers[i].itemsize; + ssize_t expect_stride = static_cast(buffers[i].itemsize); auto end = buffers[i].shape.cend(); - for (auto shape_iter = buffers[i].shape.cbegin(), stride_iter = buffers[i].strides.cbegin(); - trivial_broadcast_f && shape_iter != end; ++shape_iter, ++stride_iter) { + auto shape_iter = buffers[i].shape.cbegin(); + auto stride_iter = buffers[i].strides.cbegin(); + for (; trivial_broadcast_f && shape_iter != end; ++shape_iter, ++stride_iter) { if (expect_stride == *stride_iter) expect_stride *= *shape_iter; else @@ -1336,20 +1338,20 @@ struct vectorize_helper { auto trivial = broadcast(buffers, ndim, shape); size_t size = 1; - std::vector strides(ndim); + std::vector strides(ndim); if (ndim > 0) { if (trivial == broadcast_trivial::f_trivial) { - strides[0] = sizeof(Return); + strides[0] = static_cast(sizeof(Return)); for (size_t i = 1; i < ndim; ++i) { - strides[i] = strides[i - 1] * shape[i - 1]; + strides[i] = strides[i - 1] * static_cast(shape[i - 1]); size *= shape[i - 1]; } size *= shape[ndim - 1]; } else { - strides[ndim-1] = sizeof(Return); + strides[ndim-1] = static_cast(sizeof(Return)); for (size_t i = ndim - 1; i > 0; --i) { - strides[i - 1] = strides[i] * shape[i]; + strides[i - 1] = strides[i] * static_cast(shape[i]); size *= shape[i]; } size *= shape[0]; diff --git a/tests/test_buffers.cpp b/tests/test_buffers.cpp index 057250d292..d533bd3804 100644 --- a/tests/test_buffers.cpp +++ b/tests/test_buffers.cpp @@ -109,8 +109,8 @@ test_initializer buffers([](py::module &m) { py::format_descriptor::format(), /* Python struct-style format descriptor */ 2, /* Number of dimensions */ { m.rows(), m.cols() }, /* Buffer dimensions */ - { sizeof(float) * m.rows(), /* Strides (in bytes) for each index */ - sizeof(float) } + { static_cast(sizeof(float) * m.rows()), /* Strides (in bytes) for each index */ + static_cast(sizeof(float)) } ); }) ; diff --git a/tests/test_numpy_array.cpp b/tests/test_numpy_array.cpp index 85c185f6b2..e431e093e5 100644 --- a/tests/test_numpy_array.cpp +++ b/tests/test_numpy_array.cpp @@ -13,6 +13,7 @@ #include #include +#include using arr = py::array; using arr_t = py::array_t; @@ -294,4 +295,4 @@ test_initializer numpy_array([](py::module &m) { std::fill(a.mutable_data(), a.mutable_data() + a.size(), 42.); return a; }); -}); \ No newline at end of file +}); diff --git a/tests/test_numpy_array.py b/tests/test_numpy_array.py index 10af7486a1..90f9b80281 100644 --- a/tests/test_numpy_array.py +++ b/tests/test_numpy_array.py @@ -203,6 +203,10 @@ def assert_references(a, b, base=None): a2 = wrap(a1d) assert_references(a1d, a2, a1) + a1m = a1[::-1, ::-1, ::-1] + a2 = wrap(a1m) + assert_references(a1m, a2, a1) + def test_numpy_view(capture): from pybind11_tests.array import ArrayClass diff --git a/tests/test_numpy_dtypes.cpp b/tests/test_numpy_dtypes.cpp index 1f6c857043..4fc797c8c4 100644 --- a/tests/test_numpy_dtypes.cpp +++ b/tests/test_numpy_dtypes.cpp @@ -226,7 +226,7 @@ py::array_t test_array_ctors(int i) { std::vector data { 1, 2, 3, 4, 5, 6 }; std::vector shape { 3, 2 }; - std::vector strides { 8, 4 }; + std::vector strides { 8, 4 }; auto ptr = data.data(); auto vptr = (void *) ptr;