[Python-checkins] python/dist/src/Objects listobject.c,2.181,2.182

rhettinger at users.sourceforge.net rhettinger at users.sourceforge.net
Sat Feb 14 22:57:14 EST 2004


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

Modified Files:
	listobject.c 
Log Message:
Refactor list_extend() and list_fill() for gains in code size, memory
utilization, and speed:

* Moved the responsibility for emptying the previous list from list_fill
  to list_init.

* Replaced the code in list_extend with the superior code from list_fill.

* Eliminated list_fill.

Results:

* list.extend() no longer creates an intermediate tuple except to handle
  the special case of x.extend(x).  The saves memory and time.

* list.extend(x) runs
    5 to 10% faster when x is a list or tuple
    15% faster when x is an iterable not defining __len__
    twice as fast when x is an iterable defining __len__
    
* the code is about 15 lines shorter and no longer duplicates
  functionality.



Index: listobject.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/listobject.c,v
retrieving revision 2.181
retrieving revision 2.182
diff -C2 -d -r2.181 -r2.182
*** listobject.c	14 Feb 2004 18:34:46 -0000	2.181
--- listobject.c	15 Feb 2004 03:57:00 -0000	2.182
***************
*** 325,329 ****
  }
  
- 
  static PyObject *
  list_item(PyListObject *a, int i)
--- 325,328 ----
***************
*** 687,691 ****
  }
  
- 
  static PyObject *
  list_inplace_concat(PyListObject *self, PyObject *other)
--- 686,689 ----
***************
*** 705,718 ****
  listextend(PyListObject *self, PyObject *b)
  {
  
! 	b = PySequence_Fast(b, "list.extend() argument must be iterable");
! 	if (!b)
! 		return NULL;
  
! 	if (listextend_internal(self, b) < 0)
  		return NULL;
  
! 	Py_INCREF(Py_None);
! 	return Py_None;
  }
  
--- 703,770 ----
  listextend(PyListObject *self, PyObject *b)
  {
+ 	PyObject *it;      /* iter(v) */
+ 	int m;		   /* size of self */
+ 	int n;		   /* guess for size of b */
+ 	int mn;		   /* m + n */
+ 	int i;
  
! 	/* Special cases:
! 	   1) lists and tuples which can use PySequence_Fast ops 
! 	   2) extending self to self requires making a copy first 
! 	*/
! 	if (PyList_CheckExact(b) || PyTuple_CheckExact(b) || (PyObject *)self == b) {
! 		b = PySequence_Fast(b, "argument must be iterable");
! 		if (!b)
! 			return NULL;
! 		if (listextend_internal(self, b) < 0)
! 			return NULL;
! 		Py_RETURN_NONE;
! 	}
  
! 	it = PyObject_GetIter(b);
! 	if (it == NULL)
  		return NULL;
  
! 	/* Guess a result list size. */
! 	n = PyObject_Size(b);
! 	if (n < 0) {
! 		PyErr_Clear();
! 		n = 8;	/* arbitrary */
! 	}
! 	m = self->ob_size;
! 	mn = m + n;
! 	if (list_resize(self, mn) == -1)
! 		goto error;
! 	memset(&(self->ob_item[m]), 0, sizeof(*self->ob_item) * n);
! 
! 	/* Run iterator to exhaustion. */
! 	for (i = m; ; i++) {
! 		PyObject *item = PyIter_Next(it);
! 		if (item == NULL) {
! 			if (PyErr_Occurred())
! 				goto error;
! 			break;
! 		}
! 		if (i < mn)
! 			PyList_SET_ITEM(self, i, item); /* steals ref */
! 		else {
! 			int status = ins1(self, self->ob_size, item);
! 			Py_DECREF(item);  /* append creates a new ref */
! 			if (status < 0)
! 				goto error;
! 		}
! 	}
! 
! 	/* Cut back result list if initial guess was too large. */
! 	if (i < mn && self != NULL) {
! 		if (list_ass_slice(self, i, mn, (PyObject *)NULL) != 0)
! 			goto error;
! 	}
! 	Py_DECREF(it);
! 	Py_RETURN_NONE;
! 
!   error:
! 	Py_DECREF(it);
! 	return NULL;
  }
  
