Commit efd43a34 authored by Raymond Hettinger's avatar Raymond Hettinger

Issue #16398: Optimize deque.rotate()

parent 578684aa
...@@ -189,6 +189,9 @@ Library ...@@ -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).
......
...@@ -414,9 +414,10 @@ static int ...@@ -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) ...@@ -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;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment