diff -r eae03e8aef0e Modules/_struct.c --- a/Modules/_struct.c Wed Aug 15 16:26:15 2012 +0200 +++ b/Modules/_struct.c Wed Aug 15 16:39:35 2012 +0200 @@ -9,7 +9,46 @@ #include "structmember.h" #include -static PyTypeObject PyStructType; +typedef struct { + PyObject *PyStructType; + /* Exception */ + PyObject *StructError; + PyObject *cache; +} _structstate; + + +#define _struct_state(o) ((_structstate *)PyModule_GetState(o)) + +static int +_struct_clear(PyObject *m) +{ + _structstate *state = _struct_state(m); + Py_CLEAR(state->PyStructType); + Py_CLEAR(state->StructError); + Py_CLEAR(state->cache); + return 0; +} + +static int +_struct_traverse(PyObject *m, visitproc visit, void *arg) +{ + _structstate *state = _struct_state(m); + Py_VISIT(state->PyStructType); + Py_VISIT(state->StructError); + Py_VISIT(state->cache); + return 0; +} + +static void +_struct_free(void *m) +{ + _struct_clear((PyObject *)m); +} + +static PyModuleDef _structmodule; + +#define _structstate_global ((_structstate *)PyModule_GetState(PyState_FindModule(&_structmodule))) + /* The translation function for each format character is table driven */ typedef struct _formatdef { @@ -40,14 +79,10 @@ } PyStructObject; -#define PyStruct_Check(op) PyObject_TypeCheck(op, &PyStructType) -#define PyStruct_CheckExact(op) (Py_TYPE(op) == &PyStructType) - - -/* Exception */ - -static PyObject *StructError; - +#define PyStruct_Check(op) PyObject_TypeCheck(op, \ + (PyTypeObject *)_structstate_global->PyStructType) +#define PyStruct_CheckExact(op) (Py_TYPE(op) == \ + (PyTypeObject *)_structstate_global->PyStructType) /* Define various structs to figure out the alignments of types */ @@ -105,7 +140,7 @@ return NULL; } else { - PyErr_SetString(StructError, + PyErr_SetString(_structstate_global->StructError, "required argument is not an integer"); return NULL; } @@ -133,7 +168,7 @@ Py_DECREF(v); if (x == (long)-1 && PyErr_Occurred()) { if (PyErr_ExceptionMatches(PyExc_OverflowError)) - PyErr_SetString(StructError, + PyErr_SetString(_structstate_global->StructError, "argument out of range"); return -1; } @@ -157,7 +192,7 @@ Py_DECREF(v); if (x == (unsigned long)-1 && PyErr_Occurred()) { if (PyErr_ExceptionMatches(PyExc_OverflowError)) - PyErr_SetString(StructError, + PyErr_SetString(_structstate_global->StructError, "argument out of range"); return -1; } @@ -182,7 +217,7 @@ Py_DECREF(v); if (x == (PY_LONG_LONG)-1 && PyErr_Occurred()) { if (PyErr_ExceptionMatches(PyExc_OverflowError)) - PyErr_SetString(StructError, + PyErr_SetString(_structstate_global->StructError, "argument out of range"); return -1; } @@ -205,7 +240,7 @@ Py_DECREF(v); if (x == (unsigned PY_LONG_LONG)-1 && PyErr_Occurred()) { if (PyErr_ExceptionMatches(PyExc_OverflowError)) - PyErr_SetString(StructError, + PyErr_SetString(_structstate_global->StructError, "argument out of range"); return -1; } @@ -230,7 +265,7 @@ Py_DECREF(v); if (x == (Py_ssize_t)-1 && PyErr_Occurred()) { if (PyErr_ExceptionMatches(PyExc_OverflowError)) - PyErr_SetString(StructError, + PyErr_SetString(_structstate_global->StructError, "argument out of range"); return -1; } @@ -253,7 +288,7 @@ Py_DECREF(v); if (x == (size_t)-1 && PyErr_Occurred()) { if (PyErr_ExceptionMatches(PyExc_OverflowError)) - PyErr_SetString(StructError, + PyErr_SetString(_structstate_global->StructError, "argument out of range"); return -1; } @@ -306,13 +341,13 @@ const size_t ulargest = (size_t)-1 >> ((SIZEOF_SIZE_T - f->size)*8); assert(f->size >= 1 && f->size <= SIZEOF_SIZE_T); if (is_unsigned) - PyErr_Format(StructError, + PyErr_Format(_structstate_global->StructError, "'%c' format requires 0 <= number <= %zu", f->format, ulargest); else { const Py_ssize_t largest = (Py_ssize_t)(ulargest >> 1); - PyErr_Format(StructError, + PyErr_Format(_structstate_global->StructError, "'%c' format requires %zd <= number <= %zd", f->format, ~ largest, @@ -501,7 +536,7 @@ if (get_long(v, &x) < 0) return -1; if (x < -128 || x > 127){ - PyErr_SetString(StructError, + PyErr_SetString(_structstate_global->StructError, "byte format requires -128 <= number <= 127"); return -1; } @@ -516,7 +551,7 @@ if (get_long(v, &x) < 0) return -1; if (x < 0 || x > 255){ - PyErr_SetString(StructError, + PyErr_SetString(_structstate_global->StructError, "ubyte format requires 0 <= number <= 255"); return -1; } @@ -528,7 +563,7 @@ np_char(char *p, PyObject *v, const formatdef *f) { if (!PyBytes_Check(v) || PyBytes_Size(v) != 1) { - PyErr_SetString(StructError, + PyErr_SetString(_structstate_global->StructError, "char format requires a bytes object of length 1"); return -1; } @@ -544,7 +579,7 @@ if (get_long(v, &x) < 0) return -1; if (x < SHRT_MIN || x > SHRT_MAX){ - PyErr_SetString(StructError, + PyErr_SetString(_structstate_global->StructError, "short format requires " STRINGIFY(SHRT_MIN) " <= number <= " STRINGIFY(SHRT_MAX)); return -1; @@ -562,7 +597,7 @@ if (get_long(v, &x) < 0) return -1; if (x < 0 || x > USHRT_MAX){ - PyErr_SetString(StructError, + PyErr_SetString(_structstate_global->StructError, "ushort format requires 0 <= number <= " STRINGIFY(USHRT_MAX)); return -1; } @@ -685,7 +720,7 @@ { float x = (float)PyFloat_AsDouble(v); if (x == -1 && PyErr_Occurred()) { - PyErr_SetString(StructError, + PyErr_SetString(_structstate_global->StructError, "required argument is not a float"); return -1; } @@ -698,7 +733,7 @@ { double x = PyFloat_AsDouble(v); if (x == -1 && PyErr_Occurred()) { - PyErr_SetString(StructError, + PyErr_SetString(_structstate_global->StructError, "required argument is not a float"); return -1; } @@ -926,7 +961,7 @@ { double x = PyFloat_AsDouble(v); if (x == -1 && PyErr_Occurred()) { - PyErr_SetString(StructError, + PyErr_SetString(_structstate_global->StructError, "required argument is not a float"); return -1; } @@ -938,7 +973,7 @@ { double x = PyFloat_AsDouble(v); if (x == -1 && PyErr_Occurred()) { - PyErr_SetString(StructError, + PyErr_SetString(_structstate_global->StructError, "required argument is not a float"); return -1; } @@ -1146,7 +1181,7 @@ { double x = PyFloat_AsDouble(v); if (x == -1 && PyErr_Occurred()) { - PyErr_SetString(StructError, + PyErr_SetString(_structstate_global->StructError, "required argument is not a float"); return -1; } @@ -1158,7 +1193,7 @@ { double x = PyFloat_AsDouble(v); if (x == -1 && PyErr_Occurred()) { - PyErr_SetString(StructError, + PyErr_SetString(_structstate_global->StructError, "required argument is not a float"); return -1; } @@ -1225,7 +1260,7 @@ return f; } } - PyErr_SetString(StructError, "bad char in struct format"); + PyErr_SetString(_structstate_global->StructError, "bad char in struct format"); return NULL; } @@ -1285,7 +1320,7 @@ num = num*10 + (c - '0'); } if (c == '\0') { - PyErr_SetString(StructError, + PyErr_SetString(_structstate_global->StructError, "repeat count given without format specifier"); return -1; } @@ -1376,7 +1411,7 @@ return 0; overflow: - PyErr_SetString(StructError, + PyErr_SetString(_structstate_global->StructError, "total struct size too long"); return -1; } @@ -1442,13 +1477,17 @@ static void s_dealloc(PyStructObject *s) { + PyTypeObject *type = Py_TYPE(s); if (s->weakreflist != NULL) PyObject_ClearWeakRefs((PyObject *)s); if (s->s_codes != NULL) { PyMem_FREE(s->s_codes); } Py_XDECREF(s->s_format); - Py_TYPE(s)->tp_free((PyObject *)s); + type->tp_free((PyObject *)s); + if((void *)type->tp_dealloc == (void *)s_dealloc) { + Py_DECREF(type); + } } static PyObject * @@ -1504,7 +1543,7 @@ if (PyObject_GetBuffer(input, &vbuf, PyBUF_SIMPLE) < 0) return NULL; if (vbuf.len != soself->s_size) { - PyErr_Format(StructError, + PyErr_Format(_structstate_global->StructError, "unpack requires a bytes object of length %zd", soself->s_size); PyBuffer_Release(&vbuf); @@ -1545,7 +1584,7 @@ if (offset < 0) offset += vbuf.len; if (offset < 0 || vbuf.len - offset < soself->s_size) { - PyErr_Format(StructError, + PyErr_Format(_structstate_global->StructError, "unpack_from requires a buffer of at least %zd bytes", soself->s_size); PyBuffer_Release(&vbuf); @@ -1587,7 +1626,7 @@ void *p; isstring = PyBytes_Check(v); if (!isstring && !PyByteArray_Check(v)) { - PyErr_SetString(StructError, + PyErr_SetString(_structstate_global->StructError, "argument for 's' must be a bytes object"); return -1; } @@ -1608,7 +1647,7 @@ void *p; isstring = PyBytes_Check(v); if (!isstring && !PyByteArray_Check(v)) { - PyErr_SetString(StructError, + PyErr_SetString(_structstate_global->StructError, "argument for 'p' must be a bytes object"); return -1; } @@ -1630,7 +1669,7 @@ } else { if (e->pack(res, v, e) < 0) { if (PyLong_Check(v) && PyErr_ExceptionMatches(PyExc_OverflowError)) - PyErr_SetString(StructError, + PyErr_SetString(_structstate_global->StructError, "long too large to convert to int"); return -1; } @@ -1661,7 +1700,7 @@ assert(soself->s_codes != NULL); if (PyTuple_GET_SIZE(args) != soself->s_len) { - PyErr_Format(StructError, + PyErr_Format(_structstate_global->StructError, "pack requires exactly %zd arguments", soself->s_len); return NULL; } @@ -1701,7 +1740,7 @@ assert(soself->s_codes != NULL); if (PyTuple_GET_SIZE(args) != (soself->s_len + 2)) { - PyErr_Format(StructError, + PyErr_Format(_structstate_global->StructError, "pack_into requires exactly %zd arguments", (soself->s_len + 2)); return NULL; @@ -1725,7 +1764,7 @@ /* Check boundaries */ if (offset < 0 || (buffer_len - offset) < soself->s_size) { - PyErr_Format(StructError, + PyErr_Format(_structstate_global->StructError, "pack_into requires a buffer of at least %zd bytes", soself->s_size); return NULL; @@ -1790,78 +1829,59 @@ {NULL} /* sentinel */ }; -static -PyTypeObject PyStructType = { - PyVarObject_HEAD_INIT(NULL, 0) +static PyType_Slot PyStructType_slots[] = { + {Py_tp_dealloc, (destructor)s_dealloc}, + {Py_tp_getattro, PyObject_GenericGetAttr}, + {Py_tp_setattro, PyObject_GenericSetAttr}, + {Py_tp_doc, s__doc__}, + {Py_tp_methods, s_methods}, + {Py_tp_members, NULL}, + {Py_tp_getset, s_getsetlist}, + {Py_tp_init, s_init}, + {Py_tp_alloc, PyType_GenericAlloc}, + {Py_tp_new, s_new}, + {Py_tp_free, PyObject_Del}, + {0, 0} +}; + +static PyType_Spec PyStructType_spec = { "Struct", sizeof(PyStructObject), 0, - (destructor)s_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_reserved */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - PyObject_GenericSetAttr, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - s__doc__, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - offsetof(PyStructObject, weakreflist), /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - s_methods, /* tp_methods */ - NULL, /* tp_members */ - s_getsetlist, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - s_init, /* tp_init */ - PyType_GenericAlloc,/* tp_alloc */ - s_new, /* tp_new */ - PyObject_Del, /* tp_free */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + PyStructType_slots, }; + /* ---- Standalone functions ---- */ #define MAXCACHE 100 -static PyObject *cache = NULL; + static PyObject * cache_struct(PyObject *fmt) { PyObject * s_object; - if (cache == NULL) { - cache = PyDict_New(); - if (cache == NULL) + if (_structstate_global->cache == NULL) { + _structstate_global->cache = PyDict_New(); + if (_structstate_global->cache == NULL) return NULL; } - s_object = PyDict_GetItem(cache, fmt); + s_object = PyDict_GetItem(_structstate_global->cache, fmt); if (s_object != NULL) { Py_INCREF(s_object); return s_object; } - s_object = PyObject_CallFunctionObjArgs((PyObject *)(&PyStructType), fmt, NULL); + s_object = PyObject_CallFunctionObjArgs(_structstate_global->PyStructType, fmt, NULL); if (s_object != NULL) { - if (PyDict_Size(cache) >= MAXCACHE) - PyDict_Clear(cache); + if (PyDict_Size(_structstate_global->cache) >= MAXCACHE) + PyDict_Clear(_structstate_global->cache); /* Attempt to cache the result */ - if (PyDict_SetItem(cache, fmt, s_object) == -1) + if (PyDict_SetItem(_structstate_global->cache, fmt, s_object) == -1) PyErr_Clear(); } return s_object; @@ -1873,7 +1893,7 @@ static PyObject * clearcache(PyObject *self) { - Py_CLEAR(cache); + Py_CLEAR(_structstate_global->cache); Py_RETURN_NONE; } @@ -2065,25 +2085,31 @@ PyModuleDef_HEAD_INIT, "_struct", module_doc, - -1, + sizeof(_structstate), module_functions, NULL, - NULL, - NULL, - NULL + _struct_traverse, + _struct_clear, + _struct_free }; PyMODINIT_FUNC PyInit__struct(void) { PyObject *m; + _structstate *state; m = PyModule_Create(&_structmodule); if (m == NULL) return NULL; - Py_TYPE(&PyStructType) = &PyType_Type; - if (PyType_Ready(&PyStructType) < 0) + state = _struct_state(m); + + state->PyStructType = PyType_FromSpec(&PyStructType_spec); + ((PyTypeObject *)(state->PyStructType))->tp_weaklistoffset = + offsetof(PyStructObject, weakreflist); + Py_TYPE(state->PyStructType) = &PyType_Type; + if (state->PyStructType == NULL) return NULL; /* Check endian and swap in faster functions */ @@ -2126,17 +2152,17 @@ } /* Add some symbolic constants to the module */ - if (StructError == NULL) { - StructError = PyErr_NewException("struct.error", NULL, NULL); - if (StructError == NULL) + if (state->StructError == NULL) { + state->StructError = PyErr_NewException("struct.error", NULL, NULL); + if (state->StructError == NULL) return NULL; } - Py_INCREF(StructError); - PyModule_AddObject(m, "error", StructError); + Py_INCREF(state->StructError); + PyModule_AddObject(m, "error", state->StructError); - Py_INCREF((PyObject*)&PyStructType); - PyModule_AddObject(m, "Struct", (PyObject*)&PyStructType); + Py_INCREF(state->PyStructType); + PyModule_AddObject(m, "Struct", state->PyStructType); return m; }