***************
*** 2221,2296 ****
  }
  
- /* Adapted from newer code by Tim */
- static int
- list_fill(PyListObject *result, PyObject *v)
- {
- 	PyObject *it;      /* iter(v) */
- 	int n;		   /* guess for result list size */
- 	int i;
- 
- 	n = result->ob_size;
- 
- 	/* Special-case list(a_list), for speed. */
- 	if (PyList_Check(v)) {
- 		if (v == (PyObject *)result)
- 			return 0; /* source is destination, we're done */
- 		return list_ass_slice(result, 0, n, v);
- 	}
- 
- 	/* Empty previous contents */
- 	if (n != 0) {
- 		if (list_ass_slice(result, 0, n, (PyObject *)NULL) != 0)
- 			return -1;
- 	}
- 
- 	/* Get iterator.  There may be some low-level efficiency to be gained
- 	 * by caching the tp_iternext slot instead of using PyIter_Next()
- 	 * later, but premature optimization is the root etc.
- 	 */
- 	it = PyObject_GetIter(v);
- 	if (it == NULL)
- 		return -1;
- 
- 	/* Guess a result list size. */
- 	n = PyObject_Size(v);
- 	if (n < 0) {
- 		PyErr_Clear();
- 		n = 8;	/* arbitrary */
- 	}
- 	if (list_resize(result, n) == -1)
- 		goto error;
- 	memset(result->ob_item, 0, sizeof(*result->ob_item) * n);
- 
- 	/* Run iterator to exhaustion. */
- 	for (i = 0; ; i++) {
- 		PyObject *item = PyIter_Next(it);
- 		if (item == NULL) {
- 			if (PyErr_Occurred())
- 				goto error;
- 			break;
- 		}
- 		if (i < n)
- 			PyList_SET_ITEM(result, i, item); /* steals ref */
- 		else {
- 			int status = ins1(result, result->ob_size, item);
- 			Py_DECREF(item);  /* append creates a new ref */
- 			if (status < 0)
- 				goto error;
- 		}
- 	}
- 
- 	/* Cut back result list if initial guess was too large. */
- 	if (i < n && result != NULL) {
- 		if (list_ass_slice(result, i, n, (PyObject *)NULL) != 0)
- 			goto error;
- 	}
- 	Py_DECREF(it);
- 	return 0;
- 
-   error:
- 	Py_DECREF(it);
- 	return -1;
- }
- 
  static int
  list_init(PyListObject *self, PyObject *args, PyObject *kw)
--- 2273,2276 ----
***************
*** 2301,2308 ****
  	if (!PyArg_ParseTupleAndKeywords(args, kw, "|O:list", kwlist, &arg))
  		return -1;
! 	if (arg != NULL)
! 		return list_fill(self, arg);
! 	if (self->ob_size > 0)
! 		return list_ass_slice(self, 0, self->ob_size, (PyObject*)NULL);
  	return 0;
  }
--- 2281,2295 ----
  	if (!PyArg_ParseTupleAndKeywords(args, kw, "|O:list", kwlist, &arg))
  		return -1;
! 	/* Empty previous contents */
! 	if (self->ob_size != 0) {
! 		if (list_ass_slice(self, 0, self->ob_size, (PyObject *)NULL) != 0)
! 			return -1;
! 	}
! 	if (arg != NULL) {
! 		PyObject *rv = listextend(self, arg);
! 		if (rv == NULL)
! 			return -1;
! 		Py_DECREF(rv);
! 	}
  	return 0;
  }




More information about the Python-checkins mailing list