[Python-checkins] r68088 - in sandbox/trunk/io-c: _bufferedio.c _iomodule.h io.c

antoine.pitrou python-checkins at python.org
Wed Dec 31 03:35:06 CET 2008


Author: antoine.pitrou
Date: Wed Dec 31 03:35:05 2008
New Revision: 68088

Log:
mildly faster BufferedReader seeks, by caching the current raw position



Modified:
   sandbox/trunk/io-c/_bufferedio.c
   sandbox/trunk/io-c/_iomodule.h
   sandbox/trunk/io-c/io.c

Modified: sandbox/trunk/io-c/_bufferedio.c
==============================================================================
--- sandbox/trunk/io-c/_bufferedio.c	(original)
+++ sandbox/trunk/io-c/_bufferedio.c	Wed Dec 31 03:35:05 2008
@@ -3,6 +3,8 @@
 #include "pythread.h"
 #include "_iomodule.h"
 
+/* TODO: offsets must be off_t, not Py_ssize_t. See _fileio.c for examples */
+
 /*
  * BufferedIOBase class, inherits from IOBase.
  */
@@ -109,6 +111,9 @@
     PyObject *raw;
     int ok;    /* Initialized? */
 
+    /* Position inside the raw stream (-1 if unknown). */
+    Py_ssize_t raw_pos;
+
     /* A static buffer of size `buffer_size` */
     unsigned char *read_buf;
     /* Current reading pos in the buffer. */
@@ -340,39 +345,20 @@
 BufferedIOMixin_fileno(BufferedObject *self, PyObject *args)
 {
     CHECK_INITIALIZED(self)
-    return PyObject_CallMethod(self->raw, "fileno", NULL);
+    return PyObject_CallMethodObjArgs(self->raw, _PyIO_str_fileno, NULL);
 }
 
 static PyObject *
 BufferedIOMixin_isatty(BufferedObject *self, PyObject *args)
 {
     CHECK_INITIALIZED(self)
-    return PyObject_CallMethod(self->raw, "isatty", NULL);
+    return PyObject_CallMethodObjArgs(self->raw, _PyIO_str_isatty, NULL);
 }
 
 /*
  * Helpers
  */
 
-static int
-_Buffered_init(BufferedObject *self)
-{
-    Py_ssize_t n;
-    if (self->buffer_size <= 0) {
-        PyErr_SetString(PyExc_ValueError,
-            "buffer size must be strictly positive");
-        return -1;
-    }
-    /* Find out whether buffer_size is a power of 2 */
-    for (n = self->buffer_size - 1; n & 1; n >>= 1)
-        ;
-    if (n == 0)
-        self->buffer_mask = self->buffer_size - 1;
-    else
-        self->buffer_mask = 0;
-    return 0;
-}
-
 /* Returns the address of the `written` member if a BlockingIOError was
    raised, NULL otherwise. The error is always re-raised. */
 static Py_ssize_t *
@@ -402,10 +388,47 @@
         return -1;
     n = PyNumber_AsSsize_t(res, PyExc_ValueError);
     Py_DECREF(res);
+    self->raw_pos = n;
     /* TODO: sanity check (n >= 0) */
     return n;
 }
 
+static Py_ssize_t
+_Buffered_raw_seek(BufferedObject *self, Py_ssize_t target, int whence)
+{
+    PyObject *res;
+    Py_ssize_t n;
+    res = PyObject_CallMethod(self->raw, "seek", "ni", target, whence);
+    if (res == NULL)
+        return -1;
+    n = PyNumber_AsSsize_t(res, PyExc_ValueError);
+    Py_DECREF(res);
+    self->raw_pos = n;
+    /* TODO: sanity check (n >= 0) */
+    return n;
+}
+
+static int
+_Buffered_init(BufferedObject *self)
+{
+    Py_ssize_t n;
+    if (self->buffer_size <= 0) {
+        PyErr_SetString(PyExc_ValueError,
+            "buffer size must be strictly positive");
+        return -1;
+    }
+    /* Find out whether buffer_size is a power of 2 */
+    for (n = self->buffer_size - 1; n & 1; n >>= 1)
+        ;
+    if (n == 0)
+        self->buffer_mask = self->buffer_size - 1;
+    else
+        self->buffer_mask = 0;
+    if (_Buffered_raw_tell(self) == -1)
+        PyErr_Clear();
+    return 0;
+}
+
 
 /*
  * class BufferedReader
@@ -491,15 +514,18 @@
     n = PyNumber_AsSsize_t(res, PyExc_ValueError);
     Py_DECREF(res);
     /* TODO: sanity check (0 <= n <= len) */
+    if (n > 0 && self->raw_pos != -1)
+        self->raw_pos += n;
     return n;
 }
 
 static PyObject *
 _BufferedReader_read_unlocked(BufferedObject *self, Py_ssize_t n)
 {
-    PyObject *data, *chunks, *sep, *res = NULL;
+    PyObject *data, *chunks, *res = NULL;
     Py_ssize_t current_size, remaining, written;
     unsigned char *out;
+    static PyObject *sep = NULL;
 
     /* Special case for when the number of bytes to read is unspecified. */
     if (n == -1) {
@@ -550,19 +576,22 @@
                     return data;
                 }
                 else {
-                    Py_DECREF(data);
-                    sep = PyBytes_FromStringAndSize(NULL, 0);
                     if (sep == NULL) {
-                        Py_DECREF(chunks);
-                        return NULL;
+                        sep = PyBytes_FromStringAndSize(NULL, 0);
+                        if (sep == NULL) {
+                            Py_DECREF(data);
+                            Py_DECREF(chunks);
+                            return NULL;
+                        }
                     }
                     res =_PyBytes_Join(sep, chunks);
-                    Py_DECREF(sep);
                     Py_DECREF(chunks);
                     return res;
                 }
             }
             current_size += PyBytes_GET_SIZE(data);
