@@ -31,17 +31,34 @@ typedef struct {
3131 * exports > 0. Py_REFCNT(buf) == 1, any modifications are forbidden.
3232*/
3333
34+ static int
35+ check_closed (bytesio * self )
36+ {
37+ if (self -> buf == NULL ) {
38+ PyErr_SetString (PyExc_ValueError , "I/O operation on closed file." );
39+ return 1 ;
40+ }
41+ return 0 ;
42+ }
43+
44+ static int
45+ check_exports (bytesio * self )
46+ {
47+ if (self -> exports > 0 ) {
48+ PyErr_SetString (PyExc_BufferError ,
49+ "Existing exports of data: object cannot be re-sized" );
50+ return 1 ;
51+ }
52+ return 0 ;
53+ }
54+
3455#define CHECK_CLOSED (self ) \
35- if ((self)->buf == NULL) { \
36- PyErr_SetString(PyExc_ValueError, \
37- "I/O operation on closed file."); \
56+ if (check_closed(self)) { \
3857 return NULL; \
3958 }
4059
4160#define CHECK_EXPORTS (self ) \
42- if ((self)->exports > 0) { \
43- PyErr_SetString(PyExc_BufferError, \
44- "Existing exports of data: object cannot be re-sized"); \
61+ if (check_exports(self)) { \
4562 return NULL; \
4663 }
4764
@@ -156,23 +173,41 @@ resize_buffer(bytesio *self, size_t size)
156173}
157174
158175/* Internal routine for writing a string of bytes to the buffer of a BytesIO
159- object. Returns the number of bytes written, or -1 on error. */
160- static Py_ssize_t
161- write_bytes (bytesio * self , const char * bytes , Py_ssize_t len )
176+ object. Returns the number of bytes written, or -1 on error.
177+ Inlining is disabled because it's significantly decreases performance
178+ of writelines() in PGO build. */
179+ _Py_NO_INLINE static Py_ssize_t
180+ write_bytes (bytesio * self , PyObject * b )
162181{
163- size_t endpos ;
164- assert (self -> buf != NULL );
165- assert (self -> pos >= 0 );
166- assert (len >= 0 );
182+ if (check_closed (self )) {
183+ return -1 ;
184+ }
185+ if (check_exports (self )) {
186+ return -1 ;
187+ }
167188
168- endpos = (size_t )self -> pos + len ;
189+ Py_buffer buf ;
190+ if (PyObject_GetBuffer (b , & buf , PyBUF_CONTIG_RO ) < 0 ) {
191+ return -1 ;
192+ }
193+ Py_ssize_t len = buf .len ;
194+ if (len == 0 ) {
195+ goto done ;
196+ }
197+
198+ assert (self -> pos >= 0 );
199+ size_t endpos = (size_t )self -> pos + len ;
169200 if (endpos > (size_t )PyBytes_GET_SIZE (self -> buf )) {
170- if (resize_buffer (self , endpos ) < 0 )
171- return -1 ;
201+ if (resize_buffer (self , endpos ) < 0 ) {
202+ len = -1 ;
203+ goto done ;
204+ }
172205 }
173206 else if (SHARED_BUF (self )) {
174- if (unshare_buffer (self , Py_MAX (endpos , (size_t )self -> string_size )) < 0 )
175- return -1 ;
207+ if (unshare_buffer (self , Py_MAX (endpos , (size_t )self -> string_size )) < 0 ) {
208+ len = -1 ;
209+ goto done ;
210+ }
176211 }
177212
178213 if (self -> pos > self -> string_size ) {
@@ -190,14 +225,16 @@ write_bytes(bytesio *self, const char *bytes, Py_ssize_t len)
190225
191226 /* Copy the data to the internal buffer, overwriting some of the existing
192227 data if self->pos < self->string_size. */
193- memcpy (PyBytes_AS_STRING (self -> buf ) + self -> pos , bytes , len );
228+ memcpy (PyBytes_AS_STRING (self -> buf ) + self -> pos , buf . buf , len );
194229 self -> pos = endpos ;
195230
196231 /* Set the new length of the internal string if it has changed. */
197232 if ((size_t )self -> string_size < endpos ) {
198233 self -> string_size = endpos ;
199234 }
200235
236+ done :
237+ PyBuffer_Release (& buf );
201238 return len ;
202239}
203240
@@ -669,19 +706,7 @@ static PyObject *
669706_io_BytesIO_write (bytesio * self , PyObject * b )
670707/*[clinic end generated code: output=53316d99800a0b95 input=f5ec7c8c64ed720a]*/
671708{
672- Py_ssize_t n = 0 ;
673- Py_buffer buf ;
674-
675- CHECK_CLOSED (self );
676- CHECK_EXPORTS (self );
677-
678- if (PyObject_GetBuffer (b , & buf , PyBUF_CONTIG_RO ) < 0 )
679- return NULL ;
680-
681- if (buf .len != 0 )
682- n = write_bytes (self , buf .buf , buf .len );
683-
684- PyBuffer_Release (& buf );
709+ Py_ssize_t n = write_bytes (self , b );
685710 return n >= 0 ? PyLong_FromSsize_t (n ) : NULL ;
686711}
687712
@@ -702,7 +727,6 @@ _io_BytesIO_writelines(bytesio *self, PyObject *lines)
702727/*[clinic end generated code: output=7f33aa3271c91752 input=e972539176fc8fc1]*/
703728{
704729 PyObject * it , * item ;
705- PyObject * ret ;
706730
707731 CHECK_CLOSED (self );
708732
@@ -711,13 +735,12 @@ _io_BytesIO_writelines(bytesio *self, PyObject *lines)
711735 return NULL ;
712736
713737 while ((item = PyIter_Next (it )) != NULL ) {
714- ret = _io_BytesIO_write (self , item );
738+ Py_ssize_t ret = write_bytes (self , item );
715739 Py_DECREF (item );
716- if (ret == NULL ) {
740+ if (ret < 0 ) {
717741 Py_DECREF (it );
718742 return NULL ;
719743 }
720- Py_DECREF (ret );
721744 }
722745 Py_DECREF (it );
723746
0 commit comments