[Patches] list.extend(sequence), new PySequence_Fast API

Fredrik Lundh Fredrik Lundh" <effbot@telia.com
Sun, 18 Jun 2000 15:02:42 +0200


This is a multi-part message in MIME format.

------=_NextPart_000_0024_01BFD936.405A8A00
Content-Type: text/plain;
	charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable

[as discussed on python-dev]

this patch introduces PySequence_Fast and PySequence_Fast_GET_ITEM,
and modifies the list.extend method to accept any kind of sequence.

</F>

I confirm that, to the best of my knowledge and belief, this
contribution is free of any claims of third parties under copyright,
patent or other rights or interests ("claims").  To the extent that I
have any such claims, I hereby grant to CNRI a nonexclusive,
irrevocable, royalty-free, worldwide license to reproduce, distribute,
perform and/or display publicly, prepare derivative versions, and
otherwise use this contribution as part of the Python software and its
related documentation, or any derivative versions thereof, at no cost to
CNRI or its licensed users, and to authorize others to do so.

I acknowledge that CNRI may, at its sole discretion, decide whether or
not to incorporate this contribution in the Python software and its
related documentation.  I further grant CNRI permission to use my name
and other identifying information provided to CNRI by me for use in
connection with the Python software and its related documentation.

------=_NextPart_000_0024_01BFD936.405A8A00
Content-Type: text/plain;
	name="extend-patch.txt"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
	filename="extend-patch.txt"

Index: Include/abstract.h
===================================================================
RCS file: /cvsroot/python/python/dist/src/Include/abstract.h,v
retrieving revision 2.17
diff -u -r2.17 abstract.h
--- Include/abstract.h	2000/03/10 22:35:06	2.17
+++ Include/abstract.h	2000/06/18 12:54:02
@@ -731,7 +731,6 @@
        /*
 	 Return the ith element of o, or NULL on failure. This is the
 	 equivalent of the Python expression: o[i].
-
        */
 
      DL_IMPORT(PyObject *) PySequence_GetSlice Py_PROTO((PyObject *o, int i1, int i2));
@@ -783,11 +782,31 @@
 	 This is equivalent to the Python expression: tuple(o)
        */
 
+
      DL_IMPORT(PyObject *) PySequence_List Py_PROTO((PyObject *o));
 
        /*
 	 Returns the sequence, o, as a list on success, and NULL on failure.
 	 This is equivalent to the Python expression: list(o)
+       */
+
+     DL_IMPORT(PyObject *) PySequence_Fast Py_PROTO((PyObject *o, const char* m));
+
+       /*
+         Returns the sequence, o, as a tuple, unless it's already a
+         tuple or list.  Use PySequence_Fast_GET_ITEM to access the
+         members of this list.
+
+         Returns NULL on failure.  If the object is not a sequence,
+         raises a TypeError exception with m as the message text.
+       */
+
+#define PySequence_Fast_GET_ITEM(o, i)\
+     (PyList_Check(o) ? PyList_GET_ITEM(o, i) : PyTuple_GET_ITEM(o, i))
+
+       /*
+	 Return the ith element of o, assuming that o was returned by
+         PySequence_Fast, and that i is within bounds.
        */
 
      DL_IMPORT(int) PySequence_Count Py_PROTO((PyObject *o, PyObject *value));
Index: Objects/abstract.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/abstract.c,v
retrieving revision 2.34
diff -u -r2.34 abstract.c
--- Objects/abstract.c	2000/04/05 20:11:20	2.34
+++ Objects/abstract.c	2000/06/18 12:54:12
@@ -1207,6 +1207,26 @@
 	return type_error("list() argument must be a sequence");
 }
 
+PyObject *
+PySequence_Fast(v, m)
+	PyObject *v;
+	const char* m;
+{
+	if (v == NULL)
+		return null_error();
+
+	if (PyList_Check(v) || PyTuple_Check(v)) {
+		Py_INCREF(v);
+		return v;
+	}
+
+	v = PySequence_Tuple(v);
+	if (v == NULL && PyErr_ExceptionMatches(PyExc_TypeError))
+		return type_error(m);
+
+	return v;
+}
+
 int
 PySequence_Count(s, o)
 	PyObject *s;
Index: Objects/listobject.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/listobject.c,v
retrieving revision 2.72
diff -u -r2.72 listobject.c
--- Objects/listobject.c	2000/06/15 14:50:20	2.72
+++ Objects/listobject.c	2000/06/18 12:54:18
@@ -627,16 +627,14 @@
 	if (!PyArg_ParseTuple(args, "O:extend", &b))
 		return NULL;
 
-	if (!PyList_Check(b)) {
-		PyErr_SetString(PyExc_TypeError,
-				"list.extend() argument must be a list");
+	b = PySequence_Fast(b, "list.extend() argument must be a sequence");
+	if (!b)
 		return NULL;
-	}
-	if (PyList_GET_SIZE(b) == 0) {
+
+	if (PyObject_Length(b) == 0)
 		/* short circuit when b is empty */
-		Py_INCREF(Py_None);
-		return Py_None;
-	}
+		goto ok;
+
 	if (self == (PyListObject*)b) {
 		/* as in list_ass_slice() we must special case the
 		 * situation: a.extend(a)
@@ -644,6 +642,7 @@
 		 * XXX: I think this way ought to be faster than using
 		 * list_slice() the way list_ass_slice() does.
 		 */
+		Py_DECREF(b);
 		b = PyList_New(selflen);
 		if (!b)
 			return NULL;
@@ -653,33 +652,29 @@
 			PyList_SET_ITEM(b, i, o);
 		}
 	}
-	else
-		/* we want b to have the same refcount semantics for the
-		 * Py_XDECREF() in the finally clause regardless of which
-		 * branch in the above conditional we took.
-		 */
-		Py_INCREF(b);
+
+	blen = PyObject_Length(b);
 
-	blen = PyList_GET_SIZE(b);
 	/* resize a using idiom */
 	items = self->ob_item;
 	NRESIZE(items, PyObject*, selflen + blen);
-	if (items == NULL ) {
+	if (items == NULL) {
 		PyErr_NoMemory();
-		goto finally;
+		goto failed;
 	}
 	self->ob_item = items;
 
-	/* populate the end self with b's items */
+	/* populate the end of self with b's items */
 	for (i = 0; i < blen; i++) {
-		PyObject *o = PyList_GET_ITEM(b, i);
+		PyObject *o = PySequence_Fast_GET_ITEM(b, i);
 		Py_INCREF(o);
 		PyList_SET_ITEM(self, self->ob_size++, o);
 	}
+  ok:
 	res = Py_None;
 	Py_INCREF(res);
-  finally:
-	Py_XDECREF(b);
+  failed:
+	Py_DECREF(b);
 	return res;
 }
 

------=_NextPart_000_0024_01BFD936.405A8A00--