LCOV - code coverage report
Current view: top level - Objects - memoryobject.c (source / functions) Hit Total Coverage
Test: CPython lcov report Lines: 0 356 0.0 %
Date: 2017-04-19 Functions: 0 29 0.0 %

          Line data    Source code
       1             : 
       2             : /* Memoryview object implementation */
       3             : 
       4             : #include "Python.h"
       5             : 
       6             : static Py_ssize_t
       7           0 : get_shape0(Py_buffer *buf)
       8             : {
       9           0 :     if (buf->shape != NULL)
      10           0 :         return buf->shape[0];
      11           0 :     if (buf->ndim == 0)
      12           0 :         return 1;
      13           0 :     PyErr_SetString(PyExc_TypeError,
      14             :         "exported buffer does not have any shape information associated "
      15             :         "to it");
      16           0 :     return -1;
      17             : }
      18             : 
      19             : static void
      20           0 : dup_buffer(Py_buffer *dest, Py_buffer *src)
      21             : {
      22           0 :     *dest = *src;
      23           0 :     if (src->ndim == 1 && src->shape != NULL) {
      24           0 :         dest->shape = &(dest->smalltable[0]);
      25           0 :         dest->shape[0] = get_shape0(src);
      26             :     }
      27           0 :     if (src->ndim == 1 && src->strides != NULL) {
      28           0 :         dest->strides = &(dest->smalltable[1]);
      29           0 :         dest->strides[0] = src->strides[0];
      30             :     }
      31           0 : }
      32             : 
      33             : static int
      34           0 : memory_getbuf(PyMemoryViewObject *self, Py_buffer *view, int flags)
      35             : {
      36           0 :     int res = 0;
      37           0 :     if (self->view.obj != NULL)
      38           0 :         res = PyObject_GetBuffer(self->view.obj, view, flags);
      39           0 :     if (view)
      40           0 :         dup_buffer(view, &self->view);
      41           0 :     return res;
      42             : }
      43             : 
      44             : static void
      45           0 : memory_releasebuf(PyMemoryViewObject *self, Py_buffer *view)
      46             : {
      47           0 :     PyBuffer_Release(view);
      48           0 : }
      49             : 
      50             : PyDoc_STRVAR(memory_doc,
      51             : "memoryview(object)\n\
      52             : \n\
      53             : Create a new memoryview object which references the given object.");
      54             : 
      55             : PyObject *
      56           0 : PyMemoryView_FromBuffer(Py_buffer *info)
      57             : {
      58             :     PyMemoryViewObject *mview;
      59             : 
      60           0 :     mview = (PyMemoryViewObject *)
      61             :         PyObject_GC_New(PyMemoryViewObject, &PyMemoryView_Type);
      62           0 :     if (mview == NULL)
      63           0 :         return NULL;
      64           0 :     mview->base = NULL;
      65           0 :     dup_buffer(&mview->view, info);
      66             :     /* NOTE: mview->view.obj should already have been incref'ed as
      67             :        part of PyBuffer_FillInfo(). */
      68           0 :     _PyObject_GC_TRACK(mview);
      69           0 :     return (PyObject *)mview;
      70             : }
      71             : 
      72             : PyObject *
      73           0 : PyMemoryView_FromObject(PyObject *base)
      74             : {
      75             :     PyMemoryViewObject *mview;
      76             :     Py_buffer view;
      77             : 
      78           0 :     if (!PyObject_CheckBuffer(base)) {
      79           0 :         PyErr_SetString(PyExc_TypeError,
      80             :             "cannot make memory view because object does "
      81             :             "not have the buffer interface");
      82           0 :         return NULL;
      83             :     }
      84             : 
      85           0 :     if (PyObject_GetBuffer(base, &view, PyBUF_FULL_RO) < 0)
      86           0 :         return NULL;
      87             : 
      88           0 :     mview = (PyMemoryViewObject *)PyMemoryView_FromBuffer(&view);
      89           0 :     if (mview == NULL) {
      90           0 :         PyBuffer_Release(&view);
      91           0 :         return NULL;
      92             :     }
      93             : 
      94           0 :     mview->base = base;
      95           0 :     Py_INCREF(base);
      96           0 :     return (PyObject *)mview;
      97             : }
      98             : 
      99             : static PyObject *
     100           0 : memory_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds)
     101             : {
     102             :     PyObject *obj;
     103             :     static char *kwlist[] = {"object", 0};
     104             : 
     105           0 :     if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:memoryview", kwlist,
     106             :                                      &obj)) {
     107           0 :         return NULL;
     108             :     }
     109             : 
     110           0 :     return PyMemoryView_FromObject(obj);
     111             : }
     112             : 
     113             : 
     114             : static void
     115           0 : _strided_copy_nd(char *dest, char *src, int nd, Py_ssize_t *shape,
     116             :                  Py_ssize_t *strides, Py_ssize_t itemsize, char fort)
     117             : {
     118             :     int k;
     119             :     Py_ssize_t outstride;
     120             : 
     121           0 :     if (nd==0) {
     122           0 :         memcpy(dest, src, itemsize);
     123             :     }
     124           0 :     else if (nd == 1) {
     125           0 :         for (k = 0; k<shape[0]; k++) {
     126           0 :             memcpy(dest, src, itemsize);
     127           0 :             dest += itemsize;
     128           0 :             src += strides[0];
     129             :         }
     130             :     }
     131             :     else {
     132           0 :         if (fort == 'F') {
     133             :             /* Copy first dimension first,
     134             :                second dimension second, etc...
     135             :                Set up the recursive loop backwards so that final
     136             :                dimension is actually copied last.
     137             :             */
     138           0 :             outstride = itemsize;
     139           0 :             for (k=1; k<nd-1;k++) {
     140           0 :                 outstride *= shape[k];
     141             :             }
     142           0 :             for (k=0; k<shape[nd-1]; k++) {
     143           0 :                 _strided_copy_nd(dest, src, nd-1, shape,
     144             :                                  strides, itemsize, fort);
     145           0 :                 dest += outstride;
     146           0 :                 src += strides[nd-1];
     147             :             }
     148             :         }
     149             : 
     150             :         else {
     151             :             /* Copy last dimension first,
     152             :                second-to-last dimension second, etc.
     153             :                Set up the recursion so that the
     154             :                first dimension is copied last
     155             :             */
     156           0 :             outstride = itemsize;
     157           0 :             for (k=1; k < nd; k++) {
     158           0 :                 outstride *= shape[k];
     159             :             }
     160           0 :             for (k=0; k<shape[0]; k++) {
     161           0 :                 _strided_copy_nd(dest, src, nd-1, shape+1,
     162             :                                  strides+1, itemsize,
     163             :                                  fort);
     164           0 :                 dest += outstride;
     165           0 :                 src += strides[0];
     166             :             }
     167             :         }
     168             :     }
     169           0 :     return;
     170             : }
     171             : 
     172             : static int
     173           0 : _indirect_copy_nd(char *dest, Py_buffer *view, char fort)
     174             : {
     175             :     Py_ssize_t *indices;
     176             :     int k;
     177             :     Py_ssize_t elements;
     178             :     char *ptr;
     179             :     void (*func)(int, Py_ssize_t *, const Py_ssize_t *);
     180             : 
     181           0 :     if (view->ndim > PY_SSIZE_T_MAX / sizeof(Py_ssize_t)) {
     182           0 :         PyErr_NoMemory();
     183           0 :         return -1;
     184             :     }
     185             : 
     186           0 :     indices = (Py_ssize_t *)PyMem_Malloc(sizeof(Py_ssize_t)*view->ndim);
     187           0 :     if (indices == NULL) {
     188           0 :         PyErr_NoMemory();
     189           0 :         return -1;
     190             :     }
     191           0 :     for (k=0; k<view->ndim;k++) {
     192           0 :         indices[k] = 0;
     193             :     }
     194             : 
     195           0 :     elements = 1;
     196           0 :     for (k=0; k<view->ndim; k++) {
     197           0 :         elements *= view->shape[k];
     198             :     }
     199           0 :     if (fort == 'F') {
     200           0 :         func = _Py_add_one_to_index_F;
     201             :     }
     202             :     else {
     203           0 :         func = _Py_add_one_to_index_C;
     204             :     }
     205           0 :     while (elements--) {
     206           0 :         func(view->ndim, indices, view->shape);
     207           0 :         ptr = PyBuffer_GetPointer(view, indices);
     208           0 :         memcpy(dest, ptr, view->itemsize);
     209           0 :         dest += view->itemsize;
     210             :     }
     211             : 
     212           0 :     PyMem_Free(indices);
     213           0 :     return 0;
     214             : }
     215             : 
     216             : /*
     217             :    Get a the data from an object as a contiguous chunk of memory (in
     218             :    either 'C' or 'F'ortran order) even if it means copying it into a
     219             :    separate memory area.
     220             : 
     221             :    Returns a new reference to a Memory view object.  If no copy is needed,
     222             :    the memory view object points to the original memory and holds a
     223             :    lock on the original.  If a copy is needed, then the memory view object
     224             :    points to a brand-new Bytes object (and holds a memory lock on it).
     225             : 
     226             :    buffertype
     227             : 
     228             :    PyBUF_READ  buffer only needs to be read-only
     229             :    PyBUF_WRITE buffer needs to be writable (give error if not contiguous)
     230             :    PyBUF_SHADOW buffer needs to be writable so shadow it with
     231             :                 a contiguous buffer if it is not. The view will point to
     232             :                 the shadow buffer which can be written to and then
     233             :                 will be copied back into the other buffer when the memory
     234             :                 view is de-allocated.  While the shadow buffer is
     235             :                 being used, it will have an exclusive write lock on
     236             :                 the original buffer.
     237             :  */
     238             : 
     239             : PyObject *
     240           0 : PyMemoryView_GetContiguous(PyObject *obj, int buffertype, char fort)
     241             : {
     242             :     PyMemoryViewObject *mem;
     243             :     PyObject *bytes;
     244             :     Py_buffer *view;
     245             :     int flags;
     246             :     char *dest;
     247             : 
     248           0 :     if (!PyObject_CheckBuffer(obj)) {
     249           0 :         PyErr_SetString(PyExc_TypeError,
     250             :                         "object does not have the buffer interface");
     251           0 :         return NULL;
     252             :     }
     253             : 
     254           0 :     mem = PyObject_GC_New(PyMemoryViewObject, &PyMemoryView_Type);
     255           0 :     if (mem == NULL)
     256           0 :         return NULL;
     257             : 
     258           0 :     view = &mem->view;
     259           0 :     flags = PyBUF_FULL_RO;
     260           0 :     switch(buffertype) {
     261             :     case PyBUF_WRITE:
     262           0 :         flags = PyBUF_FULL;
     263           0 :         break;
     264             :     }
     265             : 
     266           0 :     if (PyObject_GetBuffer(obj, view, flags) != 0) {
     267           0 :         Py_DECREF(mem);
     268           0 :         return NULL;
     269             :     }
     270             : 
     271           0 :     if (PyBuffer_IsContiguous(view, fort)) {
     272             :         /* no copy needed */
     273           0 :         Py_INCREF(obj);
     274           0 :         mem->base = obj;
     275           0 :         _PyObject_GC_TRACK(mem);
     276           0 :         return (PyObject *)mem;
     277             :     }
     278             :     /* otherwise a copy is needed */
     279           0 :     if (buffertype == PyBUF_WRITE) {
     280           0 :         Py_DECREF(mem);
     281           0 :         PyErr_SetString(PyExc_BufferError,
     282             :                         "writable contiguous buffer requested "
     283             :                         "for a non-contiguousobject.");
     284           0 :         return NULL;
     285             :     }
     286           0 :     bytes = PyBytes_FromStringAndSize(NULL, view->len);
     287           0 :     if (bytes == NULL) {
     288           0 :         Py_DECREF(mem);
     289           0 :         return NULL;
     290             :     }
     291           0 :     dest = PyBytes_AS_STRING(bytes);
     292             :     /* different copying strategy depending on whether
     293             :        or not any pointer de-referencing is needed
     294             :     */
     295             :     /* strided or in-direct copy */
     296           0 :     if (view->suboffsets==NULL) {
     297           0 :         _strided_copy_nd(dest, view->buf, view->ndim, view->shape,
     298             :                          view->strides, view->itemsize, fort);
     299             :     }
     300             :     else {
     301           0 :         if (_indirect_copy_nd(dest, view, fort) < 0) {
     302           0 :             Py_DECREF(bytes);
     303           0 :             Py_DECREF(mem);
     304           0 :             return NULL;
     305             :         }
     306             :     }
     307           0 :     if (buffertype == PyBUF_SHADOW) {
     308             :         /* return a shadowed memory-view object */
     309           0 :         view->buf = dest;
     310           0 :         mem->base = PyTuple_Pack(2, obj, bytes);
     311           0 :         Py_DECREF(bytes);
     312           0 :         if (mem->base == NULL) {
     313           0 :             Py_DECREF(mem);
     314           0 :             return NULL;
     315             :         }
     316             :     }
     317             :     else {
     318           0 :         PyBuffer_Release(view);  /* XXX ? */
     319             :         /* steal the reference */
     320           0 :         mem->base = bytes;
     321             :     }
     322           0 :     _PyObject_GC_TRACK(mem);
     323           0 :     return (PyObject *)mem;
     324             : }
     325             : 
     326             : 
     327             : static PyObject *
     328           0 : memory_format_get(PyMemoryViewObject *self)
     329             : {
     330           0 :     return PyString_FromString(self->view.format);
     331             : }
     332             : 
     333             : static PyObject *
     334           0 : memory_itemsize_get(PyMemoryViewObject *self)
     335             : {
     336           0 :     return PyLong_FromSsize_t(self->view.itemsize);
     337             : }
     338             : 
     339             : static PyObject *
     340           0 : _IntTupleFromSsizet(int len, Py_ssize_t *vals)
     341             : {
     342             :     int i;
     343             :     PyObject *o;
     344             :     PyObject *intTuple;
     345             : 
     346           0 :     if (vals == NULL) {
     347           0 :         Py_INCREF(Py_None);
     348           0 :         return Py_None;
     349             :     }
     350           0 :     intTuple = PyTuple_New(len);
     351           0 :     if (!intTuple) return NULL;
     352           0 :     for(i=0; i<len; i++) {
     353           0 :         o = PyLong_FromSsize_t(vals[i]);
     354           0 :         if (!o) {
     355           0 :             Py_DECREF(intTuple);
     356           0 :             return NULL;
     357             :         }
     358           0 :         PyTuple_SET_ITEM(intTuple, i, o);
     359             :     }
     360           0 :     return intTuple;
     361             : }
     362             : 
     363             : static PyObject *
     364           0 : memory_shape_get(PyMemoryViewObject *self)
     365             : {
     366           0 :     return _IntTupleFromSsizet(self->view.ndim, self->view.shape);
     367             : }
     368             : 
     369             : static PyObject *
     370           0 : memory_strides_get(PyMemoryViewObject *self)
     371             : {
     372           0 :     return _IntTupleFromSsizet(self->view.ndim, self->view.strides);
     373             : }
     374             : 
     375             : static PyObject *
     376           0 : memory_suboffsets_get(PyMemoryViewObject *self)
     377             : {
     378           0 :     return _IntTupleFromSsizet(self->view.ndim, self->view.suboffsets);
     379             : }
     380             : 
     381             : static PyObject *
     382           0 : memory_readonly_get(PyMemoryViewObject *self)
     383             : {
     384           0 :     return PyBool_FromLong(self->view.readonly);
     385             : }
     386             : 
     387             : static PyObject *
     388           0 : memory_ndim_get(PyMemoryViewObject *self)
     389             : {
     390           0 :     return PyLong_FromLong(self->view.ndim);
     391             : }
     392             : 
     393             : static PyGetSetDef memory_getsetlist[] ={
     394             :     {"format",          (getter)memory_format_get,      NULL, NULL},
     395             :     {"itemsize",        (getter)memory_itemsize_get,    NULL, NULL},
     396             :     {"shape",           (getter)memory_shape_get,       NULL, NULL},
     397             :     {"strides",         (getter)memory_strides_get,     NULL, NULL},
     398             :     {"suboffsets",      (getter)memory_suboffsets_get,  NULL, NULL},
     399             :     {"readonly",        (getter)memory_readonly_get,    NULL, NULL},
     400             :     {"ndim",            (getter)memory_ndim_get,        NULL, NULL},
     401             :     {NULL, NULL, NULL, NULL},
     402             : };
     403             : 
     404             : 
     405             : static PyObject *
     406           0 : memory_tobytes(PyMemoryViewObject *self, PyObject *noargs)
     407             : {
     408             :     Py_buffer view;
     409             :     PyObject *res;
     410             : 
     411           0 :     if (PyObject_GetBuffer((PyObject *)self, &view, PyBUF_SIMPLE) < 0)
     412           0 :         return NULL;
     413             : 
     414           0 :     res = PyBytes_FromStringAndSize(NULL, view.len);
     415           0 :     PyBuffer_ToContiguous(PyBytes_AS_STRING(res), &view, view.len, 'C');
     416           0 :     PyBuffer_Release(&view);
     417           0 :     return res;
     418             : }
     419             : 
     420             : /* TODO: rewrite this function using the struct module to unpack
     421             :    each buffer item */
     422             : 
     423             : static PyObject *
     424           0 : memory_tolist(PyMemoryViewObject *mem, PyObject *noargs)
     425             : {
     426           0 :     Py_buffer *view = &(mem->view);
     427             :     Py_ssize_t i;
     428             :     PyObject *res, *item;
     429             :     char *buf;
     430             : 
     431           0 :     if (strcmp(view->format, "B") || view->itemsize != 1) {
     432           0 :         PyErr_SetString(PyExc_NotImplementedError, 
     433             :                 "tolist() only supports byte views");
     434           0 :         return NULL;
     435             :     }
     436           0 :     if (view->ndim != 1) {
     437           0 :         PyErr_SetString(PyExc_NotImplementedError, 
     438             :                 "tolist() only supports one-dimensional objects");
     439           0 :         return NULL;
     440             :     }
     441           0 :     res = PyList_New(view->len);
     442           0 :     if (res == NULL)
     443           0 :         return NULL;
     444           0 :     buf = view->buf;
     445           0 :     for (i = 0; i < view->len; i++) {
     446           0 :         item = PyInt_FromLong((unsigned char) *buf);
     447           0 :         if (item == NULL) {
     448           0 :             Py_DECREF(res);
     449           0 :             return NULL;
     450             :         }
     451           0 :         PyList_SET_ITEM(res, i, item);
     452           0 :         buf++;
     453             :     }
     454           0 :     return res;
     455             : }
     456             : 
     457             : static PyMethodDef memory_methods[] = {
     458             :     {"tobytes", (PyCFunction)memory_tobytes, METH_NOARGS, NULL},
     459             :     {"tolist", (PyCFunction)memory_tolist, METH_NOARGS, NULL},
     460             :     {NULL,          NULL}           /* sentinel */
     461             : };
     462             : 
     463             : 
     464             : static void
     465           0 : memory_dealloc(PyMemoryViewObject *self)
     466             : {
     467           0 :     _PyObject_GC_UNTRACK(self);
     468           0 :     if (self->view.obj != NULL) {
     469           0 :         if (self->base && PyTuple_Check(self->base)) {
     470             :             /* Special case when first element is generic object
     471             :                with buffer interface and the second element is a
     472             :                contiguous "shadow" that must be copied back into
     473             :                the data areay of the first tuple element before
     474             :                releasing the buffer on the first element.
     475             :             */
     476             : 
     477           0 :             PyObject_CopyData(PyTuple_GET_ITEM(self->base,0),
     478           0 :                               PyTuple_GET_ITEM(self->base,1));
     479             : 
     480             :             /* The view member should have readonly == -1 in
     481             :                this instance indicating that the memory can
     482             :                be "locked" and was locked and will be unlocked
     483             :                again after this call.
     484             :             */
     485           0 :             PyBuffer_Release(&(self->view));
     486             :         }
     487             :         else {
     488           0 :             PyBuffer_Release(&(self->view));
     489             :         }
     490           0 :         Py_CLEAR(self->base);
     491             :     }
     492           0 :     PyObject_GC_Del(self);
     493           0 : }
     494             : 
     495             : static PyObject *
     496           0 : memory_repr(PyMemoryViewObject *self)
     497             : {
     498           0 :     return PyString_FromFormat("<memory at %p>", self);
     499             : }
     500             : 
     501             : /* Sequence methods */
     502             : static Py_ssize_t
     503           0 : memory_length(PyMemoryViewObject *self)
     504             : {
     505           0 :     return get_shape0(&self->view);
     506             : }
     507             : 
     508             : /* Alternate version of memory_subcript that only accepts indices.
     509             :    Used by PySeqIter_New().
     510             : */
     511             : static PyObject *
     512           0 : memory_item(PyMemoryViewObject *self, Py_ssize_t result)
     513             : {
     514           0 :     Py_buffer *view = &(self->view);
     515             : 
     516           0 :     if (view->ndim == 0) {
     517           0 :         PyErr_SetString(PyExc_IndexError,
     518             :                         "invalid indexing of 0-dim memory");
     519           0 :         return NULL;
     520             :     }
     521           0 :     if (view->ndim == 1) {
     522             :         /* Return a bytes object */
     523             :         char *ptr;
     524           0 :         ptr = (char *)view->buf;
     525           0 :         if (result < 0) {
     526           0 :             result += get_shape0(view);
     527             :         }
     528           0 :         if ((result < 0) || (result >= get_shape0(view))) {
     529           0 :             PyErr_SetString(PyExc_IndexError,
     530             :                                 "index out of bounds");
     531           0 :             return NULL;
     532             :         }
     533           0 :         if (view->strides == NULL)
     534           0 :             ptr += view->itemsize * result;
     535             :         else
     536           0 :             ptr += view->strides[0] * result;
     537           0 :         if (view->suboffsets != NULL &&
     538           0 :             view->suboffsets[0] >= 0) {
     539           0 :             ptr = *((char **)ptr) + view->suboffsets[0];
     540             :         }
     541           0 :         return PyBytes_FromStringAndSize(ptr, view->itemsize);
     542             :     } else {
     543             :         /* Return a new memory-view object */
     544             :         Py_buffer newview;
     545           0 :         memset(&newview, 0, sizeof(newview));
     546             :         /* XXX:  This needs to be fixed so it actually returns a sub-view */
     547           0 :         return PyMemoryView_FromBuffer(&newview);
     548             :     }
     549             : }
     550             : 
     551             : /*
     552             :   mem[obj] returns a bytes object holding the data for one element if
     553             :            obj fully indexes the memory view or another memory-view object
     554             :            if it does not.
     555             : 
     556             :            0-d memory-view objects can be referenced using ... or () but
     557             :            not with anything else.
     558             :  */
     559             : static PyObject *
     560           0 : memory_subscript(PyMemoryViewObject *self, PyObject *key)
     561             : {
     562             :     Py_buffer *view;
     563           0 :     view = &(self->view);
     564             :     
     565           0 :     if (view->ndim == 0) {
     566           0 :         if (key == Py_Ellipsis ||
     567           0 :             (PyTuple_Check(key) && PyTuple_GET_SIZE(key)==0)) {
     568           0 :             Py_INCREF(self);
     569           0 :             return (PyObject *)self;
     570             :         }
     571             :         else {
     572           0 :             PyErr_SetString(PyExc_IndexError,
     573             :                                 "invalid indexing of 0-dim memory");
     574           0 :             return NULL;
     575             :         }
     576             :     }
     577           0 :     if (PyIndex_Check(key)) {
     578             :         Py_ssize_t result;
     579           0 :         result = PyNumber_AsSsize_t(key, NULL);
     580           0 :         if (result == -1 && PyErr_Occurred())
     581           0 :                 return NULL;
     582           0 :         return memory_item(self, result);
     583             :     }
     584           0 :     else if (PySlice_Check(key)) {
     585             :         Py_ssize_t start, stop, step, slicelength;
     586             : 
     587           0 :         if (PySlice_GetIndicesEx((PySliceObject*)key, get_shape0(view),
     588             :                                  &start, &stop, &step, &slicelength) < 0) {
     589           0 :             return NULL;
     590             :         }
     591             :     
     592           0 :         if (step == 1 && view->ndim == 1) {
     593             :             Py_buffer newview;
     594           0 :             void *newbuf = (char *) view->buf
     595           0 :                                     + start * view->itemsize;
     596           0 :             int newflags = view->readonly
     597           0 :                     ? PyBUF_CONTIG_RO : PyBUF_CONTIG;
     598             :     
     599             :             /* XXX There should be an API to create a subbuffer */
     600           0 :             if (view->obj != NULL) {
     601           0 :                 if (PyObject_GetBuffer(view->obj, &newview, newflags) == -1)
     602           0 :                     return NULL;
     603             :             }
     604             :             else {
     605           0 :                 newview = *view;
     606             :             }
     607           0 :             newview.buf = newbuf;
     608           0 :             newview.len = slicelength * newview.itemsize;
     609           0 :             newview.format = view->format;
     610           0 :             newview.shape = &(newview.smalltable[0]);
     611           0 :             newview.shape[0] = slicelength;
     612           0 :             newview.strides = &(newview.itemsize);
     613           0 :             return PyMemoryView_FromBuffer(&newview);
     614             :         }
     615           0 :         PyErr_SetNone(PyExc_NotImplementedError);
     616           0 :         return NULL;
     617             :     }
     618           0 :     PyErr_Format(PyExc_TypeError,
     619             :         "cannot index memory using \"%.200s\"", 
     620           0 :         key->ob_type->tp_name);
     621           0 :     return NULL;
     622             : }
     623             : 
     624             : 
     625             : /* Need to support assigning memory if we can */
     626             : static int
     627           0 : memory_ass_sub(PyMemoryViewObject *self, PyObject *key, PyObject *value)
     628             : {
     629             :     Py_ssize_t start, len, bytelen;
     630             :     Py_buffer srcview;
     631           0 :     Py_buffer *view = &(self->view);
     632             :     char *srcbuf, *destbuf;
     633             : 
     634           0 :     if (view->readonly) {
     635           0 :         PyErr_SetString(PyExc_TypeError,
     636             :             "cannot modify read-only memory");
     637           0 :         return -1;
     638             :     }
     639           0 :     if (value == NULL) {
     640           0 :         PyErr_SetString(PyExc_TypeError,
     641             :                         "cannot delete memory");
     642           0 :         return -1;
     643             :     }
     644           0 :     if (view->ndim != 1) {
     645           0 :         PyErr_SetNone(PyExc_NotImplementedError);
     646           0 :         return -1;
     647             :     }
     648           0 :     if (PyIndex_Check(key)) {
     649           0 :         start = PyNumber_AsSsize_t(key, NULL);
     650           0 :         if (start == -1 && PyErr_Occurred())
     651           0 :             return -1;
     652           0 :         if (start < 0) {
     653           0 :             start += get_shape0(view);
     654             :         }
     655           0 :         if ((start < 0) || (start >= get_shape0(view))) {
     656           0 :             PyErr_SetString(PyExc_IndexError,
     657             :                             "index out of bounds");
     658           0 :             return -1;
     659             :         }
     660           0 :         len = 1;
     661             :     }
     662           0 :     else if (PySlice_Check(key)) {
     663             :         Py_ssize_t stop, step;
     664             : 
     665           0 :         if (PySlice_GetIndicesEx((PySliceObject*)key, get_shape0(view),
     666             :                          &start, &stop, &step, &len) < 0) {
     667           0 :             return -1;
     668             :         }
     669           0 :         if (step != 1) {
     670           0 :             PyErr_SetNone(PyExc_NotImplementedError);
     671           0 :             return -1;
     672             :         }
     673             :     }
     674             :     else {
     675           0 :         PyErr_Format(PyExc_TypeError,
     676             :             "cannot index memory using \"%.200s\"", 
     677           0 :             key->ob_type->tp_name);
     678           0 :         return -1;
     679             :     }
     680           0 :     if (PyObject_GetBuffer(value, &srcview, PyBUF_CONTIG_RO) == -1) {
     681           0 :         return -1;
     682             :     }
     683             :     /* XXX should we allow assignment of different item sizes
     684             :        as long as the byte length is the same?
     685             :        (e.g. assign 2 shorts to a 4-byte slice) */
     686           0 :     if (srcview.itemsize != view->itemsize) {
     687           0 :         PyErr_Format(PyExc_TypeError,
     688             :             "mismatching item sizes for \"%.200s\" and \"%.200s\"", 
     689           0 :             view->obj->ob_type->tp_name, srcview.obj->ob_type->tp_name);
     690           0 :         goto _error;
     691             :     }
     692           0 :     bytelen = len * view->itemsize;
     693           0 :     if (bytelen != srcview.len) {
     694           0 :         PyErr_SetString(PyExc_ValueError,
     695             :             "cannot modify size of memoryview object");
     696           0 :         goto _error;
     697             :     }
     698             :     /* Do the actual copy */
     699           0 :     destbuf = (char *) view->buf + start * view->itemsize;
     700           0 :     srcbuf = (char *) srcview.buf;
     701           0 :     if (destbuf + bytelen < srcbuf || srcbuf + bytelen < destbuf)
     702             :         /* No overlapping */
     703           0 :         memcpy(destbuf, srcbuf, bytelen);
     704             :     else
     705           0 :         memmove(destbuf, srcbuf, bytelen);
     706             : 
     707           0 :     PyBuffer_Release(&srcview);
     708           0 :     return 0;
     709             : 
     710             : _error:
     711           0 :     PyBuffer_Release(&srcview);
     712           0 :     return -1;
     713             : }
     714             : 
     715             : static PyObject *
     716           0 : memory_richcompare(PyObject *v, PyObject *w, int op)
     717             : {
     718             :     Py_buffer vv, ww;
     719           0 :     int equal = 0;
     720             :     PyObject *res;
     721             : 
     722           0 :     vv.obj = NULL;
     723           0 :     ww.obj = NULL;
     724           0 :     if (op != Py_EQ && op != Py_NE)
     725           0 :         goto _notimpl;
     726           0 :     if (PyObject_GetBuffer(v, &vv, PyBUF_CONTIG_RO) == -1) {
     727           0 :         PyErr_Clear();
     728           0 :         goto _notimpl;
     729             :     }
     730           0 :     if (PyObject_GetBuffer(w, &ww, PyBUF_CONTIG_RO) == -1) {
     731           0 :         PyErr_Clear();
     732           0 :         goto _notimpl;
     733             :     }
     734             : 
     735           0 :     if (vv.itemsize != ww.itemsize || vv.len != ww.len)
     736             :         goto _end;
     737             : 
     738           0 :     equal = !memcmp(vv.buf, ww.buf, vv.len);
     739             : 
     740             : _end:
     741           0 :     PyBuffer_Release(&vv);
     742           0 :     PyBuffer_Release(&ww);
     743           0 :     if ((equal && op == Py_EQ) || (!equal && op == Py_NE))
     744           0 :         res = Py_True;
     745             :     else
     746           0 :         res = Py_False;
     747           0 :     Py_INCREF(res);
     748           0 :     return res;
     749             : 
     750             : _notimpl:
     751           0 :     PyBuffer_Release(&vv);
     752           0 :     PyBuffer_Release(&ww);
     753           0 :     Py_INCREF(Py_NotImplemented);
     754           0 :     return Py_NotImplemented;
     755             : }
     756             : 
     757             : 
     758             : static int
     759           0 : memory_traverse(PyMemoryViewObject *self, visitproc visit, void *arg)
     760             : {
     761           0 :     if (self->base != NULL)
     762           0 :         Py_VISIT(self->base);
     763           0 :     if (self->view.obj != NULL)
     764           0 :         Py_VISIT(self->view.obj);
     765           0 :     return 0;
     766             : }
     767             : 
     768             : static int
     769           0 : memory_clear(PyMemoryViewObject *self)
     770             : {
     771           0 :     Py_CLEAR(self->base);
     772           0 :     PyBuffer_Release(&self->view);
     773           0 :     return 0;
     774             : }
     775             : 
     776             : 
     777             : /* As mapping */
     778             : static PyMappingMethods memory_as_mapping = {
     779             :     (lenfunc)memory_length,               /* mp_length */
     780             :     (binaryfunc)memory_subscript,         /* mp_subscript */
     781             :     (objobjargproc)memory_ass_sub,        /* mp_ass_subscript */
     782             : };
     783             : 
     784             : static PySequenceMethods memory_as_sequence = {
     785             :         0,                                  /* sq_length */
     786             :         0,                                  /* sq_concat */
     787             :         0,                                  /* sq_repeat */
     788             :         (ssizeargfunc)memory_item,          /* sq_item */
     789             : };
     790             : 
     791             : /* Buffer methods */
     792             : static PyBufferProcs memory_as_buffer = {
     793             :     0,                                    /* bf_getreadbuffer */
     794             :     0,                                    /* bf_getwritebuffer */
     795             :     0,                                    /* bf_getsegcount */
     796             :     0,                                    /* bf_getcharbuffer */
     797             :     (getbufferproc)memory_getbuf,         /* bf_getbuffer */
     798             :     (releasebufferproc)memory_releasebuf, /* bf_releasebuffer */
     799             : };
     800             : 
     801             : 
     802             : PyTypeObject PyMemoryView_Type = {
     803             :     PyVarObject_HEAD_INIT(&PyType_Type, 0)
     804             :     "memoryview",
     805             :     sizeof(PyMemoryViewObject),
     806             :     0,
     807             :     (destructor)memory_dealloc,               /* tp_dealloc */
     808             :     0,                                        /* tp_print */
     809             :     0,                                        /* tp_getattr */
     810             :     0,                                        /* tp_setattr */
     811             :     0,                                        /* tp_compare */
     812             :     (reprfunc)memory_repr,                    /* tp_repr */
     813             :     0,                                        /* tp_as_number */
     814             :     &memory_as_sequence,                      /* tp_as_sequence */
     815             :     &memory_as_mapping,                       /* tp_as_mapping */
     816             :     0,                                        /* tp_hash */
     817             :     0,                                        /* tp_call */
     818             :     0,                                        /* tp_str */
     819             :     PyObject_GenericGetAttr,                  /* tp_getattro */
     820             :     0,                                        /* tp_setattro */
     821             :     &memory_as_buffer,                        /* tp_as_buffer */
     822             :     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
     823             :         Py_TPFLAGS_HAVE_NEWBUFFER,            /* tp_flags */
     824             :     memory_doc,                               /* tp_doc */
     825             :     (traverseproc)memory_traverse,            /* tp_traverse */
     826             :     (inquiry)memory_clear,                    /* tp_clear */
     827             :     memory_richcompare,                       /* tp_richcompare */
     828             :     0,                                        /* tp_weaklistoffset */
     829             :     0,                                        /* tp_iter */
     830             :     0,                                        /* tp_iternext */
     831             :     memory_methods,                           /* tp_methods */
     832             :     0,                                        /* tp_members */
     833             :     memory_getsetlist,                        /* tp_getset */
     834             :     0,                                        /* tp_base */
     835             :     0,                                        /* tp_dict */
     836             :     0,                                        /* tp_descr_get */
     837             :     0,                                        /* tp_descr_set */
     838             :     0,                                        /* tp_dictoffset */
     839             :     0,                                        /* tp_init */
     840             :     0,                                        /* tp_alloc */
     841             :     memory_new,                               /* tp_new */
     842             : };

Generated by: LCOV version 1.10