mirror of https://github.com/python/cpython
gh-117431: Adapt str.startswith and str.endswith to Argument Clinic (#117466)
This change gives a significant speedup, as the METH_FASTCALL calling convention is now used.
This commit is contained in:
parent
65524ab388
commit
444156ede4
|
@ -1513,9 +1513,9 @@ class StringLikeTest(BaseTest):
|
||||||
x, None, None, None)
|
x, None, None, None)
|
||||||
self.assertRaisesRegex(TypeError, r'^count\(', s.count,
|
self.assertRaisesRegex(TypeError, r'^count\(', s.count,
|
||||||
x, None, None, None)
|
x, None, None, None)
|
||||||
self.assertRaisesRegex(TypeError, r'^startswith\(', s.startswith,
|
self.assertRaisesRegex(TypeError, r'^startswith\b', s.startswith,
|
||||||
x, None, None, None)
|
x, None, None, None)
|
||||||
self.assertRaisesRegex(TypeError, r'^endswith\(', s.endswith,
|
self.assertRaisesRegex(TypeError, r'^endswith\b', s.endswith,
|
||||||
x, None, None, None)
|
x, None, None, None)
|
||||||
|
|
||||||
# issue #15534
|
# issue #15534
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
Improve the performance of :meth:`str.startswith` and :meth:`str.endswith`
|
||||||
|
by adapting them to the :c:macro:`METH_FASTCALL` calling convention.
|
|
@ -1369,6 +1369,108 @@ exit:
|
||||||
return return_value;
|
return return_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PyDoc_STRVAR(unicode_startswith__doc__,
|
||||||
|
"startswith($self, prefix[, start[, end]], /)\n"
|
||||||
|
"--\n"
|
||||||
|
"\n"
|
||||||
|
"Return True if the string starts with the specified prefix, False otherwise.\n"
|
||||||
|
"\n"
|
||||||
|
" prefix\n"
|
||||||
|
" A string or a tuple of strings to try.\n"
|
||||||
|
" start\n"
|
||||||
|
" Optional start position. Default: start of the string.\n"
|
||||||
|
" end\n"
|
||||||
|
" Optional stop position. Default: end of the string.");
|
||||||
|
|
||||||
|
#define UNICODE_STARTSWITH_METHODDEF \
|
||||||
|
{"startswith", _PyCFunction_CAST(unicode_startswith), METH_FASTCALL, unicode_startswith__doc__},
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
unicode_startswith_impl(PyObject *self, PyObject *subobj, Py_ssize_t start,
|
||||||
|
Py_ssize_t end);
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
unicode_startswith(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
|
||||||
|
{
|
||||||
|
PyObject *return_value = NULL;
|
||||||
|
PyObject *subobj;
|
||||||
|
Py_ssize_t start = 0;
|
||||||
|
Py_ssize_t end = PY_SSIZE_T_MAX;
|
||||||
|
|
||||||
|
if (!_PyArg_CheckPositional("startswith", nargs, 1, 3)) {
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
subobj = args[0];
|
||||||
|
if (nargs < 2) {
|
||||||
|
goto skip_optional;
|
||||||
|
}
|
||||||
|
if (!_PyEval_SliceIndex(args[1], &start)) {
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
if (nargs < 3) {
|
||||||
|
goto skip_optional;
|
||||||
|
}
|
||||||
|
if (!_PyEval_SliceIndex(args[2], &end)) {
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
skip_optional:
|
||||||
|
return_value = unicode_startswith_impl(self, subobj, start, end);
|
||||||
|
|
||||||
|
exit:
|
||||||
|
return return_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
PyDoc_STRVAR(unicode_endswith__doc__,
|
||||||
|
"endswith($self, prefix[, start[, end]], /)\n"
|
||||||
|
"--\n"
|
||||||
|
"\n"
|
||||||
|
"Return True if the string ends with the specified prefix, False otherwise.\n"
|
||||||
|
"\n"
|
||||||
|
" prefix\n"
|
||||||
|
" A string or a tuple of strings to try.\n"
|
||||||
|
" start\n"
|
||||||
|
" Optional start position. Default: start of the string.\n"
|
||||||
|
" end\n"
|
||||||
|
" Optional stop position. Default: end of the string.");
|
||||||
|
|
||||||
|
#define UNICODE_ENDSWITH_METHODDEF \
|
||||||
|
{"endswith", _PyCFunction_CAST(unicode_endswith), METH_FASTCALL, unicode_endswith__doc__},
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
unicode_endswith_impl(PyObject *self, PyObject *subobj, Py_ssize_t start,
|
||||||
|
Py_ssize_t end);
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
unicode_endswith(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
|
||||||
|
{
|
||||||
|
PyObject *return_value = NULL;
|
||||||
|
PyObject *subobj;
|
||||||
|
Py_ssize_t start = 0;
|
||||||
|
Py_ssize_t end = PY_SSIZE_T_MAX;
|
||||||
|
|
||||||
|
if (!_PyArg_CheckPositional("endswith", nargs, 1, 3)) {
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
subobj = args[0];
|
||||||
|
if (nargs < 2) {
|
||||||
|
goto skip_optional;
|
||||||
|
}
|
||||||
|
if (!_PyEval_SliceIndex(args[1], &start)) {
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
if (nargs < 3) {
|
||||||
|
goto skip_optional;
|
||||||
|
}
|
||||||
|
if (!_PyEval_SliceIndex(args[2], &end)) {
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
skip_optional:
|
||||||
|
return_value = unicode_endswith_impl(self, subobj, start, end);
|
||||||
|
|
||||||
|
exit:
|
||||||
|
return return_value;
|
||||||
|
}
|
||||||
|
|
||||||
PyDoc_STRVAR(unicode___format____doc__,
|
PyDoc_STRVAR(unicode___format____doc__,
|
||||||
"__format__($self, format_spec, /)\n"
|
"__format__($self, format_spec, /)\n"
|
||||||
"--\n"
|
"--\n"
|
||||||
|
@ -1507,4 +1609,4 @@ skip_optional_pos:
|
||||||
exit:
|
exit:
|
||||||
return return_value;
|
return return_value;
|
||||||
}
|
}
|
||||||
/*[clinic end generated code: output=1aab29bab5201c78 input=a9049054013a1b77]*/
|
/*[clinic end generated code: output=e495e878d8283217 input=a9049054013a1b77]*/
|
||||||
|
|
|
@ -13021,30 +13021,30 @@ unicode_zfill_impl(PyObject *self, Py_ssize_t width)
|
||||||
return u;
|
return u;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyDoc_STRVAR(startswith__doc__,
|
/*[clinic input]
|
||||||
"S.startswith(prefix[, start[, end]]) -> bool\n\
|
@text_signature "($self, prefix[, start[, end]], /)"
|
||||||
\n\
|
str.startswith as unicode_startswith
|
||||||
Return True if S starts with the specified prefix, False otherwise.\n\
|
|
||||||
With optional start, test S beginning at that position.\n\
|
prefix as subobj: object
|
||||||
With optional end, stop comparing S at that position.\n\
|
A string or a tuple of strings to try.
|
||||||
prefix can also be a tuple of strings to try.");
|
start: slice_index(accept={int, NoneType}, c_default='0') = None
|
||||||
|
Optional start position. Default: start of the string.
|
||||||
|
end: slice_index(accept={int, NoneType}, c_default='PY_SSIZE_T_MAX') = None
|
||||||
|
Optional stop position. Default: end of the string.
|
||||||
|
/
|
||||||
|
|
||||||
|
Return True if the string starts with the specified prefix, False otherwise.
|
||||||
|
[clinic start generated code]*/
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
unicode_startswith(PyObject *self,
|
unicode_startswith_impl(PyObject *self, PyObject *subobj, Py_ssize_t start,
|
||||||
PyObject *args)
|
Py_ssize_t end)
|
||||||
|
/*[clinic end generated code: output=4bd7cfd0803051d4 input=5f918b5f5f89d856]*/
|
||||||
{
|
{
|
||||||
PyObject *subobj;
|
|
||||||
PyObject *substring;
|
|
||||||
Py_ssize_t start = 0;
|
|
||||||
Py_ssize_t end = PY_SSIZE_T_MAX;
|
|
||||||
int result;
|
|
||||||
|
|
||||||
if (!asciilib_parse_args_finds("startswith", args, &subobj, &start, &end))
|
|
||||||
return NULL;
|
|
||||||
if (PyTuple_Check(subobj)) {
|
if (PyTuple_Check(subobj)) {
|
||||||
Py_ssize_t i;
|
Py_ssize_t i;
|
||||||
for (i = 0; i < PyTuple_GET_SIZE(subobj); i++) {
|
for (i = 0; i < PyTuple_GET_SIZE(subobj); i++) {
|
||||||
substring = PyTuple_GET_ITEM(subobj, i);
|
PyObject *substring = PyTuple_GET_ITEM(subobj, i);
|
||||||
if (!PyUnicode_Check(substring)) {
|
if (!PyUnicode_Check(substring)) {
|
||||||
PyErr_Format(PyExc_TypeError,
|
PyErr_Format(PyExc_TypeError,
|
||||||
"tuple for startswith must only contain str, "
|
"tuple for startswith must only contain str, "
|
||||||
|
@ -13052,9 +13052,10 @@ unicode_startswith(PyObject *self,
|
||||||
Py_TYPE(substring)->tp_name);
|
Py_TYPE(substring)->tp_name);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
result = tailmatch(self, substring, start, end, -1);
|
int result = tailmatch(self, substring, start, end, -1);
|
||||||
if (result == -1)
|
if (result < 0) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
if (result) {
|
if (result) {
|
||||||
Py_RETURN_TRUE;
|
Py_RETURN_TRUE;
|
||||||
}
|
}
|
||||||
|
@ -13068,37 +13069,30 @@ unicode_startswith(PyObject *self,
|
||||||
"a tuple of str, not %.100s", Py_TYPE(subobj)->tp_name);
|
"a tuple of str, not %.100s", Py_TYPE(subobj)->tp_name);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
result = tailmatch(self, subobj, start, end, -1);
|
int result = tailmatch(self, subobj, start, end, -1);
|
||||||
if (result == -1)
|
if (result < 0) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
return PyBool_FromLong(result);
|
return PyBool_FromLong(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PyDoc_STRVAR(endswith__doc__,
|
/*[clinic input]
|
||||||
"S.endswith(suffix[, start[, end]]) -> bool\n\
|
@text_signature "($self, prefix[, start[, end]], /)"
|
||||||
\n\
|
str.endswith as unicode_endswith = str.startswith
|
||||||
Return True if S ends with the specified suffix, False otherwise.\n\
|
|
||||||
With optional start, test S beginning at that position.\n\
|
Return True if the string ends with the specified prefix, False otherwise.
|
||||||
With optional end, stop comparing S at that position.\n\
|
[clinic start generated code]*/
|
||||||
suffix can also be a tuple of strings to try.");
|
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
unicode_endswith(PyObject *self,
|
unicode_endswith_impl(PyObject *self, PyObject *subobj, Py_ssize_t start,
|
||||||
PyObject *args)
|
Py_ssize_t end)
|
||||||
|
/*[clinic end generated code: output=cce6f8ceb0102ca9 input=82cd5ce9e7623646]*/
|
||||||
{
|
{
|
||||||
PyObject *subobj;
|
|
||||||
PyObject *substring;
|
|
||||||
Py_ssize_t start = 0;
|
|
||||||
Py_ssize_t end = PY_SSIZE_T_MAX;
|
|
||||||
int result;
|
|
||||||
|
|
||||||
if (!asciilib_parse_args_finds("endswith", args, &subobj, &start, &end))
|
|
||||||
return NULL;
|
|
||||||
if (PyTuple_Check(subobj)) {
|
if (PyTuple_Check(subobj)) {
|
||||||
Py_ssize_t i;
|
Py_ssize_t i;
|
||||||
for (i = 0; i < PyTuple_GET_SIZE(subobj); i++) {
|
for (i = 0; i < PyTuple_GET_SIZE(subobj); i++) {
|
||||||
substring = PyTuple_GET_ITEM(subobj, i);
|
PyObject *substring = PyTuple_GET_ITEM(subobj, i);
|
||||||
if (!PyUnicode_Check(substring)) {
|
if (!PyUnicode_Check(substring)) {
|
||||||
PyErr_Format(PyExc_TypeError,
|
PyErr_Format(PyExc_TypeError,
|
||||||
"tuple for endswith must only contain str, "
|
"tuple for endswith must only contain str, "
|
||||||
|
@ -13106,9 +13100,10 @@ unicode_endswith(PyObject *self,
|
||||||
Py_TYPE(substring)->tp_name);
|
Py_TYPE(substring)->tp_name);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
result = tailmatch(self, substring, start, end, +1);
|
int result = tailmatch(self, substring, start, end, +1);
|
||||||
if (result == -1)
|
if (result < 0) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
if (result) {
|
if (result) {
|
||||||
Py_RETURN_TRUE;
|
Py_RETURN_TRUE;
|
||||||
}
|
}
|
||||||
|
@ -13121,9 +13116,10 @@ unicode_endswith(PyObject *self,
|
||||||
"a tuple of str, not %.100s", Py_TYPE(subobj)->tp_name);
|
"a tuple of str, not %.100s", Py_TYPE(subobj)->tp_name);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
result = tailmatch(self, subobj, start, end, +1);
|
int result = tailmatch(self, subobj, start, end, +1);
|
||||||
if (result == -1)
|
if (result < 0) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
return PyBool_FromLong(result);
|
return PyBool_FromLong(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13576,8 +13572,8 @@ static PyMethodDef unicode_methods[] = {
|
||||||
UNICODE_SWAPCASE_METHODDEF
|
UNICODE_SWAPCASE_METHODDEF
|
||||||
UNICODE_TRANSLATE_METHODDEF
|
UNICODE_TRANSLATE_METHODDEF
|
||||||
UNICODE_UPPER_METHODDEF
|
UNICODE_UPPER_METHODDEF
|
||||||
{"startswith", (PyCFunction) unicode_startswith, METH_VARARGS, startswith__doc__},
|
UNICODE_STARTSWITH_METHODDEF
|
||||||
{"endswith", (PyCFunction) unicode_endswith, METH_VARARGS, endswith__doc__},
|
UNICODE_ENDSWITH_METHODDEF
|
||||||
UNICODE_REMOVEPREFIX_METHODDEF
|
UNICODE_REMOVEPREFIX_METHODDEF
|
||||||
UNICODE_REMOVESUFFIX_METHODDEF
|
UNICODE_REMOVESUFFIX_METHODDEF
|
||||||
UNICODE_ISASCII_METHODDEF
|
UNICODE_ISASCII_METHODDEF
|
||||||
|
|
Loading…
Reference in New Issue