Improve extended slicing support in builtin types and classes. Specifically:

 - Specialcase extended slices that amount to a shallow copy the same way as
   is done for simple slices, in the tuple, string and unicode case.

 - Specialcase step-1 extended slices to optimize the common case for all
   involved types.

 - For lists, allow extended slice assignment of differing lengths as long
   as the step is 1. (Previously, 'l[:2:1] = []' failed even though
   'l[:2] = []' and 'l[:2:None] = []' do not.)

 - Implement extended slicing for buffer, array, structseq, mmap and
   UserString.UserString.

 - Implement slice-object support (but not non-step-1 slice assignment) for
   UserString.MutableString.

 - Add tests for all new functionality.
diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c
index a92954b..6114442 100644
--- a/Modules/mmapmodule.c
+++ b/Modules/mmapmodule.c
@@ -681,6 +681,60 @@
 }
 
 static PyObject *
+mmap_subscript(mmap_object *self, PyObject *item)
+{
+	CHECK_VALID(NULL);
+	if (PyIndex_Check(item)) {
+		Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
+		if (i == -1 && PyErr_Occurred())
+			return NULL;
+		if (i < 0)
+			i += self->size;
+		if (i < 0 || i > self->size) {
+			PyErr_SetString(PyExc_IndexError,
+				"mmap index out of range");
+			return NULL;
+		}
+		return PyString_FromStringAndSize(self->data + i, 1);
+	}
+	else if (PySlice_Check(item)) {
+		Py_ssize_t start, stop, step, slicelen;
+
+		if (PySlice_GetIndicesEx((PySliceObject *)item, self->size,
+				 &start, &stop, &step, &slicelen) < 0) {
+			return NULL;
+		}
+		
+		if (slicelen <= 0)
+			return PyString_FromStringAndSize("", 0);
+		else if (step == 1)
+			return PyString_FromStringAndSize(self->data + start,
+							  slicelen);
+		else {
+			char *result_buf = (char *)PyMem_Malloc(slicelen);
+			Py_ssize_t cur, i;
+			PyObject *result;
+
+			if (result_buf == NULL)
+				return PyErr_NoMemory();
+			for (cur = start, i = 0; i < slicelen;
+			     cur += step, i++) {
+			     	result_buf[i] = self->data[cur];
+			}
+			result = PyString_FromStringAndSize(result_buf,
+							    slicelen);
+			PyMem_Free(result_buf);
+			return result;
+		}
+	}
+	else {
+		PyErr_SetString(PyExc_TypeError,
+				"mmap indices must be integers");
+		return NULL;
+	}
+}
+
+static PyObject *
 mmap_concat(mmap_object *self, PyObject *bb)
 {
 	CHECK_VALID(NULL);
@@ -764,6 +818,96 @@
 	return 0;
 }
 
+static int
+mmap_ass_subscript(mmap_object *self, PyObject *item, PyObject *value)
+{
+	CHECK_VALID(-1);
+
+	if (PyIndex_Check(item)) {
+		Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
+		const char *buf;
+
+		if (i == -1 && PyErr_Occurred())
+			return -1;
+		if (i < 0)
+			i += self->size;
+		if (i < 0 || i > self->size) {
+			PyErr_SetString(PyExc_IndexError,
+				"mmap index out of range");
+			return -1;
+		}
+		if (value == NULL) {
+			PyErr_SetString(PyExc_TypeError,
+				"mmap object doesn't support item deletion");
+			return -1;
+		}
+		if (!PyString_Check(value) || PyString_Size(value) != 1) {
+			PyErr_SetString(PyExc_IndexError,
+		          "mmap assignment must be single-character string");
+			return -1;
+		}
+		if (!is_writeable(self))
+			return -1;
+		buf = PyString_AsString(value);
+		self->data[i] = buf[0];
+		return 0;
+	}
+	else if (PySlice_Check(item)) {
+		Py_ssize_t start, stop, step, slicelen;
+		
+		if (PySlice_GetIndicesEx((PySliceObject *)item,
+					 self->size, &start, &stop,
+					 &step, &slicelen) < 0) {
+			return -1;
+		}
+		if (value == NULL) {
+			PyErr_SetString(PyExc_TypeError,
+				"mmap object doesn't support slice deletion");
+			return -1;
+		}
+		if (!PyString_Check(value)) {
+			PyErr_SetString(PyExc_IndexError,
+				"mmap slice assignment must be a string");
+			return -1;
+		}
+		if (PyString_Size(value) != slicelen) {
+			PyErr_SetString(PyExc_IndexError,
+				"mmap slice assignment is wrong size");
+			return -1;
+		}
+		if (!is_writeable(self))
+			return -1;
+
+		if (slicelen == 0)
+			return 0;
+		else if (step == 1) {
+			const char *buf = PyString_AsString(value);
+
+			if (buf == NULL)
+				return -1;
+			memcpy(self->data + start, buf, slicelen);
+			return 0;
+		}
+		else {
+			Py_ssize_t cur, i;
+			const char *buf = PyString_AsString(value);
+			
+			if (buf == NULL)
+				return -1;
+			for (cur = start, i = 0; i < slicelen;
+			     cur += step, i++) {
+				self->data[cur] = buf[i];
+			}
+			return 0;
+		}
+	}
+	else {
+		PyErr_SetString(PyExc_TypeError,
+				"mmap indices must be integer");
+		return -1;
+	}
+}
+
 static PySequenceMethods mmap_as_sequence = {
 	(lenfunc)mmap_length,		       /*sq_length*/
 	(binaryfunc)mmap_concat,	       /*sq_concat*/
@@ -774,6 +918,12 @@
 	(ssizessizeobjargproc)mmap_ass_slice,      /*sq_ass_slice*/
 };
 
+static PyMappingMethods mmap_as_mapping = {
+	(lenfunc)mmap_length,
+	(binaryfunc)mmap_subscript,
+	(objobjargproc)mmap_ass_subscript,
+};
+
 static PyBufferProcs mmap_as_buffer = {
 	(readbufferproc)mmap_buffer_getreadbuf,
 	(writebufferproc)mmap_buffer_getwritebuf,
@@ -795,7 +945,7 @@
 	0,					/* tp_repr */
 	0,					/* tp_as_number */
 	&mmap_as_sequence,			/*tp_as_sequence*/
-	0,					/*tp_as_mapping*/
+	&mmap_as_mapping,			/*tp_as_mapping*/
 	0,					/*tp_hash*/
 	0,					/*tp_call*/
 	0,					/*tp_str*/