[Python-checkins] r46447 - in sandbox/trunk/hotbuffer: Modules/_hotbuf.c README.txt hotbuf.py test_hotbuf.py

martin.blais python-checkins at python.org
Sat May 27 13:36:38 CEST 2006


Author: martin.blais
Date: Sat May 27 13:36:37 2006
New Revision: 46447

Modified:
   sandbox/trunk/hotbuffer/Modules/_hotbuf.c
   sandbox/trunk/hotbuffer/README.txt
   sandbox/trunk/hotbuffer/hotbuf.py
   sandbox/trunk/hotbuffer/test_hotbuf.py
Log:
Simplified and revamped the hot buffer

Modified: sandbox/trunk/hotbuffer/Modules/_hotbuf.c
==============================================================================
--- sandbox/trunk/hotbuffer/Modules/_hotbuf.c	(original)
+++ sandbox/trunk/hotbuffer/Modules/_hotbuf.c	Sat May 27 13:36:37 2006
@@ -34,7 +34,7 @@
 
 
 /* ===========================================================================
- * Byte Buffer object implementation
+ * Object declaration
  */
 
 
@@ -62,7 +62,6 @@
  capacity values:
 
  0 <= position <= limit <= capacity
- 0 <= mark_position <= mark_limit <= capacity
 
 */
 typedef struct {
@@ -85,45 +84,55 @@
     /* The limit position in the buffer. */
     Py_ssize_t b_limit;
 
-    /* The mark (position and limit), which save the current position and
-       limit on save(), to be reset later with restore().  The mark variables are
-       set to -1 to indicate that the mark is unset.
-    */
-    Py_ssize_t b_mark_position;
-    Py_ssize_t b_mark_limit;
-
 } PyHotbufObject;
 
 
-/*
- * Given a hotbuf object, return the buffer memory (in 'ptr' and 'size') and
- * true if there was no error.
+
+/* ===========================================================================
+ * Private Declarations
  */
 
