Commit 5eb6b392 authored by Benjamin Peterson's avatar Benjamin Peterson

support pep 3118 format strings for ctypes objects with nontrivial shapes (closes #10744)

Patch by Matti Picus.
parent 5d520224
...@@ -96,6 +96,9 @@ class EmptyStruct(Structure): ...@@ -96,6 +96,9 @@ class EmptyStruct(Structure):
class aUnion(Union): class aUnion(Union):
_fields_ = [("a", c_int)] _fields_ = [("a", c_int)]
class StructWithArrays(Structure):
_fields_ = [("x", c_long * 3 * 2), ("y", Point * 4)]
class Incomplete(Structure): class Incomplete(Structure):
pass pass
...@@ -145,10 +148,10 @@ native_types = [ ...@@ -145,10 +148,10 @@ native_types = [
## arrays and pointers ## arrays and pointers
(c_double * 4, "(4)<d", (4,), c_double), (c_double * 4, "<d", (4,), c_double),
(c_float * 4 * 3 * 2, "(2,3,4)<f", (2,3,4), c_float), (c_float * 4 * 3 * 2, "<f", (2,3,4), c_float),
(POINTER(c_short) * 2, "(2)&<h", (2,), POINTER(c_short)), (POINTER(c_short) * 2, "&<h", (2,), POINTER(c_short)),
(POINTER(c_short) * 2 * 3, "(3,2)&<h", (3,2,), POINTER(c_short)), (POINTER(c_short) * 2 * 3, "&<h", (3,2,), POINTER(c_short)),
(POINTER(c_short * 2), "&(2)<h", (), POINTER(c_short)), (POINTER(c_short * 2), "&(2)<h", (), POINTER(c_short)),
## structures and unions ## structures and unions
...@@ -160,6 +163,9 @@ native_types = [ ...@@ -160,6 +163,9 @@ native_types = [
(EmptyStruct, "T{}", (), EmptyStruct), (EmptyStruct, "T{}", (), EmptyStruct),
# the pep does't support unions # the pep does't support unions
(aUnion, "B", (), aUnion), (aUnion, "B", (), aUnion),
# structure with sub-arrays
(StructWithArrays, "T{(2,3)<l:x:(4)T{<l:x:<l:y:}:y:}", (), StructWithArrays),
(StructWithArrays * 3, "T{(2,3)<l:x:(4)T{<l:x:<l:y:}:y:}", (3,), StructWithArrays),
## pointer to incomplete structure ## pointer to incomplete structure
(Incomplete, "B", (), Incomplete), (Incomplete, "B", (), Incomplete),
......
...@@ -23,6 +23,9 @@ Core and Builtins ...@@ -23,6 +23,9 @@ Core and Builtins
Library Library
------- -------
- Issue #10744: Fix PEP 3118 format strings on ctypes objects with a nontrivial
shape.
- Issue #20998: Fixed re.fullmatch() of repeated single character pattern - Issue #20998: Fixed re.fullmatch() of repeated single character pattern
with ignore case. Original patch by Matthew Barnett. with ignore case. Original patch by Matthew Barnett.
......
...@@ -288,6 +288,48 @@ _ctypes_alloc_format_string(const char *prefix, const char *suffix) ...@@ -288,6 +288,48 @@ _ctypes_alloc_format_string(const char *prefix, const char *suffix)
return result; return result;
} }
/*
Allocate a memory block for a pep3118 format string, adding
the given prefix (if non-null), an additional shape prefix, and a suffix.
Returns NULL on failure, with the error indicator set. If called with
a suffix of NULL the error indicator must already be set.
*/
char *
_ctypes_alloc_format_string_with_shape(int ndim, const Py_ssize_t *shape,
const char *prefix, const char *suffix)
{
char *new_prefix;
char *result;
char buf[32];
int prefix_len;
int k;
prefix_len = 32 * ndim + 3;
if (prefix)
prefix_len += strlen(prefix);
new_prefix = PyMem_Malloc(prefix_len);
if (new_prefix == NULL)
return NULL;
new_prefix[0] = '\0';
if (prefix)
strcpy(new_prefix, prefix);
if (ndim > 0) {
/* Add the prefix "(shape[0],shape[1],...,shape[ndim-1])" */
strcat(new_prefix, "(");
for (k = 0; k < ndim; ++k) {
if (k < ndim-1) {
sprintf(buf, "%"PY_FORMAT_SIZE_T"d,", shape[k]);
} else {
sprintf(buf, "%"PY_FORMAT_SIZE_T"d)", shape[k]);
}
strcat(new_prefix, buf);
}
}
result = _ctypes_alloc_format_string(new_prefix, suffix);
PyMem_Free(new_prefix);
return result;
}
/* /*
PyCStructType_Type - a meta type/class. Creating a new class using this one as PyCStructType_Type - a meta type/class. Creating a new class using this one as
__metaclass__ will call the contructor StructUnionType_new. It replaces the __metaclass__ will call the contructor StructUnionType_new. It replaces the
...@@ -860,14 +902,21 @@ PyCPointerType_new(PyTypeObject *type, PyObject *args, PyObject *kwds) ...@@ -860,14 +902,21 @@ PyCPointerType_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
if (proto) { if (proto) {
StgDictObject *itemdict = PyType_stgdict(proto); StgDictObject *itemdict = PyType_stgdict(proto);
const char *current_format;
assert(itemdict); assert(itemdict);
/* If itemdict->format is NULL, then this is a pointer to an /* If itemdict->format is NULL, then this is a pointer to an
incomplete type. We create a generic format string incomplete type. We create a generic format string
'pointer to bytes' in this case. XXX Better would be to 'pointer to bytes' in this case. XXX Better would be to
fix the format string later... fix the format string later...
*/ */
stgdict->format = _ctypes_alloc_format_string("&", current_format = itemdict->format ? itemdict->format : "B";
itemdict->format ? itemdict->format : "B"); if (itemdict->shape != NULL) {
/* pointer to an array: the shape needs to be prefixed */
stgdict->format = _ctypes_alloc_format_string_with_shape(
itemdict->ndim, itemdict->shape, "&", current_format);
} else {
stgdict->format = _ctypes_alloc_format_string("&", current_format);
}
if (stgdict->format == NULL) { if (stgdict->format == NULL) {
Py_DECREF((PyObject *)stgdict); Py_DECREF((PyObject *)stgdict);
return NULL; return NULL;
...@@ -1245,7 +1294,6 @@ PyCArrayType_new(PyTypeObject *type, PyObject *args, PyObject *kwds) ...@@ -1245,7 +1294,6 @@ PyCArrayType_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
long length; long length;
int overflow; int overflow;
Py_ssize_t itemsize, itemalign; Py_ssize_t itemsize, itemalign;
char buf[32];
/* create the new instance (which is a class, /* create the new instance (which is a class,
since we are a metatype!) */ since we are a metatype!) */
...@@ -1295,13 +1343,7 @@ PyCArrayType_new(PyTypeObject *type, PyObject *args, PyObject *kwds) ...@@ -1295,13 +1343,7 @@ PyCArrayType_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
} }
assert(itemdict->format); assert(itemdict->format);
if (itemdict->format[0] == '(') { stgdict->format = _ctypes_alloc_format_string(NULL, itemdict->format);
sprintf(buf, "(%ld,", length);
stgdict->format = _ctypes_alloc_format_string(buf, itemdict->format+1);
} else {
sprintf(buf, "(%ld)", length);
stgdict->format = _ctypes_alloc_format_string(buf, itemdict->format);
}
if (stgdict->format == NULL) if (stgdict->format == NULL)
goto error; goto error;
stgdict->ndim = itemdict->ndim + 1; stgdict->ndim = itemdict->ndim + 1;
......
...@@ -357,6 +357,9 @@ extern void _ctypes_add_traceback(char *, char *, int); ...@@ -357,6 +357,9 @@ extern void _ctypes_add_traceback(char *, char *, int);
extern PyObject *PyCData_FromBaseObj(PyObject *type, PyObject *base, Py_ssize_t index, char *adr); extern PyObject *PyCData_FromBaseObj(PyObject *type, PyObject *base, Py_ssize_t index, char *adr);
extern char *_ctypes_alloc_format_string(const char *prefix, const char *suffix); extern char *_ctypes_alloc_format_string(const char *prefix, const char *suffix);
extern char *_ctypes_alloc_format_string_with_shape(int ndim,
const Py_ssize_t *shape,
const char *prefix, const char *suffix);
extern int _ctypes_simple_instance(PyObject *obj); extern int _ctypes_simple_instance(PyObject *obj);
......
...@@ -505,7 +505,12 @@ PyCStructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct ...@@ -505,7 +505,12 @@ PyCStructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct
sprintf(buf, "%s:%s:", fieldfmt, fieldname); sprintf(buf, "%s:%s:", fieldfmt, fieldname);
ptr = stgdict->format; ptr = stgdict->format;
if (dict->shape != NULL) {
stgdict->format = _ctypes_alloc_format_string_with_shape(
dict->ndim, dict->shape, stgdict->format, buf);
} else {
stgdict->format = _ctypes_alloc_format_string(stgdict->format, buf); stgdict->format = _ctypes_alloc_format_string(stgdict->format, buf);
}
PyMem_Free(ptr); PyMem_Free(ptr);
PyMem_Free(buf); PyMem_Free(buf);
......
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