[Python-checkins] r46118 - in python/branches/blais-bytebuf: Modules/bytebufmodule.c setup.py

martin.blais python-checkins at python.org
Tue May 23 18:19:50 CEST 2006


Author: martin.blais
Date: Tue May 23 18:19:49 2006
New Revision: 46118

Added:
   python/branches/blais-bytebuf/Modules/bytebufmodule.c
      - copied, changed from r46090, python/branches/blais-bytebuf/Objects/bufferobject.c
Modified:
   python/branches/blais-bytebuf/setup.py
Log:
Basic byte buffer class skeleton for adding fast I/O functions.

Copied: python/branches/blais-bytebuf/Modules/bytebufmodule.c (from r46090, python/branches/blais-bytebuf/Objects/bufferobject.c)
==============================================================================
--- python/branches/blais-bytebuf/Objects/bufferobject.c	(original)
+++ python/branches/blais-bytebuf/Modules/bytebufmodule.c	Tue May 23 18:19:49 2006
@@ -1,657 +1,353 @@
-
-/* Buffer object implementation */
+/* Bytebuf object interface */
 
 #include "Python.h"
 
+/* Note: the object's structure is private */
 
-typedef struct {
-	PyObject_HEAD
-	PyObject *b_base;
-	void *b_ptr;
-	Py_ssize_t b_size;
-	Py_ssize_t b_offset;
-	int b_readonly;
-	long b_hash;
-} PyBufferObject;
+#ifndef Py_BYTEBUFOBJECT_H
+#define Py_BYTEBUFOBJECT_H
+#ifdef __cplusplus
+extern "C" {
+#endif
 
 
-static int
-get_buf(PyBufferObject *self, void **ptr, Py_ssize_t *size)
-{
-	if (self->b_base == NULL) {
-		assert (ptr != NULL);
-		*ptr = self->b_ptr;
-		*size = self->b_size;
-	}
-	else {
-		Py_ssize_t count, offset;
-		readbufferproc proc;
-		PyBufferProcs *bp = self->b_base->ob_type->tp_as_buffer;
-		if ((*bp->bf_getsegcount)(self->b_base, NULL) != 1) {
-			PyErr_SetString(PyExc_TypeError,
-				"single-segment buffer object expected");
-			return 0;
-		}
-		if (self->b_readonly)
-			proc = bp->bf_getreadbuffer;
-		else
-			proc = (readbufferproc)bp->bf_getwritebuffer;
-		if ((count = (*proc)(self->b_base, 0, ptr)) < 0)
-			return 0;
-		/* apply constraints to the start/end */
-		if (self->b_offset > count)
-			offset = count;
-		else
-			offset = self->b_offset;
-		*(char **)ptr = *(char **)ptr + offset;
-		if (self->b_size == Py_END_OF_BUFFER)
-			*size = count;
-		else
-			*size = self->b_size;
-		if (offset + *size > count)
-			*size = count - offset;
-	}
-	return 1;
-}
+PyAPI_DATA(PyTypeObject) PyBytebuf_Type;
 
+#define PyBytebuf_Check(op) ((op)->ob_type == &PyBytebuf_Type)
 
-static PyObject *
-buffer_from_memory(PyObject *base, Py_ssize_t size, Py_ssize_t offset, void *ptr,
-		   int readonly)
-{
-	PyBufferObject * b;
+#define Py_END_OF_BYTEBUF       (-1)
 
-	if (size < 0 && size != Py_END_OF_BUFFER) {
-		PyErr_SetString(PyExc_ValueError,
-				"size must be zero or positive");
-		return NULL;
-	}
-	if (offset < 0) {
-		PyErr_SetString(PyExc_ValueError,
-				"offset must be zero or positive");
-		return NULL;
-	}
-
-	b = PyObject_NEW(PyBufferObject, &PyBuffer_Type);
-	if ( b == NULL )
-		return NULL;
-
-	Py_XINCREF(base);
-	b->b_base = base;
-	b->b_ptr = ptr;
-	b->b_size = size;
-	b->b_offset = offset;
-	b->b_readonly = readonly;
-	b->b_hash = -1;
+PyAPI_FUNC(PyObject *) PyBytebuf_New(Py_ssize_t size);
 
-	return (PyObject *) b;
+#ifdef __cplusplus
 }
+#endif
+#endif /* !Py_BYTEBUFOBJECT_H */
 
-static PyObject *
-buffer_from_object(PyObject *base, Py_ssize_t size, Py_ssize_t offset, int readonly)
-{
-	if (offset < 0) {
-		PyErr_SetString(PyExc_ValueError,
-				"offset must be zero or positive");
-		return NULL;
-	}
-	if ( PyBuffer_Check(base) && (((PyBufferObject *)base)->b_base) ) {
-		/* another buffer, refer to the base object */
-		PyBufferObject *b = (PyBufferObject *)base;
-		if (b->b_size != Py_END_OF_BUFFER) {
-			Py_ssize_t base_size = b->b_size - offset;
-			if (base_size < 0)
-				base_size = 0;
-			if (size == Py_END_OF_BUFFER || size > base_size)
-				size = base_size;
-		}
-		offset += b->b_offset;
-		base = b->b_base;
-	}
-	return buffer_from_memory(base, size, offset, NULL, readonly);
-}
 
+/* Byte Buffer object implementation */
 
-PyObject *
-PyBuffer_FromObject(PyObject *base, Py_ssize_t offset, Py_ssize_t size)
-{
-	PyBufferProcs *pb = base->ob_type->tp_as_buffer;
+/*
+ * bytebuf object structure declaration.
+ */
+typedef struct {
+    PyObject_HEAD
 
-	if ( pb == NULL ||
-	     pb->bf_getreadbuffer == NULL ||
-	     pb->bf_getsegcount == NULL )
-	{
-		PyErr_SetString(PyExc_TypeError, "buffer object expected");
-		return NULL;
-	}
+    /* Base pointer location */
+    void*      b_ptr;
 
-	return buffer_from_object(base, size, offset, 1);
-}
-
-PyObject *
-PyBuffer_FromReadWriteObject(PyObject *base, Py_ssize_t offset, Py_ssize_t size)
-{
-	PyBufferProcs *pb = base->ob_type->tp_as_buffer;
+    /* Total size in bytes of the area that we can access.  The allocated
+       memory must be at least as large as this size. */
+    Py_ssize_t b_size;
 
-	if ( pb == NULL ||
-	     pb->bf_getwritebuffer == NULL ||
-	     pb->bf_getsegcount == NULL )
-	{
-		PyErr_SetString(PyExc_TypeError, "buffer object expected");
-		return NULL;
-	}
+} PyBytebufObject;
 
-	return buffer_from_object(base, size,  offset, 0);
-}
 
-PyObject *
-PyBuffer_FromMemory(void *ptr, Py_ssize_t size)
-{
-	return buffer_from_memory(NULL, size, 0, ptr, 1);
-}
-
-PyObject *
-PyBuffer_FromReadWriteMemory(void *ptr, Py_ssize_t size)
+/*
+ * Given a bytebuf object, return the buffer memory (in 'ptr' and 'size') and
+ * true if there was no error.
+ */
+static int
+get_buf(PyBytebufObject *self, void **ptr, Py_ssize_t *size)
 {
-	return buffer_from_memory(NULL, size, 0, ptr, 0);
+    assert(ptr != NULL);
+    *ptr = self->b_ptr;
+    *size = self->b_size;
+    return 1;
 }
 
+/*
+ * Create a new bytebuf where we allocate the memory ourselves.
+ */
 PyObject *
-PyBuffer_New(Py_ssize_t size)
+PyBytebuf_New(Py_ssize_t size)
 {
-	PyObject *o;
-	PyBufferObject * b;
+    PyObject *o;
+    PyBytebufObject * b;
 
-	if (size < 0) {
-		PyErr_SetString(PyExc_ValueError,
-				"size must be zero or positive");
-		return NULL;
-	}
-	/* XXX: check for overflow in multiply */
-	/* Inline PyObject_New */
-	o = (PyObject *)PyObject_MALLOC(sizeof(*b) + size);
-	if ( o == NULL )
-		return PyErr_NoMemory();
-	b = (PyBufferObject *) PyObject_INIT(o, &PyBuffer_Type);
-
-	b->b_base = NULL;
-	b->b_ptr = (void *)(b + 1);
-	b->b_size = size;
-	b->b_offset = 0;
-	b->b_readonly = 0;
-	b->b_hash = -1;
+    if (size < 0) {
+        PyErr_SetString(PyExc_ValueError,
+                        "size must be zero or positive");
+        return NULL;
+    }
+
+    /* FIXME: check for overflow in multiply */
+    o = (PyObject *)PyObject_MALLOC(sizeof(*b) + size);
+    if ( o == NULL )
+        return PyErr_NoMemory();
+    b = (PyBytebufObject *) PyObject_INIT(o, &PyBytebuf_Type);
+
+    /* We setup the memory buffer to be right after the object itself. */
+    b->b_ptr = (void *)(b + 1);
+    b->b_size = size;
 
-	return o;
+    return o;
 }
 
 /* Methods */
 
+/*
+ * Constructor.
+ */
 static PyObject *
-buffer_new(PyTypeObject *type, PyObject *args, PyObject *kw)
+bytebuf_new(PyTypeObject *type, PyObject *args, PyObject *kw)
 {
-	PyObject *ob;
-	Py_ssize_t offset = 0;
-	Py_ssize_t size = Py_END_OF_BUFFER;
+    Py_ssize_t size = -1;
 
-	if (!_PyArg_NoKeywords("buffer()", kw))
-		return NULL;
-
-	if (!PyArg_ParseTuple(args, "O|nn:buffer", &ob, &offset, &size))
-	    return NULL;
-	return PyBuffer_FromObject(ob, offset, size);
-}
+    if (!_PyArg_NoKeywords("bytebuf()", kw))
+        return NULL;
+ 
+    if (!PyArg_ParseTuple(args, "n:bytebuf", &size))
+        return NULL;
 
-PyDoc_STRVAR(buffer_doc,
-"buffer(object [, offset[, size]])\n\
-\n\
-Create a new buffer object which references the given object.\n\
-The buffer will reference a slice of the target object from the\n\
-start of the object (or at the specified offset). The slice will\n\
-extend to the end of the target object (or with the specified size).");
+    if ( size <= 0 ) {
+        PyErr_SetString(PyExc_TypeError,
+                        "size must be greater than zero");
+        return NULL;
+    }
 
+    return PyBytebuf_New(size);
+}
 
