Author: Armin Rigo <[email protected]>
Branch: py3k
Changeset: r86590:fbf9c57aa038
Date: 2016-08-27 09:46 +0200
http://bitbucket.org/pypy/pypy/changeset/fbf9c57aa038/

Log:    Backport memoryview.cast(), fix getitem

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
@@ -17,6 +17,7 @@
     """Implement the built-in 'memoryview' type as a wrapper around
     an interp-level buffer.
     """
+    _immutable_fields_ = ['format', 'itemsize']
 
     def __init__(self, buf, format='B', itemsize=1):
         assert isinstance(buf, Buffer)
@@ -62,8 +63,7 @@
 
     def as_str(self):
         buf = self.buf
-        n_bytes = buf.getlength()
-        return buf.getslice(0, n_bytes, 1, n_bytes)
+        return buf.as_str()
 
     def getlength(self):
         return self.buf.getlength() // self.itemsize
@@ -82,27 +82,24 @@
     def descr_getitem(self, space, w_index):
         self._check_released(space)
         start, stop, step, size = space.decode_index4(w_index, 
self.getlength())
-        itemsize = self.buf.getitemsize()
-        if itemsize > 1:
-            start *= itemsize
-            size *= itemsize
-            stop  = start + size
-            if step == 0:
-                step = 1
-            if stop > self.getlength():
-                raise oefmt(space.w_IndexError, 'index out of range')
+        # ^^^ for a non-slice index, this returns (index, 0, 0, 1)
+        itemsize = self.itemsize
         if step == 0:  # index only
-            # TODO: this probably isn't very fast
-            buf = SubBuffer(self.buf, start, self.itemsize)
-            fmtiter = UnpackFormatIterator(space, buf)
-            fmtiter.interpret(self.format)
-            return fmtiter.result_w[0]
+            if itemsize == 1:
+                ch = self.buf.getitem(start)
+                return space.newint(ord(ch))
+            else:
+                # TODO: this probably isn't very fast
+                buf = SubBuffer(self.buf, start * itemsize, itemsize)
+                fmtiter = UnpackFormatIterator(space, buf)
+                fmtiter.interpret(self.format)
+                return fmtiter.result_w[0]
         elif step == 1:
-            buf = SubBuffer(self.buf, start, size)
-            return W_MemoryView(buf, self.format, self.itemsize)
+            buf = SubBuffer(self.buf, start * itemsize, size * itemsize)
+            return W_MemoryView(buf, self.format, itemsize)
         else:
-            buf = SubBuffer(self.buf, start, size)
-            return W_MemoryView(buf)
+            raise oefmt(space.w_NotImplementedError,
+                        "XXX extended slicing")
 
     def descr_setitem(self, space, w_index, w_obj):
         self._check_released(space)
@@ -141,7 +138,7 @@
 
     def descr_len(self, space):
         self._check_released(space)
-        return space.wrap(self.buf.getlength())
+        return space.wrap(self.getlength())
 
     def w_get_format(self, space):
         self._check_released(space)
@@ -214,6 +211,44 @@
             raise OperationError(space.w_ValueError, space.wrap(msg))
         return space.wrap(rffi.cast(lltype.Signed, ptr))
 
