2323#define BLOCKLEN 64
2424#define CENTER ((BLOCKLEN - 1) / 2)
2525
26- /* A `dequeobject` is composed of a doubly-linked list of `block` nodes.
26+ /* Data for deque objects is stored in a doubly-linked list of fixed
27+ * length blocks. This assures that appends or pops never move any
28+ * other data elements besides the one being appended or popped.
29+ *
30+ * Another advantage is that it completely avoids use of realloc(),
31+ * resulting in more predictable performance.
32+ *
33+ * Textbook implementations of doubly-linked lists store one datum
34+ * per link, but that gives them a 200% memory overhead (a prev and
35+ * next link for each datum) and it costs one malloc() call per data
36+ * element. By using fixed-length blocks, the link to data ratio is
37+ * significantly improved and there are proportionally fewer calls
38+ * to malloc() and free(). The data blocks of consecutive pointers
39+ * also improve cache locality.
40+ *
2741 * The list of blocks is never empty, so d.leftblock and d.rightblock
2842 * are never equal to NULL. The list is not circular.
2943 *
3044 * A deque d's first element is at d.leftblock[leftindex]
3145 * and its last element is at d.rightblock[rightindex].
32- * Unlike Python slice indices, these indices are inclusive
33- * on both ends. This makes the algorithms for left and
34- * right operations more symmetrical and simplifies the design.
3546 *
36- * The indices, d.leftindex and d.rightindex are always in the range
37- * 0 <= index < BLOCKLEN.
38- * Their exact relationship is:
39- * (d.leftindex + d.len - 1) % BLOCKLEN == d.rightindex.
47+ * Unlike Python slice indices, these indices are inclusive on both
48+ * ends. This makes the algorithms for left and right operations
49+ * more symmetrical and it simplifies the design.
4050 *
41- * Empty deques have d.len == 0; d.leftblock==d.rightblock;
42- * d.leftindex == CENTER+1; and d.rightindex == CENTER.
43- * Checking for d.len == 0 is the intended way to see whether d is empty.
51+ * The indices, d.leftindex and d.rightindex are always in the range:
52+ * 0 <= index < BLOCKLEN
53+ *
54+ * And their exact relationship is:
55+ * (d.leftindex + d.len - 1) % BLOCKLEN == d.rightindex
4456 *
4557 * Whenever d.leftblock == d.rightblock,
46- * d.leftindex + d.len - 1 == d.rightindex.
58+ * d.leftindex + d.len - 1 == d.rightindex
59+ *
60+ * However, when d.leftblock != d.rightblock, the d.leftindex and
61+ * d.rightindex become indices into distinct blocks and either may
62+ * be larger than the other.
4763 *
48- * However, when d.leftblock != d.rightblock, d.leftindex and d.rightindex
49- * become indices into distinct blocks and either may be larger than the
50- * other.
64+ * Empty deques have:
65+ * d.len == 0
66+ * d.leftblock == d.rightblock
67+ * d.leftindex == CENTER + 1
68+ * d.rightindex == CENTER
69+ *
70+ * Checking for d.len == 0 is the intended way to see whether d is empty.
5171 */
5272
5373typedef struct BLOCK {
@@ -60,8 +80,8 @@ typedef struct {
6080 PyObject_VAR_HEAD
6181 block * leftblock ;
6282 block * rightblock ;
63- Py_ssize_t leftindex ; /* in range( BLOCKLEN) */
64- Py_ssize_t rightindex ; /* in range( BLOCKLEN) */
83+ Py_ssize_t leftindex ; /* 0 <= leftindex < BLOCKLEN */
84+ Py_ssize_t rightindex ; /* 0 <= rightindex < BLOCKLEN */
6585 size_t state ; /* incremented whenever the indices move */
6686 Py_ssize_t maxlen ;
6787 PyObject * weakreflist ;
@@ -91,7 +111,7 @@ static PyTypeObject deque_type;
91111#endif
92112
93113/* A simple freelisting scheme is used to minimize calls to the memory
94- allocator. It accomodates common use cases where new blocks are being
114+ allocator. It accommodates common use cases where new blocks are being
95115 added at about the same rate as old blocks are being freed.
96116 */
97117
@@ -816,6 +836,14 @@ PyDoc_STRVAR(index_doc,
816836"D.index(value, [start, [stop]]) -> integer -- return first index of value.\n"
817837"Raises ValueError if the value is not present." );
818838
839+ /* insert(), remove(), and delitem() are implemented in terms of
840+ rotate() for simplicity and reasonable performance near the end
841+ points. If for some reason these methods become popular, it is not
842+ hard to re-implement this using direct data movement (similar to
843+ the code used in list slice assignments) and achieve a performance
844+ boost (by moving each pointer only one instead of twice).
845+ */
846+
819847static PyObject *
820848deque_insert (dequeobject * deque , PyObject * args )
821849{
@@ -945,13 +973,6 @@ deque_item(dequeobject *deque, Py_ssize_t i)
945973 return item ;
946974}
947975
948- /* delitem() implemented in terms of rotate for simplicity and reasonable
949- performance near the end points. If for some reason this method becomes
950- popular, it is not hard to re-implement this using direct data movement
951- (similar to code in list slice assignment) and achieve a two or threefold
952- performance boost.
953- */
954-
955976static int
956977deque_del_item (dequeobject * deque , Py_ssize_t i )
957978{
0 commit comments