+/*
+ * Destructor.
+ */
 static void
-buffer_dealloc(PyBufferObject *self)
+bytebuf_dealloc(PyBytebufObject *self)
 {
-	Py_XDECREF(self->b_base);
-	PyObject_DEL(self);
+    /* Note: by virtue of the memory buffer being allocated with the PyObject
+       itself, this frees the buffer as well. */
+    PyObject_DEL(self);
 }
 
+/* 
+ * Comparison.
+ */
 static int
-buffer_compare(PyBufferObject *self, PyBufferObject *other)
+bytebuf_compare(PyBytebufObject *self, PyBytebufObject *other)
 {
-	void *p1, *p2;
-	Py_ssize_t len_self, len_other, min_len;
-	int cmp;
-
-	if (!get_buf(self, &p1, &len_self))
-		return -1;
-	if (!get_buf(other, &p2, &len_other))
-		return -1;
-	min_len = (len_self < len_other) ? len_self : len_other;
-	if (min_len > 0) {
-		cmp = memcmp(p1, p2, min_len);
-		if (cmp != 0)
-			return cmp;
-	}
-	return (len_self < len_other) ? -1 : (len_self > len_other) ? 1 : 0;
+    void *p1, *p2;
+    Py_ssize_t len_self, len_other, min_len;
+    int cmp;
+
+    if (!get_buf(self, &p1, &len_self))
+        return -1;
+    if (!get_buf(other, &p2, &len_other))
+        return -1;
+    min_len = (len_self < len_other) ? len_self : len_other;
+    if (min_len > 0) {
+        cmp = memcmp(p1, p2, min_len);
+        if (cmp != 0)
+            return cmp;
+    }
+    return (len_self < len_other) ? -1 : (len_self > len_other) ? 1 : 0;
 }
 
