Author: Richard Plangger <planri...@gmail.com> Branch: py3.5 Changeset: r89540:4cada5dbc4cd Date: 2017-01-13 13:10 +0100 http://bitbucket.org/pypy/pypy/changeset/4cada5dbc4cd/
Log: new test case (reverse buffer type i), copy over flag checking from cpyext and adapt the code there. changes needed to properly setup the memoryview flags diff --git a/pypy/module/cpyext/memoryobject.py b/pypy/module/cpyext/memoryobject.py --- a/pypy/module/cpyext/memoryobject.py +++ b/pypy/module/cpyext/memoryobject.py @@ -8,7 +8,7 @@ from rpython.rtyper.lltypesystem import lltype, rffi from rpython.rlib.rarithmetic import widen from pypy.interpreter.error import oefmt -from pypy.objspace.std.memoryobject import W_MemoryView +from pypy.objspace.std.memoryobject import W_MemoryView, _pybuffer_iscontiguous from pypy.module.cpyext.object import _dealloc from pypy.module.cpyext.import_ import PyImport_Import @@ -164,41 +164,8 @@ view.c_internal = lltype.nullptr(rffi.VOIDP.TO) return 0 -def _IsFortranContiguous(view): - ndim = widen(view.c_ndim) - if ndim == 0: - return 1 - if not view.c_strides: - return ndim == 1 - sd = view.c_itemsize - if ndim == 1: - return view.c_shape[0] == 1 or sd == view.c_strides[0] - for i in range(view.c_ndim): - dim = view.c_shape[i] - if dim == 0: - return 1 - if view.c_strides[i] != sd: - return 0 - sd *= dim - return 1 - -def _IsCContiguous(view): - ndim = widen(view.c_ndim) - if ndim == 0: - return 1 - if not view.c_strides: - return ndim == 1 - sd = view.c_itemsize - if ndim == 1: - return view.c_shape[0] == 1 or sd == view.c_strides[0] - for i in range(ndim - 1, -1, -1): - dim = view.c_shape[i] - if dim == 0: - return 1 - if view.c_strides[i] != sd: - return 0 - sd *= dim - return 1 +# If you are looking for _IsFortran/CContiguous look in +# pypy/module/cpyext/memoryobject.py @cpython_api([Py_bufferP, lltype.Char], rffi.INT_real, error=CANNOT_FAIL) def PyBuffer_IsContiguous(space, view, fort): @@ -207,15 +174,13 @@ (fort is 'A'). Return 0 otherwise.""" # traverse the strides, checking for consistent stride increases from # right-to-left (c) or left-to-right (fortran). Copied from cpython - if view.c_suboffsets: - return 0 - if (fort == 'C'): - return _IsCContiguous(view) - elif (fort == 'F'): - return _IsFortranContiguous(view) - elif (fort == 'A'): - return (_IsCContiguous(view) or _IsFortranContiguous(view)) - return 0 + + # plan_rich: I wanted to reuse this check in pypy/objspace/std/... + # memoryview.py, thus I have rewritten it, maybe it is time to + # find a way to share this code? + return _pybuffer_iscontiguous(view.c_suboffsets, + widen(view.c_ndim), view.c_shape, view.c_strides, + view.c_itemsize, fort) @cpython_api([PyObject], PyObject, result_is_ll=True) def PyMemoryView_FromObject(space, w_obj): diff --git a/pypy/objspace/std/memoryobject.py b/pypy/objspace/std/memoryobject.py --- a/pypy/objspace/std/memoryobject.py +++ b/pypy/objspace/std/memoryobject.py @@ -13,6 +13,7 @@ from pypy.module.struct.formatiterator import UnpackFormatIterator, PackFormatIterator from pypy.objspace.std.bytesobject import getbytevalue from rpython.rlib.unroll import unrolling_iterable +from rpython.rlib.objectmodel import always_inline MEMORYVIEW_MAX_DIM = 64 MEMORYVIEW_SCALAR = 0x0001 @@ -571,19 +572,26 @@ flags = 0 if ndim == 0: flags |= MEMORYVIEW_SCALAR | MEMORYVIEW_C | MEMORYVIEW_FORTRAN - if ndim == 1: - shape = buf.getshape() - strides = buf.getstrides() - if len(shape) > 0 and shape[0] == 1 and \ - len(strides) > 0 and strides[0] == buf.getitemsize(): + elif ndim == 1: + shape = self.getshape() + strides = self.getstrides() + if shape[0] == 1 or strides[0] == self.getitemsize(): flags |= MEMORYVIEW_C | MEMORYVIEW_SCALAR - # TODO for now? - flags |= MEMORYVIEW_C - # TODO if buf.is_contiguous('C'): - # TODO flags |= MEMORYVIEW_C - # TODO elif buf.is_contiguous('F'): - # TODO flags |= MEMORYVIEW_FORTRAN + else: + ndim = self.getndim() + shape = self.getshape() + strides = self.getstrides() + itemsize = self.getitemsize() + if _pybuffer_iscontiguous(None, ndim, shape, strides, + itemsize, 'C'): + flags |= MEMORYVIEW_C + if _pybuffer_iscontiguous(None, ndim, shape, strides, + itemsize, 'F'): + flags |= MEMORYVIEW_C + if self.suboffsets: + flags |= MEMORYVIEW_PIL + flags &= ~(MEMORYVIEW_C|MEMORYVIEW_FORTRAN) # TODO missing suboffsets self.flags = flags @@ -675,19 +683,17 @@ def descr_hex(self, space): from pypy.objspace.std.bytearrayobject import _array_to_hexstring self._check_released(space) - if isinstance(self.buf, SubBuffer): - step = self.strides[0] - return _array_to_hexstring(space, self.buf.buffer, - self.buf.offset, step, - self.getlength()) + if memory_view_c_contiguous(space, self.flags): + return _array_to_hexstring(space, self.buf, 0, 1, self.getlength()) else: - return _array_to_hexstring(space, self.buf, 0, 1, self.getlength()) + bytes = self.as_str() + return _array_to_hexstring(space, bytes, 0, 1, len(bytes), True) def is_byte_format(char): return char == 'b' or char == 'B' or char == 'c' def memory_view_c_contiguous(space, flags): - return flags & (space.BUF_CONTIG_RO|MEMORYVIEW_C) != 0 + return flags & (MEMORYVIEW_SCALAR|MEMORYVIEW_C) W_MemoryView.typedef = TypeDef( "memoryview", @@ -721,3 +727,51 @@ _pypy_raw_address = interp2app(W_MemoryView.descr_pypy_raw_address), ) W_MemoryView.typedef.acceptable_as_base_class = False + +def _IsFortranContiguous(ndim, shape, strides, itemsize): + if ndim == 0: + return 1 + if not strides: + return ndim == 1 + sd = itemsize + if ndim == 1: + return shape[0] == 1 or sd == strides[0] + for i in range(ndim): + dim = shape[i] + if dim == 0: + return 1 + if strides[i] != sd: + return 0 + sd *= dim + return 1 + +def _IsCContiguous(ndim, shape, strides, itemsize): + if ndim == 0: + return 1 + if not strides: + return ndim == 1 + sd = itemsize + if ndim == 1: + return shape[0] == 1 or sd == strides[0] + for i in range(ndim - 1, -1, -1): + dim = shape[i] + if dim == 0: + return 1 + if strides[i] != sd: + return 0 + sd *= dim + return 1 + +@always_inline +def _pybuffer_iscontiguous(suboffsets, ndim, shape, strides, itemsize, fort): + if suboffsets: + return 0 + if (fort == 'C'): + return _IsCContiguous(ndim, shape, strides, itemsize) + elif (fort == 'F'): + return _IsFortranContiguous(ndim, shape, strides, itemsize) + elif (fort == 'A'): + return (_IsCContiguous(ndim, shape, strides, itemsize) or \ + _IsFortranContiguous(ndim, shape, strides, itemsize)) + return 0 + diff --git a/pypy/objspace/std/test/test_memoryobject.py b/pypy/objspace/std/test/test_memoryobject.py --- a/pypy/objspace/std/test/test_memoryobject.py +++ b/pypy/objspace/std/test/test_memoryobject.py @@ -8,7 +8,7 @@ from pypy.conftest import option class AppTestMemoryView: - spaceconfig = dict(usemodules=['array']) + spaceconfig = dict(usemodules=['array', 'sys']) def test_basic(self): v = memoryview(b"abc") @@ -199,6 +199,16 @@ m2 = m1[::-1] assert m2.hex() == '3130' * 100000 + def test_hex_2(self): + import array + import sys + m1 = memoryview(array.array('i', [1,2,3,4])) + m2 = m1[::-1] + if sys.byteorder == 'little': + assert m2.hex() == "04000000030000000200000001000000" + else: + assert m2.hex() == "00000004000000030000000200000001" + def test_memoryview_cast(self): m1 = memoryview(b'abcdefgh') m2 = m1.cast('I') @@ -391,7 +401,10 @@ assert view.format == 'b' assert cview.format == 'i' # - assert cview.cast('b').cast('q').cast('b').tolist() == [] + a = cview.cast('b') + b = a.cast('q') + c = b.cast('b') + assert c.tolist() == [] # assert cview.format == 'i' raises(TypeError, "cview.cast('i')") @@ -399,7 +412,7 @@ def test_cast_with_shape(self): empty = self.MockArray([1,0,2,0,3,0], dim=1, fmt='h', size=2, - strides=[8], shape=[6]) + strides=[2], shape=[6]) view = memoryview(empty) byteview = view.cast('b') assert byteview.tolist() == [1,0,0,0,2,0,0,0,3,0,0,0] _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit