Backport from py3k: Implement the new buffer interface from pep3118
for ctypes instances. Closes issue #2404.
This commit is contained in:
parent
259a566ac5
commit
2e75c450d2
|
@ -0,0 +1,191 @@
|
|||
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()
|
|
@ -293,6 +293,36 @@ PyDict_GetItemProxy(PyObject *dict, PyObject *key)
|
|||
}
|
||||
|
||||
/******************************************************************/
|
||||
/*
|
||||
Allocate a memory block for a pep3118 format string, copy prefix (if
|
||||
non-null) and suffix into it. Returns NULL on failure, with the error
|
||||
indicator set. If called with a suffix of NULL the error indicator must
|
||||
already be set.
|
||||
*/
|
||||
char *
|
||||
alloc_format_string(const char *prefix, const char *suffix)
|
||||
{
|
||||
size_t len;
|
||||
char *result;
|
||||
|
||||
if (suffix == NULL) {
|
||||
assert(PyErr_Occurred());
|
||||
return NULL;
|
||||
}
|
||||
len = strlen(suffix);
|
||||
if (prefix)
|
||||
len += strlen(prefix);
|
||||
result = PyMem_Malloc(len + 1);
|
||||
if (result == NULL)
|
||||
return NULL;
|
||||
if (prefix)
|
||||
strcpy(result, prefix);
|
||||
else
|
||||
result[0] = '\0';
|
||||
strcat(result, suffix);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
StructType_Type - a meta type/class. Creating a new class using this one as
|
||||
__metaclass__ will call the contructor StructUnionType_new. It replaces the
|
||||
|
@ -874,6 +904,16 @@ PointerType_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
if (proto) {
|
||||
StgDictObject *itemdict = PyType_stgdict(proto);
|
||||
assert(itemdict);
|
||||
stgdict->format = alloc_format_string("&", itemdict->format);
|
||||
if (stgdict->format == NULL) {
|
||||
Py_DECREF((PyObject *)stgdict);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* create the new instance (which is a class,
|
||||
since we are a metatype!) */
|
||||
result = (PyTypeObject *)PyType_Type.tp_new(type, args, kwds);
|
||||
|
@ -1244,9 +1284,10 @@ ArrayType_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
|||
StgDictObject *itemdict;
|
||||
PyObject *proto;
|
||||
PyObject *typedict;
|
||||
int length;
|
||||
long length;
|
||||
|
||||
Py_ssize_t itemsize, itemalign;
|
||||
char buf[32];
|
||||
|
||||
typedict = PyTuple_GetItem(args, 2);
|
||||
if (!typedict)
|
||||
|
@ -1281,6 +1322,28 @@ ArrayType_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
assert(itemdict->format);
|
||||
if (itemdict->format[0] == '(') {
|
||||
sprintf(buf, "(%ld,", length);
|
||||
stgdict->format = alloc_format_string(buf, itemdict->format+1);
|
||||
} else {
|
||||
sprintf(buf, "(%ld)", length);
|
||||
stgdict->format = alloc_format_string(buf, itemdict->format);
|
||||
}
|
||||
if (stgdict->format == NULL) {
|
||||
Py_DECREF((PyObject *)stgdict);
|
||||
return NULL;
|
||||
}
|
||||
stgdict->ndim = itemdict->ndim + 1;
|
||||
stgdict->shape = PyMem_Malloc(sizeof(Py_ssize_t *) * stgdict->ndim);
|
||||
if (stgdict->shape == NULL) {
|
||||
Py_DECREF((PyObject *)stgdict);
|
||||
return NULL;
|
||||
}
|
||||
stgdict->shape[0] = length;
|
||||
memmove(&stgdict->shape[1], itemdict->shape,
|
||||
sizeof(Py_ssize_t) * (stgdict->ndim - 1));
|
||||
|
||||
itemsize = itemdict->size;
|
||||
if (length * itemsize < 0) {
|
||||
PyErr_SetString(PyExc_OverflowError,
|
||||
|
@ -1768,6 +1831,8 @@ SimpleType_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
|||
PyTypeObject *result;
|
||||
StgDictObject *stgdict;
|
||||
PyObject *proto;
|
||||
const char *proto_str;
|
||||
Py_ssize_t proto_len;
|
||||
PyMethodDef *ml;
|
||||
struct fielddesc *fmt;
|
||||
|
||||
|
@ -1778,17 +1843,34 @@ SimpleType_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
|||
return NULL;
|
||||
|
||||
proto = PyObject_GetAttrString((PyObject *)result, "_type_"); /* new ref */
|
||||
if (!proto
|
||||
|| !PyBytes_Check(proto)
|
||||
|| 1 != strlen(PyBytes_AS_STRING(proto))
|
||||
|| !strchr(SIMPLE_TYPE_CHARS, PyBytes_AS_STRING(proto)[0])) {
|
||||
if (!proto) {
|
||||
PyErr_SetString(PyExc_AttributeError,
|
||||
"class must define a '_type_' attribute");
|
||||
error:
|
||||
Py_XDECREF(proto);
|
||||
Py_XDECREF(result);
|
||||
return NULL;
|
||||
}
|
||||
if (PyString_Check(proto)) {
|
||||
proto_str = PyBytes_AS_STRING(proto);
|
||||
proto_len = PyBytes_GET_SIZE(proto);
|
||||
} else {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"class must define a '_type_' string attribute");
|
||||
goto error;
|
||||
}
|
||||
if (proto_len != 1) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"class must define a '_type_' attribute "
|
||||
"which must be a string of length 1");
|
||||
goto error;
|
||||
}
|
||||
if (!strchr(SIMPLE_TYPE_CHARS, *proto_str)) {
|
||||
PyErr_Format(PyExc_AttributeError,
|
||||
"class must define a '_type_' attribute which must be\n"
|
||||
"a single character string containing one of '%s'.",
|
||||
SIMPLE_TYPE_CHARS);
|
||||
Py_XDECREF(proto);
|
||||
Py_DECREF(result);
|
||||
return NULL;
|
||||
goto error;
|
||||
}
|
||||
fmt = getentry(PyBytes_AS_STRING(proto));
|
||||
if (fmt == NULL) {
|
||||
|
@ -1810,6 +1892,16 @@ SimpleType_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
|||
stgdict->size = fmt->pffi_type->size;
|
||||
stgdict->setfunc = fmt->setfunc;
|
||||
stgdict->getfunc = fmt->getfunc;
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
stgdict->format = alloc_format_string(">", proto_str);
|
||||
#else
|
||||
stgdict->format = alloc_format_string("<", proto_str);
|
||||
#endif
|
||||
if (stgdict->format == NULL) {
|
||||
Py_DECREF(result);
|
||||
Py_DECREF((PyObject *)stgdict);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
stgdict->paramfunc = SimpleType_paramfunc;
|
||||
/*
|
||||
|
@ -1895,22 +1987,32 @@ SimpleType_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
|||
if (type == &SimpleType_Type && fmt->setfunc_swapped && fmt->getfunc_swapped) {
|
||||
PyObject *swapped = CreateSwappedType(type, args, kwds,
|
||||
proto, fmt);
|
||||
StgDictObject *sw_dict;
|
||||
if (swapped == NULL) {
|
||||
Py_DECREF(result);
|
||||
return NULL;
|
||||
}
|
||||
sw_dict = PyType_stgdict(swapped);
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
PyObject_SetAttrString((PyObject *)result, "__ctype_le__", swapped);
|
||||
PyObject_SetAttrString((PyObject *)result, "__ctype_be__", (PyObject *)result);
|
||||
PyObject_SetAttrString(swapped, "__ctype_be__", (PyObject *)result);
|
||||
PyObject_SetAttrString(swapped, "__ctype_le__", swapped);
|
||||
/* We are creating the type for the OTHER endian */
|
||||
sw_dict->format = alloc_format_string("<", stgdict->format+1);
|
||||
#else
|
||||
PyObject_SetAttrString((PyObject *)result, "__ctype_be__", swapped);
|
||||
PyObject_SetAttrString((PyObject *)result, "__ctype_le__", (PyObject *)result);
|
||||
PyObject_SetAttrString(swapped, "__ctype_le__", (PyObject *)result);
|
||||
PyObject_SetAttrString(swapped, "__ctype_be__", swapped);
|
||||
/* We are creating the type for the OTHER endian */
|
||||
sw_dict->format = alloc_format_string(">", stgdict->format+1);
|
||||
#endif
|
||||
Py_DECREF(swapped);
|
||||
if (PyErr_Occurred()) {
|
||||
Py_DECREF(result);
|
||||
return NULL;
|
||||
}
|
||||
};
|
||||
|
||||
return (PyObject *)result;
|
||||
|
@ -2166,6 +2268,13 @@ CFuncPtrType_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
|||
return NULL;
|
||||
|
||||
stgdict->paramfunc = CFuncPtrType_paramfunc;
|
||||
/* We do NOT expose the function signature in the format string. It
|
||||
is impossible, generally, because the only requirement for the
|
||||
argtypes items is that they have a .from_param method - we do not
|
||||
know the types of the arguments (although, in practice, most
|
||||
argtypes would be a ctypes type).
|
||||
*/
|
||||
stgdict->format = alloc_format_string(NULL, "X{}");
|
||||
stgdict->flags |= TYPEFLAG_ISPOINTER;
|
||||
|
||||
/* create the new instance (which is a class,
|
||||
|
@ -2386,6 +2495,43 @@ static PyMemberDef CData_members[] = {
|
|||
{ NULL },
|
||||
};
|
||||
|
||||
static int CData_NewGetBuffer(PyObject *_self, Py_buffer *view, int flags)
|
||||
{
|
||||
CDataObject *self = (CDataObject *)_self;
|
||||
StgDictObject *dict = PyObject_stgdict(_self);
|
||||
Py_ssize_t i;
|
||||
|
||||
if (view == NULL) return 0;
|
||||
if (((flags & PyBUF_LOCK) == PyBUF_LOCK)) {
|
||||
PyErr_SetString(PyExc_BufferError,
|
||||
"Cannot lock this object.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
view->buf = self->b_ptr;
|
||||
view->len = self->b_size;
|
||||
view->readonly = 0;
|
||||
/* use default format character if not set */
|
||||
view->format = dict->format ? dict->format : "B";
|
||||
view->ndim = dict->ndim;
|
||||
view->shape = dict->shape;
|
||||
view->itemsize = self->b_size;
|
||||
for (i = 0; i < view->ndim; ++i) {
|
||||
view->itemsize /= dict->shape[i];
|
||||
}
|
||||
view->strides = NULL;
|
||||
view->suboffsets = NULL;
|
||||
view->internal = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Py_ssize_t CData_GetSegcount(PyObject *_self, Py_ssize_t *lenp)
|
||||
{
|
||||
if (lenp)
|
||||
*lenp = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static Py_ssize_t CData_GetBuffer(PyObject *_self, Py_ssize_t seg, void **pptr)
|
||||
{
|
||||
CDataObject *self = (CDataObject *)_self;
|
||||
|
@ -2397,18 +2543,13 @@ static Py_ssize_t CData_GetBuffer(PyObject *_self, Py_ssize_t seg, void **pptr)
|
|||
return self->b_size;
|
||||
}
|
||||
|
||||
static Py_ssize_t CData_GetSegcount(PyObject *_self, Py_ssize_t *lenp)
|
||||
{
|
||||
if (lenp)
|
||||
*lenp = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static PyBufferProcs CData_as_buffer = {
|
||||
CData_GetBuffer,
|
||||
CData_GetBuffer,
|
||||
CData_GetSegcount,
|
||||
NULL,
|
||||
(readbufferproc)CData_GetBuffer,
|
||||
(writebufferproc)CData_GetBuffer,
|
||||
(segcountproc)CData_GetSegcount,
|
||||
(charbufferproc)NULL,
|
||||
(getbufferproc)CData_NewGetBuffer,
|
||||
(releasebufferproc)NULL,
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -2497,7 +2638,7 @@ PyTypeObject CData_Type = {
|
|||
0, /* tp_getattro */
|
||||
0, /* tp_setattro */
|
||||
&CData_as_buffer, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_NEWBUFFER | Py_TPFLAGS_BASETYPE, /* tp_flags */
|
||||
"XXX to be provided", /* tp_doc */
|
||||
(traverseproc)CData_traverse, /* tp_traverse */
|
||||
(inquiry)CData_clear, /* tp_clear */
|
||||
|
@ -3824,7 +3965,7 @@ PyTypeObject CFuncPtr_Type = {
|
|||
0, /* tp_getattro */
|
||||
0, /* tp_setattro */
|
||||
&CData_as_buffer, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_NEWBUFFER | Py_TPFLAGS_BASETYPE, /* tp_flags */
|
||||
"Function Pointer", /* tp_doc */
|
||||
(traverseproc)CFuncPtr_traverse, /* tp_traverse */
|
||||
(inquiry)CFuncPtr_clear, /* tp_clear */
|
||||
|
@ -3967,7 +4108,7 @@ static PyTypeObject Struct_Type = {
|
|||
0, /* tp_getattro */
|
||||
0, /* tp_setattro */
|
||||
&CData_as_buffer, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_NEWBUFFER | Py_TPFLAGS_BASETYPE, /* tp_flags */
|
||||
"Structure base class", /* tp_doc */
|
||||
(traverseproc)CData_traverse, /* tp_traverse */
|
||||
(inquiry)CData_clear, /* tp_clear */
|
||||
|
@ -4009,7 +4150,7 @@ static PyTypeObject Union_Type = {
|
|||
0, /* tp_getattro */
|
||||
0, /* tp_setattro */
|
||||
&CData_as_buffer, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_NEWBUFFER | Py_TPFLAGS_BASETYPE, /* tp_flags */
|
||||
"Union base class", /* tp_doc */
|
||||
(traverseproc)CData_traverse, /* tp_traverse */
|
||||
(inquiry)CData_clear, /* tp_clear */
|
||||
|
@ -4406,7 +4547,7 @@ PyTypeObject Array_Type = {
|
|||
0, /* tp_getattro */
|
||||
0, /* tp_setattro */
|
||||
&CData_as_buffer, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_NEWBUFFER | Py_TPFLAGS_BASETYPE, /* tp_flags */
|
||||
"XXX to be provided", /* tp_doc */
|
||||
(traverseproc)CData_traverse, /* tp_traverse */
|
||||
(inquiry)CData_clear, /* tp_clear */
|
||||
|
@ -4643,7 +4784,7 @@ static PyTypeObject Simple_Type = {
|
|||
0, /* tp_getattro */
|
||||
0, /* tp_setattro */
|
||||
&CData_as_buffer, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_NEWBUFFER | Py_TPFLAGS_BASETYPE, /* tp_flags */
|
||||
"XXX to be provided", /* tp_doc */
|
||||
(traverseproc)CData_traverse, /* tp_traverse */
|
||||
(inquiry)CData_clear, /* tp_clear */
|
||||
|
@ -5043,7 +5184,7 @@ PyTypeObject Pointer_Type = {
|
|||
0, /* tp_getattro */
|
||||
0, /* tp_setattro */
|
||||
&CData_as_buffer, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_NEWBUFFER | Py_TPFLAGS_BASETYPE, /* tp_flags */
|
||||
"XXX to be provided", /* tp_doc */
|
||||
(traverseproc)CData_traverse, /* tp_traverse */
|
||||
(inquiry)CData_clear, /* tp_clear */
|
||||
|
|
|
@ -1666,10 +1666,37 @@ pointer(PyObject *self, PyObject *arg)
|
|||
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[] = {
|
||||
{"POINTER", POINTER, METH_O },
|
||||
{"pointer", pointer, METH_O },
|
||||
{"_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"},
|
||||
#ifdef CTYPES_UNICODE
|
||||
{"set_conversion_mode", set_conversion_mode, METH_VARARGS, set_conversion_mode_doc},
|
||||
|
|
|
@ -235,6 +235,14 @@ typedef struct {
|
|||
PyObject *restype; /* CDataObject or NULL */
|
||||
PyObject *checker;
|
||||
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;
|
||||
|
||||
/****************************************************************
|
||||
|
@ -415,6 +423,7 @@ extern void *MallocClosure(void);
|
|||
extern void _AddTraceback(char *, char *, int);
|
||||
|
||||
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! */
|
||||
extern int IsSimpleSubType(PyObject *obj);
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <ffi.h>
|
||||
#ifdef MS_WIN32
|
||||
#include <windows.h>
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
#include "ctypes.h"
|
||||
|
||||
|
@ -24,6 +25,9 @@ StgDict_init(StgDictObject *self, PyObject *args, PyObject *kwds)
|
|||
{
|
||||
if (PyDict_Type.tp_init((PyObject *)self, args, kwds) < 0)
|
||||
return -1;
|
||||
self->format = NULL;
|
||||
self->ndim = 0;
|
||||
self->shape = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -42,6 +46,8 @@ static void
|
|||
StgDict_dealloc(StgDictObject *self)
|
||||
{
|
||||
StgDict_clear(self);
|
||||
PyMem_Free(self->format);
|
||||
PyMem_Free(self->shape);
|
||||
PyMem_Free(self->ffi_type_pointer.elements);
|
||||
PyDict_Type.tp_dealloc((PyObject *)self);
|
||||
}
|
||||
|
@ -54,6 +60,10 @@ StgDict_clone(StgDictObject *dst, StgDictObject *src)
|
|||
|
||||
StgDict_clear(dst);
|
||||
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;
|
||||
|
||||
d = (char *)dst;
|
||||
|
@ -68,6 +78,20 @@ StgDict_clone(StgDictObject *dst, StgDictObject *src)
|
|||
Py_XINCREF(dst->restype);
|
||||
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)
|
||||
return 0;
|
||||
size = sizeof(ffi_type *) * (src->length + 1);
|
||||
|
@ -349,6 +373,11 @@ StructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct)
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (stgdict->format) {
|
||||
PyMem_Free(stgdict->format);
|
||||
stgdict->format = NULL;
|
||||
}
|
||||
|
||||
if (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)
|
|||
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)
|
||||
for (i = 0; i < len; ++i) {
|
||||
PyObject *name = NULL, *desc = NULL;
|
||||
|
@ -451,6 +489,24 @@ StructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct)
|
|||
}
|
||||
} else
|
||||
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) {
|
||||
prop = CField_FromDesc(desc, i,
|
||||
&field_size, bitsize, &bitofs,
|
||||
|
@ -481,6 +537,13 @@ StructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct)
|
|||
Py_DECREF(prop);
|
||||
}
|
||||
#undef realdict
|
||||
|
||||
if (isStruct && !isPacked) {
|
||||
stgdict->format = alloc_format_string(stgdict->format, "}");
|
||||
if (stgdict->format == NULL)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!isStruct)
|
||||
size = union_size;
|
||||
|
||||
|
|
Loading…
Reference in New Issue