+
+/* 
+ * Conversion to 'repr' string.
+ */
 static PyObject *
-buffer_repr(PyBufferObject *self)
+bytebuf_repr(PyBytebufObject *self)
 {
-	const char *status = self->b_readonly ? "read-only" : "read-write";
-
-	if ( self->b_base == NULL )
-		return PyString_FromFormat("<%s buffer ptr %p, size %zd at %p>",
-					   status,
-					   self->b_ptr,
-					   self->b_size,
-					   self);
-	else
-		return PyString_FromFormat(
-			"<%s buffer for %p, size %zd, offset %zd at %p>",
-			status,
-			self->b_base,
-			self->b_size,
-			self->b_offset,
-			self);
-}
-
-static long
-buffer_hash(PyBufferObject *self)
-{
-	void *ptr;
-	Py_ssize_t size;
-	register Py_ssize_t len;
-	register unsigned char *p;
-	register long x;
-
-	if ( self->b_hash != -1 )
-		return self->b_hash;
-
-	/* XXX potential bugs here, a readonly buffer does not imply that the
-	 * underlying memory is immutable.  b_readonly is a necessary but not
-	 * sufficient condition for a buffer to be hashable.  Perhaps it would
-	 * be better to only allow hashing if the underlying object is known to
-	 * be immutable (e.g. PyString_Check() is true).  Another idea would
-	 * be to call tp_hash on the underlying object and see if it raises
-	 * an error. */
-	if ( !self->b_readonly )
-	{
-		PyErr_SetString(PyExc_TypeError,
-				"writable buffers are not hashable");
-		return -1;
-	}
-
-	if (!get_buf(self, &ptr, &size))
-		return -1;
-	p = (unsigned char *) ptr;
-	len = size;
-	x = *p << 7;
-	while (--len >= 0)
-		x = (1000003*x) ^ *p++;
-	x ^= size;
-	if (x == -1)
-		x = -2;
-	self->b_hash = x;
-	return x;
+    return PyString_FromFormat("<bytebuf ptr %p, size %zd at %p>",
+                               self->b_ptr,
+                               self->b_size,
+                               self);
 }
 
