Author: Armin Rigo <[email protected]>
Branch: 
Changeset: r395:f19a438dc009
Date: 2012-06-16 17:44 +0200
http://bitbucket.org/cffi/cffi/changeset/f19a438dc009/

Log:    ffi.buffer() with an optional second argument "size".

diff --git a/c/_ffi_backend.c b/c/_ffi_backend.c
--- a/c/_ffi_backend.c
+++ b/c/_ffi_backend.c
@@ -3104,28 +3104,32 @@
 static PyObject *b_buffer(PyObject *self, PyObject *args)
 {
     CDataObject *cd;
-    Py_ssize_t length;
-    if (!PyArg_ParseTuple(args, "O!:buffer",
-                          &CData_Type, &cd))
+    Py_ssize_t size = -1;
+    if (!PyArg_ParseTuple(args, "O!|n:buffer",
+                          &CData_Type, &cd, &size))
         return NULL;
 
-    if (cd->c_type->ct_flags & CT_POINTER)
-        length = cd->c_type->ct_itemdescr->ct_size;
-    else if (cd->c_type->ct_flags & CT_ARRAY)
-        length = get_array_length(cd) * cd->c_type->ct_itemdescr->ct_size;
+    if (cd->c_type->ct_flags & CT_POINTER) {
+        if (size < 0)
+            size = cd->c_type->ct_itemdescr->ct_size;
+    }
+    else if (cd->c_type->ct_flags & CT_ARRAY) {
+        if (size < 0)
+            size = get_array_length(cd) * cd->c_type->ct_itemdescr->ct_size;
+    }
     else {
         PyErr_Format(PyExc_TypeError,
                      "expected a pointer or array cdata, got '%s'",
                      cd->c_type->ct_name);
         return NULL;
     }
-    if (length < 0) {
+    if (size < 0) {
         PyErr_Format(PyExc_TypeError,
                      "don't know the size pointed to by '%s'",
                      cd->c_type->ct_name);
         return NULL;
     }
-    return PyBuffer_FromReadWriteMemory(cd->c_data, length);
+    return PyBuffer_FromReadWriteMemory(cd->c_data, size);
 }
 
 static PyObject *b_get_errno(PyObject *self, PyObject *noarg)
diff --git a/cffi/api.py b/cffi/api.py
--- a/cffi/api.py
+++ b/cffi/api.py
@@ -160,13 +160,13 @@
         BType = self.typeof(cdecl)
         return self._backend.cast(BType, source)
 
-    def buffer(self, cdata):
+    def buffer(self, cdata, size=-1):
         """Return a read-write buffer object that references the raw C data
         pointed to by the given 'cdata'.  The 'cdata' must be a pointer or
         an array.  To get a copy of it in a regular string, call str() on
         the result.
         """
-        return self._backend.buffer(cdata)
+        return self._backend.buffer(cdata, size)
 
     def callback(self, cdecl, python_callable):
         if not callable(python_callable):
diff --git a/cffi/backend_ctypes.py b/cffi/backend_ctypes.py
--- a/cffi/backend_ctypes.py
+++ b/cffi/backend_ctypes.py
@@ -760,18 +760,22 @@
     def set_errno(self, value):
         ctypes.set_errno(value)
 
-    def buffer(self, bptr):
+    def buffer(self, bptr, size=-1):
         # haaaaaaaaaaaack
         call = ctypes.pythonapi.PyBuffer_FromReadWriteMemory
         call.argtypes = (ctypes.c_void_p, ctypes.c_size_t)
         call.restype = ctypes.py_object
         #
         if isinstance(bptr, CTypesGenericPtr):
-            return call(bptr._as_ctype_ptr, bptr._bitem_size)
+            if size < 0:
+                size = bptr._bitem_size
+            return call(bptr._as_ctype_ptr, size)
         elif isinstance(bptr, CTypesGenericArray):
-            return call(ctypes.pointer(bptr._blob), ctypes.sizeof(bptr._blob))
+            if size < 0:
+                size = ctypes.sizeof(bptr._blob)
+            return call(ctypes.pointer(bptr._blob), size)
         else:
-            raise TypeError("'void *' argument expected, got %r" %
+            raise TypeError("pointer or array argument expected, got %r" %
                             (type(bptr).__name__,))
 
     def sizeof(self, cdata_or_BType):
diff --git a/doc/source/index.rst b/doc/source/index.rst
--- a/doc/source/index.rst
+++ b/doc/source/index.rst
@@ -336,7 +336,7 @@
 obvious Python equivalent.  Thus, they correspond to objects of type
 ``cdata``, which are printed for example as ``<cdata 'struct foo_s *'>``.
 
-``ffi.new(ctype [, initializer])``: this function builds a new cdata
+``ffi.new(ctype, [initializer])``: this function builds a new cdata
 object of the given ``ctype``.  The ctype is usually some constant
 string describing the C type.  This is similar to a malloc: it allocates
 the memory needed to store an object of the given C type, and returns a
@@ -504,13 +504,15 @@
 in this thread, and passed to the following C call, is available via
 reads and writes of the property ``ffi.errno``.
 
-``ffi.buffer(pointer)``: return a read-write buffer object that
-references the raw C data pointed to by the given 'cdata'.  The 'cdata'
-must be a pointer or an array.  To get a copy of it in a regular string,
-call str() on the result.  Getting a buffer is useful because you can
-read from it without an extra copy, or write to it to change the original
-value; you can use for example ``file.readinto()`` and ``file.write()``
-with such a buffer.
+``ffi.buffer(pointer, [size])``: return a read-write buffer object that
+references the raw C data pointed to by the given 'cdata', of 'size'
+bytes.  The 'cdata' must be a pointer or an array.  To get a copy of it
+in a regular string, call str() on the result.  If unspecified, the
+default size of the buffer is ``sizeof(*pointer)`` or the whole size of
+the array.  Getting a buffer is useful because you can read from it
+without an extra copy, or write into it to change the original value;
+you can use for example ``file.write()`` and ``file.readinto()`` with
+such a buffer.
 
 ``ffi.typeof("C type" or cdata object)``: return an object of type
 ``<ctype>`` corresponding to the parsed string, or to the C type of the
diff --git a/testing/backend_tests.py b/testing/backend_tests.py
--- a/testing/backend_tests.py
+++ b/testing/backend_tests.py
@@ -785,6 +785,27 @@
         assert len(str(b)) == 4 * 10
         assert a[1] == 0x45
 
+    def test_ffi_buffer_ptr_size(self):
+        ffi = FFI(backend=self.Backend())
+        a = ffi.new("short", 0x4243)
+        b = ffi.buffer(a, 1)
+        assert type(b) is buffer
+        assert len(str(b)) == 1
+        if sys.byteorder == 'little':
+            assert str(b) == '\x43'
+            b[0] = '\x62'
+            assert a[0] == 0x4262
+        else:
+            assert str(b) == '\x42'
+            b[0] = '\x63'
+            assert a[0] == 0x6343
+
+    def test_ffi_buffer_array_size(self):
+        ffi = FFI(backend=self.Backend())
+        a1 = ffi.new("int[]", range(100, 110))
+        a2 = ffi.new("int[]", range(100, 115))
+        assert str(ffi.buffer(a1)) == str(ffi.buffer(a2, 4*10))
+
     def test_new_struct_containing_array_varsize(self):
         py.test.skip("later?")
         ffi = FFI(backend=self.Backend())
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to