[pypy-commit] pypy ffi-backend: Test and implementation of ffi.buffer().

arigo noreply at buildbot.pypy.org
Sat Jul 7 14:27:41 CEST 2012


Author: Armin Rigo <arigo at tunes.org>
Branch: ffi-backend
Changeset: r55965:8c71371063a6
Date: 2012-07-07 14:27 +0200
http://bitbucket.org/pypy/pypy/changeset/8c71371063a6/

Log:	Test and implementation of ffi.buffer().

diff --git a/pypy/module/_cffi_backend/__init__.py b/pypy/module/_cffi_backend/__init__.py
--- a/pypy/module/_cffi_backend/__init__.py
+++ b/pypy/module/_cffi_backend/__init__.py
@@ -27,4 +27,5 @@
         'typeof': 'func.typeof',
         'offsetof': 'func.offsetof',
         '_getfields': 'func._getfields',
+        'buffer': 'cbuffer.buffer',
         }
diff --git a/pypy/module/_cffi_backend/cbuffer.py b/pypy/module/_cffi_backend/cbuffer.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_cffi_backend/cbuffer.py
@@ -0,0 +1,49 @@
+from pypy.interpreter.error import operationerrfmt
+from pypy.interpreter.buffer import RWBuffer
+from pypy.interpreter.gateway import unwrap_spec
+from pypy.rpython.lltypesystem import rffi
+from pypy.module._cffi_backend import cdataobj, ctypeptr
+
+
+class LLBuffer(RWBuffer):
+
+    def __init__(self, raw_cdata, size):
+        self.raw_cdata = raw_cdata
+        self.size = size
+
+    def getlength(self):
+        return self.size
+
+    def getitem(self, index):
+        return self.raw_cdata[index]
+
+    def setitem(self, index, char):
+        self.raw_cdata[index] = char
+
+    def get_raw_address(self):
+        return self.raw_cdata
+
+    def getslice(self, start, stop, step, size):
+        if step == 1:
+            return rffi.charpsize2str(rffi.ptradd(self.raw_cdata, start), size)
+        return RWBuffer.getslice(self, start, stop, step, size)
+
+    def setslice(self, start, string):
+        raw_cdata = rffi.ptradd(self.raw_cdata, start)
+        for i in range(len(string)):
+            raw_cdata[i] = string[i]
+
+
+ at unwrap_spec(cdata=cdataobj.W_CData, size=int)
+def buffer(space, cdata, size=-1):
+    if not isinstance(cdata.ctype, ctypeptr.W_CTypePtrOrArray):
+        raise operationerrfmt(space.w_TypeError,
+                              "expected a pointer or array cdata, got '%s'",
+                              cdata.ctype.name)
+    if size < 0:
+        size = cdata._sizeof()
+        if size < 0:
+            raise operationerrfmt(space.w_TypeError,
+                                  "don't know the size pointed to by '%s'",
+                                  cdata.ctype.name)
+    return space.wrap(LLBuffer(cdata._cdata, size))
diff --git a/pypy/module/_cffi_backend/cdataobj.py b/pypy/module/_cffi_backend/cdataobj.py
--- a/pypy/module/_cffi_backend/cdataobj.py
+++ b/pypy/module/_cffi_backend/cdataobj.py
@@ -208,6 +208,9 @@
         assert length >= 0
         return length
 
+    def _sizeof(self):
+        return self.ctype.size
+
 
 class W_CDataApplevelOwning(W_CData):
     """This is the abstract base class for classes that are of the app-level
@@ -247,12 +250,15 @@
         W_CDataNewOwning.__init__(self, space, size, ctype)
         self.length = length
 
-    def _owning_num_bytes(self):
+    def _sizeof(self):
         from pypy.module._cffi_backend import ctypearray
         ctype = self.ctype
         assert isinstance(ctype, ctypearray.W_CTypeArray)
         return self.length * ctype.ctitem.size
 
+    def _owning_num_bytes(self):
+        return self._sizeof()
+
     def get_array_length(self):
         return self.length
 
diff --git a/pypy/module/_cffi_backend/func.py b/pypy/module/_cffi_backend/func.py
--- a/pypy/module/_cffi_backend/func.py
+++ b/pypy/module/_cffi_backend/func.py
@@ -36,10 +36,7 @@
 def sizeof(space, w_obj):
     ob = space.interpclass_w(w_obj)
     if isinstance(ob, cdataobj.W_CData):
-        if isinstance(ob, cdataobj.W_CDataNewOwningLength):
-            size = ob._owning_num_bytes()
-        else:
-            size = ob.ctype.size
+        size = ob._sizeof()
     elif isinstance(ob, ctypeobj.W_CType):
         size = ob.size
         if size < 0:
diff --git a/pypy/module/_cffi_backend/test/_backend_test_c.py b/pypy/module/_cffi_backend/test/_backend_test_c.py
--- a/pypy/module/_cffi_backend/test/_backend_test_c.py
+++ b/pypy/module/_cffi_backend/test/_backend_test_c.py
@@ -1346,3 +1346,24 @@
     assert (p < s) is (p <= s) is (s > p) is (s >= p)
     assert (p > s) is (p >= s) is (s < p) is (s <= p)
     assert (p < s) ^ (p > s)
+
+def test_buffer():
+    BChar = new_primitive_type("char")
+    BCharArray = new_array_type(new_pointer_type(BChar), None)
+    c = newp(BCharArray, "hi there")
+    buf = buffer(c)
+    assert str(buf) == "hi there\x00"
+    assert len(buf) == len("hi there\x00")
+    assert buf[0] == 'h'
+    assert buf[2] == ' '
+    assert list(buf) == ['h', 'i', ' ', 't', 'h', 'e', 'r', 'e', '\x00']
+    buf[2] = '-'
+    assert c[2] == '-'
+    assert str(buf) == "hi-there\x00"
+    buf[:2] = 'HI'
+    assert str(c) == 'HI-there'
+    assert buf[:4:2] == 'H-'
+    if '__pypy__' not in sys.builtin_module_names:
+        # XXX pypy doesn't support the following assignment so far
+        buf[:4:2] = 'XY'
+        assert str(c) == 'XIYthere'


More information about the pypy-commit mailing list