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:
Alexandre Vassalotti 2010-01-09 22:14:46 +00:00
parent 0c0e229dd0
commit a5c565a534
1 changed files with 52 additions and 7 deletions

View File

@ -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;
} }