[Python-checkins] python/dist/src/Modules collectionsmodule.c, 1.31, 1.32

arigo at users.sourceforge.net arigo at users.sourceforge.net
Sat Oct 2 15:59:36 CEST 2004


Update of /cvsroot/python/python/dist/src/Modules
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv2501/Modules

Modified Files:
	collectionsmodule.c 
Log Message:
Upon insertion, if memory runs out, the deque was left in a corrupted state.

deque_item(): a performance bug: the linked list of blocks was followed
from the left in most cases, because the test (i < (deque->len >> 1)) was
after "i %= BLOCKLEN".

deque_clear(): replaced a call to deque_len() with deque->len; not sure what
this call was here for, nor if all compilers under the sun would inline it.

deque_traverse(): I belive that it could be called by the GC when the deque
has leftblock==rightblock==NULL, because it is tracked before the first block
is allocated (though closely before).  Still, a C extension module subclassing
deque could provide its own tp_alloc that could trigger a GC collection after
the PyObject_GC_Track()...

deque_richcompare(): rewrote to cleanly check for end-of-iterations instead of
relying on deque.__iter__().next() to succeed exactly len(deque) times -- an
assumption which can break if deques are subclassed.  Added a test.

I wonder if the length should be explicitely bounded to INT_MAX, with
OverflowErrors, as in listobject.c.  On 64-bit machines, adding more than
INT_MAX in the deque will result in trouble.  (Note to anyone/me fixing
this: carefully check for overflows if len is close to INT_MAX in the
following functions: deque_rotate(), deque_item(), deque_ass_item())


