[Python-checkins] cpython: Improve and fix-up comments.

raymond.hettinger python-checkins at python.org
Tue Mar 24 08:20:02 CET 2015


https://hg.python.org/cpython/rev/8ddd8b5705b9
changeset:   95148:8ddd8b5705b9
user:        Raymond Hettinger <python at rcn.com>
date:        Tue Mar 24 00:19:53 2015 -0700
summary:
  Improve and fix-up comments.

files:
  Modules/_collectionsmodule.c |  71 +++++++++++++++--------
  1 files changed, 46 insertions(+), 25 deletions(-)


diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c
--- a/Modules/_collectionsmodule.c
+++ b/Modules/_collectionsmodule.c
@@ -23,31 +23,51 @@
 #define BLOCKLEN 64
 #define CENTER ((BLOCKLEN - 1) / 2)
 
-/* A `dequeobject` is composed of a doubly-linked list of `block` nodes.
+/* Data for deque objects is stored in a doubly-linked list of fixed
+ * length blocks.  This assures that appends or pops never move any
+ * other data elements besides the one being appended or popped.
+ *
+ * Another advantage is that it completely avoids use of realloc(),
+ * resulting in more predictable performance.
+ *
+ * Textbook implementations of doubly-linked lists store one datum
+ * per link, but that gives them a 200% memory overhead (a prev and
+ * next link for each datum) and it costs one malloc() call per data
+ * element.  By using fixed-length blocks, the link to data ratio is
+ * significantly improved and there are proportionally fewer calls
+ * to malloc() and free().  The data blocks of consecutive pointers
+ * also improve cache locality.
+ *
  * The list of blocks is never empty, so d.leftblock and d.rightblock
  * are never equal to NULL.  The list is not circular.
  *
  * A deque d's first element is at d.leftblock[leftindex]
  * and its last element is at d.rightblock[rightindex].
- * Unlike Python slice indices, these indices are inclusive
- * on both ends.  This makes the algorithms for left and
- * right operations more symmetrical and simplifies the design.
  *
- * The indices, d.leftindex and d.rightindex are always in the range
- *     0 <= index < BLOCKLEN.
- * Their exact relationship is:
- *     (d.leftindex + d.len - 1) % BLOCKLEN == d.rightindex.
+ * Unlike Python slice indices, these indices are inclusive on both
+ * ends.  This makes the algorithms for left and right operations
+ * more symmetrical and it simplifies the design.
  *
- * Empty deques have d.len == 0; d.leftblock==d.rightblock;
- * d.leftindex == CENTER+1; and d.rightindex == CENTER.
- * Checking for d.len == 0 is the intended way to see whether d is empty.
+ * The indices, d.leftindex and d.rightindex are always in the range:
+ *     0 <= index < BLOCKLEN
+ *
+ * And their exact relationship is:
+ *     (d.leftindex + d.len - 1) % BLOCKLEN == d.rightindex
  *
  * Whenever d.leftblock == d.rightblock,
- *     d.leftindex + d.len - 1 == d.rightindex.
+ *     d.leftindex + d.len - 1 == d.rightindex
  *
- * However, when d.leftblock != d.rightblock, d.leftindex and d.rightindex
- * become indices into distinct blocks and either may be larger than the
- * other.
+ * However, when d.leftblock != d.rightblock, the d.leftindex and
+ * d.rightindex become indices into distinct blocks and either may
+ * be larger than the other.
+ *
+ * Empty deques have:
+ *     d.len == 0
+ *     d.leftblock == d.rightblock
+ *     d.leftindex == CENTER + 1
+ *     d.rightindex == CENTER
+ *
+ * Checking for d.len == 0 is the intended way to see whether d is empty.
  */
 
 typedef struct BLOCK {
@@ -60,8 +80,8 @@
     PyObject_VAR_HEAD
     block *leftblock;
     block *rightblock;
-    Py_ssize_t leftindex;       /* in range(BLOCKLEN) */
-    Py_ssize_t rightindex;      /* in range(BLOCKLEN) */
+    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;
     PyObject *weakreflist;
@@ -91,7 +111,7 @@
 #endif
 
 /* A simple freelisting scheme is used to minimize calls to the memory
-   allocator.  It accomodates common use cases where new blocks are being
+   allocator.  It accommodates common use cases where new blocks are being
    added at about the same rate as old blocks are being freed.
  */
 
@@ -816,6 +836,14 @@
 "D.index(value, [start, [stop]]) -> integer -- return first index of value.\n"
 "Raises ValueError if the value is not present.");
 
+/* insert(), remove(), and delitem() are implemented in terms of
+   rotate() for simplicity and reasonable performance near the end
+   points.  If for some reason these methods become popular, it is not
+   hard to re-implement this using direct data movement (similar to
+   the code used in list slice assignments) and achieve a performance
+   boost (by moving each pointer only one instead of twice).
+*/
+
 static PyObject *
 deque_insert(dequeobject *deque, PyObject *args)
 {
@@ -945,13 +973,6 @@
     return item;
 }
 
-/* delitem() implemented in terms of rotate for simplicity and reasonable
-   performance near the end points.  If for some reason this method becomes
-   popular, it is not hard to re-implement this using direct data movement
-   (similar to code in list slice assignment) and achieve a two or threefold
-   performance boost.
-*/
-
 static int
 deque_del_item(dequeobject *deque, Py_ssize_t i)
 {

-- 
Repository URL: https://hg.python.org/cpython


More information about the Python-checkins mailing list