+/* 
+ * Conversion to string.
+ */
 static PyObject *
-buffer_str(PyBufferObject *self)
+bytebuf_str(PyBytebufObject *self)
 {
-	void *ptr;
-	Py_ssize_t size;
-	if (!get_buf(self, &ptr, &size))
-		return NULL;
-	return PyString_FromStringAndSize((const char *)ptr, size);
+    void *ptr;
+    Py_ssize_t size;
+    if (!get_buf(self, &ptr, &size))
+        return NULL;
+    return PyString_FromStringAndSize((const char *)ptr, size);
 }
 
-/* Sequence methods */
 
+/* Bytebuf methods */
+
+/*
+ * Returns the buffer for reading or writing.
+ */
 static Py_ssize_t
-buffer_length(PyBufferObject *self)
+bytebuf_getwritebuf(PyBytebufObject *self, Py_ssize_t idx, void **pp)
 {
-	void *ptr;
-	Py_ssize_t size;
-	if (!get_buf(self, &ptr, &size))
-		return -1;
-	return size;
+    Py_ssize_t size;
+    if ( idx != 0 ) {
+        PyErr_SetString(PyExc_SystemError,
+                        "accessing non-existent bytebuf segment");
+        return -1;
+    }
+    if (!get_buf(self, pp, &size))
+        return -1;
+    return size;
 }
 
-static PyObject *
-buffer_concat(PyBufferObject *self, PyObject *other)
+static Py_ssize_t
+bytebuf_getsegcount(PyBytebufObject *self, Py_ssize_t *lenp)
 {
-	PyBufferProcs *pb = other->ob_type->tp_as_buffer;
-	void *ptr1, *ptr2;
-	char *p;
-	PyObject *ob;
-	Py_ssize_t size, count;
-
-	if ( pb == NULL ||
-	     pb->bf_getreadbuffer == NULL ||
-	     pb->bf_getsegcount == NULL )
-	{
-		PyErr_BadArgument();
-		return NULL;
-	}
-	if ( (*pb->bf_getsegcount)(other, NULL) != 1 )
-	{
-		/* ### use a different exception type/message? */
-		PyErr_SetString(PyExc_TypeError,
-				"single-segment buffer object expected");
-		return NULL;
-	}
+    void *ptr;
+    Py_ssize_t size;
+    if (!get_buf(self, &ptr, &size))
+        return -1;
+    if (lenp)
+        *lenp = size;
+    return 1;
+}
 
