From d84ec225bdf88a8ad54c57b78beb6c32ae9fffde Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Sun, 24 Jan 2016 09:12:06 -0800 Subject: [PATCH] Miscellaneous refactorings * Add comment to the maxlen structure entry about the meaning of maxlen == -1 * Factor-out code common to deque_append(left) and deque_extend(left) * Factor inner-loop in deque_clear() to use only 1 test per loop instead of 2 * Tighten inner-loops for deque_item() and deque_ass_item() so that the compiler can combine the decrement and test into a single step. --- Modules/_collectionsmodule.c | 123 +++++++++++++++++------------------ 1 file changed, 58 insertions(+), 65 deletions(-) diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c index fbf07a87a56..3ab987daee8 100644 --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -81,7 +81,7 @@ typedef struct { Py_ssize_t leftindex; /* 0 <= leftindex < BLOCKLEN */ Py_ssize_t rightindex; /* 0 <= rightindex < BLOCKLEN */ size_t state; /* incremented whenever the indices move */ - Py_ssize_t maxlen; + Py_ssize_t maxlen; /* maxlen is -1 for unbounded deques */ PyObject *weakreflist; } dequeobject; @@ -264,13 +264,13 @@ PyDoc_STRVAR(popleft_doc, "Remove and return the leftmost element."); #define NEEDS_TRIM(deque, maxlen) ((size_t)(maxlen) < (size_t)(Py_SIZE(deque))) -static PyObject * -deque_append(dequeobject *deque, PyObject *item) +int +deque_append_internal(dequeobject *deque, PyObject *item, Py_ssize_t maxlen) { if (deque->rightindex == BLOCKLEN - 1) { block *b = newblock(); if (b == NULL) - return NULL; + return -1; b->leftlink = deque->rightblock; CHECK_END(deque->rightblock->rightlink); deque->rightblock->rightlink = b; @@ -279,27 +279,35 @@ deque_append(dequeobject *deque, PyObject *item) deque->rightindex = -1; } Py_SIZE(deque)++; - Py_INCREF(item); deque->rightindex++; deque->rightblock->data[deque->rightindex] = item; - if (NEEDS_TRIM(deque, deque->maxlen)) { + if (NEEDS_TRIM(deque, maxlen)) { PyObject *olditem = deque_popleft(deque, NULL); Py_DECREF(olditem); } else { deque->state++; } + return 0; +} + +static PyObject * +deque_append(dequeobject *deque, PyObject *item) +{ + Py_INCREF(item); + if (deque_append_internal(deque, item, deque->maxlen) < 0) + return NULL; Py_RETURN_NONE; } PyDoc_STRVAR(append_doc, "Add an element to the right side of the deque."); -static PyObject * -deque_appendleft(dequeobject *deque, PyObject *item) +int +deque_appendleft_internal(dequeobject *deque, PyObject *item, Py_ssize_t maxlen) { if (deque->leftindex == 0) { block *b = newblock(); if (b == NULL) - return NULL; + return -1; b->rightlink = deque->leftblock; CHECK_END(deque->leftblock->leftlink); deque->leftblock->leftlink = b; @@ -308,7 +316,6 @@ deque_appendleft(dequeobject *deque, PyObject *item) deque->leftindex = BLOCKLEN; } Py_SIZE(deque)++; - Py_INCREF(item); deque->leftindex--; deque->leftblock->data[deque->leftindex] = item; if (NEEDS_TRIM(deque, deque->maxlen)) { @@ -317,6 +324,15 @@ deque_appendleft(dequeobject *deque, PyObject *item) } else { deque->state++; } + return 0; +} + +static PyObject * +deque_appendleft(dequeobject *deque, PyObject *item) +{ + Py_INCREF(item); + if (deque_appendleft_internal(deque, item, deque->maxlen) < 0) + return NULL; Py_RETURN_NONE; } @@ -387,28 +403,10 @@ deque_extend(dequeobject *deque, PyObject *iterable) iternext = *Py_TYPE(it)->tp_iternext; while ((item = iternext(it)) != NULL) { - if (deque->rightindex == BLOCKLEN - 1) { - block *b = newblock(); - if (b == NULL) { - Py_DECREF(item); - Py_DECREF(it); - return NULL; - } - b->leftlink = deque->rightblock; - CHECK_END(deque->rightblock->rightlink); - deque->rightblock->rightlink = b; - deque->rightblock = b; - MARK_END(b->rightlink); - deque->rightindex = -1; - } - Py_SIZE(deque)++; - deque->rightindex++; - deque->rightblock->data[deque->rightindex] = item; - if (NEEDS_TRIM(deque, maxlen)) { - PyObject *olditem = deque_popleft(deque, NULL); - Py_DECREF(olditem); - } else { - deque->state++; + if (deque_append_internal(deque, item, maxlen) < 0) { + Py_DECREF(item); + Py_DECREF(it); + return NULL; } } return finalize_iterator(it); @@ -452,28 +450,10 @@ deque_extendleft(dequeobject *deque, PyObject *iterable) iternext = *Py_TYPE(it)->tp_iternext; while ((item = iternext(it)) != NULL) { - if (deque->leftindex == 0) { - block *b = newblock(); - if (b == NULL) { - Py_DECREF(item); - Py_DECREF(it); - return NULL; - } - b->rightlink = deque->leftblock; - CHECK_END(deque->leftblock->leftlink); - deque->leftblock->leftlink = b; - deque->leftblock = b; - MARK_END(b->leftlink); - deque->leftindex = BLOCKLEN; - } - Py_SIZE(deque)++; - deque->leftindex--; - deque->leftblock->data[deque->leftindex] = item; - if (NEEDS_TRIM(deque, maxlen)) { - PyObject *olditem = deque_pop(deque, NULL); - Py_DECREF(olditem); - } else { - deque->state++; + if (deque_appendleft_internal(deque, item, maxlen) < 0) { + Py_DECREF(item); + Py_DECREF(it); + return NULL; } } return finalize_iterator(it); @@ -565,8 +545,9 @@ deque_clear(dequeobject *deque) block *prevblock; block *leftblock; Py_ssize_t leftindex; - Py_ssize_t n; + Py_ssize_t n, m; PyObject *item; + PyObject **itemptr, **limit; if (Py_SIZE(deque) == 0) return; @@ -608,17 +589,25 @@ deque_clear(dequeobject *deque) /* Now the old size, leftblock, and leftindex are disconnected from the empty deque and we can use them to decref the pointers. */ - while (n--) { - item = leftblock->data[leftindex]; - Py_DECREF(item); - leftindex++; - if (leftindex == BLOCKLEN && n) { + itemptr = &leftblock->data[leftindex]; + m = (BLOCKLEN - leftindex > n) ? n : BLOCKLEN - leftindex; + limit = &leftblock->data[leftindex + m]; + n -= m; + while (1) { + if (itemptr == limit) { + if (n == 0) + break; CHECK_NOT_END(leftblock->rightlink); prevblock = leftblock; leftblock = leftblock->rightlink; - leftindex = 0; + itemptr = leftblock->data; + m = (n > BLOCKLEN) ? BLOCKLEN : n; + limit = &leftblock->data[m]; + n -= m; freeblock(prevblock); } + item = *(itemptr++); + Py_DECREF(item); } CHECK_END(leftblock->rightlink); freeblock(leftblock); @@ -1185,14 +1174,16 @@ deque_item(dequeobject *deque, Py_ssize_t i) i = (Py_ssize_t)((size_t) i % BLOCKLEN); if (index < (Py_SIZE(deque) >> 1)) { b = deque->leftblock; - while (n--) + n++; + while (--n) b = b->rightlink; } else { n = (Py_ssize_t)( ((size_t)(deque->leftindex + Py_SIZE(deque) - 1)) / BLOCKLEN - n); b = deque->rightblock; - while (n--) + n++; + while (--n) b = b->leftlink; } } @@ -1235,14 +1226,16 @@ deque_ass_item(dequeobject *deque, Py_ssize_t i, PyObject *v) i = (Py_ssize_t)((size_t) i % BLOCKLEN); if (index <= halflen) { b = deque->leftblock; - while (n--) + n++; + while (--n) b = b->rightlink; } else { n = (Py_ssize_t)( ((size_t)(deque->leftindex + Py_SIZE(deque) - 1)) / BLOCKLEN - n); b = deque->rightblock; - while (n--) + n++; + while (--n) b = b->leftlink; } Py_INCREF(v);