Index: collectionsmodule.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Modules/collectionsmodule.c,v
retrieving revision 1.31
retrieving revision 1.32
diff -u -d -r1.31 -r1.32
--- collectionsmodule.c	2 Oct 2004 00:43:13 -0000	1.31
+++ collectionsmodule.c	2 Oct 2004 13:59:33 -0000	1.32
@@ -108,19 +108,19 @@
 static PyObject *
 deque_append(dequeobject *deque, PyObject *item)
 {
-	deque->rightindex++;
-	deque->len++;
 	deque->state++;
-	if (deque->rightindex == BLOCKLEN) {
+	if (deque->rightindex == BLOCKLEN-1) {
 		block *b = newblock(deque->rightblock, NULL);
 		if (b == NULL)
 			return NULL;
 		assert(deque->rightblock->rightlink == NULL);
 		deque->rightblock->rightlink = b;
 		deque->rightblock = b;
-		deque->rightindex = 0;
+		deque->rightindex = -1;
 	}
 	Py_INCREF(item);
+	deque->len++;
+	deque->rightindex++;
 	deque->rightblock->data[deque->rightindex] = item;
 	Py_RETURN_NONE;
 }
@@ -130,19 +130,19 @@
 static PyObject *
 deque_appendleft(dequeobject *deque, PyObject *item)
 {
-	deque->leftindex--;
-	deque->len++;
 	deque->state++;
-	if (deque->leftindex == -1) {
+	if (deque->leftindex == 0) {
 		block *b = newblock(NULL, deque->leftblock);
 		if (b == NULL)
 			return NULL;
 		assert(deque->leftblock->leftlink == NULL);
 		deque->leftblock->leftlink = b;
 		deque->leftblock = b;
-		deque->leftindex = BLOCKLEN - 1;
+		deque->leftindex = BLOCKLEN;
 	}
 	Py_INCREF(item);
+	deque->len++;
+	deque->leftindex--;
 	deque->leftblock->data[deque->leftindex] = item;
 	Py_RETURN_NONE;
 }
@@ -233,10 +233,8 @@
 		return NULL;
 
 	while ((item = PyIter_Next(it)) != NULL) {
-		deque->rightindex++;
-		deque->len++;
 		deque->state++;
-		if (deque->rightindex == BLOCKLEN) {
+		if (deque->rightindex == BLOCKLEN-1) {
 			block *b = newblock(deque->rightblock, NULL);
 			if (b == NULL) {
 				Py_DECREF(item);
@@ -246,8 +244,10 @@
 			assert(deque->rightblock->rightlink == NULL);
 			deque->rightblock->rightlink = b;
 			deque->rightblock = b;
-			deque->rightindex = 0;
+			deque->rightindex = -1;
 		}
+		deque->len++;
+		deque->rightindex++;
 		deque->rightblock->data[deque->rightindex] = item;
 	}
 	Py_DECREF(it);
@@ -269,10 +269,8 @@
 		return NULL;
 
 	while ((item = PyIter_Next(it)) != NULL) {
-		deque->leftindex--;
-		deque->len++;
 		deque->state++;
-		if (deque->leftindex == -1) {
+		if (deque->leftindex == 0) {
 			block *b = newblock(NULL, deque->leftblock);
 			if (b == NULL) {
 				Py_DECREF(item);
@@ -282,8 +280,10 @@
 			assert(deque->leftblock->leftlink == NULL);
 			deque->leftblock->leftlink = b;
 			deque->leftblock = b;
-			deque->leftindex = BLOCKLEN - 1;
+			deque->leftindex = BLOCKLEN;
 		}
+		deque->len++;
+		deque->leftindex--;
 		deque->leftblock->data[deque->leftindex] = item;
 	}
 	Py_DECREF(it);
@@ -365,7 +365,7 @@
 {
 	block *b;
 	PyObject *item;
-	int n;
+	int n, index=i;
 
 	if (i < 0 || i >= deque->len) {
 		PyErr_SetString(PyExc_IndexError,
@@ -383,7 +383,7 @@
 		i += deque->leftindex;
 		n = i / BLOCKLEN;
 		i %= BLOCKLEN;
-		if (i < (deque->len >> 1)) {
+		if (index < (deque->len >> 1)) {
 			b = deque->leftblock;
 			while (n--)
 				b = b->rightlink;
@@ -514,7 +514,6 @@
 	int index;
 	int indexlo = deque->leftindex;
 
-	assert(deque->leftblock != NULL);
 	for (b = deque->leftblock; b != NULL; b = b->rightlink) {
 		const int indexhi = b == deque->rightblock ?
 					 deque->rightindex :
@@ -642,7 +641,7 @@
 deque_richcompare(PyObject *v, PyObject *w, int op)
 {
 	PyObject *it1=NULL, *it2=NULL, *x, *y;
-	int i, b, vs, ws, minlen, cmp=-1;
+	int b, vs, ws, cmp=-1;
 
 	if (!PyObject_TypeCheck(v, &deque_type) ||
 	    !PyObject_TypeCheck(w, &deque_type)) {
@@ -673,16 +672,13 @@
 	it2 = PyObject_GetIter(w);
 	if (it2 == NULL)
 		goto done;
-	minlen = (vs < ws)  ?  vs  :  ws;
-	for (i=0 ; i < minlen ; i++) {
+	for (;;) {
 		x = PyIter_Next(it1);
-		if (x == NULL)
+		if (x == NULL && PyErr_Occurred())
 			goto done;
 		y = PyIter_Next(it2);
-		if (y == NULL) {
-			Py_DECREF(x);
-			goto done;
-		}
+		if (x == NULL || y == NULL)
+			break;
 		b = PyObject_RichCompareBool(x, y, Py_EQ);
 		if (b == 0) {
 			cmp = PyObject_RichCompareBool(x, y, op);
@@ -695,14 +691,18 @@
 		if (b == -1)
 			goto done;
 	}
-	/* Elements are equal through minlen.  The longest input is the greatest */
+	/* We reached the end of one deque or both */
+	Py_XDECREF(x);
+	Py_XDECREF(y);
+	if (PyErr_Occurred())
+		goto done;
 	switch (op) {
-	case Py_LT: cmp = vs <  ws; break;
-	case Py_LE: cmp = vs <= ws; break;
-	case Py_EQ: cmp = vs == ws; break;
-	case Py_NE: cmp = vs != ws; break;
-	case Py_GT: cmp = vs >  ws; break;
-	case Py_GE: cmp = vs >= ws; break;
+	case Py_LT: cmp = y != NULL; break;  /* if w was longer */
+	case Py_LE: cmp = x == NULL; break;  /* if v was not longer */
+	case Py_EQ: cmp = x == y;    break;  /* if we reached the end of both */
+	case Py_NE: cmp = x != y;    break;  /* if one deque continues */
+	case Py_GT: cmp = x != NULL; break;  /* if v was longer */
+	case Py_GE: cmp = y == NULL; break;  /* if w was not longer */
 	}
 
 done:



More information about the Python-checkins mailing list