Optimize tuple_slice() and make further improvements to list_slice()

and list.extend().  Factoring the inner loops to remove the constant
structure references and fixed offsets gives speedups ranging from
20% to 30%.
This commit is contained in:
Raymond Hettinger 2004-03-08 07:25:05 +00:00
parent f0e3569a28
commit b7d05db0be
3 changed files with 28 additions and 18 deletions

View file

@ -263,6 +263,9 @@ yellow 5
\begin{itemize} \begin{itemize}
\item The inner loops for \class{list} and \class{tuple} slicing
were optimized and now run about one-third faster.
\item The machinery for growing and shrinking lists was optimized \item The machinery for growing and shrinking lists was optimized
for speed and for space efficiency. Small lists (under eight elements) for speed and for space efficiency. Small lists (under eight elements)
never over-allocate by more than three elements. Large lists do not never over-allocate by more than three elements. Large lists do not

View file

@ -342,6 +342,7 @@ static PyObject *
list_slice(PyListObject *a, int ilow, int ihigh) list_slice(PyListObject *a, int ilow, int ihigh)
{ {
PyListObject *np; PyListObject *np;
PyObject **src, **dest;
int i, len; int i, len;
if (ilow < 0) if (ilow < 0)
ilow = 0; ilow = 0;
@ -356,10 +357,12 @@ list_slice(PyListObject *a, int ilow, int ihigh)
if (np == NULL) if (np == NULL)
return NULL; return NULL;
src = a->ob_item + ilow;
dest = np->ob_item;
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
PyObject *v = a->ob_item[i+ilow]; PyObject *v = src[i];
Py_INCREF(v); Py_INCREF(v);
np->ob_item[i] = v; dest[i] = v;
} }
return (PyObject *)np; return (PyObject *)np;
} }
@ -646,6 +649,7 @@ listextend_internal(PyListObject *self, PyObject *b)
register int selflen = PyList_GET_SIZE(self); register int selflen = PyList_GET_SIZE(self);
int blen; int blen;
register int i; register int i;
PyObject **src, **dest;
if (PyObject_Size(b) == 0) { if (PyObject_Size(b) == 0) {
/* short circuit when b is empty */ /* short circuit when b is empty */
@ -678,19 +682,17 @@ listextend_internal(PyListObject *self, PyObject *b)
} }
/* populate the end of self with b's items */ /* populate the end of self with b's items */
if (PyList_Check(b)) { if (PyList_Check(b))
for (i = 0; i < blen; i++) { src = ((PyListObject *)b)->ob_item;
PyObject *o = PyList_GET_ITEM(b, i); else {
Py_INCREF(o);
PyList_SET_ITEM(self, i+selflen, o);
}
} else {
assert (PyTuple_Check(b)); assert (PyTuple_Check(b));
for (i = 0; i < blen; i++) { src = ((PyTupleObject *)b)->ob_item;
PyObject *o = PyTuple_GET_ITEM(b, i);
Py_INCREF(o);
PyList_SET_ITEM(self, i+selflen, o);
} }
dest = self->ob_item + selflen;
for (i = 0; i < blen; i++) {
PyObject *o = src[i];
Py_INCREF(o);
dest[i] = o;
} }
Py_DECREF(b); Py_DECREF(b);
return 0; return 0;

View file

@ -306,7 +306,9 @@ static PyObject *
tupleslice(register PyTupleObject *a, register int ilow, register int ihigh) tupleslice(register PyTupleObject *a, register int ilow, register int ihigh)
{ {
register PyTupleObject *np; register PyTupleObject *np;
PyObject **src, **dest;
register int i; register int i;
int len;
if (ilow < 0) if (ilow < 0)
ilow = 0; ilow = 0;
if (ihigh > a->ob_size) if (ihigh > a->ob_size)
@ -317,13 +319,16 @@ tupleslice(register PyTupleObject *a, register int ilow, register int ihigh)
Py_INCREF(a); Py_INCREF(a);
return (PyObject *)a; return (PyObject *)a;
} }
np = (PyTupleObject *)PyTuple_New(ihigh - ilow); len = ihigh - ilow;
np = (PyTupleObject *)PyTuple_New(len);
if (np == NULL) if (np == NULL)
return NULL; return NULL;
for (i = ilow; i < ihigh; i++) { src = a->ob_item + ilow;
PyObject *v = a->ob_item[i]; dest = np->ob_item;
for (i = 0; i < len; i++) {
PyObject *v = src[i];
Py_INCREF(v); Py_INCREF(v);
np->ob_item[i - ilow] = v; dest[i] = v;
} }
return (PyObject *)np; return (PyObject *)np;
} }