Issue #2394: implement more of the memoryview API.
diff --git a/Objects/memoryobject.c b/Objects/memoryobject.c
index c108363..bd5820f 100644
--- a/Objects/memoryobject.c
+++ b/Objects/memoryobject.c
@@ -13,8 +13,8 @@
 	}
 	if (self->view.obj == NULL)
 		return 0;
-        return self->view.obj->ob_type->tp_as_buffer->bf_getbuffer(self->base, NULL,
-                                                               PyBUF_FULL);
+        return self->view.obj->ob_type->tp_as_buffer->bf_getbuffer(
+            self->view.obj, NULL, PyBUF_FULL);
 }
 
 static void
@@ -37,9 +37,14 @@
 						   &PyMemoryView_Type);
 	if (mview == NULL) return NULL;
 	mview->base = NULL;
+        /* XXX there should be an API to duplicate a buffer object */
 	mview->view = *info;
-	if (info->obj)
-		Py_INCREF(mview->view.obj);
+        if (info->shape == &(info->len))
+            mview->view.shape = &(mview->view.len);
+        if (info->strides == &(info->itemsize))
+            mview->view.strides = &(mview->view.itemsize);
+        /* NOTE: mview->view.obj should already have been incref'ed as
+           part of PyBuffer_FillInfo(). */
 	return (PyObject *)mview;
 }
 
@@ -258,12 +263,12 @@
                                 "for a non-contiguousobject.");
                 return NULL;
         }
-        bytes = PyByteArray_FromStringAndSize(NULL, view->len);
+        bytes = PyBytes_FromStringAndSize(NULL, view->len);
         if (bytes == NULL) {
                 PyBuffer_Release(view);
                 return NULL;
         }
-        dest = PyByteArray_AS_STRING(bytes);
+        dest = PyBytes_AS_STRING(bytes);
         /* different copying strategy depending on whether
            or not any pointer de-referencing is needed
         */
@@ -386,17 +391,45 @@
 static PyObject *
 memory_tobytes(PyMemoryViewObject *mem, PyObject *noargs)
 {
-        return PyByteArray_FromObject((PyObject *)mem);
+	return PyObject_CallFunctionObjArgs(
+		(PyObject *) &PyBytes_Type, mem, NULL);
 }
 
+/* TODO: rewrite this function using the struct module to unpack
+   each buffer item */
+
 static PyObject *
 memory_tolist(PyMemoryViewObject *mem, PyObject *noargs)
 {
-	/* This should construct a (nested) list of unpacked objects
-	   possibly using the struct module.
-	 */
-        Py_INCREF(Py_NotImplemented);
-        return Py_NotImplemented;
+	Py_buffer *view = &(mem->view);
+	Py_ssize_t i;
+	PyObject *res, *item;
+	char *buf;
+
+	if (strcmp(view->format, "B") || view->itemsize != 1) {
+		PyErr_SetString(PyExc_NotImplementedError, 
+			"tolist() only supports byte views");
+		return NULL;
+	}
+	if (view->ndim != 1) {
+		PyErr_SetString(PyExc_NotImplementedError, 
+			"tolist() only supports one-dimensional objects");
+		return NULL;
+	}
+	res = PyList_New(view->len);
+	if (res == NULL)
+		return NULL;
+	buf = view->buf;
+	for (i = 0; i < view->len; i++) {
+		item = PyLong_FromUnsignedLong((unsigned char) *buf);
+		if (item == NULL) {
+			Py_DECREF(res);
+			return NULL;
+		}
+		PyList_SET_ITEM(res, i, item);
+		buf++;
+	}
+	return res;
 }
 
 
