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