Skip to content

Commit 6f699b5

Browse files
committed
gh-128213: fast path for bytes creation from list and tuple
1 parent 30efede commit 6f699b5

File tree

1 file changed

+22
-67
lines changed

1 file changed

+22
-67
lines changed

Objects/bytesobject.c

Lines changed: 22 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -2810,79 +2810,33 @@ _PyBytes_FromBuffer(PyObject *x)
28102810
}
28112811

28122812
static PyObject*
2813-
_PyBytes_FromList(PyObject *x)
2813+
_PyBytes_FromSequence(PyObject *x)
28142814
{
2815-
Py_ssize_t i, size = PyList_GET_SIZE(x);
2816-
Py_ssize_t value;
2817-
char *str;
2818-
PyObject *item;
2819-
_PyBytesWriter writer;
2820-
2821-
_PyBytesWriter_Init(&writer);
2822-
str = _PyBytesWriter_Alloc(&writer, size);
2823-
if (str == NULL)
2824-
return NULL;
2825-
writer.overallocate = 1;
2826-
size = writer.allocated;
2827-
2828-
for (i = 0; i < PyList_GET_SIZE(x); i++) {
2829-
item = PyList_GET_ITEM(x, i);
2830-
Py_INCREF(item);
2831-
value = PyNumber_AsSsize_t(item, NULL);
2832-
Py_DECREF(item);
2833-
if (value == -1 && PyErr_Occurred())
2834-
goto error;
2835-
2836-
if (value < 0 || value >= 256) {
2837-
PyErr_SetString(PyExc_ValueError,
2838-
"bytes must be in range(0, 256)");
2839-
goto error;
2840-
}
2841-
2842-
if (i >= size) {
2843-
str = _PyBytesWriter_Resize(&writer, str, size+1);
2844-
if (str == NULL)
2845-
return NULL;
2846-
size = writer.allocated;
2847-
}
2848-
*str++ = (char) value;
2849-
}
2850-
return _PyBytesWriter_Finish(&writer, str);
2851-
2852-
error:
2853-
_PyBytesWriter_Dealloc(&writer);
2854-
return NULL;
2855-
}
2856-
2857-
static PyObject*
2858-
_PyBytes_FromTuple(PyObject *x)
2859-
{
2860-
PyObject *bytes;
2861-
Py_ssize_t i, size = PyTuple_GET_SIZE(x);
2862-
Py_ssize_t value;
2863-
char *str;
2864-
PyObject *item;
2865-
2866-
bytes = PyBytes_FromStringAndSize(NULL, size);
2815+
Py_ssize_t size = PySequence_Fast_GET_SIZE(x);
2816+
PyObject *bytes = PyBytes_FromStringAndSize(NULL, size);
28672817
if (bytes == NULL)
28682818
return NULL;
2869-
str = ((PyBytesObject *)bytes)->ob_sval;
2870-
2871-
for (i = 0; i < size; i++) {
2872-
item = PyTuple_GET_ITEM(x, i);
2873-
value = PyNumber_AsSsize_t(item, NULL);
2874-
if (value == -1 && PyErr_Occurred())
2819+
char *s = PyBytes_AS_STRING(bytes);
2820+
PyObject **items = PySequence_Fast_ITEMS(x);
2821+
for (Py_ssize_t i = 0; i < size; i++) {
2822+
if (!PyLong_CheckExact(items[i])) {
2823+
Py_DECREF(bytes);
2824+
return Py_None; // None as fallback sentinel to the slow path
2825+
}
2826+
int overflow;
2827+
long value = PyLong_AsLongAndOverflow(items[i], &overflow);
2828+
if (value == -1 && PyErr_Occurred()) {
28752829
goto error;
2876-
2830+
}
28772831
if (value < 0 || value >= 256) {
2832+
/* this includes an overflow in converting to C long */
28782833
PyErr_SetString(PyExc_ValueError,
28792834
"bytes must be in range(0, 256)");
28802835
goto error;
28812836
}
2882-
*str++ = (char) value;
2837+
s[i] = value;
28832838
}
28842839
return bytes;
2885-
28862840
error:
28872841
Py_DECREF(bytes);
28882842
return NULL;
@@ -2968,11 +2922,12 @@ PyBytes_FromObject(PyObject *x)
29682922
if (PyObject_CheckBuffer(x))
29692923
return _PyBytes_FromBuffer(x);
29702924

2971-
if (PyList_CheckExact(x))
2972-
return _PyBytes_FromList(x);
2973-
2974-
if (PyTuple_CheckExact(x))
2975-
return _PyBytes_FromTuple(x);
2925+
if (PyList_CheckExact(x) || PyTuple_CheckExact(x)) {
2926+
PyObject *bytes = _PyBytes_FromSequence(x);
2927+
if (bytes != Py_None) {
2928+
return bytes;
2929+
}
2930+
}
29762931

29772932
if (!PyUnicode_Check(x)) {
29782933
it = PyObject_GetIter(x);

0 commit comments

Comments
 (0)