@@ -412,7 +445,7 @@
 memory_dealloc(PyMemoryViewObject *self)
 {
         if (self->view.obj != NULL) {
-            if (PyTuple_Check(self->base)) {
+            if (self->base && PyTuple_Check(self->base)) {
                 /* Special case when first element is generic object
                    with buffer interface and the second element is a
                    contiguous "shadow" that must be copied back into
@@ -454,8 +487,8 @@
         if (PyObject_GetBuffer((PyObject *)self, &view, PyBUF_FULL) < 0)
                 return NULL;
 
-	res = PyByteArray_FromStringAndSize(NULL, view.len);
-        PyBuffer_ToContiguous(PyByteArray_AS_STRING(res), &view, view.len, 'C');
+	res = PyBytes_FromStringAndSize(NULL, view.len);
+        PyBuffer_ToContiguous(PyBytes_AS_STRING(res), &view, view.len, 'C');
         PyBuffer_Release(&view);
         return res;
 }
@@ -511,7 +544,7 @@
 			if (result < 0) {
 				result += view->shape[0];
 			}
-			if ((result < 0) || (result > view->shape[0])) {
+			if ((result < 0) || (result >= view->shape[0])) {
 				PyErr_SetString(PyExc_IndexError,
 						"index out of bounds");
 				return NULL;
@@ -525,7 +558,7 @@
                         {
 				ptr = *((char **)ptr) + view->suboffsets[0];
 			}
-			return PyByteArray_FromStringAndSize(ptr, view->itemsize);
+			return PyBytes_FromStringAndSize(ptr, view->itemsize);
 		}
 		else {
 			/* Return a new memory-view object */
@@ -537,10 +570,46 @@
 			return PyMemoryView_FromBuffer(&newview);
 		}
 	}
+	else if (PySlice_Check(key)) {
+		Py_ssize_t start, stop, step, slicelength;
 
-	/* Need to support getting a sliced view */
-        Py_INCREF(Py_NotImplemented);
-        return Py_NotImplemented;
+		if (PySlice_GetIndicesEx((PySliceObject*)key, view->len,
+				 &start, &stop, &step, &slicelength) < 0) {
+			return NULL;
+		}
+
+		if (step == 1 && view->ndim == 1) {
+			Py_buffer newview;
+			void *newbuf = (char *) view->buf
+						+ start * view->itemsize;
+			int newflags = view->readonly
+				? PyBUF_CONTIG_RO : PyBUF_CONTIG;
+
+			/* XXX There should be an API to create a subbuffer */
+			if (view->obj != NULL) {
+				if (PyObject_GetBuffer(view->obj,
+						&newview, newflags) == -1)
+					return NULL;
+			}
+			else {
+				newview = *view;
+			}
+			newview.buf = newbuf;
+			newview.len = slicelength;
+			newview.format = view->format;
+			if (view->shape == &(view->len))
+				newview.shape = &(newview.len);
+			if (view->strides == &(view->itemsize))
+				newview.strides = &(newview.itemsize);
+			return PyMemoryView_FromBuffer(&newview);
+		}
+		PyErr_SetNone(PyExc_NotImplementedError);
+		return NULL;
+	}
+	PyErr_Format(PyExc_TypeError,
+		"cannot index memory using \"%.200s\"", 
+		key->ob_type->tp_name);
+	return NULL;
 }
 
 
@@ -548,9 +617,138 @@
 static int
 memory_ass_sub(PyMemoryViewObject *self, PyObject *key, PyObject *value)
 {
-        return 0;
+    Py_ssize_t start, len, bytelen, i;
+    Py_buffer srcview;
+    Py_buffer *view = &(self->view);
+    char *srcbuf, *destbuf;
+
+    if (view->readonly) {
+        PyErr_SetString(PyExc_TypeError,
+            "cannot modify read-only memory");
+        return -1;
+    }
+    if (view->ndim != 1) {
+        PyErr_SetNone(PyExc_NotImplementedError);
+        return -1;
+    }
+    if (PyIndex_Check(key)) {
+        start = PyNumber_AsSsize_t(key, NULL);
+        if (start == -1 && PyErr_Occurred())
+            return -1;
+        if (start < 0) {
+            start += view->shape[0];
+        }
+        if ((start < 0) || (start >= view->shape[0])) {
+            PyErr_SetString(PyExc_IndexError,
+                            "index out of bounds");
+            return -1;
+        }
+        len = 1;
+    }
+    else if (PySlice_Check(key)) {
+        Py_ssize_t stop, step;
+
+        if (PySlice_GetIndicesEx((PySliceObject*)key, view->len,
+                         &start, &stop, &step, &len) < 0) {
+            return -1;
+        }
+        if (step != 1) {
+            PyErr_SetNone(PyExc_NotImplementedError);
+            return -1;
+        }
+    }
+    else {
+        PyErr_Format(PyExc_TypeError,
+            "cannot index memory using \"%.200s\"", 
+            key->ob_type->tp_name);
+        return -1;
+    }
+    if (PyObject_GetBuffer(value, &srcview, PyBUF_CONTIG_RO) == -1) {
+        return -1;
+    }
+    /* XXX should we allow assignment of different item sizes
+       as long as the byte length is the same?
+       (e.g. assign 2 shorts to a 4-byte slice) */
+    if (srcview.itemsize != view->itemsize) {
+        PyErr_Format(PyExc_TypeError,
+            "mismatching item sizes for \"%.200s\" and \"%.200s\"", 
+            view->obj->ob_type->tp_name, srcview.obj->ob_type->tp_name);
+        goto _error;
+    }
+    if (srcview.len != len) {
+        PyErr_SetString(PyExc_ValueError,
+            "cannot modify size of memoryview object");
+        goto _error;
+    }
+    /* Do the actual copy */
+    destbuf = (char *) view->buf + start * view->itemsize;
+    srcbuf = (char *) srcview.buf;
+    bytelen = len * view->itemsize;
+    if (destbuf + bytelen < srcbuf || srcbuf + bytelen < destbuf)
+        /* No overlapping */
+        memcpy(destbuf, srcbuf, bytelen);
+    else if (destbuf < srcbuf) {
+        /* Copy in ascending order */
+        for (i = 0; i < bytelen; i++)
+            destbuf[i] = srcbuf[i];
+    }
+    else {
+        /* Copy in descencing order */
+        for (i = bytelen - 1; i >= 0; i--)
+            destbuf[i] = srcbuf[i];
+    }
+
+    PyBuffer_Release(&srcview);
+    return 0;
+
+_error:
+    PyBuffer_Release(&srcview);
+    return -1;
 }
 
+static PyObject *
+memory_richcompare(PyObject *v, PyObject *w, int op)
+{
+	Py_buffer vv, ww;
+	int equal = 0;
+	PyObject *res;
+
+	vv.obj = NULL;
+	ww.obj = NULL;
+	if (op != Py_EQ && op != Py_NE)
+		goto _notimpl;
+	if (PyObject_GetBuffer(v, &vv, PyBUF_CONTIG_RO) == -1) {
+		PyErr_Clear();
+		goto _notimpl;
+	}
+	if (PyObject_GetBuffer(w, &ww, PyBUF_CONTIG_RO) == -1) {
+		PyErr_Clear();
+		goto _notimpl;
+	}
+
+	if (vv.itemsize != ww.itemsize || vv.len != ww.len)
+		goto _end;
+
+	equal = !memcmp(vv.buf, ww.buf, vv.len * vv.itemsize);
+
+_end:
+	PyBuffer_Release(&vv);
+	PyBuffer_Release(&ww);
+	if ((equal && op == Py_EQ) || (!equal && op == Py_NE))
+		res = Py_True;
+	else
+		res = Py_False;
+	Py_INCREF(res);
+	return res;
+
+_notimpl:
+	PyBuffer_Release(&vv);
+	PyBuffer_Release(&ww);
+	Py_INCREF(Py_NotImplemented);
+	return Py_NotImplemented;
+}
+
+
 /* As mapping */
 static PyMappingMethods memory_as_mapping = {
 	(lenfunc)memory_length, /*mp_length*/
@@ -591,7 +789,7 @@
 	memory_doc,				/* tp_doc */
 	0,					/* tp_traverse */
 	0,					/* tp_clear */
-	0,		                	/* tp_richcompare */
+	memory_richcompare,                     /* tp_richcompare */
 	0,					/* tp_weaklistoffset */
 	0,					/* tp_iter */
 	0,					/* tp_iternext */