- 	if (!get_buf(self, &ptr1, &size))
- 		return NULL;
- 
-	/* optimize special case */
-	if ( size == 0 )
-	{
-	    Py_INCREF(other);
-	    return other;
-	}
-
-	if ( (count = (*pb->bf_getreadbuffer)(other, 0, &ptr2)) < 0 )
-		return NULL;
-
- 	ob = PyString_FromStringAndSize(NULL, size + count);
-	if ( ob == NULL )
-		return NULL;
- 	p = PyString_AS_STRING(ob);
- 	memcpy(p, ptr1, size);
- 	memcpy(p + size, ptr2, count);
+static Py_ssize_t
+bytebuf_getcharbuf(PyBytebufObject *self, Py_ssize_t idx, const char **pp)
+{
+    void *ptr;
+    Py_ssize_t size;
+    if ( idx != 0 ) {
+        PyErr_SetString(PyExc_SystemError,
+                        "accessing non-existent bytebuf segment");
+        return -1;
+    }
+    if (!get_buf(self, &ptr, &size))
+        return -1;
+    *pp = (const char *)ptr;
+    return size;
+}
 
-	/* there is an extra byte in the string object, so this is safe */
-	p[size + count] = '\0';
 
-	return ob;
-}
+PyDoc_STRVAR(module_doc,
+             "This module defines an object type which can represent a fixed size\n\
+buffer of bytes in momery, from which you can directly read and into\n\
+which you can directly write objects in various other types.  This is\n\
+used to avoid buffer copies in network I/O as much as possible.  For\n\
+example, socket recv() can directly fill a byte buffer's memory and\n\
+send() can read the data to be sent from one as well.\n\
+\n\
+In addition, a byte buffer has two pointers within it, that delimit\n\
+an active slice, the current \"position\" and the \"limit\".  The\n\
+active region of a byte buffer is located within these boundaries.\n\
+\n\
+This class is heaviliy inspired from Java's NIO ByteBuffer class.\n\
+\n\
+The constructor is:\n\
+\n\
+bytebuf(nbytes) -- create a new bytebuf\n\
+");
 
-static PyObject *
-buffer_repeat(PyBufferObject *self, Py_ssize_t count)
-{
-	PyObject *ob;
-	register char *p;
-	void *ptr;
-	Py_ssize_t size;
-
-	if ( count < 0 )
-		count = 0;
-	if (!get_buf(self, &ptr, &size))
-		return NULL;
-	ob = PyString_FromStringAndSize(NULL, size * count);
-	if ( ob == NULL )
-		return NULL;
-
-	p = PyString_AS_STRING(ob);
-	while ( count-- )
-	{
-	    memcpy(p, ptr, size);
-	    p += size;
-	}
 
-	/* there is an extra byte in the string object, so this is safe */
-	*p = '\0';
+/* FIXME: needs an update */
 
-	return ob;
-}
+/* PyDoc_STRVAR(bytebuf_doc, */
+/*              "bytebuf(object [, offset[, size]])\n\ */
+/* \n\ */
+/* Create a new bytebuf object which references the given object.\n\ */
+/* The bytebuf will reference a slice of the target object from the\n\ */
+/* start of the object (or at the specified offset). The slice will\n\ */
+/* extend to the end of the target object (or with the specified size)."); */
 
-static PyObject *
-buffer_item(PyBufferObject *self, Py_ssize_t idx)
-{
-	void *ptr;
-	Py_ssize_t size;
-	if (!get_buf(self, &ptr, &size))
-		return NULL;
-	if ( idx < 0 || idx >= size ) {
-		PyErr_SetString(PyExc_IndexError, "buffer index out of range");
-		return NULL;
-	}
-	return PyString_FromStringAndSize((char *)ptr + idx, 1);
-}
+PyDoc_STRVAR(bytebuftype_doc,
+             "bytebuf(size) -> bytebuf\n\
+\n\
+Return a new bytebuf with a new buffer of fixed size 'size'.\n\
+\n\
+Methods:\n\
+\n\
+Attributes:\n\
+\n\
+");
 
