[Python-checkins] r46171 - python/branches/rjones-prealloc/Objects/listobject.c

richard.jones python-checkins at python.org
Wed May 24 15:38:52 CEST 2006


Author: richard.jones
Date: Wed May 24 15:38:52 2006
New Revision: 46171

Modified:
   python/branches/rjones-prealloc/Objects/listobject.c
Log:
Enable pre-allocating list storage to avoid later mallocs.

list(size=100) will pre-allocate 100 elements in the list.

Modified list_resize to not shrink lists when invoked by a list operation
that increases the list size.



Modified: python/branches/rjones-prealloc/Objects/listobject.c
==============================================================================
--- python/branches/rjones-prealloc/Objects/listobject.c	(original)
+++ python/branches/rjones-prealloc/Objects/listobject.c	Wed May 24 15:38:52 2006
@@ -22,17 +22,20 @@
  * than ob_size on entry.
  */
 static int
-list_resize(PyListObject *self, Py_ssize_t newsize)
+list_resize(PyListObject *self, Py_ssize_t newsize, int allow_shrink)
 {
 	PyObject **items;
 	size_t new_allocated;
 	Py_ssize_t allocated = self->allocated;
 
 	/* Bypass realloc() when a previous overallocation is large enough
-	   to accommodate the newsize.  If the newsize falls lower than half
-	   the allocated size, then proceed with the realloc() to shrink the list.
+	   to accommodate the newsize.
+           If the newsize falls lower than half the allocated size and we
+           allow shrinking, then proceed with the realloc() to shrink the
+           list.
 	*/
-	if (allocated >= newsize && newsize >= (allocated >> 1)) {
+	if (allocated >= newsize && (newsize >= (allocated >> 1) ||
+                        !allow_shrink)) {
 		assert(self->ob_item != NULL || newsize == 0);
 		self->ob_size = newsize;
 		return 0;
@@ -187,7 +190,7 @@
 		return -1;
 	}
 
-	if (list_resize(self, n+1) == -1)
+	if (list_resize(self, n+1, 0) == -1)
 		return -1;
 
 	if (where < 0) {
@@ -227,7 +230,7 @@
 		return -1;
 	}
 
-	if (list_resize(self, n+1) == -1)
+	if (list_resize(self, n+1, 0) == -1)
 		return -1;
 
 	Py_INCREF(v);
@@ -614,12 +617,12 @@
 	if (d < 0) { /* Delete -d items */
 		memmove(&item[ihigh+d], &item[ihigh],
 			(a->ob_size - ihigh)*sizeof(PyObject *));
-		list_resize(a, a->ob_size + d);
+		list_resize(a, a->ob_size + d, 1);
 		item = a->ob_item;
 	}
 	else if (d > 0) { /* Insert d items */
 		k = a->ob_size;
-		if (list_resize(a, k+d) < 0)
+		if (list_resize(a, k+d, 0) < 0)
 			goto Error;
 		item = a->ob_item;
 		memmove(&item[ihigh+d], &item[ihigh],
@@ -670,7 +673,7 @@
 		return (PyObject *)self;
 	}
 
-	if (list_resize(self, size*n) == -1)
+	if (list_resize(self, size*n, 0) == -1)
 		return NULL;
 
 	p = size;
@@ -750,7 +753,7 @@
 			Py_RETURN_NONE;
 		}
 		m = self->ob_size;
-		if (list_resize(self, m + n) == -1) {
+		if (list_resize(self, m + n, 0) == -1) {
 			Py_DECREF(b);
 			return NULL;
 		}
@@ -791,7 +794,7 @@
 	mn = m + n;
 	if (mn >= m) {
 		/* Make room. */
-		if (list_resize(self, mn) == -1)
+		if (list_resize(self, mn, 0) == -1)
 			goto error;
 		/* Make the list sane again. */
 		self->ob_size = m;
@@ -828,7 +831,7 @@
 
 	/* Cut back result list if initial guess was too large. */
 	if (self->ob_size < self->allocated)
-		list_resize(self, self->ob_size);  /* shrinking can't fail */
+		list_resize(self, self->ob_size, 1);  /* shrinking can't fail */
 
 	Py_DECREF(it);
 	Py_RETURN_NONE;
@@ -885,7 +888,7 @@
 	}
 	v = self->ob_item[i];
 	if (i == self->ob_size - 1) {
-		status = list_resize(self, self->ob_size - 1);
+		status = list_resize(self, self->ob_size - 1, 1);
 		assert(status >= 0);
 		return v; /* and v now owns the reference the list had */
 	}
@@ -2355,10 +2358,13 @@
 static int
 list_init(PyListObject *self, PyObject *args, PyObject *kw)
 {
-	PyObject *arg = NULL;
-	static char *kwlist[] = {"sequence", 0};
+	PyObject *sequence = NULL;
+        Py_ssize_t size = 0;
+	static char *kwlist[] = {"sequence", "size", 0};
+	PyObject **items;
 
-	if (!PyArg_ParseTupleAndKeywords(args, kw, "|O:list", kwlist, &arg))
+	if (!PyArg_ParseTupleAndKeywords(args, kw, "|On:list", kwlist,
+                &sequence, &size))
 		return -1;
 
 	/* Verify list invariants established by PyType_GenericAlloc() */
@@ -2371,12 +2377,32 @@
 	if (self->ob_item != NULL) {
 		(void)list_clear(self);
 	}
-	if (arg != NULL) {
-		PyObject *rv = listextend(self, arg);
+	if (sequence != NULL) {
+		PyObject *rv = listextend(self, sequence);
 		if (rv == NULL)
 			return -1;
 		Py_DECREF(rv);
 	}
+
+        if (size != 0) {
+                if (size < PyList_GET_SIZE(self)) {
+                        PyErr_SetString(PyExc_ValueError, "size argument"
+                                " too small to contain supplied sequence");
+			return -1;
+                }
+                /* (p)re-allocate to the indicated size */
+                items = self->ob_item;
+                if (size <= ((~(size_t)0) / sizeof(PyObject *)))
+                        PyMem_RESIZE(items, PyObject *, size);
+                else
+                        items = NULL;
+                if (items == NULL) {
+                        PyErr_NoMemory();
+                        return -1;
+                }
+                self->ob_item = items;
+                self->allocated = size;
+        }
 	return 0;
 }
 
@@ -2565,7 +2591,7 @@
 			}
 
 			self->ob_size -= slicelength;
-			list_resize(self, self->ob_size);
+			list_resize(self, self->ob_size, 1);
 
 			for (i = 0; i < slicelength; i++) {
 				Py_DECREF(garbage[i]);


More information about the Python-checkins mailing list