Issue #16398: Optimize deque.rotate()

This commit is contained in:
Raymond Hettinger 2013-01-12 00:05:00 -08:00
parent 92e2fc8360
commit 2cdb6435d6
2 changed files with 61 additions and 14 deletions

View File

@ -189,6 +189,9 @@ Library
- Issue #13899: \A, \Z, and \B now correctly match the A, Z, and B literals - Issue #13899: \A, \Z, and \B now correctly match the A, Z, and B literals
when used inside character classes (e.g. '[\A]'). Patch by Matthew Barnett. when used inside character classes (e.g. '[\A]'). Patch by Matthew Barnett.
- Issue #16398: Optimize deque.rotate() so that it only moves pointers
and doesn't touch the underlying data with increfs and decrefs.
- Issue #15109: Fix regression in sqlite3's iterdump method where it would - Issue #15109: Fix regression in sqlite3's iterdump method where it would
die with an encoding error if the database contained string values die with an encoding error if the database contained string values
containing non-ASCII. (Regression was introduced by fix for 9750). containing non-ASCII. (Regression was introduced by fix for 9750).

View File

@ -414,9 +414,10 @@ static int
_deque_rotate(dequeobject *deque, Py_ssize_t n) _deque_rotate(dequeobject *deque, Py_ssize_t n)
{ {
Py_ssize_t i, len=deque->len, halflen=(len+1)>>1; Py_ssize_t i, len=deque->len, halflen=(len+1)>>1;
PyObject *item, *rv; PyObject *item;
block *prevblock, *leftblock, *rightblock;
if (len == 0) if (len <= 1)
return 0; return 0;
if (n > halflen || n < -halflen) { if (n > halflen || n < -halflen) {
n %= len; n %= len;
@ -426,23 +427,66 @@ _deque_rotate(dequeobject *deque, Py_ssize_t n)
n += len; n += len;
} }
assert(deque->len > 1);
deque->state++;
leftblock = deque->leftblock;
rightblock = deque->rightblock;
for (i=0 ; i<n ; i++) { for (i=0 ; i<n ; i++) {
item = deque_pop(deque, NULL); item = rightblock->data[deque->rightindex];
assert (item != NULL); assert (item != NULL);
rv = deque_appendleft(deque, item); deque->rightindex--;
Py_DECREF(item); if (deque->rightindex == -1) {
if (rv == NULL) assert(rightblock != NULL);
return -1; prevblock = rightblock->leftlink;
Py_DECREF(rv); assert(leftblock != rightblock);
freeblock(rightblock);
prevblock->rightlink = NULL;
deque->rightblock = rightblock = prevblock;
deque->rightindex = BLOCKLEN - 1;
}
if (deque->leftindex == 0) {
block *b = newblock(NULL, leftblock, deque->len);
if (b == NULL) {
deque->len--;
Py_DECREF(item);
return -1;
}
assert(leftblock->leftlink == NULL);
leftblock->leftlink = b;
deque->leftblock = leftblock = b;
deque->leftindex = BLOCKLEN;
}
deque->leftindex--;
leftblock->data[deque->leftindex] = item;
} }
for (i=0 ; i>n ; i--) { for (i=0 ; i>n ; i--) {
item = deque_popleft(deque, NULL); assert(leftblock != NULL);
item = leftblock->data[deque->leftindex];
assert (item != NULL); assert (item != NULL);
rv = deque_append(deque, item); deque->leftindex++;
Py_DECREF(item); if (deque->leftindex == BLOCKLEN) {
if (rv == NULL) assert(leftblock != rightblock);
return -1; prevblock = leftblock->rightlink;
Py_DECREF(rv); freeblock(leftblock);
assert(prevblock != NULL);
prevblock->leftlink = NULL;
deque->leftblock = leftblock = prevblock;
deque->leftindex = 0;
}
if (deque->rightindex == BLOCKLEN-1) {
block *b = newblock(rightblock, NULL, deque->len);
if (b == NULL) {
deque->len--;
Py_DECREF(item);
return -1;
}
assert(rightblock->rightlink == NULL);
rightblock->rightlink = b;
deque->rightblock = rightblock = b;
deque->rightindex = -1;
}
deque->rightindex++;
rightblock->data[deque->rightindex] = item;
} }
return 0; return 0;
} }