Issue #17170: speed up PyArg_ParseTuple[AndKeywords] a bit.

This commit is contained in:
Antoine Pitrou 2013-02-17 01:04:57 +01:00
parent e924ddb23e
commit 7056cb2867

View file

@ -46,10 +46,12 @@ typedef struct {
} freelistentry_t; } freelistentry_t;
typedef struct { typedef struct {
int first_available;
freelistentry_t *entries; freelistentry_t *entries;
int first_available;
int entries_malloced;
} freelist_t; } freelist_t;
#define STATIC_FREELIST_ENTRIES 8
/* Forward */ /* Forward */
static int vgetargs1(PyObject *, const char *, va_list *, int); static int vgetargs1(PyObject *, const char *, va_list *, int);
@ -187,6 +189,7 @@ cleanreturn(int retval, freelist_t *freelist)
freelist->entries[index].item); freelist->entries[index].item);
} }
} }
if (freelist->entries_malloced)
PyMem_FREE(freelist->entries); PyMem_FREE(freelist->entries);
return retval; return retval;
} }
@ -197,6 +200,8 @@ vgetargs1(PyObject *args, const char *format, va_list *p_va, int flags)
{ {
char msgbuf[256]; char msgbuf[256];
int levels[32]; int levels[32];
freelistentry_t static_entries[STATIC_FREELIST_ENTRIES];
freelist_t freelist = {static_entries, 0, 0};
const char *fname = NULL; const char *fname = NULL;
const char *message = NULL; const char *message = NULL;
int min = -1; int min = -1;
@ -206,7 +211,6 @@ vgetargs1(PyObject *args, const char *format, va_list *p_va, int flags)
const char *formatsave = format; const char *formatsave = format;
Py_ssize_t i, len; Py_ssize_t i, len;
char *msg; char *msg;
freelist_t freelist = {0, NULL};
int compat = flags & FLAG_COMPAT; int compat = flags & FLAG_COMPAT;
assert(compat || (args != (PyObject*)NULL)); assert(compat || (args != (PyObject*)NULL));
@ -240,15 +244,15 @@ vgetargs1(PyObject *args, const char *format, va_list *p_va, int flags)
message = format; message = format;
endfmt = 1; endfmt = 1;
break; break;
case '|':
if (level == 0)
min = max;
break;
default: default:
if (level == 0) { if (level == 0) {
if (c == 'O') if (Py_ISALPHA(Py_CHARMASK(c)))
max++;
else if (Py_ISALPHA(Py_CHARMASK(c))) {
if (c != 'e') /* skip encoded */ if (c != 'e') /* skip encoded */
max++; max++;
} else if (c == '|')
min = max;
} }
break; break;
} }
@ -262,11 +266,14 @@ vgetargs1(PyObject *args, const char *format, va_list *p_va, int flags)
format = formatsave; format = formatsave;
if (max > STATIC_FREELIST_ENTRIES) {
freelist.entries = PyMem_NEW(freelistentry_t, max); freelist.entries = PyMem_NEW(freelistentry_t, max);
if (freelist.entries == NULL) { if (freelist.entries == NULL) {
PyErr_NoMemory(); PyErr_NoMemory();
return 0; return 0;
} }
freelist.entries_malloced = 1;
}
if (compat) { if (compat) {
if (max == 0) { if (max == 0) {
@ -1421,7 +1428,8 @@ vgetargskeywords(PyObject *args, PyObject *keywords, const char *format,
int max = INT_MAX; int max = INT_MAX;
int i, len, nargs, nkeywords; int i, len, nargs, nkeywords;
PyObject *current_arg; PyObject *current_arg;
freelist_t freelist = {0, NULL}; freelistentry_t static_entries[STATIC_FREELIST_ENTRIES];
freelist_t freelist = {static_entries, 0, 0};
assert(args != NULL && PyTuple_Check(args)); assert(args != NULL && PyTuple_Check(args));
assert(keywords == NULL || PyDict_Check(keywords)); assert(keywords == NULL || PyDict_Check(keywords));
@ -1445,11 +1453,14 @@ vgetargskeywords(PyObject *args, PyObject *keywords, const char *format,
for (len=0; kwlist[len]; len++) for (len=0; kwlist[len]; len++)
continue; continue;
if (len > STATIC_FREELIST_ENTRIES) {
freelist.entries = PyMem_NEW(freelistentry_t, len); freelist.entries = PyMem_NEW(freelistentry_t, len);
if (freelist.entries == NULL) { if (freelist.entries == NULL) {
PyErr_NoMemory(); PyErr_NoMemory();
return 0; return 0;
} }
freelist.entries_malloced = 1;
}
nargs = PyTuple_GET_SIZE(args); nargs = PyTuple_GET_SIZE(args);
nkeywords = (keywords == NULL) ? 0 : PyDict_Size(keywords); nkeywords = (keywords == NULL) ? 0 : PyDict_Size(keywords);
@ -1574,22 +1585,18 @@ vgetargskeywords(PyObject *args, PyObject *keywords, const char *format,
Py_ssize_t pos = 0; Py_ssize_t pos = 0;
while (PyDict_Next(keywords, &pos, &key, &value)) { while (PyDict_Next(keywords, &pos, &key, &value)) {
int match = 0; int match = 0;
char *ks;
if (!PyUnicode_Check(key)) { if (!PyUnicode_Check(key)) {
PyErr_SetString(PyExc_TypeError, PyErr_SetString(PyExc_TypeError,
"keywords must be strings"); "keywords must be strings");
return cleanreturn(0, &freelist); return cleanreturn(0, &freelist);
} }
/* check that _PyUnicode_AsString() result is not NULL */ /* check that _PyUnicode_AsString() result is not NULL */
ks = _PyUnicode_AsString(key);
if (ks != NULL) {
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
if (!strcmp(ks, kwlist[i])) { if (!PyUnicode_CompareWithASCIIString(key, kwlist[i])) {
match = 1; match = 1;
break; break;
} }
} }
}
if (!match) { if (!match) {
PyErr_Format(PyExc_TypeError, PyErr_Format(PyExc_TypeError,
"'%U' is an invalid keyword " "'%U' is an invalid keyword "