@@ -80,8 +80,9 @@ Create, Finish, Discard
80
80
81
81
Create a :c:type:`PyBytesWriter` to write *size* bytes.
82
82
83
- If *size* is greater than zero, allocate *size* bytes for the
84
- returned buffer.
83
+ If *size* is greater than zero, allocate *size* bytes, and set the
84
+ writer size to *size*. The caller is responsible to write *size*
85
+ bytes using :c:func:`PyBytesWriter_GetData`.
85
86
86
87
On error, set an exception and return NULL.
87
88
@@ -107,14 +108,14 @@ Create, Finish, Discard
107
108
Similar to :c:func: `PyBytesWriter_Finish `, but resize the writer
108
109
using *buf * pointer before creating the :class: `bytes ` object.
109
110
110
- Pseudo-code::
111
+ Set an exception and return ``NULL `` if *buf * pointer is outside the
112
+ internal buffer bounds.
113
+
114
+ Function pseudo-code::
111
115
112
116
Py_ssize_t size = (char*)buf - (char*)PyBytesWriter_GetData(writer);
113
117
return PyBytesWriter_FinishWithSize(writer, size);
114
118
115
- Set an exception and return ``NULL `` if *buf * pointer is outside the
116
- internal buffer bounds.
117
-
118
119
.. c :function :: void PyBytesWriter_Discard (PyBytesWriter *writer)
119
120
120
121
Discard a :c:type: `PyBytesWriter ` created by :c:func: `PyBytesWriter_Create `.
@@ -128,7 +129,9 @@ High-level API
128
129
129
130
.. c :function :: int PyBytesWriter_WriteBytes (PyBytesWriter *writer, const void *bytes, Py_ssize_t size)
130
131
131
- Write *size * bytes of *bytes * into the *writer *.
132
+ Grow the *writer * internal buffer by *size * bytes,
133
+ write *size * bytes of *bytes * at the *writer * end,
134
+ and add *size * to the *writer * size.
132
135
133
136
If *size * is equal to ``-1 ``, call ``strlen(bytes) `` to get the
134
137
string length.
@@ -138,8 +141,9 @@ High-level API
138
141
139
142
.. c :function :: int PyBytesWriter_Format (PyBytesWriter *writer, const char *format, ...)
140
143
141
- Similar to ``PyBytes_FromFormat() ``, but write the output directly
142
- into the writer.
144
+ Similar to ``PyBytes_FromFormat() ``, but write the output directly at
145
+ the writer end. Grow the writer internal buffer on demand.
146
+ Then add the written size to the writer size.
143
147
144
148
On success, return ``0 ``.
145
149
On error, set an exception and return ``-1 ``.
@@ -153,7 +157,7 @@ Getters
153
157
154
158
.. c :function :: void * PyBytesWriter_GetData (PyBytesWriter *writer)
155
159
156
- Get the writer data.
160
+ Get the writer data: start of the internal buffer .
157
161
158
162
The pointer is valid until :c:func: `PyBytesWriter_Finish ` or
159
163
:c:func: `PyBytesWriter_Discard ` is called on *writer *.
@@ -182,16 +186,22 @@ Low-level API
182
186
On success, return ``0 ``.
183
187
On error, set an exception and return ``-1 ``.
184
188
185
- *size * must be positive or zero .
189
+ *size * can be negative to shrink the writer .
186
190
187
191
.. c :function :: void * PyBytesWriter_GrowAndUpdatePointer (PyBytesWriter *writer, Py_ssize_t size, void *buf)
188
192
189
193
Similar to :c:func: `PyBytesWriter_Grow `, but update also the *buf *
190
194
pointer.
191
195
196
+ The *buf * pointer is moved if the internal buffer is moved in memory.
197
+ The *buf * relative position within the internal buffer is left
198
+ unchanged.
199
+
192
200
On error, set an exception and return ``NULL ``.
193
201
194
- Pseudo-code::
202
+ *buf * must not be ``NULL ``.
203
+
204
+ Function pseudo-code::
195
205
196
206
Py_ssize_t pos = (char*)buf - (char*)PyBytesWriter_GetData(writer);
197
207
if (PyBytesWriter_Grow(writer, size) < 0) {
@@ -207,6 +217,10 @@ Overallocation
207
217
overallocate the internal buffer to reduce the number of ``realloc() ``
208
218
calls and so reduce memory copies.
209
219
220
+ :c:func: `PyBytesWriter_Finish ` trims overallocations: it shrinks the
221
+ internal buffer to the exact size when creating the final :class: `bytes `
222
+ object.
223
+
210
224
211
225
Thread safety
212
226
-------------
@@ -273,8 +287,8 @@ Example creating the bytes string ``b"abc"``, with a fixed size of 3 bytes::
273
287
return PyBytesWriter_Finish(writer);
274
288
}
275
289
276
- GrowAndUpdatePointer() example
277
- ------------------------------
290
+ `` GrowAndUpdatePointer() `` example
291
+ ----------------------------------
278
292
279
293
Example using a pointer to write bytes and to track the written size.
280
294
@@ -310,22 +324,84 @@ Create the bytes string ``b"Hello World"``::
310
324
}
311
325
312
326
327
+ Update ``PyBytes_FromStringAndSize() `` code
328
+ -------------------------------------------
329
+
330
+ Example of code using the soft deprecated
331
+ ``PyBytes_FromStringAndSize(NULL, size) `` API::
332
+
333
+ PyObject *result = PyBytes_FromStringAndSize(NULL, num_bytes);
334
+ if (result == NULL) {
335
+ return NULL;
336
+ }
337
+ if (copy_bytes(PyBytes_AS_STRING(result), start, num_bytes) < 0) {
338
+ Py_CLEAR(result);
339
+ }
340
+ return result;
341
+
342
+ It can now be updated to::
343
+
344
+ PyBytesWriter *writer = PyBytesWriter_Create(num_bytes);
345
+ if (writer == NULL) {
346
+ return NULL;
347
+ }
348
+ if (copy_bytes(PyBytesWriter_GetData(writer), start, num_bytes) < 0) {
349
+ PyBytesWriter_Discard(writer);
350
+ return NULL;
351
+ }
352
+ return PyBytesWriter_Finish(writer);
353
+
354
+
355
+ Update ``_PyBytes_Resize() `` code
356
+ ---------------------------------
357
+
358
+ Example of code using the soft deprecated ``_PyBytes_Resize() `` API::
359
+
360
+ PyObject *v = PyBytes_FromStringAndSize(NULL, size);
361
+ if (v == NULL) {
362
+ return NULL;
363
+ }
364
+ char *p = PyBytes_AS_STRING(v);
365
+
366
+ // ... fill bytes into 'p' ...
367
+
368
+ if (_PyBytes_Resize(&v, (p - PyBytes_AS_STRING(v)))) {
369
+ return NULL;
370
+ }
371
+ return v;
372
+
373
+ It can now be updated to::
374
+
375
+ PyBytesWriter *writer = PyBytesWriter_Create(size);
376
+ if (writer == NULL) {
377
+ return NULL;
378
+ }
379
+ char *p = PyBytesWriter_GetData(writer);
380
+
381
+ // ... fill bytes into 'p' ...
382
+
383
+ return PyBytesWriter_FinishWithPointer(writer, p);
384
+
385
+
313
386
Reference Implementation
314
387
========================
315
388
316
389
`Pull request gh-131681 <https://github.com/python/cpython/pull/131681 >`__.
317
390
318
- The implementation allocates internally a :class: `bytes ` object, so
319
- :c:func: `PyBytesWriter_Finish ` just returns the object without having
320
- to copy memory.
391
+ Notes on the CPython reference implementation which are not part of the
392
+ Specification:
321
393
322
- For strings up to 256 bytes, a small internal raw buffer of bytes is
323
- used. It avoids having to resize a :class: `bytes ` object which is
324
- inefficient. At the end, :c:func: `PyBytesWriter_Finish ` creates the
325
- :class: `bytes ` object from this small buffer.
394
+ * The implementation allocates internally a :class: `bytes ` object, so
395
+ :c:func: `PyBytesWriter_Finish ` just returns the object without having
396
+ to copy memory.
326
397
327
- A free list is used to reduce the cost of allocating a
328
- :c:type: `PyBytesWriter ` on the heap memory.
398
+ * For strings up to 256 bytes, a small internal raw buffer of bytes is
399
+ used. It avoids having to resize a :class: `bytes ` object which is
400
+ inefficient. At the end, :c:func: `PyBytesWriter_Finish ` creates the
401
+ :class: `bytes ` object from this small buffer.
402
+
403
+ * A free list is used to reduce the cost of allocating a
404
+ :c:type: `PyBytesWriter ` on the heap memory.
329
405
330
406
331
407
Backwards Compatibility
@@ -334,6 +410,10 @@ Backwards Compatibility
334
410
There is no impact on the backward compatibility, only new APIs are
335
411
added.
336
412
413
+ ``PyBytes_FromStringAndSize(NULL, size) `` and ``_PyBytes_Resize() `` APIs
414
+ are soft deprecated. No new warnings is emitted when these functions are
415
+ used and they are not planned for removal.
416
+
337
417
338
418
Prior Discussions
339
419
=================
0 commit comments