diff -r b79d276041a8 Modules/_io/bytesio.c --- a/Modules/_io/bytesio.c Tue Jul 17 17:33:46 2012 +0100 +++ b/Modules/_io/bytesio.c Wed Jul 18 22:26:01 2012 +0300 @@ -4,10 +4,9 @@ typedef struct { PyObject_HEAD - char *buf; + PyObject *buf; Py_ssize_t pos; Py_ssize_t string_size; - size_t buf_size; PyObject *dict; PyObject *weakreflist; Py_ssize_t exports; @@ -41,14 +40,16 @@ get_line(bytesio *self, char **output) { char *n; + char *str_start; const char *str_end; Py_ssize_t len; assert(self->buf != NULL); /* Move to the end of the line, up to the end of the string, s. */ - str_end = self->buf + self->string_size; - for (n = self->buf + self->pos; + str_start = PyBytes_AS_STRING(self->buf) + self->pos; + str_end = PyBytes_AS_STRING(self->buf) + self->string_size; + for (n = str_start; n < str_end && *n != '\n'; n++); @@ -57,8 +58,8 @@ n++; /* Get the length from the current position to the end of the line. */ - len = n - (self->buf + self->pos); - *output = self->buf + self->pos; + len = n - str_start; + *output = str_start; assert(len >= 0); assert(self->pos < PY_SSIZE_T_MAX - len); @@ -67,6 +68,22 @@ return len; } +/* Internal routine for detaching the shared buffer of BytesIO objects. + The caller should ensure that the 'size' argument is non-negative. Returns + 0 on success, -1 otherwise. */ +static int +realloc_buffer(bytesio *self, size_t size) +{ + PyObject * new_buf = PyBytes_FromStringAndSize(NULL, size); + if (new_buf == NULL) + return -1; + memcpy(PyBytes_AS_STRING(new_buf), PyBytes_AS_STRING(self->buf), + self->string_size); + Py_DECREF(self->buf); + self->buf = new_buf; + return 0; +} + /* Internal routine for changing the size of the buffer of BytesIO objects. The caller should ensure that the 'size' argument is non-negative. Returns 0 on success, -1 otherwise. */ @@ -75,8 +92,7 @@ { /* Here, unsigned types are used to avoid dealing with signed integer overflow, which is undefined in C. */ - size_t alloc = self->buf_size; - char *new_buf = NULL; + size_t alloc = PyBytes_GET_SIZE(self->buf); assert(self->buf != NULL); @@ -104,13 +120,15 @@ if (alloc > ((size_t)-1) / sizeof(char)) goto overflow; - new_buf = (char *)PyMem_Realloc(self->buf, alloc * sizeof(char)); - if (new_buf == NULL) { - PyErr_NoMemory(); - return -1; + + if (Py_REFCNT(self->buf) > 1) { + if (realloc_buffer(self, alloc) < 0) + return -1; } - self->buf_size = alloc; - self->buf = new_buf; + else { + if (_PyBytes_Resize(&self->buf, alloc) < 0) + return -1; + } return 0; @@ -129,7 +147,8 @@ assert(self->pos >= 0); assert(len >= 0); - if ((size_t)self->pos + len > self->buf_size) { + if (Py_REFCNT(self->buf) > 1 || + (size_t)self->pos + len > PyBytes_GET_SIZE(self->buf)) { if (resize_buffer(self, (size_t)self->pos + len) < 0) return -1; } @@ -143,13 +162,13 @@ | | <--to pad-->|<---to write---> | 0 buf position */ - memset(self->buf + self->string_size, '\0', + memset(PyBytes_AS_STRING(self->buf) + self->string_size, '\0', (self->pos - self->string_size) * sizeof(char)); } /* Copy the data to the internal buffer, overwriting some of the existing data if self->pos < self->string_size. */ - memcpy(self->buf + self->pos, bytes, len); + memcpy(PyBytes_AS_STRING(self->buf) + self->pos, bytes, len); self->pos += len; /* Set the new length of the internal string if it has changed. */ @@ -221,7 +240,18 @@ bytesio_getvalue(bytesio *self) { CHECK_CLOSED(self); - return PyBytes_FromStringAndSize(self->buf, self->string_size); + if (self->string_size != PyBytes_GET_SIZE(self->buf)) { + if (Py_REFCNT(self->buf) > 1) { + if (realloc_buffer(self, self->string_size) < 0) + return NULL; + } + else { + if (_PyBytes_Resize(&self->buf, self->string_size) < 0) + return NULL; + } + } + Py_INCREF(self->buf); + return self->buf; } PyDoc_STRVAR(isatty_doc, @@ -289,7 +319,14 @@ } assert(self->buf != NULL); - output = self->buf + self->pos; + if (self->exports == 0 && + self->pos == 0 && size == PyBytes_GET_SIZE(self->buf)) { + self->pos += size; + Py_INCREF(self->buf); + return self->buf; + } + + output = PyBytes_AS_STRING(self->buf) + self->pos; self->pos += size; return PyBytes_FromStringAndSize(output, size); @@ -357,6 +394,12 @@ self->pos -= size; } + if (self->exports == 0 && + self->pos == n && n == PyBytes_GET_SIZE(self->buf)) { + Py_INCREF(self->buf); + return self->buf; + } + return PyBytes_FromStringAndSize(output, n); } @@ -445,7 +488,7 @@ len = 0; } - memcpy(raw_buffer, self->buf + self->pos, len); + memcpy(raw_buffer, PyBytes_AS_STRING(self->buf) + self->pos, len); assert(self->pos + len < PY_SSIZE_T_MAX); assert(len >= 0); self->pos += len; @@ -514,6 +557,12 @@ if (!next || n == 0) return NULL; + if (self->exports == 0 && + self->pos == n && n == PyBytes_GET_SIZE(self->buf)) { + Py_INCREF(self->buf); + return self->buf; + } + return PyBytes_FromStringAndSize(next, n); } @@ -645,10 +694,7 @@ static PyObject * bytesio_close(bytesio *self) { - if (self->buf != NULL) { - PyMem_Free(self->buf); - self->buf = NULL; - } + Py_CLEAR(self->buf); Py_RETURN_NONE; } @@ -776,10 +822,7 @@ "deallocated BytesIO object has exported buffers"); PyErr_Print(); } - if (self->buf != NULL) { - PyMem_Free(self->buf); - self->buf = NULL; - } + Py_CLEAR(self->buf); Py_CLEAR(self->dict); if (self->weakreflist != NULL) PyObject_ClearWeakRefs((PyObject *) self); @@ -799,7 +842,7 @@ /* tp_alloc initializes all the fields to zero. So we don't have to initialize them here. */ - self->buf = (char *)PyMem_Malloc(0); + self->buf = PyBytes_FromStringAndSize(NULL, 0); if (self->buf == NULL) { Py_DECREF(self); return PyErr_NoMemory(); @@ -943,7 +986,12 @@ b->exports++; return 0; } - ret = PyBuffer_FillInfo(view, (PyObject*)obj, b->buf, b->string_size, + if (Py_REFCNT(b->buf) > 1) { + if (realloc_buffer(b, b->string_size) < 0) + return -1; + } + ret = PyBuffer_FillInfo(view, (PyObject*)obj, + PyBytes_AS_STRING(b->buf), b->string_size, 0, flags); if (ret >= 0) { b->exports++;