[pypy-commit] pypy faster-rstruct-2: add a new Buffer.typed_read method, which does the same as the current strstorage.py: the idea is that this will be implemented by all Buffer subclasses for which it makes sense (e.g. ByteArrayBuffer can use the same gc_load_indexed approach as StringBuffer; and raw buffers should be able to use raw_load or similar). Copy the logic and the tests from strstorage.py, which will be deleted later

antocuni pypy.commits at gmail.com
Wed May 3 13:10:57 EDT 2017


Author: Antonio Cuni <anto.cuni at gmail.com>
Branch: faster-rstruct-2
Changeset: r91177:19988cc7db57
Date: 2017-05-03 19:06 +0200
http://bitbucket.org/pypy/pypy/changeset/19988cc7db57/

Log:	add a new Buffer.typed_read method, which does the same as the
	current strstorage.py: the idea is that this will be implemented by
	all Buffer subclasses for which it makes sense (e.g. ByteArrayBuffer
	can use the same gc_load_indexed approach as StringBuffer; and raw
	buffers should be able to use raw_load or similar). Copy the logic
	and the tests from strstorage.py, which will be deleted later

diff --git a/rpython/rlib/buffer.py b/rpython/rlib/buffer.py
--- a/rpython/rlib/buffer.py
+++ b/rpython/rlib/buffer.py
@@ -1,11 +1,23 @@
 """
 Buffer protocol support.
 """
+from rpython.rtyper.lltypesystem import lltype, llmemory
+from rpython.rtyper.lltypesystem.lloperation import llop
+from rpython.rtyper.lltypesystem.rstr import STR
+from rpython.rtyper.annlowlevel import llstr
+from rpython.rlib.objectmodel import specialize
 from rpython.rlib import jit
 from rpython.rlib.rgc import (resizable_list_supporting_raw_ptr,
         nonmoving_raw_ptr_for_resizable_list)
 
 
+class CannotRead(Exception):
+    """
+    Exception raised by Buffer.typed_read in case it is not possible to
+    accomplish the request. This might be because it is not supported by the
+    specific type of buffer, or because of alignment issues.
+    """
+
 class Buffer(object):
     """Abstract base class for buffers."""
     _attrs_ = ['readonly']
@@ -80,6 +92,12 @@
     def releasebuffer(self):
         pass
 
+    #@specialize.??
+    def typed_read(self, TP, byte_offset):
+        raise CannotRead
+
+
+
 class StringBuffer(Buffer):
     _attrs_ = ['readonly', 'value']
     _immutable_ = True
@@ -115,6 +133,19 @@
         # may still raise ValueError on some GCs
         return rffi.get_raw_address_of_string(self.value)
 
+    #@specialize.??
+    def typed_read(self, TP, byte_offset):
+        # WARNING: the 'byte_offset' is, as its name says, measured in bytes;
+        # however, it should be aligned for TP, otherwise on some platforms this
+        # code will crash!
+        lls = llstr(self.value)
+        base_ofs = (llmemory.offsetof(STR, 'chars') +
+                    llmemory.itemoffsetof(STR.chars, 0))
+        scale_factor = llmemory.sizeof(lltype.Char)
+        return llop.gc_load_indexed(TP, lls, byte_offset,
+                                    scale_factor, base_ofs)
+
+
 class SubBuffer(Buffer):
     _attrs_ = ['buffer', 'offset', 'size', 'readonly']
     _immutable_ = True
diff --git a/rpython/rlib/test/test_buffer.py b/rpython/rlib/test/test_buffer.py
--- a/rpython/rlib/test/test_buffer.py
+++ b/rpython/rlib/test/test_buffer.py
@@ -1,3 +1,6 @@
+import struct
+from rpython.rtyper.lltypesystem import lltype, rffi
+from rpython.rlib.rarithmetic import r_singlefloat
 from rpython.rlib.buffer import StringBuffer, SubBuffer, Buffer
 from rpython.annotator.annrpython import RPythonAnnotator
 from rpython.annotator.model import SomeInteger
@@ -71,3 +74,43 @@
     assert addr[0] == b'h'
     assert addr[4] == b'o'
     assert addr[6] == b'w'
+
+
+class BaseTypedReadTest:
+
+    def test_signed(self):
+        buf = struct.pack('@ll', 42, 43)
+        size = struct.calcsize('@l')
+        assert self.read(lltype.Signed, buf, 0) == 42
+        assert self.read(lltype.Signed, buf, size) == 43
+
+    def test_short(self):
+        buf = struct.pack('@hh', 42, 43)
+        size = struct.calcsize('@h')
+        x = self.read(rffi.SHORT, buf, 0)
+        assert int(x) == 42
+        x = self.read(rffi.SHORT, buf, size)
+        assert int(x) == 43
+
+    def test_float(self):
+        buf = struct.pack('@dd', 12.3, 45.6)
+        size = struct.calcsize('@d')
+        assert self.read(lltype.Float, buf, 0) == 12.3
+        assert self.read(lltype.Float, buf, size) == 45.6
+
+    def test_singlefloat(self):
+        buf = struct.pack('@ff', 12.3, 45.6)
+        size = struct.calcsize('@f')
+        x = self.read(lltype.SingleFloat, buf, 0)
+        assert x == r_singlefloat(12.3)
+        x = self.read(lltype.SingleFloat, buf, size)
+        assert x == r_singlefloat(45.6)
+
+
+class TestTypedReadDirect(BaseTypedReadTest):
+
+    def read(self, TYPE, data, offset):
+        buf = StringBuffer(data)
+        return buf.typed_read(TYPE, offset)
+
+


More information about the pypy-commit mailing list