-/* Internal Methods */
-
-static int
-hotbuf_advance_internal(PyHotbufObject *self, Py_ssize_t nbytes)
-{
-    Py_ssize_t newposition = self->b_position + nbytes;
-    if (newposition > self->b_limit) {
-        PyErr_SetString(BoundaryError,
-                        "position must be smaller than limit");
-        return -1;
+/*
+ * Inline error check for the given position, check that it is within the
+ * buffer's limits, if not return error.
+ */
+#define CHECK_LIMIT_RETURN(pos, eval)                                   \
+    if ( pos < 0 ) {                                                    \
+        PyErr_SetString(BoundaryError,                                  \
+                        "attempted access before buffer");              \
+        return eval;                                                    \
+    }                                                                   \
+    if ( pos > self->b_limit ) {                                        \
+        PyErr_SetString(BoundaryError,                                  \
+                        "attempted access beyond buffer limit");        \
+        return eval;                                                    \
+    }
+
+#define CHECK_CAPACITY_RETURN(pos, eval)                        \
+    if ( pos < 0 ) {                                            \
+        PyErr_SetString(BoundaryError,                          \
+                        "attempted access before buffer");      \
+        return eval;                                            \
+    }                                                           \
+    if ( pos > self->b_capacity ) {                             \
+        PyErr_SetString(BoundaryError,                          \
+                        "attempted access beyond buffer");      \
+        return eval;                                            \
     }
 
-    /* Set the new position */
-    self->b_position = newposition;
-
-    return 0;
-}
+/*
+ * Calculate the size of the buffer window between position and limit
+ */
+#define WINDOW_LENGTH(self)    self->b_limit - self->b_position
 
 
-/* Methods */
+
+/* ===========================================================================
+ * Constructors / Destructors
+ */
 
 /*
- * Constructor.  Note that we allocate the memory ourselves, unlike
- * the buffer object.
+ * Constructor.  Note that we allocate memory here.
  */
 static PyObject *
 hotbuf_new(PyTypeObject *type, PyObject *args, PyObject *kw)
@@ -149,7 +158,7 @@
     if ( ptr == NULL ) {
         return PyErr_NoMemory();
     }
-    
+
     /* Allocate the Python object itself. */
     new = (PyHotbufObject *) type->tp_alloc(type, 0);
     if (new == NULL) {
@@ -159,11 +168,10 @@
 
     /* Initialize the members */
     new->b_ptr = ptr;
+    new->b_capacity = capacity;
+
     new->b_position = 0;
     new->b_limit = capacity;
-    new->b_mark_position = -1;
-    new->b_mark_limit = -1;
-    new->b_capacity = capacity;
 
     return (PyObject*)new;
 }
@@ -172,7 +180,6 @@
 /*
  * Destructor.
  */
-
 static void
 hotbuf_dealloc(PyHotbufObject *self)
 {
@@ -184,6 +191,11 @@
 }
 
 
+
+/* ===========================================================================
+ * Public (Exposed) Declarations
+ */
+
 /*
  * Comparison.  We compare the active windows, not the entire allocated buffer
  * memory.
@@ -194,8 +206,8 @@
     Py_ssize_t len_self, len_other, min_len;
     int cmp;
 
-    len_self = self->b_limit - self->b_position;
-    len_other = other->b_limit - other->b_position;
+    len_self = WINDOW_LENGTH(self);
+    len_other = WINDOW_LENGTH(other);
 
     min_len = ((len_self < len_other) ? len_self : len_other);
     if (min_len > 0) {
@@ -216,12 +228,10 @@
 hotbuf_repr(PyHotbufObject *self)
 {
     return PyString_FromFormat(
-        "<hotbuf position %zd, limit %zd, capacity %zd, mark %zd %zd, ptr %p, at %p>",
+        "<hotbuf position %zd, limit %zd, capacity %zd, ptr %p, at %p>",
         self->b_position,
         self->b_limit,
         self->b_capacity,
-        self->b_mark_position,
-        self->b_mark_limit,
         self->b_ptr,
         self);
 }
@@ -234,8 +244,7 @@
 {
     assert( self->b_position <= self->b_limit );
     return PyString_FromStringAndSize(
-        (const char *)(self->b_ptr + self->b_position),
-        self->b_limit - self->b_position);
+        (const char *)(self->b_ptr + self->b_position), WINDOW_LENGTH(self));
 }
 
 
@@ -244,188 +253,48 @@
  * Object Methods (basic interface)
  */
 
-PyDoc_STRVAR(setposition__doc__,
-             "B.setposition(int)\n\
-\n\
-Sets this buffer's position. If the given position is\n\
-larger than the limit an exception is raised.");
-
-static PyObject*
-hotbuf_setposition(PyHotbufObject *self, PyObject* arg)
-{
-    Py_ssize_t newposition;
-
-    newposition = PyInt_AsSsize_t(arg);
-    if (newposition == -1 && PyErr_Occurred())
-        return NULL;
-
-    if ( newposition > self->b_capacity ) {
-        PyErr_SetString(BoundaryError,
-                        "position must be smaller than capacity");
-        return NULL;
-    }
-
-    /* Set the new position */
-    self->b_position = newposition;
-
-    Py_RETURN_NONE;
-}
-
-
-PyDoc_STRVAR(advance__doc__,
-             "B.advance(int)\n\
-\n\
-Advance this buffer's position by the given number of bytes. \n\
-If the given position is larger than the limit an exception \n\
-is raised.");
-
-static PyObject*
-hotbuf_advance(PyHotbufObject *self, PyObject* arg)
-{
-    Py_ssize_t nbytes = PyInt_AsSsize_t(arg);
-    if (nbytes == -1 && PyErr_Occurred())
-        return NULL;
-
-    if (hotbuf_advance_internal(self, nbytes) < 0)
-        return NULL;
-
-    Py_RETURN_NONE;
-}
-
-
-
-
-PyDoc_STRVAR(setlimit__doc__,
-             "B.setlimit(int)\n\
-\n\
-Sets this buffer's limit. If the position is larger than the new limit\n\
-then it is set to the new limit.");
-
-static PyObject*
-hotbuf_setlimit(PyHotbufObject *self, PyObject* arg)
-{
-    Py_ssize_t newlimit;
-
-    newlimit = PyInt_AsSsize_t(arg);
-    if (newlimit == -1 && PyErr_Occurred())
-        return NULL;
-
-    if ( newlimit > self->b_capacity ) {
-        PyErr_SetString(BoundaryError,
-                        "limit must be smaller than capacity");
-        return NULL;
-    }
-
-    /* Set the new limit. */
-    self->b_limit = newlimit;
-
-    /* If the position is larger than the new limit, set it to the new
-       limit. */
-    if ( self->b_position > self->b_limit )
-        self->b_position = newlimit;
-
-    Py_RETURN_NONE;
-}
-
-
-PyDoc_STRVAR(setwindow__doc__,
-             "B.setwindow(int)\n\
+PyDoc_STRVAR(setlen__doc__,
+"B.setlen(int)\n\
 \n\
 Sets this buffer's limit to be beyond position by the given\n\
 number number of bytes. If the limit is larger than the \n\
 capacity an BoundaryError is raised.");
 
 static PyObject*
-hotbuf_setwindow(PyHotbufObject *self, PyObject* arg)
-{
-    Py_ssize_t window;
-    Py_ssize_t newlimit;
-
-    window = PyInt_AsSsize_t(arg);
-    if (window == -1 && PyErr_Occurred())
-        return NULL;
-
-    newlimit = self->b_position + window;
-    if ( newlimit > self->b_capacity ) {
-        PyErr_SetString(BoundaryError,
-                        "limit must be smaller than capacity");
-        return NULL;
-    }
-
-    /* Set the new limit. */
-    self->b_limit = newlimit;
-
-    Py_RETURN_NONE;
-}
-
-
-PyDoc_STRVAR(save__doc__,
-             "B.save()\n\
-\n\
-Save this buffer's position and limit for later.");
-
-static PyObject*
-hotbuf_save(PyHotbufObject *self)
-{
-    self->b_mark_position = self->b_position;
-    self->b_mark_limit = self->b_limit;
-    Py_RETURN_NONE;
-}
-
-
-PyDoc_STRVAR(restore__doc__,
-             "B.restore([advbytes]) -> int\n\
-\n\
-Resets this buffer's position to the previously-marked\n\
-position and limit.  Invoking this method neither changes nor\n\
-discards the mark's value.  An BoundaryError is raised if the\n\
-mark has not been set.  This method returns the new\n\
-position's value.  If you specify a number of bytes via \n\
-'advbytes', the method advances the position by that many bytes.");
-
-static PyObject*
-hotbuf_restore(PyHotbufObject *self, PyObject* args)
+hotbuf_setlen(PyHotbufObject *self, PyObject* arg)
 {
-    Py_ssize_t advbytes = 0;
-    Py_ssize_t newposition = -1;
+    Py_ssize_t window_size = -1;
+    Py_ssize_t new_limit;
 
-    /* Validate that the mark is set. */
-    if ( self->b_mark_position == -1 || self->b_mark_limit == -1 ) {
-        PyErr_SetString(BoundaryError,
-                        "mark has not been yet set");
+    /* Read and validate the window size */
+    window_size = PyInt_AsSsize_t(arg);
+    if (window_size == -1 && PyErr_Occurred())
         return NULL;
-    }
-
-    /* Extract and validate advbytes */
-    if (!PyArg_ParseTuple(args, "|n:hotbuf", &advbytes))
-        return NULL;
-
-    if (advbytes < 0) {
-        PyErr_SetString(PyExc_ValueError,
-                        "advbytes must be a positive number");
+    if (window_size < 0) {
+        PyErr_SetString(BoundaryError, "window size must be positive");
         return NULL;
     }
 
-    /* Validate the new position, if specified */
-    newposition = self->b_mark_position + advbytes;
-    if (newposition > self->b_limit) {
+    /* Validate the new limit */
+    new_limit = self->b_position + window_size;
+    if ( new_limit > self->b_capacity ) {
         PyErr_SetString(BoundaryError,
-                        "new position must be smaller than limit");
+                        "new limit is beyond buffer");
         return NULL;
     }
 
-    self->b_position = newposition;
-    self->b_limit = self->b_mark_limit;
+    /* Set the new limit. */
+    self->b_limit = new_limit;
 
-    return PyInt_FromLong(newposition);
+    Py_RETURN_NONE;
 }
 
 
 PyDoc_STRVAR(clear__doc__,
-             "B.clear()\n\
+"B.clear()\n\
 \n\
 Clears this buffer. The position is set to zero, the limit is set to\n\
-the capacity, and the mark is discarded.\n\
+the capacity.\n\
 \n\
 Invoke this method before using a sequence of channel-read or put\n\
 operations to fill this buffer. For example:\n\
@@ -442,17 +311,15 @@
 {
     self->b_position = 0;
     self->b_limit = self->b_capacity;
-    self->b_mark_position = self->b_mark_limit = -1;
     Py_RETURN_NONE;
 }
 
 
 PyDoc_STRVAR(flip__doc__,
-             "B.flip()\n\
+"B.flip()\n\
 \n\
 Flips this buffer. The limit is set to the current position and then\n\
-the position is set to zero. If the mark is defined then it is\n\
-discarded.\n\
+the position is set to zero. \n\
 \n\
 After a sequence of channel-read or put operations, invoke this method\n\
 to prepare for a sequence of channel-write or relative get\n\
@@ -471,35 +338,12 @@
 {
     self->b_limit = self->b_position;
     self->b_position = 0;
-    self->b_mark_position = self->b_mark_limit = -1;
-    Py_RETURN_NONE;
-}
-
-
-PyDoc_STRVAR(rewind__doc__,
-             "B.rewind()\n\
-\n\
-Rewinds this buffer. The position is set to zero.\n\
-\n\
-Invoke this method before a sequence of channel-write or get\n\
-operations, assuming that the limit has already been set\n\
-appropriately. For example:\n\
-\n\
-     out.write(buf)    # Write remaining data\n\
-     buf.rewind()      # Rewind buffer\n\
-     buf.get(array)    # Copy data into array\n\
-");
-
-static PyObject*
-hotbuf_rewind(PyHotbufObject *self)
-{
-    self->b_position = 0;
     Py_RETURN_NONE;
 }
 
 
 PyDoc_STRVAR(compact__doc__,
-             "B.compact()\n\
+"B.compact()\n\
 \n\
 Compacts this buffer.\n\
 \n\
@@ -509,7 +353,7 @@
 p + 1 is copied to index one, and so forth until the byte at index\n\
 limit() - 1 is copied to index n = limit() - 1 - p. The buffer's\n\
 position is then set to n+1 and its limit is set to its\n\
-capacity. The mark, if defined, is discarded.\n\
+capacity.\n\
 \n\
 The buffer's position is set to the number of bytes copied, rather\n\
 than to zero, so that an invocation of this method can be followed\n\
@@ -535,7 +379,7 @@
     Py_ssize_t length;
 
     /* Calculate the number of bytes in the active window */
-    length = self->b_limit - self->b_position;
+    length = WINDOW_LENGTH(self);
 
     /* Move the memory from the active window to the beginning of the
        allocated buffer (only if we need to). */
@@ -545,7 +389,6 @@
 
     self->b_position = length;
     self->b_limit = self->b_capacity;
-    self->b_mark_position = self->b_mark_limit = -1;
 
     Py_RETURN_NONE;
 }
@@ -556,50 +399,47 @@
  * Object Methods (get/put methods)
  */
 
-PyDoc_STRVAR(get__doc__,
-             "B.get*() -> data\n\
-\n\
-Relative get methods. \n\
-Reads something at this buffer's current position, \n\
-and then increments the position.\n\
-An BoundaryError is raised if the position is at the end of the buffer.");
-
-PyDoc_STRVAR(put__doc__,
-             "B.put*(data)\n\
+PyDoc_STRVAR(getbyte__doc__,
+"B.getbyte() -> data\n\
 \n\
-Relative put methods. \n\
-Writes the given byte into this buffer at the current position,\n\
+Reads a byte at this buffer's current position, \n\
 and then increments the position.\n\
-An BoundaryError is raised if the position is at the end of the buffer.");
-
-
-/* Check if we're going to be trying to year beyond the buffer active
-   window limit, and if so, sets and error and return */
-#define CHECK_LIMIT_ERROR(sz)                                   \
-    if ( (self->b_position + sz) > self->b_limit ) {            \
-        PyErr_SetString(BoundaryError,                       \
-                        "attempted read beyond buffer limit");  \
-        return NULL;                                            \
-    }
-
+A BoundaryError is raised if the position is at the end of the buffer.");
 
 static PyObject*
 hotbuf_getbyte(PyHotbufObject *self)
 {
     unsigned char byte;
-    CHECK_LIMIT_ERROR(sizeof(byte));
+    Py_ssize_t new_position;
+
+    /* Validate new position */
+    new_position = self->b_position + sizeof(byte);
+    
+    CHECK_LIMIT_RETURN(new_position, NULL);
 
+    /* Read the byte and return it */
     byte = *(unsigned char*)(self->b_ptr + self->b_position);
-    self->b_position += sizeof(byte);
+    self->b_position = new_position;
+
     return PyInt_FromLong(byte);
 }
 
+
+PyDoc_STRVAR(putbyte__doc__,
+"B.putbyte(byte)\n\
+\n\
+Writes the given byte into this buffer at the current position,\n\
+and then increment the position.\n\
+A BoundaryError is raised if the position is at the end of the buffer.");
+
 static PyObject*
 hotbuf_putbyte(PyHotbufObject *self, PyObject* arg)
 {
     int byte_i;
     unsigned char byte;
+    Py_ssize_t new_position;
 
+    /* Parse, validate and convert the byte to be written */
     byte_i = PyInt_AsLong(arg);
     if ( byte_i > 255 ) {
         PyErr_SetString(PyExc_ValueError,
@@ -608,15 +448,81 @@
     }
     byte = (unsigned char)byte_i;
 
-    CHECK_LIMIT_ERROR(sizeof(byte));
+    /* Validate the new position */
+    new_position = self->b_position + sizeof(byte);
+    CHECK_LIMIT_RETURN(new_position, NULL);
+
+    /* Write the byte and advance the position */
     *(unsigned char*)(self->b_ptr + self->b_position) = byte;
-    self->b_position += sizeof(byte);
+    self->b_position = new_position;
+    Py_RETURN_NONE;
+}
+
+
+PyDoc_STRVAR(getbyterel__doc__,
+"B.getbyterel(offset) -> data\n\
+\n\
+Reads a byte at the given offset calculated from position. \n\
+This does then not increment the position.");
+
+static PyObject*
+hotbuf_getbyterel(PyHotbufObject *self, PyObject* args)
+{
+    Py_ssize_t offset;
+    Py_ssize_t read_position;
+
+    /* Extract the offset */
+    if (!PyArg_ParseTuple(args, "n:hotbuf", &offset))
+        return NULL;
+
+    /* Validate position */
+    read_position = self->b_position + offset;
+    CHECK_LIMIT_RETURN(read_position, NULL);
+
+    /* Note that we do not increment, on purpose. */
+    return PyInt_FromLong(*(unsigned char*)(read_position));
+}
+
+
+PyDoc_STRVAR(putbyterel__doc__,
+"B.putbyterel(offset, byte) -> data\n\
+\n\
+Writes a byte at the given offset calculated from position. \n\
+This does then not increment the position.");
+
+static PyObject*
+hotbuf_putbyterel(PyHotbufObject *self, PyObject* args)
+{
+    Py_ssize_t offset = -1;
+    Py_ssize_t write_position;
+    int byte_i;
+    unsigned char byte;
+
+    /* Extract the offset and byte */
+    if (!PyArg_ParseTuple(args, "ni:hotbuf", &offset, &byte_i))
+        return NULL;
+
+    /* Validate position */
+    write_position = self->b_position + offset;
+    CHECK_LIMIT_RETURN(write_position, NULL);
+
+    /* Validate the byte value */
+    if ( byte_i > 255 ) {
+        PyErr_SetString(PyExc_ValueError,
+                        "overflow for byte");
+        return NULL;
+    }
+    byte = (unsigned char)byte_i;
+
+    /* Write the byte and return */
+    *(unsigned char*)(self->b_ptr + write_position) = byte;
+
     Py_RETURN_NONE;
 }
 
 
 PyDoc_STRVAR(getstr__doc__,
-             "B.getstr([nbytes]) -> data\n\
+"B.getstr([nbytes]) -> data\n\
 \n\
 Extract a string of 'nbytes' bytes from the buffer and advance the\n\
 position accordingly.  If 'nbytes' is not specified, get the string\n\
@@ -636,7 +542,7 @@
     /* Validate positive */
     if (len == -1) {
         /* Using default value. */
-        len = self->b_limit - self->b_position;
+        len = WINDOW_LENGTH(self);
     }
     else if (len < 0) {
         PyErr_SetString(PyExc_ValueError,
@@ -644,7 +550,7 @@
         return NULL;
     }
 
-    CHECK_LIMIT_ERROR(len);
+    CHECK_LIMIT_RETURN(self->b_position + len, NULL);
 
     /* Extract the string object from the buffer */
     s = PyString_FromStringAndSize(
@@ -659,7 +565,7 @@
 
 
 PyDoc_STRVAR(putstr__doc__,
-             "B.putstr(str)\n\
+"B.putstr(str)\n\
 \n\
 Write a string of 'nbytes' bytes from the buffer and advance the \n\
 position accordingly.\n\
@@ -680,7 +586,7 @@
     instring = PyString_AS_STRING(arg);
     len = PyString_GET_SIZE(arg);
 
-    CHECK_LIMIT_ERROR(len);
+    CHECK_LIMIT_RETURN(self->b_position + len, NULL);
 
     /* Copy the string into the buffer */
     memcpy(self->b_ptr + self->b_position, instring, len);
@@ -692,7 +598,7 @@
 }
 
 PyDoc_STRVAR(unpack__doc__,
-             "B.unpack(structobj) -> v1, v2, ...\n\
+"B.unpack(structobj) -> v1, v2, ...\n\
 \n\
 Unpack the given structure directly from this buffer and advance\n\
 the position accordingly.");
@@ -705,6 +611,7 @@
     Py_ssize_t len = -1;
     PyObject *size_obj;
     PyObject *result;
+    Py_ssize_t new_position;
 
     if (str_size == NULL) {
         str_size = PyString_InternFromString("size");
@@ -729,25 +636,30 @@
         PyErr_SetString(PyExc_TypeError,
                         "unpack requires a single struct argument");
     }
-    
+
     len = PyInt_AsSsize_t(size_obj);
     if (len < 0)
         PyErr_SetString(PyExc_TypeError,
                         "unpack requires a single struct argument");
-    
-    CHECK_LIMIT_ERROR(len);
-    
-    result = PyObject_CallMethodObjArgs(structobj, 
+
+    CHECK_LIMIT_RETURN(self->b_position + len, NULL);
+
+    result = PyObject_CallMethodObjArgs(structobj,
                                         str_unpack_from, self, NULL);
-    
+
     if (result == NULL)
         return NULL;
-        
-    if (hotbuf_advance_internal(self, len) < 0) {
+
+    /* Advance beyond the packed data */
+    new_position = self->b_position + len;
+    if ( new_position > self->b_limit ) {
+        PyErr_SetString(BoundaryError,
+                        "attempted access beyond buffer limit");
         Py_DECREF(result);
-        result = NULL;
+        return NULL;
     }
-    
+    self->b_position = new_position;
+
     return result;
 }
 
@@ -772,7 +684,7 @@
     }
 
     result = fastsearch(self->b_ptr + self->b_position,
-                        self->b_limit - self->b_position,
+                        WINDOW_LENGTH(self),
                         PyString_AS_STRING(arg),
                         PyString_GET_SIZE(arg),
                         FAST_SEARCH);
@@ -799,7 +711,7 @@
     }
 
     result = fastsearch(self->b_ptr + self->b_position,
-                        self->b_limit - self->b_position,
+                        WINDOW_LENGTH(self),
                         PyString_AS_STRING(arg),
                         PyString_GET_SIZE(arg),
                         FAST_COUNT);
@@ -810,6 +722,7 @@
     return PyInt_FromSsize_t(result);
 }
 
+
 
 /* ===========================================================================
  * Buffer protocol methods
@@ -829,7 +742,7 @@
     }
 
     *pp = self->b_ptr + self->b_position;
-    return self->b_limit - self->b_position;
+    return WINDOW_LENGTH(self);
 }
 
 static Py_ssize_t
@@ -855,38 +768,15 @@
 static Py_ssize_t
 hotbuf_length(PyHotbufObject *self)
 {
-    return self->b_limit - self->b_position;
+    return WINDOW_LENGTH(self);
 }
 
 
 
 /* ===========================================================================
- * Object interfaces declaration
+ * Getters and setters
  */
 
-
-PyDoc_STRVAR(hotbuf_doc,
-             "hotbuf(capacity) -> hotbuf\n\
-\n\
-Return a new hotbuf with a buffer of fixed size 'capacity'.\n\
-\n\
-hotbuf is a C encapsulation of a fixed-size buffer of bytes in memory.\n\
-One can read and write objects of different primitive types directly\n\
-into it, without having to convert from/to strings.  Also, this is\n\
-meant for the network I/O functions (recv, recvfrom, send, sendto) to\n\
-read/write directly into without having to create temporary strings.\n\
-\n\
-Note that hotbuf is a direct Python equivalent of Java's NIO\n\
-ByteBuffer class.");
-
-
-
-#define OFF(x) offsetof(PyHotbufObject, x)
-
-/* 
-    Hotbuf Getters and setters
-*/
-
 static PyObject *
 hotbuf_get_capacity(PyHotbufObject *self, void *unused)
 {
@@ -902,20 +792,16 @@
 static int
 hotbuf_set_position(PyHotbufObject *self, PyObject *arg, void *unused)
 {
-    Py_ssize_t newposition;
+    Py_ssize_t new_position;
 
-    newposition = PyInt_AsSsize_t(arg);
-    if (newposition == -1 && PyErr_Occurred())
+    new_position = PyInt_AsSsize_t(arg);
+    if (new_position == -1 && PyErr_Occurred())
         return -1;
 
-    if (newposition > self->b_capacity) {
-        PyErr_SetString(BoundaryError,
-                        "position must be smaller than capacity");
-        return -1;
-    }
+    CHECK_LIMIT_RETURN(new_position, -1);
 
     /* Set the new position */
-    self->b_position = newposition;
+    self->b_position = new_position;
 
     return 0;
 }
@@ -929,68 +815,79 @@
 static int
 hotbuf_set_limit(PyHotbufObject *self, PyObject *arg, void *unused)
 {
-    Py_ssize_t newlimit;
+    Py_ssize_t new_limit;
 
-    newlimit = PyInt_AsSsize_t(arg);
-    if (newlimit == -1 && PyErr_Occurred())
+    new_limit = PyInt_AsSsize_t(arg);
+    if (new_limit == -1 && PyErr_Occurred())
         return -1;
 
-    if (newlimit > self->b_capacity) {
-        PyErr_SetString(BoundaryError,
-                        "limit must be smaller than capacity");
-        return -1;
-    }
+    CHECK_CAPACITY_RETURN(new_limit, -1);
 
     /* Set the new limit */
-    self->b_limit = newlimit;
+    self->b_limit = new_limit;
 
     /* If the position is larger than the new limit, set it to the new
        limit. */
-    if (self->b_position > self->b_limit)
-        self->b_position = newlimit;
+    if (self->b_position > self->b_limit) {
+        self->b_position = new_limit;
+    }
 
     return 0;
 }
 
-static PyObject *
-hotbuf_get_mark_position(PyHotbufObject *self, void *unused)
-{
-    return PyInt_FromSsize_t(self->b_mark_position);
-}
 
-static PyObject *
-hotbuf_get_mark_limit(PyHotbufObject *self, void *unused)
-{
-    return PyInt_FromSsize_t(self->b_mark_limit);
-}
+
+/* ===========================================================================
+ * Interfaces Declarations
+ */
+
+PyDoc_STRVAR(hotbuf_doc,
+"hotbuf(capacity) -> hotbuf\n\
+\n\
+Return a new hotbuf with a buffer of fixed size 'capacity'.\n\
+\n\
+hotbuf is a C encapsulation of a fixed-size buffer of bytes in memory.\n\
+One can read and write objects of different primitive types directly\n\
+into it, without having to convert from/to strings.  Also, this is\n\
+meant for the network I/O functions (recv, recvfrom, send, sendto) to\n\
+read/write directly into without having to create temporary strings.\n\
+\n\
+Note that hotbuf is a direct Python equivalent of Java's NIO\n\
+ByteBuffer class.");
+
 
 static PyGetSetDef hotbuf_getsetlist[] = {
-    {"capacity", (getter)hotbuf_get_capacity, (setter)NULL, "buffer's capacity", NULL},
-    {"position", (getter)hotbuf_get_position, (setter)hotbuf_set_position, "buffer's position", NULL},
-    {"limit", (getter)hotbuf_get_limit, (setter)hotbuf_set_limit, "buffer's limit", NULL},
-    {"mark_position", (getter)hotbuf_get_mark_position, (setter)NULL, "buffer's mark_position, -1 if not set", NULL},
-    {"mark_limit", (getter)hotbuf_get_mark_limit, (setter)NULL, "buffer's mark_limit, -1 if not set", NULL},
+    {"capacity", (getter)hotbuf_get_capacity, (setter)NULL,
+     "buffer's capacity", NULL},
+    {"position", (getter)hotbuf_get_position, (setter)hotbuf_set_position,
+     "buffer's position", NULL},
+    {"limit", (getter)hotbuf_get_limit, (setter)hotbuf_set_limit,
+     "buffer's limit", NULL},
     {NULL}
 };
 
 static PyMethodDef hotbuf_methods[] = {
     {"clear", (PyCFunction)hotbuf_clear, METH_NOARGS, clear__doc__},
-    {"setposition", (PyCFunction)hotbuf_setposition, METH_O, setposition__doc__},
-    {"advance", (PyCFunction)hotbuf_advance, METH_O, advance__doc__},
-    {"setlimit", (PyCFunction)hotbuf_setlimit, METH_O, setlimit__doc__},
-    {"setwindow", (PyCFunction)hotbuf_setwindow, METH_O, setwindow__doc__},
-    {"save", (PyCFunction)hotbuf_save, METH_NOARGS, save__doc__},
-    {"restore", (PyCFunction)hotbuf_restore, METH_VARARGS, restore__doc__},
+    {"setlen", (PyCFunction)hotbuf_setlen, METH_O, setlen__doc__},
+
     {"flip", (PyCFunction)hotbuf_flip, METH_NOARGS, flip__doc__},
-    {"rewind", (PyCFunction)hotbuf_rewind, METH_NOARGS, rewind__doc__},
     {"compact", (PyCFunction)hotbuf_compact, METH_NOARGS, compact__doc__},
-    {"getbyte", (PyCFunction)hotbuf_getbyte, METH_NOARGS, get__doc__},
-    {"putbyte", (PyCFunction)hotbuf_putbyte, METH_O, put__doc__},
+
+    {"getbyte", (PyCFunction)hotbuf_getbyte, METH_NOARGS, getbyte__doc__},
+    {"putbyte", (PyCFunction)hotbuf_putbyte, METH_O, putbyte__doc__},
+
+    {"getbyterel", (PyCFunction)hotbuf_getbyterel, METH_O, 
+     getbyterel__doc__},
+    {"putbyterel", (PyCFunction)hotbuf_putbyterel, METH_VARARGS, 
+     putbyterel__doc__},
+
     {"getstr", (PyCFunction)hotbuf_getstr, METH_VARARGS, getstr__doc__},
     {"putstr", (PyCFunction)hotbuf_putstr, METH_O, putstr__doc__},
+
     {"unpack", (PyCFunction)hotbuf_unpack, METH_O, unpack__doc__},
     {"find", (PyCFunction)hotbuf_find, METH_O, find__doc__},
     {"count", (PyCFunction)hotbuf_count, METH_O, count__doc__},
+
     {NULL, NULL} /* sentinel */
 };
 
@@ -1061,7 +958,7 @@
  */
 
 PyDoc_STRVAR(module_doc,
-             "This module defines an object type which can represent a fixed size\n\
+"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\
@@ -1099,16 +996,19 @@
     if (PyType_Ready(&PyHotbuf_Type) < 0)
         return;
 
-	if (BoundaryError == NULL) {
-		BoundaryError = PyErr_NewException("hotbuf.BoundaryError", NULL, NULL);
-		if (BoundaryError == NULL)
-			return;
-	}
-	Py_INCREF(BoundaryError);
-	PyModule_AddObject(m, "BoundaryError", BoundaryError);
+    if (BoundaryError == NULL) {
+        BoundaryError = PyErr_NewException(
+            "hotbuf.BoundaryError", NULL, NULL);
+        if (BoundaryError == NULL)
+            return;
+    }
+    Py_INCREF(BoundaryError);
+    PyModule_AddObject(m, "BoundaryError", BoundaryError);
+
     Py_INCREF((PyObject *)&PyHotbuf_Type);
     PyModule_AddObject(m, "HotbufType", (PyObject *)&PyHotbuf_Type);
     Py_INCREF((PyObject *)&PyHotbuf_Type);
     PyModule_AddObject(m, "_hotbuf", (PyObject *)&PyHotbuf_Type);
 }
 
+

Modified: sandbox/trunk/hotbuffer/README.txt
==============================================================================
--- sandbox/trunk/hotbuffer/README.txt	(original)
+++ sandbox/trunk/hotbuffer/README.txt	Sat May 27 13:36:37 2006
@@ -25,10 +25,12 @@
 
 * Remove the mark, save() and restore().
 
+* Implement the entire string protocol, since that will be a fast to contents
+
 * Make it possible to read from a file directly into a hotbuf
 
   - implement the file protocol (read(), write()) on the hotbuf object
-  - is there a file protocol?
+  - euh, is there a file protocol?
 
 * Implement relative get/put methods that don't increment the position.
 
@@ -45,6 +47,8 @@
 
 * Write a small PEP about this, when all is said and done.
 
+
+
 Other Features
 --------------
 

Modified: sandbox/trunk/hotbuffer/hotbuf.py
==============================================================================
--- sandbox/trunk/hotbuffer/hotbuf.py	(original)
+++ sandbox/trunk/hotbuffer/hotbuf.py	Sat May 27 13:36:37 2006
@@ -19,4 +19,5 @@
         if size > len(self):
             raise BoundaryError("attempted to write beyond buffer limit")
         structobj.pack_to(self, 0, *values)
-        self.advance(size)
+        self.position += size
+

Modified: sandbox/trunk/hotbuffer/test_hotbuf.py
==============================================================================
--- sandbox/trunk/hotbuffer/test_hotbuf.py	(original)
+++ sandbox/trunk/hotbuffer/test_hotbuf.py	Sat May 27 13:36:37 2006
@@ -33,96 +33,75 @@
         self.assertEquals(b.capacity, CAPACITY)
 
         # Play with the position
-        assert b.position == 0
-        b.setposition(10)
+        b.limit = 100
+        self.assertEquals(b.position, 0)
+        b.position = 10
         self.assertEquals(b.position, 10)
-        self.assertRaises(BoundaryError, b.setposition, CAPACITY + 1)
+        self.assertEquals(len(b), 90)
+        b.position = b.limit
+        self.assertEquals(b.position, b.limit)
+        def setposition( b, val ):
+            b.position = val
+        self.assertRaises(BoundaryError, setposition, b, -1)
+        self.assertRaises(BoundaryError, setposition, b, b.limit + 1)
+        self.assertRaises(BoundaryError, setposition, b, CAPACITY + 1)
 
         # Play with the limit
-        assert b.limit == CAPACITY
-        b.setlimit(CAPACITY - 10)
-        self.assertEquals(b.limit, CAPACITY - 10)
-        self.assertRaises(BoundaryError, b.setlimit, CAPACITY + 1)
-        b.setlimit(b.position - 1)
+        b.position = 10
+        b.limit = 100
+        self.assertEquals(b.limit, 100)
+        b.limit = 110
+        self.assertEquals(b.limit, 110)
+        def setlimit( b, val ):
+            b.limit = val
+        self.assertRaises(BoundaryError, setlimit, b, CAPACITY + 1)
+        b.limit = b.position - 1
         self.assertEquals(b.position, b.limit)
 
-        # Play with reset before the mark has been set.
-        self.assertRaises(BoundaryError, b.setlimit, CAPACITY + 1)
-
-        # Play with the mark
-        b.setposition(10)
-        b.setlimit(100)
-        b.save()
-        b.setposition(15)
-        self.assertEquals(b.mark_position, 10)
-
-        # Play with restore
-        b.setposition(10)
-        b.setlimit(100)
-        b.save()
-        b.setposition(0)
-        b.setlimit(b.capacity)
-        b.restore()
-        self.assertEquals((b.position, b.limit),
-                          (10, 100))
-
         # Play with clear
         b.clear()
-        self.assertEquals((b.position, b.limit, b.mark_position),
-                          (0, CAPACITY, -1))
+        self.assertEquals((b.position, b.limit), (0, CAPACITY))
 
         # Play with flip.
-        b.setposition(42)
-        b.setlimit(104)
-        b.save()
-        b.flip()
-        self.assertEquals((b.position, b.limit, b.mark_position),
-                          (0, 42, -1))
-
-        # Play with rewind.
-        b.setposition(42)
-        b.setlimit(104)
-        b.save()
-        b.rewind()
-        self.assertEquals((b.position, b.limit, b.mark_position),
-                          (0, 104, 42))
-
-        # Play with remaining.
-        self.assertEquals(len(b), 104)
-        b.setposition(10)
-        self.assertEquals(len(b), 94)
+        b.position = 42
+        b.limit = 104
+        b.flip()
+        self.assertEquals((b.position, b.limit), (0, 42))
+
+        # Play with length.
+        self.assertEquals(len(b), 42)
+        b.position = 10
+        self.assertEquals(len(b), 32)
 
         # Play with advance.
         self.assertEquals(b.position, 10)
-        b.advance(32)
+        b.position += 32
         self.assertEquals(b.position, 42)
 
-        self.assertRaises(BoundaryError, b.advance, CAPACITY)
+        self.assertRaises(BoundaryError, setposition, b, CAPACITY)
 
-        # Play with setwindow()
+        # Play with setlen()
         b.clear()
-        b.setwindow(12)
+        b.setlen(12)
         self.assertEquals((b.position, b.limit), (0, 12))
-        b.advance(3)
-        b.setwindow(12)
+        b.position += 3
+        b.setlen(12)
         self.assertEquals((b.position, b.limit), (3, 15))
 
     def test_compact( self ):
         b = hotbuf(CAPACITY)
 
-        b.setposition(100)
-        b.setlimit(200)
-        m = b.mark_position
+        b.position = 100
+        b.limit = 200
         b.compact()
-        self.assertEquals((b.position, b.limit, b.mark_position),
-                          (100, CAPACITY, -1))
+        self.assertEquals((b.position, b.limit), (100, CAPACITY))
 
         # Compare the text that gets compacted.
         b.clear()
-        b.setposition(100)
+        b.position = 100
         b.putstr(MSG)
-        b.setlimit(b.position)
-        b.setposition(100)
+        b.limit = b.position
+        b.position = 100
         b.compact()
         b.flip()
         self.assertEquals(str(b), MSG)
@@ -173,8 +152,8 @@
     def test_conversion( self ):
         b = hotbuf(CAPACITY)
 
-        b.setposition(100)
-        b.setlimit(132)
+        b.position = 100
+        b.limit = 132
 
         self.assertEquals(len(b), 32)
         s = str(b)
@@ -194,7 +173,7 @@
         # Pack directly into the buffer and compare the strings.
         b = hotbuf(CAPACITY)
         self.fmt.pack_to(b, 0, *ARGS)
-        b.setlimit(len(s))
+        b.limit = len(s)
         self.assertEquals(str(b), s)
 
     def test_pack_method(self):
@@ -204,7 +183,7 @@
 
         # Pack directly into the buffer and compare the strings.
         b = hotbuf(CAPACITY)
-        b.setlimit(len(s))
+        b.limit = len(s)
         b.pack(self.fmt, *ARGS)
         self.assertEquals(b.position, self.fmt.size)
         b.flip()
@@ -237,7 +216,7 @@
 
     def test_zerolen( self ):
         b = hotbuf(CAPACITY)
-        b.setlimit(0)
+        b.limit = 0
         self.assertEquals(str(b), '')
         self.assertEquals(b.getstr(), '')
 
@@ -257,7 +236,7 @@
         self.assertEquals(b.count('ab'), 1)
         self.assertEquals(b.count('d'), 2)
         self.assertEquals(b.count('1' * 100), 0)
-        b.advance(1)
+        b.position += 1
         self.assertEquals(b.count('ab'), 0)
         self.assertEquals(b.count('d'), 2)
         self.assertEquals(b.count('1' * 100), 0)
@@ -282,7 +261,7 @@
         self.assertEquals(b.find('ab'), 0)
         self.assertEquals(b.find('d'), 3)
         self.assertEquals(b.find('1' * 100), -1)
-        b.advance(1)
+        b.position += 1
         self.assertEquals(b.find('ab'), -1)
         self.assertEquals(b.find('d'), 2)
         self.assertEquals(b.find('1' * 100), -1)
@@ -294,7 +273,7 @@
     def test_nonzero(self):
         b = hotbuf(CAPACITY)
         self.assertEquals(bool(b), True)
-        b.setposition(b.limit)
+        b.position = b.limit
         self.assertEquals(bool(b), False)
 
 
@@ -419,6 +398,8 @@
         """
         Use case for newline-delimited data.
         """
+        newline, cr = ord('\n'), ord('\r')
+        
         # Initiallly put some data into the buffer.
         hot.putstr(read(len(hot)))
 
@@ -428,18 +409,25 @@
             abslimit = hot.limit
             mark_position = hot.position # setmark
 
+            print 1, repr(hot)
+
+
             # Loop over the current buffer contents
             while hot:
                 # Save the starting position
                 start = hot.position
 
+                print 2, repr(hot)
+
 ## FIXME we need to replace what follows by the hot.find method, the
 ## overhead of funcall for every char is too high
 
                 # Loop over all characters
                 while 1:
+                    print 3, repr(hot)
+
                     # If we got to the end of the line
-                    if hot.getbyte() == '\n':
+                    if hot.getbyte() == newline:
                         # Process the line we found
 
                         # Calculate how much characters are needed to
@@ -448,7 +436,7 @@
                         backup = 1
                         # Make sure we don't look before the first char
                         if end - start > 1:
-                            if hot.getbyte(end - 2) == '\r':
+                            if hot.getbyte(end - 2) == cr:
                                 backup = 2
 
                         # Restrict the window to the current line
@@ -469,6 +457,8 @@
                     if not hot:
                         break
 
+                print 4, repr(hot)
+
             # Set the position to the last marker
             hot.position = mark_position # reset
 
@@ -487,7 +477,7 @@
         """
         inp = StringIO(self.data1)
         hot = hotbuf(CAPACITY)
-
+        
         lineidx = [0]
         def assert_lines( hot ):
             "Assert the lines we process are the ones we expect."


More information about the Python-checkins mailing list