#define BLOCKLEN 64
#define CENTER ((BLOCKLEN - 1) / 2)
+#define MAXFREEBLOCKS 16
/* Data for deque objects is stored in a doubly-linked list of fixed
* length blocks. This assures that appends or pops never move any
Py_ssize_t rightindex; /* 0 <= rightindex < BLOCKLEN */
size_t state; /* incremented whenever the indices move */
Py_ssize_t maxlen; /* maxlen is -1 for unbounded deques */
+ Py_ssize_t numfreeblocks;
+ block *freeblocks[MAXFREEBLOCKS];
PyObject *weakreflist;
} dequeobject;
added at about the same rate as old blocks are being freed.
*/
-#define MAXFREEBLOCKS 16
-static Py_ssize_t numfreeblocks = 0;
-static block *freeblocks[MAXFREEBLOCKS];
-
-static block *
-newblock(void) {
+static inline block *
+newblock(dequeobject *deque) {
block *b;
- if (numfreeblocks) {
- numfreeblocks--;
- return freeblocks[numfreeblocks];
+ if (deque->numfreeblocks) {
+ deque->numfreeblocks--;
+ return deque->freeblocks[deque->numfreeblocks];
}
b = PyMem_Malloc(sizeof(block));
if (b != NULL) {
return NULL;
}
-static void
-freeblock(block *b)
+static inline void
+freeblock(dequeobject *deque, block *b)
{
- if (numfreeblocks < MAXFREEBLOCKS) {
- freeblocks[numfreeblocks] = b;
- numfreeblocks++;
+ if (deque->numfreeblocks < MAXFREEBLOCKS) {
+ deque->freeblocks[deque->numfreeblocks] = b;
+ deque->numfreeblocks++;
} else {
PyMem_Free(b);
}
if (deque == NULL)
return NULL;
- b = newblock();
+ b = newblock(deque);
if (b == NULL) {
Py_DECREF(deque);
return NULL;
deque->rightindex = CENTER;
deque->state = 0;
deque->maxlen = -1;
+ deque->numfreeblocks = 0;
deque->weakreflist = NULL;
return (PyObject *)deque;
if (Py_SIZE(deque)) {
prevblock = deque->rightblock->leftlink;
assert(deque->leftblock != deque->rightblock);
- freeblock(deque->rightblock);
+ freeblock(deque, deque->rightblock);
CHECK_NOT_END(prevblock);
MARK_END(prevblock->rightlink);
deque->rightblock = prevblock;
if (Py_SIZE(deque)) {
assert(deque->leftblock != deque->rightblock);
prevblock = deque->leftblock->rightlink;
- freeblock(deque->leftblock);
+ freeblock(deque, deque->leftblock);
CHECK_NOT_END(prevblock);
MARK_END(prevblock->leftlink);
deque->leftblock = prevblock;
deque_append_internal(dequeobject *deque, PyObject *item, Py_ssize_t maxlen)
{
if (deque->rightindex == BLOCKLEN - 1) {
- block *b = newblock();
+ block *b = newblock(deque);
if (b == NULL)
return -1;
b->leftlink = deque->rightblock;
deque_appendleft_internal(dequeobject *deque, PyObject *item, Py_ssize_t maxlen)
{
if (deque->leftindex == 0) {
- block *b = newblock();
+ block *b = newblock(deque);
if (b == NULL)
return -1;
b->rightlink = deque->leftblock;
adversary could cause it to never terminate).
*/
- b = newblock();
+ b = newblock(deque);
if (b == NULL) {
PyErr_Clear();
goto alternate_method;
itemptr = leftblock->data;
limit = itemptr + m;
n -= m;
- freeblock(prevblock);
+ freeblock(deque, prevblock);
}
item = *(itemptr++);
Py_DECREF(item);
}
CHECK_END(leftblock->rightlink);
- freeblock(leftblock);
+ freeblock(deque, leftblock);
return 0;
alternate_method:
deque->state++;
for (i = 0 ; i < n-1 ; ) {
if (deque->rightindex == BLOCKLEN - 1) {
- block *b = newblock();
+ block *b = newblock(deque);
if (b == NULL) {
Py_SET_SIZE(deque, Py_SIZE(deque) + i);
return NULL;
while (n > 0) {
if (leftindex == 0) {
if (b == NULL) {
- b = newblock();
+ b = newblock(deque);
if (b == NULL)
goto done;
}
while (n < 0) {
if (rightindex == BLOCKLEN - 1) {
if (b == NULL) {
- b = newblock();
+ b = newblock(deque);
if (b == NULL)
goto done;
}
rv = 0;
done:
if (b != NULL)
- freeblock(b);
+ freeblock(deque, b);
deque->leftblock = leftblock;
deque->rightblock = rightblock;
deque->leftindex = leftindex;
static void
deque_dealloc(dequeobject *deque)
{
+ Py_ssize_t i;
+
PyObject_GC_UnTrack(deque);
if (deque->weakreflist != NULL)
PyObject_ClearWeakRefs((PyObject *) deque);
if (deque->leftblock != NULL) {
deque_clear(deque);
assert(deque->leftblock != NULL);
- freeblock(deque->leftblock);
+ freeblock(deque, deque->leftblock);
}
deque->leftblock = NULL;
deque->rightblock = NULL;
+ for (i=0 ; i < deque->numfreeblocks ; i++) {
+ PyMem_Free(deque->freeblocks[i]);
+ }
Py_TYPE(deque)->tp_free(deque);
}