diff --git a/docs/advanced/pycpp/numpy.rst b/docs/advanced/pycpp/numpy.rst index d06370611..71123631a 100644 --- a/docs/advanced/pycpp/numpy.rst +++ b/docs/advanced/pycpp/numpy.rst @@ -57,10 +57,10 @@ specification. struct buffer_info { void *ptr; - size_t itemsize; + ssize_t itemsize; std::string format; - int ndim; - std::vector shape; + ssize_t ndim; + std::vector shape; std::vector strides; }; @@ -95,8 +95,8 @@ buffer objects (e.g. a NumPy matrix). throw std::runtime_error("Incompatible buffer dimension!"); auto strides = Strides( - info.strides[rowMajor ? 0 : 1] / sizeof(Scalar), - info.strides[rowMajor ? 1 : 0] / sizeof(Scalar)); + info.strides[rowMajor ? 0 : 1] / (py::ssize_t)sizeof(Scalar), + info.strides[rowMajor ? 1 : 0] / (py::ssize_t)sizeof(Scalar)); auto map = Eigen::Map( static_cat(info.ptr), info.shape[0], info.shape[1], strides); @@ -111,17 +111,14 @@ as follows: .def_buffer([](Matrix &m) -> py::buffer_info { return py::buffer_info( - m.data(), /* Pointer to buffer */ - sizeof(Scalar), /* Size of one scalar */ - /* Python struct-style format descriptor */ - py::format_descriptor::format(), - /* Number of dimensions */ - 2, - /* Buffer dimensions */ - { m.rows(), m.cols() }, - /* Strides (in bytes) for each index */ + m.data(), /* Pointer to buffer */ + sizeof(Scalar), /* Size of one scalar */ + py::format_descriptor::format(), /* Python struct-style format descriptor */ + 2, /* Number of dimensions */ + { m.rows(), m.cols() }, /* Buffer dimensions */ { sizeof(Scalar) * (rowMajor ? m.cols() : 1), sizeof(Scalar) * (rowMajor ? 1 : m.rows()) } + /* Strides (in bytes) for each index */ ); }) @@ -321,17 +318,17 @@ where ``N`` gives the required dimensionality of the array: m.def("sum_3d", [](py::array_t x) { auto r = x.unchecked<3>(); // x must have ndim = 3; can be non-writeable double sum = 0; - for (size_t i = 0; i < r.shape(0); i++) - for (size_t j = 0; j < r.shape(1); j++) - for (size_t k = 0; k < r.shape(2); k++) + for (ssize_t i = 0; i < r.shape(0); i++) + for (ssize_t j = 0; j < r.shape(1); j++) + for (ssize_t k = 0; k < r.shape(2); k++) sum += r(i, j, k); return sum; }); m.def("increment_3d", [](py::array_t x) { auto r = x.mutable_unchecked<3>(); // Will throw if ndim != 3 or flags.writeable is false - for (size_t i = 0; i < r.shape(0); i++) - for (size_t j = 0; j < r.shape(1); j++) - for (size_t k = 0; k < r.shape(2); k++) + for (ssize_t i = 0; i < r.shape(0); i++) + for (ssize_t j = 0; j < r.shape(1); j++) + for (ssize_t k = 0; k < r.shape(2); k++) r(i, j, k) += 1.0; }, py::arg().noconvert()); diff --git a/include/pybind11/buffer_info.h b/include/pybind11/buffer_info.h index 3090a4242..08877ef30 100644 --- a/include/pybind11/buffer_info.h +++ b/include/pybind11/buffer_info.h @@ -15,31 +15,31 @@ NAMESPACE_BEGIN(pybind11) /// Information record describing a Python buffer object struct buffer_info { - void *ptr = nullptr; // Pointer to the underlying storage - size_t itemsize = 0; // Size of individual items in bytes - size_t size = 0; // Total number of entries - std::string format; // For homogeneous buffers, this should be set to format_descriptor::format() - size_t ndim = 0; // Number of dimensions - std::vector shape; // Shape of the tensor (1 entry per dimension) + void *ptr = nullptr; // Pointer to the underlying storage + ssize_t itemsize = 0; // Size of individual items in bytes + ssize_t size = 0; // Total number of entries + std::string format; // For homogeneous buffers, this should be set to format_descriptor::format() + ssize_t ndim = 0; // Number of dimensions + std::vector shape; // Shape of the tensor (1 entry per dimension) std::vector strides; // Number of entries between adjacent entries (for each per dimension) buffer_info() { } - buffer_info(void *ptr, size_t itemsize, const std::string &format, size_t ndim, - detail::any_container shape_in, detail::any_container strides_in) + buffer_info(void *ptr, ssize_t itemsize, const std::string &format, ssize_t ndim, + detail::any_container shape_in, detail::any_container strides_in) : ptr(ptr), itemsize(itemsize), size(1), format(format), ndim(ndim), shape(std::move(shape_in)), strides(std::move(strides_in)) { - if (ndim != shape.size() || ndim != strides.size()) + if (ndim != (ssize_t) shape.size() || ndim != (ssize_t) strides.size()) pybind11_fail("buffer_info: ndim doesn't match shape and/or strides length"); - for (size_t i = 0; i < ndim; ++i) + for (size_t i = 0; i < (size_t) ndim; ++i) size *= shape[i]; } - buffer_info(void *ptr, size_t itemsize, const std::string &format, size_t size) + buffer_info(void *ptr, ssize_t itemsize, const std::string &format, ssize_t size) : buffer_info(ptr, itemsize, format, 1, {size}, {itemsize}) { } explicit buffer_info(Py_buffer *view, bool ownview = true) - : buffer_info(view->buf, (size_t) view->itemsize, view->format, (size_t) view->ndim, + : buffer_info(view->buf, view->itemsize, view->format, view->ndim, {view->shape, view->shape + view->ndim}, {view->strides, view->strides + view->ndim}) { this->view = view; this->ownview = ownview; @@ -78,13 +78,13 @@ NAMESPACE_BEGIN(detail) template struct compare_buffer_info { static bool compare(const buffer_info& b) { - return b.format == format_descriptor::format() && b.itemsize == sizeof(T); + return b.format == format_descriptor::format() && b.itemsize == (ssize_t) sizeof(T); } }; template struct compare_buffer_info::value>> { static bool compare(const buffer_info& b) { - return b.itemsize == sizeof(T) && (b.format == format_descriptor::value || + return (size_t) b.itemsize == sizeof(T) && (b.format == format_descriptor::value || ((sizeof(T) == sizeof(long)) && b.format == (std::is_unsigned::value ? "L" : "l")) || ((sizeof(T) == sizeof(size_t)) && b.format == (std::is_unsigned::value ? "N" : "n"))); } diff --git a/include/pybind11/class_support.h b/include/pybind11/class_support.h index 99d1477f9..995f57adf 100644 --- a/include/pybind11/class_support.h +++ b/include/pybind11/class_support.h @@ -433,7 +433,7 @@ inline void enable_dynamic_attributes(PyHeapTypeObject *heap_type) { #endif type->tp_flags |= Py_TPFLAGS_HAVE_GC; type->tp_dictoffset = type->tp_basicsize; // place dict at the end - type->tp_basicsize += (Py_ssize_t)sizeof(PyObject *); // and allocate enough space for it + type->tp_basicsize += (ssize_t)sizeof(PyObject *); // and allocate enough space for it type->tp_traverse = pybind11_traverse; type->tp_clear = pybind11_clear; @@ -459,18 +459,16 @@ extern "C" inline int pybind11_getbuffer(PyObject *obj, Py_buffer *view, int fla view->ndim = 1; view->internal = info; view->buf = info->ptr; - view->itemsize = (Py_ssize_t) info->itemsize; + view->itemsize = info->itemsize; view->len = view->itemsize; for (auto s : info->shape) - view->len *= (Py_ssize_t) s; + view->len *= s; if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT) view->format = const_cast(info->format.c_str()); if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES) { view->ndim = (int) info->ndim; view->strides = &info->strides[0]; - // Next is a pointer cast, let's make sure it's safe. - static_assert(sizeof(Py_ssize_t)==sizeof(info->shape[0]), "sizeof(Py_ssize_t) != sizeof(size_t)"); - view->shape = (Py_ssize_t *) &info->shape[0]; + view->shape = &info->shape[0]; } Py_INCREF(view->obj); return 0; diff --git a/include/pybind11/eigen.h b/include/pybind11/eigen.h index 8022a2cbe..b78045520 100644 --- a/include/pybind11/eigen.h +++ b/include/pybind11/eigen.h @@ -68,7 +68,7 @@ template using is_eigen_other = all_of< template struct EigenConformable { bool conformable = false; EigenIndex rows = 0, cols = 0; - EigenDStride stride{0, 0}; // Only valid if negativestridees is false! + EigenDStride stride{0, 0}; // Only valid if negativestrides is false! bool negativestrides = false; // If true, do not use stride! EigenConformable(bool fits = false) : conformable{fits} {} @@ -207,7 +207,7 @@ template struct EigenProps { // Casts an Eigen type to numpy array. If given a base, the numpy array references the src data, // otherwise it'll make a copy. writeable lets you turn off the writeable flag for the array. template handle eigen_array_cast(typename props::Type const &src, handle base = handle(), bool writeable = true) { - constexpr size_t elem_size = sizeof(typename props::Scalar); + constexpr ssize_t elem_size = sizeof(typename props::Scalar); array a; if (props::vector) a = array({ src.size() }, { elem_size * src.innerStride() }, src.data(), base); @@ -581,9 +581,9 @@ struct type_caster::value>> { object matrix_type = module::import("scipy.sparse").attr( rowMajor ? "csr_matrix" : "csc_matrix"); - array data((size_t) src.nonZeros(), src.valuePtr()); - array outerIndices((size_t) (rowMajor ? src.rows() : src.cols()) + 1, src.outerIndexPtr()); - array innerIndices((size_t) src.nonZeros(), src.innerIndexPtr()); + array data(src.nonZeros(), src.valuePtr()); + array outerIndices((rowMajor ? src.rows() : src.cols()) + 1, src.outerIndexPtr()); + array innerIndices(src.nonZeros(), src.innerIndexPtr()); return matrix_type( std::make_tuple(data, innerIndices, outerIndices), diff --git a/include/pybind11/numpy.h b/include/pybind11/numpy.h index 0107366b7..72bb35001 100644 --- a/include/pybind11/numpy.h +++ b/include/pybind11/numpy.h @@ -251,10 +251,10 @@ template using is_pod_struct = all_of< satisfies_none_of >; -template ssize_t byte_offset_unsafe(const Strides &) { return 0; } -template -ssize_t byte_offset_unsafe(const Strides &strides, size_t i, Ix... index) { - return static_cast(i) * strides[Dim] + byte_offset_unsafe(strides, index...); +template ssize_t byte_offset_unsafe(const Strides &) { return 0; } +template +ssize_t byte_offset_unsafe(const Strides &strides, ssize_t i, Ix... index) { + return i * strides[Dim] + byte_offset_unsafe(strides, index...); } /** Proxy class providing unsafe, unchecked const access to array data. This is constructed through @@ -268,23 +268,23 @@ protected: 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_; - conditional_t> strides_; - const size_t dims_; + conditional_t> + shape_, strides_; + const ssize_t dims_; friend class pybind11::array; // Constructor for compile-time dimensions: template - unchecked_reference(const void *data, const size_t *shape, const ssize_t *strides, enable_if_t) + unchecked_reference(const void *data, const ssize_t *shape, const ssize_t *strides, enable_if_t) : data_{reinterpret_cast(data)}, dims_{Dims} { - for (size_t i = 0; i < dims_; i++) { + for (size_t i = 0; i < (size_t) dims_; i++) { shape_[i] = shape[i]; strides_[i] = strides[i]; } } // Constructor for runtime dimensions: template - unchecked_reference(const void *data, const size_t *shape, const ssize_t *strides, enable_if_t dims) + unchecked_reference(const void *data, const ssize_t *shape, const ssize_t *strides, enable_if_t dims) : data_{reinterpret_cast(data)}, shape_{shape}, strides_{strides}, dims_{dims} {} public: @@ -295,39 +295,39 @@ public: template const T &operator()(Ix... index) const { static_assert(sizeof...(Ix) == Dims || Dynamic, "Invalid number of indices for unchecked array reference"); - return *reinterpret_cast(data_ + byte_offset_unsafe(strides_, size_t(index)...)); + return *reinterpret_cast(data_ + byte_offset_unsafe(strides_, ssize_t(index)...)); } /** Unchecked const reference access to data; this operator only participates if the reference * is to a 1-dimensional array. When present, this is exactly equivalent to `obj(index)`. */ - template > - const T &operator[](size_t index) const { return operator()(index); } + template > + const T &operator[](ssize_t index) const { return operator()(index); } /// Pointer access to the data at the given indices. - template const T *data(Ix... ix) const { return &operator()(size_t(ix)...); } + template const T *data(Ix... ix) const { return &operator()(ssize_t(ix)...); } /// Returns the item size, i.e. sizeof(T) - constexpr static size_t itemsize() { return sizeof(T); } + constexpr static ssize_t itemsize() { return sizeof(T); } /// Returns the shape (i.e. size) of dimension `dim` - size_t shape(size_t dim) const { return shape_[dim]; } + ssize_t shape(ssize_t dim) const { return shape_[(size_t) dim]; } /// Returns the number of dimensions of the array - size_t ndim() const { return dims_; } + ssize_t ndim() const { return dims_; } /// Returns the total number of elements in the referenced array, i.e. the product of the shapes template - enable_if_t size() const { - return std::accumulate(shape_.begin(), shape_.end(), (size_t) 1, std::multiplies()); + enable_if_t size() const { + return std::accumulate(shape_.begin(), shape_.end(), (ssize_t) 1, std::multiplies()); } template - enable_if_t size() const { - return std::accumulate(shape_, shape_ + ndim(), (size_t) 1, std::multiplies()); + enable_if_t size() const { + return std::accumulate(shape_, shape_ + ndim(), (ssize_t) 1, std::multiplies()); } /// Returns the total number of bytes used by the referenced data. Note that the actual span in /// memory may be larger if the referenced array has non-contiguous strides (e.g. for a slice). - size_t nbytes() const { + ssize_t nbytes() const { return size() * itemsize(); } }; @@ -349,11 +349,11 @@ public: * reference is to a 1-dimensional array (or has runtime dimensions). When present, this is * exactly equivalent to `obj(index)`. */ - template > - T &operator[](size_t index) { return operator()(index); } + template > + T &operator[](ssize_t index) { return operator()(index); } /// Mutable pointer access to the data at the given indices. - template T *mutable_data(Ix... ix) { return &operator()(size_t(ix)...); } + template T *mutable_data(Ix... ix) { return &operator()(ssize_t(ix)...); } }; template @@ -381,7 +381,7 @@ public: dtype(const char *format) : dtype(std::string(format)) { } - dtype(list names, list formats, list offsets, size_t itemsize) { + dtype(list names, list formats, list offsets, ssize_t itemsize) { dict args; args["names"] = names; args["formats"] = formats; @@ -404,8 +404,8 @@ public: } /// Size of the data type in bytes. - size_t itemsize() const { - return (size_t) detail::array_descriptor_proxy(m_ptr)->elsize; + ssize_t itemsize() const { + return detail::array_descriptor_proxy(m_ptr)->elsize; } /// Returns true for structured data types. @@ -425,7 +425,7 @@ private: return reinterpret_borrow(obj); } - dtype strip_padding(size_t itemsize) { + dtype strip_padding(ssize_t itemsize) { // Recursively strip all void fields with empty names that are generated for // padding fields (as of NumPy v1.11). if (!has_fields()) @@ -501,7 +501,7 @@ public: api.PyArray_Type_, descr.release().ptr(), (int) ndim, shape->data(), strides->data(), const_cast(ptr), flags, nullptr)); if (!tmp) - pybind11_fail("NumPy: unable to create array!"); + throw error_already_set(); if (ptr) { if (base) { api.PyArray_SetBaseObject_(tmp.ptr(), base.inc_ref().ptr()); @@ -528,7 +528,7 @@ public: : array(std::move(shape), {}, ptr, base) { } template - explicit array(size_t count, const T *ptr, handle base = handle()) : array({count}, {}, ptr, base) { } + explicit array(ssize_t count, const T *ptr, handle base = handle()) : array({count}, {}, ptr, base) { } explicit array(const buffer_info &info) : array(pybind11::dtype(info), info.shape, info.strides, info.ptr) { } @@ -539,23 +539,23 @@ public: } /// Total number of elements - size_t size() const { - return std::accumulate(shape(), shape() + ndim(), (size_t) 1, std::multiplies()); + ssize_t size() const { + return std::accumulate(shape(), shape() + ndim(), (ssize_t) 1, std::multiplies()); } /// Byte size of a single element - size_t itemsize() const { - return (size_t) detail::array_descriptor_proxy(detail::array_proxy(m_ptr)->descr)->elsize; + ssize_t itemsize() const { + return detail::array_descriptor_proxy(detail::array_proxy(m_ptr)->descr)->elsize; } /// Total number of bytes - size_t nbytes() const { + ssize_t nbytes() const { return size() * itemsize(); } /// Number of dimensions - size_t ndim() const { - return (size_t) detail::array_proxy(m_ptr)->nd; + ssize_t ndim() const { + return detail::array_proxy(m_ptr)->nd; } /// Base object @@ -564,12 +564,12 @@ public: } /// Dimensions of the array - const size_t* shape() const { - return reinterpret_cast(detail::array_proxy(m_ptr)->dimensions); + const ssize_t* shape() const { + return detail::array_proxy(m_ptr)->dimensions; } /// Dimension along a given axis - size_t shape(size_t dim) const { + ssize_t shape(ssize_t dim) const { if (dim >= ndim()) fail_dim_check(dim, "invalid axis"); return shape()[dim]; @@ -577,11 +577,11 @@ public: /// Strides of the array const ssize_t* strides() const { - return reinterpret_cast(detail::array_proxy(m_ptr)->strides); + return detail::array_proxy(m_ptr)->strides; } /// Stride along a given axis - ssize_t strides(size_t dim) const { + ssize_t strides(ssize_t dim) const { if (dim >= ndim()) fail_dim_check(dim, "invalid axis"); return strides()[dim]; @@ -619,9 +619,9 @@ public: /// Byte offset from beginning of the array to a given index (full or partial). /// May throw if the index would lead to out of bounds access. template ssize_t offset_at(Ix... index) const { - if (sizeof...(index) > ndim()) + if ((ssize_t) sizeof...(index) > ndim()) fail_dim_check(sizeof...(index), "too many indices for an array"); - return byte_offset(size_t(index)...); + return byte_offset(ssize_t(index)...); } ssize_t offset_at() const { return 0; } @@ -629,7 +629,7 @@ public: /// Item count from beginning of the array to a given index (full or partial). /// May throw if the index would lead to out of bounds access. template ssize_t index_at(Ix... index) const { - return offset_at(index...) / static_cast(itemsize()); + return offset_at(index...) / itemsize(); } /** Returns a proxy object that provides access to the array's data without bounds or @@ -638,7 +638,7 @@ public: * and the caller must take care not to access invalid dimensions or dimension indices. */ template detail::unchecked_mutable_reference mutable_unchecked() { - if (Dims >= 0 && ndim() != (size_t) Dims) + if (Dims >= 0 && ndim() != Dims) throw std::domain_error("array has incorrect number of dimensions: " + std::to_string(ndim()) + "; expected " + std::to_string(Dims)); return detail::unchecked_mutable_reference(mutable_data(), shape(), strides(), ndim()); @@ -651,7 +651,7 @@ public: * invalid dimensions or dimension indices. */ template detail::unchecked_reference unchecked() const { - if (Dims >= 0 && ndim() != (size_t) Dims) + if (Dims >= 0 && ndim() != Dims) throw std::domain_error("array has incorrect number of dimensions: " + std::to_string(ndim()) + "; expected " + std::to_string(Dims)); return detail::unchecked_reference(data(), shape(), strides(), ndim()); @@ -690,14 +690,14 @@ public: protected: template friend struct detail::npy_format_descriptor; - void fail_dim_check(size_t dim, const std::string& msg) const { + void fail_dim_check(ssize_t dim, const std::string& msg) const { throw index_error(msg + ": " + std::to_string(dim) + " (ndim = " + std::to_string(ndim()) + ")"); } template ssize_t byte_offset(Ix... index) const { check_dimensions(index...); - return detail::byte_offset_unsafe(strides(), size_t(index)...); + return detail::byte_offset_unsafe(strides(), ssize_t(index)...); } void check_writeable() const { @@ -705,7 +705,7 @@ protected: 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, ssize_t itemsize) { auto ndim = shape.size(); std::vector strides(ndim); if (ndim) { @@ -718,12 +718,12 @@ protected: } template void check_dimensions(Ix... index) const { - check_dimensions_impl(size_t(0), shape(), size_t(index)...); + check_dimensions_impl(ssize_t(0), shape(), ssize_t(index)...); } - void check_dimensions_impl(size_t, const size_t*) const { } + void check_dimensions_impl(ssize_t, const ssize_t*) const { } - template void check_dimensions_impl(size_t axis, const size_t* shape, size_t i, Ix... index) const { + template void check_dimensions_impl(ssize_t axis, const ssize_t* shape, ssize_t i, Ix... index) const { if (i >= *shape) { throw index_error(std::string("index ") + std::to_string(i) + " is out of bounds for axis " + std::to_string(axis) + @@ -772,12 +772,12 @@ public: explicit array_t(size_t count, const T *ptr = nullptr, handle base = handle()) : array({count}, {}, ptr, base) { } - constexpr size_t itemsize() const { + constexpr ssize_t itemsize() const { return sizeof(T); } template ssize_t index_at(Ix... index) const { - return offset_at(index...) / static_cast(itemsize()); + return offset_at(index...) / itemsize(); } template const T* data(Ix... index) const { @@ -792,14 +792,14 @@ public: template const T& at(Ix... index) const { if (sizeof...(index) != ndim()) fail_dim_check(sizeof...(index), "index dimension mismatch"); - return *(static_cast(array::data()) + byte_offset(size_t(index)...) / static_cast(itemsize())); + return *(static_cast(array::data()) + byte_offset(ssize_t(index)...) / itemsize()); } // Mutable reference to element at a given index template T& mutable_at(Ix... index) { if (sizeof...(index) != ndim()) fail_dim_check(sizeof...(index), "index dimension mismatch"); - return *(static_cast(array::mutable_data()) + byte_offset(size_t(index)...) / static_cast(itemsize())); + return *(static_cast(array::mutable_data()) + byte_offset(ssize_t(index)...) / itemsize()); } /** Returns a proxy object that provides access to the array's data without bounds or @@ -949,16 +949,16 @@ public: struct field_descriptor { const char *name; - size_t offset; - size_t size; - size_t alignment; + ssize_t offset; + ssize_t size; + ssize_t alignment; std::string format; dtype descr; }; inline PYBIND11_NOINLINE void register_structured_dtype( const std::initializer_list& fields, - const std::type_info& tinfo, size_t itemsize, + const std::type_info& tinfo, ssize_t itemsize, bool (*direct_converter)(PyObject *, void *&)) { auto& numpy_internals = get_numpy_internals(); @@ -986,7 +986,7 @@ inline PYBIND11_NOINLINE void register_structured_dtype( std::vector ordered_fields(fields); std::sort(ordered_fields.begin(), ordered_fields.end(), [](const field_descriptor &a, const field_descriptor &b) { return a.offset < b.offset; }); - size_t offset = 0; + ssize_t offset = 0; std::ostringstream oss; oss << "T{"; for (auto& field : ordered_fields) { @@ -1142,7 +1142,7 @@ public: common_iterator() : p_ptr(0), m_strides() {} - common_iterator(void* ptr, const container_type& strides, const std::vector& shape) + common_iterator(void* ptr, const container_type& strides, const container_type& shape) : p_ptr(reinterpret_cast(ptr)), m_strides(strides.size()) { m_strides.back() = static_cast(strides.back()); for (size_type i = m_strides.size() - 1; i != 0; --i) { @@ -1167,18 +1167,18 @@ private: template class multi_array_iterator { public: - using container_type = std::vector; + using container_type = std::vector; multi_array_iterator(const std::array &buffers, - const std::vector &shape) + const container_type &shape) : m_shape(shape.size()), m_index(shape.size(), 0), m_common_iterator() { // Manual copy to avoid conversion warning if using std::copy for (size_t i = 0; i < shape.size(); ++i) - m_shape[i] = static_cast(shape[i]); + m_shape[i] = shape[i]; - std::vector strides(shape.size()); + container_type strides(shape.size()); for (size_t i = 0; i < N; ++i) init_common_iterator(buffers[i], shape, m_common_iterator[i], strides); } @@ -1205,8 +1205,9 @@ private: using common_iter = common_iterator; void init_common_iterator(const buffer_info &buffer, - const std::vector &shape, - common_iter &iterator, std::vector &strides) { + const container_type &shape, + common_iter &iterator, + container_type &strides) { auto buffer_shape_iter = buffer.shape.rbegin(); auto buffer_strides_iter = buffer.strides.rbegin(); auto shape_iter = shape.rbegin(); @@ -1245,13 +1246,13 @@ enum class broadcast_trivial { non_trivial, c_trivial, f_trivial }; // singleton or a full-size, C-contiguous (`c_trivial`) or Fortran-contiguous (`f_trivial`) storage // buffer; returns `non_trivial` otherwise. template -broadcast_trivial broadcast(const std::array &buffers, size_t &ndim, std::vector &shape) { - ndim = std::accumulate(buffers.begin(), buffers.end(), size_t(0), [](size_t res, const buffer_info& buf) { +broadcast_trivial broadcast(const std::array &buffers, ssize_t &ndim, std::vector &shape) { + ndim = std::accumulate(buffers.begin(), buffers.end(), ssize_t(0), [](ssize_t res, const buffer_info& buf) { return std::max(res, buf.ndim); }); shape.clear(); - shape.resize(ndim, 1); + shape.resize((size_t) ndim, 1); // Figure out the output size, and make sure all input arrays conform (i.e. are either size 1 or // the full size). @@ -1286,11 +1287,10 @@ 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) { - ssize_t expect_stride = static_cast(buffers[i].itemsize); + ssize_t expect_stride = buffers[i].itemsize; auto end = buffers[i].shape.crend(); - 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) { + for (auto shape_iter = buffers[i].shape.crbegin(), stride_iter = buffers[i].strides.crbegin(); + trivial_broadcast_c && shape_iter != end; ++shape_iter, ++stride_iter) { if (expect_stride == *stride_iter) expect_stride *= *shape_iter; else @@ -1300,11 +1300,10 @@ 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) { - ssize_t expect_stride = static_cast(buffers[i].itemsize); + ssize_t expect_stride = buffers[i].itemsize; auto end = buffers[i].shape.cend(); - 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) { + for (auto shape_iter = buffers[i].shape.cbegin(), stride_iter = buffers[i].strides.cbegin(); + trivial_broadcast_f && shape_iter != end; ++shape_iter, ++stride_iter) { if (expect_stride == *stride_iter) expect_stride *= *shape_iter; else @@ -1336,25 +1335,26 @@ struct vectorize_helper { std::array buffers {{ args.request()... }}; /* Determine dimensions parameters of output array */ - size_t ndim = 0; - std::vector shape(0); - auto trivial = broadcast(buffers, ndim, shape); + ssize_t nd = 0; + std::vector shape(0); + auto trivial = broadcast(buffers, nd, shape); + size_t ndim = (size_t) nd; - size_t size = 1; + ssize_t size = 1; std::vector strides(ndim); if (ndim > 0) { if (trivial == broadcast_trivial::f_trivial) { - strides[0] = static_cast(sizeof(Return)); + strides[0] = sizeof(Return); for (size_t i = 1; i < ndim; ++i) { - strides[i] = strides[i - 1] * static_cast(shape[i - 1]); + strides[i] = strides[i - 1] * shape[i - 1]; size *= shape[i - 1]; } size *= shape[ndim - 1]; } else { - strides[ndim-1] = static_cast(sizeof(Return)); + strides[ndim-1] = sizeof(Return); for (size_t i = ndim - 1; i > 0; --i) { - strides[i - 1] = strides[i] * static_cast(shape[i]); + strides[i - 1] = strides[i] * shape[i]; size *= shape[i]; } size *= shape[0]; @@ -1372,7 +1372,7 @@ struct vectorize_helper { if (trivial == broadcast_trivial::non_trivial) { apply_broadcast(buffers, buf, index); } else { - for (size_t i = 0; i < size; ++i) + for (ssize_t i = 0; i < size; ++i) output[i] = f((reinterpret_cast(buffers[Index].ptr)[buffers[Index].size == 1 ? 0 : i])...); } diff --git a/include/pybind11/pytypes.h b/include/pybind11/pytypes.h index 26f5ae409..f1763110e 100644 --- a/include/pybind11/pytypes.h +++ b/include/pybind11/pytypes.h @@ -1165,15 +1165,15 @@ public: static std::vector py_strides { }; static std::vector py_shape { }; buf.buf = info.ptr; - buf.itemsize = (Py_ssize_t) info.itemsize; + buf.itemsize = info.itemsize; buf.format = const_cast(info.format.c_str()); buf.ndim = (int) info.ndim; - buf.len = (Py_ssize_t) info.size; + buf.len = info.size; py_strides.clear(); py_shape.clear(); - for (size_t i = 0; i < info.ndim; ++i) { - py_strides.push_back((Py_ssize_t) info.strides[i]); - py_shape.push_back((Py_ssize_t) info.shape[i]); + for (size_t i = 0; i < (size_t) info.ndim; ++i) { + py_strides.push_back(info.strides[i]); + py_shape.push_back(info.shape[i]); } buf.strides = py_strides.data(); buf.shape = py_shape.data(); diff --git a/include/pybind11/stl_bind.h b/include/pybind11/stl_bind.h index 7bba090b2..e581b73eb 100644 --- a/include/pybind11/stl_bind.h +++ b/include/pybind11/stl_bind.h @@ -345,21 +345,21 @@ vector_buffer(Class_& cl) { format_descriptor::format(); cl.def_buffer([](Vector& v) -> buffer_info { - return buffer_info(v.data(), sizeof(T), format_descriptor::format(), 1, {v.size()}, {sizeof(T)}); + return buffer_info(v.data(), static_cast(sizeof(T)), format_descriptor::format(), 1, {v.size()}, {sizeof(T)}); }); cl.def("__init__", [](Vector& vec, buffer buf) { auto info = buf.request(); - if (info.ndim != 1 || info.strides[0] <= 0 || info.strides[0] % static_cast(sizeof(T))) + if (info.ndim != 1 || info.strides[0] % static_cast(sizeof(T))) throw type_error("Only valid 1D buffers can be copied to a vector"); - if (!detail::compare_buffer_info::compare(info) || sizeof(T) != info.itemsize) + if (!detail::compare_buffer_info::compare(info) || (ssize_t) sizeof(T) != info.itemsize) throw type_error("Format mismatch (Python: " + info.format + " C++: " + format_descriptor::format() + ")"); new (&vec) Vector(); - vec.reserve(info.shape[0]); + vec.reserve((size_t) info.shape[0]); T *p = static_cast(info.ptr); - auto step = info.strides[0] / static_cast(sizeof(T)); - T *end = p + static_cast(info.shape[0]) * step; - for (; p < end; p += step) + ssize_t step = info.strides[0] / static_cast(sizeof(T)); + T *end = p + info.shape[0] * step; + for (; p != end; p += step) vec.push_back(*p); }); diff --git a/tests/test_buffers.cpp b/tests/test_buffers.cpp index d533bd380..6b5b75551 100644 --- a/tests/test_buffers.cpp +++ b/tests/test_buffers.cpp @@ -12,16 +12,16 @@ class Matrix { public: - Matrix(size_t rows, size_t cols) : m_rows(rows), m_cols(cols) { + Matrix(ssize_t rows, ssize_t cols) : m_rows(rows), m_cols(cols) { print_created(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix"); - m_data = new float[rows*cols]; - memset(m_data, 0, sizeof(float) * rows * cols); + m_data = new float[(size_t) (rows*cols)]; + memset(m_data, 0, sizeof(float) * (size_t) (rows * cols)); } Matrix(const Matrix &s) : m_rows(s.m_rows), m_cols(s.m_cols) { print_copy_created(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix"); - m_data = new float[m_rows * m_cols]; - memcpy(m_data, s.m_data, sizeof(float) * m_rows * m_cols); + m_data = new float[(size_t) (m_rows * m_cols)]; + memcpy(m_data, s.m_data, sizeof(float) * (size_t) (m_rows * m_cols)); } Matrix(Matrix &&s) : m_rows(s.m_rows), m_cols(s.m_cols), m_data(s.m_data) { @@ -41,8 +41,8 @@ public: delete[] m_data; m_rows = s.m_rows; m_cols = s.m_cols; - m_data = new float[m_rows * m_cols]; - memcpy(m_data, s.m_data, sizeof(float) * m_rows * m_cols); + m_data = new float[(size_t) (m_rows * m_cols)]; + memcpy(m_data, s.m_data, sizeof(float) * (size_t) (m_rows * m_cols)); return *this; } @@ -56,47 +56,47 @@ public: return *this; } - float operator()(size_t i, size_t j) const { - return m_data[i*m_cols + j]; + float operator()(ssize_t i, ssize_t j) const { + return m_data[(size_t) (i*m_cols + j)]; } - float &operator()(size_t i, size_t j) { - return m_data[i*m_cols + j]; + float &operator()(ssize_t i, ssize_t j) { + return m_data[(size_t) (i*m_cols + j)]; } float *data() { return m_data; } - size_t rows() const { return m_rows; } - size_t cols() const { return m_cols; } + ssize_t rows() const { return m_rows; } + ssize_t cols() const { return m_cols; } private: - size_t m_rows; - size_t m_cols; + ssize_t m_rows; + ssize_t m_cols; float *m_data; }; test_initializer buffers([](py::module &m) { py::class_ mtx(m, "Matrix", py::buffer_protocol()); - mtx.def(py::init()) + mtx.def(py::init()) /// Construct from a buffer .def("__init__", [](Matrix &v, py::buffer b) { py::buffer_info info = b.request(); if (info.format != py::format_descriptor::format() || info.ndim != 2) throw std::runtime_error("Incompatible buffer format!"); new (&v) Matrix(info.shape[0], info.shape[1]); - memcpy(v.data(), info.ptr, sizeof(float) * v.rows() * v.cols()); + memcpy(v.data(), info.ptr, sizeof(float) * (size_t) (v.rows() * v.cols())); }) .def("rows", &Matrix::rows) .def("cols", &Matrix::cols) /// Bare bones interface - .def("__getitem__", [](const Matrix &m, std::pair i) { + .def("__getitem__", [](const Matrix &m, std::pair i) { if (i.first >= m.rows() || i.second >= m.cols()) throw py::index_error(); return m(i.first, i.second); }) - .def("__setitem__", [](Matrix &m, std::pair i, float v) { + .def("__setitem__", [](Matrix &m, std::pair i, float v) { if (i.first >= m.rows() || i.second >= m.cols()) throw py::index_error(); m(i.first, i.second) = v; @@ -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 */ - { static_cast(sizeof(float) * m.rows()), /* Strides (in bytes) for each index */ - static_cast(sizeof(float)) } + { sizeof(float) * size_t(m.rows()), /* Strides (in bytes) for each index */ + sizeof(float) } ); }) ; diff --git a/tests/test_eigen.py b/tests/test_eigen.py index 67524f67b..4548fb0e9 100644 --- a/tests/test_eigen.py +++ b/tests/test_eigen.py @@ -186,7 +186,7 @@ def test_negative_stride_from_python(msg): double_threer(second_row) assert msg(excinfo.value) == """ double_threer(): incompatible function arguments. The following argument types are supported: - 1. (numpy.ndarray[float32[1, 3], flags.writeable]) -> arg0: None + 1. (arg0: numpy.ndarray[float32[1, 3], flags.writeable]) -> None Invoked with: array([ 5., 4., 3.], dtype=float32) """ @@ -195,7 +195,7 @@ def test_negative_stride_from_python(msg): double_threec(second_col) assert msg(excinfo.value) == """ double_threec(): incompatible function arguments. The following argument types are supported: - 1. (numpy.ndarray[float32[3, 1], flags.writeable]) -> arg0: None + 1. (arg0: numpy.ndarray[float32[3, 1], flags.writeable]) -> None Invoked with: array([ 7., 4., 1.], dtype=float32) """ diff --git a/tests/test_numpy_array.cpp b/tests/test_numpy_array.cpp index 2e7004eb5..ea5be7902 100644 --- a/tests/test_numpy_array.cpp +++ b/tests/test_numpy_array.cpp @@ -13,53 +13,52 @@ #include #include -#include using arr = py::array; using arr_t = py::array_t; static_assert(std::is_same::value, ""); template arr data(const arr& a, Ix... index) { - return arr(a.nbytes() - size_t(a.offset_at(index...)), (const uint8_t *) a.data(index...)); + return arr(a.nbytes() - a.offset_at(index...), (const uint8_t *) a.data(index...)); } template arr data_t(const arr_t& a, Ix... index) { - return arr(a.size() - size_t(a.index_at(index...)), a.data(index...)); + return arr(a.size() - a.index_at(index...), a.data(index...)); } arr& mutate_data(arr& a) { auto ptr = (uint8_t *) a.mutable_data(); - for (size_t i = 0; i < a.nbytes(); i++) + for (ssize_t i = 0; i < a.nbytes(); i++) ptr[i] = (uint8_t) (ptr[i] * 2); return a; } arr_t& mutate_data_t(arr_t& a) { auto ptr = a.mutable_data(); - for (size_t i = 0; i < a.size(); i++) + for (ssize_t i = 0; i < a.size(); i++) ptr[i]++; return a; } template arr& mutate_data(arr& a, Ix... index) { auto ptr = (uint8_t *) a.mutable_data(index...); - for (size_t i = 0; i < a.nbytes() - size_t(a.offset_at(index...)); i++) + for (ssize_t i = 0; i < a.nbytes() - a.offset_at(index...); i++) ptr[i] = (uint8_t) (ptr[i] * 2); return a; } template arr_t& mutate_data_t(arr_t& a, Ix... index) { auto ptr = a.mutable_data(index...); - for (size_t i = 0; i < a.size() - size_t(a.index_at(index...)); i++) + for (ssize_t i = 0; i < a.size() - a.index_at(index...); i++) ptr[i]++; return a; } -template py::ssize_t index_at(const arr& a, Ix... idx) { return a.index_at(idx...); } -template py::ssize_t index_at_t(const arr_t& a, Ix... idx) { return a.index_at(idx...); } -template py::ssize_t offset_at(const arr& a, Ix... idx) { return a.offset_at(idx...); } -template py::ssize_t offset_at_t(const arr_t& a, Ix... idx) { return a.offset_at(idx...); } -template py::ssize_t at_t(const arr_t& a, Ix... idx) { return a.at(idx...); } +template ssize_t index_at(const arr& a, Ix... idx) { return a.index_at(idx...); } +template ssize_t index_at_t(const arr_t& a, Ix... idx) { return a.index_at(idx...); } +template ssize_t offset_at(const arr& a, Ix... idx) { return a.offset_at(idx...); } +template ssize_t offset_at_t(const arr_t& a, Ix... idx) { return a.offset_at(idx...); } +template ssize_t at_t(const arr_t& a, Ix... idx) { return a.at(idx...); } template arr_t& mutate_at_t(arr_t& a, Ix... idx) { a.mutable_at(idx...)++; return a; } #define def_index_fn(name, type) \ @@ -88,9 +87,9 @@ test_initializer numpy_array([](py::module &m) { sm.def("ndim", [](const arr& a) { return a.ndim(); }); sm.def("shape", [](const arr& a) { return arr(a.ndim(), a.shape()); }); - sm.def("shape", [](const arr& a, size_t dim) { return a.shape(dim); }); + sm.def("shape", [](const arr& a, ssize_t dim) { return a.shape(dim); }); sm.def("strides", [](const arr& a) { return arr(a.ndim(), a.strides()); }); - sm.def("strides", [](const arr& a, size_t dim) { return a.strides(dim); }); + sm.def("strides", [](const arr& a, ssize_t dim) { return a.strides(dim); }); sm.def("writeable", [](const arr& a) { return a.writeable(); }); sm.def("size", [](const arr& a) { return a.size(); }); sm.def("itemsize", [](const arr& a) { return a.itemsize(); }); @@ -202,33 +201,33 @@ test_initializer numpy_array([](py::module &m) { sm.def("proxy_add2", [](py::array_t a, double v) { auto r = a.mutable_unchecked<2>(); - for (size_t i = 0; i < r.shape(0); i++) - for (size_t j = 0; j < r.shape(1); j++) + for (ssize_t i = 0; i < r.shape(0); i++) + for (ssize_t j = 0; j < r.shape(1); j++) r(i, j) += v; }, py::arg().noconvert(), py::arg()); sm.def("proxy_init3", [](double start) { py::array_t a({ 3, 3, 3 }); auto r = a.mutable_unchecked<3>(); - for (size_t i = 0; i < r.shape(0); i++) - for (size_t j = 0; j < r.shape(1); j++) - for (size_t k = 0; k < r.shape(2); k++) + for (ssize_t i = 0; i < r.shape(0); i++) + for (ssize_t j = 0; j < r.shape(1); j++) + for (ssize_t k = 0; k < r.shape(2); k++) r(i, j, k) = start++; return a; }); sm.def("proxy_init3F", [](double start) { py::array_t a({ 3, 3, 3 }); auto r = a.mutable_unchecked<3>(); - for (size_t k = 0; k < r.shape(2); k++) - for (size_t j = 0; j < r.shape(1); j++) - for (size_t i = 0; i < r.shape(0); i++) + for (ssize_t k = 0; k < r.shape(2); k++) + for (ssize_t j = 0; j < r.shape(1); j++) + for (ssize_t i = 0; i < r.shape(0); i++) r(i, j, k) = start++; return a; }); sm.def("proxy_squared_L2_norm", [](py::array_t a) { auto r = a.unchecked<1>(); double sumsq = 0; - for (size_t i = 0; i < r.shape(0); i++) + for (ssize_t i = 0; i < r.shape(0); i++) sumsq += r[i] * r(i); // Either notation works for a 1D array return sumsq; }); @@ -243,17 +242,17 @@ test_initializer numpy_array([](py::module &m) { sm.def("proxy_add2_dyn", [](py::array_t a, double v) { auto r = a.mutable_unchecked(); if (r.ndim() != 2) throw std::domain_error("error: ndim != 2"); - for (size_t i = 0; i < r.shape(0); i++) - for (size_t j = 0; j < r.shape(1); j++) + for (ssize_t i = 0; i < r.shape(0); i++) + for (ssize_t j = 0; j < r.shape(1); j++) r(i, j) += v; }, py::arg().noconvert(), py::arg()); sm.def("proxy_init3_dyn", [](double start) { py::array_t a({ 3, 3, 3 }); auto r = a.mutable_unchecked(); if (r.ndim() != 3) throw std::domain_error("error: ndim != 3"); - for (size_t i = 0; i < r.shape(0); i++) - for (size_t j = 0; j < r.shape(1); j++) - for (size_t k = 0; k < r.shape(2); k++) + for (ssize_t i = 0; i < r.shape(0); i++) + for (ssize_t j = 0; j < r.shape(1); j++) + for (ssize_t k = 0; k < r.shape(2); k++) r(i, j, k) = start++; return a; }); @@ -269,6 +268,9 @@ test_initializer numpy_array([](py::module &m) { sm.def("array_fail_test", []() { return py::array(py::object()); }); sm.def("array_t_fail_test", []() { return py::array_t(py::object()); }); + // Make sure the error from numpy is being passed through: + sm.def("array_fail_test_negative_size", []() { int c = 0; return py::array(-1, &c); }); + // Issue (unnumbered; reported in #788): regression: initializer lists can be ambiguous sm.def("array_initializer_list", []() { return py::array_t(1); }); // { 1 } also works, but clang warns about it sm.def("array_initializer_list", []() { return py::array_t({ 1, 2 }); }); @@ -277,7 +279,7 @@ test_initializer numpy_array([](py::module &m) { // reshape array to 2D without changing size sm.def("array_reshape2", [](py::array_t a) { - const size_t dim_sz = (size_t)std::sqrt(a.size()); + const ssize_t dim_sz = (ssize_t)std::sqrt(a.size()); if (dim_sz * dim_sz != a.size()) throw std::domain_error("array_reshape2: input array total size is not a squared integer"); a.resize({dim_sz, dim_sz}); diff --git a/tests/test_numpy_array.py b/tests/test_numpy_array.py index 90f9b8028..90fa142d8 100644 --- a/tests/test_numpy_array.py +++ b/tests/test_numpy_array.py @@ -384,7 +384,8 @@ def test_array_unchecked_dyn_dims(msg): def test_array_failure(): - from pybind11_tests.array import array_fail_test, array_t_fail_test + from pybind11_tests.array import (array_fail_test, array_t_fail_test, + array_fail_test_negative_size) with pytest.raises(ValueError) as excinfo: array_fail_test() @@ -394,6 +395,10 @@ def test_array_failure(): array_t_fail_test() assert str(excinfo.value) == 'cannot create a pybind11::array_t from a nullptr' + with pytest.raises(ValueError) as excinfo: + array_fail_test_negative_size() + assert str(excinfo.value) == 'negative dimensions are not allowed' + def test_array_resize(msg): from pybind11_tests.array import (array_reshape2, array_resize3) diff --git a/tests/test_numpy_dtypes.cpp b/tests/test_numpy_dtypes.cpp index 4fc797c8c..a8ba3d87f 100644 --- a/tests/test_numpy_dtypes.cpp +++ b/tests/test_numpy_dtypes.cpp @@ -149,7 +149,7 @@ py::array_t create_string_array(bool non_empty) { if (non_empty) { auto req = arr.request(); auto ptr = static_cast(req.ptr); - for (size_t i = 0; i < req.size * req.itemsize; i++) + for (ssize_t i = 0; i < req.size * req.itemsize; i++) static_cast(req.ptr)[i] = 0; ptr[1].a[0] = 'a'; ptr[1].b[0] = 'a'; ptr[2].a[0] = 'a'; ptr[2].b[0] = 'a'; @@ -178,7 +178,7 @@ py::list print_recarray(py::array_t arr) { const auto req = arr.request(); const auto ptr = static_cast(req.ptr); auto l = py::list(); - for (size_t i = 0; i < req.size; i++) { + for (ssize_t i = 0; i < req.size; i++) { std::stringstream ss; ss << ptr[i]; l.append(py::str(ss.str())); @@ -225,7 +225,7 @@ py::array_t test_array_ctors(int i) { using arr_t = py::array_t; std::vector data { 1, 2, 3, 4, 5, 6 }; - std::vector shape { 3, 2 }; + std::vector shape { 3, 2 }; std::vector strides { 8, 4 }; auto ptr = data.data(); diff --git a/tests/test_numpy_vectorize.cpp b/tests/test_numpy_vectorize.cpp index 8e951c6e1..34197469c 100644 --- a/tests/test_numpy_vectorize.cpp +++ b/tests/test_numpy_vectorize.cpp @@ -50,8 +50,8 @@ test_initializer numpy_vectorize([](py::module &m) { py::array_t arg2, py::array_t arg3 ) { - size_t ndim; - std::vector shape; + ssize_t ndim; + std::vector shape; std::array buffers {{ arg1.request(), arg2.request(), arg3.request() }}; return py::detail::broadcast(buffers, ndim, shape); });