+    def get_native_fmtchar(self, fmt):
+        from rpython.rtyper.lltypesystem import rffi
+        size = -1
+        if fmt[0] == '@':
+            f = fmt[1]
+        else:
+            f = fmt[0]
+        if f == 'c' or f == 'b' or f == 'B':
+            size = rffi.sizeof(rffi.CHAR)
+        elif f == 'h' or f == 'H':
+            size = rffi.sizeof(rffi.SHORT)
+        elif f == 'i' or f == 'I':
+            size = rffi.sizeof(rffi.INT)
+        elif f == 'l' or f == 'L':
+            size = rffi.sizeof(rffi.LONG)
+        elif f == 'q' or f == 'Q':
+            size = rffi.sizeof(rffi.LONGLONG)
+        elif f == 'n' or f == 'N':
+            size = rffi.sizeof(rffi.SIZE_T)
+        elif f == 'f':
+            size = rffi.sizeof(rffi.FLOAT)
+        elif f == 'd':
+            size = rffi.sizeof(rffi.DOUBLE)
+        elif f == '?':
+            size = rffi.sizeof(rffi.CHAR)
+        elif f == 'P':
+            size = rffi.sizeof(rffi.VOIDP)
+        return size
+
+    def descr_cast(self, space, w_format, w_shape=None):
+        self._check_released(space)
+        if not space.is_none(w_shape):
+            raise oefmt(space.w_NotImplementedError,
+                        "XXX cast() with a shape")
+        fmt = space.str_w(w_format)
+        newitemsize = self.get_native_fmtchar(fmt)
+        return W_MemoryView(self.buf, fmt, newitemsize)
+
 W_MemoryView.typedef = TypeDef(
     "memoryview",
     __doc__ = """\
@@ -230,6 +265,7 @@
     __enter__   = interp2app(W_MemoryView.descr_enter),
     __exit__    = interp2app(W_MemoryView.descr_exit),
     __weakref__ = make_weakref_descr(W_MemoryView),
+    cast        = interp2app(W_MemoryView.descr_cast),
     tobytes     = interp2app(W_MemoryView.descr_tobytes),
     tolist      = interp2app(W_MemoryView.descr_tolist),
     release     = interp2app(W_MemoryView.descr_release),
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
@@ -16,8 +16,6 @@
         w = v[1:234]
         assert isinstance(w, memoryview)
         assert len(w) == 2
-        exc = raises(NotImplementedError, "v[0:2:2]")
-        assert str(exc.value) == ""
 
     def test_rw(self):
         data = bytearray(b'abcefg')
@@ -31,8 +29,15 @@
         assert data == bytearray(eval("b'23f3fg'"))
         exc = raises(ValueError, "v[2:3] = b'spam'")
         assert str(exc.value) == "cannot modify size of memoryview object"
-        exc = raises(NotImplementedError, "v[0:2:2] = b'spam'")
-        assert str(exc.value) == ""
+
+    def test_extended_slice(self):
+        data = bytearray(b'abcefg')
+        v = memoryview(data)
+        w = v[0:2:2]      # failing for now: NotImplementedError
+        assert len(w) == 1
+        assert list(w) == [97]
+        v[::2] = b'ABC'
+        assert data == bytearray(b'AbBeCg')
 
     def test_memoryview_attrs(self):
         v = memoryview(b"a"*100)
@@ -161,3 +166,33 @@
         raises(ValueError, memoryview(b"foobar")._pypy_raw_address)
         a = memoryview(bytearray(b"foobar"))._pypy_raw_address()
         assert a != 0
+
+    def test_memoryview_cast(self):
+        m1 = memoryview(b'abcdefgh')
+        m2 = m1.cast('I')
+        m3 = m1.cast('h')
+        assert list(m1) == [97, 98, 99, 100, 101, 102, 103, 104]
+        assert list(m2) == [1684234849, 1751606885]
+        assert list(m3) == [25185, 25699, 26213, 26727]
+        assert m1[1] == 98
+        assert m2[1] == 1751606885
+        assert m3[1] == 25699
+        assert list(m3[1:3]) == [25699, 26213]
+        assert m3[1:3].tobytes() == b'cdef'
+        assert len(m2) == 2
+        assert len(m3) == 4
+        assert (m2[-2], m2[-1]) == (1684234849, 1751606885)
+        raises(IndexError, "m2[2]")
+        raises(IndexError, "m2[-3]")
+        assert list(m3[-99:3]) == [25185, 25699, 26213]
+        assert list(m3[1:99]) == [25699, 26213, 26727]
+        raises(IndexError, "m1[8]")
+        raises(IndexError, "m1[-9]")
+        assert m1[-8] == 97
+
+    def test_memoryview_cast_extended_slicing(self):
+        m1 = memoryview(b'abcdefgh')
+        m3 = m1.cast('h')
+        assert m3[1::2].tobytes() == b'cdgh'
+        assert m3[::2].tobytes() == b'abef'
+        assert m3[:2:2].tobytes() == b'ab'
diff --git a/rpython/rlib/buffer.py b/rpython/rlib/buffer.py
--- a/rpython/rlib/buffer.py
+++ b/rpython/rlib/buffer.py
@@ -10,6 +10,7 @@
     _immutable_ = True
 
     def getlength(self):
+        """Returns the size in bytes (even if getitemsize() > 1)."""
         raise NotImplementedError
 
     def __len__(self):
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to