summaryrefslogtreecommitdiffstats
path: root/Objects
diff options
context:
space:
mode:
authorAlexandre Vassalotti <alexandre@peadrop.com>2010-01-09 22:14:46 (GMT)
committerAlexandre Vassalotti <alexandre@peadrop.com>2010-01-09 22:14:46 (GMT)
commita5c565a53493eefd9f0e531003bc2396e3cb726a (patch)
tree407e0072c1d10ac1003a4651a51095610ae887ed /Objects
parent0c0e229dd0a12eed81e08917339f2f11e12be96c (diff)
downloadcpython-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.c59
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;
}