summaryrefslogtreecommitdiffstats
path: root/Modules
diff options
context:
space:
mode:
authorPetr Viktorin <encukou@gmail.com>2024-03-20 16:33:08 (GMT)
committerGitHub <noreply@github.com>2024-03-20 16:33:08 (GMT)
commitdcaf33a41d5d220523d71c9b35bc08f5b8405dac (patch)
tree495bf3368e58d9fef72317a883d96cf81228c169 /Modules
parent44fbab43d8f3f2df07091d237824cf4fa1f6c57c (diff)
downloadcpython-dcaf33a41d5d220523d71c9b35bc08f5b8405dac.zip
cpython-dcaf33a41d5d220523d71c9b35bc08f5b8405dac.tar.gz
cpython-dcaf33a41d5d220523d71c9b35bc08f5b8405dac.tar.bz2
gh-114314: ctypes: remove stgdict and switch to heap types (GH-116458)
Before this change, ctypes classes used a custom dict subclass, `StgDict`, as their `tp_dict`. This acts like a regular dict but also includes extra information about the type. This replaces stgdict by `StgInfo`, a C struct on the type, accessed by `PyObject_GetTypeData()` (PEP-697). All usage of `StgDict` (mainly variables named `stgdict`, `dict`, `edict` etc.) is converted to `StgInfo` (named `stginfo`, `info`, `einfo`, etc.). Where the dict is actually used for class attributes (as a regular PyDict), it's now called `attrdict`. This change -- not overriding `tp_dict` -- is made to make me comfortable with the next part of this PR: moving the initialization logic from `tp_new` to `tp_init`. The `StgInfo` is set up in `__init__` of each class, with a guard that prevents calling `__init__` more than once. Note that abstract classes (like `Array` or `Structure`) are created using `PyType_FromMetaclass` and do not have `__init__` called. Previously, this was done in `__new__`, which also wasn't called for abstract classes. Since `__init__` can be called from Python code or skipped, there is a tested guard to ensure `StgInfo` is initialized exactly once before it's used. Co-authored-by: neonene <53406459+neonene@users.noreply.github.com> Co-authored-by: Erlend E. Aasland <erlend.aasland@protonmail.com>
Diffstat (limited to 'Modules')
-rw-r--r--Modules/_ctypes/_ctypes.c1986
-rw-r--r--Modules/_ctypes/callbacks.c42
-rw-r--r--Modules/_ctypes/callproc.c124
-rw-r--r--Modules/_ctypes/cfield.c55
-rw-r--r--Modules/_ctypes/ctypes.h172
-rw-r--r--Modules/_ctypes/stgdict.c427
6 files changed, 1402 insertions, 1404 deletions
diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c
index 94245ae..af094a0 100644
--- a/Modules/_ctypes/_ctypes.c
+++ b/Modules/_ctypes/_ctypes.c
@@ -2,7 +2,7 @@
ToDo:
Get rid of the checker (and also the converters) field in PyCFuncPtrObject and
- StgDictObject, and replace them by slot functions in StgDictObject.
+ StgInfo, and replace them by slot functions in StgInfo.
think about a buffer-like object (memory? bytes?)
@@ -36,7 +36,6 @@ PyCData_Type
Simple_Type __new__(), __init__(), _as_parameter_
PyCField_Type
-PyCStgDict_Type
==============================================================================
@@ -82,7 +81,6 @@ bytes(cdata)
*/
/*
- * PyCStgDict_Type
* PyCStructType_Type
* UnionType_Type
* PyCPointerType_Type
@@ -128,20 +126,7 @@ bytes(cdata)
#include "pycore_long.h" // _PyLong_GetZero()
-static PyTypeObject Union_Type;
-static PyTypeObject Struct_Type;
-static PyTypeObject Simple_Type;
-
-ctypes_state global_state = {
- .PyCStgDict_Type = &PyCStgDict_Type,
- .PyCData_Type = &PyCData_Type,
- .Struct_Type = &Struct_Type,
- .Union_Type = &Union_Type,
- .PyCArray_Type = &PyCArray_Type,
- .Simple_Type = &Simple_Type,
- .PyCPointer_Type = &PyCPointer_Type,
- .PyCFuncPtr_Type = &PyCFuncPtr_Type,
-};
+ctypes_state global_state = {0};
PyObject *PyExc_ArgError = NULL;
@@ -459,12 +444,121 @@ static PyType_Spec structparam_spec = {
.slots = structparam_slots,
};
+/*
+ CType_Type - a base metaclass. Its instances (classes) have a StgInfo.
+ */
+
+static int
+CType_Type_traverse(PyObject *self, visitproc visit, void *arg)
+{
+ Py_VISIT(Py_TYPE(self));
+ return 0;
+}
+
+static void
+_ctype_clear_stginfo(StgInfo *info)
+{
+ assert(info);
+ Py_CLEAR(info->proto);
+ Py_CLEAR(info->argtypes);
+ Py_CLEAR(info->converters);
+ Py_CLEAR(info->restype);
+ Py_CLEAR(info->checker);
+}
+
+static int
+CType_Type_clear(PyObject *self)
+{
+ ctypes_state *st = GLOBAL_STATE();
+ if (st && st->PyCType_Type) {
+ StgInfo *info;
+ if (PyStgInfo_FromType(st, self, &info) < 0) {
+ return -1;
+ }
+ if (info) {
+ _ctype_clear_stginfo(info);
+ }
+ }
+ return 0;
+}
+
+static void
+CType_Type_dealloc(PyObject *self)
+{
+ ctypes_state *st = GLOBAL_STATE();
+
+ if (st && st->PyCType_Type) {
+ StgInfo *info;
+ if (PyStgInfo_FromType(st, self, &info) < 0) {
+ PyErr_WriteUnraisable(self);
+ }
+ if (info) {
+ PyMem_Free(info->ffi_type_pointer.elements);
+ info->ffi_type_pointer.elements = NULL;
+ PyMem_Free(info->format);
+ info->format = NULL;
+ PyMem_Free(info->shape);
+ info->shape = NULL;
+ _ctype_clear_stginfo(info);
+ }
+ }
+
+ PyTypeObject *tp = Py_TYPE(self);
+ PyType_Type.tp_dealloc(self);
+ Py_DECREF(tp);
+}
+
+static PyObject *
+CType_Type_sizeof(PyObject *self)
+{
+ Py_ssize_t size = Py_TYPE(self)->tp_basicsize;
+ size += Py_TYPE(self)->tp_itemsize * Py_SIZE(self);
+
+ ctypes_state *st = GLOBAL_STATE();
+ StgInfo *info;
+ if (PyStgInfo_FromType(st, self, &info) < 0) {
+ return NULL;
+ }
+ if (info) {
+ if (info->format) {
+ size += strlen(info->format) + 1;
+ }
+ if (info->ffi_type_pointer.elements) {
+ size += (info->length + 1) * sizeof(ffi_type *);
+ }
+ size += info->ndim * sizeof(Py_ssize_t);
+ }
+
+ return PyLong_FromSsize_t(size);
+}
+
+static PyMethodDef ctype_methods[] = {
+ {"__sizeof__", _PyCFunction_CAST(CType_Type_sizeof),
+ METH_NOARGS, PyDoc_STR("Return memory consumption of the type object.")},
+ {0},
+};
+
+static PyType_Slot ctype_type_slots[] = {
+ {Py_tp_traverse, CType_Type_traverse},
+ {Py_tp_clear, CType_Type_clear},
+ {Py_tp_dealloc, CType_Type_dealloc},
+ {Py_tp_methods, ctype_methods},
+ {0, NULL},
+};
+
+static PyType_Spec pyctype_type_spec = {
+ .name = "_ctypes.CType_Type",
+ .basicsize = -(Py_ssize_t)sizeof(StgInfo),
+ .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE |
+ Py_TPFLAGS_HAVE_GC |
+ Py_TPFLAGS_BASETYPE ),
+ .slots = ctype_type_slots,
+};
/*
PyCStructType_Type - a meta type/class. Creating a new class using this one as
- __metaclass__ will call the constructor StructUnionType_new. It replaces the
- tp_dict member with a new instance of StgDict, and initializes the C
- accessible fields somehow.
+ __metaclass__ will call the constructor StructUnionType_new.
+ It initializes the C accessible fields somehow.
*/
static PyCArgObject *
@@ -472,7 +566,6 @@ StructUnionType_paramfunc(CDataObject *self)
{
PyCArgObject *parg;
PyObject *obj;
- StgDictObject *stgdict;
void *ptr;
if ((size_t)self->b_size > sizeof(void*)) {
@@ -507,104 +600,104 @@ StructUnionType_paramfunc(CDataObject *self)
return NULL;
}
+ ctypes_state *st = GLOBAL_STATE();
+ StgInfo *stginfo;
+ if (PyStgInfo_FromObject(st, (PyObject *)self, &stginfo) < 0) {
+ Py_DECREF(obj);
+ return NULL;
+ }
+ assert(stginfo); /* Cannot be NULL for structure/union instances */
+
parg->tag = 'V';
- stgdict = PyObject_stgdict((PyObject *)self);
- assert(stgdict); /* Cannot be NULL for structure/union instances */
- parg->pffi_type = &stgdict->ffi_type_pointer;
+ parg->pffi_type = &stginfo->ffi_type_pointer;
parg->value.p = ptr;
parg->size = self->b_size;
parg->obj = obj;
return parg;
}
-static PyObject *
-StructUnionType_new(PyTypeObject *type, PyObject *args, PyObject *kwds, int isStruct)
+static int
+StructUnionType_init(PyObject *self, PyObject *args, PyObject *kwds, int isStruct)
{
- PyTypeObject *result;
PyObject *fields;
- StgDictObject *dict;
- /* create the new instance (which is a class,
- since we are a metatype!) */
- result = (PyTypeObject *)PyType_Type.tp_new(type, args, kwds);
- if (!result)
- return NULL;
+ PyObject *attrdict = PyType_GetDict((PyTypeObject *)self);
+ if (!attrdict) {
+ return -1;
+ }
/* keep this for bw compatibility */
- int r = PyDict_Contains(result->tp_dict, &_Py_ID(_abstract_));
+ int r = PyDict_Contains(attrdict, &_Py_ID(_abstract_));
if (r > 0) {
- return (PyObject *)result;
+ Py_DECREF(attrdict);
+ return 0;
}
if (r < 0) {
- Py_DECREF(result);
- return NULL;
+ Py_DECREF(attrdict);
+ return -1;
}
ctypes_state *st = GLOBAL_STATE();
- dict = (StgDictObject *)_PyObject_CallNoArgs((PyObject *)st->PyCStgDict_Type);
- if (!dict) {
- Py_DECREF(result);
- return NULL;
+ StgInfo *info = PyStgInfo_Init(st, (PyTypeObject *)self);
+ if (!info) {
+ Py_DECREF(attrdict);
+ return -1;
}
if (!isStruct) {
- dict->flags |= TYPEFLAG_HASUNION;
- }
- /* replace the class dict by our updated stgdict, which holds info
- about storage requirements of the instances */
- if (-1 == PyDict_Update((PyObject *)dict, result->tp_dict)) {
- Py_DECREF(result);
- Py_DECREF((PyObject *)dict);
- return NULL;
+ info->flags |= TYPEFLAG_HASUNION;
}
- Py_SETREF(result->tp_dict, (PyObject *)dict);
- dict->format = _ctypes_alloc_format_string(NULL, "B");
- if (dict->format == NULL) {
- Py_DECREF(result);
- return NULL;
+
+ info->format = _ctypes_alloc_format_string(NULL, "B");
+ if (info->format == NULL) {
+ Py_DECREF(attrdict);
+ return -1;
}
- dict->paramfunc = StructUnionType_paramfunc;
+ info->paramfunc = StructUnionType_paramfunc;
- if (PyDict_GetItemRef((PyObject *)dict, &_Py_ID(_fields_), &fields) < 0) {
- Py_DECREF(result);
- return NULL;
+ if (PyDict_GetItemRef((PyObject *)attrdict, &_Py_ID(_fields_), &fields) < 0) {
+ Py_DECREF(attrdict);
+ return -1;
}
+ Py_CLEAR(attrdict);
if (fields) {
- if (PyObject_SetAttr((PyObject *)result, &_Py_ID(_fields_), fields) < 0) {
- Py_DECREF(result);
+ if (PyObject_SetAttr(self, &_Py_ID(_fields_), fields) < 0) {
Py_DECREF(fields);
- return NULL;
+ return -1;
}
Py_DECREF(fields);
- return (PyObject *)result;
+ return 0;
}
else {
- StgDictObject *basedict = PyType_stgdict((PyObject *)result->tp_base);
-
- if (basedict == NULL) {
- return (PyObject *)result;
+ StgInfo *baseinfo;
+ if (PyStgInfo_FromType(st, (PyObject *)((PyTypeObject *)self)->tp_base,
+ &baseinfo) < 0) {
+ return -1;
}
- /* copy base dict */
- if (-1 == PyCStgDict_clone(dict, basedict)) {
- Py_DECREF(result);
- return NULL;
+ if (baseinfo == NULL) {
+ return 0;
}
- dict->flags &= ~DICTFLAG_FINAL; /* clear the 'final' flag in the subclass dict */
- basedict->flags |= DICTFLAG_FINAL; /* set the 'final' flag in the baseclass dict */
- return (PyObject *)result;
+
+ /* copy base info */
+ if (PyCStgInfo_clone(info, baseinfo) < 0) {
+ return -1;
+ }
+ info->flags &= ~DICTFLAG_FINAL; /* clear the 'final' flag in the subclass info */
+ baseinfo->flags |= DICTFLAG_FINAL; /* set the 'final' flag in the baseclass info */
}
+ return 0;
}
-static PyObject *
-PyCStructType_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+static int
+PyCStructType_init(PyObject *self, PyObject *args, PyObject *kwds)
{
- return StructUnionType_new(type, args, kwds, 1);
+ return StructUnionType_init(self, args, kwds, 1);
}
-static PyObject *
-UnionType_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+static int
+UnionType_init(PyObject *self, PyObject *args, PyObject *kwds)
{
- return StructUnionType_new(type, args, kwds, 0);
+ return StructUnionType_init(self, args, kwds, 0);
}
PyDoc_STRVAR(from_address_doc,
@@ -640,8 +733,12 @@ CDataType_from_buffer(PyObject *type, PyObject *args)
Py_buffer *buffer;
Py_ssize_t offset = 0;
- StgDictObject *dict = PyType_stgdict(type);
- if (!dict) {
+ ctypes_state *st = GLOBAL_STATE();
+ StgInfo *info;
+ if (PyStgInfo_FromType(st, type, &info) < 0) {
+ return NULL;
+ }
+ if (!info) {
PyErr_SetString(PyExc_TypeError, "abstract class");
return NULL;
}
@@ -676,11 +773,11 @@ CDataType_from_buffer(PyObject *type, PyObject *args)
return NULL;
}
- if (dict->size > buffer->len - offset) {
+ if (info->size > buffer->len - offset) {
PyErr_Format(PyExc_ValueError,
"Buffer size too small "
"(%zd instead of at least %zd bytes)",
- buffer->len, dict->size + offset);
+ buffer->len, info->size + offset);
Py_DECREF(mv);
return NULL;
}
@@ -717,8 +814,13 @@ CDataType_from_buffer_copy(PyObject *type, PyObject *args)
Py_buffer buffer;
Py_ssize_t offset = 0;
PyObject *result;
- StgDictObject *dict = PyType_stgdict(type);
- if (!dict) {
+
+ ctypes_state *st = GLOBAL_STATE();
+ StgInfo *info;
+ if (PyStgInfo_FromType(st, type, &info) < 0) {
+ return NULL;
+ }
+ if (!info) {
PyErr_SetString(PyExc_TypeError, "abstract class");
return NULL;
}
@@ -733,10 +835,10 @@ CDataType_from_buffer_copy(PyObject *type, PyObject *args)
return NULL;
}
- if (dict->size > buffer.len - offset) {
+ if (info->size > buffer.len - offset) {
PyErr_Format(PyExc_ValueError,
"Buffer size too small (%zd instead of at least %zd bytes)",
- buffer.len, dict->size + offset);
+ buffer.len, info->size + offset);
PyBuffer_Release(&buffer);
return NULL;
}
@@ -750,7 +852,7 @@ CDataType_from_buffer_copy(PyObject *type, PyObject *args)
result = GenericPyCData_new((PyTypeObject *)type, NULL, NULL);
if (result != NULL) {
memcpy(((CDataObject *)result)->b_ptr,
- (char *)buffer.buf + offset, dict->size);
+ (char *)buffer.buf + offset, info->size);
}
PyBuffer_Release(&buffer);
return result;
@@ -836,13 +938,14 @@ CDataType_from_param(PyObject *type, PyObject *value)
PyCArgObject *p = (PyCArgObject *)value;
PyObject *ob = p->obj;
const char *ob_name;
- StgDictObject *dict;
- dict = PyType_stgdict(type);
-
+ StgInfo *info;
+ if (PyStgInfo_FromType(st, type, &info) < 0) {
+ return NULL;
+ }
/* If we got a PyCArgObject, we must check if the object packed in it
- is an instance of the type's dict->proto */
- if(dict && ob) {
- res = PyObject_IsInstance(ob, dict->proto);
+ is an instance of the type's info->proto */
+ if(info && ob) {
+ res = PyObject_IsInstance(ob, info->proto);
if (res == -1)
return NULL;
if (res) {
@@ -893,18 +996,27 @@ CDataType_repeat(PyObject *self, Py_ssize_t length)
static int
CDataType_clear(PyTypeObject *self)
{
- StgDictObject *dict = PyType_stgdict((PyObject *)self);
- if (dict)
- Py_CLEAR(dict->proto);
+ ctypes_state *st = GLOBAL_STATE();
+ StgInfo *info;
+ if (PyStgInfo_FromType(st, (PyObject *)self, &info) < 0) {
+ return -1;
+ }
+ if (info) {
+ Py_CLEAR(info->proto);
+ }
return PyType_Type.tp_clear((PyObject *)self);
}
static int
CDataType_traverse(PyTypeObject *self, visitproc visit, void *arg)
{
- StgDictObject *dict = PyType_stgdict((PyObject *)self);
- if (dict) {
- Py_VISIT(dict->proto);
+ ctypes_state *st = GLOBAL_STATE();
+ StgInfo *info;
+ if (PyStgInfo_FromType(st, (PyObject *)self, &info) < 0) {
+ return -1;
+ }
+ if (info) {
+ Py_VISIT(info->proto);
}
Py_VISIT(Py_TYPE(self));
return PyType_Type.tp_traverse((PyObject *)self, visit, arg);
@@ -919,7 +1031,7 @@ PyCStructType_setattro(PyObject *self, PyObject *key, PyObject *value)
if (value && PyUnicode_Check(key) &&
_PyUnicode_EqualToASCIIString(key, "_fields_"))
- return PyCStructUnionType_update_stgdict(self, value, 1);
+ return PyCStructUnionType_update_stginfo(self, value, 1);
return 0;
}
@@ -933,7 +1045,7 @@ UnionType_setattro(PyObject *self, PyObject *key, PyObject *value)
if (PyUnicode_Check(key) &&
_PyUnicode_EqualToASCIIString(key, "_fields_"))
- return PyCStructUnionType_update_stgdict(self, value, 0);
+ return PyCStructUnionType_update_stginfo(self, value, 0);
return 0;
}
@@ -943,14 +1055,14 @@ static PyType_Slot pycstruct_type_slots[] = {
{Py_tp_traverse, CDataType_traverse},
{Py_tp_clear, CDataType_clear},
{Py_tp_methods, CDataType_methods},
- {Py_tp_new, PyCStructType_new},
+ {Py_tp_init, PyCStructType_init},
// Sequence protocol.
{Py_sq_repeat, CDataType_repeat},
{0, NULL},
};
-PyType_Spec pycstruct_type_spec = {
+static PyType_Spec pycstruct_type_spec = {
.name = "_ctypes.PyCStructType",
.flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC |
Py_TPFLAGS_IMMUTABLETYPE),
@@ -963,7 +1075,7 @@ static PyType_Slot union_type_slots[] = {
{Py_tp_traverse, CDataType_traverse},
{Py_tp_clear, CDataType_clear},
{Py_tp_methods, CDataType_methods},
- {Py_tp_new, UnionType_new},
+ {Py_tp_init, UnionType_init},
// Sequence protocol.
{Py_sq_repeat, CDataType_repeat},
@@ -994,20 +1106,25 @@ size property/method, and the sequence protocol.
*/
static int
-PyCPointerType_SetProto(StgDictObject *stgdict, PyObject *proto)
+PyCPointerType_SetProto(StgInfo *stginfo, PyObject *proto)
{
+ ctypes_state *st = GLOBAL_STATE();
if (!proto || !PyType_Check(proto)) {
PyErr_SetString(PyExc_TypeError,
"_type_ must be a type");
return -1;
}
- if (!PyType_stgdict(proto)) {
+ StgInfo *info;
+ if (PyStgInfo_FromType(st, proto, &info) < 0) {
+ return -1;
+ }
+ if (!info) {
PyErr_SetString(PyExc_TypeError,
"_type_ must have storage info");
return -1;
}
Py_INCREF(proto);
- Py_XSETREF(stgdict->proto, proto);
+ Py_XSETREF(stginfo->proto, proto);
return 0;
}
@@ -1027,110 +1144,103 @@ PyCPointerType_paramfunc(CDataObject *self)
return parg;
}
-static PyObject *
-PyCPointerType_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+static int
+PyCPointerType_init(PyObject *self, PyObject *args, PyObject *kwds)
{
- PyTypeObject *result;
- StgDictObject *stgdict;
PyObject *proto;
PyObject *typedict;
-
typedict = PyTuple_GetItem(args, 2);
if (!typedict) {
- return NULL;
+ return -1;
}
+
/*
- stgdict items size, align, length contain info about pointers itself,
- stgdict->proto has info about the pointed to type!
+ stginfo items size, align, length contain info about pointers itself,
+ stginfo->proto has info about the pointed to type!
*/
ctypes_state *st = GLOBAL_STATE();
- stgdict = (StgDictObject *)_PyObject_CallNoArgs(
- (PyObject *)st->PyCStgDict_Type);
- if (!stgdict) {
- return NULL;
+ StgInfo *stginfo = PyStgInfo_Init(st, (PyTypeObject *)self);
+ if (!stginfo) {
+ return -1;
}
- stgdict->size = sizeof(void *);
- stgdict->align = _ctypes_get_fielddesc("P")->pffi_type->alignment;
- stgdict->length = 1;
- stgdict->ffi_type_pointer = ffi_type_pointer;
- stgdict->paramfunc = PyCPointerType_paramfunc;
- stgdict->flags |= TYPEFLAG_ISPOINTER;
+ stginfo->size = sizeof(void *);
+ stginfo->align = _ctypes_get_fielddesc("P")->pffi_type->alignment;
+ stginfo->length = 1;
+ stginfo->ffi_type_pointer = ffi_type_pointer;
+ stginfo->paramfunc = PyCPointerType_paramfunc;
+ stginfo->flags |= TYPEFLAG_ISPOINTER;
if (PyDict_GetItemRef(typedict, &_Py_ID(_type_), &proto) < 0) {
- Py_DECREF((PyObject *)stgdict);
- return NULL;
+ return -1;
}
if (proto) {
- StgDictObject *itemdict;
const char *current_format;
- if (-1 == PyCPointerType_SetProto(stgdict, proto)) {
+ if (-1 == PyCPointerType_SetProto(stginfo, proto)) {
Py_DECREF(proto);
- Py_DECREF((PyObject *)stgdict);
- return NULL;
+ return -1;
}
- itemdict = PyType_stgdict(proto);
- /* PyCPointerType_SetProto has verified proto has a stgdict. */
- assert(itemdict);
- /* If itemdict->format is NULL, then this is a pointer to an
+ StgInfo *iteminfo;
+ if (PyStgInfo_FromType(st, proto, &iteminfo) < 0) {
+ Py_DECREF(proto);
+ return -1;
+ }
+ /* PyCPointerType_SetProto has verified proto has a stginfo. */
+ assert(iteminfo);
+ /* If iteminfo->format is NULL, then this is a pointer to an
incomplete type. We create a generic format string
'pointer to bytes' in this case. XXX Better would be to
fix the format string later...
*/
- current_format = itemdict->format ? itemdict->format : "B";
- if (itemdict->shape != NULL) {
+ current_format = iteminfo->format ? iteminfo->format : "B";
+ if (iteminfo->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);
+ stginfo->format = _ctypes_alloc_format_string_with_shape(
+ iteminfo->ndim, iteminfo->shape, "&", current_format);
} else {
- stgdict->format = _ctypes_alloc_format_string("&", current_format);
+ stginfo->format = _ctypes_alloc_format_string("&", current_format);
}
Py_DECREF(proto);
- if (stgdict->format == NULL) {
- Py_DECREF((PyObject *)stgdict);
- return NULL;
+ if (stginfo->format == NULL) {
+ return -1;
}
}
- /* create the new instance (which is a class,
- since we are a metatype!) */
- result = (PyTypeObject *)PyType_Type.tp_new(type, args, kwds);
- if (result == NULL) {
- Py_DECREF((PyObject *)stgdict);
- return NULL;
- }
-
- /* replace the class dict by our updated spam dict */
- if (-1 == PyDict_Update((PyObject *)stgdict, result->tp_dict)) {
- Py_DECREF(result);
- Py_DECREF((PyObject *)stgdict);
- return NULL;
- }
- Py_SETREF(result->tp_dict, (PyObject *)stgdict);
-
- return (PyObject *)result;
+ return 0;
}
static PyObject *
PyCPointerType_set_type(PyTypeObject *self, PyObject *type)
{
- StgDictObject *dict;
-
-
- dict = PyType_stgdict((PyObject *)self);
- if (!dict) {
+ PyObject *attrdict = PyType_GetDict(self);
+ if (!attrdict) {
+ return NULL;
+ }
+ ctypes_state *st = GLOBAL_STATE();
+ StgInfo *info;
+ if (PyStgInfo_FromType(st, (PyObject *)self, &info) < 0) {
+ Py_DECREF(attrdict);
+ return NULL;
+ }
+ if (!info) {
PyErr_SetString(PyExc_TypeError,
"abstract class");
+ Py_DECREF(attrdict);
return NULL;
}
- if (-1 == PyCPointerType_SetProto(dict, type))
+ if (-1 == PyCPointerType_SetProto(info, type)) {
+ Py_DECREF(attrdict);
return NULL;
+ }
- if (-1 == PyDict_SetItem((PyObject *)dict, &_Py_ID(_type_), type))
+ if (-1 == PyDict_SetItem(attrdict, &_Py_ID(_type_), type)) {
+ Py_DECREF(attrdict);
return NULL;
+ }
+ Py_DECREF(attrdict);
Py_RETURN_NONE;
}
@@ -1139,15 +1249,17 @@ static PyObject *_byref(PyObject *);
static PyObject *
PyCPointerType_from_param(PyObject *type, PyObject *value)
{
- StgDictObject *typedict;
-
if (value == Py_None) {
/* ConvParam will convert to a NULL pointer later */
return Py_NewRef(value);
}
- typedict = PyType_stgdict(type);
- if (!typedict) {
+ ctypes_state *st = GLOBAL_STATE();
+ StgInfo *typeinfo;
+ if (PyStgInfo_FromType(st, type, &typeinfo) < 0) {
+ return NULL;
+ }
+ if (!typeinfo) {
PyErr_SetString(PyExc_TypeError,
"abstract class");
return NULL;
@@ -1156,7 +1268,8 @@ PyCPointerType_from_param(PyObject *type, PyObject *value)
/* If we expect POINTER(<type>), but receive a <type> instance, accept
it by calling byref(<type>).
*/
- switch (PyObject_IsInstance(value, typedict->proto)) {
+ assert(typeinfo->proto);
+ switch (PyObject_IsInstance(value, typeinfo->proto)) {
case 1:
Py_INCREF(value); /* _byref steals a refcount */
return _byref(value);
@@ -1166,14 +1279,16 @@ PyCPointerType_from_param(PyObject *type, PyObject *value)
break;
}
- ctypes_state *st = GLOBAL_STATE();
if (PointerObject_Check(st, value) || ArrayObject_Check(st, value)) {
/* Array instances are also pointers when
the item types are the same.
*/
- StgDictObject *v = PyObject_stgdict(value);
+ StgInfo *v;
+ if (PyStgInfo_FromObject(st, value, &v) < 0) {
+ return NULL;
+ }
assert(v); /* Cannot be NULL for pointer or array objects */
- int ret = PyObject_IsSubclass(v->proto, typedict->proto);
+ int ret = PyObject_IsSubclass(v->proto, typeinfo->proto);
if (ret < 0) {
return NULL;
}
@@ -1199,7 +1314,7 @@ static PyType_Slot pycpointer_type_slots[] = {
{Py_tp_traverse, CDataType_traverse},
{Py_tp_clear, CDataType_clear},
{Py_tp_methods, PyCPointerType_methods},
- {Py_tp_new, PyCPointerType_new},
+ {Py_tp_init, PyCPointerType_init},
// Sequence protocol.
{Py_sq_repeat, CDataType_repeat},
@@ -1219,7 +1334,7 @@ static PyType_Spec pycpointer_type_spec = {
PyCArrayType_Type
*/
/*
- PyCArrayType_new ensures that the new Array subclass created has a _length_
+ PyCArrayType_init ensures that the new Array subclass created has a _length_
attribute, and a _type_ attribute.
*/
@@ -1403,28 +1518,18 @@ PyCArrayType_paramfunc(CDataObject *self)
return p;
}
-static PyObject *
-PyCArrayType_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+static int
+PyCArrayType_init(PyObject *self, PyObject *args, PyObject *kwds)
{
- PyTypeObject *result;
- StgDictObject *stgdict;
- StgDictObject *itemdict;
PyObject *length_attr, *type_attr;
Py_ssize_t length;
Py_ssize_t itemsize, itemalign;
- /* create the new instance (which is a class,
- since we are a metatype!) */
- result = (PyTypeObject *)PyType_Type.tp_new(type, args, kwds);
- if (result == NULL)
- return NULL;
-
/* Initialize these variables to NULL so that we can simplify error
handling by using Py_XDECREF. */
- stgdict = NULL;
type_attr = NULL;
- if (PyObject_GetOptionalAttr((PyObject *)result, &_Py_ID(_length_), &length_attr) < 0) {
+ if (PyObject_GetOptionalAttr(self, &_Py_ID(_length_), &length_attr) < 0) {
goto error;
}
if (!length_attr) {
@@ -1457,7 +1562,7 @@ PyCArrayType_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
goto error;
}
- if (PyObject_GetOptionalAttr((PyObject *)result, &_Py_ID(_type_), &type_attr) < 0) {
+ if (PyObject_GetOptionalAttr(self, &_Py_ID(_type_), &type_attr) < 0) {
goto error;
}
if (!type_attr) {
@@ -1467,88 +1572,83 @@ PyCArrayType_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
}
ctypes_state *st = GLOBAL_STATE();
- stgdict = (StgDictObject *)_PyObject_CallNoArgs(
- (PyObject *)st->PyCStgDict_Type);
- if (!stgdict) {
+ StgInfo *stginfo = PyStgInfo_Init(st, (PyTypeObject*)self);
+ if (!stginfo) {
+ goto error;
+ }
+
+ StgInfo *iteminfo;
+ if (PyStgInfo_FromType(st, type_attr, &iteminfo) < 0) {
goto error;
}
- itemdict = PyType_stgdict(type_attr);
- if (!itemdict) {
+ if (!iteminfo) {
PyErr_SetString(PyExc_TypeError,
"_type_ must have storage info");
goto error;
}
- assert(itemdict->format);
- stgdict->format = _ctypes_alloc_format_string(NULL, itemdict->format);
- if (stgdict->format == NULL)
+ assert(iteminfo->format);
+ stginfo->format = _ctypes_alloc_format_string(NULL, iteminfo->format);
+ if (stginfo->format == NULL)
goto error;
- stgdict->ndim = itemdict->ndim + 1;
- stgdict->shape = PyMem_Malloc(sizeof(Py_ssize_t) * stgdict->ndim);
- if (stgdict->shape == NULL) {
+ stginfo->ndim = iteminfo->ndim + 1;
+ stginfo->shape = PyMem_Malloc(sizeof(Py_ssize_t) * stginfo->ndim);
+ if (stginfo->shape == NULL) {
PyErr_NoMemory();
goto error;
}
- stgdict->shape[0] = length;
- if (stgdict->ndim > 1) {
- memmove(&stgdict->shape[1], itemdict->shape,
- sizeof(Py_ssize_t) * (stgdict->ndim - 1));
+ stginfo->shape[0] = length;
+ if (stginfo->ndim > 1) {
+ memmove(&stginfo->shape[1], iteminfo->shape,
+ sizeof(Py_ssize_t) * (stginfo->ndim - 1));
}
- itemsize = itemdict->size;
+ itemsize = iteminfo->size;
if (itemsize != 0 && length > PY_SSIZE_T_MAX / itemsize) {
PyErr_SetString(PyExc_OverflowError,
"array too large");
goto error;
}
- itemalign = itemdict->align;
+ itemalign = iteminfo->align;
- if (itemdict->flags & (TYPEFLAG_ISPOINTER | TYPEFLAG_HASPOINTER))
- stgdict->flags |= TYPEFLAG_HASPOINTER;
+ if (iteminfo->flags & (TYPEFLAG_ISPOINTER | TYPEFLAG_HASPOINTER))
+ stginfo->flags |= TYPEFLAG_HASPOINTER;
- stgdict->size = itemsize * length;
- stgdict->align = itemalign;
- stgdict->length = length;
- stgdict->proto = type_attr;
+ stginfo->size = itemsize * length;
+ stginfo->align = itemalign;
+ stginfo->length = length;
+ stginfo->proto = type_attr;
type_attr = NULL;
- stgdict->paramfunc = &PyCArrayType_paramfunc;
+ stginfo->paramfunc = &PyCArrayType_paramfunc;
/* Arrays are passed as pointers to function calls. */
- stgdict->ffi_type_pointer = ffi_type_pointer;
-
- /* replace the class dict by our updated spam dict */
- if (-1 == PyDict_Update((PyObject *)stgdict, result->tp_dict))
- goto error;
- Py_SETREF(result->tp_dict, (PyObject *)stgdict); /* steal the reference */
- stgdict = NULL;
+ stginfo->ffi_type_pointer = ffi_type_pointer;
/* Special case for character arrays.
A permanent annoyance: char arrays are also strings!
*/
- if (itemdict->getfunc == _ctypes_get_fielddesc("c")->getfunc) {
- if (-1 == add_getset(result, CharArray_getsets))
+ if (iteminfo->getfunc == _ctypes_get_fielddesc("c")->getfunc) {
+ if (-1 == add_getset((PyTypeObject*)self, CharArray_getsets))
goto error;
}
- else if (itemdict->getfunc == _ctypes_get_fielddesc("u")->getfunc) {
- if (-1 == add_getset(result, WCharArray_getsets))
+ else if (iteminfo->getfunc == _ctypes_get_fielddesc("u")->getfunc) {
+ if (-1 == add_getset((PyTypeObject*)self, WCharArray_getsets))
goto error;
}
- return (PyObject *)result;
+ return 0;
error:
- Py_XDECREF((PyObject*)stgdict);
Py_XDECREF(type_attr);
- Py_DECREF(result);
- return NULL;
+ return -1;
}
static PyType_Slot pycarray_type_slots[] = {
{Py_tp_doc, PyDoc_STR("metatype for the Array Objects")},
{Py_tp_traverse, CDataType_traverse},
{Py_tp_methods, CDataType_methods},
- {Py_tp_new, PyCArrayType_new},
+ {Py_tp_init, PyCArrayType_init},
{Py_tp_clear, CDataType_clear},
// Sequence protocol.
@@ -1569,7 +1669,7 @@ static PyType_Spec pycarray_type_spec = {
*/
/*
-PyCSimpleType_new ensures that the new Simple_Type subclass created has a valid
+PyCSimpleType_init ensures that the new Simple_Type subclass created has a valid
_type_ attribute.
*/
@@ -1609,19 +1709,29 @@ c_wchar_p_from_param(PyObject *type, PyObject *value)
ctypes_state *st = GLOBAL_STATE();
if (ArrayObject_Check(st, value) || PointerObject_Check(st, value)) {
/* c_wchar array instance or pointer(c_wchar(...)) */
- StgDictObject *dt = PyObject_stgdict(value);
- StgDictObject *dict;
- assert(dt); /* Cannot be NULL for pointer or array objects */
- dict = dt && dt->proto ? PyType_stgdict(dt->proto) : NULL;
- if (dict && (dict->setfunc == _ctypes_get_fielddesc("u")->setfunc)) {
+ StgInfo *it;
+ if (PyStgInfo_FromObject(st, value, &it) < 0) {
+ return NULL;
+ }
+ assert(it); /* Cannot be NULL for pointer or array objects */
+ StgInfo *info = NULL;
+ if (it && it->proto) {
+ if (PyStgInfo_FromType(st, it->proto, &info) < 0) {
+ return NULL;
+ }
+ }
+ if (info && (info->setfunc == _ctypes_get_fielddesc("u")->setfunc)) {
return Py_NewRef(value);
}
}
if (PyCArg_CheckExact(st, value)) {
/* byref(c_char(...)) */
PyCArgObject *a = (PyCArgObject *)value;
- StgDictObject *dict = PyObject_stgdict(a->obj);
- if (dict && (dict->setfunc == _ctypes_get_fielddesc("u")->setfunc)) {
+ StgInfo *info;
+ if (PyStgInfo_FromObject(st, a->obj, &info) < 0) {
+ return NULL;
+ }
+ if (info && (info->setfunc == _ctypes_get_fielddesc("u")->setfunc)) {
return Py_NewRef(value);
}
}
@@ -1673,19 +1783,29 @@ c_char_p_from_param(PyObject *type, PyObject *value)
ctypes_state *st = GLOBAL_STATE();
if (ArrayObject_Check(st, value) || PointerObject_Check(st, value)) {
/* c_char array instance or pointer(c_char(...)) */
- StgDictObject *dt = PyObject_stgdict(value);
- StgDictObject *dict;
- assert(dt); /* Cannot be NULL for pointer or array objects */
- dict = dt && dt->proto ? PyType_stgdict(dt->proto) : NULL;
- if (dict && (dict->setfunc == _ctypes_get_fielddesc("c")->setfunc)) {
+ StgInfo *it;
+ if (PyStgInfo_FromObject(st, value, &it) < 0) {
+ return NULL;
+ }
+ assert(it); /* Cannot be NULL for pointer or array objects */
+ StgInfo *info = NULL;
+ if (it && it->proto) {
+ if (PyStgInfo_FromType(st, it->proto, &info) < 0) {
+ return NULL;
+ }
+ }
+ if (info && (info->setfunc == _ctypes_get_fielddesc("c")->setfunc)) {
return Py_NewRef(value);
}
}
if (PyCArg_CheckExact(st, value)) {
/* byref(c_char(...)) */
PyCArgObject *a = (PyCArgObject *)value;
- StgDictObject *dict = PyObject_stgdict(a->obj);
- if (dict && (dict->setfunc == _ctypes_get_fielddesc("c")->setfunc)) {
+ StgInfo *info;
+ if (PyStgInfo_FromObject(st, a->obj, &info) < 0) {
+ return NULL;
+ }
+ if (info && (info->setfunc == _ctypes_get_fielddesc("c")->setfunc)) {
return Py_NewRef(value);
}
}
@@ -1707,7 +1827,6 @@ c_char_p_from_param(PyObject *type, PyObject *value)
static PyObject *
c_void_p_from_param(PyObject *type, PyObject *value)
{
- StgDictObject *stgd;
PyObject *as_parameter;
int res;
@@ -1806,15 +1925,18 @@ c_void_p_from_param(PyObject *type, PyObject *value)
return (PyObject *)parg;
}
/* c_char_p, c_wchar_p */
- stgd = PyObject_stgdict(value);
- if (stgd
+ StgInfo *stgi;
+ if (PyStgInfo_FromObject(st, value, &stgi) < 0) {
+ return NULL;
+ }
+ if (stgi
&& CDataObject_Check(st, value)
- && stgd->proto
- && PyUnicode_Check(stgd->proto))
+ && stgi->proto
+ && PyUnicode_Check(stgi->proto))
{
PyCArgObject *parg;
- switch (PyUnicode_AsUTF8(stgd->proto)[0]) {
+ switch (PyUnicode_AsUTF8(stgi->proto)[0]) {
case 'z': /* c_char_p */
case 'Z': /* c_wchar_p */
parg = PyCArgObject_new();
@@ -1851,7 +1973,6 @@ static PyObject *CreateSwappedType(PyTypeObject *type, PyObject *args, PyObject
PyObject *proto, struct fielddesc *fmt)
{
PyTypeObject *result;
- StgDictObject *stgdict;
PyObject *name = PyTuple_GET_ITEM(args, 0);
PyObject *newname;
PyObject *swapped_args;
@@ -1894,29 +2015,21 @@ static PyObject *CreateSwappedType(PyTypeObject *type, PyObject *args, PyObject
return NULL;
ctypes_state *st = GLOBAL_STATE();
- stgdict = (StgDictObject *)_PyObject_CallNoArgs(
- (PyObject *)st->PyCStgDict_Type);
- if (!stgdict) {
+
+ StgInfo *stginfo = PyStgInfo_Init(st, result);
+ if (!stginfo) {
Py_DECREF(result);
return NULL;
}
- stgdict->ffi_type_pointer = *fmt->pffi_type;
- stgdict->align = fmt->pffi_type->alignment;
- stgdict->length = 0;
- stgdict->size = fmt->pffi_type->size;
- stgdict->setfunc = fmt->setfunc_swapped;
- stgdict->getfunc = fmt->getfunc_swapped;
+ stginfo->ffi_type_pointer = *fmt->pffi_type;
+ stginfo->align = fmt->pffi_type->alignment;
+ stginfo->length = 0;
+ stginfo->size = fmt->pffi_type->size;
+ stginfo->setfunc = fmt->setfunc_swapped;
+ stginfo->getfunc = fmt->getfunc_swapped;
- stgdict->proto = Py_NewRef(proto);
-
- /* replace the class dict by our updated spam dict */
- if (-1 == PyDict_Update((PyObject *)stgdict, result->tp_dict)) {
- Py_DECREF(result);
- Py_DECREF((PyObject *)stgdict);
- return NULL;
- }
- Py_SETREF(result->tp_dict, (PyObject *)stgdict);
+ stginfo->proto = Py_NewRef(proto);
return (PyObject *)result;
}
@@ -1924,14 +2037,17 @@ static PyObject *CreateSwappedType(PyTypeObject *type, PyObject *args, PyObject
static PyCArgObject *
PyCSimpleType_paramfunc(CDataObject *self)
{
- StgDictObject *dict;
const char *fmt;
PyCArgObject *parg;
struct fielddesc *fd;
- dict = PyObject_stgdict((PyObject *)self);
- assert(dict); /* Cannot be NULL for CDataObject instances */
- fmt = PyUnicode_AsUTF8(dict->proto);
+ ctypes_state *st = GLOBAL_STATE();
+ StgInfo *info;
+ if (PyStgInfo_FromObject(st, (PyObject *)self, &info) < 0) {
+ return NULL;
+ }
+ assert(info); /* Cannot be NULL for CDataObject instances */
+ fmt = PyUnicode_AsUTF8(info->proto);
assert(fmt);
fd = _ctypes_get_fielddesc(fmt);
@@ -1948,33 +2064,27 @@ PyCSimpleType_paramfunc(CDataObject *self)
return parg;
}
-static PyObject *
-PyCSimpleType_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+static int
+PyCSimpleType_init(PyObject *self, PyObject *args, PyObject *kwds)
{
- PyTypeObject *result;
- StgDictObject *stgdict;
PyObject *proto;
const char *proto_str;
Py_ssize_t proto_len;
PyMethodDef *ml;
struct fielddesc *fmt;
- /* create the new instance (which is a class,
- since we are a metatype!) */
- result = (PyTypeObject *)PyType_Type.tp_new(type, args, kwds);
- if (result == NULL)
- return NULL;
-
- if (PyObject_GetOptionalAttr((PyObject *)result, &_Py_ID(_type_), &proto) < 0) {
- return NULL;
+ if (PyType_Type.tp_init(self, args, kwds) < 0) {
+ return -1;
+ }
+ if (PyObject_GetOptionalAttr(self, &_Py_ID(_type_), &proto) < 0) {
+ return -1;
}
if (!proto) {
PyErr_SetString(PyExc_AttributeError,
"class must define a '_type_' attribute");
error:
Py_XDECREF(proto);
- Py_DECREF(result);
- return NULL;
+ return -1;
}
if (PyUnicode_Check(proto)) {
proto_str = PyUnicode_AsUTF8AndSize(proto, &proto_len);
@@ -2006,70 +2116,60 @@ PyCSimpleType_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
}
ctypes_state *st = GLOBAL_STATE();
- stgdict = (StgDictObject *)_PyObject_CallNoArgs(
- (PyObject *)st->PyCStgDict_Type);
- if (!stgdict) {
+ StgInfo *stginfo = PyStgInfo_Init(st, (PyTypeObject *)self);
+ if (!stginfo) {
goto error;
}
- stgdict->ffi_type_pointer = *fmt->pffi_type;
- stgdict->align = fmt->pffi_type->alignment;
- stgdict->length = 0;
- stgdict->size = fmt->pffi_type->size;
- stgdict->setfunc = fmt->setfunc;
- stgdict->getfunc = fmt->getfunc;
+
+ stginfo->ffi_type_pointer = *fmt->pffi_type;
+ stginfo->align = fmt->pffi_type->alignment;
+ stginfo->length = 0;
+ stginfo->size = fmt->pffi_type->size;
+ stginfo->setfunc = fmt->setfunc;
+ stginfo->getfunc = fmt->getfunc;
#ifdef WORDS_BIGENDIAN
- stgdict->format = _ctypes_alloc_format_string_for_type(proto_str[0], 1);
+ stginfo->format = _ctypes_alloc_format_string_for_type(proto_str[0], 1);
#else
- stgdict->format = _ctypes_alloc_format_string_for_type(proto_str[0], 0);
+ stginfo->format = _ctypes_alloc_format_string_for_type(proto_str[0], 0);
#endif
- if (stgdict->format == NULL) {
- Py_DECREF(result);
+ if (stginfo->format == NULL) {
Py_DECREF(proto);
- Py_DECREF((PyObject *)stgdict);
- return NULL;
+ return -1;
}
- stgdict->paramfunc = PyCSimpleType_paramfunc;
+ stginfo->paramfunc = PyCSimpleType_paramfunc;
/*
- if (result->tp_base != st->Simple_Type) {
- stgdict->setfunc = NULL;
- stgdict->getfunc = NULL;
+ if (self->tp_base != st->Simple_Type) {
+ stginfo->setfunc = NULL;
+ stginfo->getfunc = NULL;
}
*/
/* This consumes the refcount on proto which we have */
- stgdict->proto = proto;
-
- /* replace the class dict by our updated spam dict */
- if (-1 == PyDict_Update((PyObject *)stgdict, result->tp_dict)) {
- Py_DECREF(result);
- Py_DECREF((PyObject *)stgdict);
- return NULL;
- }
- Py_SETREF(result->tp_dict, (PyObject *)stgdict);
+ stginfo->proto = proto;
/* Install from_param class methods in ctypes base classes.
Overrides the PyCSimpleType_from_param generic method.
*/
- if (result->tp_base == st->Simple_Type) {
+ if (((PyTypeObject *)self)->tp_base == st->Simple_Type) {
switch (*proto_str) {
case 'z': /* c_char_p */
ml = &c_char_p_method;
- stgdict->flags |= TYPEFLAG_ISPOINTER;
+ stginfo->flags |= TYPEFLAG_ISPOINTER;
break;
case 'Z': /* c_wchar_p */
ml = &c_wchar_p_method;
- stgdict->flags |= TYPEFLAG_ISPOINTER;
+ stginfo->flags |= TYPEFLAG_ISPOINTER;
break;
case 'P': /* c_void_p */
ml = &c_void_p_method;
- stgdict->flags |= TYPEFLAG_ISPOINTER;
+ stginfo->flags |= TYPEFLAG_ISPOINTER;
break;
case 's':
case 'X':
case 'O':
ml = NULL;
- stgdict->flags |= TYPEFLAG_ISPOINTER;
+ stginfo->flags |= TYPEFLAG_ISPOINTER;
break;
default:
ml = NULL;
@@ -2079,57 +2179,57 @@ PyCSimpleType_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
if (ml) {
PyObject *meth;
int x;
- meth = PyDescr_NewClassMethod(result, ml);
+ meth = PyDescr_NewClassMethod((PyTypeObject*)self, ml);
if (!meth) {
- Py_DECREF(result);
- return NULL;
+ return -1;
}
- x = PyDict_SetItemString(result->tp_dict,
+ x = PyDict_SetItemString(((PyTypeObject*)self)->tp_dict,
ml->ml_name,
meth);
Py_DECREF(meth);
if (x == -1) {
- Py_DECREF(result);
- return NULL;
+ return -1;
}
}
}
+ PyTypeObject *type = Py_TYPE(self);
if (type == st->PyCSimpleType_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;
+ return -1;
}
- sw_dict = PyType_stgdict(swapped);
+ StgInfo *sw_info;
+ if (PyStgInfo_FromType(st, swapped, &sw_info) < 0) {
+ return -1;
+ }
+ assert(sw_info);
#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(self, "__ctype_le__", swapped);
+ PyObject_SetAttrString(self, "__ctype_be__", self);
+ PyObject_SetAttrString(swapped, "__ctype_be__", self);
PyObject_SetAttrString(swapped, "__ctype_le__", swapped);
/* We are creating the type for the OTHER endian */
- sw_dict->format = _ctypes_alloc_format_string("<", stgdict->format+1);
+ sw_info->format = _ctypes_alloc_format_string("<", stginfo->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(self, "__ctype_be__", swapped);
+ PyObject_SetAttrString(self, "__ctype_le__", self);
+ PyObject_SetAttrString(swapped, "__ctype_le__", self);
PyObject_SetAttrString(swapped, "__ctype_be__", swapped);
/* We are creating the type for the OTHER endian */
- sw_dict->format = _ctypes_alloc_format_string(">", stgdict->format+1);
+ sw_info->format = _ctypes_alloc_format_string(">", stginfo->format+1);
#endif
Py_DECREF(swapped);
if (PyErr_Occurred()) {
- Py_DECREF(result);
- return NULL;
+ return -1;
}
};
- return (PyObject *)result;
+ return 0;
}
/*
@@ -2139,7 +2239,6 @@ PyCSimpleType_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
static PyObject *
PyCSimpleType_from_param(PyObject *type, PyObject *value)
{
- StgDictObject *dict;
const char *fmt;
PyCArgObject *parg;
struct fielddesc *fd;
@@ -2155,15 +2254,19 @@ PyCSimpleType_from_param(PyObject *type, PyObject *value)
return Py_NewRef(value);
}
- dict = PyType_stgdict(type);
- if (!dict) {
+ ctypes_state *st = GLOBAL_STATE();
+ StgInfo *info;
+ if (PyStgInfo_FromType(st, type, &info) < 0) {
+ return NULL;
+ }
+ if (!info) {
PyErr_SetString(PyExc_TypeError,
"abstract class");
return NULL;
}
/* I think we can rely on this being a one-character string */
- fmt = PyUnicode_AsUTF8(dict->proto);
+ fmt = PyUnicode_AsUTF8(info->proto);
assert(fmt);
fd = _ctypes_get_fielddesc(fmt);
@@ -2218,7 +2321,7 @@ static PyMethodDef PyCSimpleType_methods[] = {
static PyType_Slot pycsimple_type_slots[] = {
{Py_tp_doc, PyDoc_STR("metatype for the PyCSimpleType Objects")},
{Py_tp_methods, PyCSimpleType_methods},
- {Py_tp_new, PyCSimpleType_new},
+ {Py_tp_init, PyCSimpleType_init},
{Py_tp_traverse, CDataType_traverse},
{Py_tp_clear, CDataType_clear},
@@ -2227,7 +2330,7 @@ static PyType_Slot pycsimple_type_slots[] = {
{0, NULL},
};
-PyType_Spec pycsimple_type_spec = {
+static PyType_Spec pycsimple_type_spec = {
.name = "_ctypes.PyCSimpleType",
.flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC |
Py_TPFLAGS_IMMUTABLETYPE),
@@ -2292,10 +2395,13 @@ converters_from_argtypes(PyObject *ob)
* not bitfields, the bitfields check is also being disabled as a
* precaution.
- StgDictObject *stgdict = PyType_stgdict(tp);
+ StgInfo *stginfo;
+ if (PyStgInfo_FromType(st, tp, &stginfo) < 0) {
+ return -1;
+ }
- if (stgdict != NULL) {
- if (stgdict->flags & TYPEFLAG_HASUNION) {
+ if (stginfo != NULL) {
+ if (stginfo->flags & TYPEFLAG_HASUNION) {
Py_DECREF(converters);
Py_DECREF(ob);
if (!PyErr_Occurred()) {
@@ -2306,7 +2412,7 @@ converters_from_argtypes(PyObject *ob)
}
return NULL;
}
- if (stgdict->flags & TYPEFLAG_HASBITFIELD) {
+ if (stginfo->flags & TYPEFLAG_HASBITFIELD) {
Py_DECREF(converters);
Py_DECREF(ob);
if (!PyErr_Occurred()) {
@@ -2338,19 +2444,19 @@ converters_from_argtypes(PyObject *ob)
}
static int
-make_funcptrtype_dict(StgDictObject *stgdict)
+make_funcptrtype_dict(PyObject *attrdict, StgInfo *stginfo)
{
PyObject *ob;
PyObject *converters = NULL;
- stgdict->align = _ctypes_get_fielddesc("P")->pffi_type->alignment;
- stgdict->length = 1;
- stgdict->size = sizeof(void *);
- stgdict->setfunc = NULL;
- stgdict->getfunc = NULL;
- stgdict->ffi_type_pointer = ffi_type_pointer;
+ stginfo->align = _ctypes_get_fielddesc("P")->pffi_type->alignment;
+ stginfo->length = 1;
+ stginfo->size = sizeof(void *);
+ stginfo->setfunc = NULL;
+ stginfo->getfunc = NULL;
+ stginfo->ffi_type_pointer = ffi_type_pointer;
- if (PyDict_GetItemRef((PyObject *)stgdict, &_Py_ID(_flags_), &ob) < 0) {
+ if (PyDict_GetItemRef((PyObject *)attrdict, &_Py_ID(_flags_), &ob) < 0) {
return -1;
}
if (!ob || !PyLong_Check(ob)) {
@@ -2359,11 +2465,11 @@ make_funcptrtype_dict(StgDictObject *stgdict)
Py_XDECREF(ob);
return -1;
}
- stgdict->flags = PyLong_AsUnsignedLongMask(ob) | TYPEFLAG_ISPOINTER;
+ stginfo->flags = PyLong_AsUnsignedLongMask(ob) | TYPEFLAG_ISPOINTER;
Py_DECREF(ob);
/* _argtypes_ is optional... */
- if (PyDict_GetItemRef((PyObject *)stgdict, &_Py_ID(_argtypes_), &ob) < 0) {
+ if (PyDict_GetItemRef((PyObject *)attrdict, &_Py_ID(_argtypes_), &ob) < 0) {
return -1;
}
if (ob) {
@@ -2372,29 +2478,34 @@ make_funcptrtype_dict(StgDictObject *stgdict)
Py_DECREF(ob);
return -1;
}
- stgdict->argtypes = ob;
- stgdict->converters = converters;
+ stginfo->argtypes = ob;
+ stginfo->converters = converters;
}
- if (PyDict_GetItemRef((PyObject *)stgdict, &_Py_ID(_restype_), &ob) < 0) {
+ if (PyDict_GetItemRef((PyObject *)attrdict, &_Py_ID(_restype_), &ob) < 0) {
return -1;
}
if (ob) {
- if (ob != Py_None && !PyType_stgdict(ob) && !PyCallable_Check(ob)) {
+ StgInfo *info;
+ ctypes_state *st = GLOBAL_STATE();
+ if (PyStgInfo_FromType(st, ob, &info) < 0) {
+ return -1;
+ }
+ if (ob != Py_None && !info && !PyCallable_Check(ob)) {
PyErr_SetString(PyExc_TypeError,
"_restype_ must be a type, a callable, or None");
Py_DECREF(ob);
return -1;
}
- stgdict->restype = ob;
+ stginfo->restype = ob;
if (PyObject_GetOptionalAttr(ob, &_Py_ID(_check_retval_),
- &stgdict->checker) < 0)
+ &stginfo->checker) < 0)
{
return -1;
}
}
/* XXX later, maybe.
- if (PyDict_GetItemRef((PyObject *)stgdict, &_Py _ID(_errcheck_), &ob) < 0) {
+ if (PyDict_GetItemRef((PyObject *)attrdict, &_Py _ID(_errcheck_), &ob) < 0) {
return -1;
}
if (ob) {
@@ -2404,7 +2515,7 @@ make_funcptrtype_dict(StgDictObject *stgdict)
Py_DECREF(ob);
return -1;
}
- stgdict->errcheck = ob;
+ stginfo->errcheck = ob;
}
*/
return 0;
@@ -2426,54 +2537,43 @@ PyCFuncPtrType_paramfunc(CDataObject *self)
return parg;
}
-static PyObject *
-PyCFuncPtrType_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+static int
+PyCFuncPtrType_init(PyObject *self, PyObject *args, PyObject *kwds)
{
- PyTypeObject *result;
- StgDictObject *stgdict;
+ PyObject *attrdict = PyType_GetDict((PyTypeObject *)self);
+ if (!attrdict) {
+ return -1;
+ }
ctypes_state *st = GLOBAL_STATE();
- stgdict = (StgDictObject *)_PyObject_CallNoArgs(
- (PyObject *)st->PyCStgDict_Type);
- if (!stgdict) {
- return NULL;
+ StgInfo *stginfo = PyStgInfo_Init(st, (PyTypeObject *)self);
+ if (!stginfo) {
+ Py_DECREF(attrdict);
+ return -1;
}
- stgdict->paramfunc = PyCFuncPtrType_paramfunc;
+
+ stginfo->paramfunc = PyCFuncPtrType_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 = _ctypes_alloc_format_string(NULL, "X{}");
- if (stgdict->format == NULL) {
- Py_DECREF((PyObject *)stgdict);
- return NULL;
- }
- stgdict->flags |= TYPEFLAG_ISPOINTER;
-
- /* create the new instance (which is a class,
- since we are a metatype!) */
- result = (PyTypeObject *)PyType_Type.tp_new(type, args, kwds);
- if (result == NULL) {
- Py_DECREF((PyObject *)stgdict);
- return NULL;
- }
-
- /* replace the class dict by our updated storage dict */
- if (-1 == PyDict_Update((PyObject *)stgdict, result->tp_dict)) {
- Py_DECREF(result);
- Py_DECREF((PyObject *)stgdict);
- return NULL;
+ stginfo->format = _ctypes_alloc_format_string(NULL, "X{}");
+ if (stginfo->format == NULL) {
+ Py_DECREF(attrdict);
+ return -1;
}
- Py_SETREF(result->tp_dict, (PyObject *)stgdict);
+ stginfo->flags |= TYPEFLAG_ISPOINTER;
- if (-1 == make_funcptrtype_dict(stgdict)) {
- Py_DECREF(result);
- return NULL;
+ if (-1 == make_funcptrtype_dict(attrdict, stginfo)) {
+ Py_DECREF(attrdict);
+ return -1;
}
- return (PyObject *)result;
+ Py_DECREF(attrdict);
+ return 0;
}
static PyType_Slot pycfuncptr_type_slots[] = {
@@ -2481,7 +2581,7 @@ static PyType_Slot pycfuncptr_type_slots[] = {
{Py_tp_traverse, CDataType_traverse},
{Py_tp_clear, CDataType_clear},
{Py_tp_methods, CDataType_methods},
- {Py_tp_new, PyCFuncPtrType_new},
+ {Py_tp_init, PyCFuncPtrType_init},
// Sequence protocol.
{Py_sq_repeat, CDataType_repeat},
@@ -2609,6 +2709,8 @@ PyCData_traverse(CDataObject *self, visitproc visit, void *arg)
{
Py_VISIT(self->b_objects);
Py_VISIT((PyObject *)self->b_base);
+ PyTypeObject *type = Py_TYPE(self);
+ Py_VISIT(type);
return 0;
}
@@ -2627,8 +2729,11 @@ PyCData_clear(CDataObject *self)
static void
PyCData_dealloc(PyObject *self)
{
+ PyTypeObject *type = Py_TYPE(self);
+ PyObject_GC_UnTrack(self);
PyCData_clear((CDataObject *)self);
- Py_TYPE(self)->tp_free(self);
+ type->tp_free(self);
+ Py_DECREF(type);
}
static PyMemberDef PyCData_members[] = {
@@ -2650,13 +2755,15 @@ PyCData_item_type(PyObject *type)
{
ctypes_state *st = GLOBAL_STATE();
if (PyCArrayTypeObject_Check(st, type)) {
- StgDictObject *stg_dict;
PyObject *elem_type;
/* asserts used here as these are all guaranteed by construction */
- stg_dict = PyType_stgdict(type);
- assert(stg_dict);
- elem_type = stg_dict->proto;
+ StgInfo *stg_info;
+ if (PyStgInfo_FromType(st, type, &stg_info) < 0) {
+ return NULL;
+ }
+ assert(stg_info);
+ elem_type = stg_info->proto;
assert(elem_type);
return PyCData_item_type(elem_type);
}
@@ -2669,32 +2776,42 @@ static int
PyCData_NewGetBuffer(PyObject *myself, Py_buffer *view, int flags)
{
CDataObject *self = (CDataObject *)myself;
- StgDictObject *dict = PyObject_stgdict(myself);
+
+ ctypes_state *st = GLOBAL_STATE();
+ StgInfo *info;
+ if (PyStgInfo_FromObject(st, myself, &info) < 0) {
+ return -1;
+ }
+ assert(info);
+
PyObject *item_type = PyCData_item_type((PyObject*)Py_TYPE(myself));
- StgDictObject *item_dict = PyType_stgdict(item_type);
+ if (item_type == NULL) {
+ return 0;
+ }
if (view == NULL) return 0;
+ StgInfo *item_info;
+ if (PyStgInfo_FromType(st, item_type, &item_info) < 0) {
+ return -1;
+ }
+ assert(item_info);
+
view->buf = self->b_ptr;
view->obj = Py_NewRef(myself);
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 = item_dict->size;
+ view->format = info->format ? info->format : "B";
+ view->ndim = info->ndim;
+ view->shape = info->shape;
+ view->itemsize = item_info->size;
view->strides = NULL;
view->suboffsets = NULL;
view->internal = NULL;
return 0;
}
-static PyBufferProcs PyCData_as_buffer = {
- PyCData_NewGetBuffer,
- NULL,
-};
-
/*
* CData objects are mutable, so they cannot be hashable!
*/
@@ -2710,7 +2827,14 @@ PyCData_reduce(PyObject *myself, PyObject *args)
{
CDataObject *self = (CDataObject *)myself;
- if (PyObject_stgdict(myself)->flags & (TYPEFLAG_ISPOINTER|TYPEFLAG_HASPOINTER)) {
+ ctypes_state *st = GLOBAL_STATE();
+ StgInfo *info;
+ if (PyStgInfo_FromObject(st, myself, &info) < 0) {
+ return NULL;
+ }
+ assert(info);
+
+ if (info->flags & (TYPEFLAG_ISPOINTER|TYPEFLAG_HASPOINTER)) {
PyErr_SetString(PyExc_ValueError,
"ctypes objects containing pointers cannot be pickled");
return NULL;
@@ -2773,51 +2897,30 @@ static PyMethodDef PyCData_methods[] = {
{ NULL, NULL },
};
-PyTypeObject PyCData_Type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- "_ctypes._CData",
- sizeof(CDataObject), /* tp_basicsize */
- 0, /* tp_itemsize */
- PyCData_dealloc, /* tp_dealloc */
- 0, /* tp_vectorcall_offset */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_as_async */
- 0, /* tp_repr */
- 0, /* tp_as_number */
- 0, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- PyCData_nohash, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- 0, /* tp_getattro */
- 0, /* tp_setattro */
- &PyCData_as_buffer, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
- PyDoc_STR("XXX to be provided"), /* tp_doc */
- (traverseproc)PyCData_traverse, /* tp_traverse */
- (inquiry)PyCData_clear, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
- 0, /* tp_iternext */
- PyCData_methods, /* tp_methods */
- PyCData_members, /* tp_members */
- 0, /* tp_getset */
- 0, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- 0, /* tp_init */
- 0, /* tp_alloc */
- 0, /* tp_new */
- 0, /* tp_free */
+static PyType_Slot pycdata_slots[] = {
+ {Py_tp_dealloc, PyCData_dealloc},
+ {Py_tp_hash, PyCData_nohash},
+ {Py_tp_doc, PyDoc_STR("XXX to be provided")},
+ {Py_tp_traverse, PyCData_traverse},
+ {Py_tp_clear, PyCData_clear},
+ {Py_tp_methods, PyCData_methods},
+ {Py_tp_members, PyCData_members},
+ {Py_bf_getbuffer, PyCData_NewGetBuffer},
+ {0, NULL},
};
-static int PyCData_MallocBuffer(CDataObject *obj, StgDictObject *dict)
+static PyType_Spec pycdata_spec = {
+ .name = "_ctypes._CData",
+ .basicsize = sizeof(CDataObject),
+ .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC |
+ Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_DISALLOW_INSTANTIATION),
+ .slots = pycdata_slots,
+};
+
+static int
+PyCData_MallocBuffer(CDataObject *obj, StgInfo *info)
{
- if ((size_t)dict->size <= sizeof(obj->b_value)) {
+ if ((size_t)info->size <= sizeof(obj->b_value)) {
/* No need to call malloc, can use the default buffer */
obj->b_ptr = (char *)&obj->b_value;
/* The b_needsfree flag does not mean that we actually did
@@ -2831,15 +2934,15 @@ static int PyCData_MallocBuffer(CDataObject *obj, StgDictObject *dict)
/* In python 2.4, and ctypes 0.9.6, the malloc call took about
33% of the creation time for c_int().
*/
- obj->b_ptr = (char *)PyMem_Malloc(dict->size);
+ obj->b_ptr = (char *)PyMem_Malloc(info->size);
if (obj->b_ptr == NULL) {
PyErr_NoMemory();
return -1;
}
obj->b_needsfree = 1;
- memset(obj->b_ptr, 0, dict->size);
+ memset(obj->b_ptr, 0, info->size);
}
- obj->b_size = dict->size;
+ obj->b_size = info->size;
return 0;
}
@@ -2847,23 +2950,28 @@ PyObject *
PyCData_FromBaseObj(PyObject *type, PyObject *base, Py_ssize_t index, char *adr)
{
CDataObject *cmem;
- StgDictObject *dict;
assert(PyType_Check(type));
- dict = PyType_stgdict(type);
- if (!dict) {
+
+ ctypes_state *st = GLOBAL_STATE();
+ StgInfo *info;
+ if (PyStgInfo_FromType(st, type, &info) < 0) {
+ return NULL;
+ }
+ if (!info) {
PyErr_SetString(PyExc_TypeError,
"abstract class");
return NULL;
}
- dict->flags |= DICTFLAG_FINAL;
+
+ info->flags |= DICTFLAG_FINAL;
cmem = (CDataObject *)((PyTypeObject *)type)->tp_alloc((PyTypeObject *)type, 0);
if (cmem == NULL) {
return NULL;
}
assert(CDataObject_Check(GLOBAL_STATE(), cmem));
- cmem->b_length = dict->length;
- cmem->b_size = dict->size;
+ cmem->b_length = info->length;
+ cmem->b_size = info->size;
if (base) { /* use base's buffer */
assert(CDataObject_Check(GLOBAL_STATE(), base));
cmem->b_ptr = adr;
@@ -2871,11 +2979,11 @@ PyCData_FromBaseObj(PyObject *type, PyObject *base, Py_ssize_t index, char *adr)
cmem->b_base = (CDataObject *)Py_NewRef(base);
cmem->b_index = index;
} else { /* copy contents of adr */
- if (-1 == PyCData_MallocBuffer(cmem, dict)) {
+ if (-1 == PyCData_MallocBuffer(cmem, info)) {
Py_DECREF(cmem);
return NULL;
}
- memcpy(cmem->b_ptr, adr, dict->size);
+ memcpy(cmem->b_ptr, adr, info->size);
cmem->b_index = index;
}
return (PyObject *)cmem;
@@ -2888,20 +2996,25 @@ PyObject *
PyCData_AtAddress(PyObject *type, void *buf)
{
CDataObject *pd;
- StgDictObject *dict;
if (PySys_Audit("ctypes.cdata", "n", (Py_ssize_t)buf) < 0) {
return NULL;
}
assert(PyType_Check(type));
- dict = PyType_stgdict(type);
- if (!dict) {
+
+ ctypes_state *st = GLOBAL_STATE();
+ StgInfo *info;
+ if (PyStgInfo_FromType(st, type, &info) < 0) {
+ return NULL;
+ }
+ if (!info) {
PyErr_SetString(PyExc_TypeError,
"abstract class");
return NULL;
}
- dict->flags |= DICTFLAG_FINAL;
+
+ info->flags |= DICTFLAG_FINAL;
pd = (CDataObject *)((PyTypeObject *)type)->tp_alloc((PyTypeObject *)type, 0);
if (!pd) {
@@ -2909,8 +3022,8 @@ PyCData_AtAddress(PyObject *type, void *buf)
}
assert(CDataObject_Check(GLOBAL_STATE(), pd));
pd->b_ptr = (char *)buf;
- pd->b_length = dict->length;
- pd->b_size = dict->size;
+ pd->b_length = info->length;
+ pd->b_size = info->size;
return (PyObject *)pd;
}
@@ -2934,13 +3047,16 @@ PyObject *
PyCData_get(PyObject *type, GETFUNC getfunc, PyObject *src,
Py_ssize_t index, Py_ssize_t size, char *adr)
{
- StgDictObject *dict;
if (getfunc)
return getfunc(adr, size);
assert(type);
- dict = PyType_stgdict(type);
- if (dict && dict->getfunc && !_ctypes_simple_instance(type))
- return dict->getfunc(adr, size);
+ ctypes_state *st = GLOBAL_STATE();
+ StgInfo *info;
+ if (PyStgInfo_FromType(st, type, &info) < 0) {
+ return NULL;
+ }
+ if (info && info->getfunc && !_ctypes_simple_instance(type))
+ return info->getfunc(adr, size);
return PyCData_FromBaseObj(type, src, index, adr);
}
@@ -2959,9 +3075,12 @@ _PyCData_set(CDataObject *dst, PyObject *type, SETFUNC setfunc, PyObject *value,
}
ctypes_state *st = GLOBAL_STATE();
if (!CDataObject_Check(st, value)) {
- StgDictObject *dict = PyType_stgdict(type);
- if (dict && dict->setfunc)
- return dict->setfunc(ptr, value, size);
+ StgInfo *info;
+ if (PyStgInfo_FromType(st, type, &info) < 0) {
+ return NULL;
+ }
+ if (info && info->setfunc)
+ return info->setfunc(ptr, value, size);
/*
If value is a tuple, we try to call the type with the tuple
and use the result!
@@ -3014,11 +3133,16 @@ _PyCData_set(CDataObject *dst, PyObject *type, SETFUNC setfunc, PyObject *value,
if (PyCPointerTypeObject_Check(st, type)
&& ArrayObject_Check(st, value)) {
- StgDictObject *p1, *p2;
PyObject *keep;
- p1 = PyObject_stgdict(value);
+
+ StgInfo *p1, *p2;
+ if (PyStgInfo_FromObject(st, value, &p1) < 0) {
+ return NULL;
+ }
assert(p1); /* Cannot be NULL for array instances */
- p2 = PyType_stgdict(type);
+ if (PyStgInfo_FromType(st, type, &p2) < 0) {
+ return NULL;
+ }
assert(p2); /* Cannot be NULL for pointer types */
if (p1->proto != p2->proto) {
@@ -3086,15 +3210,19 @@ static PyObject *
GenericPyCData_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
CDataObject *obj;
- StgDictObject *dict;
- dict = PyType_stgdict((PyObject *)type);
- if (!dict) {
+ ctypes_state *st = GLOBAL_STATE();
+ StgInfo *info;
+ if (PyStgInfo_FromType(st, (PyObject *)type, &info) < 0) {
+ return NULL;
+ }
+ if (!info) {
PyErr_SetString(PyExc_TypeError,
"abstract class");
return NULL;
}
- dict->flags |= DICTFLAG_FINAL;
+
+ info->flags |= DICTFLAG_FINAL;
obj = (CDataObject *)type->tp_alloc(type, 0);
if (!obj)
@@ -3103,9 +3231,9 @@ GenericPyCData_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
obj->b_base = NULL;
obj->b_index = 0;
obj->b_objects = NULL;
- obj->b_length = dict->length;
+ obj->b_length = info->length;
- if (-1 == PyCData_MallocBuffer(obj, dict)) {
+ if (-1 == PyCData_MallocBuffer(obj, info)) {
Py_DECREF(obj);
return NULL;
}
@@ -3149,7 +3277,12 @@ PyCFuncPtr_set_restype(PyCFuncPtrObject *self, PyObject *ob, void *Py_UNUSED(ign
Py_XDECREF(oldchecker);
return 0;
}
- if (ob != Py_None && !PyType_stgdict(ob) && !PyCallable_Check(ob)) {
+ ctypes_state *st = GLOBAL_STATE();
+ StgInfo *info;
+ if (PyStgInfo_FromType(st, ob, &info) < 0) {
+ return -1;
+ }
+ if (ob != Py_None && !info && !PyCallable_Check(ob)) {
PyErr_SetString(PyExc_TypeError,
"restype must be a type, a callable, or None");
return -1;
@@ -3168,14 +3301,17 @@ PyCFuncPtr_set_restype(PyCFuncPtrObject *self, PyObject *ob, void *Py_UNUSED(ign
static PyObject *
PyCFuncPtr_get_restype(PyCFuncPtrObject *self, void *Py_UNUSED(ignored))
{
- StgDictObject *dict;
if (self->restype) {
return Py_NewRef(self->restype);
}
- dict = PyObject_stgdict((PyObject *)self);
- assert(dict); /* Cannot be NULL for PyCFuncPtrObject instances */
- if (dict->restype) {
- return Py_NewRef(dict->restype);
+ ctypes_state *st = GLOBAL_STATE();
+ StgInfo *info;
+ if (PyStgInfo_FromObject(st, (PyObject *)self, &info) < 0) {
+ return NULL;
+ }
+ assert(info); /* Cannot be NULL for PyCFuncPtrObject instances */
+ if (info->restype) {
+ return Py_NewRef(info->restype);
} else {
Py_RETURN_NONE;
}
@@ -3203,14 +3339,17 @@ PyCFuncPtr_set_argtypes(PyCFuncPtrObject *self, PyObject *ob, void *Py_UNUSED(ig
static PyObject *
PyCFuncPtr_get_argtypes(PyCFuncPtrObject *self, void *Py_UNUSED(ignored))
{
- StgDictObject *dict;
if (self->argtypes) {
return Py_NewRef(self->argtypes);
}
- dict = PyObject_stgdict((PyObject *)self);
- assert(dict); /* Cannot be NULL for PyCFuncPtrObject instances */
- if (dict->argtypes) {
- return Py_NewRef(dict->argtypes);
+ ctypes_state *st = GLOBAL_STATE();
+ StgInfo *info;
+ if (PyStgInfo_FromObject(st, (PyObject *)self, &info) < 0) {
+ return NULL;
+ }
+ assert(info); /* Cannot be NULL for PyCFuncPtrObject instances */
+ if (info->argtypes) {
+ return Py_NewRef(info->argtypes);
} else {
Py_RETURN_NONE;
}
@@ -3242,7 +3381,6 @@ static PPROC FindAddress(void *handle, const char *name, PyObject *type)
#else
char *mangled_name;
int i;
- StgDictObject *dict;
Py_BEGIN_ALLOW_THREADS
address = (PPROC)GetProcAddress(handle, name);
@@ -3253,9 +3391,13 @@ static PPROC FindAddress(void *handle, const char *name, PyObject *type)
return NULL;
}
- dict = PyType_stgdict((PyObject *)type);
- /* It should not happen that dict is NULL, but better be safe */
- if (dict==NULL || dict->flags & FUNCFLAG_CDECL)
+ ctypes_state *st = GLOBAL_STATE();
+ StgInfo *info;
+ if (PyStgInfo_FromType(st, (PyObject *)type, &info) < 0) {
+ return NULL;
+ }
+ /* It should not happen that info is NULL, but better be safe */
+ if (info==NULL || info->flags & FUNCFLAG_CDECL)
return address;
/* for stdcall, try mangled names:
@@ -3282,7 +3424,6 @@ static PPROC FindAddress(void *handle, const char *name, PyObject *type)
static int
_check_outarg_type(PyObject *arg, Py_ssize_t index)
{
- StgDictObject *dict;
ctypes_state *st = GLOBAL_STATE();
if (PyCPointerTypeObject_Check(st, arg)) {
@@ -3291,12 +3432,15 @@ _check_outarg_type(PyObject *arg, Py_ssize_t index)
if (PyCArrayTypeObject_Check(st, arg)) {
return 1;
}
- dict = PyType_stgdict(arg);
- if (dict
+ StgInfo *info;
+ if (PyStgInfo_FromType(st, arg, &info) < 0) {
+ return -1;
+ }
+ if (info
/* simple pointer types, c_void_p, c_wchar_p, BSTR, ... */
- && PyUnicode_Check(dict->proto)
+ && PyUnicode_Check(info->proto)
/* We only allow c_void_p, c_char_p and c_wchar_p as a simple output parameter type */
- && (strchr("PzZ", PyUnicode_AsUTF8(dict->proto)[0]))) {
+ && (strchr("PzZ", PyUnicode_AsUTF8(info->proto)[0]))) {
return 1;
}
@@ -3314,18 +3458,21 @@ static int
_validate_paramflags(PyTypeObject *type, PyObject *paramflags)
{
Py_ssize_t i, len;
- StgDictObject *dict;
PyObject *argtypes;
- dict = PyType_stgdict((PyObject *)type);
- if (!dict) {
+ ctypes_state *st = GLOBAL_STATE();
+ StgInfo *info;
+ if (PyStgInfo_FromType(st, (PyObject *)type, &info) < 0) {
+ return -1;
+ }
+ if (!info) {
PyErr_SetString(PyExc_TypeError,
"abstract class");
return 0;
}
- argtypes = dict->argtypes;
+ argtypes = info->argtypes;
- if (paramflags == NULL || dict->argtypes == NULL)
+ if (paramflags == NULL || info->argtypes == NULL)
return 1;
if (!PyTuple_Check(paramflags)) {
@@ -3335,7 +3482,7 @@ _validate_paramflags(PyTypeObject *type, PyObject *paramflags)
}
len = PyTuple_GET_SIZE(paramflags);
- if (len != PyTuple_GET_SIZE(dict->argtypes)) {
+ if (len != PyTuple_GET_SIZE(info->argtypes)) {
PyErr_SetString(PyExc_ValueError,
"paramflags must have the same length as argtypes");
return 0;
@@ -3565,7 +3712,6 @@ PyCFuncPtr_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
PyCFuncPtrObject *self;
PyObject *callable;
- StgDictObject *dict;
CThunkObject *thunk;
if (PyTuple_GET_SIZE(args) == 0)
@@ -3616,9 +3762,13 @@ PyCFuncPtr_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
}
*/
- dict = PyType_stgdict((PyObject *)type);
+ ctypes_state *st = GLOBAL_STATE();
+ StgInfo *info;
+ if (PyStgInfo_FromType(st, (PyObject *)type, &info) < 0) {
+ return NULL;
+ }
/* XXXX Fails if we do: 'PyCFuncPtr(lambda x: x)' */
- if (!dict || !dict->argtypes) {
+ if (!info || !info->argtypes) {
PyErr_SetString(PyExc_TypeError,
"cannot construct instance of this class:"
" no argtypes");
@@ -3626,9 +3776,9 @@ PyCFuncPtr_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
}
thunk = _ctypes_alloc_callback(callable,
- dict->argtypes,
- dict->restype,
- dict->flags);
+ info->argtypes,
+ info->restype,
+ info->flags);
if (!thunk)
return NULL;
@@ -3737,7 +3887,6 @@ _build_callargs(PyCFuncPtrObject *self, PyObject *argtypes,
{
PyObject *paramflags = self->paramflags;
PyObject *callargs;
- StgDictObject *dict;
Py_ssize_t i, len;
int inargs_index = 0;
/* It's a little bit difficult to determine how many arguments the
@@ -3826,15 +3975,18 @@ _build_callargs(PyCFuncPtrObject *self, PyObject *argtypes,
break;
}
ob = PyTuple_GET_ITEM(argtypes, i);
- dict = PyType_stgdict(ob);
- if (dict == NULL) {
+ StgInfo *info;
+ if (PyStgInfo_FromType(st, ob, &info) < 0) {
+ goto error;
+ }
+ if (info == NULL) {
/* Cannot happen: _validate_paramflags()
would not accept such an object */
PyErr_Format(PyExc_RuntimeError,
- "NULL stgdict unexpected");
+ "NULL stginfo unexpected");
goto error;
}
- if (PyUnicode_Check(dict->proto)) {
+ if (PyUnicode_Check(info->proto)) {
PyErr_Format(
PyExc_TypeError,
"%s 'out' parameter must be passed as default value",
@@ -3846,7 +3998,7 @@ _build_callargs(PyCFuncPtrObject *self, PyObject *argtypes,
}
else {
/* Create an instance of the pointed-to type */
- ob = _PyObject_CallNoArgs(dict->proto);
+ ob = _PyObject_CallNoArgs(info->proto);
}
/*
XXX Is the following correct any longer?
@@ -3966,7 +4118,6 @@ PyCFuncPtr_call(PyCFuncPtrObject *self, PyObject *inargs, PyObject *kwds)
PyObject *converters;
PyObject *checker;
PyObject *argtypes;
- StgDictObject *dict = PyObject_stgdict((PyObject *)self);
PyObject *result;
PyObject *callargs;
PyObject *errcheck;
@@ -3979,13 +4130,19 @@ PyCFuncPtr_call(PyCFuncPtrObject *self, PyObject *inargs, PyObject *kwds)
int outmask;
unsigned int numretvals;
- assert(dict); /* Cannot be NULL for PyCFuncPtrObject instances */
- restype = self->restype ? self->restype : dict->restype;
- converters = self->converters ? self->converters : dict->converters;
- checker = self->checker ? self->checker : dict->checker;
- argtypes = self->argtypes ? self->argtypes : dict->argtypes;
-/* later, we probably want to have an errcheck field in stgdict */
- errcheck = self->errcheck /* ? self->errcheck : dict->errcheck */;
+ ctypes_state *st = GLOBAL_STATE();
+ StgInfo *info;
+ if (PyStgInfo_FromObject(st, (PyObject *)self, &info) < 0) {
+ return NULL;
+ }
+ assert(info); /* Cannot be NULL for PyCFuncPtrObject instances */
+
+ restype = self->restype ? self->restype : info->restype;
+ converters = self->converters ? self->converters : info->converters;
+ checker = self->checker ? self->checker : info->checker;
+ argtypes = self->argtypes ? self->argtypes : info->argtypes;
+/* later, we probably want to have an errcheck field in stginfo */
+ errcheck = self->errcheck /* ? self->errcheck : info->errcheck */;
pProc = *(void **)self->b_ptr;
@@ -4033,7 +4190,7 @@ PyCFuncPtr_call(PyCFuncPtrObject *self, PyObject *inargs, PyObject *kwds)
int actual = Py_SAFE_DOWNCAST(PyTuple_GET_SIZE(callargs),
Py_ssize_t, int);
- if ((dict->flags & FUNCFLAG_CDECL) == FUNCFLAG_CDECL) {
+ if ((info->flags & FUNCFLAG_CDECL) == FUNCFLAG_CDECL) {
/* For cdecl functions, we allow more actual arguments
than the length of the argtypes tuple.
*/
@@ -4063,7 +4220,7 @@ PyCFuncPtr_call(PyCFuncPtrObject *self, PyObject *inargs, PyObject *kwds)
piunk,
self->iid,
#endif
- dict->flags,
+ info->flags,
converters,
restype,
checker);
@@ -4123,8 +4280,11 @@ PyCFuncPtr_clear(PyCFuncPtrObject *self)
static void
PyCFuncPtr_dealloc(PyCFuncPtrObject *self)
{
+ PyObject_GC_UnTrack(self);
PyCFuncPtr_clear(self);
- Py_TYPE(self)->tp_free((PyObject *)self);
+ PyTypeObject *type = Py_TYPE(self);
+ type->tp_free((PyObject *)self);
+ Py_DECREF(type);
}
static PyObject *
@@ -4152,59 +4312,26 @@ PyCFuncPtr_bool(PyCFuncPtrObject *self)
);
}
-static PyNumberMethods PyCFuncPtr_as_number = {
- 0, /* nb_add */
- 0, /* nb_subtract */
- 0, /* nb_multiply */
- 0, /* nb_remainder */
- 0, /* nb_divmod */
- 0, /* nb_power */
- 0, /* nb_negative */
- 0, /* nb_positive */
- 0, /* nb_absolute */
- (inquiry)PyCFuncPtr_bool, /* nb_bool */
+static PyType_Slot pycfuncptr_slots[] = {
+ {Py_tp_dealloc, PyCFuncPtr_dealloc},
+ {Py_tp_repr, PyCFuncPtr_repr},
+ {Py_tp_call, PyCFuncPtr_call},
+ {Py_tp_doc, PyDoc_STR("Function Pointer")},
+ {Py_tp_traverse, PyCFuncPtr_traverse},
+ {Py_tp_clear, PyCFuncPtr_clear},
+ {Py_tp_getset, PyCFuncPtr_getsets},
+ {Py_tp_new, PyCFuncPtr_new},
+ {Py_bf_getbuffer, PyCData_NewGetBuffer},
+ {Py_nb_bool, PyCFuncPtr_bool},
+ {0, NULL},
};
-PyTypeObject PyCFuncPtr_Type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- "_ctypes.CFuncPtr",
- sizeof(PyCFuncPtrObject), /* tp_basicsize */
- 0, /* tp_itemsize */
- (destructor)PyCFuncPtr_dealloc, /* tp_dealloc */
- 0, /* tp_vectorcall_offset */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_as_async */
- (reprfunc)PyCFuncPtr_repr, /* tp_repr */
- &PyCFuncPtr_as_number, /* tp_as_number */
- 0, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- (ternaryfunc)PyCFuncPtr_call, /* tp_call */
- 0, /* tp_str */
- 0, /* tp_getattro */
- 0, /* tp_setattro */
- &PyCData_as_buffer, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
- PyDoc_STR("Function Pointer"), /* tp_doc */
- (traverseproc)PyCFuncPtr_traverse, /* tp_traverse */
- (inquiry)PyCFuncPtr_clear, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
- 0, /* tp_iternext */
- 0, /* tp_methods */
- 0, /* tp_members */
- PyCFuncPtr_getsets, /* tp_getset */
- 0, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- 0, /* tp_init */
- 0, /* tp_alloc */
- PyCFuncPtr_new, /* tp_new */
- 0, /* tp_free */
+static PyType_Spec pycfuncptr_spec = {
+ .name = "_ctypes.CFuncPtr",
+ .basicsize = sizeof(PyCFuncPtrObject),
+ .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC |
+ Py_TPFLAGS_IMMUTABLETYPE),
+ .slots = pycfuncptr_slots,
};
/*****************************************************************/
@@ -4224,11 +4351,15 @@ _init_pos_args(PyObject *self, PyTypeObject *type,
PyObject *args, PyObject *kwds,
Py_ssize_t index)
{
- StgDictObject *dict;
PyObject *fields;
Py_ssize_t i;
- if (PyType_stgdict((PyObject *)type->tp_base)) {
+ ctypes_state *st = GLOBAL_STATE();
+ StgInfo *baseinfo;
+ if (PyStgInfo_FromType(st, (PyObject *)type->tp_base, &baseinfo) < 0) {
+ return -1;
+ }
+ if (baseinfo) {
index = _init_pos_args(self, type->tp_base,
args, kwds,
index);
@@ -4236,8 +4367,17 @@ _init_pos_args(PyObject *self, PyTypeObject *type,
return -1;
}
- dict = PyType_stgdict((PyObject *)type);
- fields = PyDict_GetItemWithError((PyObject *)dict, &_Py_ID(_fields_));
+ StgInfo *info;
+ if (PyStgInfo_FromType(st, (PyObject *)type, &info) < 0) {
+ return -1;
+ }
+ assert(info);
+
+ PyObject *attrdict = PyType_GetDict(type);
+ assert(attrdict);
+
+ fields = PyDict_GetItemWithError((PyObject *)attrdict, &_Py_ID(_fields_));
+ Py_CLEAR(attrdict);
if (fields == NULL) {
if (PyErr_Occurred()) {
return -1;
@@ -4246,7 +4386,7 @@ _init_pos_args(PyObject *self, PyTypeObject *type,
}
for (i = index;
- i < dict->length && i < PyTuple_GET_SIZE(args);
+ i < info->length && i < PyTuple_GET_SIZE(args);
++i) {
PyObject *pair = PySequence_GetItem(fields, i - index);
PyObject *name, *val;
@@ -4279,7 +4419,7 @@ _init_pos_args(PyObject *self, PyTypeObject *type,
if (res == -1)
return -1;
}
- return dict->length;
+ return info->length;
}
static int
@@ -4316,88 +4456,34 @@ Struct_init(PyObject *self, PyObject *args, PyObject *kwds)
return 0;
}
-static PyTypeObject Struct_Type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- "_ctypes.Structure",
- sizeof(CDataObject), /* tp_basicsize */
- 0, /* tp_itemsize */
- 0, /* tp_dealloc */
- 0, /* tp_vectorcall_offset */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_as_async */
- 0, /* tp_repr */
- 0, /* tp_as_number */
- 0, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- 0, /* tp_getattro */
- 0, /* tp_setattro */
- &PyCData_as_buffer, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
- PyDoc_STR("Structure base class"), /* tp_doc */
- (traverseproc)PyCData_traverse, /* tp_traverse */
- (inquiry)PyCData_clear, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
- 0, /* tp_iternext */
- 0, /* tp_methods */
- 0, /* tp_members */
- 0, /* tp_getset */
- 0, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- Struct_init, /* tp_init */
- 0, /* tp_alloc */
- GenericPyCData_new, /* tp_new */
- 0, /* tp_free */
+static PyType_Slot pycstruct_slots[] = {
+ {Py_tp_doc, PyDoc_STR("Structure base class")},
+ {Py_tp_init, Struct_init},
+ {Py_tp_new, GenericPyCData_new},
+ {Py_bf_getbuffer, PyCData_NewGetBuffer},
+ {0, NULL},
+};
+
+static PyType_Spec pycstruct_spec = {
+ .name = "_ctypes.Structure",
+ .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
+ Py_TPFLAGS_IMMUTABLETYPE),
+ .slots = pycstruct_slots,
+};
+
+static PyType_Slot pycunion_slots[] = {
+ {Py_tp_doc, PyDoc_STR("Union base class")},
+ {Py_tp_init, Struct_init},
+ {Py_tp_new, GenericPyCData_new},
+ {Py_bf_getbuffer, PyCData_NewGetBuffer},
+ {0, NULL},
};
-static PyTypeObject Union_Type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- "_ctypes.Union",
- sizeof(CDataObject), /* tp_basicsize */
- 0, /* tp_itemsize */
- 0, /* tp_dealloc */
- 0, /* tp_vectorcall_offset */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_as_async */
- 0, /* tp_repr */
- 0, /* tp_as_number */
- 0, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- 0, /* tp_getattro */
- 0, /* tp_setattro */
- &PyCData_as_buffer, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
- PyDoc_STR("Union base class"), /* tp_doc */
- (traverseproc)PyCData_traverse, /* tp_traverse */
- (inquiry)PyCData_clear, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
- 0, /* tp_iternext */
- 0, /* tp_methods */
- 0, /* tp_members */
- 0, /* tp_getset */
- 0, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- Struct_init, /* tp_init */
- 0, /* tp_alloc */
- GenericPyCData_new, /* tp_new */
- 0, /* tp_free */
+static PyType_Spec pycunion_spec = {
+ .name = "_ctypes.Union",
+ .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
+ Py_TPFLAGS_IMMUTABLETYPE),
+ .slots = pycunion_slots,
};
@@ -4431,8 +4517,6 @@ Array_item(PyObject *myself, Py_ssize_t index)
{
CDataObject *self = (CDataObject *)myself;
Py_ssize_t offset, size;
- StgDictObject *stgdict;
-
if (index < 0 || index >= self->b_length) {
PyErr_SetString(PyExc_IndexError,
@@ -4440,15 +4524,19 @@ Array_item(PyObject *myself, Py_ssize_t index)
return NULL;
}
- stgdict = PyObject_stgdict((PyObject *)self);
- assert(stgdict); /* Cannot be NULL for array instances */
+ ctypes_state *st = GLOBAL_STATE();
+ StgInfo *stginfo;
+ if (PyStgInfo_FromObject(st, (PyObject *)self, &stginfo) < 0) {
+ return NULL;
+ }
+
/* Would it be clearer if we got the item size from
- stgdict->proto's stgdict?
+ stginfo->proto's stginfo?
*/
- size = stgdict->size / stgdict->length;
+ size = stginfo->size / stginfo->length;
offset = index * size;
- return PyCData_get(stgdict->proto, stgdict->getfunc, (PyObject *)self,
+ return PyCData_get(stginfo->proto, stginfo->getfunc, (PyObject *)self,
index, size, self->b_ptr + offset);
}
@@ -4467,7 +4555,6 @@ Array_subscript(PyObject *myself, PyObject *item)
return Array_item(myself, i);
}
else if (PySlice_Check(item)) {
- StgDictObject *stgdict, *itemdict;
PyObject *proto;
PyObject *np;
Py_ssize_t start, stop, step, slicelen, i;
@@ -4478,14 +4565,21 @@ Array_subscript(PyObject *myself, PyObject *item)
}
slicelen = PySlice_AdjustIndices(self->b_length, &start, &stop, step);
- stgdict = PyObject_stgdict((PyObject *)self);
- assert(stgdict); /* Cannot be NULL for array object instances */
- proto = stgdict->proto;
- itemdict = PyType_stgdict(proto);
- assert(itemdict); /* proto is the item type of the array, a
+ ctypes_state *st = GLOBAL_STATE();
+ StgInfo *stginfo;
+ if (PyStgInfo_FromObject(st, (PyObject *)self, &stginfo) < 0) {
+ return NULL;
+ }
+ assert(stginfo); /* Cannot be NULL for array object instances */
+ proto = stginfo->proto;
+ StgInfo *iteminfo;
+ if (PyStgInfo_FromType(st, proto, &iteminfo) < 0) {
+ return NULL;
+ }
+ assert(iteminfo); /* proto is the item type of the array, a
ctypes type, so this cannot be NULL */
- if (itemdict->getfunc == _ctypes_get_fielddesc("c")->getfunc) {
+ if (iteminfo->getfunc == _ctypes_get_fielddesc("c")->getfunc) {
char *ptr = (char *)self->b_ptr;
char *dest;
@@ -4509,7 +4603,7 @@ Array_subscript(PyObject *myself, PyObject *item)
PyMem_Free(dest);
return np;
}
- if (itemdict->getfunc == _ctypes_get_fielddesc("u")->getfunc) {
+ if (iteminfo->getfunc == _ctypes_get_fielddesc("u")->getfunc) {
wchar_t *ptr = (wchar_t *)self->b_ptr;
wchar_t *dest;
@@ -4564,7 +4658,6 @@ Array_ass_item(PyObject *myself, Py_ssize_t index, PyObject *value)
{
CDataObject *self = (CDataObject *)myself;
Py_ssize_t size, offset;
- StgDictObject *stgdict;
char *ptr;
if (value == NULL) {
@@ -4573,18 +4666,23 @@ Array_ass_item(PyObject *myself, Py_ssize_t index, PyObject *value)
return -1;
}
- stgdict = PyObject_stgdict((PyObject *)self);
- assert(stgdict); /* Cannot be NULL for array object instances */
- if (index < 0 || index >= stgdict->length) {
+ ctypes_state *st = GLOBAL_STATE();
+ StgInfo *stginfo;
+ if (PyStgInfo_FromObject(st, (PyObject *)self, &stginfo) < 0) {
+ return -1;
+ }
+ assert(stginfo); /* Cannot be NULL for array object instances */
+
+ if (index < 0 || index >= stginfo->length) {
PyErr_SetString(PyExc_IndexError,
"invalid index");
return -1;
}
- size = stgdict->size / stgdict->length;
+ size = stginfo->size / stginfo->length;
offset = index * size;
ptr = self->b_ptr + offset;
- return PyCData_set((PyObject *)self, stgdict->proto, stgdict->setfunc, value,
+ return PyCData_set((PyObject *)self, stginfo->proto, stginfo->setfunc, value,
index, size, ptr);
}
@@ -4658,26 +4756,6 @@ static PyMethodDef Array_methods[] = {
{ NULL, NULL }
};
-static PySequenceMethods Array_as_sequence = {
- Array_length, /* sq_length; */
- 0, /* sq_concat; */
- 0, /* sq_repeat; */
- Array_item, /* sq_item; */
- 0, /* sq_slice; */
- Array_ass_item, /* sq_ass_item; */
- 0, /* sq_ass_slice; */
- 0, /* sq_contains; */
-
- 0, /* sq_inplace_concat; */
- 0, /* sq_inplace_repeat; */
-};
-
-static PyMappingMethods Array_as_mapping = {
- Array_length,
- Array_subscript,
- Array_ass_subscript,
-};
-
PyDoc_STRVAR(array_doc,
"Abstract base class for arrays.\n"
"\n"
@@ -4688,46 +4766,26 @@ PyDoc_STRVAR(array_doc,
"reads, the resulting object is not itself an Array."
);
-PyTypeObject PyCArray_Type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- "_ctypes.Array",
- sizeof(CDataObject), /* tp_basicsize */
- 0, /* tp_itemsize */
- 0, /* tp_dealloc */
- 0, /* tp_vectorcall_offset */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_as_async */
- 0, /* tp_repr */
- 0, /* tp_as_number */
- &Array_as_sequence, /* tp_as_sequence */
- &Array_as_mapping, /* tp_as_mapping */
- 0, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- 0, /* tp_getattro */
- 0, /* tp_setattro */
- &PyCData_as_buffer, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
- array_doc, /* tp_doc */
- (traverseproc)PyCData_traverse, /* tp_traverse */
- (inquiry)PyCData_clear, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
- 0, /* tp_iternext */
- Array_methods, /* tp_methods */
- 0, /* tp_members */
- 0, /* tp_getset */
- 0, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- (initproc)Array_init, /* tp_init */
- 0, /* tp_alloc */
- GenericPyCData_new, /* tp_new */
- 0, /* tp_free */
+static PyType_Slot pycarray_slots[] = {
+ {Py_tp_doc, (char*)array_doc},
+ {Py_tp_methods, Array_methods},
+ {Py_tp_init, Array_init},
+ {Py_tp_new, GenericPyCData_new},
+ {Py_bf_getbuffer, PyCData_NewGetBuffer},
+ {Py_sq_length, Array_length},
+ {Py_sq_item, Array_item},
+ {Py_sq_ass_item, Array_ass_item},
+ {Py_mp_length, Array_length},
+ {Py_mp_subscript, Array_subscript},
+ {Py_mp_ass_subscript, Array_ass_subscript},
+ {0, NULL},
+};
+
+static PyType_Spec pycarray_spec = {
+ .name = "_ctypes.Array",
+ .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
+ Py_TPFLAGS_IMMUTABLETYPE),
+ .slots = pycarray_slots,
};
PyObject *
@@ -4804,16 +4862,22 @@ static int
Simple_set_value(CDataObject *self, PyObject *value, void *Py_UNUSED(ignored))
{
PyObject *result;
- StgDictObject *dict = PyObject_stgdict((PyObject *)self);
if (value == NULL) {
PyErr_SetString(PyExc_TypeError,
"can't delete attribute");
return -1;
}
- assert(dict); /* Cannot be NULL for CDataObject instances */
- assert(dict->setfunc);
- result = dict->setfunc(self->b_ptr, value, dict->size);
+
+ ctypes_state *st = GLOBAL_STATE();
+ StgInfo *info;
+ if (PyStgInfo_FromObject(st, (PyObject *)self, &info) < 0) {
+ return -1;
+ }
+ assert(info); /* Cannot be NULL for CDataObject instances */
+ assert(info->setfunc);
+
+ result = info->setfunc(self->b_ptr, value, info->size);
if (!result)
return -1;
@@ -4835,11 +4899,14 @@ Simple_init(CDataObject *self, PyObject *args, PyObject *kw)
static PyObject *
Simple_get_value(CDataObject *self, void *Py_UNUSED(ignored))
{
- StgDictObject *dict;
- dict = PyObject_stgdict((PyObject *)self);
- assert(dict); /* Cannot be NULL for CDataObject instances */
- assert(dict->getfunc);
- return dict->getfunc(self->b_ptr, self->b_size);
+ ctypes_state *st = GLOBAL_STATE();
+ StgInfo *info;
+ if (PyStgInfo_FromObject(st, (PyObject *)self, &info) < 0) {
+ return NULL;
+ }
+ assert(info); /* Cannot be NULL for CDataObject instances */
+ assert(info->getfunc);
+ return info->getfunc(self->b_ptr, self->b_size);
}
static PyGetSetDef Simple_getsets[] = {
@@ -4854,7 +4921,7 @@ Simple_from_outparm(PyObject *self, PyObject *args)
if (_ctypes_simple_instance((PyObject *)Py_TYPE(self))) {
return Py_NewRef(self);
}
- /* call stgdict->getfunc */
+ /* call stginfo->getfunc */
return Simple_get_value((CDataObject *)self, NULL);
}
@@ -4868,19 +4935,6 @@ static int Simple_bool(CDataObject *self)
return memcmp(self->b_ptr, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", self->b_size);
}
-static PyNumberMethods Simple_as_number = {
- 0, /* nb_add */
- 0, /* nb_subtract */
- 0, /* nb_multiply */
- 0, /* nb_remainder */
- 0, /* nb_divmod */
- 0, /* nb_power */
- 0, /* nb_negative */
- 0, /* nb_positive */
- 0, /* nb_absolute */
- (inquiry)Simple_bool, /* nb_bool */
-};
-
/* "%s(%s)" % (self.__class__.__name__, self.value) */
static PyObject *
Simple_repr(CDataObject *self)
@@ -4903,48 +4957,26 @@ Simple_repr(CDataObject *self)
return result;
}
-static PyTypeObject Simple_Type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- "_ctypes._SimpleCData",
- sizeof(CDataObject), /* tp_basicsize */
- 0, /* tp_itemsize */
- 0, /* tp_dealloc */
- 0, /* tp_vectorcall_offset */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_as_async */
- (reprfunc)&Simple_repr, /* tp_repr */
- &Simple_as_number, /* tp_as_number */
- 0, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- 0, /* tp_getattro */
- 0, /* tp_setattro */
- &PyCData_as_buffer, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
- PyDoc_STR("XXX to be provided"), /* tp_doc */
- (traverseproc)PyCData_traverse, /* tp_traverse */
- (inquiry)PyCData_clear, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
- 0, /* tp_iternext */
- Simple_methods, /* tp_methods */
- 0, /* tp_members */
- Simple_getsets, /* tp_getset */
- 0, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- (initproc)Simple_init, /* tp_init */
- 0, /* tp_alloc */
- GenericPyCData_new, /* tp_new */
- 0, /* tp_free */
+static PyType_Slot pycsimple_slots[] = {
+ {Py_tp_repr, &Simple_repr},
+ {Py_tp_doc, PyDoc_STR("XXX to be provided")},
+ {Py_tp_methods, Simple_methods},
+ {Py_tp_getset, Simple_getsets},
+ {Py_tp_init, Simple_init},
+ {Py_tp_new, GenericPyCData_new},
+ {Py_bf_getbuffer, PyCData_NewGetBuffer},
+ {Py_nb_bool, Simple_bool},
+ {0, NULL},
+};
+
+static PyType_Spec pycsimple_spec = {
+ .name = "_ctypes._SimpleCData",
+ .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
+ Py_TPFLAGS_IMMUTABLETYPE),
+ .slots = pycsimple_slots,
};
+
/******************************************************************/
/*
PyCPointer_Type
@@ -4955,7 +4987,6 @@ Pointer_item(PyObject *myself, Py_ssize_t index)
CDataObject *self = (CDataObject *)myself;
Py_ssize_t size;
Py_ssize_t offset;
- StgDictObject *stgdict, *itemdict;
PyObject *proto;
if (*(void **)self->b_ptr == NULL) {
@@ -4964,19 +4995,27 @@ Pointer_item(PyObject *myself, Py_ssize_t index)
return NULL;
}
- stgdict = PyObject_stgdict((PyObject *)self);
- assert(stgdict); /* Cannot be NULL for pointer object instances */
+ ctypes_state *st = GLOBAL_STATE();
+ StgInfo *stginfo;
+ if (PyStgInfo_FromObject(st, (PyObject *)self, &stginfo) < 0) {
+ return NULL;
+ }
+ assert(stginfo); /* Cannot be NULL for pointer object instances */
- proto = stgdict->proto;
+ proto = stginfo->proto;
assert(proto);
- itemdict = PyType_stgdict(proto);
- assert(itemdict); /* proto is the item type of the pointer, a ctypes
+
+ StgInfo *iteminfo;
+ if (PyStgInfo_FromType(st, proto, &iteminfo) < 0) {
+ return NULL;
+ }
+ assert(iteminfo); /* proto is the item type of the pointer, a ctypes
type, so this cannot be NULL */
- size = itemdict->size;
- offset = index * itemdict->size;
+ size = iteminfo->size;
+ offset = index * iteminfo->size;
- return PyCData_get(proto, stgdict->getfunc, (PyObject *)self,
+ return PyCData_get(proto, stginfo->getfunc, (PyObject *)self,
index, size, (*(char **)self->b_ptr) + offset);
}
@@ -4986,7 +5025,6 @@ Pointer_ass_item(PyObject *myself, Py_ssize_t index, PyObject *value)
CDataObject *self = (CDataObject *)myself;
Py_ssize_t size;
Py_ssize_t offset;
- StgDictObject *stgdict, *itemdict;
PyObject *proto;
if (value == NULL) {
@@ -5001,37 +5039,47 @@ Pointer_ass_item(PyObject *myself, Py_ssize_t index, PyObject *value)
return -1;
}
- stgdict = PyObject_stgdict((PyObject *)self);
- assert(stgdict); /* Cannot be NULL for pointer instances */
+ ctypes_state *st = GLOBAL_STATE();
+ StgInfo *stginfo;
+ if (PyStgInfo_FromObject(st, (PyObject *)self, &stginfo) < 0) {
+ return -1;
+ }
+ assert(stginfo); /* Cannot be NULL for pointer instances */
- proto = stgdict->proto;
+ proto = stginfo->proto;
assert(proto);
- itemdict = PyType_stgdict(proto);
- assert(itemdict); /* Cannot be NULL because the itemtype of a pointer
+ StgInfo *iteminfo;
+ if (PyStgInfo_FromType(st, proto, &iteminfo) < 0) {
+ return -1;
+ }
+ assert(iteminfo); /* Cannot be NULL because the itemtype of a pointer
is always a ctypes type */
- size = itemdict->size;
- offset = index * itemdict->size;
+ size = iteminfo->size;
+ offset = index * iteminfo->size;
- return PyCData_set((PyObject *)self, proto, stgdict->setfunc, value,
+ return PyCData_set((PyObject *)self, proto, stginfo->setfunc, value,
index, size, (*(char **)self->b_ptr) + offset);
}
static PyObject *
Pointer_get_contents(CDataObject *self, void *closure)
{
- StgDictObject *stgdict;
-
if (*(void **)self->b_ptr == NULL) {
PyErr_SetString(PyExc_ValueError,
"NULL pointer access");
return NULL;
}
- stgdict = PyObject_stgdict((PyObject *)self);
- assert(stgdict); /* Cannot be NULL for pointer instances */
- return PyCData_FromBaseObj(stgdict->proto,
+ ctypes_state *st = GLOBAL_STATE();
+ StgInfo *stginfo;
+ if (PyStgInfo_FromObject(st, (PyObject *)self, &stginfo) < 0) {
+ return NULL;
+ }
+ assert(stginfo); /* Cannot be NULL for pointer instances */
+
+ return PyCData_FromBaseObj(stginfo->proto,
(PyObject *)self, 0,
*(void **)self->b_ptr);
}
@@ -5039,7 +5087,6 @@ Pointer_get_contents(CDataObject *self, void *closure)
static int
Pointer_set_contents(CDataObject *self, PyObject *value, void *closure)
{
- StgDictObject *stgdict;
CDataObject *dst;
PyObject *keep;
@@ -5048,18 +5095,21 @@ Pointer_set_contents(CDataObject *self, PyObject *value, void *closure)
"Pointer does not support item deletion");
return -1;
}
- stgdict = PyObject_stgdict((PyObject *)self);
- assert(stgdict); /* Cannot be NULL for pointer instances */
- assert(stgdict->proto);
ctypes_state *st = GLOBAL_STATE();
+ StgInfo *stginfo;
+ if (PyStgInfo_FromObject(st, (PyObject *)self, &stginfo) < 0) {
+ return -1;
+ }
+ assert(stginfo); /* Cannot be NULL for pointer instances */
+ assert(stginfo->proto);
if (!CDataObject_Check(st, value)) {
- int res = PyObject_IsInstance(value, stgdict->proto);
+ int res = PyObject_IsInstance(value, stginfo->proto);
if (res == -1)
return -1;
if (!res) {
PyErr_Format(PyExc_TypeError,
"expected %s instead of %s",
- ((PyTypeObject *)(stgdict->proto))->tp_name,
+ ((PyTypeObject *)(stginfo->proto))->tp_name,
Py_TYPE(value)->tp_name);
return -1;
}
@@ -5107,8 +5157,12 @@ Pointer_init(CDataObject *self, PyObject *args, PyObject *kw)
static PyObject *
Pointer_new(PyTypeObject *type, PyObject *args, PyObject *kw)
{
- StgDictObject *dict = PyType_stgdict((PyObject *)type);
- if (!dict || !dict->proto) {
+ ctypes_state *st = GLOBAL_STATE();
+ StgInfo *info;
+ if (PyStgInfo_FromType(st, (PyObject *)type, &info) < 0) {
+ return NULL;
+ }
+ if (!info || !info->proto) {
PyErr_SetString(PyExc_TypeError,
"Cannot create instance: has no _type_");
return NULL;
@@ -5130,7 +5184,6 @@ Pointer_subscript(PyObject *myself, PyObject *item)
PySliceObject *slice = (PySliceObject *)item;
Py_ssize_t start, stop, step;
PyObject *np;
- StgDictObject *stgdict, *itemdict;
PyObject *proto;
Py_ssize_t i, len;
size_t cur;
@@ -5184,13 +5237,20 @@ Pointer_subscript(PyObject *myself, PyObject *item)
else
len = (stop - start + 1) / step + 1;
- stgdict = PyObject_stgdict((PyObject *)self);
- assert(stgdict); /* Cannot be NULL for pointer instances */
- proto = stgdict->proto;
+ ctypes_state *st = GLOBAL_STATE();
+ StgInfo *stginfo;
+ if (PyStgInfo_FromObject(st, (PyObject *)self, &stginfo) < 0) {
+ return NULL;
+ }
+ assert(stginfo); /* Cannot be NULL for pointer instances */
+ proto = stginfo->proto;
assert(proto);
- itemdict = PyType_stgdict(proto);
- assert(itemdict);
- if (itemdict->getfunc == _ctypes_get_fielddesc("c")->getfunc) {
+ StgInfo *iteminfo;
+ if (PyStgInfo_FromType(st, proto, &iteminfo) < 0) {
+ return NULL;
+ }
+ assert(iteminfo);
+ if (iteminfo->getfunc == _ctypes_get_fielddesc("c")->getfunc) {
char *ptr = *(char **)self->b_ptr;
char *dest;
@@ -5210,7 +5270,7 @@ Pointer_subscript(PyObject *myself, PyObject *item)
PyMem_Free(dest);
return np;
}
- if (itemdict->getfunc == _ctypes_get_fielddesc("u")->getfunc) {
+ if (iteminfo->getfunc == _ctypes_get_fielddesc("u")->getfunc) {
wchar_t *ptr = *(wchar_t **)self->b_ptr;
wchar_t *dest;
@@ -5248,87 +5308,32 @@ Pointer_subscript(PyObject *myself, PyObject *item)
}
}
-static PySequenceMethods Pointer_as_sequence = {
- 0, /* inquiry sq_length; */
- 0, /* binaryfunc sq_concat; */
- 0, /* intargfunc sq_repeat; */
- Pointer_item, /* intargfunc sq_item; */
- 0, /* intintargfunc sq_slice; */
- Pointer_ass_item, /* intobjargproc sq_ass_item; */
- 0, /* intintobjargproc sq_ass_slice; */
- 0, /* objobjproc sq_contains; */
- /* Added in release 2.0 */
- 0, /* binaryfunc sq_inplace_concat; */
- 0, /* intargfunc sq_inplace_repeat; */
-};
-
-static PyMappingMethods Pointer_as_mapping = {
- 0,
- Pointer_subscript,
-};
-
static int
Pointer_bool(CDataObject *self)
{
return (*(void **)self->b_ptr != NULL);
}
-static PyNumberMethods Pointer_as_number = {
- 0, /* nb_add */
- 0, /* nb_subtract */
- 0, /* nb_multiply */
- 0, /* nb_remainder */
- 0, /* nb_divmod */
- 0, /* nb_power */
- 0, /* nb_negative */
- 0, /* nb_positive */
- 0, /* nb_absolute */
- (inquiry)Pointer_bool, /* nb_bool */
+static PyType_Slot pycpointer_slots[] = {
+ {Py_tp_doc, PyDoc_STR("XXX to be provided")},
+ {Py_tp_getset, Pointer_getsets},
+ {Py_tp_init, Pointer_init},
+ {Py_tp_new, Pointer_new},
+ {Py_bf_getbuffer, PyCData_NewGetBuffer},
+ {Py_nb_bool, Pointer_bool},
+ {Py_mp_subscript, Pointer_subscript},
+ {Py_sq_item, Pointer_item},
+ {Py_sq_ass_item, Pointer_ass_item},
+ {0, NULL},
};
-PyTypeObject PyCPointer_Type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- "_ctypes._Pointer",
- sizeof(CDataObject), /* tp_basicsize */
- 0, /* tp_itemsize */
- 0, /* tp_dealloc */
- 0, /* tp_vectorcall_offset */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_as_async */
- 0, /* tp_repr */
- &Pointer_as_number, /* tp_as_number */
- &Pointer_as_sequence, /* tp_as_sequence */
- &Pointer_as_mapping, /* tp_as_mapping */
- 0, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- 0, /* tp_getattro */
- 0, /* tp_setattro */
- &PyCData_as_buffer, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
- PyDoc_STR("XXX to be provided"), /* tp_doc */
- (traverseproc)PyCData_traverse, /* tp_traverse */
- (inquiry)PyCData_clear, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
- 0, /* tp_iternext */
- 0, /* tp_methods */
- 0, /* tp_members */
- Pointer_getsets, /* tp_getset */
- 0, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- (initproc)Pointer_init, /* tp_init */
- 0, /* tp_alloc */
- Pointer_new, /* tp_new */
- 0, /* tp_free */
+static PyType_Spec pycpointer_spec = {
+ .name = "_ctypes._Pointer",
+ .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
+ Py_TPFLAGS_IMMUTABLETYPE),
+ .slots = pycpointer_slots,
};
-
/******************************************************************/
/*
* Module initialization.
@@ -5433,7 +5438,6 @@ string_at(const char *ptr, int size)
static int
cast_check_pointertype(PyObject *arg)
{
- StgDictObject *dict;
ctypes_state *st = GLOBAL_STATE();
if (PyCPointerTypeObject_Check(st, arg)) {
@@ -5442,10 +5446,13 @@ cast_check_pointertype(PyObject *arg)
if (PyCFuncPtrTypeObject_Check(st, arg)) {
return 1;
}
- dict = PyType_stgdict(arg);
- if (dict != NULL && dict->proto != NULL) {
- if (PyUnicode_Check(dict->proto)
- && (strchr("sPzUZXO", PyUnicode_AsUTF8(dict->proto)[0]))) {
+ StgInfo *info;
+ if (PyStgInfo_FromType(st, arg, &info) < 0) {
+ return 0;
+ }
+ if (info != NULL && info->proto != NULL) {
+ if (PyUnicode_Check(info->proto)
+ && (strchr("sPzUZXO", PyUnicode_AsUTF8(info->proto)[0]))) {
/* simple pointer types, c_void_p, c_wchar_p, BSTR, ... */
return 1;
}
@@ -5544,26 +5551,8 @@ _ctypes_add_types(PyObject *mod)
if (PyType_Ready(TYPE) < 0) { \
return -1; \
}
-
-#define TYPE_READY_BASE(TYPE_EXPR, TP_BASE) \
- do { \
- PyTypeObject *type = (TYPE_EXPR); \
- type->tp_base = (TP_BASE); \
- TYPE_READY(type); \
- } while (0)
-
-#define MOD_ADD_TYPE(TYPE_EXPR, TP_TYPE, TP_BASE) \
- do { \
- PyTypeObject *type = (TYPE_EXPR); \
- Py_SET_TYPE(type, TP_TYPE); \
- type->tp_base = TP_BASE; \
- if (PyModule_AddType(mod, type) < 0) { \
- return -1; \
- } \
- } while (0)
-
-#define CREATE_TYPE(MOD, TP, SPEC, BASE) do { \
- PyObject *type = PyType_FromMetaclass(NULL, MOD, SPEC, \
+#define CREATE_TYPE(TP, SPEC, META, BASE) do { \
+ PyObject *type = PyType_FromMetaclass(META, mod, SPEC, \
(PyObject *)BASE); \
if (type == NULL) { \
return -1; \
@@ -5571,67 +5560,82 @@ _ctypes_add_types(PyObject *mod)
TP = (PyTypeObject *)type; \
} while (0)
+#define MOD_ADD_TYPE(TP, SPEC, META, BASE) do { \
+ CREATE_TYPE(TP, SPEC, META, BASE); \
+ if (PyModule_AddType(mod, (PyTypeObject *)(TP)) < 0) { \
+ return -1; \
+ } \
+} while (0)
+
ctypes_state *st = GLOBAL_STATE();
/* Note:
ob_type is the metatype (the 'type'), defaults to PyType_Type,
tp_base is the base type, defaults to 'object' aka PyBaseObject_Type.
*/
- CREATE_TYPE(mod, st->PyCArg_Type, &carg_spec, NULL);
- CREATE_TYPE(mod, st->PyCThunk_Type, &cthunk_spec, NULL);
- TYPE_READY(st->PyCData_Type);
- /* StgDict is derived from PyDict_Type */
- TYPE_READY_BASE(st->PyCStgDict_Type, &PyDict_Type);
+ CREATE_TYPE(st->PyCArg_Type, &carg_spec, NULL, NULL);
+ CREATE_TYPE(st->PyCThunk_Type, &cthunk_spec, NULL, NULL);
+ CREATE_TYPE(st->PyCData_Type, &pycdata_spec, NULL, NULL);
+
+ // Common Metaclass
+ CREATE_TYPE(st->PyCType_Type, &pyctype_type_spec,
+ NULL, &PyType_Type);
/*************************************************
*
* Metaclasses
*/
- CREATE_TYPE(mod, st->PyCStructType_Type, &pycstruct_type_spec,
- &PyType_Type);
- CREATE_TYPE(mod, st->UnionType_Type, &union_type_spec, &PyType_Type);
- CREATE_TYPE(mod, st->PyCPointerType_Type, &pycpointer_type_spec,
- &PyType_Type);
- CREATE_TYPE(mod, st->PyCArrayType_Type, &pycarray_type_spec,
- &PyType_Type);
- CREATE_TYPE(mod, st->PyCSimpleType_Type, &pycsimple_type_spec,
- &PyType_Type);
- CREATE_TYPE(mod, st->PyCFuncPtrType_Type, &pycfuncptr_type_spec,
- &PyType_Type);
+ CREATE_TYPE(st->PyCStructType_Type, &pycstruct_type_spec,
+ NULL, st->PyCType_Type);
+ CREATE_TYPE(st->UnionType_Type, &union_type_spec,
+ NULL, st->PyCType_Type);
+ CREATE_TYPE(st->PyCPointerType_Type, &pycpointer_type_spec,
+ NULL, st->PyCType_Type);
+ CREATE_TYPE(st->PyCArrayType_Type, &pycarray_type_spec,
+ NULL, st->PyCType_Type);
+ CREATE_TYPE(st->PyCSimpleType_Type, &pycsimple_type_spec,
+ NULL, st->PyCType_Type);
+ CREATE_TYPE(st->PyCFuncPtrType_Type, &pycfuncptr_type_spec,
+ NULL, st->PyCType_Type);
/*************************************************
*
* Classes using a custom metaclass
*/
- MOD_ADD_TYPE(st->Struct_Type, st->PyCStructType_Type, st->PyCData_Type);
- MOD_ADD_TYPE(st->Union_Type, st->UnionType_Type, st->PyCData_Type);
- MOD_ADD_TYPE(st->PyCPointer_Type, st->PyCPointerType_Type, st->PyCData_Type);
- MOD_ADD_TYPE(st->PyCArray_Type, st->PyCArrayType_Type, st->PyCData_Type);
- MOD_ADD_TYPE(st->Simple_Type, st->PyCSimpleType_Type, st->PyCData_Type);
- MOD_ADD_TYPE(st->PyCFuncPtr_Type, st->PyCFuncPtrType_Type, st->PyCData_Type);
+ MOD_ADD_TYPE(st->Struct_Type, &pycstruct_spec,
+ st->PyCStructType_Type, st->PyCData_Type);
+ MOD_ADD_TYPE(st->Union_Type, &pycunion_spec,
+ st->UnionType_Type, st->PyCData_Type);
+ MOD_ADD_TYPE(st->PyCPointer_Type, &pycpointer_spec,
+ st->PyCPointerType_Type, st->PyCData_Type);
+ MOD_ADD_TYPE(st->PyCArray_Type, &pycarray_spec,
+ st->PyCArrayType_Type, st->PyCData_Type);
+ MOD_ADD_TYPE(st->Simple_Type, &pycsimple_spec,
+ st->PyCSimpleType_Type, st->PyCData_Type);
+ MOD_ADD_TYPE(st->PyCFuncPtr_Type, &pycfuncptr_spec,
+ st->PyCFuncPtrType_Type, st->PyCData_Type);
/*************************************************
*
* Simple classes
*/
- CREATE_TYPE(mod, st->PyCField_Type, &cfield_spec, NULL);
+ CREATE_TYPE(st->PyCField_Type, &cfield_spec, NULL, NULL);
/*************************************************
*
* Other stuff
*/
- CREATE_TYPE(mod, st->DictRemover_Type, &dictremover_spec, NULL);
- CREATE_TYPE(mod, st->StructParam_Type, &structparam_spec, NULL);
+ CREATE_TYPE(st->DictRemover_Type, &dictremover_spec, NULL, NULL);
+ CREATE_TYPE(st->StructParam_Type, &structparam_spec, NULL, NULL);
#ifdef MS_WIN32
- CREATE_TYPE(mod, st->PyComError_Type, &comerror_spec, PyExc_Exception);
+ CREATE_TYPE(st->PyComError_Type, &comerror_spec, NULL, PyExc_Exception);
#endif
#undef TYPE_READY
-#undef TYPE_READY_BASE
#undef MOD_ADD_TYPE
#undef CREATE_TYPE
return 0;
diff --git a/Modules/_ctypes/callbacks.c b/Modules/_ctypes/callbacks.c
index f704794..08d068e 100644
--- a/Modules/_ctypes/callbacks.c
+++ b/Modules/_ctypes/callbacks.c
@@ -109,10 +109,14 @@ PrintError(const char *msg, ...)
* slower.
*/
static void
-TryAddRef(StgDictObject *dict, CDataObject *obj)
+TryAddRef(PyObject *cnv, CDataObject *obj)
{
IUnknown *punk;
- int r = PyDict_Contains((PyObject *)dict, &_Py_ID(_needs_com_addref_));
+ PyObject *attrdict = _PyType_GetDict((PyTypeObject *)cnv);
+ if (!attrdict) {
+ return;
+ }
+ int r = PyDict_Contains(attrdict, &_Py_ID(_needs_com_addref_));
if (r <= 0) {
if (r < 0) {
PrintError("getting _needs_com_addref_");
@@ -154,22 +158,26 @@ static void _CallPythonObject(void *mem,
ctypes_state *st = GLOBAL_STATE();
for (i = 0; i < nargs; i++) {
PyObject *cnv = cnvs[i]; // borrowed ref
- StgDictObject *dict;
- dict = PyType_stgdict(cnv);
- if (dict && dict->getfunc && !_ctypes_simple_instance(cnv)) {
- PyObject *v = dict->getfunc(*pArgs, dict->size);
+ StgInfo *info;
+ if (PyStgInfo_FromType(st, cnv, &info) < 0) {
+ goto Done;
+ }
+
+ if (info && info->getfunc && !_ctypes_simple_instance(cnv)) {
+ PyObject *v = info->getfunc(*pArgs, info->size);
if (!v) {
PrintError("create argument %zd:\n", i);
goto Done;
}
args[i] = v;
/* XXX XXX XX
- We have the problem that c_byte or c_short have dict->size of
+ We have the problem that c_byte or c_short have info->size of
1 resp. 4, but these parameters are pushed as sizeof(int) bytes.
BTW, the same problem occurs when they are pushed as parameters
*/
- } else if (dict) {
+ }
+ else if (info) {
/* Hm, shouldn't we use PyCData_AtAddress() or something like that instead? */
CDataObject *obj = (CDataObject *)_PyObject_CallNoArgs(cnv);
if (!obj) {
@@ -181,10 +189,10 @@ static void _CallPythonObject(void *mem,
PrintError("unexpected result of create argument %zd:\n", i);
goto Done;
}
- memcpy(obj->b_ptr, *pArgs, dict->size);
+ memcpy(obj->b_ptr, *pArgs, info->size);
args[i] = (PyObject *)obj;
#ifdef MS_WIN32
- TryAddRef(dict, obj);
+ TryAddRef(cnv, obj);
#endif
} else {
PyErr_SetString(PyExc_TypeError,
@@ -348,10 +356,8 @@ CThunkObject *_ctypes_alloc_callback(PyObject *callable,
if (p == NULL)
return NULL;
-#ifdef Py_DEBUG
ctypes_state *st = GLOBAL_STATE();
assert(CThunk_CheckExact(st, (PyObject *)p));
-#endif
p->pcl_write = Py_ffi_closure_alloc(sizeof(ffi_closure), &p->pcl_exec);
if (p->pcl_write == NULL) {
@@ -372,14 +378,18 @@ CThunkObject *_ctypes_alloc_callback(PyObject *callable,
p->setfunc = NULL;
p->ffi_restype = &ffi_type_void;
} else {
- StgDictObject *dict = PyType_stgdict(restype);
- if (dict == NULL || dict->setfunc == NULL) {
+ StgInfo *info;
+ if (PyStgInfo_FromType(st, restype, &info) < 0) {
+ goto error;
+ }
+
+ if (info == NULL || info->setfunc == NULL) {
PyErr_SetString(PyExc_TypeError,
"invalid result type for callback function");
goto error;
}
- p->setfunc = dict->setfunc;
- p->ffi_restype = &dict->ffi_type_pointer;
+ p->setfunc = info->setfunc;
+ p->ffi_restype = &info->ffi_type_pointer;
}
cc = FFI_DEFAULT_ABI;
diff --git a/Modules/_ctypes/callproc.c b/Modules/_ctypes/callproc.c
index 97d1dba..6ebbb64 100644
--- a/Modules/_ctypes/callproc.c
+++ b/Modules/_ctypes/callproc.c
@@ -664,15 +664,20 @@ struct argument {
*/
static int ConvParam(PyObject *obj, Py_ssize_t index, struct argument *pa)
{
- StgDictObject *dict;
pa->keep = NULL; /* so we cannot forget it later */
+ ctypes_state *st = GLOBAL_STATE();
- dict = PyObject_stgdict(obj);
- if (dict) {
+ StgInfo *info;
+ int result = PyStgInfo_FromObject(st, obj, &info);
+ if (result < 0) {
+ return -1;
+ }
+ if (info) {
+ assert(info);
PyCArgObject *carg;
- assert(dict->paramfunc);
- /* If it has an stgdict, it is a CDataObject */
- carg = dict->paramfunc((CDataObject *)obj);
+ assert(info->paramfunc);
+ /* If it has an stginfo, it is a CDataObject */
+ carg = info->paramfunc((CDataObject *)obj);
if (carg == NULL)
return -1;
pa->ffi_type = carg->pffi_type;
@@ -681,7 +686,6 @@ static int ConvParam(PyObject *obj, Py_ssize_t index, struct argument *pa)
return 0;
}
- ctypes_state *st = GLOBAL_STATE();
if (PyCArg_CheckExact(st, obj)) {
PyCArgObject *carg = (PyCArgObject *)obj;
pa->ffi_type = carg->pffi_type;
@@ -778,26 +782,34 @@ int can_return_struct_as_sint64(size_t s)
#endif
+// returns NULL with exception set on error
ffi_type *_ctypes_get_ffi_type(PyObject *obj)
{
- StgDictObject *dict;
- if (obj == NULL)
+ if (obj == NULL) {
return &ffi_type_sint;
- dict = PyType_stgdict(obj);
- if (dict == NULL)
+ }
+
+ ctypes_state *st = GLOBAL_STATE();
+ StgInfo *info;
+ if (PyStgInfo_FromType(st, obj, &info) < 0) {
+ return NULL;
+ }
+
+ if (info == NULL) {
return &ffi_type_sint;
+ }
#if defined(MS_WIN32) && !defined(_WIN32_WCE)
/* This little trick works correctly with MSVC.
It returns small structures in registers
*/
- if (dict->ffi_type_pointer.type == FFI_TYPE_STRUCT) {
- if (can_return_struct_as_int(dict->ffi_type_pointer.size))
+ if (info->ffi_type_pointer.type == FFI_TYPE_STRUCT) {
+ if (can_return_struct_as_int(info->ffi_type_pointer.size))
return &ffi_type_sint32;
- else if (can_return_struct_as_sint64 (dict->ffi_type_pointer.size))
+ else if (can_return_struct_as_sint64 (info->ffi_type_pointer.size))
return &ffi_type_sint64;
}
#endif
- return &dict->ffi_type_pointer;
+ return &info->ffi_type_pointer;
}
@@ -983,7 +995,6 @@ static int _call_function_pointer(int flags,
*/
static PyObject *GetResult(PyObject *restype, void *result, PyObject *checker)
{
- StgDictObject *dict;
PyObject *retval, *v;
if (restype == NULL)
@@ -993,17 +1004,22 @@ static PyObject *GetResult(PyObject *restype, void *result, PyObject *checker)
Py_RETURN_NONE;
}
- dict = PyType_stgdict(restype);
- if (dict == NULL)
+ ctypes_state *st = GLOBAL_STATE();
+ StgInfo *info;
+ if (PyStgInfo_FromType(st, restype, &info) < 0) {
+ return NULL;
+ }
+ if (info == NULL) {
return PyObject_CallFunction(restype, "i", *(int *)result);
+ }
- if (dict->getfunc && !_ctypes_simple_instance(restype)) {
- retval = dict->getfunc(result, dict->size);
+ if (info->getfunc && !_ctypes_simple_instance(restype)) {
+ retval = info->getfunc(result, info->size);
/* If restype is py_object (detected by comparing getfunc with
O_get), we have to call Py_DECREF because O_get has already
called Py_INCREF.
*/
- if (dict->getfunc == _ctypes_get_fielddesc("O")->getfunc) {
+ if (info->getfunc == _ctypes_get_fielddesc("O")->getfunc) {
Py_DECREF(retval);
}
} else
@@ -1240,6 +1256,9 @@ PyObject *_ctypes_callproc(PPROC pProc,
} else {
rtype = _ctypes_get_ffi_type(restype);
}
+ if (!rtype) {
+ goto cleanup;
+ }
resbuf = alloca(max(rtype->size, sizeof(ffi_arg)));
@@ -1683,13 +1702,16 @@ PyDoc_STRVAR(sizeof_doc,
static PyObject *
sizeof_func(PyObject *self, PyObject *obj)
{
- StgDictObject *dict;
+ ctypes_state *st = GLOBAL_STATE();
- dict = PyType_stgdict(obj);
- if (dict) {
- return PyLong_FromSsize_t(dict->size);
+ StgInfo *info;
+ if (PyStgInfo_FromType(st, obj, &info) < 0) {
+ return NULL;
}
- ctypes_state *st = GLOBAL_STATE();
+ if (info) {
+ return PyLong_FromSsize_t(info->size);
+ }
+
if (CDataObject_Check(st, obj)) {
return PyLong_FromSsize_t(((CDataObject *)obj)->b_size);
}
@@ -1706,16 +1728,14 @@ PyDoc_STRVAR(alignment_doc,
static PyObject *
align_func(PyObject *self, PyObject *obj)
{
- StgDictObject *dict;
-
- dict = PyType_stgdict(obj);
- if (dict)
- return PyLong_FromSsize_t(dict->align);
-
- dict = PyObject_stgdict(obj);
- if (dict)
- return PyLong_FromSsize_t(dict->align);
-
+ ctypes_state *st = GLOBAL_STATE();
+ StgInfo *info;
+ if (PyStgInfo_FromAny(st, obj, &info) < 0) {
+ return NULL;
+ }
+ if (info) {
+ return PyLong_FromSsize_t(info->align);
+ }
PyErr_SetString(PyExc_TypeError,
"no alignment info");
return NULL;
@@ -1824,7 +1844,6 @@ static PyObject *
resize(PyObject *self, PyObject *args)
{
CDataObject *obj;
- StgDictObject *dict;
Py_ssize_t size;
if (!PyArg_ParseTuple(args,
@@ -1832,16 +1851,21 @@ resize(PyObject *self, PyObject *args)
&obj, &size))
return NULL;
- dict = PyObject_stgdict((PyObject *)obj);
- if (dict == NULL) {
+ ctypes_state *st = GLOBAL_STATE();
+ StgInfo *info;
+ int result = PyStgInfo_FromObject(st, (PyObject *)obj, &info);
+ if (result < 0) {
+ return NULL;
+ }
+ if (info == NULL) {
PyErr_SetString(PyExc_TypeError,
"expected ctypes instance");
return NULL;
}
- if (size < dict->size) {
+ if (size < info->size) {
PyErr_Format(PyExc_ValueError,
"minimum size is %zd",
- dict->size);
+ info->size);
return NULL;
}
if (obj->b_needsfree == 0) {
@@ -2004,28 +2028,30 @@ create_pointer_inst(PyObject *module, PyObject *arg)
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) {
+ ctypes_state *st = GLOBAL_STATE();
+ StgInfo *info;
+ if (PyStgInfo_FromAny(st, arg, &info) < 0) {
+ return NULL;
+ }
+ if (info == NULL) {
PyErr_SetString(PyExc_TypeError,
"not a ctypes type or object");
return NULL;
}
- shape = PyTuple_New(dict->ndim);
+ shape = PyTuple_New(info->ndim);
if (shape == NULL)
return NULL;
- for (i = 0; i < (int)dict->ndim; ++i)
- PyTuple_SET_ITEM(shape, i, PyLong_FromSsize_t(dict->shape[i]));
+ for (i = 0; i < (int)info->ndim; ++i)
+ PyTuple_SET_ITEM(shape, i, PyLong_FromSsize_t(info->shape[i]));
if (PyErr_Occurred()) {
Py_DECREF(shape);
return NULL;
}
- return Py_BuildValue("siN", dict->format, dict->ndim, shape);
+ return Py_BuildValue("siN", info->format, info->ndim, shape);
}
diff --git a/Modules/_ctypes/cfield.c b/Modules/_ctypes/cfield.c
index 1d5b0b1..16b66382 100644
--- a/Modules/_ctypes/cfield.c
+++ b/Modules/_ctypes/cfield.c
@@ -54,7 +54,6 @@ PyCField_FromDesc(PyObject *desc, Py_ssize_t index,
Py_ssize_t size, align;
SETFUNC setfunc = NULL;
GETFUNC getfunc = NULL;
- StgDictObject *dict;
int fieldtype;
#define NO_BITFIELD 0
#define NEW_BITFIELD 1
@@ -66,21 +65,27 @@ PyCField_FromDesc(PyObject *desc, Py_ssize_t index,
self = (CFieldObject *)tp->tp_alloc(tp, 0);
if (self == NULL)
return NULL;
- dict = PyType_stgdict(desc);
- if (!dict) {
+
+ StgInfo *info;
+ if (PyStgInfo_FromType(st, desc, &info) < 0) {
+ Py_DECREF(self);
+ return NULL;
+ }
+ if (!info) {
PyErr_SetString(PyExc_TypeError,
"has no _stginfo_");
Py_DECREF(self);
return NULL;
}
+
if (bitsize /* this is a bitfield request */
&& *pfield_size /* we have a bitfield open */
#ifdef MS_WIN32
/* MSVC, GCC with -mms-bitfields */
- && dict->size * 8 == *pfield_size
+ && info->size * 8 == *pfield_size
#else
/* GCC */
- && dict->size * 8 <= *pfield_size
+ && info->size * 8 <= *pfield_size
#endif
&& (*pbitofs + bitsize) <= *pfield_size) {
/* continue bit field */
@@ -88,8 +93,8 @@ PyCField_FromDesc(PyObject *desc, Py_ssize_t index,
#ifndef MS_WIN32
} else if (bitsize /* this is a bitfield request */
&& *pfield_size /* we have a bitfield open */
- && dict->size * 8 >= *pfield_size
- && (*pbitofs + bitsize) <= dict->size * 8) {
+ && info->size * 8 >= *pfield_size
+ && (*pbitofs + bitsize) <= info->size * 8) {
/* expand bit field */
fieldtype = EXPAND_BITFIELD;
#endif
@@ -97,7 +102,7 @@ PyCField_FromDesc(PyObject *desc, Py_ssize_t index,
/* start new bitfield */
fieldtype = NEW_BITFIELD;
*pbitofs = 0;
- *pfield_size = dict->size * 8;
+ *pfield_size = info->size * 8;
} else {
/* not a bit field */
fieldtype = NO_BITFIELD;
@@ -105,29 +110,37 @@ PyCField_FromDesc(PyObject *desc, Py_ssize_t index,
*pfield_size = 0;
}
- size = dict->size;
+ size = info->size;
proto = desc;
/* Field descriptors for 'c_char * n' are be scpecial cased to
return a Python string instead of an Array object instance...
*/
if (PyCArrayTypeObject_Check(st, proto)) {
- StgDictObject *adict = PyType_stgdict(proto);
- StgDictObject *idict;
- if (adict && adict->proto) {
- idict = PyType_stgdict(adict->proto);
- if (!idict) {
+ StgInfo *ainfo;
+ if (PyStgInfo_FromType(st, proto, &ainfo) < 0) {
+ Py_DECREF(self);
+ return NULL;
+ }
+
+ if (ainfo && ainfo->proto) {
+ StgInfo *iinfo;
+ if (PyStgInfo_FromType(st, ainfo->proto, &iinfo) < 0) {
+ Py_DECREF(self);
+ return NULL;
+ }
+ if (!iinfo) {
PyErr_SetString(PyExc_TypeError,
"has no _stginfo_");
Py_DECREF(self);
return NULL;
}
- if (idict->getfunc == _ctypes_get_fielddesc("c")->getfunc) {
+ if (iinfo->getfunc == _ctypes_get_fielddesc("c")->getfunc) {
struct fielddesc *fd = _ctypes_get_fielddesc("s");
getfunc = fd->getfunc;
setfunc = fd->setfunc;
}
- if (idict->getfunc == _ctypes_get_fielddesc("u")->getfunc) {
+ if (iinfo->getfunc == _ctypes_get_fielddesc("u")->getfunc) {
struct fielddesc *fd = _ctypes_get_fielddesc("U");
getfunc = fd->getfunc;
setfunc = fd->setfunc;
@@ -151,9 +164,9 @@ PyCField_FromDesc(PyObject *desc, Py_ssize_t index,
/* fall through */
case NO_BITFIELD:
if (pack)
- align = min(pack, dict->align);
+ align = min(pack, info->align);
else
- align = dict->align;
+ align = info->align;
if (align && *poffset % align) {
Py_ssize_t delta = align - (*poffset % align);
*psize += delta;
@@ -171,10 +184,10 @@ PyCField_FromDesc(PyObject *desc, Py_ssize_t index,
break;
case EXPAND_BITFIELD:
- *poffset += dict->size - *pfield_size/8;
- *psize += dict->size - *pfield_size/8;
+ *poffset += info->size - *pfield_size/8;
+ *psize += info->size - *pfield_size/8;
- *pfield_size = dict->size * 8;
+ *pfield_size = info->size * 8;
if (big_endian)
self->size = (bitsize << 16) + *pfield_size - *pbitofs - bitsize;
diff --git a/Modules/_ctypes/ctypes.h b/Modules/_ctypes/ctypes.h
index 02f48a9..d7d725a 100644
--- a/Modules/_ctypes/ctypes.h
+++ b/Modules/_ctypes/ctypes.h
@@ -41,7 +41,6 @@ typedef struct {
PyTypeObject *PyCArg_Type;
PyTypeObject *PyCField_Type;
PyTypeObject *PyCThunk_Type;
- PyTypeObject *PyCStgDict_Type;
PyTypeObject *StructParam_Type;
PyTypeObject *PyCStructType_Type;
PyTypeObject *UnionType_Type;
@@ -59,6 +58,7 @@ typedef struct {
#ifdef MS_WIN32
PyTypeObject *PyComError_Type;
#endif
+ PyTypeObject *PyCType_Type;
} ctypes_state;
extern ctypes_state global_state;
@@ -144,7 +144,7 @@ typedef struct {
CThunkObject *thunk;
PyObject *callable;
- /* These two fields will override the ones in the type's stgdict if
+ /* These two fields will override the ones in the type's stginfo if
they are set */
PyObject *converters;
PyObject *argtypes;
@@ -158,17 +158,12 @@ typedef struct {
PyObject *paramflags;
} PyCFuncPtrObject;
-extern PyTypeObject PyCStgDict_Type;
-#define PyCStgDict_CheckExact(st, v) Py_IS_TYPE((v), (st)->PyCStgDict_Type)
-#define PyCStgDict_Check(st, v) PyObject_TypeCheck((v), (st)->PyCStgDict_Type)
-
-extern int PyCStructUnionType_update_stgdict(PyObject *fields, PyObject *type, int isStruct);
+extern int PyCStructUnionType_update_stginfo(PyObject *fields, PyObject *type, int isStruct);
extern int PyType_stginfo(PyTypeObject *self, Py_ssize_t *psize, Py_ssize_t *palign, Py_ssize_t *plength);
extern int PyObject_stginfo(PyObject *self, Py_ssize_t *psize, Py_ssize_t *palign, Py_ssize_t *plength);
-extern PyTypeObject PyCData_Type;
#define CDataObject_CheckExact(st, v) Py_IS_TYPE((v), (st)->PyCData_Type)
#define CDataObject_Check(st, v) PyObject_TypeCheck((v), (st)->PyCData_Type)
#define _CDataObject_HasExternalBuffer(v) ((v)->b_ptr != (char *)&(v)->b_value)
@@ -188,10 +183,6 @@ PyCField_FromDesc(PyObject *desc, Py_ssize_t index,
extern PyObject *PyCData_AtAddress(PyObject *type, void *buf);
extern PyObject *PyCData_FromBytes(PyObject *type, char *data, Py_ssize_t length);
-extern PyTypeObject PyCArray_Type;
-extern PyTypeObject PyCPointer_Type;
-extern PyTypeObject PyCFuncPtr_Type;
-
#define PyCArrayTypeObject_Check(st, v) PyObject_TypeCheck((v), (st)->PyCArrayType_Type)
#define ArrayObject_Check(st, v) PyObject_TypeCheck((v), (st)->PyCArray_Type)
#define PointerObject_Check(st, v) PyObject_TypeCheck((v), (st)->PyCPointer_Type)
@@ -231,45 +222,22 @@ typedef struct {
int anonymous;
} CFieldObject;
-/* A subclass of PyDictObject, used as the instance dictionary of ctypes
- metatypes */
-typedef struct {
- PyDictObject dict; /* first part identical to PyDictObject */
-/* The size and align fields are unneeded, they are in ffi_type as well. As
- an experiment shows, it's trivial to get rid of them, the only thing to
- remember is that in PyCArrayType_new the ffi_type fields must be filled in -
- so far it was unneeded because libffi doesn't support arrays at all
- (because they are passed as pointers to function calls anyway). But it's
- too much risk to change that now, and there are other fields which doesn't
- belong into this structure anyway. Maybe in ctypes 2.0... (ctypes 2000?)
-*/
- Py_ssize_t size; /* number of bytes */
- Py_ssize_t align; /* alignment requirements */
- Py_ssize_t length; /* number of fields */
- ffi_type ffi_type_pointer;
- PyObject *proto; /* Only for Pointer/ArrayObject */
- SETFUNC setfunc; /* Only for simple objects */
- GETFUNC getfunc; /* Only for simple objects */
- PARAMFUNC paramfunc;
+/****************************************************************
+ StgInfo
- /* Following fields only used by PyCFuncPtrType_Type instances */
- PyObject *argtypes; /* tuple of CDataObjects */
- PyObject *converters; /* tuple([t.from_param for t in argtypes]) */
- PyObject *restype; /* CDataObject or NULL */
- PyObject *checker;
- int flags; /* calling convention and such */
+ Since Python 3.13, ctypes-specific type information is stored in the
+ corresponding type object, in a `StgInfo` struct accessed by the helpers
+ below.
+ Before that, each type's `tp_dict` was set to a dict *subclass* that included
+ the fields that are now in StgInfo. The mechanism was called "StgDict"; a few
+ references to that name might remain.
- /* pep3118 fields, pointers need PyMem_Free */
- char *format;
- int ndim;
- Py_ssize_t *shape;
-/* Py_ssize_t *strides; */ /* unused in ctypes */
-/* Py_ssize_t *suboffsets; */ /* unused in ctypes */
+ Functions for accessing StgInfo are `static inline` for performance;
+ see later in this file.
-} StgDictObject;
+ ****************************************************************
-/****************************************************************
- StgDictObject fields
+ StgInfo fields
setfunc and getfunc is only set for simple data types, it is copied from the
corresponding fielddesc entry. These are functions to set and get the value
@@ -280,11 +248,11 @@ typedef struct {
object.
Probably all the magic ctypes methods (like from_param) should have C
- callable wrappers in the StgDictObject. For simple data type, for example,
+ callable wrappers in the StgInfo. For simple data type, for example,
the fielddesc table could have entries for C codec from_param functions or
other methods as well, if a subtype overrides this method in Python at
construction time, or assigns to it later, tp_setattro should update the
- StgDictObject function to a generic one.
+ StgInfo function to a generic one.
Currently, PyCFuncPtr types have 'converters' and 'checker' entries in their
type dict. They are only used to cache attributes from other entries, which
@@ -308,13 +276,33 @@ typedef struct {
*****************************************************************/
-/* May return NULL, but does not set an exception! */
-extern StgDictObject *PyType_stgdict(PyObject *obj);
+typedef struct {
+ int initialized;
+ Py_ssize_t size; /* number of bytes */
+ Py_ssize_t align; /* alignment requirements */
+ Py_ssize_t length; /* number of fields */
+ ffi_type ffi_type_pointer;
+ PyObject *proto; /* Only for Pointer/ArrayObject */
+ SETFUNC setfunc; /* Only for simple objects */
+ GETFUNC getfunc; /* Only for simple objects */
+ PARAMFUNC paramfunc;
+
+ /* Following fields only used by PyCFuncPtrType_Type instances */
+ PyObject *argtypes; /* tuple of CDataObjects */
+ PyObject *converters; /* tuple([t.from_param for t in argtypes]) */
+ PyObject *restype; /* CDataObject or NULL */
+ PyObject *checker;
+ int flags; /* calling convention and such */
-/* May return NULL, but does not set an exception! */
-extern StgDictObject *PyObject_stgdict(PyObject *self);
+ /* pep3118 fields, pointers need PyMem_Free */
+ char *format;
+ int ndim;
+ Py_ssize_t *shape;
+/* Py_ssize_t *strides; */ /* unused in ctypes */
+/* Py_ssize_t *suboffsets; */ /* unused in ctypes */
+} StgInfo;
-extern int PyCStgDict_clone(StgDictObject *src, StgDictObject *dst);
+extern int PyCStgInfo_clone(StgInfo *dst_info, StgInfo *src_info);
typedef int(* PPROC)(void);
@@ -416,8 +404,74 @@ void *Py_ffi_closure_alloc(size_t size, void** codeloc);
#define Py_ffi_closure_alloc ffi_closure_alloc
#endif
-/*
- Local Variables:
- compile-command: "python setup.py -q build install --home ~"
- End:
-*/
+
+/****************************************************************
+ * Accessing StgInfo -- these are inlined for performance reasons.
+ */
+
+// `PyStgInfo_From**` functions get a PyCTypeDataObject.
+// These return -1 on error, 0 if "not found", 1 on OK.
+// (Currently, these do not return -1 in practice. This might change
+// in the future.)
+
+//
+// Common helper:
+static inline int
+_stginfo_from_type(ctypes_state *state, PyTypeObject *type, StgInfo **result)
+{
+ *result = NULL;
+ if (!PyObject_IsInstance((PyObject *)type, (PyObject *)state->PyCType_Type)) {
+ // not a ctypes class.
+ return 0;
+ }
+ StgInfo *info = PyObject_GetTypeData((PyObject *)type, state->PyCType_Type);
+ assert(info != NULL);
+ if (!info->initialized) {
+ // StgInfo is not initialized. This happens in abstract classes.
+ return 0;
+ }
+ *result = info;
+ return 1;
+}
+// from a type:
+static inline int
+PyStgInfo_FromType(ctypes_state *state, PyObject *type, StgInfo **result)
+{
+ return _stginfo_from_type(state, (PyTypeObject *)type, result);
+}
+// from an instance:
+static inline int
+PyStgInfo_FromObject(ctypes_state *state, PyObject *obj, StgInfo **result)
+{
+ return _stginfo_from_type(state, Py_TYPE(obj), result);
+}
+// from either a type or an instance:
+static inline int
+PyStgInfo_FromAny(ctypes_state *state, PyObject *obj, StgInfo **result)
+{
+ if (PyType_Check(obj)) {
+ return _stginfo_from_type(state, (PyTypeObject *)obj, result);
+ }
+ return _stginfo_from_type(state, Py_TYPE(obj), result);
+}
+
+// Initialize StgInfo on a newly created type
+static inline StgInfo *
+PyStgInfo_Init(ctypes_state *state, PyTypeObject *type)
+{
+ if (!PyObject_IsInstance((PyObject *)type, (PyObject *)state->PyCType_Type)) {
+ PyErr_Format(PyExc_SystemError,
+ "'%s' is not a ctypes class.",
+ type->tp_name);
+ return NULL;
+ }
+ StgInfo *info = PyObject_GetTypeData((PyObject *)type, state->PyCType_Type);
+ if (info->initialized) {
+ PyErr_Format(PyExc_SystemError,
+ "StgInfo of '%s' is already initialized.",
+ type->tp_name);
+ return NULL;
+ }
+ info->initialized = 1;
+ return info;
+}
diff --git a/Modules/_ctypes/stgdict.c b/Modules/_ctypes/stgdict.c
index 32ee414..8666ded 100644
--- a/Modules/_ctypes/stgdict.c
+++ b/Modules/_ctypes/stgdict.c
@@ -16,201 +16,62 @@
#endif
#include "ctypes.h"
-/******************************************************************/
-/*
- StdDict - a dictionary subclass, containing additional C accessible fields
-
- XXX blabla more
-*/
-
-/* Seems we need this, otherwise we get problems when calling
- * PyDict_SetItem() (ma_lookup is NULL)
+/* This file relates to StgInfo -- type-specific information for ctypes.
+ * See ctypes.h for details.
*/
-static int
-PyCStgDict_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;
-}
-static int
-PyCStgDict_clear(StgDictObject *self)
+int
+PyCStgInfo_clone(StgInfo *dst_info, StgInfo *src_info)
{
- Py_CLEAR(self->proto);
- Py_CLEAR(self->argtypes);
- Py_CLEAR(self->converters);
- Py_CLEAR(self->restype);
- Py_CLEAR(self->checker);
- return 0;
-}
+ Py_ssize_t size;
-static void
-PyCStgDict_dealloc(StgDictObject *self)
-{
- PyCStgDict_clear(self);
- PyMem_Free(self->format);
- PyMem_Free(self->shape);
- PyMem_Free(self->ffi_type_pointer.elements);
- PyDict_Type.tp_dealloc((PyObject *)self);
-}
+ PyMem_Free(dst_info->ffi_type_pointer.elements);
+ PyMem_Free(dst_info->format);
+ dst_info->format = NULL;
+ PyMem_Free(dst_info->shape);
+ dst_info->shape = NULL;
+ dst_info->ffi_type_pointer.elements = NULL;
-static PyObject *
-PyCStgDict_sizeof(StgDictObject *self, void *unused)
-{
- Py_ssize_t res;
-
- res = _PyDict_SizeOf((PyDictObject *)self);
- res += sizeof(StgDictObject) - sizeof(PyDictObject);
- if (self->format)
- res += strlen(self->format) + 1;
- res += self->ndim * sizeof(Py_ssize_t);
- if (self->ffi_type_pointer.elements)
- res += (self->length + 1) * sizeof(ffi_type *);
- return PyLong_FromSsize_t(res);
-}
+ memcpy(dst_info, src_info, sizeof(StgInfo));
-int
-PyCStgDict_clone(StgDictObject *dst, StgDictObject *src)
-{
- char *d, *s;
- Py_ssize_t size;
+ Py_XINCREF(dst_info->proto);
+ Py_XINCREF(dst_info->argtypes);
+ Py_XINCREF(dst_info->converters);
+ Py_XINCREF(dst_info->restype);
+ Py_XINCREF(dst_info->checker);
- PyCStgDict_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;
- s = (char *)src;
- memcpy(d + sizeof(PyDictObject),
- s + sizeof(PyDictObject),
- sizeof(StgDictObject) - sizeof(PyDictObject));
-
- Py_XINCREF(dst->proto);
- Py_XINCREF(dst->argtypes);
- Py_XINCREF(dst->converters);
- Py_XINCREF(dst->restype);
- Py_XINCREF(dst->checker);
-
- if (src->format) {
- dst->format = PyMem_Malloc(strlen(src->format) + 1);
- if (dst->format == NULL) {
+ if (src_info->format) {
+ dst_info->format = PyMem_Malloc(strlen(src_info->format) + 1);
+ if (dst_info->format == NULL) {
PyErr_NoMemory();
return -1;
}
- strcpy(dst->format, src->format);
+ strcpy(dst_info->format, src_info->format);
}
- if (src->shape) {
- dst->shape = PyMem_Malloc(sizeof(Py_ssize_t) * src->ndim);
- if (dst->shape == NULL) {
+ if (src_info->shape) {
+ dst_info->shape = PyMem_Malloc(sizeof(Py_ssize_t) * src_info->ndim);
+ if (dst_info->shape == NULL) {
PyErr_NoMemory();
return -1;
}
- memcpy(dst->shape, src->shape,
- sizeof(Py_ssize_t) * src->ndim);
+ memcpy(dst_info->shape, src_info->shape,
+ sizeof(Py_ssize_t) * src_info->ndim);
}
- if (src->ffi_type_pointer.elements == NULL)
+ if (src_info->ffi_type_pointer.elements == NULL)
return 0;
- size = sizeof(ffi_type *) * (src->length + 1);
- dst->ffi_type_pointer.elements = PyMem_Malloc(size);
- if (dst->ffi_type_pointer.elements == NULL) {
+ size = sizeof(ffi_type *) * (src_info->length + 1);
+ dst_info->ffi_type_pointer.elements = PyMem_Malloc(size);
+ if (dst_info->ffi_type_pointer.elements == NULL) {
PyErr_NoMemory();
return -1;
}
- memcpy(dst->ffi_type_pointer.elements,
- src->ffi_type_pointer.elements,
+ memcpy(dst_info->ffi_type_pointer.elements,
+ src_info->ffi_type_pointer.elements,
size);
return 0;
}
-static struct PyMethodDef PyCStgDict_methods[] = {
- {"__sizeof__", (PyCFunction)PyCStgDict_sizeof, METH_NOARGS},
- {NULL, NULL} /* sentinel */
-};
-
-PyTypeObject PyCStgDict_Type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- "StgDict",
- sizeof(StgDictObject),
- 0,
- (destructor)PyCStgDict_dealloc, /* tp_dealloc */
- 0, /* tp_vectorcall_offset */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_as_async */
- 0, /* tp_repr */
- 0, /* tp_as_number */
- 0, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- 0, /* tp_getattro */
- 0, /* tp_setattro */
- 0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
- 0, /* tp_doc */
- 0, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
- 0, /* tp_iternext */
- PyCStgDict_methods, /* tp_methods */
- 0, /* tp_members */
- 0, /* tp_getset */
- 0, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- (initproc)PyCStgDict_init, /* tp_init */
- 0, /* tp_alloc */
- 0, /* tp_new */
- 0, /* tp_free */
-};
-
-/* May return NULL, but does not set an exception! */
-StgDictObject *
-PyType_stgdict(PyObject *obj)
-{
- PyTypeObject *type;
-
- if (!PyType_Check(obj)) {
- return NULL;
- }
- ctypes_state *st = GLOBAL_STATE();
- type = (PyTypeObject *)obj;
- if (!type->tp_dict || !PyCStgDict_CheckExact(st, type->tp_dict)) {
- return NULL;
- }
- return (StgDictObject *)type->tp_dict;
-}
-
-/* May return NULL, but does not set an exception! */
-/*
- This function should be as fast as possible, so we don't call PyType_stgdict
- above but inline the code, and avoid the PyType_Check().
-*/
-StgDictObject *
-PyObject_stgdict(PyObject *self)
-{
- PyTypeObject *type = Py_TYPE(self);
- ctypes_state *st = GLOBAL_STATE();
- if (!type->tp_dict || !PyCStgDict_CheckExact(st, type->tp_dict)) {
- return NULL;
- }
- return (StgDictObject *)type->tp_dict;
-}
-
/* descr is the descriptor for a field marked as anonymous. Get all the
_fields_ descriptors from descr->proto, create new descriptors with offset
and index adjusted, and stuff them into type.
@@ -372,12 +233,11 @@ _ctypes_alloc_format_padding(const char *prefix, Py_ssize_t padding)
/*
Retrieve the (optional) _pack_ attribute from a type, the _fields_ attribute,
- and create an StgDictObject. Used for Structure and Union subclasses.
+ and initialize StgInfo. Used for Structure and Union subclasses.
*/
int
-PyCStructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct)
+PyCStructUnionType_update_stginfo(PyObject *type, PyObject *fields, int isStruct)
{
- StgDictObject *stgdict, *basedict;
Py_ssize_t len, offset, size, align, i;
Py_ssize_t union_size, total_align, aligned_size;
Py_ssize_t field_size = 0;
@@ -456,90 +316,97 @@ PyCStructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct
return -1;
}
- stgdict = PyType_stgdict(type);
- if (!stgdict) {
+ ctypes_state *st = GLOBAL_STATE();
+ StgInfo *stginfo;
+ if (PyStgInfo_FromType(st, type, &stginfo) < 0) {
+ return -1;
+ }
+ if (!stginfo) {
PyErr_SetString(PyExc_TypeError,
"ctypes state is not initialized");
return -1;
}
+
/* If this structure/union is already marked final we cannot assign
_fields_ anymore. */
- if (stgdict->flags & DICTFLAG_FINAL) {/* is final ? */
+ if (stginfo->flags & DICTFLAG_FINAL) {/* is final ? */
PyErr_SetString(PyExc_AttributeError,
"_fields_ is final");
return -1;
}
- if (stgdict->format) {
- PyMem_Free(stgdict->format);
- stgdict->format = NULL;
+ if (stginfo->format) {
+ PyMem_Free(stginfo->format);
+ stginfo->format = NULL;
}
- if (stgdict->ffi_type_pointer.elements)
- PyMem_Free(stgdict->ffi_type_pointer.elements);
+ if (stginfo->ffi_type_pointer.elements)
+ PyMem_Free(stginfo->ffi_type_pointer.elements);
- basedict = PyType_stgdict((PyObject *)((PyTypeObject *)type)->tp_base);
- if (basedict) {
- stgdict->flags |= (basedict->flags &
+ StgInfo *baseinfo;
+ if (PyStgInfo_FromType(st, (PyObject *)((PyTypeObject *)type)->tp_base,
+ &baseinfo) < 0) {
+ return -1;
+ }
+ if (baseinfo) {
+ stginfo->flags |= (baseinfo->flags &
(TYPEFLAG_HASUNION | TYPEFLAG_HASBITFIELD));
}
if (!isStruct) {
- stgdict->flags |= TYPEFLAG_HASUNION;
+ stginfo->flags |= TYPEFLAG_HASUNION;
}
- if (basedict) {
- size = offset = basedict->size;
- align = basedict->align;
+ if (baseinfo) {
+ size = offset = baseinfo->size;
+ align = baseinfo->align;
union_size = 0;
total_align = align ? align : 1;
total_align = max(total_align, forced_alignment);
- stgdict->ffi_type_pointer.type = FFI_TYPE_STRUCT;
- stgdict->ffi_type_pointer.elements = PyMem_New(ffi_type *, basedict->length + len + 1);
- if (stgdict->ffi_type_pointer.elements == NULL) {
+ stginfo->ffi_type_pointer.type = FFI_TYPE_STRUCT;
+ stginfo->ffi_type_pointer.elements = PyMem_New(ffi_type *, baseinfo->length + len + 1);
+ if (stginfo->ffi_type_pointer.elements == NULL) {
PyErr_NoMemory();
return -1;
}
- memset(stgdict->ffi_type_pointer.elements, 0,
- sizeof(ffi_type *) * (basedict->length + len + 1));
- if (basedict->length > 0) {
- memcpy(stgdict->ffi_type_pointer.elements,
- basedict->ffi_type_pointer.elements,
- sizeof(ffi_type *) * (basedict->length));
+ memset(stginfo->ffi_type_pointer.elements, 0,
+ sizeof(ffi_type *) * (baseinfo->length + len + 1));
+ if (baseinfo->length > 0) {
+ memcpy(stginfo->ffi_type_pointer.elements,
+ baseinfo->ffi_type_pointer.elements,
+ sizeof(ffi_type *) * (baseinfo->length));
}
- ffi_ofs = basedict->length;
+ ffi_ofs = baseinfo->length;
} else {
offset = 0;
size = 0;
align = 0;
union_size = 0;
total_align = forced_alignment;
- stgdict->ffi_type_pointer.type = FFI_TYPE_STRUCT;
- stgdict->ffi_type_pointer.elements = PyMem_New(ffi_type *, len + 1);
- if (stgdict->ffi_type_pointer.elements == NULL) {
+ stginfo->ffi_type_pointer.type = FFI_TYPE_STRUCT;
+ stginfo->ffi_type_pointer.elements = PyMem_New(ffi_type *, len + 1);
+ if (stginfo->ffi_type_pointer.elements == NULL) {
PyErr_NoMemory();
return -1;
}
- memset(stgdict->ffi_type_pointer.elements, 0,
+ memset(stginfo->ffi_type_pointer.elements, 0,
sizeof(ffi_type *) * (len + 1));
ffi_ofs = 0;
}
- assert(stgdict->format == NULL);
+ assert(stginfo->format == NULL);
if (isStruct) {
- stgdict->format = _ctypes_alloc_format_string(NULL, "T{");
+ stginfo->format = _ctypes_alloc_format_string(NULL, "T{");
} else {
/* PEP3118 doesn't support union. Use 'B' for bytes. */
- stgdict->format = _ctypes_alloc_format_string(NULL, "B");
+ stginfo->format = _ctypes_alloc_format_string(NULL, "B");
}
- if (stgdict->format == NULL)
+ if (stginfo->format == NULL)
return -1;
- ctypes_state *st = GLOBAL_STATE();
for (i = 0; i < len; ++i) {
PyObject *name = NULL, *desc = NULL;
PyObject *pair = PySequence_GetItem(fields, i);
PyObject *prop;
- StgDictObject *dict;
int bitsize = 0;
if (!pair || !PyArg_ParseTuple(pair, "UO|i", &name, &desc, &bitsize)) {
@@ -551,22 +418,28 @@ PyCStructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct
if (PyCArrayTypeObject_Check(st, desc)) {
arrays_seen = 1;
}
- dict = PyType_stgdict(desc);
- if (dict == NULL) {
+
+ StgInfo *info;
+ if (PyStgInfo_FromType(st, desc, &info) < 0) {
+ Py_DECREF(pair);
+ return -1;
+ }
+ if (info == NULL) {
Py_DECREF(pair);
PyErr_Format(PyExc_TypeError,
"second item in _fields_ tuple (index %zd) must be a C type",
i);
return -1;
}
- stgdict->ffi_type_pointer.elements[ffi_ofs + i] = &dict->ffi_type_pointer;
- if (dict->flags & (TYPEFLAG_ISPOINTER | TYPEFLAG_HASPOINTER))
- stgdict->flags |= TYPEFLAG_HASPOINTER;
- stgdict->flags |= dict->flags & (TYPEFLAG_HASUNION | TYPEFLAG_HASBITFIELD);
- dict->flags |= DICTFLAG_FINAL; /* mark field type final */
+
+ stginfo->ffi_type_pointer.elements[ffi_ofs + i] = &info->ffi_type_pointer;
+ if (info->flags & (TYPEFLAG_ISPOINTER | TYPEFLAG_HASPOINTER))
+ stginfo->flags |= TYPEFLAG_HASPOINTER;
+ stginfo->flags |= info->flags & (TYPEFLAG_HASUNION | TYPEFLAG_HASBITFIELD);
+ info->flags |= DICTFLAG_FINAL; /* mark field type final */
if (PyTuple_Size(pair) == 3) { /* bits specified */
- stgdict->flags |= TYPEFLAG_HASBITFIELD;
- switch(dict->ffi_type_pointer.type) {
+ stginfo->flags |= TYPEFLAG_HASBITFIELD;
+ switch(info->ffi_type_pointer.type) {
case FFI_TYPE_UINT8:
case FFI_TYPE_UINT16:
case FFI_TYPE_UINT32:
@@ -577,8 +450,8 @@ PyCStructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct
case FFI_TYPE_SINT8:
case FFI_TYPE_SINT16:
case FFI_TYPE_SINT32:
- if (dict->getfunc != _ctypes_get_fielddesc("c")->getfunc
- && dict->getfunc != _ctypes_get_fielddesc("u")->getfunc
+ if (info->getfunc != _ctypes_get_fielddesc("c")->getfunc
+ && info->getfunc != _ctypes_get_fielddesc("u")->getfunc
)
break;
/* else fall through */
@@ -589,7 +462,7 @@ PyCStructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct
Py_DECREF(pair);
return -1;
}
- if (bitsize <= 0 || bitsize > dict->size * 8) {
+ if (bitsize <= 0 || bitsize > info->size * 8) {
PyErr_SetString(PyExc_ValueError,
"number of bits invalid for bit field");
Py_DECREF(pair);
@@ -599,7 +472,7 @@ PyCStructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct
bitsize = 0;
if (isStruct) {
- const char *fieldfmt = dict->format ? dict->format : "B";
+ const char *fieldfmt = info->format ? info->format : "B";
const char *fieldname = PyUnicode_AsUTF8(name);
char *ptr;
Py_ssize_t len;
@@ -629,10 +502,10 @@ PyCStructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct
padding = ((CFieldObject *)prop)->offset - last_size;
if (padding > 0) {
- ptr = stgdict->format;
- stgdict->format = _ctypes_alloc_format_padding(ptr, padding);
+ ptr = stginfo->format;
+ stginfo->format = _ctypes_alloc_format_padding(ptr, padding);
PyMem_Free(ptr);
- if (stgdict->format == NULL) {
+ if (stginfo->format == NULL) {
Py_DECREF(pair);
Py_DECREF(prop);
return -1;
@@ -650,17 +523,17 @@ PyCStructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct
}
sprintf(buf, "%s:%s:", fieldfmt, fieldname);
- ptr = stgdict->format;
- if (dict->shape != NULL) {
- stgdict->format = _ctypes_alloc_format_string_with_shape(
- dict->ndim, dict->shape, stgdict->format, buf);
+ ptr = stginfo->format;
+ if (info->shape != NULL) {
+ stginfo->format = _ctypes_alloc_format_string_with_shape(
+ info->ndim, info->shape, stginfo->format, buf);
} else {
- stgdict->format = _ctypes_alloc_format_string(stgdict->format, buf);
+ stginfo->format = _ctypes_alloc_format_string(stginfo->format, buf);
}
PyMem_Free(ptr);
PyMem_Free(buf);
- if (stgdict->format == NULL) {
+ if (stginfo->format == NULL) {
Py_DECREF(pair);
Py_DECREF(prop);
return -1;
@@ -704,29 +577,29 @@ PyCStructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct
/* Pad up to the full size of the struct */
padding = aligned_size - size;
if (padding > 0) {
- ptr = stgdict->format;
- stgdict->format = _ctypes_alloc_format_padding(ptr, padding);
+ ptr = stginfo->format;
+ stginfo->format = _ctypes_alloc_format_padding(ptr, padding);
PyMem_Free(ptr);
- if (stgdict->format == NULL) {
+ if (stginfo->format == NULL) {
return -1;
}
}
- ptr = stgdict->format;
- stgdict->format = _ctypes_alloc_format_string(stgdict->format, "}");
+ ptr = stginfo->format;
+ stginfo->format = _ctypes_alloc_format_string(stginfo->format, "}");
PyMem_Free(ptr);
- if (stgdict->format == NULL)
+ if (stginfo->format == NULL)
return -1;
}
- stgdict->ffi_type_pointer.alignment = Py_SAFE_DOWNCAST(total_align,
+ stginfo->ffi_type_pointer.alignment = Py_SAFE_DOWNCAST(total_align,
Py_ssize_t,
unsigned short);
- stgdict->ffi_type_pointer.size = aligned_size;
+ stginfo->ffi_type_pointer.size = aligned_size;
- stgdict->size = aligned_size;
- stgdict->align = total_align;
- stgdict->length = ffi_ofs + len;
+ stginfo->size = aligned_size;
+ stginfo->align = total_align;
+ stginfo->length = ffi_ofs + len;
/*
* The value of MAX_STRUCT_SIZE depends on the platform Python is running on.
@@ -817,7 +690,6 @@ PyCStructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct
for (i = 0; i < len; ++i) {
PyObject *name, *desc;
PyObject *pair = PySequence_GetItem(fields, i);
- StgDictObject *dict;
int bitsize = 0;
if (pair == NULL) {
@@ -829,25 +701,34 @@ PyCStructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct
Py_DECREF(pair);
return -1;
}
- dict = PyType_stgdict(desc);
- if (dict == NULL) {
+
+ StgInfo *info;
+ if (PyStgInfo_FromType(st, desc, &info) < 0) {
+ Py_DECREF(pair);
+ return -1;
+ }
+ if (info == NULL) {
Py_DECREF(pair);
PyErr_Format(PyExc_TypeError,
"second item in _fields_ tuple (index %zd) must be a C type",
i);
return -1;
}
+
if (!PyCArrayTypeObject_Check(st, desc)) {
/* Not an array. Just need an ffi_type pointer. */
num_ffi_type_pointers++;
}
else {
/* It's an array. */
- Py_ssize_t length = dict->length;
- StgDictObject *edict;
+ Py_ssize_t length = info->length;
- edict = PyType_stgdict(dict->proto);
- if (edict == NULL) {
+ StgInfo *einfo;
+ if (PyStgInfo_FromType(st, info->proto, &einfo) < 0) {
+ Py_DECREF(pair);
+ return -1;
+ }
+ if (einfo == NULL) {
Py_DECREF(pair);
PyErr_Format(PyExc_TypeError,
"second item in _fields_ tuple (index %zd) must be a C type",
@@ -895,9 +776,9 @@ PyCStructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct
if (num_ffi_types > 0) {
memset(structs, 0, num_ffi_types * sizeof(ffi_type));
}
- if (ffi_ofs && (basedict != NULL)) {
+ if (ffi_ofs && (baseinfo != NULL)) {
memcpy(element_types,
- basedict->ffi_type_pointer.elements,
+ baseinfo->ffi_type_pointer.elements,
ffi_ofs * sizeof(ffi_type *));
}
element_index = ffi_ofs;
@@ -906,7 +787,6 @@ PyCStructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct
for (i = 0; i < len; ++i) {
PyObject *name, *desc;
PyObject *pair = PySequence_GetItem(fields, i);
- StgDictObject *dict;
int bitsize = 0;
if (pair == NULL) {
@@ -926,9 +806,16 @@ PyCStructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct
PyMem_Free(type_block);
return -1;
}
- dict = PyType_stgdict(desc);
+
+ StgInfo *info;
+ if (PyStgInfo_FromType(st, desc, &info) < 0) {
+ Py_DECREF(pair);
+ PyMem_Free(type_block);
+ return -1;
+ }
+
/* Possibly this check could be avoided, but see above comment. */
- if (dict == NULL) {
+ if (info == NULL) {
Py_DECREF(pair);
PyMem_Free(type_block);
PyErr_Format(PyExc_TypeError,
@@ -936,17 +823,21 @@ PyCStructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct
i);
return -1;
}
+
assert(element_index < (ffi_ofs + len)); /* will be used below */
if (!PyCArrayTypeObject_Check(st, desc)) {
/* Not an array. Just copy over the element ffi_type. */
- element_types[element_index++] = &dict->ffi_type_pointer;
+ element_types[element_index++] = &info->ffi_type_pointer;
}
else {
- Py_ssize_t length = dict->length;
- StgDictObject *edict;
-
- edict = PyType_stgdict(dict->proto);
- if (edict == NULL) {
+ Py_ssize_t length = info->length;
+ StgInfo *einfo;
+ if (PyStgInfo_FromType(st, info->proto, &einfo) < 0) {
+ Py_DECREF(pair);
+ PyMem_Free(type_block);
+ return -1;
+ }
+ if (einfo == NULL) {
Py_DECREF(pair);
PyMem_Free(type_block);
PyErr_Format(PyExc_TypeError,
@@ -955,15 +846,15 @@ PyCStructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct
return -1;
}
element_types[element_index++] = &structs[struct_index];
- structs[struct_index].size = length * edict->ffi_type_pointer.size;
- structs[struct_index].alignment = edict->ffi_type_pointer.alignment;
+ structs[struct_index].size = length * einfo->ffi_type_pointer.size;
+ structs[struct_index].alignment = einfo->ffi_type_pointer.alignment;
structs[struct_index].type = FFI_TYPE_STRUCT;
structs[struct_index].elements = &dummy_types[dummy_index];
++struct_index;
/* Copy over the element's type, length times. */
while (length > 0) {
assert(dummy_index < (num_ffi_type_pointers));
- dummy_types[dummy_index++] = &edict->ffi_type_pointer;
+ dummy_types[dummy_index++] = &einfo->ffi_type_pointer;
length--;
}
assert(dummy_index < (num_ffi_type_pointers));
@@ -977,19 +868,19 @@ PyCStructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct
* Replace the old elements with the new, taking into account
* base class elements where necessary.
*/
- assert(stgdict->ffi_type_pointer.elements);
- PyMem_Free(stgdict->ffi_type_pointer.elements);
- stgdict->ffi_type_pointer.elements = element_types;
+ assert(stginfo->ffi_type_pointer.elements);
+ PyMem_Free(stginfo->ffi_type_pointer.elements);
+ stginfo->ffi_type_pointer.elements = element_types;
}
/* We did check that this flag was NOT set above, it must not
have been set until now. */
- if (stgdict->flags & DICTFLAG_FINAL) {
+ if (stginfo->flags & DICTFLAG_FINAL) {
PyErr_SetString(PyExc_AttributeError,
"Structure or union cannot contain itself");
return -1;
}
- stgdict->flags |= DICTFLAG_FINAL;
+ stginfo->flags |= DICTFLAG_FINAL;
return MakeAnonFields(type);
}