mirror of
https://github.com/pybind/pybind11.git
synced 2024-11-22 05:05:11 +00:00
Now shape
, size
, ndims
and itemsize
are also signed integers.
This commit is contained in:
parent
b68959e822
commit
30d43c4992
@ -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());
|
||||
|
||||
|
@ -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")));
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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),
|
||||
|
@ -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])...);
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
});
|
||||
|
||||
|
@ -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) }
|
||||
);
|
||||
})
|
||||
;
|
||||
|
@ -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)
|
||||
"""
|
||||
|
@ -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});
|
||||
|
@ -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)
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user