Issue #14596: The struct.Struct() objects now use more compact implementation.

This commit is contained in:
Serhiy Storchaka 2013-05-17 10:49:44 +03:00
parent e67f8e7419
commit fff61f2cd3
3 changed files with 98 additions and 86 deletions

View File

@ -8,7 +8,6 @@ import sys
from test import support from test import support
ISBIGENDIAN = sys.byteorder == "big" ISBIGENDIAN = sys.byteorder == "big"
IS32BIT = sys.maxsize == 0x7fffffff
integer_codes = 'b', 'B', 'h', 'H', 'i', 'I', 'l', 'L', 'q', 'Q', 'n', 'N' integer_codes = 'b', 'B', 'h', 'H', 'i', 'I', 'l', 'L', 'q', 'Q', 'n', 'N'
byteorders = '', '@', '=', '<', '>', '!' byteorders = '', '@', '=', '<', '>', '!'
@ -538,10 +537,6 @@ class StructTest(unittest.TestCase):
hugecount2 = '{}b{}H'.format(sys.maxsize//2, sys.maxsize//2) hugecount2 = '{}b{}H'.format(sys.maxsize//2, sys.maxsize//2)
self.assertRaises(struct.error, struct.calcsize, hugecount2) self.assertRaises(struct.error, struct.calcsize, hugecount2)
if IS32BIT:
def test_crasher(self):
self.assertRaises(MemoryError, struct.pack, "357913941b", "a")
def test_trailing_counter(self): def test_trailing_counter(self):
store = array.array('b', b' '*100) store = array.array('b', b' '*100)
@ -578,7 +573,7 @@ class StructTest(unittest.TestCase):
# The size of 'PyStructObject' # The size of 'PyStructObject'
totalsize = support.calcobjsize('2n3P') totalsize = support.calcobjsize('2n3P')
# The size taken up by the 'formatcode' dynamic array # The size taken up by the 'formatcode' dynamic array
totalsize += struct.calcsize('P2n0P') * (number_of_codes + 1) totalsize += struct.calcsize('P3n0P') * (number_of_codes + 1)
support.check_sizeof(self, struct.Struct(format_str), totalsize) support.check_sizeof(self, struct.Struct(format_str), totalsize)
@support.cpython_only @support.cpython_only
@ -589,7 +584,7 @@ class StructTest(unittest.TestCase):
self.check_sizeof('B' * 1234, 1234) self.check_sizeof('B' * 1234, 1234)
self.check_sizeof('fd', 2) self.check_sizeof('fd', 2)
self.check_sizeof('xxxxxxxxxxxxxx', 0) self.check_sizeof('xxxxxxxxxxxxxx', 0)
self.check_sizeof('100H', 100) self.check_sizeof('100H', 1)
self.check_sizeof('187s', 1) self.check_sizeof('187s', 1)
self.check_sizeof('20p', 1) self.check_sizeof('20p', 1)
self.check_sizeof('0s', 1) self.check_sizeof('0s', 1)

View File

@ -91,6 +91,8 @@ Core and Builtins
Library Library
------- -------
- Issue #14596: The struct.Struct() objects now use more compact implementation.
- Issue #17981: Closed socket on error in SysLogHandler. - Issue #17981: Closed socket on error in SysLogHandler.
- Issue #17964: Fix os.sysconf(): the return type of the C sysconf() function - Issue #17964: Fix os.sysconf(): the return type of the C sysconf() function

View File

@ -26,6 +26,7 @@ typedef struct _formatcode {
const struct _formatdef *fmtdef; const struct _formatdef *fmtdef;
Py_ssize_t offset; Py_ssize_t offset;
Py_ssize_t size; Py_ssize_t size;
Py_ssize_t repeat;
} formatcode; } formatcode;
/* Struct object interface */ /* Struct object interface */
@ -1263,7 +1264,7 @@ prepare_s(PyStructObject *self)
const char *s; const char *s;
const char *fmt; const char *fmt;
char c; char c;
Py_ssize_t size, len, num, itemsize; Py_ssize_t size, len, ncodes, num, itemsize;
fmt = PyBytes_AS_STRING(self->s_format); fmt = PyBytes_AS_STRING(self->s_format);
@ -1272,6 +1273,7 @@ prepare_s(PyStructObject *self)
s = fmt; s = fmt;
size = 0; size = 0;
len = 0; len = 0;
ncodes = 0;
while ((c = *s++) != '\0') { while ((c = *s++) != '\0') {
if (Py_ISSPACE(Py_CHARMASK(c))) if (Py_ISSPACE(Py_CHARMASK(c)))
continue; continue;
@ -1301,9 +1303,9 @@ prepare_s(PyStructObject *self)
switch (c) { switch (c) {
case 's': /* fall through */ case 's': /* fall through */
case 'p': len++; break; case 'p': len++; ncodes++; break;
case 'x': break; case 'x': break;
default: len += num; break; default: len += num; if (num) ncodes++; break;
} }
itemsize = e->size; itemsize = e->size;
@ -1318,14 +1320,14 @@ prepare_s(PyStructObject *self)
} }
/* check for overflow */ /* check for overflow */
if ((len + 1) > (PY_SSIZE_T_MAX / sizeof(formatcode))) { if ((ncodes + 1) > (PY_SSIZE_T_MAX / sizeof(formatcode))) {
PyErr_NoMemory(); PyErr_NoMemory();
return -1; return -1;
} }
self->s_size = size; self->s_size = size;
self->s_len = len; self->s_len = len;
codes = PyMem_MALLOC((len + 1) * sizeof(formatcode)); codes = PyMem_MALLOC((ncodes + 1) * sizeof(formatcode));
if (codes == NULL) { if (codes == NULL) {
PyErr_NoMemory(); PyErr_NoMemory();
return -1; return -1;
@ -1357,23 +1359,24 @@ prepare_s(PyStructObject *self)
codes->offset = size; codes->offset = size;
codes->size = num; codes->size = num;
codes->fmtdef = e; codes->fmtdef = e;
codes->repeat = 1;
codes++; codes++;
size += num; size += num;
} else if (c == 'x') { } else if (c == 'x') {
size += num; size += num;
} else { } else if (num) {
while (--num >= 0) {
codes->offset = size; codes->offset = size;
codes->size = e->size; codes->size = e->size;
codes->fmtdef = e; codes->fmtdef = e;
codes->repeat = num;
codes++; codes++;
size += e->size; size += e->size * num;
}
} }
} }
codes->fmtdef = NULL; codes->fmtdef = NULL;
codes->offset = size; codes->offset = size;
codes->size = 0; codes->size = 0;
codes->repeat = 0;
return 0; return 0;
@ -1462,9 +1465,11 @@ s_unpack_internal(PyStructObject *soself, char *startfrom) {
return NULL; return NULL;
for (code = soself->s_codes; code->fmtdef != NULL; code++) { for (code = soself->s_codes; code->fmtdef != NULL; code++) {
PyObject *v;
const formatdef *e = code->fmtdef; const formatdef *e = code->fmtdef;
const char *res = startfrom + code->offset; const char *res = startfrom + code->offset;
Py_ssize_t j = code->repeat;
while (j--) {
PyObject *v;
if (e->format == 's') { if (e->format == 's') {
v = PyBytes_FromStringAndSize(res, code->size); v = PyBytes_FromStringAndSize(res, code->size);
} else if (e->format == 'p') { } else if (e->format == 'p') {
@ -1478,6 +1483,8 @@ s_unpack_internal(PyStructObject *soself, char *startfrom) {
if (v == NULL) if (v == NULL)
goto fail; goto fail;
PyTuple_SET_ITEM(result, i++, v); PyTuple_SET_ITEM(result, i++, v);
res += code->size;
}
} }
return result; return result;
@ -1716,11 +1723,13 @@ s_pack_internal(PyStructObject *soself, PyObject *args, int offset, char* buf)
memset(buf, '\0', soself->s_size); memset(buf, '\0', soself->s_size);
i = offset; i = offset;
for (code = soself->s_codes; code->fmtdef != NULL; code++) { for (code = soself->s_codes; code->fmtdef != NULL; code++) {
Py_ssize_t n;
PyObject *v = PyTuple_GET_ITEM(args, i++);
const formatdef *e = code->fmtdef; const formatdef *e = code->fmtdef;
char *res = buf + code->offset; char *res = buf + code->offset;
Py_ssize_t j = code->repeat;
while (j--) {
PyObject *v = PyTuple_GET_ITEM(args, i++);
if (e->format == 's') { if (e->format == 's') {
Py_ssize_t n;
int isstring; int isstring;
void *p; void *p;
isstring = PyBytes_Check(v); isstring = PyBytes_Check(v);
@ -1742,6 +1751,7 @@ s_pack_internal(PyStructObject *soself, PyObject *args, int offset, char* buf)
if (n > 0) if (n > 0)
memcpy(res, p, n); memcpy(res, p, n);
} else if (e->format == 'p') { } else if (e->format == 'p') {
Py_ssize_t n;
int isstring; int isstring;
void *p; void *p;
isstring = PyBytes_Check(v); isstring = PyBytes_Check(v);
@ -1773,6 +1783,8 @@ s_pack_internal(PyStructObject *soself, PyObject *args, int offset, char* buf)
return -1; return -1;
} }
} }
res += code->size;
}
} }
/* Success */ /* Success */
@ -1907,8 +1919,11 @@ static PyObject *
s_sizeof(PyStructObject *self, void *unused) s_sizeof(PyStructObject *self, void *unused)
{ {
Py_ssize_t size; Py_ssize_t size;
formatcode *code;
size = sizeof(PyStructObject) + sizeof(formatcode) * (self->s_len + 1); size = sizeof(PyStructObject) + sizeof(formatcode);
for (code = self->s_codes; code->fmtdef != NULL; code++)
size += sizeof(formatcode);
return PyLong_FromSsize_t(size); return PyLong_FromSsize_t(size);
} }