Commit dd40fc3e authored by Serhiy Storchaka's avatar Serhiy Storchaka

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

to bytes_methods.c.
parent 045e6351
...@@ -21,6 +21,15 @@ extern void _Py_bytes_title(char *result, const char *s, Py_ssize_t len); ...@@ -21,6 +21,15 @@ 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_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 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 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 *args);
extern PyObject *_Py_bytes_endswith(const char *str, Py_ssize_t len, PyObject *args);
/* The maketrans() static method. */ /* The maketrans() static method. */
extern PyObject* _Py_bytes_maketrans(Py_buffer *frm, Py_buffer *to); extern PyObject* _Py_bytes_maketrans(Py_buffer *frm, Py_buffer *to);
...@@ -37,7 +46,19 @@ extern const char _Py_upper__doc__[]; ...@@ -37,7 +46,19 @@ extern const char _Py_upper__doc__[];
extern const char _Py_title__doc__[]; extern const char _Py_title__doc__[];
extern const char _Py_capitalize__doc__[]; extern const char _Py_capitalize__doc__[];
extern const char _Py_swapcase__doc__[]; extern const char _Py_swapcase__doc__[];
extern const char _Py_count__doc__[];
extern const char _Py_find__doc__[];
extern const char _Py_index__doc__[];
extern const char _Py_rfind__doc__[];
extern const char _Py_rindex__doc__[];
extern const char _Py_startswith__doc__[];
extern const char _Py_endswith__doc__[];
extern const char _Py_maketrans__doc__[]; extern const char _Py_maketrans__doc__[];
extern const char _Py_expandtabs__doc__[];
extern const char _Py_ljust__doc__[];
extern const char _Py_rjust__doc__[];
extern const char _Py_center__doc__[];
extern const char _Py_zfill__doc__[];
/* this is needed because some docs are shared from the .o, not static */ /* this is needed because some docs are shared from the .o, not static */
#define PyDoc_STRVAR_shared(name,str) const char name[] = PyDoc_STR(str) #define PyDoc_STRVAR_shared(name,str) const char name[] = PyDoc_STR(str)
......
...@@ -1097,147 +1097,16 @@ bytearray_dealloc(PyByteArrayObject *self) ...@@ -1097,147 +1097,16 @@ bytearray_dealloc(PyByteArrayObject *self)
#include "stringlib/transmogrify.h" #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 * static PyObject *
bytearray_find(PyByteArrayObject *self, PyObject *args) bytearray_find(PyByteArrayObject *self, PyObject *args)
{ {
Py_ssize_t result = bytearray_find_internal(self, args, +1); return _Py_bytes_find(PyByteArray_AS_STRING(self), PyByteArray_GET_SIZE(self), args);
if (result == -2)
return NULL;
return PyLong_FromSsize_t(result);
} }
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 * static PyObject *
bytearray_count(PyByteArrayObject *self, PyObject *args) bytearray_count(PyByteArrayObject *self, PyObject *args)
{ {
PyObject *sub_obj; return _Py_bytes_count(PyByteArray_AS_STRING(self), PyByteArray_GET_SIZE(self), args);
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;
} }
/*[clinic input] /*[clinic input]
...@@ -1269,216 +1138,40 @@ bytearray_copy_impl(PyByteArrayObject *self) ...@@ -1269,216 +1138,40 @@ bytearray_copy_impl(PyByteArrayObject *self)
PyByteArray_GET_SIZE(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 * static PyObject *
bytearray_index(PyByteArrayObject *self, PyObject *args) bytearray_index(PyByteArrayObject *self, PyObject *args)
{ {
Py_ssize_t result = bytearray_find_internal(self, args, +1); return _Py_bytes_index(PyByteArray_AS_STRING(self), PyByteArray_GET_SIZE(self), args);
if (result == -2)
return NULL;
if (result == -1) {
PyErr_SetString(PyExc_ValueError,
"subsection not found");
return NULL;
}
return PyLong_FromSsize_t(result);
} }
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 * static PyObject *
bytearray_rfind(PyByteArrayObject *self, PyObject *args) bytearray_rfind(PyByteArrayObject *self, PyObject *args)
{ {
Py_ssize_t result = bytearray_find_internal(self, args, -1); return _Py_bytes_rfind(PyByteArray_AS_STRING(self), PyByteArray_GET_SIZE(self), args);
if (result == -2)
return NULL;
return PyLong_FromSsize_t(result);
} }
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 * static PyObject *
bytearray_rindex(PyByteArrayObject *self, PyObject *args) bytearray_rindex(PyByteArrayObject *self, PyObject *args)
{ {
Py_ssize_t result = bytearray_find_internal(self, args, -1); return _Py_bytes_rindex(PyByteArray_AS_STRING(self), PyByteArray_GET_SIZE(self), args);
if (result == -2)
return NULL;
if (result == -1) {
PyErr_SetString(PyExc_ValueError,
"subsection not found");
return NULL;
}
return PyLong_FromSsize_t(result);
} }
static int static int
bytearray_contains(PyObject *self, PyObject *arg) bytearray_contains(PyObject *self, PyObject *arg)
{ {
Py_ssize_t ival = PyNumber_AsSsize_t(arg, PyExc_ValueError); return _Py_bytes_contains(PyByteArray_AS_STRING(self), PyByteArray_GET_SIZE(self), arg);
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;
} }
/* 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 * static PyObject *
bytearray_startswith(PyByteArrayObject *self, PyObject *args) bytearray_startswith(PyByteArrayObject *self, PyObject *args)
{ {
Py_ssize_t start = 0; return _Py_bytes_startswith(PyByteArray_AS_STRING(self), PyByteArray_GET_SIZE(self), args);
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);
} }
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 * static PyObject *
bytearray_endswith(PyByteArrayObject *self, PyObject *args) bytearray_endswith(PyByteArrayObject *self, PyObject *args)
{ {
Py_ssize_t start = 0; return _Py_bytes_endswith(PyByteArray_AS_STRING(self), PyByteArray_GET_SIZE(self), args);
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);
} }
...@@ -1544,7 +1237,7 @@ bytearray_translate_impl(PyByteArrayObject *self, PyObject *table, ...@@ -1544,7 +1237,7 @@ bytearray_translate_impl(PyByteArrayObject *self, PyObject *table,
result = PyByteArray_FromStringAndSize((char *)NULL, inlen); result = PyByteArray_FromStringAndSize((char *)NULL, inlen);
if (result == NULL) if (result == NULL)
goto done; goto done;
output_start = output = PyByteArray_AsString(result); output_start = output = PyByteArray_AS_STRING(result);
input = PyByteArray_AS_STRING(input_obj); input = PyByteArray_AS_STRING(input_obj);
if (vdel.len == 0 && table_chars != NULL) { if (vdel.len == 0 && table_chars != NULL) {
...@@ -2919,19 +2612,22 @@ bytearray_methods[] = { ...@@ -2919,19 +2612,22 @@ bytearray_methods[] = {
BYTEARRAY_APPEND_METHODDEF BYTEARRAY_APPEND_METHODDEF
{"capitalize", (PyCFunction)stringlib_capitalize, METH_NOARGS, {"capitalize", (PyCFunction)stringlib_capitalize, METH_NOARGS,
_Py_capitalize__doc__}, _Py_capitalize__doc__},
{"center", (PyCFunction)stringlib_center, METH_VARARGS, center__doc__}, {"center", (PyCFunction)stringlib_center, METH_VARARGS, _Py_center__doc__},
BYTEARRAY_CLEAR_METHODDEF BYTEARRAY_CLEAR_METHODDEF
BYTEARRAY_COPY_METHODDEF BYTEARRAY_COPY_METHODDEF
{"count", (PyCFunction)bytearray_count, METH_VARARGS, count__doc__}, {"count", (PyCFunction)bytearray_count, METH_VARARGS,
_Py_count__doc__},
BYTEARRAY_DECODE_METHODDEF 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", (PyCFunction)stringlib_expandtabs, METH_VARARGS | METH_KEYWORDS,
expandtabs__doc__}, _Py_expandtabs__doc__},
BYTEARRAY_EXTEND_METHODDEF BYTEARRAY_EXTEND_METHODDEF
{"find", (PyCFunction)bytearray_find, METH_VARARGS, find__doc__}, {"find", (PyCFunction)bytearray_find, METH_VARARGS,
_Py_find__doc__},
BYTEARRAY_FROMHEX_METHODDEF BYTEARRAY_FROMHEX_METHODDEF
{"hex", (PyCFunction)bytearray_hex, METH_NOARGS, hex__doc__}, {"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 BYTEARRAY_INSERT_METHODDEF
{"isalnum", (PyCFunction)stringlib_isalnum, METH_NOARGS, {"isalnum", (PyCFunction)stringlib_isalnum, METH_NOARGS,
_Py_isalnum__doc__}, _Py_isalnum__doc__},
...@@ -2948,7 +2644,7 @@ bytearray_methods[] = { ...@@ -2948,7 +2644,7 @@ bytearray_methods[] = {
{"isupper", (PyCFunction)stringlib_isupper, METH_NOARGS, {"isupper", (PyCFunction)stringlib_isupper, METH_NOARGS,
_Py_isupper__doc__}, _Py_isupper__doc__},
BYTEARRAY_JOIN_METHODDEF 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__}, {"lower", (PyCFunction)stringlib_lower, METH_NOARGS, _Py_lower__doc__},
BYTEARRAY_LSTRIP_METHODDEF BYTEARRAY_LSTRIP_METHODDEF
BYTEARRAY_MAKETRANS_METHODDEF BYTEARRAY_MAKETRANS_METHODDEF
...@@ -2957,23 +2653,23 @@ bytearray_methods[] = { ...@@ -2957,23 +2653,23 @@ bytearray_methods[] = {
BYTEARRAY_REMOVE_METHODDEF BYTEARRAY_REMOVE_METHODDEF
BYTEARRAY_REPLACE_METHODDEF BYTEARRAY_REPLACE_METHODDEF
BYTEARRAY_REVERSE_METHODDEF BYTEARRAY_REVERSE_METHODDEF
{"rfind", (PyCFunction)bytearray_rfind, METH_VARARGS, rfind__doc__}, {"rfind", (PyCFunction)bytearray_rfind, METH_VARARGS, _Py_rfind__doc__},
{"rindex", (PyCFunction)bytearray_rindex, METH_VARARGS, rindex__doc__}, {"rindex", (PyCFunction)bytearray_rindex, METH_VARARGS, _Py_rindex__doc__},
{"rjust", (PyCFunction)stringlib_rjust, METH_VARARGS, rjust__doc__}, {"rjust", (PyCFunction)stringlib_rjust, METH_VARARGS, _Py_rjust__doc__},
BYTEARRAY_RPARTITION_METHODDEF BYTEARRAY_RPARTITION_METHODDEF
BYTEARRAY_RSPLIT_METHODDEF BYTEARRAY_RSPLIT_METHODDEF
BYTEARRAY_RSTRIP_METHODDEF BYTEARRAY_RSTRIP_METHODDEF
BYTEARRAY_SPLIT_METHODDEF BYTEARRAY_SPLIT_METHODDEF
BYTEARRAY_SPLITLINES_METHODDEF BYTEARRAY_SPLITLINES_METHODDEF
{"startswith", (PyCFunction)bytearray_startswith, METH_VARARGS , {"startswith", (PyCFunction)bytearray_startswith, METH_VARARGS ,
startswith__doc__}, _Py_startswith__doc__},
BYTEARRAY_STRIP_METHODDEF BYTEARRAY_STRIP_METHODDEF
{"swapcase", (PyCFunction)stringlib_swapcase, METH_NOARGS, {"swapcase", (PyCFunction)stringlib_swapcase, METH_NOARGS,
_Py_swapcase__doc__}, _Py_swapcase__doc__},
{"title", (PyCFunction)stringlib_title, METH_NOARGS, _Py_title__doc__}, {"title", (PyCFunction)stringlib_title, METH_NOARGS, _Py_title__doc__},
BYTEARRAY_TRANSLATE_METHODDEF BYTEARRAY_TRANSLATE_METHODDEF
{"upper", (PyCFunction)stringlib_upper, METH_NOARGS, _Py_upper__doc__}, {"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} {NULL}
}; };
......
...@@ -387,3 +387,427 @@ _Py_bytes_maketrans(Py_buffer *frm, Py_buffer *to) ...@@ -387,3 +387,427 @@ _Py_bytes_maketrans(Py_buffer *frm, Py_buffer *to)
return res; return res;
} }
#define FASTSEARCH fastsearch
#define STRINGLIB(F) stringlib_##F
#define STRINGLIB_CHAR char
#define STRINGLIB_SIZEOF_CHAR 1
#include "stringlib/fastsearch.h"
#include "stringlib/count.h"
#include "stringlib/find.h"
/*
Wraps stringlib_parse_args_finds() and additionally checks whether the
first argument is an integer in range(0, 256).
If this is the case, writes the integer value to the byte parameter
and sets subobj to NULL. Otherwise, sets the first argument to subobj
and doesn't touch byte. The other parameters are similar to those of
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)
{
PyObject *tmp_subobj;
Py_ssize_t ival;
PyObject *err;
if(!stringlib_parse_args_finds(function_name, args, &tmp_subobj,
start, end))
return 0;
if (!PyNumber_Check(tmp_subobj)) {
*subobj = tmp_subobj;
return 1;
}
ival = PyNumber_AsSsize_t(tmp_subobj, PyExc_OverflowError);
if (ival == -1) {
err = PyErr_Occurred();
if (err && !PyErr_GivenExceptionMatches(err, PyExc_OverflowError)) {
PyErr_Clear();
*subobj = tmp_subobj;
return 1;
}
}
if (ival < 0 || ival > 255) {
PyErr_SetString(PyExc_ValueError, "byte must be in range(0, 256)");
return 0;
}
*subobj = NULL;
*byte = (char)ival;
return 1;
}
/* 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)
find_internal(const char *str, Py_ssize_t len,
const char *function_name, PyObject *args, 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))
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;
}
ADJUST_INDICES(start, end, len);
if (end - start < sub_len)
res = -1;
else if (sub_len == 1) {
if (dir > 0)
res = stringlib_find_char(
str + start, end - start,
*sub);
else
res = stringlib_rfind_char(
str + start, end - start,
*sub);
if (res >= 0)
res += start;
}
else {
if (dir > 0)
res = stringlib_find_slice(
str, len,
sub, sub_len, start, end);
else
res = stringlib_rfind_slice(
str, len,
sub, sub_len, start, end);
}
if (subobj)
PyBuffer_Release(&subbuf);
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_ssize_t result = find_internal(str, len, "find", args, +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\
Like B.find() but raise ValueError when the subsection is not found.");
PyObject *
_Py_bytes_index(const char *str, Py_ssize_t len, PyObject *args)
{
Py_ssize_t result = find_internal(str, len, "index", args, +1);
if (result == -2)
return NULL;
if (result == -1) {
PyErr_SetString(PyExc_ValueError,
"subsection not found");
return NULL;
}
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_ssize_t result = find_internal(str, len, "rfind", args, -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\
Like B.rfind() but raise ValueError when the subsection is not found.");
PyObject *
_Py_bytes_rindex(const char *str, Py_ssize_t len, PyObject *args)
{
Py_ssize_t result = find_internal(str, len, "rindex", args, -1);
if (result == -2)
return NULL;
if (result == -1) {
PyErr_SetString(PyExc_ValueError,
"subsection not found");
return NULL;
}
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)
{
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))
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, len);
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;
}
int
_Py_bytes_contains(const char *str, Py_ssize_t len, 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(str, len,
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(str, (int) ival, len) != NULL;
}
/* Matches the end (direction >= 0) or start (direction < 0) of the buffer
* against substr, using the start and end arguments. Returns
* -1 on error, 0 if not found and 1 if found.
*/
Py_LOCAL(int)
tailmatch(const char *str, Py_ssize_t len, PyObject *substr,
Py_ssize_t start, Py_ssize_t end, int direction)
{
Py_buffer sub_view = {NULL, NULL};
const char *sub;
Py_ssize_t slen;
if (PyBytes_Check(substr)) {
sub = PyBytes_AS_STRING(substr);
slen = PyBytes_GET_SIZE(substr);
}
else {
if (PyObject_GetBuffer(substr, &sub_view, PyBUF_SIMPLE) != 0)
return -1;
sub = sub_view.buf;
slen = sub_view.len;
}
ADJUST_INDICES(start, end, len);
if (direction < 0) {
/* startswith */
if (start + slen > len)
goto notfound;
} else {
/* endswith */
if (end - start < slen || start > len)
goto notfound;
if (end - slen > start)
start = end - slen;
}
if (end - start < slen)
goto notfound;
if (memcmp(str + start, sub, slen) != 0)
goto notfound;
PyBuffer_Release(&sub_view);
return 1;
notfound:
PyBuffer_Release(&sub_view);
return 0;
}
Py_LOCAL(PyObject *)
_Py_bytes_tailmatch(const char *str, Py_ssize_t len,
const char *function_name, PyObject *args,
int direction)
{
Py_ssize_t start = 0;
Py_ssize_t end = PY_SSIZE_T_MAX;
PyObject *subobj;
int result;
if (!stringlib_parse_args_finds(function_name, args, &subobj, &start, &end))
return NULL;
if (PyTuple_Check(subobj)) {
Py_ssize_t i;
for (i = 0; i < PyTuple_GET_SIZE(subobj); i++) {
result = tailmatch(str, len, PyTuple_GET_ITEM(subobj, i),
start, end, direction);
if (result == -1)
return NULL;
else if (result) {
Py_RETURN_TRUE;
}
}
Py_RETURN_FALSE;
}
result = tailmatch(str, len, subobj, start, end, direction);
if (result == -1) {
if (PyErr_ExceptionMatches(PyExc_TypeError))
PyErr_Format(PyExc_TypeError,
"%s first arg must be bytes or a tuple of bytes, "
"not %s",
function_name, Py_TYPE(subobj)->tp_name);
return NULL;
}
else
return PyBool_FromLong(result);
}
PyDoc_STRVAR_shared(_Py_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.");
PyObject *
_Py_bytes_startswith(const char *str, Py_ssize_t len, PyObject *args)
{
return _Py_bytes_tailmatch(str, len, "startswith", args, -1);
}
PyDoc_STRVAR_shared(_Py_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.");
PyObject *
_Py_bytes_endswith(const char *str, Py_ssize_t len, PyObject *args)
{
return _Py_bytes_tailmatch(str, len, "endswith", args, +1);
}
PyDoc_STRVAR_shared(_Py_expandtabs__doc__,
"B.expandtabs(tabsize=8) -> copy of B\n\
\n\
Return a copy of B where all tab characters are expanded using spaces.\n\
If tabsize is not given, a tab size of 8 characters is assumed.");
PyDoc_STRVAR_shared(_Py_ljust__doc__,
"B.ljust(width[, fillchar]) -> copy of B\n"
"\n"
"Return B left justified in a string of length width. Padding is\n"
"done using the specified fill character (default is a space).");
PyDoc_STRVAR_shared(_Py_rjust__doc__,
"B.rjust(width[, fillchar]) -> copy of B\n"
"\n"
"Return B right justified in a string of length width. Padding is\n"
"done using the specified fill character (default is a space)");
PyDoc_STRVAR_shared(_Py_center__doc__,
"B.center(width[, fillchar]) -> copy of B\n"
"\n"
"Return B centered in a string of length width. Padding is\n"
"done using the specified fill character (default is a space).");
PyDoc_STRVAR_shared(_Py_zfill__doc__,
"B.zfill(width) -> copy of B\n"
"\n"
"Pad a numeric string B with zeros on the left, to fill a field\n"
"of the specified width. B is never truncated.");
...@@ -486,11 +486,11 @@ formatlong(PyObject *v, int flags, int prec, int type) ...@@ -486,11 +486,11 @@ formatlong(PyObject *v, int flags, int prec, int type)
static int static int
byte_converter(PyObject *arg, char *p) byte_converter(PyObject *arg, char *p)
{ {
if (PyBytes_Check(arg) && PyBytes_Size(arg) == 1) { if (PyBytes_Check(arg) && PyBytes_GET_SIZE(arg) == 1) {
*p = PyBytes_AS_STRING(arg)[0]; *p = PyBytes_AS_STRING(arg)[0];
return 1; return 1;
} }
else if (PyByteArray_Check(arg) && PyByteArray_Size(arg) == 1) { else if (PyByteArray_Check(arg) && PyByteArray_GET_SIZE(arg) == 1) {
*p = PyByteArray_AS_STRING(arg)[0]; *p = PyByteArray_AS_STRING(arg)[0];
return 1; return 1;
} }
...@@ -1488,24 +1488,7 @@ bytes_repeat(PyBytesObject *a, Py_ssize_t n) ...@@ -1488,24 +1488,7 @@ bytes_repeat(PyBytesObject *a, Py_ssize_t n)
static int static int
bytes_contains(PyObject *self, PyObject *arg) bytes_contains(PyObject *self, PyObject *arg)
{ {
Py_ssize_t ival = PyNumber_AsSsize_t(arg, PyExc_ValueError); return _Py_bytes_contains(PyBytes_AS_STRING(self), PyBytes_GET_SIZE(self), arg);
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(PyBytes_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(PyBytes_AS_STRING(self), (int) ival, Py_SIZE(self)) != NULL;
} }
static PyObject * static PyObject *
...@@ -1890,157 +1873,30 @@ _PyBytes_Join(PyObject *sep, PyObject *x) ...@@ -1890,157 +1873,30 @@ _PyBytes_Join(PyObject *sep, PyObject *x)
return bytes_join((PyBytesObject*)sep, x); return bytes_join((PyBytesObject*)sep, x);
} }
/* 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)
bytes_find_internal(PyBytesObject *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 = PyBytes_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(
PyBytes_AS_STRING(self) + start, end - start,
*sub);
else
res = stringlib_rfind_char(
PyBytes_AS_STRING(self) + start, end - start,
*sub);
if (res >= 0)
res += start;
}
else {
if (dir > 0)
res = stringlib_find_slice(
PyBytes_AS_STRING(self), len,
sub, sub_len, start, end);
else
res = stringlib_rfind_slice(
PyBytes_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 substring 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 * static PyObject *
bytes_find(PyBytesObject *self, PyObject *args) bytes_find(PyBytesObject *self, PyObject *args)
{ {
Py_ssize_t result = bytes_find_internal(self, args, +1); return _Py_bytes_find(PyBytes_AS_STRING(self), PyBytes_GET_SIZE(self), args);
if (result == -2)
return NULL;
return PyLong_FromSsize_t(result);
} }
PyDoc_STRVAR(index__doc__,
"B.index(sub[, start[, end]]) -> int\n\
\n\
Like B.find() but raise ValueError when the substring is not found.");
static PyObject * static PyObject *
bytes_index(PyBytesObject *self, PyObject *args) bytes_index(PyBytesObject *self, PyObject *args)
{ {
Py_ssize_t result = bytes_find_internal(self, args, +1); return _Py_bytes_index(PyBytes_AS_STRING(self), PyBytes_GET_SIZE(self), args);
if (result == -2)
return NULL;
if (result == -1) {
PyErr_SetString(PyExc_ValueError,
"substring not found");
return NULL;
}
return PyLong_FromSsize_t(result);
} }
PyDoc_STRVAR(rfind__doc__,
"B.rfind(sub[, start[, end]]) -> int\n\
\n\
Return the highest index in B where substring 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 * static PyObject *
bytes_rfind(PyBytesObject *self, PyObject *args) bytes_rfind(PyBytesObject *self, PyObject *args)
{ {
Py_ssize_t result = bytes_find_internal(self, args, -1); return _Py_bytes_rfind(PyBytes_AS_STRING(self), PyBytes_GET_SIZE(self), args);
if (result == -2)
return NULL;
return PyLong_FromSsize_t(result);
} }
PyDoc_STRVAR(rindex__doc__,
"B.rindex(sub[, start[, end]]) -> int\n\
\n\
Like B.rfind() but raise ValueError when the substring is not found.");
static PyObject * static PyObject *
bytes_rindex(PyBytesObject *self, PyObject *args) bytes_rindex(PyBytesObject *self, PyObject *args)
{ {
Py_ssize_t result = bytes_find_internal(self, args, -1); return _Py_bytes_rindex(PyBytes_AS_STRING(self), PyBytes_GET_SIZE(self), args);
if (result == -2)
return NULL;
if (result == -1) {
PyErr_SetString(PyExc_ValueError,
"substring not found");
return NULL;
}
return PyLong_FromSsize_t(result);
} }
...@@ -2179,51 +2035,10 @@ bytes_rstrip_impl(PyBytesObject *self, PyObject *bytes) ...@@ -2179,51 +2035,10 @@ bytes_rstrip_impl(PyBytesObject *self, PyObject *bytes)
} }
PyDoc_STRVAR(count__doc__,
"B.count(sub[, start[, end]]) -> int\n\
\n\
Return the number of non-overlapping occurrences of substring sub in\n\
string B[start:end]. Optional arguments start and end are interpreted\n\
as in slice notation.");
static PyObject * static PyObject *
bytes_count(PyBytesObject *self, PyObject *args) bytes_count(PyBytesObject *self, PyObject *args)
{ {
PyObject *sub_obj; return _Py_bytes_count(PyBytes_AS_STRING(self), PyBytes_GET_SIZE(self), args);
const char *str = PyBytes_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, PyBytes_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;
} }
...@@ -2307,7 +2122,7 @@ bytes_translate_impl(PyBytesObject *self, PyObject *table, int group_right_1, ...@@ -2307,7 +2122,7 @@ bytes_translate_impl(PyBytesObject *self, PyObject *table, int group_right_1,
PyBuffer_Release(&table_view); PyBuffer_Release(&table_view);
return NULL; return NULL;
} }
output_start = output = PyBytes_AsString(result); output_start = output = PyBytes_AS_STRING(result);
input = PyBytes_AS_STRING(input_obj); input = PyBytes_AS_STRING(input_obj);
if (dellen == 0 && table_chars != NULL) { if (dellen == 0 && table_chars != NULL) {
...@@ -2914,145 +2729,17 @@ bytes_replace_impl(PyBytesObject *self, Py_buffer *old, Py_buffer *new, ...@@ -2914,145 +2729,17 @@ bytes_replace_impl(PyBytesObject *self, Py_buffer *old, Py_buffer *new,
/** End DALKE **/ /** End DALKE **/
/* 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)
_bytes_tailmatch(PyBytesObject *self, PyObject *substr, Py_ssize_t start,
Py_ssize_t end, int direction)
{
Py_ssize_t len = PyBytes_GET_SIZE(self);
Py_ssize_t slen;
Py_buffer sub_view = {NULL, NULL};
const char* sub;
const char* str;
if (PyBytes_Check(substr)) {
sub = PyBytes_AS_STRING(substr);
slen = PyBytes_GET_SIZE(substr);
}
else {
if (PyObject_GetBuffer(substr, &sub_view, PyBUF_SIMPLE) != 0)
return -1;
sub = sub_view.buf;
slen = sub_view.len;
}
str = PyBytes_AS_STRING(self);
ADJUST_INDICES(start, end, len);
if (direction < 0) {
/* startswith */
if (start+slen > len)
goto notfound;
} else {
/* endswith */
if (end-start < slen || start > len)
goto notfound;
if (end-slen > start)
start = end - slen;
}
if (end-start < slen)
goto notfound;
if (memcmp(str+start, sub, slen) != 0)
goto notfound;
PyBuffer_Release(&sub_view);
return 1;
notfound:
PyBuffer_Release(&sub_view);
return 0;
}
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 * static PyObject *
bytes_startswith(PyBytesObject *self, PyObject *args) bytes_startswith(PyBytesObject *self, PyObject *args)
{ {
Py_ssize_t start = 0; return _Py_bytes_startswith(PyBytes_AS_STRING(self), PyBytes_GET_SIZE(self), args);
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 = _bytes_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 = _bytes_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);
} }
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 * static PyObject *
bytes_endswith(PyBytesObject *self, PyObject *args) bytes_endswith(PyBytesObject *self, PyObject *args)
{ {
Py_ssize_t start = 0; return _Py_bytes_endswith(PyBytes_AS_STRING(self), PyBytes_GET_SIZE(self), args);
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 = _bytes_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 = _bytes_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);
} }
...@@ -3224,17 +2911,20 @@ bytes_methods[] = { ...@@ -3224,17 +2911,20 @@ bytes_methods[] = {
{"__getnewargs__", (PyCFunction)bytes_getnewargs, METH_NOARGS}, {"__getnewargs__", (PyCFunction)bytes_getnewargs, METH_NOARGS},
{"capitalize", (PyCFunction)stringlib_capitalize, METH_NOARGS, {"capitalize", (PyCFunction)stringlib_capitalize, METH_NOARGS,
_Py_capitalize__doc__}, _Py_capitalize__doc__},
{"center", (PyCFunction)stringlib_center, METH_VARARGS, center__doc__}, {"center", (PyCFunction)stringlib_center, METH_VARARGS,
{"count", (PyCFunction)bytes_count, METH_VARARGS, count__doc__}, _Py_center__doc__},
{"count", (PyCFunction)bytes_count, METH_VARARGS,
_Py_count__doc__},
BYTES_DECODE_METHODDEF BYTES_DECODE_METHODDEF
{"endswith", (PyCFunction)bytes_endswith, METH_VARARGS, {"endswith", (PyCFunction)bytes_endswith, METH_VARARGS,
endswith__doc__}, _Py_endswith__doc__},
{"expandtabs", (PyCFunction)stringlib_expandtabs, METH_VARARGS | METH_KEYWORDS, {"expandtabs", (PyCFunction)stringlib_expandtabs, METH_VARARGS | METH_KEYWORDS,
expandtabs__doc__}, _Py_expandtabs__doc__},
{"find", (PyCFunction)bytes_find, METH_VARARGS, find__doc__}, {"find", (PyCFunction)bytes_find, METH_VARARGS,
_Py_find__doc__},
BYTES_FROMHEX_METHODDEF BYTES_FROMHEX_METHODDEF
{"hex", (PyCFunction)bytes_hex, METH_NOARGS, hex__doc__}, {"hex", (PyCFunction)bytes_hex, METH_NOARGS, hex__doc__},
{"index", (PyCFunction)bytes_index, METH_VARARGS, index__doc__}, {"index", (PyCFunction)bytes_index, METH_VARARGS, _Py_index__doc__},
{"isalnum", (PyCFunction)stringlib_isalnum, METH_NOARGS, {"isalnum", (PyCFunction)stringlib_isalnum, METH_NOARGS,
_Py_isalnum__doc__}, _Py_isalnum__doc__},
{"isalpha", (PyCFunction)stringlib_isalpha, METH_NOARGS, {"isalpha", (PyCFunction)stringlib_isalpha, METH_NOARGS,
...@@ -3250,29 +2940,29 @@ bytes_methods[] = { ...@@ -3250,29 +2940,29 @@ bytes_methods[] = {
{"isupper", (PyCFunction)stringlib_isupper, METH_NOARGS, {"isupper", (PyCFunction)stringlib_isupper, METH_NOARGS,
_Py_isupper__doc__}, _Py_isupper__doc__},
BYTES_JOIN_METHODDEF BYTES_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__}, {"lower", (PyCFunction)stringlib_lower, METH_NOARGS, _Py_lower__doc__},
BYTES_LSTRIP_METHODDEF BYTES_LSTRIP_METHODDEF
BYTES_MAKETRANS_METHODDEF BYTES_MAKETRANS_METHODDEF
BYTES_PARTITION_METHODDEF BYTES_PARTITION_METHODDEF
BYTES_REPLACE_METHODDEF BYTES_REPLACE_METHODDEF
{"rfind", (PyCFunction)bytes_rfind, METH_VARARGS, rfind__doc__}, {"rfind", (PyCFunction)bytes_rfind, METH_VARARGS, _Py_rfind__doc__},
{"rindex", (PyCFunction)bytes_rindex, METH_VARARGS, rindex__doc__}, {"rindex", (PyCFunction)bytes_rindex, METH_VARARGS, _Py_rindex__doc__},
{"rjust", (PyCFunction)stringlib_rjust, METH_VARARGS, rjust__doc__}, {"rjust", (PyCFunction)stringlib_rjust, METH_VARARGS, _Py_rjust__doc__},
BYTES_RPARTITION_METHODDEF BYTES_RPARTITION_METHODDEF
BYTES_RSPLIT_METHODDEF BYTES_RSPLIT_METHODDEF
BYTES_RSTRIP_METHODDEF BYTES_RSTRIP_METHODDEF
BYTES_SPLIT_METHODDEF BYTES_SPLIT_METHODDEF
BYTES_SPLITLINES_METHODDEF BYTES_SPLITLINES_METHODDEF
{"startswith", (PyCFunction)bytes_startswith, METH_VARARGS, {"startswith", (PyCFunction)bytes_startswith, METH_VARARGS,
startswith__doc__}, _Py_startswith__doc__},
BYTES_STRIP_METHODDEF BYTES_STRIP_METHODDEF
{"swapcase", (PyCFunction)stringlib_swapcase, METH_NOARGS, {"swapcase", (PyCFunction)stringlib_swapcase, METH_NOARGS,
_Py_swapcase__doc__}, _Py_swapcase__doc__},
{"title", (PyCFunction)stringlib_title, METH_NOARGS, _Py_title__doc__}, {"title", (PyCFunction)stringlib_title, METH_NOARGS, _Py_title__doc__},
BYTES_TRANSLATE_METHODDEF BYTES_TRANSLATE_METHODDEF
{"upper", (PyCFunction)stringlib_upper, METH_NOARGS, _Py_upper__doc__}, {"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, NULL} /* sentinel */ {NULL, NULL} /* sentinel */
}; };
......
...@@ -117,76 +117,3 @@ STRINGLIB(parse_args_finds)(const char * function_name, PyObject *args, ...@@ -117,76 +117,3 @@ STRINGLIB(parse_args_finds)(const char * function_name, PyObject *args,
} }
#undef FORMAT_BUFFER_SIZE #undef FORMAT_BUFFER_SIZE
#if STRINGLIB_IS_UNICODE
/*
Wraps stringlib_parse_args_finds() and additionally ensures that the
first argument is a unicode object.
*/
Py_LOCAL_INLINE(int)
STRINGLIB(parse_args_finds_unicode)(const char * function_name, PyObject *args,
PyObject **substring,
Py_ssize_t *start, Py_ssize_t *end)
{
if(STRINGLIB(parse_args_finds)(function_name, args, substring,
start, end)) {
if (ensure_unicode(*substring) < 0)
return 0;
return 1;
}
return 0;
}
#else /* !STRINGLIB_IS_UNICODE */
/*
Wraps stringlib_parse_args_finds() and additionally checks whether the
first argument is an integer in range(0, 256).
If this is the case, writes the integer value to the byte parameter
and sets subobj to NULL. Otherwise, sets the first argument to subobj
and doesn't touch byte. The other parameters are similar to those of
stringlib_parse_args_finds().
*/
Py_LOCAL_INLINE(int)
STRINGLIB(parse_args_finds_byte)(const char *function_name, PyObject *args,
PyObject **subobj, char *byte,
Py_ssize_t *start, Py_ssize_t *end)
{
PyObject *tmp_subobj;
Py_ssize_t ival;
PyObject *err;
if(!STRINGLIB(parse_args_finds)(function_name, args, &tmp_subobj,
start, end))
return 0;
if (!PyNumber_Check(tmp_subobj)) {
*subobj = tmp_subobj;
return 1;
}
ival = PyNumber_AsSsize_t(tmp_subobj, PyExc_OverflowError);
if (ival == -1) {
err = PyErr_Occurred();
if (err && !PyErr_GivenExceptionMatches(err, PyExc_OverflowError)) {
PyErr_Clear();
*subobj = tmp_subobj;
return 1;
}
}
if (ival < 0 || ival > 255) {
PyErr_SetString(PyExc_ValueError, "byte must be in range(0, 256)");
return 0;
}
*subobj = NULL;
*byte = (char)ival;
return 1;
}
#endif /* STRINGLIB_IS_UNICODE */
...@@ -4,12 +4,6 @@ ...@@ -4,12 +4,6 @@
/* the more complicated methods. parts of these should be pulled out into the /* the more complicated methods. parts of these should be pulled out into the
shared code in bytes_methods.c to cut down on duplicate code bloat. */ shared code in bytes_methods.c to cut down on duplicate code bloat. */
PyDoc_STRVAR(expandtabs__doc__,
"B.expandtabs(tabsize=8) -> copy of B\n\
\n\
Return a copy of B where all tab characters are expanded using spaces.\n\
If tabsize is not given, a tab size of 8 characters is assumed.");
static PyObject* static PyObject*
stringlib_expandtabs(PyObject *self, PyObject *args, PyObject *kwds) stringlib_expandtabs(PyObject *self, PyObject *args, PyObject *kwds)
{ {
...@@ -120,12 +114,6 @@ pad(PyObject *self, Py_ssize_t left, Py_ssize_t right, char fill) ...@@ -120,12 +114,6 @@ pad(PyObject *self, Py_ssize_t left, Py_ssize_t right, char fill)
return u; return u;
} }
PyDoc_STRVAR(ljust__doc__,
"B.ljust(width[, fillchar]) -> copy of B\n"
"\n"
"Return B left justified in a string of length width. Padding is\n"
"done using the specified fill character (default is a space).");
static PyObject * static PyObject *
stringlib_ljust(PyObject *self, PyObject *args) stringlib_ljust(PyObject *self, PyObject *args)
{ {
...@@ -150,12 +138,6 @@ stringlib_ljust(PyObject *self, PyObject *args) ...@@ -150,12 +138,6 @@ stringlib_ljust(PyObject *self, PyObject *args)
} }
PyDoc_STRVAR(rjust__doc__,
"B.rjust(width[, fillchar]) -> copy of B\n"
"\n"
"Return B right justified in a string of length width. Padding is\n"
"done using the specified fill character (default is a space)");
static PyObject * static PyObject *
stringlib_rjust(PyObject *self, PyObject *args) stringlib_rjust(PyObject *self, PyObject *args)
{ {
...@@ -180,12 +162,6 @@ stringlib_rjust(PyObject *self, PyObject *args) ...@@ -180,12 +162,6 @@ stringlib_rjust(PyObject *self, PyObject *args)
} }
PyDoc_STRVAR(center__doc__,
"B.center(width[, fillchar]) -> copy of B\n"
"\n"
"Return B centered in a string of length width. Padding is\n"
"done using the specified fill character (default is a space).");
static PyObject * static PyObject *
stringlib_center(PyObject *self, PyObject *args) stringlib_center(PyObject *self, PyObject *args)
{ {
...@@ -213,12 +189,6 @@ stringlib_center(PyObject *self, PyObject *args) ...@@ -213,12 +189,6 @@ stringlib_center(PyObject *self, PyObject *args)
return pad(self, left, marg - left, fillchar); return pad(self, left, marg - left, fillchar);
} }
PyDoc_STRVAR(zfill__doc__,
"B.zfill(width) -> copy of B\n"
"\n"
"Pad a numeric string B with zeros on the left, to fill a field\n"
"of the specified width. B is never truncated.");
static PyObject * static PyObject *
stringlib_zfill(PyObject *self, PyObject *args) stringlib_zfill(PyObject *self, PyObject *args)
{ {
......
...@@ -11244,6 +11244,25 @@ PyUnicode_AppendAndDel(PyObject **pleft, PyObject *right) ...@@ -11244,6 +11244,25 @@ PyUnicode_AppendAndDel(PyObject **pleft, PyObject *right)
Py_XDECREF(right); Py_XDECREF(right);
} }
/*
Wraps stringlib_parse_args_finds() and additionally ensures that the
first argument is a unicode object.
*/
Py_LOCAL_INLINE(int)
parse_args_finds_unicode(const char * function_name, PyObject *args,
PyObject **substring,
Py_ssize_t *start, Py_ssize_t *end)
{
if(stringlib_parse_args_finds(function_name, args, substring,
start, end)) {
if (ensure_unicode(*substring) < 0)
return 0;
return 1;
}
return 0;
}
PyDoc_STRVAR(count__doc__, PyDoc_STRVAR(count__doc__,
"S.count(sub[, start[, end]]) -> int\n\ "S.count(sub[, start[, end]]) -> int\n\
\n\ \n\
...@@ -11262,8 +11281,7 @@ unicode_count(PyObject *self, PyObject *args) ...@@ -11262,8 +11281,7 @@ unicode_count(PyObject *self, PyObject *args)
void *buf1, *buf2; void *buf1, *buf2;
Py_ssize_t len1, len2, iresult; Py_ssize_t len1, len2, iresult;
if (!stringlib_parse_args_finds_unicode("count", args, &substring, if (!parse_args_finds_unicode("count", args, &substring, &start, &end))
&start, &end))
return NULL; return NULL;
kind1 = PyUnicode_KIND(self); kind1 = PyUnicode_KIND(self);
...@@ -11445,8 +11463,7 @@ unicode_find(PyObject *self, PyObject *args) ...@@ -11445,8 +11463,7 @@ unicode_find(PyObject *self, PyObject *args)
Py_ssize_t end = 0; Py_ssize_t end = 0;
Py_ssize_t result; Py_ssize_t result;
if (!stringlib_parse_args_finds_unicode("find", args, &substring, if (!parse_args_finds_unicode("find", args, &substring, &start, &end))
&start, &end))
return NULL; return NULL;
if (PyUnicode_READY(self) == -1) if (PyUnicode_READY(self) == -1)
...@@ -11525,8 +11542,7 @@ unicode_index(PyObject *self, PyObject *args) ...@@ -11525,8 +11542,7 @@ unicode_index(PyObject *self, PyObject *args)
Py_ssize_t start = 0; Py_ssize_t start = 0;
Py_ssize_t end = 0; Py_ssize_t end = 0;
if (!stringlib_parse_args_finds_unicode("index", args, &substring, if (!parse_args_finds_unicode("index", args, &substring, &start, &end))
&start, &end))
return NULL; return NULL;
if (PyUnicode_READY(self) == -1) if (PyUnicode_READY(self) == -1)
...@@ -12555,8 +12571,7 @@ unicode_rfind(PyObject *self, PyObject *args) ...@@ -12555,8 +12571,7 @@ unicode_rfind(PyObject *self, PyObject *args)
Py_ssize_t end = 0; Py_ssize_t end = 0;
Py_ssize_t result; Py_ssize_t result;
if (!stringlib_parse_args_finds_unicode("rfind", args, &substring, if (!parse_args_finds_unicode("rfind", args, &substring, &start, &end))
&start, &end))
return NULL; return NULL;
if (PyUnicode_READY(self) == -1) if (PyUnicode_READY(self) == -1)
...@@ -12584,8 +12599,7 @@ unicode_rindex(PyObject *self, PyObject *args) ...@@ -12584,8 +12599,7 @@ unicode_rindex(PyObject *self, PyObject *args)
Py_ssize_t end = 0; Py_ssize_t end = 0;
Py_ssize_t result; Py_ssize_t result;
if (!stringlib_parse_args_finds_unicode("rindex", args, &substring, if (!parse_args_finds_unicode("rindex", args, &substring, &start, &end))
&start, &end))
return NULL; return NULL;
if (PyUnicode_READY(self) == -1) if (PyUnicode_READY(self) == -1)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment