gh-117431: Adapt bytes and bytearray .find() and friends to Argument Clinic (#117502)

This change gives a significant speedup, as the METH_FASTCALL calling
convention is now used. The following bytes and bytearray methods are adapted:

- count()
- find()
- index()
- rfind()
- rindex()

Co-authored-by: Inada Naoki <songofacandy@gmail.com>
This commit is contained in:
Erlend E. Aasland 2024-04-12 09:40:55 +02:00 committed by GitHub
parent 49fc1414b5
commit deb921f851
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 709 additions and 170 deletions

View File

@ -26,11 +26,16 @@ extern void _Py_bytes_title(char *result, const char *s, Py_ssize_t len);
extern void _Py_bytes_capitalize(char *result, const char *s, Py_ssize_t len);
extern void _Py_bytes_swapcase(char *result, const char *s, Py_ssize_t len);
extern PyObject *_Py_bytes_find(const char *str, Py_ssize_t len, PyObject *args);
extern PyObject *_Py_bytes_index(const char *str, Py_ssize_t len, PyObject *args);
extern PyObject *_Py_bytes_rfind(const char *str, Py_ssize_t len, PyObject *args);
extern PyObject *_Py_bytes_rindex(const char *str, Py_ssize_t len, PyObject *args);
extern PyObject *_Py_bytes_count(const char *str, Py_ssize_t len, PyObject *args);
extern PyObject *_Py_bytes_find(const char *str, Py_ssize_t len, PyObject *sub,
Py_ssize_t start, Py_ssize_t end);
extern PyObject *_Py_bytes_index(const char *str, Py_ssize_t len, PyObject *sub,
Py_ssize_t start, Py_ssize_t end);
extern PyObject *_Py_bytes_rfind(const char *str, Py_ssize_t len, PyObject *sub,
Py_ssize_t start, Py_ssize_t end);
extern PyObject *_Py_bytes_rindex(const char *str, Py_ssize_t len, PyObject *sub,
Py_ssize_t start, Py_ssize_t end);
extern PyObject *_Py_bytes_count(const char *str, Py_ssize_t len, PyObject *sub,
Py_ssize_t start, Py_ssize_t end);
extern int _Py_bytes_contains(const char *str, Py_ssize_t len, PyObject *arg);
extern PyObject *_Py_bytes_startswith(const char *str, Py_ssize_t len,
PyObject *subobj, Py_ssize_t start,

View File

@ -0,0 +1,9 @@
Improve the performance of the following :class:`bytes` and
:class:`bytearray` methods by adapting them to the :c:macro:`METH_FASTCALL`
calling convention:
* :meth:`!count`
* :meth:`!find`
* :meth:`!index`
* :meth:`!rfind`
* :meth:`!rindex`

View File

@ -1121,16 +1121,44 @@ bytearray_dealloc(PyByteArrayObject *self)
#include "stringlib/transmogrify.h"
static PyObject *
bytearray_find(PyByteArrayObject *self, PyObject *args)
{
return _Py_bytes_find(PyByteArray_AS_STRING(self), PyByteArray_GET_SIZE(self), args);
}
/*[clinic input]
@text_signature "($self, sub[, start[, end]], /)"
bytearray.find
sub: object
start: slice_index(accept={int, NoneType}, c_default='0') = None
Optional start position. Default: start of the bytes.
end: slice_index(accept={int, NoneType}, c_default='PY_SSIZE_T_MAX') = None
Optional stop position. Default: end of the bytes.
/
Return the lowest index in B where subsection 'sub' is found, such that 'sub' is contained within B[start:end].
Return -1 on failure.
[clinic start generated code]*/
static PyObject *
bytearray_count(PyByteArrayObject *self, PyObject *args)
bytearray_find_impl(PyByteArrayObject *self, PyObject *sub, Py_ssize_t start,
Py_ssize_t end)
/*[clinic end generated code: output=413e1cab2ae87da0 input=793dfad803e2952f]*/
{
return _Py_bytes_count(PyByteArray_AS_STRING(self), PyByteArray_GET_SIZE(self), args);
return _Py_bytes_find(PyByteArray_AS_STRING(self), PyByteArray_GET_SIZE(self),
sub, start, end);
}
/*[clinic input]
bytearray.count = bytearray.find
Return the number of non-overlapping occurrences of subsection 'sub' in bytes B[start:end].
[clinic start generated code]*/
static PyObject *
bytearray_count_impl(PyByteArrayObject *self, PyObject *sub,
Py_ssize_t start, Py_ssize_t end)
/*[clinic end generated code: output=a21ee2692e4f1233 input=4deb529db38deda8]*/
{
return _Py_bytes_count(PyByteArray_AS_STRING(self), PyByteArray_GET_SIZE(self),
sub, start, end);
}
/*[clinic input]
@ -1162,22 +1190,55 @@ bytearray_copy_impl(PyByteArrayObject *self)
PyByteArray_GET_SIZE(self));
}
static PyObject *
bytearray_index(PyByteArrayObject *self, PyObject *args)
{
return _Py_bytes_index(PyByteArray_AS_STRING(self), PyByteArray_GET_SIZE(self), args);
}
/*[clinic input]
bytearray.index = bytearray.find
Return the lowest index in B where subsection 'sub' is found, such that 'sub' is contained within B[start:end].
Raise ValueError if the subsection is not found.
[clinic start generated code]*/
static PyObject *
bytearray_rfind(PyByteArrayObject *self, PyObject *args)
bytearray_index_impl(PyByteArrayObject *self, PyObject *sub,
Py_ssize_t start, Py_ssize_t end)
/*[clinic end generated code: output=067a1e78efc672a7 input=8cbaf6836dbd2a9a]*/
{
return _Py_bytes_rfind(PyByteArray_AS_STRING(self), PyByteArray_GET_SIZE(self), args);
return _Py_bytes_index(PyByteArray_AS_STRING(self), PyByteArray_GET_SIZE(self),
sub, start, end);
}
/*[clinic input]
bytearray.rfind = bytearray.find
Return the highest index in B where subsection 'sub' is found, such that 'sub' is contained within B[start:end].
Return -1 on failure.
[clinic start generated code]*/
static PyObject *
bytearray_rindex(PyByteArrayObject *self, PyObject *args)
bytearray_rfind_impl(PyByteArrayObject *self, PyObject *sub,
Py_ssize_t start, Py_ssize_t end)
/*[clinic end generated code: output=51bf886f932b283c input=eaa107468a158423]*/
{
return _Py_bytes_rindex(PyByteArray_AS_STRING(self), PyByteArray_GET_SIZE(self), args);
return _Py_bytes_rfind(PyByteArray_AS_STRING(self), PyByteArray_GET_SIZE(self),
sub, start, end);
}
/*[clinic input]
bytearray.rindex = bytearray.find
Return the highest index in B where subsection 'sub' is found, such that 'sub' is contained within B[start:end].
Raise ValueError if the subsection is not found.
[clinic start generated code]*/
static PyObject *
bytearray_rindex_impl(PyByteArrayObject *self, PyObject *sub,
Py_ssize_t start, Py_ssize_t end)
/*[clinic end generated code: output=38e1cf66bafb08b9 input=81cf49d0af4d5bd0]*/
{
return _Py_bytes_rindex(PyByteArray_AS_STRING(self), PyByteArray_GET_SIZE(self),
sub, start, end);
}
static int
@ -2236,17 +2297,15 @@ bytearray_methods[] = {
STRINGLIB_CENTER_METHODDEF
BYTEARRAY_CLEAR_METHODDEF
BYTEARRAY_COPY_METHODDEF
{"count", (PyCFunction)bytearray_count, METH_VARARGS,
_Py_count__doc__},
BYTEARRAY_COUNT_METHODDEF
BYTEARRAY_DECODE_METHODDEF
BYTEARRAY_ENDSWITH_METHODDEF
STRINGLIB_EXPANDTABS_METHODDEF
BYTEARRAY_EXTEND_METHODDEF
{"find", (PyCFunction)bytearray_find, METH_VARARGS,
_Py_find__doc__},
BYTEARRAY_FIND_METHODDEF
BYTEARRAY_FROMHEX_METHODDEF
BYTEARRAY_HEX_METHODDEF
{"index", (PyCFunction)bytearray_index, METH_VARARGS, _Py_index__doc__},
BYTEARRAY_INDEX_METHODDEF
BYTEARRAY_INSERT_METHODDEF
{"isalnum", stringlib_isalnum, METH_NOARGS,
_Py_isalnum__doc__},
@ -2276,8 +2335,8 @@ bytearray_methods[] = {
BYTEARRAY_REMOVEPREFIX_METHODDEF
BYTEARRAY_REMOVESUFFIX_METHODDEF
BYTEARRAY_REVERSE_METHODDEF
{"rfind", (PyCFunction)bytearray_rfind, METH_VARARGS, _Py_rfind__doc__},
{"rindex", (PyCFunction)bytearray_rindex, METH_VARARGS, _Py_rindex__doc__},
BYTEARRAY_RFIND_METHODDEF
BYTEARRAY_RINDEX_METHODDEF
STRINGLIB_RJUST_METHODDEF
BYTEARRAY_RPARTITION_METHODDEF
BYTEARRAY_RSPLIT_METHODDEF

View File

@ -453,31 +453,21 @@ stringlib_parse_args_finds().
*/
Py_LOCAL_INLINE(int)
parse_args_finds_byte(const char *function_name, PyObject *args,
PyObject **subobj, char *byte,
Py_ssize_t *start, Py_ssize_t *end)
parse_args_finds_byte(const char *function_name, PyObject **subobj, char *byte)
{
PyObject *tmp_subobj;
Py_ssize_t ival;
if(!stringlib_parse_args_finds(function_name, args, &tmp_subobj,
start, end))
return 0;
if (PyObject_CheckBuffer(tmp_subobj)) {
*subobj = tmp_subobj;
if (PyObject_CheckBuffer(*subobj)) {
return 1;
}
if (!_PyIndex_Check(tmp_subobj)) {
if (!_PyIndex_Check(*subobj)) {
PyErr_Format(PyExc_TypeError,
"argument should be integer or bytes-like object, "
"not '%.200s'",
Py_TYPE(tmp_subobj)->tp_name);
Py_TYPE(*subobj)->tp_name);
return 0;
}
ival = PyNumber_AsSsize_t(tmp_subobj, NULL);
Py_ssize_t ival = PyNumber_AsSsize_t(*subobj, NULL);
if (ival == -1 && PyErr_Occurred()) {
return 0;
}
@ -508,19 +498,19 @@ parse_args_finds_byte(const char *function_name, PyObject *args,
Py_LOCAL_INLINE(Py_ssize_t)
find_internal(const char *str, Py_ssize_t len,
const char *function_name, PyObject *args, int dir)
const char *function_name, PyObject *subobj,
Py_ssize_t start, Py_ssize_t end,
int dir)
{
PyObject *subobj;
char byte;
Py_buffer subbuf;
const char *sub;
Py_ssize_t sub_len;
Py_ssize_t start = 0, end = PY_SSIZE_T_MAX;
Py_ssize_t res;
if (!parse_args_finds_byte(function_name, args,
&subobj, &byte, &start, &end))
if (!parse_args_finds_byte(function_name, &subobj, &byte)) {
return -2;
}
if (subobj) {
if (PyObject_GetBuffer(subobj, &subbuf, PyBUF_SIMPLE) != 0)
@ -566,37 +556,21 @@ find_internal(const char *str, Py_ssize_t len,
return res;
}
PyDoc_STRVAR_shared(_Py_find__doc__,
"B.find(sub[, start[, end]]) -> int\n\
\n\
Return the lowest index in B where subsection sub is found,\n\
such that sub is contained within B[start,end]. Optional\n\
arguments start and end are interpreted as in slice notation.\n\
\n\
Return -1 on failure.");
PyObject *
_Py_bytes_find(const char *str, Py_ssize_t len, PyObject *args)
_Py_bytes_find(const char *str, Py_ssize_t len, PyObject *sub,
Py_ssize_t start, Py_ssize_t end)
{
Py_ssize_t result = find_internal(str, len, "find", args, +1);
Py_ssize_t result = find_internal(str, len, "find", sub, start, end, +1);
if (result == -2)
return NULL;
return PyLong_FromSsize_t(result);
}
PyDoc_STRVAR_shared(_Py_index__doc__,
"B.index(sub[, start[, end]]) -> int\n\
\n\
Return the lowest index in B where subsection sub is found,\n\
such that sub is contained within B[start,end]. Optional\n\
arguments start and end are interpreted as in slice notation.\n\
\n\
Raises ValueError when the subsection is not found.");
PyObject *
_Py_bytes_index(const char *str, Py_ssize_t len, PyObject *args)
_Py_bytes_index(const char *str, Py_ssize_t len, PyObject *sub,
Py_ssize_t start, Py_ssize_t end)
{
Py_ssize_t result = find_internal(str, len, "index", args, +1);
Py_ssize_t result = find_internal(str, len, "index", sub, start, end, +1);
if (result == -2)
return NULL;
if (result == -1) {
@ -607,37 +581,21 @@ _Py_bytes_index(const char *str, Py_ssize_t len, PyObject *args)
return PyLong_FromSsize_t(result);
}
PyDoc_STRVAR_shared(_Py_rfind__doc__,
"B.rfind(sub[, start[, end]]) -> int\n\
\n\
Return the highest index in B where subsection sub is found,\n\
such that sub is contained within B[start,end]. Optional\n\
arguments start and end are interpreted as in slice notation.\n\
\n\
Return -1 on failure.");
PyObject *
_Py_bytes_rfind(const char *str, Py_ssize_t len, PyObject *args)
_Py_bytes_rfind(const char *str, Py_ssize_t len, PyObject *sub,
Py_ssize_t start, Py_ssize_t end)
{
Py_ssize_t result = find_internal(str, len, "rfind", args, -1);
Py_ssize_t result = find_internal(str, len, "rfind", sub, start, end, -1);
if (result == -2)
return NULL;
return PyLong_FromSsize_t(result);
}
PyDoc_STRVAR_shared(_Py_rindex__doc__,
"B.rindex(sub[, start[, end]]) -> int\n\
\n\
Return the highest index in B where subsection sub is found,\n\
such that sub is contained within B[start,end]. Optional\n\
arguments start and end are interpreted as in slice notation.\n\
\n\
Raise ValueError when the subsection is not found.");
PyObject *
_Py_bytes_rindex(const char *str, Py_ssize_t len, PyObject *args)
_Py_bytes_rindex(const char *str, Py_ssize_t len, PyObject *sub,
Py_ssize_t start, Py_ssize_t end)
{
Py_ssize_t result = find_internal(str, len, "rindex", args, -1);
Py_ssize_t result = find_internal(str, len, "rindex", sub, start, end, -1);
if (result == -2)
return NULL;
if (result == -1) {
@ -648,28 +606,20 @@ _Py_bytes_rindex(const char *str, Py_ssize_t len, PyObject *args)
return PyLong_FromSsize_t(result);
}
PyDoc_STRVAR_shared(_Py_count__doc__,
"B.count(sub[, start[, end]]) -> int\n\
\n\
Return the number of non-overlapping occurrences of subsection sub in\n\
bytes B[start:end]. Optional arguments start and end are interpreted\n\
as in slice notation.");
PyObject *
_Py_bytes_count(const char *str, Py_ssize_t len, PyObject *args)
_Py_bytes_count(const char *str, Py_ssize_t len, PyObject *sub_obj,
Py_ssize_t start, Py_ssize_t end)
{
PyObject *sub_obj;
const char *sub;
Py_ssize_t sub_len;
char byte;
Py_ssize_t start = 0, end = PY_SSIZE_T_MAX;
Py_buffer vsub;
PyObject *count_obj;
if (!parse_args_finds_byte("count", args,
&sub_obj, &byte, &start, &end))
if (!parse_args_finds_byte("count", &sub_obj, &byte)) {
return NULL;
}
if (sub_obj) {
if (PyObject_GetBuffer(sub_obj, &vsub, PyBUF_SIMPLE) != 0)

View File

@ -1863,30 +1863,80 @@ _PyBytes_Join(PyObject *sep, PyObject *x)
return bytes_join((PyBytesObject*)sep, x);
}
/*[clinic input]
@text_signature "($self, sub[, start[, end]], /)"
bytes.find
sub: object
start: slice_index(accept={int, NoneType}, c_default='0') = None
Optional start position. Default: start of the bytes.
end: slice_index(accept={int, NoneType}, c_default='PY_SSIZE_T_MAX') = None
Optional stop position. Default: end of the bytes.
/
Return the lowest index in B where subsection 'sub' is found, such that 'sub' is contained within B[start,end].
Return -1 on failure.
[clinic start generated code]*/
static PyObject *
bytes_find(PyBytesObject *self, PyObject *args)
bytes_find_impl(PyBytesObject *self, PyObject *sub, Py_ssize_t start,
Py_ssize_t end)
/*[clinic end generated code: output=d5961a1c77b472a1 input=3171e62a8ae7f240]*/
{
return _Py_bytes_find(PyBytes_AS_STRING(self), PyBytes_GET_SIZE(self), args);
return _Py_bytes_find(PyBytes_AS_STRING(self), PyBytes_GET_SIZE(self),
sub, start, end);
}
/*[clinic input]
bytes.index = bytes.find
Return the lowest index in B where subsection 'sub' is found, such that 'sub' is contained within B[start,end].
Raise ValueError if the subsection is not found.
[clinic start generated code]*/
static PyObject *
bytes_index(PyBytesObject *self, PyObject *args)
bytes_index_impl(PyBytesObject *self, PyObject *sub, Py_ssize_t start,
Py_ssize_t end)
/*[clinic end generated code: output=0da25cc74683ba42 input=aa34ad71ba0bafe3]*/
{
return _Py_bytes_index(PyBytes_AS_STRING(self), PyBytes_GET_SIZE(self), args);
return _Py_bytes_index(PyBytes_AS_STRING(self), PyBytes_GET_SIZE(self),
sub, start, end);
}
/*[clinic input]
bytes.rfind = bytes.find
Return the highest index in B where subsection 'sub' is found, such that 'sub' is contained within B[start,end].
Return -1 on failure.
[clinic start generated code]*/
static PyObject *
bytes_rfind(PyBytesObject *self, PyObject *args)
bytes_rfind_impl(PyBytesObject *self, PyObject *sub, Py_ssize_t start,
Py_ssize_t end)
/*[clinic end generated code: output=51b60fa4ad011c09 input=864c3e7f3010b33c]*/
{
return _Py_bytes_rfind(PyBytes_AS_STRING(self), PyBytes_GET_SIZE(self), args);
return _Py_bytes_rfind(PyBytes_AS_STRING(self), PyBytes_GET_SIZE(self),
sub, start, end);
}
/*[clinic input]
bytes.rindex = bytes.find
Return the highest index in B where subsection 'sub' is found, such that 'sub' is contained within B[start,end].
Raise ValueError if the subsection is not found.
[clinic start generated code]*/
static PyObject *
bytes_rindex(PyBytesObject *self, PyObject *args)
bytes_rindex_impl(PyBytesObject *self, PyObject *sub, Py_ssize_t start,
Py_ssize_t end)
/*[clinic end generated code: output=42bf674e0a0aabf6 input=21051fc5cfeacf2c]*/
{
return _Py_bytes_rindex(PyBytes_AS_STRING(self), PyBytes_GET_SIZE(self), args);
return _Py_bytes_rindex(PyBytes_AS_STRING(self), PyBytes_GET_SIZE(self),
sub, start, end);
}
@ -2023,10 +2073,19 @@ bytes_rstrip_impl(PyBytesObject *self, PyObject *bytes)
}
/*[clinic input]
bytes.count = bytes.find
Return the number of non-overlapping occurrences of subsection 'sub' in bytes B[start:end].
[clinic start generated code]*/
static PyObject *
bytes_count(PyBytesObject *self, PyObject *args)
bytes_count_impl(PyBytesObject *self, PyObject *sub, Py_ssize_t start,
Py_ssize_t end)
/*[clinic end generated code: output=9848140b9be17d0f input=b6e4a5ed515e1e59]*/
{
return _Py_bytes_count(PyBytes_AS_STRING(self), PyBytes_GET_SIZE(self), args);
return _Py_bytes_count(PyBytes_AS_STRING(self), PyBytes_GET_SIZE(self),
sub, start, end);
}
@ -2524,16 +2583,14 @@ bytes_methods[] = {
{"capitalize", stringlib_capitalize, METH_NOARGS,
_Py_capitalize__doc__},
STRINGLIB_CENTER_METHODDEF
{"count", (PyCFunction)bytes_count, METH_VARARGS,
_Py_count__doc__},
BYTES_COUNT_METHODDEF
BYTES_DECODE_METHODDEF
BYTES_ENDSWITH_METHODDEF
STRINGLIB_EXPANDTABS_METHODDEF
{"find", (PyCFunction)bytes_find, METH_VARARGS,
_Py_find__doc__},
BYTES_FIND_METHODDEF
BYTES_FROMHEX_METHODDEF
BYTES_HEX_METHODDEF
{"index", (PyCFunction)bytes_index, METH_VARARGS, _Py_index__doc__},
BYTES_INDEX_METHODDEF
{"isalnum", stringlib_isalnum, METH_NOARGS,
_Py_isalnum__doc__},
{"isalpha", stringlib_isalpha, METH_NOARGS,
@ -2559,8 +2616,8 @@ bytes_methods[] = {
BYTES_REPLACE_METHODDEF
BYTES_REMOVEPREFIX_METHODDEF
BYTES_REMOVESUFFIX_METHODDEF
{"rfind", (PyCFunction)bytes_rfind, METH_VARARGS, _Py_rfind__doc__},
{"rindex", (PyCFunction)bytes_rindex, METH_VARARGS, _Py_rindex__doc__},
BYTES_RFIND_METHODDEF
BYTES_RINDEX_METHODDEF
STRINGLIB_RJUST_METHODDEF
BYTES_RPARTITION_METHODDEF
BYTES_RSPLIT_METHODDEF

View File

@ -101,6 +101,106 @@ exit:
return return_value;
}
PyDoc_STRVAR(bytearray_find__doc__,
"find($self, sub[, start[, end]], /)\n"
"--\n"
"\n"
"Return the lowest index in B where subsection \'sub\' is found, such that \'sub\' is contained within B[start:end].\n"
"\n"
" start\n"
" Optional start position. Default: start of the bytes.\n"
" end\n"
" Optional stop position. Default: end of the bytes.\n"
"\n"
"Return -1 on failure.");
#define BYTEARRAY_FIND_METHODDEF \
{"find", _PyCFunction_CAST(bytearray_find), METH_FASTCALL, bytearray_find__doc__},
static PyObject *
bytearray_find_impl(PyByteArrayObject *self, PyObject *sub, Py_ssize_t start,
Py_ssize_t end);
static PyObject *
bytearray_find(PyByteArrayObject *self, PyObject *const *args, Py_ssize_t nargs)
{
PyObject *return_value = NULL;
PyObject *sub;
Py_ssize_t start = 0;
Py_ssize_t end = PY_SSIZE_T_MAX;
if (!_PyArg_CheckPositional("find", nargs, 1, 3)) {
goto exit;
}
sub = 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 = bytearray_find_impl(self, sub, start, end);
exit:
return return_value;
}
PyDoc_STRVAR(bytearray_count__doc__,
"count($self, sub[, start[, end]], /)\n"
"--\n"
"\n"
"Return the number of non-overlapping occurrences of subsection \'sub\' in bytes B[start:end].\n"
"\n"
" start\n"
" Optional start position. Default: start of the bytes.\n"
" end\n"
" Optional stop position. Default: end of the bytes.");
#define BYTEARRAY_COUNT_METHODDEF \
{"count", _PyCFunction_CAST(bytearray_count), METH_FASTCALL, bytearray_count__doc__},
static PyObject *
bytearray_count_impl(PyByteArrayObject *self, PyObject *sub,
Py_ssize_t start, Py_ssize_t end);
static PyObject *
bytearray_count(PyByteArrayObject *self, PyObject *const *args, Py_ssize_t nargs)
{
PyObject *return_value = NULL;
PyObject *sub;
Py_ssize_t start = 0;
Py_ssize_t end = PY_SSIZE_T_MAX;
if (!_PyArg_CheckPositional("count", nargs, 1, 3)) {
goto exit;
}
sub = 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 = bytearray_count_impl(self, sub, start, end);
exit:
return return_value;
}
PyDoc_STRVAR(bytearray_clear__doc__,
"clear($self, /)\n"
"--\n"
@ -137,6 +237,159 @@ bytearray_copy(PyByteArrayObject *self, PyObject *Py_UNUSED(ignored))
return bytearray_copy_impl(self);
}
PyDoc_STRVAR(bytearray_index__doc__,
"index($self, sub[, start[, end]], /)\n"
"--\n"
"\n"
"Return the lowest index in B where subsection \'sub\' is found, such that \'sub\' is contained within B[start:end].\n"
"\n"
" start\n"
" Optional start position. Default: start of the bytes.\n"
" end\n"
" Optional stop position. Default: end of the bytes.\n"
"\n"
"Raise ValueError if the subsection is not found.");
#define BYTEARRAY_INDEX_METHODDEF \
{"index", _PyCFunction_CAST(bytearray_index), METH_FASTCALL, bytearray_index__doc__},
static PyObject *
bytearray_index_impl(PyByteArrayObject *self, PyObject *sub,
Py_ssize_t start, Py_ssize_t end);
static PyObject *
bytearray_index(PyByteArrayObject *self, PyObject *const *args, Py_ssize_t nargs)
{
PyObject *return_value = NULL;
PyObject *sub;
Py_ssize_t start = 0;
Py_ssize_t end = PY_SSIZE_T_MAX;
if (!_PyArg_CheckPositional("index", nargs, 1, 3)) {
goto exit;
}
sub = 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 = bytearray_index_impl(self, sub, start, end);
exit:
return return_value;
}
PyDoc_STRVAR(bytearray_rfind__doc__,
"rfind($self, sub[, start[, end]], /)\n"
"--\n"
"\n"
"Return the highest index in B where subsection \'sub\' is found, such that \'sub\' is contained within B[start:end].\n"
"\n"
" start\n"
" Optional start position. Default: start of the bytes.\n"
" end\n"
" Optional stop position. Default: end of the bytes.\n"
"\n"
"Return -1 on failure.");
#define BYTEARRAY_RFIND_METHODDEF \
{"rfind", _PyCFunction_CAST(bytearray_rfind), METH_FASTCALL, bytearray_rfind__doc__},
static PyObject *
bytearray_rfind_impl(PyByteArrayObject *self, PyObject *sub,
Py_ssize_t start, Py_ssize_t end);
static PyObject *
bytearray_rfind(PyByteArrayObject *self, PyObject *const *args, Py_ssize_t nargs)
{
PyObject *return_value = NULL;
PyObject *sub;
Py_ssize_t start = 0;
Py_ssize_t end = PY_SSIZE_T_MAX;
if (!_PyArg_CheckPositional("rfind", nargs, 1, 3)) {
goto exit;
}
sub = 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 = bytearray_rfind_impl(self, sub, start, end);
exit:
return return_value;
}
PyDoc_STRVAR(bytearray_rindex__doc__,
"rindex($self, sub[, start[, end]], /)\n"
"--\n"
"\n"
"Return the highest index in B where subsection \'sub\' is found, such that \'sub\' is contained within B[start:end].\n"
"\n"
" start\n"
" Optional start position. Default: start of the bytes.\n"
" end\n"
" Optional stop position. Default: end of the bytes.\n"
"\n"
"Raise ValueError if the subsection is not found.");
#define BYTEARRAY_RINDEX_METHODDEF \
{"rindex", _PyCFunction_CAST(bytearray_rindex), METH_FASTCALL, bytearray_rindex__doc__},
static PyObject *
bytearray_rindex_impl(PyByteArrayObject *self, PyObject *sub,
Py_ssize_t start, Py_ssize_t end);
static PyObject *
bytearray_rindex(PyByteArrayObject *self, PyObject *const *args, Py_ssize_t nargs)
{
PyObject *return_value = NULL;
PyObject *sub;
Py_ssize_t start = 0;
Py_ssize_t end = PY_SSIZE_T_MAX;
if (!_PyArg_CheckPositional("rindex", nargs, 1, 3)) {
goto exit;
}
sub = 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 = bytearray_rindex_impl(self, sub, start, end);
exit:
return return_value;
}
PyDoc_STRVAR(bytearray_startswith__doc__,
"startswith($self, prefix[, start[, end]], /)\n"
"--\n"
@ -1363,4 +1616,4 @@ bytearray_sizeof(PyByteArrayObject *self, PyObject *Py_UNUSED(ignored))
{
return bytearray_sizeof_impl(self);
}
/*[clinic end generated code: output=0147908e97ebe882 input=a9049054013a1b77]*/
/*[clinic end generated code: output=5f861b02e3fa278b input=a9049054013a1b77]*/

View File

@ -294,6 +294,210 @@ PyDoc_STRVAR(bytes_join__doc__,
#define BYTES_JOIN_METHODDEF \
{"join", (PyCFunction)bytes_join, METH_O, bytes_join__doc__},
PyDoc_STRVAR(bytes_find__doc__,
"find($self, sub[, start[, end]], /)\n"
"--\n"
"\n"
"Return the lowest index in B where subsection \'sub\' is found, such that \'sub\' is contained within B[start,end].\n"
"\n"
" start\n"
" Optional start position. Default: start of the bytes.\n"
" end\n"
" Optional stop position. Default: end of the bytes.\n"
"\n"
"Return -1 on failure.");
#define BYTES_FIND_METHODDEF \
{"find", _PyCFunction_CAST(bytes_find), METH_FASTCALL, bytes_find__doc__},
static PyObject *
bytes_find_impl(PyBytesObject *self, PyObject *sub, Py_ssize_t start,
Py_ssize_t end);
static PyObject *
bytes_find(PyBytesObject *self, PyObject *const *args, Py_ssize_t nargs)
{
PyObject *return_value = NULL;
PyObject *sub;
Py_ssize_t start = 0;
Py_ssize_t end = PY_SSIZE_T_MAX;
if (!_PyArg_CheckPositional("find", nargs, 1, 3)) {
goto exit;
}
sub = 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 = bytes_find_impl(self, sub, start, end);
exit:
return return_value;
}
PyDoc_STRVAR(bytes_index__doc__,
"index($self, sub[, start[, end]], /)\n"
"--\n"
"\n"
"Return the lowest index in B where subsection \'sub\' is found, such that \'sub\' is contained within B[start,end].\n"
"\n"
" start\n"
" Optional start position. Default: start of the bytes.\n"
" end\n"
" Optional stop position. Default: end of the bytes.\n"
"\n"
"Raise ValueError if the subsection is not found.");
#define BYTES_INDEX_METHODDEF \
{"index", _PyCFunction_CAST(bytes_index), METH_FASTCALL, bytes_index__doc__},
static PyObject *
bytes_index_impl(PyBytesObject *self, PyObject *sub, Py_ssize_t start,
Py_ssize_t end);
static PyObject *
bytes_index(PyBytesObject *self, PyObject *const *args, Py_ssize_t nargs)
{
PyObject *return_value = NULL;
PyObject *sub;
Py_ssize_t start = 0;
Py_ssize_t end = PY_SSIZE_T_MAX;
if (!_PyArg_CheckPositional("index", nargs, 1, 3)) {
goto exit;
}
sub = 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 = bytes_index_impl(self, sub, start, end);
exit:
return return_value;
}
PyDoc_STRVAR(bytes_rfind__doc__,
"rfind($self, sub[, start[, end]], /)\n"
"--\n"
"\n"
"Return the highest index in B where subsection \'sub\' is found, such that \'sub\' is contained within B[start,end].\n"
"\n"
" start\n"
" Optional start position. Default: start of the bytes.\n"
" end\n"
" Optional stop position. Default: end of the bytes.\n"
"\n"
"Return -1 on failure.");
#define BYTES_RFIND_METHODDEF \
{"rfind", _PyCFunction_CAST(bytes_rfind), METH_FASTCALL, bytes_rfind__doc__},
static PyObject *
bytes_rfind_impl(PyBytesObject *self, PyObject *sub, Py_ssize_t start,
Py_ssize_t end);
static PyObject *
bytes_rfind(PyBytesObject *self, PyObject *const *args, Py_ssize_t nargs)
{
PyObject *return_value = NULL;
PyObject *sub;
Py_ssize_t start = 0;
Py_ssize_t end = PY_SSIZE_T_MAX;
if (!_PyArg_CheckPositional("rfind", nargs, 1, 3)) {
goto exit;
}
sub = 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 = bytes_rfind_impl(self, sub, start, end);
exit:
return return_value;
}
PyDoc_STRVAR(bytes_rindex__doc__,
"rindex($self, sub[, start[, end]], /)\n"
"--\n"
"\n"
"Return the highest index in B where subsection \'sub\' is found, such that \'sub\' is contained within B[start,end].\n"
"\n"
" start\n"
" Optional start position. Default: start of the bytes.\n"
" end\n"
" Optional stop position. Default: end of the bytes.\n"
"\n"
"Raise ValueError if the subsection is not found.");
#define BYTES_RINDEX_METHODDEF \
{"rindex", _PyCFunction_CAST(bytes_rindex), METH_FASTCALL, bytes_rindex__doc__},
static PyObject *
bytes_rindex_impl(PyBytesObject *self, PyObject *sub, Py_ssize_t start,
Py_ssize_t end);
static PyObject *
bytes_rindex(PyBytesObject *self, PyObject *const *args, Py_ssize_t nargs)
{
PyObject *return_value = NULL;
PyObject *sub;
Py_ssize_t start = 0;
Py_ssize_t end = PY_SSIZE_T_MAX;
if (!_PyArg_CheckPositional("rindex", nargs, 1, 3)) {
goto exit;
}
sub = 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 = bytes_rindex_impl(self, sub, start, end);
exit:
return return_value;
}
PyDoc_STRVAR(bytes_strip__doc__,
"strip($self, bytes=None, /)\n"
"--\n"
@ -396,6 +600,55 @@ exit:
return return_value;
}
PyDoc_STRVAR(bytes_count__doc__,
"count($self, sub[, start[, end]], /)\n"
"--\n"
"\n"
"Return the number of non-overlapping occurrences of subsection \'sub\' in bytes B[start:end].\n"
"\n"
" start\n"
" Optional start position. Default: start of the bytes.\n"
" end\n"
" Optional stop position. Default: end of the bytes.");
#define BYTES_COUNT_METHODDEF \
{"count", _PyCFunction_CAST(bytes_count), METH_FASTCALL, bytes_count__doc__},
static PyObject *
bytes_count_impl(PyBytesObject *self, PyObject *sub, Py_ssize_t start,
Py_ssize_t end);
static PyObject *
bytes_count(PyBytesObject *self, PyObject *const *args, Py_ssize_t nargs)
{
PyObject *return_value = NULL;
PyObject *sub;
Py_ssize_t start = 0;
Py_ssize_t end = PY_SSIZE_T_MAX;
if (!_PyArg_CheckPositional("count", nargs, 1, 3)) {
goto exit;
}
sub = 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 = bytes_count_impl(self, sub, start, end);
exit:
return return_value;
}
PyDoc_STRVAR(bytes_translate__doc__,
"translate($self, table, /, delete=b\'\')\n"
"--\n"
@ -1131,4 +1384,4 @@ skip_optional_pos:
exit:
return return_value;
}
/*[clinic end generated code: output=f2b10ccd2e3155c3 input=a9049054013a1b77]*/
/*[clinic end generated code: output=d6801c6001e57f91 input=a9049054013a1b77]*/

View File

@ -70,50 +70,3 @@ STRINGLIB(contains_obj)(PyObject* str, PyObject* sub)
}
#endif /* STRINGLIB_WANT_CONTAINS_OBJ */
/*
This function is a helper for the "find" family (find, rfind, index,
rindex) and for count, startswith and endswith, because they all have
the same behaviour for the arguments.
It does not touch the variables received until it knows everything
is ok.
*/
#define FORMAT_BUFFER_SIZE 50
Py_LOCAL_INLINE(int)
STRINGLIB(parse_args_finds)(const char * function_name, PyObject *args,
PyObject **subobj,
Py_ssize_t *start, Py_ssize_t *end)
{
PyObject *tmp_subobj;
Py_ssize_t tmp_start = 0;
Py_ssize_t tmp_end = PY_SSIZE_T_MAX;
PyObject *obj_start=Py_None, *obj_end=Py_None;
char format[FORMAT_BUFFER_SIZE] = "O|OO:";
size_t len = strlen(format);
strncpy(format + len, function_name, FORMAT_BUFFER_SIZE - len - 1);
format[FORMAT_BUFFER_SIZE - 1] = '\0';
if (!PyArg_ParseTuple(args, format, &tmp_subobj, &obj_start, &obj_end))
return 0;
/* To support None in "start" and "end" arguments, meaning
the same as if they were not passed.
*/
if (obj_start != Py_None)
if (!_PyEval_SliceIndex(obj_start, &tmp_start))
return 0;
if (obj_end != Py_None)
if (!_PyEval_SliceIndex(obj_end, &tmp_end))
return 0;
*start = tmp_start;
*end = tmp_end;
*subobj = tmp_subobj;
return 1;
}
#undef FORMAT_BUFFER_SIZE