@@ -31,17 +31,34 @@ typedef struct {
31
31
* exports > 0. Py_REFCNT(buf) == 1, any modifications are forbidden.
32
32
*/
33
33
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
+
34
55
#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)) { \
38
57
return NULL; \
39
58
}
40
59
41
60
#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)) { \
45
62
return NULL; \
46
63
}
47
64
@@ -156,23 +173,41 @@ resize_buffer(bytesio *self, size_t size)
156
173
}
157
174
158
175
/* 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 )
162
181
{
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
+ }
167
188
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 ;
169
200
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
+ }
172
205
}
173
206
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
+ }
176
211
}
177
212
178
213
if (self -> pos > self -> string_size ) {
@@ -190,14 +225,16 @@ write_bytes(bytesio *self, const char *bytes, Py_ssize_t len)
190
225
191
226
/* Copy the data to the internal buffer, overwriting some of the existing
192
227
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 );
194
229
self -> pos = endpos ;
195
230
196
231
/* Set the new length of the internal string if it has changed. */
197
232
if ((size_t )self -> string_size < endpos ) {
198
233
self -> string_size = endpos ;
199
234
}
200
235
236
+ done :
237
+ PyBuffer_Release (& buf );
201
238
return len ;
202
239
}
203
240
@@ -669,19 +706,7 @@ static PyObject *
669
706
_io_BytesIO_write (bytesio * self , PyObject * b )
670
707
/*[clinic end generated code: output=53316d99800a0b95 input=f5ec7c8c64ed720a]*/
671
708
{
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 );
685
710
return n >= 0 ? PyLong_FromSsize_t (n ) : NULL ;
686
711
}
687
712
@@ -702,7 +727,6 @@ _io_BytesIO_writelines(bytesio *self, PyObject *lines)
702
727
/*[clinic end generated code: output=7f33aa3271c91752 input=e972539176fc8fc1]*/
703
728
{
704
729
PyObject * it , * item ;
705
- PyObject * ret ;
706
730
707
731
CHECK_CLOSED (self );
708
732
@@ -711,13 +735,12 @@ _io_BytesIO_writelines(bytesio *self, PyObject *lines)
711
735
return NULL ;
712
736
713
737
while ((item = PyIter_Next (it )) != NULL ) {
714
- ret = _io_BytesIO_write (self , item );
738
+ Py_ssize_t ret = write_bytes (self , item );
715
739
Py_DECREF (item );
716
- if (ret == NULL ) {
740
+ if (ret < 0 ) {
717
741
Py_DECREF (it );
718
742
return NULL ;
719
743
}
720
- Py_DECREF (ret );
721
744
}
722
745
Py_DECREF (it );
723
746
0 commit comments