1818#define CENTER ((BLOCKLEN - 1) / 2)
1919
2020/* A `dequeobject` is composed of a doubly-linked list of `block` nodes.
21- * This list is not circular (the leftmost block has leftlink==NULL,
22- * and the rightmost block has rightlink==NULL). A deque d's first
23- * element is at d.leftblock[leftindex] and its last element is at
24- * d.rightblock[rightindex]; note that, unlike as for Python slice
25- * indices, these indices are inclusive on both ends. By being inclusive
26- * on both ends, algorithms for left and right operations become
27- * symmetrical which simplifies the design.
28- *
2921 * The list of blocks is never empty, so d.leftblock and d.rightblock
30- * are never equal to NULL.
22+ * are never equal to NULL. The list is not circular.
23+ *
24+ * A deque d's first element is at d.leftblock[leftindex]
25+ * and its last element is at d.rightblock[rightindex].
26+ * Unlike Python slice indices, these indices are inclusive
27+ * on both ends. This makes the algorithms for left and
28+ * right operations more symmetrical and simplifies the design.
3129 *
3230 * The indices, d.leftindex and d.rightindex are always in the range
3331 * 0 <= index < BLOCKLEN.
@@ -52,12 +50,38 @@ typedef struct BLOCK {
5250 struct BLOCK * rightlink ;
5351} block ;
5452
53+ /* For debug builds, add error checking to track the endpoints
54+ * in the chain of links. The goal is to make sure that link
55+ * assignments only take place at endpoints so that links already
56+ * in use do not get overwritten.
57+ *
58+ * CHECK_END should happen before each assignment to a block's link field.
59+ * MARK_END should happen whenever a link field becomes a new endpoint.
60+ * This happens when new blocks are added or whenever an existing
61+ * block is freed leaving another existing block as the new endpoint.
62+ */
63+
64+ #if Py_DEBUG
65+ #define MARK_END (link ) link = NULL;
66+ #define CHECK_END (link ) assert(link == NULL);
67+ #define CHECK_NOT_END (link ) assert(link != NULL);
68+ #else
69+ #define MARK_END (link )
70+ #define CHECK_END (link )
71+ #define CHECK_NOT_END (link )
72+ #endif
73+
74+ /* A simple freelisting scheme is used to minimize calls to the memory
75+ allocator. It accomodates common use cases where new blocks are being
76+ added at about the same rate as old blocks are being freed.
77+ */
78+
5579#define MAXFREEBLOCKS 10
5680static Py_ssize_t numfreeblocks = 0 ;
5781static block * freeblocks [MAXFREEBLOCKS ];
5882
5983static block *
60- newblock (block * leftlink , block * rightlink , Py_ssize_t len ) {
84+ newblock (Py_ssize_t len ) {
6185 block * b ;
6286 /* To prevent len from overflowing PY_SSIZE_T_MAX, we refuse to
6387 * allocate new blocks if the current len is nearing overflow. */
@@ -68,17 +92,14 @@ newblock(block *leftlink, block *rightlink, Py_ssize_t len) {
6892 }
6993 if (numfreeblocks ) {
7094 numfreeblocks -- ;
71- b = freeblocks [numfreeblocks ];
72- } else {
73- b = PyMem_Malloc (sizeof (block ));
74- if (b == NULL ) {
75- PyErr_NoMemory ();
76- return NULL ;
77- }
95+ return freeblocks [numfreeblocks ];
96+ }
97+ b = PyMem_Malloc (sizeof (block ));
98+ if (b != NULL ) {
99+ return b ;
78100 }
79- b -> leftlink = leftlink ;
80- b -> rightlink = rightlink ;
81- return b ;
101+ PyErr_NoMemory ();
102+ return NULL ;
82103}
83104
84105static void
@@ -132,11 +153,13 @@ deque_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
132153 if (deque == NULL )
133154 return NULL ;
134155
135- b = newblock (NULL , NULL , 0 );
156+ b = newblock (0 );
136157 if (b == NULL ) {
137158 Py_DECREF (deque );
138159 return NULL ;
139160 }
161+ MARK_END (b -> leftlink );
162+ MARK_END (b -> rightlink );
140163
141164 assert (BLOCKLEN >= 2 );
142165 deque -> leftblock = b ;
@@ -177,7 +200,8 @@ deque_pop(dequeobject *deque, PyObject *unused)
177200 prevblock = deque -> rightblock -> leftlink ;
178201 assert (deque -> leftblock != deque -> rightblock );
179202 freeblock (deque -> rightblock );
180- prevblock -> rightlink = NULL ;
203+ CHECK_NOT_END (prevblock );
204+ MARK_END (prevblock -> rightlink );
181205 deque -> rightblock = prevblock ;
182206 deque -> rightindex = BLOCKLEN - 1 ;
183207 }
@@ -214,8 +238,8 @@ deque_popleft(dequeobject *deque, PyObject *unused)
214238 assert (deque -> leftblock != deque -> rightblock );
215239 prevblock = deque -> leftblock -> rightlink ;
216240 freeblock (deque -> leftblock );
217- assert (prevblock != NULL );
218- prevblock -> leftlink = NULL ;
241+ CHECK_NOT_END (prevblock );
242+ MARK_END ( prevblock -> leftlink ) ;
219243 deque -> leftblock = prevblock ;
220244 deque -> leftindex = 0 ;
221245 }
@@ -230,12 +254,14 @@ deque_append(dequeobject *deque, PyObject *item)
230254{
231255 deque -> state ++ ;
232256 if (deque -> rightindex == BLOCKLEN - 1 ) {
233- block * b = newblock (deque -> rightblock , NULL , Py_SIZE (deque ));
257+ block * b = newblock (Py_SIZE (deque ));
234258 if (b == NULL )
235259 return NULL ;
236- assert (deque -> rightblock -> rightlink == NULL );
260+ b -> leftlink = deque -> rightblock ;
261+ CHECK_END (deque -> rightblock -> rightlink );
237262 deque -> rightblock -> rightlink = b ;
238263 deque -> rightblock = b ;
264+ MARK_END (b -> rightlink );
239265 deque -> rightindex = -1 ;
240266 }
241267 Py_INCREF (item );
@@ -253,12 +279,14 @@ deque_appendleft(dequeobject *deque, PyObject *item)
253279{
254280 deque -> state ++ ;
255281 if (deque -> leftindex == 0 ) {
256- block * b = newblock (NULL , deque -> leftblock , Py_SIZE (deque ));
282+ block * b = newblock (Py_SIZE (deque ));
257283 if (b == NULL )
258284 return NULL ;
259- assert (deque -> leftblock -> leftlink == NULL );
285+ b -> rightlink = deque -> leftblock ;
286+ CHECK_END (deque -> leftblock -> leftlink );
260287 deque -> leftblock -> leftlink = b ;
261288 deque -> leftblock = b ;
289+ MARK_END (b -> leftlink );
262290 deque -> leftindex = BLOCKLEN ;
263291 }
264292 Py_INCREF (item );
@@ -314,16 +342,17 @@ deque_extend(dequeobject *deque, PyObject *iterable)
314342 while ((item = PyIter_Next (it )) != NULL ) {
315343 deque -> state ++ ;
316344 if (deque -> rightindex == BLOCKLEN - 1 ) {
317- block * b = newblock (deque -> rightblock , NULL ,
318- Py_SIZE (deque ));
345+ block * b = newblock (Py_SIZE (deque ));
319346 if (b == NULL ) {
320347 Py_DECREF (item );
321348 Py_DECREF (it );
322349 return NULL ;
323350 }
324- assert (deque -> rightblock -> rightlink == NULL );
351+ b -> leftlink = deque -> rightblock ;
352+ CHECK_END (deque -> rightblock -> rightlink );
325353 deque -> rightblock -> rightlink = b ;
326354 deque -> rightblock = b ;
355+ MARK_END (b -> rightlink );
327356 deque -> rightindex = -1 ;
328357 }
329358 Py_SIZE (deque )++ ;
@@ -366,16 +395,17 @@ deque_extendleft(dequeobject *deque, PyObject *iterable)
366395 while ((item = PyIter_Next (it )) != NULL ) {
367396 deque -> state ++ ;
368397 if (deque -> leftindex == 0 ) {
369- block * b = newblock (NULL , deque -> leftblock ,
370- Py_SIZE (deque ));
398+ block * b = newblock (Py_SIZE (deque ));
371399 if (b == NULL ) {
372400 Py_DECREF (item );
373401 Py_DECREF (it );
374402 return NULL ;
375403 }
376- assert (deque -> leftblock -> leftlink == NULL );
404+ b -> rightlink = deque -> leftblock ;
405+ CHECK_END (deque -> leftblock -> leftlink );
377406 deque -> leftblock -> leftlink = b ;
378407 deque -> leftblock = b ;
408+ MARK_END (b -> leftlink );
379409 deque -> leftindex = BLOCKLEN ;
380410 }
381411 Py_SIZE (deque )++ ;
@@ -430,14 +460,16 @@ _deque_rotate(dequeobject *deque, Py_ssize_t n)
430460 deque -> state ++ ;
431461 while (n > 0 ) {
432462 if (leftindex == 0 ) {
433- block * b = newblock (NULL , leftblock , len );
463+ block * b = newblock (len );
434464 if (b == NULL ) {
435465 rv = -1 ;
436466 goto done ;
437467 }
438- assert (leftblock -> leftlink == NULL );
468+ b -> rightlink = leftblock ;
469+ CHECK_END (leftblock -> leftlink );
439470 leftblock -> leftlink = b ;
440471 leftblock = b ;
472+ MARK_END (b -> leftlink );
441473 leftindex = BLOCKLEN ;
442474 }
443475 assert (leftindex > 0 );
@@ -462,24 +494,26 @@ _deque_rotate(dequeobject *deque, Py_ssize_t n)
462494
463495 if (rightindex == -1 ) {
464496 block * prevblock = rightblock -> leftlink ;
465- assert (rightblock != NULL );
466497 assert (leftblock != rightblock );
467498 freeblock (rightblock );
468- prevblock -> rightlink = NULL ;
499+ CHECK_NOT_END (prevblock );
500+ MARK_END (prevblock -> rightlink );
469501 rightblock = prevblock ;
470502 rightindex = BLOCKLEN - 1 ;
471503 }
472504 }
473505 while (n < 0 ) {
474506 if (rightindex == BLOCKLEN - 1 ) {
475- block * b = newblock (rightblock , NULL , len );
507+ block * b = newblock (len );
476508 if (b == NULL ) {
477509 rv = -1 ;
478510 goto done ;
479511 }
480- assert (rightblock -> rightlink == NULL );
512+ b -> leftlink = rightblock ;
513+ CHECK_END (rightblock -> rightlink );
481514 rightblock -> rightlink = b ;
482515 rightblock = b ;
516+ MARK_END (b -> rightlink );
483517 rightindex = -1 ;
484518 }
485519 assert (rightindex < BLOCKLEN - 1 );
@@ -506,8 +540,8 @@ _deque_rotate(dequeobject *deque, Py_ssize_t n)
506540 block * nextblock = leftblock -> rightlink ;
507541 assert (leftblock != rightblock );
508542 freeblock (leftblock );
509- assert (nextblock != NULL );
510- nextblock -> leftlink = NULL ;
543+ CHECK_NOT_END (nextblock );
544+ MARK_END ( nextblock -> leftlink ) ;
511545 leftblock = nextblock ;
512546 leftindex = 0 ;
513547 }
@@ -550,8 +584,8 @@ deque_reverse(dequeobject *deque, PyObject *unused)
550584 for (i = 0 ; i < n ; i ++ ) {
551585 /* Validate that pointers haven't met in the middle */
552586 assert (leftblock != rightblock || leftindex < rightindex );
553- assert (leftblock != NULL );
554- assert (rightblock != NULL );
587+ CHECK_NOT_END (leftblock );
588+ CHECK_NOT_END (rightblock );
555589
556590 /* Swap */
557591 tmp = leftblock -> data [leftindex ];
@@ -591,7 +625,7 @@ deque_count(dequeobject *deque, PyObject *v)
591625 int cmp ;
592626
593627 for (i = 0 ; i < n ; i ++ ) {
594- assert ( b != NULL );
628+ CHECK_NOT_END ( b );
595629 item = b -> data [index ];
596630 cmp = PyObject_RichCompareBool (item , v , Py_EQ );
597631 if (cmp > 0 )
@@ -1199,7 +1233,7 @@ dequeiter_next(dequeiterobject *it)
11991233 it -> index ++ ;
12001234 it -> counter -- ;
12011235 if (it -> index == BLOCKLEN && it -> counter > 0 ) {
1202- assert (it -> b -> rightlink != NULL );
1236+ CHECK_NOT_END (it -> b -> rightlink );
12031237 it -> b = it -> b -> rightlink ;
12041238 it -> index = 0 ;
12051239 }
@@ -1341,7 +1375,7 @@ dequereviter_next(dequeiterobject *it)
13411375 it -> index -- ;
13421376 it -> counter -- ;
13431377 if (it -> index == -1 && it -> counter > 0 ) {
1344- assert (it -> b -> leftlink != NULL );
1378+ CHECK_NOT_END (it -> b -> leftlink );
13451379 it -> b = it -> b -> leftlink ;
13461380 it -> index = BLOCKLEN - 1 ;
13471381 }
0 commit comments