Skip to main content

Modules/_io/bufferedio.c (part 11)

Source:

cpython 3.14 @ ab2d84fe1023/Modules/_io/bufferedio.c

This annotation covers BufferedRandom and BufferedRWPair. See modules_io10_detail for BufferedReader and BufferedWriter read/write paths.

Map

LinesSymbolRole
1-80BufferedRandom.seekSeek with buffer flush
81-180BufferedRandom.tellCurrent position accounting for buffer
181-280BufferedRWPairSeparate reader and writer for the same stream
281-380_buffered_peekLook ahead without consuming
381-500_read_into_bufferFill the read buffer from raw

Reading

BufferedRandom.seek

// CPython: Modules/_io/bufferedio.c:1820 bufferedrandom_seek
static PyObject *
bufferedrandom_seek(buffered *self, PyObject *args)
{
Py_off_t target;
int whence = 0;
if (!PyArg_ParseTuple(args, "O&|i:seek", PyNumber_AsOff_t, &target, &whence)) return NULL;
/* Flush write buffer before seeking */
if (VALID_WRITE_BUFFER(self) && self->write_pos < self->write_end) {
if (_bufferedwriter_flush_unlocked(self) == NULL) return NULL;
}
/* Adjust for read buffer: seek target minus unread bytes */
if (VALID_READ_BUFFER(self)) {
if (whence == 1) /* SEEK_CUR */
target -= RAW_OFFSET(self);
RESET_BUFFER(self);
}
return PyObject_CallMethodOneArg(self->raw, &_Py_ID(seek),
_PyLong_FromOff_t(target));
}

BufferedRandom.seek must flush the write buffer and adjust the target for any unread data in the read buffer before delegating to raw.seek. SEEK_CUR requires subtracting the number of unread bytes in the buffer because the raw position is already ahead of the logical position.

BufferedRWPair

// CPython: Modules/_io/bufferedio.c:1940 bufferedrwpair_read
static PyObject *
bufferedrwpair_read(rwpair *self, PyObject *args)
{
return _PyObject_CallMethodIdObjArgs(self->reader, &PyId_read, args, NULL);
}

static PyObject *
bufferedrwpair_write(rwpair *self, PyObject *args)
{
return _PyObject_CallMethodIdObjArgs(self->writer, &PyId_write, args, NULL);
}

BufferedRWPair pairs a BufferedReader and BufferedWriter over the same raw stream (e.g., a bidirectional socket). Read operations delegate to the reader; write operations delegate to the writer. This avoids the seek penalty of BufferedRandom for full-duplex streams.

_buffered_peek

// CPython: Modules/_io/bufferedio.c:1120 _buffered_peek
static PyObject *
_buffered_peek(buffered *self, Py_ssize_t n)
{
/* Return unread bytes in the buffer without advancing position */
if (VALID_READ_BUFFER(self)) {
Py_ssize_t have = READAHEAD(self);
if (n <= have) {
return PyBytes_FromStringAndSize(self->buffer + self->pos, n);
}
}
/* Fill buffer */
if (_bufferedreader_fill_buffer(self) == -1) return NULL;
have = READAHEAD(self);
return PyBytes_FromStringAndSize(self->buffer + self->pos,
Py_MIN(n, have));
}

f.peek(1) returns up to 1 byte from the buffer without advancing the position. It may return more bytes than requested (up to the full buffer). Used by TextIOWrapper to detect BOMs and newline styles without consuming the data.

_read_into_buffer

// CPython: Modules/_io/bufferedio.c:1060 _bufferedreader_fill_buffer
static Py_ssize_t
_bufferedreader_fill_buffer(buffered *self)
{
Py_ssize_t requested = self->buffer_size - READAHEAD(self);
PyObject *data = PyObject_CallMethodOneArg(self->raw, &_Py_ID(readinto),
self->memobj);
if (data == NULL) return -1;
Py_ssize_t n = PyLong_AsSsize_t(data);
Py_DECREF(data);
if (n == 0) return 0; /* EOF */
self->read_end += n;
return n;
}

raw.readinto(memoryview) writes directly into the buffer memory without an intermediate copy. This is the C-level equivalent of io.RawIOBase.readinto — the buffer's backing memoryview is passed and the raw layer fills it.

gopy notes

BufferedRandom.seek is objects.BufferedRandomSeek in objects/io.go. The write-flush-before-seek logic calls objects.BufferedWriterFlush. BufferedRWPair holds objects.BufferedReader and objects.BufferedWriter fields. _buffered_peek is objects.BufferedPeek; reads ahead using objects.RawReadInto. _bufferedreader_fill_buffer uses objects.MemoryView passed to objects.RawReadInto.