Index: Include/pythonrun.h =================================================================== --- Include/pythonrun.h (revision 85878) +++ Include/pythonrun.h (working copy) @@ -150,6 +150,7 @@ PyAPI_FUNC(void) PyFloat_Fini(void); PyAPI_FUNC(void) PyOS_FiniInterrupts(void); PyAPI_FUNC(void) _PyGC_Fini(void); +PyAPI_FUNC(void) PySlice_Fini(); /* Stuff with no proper home (yet) */ PyAPI_FUNC(char *) PyOS_Readline(FILE *, FILE *, char *); Index: Objects/memoryobject.c =================================================================== --- Objects/memoryobject.c (revision 85878) +++ Objects/memoryobject.c (working copy) @@ -118,6 +118,54 @@ } static PyObject * +_PyMemoryView_FromMemoryViewAndSlice(PyMemoryViewObject *base, PyObject *slice) +{ + Py_ssize_t start, stop, step, slicelength; + PyMemoryViewObject *mview; + + if (PySlice_GetIndicesEx((PySliceObject*)slice, base->view.shape[0], + &start, &stop, &step, &slicelength) < 0) { + return NULL; + } + + if (step != 1 || base->view.ndim != 1) { + //Only support simple slices of 1-dimensional objects + PyErr_SetNone(PyExc_NotImplementedError); + return NULL; + } + + mview = (PyMemoryViewObject *) + PyObject_GC_New(PyMemoryViewObject, &PyMemoryView_Type); + if (mview == NULL) + return NULL; + + mview->base = NULL; /* is this ever used? */ + mview->view.obj = NULL; + if (base->view.obj != NULL) { + int newflags = base->view.readonly ? + PyBUF_CONTIG_RO : PyBUF_CONTIG; + if (PyObject_GetBuffer(base->view.obj, &mview->view, newflags)) { + Py_DECREF(mview); + return NULL; + } + } else { + dup_buffer(&mview->view, &base->view); + } + /* now, assume that the new Py_buffer points to the same range as + * the earlier one, and also that it is ok to modify the "buf" + * returned by the buf_getbuffer slot (that buf_releasebuffer won't + * need it later + */ + mview->view.buf = (char *) base->view.buf + + start * base->view.itemsize; + mview->view.len = slicelength * mview->view.itemsize; + mview->view.shape[0] = slicelength; + + _PyObject_GC_TRACK(mview); + return (PyObject *)mview; +} + +static PyObject * memory_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds) { PyObject *obj; @@ -636,38 +684,7 @@ return memory_item(self, result); } else if (PySlice_Check(key)) { - Py_ssize_t start, stop, step, slicelength; - - if (PySlice_GetIndicesEx((PySliceObject*)key, get_shape0(view), - &start, &stop, &step, &slicelength) < 0) { - return NULL; - } - - if (step == 1 && view->ndim == 1) { - Py_buffer newview; - void *newbuf = (char *) view->buf - + start * view->itemsize; - int newflags = view->readonly - ? PyBUF_CONTIG_RO : PyBUF_CONTIG; - - /* XXX There should be an API to create a subbuffer */ - if (view->obj != NULL) { - if (PyObject_GetBuffer(view->obj, &newview, newflags) == -1) - return NULL; - } - else { - newview = *view; - } - newview.buf = newbuf; - newview.len = slicelength * newview.itemsize; - newview.format = view->format; - newview.shape = &(newview.smalltable[0]); - newview.shape[0] = slicelength; - newview.strides = &(newview.itemsize); - return PyMemoryView_FromBuffer(&newview); - } - PyErr_SetNone(PyExc_NotImplementedError); - return NULL; + return _PyMemoryView_FromMemoryViewAndSlice(self, key); } PyErr_Format(PyExc_TypeError, "cannot index memory using \"%.200s\"", Index: Objects/sliceobject.c =================================================================== --- Objects/sliceobject.c (revision 85878) +++ Objects/sliceobject.c (working copy) @@ -51,20 +51,35 @@ }; -/* Slice object implementation +/* Slice object implementation */ - start, stop, and step are python objects with None indicating no +/* Using a cache is very effective since typically only a single slice is + * created and then deleted again + */ +static PySliceObject *slice_cache = NULL; +void PySlice_Fini() +{ + Py_CLEAR(slice_cache); +} + +/* start, stop, and step are python objects with None indicating no index is present. */ PyObject * PySlice_New(PyObject *start, PyObject *stop, PyObject *step) { - PySliceObject *obj = PyObject_New(PySliceObject, &PySlice_Type); + PySliceObject *obj; + if (slice_cache != NULL) { + obj = slice_cache; + slice_cache = NULL; + PyObject_INIT(obj, &PySlice_Type); + } else { + obj = PyObject_New(PySliceObject, &PySlice_Type); + if (obj == NULL) + return NULL; + } - if (obj == NULL) - return NULL; - if (step == NULL) step = Py_None; Py_INCREF(step); if (start == NULL) start = Py_None; @@ -131,19 +146,20 @@ int PySlice_GetIndicesEx(PySliceObject *r, Py_ssize_t length, - Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t *step, - Py_ssize_t *slicelength) + Py_ssize_t *_start, Py_ssize_t *_stop, Py_ssize_t *_step, + Py_ssize_t *_slicelength) { /* this is harder to get right than you might think */ - Py_ssize_t defstart, defstop; + /* work with locals so that optimization isn't hindered by aliasing concerns */ + Py_ssize_t start, stop, step, astep, slicelength; if (r->step == Py_None) { - *step = 1; + step = 1; } else { - if (!_PyEval_SliceIndex(r->step, step)) return -1; - if (*step == 0) { + if (!_PyEval_SliceIndex(r->step, &step)) return -1; + if (step == 0) { PyErr_SetString(PyExc_ValueError, "slice step cannot be zero"); return -1; @@ -153,46 +169,49 @@ * guards against later undefined behaviour resulting from code that * does "step = -step" as part of a slice reversal. */ - if (*step < -PY_SSIZE_T_MAX) - *step = -PY_SSIZE_T_MAX; + if (step < -PY_SSIZE_T_MAX) + step = -PY_SSIZE_T_MAX; } - defstart = *step < 0 ? length-1 : 0; - defstop = *step < 0 ? -1 : length; - if (r->start == Py_None) { - *start = defstart; + start = step < 0 ? length-1 : 0; } else { - if (!_PyEval_SliceIndex(r->start, start)) return -1; - if (*start < 0) *start += length; - if (*start < 0) *start = (*step < 0) ? -1 : 0; - if (*start >= length) - *start = (*step < 0) ? length - 1 : length; + if (!_PyEval_SliceIndex(r->start, &start)) return -1; + if (start < 0) start += length; + if (start < 0) start = (step < 0) ? -1 : 0; + if (start >= length) + start = (step < 0) ? length - 1 : length; } if (r->stop == Py_None) { - *stop = defstop; + stop = step < 0 ? -1 : length; } else { - if (!_PyEval_SliceIndex(r->stop, stop)) return -1; - if (*stop < 0) *stop += length; - if (*stop < 0) *stop = (*step < 0) ? -1 : 0; - if (*stop >= length) - *stop = (*step < 0) ? length - 1 : length; + if (!_PyEval_SliceIndex(r->stop, &stop)) return -1; + if (stop < 0) stop += length; + if (stop < 0) stop = (step < 0) ? -1 : 0; + if (stop >= length) + stop = (step < 0) ? length - 1 : length; } - if ((*step < 0 && *stop >= *start) - || (*step > 0 && *start >= *stop)) { - *slicelength = 0; + if (step > 0) { + slicelength = stop - start; + astep = step; + } else { + slicelength = start - stop; + astep = -step; } - else if (*step < 0) { - *slicelength = (*stop-*start+1)/(*step)+1; - } - else { - *slicelength = (*stop-*start-1)/(*step)+1; - } + if (slicelength < 0) + slicelength = 0; + else if (astep != 1) + slicelength = (slicelength-1)/astep+1; + *_start = start; + *_stop = stop; + *_step = step; + *_slicelength = slicelength; + return 0; } @@ -229,7 +248,10 @@ Py_DECREF(r->step); Py_DECREF(r->start); Py_DECREF(r->stop); - PyObject_Del(r); + if (slice_cache == NULL) + slice_cache = r; + else + PyObject_Del(r); } static PyObject * Index: Python/pythonrun.c =================================================================== --- Python/pythonrun.c (revision 85878) +++ Python/pythonrun.c (working copy) @@ -503,6 +503,7 @@ PyLong_Fini(); PyFloat_Fini(); PyDict_Fini(); + PySlice_Fini(); /* Cleanup Unicode implementation */ _PyUnicode_Fini();