Now `shape`, `size`, `ndims` and `itemsize` are also signed integers.

This commit is contained in:
Cris Luengo 2017-04-14 14:33:44 -06:00 committed by Dean Moldovan
parent b68959e822
commit 30d43c4992
13 changed files with 207 additions and 205 deletions

View File

@ -57,10 +57,10 @@ specification.
struct buffer_info {
void *ptr;
size_t itemsize;
ssize_t itemsize;
std::string format;
int ndim;
std::vector<size_t> shape;
ssize_t ndim;
std::vector<ssize_t> shape;
std::vector<ssize_t> 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<Matrix, 0, Strides>(
static_cat<Scalar *>(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<Scalar>::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<Scalar>::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<double> 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<double> 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());

View File

@ -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<T>::format()
size_t ndim = 0; // Number of dimensions
std::vector<size_t> 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<T>::format()
ssize_t ndim = 0; // Number of dimensions
std::vector<ssize_t> shape; // Shape of the tensor (1 entry per dimension)
std::vector<ssize_t> 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<size_t> shape_in, detail::any_container<ssize_t> strides_in)
buffer_info(void *ptr, ssize_t itemsize, const std::string &format, ssize_t ndim,
detail::any_container<ssize_t> shape_in, detail::any_container<ssize_t> 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 <typename T, typename SFINAE = void> struct compare_buffer_info {
static bool compare(const buffer_info& b) {
return b.format == format_descriptor<T>::format() && b.itemsize == sizeof(T);
return b.format == format_descriptor<T>::format() && b.itemsize == (ssize_t) sizeof(T);
}
};
template <typename T> struct compare_buffer_info<T, detail::enable_if_t<std::is_integral<T>::value>> {
static bool compare(const buffer_info& b) {
return b.itemsize == sizeof(T) && (b.format == format_descriptor<T>::value ||
return (size_t) b.itemsize == sizeof(T) && (b.format == format_descriptor<T>::value ||
((sizeof(T) == sizeof(long)) && b.format == (std::is_unsigned<T>::value ? "L" : "l")) ||
((sizeof(T) == sizeof(size_t)) && b.format == (std::is_unsigned<T>::value ? "N" : "n")));
}

View File

@ -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<char *>(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;

View File

@ -68,7 +68,7 @@ template <typename T> using is_eigen_other = all_of<
template <bool EigenRowMajor> 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 <typename Type_> 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 <typename props> 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<Type, enable_if_t<is_eigen_sparse<Type>::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),

View File

@ -251,10 +251,10 @@ template <typename T> using is_pod_struct = all_of<
satisfies_none_of<T, std::is_reference, std::is_array, is_std_array, std::is_arithmetic, is_complex, std::is_enum>
>;
template <size_t Dim = 0, typename Strides> ssize_t byte_offset_unsafe(const Strides &) { return 0; }
template <size_t Dim = 0, typename Strides, typename... Ix>
ssize_t byte_offset_unsafe(const Strides &strides, size_t i, Ix... index) {
return static_cast<ssize_t>(i) * strides[Dim] + byte_offset_unsafe<Dim + 1>(strides, index...);
template <ssize_t Dim = 0, typename Strides> ssize_t byte_offset_unsafe(const Strides &) { return 0; }
template <ssize_t Dim = 0, typename Strides, typename... Ix>
ssize_t byte_offset_unsafe(const Strides &strides, ssize_t i, Ix... index) {
return i * strides[Dim] + byte_offset_unsafe<Dim + 1>(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<Dynamic, const size_t *, std::array<size_t, (size_t) Dims>> shape_;
conditional_t<Dynamic, const ssize_t *, std::array<ssize_t, (size_t) Dims>> strides_;
const size_t dims_;
conditional_t<Dynamic, const ssize_t *, std::array<ssize_t, (size_t) Dims>>
shape_, strides_;
const ssize_t dims_;
friend class pybind11::array;
// Constructor for compile-time dimensions:
template <bool Dyn = Dynamic>
unchecked_reference(const void *data, const size_t *shape, const ssize_t *strides, enable_if_t<!Dyn, size_t>)
unchecked_reference(const void *data, const ssize_t *shape, const ssize_t *strides, enable_if_t<!Dyn, ssize_t>)
: data_{reinterpret_cast<const unsigned char *>(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 <bool Dyn = Dynamic>
unchecked_reference(const void *data, const size_t *shape, const ssize_t *strides, enable_if_t<Dyn, size_t> dims)
unchecked_reference(const void *data, const ssize_t *shape, const ssize_t *strides, enable_if_t<Dyn, ssize_t> dims)
: data_{reinterpret_cast<const unsigned char *>(data)}, shape_{shape}, strides_{strides}, dims_{dims} {}
public:
@ -295,39 +295,39 @@ public:
template <typename... Ix> const T &operator()(Ix... index) const {
static_assert(sizeof...(Ix) == Dims || Dynamic,
"Invalid number of indices for unchecked array reference");
return *reinterpret_cast<const T *>(data_ + byte_offset_unsafe(strides_, size_t(index)...));
return *reinterpret_cast<const T *>(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 <size_t D = Dims, typename = enable_if_t<D == 1 || Dynamic>>
const T &operator[](size_t index) const { return operator()(index); }
template <ssize_t D = Dims, typename = enable_if_t<D == 1 || Dynamic>>
const T &operator[](ssize_t index) const { return operator()(index); }
/// Pointer access to the data at the given indices.
template <typename... Ix> const T *data(Ix... ix) const { return &operator()(size_t(ix)...); }
template <typename... Ix> 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 <bool Dyn = Dynamic>
enable_if_t<!Dyn, size_t> size() const {
return std::accumulate(shape_.begin(), shape_.end(), (size_t) 1, std::multiplies<size_t>());
enable_if_t<!Dyn, ssize_t> size() const {
return std::accumulate(shape_.begin(), shape_.end(), (ssize_t) 1, std::multiplies<ssize_t>());
}
template <bool Dyn = Dynamic>
enable_if_t<Dyn, size_t> size() const {
return std::accumulate(shape_, shape_ + ndim(), (size_t) 1, std::multiplies<size_t>());
enable_if_t<Dyn, ssize_t> size() const {
return std::accumulate(shape_, shape_ + ndim(), (ssize_t) 1, std::multiplies<ssize_t>());
}
/// 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 <size_t D = Dims, typename = enable_if_t<D == 1 || Dynamic>>
T &operator[](size_t index) { return operator()(index); }
template <ssize_t D = Dims, typename = enable_if_t<D == 1 || Dynamic>>
T &operator[](ssize_t index) { return operator()(index); }
/// Mutable pointer access to the data at the given indices.
template <typename... Ix> T *mutable_data(Ix... ix) { return &operator()(size_t(ix)...); }
template <typename... Ix> T *mutable_data(Ix... ix) { return &operator()(ssize_t(ix)...); }
};
template <typename T, ssize_t Dim>
@ -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<object>(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<void *>(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 <typename T>
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<size_t>());
ssize_t size() const {
return std::accumulate(shape(), shape() + ndim(), (ssize_t) 1, std::multiplies<ssize_t>());
}
/// 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<const size_t *>(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<const ssize_t *>(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<typename... Ix> 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<typename... Ix> ssize_t index_at(Ix... index) const {
return offset_at(index...) / static_cast<ssize_t>(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 <typename T, ssize_t Dims = -1> detail::unchecked_mutable_reference<T, Dims> 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<T, Dims>(mutable_data(), shape(), strides(), ndim());
@ -651,7 +651,7 @@ public:
* invalid dimensions or dimension indices.
*/
template <typename T, ssize_t Dims = -1> detail::unchecked_reference<T, Dims> 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<T, Dims>(data(), shape(), strides(), ndim());
@ -690,14 +690,14 @@ public:
protected:
template<typename, typename> 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<typename... Ix> 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<ssize_t> default_strides(const std::vector<size_t>& shape, size_t itemsize) {
static std::vector<Py_intptr_t> default_strides(const std::vector<Py_intptr_t>& shape, ssize_t itemsize) {
auto ndim = shape.size();
std::vector<ssize_t> strides(ndim);
if (ndim) {
@ -718,12 +718,12 @@ protected:
}
template<typename... Ix> 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<typename... Ix> void check_dimensions_impl(size_t axis, const size_t* shape, size_t i, Ix... index) const {
template<typename... Ix> 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<typename... Ix> ssize_t index_at(Ix... index) const {
return offset_at(index...) / static_cast<ssize_t>(itemsize());
return offset_at(index...) / itemsize();
}
template<typename... Ix> const T* data(Ix... index) const {
@ -792,14 +792,14 @@ public:
template<typename... Ix> const T& at(Ix... index) const {
if (sizeof...(index) != ndim())
fail_dim_check(sizeof...(index), "index dimension mismatch");
return *(static_cast<const T*>(array::data()) + byte_offset(size_t(index)...) / static_cast<ssize_t>(itemsize()));
return *(static_cast<const T*>(array::data()) + byte_offset(ssize_t(index)...) / itemsize());
}
// Mutable reference to element at a given index
template<typename... Ix> T& mutable_at(Ix... index) {
if (sizeof...(index) != ndim())
fail_dim_check(sizeof...(index), "index dimension mismatch");
return *(static_cast<T*>(array::mutable_data()) + byte_offset(size_t(index)...) / static_cast<ssize_t>(itemsize()));
return *(static_cast<T*>(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<field_descriptor>& 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<field_descriptor> 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<size_t>& shape)
common_iterator(void* ptr, const container_type& strides, const container_type& shape)
: p_ptr(reinterpret_cast<char*>(ptr)), m_strides(strides.size()) {
m_strides.back() = static_cast<value_type>(strides.back());
for (size_type i = m_strides.size() - 1; i != 0; --i) {
@ -1167,18 +1167,18 @@ private:
template <size_t N> class multi_array_iterator {
public:
using container_type = std::vector<size_t>;
using container_type = std::vector<ssize_t>;
multi_array_iterator(const std::array<buffer_info, N> &buffers,
const std::vector<size_t> &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<container_type::value_type>(shape[i]);
m_shape[i] = shape[i];
std::vector<ssize_t> 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<size_t> &shape,
common_iter &iterator, std::vector<ssize_t> &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 <size_t N>
broadcast_trivial broadcast(const std::array<buffer_info, N> &buffers, size_t &ndim, std::vector<size_t> &shape) {
ndim = std::accumulate(buffers.begin(), buffers.end(), size_t(0), [](size_t res, const buffer_info& buf) {
broadcast_trivial broadcast(const std::array<buffer_info, N> &buffers, ssize_t &ndim, std::vector<ssize_t> &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<buffer_info, N> &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<ssize_t>(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<buffer_info, N> &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<ssize_t>(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<buffer_info, N> buffers {{ args.request()... }};
/* Determine dimensions parameters of output array */
size_t ndim = 0;
std::vector<size_t> shape(0);
auto trivial = broadcast(buffers, ndim, shape);
ssize_t nd = 0;
std::vector<ssize_t> shape(0);
auto trivial = broadcast(buffers, nd, shape);
size_t ndim = (size_t) nd;
size_t size = 1;
ssize_t size = 1;
std::vector<ssize_t> strides(ndim);
if (ndim > 0) {
if (trivial == broadcast_trivial::f_trivial) {
strides[0] = static_cast<ssize_t>(sizeof(Return));
strides[0] = sizeof(Return);
for (size_t i = 1; i < ndim; ++i) {
strides[i] = strides[i - 1] * static_cast<ssize_t>(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<ssize_t>(sizeof(Return));
strides[ndim-1] = sizeof(Return);
for (size_t i = ndim - 1; i > 0; --i) {
strides[i - 1] = strides[i] * static_cast<ssize_t>(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<Index...>(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<Args *>(buffers[Index].ptr)[buffers[Index].size == 1 ? 0 : i])...);
}

View File

@ -1165,15 +1165,15 @@ public:
static std::vector<Py_ssize_t> py_strides { };
static std::vector<Py_ssize_t> py_shape { };
buf.buf = info.ptr;
buf.itemsize = (Py_ssize_t) info.itemsize;
buf.itemsize = info.itemsize;
buf.format = const_cast<char *>(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();

View File

@ -345,21 +345,21 @@ vector_buffer(Class_& cl) {
format_descriptor<T>::format();
cl.def_buffer([](Vector& v) -> buffer_info {
return buffer_info(v.data(), sizeof(T), format_descriptor<T>::format(), 1, {v.size()}, {sizeof(T)});
return buffer_info(v.data(), static_cast<ssize_t>(sizeof(T)), format_descriptor<T>::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<ssize_t>(sizeof(T)))
if (info.ndim != 1 || info.strides[0] % static_cast<ssize_t>(sizeof(T)))
throw type_error("Only valid 1D buffers can be copied to a vector");
if (!detail::compare_buffer_info<T>::compare(info) || sizeof(T) != info.itemsize)
if (!detail::compare_buffer_info<T>::compare(info) || (ssize_t) sizeof(T) != info.itemsize)
throw type_error("Format mismatch (Python: " + info.format + " C++: " + format_descriptor<T>::format() + ")");
new (&vec) Vector();
vec.reserve(info.shape[0]);
vec.reserve((size_t) info.shape[0]);
T *p = static_cast<T*>(info.ptr);
auto step = info.strides[0] / static_cast<ssize_t>(sizeof(T));
T *end = p + static_cast<ssize_t>(info.shape[0]) * step;
for (; p < end; p += step)
ssize_t step = info.strides[0] / static_cast<ssize_t>(sizeof(T));
T *end = p + info.shape[0] * step;
for (; p != end; p += step)
vec.push_back(*p);
});

View File

@ -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_<Matrix> mtx(m, "Matrix", py::buffer_protocol());
mtx.def(py::init<size_t, size_t>())
mtx.def(py::init<ssize_t, ssize_t>())
/// Construct from a buffer
.def("__init__", [](Matrix &v, py::buffer b) {
py::buffer_info info = b.request();
if (info.format != py::format_descriptor<float>::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<size_t, size_t> i) {
.def("__getitem__", [](const Matrix &m, std::pair<ssize_t, ssize_t> 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<size_t, size_t> i, float v) {
.def("__setitem__", [](Matrix &m, std::pair<ssize_t, ssize_t> 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<float>::format(), /* Python struct-style format descriptor */
2, /* Number of dimensions */
{ m.rows(), m.cols() }, /* Buffer dimensions */
{ static_cast<ssize_t>(sizeof(float) * m.rows()), /* Strides (in bytes) for each index */
static_cast<ssize_t>(sizeof(float)) }
{ sizeof(float) * size_t(m.rows()), /* Strides (in bytes) for each index */
sizeof(float) }
);
})
;

View File

@ -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)
"""

View File

@ -13,53 +13,52 @@
#include <pybind11/stl.h>
#include <cstdint>
#include <vector>
using arr = py::array;
using arr_t = py::array_t<uint16_t, 0>;
static_assert(std::is_same<arr_t::value_type, uint16_t>::value, "");
template<typename... Ix> 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<typename... Ix> 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<typename... Ix> 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<typename... Ix> 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<typename... Ix> py::ssize_t index_at(const arr& a, Ix... idx) { return a.index_at(idx...); }
template<typename... Ix> py::ssize_t index_at_t(const arr_t& a, Ix... idx) { return a.index_at(idx...); }
template<typename... Ix> py::ssize_t offset_at(const arr& a, Ix... idx) { return a.offset_at(idx...); }
template<typename... Ix> py::ssize_t offset_at_t(const arr_t& a, Ix... idx) { return a.offset_at(idx...); }
template<typename... Ix> py::ssize_t at_t(const arr_t& a, Ix... idx) { return a.at(idx...); }
template<typename... Ix> ssize_t index_at(const arr& a, Ix... idx) { return a.index_at(idx...); }
template<typename... Ix> ssize_t index_at_t(const arr_t& a, Ix... idx) { return a.index_at(idx...); }
template<typename... Ix> ssize_t offset_at(const arr& a, Ix... idx) { return a.offset_at(idx...); }
template<typename... Ix> ssize_t offset_at_t(const arr_t& a, Ix... idx) { return a.offset_at(idx...); }
template<typename... Ix> ssize_t at_t(const arr_t& a, Ix... idx) { return a.at(idx...); }
template<typename... Ix> 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<double> 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<double, py::array::c_style> 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<double, py::array::f_style> 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<double> 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<double> 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<double, py::array::c_style> 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<double>(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<float>(1); }); // { 1 } also works, but clang warns about it
sm.def("array_initializer_list", []() { return py::array_t<float>({ 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<double> 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});

View File

@ -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)

View File

@ -149,7 +149,7 @@ py::array_t<StringStruct, 0> create_string_array(bool non_empty) {
if (non_empty) {
auto req = arr.request();
auto ptr = static_cast<StringStruct*>(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<char*>(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<S, 0> arr) {
const auto req = arr.request();
const auto ptr = static_cast<S*>(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<int32_t, 0> test_array_ctors(int i) {
using arr_t = py::array_t<int32_t, 0>;
std::vector<int32_t> data { 1, 2, 3, 4, 5, 6 };
std::vector<size_t> shape { 3, 2 };
std::vector<ssize_t> shape { 3, 2 };
std::vector<ssize_t> strides { 8, 4 };
auto ptr = data.data();

View File

@ -50,8 +50,8 @@ test_initializer numpy_vectorize([](py::module &m) {
py::array_t<float, py::array::forcecast> arg2,
py::array_t<double, py::array::forcecast> arg3
) {
size_t ndim;
std::vector<size_t> shape;
ssize_t ndim;
std::vector<ssize_t> shape;
std::array<py::buffer_info, 3> buffers {{ arg1.request(), arg2.request(), arg3.request() }};
return py::detail::broadcast(buffers, ndim, shape);
});