Issue #26765: Moved common code and docstrings for bytes and bytearray methods

to bytes_methods.c.
This commit is contained in:
Serhiy Storchaka 2016-05-04 22:23:26 +03:00
parent 045e635100
commit dd40fc3e57
7 changed files with 519 additions and 777 deletions

View file

@ -1097,147 +1097,16 @@ bytearray_dealloc(PyByteArrayObject *self)
#include "stringlib/transmogrify.h"
/* The following Py_LOCAL_INLINE and Py_LOCAL functions
were copied from the old char* style string object. */
/* helper macro to fixup start/end slice values */
#define ADJUST_INDICES(start, end, len) \
if (end > len) \
end = len; \
else if (end < 0) { \
end += len; \
if (end < 0) \
end = 0; \
} \
if (start < 0) { \
start += len; \
if (start < 0) \
start = 0; \
}
Py_LOCAL_INLINE(Py_ssize_t)
bytearray_find_internal(PyByteArrayObject *self, PyObject *args, int dir)
{
PyObject *subobj;
char byte;
Py_buffer subbuf;
const char *sub;
Py_ssize_t len, sub_len;
Py_ssize_t start=0, end=PY_SSIZE_T_MAX;
Py_ssize_t res;
if (!stringlib_parse_args_finds_byte("find/rfind/index/rindex",
args, &subobj, &byte, &start, &end))
return -2;
if (subobj) {
if (PyObject_GetBuffer(subobj, &subbuf, PyBUF_SIMPLE) != 0)
return -2;
sub = subbuf.buf;
sub_len = subbuf.len;
}
else {
sub = &byte;
sub_len = 1;
}
len = PyByteArray_GET_SIZE(self);
ADJUST_INDICES(start, end, len);
if (end - start < sub_len)
res = -1;
else if (sub_len == 1) {
if (dir > 0)
res = stringlib_find_char(
PyByteArray_AS_STRING(self) + start, end - start,
*sub);
else
res = stringlib_rfind_char(
PyByteArray_AS_STRING(self) + start, end - start,
*sub);
if (res >= 0)
res += start;
}
else {
if (dir > 0)
res = stringlib_find_slice(
PyByteArray_AS_STRING(self), len,
sub, sub_len, start, end);
else
res = stringlib_rfind_slice(
PyByteArray_AS_STRING(self), len,
sub, sub_len, start, end);
}
if (subobj)
PyBuffer_Release(&subbuf);
return res;
}
PyDoc_STRVAR(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.");
static PyObject *
bytearray_find(PyByteArrayObject *self, PyObject *args)
{
Py_ssize_t result = bytearray_find_internal(self, args, +1);
if (result == -2)
return NULL;
return PyLong_FromSsize_t(result);
return _Py_bytes_find(PyByteArray_AS_STRING(self), PyByteArray_GET_SIZE(self), args);
}
PyDoc_STRVAR(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.");
static PyObject *
bytearray_count(PyByteArrayObject *self, PyObject *args)
{
PyObject *sub_obj;
const char *str = PyByteArray_AS_STRING(self), *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 (!stringlib_parse_args_finds_byte("count", args, &sub_obj, &byte,
&start, &end))
return NULL;
if (sub_obj) {
if (PyObject_GetBuffer(sub_obj, &vsub, PyBUF_SIMPLE) != 0)
return NULL;
sub = vsub.buf;
sub_len = vsub.len;
}
else {
sub = &byte;
sub_len = 1;
}
ADJUST_INDICES(start, end, PyByteArray_GET_SIZE(self));
count_obj = PyLong_FromSsize_t(
stringlib_count(str + start, end - start, sub, sub_len, PY_SSIZE_T_MAX)
);
if (sub_obj)
PyBuffer_Release(&vsub);
return count_obj;
return _Py_bytes_count(PyByteArray_AS_STRING(self), PyByteArray_GET_SIZE(self), args);
}
/*[clinic input]
@ -1269,216 +1138,40 @@ bytearray_copy_impl(PyByteArrayObject *self)
PyByteArray_GET_SIZE(self));
}
PyDoc_STRVAR(index__doc__,
"B.index(sub[, start[, end]]) -> int\n\
\n\
Like B.find() but raise ValueError when the subsection is not found.");
static PyObject *
bytearray_index(PyByteArrayObject *self, PyObject *args)
{
Py_ssize_t result = bytearray_find_internal(self, args, +1);
if (result == -2)
return NULL;
if (result == -1) {
PyErr_SetString(PyExc_ValueError,
"subsection not found");
return NULL;
}
return PyLong_FromSsize_t(result);
return _Py_bytes_index(PyByteArray_AS_STRING(self), PyByteArray_GET_SIZE(self), args);
}
PyDoc_STRVAR(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.");
static PyObject *
bytearray_rfind(PyByteArrayObject *self, PyObject *args)
{
Py_ssize_t result = bytearray_find_internal(self, args, -1);
if (result == -2)
return NULL;
return PyLong_FromSsize_t(result);
return _Py_bytes_rfind(PyByteArray_AS_STRING(self), PyByteArray_GET_SIZE(self), args);
}
PyDoc_STRVAR(rindex__doc__,
"B.rindex(sub[, start[, end]]) -> int\n\
\n\
Like B.rfind() but raise ValueError when the subsection is not found.");
static PyObject *
bytearray_rindex(PyByteArrayObject *self, PyObject *args)
{
Py_ssize_t result = bytearray_find_internal(self, args, -1);
if (result == -2)
return NULL;
if (result == -1) {
PyErr_SetString(PyExc_ValueError,
"subsection not found");
return NULL;
}
return PyLong_FromSsize_t(result);
return _Py_bytes_rindex(PyByteArray_AS_STRING(self), PyByteArray_GET_SIZE(self), args);
}
static int
bytearray_contains(PyObject *self, PyObject *arg)
{
Py_ssize_t ival = PyNumber_AsSsize_t(arg, PyExc_ValueError);
if (ival == -1 && PyErr_Occurred()) {
Py_buffer varg;
Py_ssize_t pos;
PyErr_Clear();
if (PyObject_GetBuffer(arg, &varg, PyBUF_SIMPLE) != 0)
return -1;
pos = stringlib_find(PyByteArray_AS_STRING(self), Py_SIZE(self),
varg.buf, varg.len, 0);
PyBuffer_Release(&varg);
return pos >= 0;
}
if (ival < 0 || ival >= 256) {
PyErr_SetString(PyExc_ValueError, "byte must be in range(0, 256)");
return -1;
}
return memchr(PyByteArray_AS_STRING(self), (int) ival, Py_SIZE(self)) != NULL;
return _Py_bytes_contains(PyByteArray_AS_STRING(self), PyByteArray_GET_SIZE(self), arg);
}
/* Matches the end (direction >= 0) or start (direction < 0) of self
* against substr, using the start and end arguments. Returns
* -1 on error, 0 if not found and 1 if found.
*/
Py_LOCAL(int)
_bytearray_tailmatch(PyByteArrayObject *self, PyObject *substr, Py_ssize_t start,
Py_ssize_t end, int direction)
{
Py_ssize_t len = PyByteArray_GET_SIZE(self);
const char* str;
Py_buffer vsubstr;
int rv = 0;
str = PyByteArray_AS_STRING(self);
if (PyObject_GetBuffer(substr, &vsubstr, PyBUF_SIMPLE) != 0)
return -1;
ADJUST_INDICES(start, end, len);
if (direction < 0) {
/* startswith */
if (start+vsubstr.len > len) {
goto done;
}
} else {
/* endswith */
if (end-start < vsubstr.len || start > len) {
goto done;
}
if (end-vsubstr.len > start)
start = end - vsubstr.len;
}
if (end-start >= vsubstr.len)
rv = ! memcmp(str+start, vsubstr.buf, vsubstr.len);
done:
PyBuffer_Release(&vsubstr);
return rv;
}
PyDoc_STRVAR(startswith__doc__,
"B.startswith(prefix[, start[, end]]) -> bool\n\
\n\
Return True if B starts with the specified prefix, False otherwise.\n\
With optional start, test B beginning at that position.\n\
With optional end, stop comparing B at that position.\n\
prefix can also be a tuple of bytes to try.");
static PyObject *
bytearray_startswith(PyByteArrayObject *self, PyObject *args)
{
Py_ssize_t start = 0;
Py_ssize_t end = PY_SSIZE_T_MAX;
PyObject *subobj;
int result;
if (!stringlib_parse_args_finds("startswith", args, &subobj, &start, &end))
return NULL;
if (PyTuple_Check(subobj)) {
Py_ssize_t i;
for (i = 0; i < PyTuple_GET_SIZE(subobj); i++) {
result = _bytearray_tailmatch(self,
PyTuple_GET_ITEM(subobj, i),
start, end, -1);
if (result == -1)
return NULL;
else if (result) {
Py_RETURN_TRUE;
}
}
Py_RETURN_FALSE;
}
result = _bytearray_tailmatch(self, subobj, start, end, -1);
if (result == -1) {
if (PyErr_ExceptionMatches(PyExc_TypeError))
PyErr_Format(PyExc_TypeError, "startswith first arg must be bytes "
"or a tuple of bytes, not %s", Py_TYPE(subobj)->tp_name);
return NULL;
}
else
return PyBool_FromLong(result);
return _Py_bytes_startswith(PyByteArray_AS_STRING(self), PyByteArray_GET_SIZE(self), args);
}
PyDoc_STRVAR(endswith__doc__,
"B.endswith(suffix[, start[, end]]) -> bool\n\
\n\
Return True if B ends with the specified suffix, False otherwise.\n\
With optional start, test B beginning at that position.\n\
With optional end, stop comparing B at that position.\n\
suffix can also be a tuple of bytes to try.");
static PyObject *
bytearray_endswith(PyByteArrayObject *self, PyObject *args)
{
Py_ssize_t start = 0;
Py_ssize_t end = PY_SSIZE_T_MAX;
PyObject *subobj;
int result;
if (!stringlib_parse_args_finds("endswith", args, &subobj, &start, &end))
return NULL;
if (PyTuple_Check(subobj)) {
Py_ssize_t i;
for (i = 0; i < PyTuple_GET_SIZE(subobj); i++) {
result = _bytearray_tailmatch(self,
PyTuple_GET_ITEM(subobj, i),
start, end, +1);
if (result == -1)
return NULL;
else if (result) {
Py_RETURN_TRUE;
}
}
Py_RETURN_FALSE;
}
result = _bytearray_tailmatch(self, subobj, start, end, +1);
if (result == -1) {
if (PyErr_ExceptionMatches(PyExc_TypeError))
PyErr_Format(PyExc_TypeError, "endswith first arg must be bytes or "
"a tuple of bytes, not %s", Py_TYPE(subobj)->tp_name);
return NULL;
}
else
return PyBool_FromLong(result);
return _Py_bytes_endswith(PyByteArray_AS_STRING(self), PyByteArray_GET_SIZE(self), args);
}
@ -1544,7 +1237,7 @@ bytearray_translate_impl(PyByteArrayObject *self, PyObject *table,
result = PyByteArray_FromStringAndSize((char *)NULL, inlen);
if (result == NULL)
goto done;
output_start = output = PyByteArray_AsString(result);
output_start = output = PyByteArray_AS_STRING(result);
input = PyByteArray_AS_STRING(input_obj);
if (vdel.len == 0 && table_chars != NULL) {
@ -2919,19 +2612,22 @@ bytearray_methods[] = {
BYTEARRAY_APPEND_METHODDEF
{"capitalize", (PyCFunction)stringlib_capitalize, METH_NOARGS,
_Py_capitalize__doc__},
{"center", (PyCFunction)stringlib_center, METH_VARARGS, center__doc__},
{"center", (PyCFunction)stringlib_center, METH_VARARGS, _Py_center__doc__},
BYTEARRAY_CLEAR_METHODDEF
BYTEARRAY_COPY_METHODDEF
{"count", (PyCFunction)bytearray_count, METH_VARARGS, count__doc__},
{"count", (PyCFunction)bytearray_count, METH_VARARGS,
_Py_count__doc__},
BYTEARRAY_DECODE_METHODDEF
{"endswith", (PyCFunction)bytearray_endswith, METH_VARARGS, endswith__doc__},
{"endswith", (PyCFunction)bytearray_endswith, METH_VARARGS,
_Py_endswith__doc__},
{"expandtabs", (PyCFunction)stringlib_expandtabs, METH_VARARGS | METH_KEYWORDS,
expandtabs__doc__},
_Py_expandtabs__doc__},
BYTEARRAY_EXTEND_METHODDEF
{"find", (PyCFunction)bytearray_find, METH_VARARGS, find__doc__},
{"find", (PyCFunction)bytearray_find, METH_VARARGS,
_Py_find__doc__},
BYTEARRAY_FROMHEX_METHODDEF
{"hex", (PyCFunction)bytearray_hex, METH_NOARGS, hex__doc__},
{"index", (PyCFunction)bytearray_index, METH_VARARGS, index__doc__},
{"index", (PyCFunction)bytearray_index, METH_VARARGS, _Py_index__doc__},
BYTEARRAY_INSERT_METHODDEF
{"isalnum", (PyCFunction)stringlib_isalnum, METH_NOARGS,
_Py_isalnum__doc__},
@ -2948,7 +2644,7 @@ bytearray_methods[] = {
{"isupper", (PyCFunction)stringlib_isupper, METH_NOARGS,
_Py_isupper__doc__},
BYTEARRAY_JOIN_METHODDEF
{"ljust", (PyCFunction)stringlib_ljust, METH_VARARGS, ljust__doc__},
{"ljust", (PyCFunction)stringlib_ljust, METH_VARARGS, _Py_ljust__doc__},
{"lower", (PyCFunction)stringlib_lower, METH_NOARGS, _Py_lower__doc__},
BYTEARRAY_LSTRIP_METHODDEF
BYTEARRAY_MAKETRANS_METHODDEF
@ -2957,23 +2653,23 @@ bytearray_methods[] = {
BYTEARRAY_REMOVE_METHODDEF
BYTEARRAY_REPLACE_METHODDEF
BYTEARRAY_REVERSE_METHODDEF
{"rfind", (PyCFunction)bytearray_rfind, METH_VARARGS, rfind__doc__},
{"rindex", (PyCFunction)bytearray_rindex, METH_VARARGS, rindex__doc__},
{"rjust", (PyCFunction)stringlib_rjust, METH_VARARGS, rjust__doc__},
{"rfind", (PyCFunction)bytearray_rfind, METH_VARARGS, _Py_rfind__doc__},
{"rindex", (PyCFunction)bytearray_rindex, METH_VARARGS, _Py_rindex__doc__},
{"rjust", (PyCFunction)stringlib_rjust, METH_VARARGS, _Py_rjust__doc__},
BYTEARRAY_RPARTITION_METHODDEF
BYTEARRAY_RSPLIT_METHODDEF
BYTEARRAY_RSTRIP_METHODDEF
BYTEARRAY_SPLIT_METHODDEF
BYTEARRAY_SPLITLINES_METHODDEF
{"startswith", (PyCFunction)bytearray_startswith, METH_VARARGS ,
startswith__doc__},
_Py_startswith__doc__},
BYTEARRAY_STRIP_METHODDEF
{"swapcase", (PyCFunction)stringlib_swapcase, METH_NOARGS,
_Py_swapcase__doc__},
{"title", (PyCFunction)stringlib_title, METH_NOARGS, _Py_title__doc__},
BYTEARRAY_TRANSLATE_METHODDEF
{"upper", (PyCFunction)stringlib_upper, METH_NOARGS, _Py_upper__doc__},
{"zfill", (PyCFunction)stringlib_zfill, METH_VARARGS, zfill__doc__},
{"zfill", (PyCFunction)stringlib_zfill, METH_VARARGS, _Py_zfill__doc__},
{NULL}
};