[Python-checkins] r68354 - in sandbox/trunk/io-c: _bufferedio.c _iomodule.h io.c
antoine.pitrou
python-checkins at python.org
Tue Jan 6 02:04:25 CET 2009
Author: antoine.pitrou
Date: Tue Jan 6 02:04:25 2009
New Revision: 68354
Log:
Buffered{Reader,Writer,Random} overhaul: use a shared buffer and optimize mixed
reads and writes by avoiding spurious flushes.
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 Tue Jan 6 02:04:25 2009
@@ -39,11 +39,11 @@
if (data == NULL)
goto error;
- if (!PyBytes_Check(data)) {
- Py_DECREF(data);
- PyErr_SetString(PyExc_TypeError, "read() should return bytes");
+ if (!PyBytes_Check(data)) {
+ Py_DECREF(data);
+ PyErr_SetString(PyExc_TypeError, "read() should return bytes");
goto error;
- }
+ }
len = Py_SIZE(data);
memcpy(buf.buf, PyBytes_AS_STRING(data), len);
@@ -110,27 +110,30 @@
PyObject *raw;
int ok; /* Initialized? */
+ int readable;
+ int writable;
- /* Position inside the raw stream (-1 if unknown). */
- Py_ssize_t raw_pos;
+ /* Absolute position inside the raw stream (-1 if unknown). */
+ Py_ssize_t abs_pos;
/* A static buffer of size `buffer_size` */
- unsigned char *read_buf;
- /* Current reading pos in the buffer. */
- Py_ssize_t read_pos;
+ char *buffer;
+ /* Current logical position in the buffer. */
+ Py_ssize_t pos;
+ /* Position of the raw stream in the buffer. */
+ Py_ssize_t raw_pos;
+
/* Just after the last buffered byte in the buffer, or -1 if the buffer
- is invalid.
- Should most often be equal to buffer_size for "normal" blocking I/O. */
+ isn't ready for reading. */
Py_ssize_t read_end;
- PyThread_type_lock read_lock;
- /* A static buffer of size `buffer_size` */
- unsigned char *write_buf;
/* Just after the last byte actually written */
Py_ssize_t write_pos;
- /* Just after the last buffered byte */
+ /* Just after the last byte waiting to be written, or -1 if the buffer
+ isn't ready for writing. */
Py_ssize_t write_end;
- PyThread_type_lock write_lock;
+
+ PyThread_type_lock lock;
Py_ssize_t buffer_size;
Py_ssize_t buffer_mask;
@@ -139,23 +142,39 @@
PyObject *weakreflist;
} BufferedObject;
-/* These macros protect the BufferedObject against concurrent operations. */
-
-#define ENTER_BUFFERED_READER(self) \
- Py_BEGIN_ALLOW_THREADS \
- PyThread_acquire_lock(self->read_lock, 1); \
- Py_END_ALLOW_THREADS
+/*
+ Implementation notes:
+
+ * BufferedReader, BufferedWriter and BufferedRandom try to share most
+ methods (this is helped by the members `readable` and `writable`, which
+ are initialized in the respective constructors)
+ * They also share a single buffer for reading and writing. This enables
+ interleaved reads and writes without flushing. It also makes the logic
+ a bit trickier to get right.
+ * The absolute position of the raw stream is cached, if possible, in the
+ `abs_pos` member. It must be updated every time an operation is done
+ on the raw stream. If not sure, it can be reinitialized by calling
+ _Buffered_raw_tell(), which queries the raw stream (_Buffered_raw_seek()
+ also does it). To read it, use RAW_TELL().
+ * Three helpers, _BufferedReader_raw_read, _BufferedWriter_raw_write and
+ _BufferedWriter_flush_unlocked do a lot of useful housekeeping.
+
+ NOTE: we should try to maintain block alignment of reads and writes to the
+ raw stream (according to the buffer size), but for now it is only done
+ in read() and friends.
+
+ XXX: method naming is a bit messy.
+*/
-#define LEAVE_BUFFERED_READER(self) \
- PyThread_release_lock(self->read_lock);
+/* These macros protect the BufferedObject against concurrent operations. */
-#define ENTER_BUFFERED_WRITER(self) \
+#define ENTER_BUFFERED(self) \
Py_BEGIN_ALLOW_THREADS \
- PyThread_acquire_lock(self->write_lock, 1); \
+ PyThread_acquire_lock(self->lock, 1); \
Py_END_ALLOW_THREADS
-#define LEAVE_BUFFERED_WRITER(self) \
- PyThread_release_lock(self->write_lock);
+#define LEAVE_BUFFERED(self) \
+ PyThread_release_lock(self->lock);
#define CHECK_INITIALIZED(self) \
if (self->ok <= 0) { \
@@ -172,10 +191,28 @@
}
#define VALID_READ_BUFFER(self) \
- (self->read_end != -1)
+ (self->readable && self->read_end != -1)
-#define AVAILABLE_BYTES(self) \
- (VALID_READ_BUFFER(self) ? (self->read_end - self->read_pos) : 0)
+#define VALID_WRITE_BUFFER(self) \
+ (self->writable && self->write_end != -1)
+
+#define ADJUST_POSITION(self, _new_pos) \
+ do { \
+ self->pos = _new_pos; \
+ if (VALID_READ_BUFFER(self) && self->read_end < self->pos) \
+ self->read_end = self->pos; \
+ } while(0)
+
+#define READAHEAD(self) \
+ ((self->readable && VALID_READ_BUFFER(self)) \
+ ? (self->read_end - self->pos) : 0)
+
+#define RAW_OFFSET(self) \
+ (((VALID_READ_BUFFER(self) || VALID_WRITE_BUFFER(self)) \
+ && self->raw_pos >= 0) ? self->raw_pos - self->pos : 0)
+
+#define RAW_TELL(self) \
+ (self->abs_pos != -1 ? self->abs_pos : _Buffered_raw_tell(self))
#define MINUS_LAST_BLOCK(self, size) \
(self->buffer_mask ? \
@@ -186,28 +223,38 @@
static void
BufferedObject_dealloc(BufferedObject *self)
{
+ PyObject *res;
+ /* XXX this is inelegant */
+ if (Py_TYPE(self)->tp_del == NULL) {
+ /* We need to resurrect the object as calling close() can invoke
+ arbitrary code. */
+ ((PyObject *) self)->ob_refcnt++;
+ res = PyObject_CallMethodObjArgs((PyObject *) self, _PyIO_str_close,
+ NULL);
+ if (res == NULL) {
+ /* XXX dump exception on terminal?
+ But IOBase.__del__ prefers to remain silent... */
+ PyErr_Clear();
+ }
+ Py_XDECREF(res);
+ if (--((PyObject *) self)->ob_refcnt != 0)
+ return;
+ }
if (self->weakreflist != NULL)
PyObject_ClearWeakRefs((PyObject *)self);
Py_CLEAR(self->raw);
- if (self->read_buf) {
- PyMem_Free(self->read_buf);
- self->write_buf = NULL;
- }
- if (self->write_buf) {
- PyMem_Free(self->write_buf);
- self->write_buf = NULL;
- }
- if (self->read_lock) {
- PyThread_free_lock(self->read_lock);
- self->read_lock = NULL;
- }
- if (self->write_lock) {
- PyThread_free_lock(self->write_lock);
- self->write_lock = NULL;
+ if (self->buffer) {
+ PyMem_Free(self->buffer);
+ self->buffer = NULL;
+ }
+ if (self->lock) {
+ PyThread_free_lock(self->lock);
+ self->lock = NULL;
}
Py_CLEAR(self->dict);
+ Py_TYPE(self)->tp_free((PyObject *)self);
}
-
+
/*
* _BufferedIOMixin methods
@@ -232,6 +279,8 @@
* and a flush may be necessary to synch both views of the current
* file state.
*/
+ /* FIXME: raw objects don't have flush()
+ */
res = PyObject_CallMethodObjArgs(self->raw, _PyIO_str_flush, NULL);
if (res == NULL)
return NULL;
@@ -245,7 +294,7 @@
/* XXX: Should seek() be used, instead of passing the position
* XXX directly to truncate?
*/
- res = PyObject_CallMethod(self->raw, "truncate", "O", pos);
+ res = PyObject_CallMethodObjArgs(self->raw, _PyIO_str_truncate, pos, NULL);
Py_DECREF(pos);
return res;
@@ -355,6 +404,20 @@
return PyObject_CallMethodObjArgs(self->raw, _PyIO_str_isatty, NULL);
}
+
+/* Forward decls */
+static PyObject *
+_BufferedWriter_flush_unlocked(BufferedObject *, int);
+static void
+_BufferedReader_reset_buf(BufferedObject *self);
+static void
+_BufferedWriter_reset_buf(BufferedObject *self);
+static PyObject *
+_BufferedReader_peek_unlocked(BufferedObject *self, Py_ssize_t);
+static PyObject *
+_BufferedReader_read_unlocked(BufferedObject *self, Py_ssize_t);
+
+
/*
* Helpers
*/
@@ -388,7 +451,7 @@
return -1;
n = PyNumber_AsSsize_t(res, PyExc_ValueError);
Py_DECREF(res);
- self->raw_pos = n;
+ self->abs_pos = n;
/* TODO: sanity check (n >= 0) */
return n;
}
@@ -403,7 +466,7 @@
return -1;
n = PyNumber_AsSsize_t(res, PyExc_ValueError);
Py_DECREF(res);
- self->raw_pos = n;
+ self->abs_pos = n;
/* TODO: sanity check (n >= 0) */
return n;
}
@@ -417,7 +480,20 @@
"buffer size must be strictly positive");
return -1;
}
+ if (self->buffer)
+ PyMem_Free(self->buffer);
+ self->buffer = PyMem_Malloc(self->buffer_size);
+ if (self->buffer == NULL) {
+ PyErr_NoMemory();
+ return -1;
+ }
+ self->lock = PyThread_allocate_lock();
+ if (self->lock == NULL) {
+ PyErr_SetString(PyExc_RuntimeError, "can't allocate read lock");
+ return -1;
+ }
/* Find out whether buffer_size is a power of 2 */
+ /* XXX is this optimization useful? */
for (n = self->buffer_size - 1; n & 1; n >>= 1)
;
if (n == 0)
@@ -429,6 +505,264 @@
return 0;
}
+/*
+ * Shared methods and wrappers
+ */
+
+static PyObject *
+Buffered_flush(BufferedObject *self, PyObject *args)
+{
+ PyObject *res;
+
+ CHECK_INITIALIZED(self)
+ if (BufferedIOMixin_closed(self)) {
+ PyErr_SetString(PyExc_ValueError, "flush of closed file");
+ return NULL;
+ }
+
+ ENTER_BUFFERED(self)
+ res = _BufferedWriter_flush_unlocked(self, 0);
+ if (res != NULL && self->readable) {
+ /* Rewind the raw stream so that its position corresponds to
+ the current logical position. */
+ Py_ssize_t n;
+ n = _Buffered_raw_seek(self, -RAW_OFFSET(self), 1);
+ if (n == -1)
+ Py_CLEAR(res);
+ _BufferedReader_reset_buf(self);
+ }
+ LEAVE_BUFFERED(self)
+
+ return res;
+}
+
+static PyObject *
+Buffered_peek(BufferedObject *self, PyObject *args)
+{
+ Py_ssize_t n = 0;
+ PyObject *res = NULL;
+
+ CHECK_INITIALIZED(self)
+ if (!PyArg_ParseTuple(args, "|n:peek", &n)) {
+ return NULL;
+ }
+
+ ENTER_BUFFERED(self)
+
+ if (self->writable) {
+ res = _BufferedWriter_flush_unlocked(self, 1);
+ if (res == NULL)
+ goto end;
+ Py_CLEAR(res);
+ }
+ res = _BufferedReader_peek_unlocked(self, n);
+
+end:
+ LEAVE_BUFFERED(self)
+ return res;
+}
+
+static PyObject *
+Buffered_read(BufferedObject *self, PyObject *args)
+{
+ Py_ssize_t n = -1;
+ PyObject *res;
+
+ CHECK_INITIALIZED(self)
+ if (!PyArg_ParseTuple(args, "|n:read", &n)) {
+ return NULL;
+ }
+
+ if (BufferedIOMixin_closed(self)) {
+ PyErr_SetString(PyExc_ValueError, "read of closed file");
+ return NULL;
+ }
+
+ ENTER_BUFFERED(self)
+ res = _BufferedReader_read_unlocked(self, n);
+ LEAVE_BUFFERED(self)
+
+ return res;
+}
+
+static PyObject *
+Buffered_read1(BufferedObject *self, PyObject *args)
+{
+ Py_ssize_t n, have;
+ PyObject *res;
+
+ CHECK_INITIALIZED(self)
+ if (!PyArg_ParseTuple(args, "n:read1", &n)) {
+ return NULL;
+ }
+
+ /* TODO: n < 0 should raise an error (?) */
+ if (n <= 0)
+ return PyBytes_FromStringAndSize(NULL, 0);
+
+ ENTER_BUFFERED(self)
+
+ if (self->writable) {
+ res = _BufferedWriter_flush_unlocked(self, 1);
+ if (res == NULL)
+ goto end;
+ Py_CLEAR(res);
+ }
+
+ /* Return up to n bytes. If at least one byte is buffered, we
+ only return buffered bytes. Otherwise, we do one raw read. */
+
+ /* XXX: this mimicks the io.py implementation but is probably wrong.
+ If we need to read from the raw stream, then we could actually read
+ all `n` bytes asked by the caller (and possibly more, so as to fill
+ our buffer for the next reads). */
+
+ res = _BufferedReader_peek_unlocked(self, 1);
+ if (res == NULL)
+ goto end;
+ Py_CLEAR(res);
+
+ have = self->read_end - self->pos;
+ if (n > have)
+ n = have;
+
+ res = _BufferedReader_read_unlocked(self, n);
+
+end:
+ LEAVE_BUFFERED(self)
+ return res;
+}
+
+static PyObject *
+Buffered_readinto(BufferedObject *self, PyObject *args)
+{
+ PyObject *res = NULL;
+
+ CHECK_INITIALIZED(self)
+
+ /* TODO: use raw.readinto() instead! */
+ if (self->writable) {
+ ENTER_BUFFERED(self)
+ res = _BufferedWriter_flush_unlocked(self, 0);
+ LEAVE_BUFFERED(self)
+ if (res == NULL)
+ goto end;
+ Py_DECREF(res);
+ }
+ res = BufferedIOBase_readinto((PyObject *)self, args);
+
+end:
+ return res;
+}
+
+static PyObject *
+Buffered_tell(BufferedObject *self, PyObject *args)
+{
+ Py_ssize_t pos;
+
+ CHECK_INITIALIZED(self)
+ pos = _Buffered_raw_tell(self);
+ if (pos == -1)
+ return NULL;
+ pos -= RAW_OFFSET(self);
+ /* TODO: sanity check (pos >= 0) */
+ return PyLong_FromSsize_t(pos);
+}
+
+static PyObject *
+Buffered_seek(BufferedObject *self, PyObject *args)
+{
+ Py_ssize_t current, target, avail, n;
+ int whence = 0;
+ PyObject *res = NULL;
+
+ CHECK_INITIALIZED(self)
+ if (!PyArg_ParseTuple(args, "n|i:seek", &target, &whence)) {
+ return NULL;
+ }
+ /* TODO: sanity check whence value */
+
+ if (whence != 2 && self->readable) {
+ /* 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. */
+ current = RAW_TELL(self);
+ avail = READAHEAD(self);
+ if (avail > 0) {
+ Py_ssize_t offset;
+ if (whence == 0)
+ offset = target - (current - RAW_OFFSET(self));
+ else
+ offset = target;
+ if (offset >= -self->pos && offset <= avail) {
+ self->pos += offset;
+ res = PyLong_FromSsize_t(current - avail + offset);
+ goto end;
+ }
+ }
+ }
+
+ /* Fallback: invoke raw seek() method and clear buffer */
+ if (self->writable) {
+ res = _BufferedWriter_flush_unlocked(self, 0);
+ if (res == NULL)
+ goto end;
+ Py_CLEAR(res);
+ }
+
+ /* TODO: align on block boundary and read buffer if needed? */
+ if (whence == 1)
+ target -= RAW_OFFSET(self);
+ n = _Buffered_raw_seek(self, target, whence);
+ if (n == -1)
+ goto end;
+ self->raw_pos = -1;
+ res = PyLong_FromSsize_t(n);
+ if (res != NULL)
+ _BufferedReader_reset_buf(self);
+
+end:
+ LEAVE_BUFFERED(self)
+ return res;
+}
+
+static PyObject *
+Buffered_truncate(BufferedObject *self, PyObject *args)
+{
+ PyObject *pos = Py_None;
+ PyObject *res = NULL;
+
+ CHECK_INITIALIZED(self)
+ if (!PyArg_ParseTuple(args, "|O:truncate", &pos)) {
+ return NULL;
+ }
+
+ if (pos != Py_None)
+ Py_INCREF(pos);
+
+ ENTER_BUFFERED(self)
+
+ if (self->writable) {
+ res = _BufferedWriter_flush_unlocked(self, 0);
+ if (res == NULL)
+ goto end;
+ Py_CLEAR(res);
+ _BufferedWriter_reset_buf(self);
+ }
+ if (self->readable)
+ _BufferedReader_reset_buf(self);
+ res = PyObject_CallMethodObjArgs(self->raw, _PyIO_str_truncate, pos, NULL);
+ if (res == NULL)
+ goto end;
+ /* Reset cached position */
+ if (_Buffered_raw_tell(self) == -1)
+ PyErr_Clear();
+
+end:
+ LEAVE_BUFFERED(self)
+ return res;
+}
+
/*
* class BufferedReader
@@ -437,11 +771,9 @@
PyDoc_STRVAR(BufferedReader_doc,
"Create a new buffered reader using the given readable raw IO object.");
-static int _BufferedReader_reset_buf(BufferedObject *self)
+static void _BufferedReader_reset_buf(BufferedObject *self)
{
self->read_end = -1;
- self->read_pos = 0;
- return 0;
}
static int
@@ -465,33 +797,19 @@
Py_INCREF(raw);
self->raw = raw;
self->buffer_size = buffer_size;
+ self->readable = 1;
+ self->writable = 0;
if (_Buffered_init(self) < 0)
return -1;
-
- if (self->read_buf)
- PyMem_Free(self->read_buf);
- self->read_buf = PyMem_Malloc(self->buffer_size);
- if (self->read_buf == NULL) {
- PyErr_NoMemory();
- return -1;
- }
-
- if (_BufferedReader_reset_buf(self) < 0)
- return -1;
-
- self->read_lock = PyThread_allocate_lock();
- if (self->read_lock == NULL) {
- PyErr_SetString(PyExc_RuntimeError, "can't allocate read lock");
- return -1;
- }
+ _BufferedReader_reset_buf(self);
self->ok = 1;
return 0;
}
static Py_ssize_t
-_BufferedReader_raw_read(BufferedObject *self, unsigned char *start, Py_ssize_t len)
+_BufferedReader_raw_read(BufferedObject *self, char *start, Py_ssize_t len)
{
Py_buffer buf;
PyObject *memobj, *res;
@@ -514,8 +832,25 @@
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;
+ if (n > 0 && self->abs_pos != -1)
+ self->abs_pos += n;
+ return n;
+}
+
+static Py_ssize_t
+_BufferedReader_fill_buffer(BufferedObject *self)
+{
+ Py_ssize_t start, len, n;
+ if (VALID_READ_BUFFER(self))
+ start = self->read_end;
+ else
+ start = 0;
+ len = self->buffer_size - start;
+ n = _BufferedReader_raw_read(self, self->buffer + start, len);
+ if (n <= 0)
+ return n;
+ self->read_end = start + n;
+ self->raw_pos = start + n;
return n;
}
@@ -524,7 +859,7 @@
{
PyObject *data, *chunks, *res = NULL;
Py_ssize_t current_size, remaining, written;
- unsigned char *out;
+ char *out;
static PyObject *sep = NULL;
/* Special case for when the number of bytes to read is unspecified. */
@@ -534,19 +869,23 @@
return NULL;
/* First copy what we have in the current buffer. */
- current_size = AVAILABLE_BYTES(self);
+ current_size = READAHEAD(self);
data = NULL;
if (current_size) {
data = PyBytes_FromStringAndSize(
- self->read_buf + self->read_pos, current_size);
+ self->buffer + self->pos, current_size);
if (data == NULL) {
Py_DECREF(chunks);
return NULL;
}
}
- if (_BufferedReader_reset_buf(self) == -1) {
- Py_DECREF(chunks);
- return NULL;
+ _BufferedReader_reset_buf(self);
+ /* We're going past the buffer's bounds, flush it */
+ if (self->writable) {
+ res = _BufferedWriter_flush_unlocked(self, 1);
+ if (res == NULL)
+ return NULL;
+ Py_CLEAR(res);
}
while (1) {
if (data) {
@@ -590,19 +929,19 @@
}
}
current_size += PyBytes_GET_SIZE(data);
- if (self->raw_pos != -1)
- self->raw_pos += PyBytes_GET_SIZE(data);
+ if (self->abs_pos != -1)
+ self->abs_pos += PyBytes_GET_SIZE(data);
}
}
/* The number of bytes to read is specified, return at most n bytes. */
- current_size = AVAILABLE_BYTES(self);
+ current_size = READAHEAD(self);
if (n <= current_size) {
/* Fast path: the data to read is fully buffered. */
- res = PyBytes_FromStringAndSize(self->read_buf + self->read_pos, n);
+ res = PyBytes_FromStringAndSize(self->buffer + self->pos, n);
if (res == NULL)
goto error;
- self->read_pos += n;
+ self->pos += n;
return res;
}
@@ -616,14 +955,13 @@
remaining = n;
written = 0;
if (current_size > 0) {
- memcpy(out, self->read_buf + self->read_pos, current_size);
+ memcpy(out, self->buffer + self->pos, current_size);
remaining -= current_size;
written += current_size;
}
- if (_BufferedReader_reset_buf(self) == -1)
- goto error;
+ _BufferedReader_reset_buf(self);
while (remaining > 0) {
- /* We want to read a whole block at the end into read_buf.
+ /* We want to read a whole block at the end into buffer.
If we had readv() we could do this in one pass. */
Py_ssize_t r = MINUS_LAST_BLOCK(self, remaining);
if (r == 0)
@@ -646,12 +984,11 @@
written += r;
}
assert(remaining <= self->buffer_size);
- self->read_pos = 0;
+ self->pos = 0;
+ self->raw_pos = 0;
self->read_end = 0;
while (self->read_end < self->buffer_size) {
- Py_ssize_t r = _BufferedReader_raw_read(self,
- self->read_buf + self->read_end,
- self->buffer_size - self->read_end);
+ Py_ssize_t r = _BufferedReader_fill_buffer(self);
if (r == -1)
goto error;
if (r == 0 || r == -2) {
@@ -666,212 +1003,53 @@
return Py_None;
}
if (remaining > r) {
- memcpy(out + written, self->read_buf + self->read_end, r);
+ memcpy(out + written, self->buffer + self->pos, r);
written += r;
- self->read_pos += r;
+ self->pos += r;
remaining -= r;
}
else if (remaining > 0) {
- memcpy(out + written, self->read_buf + self->read_end, remaining);
+ memcpy(out + written, self->buffer + self->pos, remaining);
written += remaining;
- self->read_pos += remaining;
+ self->pos += remaining;
remaining = 0;
}
- self->read_end += r;
if (remaining == 0)
- /* XXX perhaps we could try again to fill the buffer instead? */
break;
}
return res;
error:
- Py_XDECREF(res);
- return NULL;
-}
-
-static PyObject *
-BufferedReader_read(BufferedObject *self, PyObject *args)
-{
- Py_ssize_t n = -1;
- PyObject *res;
-
- CHECK_INITIALIZED(self)
- if (!PyArg_ParseTuple(args, "|n:read", &n)) {
- return NULL;
- }
-
- if (BufferedIOMixin_closed(self)) {
- PyErr_SetString(PyExc_ValueError, "read of closed file");
- return NULL;
- }
-
- ENTER_BUFFERED_READER(self)
-
- res = _BufferedReader_read_unlocked(self, n);
-
- LEAVE_BUFFERED_READER(self)
-
- return res;
-}
-
-static PyObject *
-_BufferedReader_peek_unlocked(BufferedObject *self, Py_ssize_t n)
-{
- Py_ssize_t have, r;
-
- have = AVAILABLE_BYTES(self);
- /* Constraints:
- 1. we don't want to advance the file position.
- 2. we don't want to lose block alignment, so we can't shift the buffer
- to make some place.
- Therefore, we either return `have` bytes (if > 0), or a full buffer.
- */
- if (have > 0) {
- return PyBytes_FromStringAndSize(self->read_buf + self->read_pos, have);
- }
-
- /* Fill the buffer from the raw stream, and copy it to the result. */
- r = _BufferedReader_raw_read(self, self->read_buf, self->buffer_size);
- if (r == -1)
- return NULL;
- if (r == -2)
- r = 0;
- self->read_pos = 0;
- self->read_end = r;
- return PyBytes_FromStringAndSize(self->read_buf, r);
-
-}
-
-static PyObject *
-BufferedReader_peek(BufferedObject *self, PyObject *args)
-{
- Py_ssize_t n = 0;
- PyObject *res;
-
- CHECK_INITIALIZED(self)
- if (!PyArg_ParseTuple(args, "|n:peek", &n)) {
- return NULL;
- }
-
- ENTER_BUFFERED_READER(self)
-
- res = _BufferedReader_peek_unlocked(self, n);
-
- LEAVE_BUFFERED_READER(self)
-
- return res;
-}
-
-static PyObject *
-BufferedReader_read1(BufferedObject *self, PyObject *args)
-{
- Py_ssize_t n, have;
- PyObject *res;
-
- CHECK_INITIALIZED(self)
- if (!PyArg_ParseTuple(args, "n:read1", &n)) {
- return NULL;
- }
-
- /* TODO: n < 0 should raise an error (?) */
- if (n <= 0)
- return PyBytes_FromStringAndSize(NULL, 0);
-
- ENTER_BUFFERED_READER(self)
-
- /* Return up to n bytes. If at least one byte is buffered, we
- only return buffered bytes. Otherwise, we do one raw read. */
-
- /* TODO: this mimicks the io.py implementation but is probably wrong.
- If we need to read from the raw stream, then we should actually read
- all `n` bytes asked by the caller (and possibly more, so as to fill
- our buffer for the next reads). */
-
- res = _BufferedReader_peek_unlocked(self, 1);
- if (res == NULL)
- goto end;
- Py_DECREF(res);
-
- have = self->read_end - self->read_pos;
- if (n > have)
- n = have;
-
- res = _BufferedReader_read_unlocked(self, n);
-
-end:
- LEAVE_BUFFERED_READER(self)
- return res;
-}
-
-static PyObject *
-BufferedReader_seek(BufferedObject *self, PyObject *args)
-{
- Py_ssize_t current, target, avail, n;
- int whence = 0;
- PyObject *res = NULL;
-
- CHECK_INITIALIZED(self)
- if (!PyArg_ParseTuple(args, "n|i:seek", &target, &whence)) {
- return NULL;
- }
- /* TODO: sanity check whence value */
-
- ENTER_BUFFERED_READER(self)
-
- 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. */
- 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;
- }
- }
- }
-
- /* Fallback: invoke raw seek() method and clear buffer */
- if (whence == 1)
- target -= AVAILABLE_BYTES(self);
-
- /* TODO: align on block boundary and read buffer if needed? */
- n = _Buffered_raw_seek(self, target, whence);
- if (n == -1)
- goto end;
- res = PyLong_FromSsize_t(n);
- if (res != NULL && _BufferedReader_reset_buf(self) < 0)
- Py_CLEAR(res);
-
-end:
- LEAVE_BUFFERED_READER(self)
- return res;
+ Py_XDECREF(res);
+ return NULL;
}
static PyObject *
-BufferedReader_tell(BufferedObject *self, PyObject *args)
+_BufferedReader_peek_unlocked(BufferedObject *self, Py_ssize_t n)
{
- Py_ssize_t pos;
+ Py_ssize_t have, r;
- CHECK_INITIALIZED(self)
- pos = _Buffered_raw_tell(self);
- if (pos == -1)
+ have = READAHEAD(self);
+ /* Constraints:
+ 1. we don't want to advance the file position.
+ 2. we don't want to lose block alignment, so we can't shift the buffer
+ to make some place.
+ Therefore, we either return `have` bytes (if > 0), or a full buffer.
+ */
+ if (have > 0) {
+ return PyBytes_FromStringAndSize(self->buffer + self->pos, have);
+ }
+
+ /* Fill the buffer from the raw stream, and copy it to the result. */
+ _BufferedReader_reset_buf(self);
+ r = _BufferedReader_fill_buffer(self);
+ if (r == -1)
return NULL;
- pos -= AVAILABLE_BYTES(self);
- /* TODO: sanity check (pos >= 0) */
- return PyLong_FromSsize_t(pos);
+ if (r == -2)
+ r = 0;
+ self->pos = 0;
+ return PyBytes_FromStringAndSize(self->buffer, r);
}
static PyMethodDef BufferedReader_methods[] = {
@@ -885,11 +1063,11 @@
{"fileno", (PyCFunction)BufferedIOMixin_fileno, METH_NOARGS},
{"isatty", (PyCFunction)BufferedIOMixin_isatty, METH_NOARGS},
- {"read", (PyCFunction)BufferedReader_read, METH_VARARGS},
- {"peek", (PyCFunction)BufferedReader_peek, METH_VARARGS},
- {"read1", (PyCFunction)BufferedReader_read1, METH_VARARGS},
- {"seek", (PyCFunction)BufferedReader_seek, METH_VARARGS},
- {"tell", (PyCFunction)BufferedReader_tell, METH_NOARGS},
+ {"read", (PyCFunction)Buffered_read, METH_VARARGS},
+ {"peek", (PyCFunction)Buffered_peek, METH_VARARGS},
+ {"read1", (PyCFunction)Buffered_read1, METH_VARARGS},
+ {"seek", (PyCFunction)Buffered_seek, METH_VARARGS},
+ {"tell", (PyCFunction)Buffered_tell, METH_NOARGS},
{NULL, NULL}
};
@@ -959,12 +1137,11 @@
"DEFAULT_BUFFER_SIZE. max_buffer_size isn't used anymore.\n"
);
-static int
+static void
_BufferedWriter_reset_buf(BufferedObject *self)
{
self->write_pos = 0;
- self->write_end = 0;
- return 0;
+ self->write_end = -1;
}
static int
@@ -989,33 +1166,21 @@
Py_CLEAR(self->raw);
Py_INCREF(raw);
self->raw = raw;
+ self->readable = 0;
+ self->writable = 1;
self->buffer_size = buffer_size;
if (_Buffered_init(self) < 0)
return -1;
-
- if (self->write_buf)
- PyMem_Free(self->write_buf);
- self->write_buf = PyMem_Malloc(self->buffer_size);
- if (self->write_buf == NULL) {
- PyErr_NoMemory();
- return -1;
- }
- if (_BufferedWriter_reset_buf(self) < 0)
- return -1;
-
- self->write_lock = PyThread_allocate_lock();
- if (self->write_lock == NULL) {
- PyErr_SetString(PyExc_RuntimeError, "can't allocate write lock");
- return -1;
- }
+ _BufferedWriter_reset_buf(self);
+ self->pos = 0;
self->ok = 1;
return 0;
}
static Py_ssize_t
-_BufferedWriter_raw_write(BufferedObject *self, unsigned char *start, Py_ssize_t len)
+_BufferedWriter_raw_write(BufferedObject *self, char *start, Py_ssize_t len)
{
Py_buffer buf;
PyObject *memobj, *res;
@@ -1033,24 +1198,39 @@
n = PyNumber_AsSsize_t(res, PyExc_ValueError);
Py_DECREF(res);
/* TODO: sanity check (0 <= n <= len) */
+ if (n > 0 && self->abs_pos != -1)
+ self->abs_pos += n;
return n;
}
+/* `restore_pos` is 1 if we need to restore the raw stream position at
+ the end, 0 otherwise. */
static PyObject *
-_BufferedWriter_flush_unlocked(BufferedObject *self)
+_BufferedWriter_flush_unlocked(BufferedObject *self, int restore_pos)
{
- Py_ssize_t written = 0, n;
- PyObject *res = NULL;
+ Py_ssize_t written = 0, n, rewind;
+ if (!VALID_WRITE_BUFFER(self) || self->write_pos == self->write_end)
+ goto end;
+ /* First, rewind */
+ rewind = RAW_OFFSET(self) + (self->pos - self->write_pos);
+ if (rewind != 0) {
+ n = _Buffered_raw_seek(self, -rewind, 1);
+ if (n < 0) {
+ goto error;
+ }
+ self->raw_pos -= rewind;
+ }
while (self->write_pos < self->write_end) {
n = _BufferedWriter_raw_write(self,
- self->write_buf + self->write_pos,
+ self->buffer + self->write_pos,
self->write_end - self->write_pos);
- if (n == -1 && PyErr_Occurred()) {
+ if (n == -1) {
Py_ssize_t *w = _Buffered_check_blocking_error();
if (w == NULL)
goto error;
self->write_pos += *w;
+ self->raw_pos = self->write_pos;
written += *w;
*w = written;
/* Already re-raised */
@@ -1058,15 +1238,26 @@
}
/* TODO: sanity check with a macro */
self->write_pos += n;
+ self->raw_pos = self->write_pos;
written += n;
}
- if (_BufferedWriter_reset_buf(self) < 0)
- goto error;
+ if (restore_pos) {
+ Py_ssize_t forward = rewind - written;
+ if (forward != 0) {
+ n = _Buffered_raw_seek(self, forward, 1);
+ if (n < 0) {
+ goto error;
+ }
+ self->raw_pos += forward;
+ }
+ }
+ _BufferedWriter_reset_buf(self);
+
+end:
Py_RETURN_NONE;
error:
- Py_XDECREF(res);
return NULL;
}
@@ -1088,48 +1279,61 @@
return NULL;
}
- ENTER_BUFFERED_WRITER(self)
+ ENTER_BUFFERED(self)
/* Fast path: the data to write can be fully buffered. */
- avail = self->buffer_size - self->write_end;
+ if (!VALID_READ_BUFFER(self) && !VALID_WRITE_BUFFER(self)) {
+ self->pos = 0;
+ self->raw_pos = 0;
+ }
+ avail = self->buffer_size - self->pos;
if (buf.len <= avail) {
- memcpy(self->write_buf + self->write_end, buf.buf, buf.len);
- self->write_end += buf.len;
+ memcpy(self->buffer + self->pos, buf.buf, buf.len);
+ if (!VALID_WRITE_BUFFER(self)) {
+ self->write_pos = self->pos;
+ }
+ ADJUST_POSITION(self, self->pos + buf.len);
+ if (self->pos > self->write_end)
+ self->write_end = self->pos;
written = buf.len;
goto end;
}
/* First write the current buffer */
- res = _BufferedWriter_flush_unlocked(self);
+ res = _BufferedWriter_flush_unlocked(self, 0);
if (res == NULL) {
Py_ssize_t *w = _Buffered_check_blocking_error();
if (w == NULL)
goto error;
+ if (self->readable)
+ _BufferedReader_reset_buf(self);
/* Make some place by shifting the buffer. */
- memmove(self->write_buf, self->write_buf + self->write_pos,
+ assert(VALID_WRITE_BUFFER(self));
+ memmove(self->buffer, self->buffer + self->write_pos,
self->write_end - self->write_pos);
self->write_end -= self->write_pos;
+ self->raw_pos -= self->write_pos;
+ self->pos -= self->write_pos;
self->write_pos = 0;
avail = self->buffer_size - self->write_end;
if (buf.len <= avail) {
/* Everything can be buffered */
PyErr_Clear();
- memcpy(self->write_buf + self->write_end, buf.buf, buf.len);
+ memcpy(self->buffer + self->write_end, buf.buf, buf.len);
self->write_end += buf.len;
written = buf.len;
goto end;
}
/* Buffer as much as possible. */
- memcpy(self->write_buf + self->write_end, buf.buf, avail);
+ memcpy(self->buffer + self->write_end, buf.buf, avail);
self->write_end += avail;
/* Already re-raised */
*w = avail;
- res = NULL;
goto error;
}
Py_CLEAR(res);
- /* Then write buf itself. At this point write_buf has been emptied. */
+ /* Then write buf itself. At this point the buffer has been emptied. */
remaining = buf.len;
written = 0;
while (remaining > self->buffer_size) {
@@ -1143,8 +1347,10 @@
remaining -= *w;
if (remaining > self->buffer_size) {
/* Can't buffer everything, still buffer as much as possible */
- memcpy(self->write_buf,
+ memcpy(self->buffer,
(char *) buf.buf + written, self->buffer_size);
+ self->raw_pos = 0;
+ ADJUST_POSITION(self, self->buffer_size);
self->write_end = self->buffer_size;
*w = written + self->buffer_size;
/* Already re-raised */
@@ -1156,123 +1362,27 @@
written += n;
remaining -= n;
}
+ if (self->readable)
+ _BufferedReader_reset_buf(self);
if (remaining > 0) {
- memcpy(self->write_buf, (char *) buf.buf + written, remaining);
+ memcpy(self->buffer, (char *) buf.buf + written, remaining);
written += remaining;
}
self->write_pos = 0;
/* TODO: sanity check (remaining >= 0) */
self->write_end = remaining;
+ ADJUST_POSITION(self, remaining);
+ self->raw_pos = 0;
end:
res = PyLong_FromSsize_t(written);
error:
- LEAVE_BUFFERED_WRITER(self)
+ LEAVE_BUFFERED(self)
PyBuffer_Release(&buf);
return res;
}
-static PyObject *
-BufferedWriter_truncate(BufferedObject *self, PyObject *args)
-{
- PyObject *pos = NULL;
- PyObject *res;
-
- CHECK_INITIALIZED(self)
- if (!PyArg_ParseTuple(args, "|O:truncate", &pos)) {
- return NULL;
- }
- /* will be parsed again by BufferedIOMixin_truncate */
- Py_XDECREF(pos);
-
- if (BufferedIOMixin_closed(self)) {
- PyErr_SetString(PyExc_ValueError, "truncate of closed file");
- return NULL;
- }
-
- ENTER_BUFFERED_WRITER(self)
-
- res = _BufferedWriter_flush_unlocked(self);
- if (res == NULL)
- goto end;
- Py_DECREF(res);
-
- res = BufferedIOMixin_truncate(self, args);
-
- end:
- LEAVE_BUFFERED_WRITER(self)
- return res;
-}
-
-static PyObject *
-BufferedWriter_flush(BufferedObject *self, PyObject *args)
-{
- PyObject *res;
-
- CHECK_INITIALIZED(self)
- if (BufferedIOMixin_closed(self)) {
- PyErr_SetString(PyExc_ValueError, "flush of closed file");
- return NULL;
- }
-
- ENTER_BUFFERED_WRITER(self)
-
- res = _BufferedWriter_flush_unlocked(self);
-
- LEAVE_BUFFERED_WRITER(self)
-
- return res;
-}
-
-static PyObject *
-BufferedWriter_tell(BufferedObject *self, PyObject *args)
-{
- PyObject *op1, *op2, *res;
-
- CHECK_INITIALIZED(self)
- op1 = PyObject_CallMethod(self->raw, "tell", NULL);
- op2 = PyLong_FromSsize_t(self->write_end - self->write_pos);
- if (op2 == NULL) {
- Py_DECREF(op1);
- return NULL;
- }
-
- res = PyNumber_Add(op1, op2);
- Py_DECREF(op1);
- Py_DECREF(op2);
- return res;
-}
-
-static PyObject *
-BufferedWriter_seek(BufferedObject *self, PyObject *args)
-{
- Py_ssize_t pos;
- int whence = 0;
- PyObject *res;
-
- CHECK_INITIALIZED(self)
- if (!PyArg_ParseTuple(args, "n|i:seek", &pos, &whence)) {
- return NULL;
- }
- if (BufferedIOMixin_closed(self)) {
- PyErr_SetString(PyExc_ValueError, "seek of closed file");
- return NULL;
- }
-
- ENTER_BUFFERED_WRITER(self)
-
- res = _BufferedWriter_flush_unlocked(self);
- if (res == NULL)
- goto end;
-
- res = PyObject_CallMethod(self->raw, "seek", "ni", pos, whence);
-
- end:
- LEAVE_BUFFERED_WRITER(self)
- return res;
-}
-
static PyMethodDef BufferedWriter_methods[] = {
/* BufferedIOMixin methods */
{"close", (PyCFunction)BufferedIOMixin_close, METH_NOARGS},
@@ -1283,10 +1393,10 @@
{"isatty", (PyCFunction)BufferedIOMixin_isatty, METH_NOARGS},
{"write", (PyCFunction)BufferedWriter_write, METH_VARARGS},
- {"truncate", (PyCFunction)BufferedWriter_truncate, METH_VARARGS},
- {"flush", (PyCFunction)BufferedWriter_flush, METH_NOARGS},
- {"seek", (PyCFunction)BufferedWriter_seek, METH_VARARGS},
- {"tell", (PyCFunction)BufferedWriter_tell, METH_NOARGS},
+ {"truncate", (PyCFunction)Buffered_truncate, METH_VARARGS},
+ {"flush", (PyCFunction)Buffered_flush, METH_NOARGS},
+ {"seek", (PyCFunction)Buffered_seek, METH_VARARGS},
+ {"tell", (PyCFunction)Buffered_tell, METH_NOARGS},
{NULL, NULL}
};
@@ -1513,6 +1623,7 @@
{"read", (PyCFunction)BufferedRWPair_read, METH_VARARGS},
{"peek", (PyCFunction)BufferedRWPair_peek, METH_VARARGS},
{"read1", (PyCFunction)BufferedRWPair_read1, METH_VARARGS},
+ {"readinto", (PyCFunction)Buffered_readinto, METH_VARARGS},
{"write", (PyCFunction)BufferedRWPair_write, METH_VARARGS},
{"flush", (PyCFunction)BufferedRWPair_flush, METH_NOARGS},
@@ -1607,211 +1718,19 @@
Py_INCREF(raw);
self->raw = raw;
self->buffer_size = buffer_size;
+ self->readable = 1;
+ self->writable = 1;
if (_Buffered_init(self) < 0)
return -1;
- Py_CLEAR(self->read_buf);
- self->read_buf = PyMem_Malloc(self->buffer_size);
- if (self->read_buf == NULL) {
- PyErr_NoMemory();
- return -1;
- }
- if (_BufferedReader_reset_buf(self) < 0)
- return -1;
-
- self->read_lock = PyThread_allocate_lock();
- if (self->read_lock == NULL) {
- PyErr_SetString(PyExc_RuntimeError, "can't allocate read lock");
- return -1;
- }
-
- Py_CLEAR(self->write_buf);
- self->write_buf = PyMem_Malloc(self->buffer_size);
- if (self->write_buf == NULL) {
- PyErr_NoMemory();
- return -1;
- }
- if (_BufferedWriter_reset_buf(self) < 0)
- return -1;
-
- self->write_lock = PyThread_allocate_lock();
- if (self->write_lock == NULL) {
- PyErr_SetString(PyExc_RuntimeError, "can't allocate write lock");
- return -1;
- }
+ _BufferedReader_reset_buf(self);
+ _BufferedWriter_reset_buf(self);
+ self->pos = 0;
self->ok = 1;
return 0;
}
-static PyObject *
-BufferedRandom_tell(BufferedObject *self, PyObject *args)
-{
- CHECK_INITIALIZED(self)
- if (self->write_end > self->write_pos)
- return BufferedWriter_tell(self, args);
- else
- return BufferedReader_tell(self, args);
-}
-
-static PyObject *
-BufferedRandom_seek(BufferedObject *self, PyObject *args)
-{
- Py_ssize_t pos;
- int whence = 0;
- PyObject *res;
-
- CHECK_INITIALIZED(self)
- if (!PyArg_ParseTuple(args, "n|i:seek", &pos, &whence)) {
- return NULL;
- }
-
- res = PyObject_CallMethod((PyObject *)self, "flush", NULL);
- if (res == NULL)
- return NULL;
-
- /* First do the raw seek, then empty the read buffer, so that
- * if the raw seek fails, we don't lose buffered data forever.
- */
-
- 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;
-}
-
-static PyObject *
-BufferedRandom_truncate(BufferedObject *self, PyObject *args)
-{
- PyObject *pos = Py_None;
- PyObject *res;
-
- CHECK_INITIALIZED(self)
- if (!PyArg_ParseTuple(args, "|O:truncate", &pos)) {
- return NULL;
- }
-
- if (pos == Py_None)
- pos = PyObject_CallMethod(self->raw, "tell", NULL);
- else
- Py_INCREF(pos);
-
- /* Use seek to flush the read buffer. */
- res = PyObject_CallMethod((PyObject *)self, "seek", "O", pos);
- Py_DECREF(pos);
- if (res == NULL)
- return NULL;
- Py_DECREF(res);
-
- args = PyTuple_New(0);
- if (args == NULL)
- return NULL;
- res = BufferedWriter_truncate(self, args);
- Py_DECREF(args);
-
- return res;
-}
-
-static PyObject *
-BufferedRandom_read(BufferedObject *self, PyObject *args)
-{
- Py_ssize_t n = -1;
- PyObject *res;
-
- CHECK_INITIALIZED(self)
- if (!PyArg_ParseTuple(args, "|n:read", &n)) {
- return NULL;
- }
-
- res = BufferedWriter_flush(self, Py_None);
- if (res == NULL)
- return NULL;
-
- return BufferedReader_read(self, args);
-}
-
-static PyObject *
-BufferedRandom_readinto(BufferedObject *self, PyObject *args)
-{
- PyObject *res;
-
- CHECK_INITIALIZED(self)
- res = BufferedWriter_flush(self, Py_None);
- if (res == NULL)
- return NULL;
- Py_DECREF(res);
-
- return BufferedIOBase_readinto((PyObject *)self, args);
-}
-
-static PyObject *
-BufferedRandom_peek(BufferedObject *self, PyObject *args)
-{
- PyObject *res;
- CHECK_INITIALIZED(self)
- res = BufferedWriter_flush(self, Py_None);
- if (res == NULL)
- return NULL;
- Py_DECREF(res);
-
- return BufferedReader_peek(self, args);
-}
-
-static PyObject *
-BufferedRandom_read1(BufferedObject *self, PyObject *args)
-{
- PyObject *res;
- CHECK_INITIALIZED(self)
- res = BufferedWriter_flush(self, Py_None);
- if (res == NULL)
- return NULL;
- Py_DECREF(res);
-
- return BufferedReader_read1(self, args);
-}
-
-static PyObject *
-BufferedRandom_write(BufferedObject *self, PyObject *args)
-{
- Py_ssize_t readahead;
- CHECK_INITIALIZED(self)
- readahead = AVAILABLE_BYTES(self);
- if (readahead > 0) {
- PyObject *res;
- /* Undo readahead */
-
- ENTER_BUFFERED_READER(self)
-
- res = PyObject_CallMethod(self->raw, "seek", "ni",
- -readahead, 1);
- Py_XDECREF(res);
- if (res != NULL) {
- if (_BufferedReader_reset_buf(self) < 0)
- res = NULL;
- }
-
- LEAVE_BUFFERED_READER(self)
-
- if (res == NULL)
- return NULL;
- }
-
- return BufferedWriter_write(self, args);
-}
-
-
static PyMethodDef BufferedRandom_methods[] = {
/* BufferedIOMixin methods */
{"close", (PyCFunction)BufferedIOMixin_close, METH_NOARGS},
@@ -1821,16 +1740,16 @@
{"fileno", (PyCFunction)BufferedIOMixin_fileno, METH_NOARGS},
{"isatty", (PyCFunction)BufferedIOMixin_isatty, METH_NOARGS},
- {"flush", (PyCFunction)BufferedWriter_flush, METH_NOARGS},
+ {"flush", (PyCFunction)Buffered_flush, METH_NOARGS},
- {"seek", (PyCFunction)BufferedRandom_seek, METH_VARARGS},
- {"tell", (PyCFunction)BufferedRandom_tell, METH_NOARGS},
- {"truncate", (PyCFunction)BufferedRandom_truncate, METH_VARARGS},
- {"read", (PyCFunction)BufferedRandom_read, METH_VARARGS},
- {"readinto", (PyCFunction)BufferedRandom_readinto, METH_VARARGS},
- {"peek", (PyCFunction)BufferedRandom_peek, METH_VARARGS},
- {"read1", (PyCFunction)BufferedRandom_read1, METH_VARARGS},
- {"write", (PyCFunction)BufferedRandom_write, METH_VARARGS},
+ {"seek", (PyCFunction)Buffered_seek, METH_VARARGS},
+ {"tell", (PyCFunction)Buffered_tell, METH_NOARGS},
+ {"truncate", (PyCFunction)Buffered_truncate, METH_VARARGS},
+ {"read", (PyCFunction)Buffered_read, METH_VARARGS},
+ {"read1", (PyCFunction)Buffered_read1, METH_VARARGS},
+ {"readinto", (PyCFunction)Buffered_readinto, METH_VARARGS},
+ {"peek", (PyCFunction)Buffered_peek, METH_VARARGS},
+ {"write", (PyCFunction)BufferedWriter_write, METH_VARARGS},
{NULL, NULL}
};
Modified: sandbox/trunk/io-c/_iomodule.h
==============================================================================
--- sandbox/trunk/io-c/_iomodule.h (original)
+++ sandbox/trunk/io-c/_iomodule.h Tue Jan 6 02:04:25 2009
@@ -60,5 +60,6 @@
extern PyObject *_PyIO_str_readinto;
extern PyObject *_PyIO_str_seekable;
extern PyObject *_PyIO_str_tell;
+extern PyObject *_PyIO_str_truncate;
extern PyObject *_PyIO_str_writable;
extern PyObject *_PyIO_str_write;
Modified: sandbox/trunk/io-c/io.c
==============================================================================
--- sandbox/trunk/io-c/io.c (original)
+++ sandbox/trunk/io-c/io.c Tue Jan 6 02:04:25 2009
@@ -24,6 +24,7 @@
PyObject *_PyIO_str_readinto;
PyObject *_PyIO_str_seekable;
PyObject *_PyIO_str_tell;
+PyObject *_PyIO_str_truncate;
PyObject *_PyIO_str_writable;
PyObject *_PyIO_str_write;
@@ -643,6 +644,8 @@
goto fail;
if (!(_PyIO_str_tell = PyUnicode_InternFromString("tell")))
goto fail;
+ if (!(_PyIO_str_truncate = PyUnicode_InternFromString("truncate")))
+ goto fail;
if (!(_PyIO_str_write = PyUnicode_InternFromString("write")))
goto fail;
if (!(_PyIO_str_writable = PyUnicode_InternFromString("writable")))
More information about the Python-checkins
mailing list