-static PyObject *
-buffer_slice(PyBufferObject *self, Py_ssize_t left, Py_ssize_t right)
-{
-	void *ptr;
-	Py_ssize_t size;
-	if (!get_buf(self, &ptr, &size))
-		return NULL;
-	if ( left < 0 )
-		left = 0;
-	if ( right < 0 )
-		right = 0;
-	if ( right > size )
-		right = size;
-	if ( right < left )
-		right = left;
-	return PyString_FromStringAndSize((char *)ptr + left,
-					  right - left);
-}
 
-static int
-buffer_ass_item(PyBufferObject *self, Py_ssize_t idx, PyObject *other)
-{
-	PyBufferProcs *pb;
-	void *ptr1, *ptr2;
-	Py_ssize_t size;
-	Py_ssize_t count;
-
-	if ( self->b_readonly ) {
-		PyErr_SetString(PyExc_TypeError,
-				"buffer is read-only");
-		return -1;
-	}
-
-	if (!get_buf(self, &ptr1, &size))
-		return -1;
-
-	if (idx < 0 || idx >= size) {
-		PyErr_SetString(PyExc_IndexError,
-				"buffer assignment index out of range");
-		return -1;
-	}
-
-	pb = other ? other->ob_type->tp_as_buffer : NULL;
-	if ( pb == NULL ||
-	     pb->bf_getreadbuffer == NULL ||
-	     pb->bf_getsegcount == NULL )
-	{
-		PyErr_BadArgument();
-		return -1;
-	}
-	if ( (*pb->bf_getsegcount)(other, NULL) != 1 )
-	{
-		/* ### use a different exception type/message? */
-		PyErr_SetString(PyExc_TypeError,
-				"single-segment buffer object expected");
-		return -1;
-	}
-
-	if ( (count = (*pb->bf_getreadbuffer)(other, 0, &ptr2)) < 0 )
-		return -1;
-	if ( count != 1 ) {
-		PyErr_SetString(PyExc_TypeError,
-				"right operand must be a single byte");
-		return -1;
-	}
+static PyBufferProcs bytebuf_as_buffer = {
+    (readbufferproc)bytebuf_getwritebuf,
+    (writebufferproc)bytebuf_getwritebuf,
+    (segcountproc)bytebuf_getsegcount,
+    (charbufferproc)bytebuf_getcharbuf,
+};
 
-	((char *)ptr1)[idx] = *(char *)ptr2;
-	return 0;
-}
+PyTypeObject PyBytebuf_Type = {
+    PyObject_HEAD_INIT(&PyType_Type)
+    0,
+    "bytebuf",
+    sizeof(PyBytebufObject),
+    0,
+    (destructor)bytebuf_dealloc,                /* tp_dealloc */
+    0,                                  /* tp_print */
+    0,                                  /* tp_getattr */
+    0,                                  /* tp_setattr */
+    (cmpfunc)bytebuf_compare,           /* tp_compare */
+    (reprfunc)bytebuf_repr,                     /* tp_repr */
+    0,                                  /* tp_as_number */
+    0,                                  /* tp_as_sequence */
+    0,                                  /* tp_as_mapping */
+    0,                                  /* tp_hash */
+    0,                                  /* tp_call */
+    (reprfunc)bytebuf_str,                      /* tp_str */
+    PyObject_GenericGetAttr,            /* tp_getattro */
+    0,                                  /* tp_setattro */
+    &bytebuf_as_buffer,                 /* tp_as_buffer */
+    Py_TPFLAGS_DEFAULT,                 /* tp_flags */
+    bytebuftype_doc,                    /* tp_doc */
+    0,                                  /* tp_traverse */
+    0,                                  /* tp_clear */
+    0,                                  /* tp_richcompare */
+    0,                                  /* tp_weaklistoffset */
+    0,                                  /* tp_iter */
+    0,                                  /* tp_iternext */
+    0,                                  /* tp_methods */        
+    0,                                  /* tp_members */
+    0,                                  /* tp_getset */
+    0,                                  /* tp_base */
+    0,                                  /* tp_dict */
+    0,                                  /* tp_descr_get */
+    0,                                  /* tp_descr_set */
+    0,                                  /* tp_dictoffset */
+    0,                                  /* tp_init */
+    0,                                  /* tp_alloc */
+    bytebuf_new,                                /* tp_new */
+};
 
