mirror of https://github.com/python/cpython
Issue #6688: Optimize PyBytes_FromObject().
- Add special-cases for list and tuple objects. - Use _PyObject_LengthHint() instead of an arbitrary value for the size of the initial buffer of the returned object.
This commit is contained in:
parent
0c0e229dd0
commit
a5c565a534
|
@ -2979,17 +2979,62 @@ PyBytes_FromObject(PyObject *x)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (PyList_CheckExact(x)) {
|
||||||
|
new = PyBytes_FromStringAndSize(NULL, Py_SIZE(x));
|
||||||
|
if (new == NULL)
|
||||||
|
return NULL;
|
||||||
|
for (i = 0; i < Py_SIZE(x); i++) {
|
||||||
|
Py_ssize_t value = PyNumber_AsSsize_t(
|
||||||
|
PyList_GET_ITEM(x, i), PyExc_ValueError);
|
||||||
|
if (value == -1 && PyErr_Occurred()) {
|
||||||
|
Py_DECREF(new);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (value < 0 || value >= 256) {
|
||||||
|
PyErr_SetString(PyExc_ValueError,
|
||||||
|
"bytes must be in range(0, 256)");
|
||||||
|
Py_DECREF(new);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
((PyBytesObject *)new)->ob_sval[i] = value;
|
||||||
|
}
|
||||||
|
return new;
|
||||||
|
}
|
||||||
|
if (PyTuple_CheckExact(x)) {
|
||||||
|
new = PyBytes_FromStringAndSize(NULL, Py_SIZE(x));
|
||||||
|
if (new == NULL)
|
||||||
|
return NULL;
|
||||||
|
for (i = 0; i < Py_SIZE(x); i++) {
|
||||||
|
Py_ssize_t value = PyNumber_AsSsize_t(
|
||||||
|
PyTuple_GET_ITEM(x, i), PyExc_ValueError);
|
||||||
|
if (value == -1 && PyErr_Occurred()) {
|
||||||
|
Py_DECREF(new);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (value < 0 || value >= 256) {
|
||||||
|
PyErr_SetString(PyExc_ValueError,
|
||||||
|
"bytes must be in range(0, 256)");
|
||||||
|
Py_DECREF(new);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
((PyBytesObject *)new)->ob_sval[i] = value;
|
||||||
|
}
|
||||||
|
return new;
|
||||||
|
}
|
||||||
|
|
||||||
/* For iterator version, create a string object and resize as needed */
|
/* For iterator version, create a string object and resize as needed */
|
||||||
/* XXX(gb): is 64 a good value? also, optimize if length is known */
|
size = _PyObject_LengthHint(x, 64);
|
||||||
/* XXX(guido): perhaps use Pysequence_Fast() -- I can't imagine the
|
if (size == -1 && PyErr_Occurred())
|
||||||
input being a truly long iterator. */
|
return NULL;
|
||||||
size = 64;
|
/* Allocate an extra byte to prevent PyBytes_FromStringAndSize() from
|
||||||
|
returning a shared empty bytes string. This required because we
|
||||||
|
want to call _PyBytes_Resize() the returned object, which we can
|
||||||
|
only do on bytes objects with refcount == 1. */
|
||||||
|
size += 1;
|
||||||
new = PyBytes_FromStringAndSize(NULL, size);
|
new = PyBytes_FromStringAndSize(NULL, size);
|
||||||
if (new == NULL)
|
if (new == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* XXX Optimize this if the arguments is a list, tuple */
|
|
||||||
|
|
||||||
/* Get the iterator */
|
/* Get the iterator */
|
||||||
it = PyObject_GetIter(x);
|
it = PyObject_GetIter(x);
|
||||||
if (it == NULL)
|
if (it == NULL)
|
||||||
|
@ -3023,7 +3068,7 @@ PyBytes_FromObject(PyObject *x)
|
||||||
|
|
||||||
/* Append the byte */
|
/* Append the byte */
|
||||||
if (i >= size) {
|
if (i >= size) {
|
||||||
size *= 2;
|
size = 2 * size + 1;
|
||||||
if (_PyBytes_Resize(&new, size) < 0)
|
if (_PyBytes_Resize(&new, size) < 0)
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue