24 if (!pyobj) PyErr_Print();
25 memset(&pyobj->
fBufInfo, 0,
sizeof(Py_buffer));
26 pyobj->
fBuf =
nullptr;
51 {(
char*)
"format", (getter)
ll_typecode,
nullptr,
nullptr,
nullptr},
52 {(
char*)
"typecode", (getter)
ll_typecode,
nullptr,
nullptr,
nullptr},
53 {(
char*)
nullptr,
nullptr,
nullptr,
nullptr,
nullptr }
61 if (!PyTuple_Check(shape) || PyTuple_GET_SIZE(shape) != 1) {
63 PyObject* pystr = PyObject_Str(shape);
65 PyErr_Format(PyExc_TypeError,
"tuple object of length 1 expected, received %s",
71 PyErr_SetString(PyExc_TypeError,
"tuple object of length 1 expected");
76 if (nlen == -1 && PyErr_Occurred())
83 PyErr_SetString(PyExc_TypeError,
"unsupported buffer dimensions");
92 {(
char*)
"reshape", (PyCFunction)
ll_reshape, METH_O,
nullptr},
93 {(
char*)
nullptr,
nullptr, 0,
nullptr}
104#define HAVE_PTR(suboffsets, dim) (suboffsets && suboffsets[dim] >= 0)
106#define ADJUST_PTR(ptr, suboffsets, dim) \
107 (HAVE_PTR(suboffsets, dim) ? *((char**)ptr) + suboffsets[dim] : ptr)
111#define HAVE_SUBOFFSETS_IN_LAST_DIM(view) \
112 (view->suboffsets && view->suboffsets[dest->ndim-1] >= 0)
117 assert(
dest->ndim > 0 && src->ndim > 0);
121 src->strides[src->ndim-1] == src->itemsize);
130 if (
dest->ndim != src->ndim)
133 for (
int i = 0; i <
dest->ndim; i++) {
134 if (
dest->shape[i] != src->shape[i])
136 if (
dest->shape[i] == 0)
148 if (strcmp(
dest->format, src->format) != 0 ||
dest->itemsize != src->itemsize ||
150 PyErr_SetString(PyExc_ValueError,
151 "low level pointer assignment: lvalue and rvalue have different structures");
169 if (dptr + size < sptr || sptr + size < dptr)
170 memcpy(dptr, sptr, size);
172 memmove(dptr, sptr, size);
177 for (i=0, p=mem; i < shape[0]; p+=itemsize, sptr+=sstrides[0], i++) {
178 char *xsptr =
ADJUST_PTR(sptr, ssuboffsets, 0);
179 memcpy(p, xsptr, itemsize);
181 for (i=0, p=mem; i < shape[0]; p+=itemsize, dptr+=dstrides[0], i++) {
182 char *xdptr =
ADJUST_PTR(dptr, dsuboffsets, 0);
183 memcpy(xdptr, p, itemsize);
195 assert(
dest->ndim == 1);
201 mem = (
char*)PyMem_Malloc(
dest->shape[0] *
dest->itemsize);
210 (
char*)src->buf, src->strides, src->suboffsets,
226 assert(view.strides);
228 nitems = view.shape[dim];
232 if (index < 0 || index >= nitems) {
233 PyErr_Format(PyExc_IndexError,
234 "index out of bounds on dimension %d", dim + 1);
238 ptr += view.strides[dim] * index;
258 if (nindices > view.ndim) {
259 PyErr_Format(PyExc_TypeError,
260 "cannot index %d-dimension view with %zd-element tuple", view.ndim, nindices);
264 char* ptr = (
char*)llview->
get_buf();
265 for (
Py_ssize_t dim = 0; dim < nindices; dim++) {
269 if (index == -1 && PyErr_Occurred())
292#if PY_VERSION_HEX < 0x03000000
293 PySliceObject* key = (PySliceObject*)_key;
298 if (PySlice_GetIndicesEx(key, base->shape[dim], &start, &stop, &step, &slicelength) < 0)
301 if (!base->suboffsets || dim == 0) {
303 base->buf = (
char *)base->buf + base->strides[dim] * start;
307 while (
n >= 0 && base->suboffsets[
n] < 0)
311 base->suboffsets[
n] = base->suboffsets[
n] + base->strides[dim] * start;
313 base->shape[dim] = slicelength;
314 base->strides[dim] = base->strides[dim] * step;
322 if (!PyTuple_Check(key))
331 if (!PySlice_Check(
x))
340 if (!PyTuple_Check(key))
362 PyErr_SetString(PyExc_ReferenceError,
"attempt to access a null-pointer");
366 if (view.ndim == 0) {
367 PyErr_SetString(PyExc_TypeError,
"invalid indexing of 0-dim memory");
385 if (nindices < view.ndim) {
387 PyErr_SetString(PyExc_NotImplementedError,
388 "sub-views are not implemented");
410 if (view.ndim == 0) {
411 if (PyTuple_Check(key) && PyTuple_GET_SIZE(key) == 0) {
414 else if (key == Py_Ellipsis) {
419 PyErr_SetString(PyExc_TypeError,
420 "invalid indexing of 0-dim memory");
427 if (index == -1 && PyErr_Occurred())
431 else if (PySlice_Check(key)) {
434 PyErr_SetString(PyExc_NotImplementedError,
435 "multi-dimensional slicing is not implemented");
442 PyErr_SetString(PyExc_NotImplementedError,
443 "multi-dimensional slicing is not implemented");
447 PyErr_SetString(PyExc_TypeError,
"invalid slice key");
458 PyErr_SetString(PyExc_TypeError,
"cannot modify read-only memory");
462 if (value ==
nullptr) {
463 PyErr_SetString(PyExc_TypeError,
"cannot delete memory");
467 if (view.ndim == 0) {
468 if (key == Py_Ellipsis ||
469 (PyTuple_Check(key) && PyTuple_GET_SIZE(key) == 0)) {
473 PyErr_SetString(PyExc_TypeError,
474 "invalid indexing of 0-dim memory");
482 PyErr_SetString(PyExc_NotImplementedError,
483 "sub-views are not implemented");
487 if (index == -1 && PyErr_Occurred())
496 if (PySlice_Check(key) && view.ndim == 1) {
502 if (PyObject_GetBuffer(value, &src, PyBUF_FULL_RO) < 0)
506 dest.shape = &arrays[0];
dest.shape[0] = view.shape[0];
507 dest.strides = &arrays[1];
dest.strides[0] = view.strides[0];
508 if (view.suboffsets) {
509 dest.suboffsets = &arrays[2];
dest.suboffsets[0] = view.suboffsets[0];
521 if (PyTuple_GET_SIZE(key) < view.ndim) {
522 PyErr_SetString(PyExc_NotImplementedError,
523 "sub-views are not implemented");
534 PyErr_SetString(PyExc_NotImplementedError,
535 "LowLevelView slice assignments are currently restricted "
540 PyErr_SetString(PyExc_TypeError,
"invalid slice key");
544#if PY_VERSION_HEX < 0x03000000
549 PyErr_SetString(PyExc_TypeError,
"accessing non-existent segment");
573 if (!(flags & PyBUF_FORMAT)) {
582 if ((flags & PyBUF_F_CONTIGUOUS) == PyBUF_F_CONTIGUOUS) {
583 PyErr_SetString(PyExc_BufferError,
584 "underlying buffer is not Fortran contiguous");
588 if (!(flags & PyBUF_FORMAT)) {
591 if (view->format != NULL) {
594 PyErr_Format(PyExc_BufferError,
595 "cannot cast to unsigned bytes if the format flag is present");
605 Py_INCREF(view->obj);
634#if PY_VERSION_HEX < 0x03000000
650 (
char*)
"cppyy.LowLevelView",
668 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES |
670 (
char*)
"memory view on C++ pointer",
695#
if PY_VERSION_HEX >= 0x02030000
698#
if PY_VERSION_HEX >= 0x02060000
701#
if PY_VERSION_HEX >= 0x03040000
710template<
typename T>
struct typecode_traits {};
711template<>
struct typecode_traits<
bool> {
712 static constexpr const char* format =
"?";
static constexpr const char*
name =
"bool"; };
713template<>
struct typecode_traits<signed char> {
714 static constexpr const char* format =
"b";
static constexpr const char*
name =
"signed char"; };
715template<>
struct typecode_traits<unsigned char> {
716 static constexpr const char* format =
"B";
static constexpr const char*
name =
"UCharAsInt"; };
717#if __cplusplus > 201402L
718template<>
struct typecode_traits<std::
byte> {
719 static constexpr const char* format =
"B";
static constexpr const char*
name =
"UCharAsInt"; };
721template<>
struct typecode_traits<const char*> {
722 static constexpr const char* format =
"b";
static constexpr const char*
name =
"const char*"; };
723template<>
struct typecode_traits<
short> {
724 static constexpr const char* format =
"h";
static constexpr const char*
name =
"short"; };
725template<>
struct typecode_traits<unsigned
short> {
726 static constexpr const char* format =
"H";
static constexpr const char*
name =
"unsigned short"; };
727template<>
struct typecode_traits<
int> {
728 static constexpr const char* format =
"i";
static constexpr const char*
name =
"int"; };
729template<>
struct typecode_traits<unsigned
int> {
730 static constexpr const char* format =
"I";
static constexpr const char*
name =
"unsigned int"; };
731template<>
struct typecode_traits<
long> {
732 static constexpr const char* format =
"l";
static constexpr const char*
733#if PY_VERSION_HEX < 0x03000000
739template<>
struct typecode_traits<unsigned
long> {
740 static constexpr const char* format =
"L";
static constexpr const char*
name =
"unsigned long"; };
741template<>
struct typecode_traits<
long long> {
742 static constexpr const char* format =
"q";
static constexpr const char*
name =
"long long"; };
743template<>
struct typecode_traits<unsigned
long long> {
744 static constexpr const char* format =
"Q";
static constexpr const char*
name =
"unsigned long long"; };
745template<>
struct typecode_traits<float> {
746 static constexpr const char* format =
"f";
static constexpr const char*
name =
"float"; };
747template<>
struct typecode_traits<
double> {
748 static constexpr const char* format =
"d";
static constexpr const char*
name =
"double"; };
749template<>
struct typecode_traits<
long double> {
750 static constexpr const char* format =
"D";
static constexpr const char*
name =
"long double"; };
751template<>
struct typecode_traits<std::complex<float>> {
752 static constexpr const char* format =
"Zf";
static constexpr const char*
name =
"std::complex<float>"; };
753template<>
struct typecode_traits<std::complex<double>> {
754 static constexpr const char* format =
"Zd";
static constexpr const char*
name =
"std::complex<double>"; };
755template<>
struct typecode_traits<std::complex<int>> {
756 static constexpr const char* format =
"Zi";
static constexpr const char*
name =
"std::complex<int>"; };
757template<>
struct typecode_traits<std::complex<long>> {
758 static constexpr const char* format =
"Zl";
static constexpr const char*
name =
"std::complex<long>"; };
768 Py_ssize_t nx = (shape && 0 <= shape[1]) ? shape[1] : INT_MAX/
sizeof(
T);
778 view.format = (
char*)typecode_traits<T>::format;
779 view.ndim = shape ? (
int)shape[0] : 1;
783 view.suboffsets =
nullptr;
784 view.internal =
nullptr;
786 if (view.ndim == 1) {
788 view.len = nx *
sizeof(
T);
789 view.itemsize =
sizeof(
T);
793 view.len = nx *
sizeof(
void*);
794 view.itemsize =
sizeof(
void*);
798 shape[1] = shape[0] - 1;
806 view.strides[0] = view.itemsize;
816 T* buf = address ? *address :
nullptr;
823#define CPPYY_IMPL_VIEW_CREATOR(type) \
824PyObject* CPyCppyy::CreateLowLevelView(type* address, Py_ssize_t* shape) { \
825 return CreateLowLevelViewT<type>(address, shape); \
827PyObject* CPyCppyy::CreateLowLevelView(type** address, Py_ssize_t* shape) { \
828 return CreateLowLevelViewT<type>(address, shape); \
834#if __cplusplus > 201402L
854 return CreateLowLevelViewT<const char*>(address, shape);
Py_ssize_t PyNumber_AsSsize_t(PyObject *obj, PyObject *)
#define CPyCppyy_PyText_AsStringChecked
#define CPyCppyy_PyText_FromString
#define PyVarObject_HEAD_INIT(type, size)
#define PyIndex_Check(obj)
static PyObject * CreateLowLevelViewT(T *address, Py_ssize_t *shape)
#define ADJUST_PTR(ptr, suboffsets, dim)
static PyObject * ll_typecode(CPyCppyy::LowLevelView *self, void *)
static void * ptr_from_index(CPyCppyy::LowLevelView *llview, Py_ssize_t index)
static int ll_ass_sub(CPyCppyy::LowLevelView *self, PyObject *key, PyObject *value)
static PyObject * ll_item_multi(CPyCppyy::LowLevelView *self, PyObject *tup)
static Py_ssize_t is_multiindex(PyObject *key)
static Py_ssize_t ll_oldgetbuf(CPyCppyy::LowLevelView *self, Py_ssize_t seg, void **pptr)
static PySequenceMethods ll_as_sequence
static Py_ssize_t ll_getsegcount(PyObject *, Py_ssize_t *lenp)
static PyObject * ll_reshape(CPyCppyy::LowLevelView *self, PyObject *shape)
static bool equiv_shape(const Py_buffer *dest, const Py_buffer *src)
static int ll_getbuf(CPyCppyy::LowLevelView *self, Py_buffer *view, int flags)
static void * ptr_from_tuple(CPyCppyy::LowLevelView *llview, PyObject *tup)
static int last_dim_is_contiguous(const Py_buffer *dest, const Py_buffer *src)
static PyBufferProcs ll_as_buffer
static PyMethodDef ll_methods[]
static bool equiv_structure(const Py_buffer *dest, const Py_buffer *src)
static void copy_base(const Py_ssize_t *shape, Py_ssize_t itemsize, char *dptr, const Py_ssize_t *dstrides, const Py_ssize_t *dsuboffsets, char *sptr, const Py_ssize_t *sstrides, const Py_ssize_t *ssuboffsets, char *mem)
static void ll_dealloc(CPyCppyy::LowLevelView *pyobj)
static PyMappingMethods ll_as_mapping
#define CPPYY_IMPL_VIEW_CREATOR(type)
static PyGetSetDef ll_getset[]
static CPyCppyy::LowLevelView * ll_new(PyTypeObject *subtype, PyObject *, PyObject *)
static PyObject * ll_item(CPyCppyy::LowLevelView *self, Py_ssize_t index)
static int copy_single(Py_buffer *dest, Py_buffer *src)
static int init_slice(Py_buffer *base, PyObject *_key, int dim)
static Py_ssize_t ll_length(CPyCppyy::LowLevelView *self)
static bool is_multislice(PyObject *key)
static PyObject * ll_subscript(CPyCppyy::LowLevelView *self, PyObject *key)
static char * lookup_dimension(Py_buffer &view, char *ptr, int dim, Py_ssize_t index)
#define HAVE_SUBOFFSETS_IN_LAST_DIM(view)
virtual PyObject * FromMemory(void *address)
virtual bool ToMemory(PyObject *value, void *address)
PyObject_HEAD Py_buffer fBufInfo
PyObject * CreateLowLevelView(const char **, Py_ssize_t *shape=nullptr)
PyTypeObject LowLevelView_Type
CPYCPPYY_EXTERN Converter * CreateConverter(const std::string &name, Py_ssize_t *dims=nullptr)
#define dest(otri, vertexptr)