diff options
author | Alexandre Vassalotti <alexandre@peadrop.com> | 2010-01-09 22:14:46 (GMT) |
---|---|---|
committer | Alexandre Vassalotti <alexandre@peadrop.com> | 2010-01-09 22:14:46 (GMT) |
commit | a5c565a53493eefd9f0e531003bc2396e3cb726a (patch) | |
tree | 407e0072c1d10ac1003a4651a51095610ae887ed /Objects | |
parent | 0c0e229dd0a12eed81e08917339f2f11e12be96c (diff) | |
download | cpython-a5c565a53493eefd9f0e531003bc2396e3cb726a.zip cpython-a5c565a53493eefd9f0e531003bc2396e3cb726a.tar.gz cpython-a5c565a53493eefd9f0e531003bc2396e3cb726a.tar.bz2 |
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.
Diffstat (limited to 'Objects')
-rw-r--r-- | Objects/bytesobject.c | 59 |
1 files changed, 52 insertions, 7 deletions
diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index cb63448..eb11940 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -2979,17 +2979,62 @@ PyBytes_FromObject(PyObject *x) 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 */ - /* XXX(gb): is 64 a good value? also, optimize if length is known */ - /* XXX(guido): perhaps use Pysequence_Fast() -- I can't imagine the - input being a truly long iterator. */ - size = 64; + size = _PyObject_LengthHint(x, 64); + if (size == -1 && PyErr_Occurred()) + return NULL; + /* 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); if (new == NULL) return NULL; - /* XXX Optimize this if the arguments is a list, tuple */ - /* Get the iterator */ it = PyObject_GetIter(x); if (it == NULL) @@ -3023,7 +3068,7 @@ PyBytes_FromObject(PyObject *x) /* Append the byte */ if (i >= size) { - size *= 2; + size = 2 * size + 1; if (_PyBytes_Resize(&new, size) < 0) goto error; } |