-static int
-buffer_ass_slice(PyBufferObject *self, Py_ssize_t left, Py_ssize_t right, PyObject *other)
-{
-	PyBufferProcs *pb;
-	void *ptr1, *ptr2;
-	Py_ssize_t size;
-	Py_ssize_t slice_len;
-	Py_ssize_t count;
-
-	if ( self->b_readonly ) {
-		PyErr_SetString(PyExc_TypeError,
-				"buffer is read-only");
-		return -1;
-	}
-
-	pb = other ? other->ob_type->tp_as_buffer : NULL;
-	if ( pb == NULL ||
-	     pb->bf_getreadbuffer == NULL ||
-	     pb->bf_getsegcount == NULL )
-	{
-		PyErr_BadArgument();
-		return -1;
-	}
-	if ( (*pb->bf_getsegcount)(other, NULL) != 1 )
-	{
-		/* ### use a different exception type/message? */
-		PyErr_SetString(PyExc_TypeError,
-				"single-segment buffer object expected");
-		return -1;
-	}
-	if (!get_buf(self, &ptr1, &size))
-		return -1;
-	if ( (count = (*pb->bf_getreadbuffer)(other, 0, &ptr2)) < 0 )
-		return -1;
-
-	if ( left < 0 )
-		left = 0;
-	else if ( left > size )
-		left = size;
-	if ( right < left )
-		right = left;
-	else if ( right > size )
-		right = size;
-	slice_len = right - left;
-
-	if ( count != slice_len ) {
-		PyErr_SetString(
-			PyExc_TypeError,
-			"right operand length must match slice length");
-		return -1;
-	}
 
-	if ( slice_len )
-	    memcpy((char *)ptr1 + left, ptr2, slice_len);
+/*********************** Install Module **************************/
 
-	return 0;
-}
+/* No functions in array module. */
+static PyMethodDef a_methods[] = {
+    {NULL, NULL, 0, NULL}        /* Sentinel */
+};
 
-/* Buffer methods */
 
-static Py_ssize_t
-buffer_getreadbuf(PyBufferObject *self, Py_ssize_t idx, void **pp)
+PyMODINIT_FUNC
+initbytebuf(void)
 {
-	Py_ssize_t size;
-	if ( idx != 0 ) {
-		PyErr_SetString(PyExc_SystemError,
-				"accessing non-existent buffer segment");
-		return -1;
-	}
-	if (!get_buf(self, pp, &size))
-		return -1;
-	return size;
-}
+    PyObject *m;
 
-static Py_ssize_t
-buffer_getwritebuf(PyBufferObject *self, Py_ssize_t idx, void **pp)
-{
-	if ( self->b_readonly )
-	{
-		PyErr_SetString(PyExc_TypeError, "buffer is read-only");
-		return -1;
-	}
-	return buffer_getreadbuf(self, idx, pp);
-}
+    PyBytebuf_Type.ob_type = &PyType_Type;
+    m = Py_InitModule3("bytebuf", a_methods, module_doc);
+    if (m == NULL)
+        return;
 
-static Py_ssize_t
-buffer_getsegcount(PyBufferObject *self, Py_ssize_t *lenp)
-{
-	void *ptr;
-	Py_ssize_t size;
-	if (!get_buf(self, &ptr, &size))
-		return -1;
-	if (lenp)
-		*lenp = size;
-	return 1;
+    Py_INCREF((PyObject *)&PyBytebuf_Type);
+    PyModule_AddObject(m, "BytebufType", (PyObject *)&PyBytebuf_Type);
+    Py_INCREF((PyObject *)&PyBytebuf_Type);
+    PyModule_AddObject(m, "bytebuf", (PyObject *)&PyBytebuf_Type);
+    /* No need to check the error here, the caller will do that */
 }
 
