mirror of
https://github.com/python/cpython.git
synced 2025-12-08 06:10:17 +00:00
gh-71679: Share the repr implementation between bytes and bytearray (GH-138181)
This allows to use the smart quotes algorithm in the bytearray's repr.
This commit is contained in:
parent
cf9ef73121
commit
a1cf6e92b6
5 changed files with 30 additions and 93 deletions
|
|
@ -1067,95 +1067,20 @@ bytearray___init___impl(PyByteArrayObject *self, PyObject *arg,
|
|||
return -1;
|
||||
}
|
||||
|
||||
/* Mostly copied from string_repr, but without the
|
||||
"smart quote" functionality. */
|
||||
static PyObject *
|
||||
bytearray_repr_lock_held(PyObject *op)
|
||||
{
|
||||
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(op);
|
||||
PyByteArrayObject *self = _PyByteArray_CAST(op);
|
||||
const char *className = _PyType_Name(Py_TYPE(self));
|
||||
const char *quote_prefix = "(b";
|
||||
const char *quote_postfix = ")";
|
||||
Py_ssize_t length = Py_SIZE(self);
|
||||
/* 6 == strlen(quote_prefix) + 2 + strlen(quote_postfix) + 1 */
|
||||
Py_ssize_t newsize;
|
||||
PyObject *v;
|
||||
Py_ssize_t i;
|
||||
char *bytes;
|
||||
char c;
|
||||
char *p;
|
||||
int quote;
|
||||
char *test, *start;
|
||||
char *buffer;
|
||||
|
||||
newsize = strlen(className);
|
||||
if (length > (PY_SSIZE_T_MAX - 6 - newsize) / 4) {
|
||||
PyErr_SetString(PyExc_OverflowError,
|
||||
"bytearray object is too large to make repr");
|
||||
const char *className = _PyType_Name(Py_TYPE(op));
|
||||
PyObject *bytes_repr = _Py_bytes_repr(PyByteArray_AS_STRING(op),
|
||||
PyByteArray_GET_SIZE(op), 1,
|
||||
"bytearray");
|
||||
if (bytes_repr == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
newsize += 6 + length * 4;
|
||||
buffer = PyMem_Malloc(newsize);
|
||||
if (buffer == NULL) {
|
||||
PyErr_NoMemory();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Figure out which quote to use; single is preferred */
|
||||
quote = '\'';
|
||||
start = PyByteArray_AS_STRING(self);
|
||||
for (test = start; test < start+length; ++test) {
|
||||
if (*test == '"') {
|
||||
quote = '\''; /* back to single */
|
||||
break;
|
||||
}
|
||||
else if (*test == '\'')
|
||||
quote = '"';
|
||||
}
|
||||
|
||||
p = buffer;
|
||||
while (*className)
|
||||
*p++ = *className++;
|
||||
while (*quote_prefix)
|
||||
*p++ = *quote_prefix++;
|
||||
*p++ = quote;
|
||||
|
||||
bytes = PyByteArray_AS_STRING(self);
|
||||
for (i = 0; i < length; i++) {
|
||||
/* There's at least enough room for a hex escape
|
||||
and a closing quote. */
|
||||
assert(newsize - (p - buffer) >= 5);
|
||||
c = bytes[i];
|
||||
if (c == '\'' || c == '\\')
|
||||
*p++ = '\\', *p++ = c;
|
||||
else if (c == '\t')
|
||||
*p++ = '\\', *p++ = 't';
|
||||
else if (c == '\n')
|
||||
*p++ = '\\', *p++ = 'n';
|
||||
else if (c == '\r')
|
||||
*p++ = '\\', *p++ = 'r';
|
||||
else if (c == 0)
|
||||
*p++ = '\\', *p++ = 'x', *p++ = '0', *p++ = '0';
|
||||
else if (c < ' ' || c >= 0x7f) {
|
||||
*p++ = '\\';
|
||||
*p++ = 'x';
|
||||
*p++ = Py_hexdigits[(c & 0xf0) >> 4];
|
||||
*p++ = Py_hexdigits[c & 0xf];
|
||||
}
|
||||
else
|
||||
*p++ = c;
|
||||
}
|
||||
assert(newsize - (p - buffer) >= 1);
|
||||
*p++ = quote;
|
||||
while (*quote_postfix) {
|
||||
*p++ = *quote_postfix++;
|
||||
}
|
||||
|
||||
v = PyUnicode_FromStringAndSize(buffer, p - buffer);
|
||||
PyMem_Free(buffer);
|
||||
return v;
|
||||
PyObject *res = PyUnicode_FromFormat("%s(%U)", className, bytes_repr);
|
||||
Py_DECREF(bytes_repr);
|
||||
return res;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
|
|
|
|||
|
|
@ -1348,27 +1348,33 @@ _PyBytes_ReverseFind(const char *haystack, Py_ssize_t len_haystack,
|
|||
PyObject *
|
||||
PyBytes_Repr(PyObject *obj, int smartquotes)
|
||||
{
|
||||
PyBytesObject* op = (PyBytesObject*) obj;
|
||||
Py_ssize_t i, length = Py_SIZE(op);
|
||||
return _Py_bytes_repr(PyBytes_AS_STRING(obj), PyBytes_GET_SIZE(obj),
|
||||
smartquotes, "bytes");
|
||||
}
|
||||
|
||||
PyObject *
|
||||
_Py_bytes_repr(const char *data, Py_ssize_t length, int smartquotes,
|
||||
const char *classname)
|
||||
{
|
||||
Py_ssize_t i;
|
||||
Py_ssize_t newsize, squotes, dquotes;
|
||||
PyObject *v;
|
||||
unsigned char quote;
|
||||
const unsigned char *s;
|
||||
Py_UCS1 *p;
|
||||
|
||||
/* Compute size of output string */
|
||||
squotes = dquotes = 0;
|
||||
newsize = 3; /* b'' */
|
||||
s = (const unsigned char*)op->ob_sval;
|
||||
for (i = 0; i < length; i++) {
|
||||
unsigned char c = data[i];
|
||||
Py_ssize_t incr = 1;
|
||||
switch(s[i]) {
|
||||
switch(c) {
|
||||
case '\'': squotes++; break;
|
||||
case '"': dquotes++; break;
|
||||
case '\\': case '\t': case '\n': case '\r':
|
||||
incr = 2; break; /* \C */
|
||||
default:
|
||||
if (s[i] < ' ' || s[i] >= 0x7f)
|
||||
if (c < ' ' || c >= 0x7f)
|
||||
incr = 4; /* \xHH */
|
||||
}
|
||||
if (newsize > PY_SSIZE_T_MAX - incr)
|
||||
|
|
@ -1392,7 +1398,7 @@ PyBytes_Repr(PyObject *obj, int smartquotes)
|
|||
|
||||
*p++ = 'b', *p++ = quote;
|
||||
for (i = 0; i < length; i++) {
|
||||
unsigned char c = op->ob_sval[i];
|
||||
unsigned char c = data[i];
|
||||
if (c == quote || c == '\\')
|
||||
*p++ = '\\', *p++ = c;
|
||||
else if (c == '\t')
|
||||
|
|
@ -1415,8 +1421,8 @@ PyBytes_Repr(PyObject *obj, int smartquotes)
|
|||
return v;
|
||||
|
||||
overflow:
|
||||
PyErr_SetString(PyExc_OverflowError,
|
||||
"bytes object is too large to make repr");
|
||||
PyErr_Format(PyExc_OverflowError,
|
||||
"%s object is too large to make repr", classname);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue