Kaydet (Commit) 2e75c450 authored tarafından Thomas Heller's avatar Thomas Heller

Backport from py3k: Implement the new buffer interface from pep3118

for ctypes instances.  Closes issue #2404.
üst 259a566a
import unittest
from ctypes import *
import re, struct, sys
if sys.byteorder == "little":
THIS_ENDIAN = "<"
OTHER_ENDIAN = ">"
else:
THIS_ENDIAN = ">"
OTHER_ENDIAN = "<"
class memoryview(object):
# This class creates a memoryview - like object from data returned
# by the private _ctypes._buffer_info() function, just enough for
# these tests.
#
# It can be removed when the py3k memoryview object is backported.
def __init__(self, ob):
from _ctypes import _buffer_info
self.format, self.ndim, self.shape = _buffer_info(ob)
if self.shape == ():
self.shape = None
self.itemsize = sizeof(ob)
else:
size = sizeof(ob)
for dim in self.shape:
size /= dim
self.itemsize = size
self.strides = None
self.readonly = False
self.size = sizeof(ob)
def normalize(format):
# Remove current endian specifier and white space from a format
# string
format = format.replace(OTHER_ENDIAN, THIS_ENDIAN)
return re.sub(r"\s", "", format)
class Test(unittest.TestCase):
def test_native_types(self):
for tp, fmt, shape, itemtp in native_types:
ob = tp()
v = memoryview(ob)
try:
self.failUnlessEqual(normalize(v.format), normalize(fmt))
self.failUnlessEqual(v.size, sizeof(ob))
self.failUnlessEqual(v.itemsize, sizeof(itemtp))
self.failUnlessEqual(v.shape, shape)
# ctypes object always have a non-strided memory block
self.failUnlessEqual(v.strides, None)
# they are always read/write
self.failIf(v.readonly)
if v.shape:
n = 1
for dim in v.shape:
n = n * dim
self.failUnlessEqual(v.itemsize * n, v.size)
except:
# so that we can see the failing type
print(tp)
raise
def test_endian_types(self):
for tp, fmt, shape, itemtp in endian_types:
ob = tp()
v = memoryview(ob)
try:
self.failUnlessEqual(v.format, fmt)
self.failUnlessEqual(v.size, sizeof(ob))
self.failUnlessEqual(v.itemsize, sizeof(itemtp))
self.failUnlessEqual(v.shape, shape)
# ctypes object always have a non-strided memory block
self.failUnlessEqual(v.strides, None)
# they are always read/write
self.failIf(v.readonly)
if v.shape:
n = 1
for dim in v.shape:
n = n * dim
self.failUnlessEqual(v.itemsize * n, v.size)
except:
# so that we can see the failing type
print(tp)
raise
# define some structure classes
class Point(Structure):
_fields_ = [("x", c_long), ("y", c_long)]
class PackedPoint(Structure):
_pack_ = 2
_fields_ = [("x", c_long), ("y", c_long)]
class Point2(Structure):
pass
Point2._fields_ = [("x", c_long), ("y", c_long)]
class EmptyStruct(Structure):
_fields_ = []
class aUnion(Union):
_fields_ = [("a", c_int)]
################################################################
#
# This table contains format strings as they look on little endian
# machines. The test replaces '<' with '>' on big endian machines.
#
native_types = [
# type format shape calc itemsize
## simple types
(c_char, "<c", None, c_char),
(c_byte, "<b", None, c_byte),
(c_ubyte, "<B", None, c_ubyte),
(c_short, "<h", None, c_short),
(c_ushort, "<H", None, c_ushort),
# c_int and c_uint may be aliases to c_long
#(c_int, "<i", None, c_int),
#(c_uint, "<I", None, c_uint),
(c_long, "<l", None, c_long),
(c_ulong, "<L", None, c_ulong),
# c_longlong and c_ulonglong are aliases on 64-bit platforms
#(c_longlong, "<q", None, c_longlong),
#(c_ulonglong, "<Q", None, c_ulonglong),
(c_float, "<f", None, c_float),
(c_double, "<d", None, c_double),
# c_longdouble may be an alias to c_double
(c_bool, "<?", None, c_bool),
(py_object, "<O", None, py_object),
## pointers
(POINTER(c_byte), "&<b", None, POINTER(c_byte)),
(POINTER(POINTER(c_long)), "&&<l", None, POINTER(POINTER(c_long))),
## arrays and pointers
(c_double * 4, "(4)<d", (4,), c_double),
(c_float * 4 * 3 * 2, "(2,3,4)<f", (2,3,4), c_float),
(POINTER(c_short) * 2, "(2)&<h", (2,), POINTER(c_short)),
(POINTER(c_short) * 2 * 3, "(3,2)&<h", (3,2,), POINTER(c_short)),
(POINTER(c_short * 2), "&(2)<h", None, POINTER(c_short)),
## structures and unions
(Point, "T{<l:x:<l:y:}", None, Point),
# packed structures do not implement the pep
(PackedPoint, "B", None, PackedPoint),
(Point2, "T{<l:x:<l:y:}", None, Point2),
(EmptyStruct, "T{}", None, EmptyStruct),
# the pep does't support unions
(aUnion, "B", None, aUnion),
## other
# function signatures are not implemented
(CFUNCTYPE(None), "X{}", None, CFUNCTYPE(None)),
]
class BEPoint(BigEndianStructure):
_fields_ = [("x", c_long), ("y", c_long)]
class LEPoint(LittleEndianStructure):
_fields_ = [("x", c_long), ("y", c_long)]
################################################################
#
# This table contains format strings as they really look, on both big
# and little endian machines.
#
endian_types = [
(BEPoint, "T{>l:x:>l:y:}", None, BEPoint),
(LEPoint, "T{<l:x:<l:y:}", None, LEPoint),
(POINTER(BEPoint), "&T{>l:x:>l:y:}", None, POINTER(BEPoint)),
(POINTER(LEPoint), "&T{<l:x:<l:y:}", None, POINTER(LEPoint)),
]
if __name__ == "__main__":
unittest.main()
This diff is collapsed.
...@@ -1666,10 +1666,37 @@ pointer(PyObject *self, PyObject *arg) ...@@ -1666,10 +1666,37 @@ pointer(PyObject *self, PyObject *arg)
return result; return result;
} }
static PyObject *
buffer_info(PyObject *self, PyObject *arg)
{
StgDictObject *dict = PyType_stgdict(arg);
PyObject *shape;
Py_ssize_t i;
if (dict == NULL)
dict = PyObject_stgdict(arg);
if (dict == NULL) {
PyErr_SetString(PyExc_TypeError,
"not a ctypes type or object");
return NULL;
}
shape = PyTuple_New(dict->ndim);
for (i = 0; i < (int)dict->ndim; ++i)
PyTuple_SET_ITEM(shape, i, PyLong_FromSsize_t(dict->shape[i]));
if (PyErr_Occurred()) {
Py_DECREF(shape);
return NULL;
}
return Py_BuildValue("siN", dict->format, dict->ndim, shape);
}
PyMethodDef module_methods[] = { PyMethodDef module_methods[] = {
{"POINTER", POINTER, METH_O }, {"POINTER", POINTER, METH_O },
{"pointer", pointer, METH_O }, {"pointer", pointer, METH_O },
{"_unpickle", unpickle, METH_VARARGS }, {"_unpickle", unpickle, METH_VARARGS },
{"_buffer_info", buffer_info, METH_O,
"Return buffer interface information (for testing only)"},
{"resize", resize, METH_VARARGS, "Resize the memory buffer of a ctypes instance"}, {"resize", resize, METH_VARARGS, "Resize the memory buffer of a ctypes instance"},
#ifdef CTYPES_UNICODE #ifdef CTYPES_UNICODE
{"set_conversion_mode", set_conversion_mode, METH_VARARGS, set_conversion_mode_doc}, {"set_conversion_mode", set_conversion_mode, METH_VARARGS, set_conversion_mode_doc},
......
...@@ -235,6 +235,14 @@ typedef struct { ...@@ -235,6 +235,14 @@ typedef struct {
PyObject *restype; /* CDataObject or NULL */ PyObject *restype; /* CDataObject or NULL */
PyObject *checker; PyObject *checker;
int flags; /* calling convention and such */ int flags; /* calling convention and such */
/* pep3118 fields, pointers neeed PyMem_Free */
char *format;
int ndim;
Py_ssize_t *shape;
/* Py_ssize_t *strides; */ /* unused in ctypes */
/* Py_ssize_t *suboffsets; */ /* unused in ctypes */
} StgDictObject; } StgDictObject;
/**************************************************************** /****************************************************************
...@@ -415,6 +423,7 @@ extern void *MallocClosure(void); ...@@ -415,6 +423,7 @@ extern void *MallocClosure(void);
extern void _AddTraceback(char *, char *, int); extern void _AddTraceback(char *, char *, int);
extern PyObject *CData_FromBaseObj(PyObject *type, PyObject *base, Py_ssize_t index, char *adr); extern PyObject *CData_FromBaseObj(PyObject *type, PyObject *base, Py_ssize_t index, char *adr);
extern char *alloc_format_string(const char *prefix, const char *suffix);
/* XXX better name needed! */ /* XXX better name needed! */
extern int IsSimpleSubType(PyObject *obj); extern int IsSimpleSubType(PyObject *obj);
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include <ffi.h> #include <ffi.h>
#ifdef MS_WIN32 #ifdef MS_WIN32
#include <windows.h> #include <windows.h>
#include <malloc.h>
#endif #endif
#include "ctypes.h" #include "ctypes.h"
...@@ -24,6 +25,9 @@ StgDict_init(StgDictObject *self, PyObject *args, PyObject *kwds) ...@@ -24,6 +25,9 @@ StgDict_init(StgDictObject *self, PyObject *args, PyObject *kwds)
{ {
if (PyDict_Type.tp_init((PyObject *)self, args, kwds) < 0) if (PyDict_Type.tp_init((PyObject *)self, args, kwds) < 0)
return -1; return -1;
self->format = NULL;
self->ndim = 0;
self->shape = NULL;
return 0; return 0;
} }
...@@ -42,6 +46,8 @@ static void ...@@ -42,6 +46,8 @@ static void
StgDict_dealloc(StgDictObject *self) StgDict_dealloc(StgDictObject *self)
{ {
StgDict_clear(self); StgDict_clear(self);
PyMem_Free(self->format);
PyMem_Free(self->shape);
PyMem_Free(self->ffi_type_pointer.elements); PyMem_Free(self->ffi_type_pointer.elements);
PyDict_Type.tp_dealloc((PyObject *)self); PyDict_Type.tp_dealloc((PyObject *)self);
} }
...@@ -54,6 +60,10 @@ StgDict_clone(StgDictObject *dst, StgDictObject *src) ...@@ -54,6 +60,10 @@ StgDict_clone(StgDictObject *dst, StgDictObject *src)
StgDict_clear(dst); StgDict_clear(dst);
PyMem_Free(dst->ffi_type_pointer.elements); PyMem_Free(dst->ffi_type_pointer.elements);
PyMem_Free(dst->format);
dst->format = NULL;
PyMem_Free(dst->shape);
dst->shape = NULL;
dst->ffi_type_pointer.elements = NULL; dst->ffi_type_pointer.elements = NULL;
d = (char *)dst; d = (char *)dst;
...@@ -68,6 +78,20 @@ StgDict_clone(StgDictObject *dst, StgDictObject *src) ...@@ -68,6 +78,20 @@ StgDict_clone(StgDictObject *dst, StgDictObject *src)
Py_XINCREF(dst->restype); Py_XINCREF(dst->restype);
Py_XINCREF(dst->checker); Py_XINCREF(dst->checker);
if (src->format) {
dst->format = PyMem_Malloc(strlen(src->format) + 1);
if (dst->format == NULL)
return -1;
strcpy(dst->format, src->format);
}
if (src->shape) {
dst->shape = PyMem_Malloc(sizeof(Py_ssize_t) * src->ndim);
if (dst->shape == NULL)
return -1;
memcpy(dst->shape, src->shape,
sizeof(Py_ssize_t) * src->ndim);
}
if (src->ffi_type_pointer.elements == NULL) if (src->ffi_type_pointer.elements == NULL)
return 0; return 0;
size = sizeof(ffi_type *) * (src->length + 1); size = sizeof(ffi_type *) * (src->length + 1);
...@@ -349,6 +373,11 @@ StructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct) ...@@ -349,6 +373,11 @@ StructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct)
return -1; return -1;
} }
if (stgdict->format) {
PyMem_Free(stgdict->format);
stgdict->format = NULL;
}
if (stgdict->ffi_type_pointer.elements) if (stgdict->ffi_type_pointer.elements)
PyMem_Free(stgdict->ffi_type_pointer.elements); PyMem_Free(stgdict->ffi_type_pointer.elements);
...@@ -387,6 +416,15 @@ StructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct) ...@@ -387,6 +416,15 @@ StructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct)
ffi_ofs = 0; ffi_ofs = 0;
} }
if (isStruct && !isPacked) {
stgdict->format = alloc_format_string(NULL, "T{");
} else {
/* PEP3118 doesn't support union, or packed structures (well,
only standard packing, but we dont support the pep for
that). Use 'B' for bytes. */
stgdict->format = alloc_format_string(NULL, "B");
}
#define realdict ((PyObject *)&stgdict->dict) #define realdict ((PyObject *)&stgdict->dict)
for (i = 0; i < len; ++i) { for (i = 0; i < len; ++i) {
PyObject *name = NULL, *desc = NULL; PyObject *name = NULL, *desc = NULL;
...@@ -451,6 +489,24 @@ StructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct) ...@@ -451,6 +489,24 @@ StructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct)
} }
} else } else
bitsize = 0; bitsize = 0;
if (isStruct && !isPacked) {
char *fieldfmt = dict->format ? dict->format : "B";
char *fieldname = PyString_AsString(name);
char *ptr;
Py_ssize_t len = strlen(fieldname) + strlen(fieldfmt);
char *buf = alloca(len + 2 + 1);
sprintf(buf, "%s:%s:", fieldfmt, fieldname);
ptr = stgdict->format;
stgdict->format = alloc_format_string(stgdict->format, buf);
PyMem_Free(ptr);
if (stgdict->format == NULL) {
Py_DECREF(pair);
return -1;
}
}
if (isStruct) { if (isStruct) {
prop = CField_FromDesc(desc, i, prop = CField_FromDesc(desc, i,
&field_size, bitsize, &bitofs, &field_size, bitsize, &bitofs,
...@@ -481,6 +537,13 @@ StructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct) ...@@ -481,6 +537,13 @@ StructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct)
Py_DECREF(prop); Py_DECREF(prop);
} }
#undef realdict #undef realdict
if (isStruct && !isPacked) {
stgdict->format = alloc_format_string(stgdict->format, "}");
if (stgdict->format == NULL)
return -1;
}
if (!isStruct) if (!isStruct)
size = union_size; size = union_size;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment