Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 1741441

Browse files
Issue #29029: Speed up processing positional arguments in
PyArg_ParseTupleAndKeywords(), _PyArg_ParseTupleAndKeywordsFast() and like.
1 parent f6b96c7 commit 1741441

1 file changed

Lines changed: 89 additions & 101 deletions

File tree

Python/getargs.c

Lines changed: 89 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -1598,7 +1598,7 @@ vgetargskeywords(PyObject *args, PyObject *kwargs, const char *format,
15981598
{
15991599
char msgbuf[512];
16001600
int levels[32];
1601-
const char *fname, *msg, *custom_msg, *keyword;
1601+
const char *fname, *msg, *custom_msg;
16021602
int min = INT_MAX;
16031603
int max = INT_MAX;
16041604
int i, pos, len;
@@ -1666,7 +1666,6 @@ vgetargskeywords(PyObject *args, PyObject *kwargs, const char *format,
16661666

16671667
/* convert tuple args and keyword args in same loop, using kwlist to drive process */
16681668
for (i = 0; i < len; i++) {
1669-
keyword = kwlist[i];
16701669
if (*format == '|') {
16711670
if (min != INT_MAX) {
16721671
PyErr_SetString(PyExc_SystemError,
@@ -1720,26 +1719,17 @@ vgetargskeywords(PyObject *args, PyObject *kwargs, const char *format,
17201719
return cleanreturn(0, &freelist);
17211720
}
17221721
if (!skip) {
1723-
current_arg = NULL;
1724-
if (nkwargs && i >= pos) {
1725-
current_arg = PyDict_GetItemString(kwargs, keyword);
1726-
if (!current_arg && PyErr_Occurred()) {
1727-
return cleanreturn(0, &freelist);
1728-
}
1722+
if (i < nargs) {
1723+
current_arg = PyTuple_GET_ITEM(args, i);
17291724
}
1730-
if (current_arg) {
1731-
--nkwargs;
1732-
if (i < nargs) {
1733-
/* arg present in tuple and in dict */
1734-
PyErr_Format(PyExc_TypeError,
1735-
"Argument given by name ('%s') "
1736-
"and position (%d)",
1737-
keyword, i+1);
1738-
return cleanreturn(0, &freelist);
1739-
}
1725+
else if (nkwargs && i >= pos) {
1726+
current_arg = PyDict_GetItemString(kwargs, kwlist[i]);
1727+
if (current_arg)
1728+
--nkwargs;
1729+
}
1730+
else {
1731+
current_arg = NULL;
17401732
}
1741-
else if (i < nargs)
1742-
current_arg = PyTuple_GET_ITEM(args, i);
17431733

17441734
if (current_arg) {
17451735
msg = convertitem(current_arg, &format, p_va, flags,
@@ -1763,8 +1753,8 @@ vgetargskeywords(PyObject *args, PyObject *kwargs, const char *format,
17631753
}
17641754
else {
17651755
PyErr_Format(PyExc_TypeError, "Required argument "
1766-
"'%s' (pos %d) not found",
1767-
keyword, i+1);
1756+
"'%s' (pos %d) not found",
1757+
kwlist[i], i+1);
17681758
return cleanreturn(0, &freelist);
17691759
}
17701760
}
@@ -1803,19 +1793,32 @@ vgetargskeywords(PyObject *args, PyObject *kwargs, const char *format,
18031793
return cleanreturn(0, &freelist);
18041794
}
18051795

1806-
/* make sure there are no extraneous keyword arguments */
18071796
if (nkwargs > 0) {
1808-
PyObject *key, *value;
1809-
Py_ssize_t pos = 0;
1810-
while (PyDict_Next(kwargs, &pos, &key, &value)) {
1797+
PyObject *key;
1798+
Py_ssize_t j;
1799+
/* make sure there are no arguments given by name and position */
1800+
for (i = pos; i < nargs; i++) {
1801+
current_arg = PyDict_GetItemString(kwargs, kwlist[i]);
1802+
if (current_arg) {
1803+
/* arg present in tuple and in dict */
1804+
PyErr_Format(PyExc_TypeError,
1805+
"Argument given by name ('%s') "
1806+
"and position (%d)",
1807+
kwlist[i], i+1);
1808+
return cleanreturn(0, &freelist);
1809+
}
1810+
}
1811+
/* make sure there are no extraneous keyword arguments */
1812+
j = 0;
1813+
while (PyDict_Next(kwargs, &j, &key, NULL)) {
18111814
int match = 0;
18121815
if (!PyUnicode_Check(key)) {
18131816
PyErr_SetString(PyExc_TypeError,
18141817
"keywords must be strings");
18151818
return cleanreturn(0, &freelist);
18161819
}
1817-
for (i = 0; i < len; i++) {
1818-
if (*kwlist[i] && _PyUnicode_EqualToASCIIString(key, kwlist[i])) {
1820+
for (i = pos; i < len; i++) {
1821+
if (_PyUnicode_EqualToASCIIString(key, kwlist[i])) {
18191822
match = 1;
18201823
break;
18211824
}
@@ -1963,10 +1966,13 @@ parser_clear(struct _PyArg_Parser *parser)
19631966
}
19641967

19651968
static PyObject*
1966-
find_keyword(PyObject *kwnames, PyObject **kwstack, PyObject *key)
1969+
find_keyword(PyObject *kwargs, PyObject *kwnames, PyObject **kwstack, PyObject *key)
19671970
{
19681971
Py_ssize_t i, nkwargs;
19691972

1973+
if (kwargs != NULL) {
1974+
return PyDict_GetItem(kwargs, key);
1975+
}
19701976
nkwargs = PyTuple_GET_SIZE(kwnames);
19711977
for (i=0; i < nkwargs; i++) {
19721978
PyObject *kwname = PyTuple_GET_ITEM(kwnames, i);
@@ -1978,7 +1984,7 @@ find_keyword(PyObject *kwnames, PyObject **kwstack, PyObject *key)
19781984
}
19791985
if (!PyUnicode_Check(kwname)) {
19801986
/* ignore non-string keyword keys:
1981-
an error will be raised above */
1987+
an error will be raised below */
19821988
continue;
19831989
}
19841990
if (_PyUnicode_EQ(kwname, key)) {
@@ -2012,8 +2018,7 @@ vgetargskeywordsfast_impl(PyObject **args, Py_ssize_t nargs,
20122018
freelist.entries_malloced = 0;
20132019

20142020
assert(kwargs == NULL || PyDict_Check(kwargs));
2015-
assert((kwargs != NULL || kwnames != NULL)
2016-
|| (kwargs == NULL && kwnames == NULL));
2021+
assert(kwargs == NULL || kwnames == NULL);
20172022
assert(p_va != NULL);
20182023

20192024
if (parser == NULL) {
@@ -2074,7 +2079,6 @@ vgetargskeywordsfast_impl(PyObject **args, Py_ssize_t nargs,
20742079
format = parser->format;
20752080
/* convert tuple args and keyword args in same loop, using kwtuple to drive process */
20762081
for (i = 0; i < len; i++) {
2077-
keyword = (i >= pos) ? PyTuple_GET_ITEM(kwtuple, i - pos) : NULL;
20782082
if (*format == '|') {
20792083
format++;
20802084
}
@@ -2083,31 +2087,17 @@ vgetargskeywordsfast_impl(PyObject **args, Py_ssize_t nargs,
20832087
}
20842088
assert(!IS_END_OF_FORMAT(*format));
20852089

2086-
current_arg = NULL;
2087-
if (nkwargs && i >= pos) {
2088-
if (kwargs != NULL) {
2089-
current_arg = PyDict_GetItem(kwargs, keyword);
2090-
if (!current_arg && PyErr_Occurred()) {
2091-
return cleanreturn(0, &freelist);
2092-
}
2093-
}
2094-
else {
2095-
current_arg = find_keyword(kwnames, kwstack, keyword);
2096-
}
2090+
if (i < nargs) {
2091+
current_arg = args[i];
20972092
}
2098-
if (current_arg) {
2099-
--nkwargs;
2100-
if (i < nargs) {
2101-
/* arg present in tuple and in dict */
2102-
PyErr_Format(PyExc_TypeError,
2103-
"Argument given by name ('%U') "
2104-
"and position (%d)",
2105-
keyword, i+1);
2106-
return cleanreturn(0, &freelist);
2107-
}
2093+
else if (nkwargs && i >= pos) {
2094+
keyword = PyTuple_GET_ITEM(kwtuple, i - pos);
2095+
current_arg = find_keyword(kwargs, kwnames, kwstack, keyword);
2096+
if (current_arg)
2097+
--nkwargs;
21082098
}
2109-
else if (i < nargs) {
2110-
current_arg = args[i];
2099+
else {
2100+
current_arg = NULL;
21112101
}
21122102

21132103
if (current_arg) {
@@ -2123,13 +2113,15 @@ vgetargskeywordsfast_impl(PyObject **args, Py_ssize_t nargs,
21232113
if (i < parser->min) {
21242114
/* Less arguments than required */
21252115
if (i < pos) {
2116+
Py_ssize_t min = Py_MIN(pos, parser->min);
21262117
PyErr_Format(PyExc_TypeError,
21272118
"Function takes %s %d positional arguments"
21282119
" (%d given)",
2129-
(Py_MIN(pos, parser->min) < parser->max) ? "at least" : "exactly",
2130-
Py_MIN(pos, parser->min), nargs);
2120+
min < parser->max ? "at least" : "exactly",
2121+
min, nargs);
21312122
}
21322123
else {
2124+
keyword = PyTuple_GET_ITEM(kwtuple, i - pos);
21332125
PyErr_Format(PyExc_TypeError, "Required argument "
21342126
"'%U' (pos %d) not found",
21352127
keyword, i+1);
@@ -2152,54 +2144,50 @@ vgetargskeywordsfast_impl(PyObject **args, Py_ssize_t nargs,
21522144

21532145
assert(IS_END_OF_FORMAT(*format) || (*format == '|') || (*format == '$'));
21542146

2155-
/* make sure there are no extraneous keyword arguments */
21562147
if (nkwargs > 0) {
2157-
if (kwargs != NULL) {
2158-
PyObject *key, *value;
2159-
Py_ssize_t pos = 0;
2160-
while (PyDict_Next(kwargs, &pos, &key, &value)) {
2161-
int match;
2162-
if (!PyUnicode_Check(key)) {
2163-
PyErr_SetString(PyExc_TypeError,
2164-
"keywords must be strings");
2165-
return cleanreturn(0, &freelist);
2166-
}
2167-
match = PySequence_Contains(kwtuple, key);
2168-
if (match <= 0) {
2169-
if (!match) {
2170-
PyErr_Format(PyExc_TypeError,
2171-
"'%U' is an invalid keyword "
2172-
"argument for this function",
2173-
key);
2174-
}
2175-
return cleanreturn(0, &freelist);
2176-
}
2148+
Py_ssize_t j;
2149+
/* make sure there are no arguments given by name and position */
2150+
for (i = pos; i < nargs; i++) {
2151+
keyword = PyTuple_GET_ITEM(kwtuple, i - pos);
2152+
current_arg = find_keyword(kwargs, kwnames, kwstack, keyword);
2153+
if (current_arg) {
2154+
/* arg present in tuple and in dict */
2155+
PyErr_Format(PyExc_TypeError,
2156+
"Argument given by name ('%U') "
2157+
"and position (%d)",
2158+
keyword, i+1);
2159+
return cleanreturn(0, &freelist);
21772160
}
21782161
}
2179-
else {
2180-
Py_ssize_t j, nkwargs;
2181-
2182-
nkwargs = PyTuple_GET_SIZE(kwnames);
2183-
for (j=0; j < nkwargs; j++) {
2184-
PyObject *key = PyTuple_GET_ITEM(kwnames, j);
2185-
int match;
2186-
2187-
if (!PyUnicode_Check(key)) {
2188-
PyErr_SetString(PyExc_TypeError,
2189-
"keywords must be strings");
2190-
return cleanreturn(0, &freelist);
2191-
}
2162+
/* make sure there are no extraneous keyword arguments */
2163+
j = 0;
2164+
while (1) {
2165+
int match;
2166+
if (kwargs != NULL) {
2167+
if (!PyDict_Next(kwargs, &j, &keyword, NULL))
2168+
break;
2169+
}
2170+
else {
2171+
if (j >= PyTuple_GET_SIZE(kwnames))
2172+
break;
2173+
keyword = PyTuple_GET_ITEM(kwnames, j);
2174+
j++;
2175+
}
21922176

2193-
match = PySequence_Contains(kwtuple, key);
2194-
if (match <= 0) {
2195-
if (!match) {
2196-
PyErr_Format(PyExc_TypeError,
2197-
"'%U' is an invalid keyword "
2198-
"argument for this function",
2199-
key);
2200-
}
2201-
return cleanreturn(0, &freelist);
2177+
if (!PyUnicode_Check(keyword)) {
2178+
PyErr_SetString(PyExc_TypeError,
2179+
"keywords must be strings");
2180+
return cleanreturn(0, &freelist);
2181+
}
2182+
match = PySequence_Contains(kwtuple, keyword);
2183+
if (match <= 0) {
2184+
if (!match) {
2185+
PyErr_Format(PyExc_TypeError,
2186+
"'%U' is an invalid keyword "
2187+
"argument for this function",
2188+
keyword);
22022189
}
2190+
return cleanreturn(0, &freelist);
22032191
}
22042192
}
22052193
}

0 commit comments

Comments
 (0)