+            if (self->raw_pos != -1)
+                self->raw_pos += PyBytes_GET_SIZE(data);
         }
     }
 
@@ -778,7 +807,7 @@
 static PyObject *
 BufferedReader_seek(BufferedObject *self, PyObject *args)
 {
-    Py_ssize_t current, target, avail;
+    Py_ssize_t current, target, avail, n;
     int whence = 0;
     PyObject *res = NULL;
 
@@ -790,24 +819,27 @@
 
     ENTER_BUFFERED_READER(self)
 
-    /* TODO: cache the value somewhere rather than always query it*/
-    current = _Buffered_raw_tell(self);
-    if (current == -1)
-        goto end;
-    avail = AVAILABLE_BYTES(self);
-    if (avail > 0 && whence != 2) {
+    if (whence != 2) {
         /* Check if seeking leaves us inside the current buffer,
            so as to return quickly if possible.
            Don't know how to do that when whence == 2, though. */
-        Py_ssize_t offset;
-        if (whence == 0)
-            offset = target - (current - avail);
-        else
-            offset = target;
-        if (offset >= -self->read_pos && offset <= avail) {
-            self->read_pos += offset;
-            res = PyLong_FromSsize_t(current - avail + offset);
+        current = self->raw_pos;
+        if (current == -1)
+            current = _Buffered_raw_tell(self);
+        if (current == -1)
             goto end;
+        avail = AVAILABLE_BYTES(self);
+        if (avail > 0) {
+            Py_ssize_t offset;
+            if (whence == 0)
+                offset = target - (current - avail);
+            else
+                offset = target;
+            if (offset >= -self->read_pos && offset <= avail) {
+                self->read_pos += offset;
+                res = PyLong_FromSsize_t(current - avail + offset);
+                goto end;
+            }
         }
     }
 
@@ -816,10 +848,11 @@
         target -= AVAILABLE_BYTES(self);
 
     /* TODO: align on block boundary and read buffer if needed? */
-    res = PyObject_CallMethod(self->raw, "seek", "ni", target, whence);
-    if (res == NULL)
+    n = _Buffered_raw_seek(self, target, whence);
+    if (n == -1)
         goto end;
-    if (_BufferedReader_reset_buf(self) < 0)
+    res = PyLong_FromSsize_t(n);
+    if (res != NULL && _BufferedReader_reset_buf(self) < 0)
         Py_CLEAR(res);
 
 end:
@@ -1641,16 +1674,20 @@
      * if the raw seek fails, we don't lose buffered data forever.
      */
 
-    res = PyObject_CallMethod(self->raw, "seek", "ni", pos, whence);
-    if (res == NULL)
-        return NULL;
-
     ENTER_BUFFERED_READER(self)
 
+    pos = _Buffered_raw_seek(self, pos, whence);
+    if (pos == -1)
+        goto end;
+    res = PyLong_FromSsize_t(pos);
+    if (res == NULL)
+        goto end;
+
     if (_BufferedReader_reset_buf(self) < 0
         || _BufferedWriter_reset_buf(self) < 0)
         Py_CLEAR(res);
 
+end:
     LEAVE_BUFFERED_READER(self)
     return res;
 }

Modified: sandbox/trunk/io-c/_iomodule.h
==============================================================================
--- sandbox/trunk/io-c/_iomodule.h	(original)
+++ sandbox/trunk/io-c/_iomodule.h	Wed Dec 31 03:35:05 2008
@@ -51,7 +51,9 @@
 /* Implementation details */
 
 extern PyObject *_PyIO_str_closed;
+extern PyObject *_PyIO_str_fileno;
 extern PyObject *_PyIO_str_flush;
+extern PyObject *_PyIO_str_isatty;
 extern PyObject *_PyIO_str_read;
 extern PyObject *_PyIO_str_readable;
 extern PyObject *_PyIO_str_readinto;

Modified: sandbox/trunk/io-c/io.c
==============================================================================
--- sandbox/trunk/io-c/io.c	(original)
+++ sandbox/trunk/io-c/io.c	Wed Dec 31 03:35:05 2008
@@ -2,12 +2,22 @@
 #include "structmember.h"
 #include "_iomodule.h"
 
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif /* HAVE_SYS_TYPES_H */
+
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif /* HAVE_SYS_STAT_H */
+
 PyObject *PyIOExc_UnsupportedOperation;
 
 /* Various interned strings */
 
 PyObject *_PyIO_str_closed;
+PyObject *_PyIO_str_fileno;
 PyObject *_PyIO_str_flush;
+PyObject *_PyIO_str_isatty;
 PyObject *_PyIO_str_read;
 PyObject *_PyIO_str_readable;
 PyObject *_PyIO_str_readinto;
@@ -614,8 +624,12 @@
     /* Interned strings */
     if (!(_PyIO_str_closed = PyUnicode_InternFromString("closed")))
         goto fail;
+    if (!(_PyIO_str_fileno = PyUnicode_InternFromString("fileno")))
+        goto fail;
     if (!(_PyIO_str_flush = PyUnicode_InternFromString("flush")))
         goto fail;
+    if (!(_PyIO_str_isatty = PyUnicode_InternFromString("isatty")))
+        goto fail;
     if (!(_PyIO_str_read = PyUnicode_InternFromString("read")))
         goto fail;
     if (!(_PyIO_str_readable = PyUnicode_InternFromString("readable")))


More information about the Python-checkins mailing list