-static Py_ssize_t
-buffer_getcharbuf(PyBufferObject *self, Py_ssize_t idx, const char **pp)
-{
-	void *ptr;
-	Py_ssize_t size;
-	if ( idx != 0 ) {
-		PyErr_SetString(PyExc_SystemError,
-				"accessing non-existent buffer segment");
-		return -1;
-	}
-	if (!get_buf(self, &ptr, &size))
-		return -1;
-	*pp = (const char *)ptr;
-	return size;
-}
 
 
-static PySequenceMethods buffer_as_sequence = {
-	(lenfunc)buffer_length, /*sq_length*/
-	(binaryfunc)buffer_concat, /*sq_concat*/
-	(ssizeargfunc)buffer_repeat, /*sq_repeat*/
-	(ssizeargfunc)buffer_item, /*sq_item*/
-	(ssizessizeargfunc)buffer_slice, /*sq_slice*/
-	(ssizeobjargproc)buffer_ass_item, /*sq_ass_item*/
-	(ssizessizeobjargproc)buffer_ass_slice, /*sq_ass_slice*/
-};
+/* 
+   TODO
+   ----
+   - Update doc.
+   - Add hash function
+   - Add support for sequence methods.
 
-static PyBufferProcs buffer_as_buffer = {
-	(readbufferproc)buffer_getreadbuf,
-	(writebufferproc)buffer_getwritebuf,
-	(segcountproc)buffer_getsegcount,
-	(charbufferproc)buffer_getcharbuf,
-};
 
-PyTypeObject PyBuffer_Type = {
-	PyObject_HEAD_INIT(&PyType_Type)
-	0,
-	"buffer",
-	sizeof(PyBufferObject),
-	0,
-	(destructor)buffer_dealloc, 		/* tp_dealloc */
-	0,					/* tp_print */
-	0,					/* tp_getattr */
-	0,					/* tp_setattr */
-	(cmpfunc)buffer_compare,		/* tp_compare */
-	(reprfunc)buffer_repr,			/* tp_repr */
-	0,					/* tp_as_number */
-	&buffer_as_sequence,			/* tp_as_sequence */
-	0,					/* tp_as_mapping */
-	(hashfunc)buffer_hash,			/* tp_hash */
-	0,					/* tp_call */
-	(reprfunc)buffer_str,			/* tp_str */
-	PyObject_GenericGetAttr,		/* tp_getattro */
-	0,					/* tp_setattro */
-	&buffer_as_buffer,			/* tp_as_buffer */
-	Py_TPFLAGS_DEFAULT,			/* tp_flags */
-	buffer_doc,				/* tp_doc */
-	0,					/* tp_traverse */
-	0,					/* tp_clear */
-	0,					/* tp_richcompare */
-	0,					/* tp_weaklistoffset */
-	0,					/* tp_iter */
-	0,					/* tp_iternext */
-	0,					/* tp_methods */	
-	0,					/* tp_members */
-	0,					/* tp_getset */
-	0,					/* tp_base */
-	0,					/* tp_dict */
-	0,					/* tp_descr_get */
-	0,					/* tp_descr_set */
-	0,					/* tp_dictoffset */
-	0,					/* tp_init */
-	0,					/* tp_alloc */
-	buffer_new,				/* tp_new */
-};
+   Pending Issues
+   --------------
+   - Should we support weakrefs?
+
+*/
+

Modified: python/branches/blais-bytebuf/setup.py
==============================================================================
--- python/branches/blais-bytebuf/setup.py	(original)
+++ python/branches/blais-bytebuf/setup.py	Tue May 23 18:19:49 2006
@@ -334,6 +334,10 @@
 
         # array objects
         exts.append( Extension('array', ['arraymodule.c']) )
+
+        # array objects
+        exts.append( Extension('bytebuf', ['bytebufmodule.c']) )
+
         # complex math library functions
         exts.append( Extension('cmath', ['cmathmodule.c'],
                                libraries=math_libs) )


More information about the Python-checkins mailing list