#1569291: speed up array.repeat() by making only O(log n) memcpy() calls; the code follows unicode_repeat.

This commit is contained in:
Georg Brandl 2010-12-04 11:02:04 +00:00
parent 9d8711964f
commit c29cc6a8f2
3 changed files with 25 additions and 9 deletions

View File

@ -504,6 +504,12 @@ class BaseTest(unittest.TestCase):
array.array(self.typecode) array.array(self.typecode)
) )
a = 5 * array.array(self.typecode, self.example[:1])
self.assertEqual(
a,
array.array(self.typecode, [a[0]] * 5)
)
self.assertRaises(TypeError, a.__mul__, "bad") self.assertRaises(TypeError, a.__mul__, "bad")
def test_imul(self): def test_imul(self):

View File

@ -45,6 +45,8 @@ Core and Builtins
Library Library
------- -------
- Issue #1569291: Speed up array.repeat().
- Provide an interface to set the optimization level of compilation in - Provide an interface to set the optimization level of compilation in
py_compile, compileall and zipfile.PyZipFile. py_compile, compileall and zipfile.PyZipFile.

View File

@ -674,11 +674,9 @@ array_concat(arrayobject *a, PyObject *bb)
static PyObject * static PyObject *
array_repeat(arrayobject *a, Py_ssize_t n) array_repeat(arrayobject *a, Py_ssize_t n)
{ {
Py_ssize_t i;
Py_ssize_t size; Py_ssize_t size;
arrayobject *np; arrayobject *np;
char *p; Py_ssize_t oldbytes, newbytes;
Py_ssize_t nbytes;
if (n < 0) if (n < 0)
n = 0; n = 0;
if ((Py_SIZE(a) != 0) && (n > PY_SSIZE_T_MAX / Py_SIZE(a))) { if ((Py_SIZE(a) != 0) && (n > PY_SSIZE_T_MAX / Py_SIZE(a))) {
@ -688,11 +686,21 @@ array_repeat(arrayobject *a, Py_ssize_t n)
np = (arrayobject *) newarrayobject(&Arraytype, size, a->ob_descr); np = (arrayobject *) newarrayobject(&Arraytype, size, a->ob_descr);
if (np == NULL) if (np == NULL)
return NULL; return NULL;
p = np->ob_item; if (n == 0)
nbytes = Py_SIZE(a) * a->ob_descr->itemsize; return (PyObject *)np;
for (i = 0; i < n; i++) { oldbytes = Py_SIZE(a) * a->ob_descr->itemsize;
memcpy(p, a->ob_item, nbytes); newbytes = oldbytes * n;
p += nbytes; /* this follows the code in unicode_repeat */
if (oldbytes == 1) {
memset(np->ob_item, a->ob_item[0], newbytes);
} else {
Py_ssize_t done = oldbytes;
Py_MEMCPY(np->ob_item, a->ob_item, oldbytes);
while (done < newbytes) {
Py_ssize_t ncopy = (done <= newbytes-done) ? done : newbytes-done;
Py_MEMCPY(np->ob_item+done, np->ob_item, ncopy);
done += ncopy;
}
} }
return (PyObject *)np; return (PyObject *)np;
} }