@@ -80,8 +80,9 @@ Create, Finish, Discard
8080
8181 Create a :c:type:`PyBytesWriter` to write *size* bytes.
8282
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`.
8586
8687 On error, set an exception and return NULL.
8788
@@ -107,14 +108,14 @@ Create, Finish, Discard
107108 Similar to :c:func: `PyBytesWriter_Finish `, but resize the writer
108109 using *buf * pointer before creating the :class: `bytes ` object.
109110
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::
111115
112116 Py_ssize_t size = (char*)buf - (char*)PyBytesWriter_GetData(writer);
113117 return PyBytesWriter_FinishWithSize(writer, size);
114118
115- Set an exception and return ``NULL `` if *buf * pointer is outside the
116- internal buffer bounds.
117-
118119.. c :function :: void PyBytesWriter_Discard (PyBytesWriter *writer)
119120
120121 Discard a :c:type: `PyBytesWriter ` created by :c:func: `PyBytesWriter_Create `.
@@ -128,7 +129,9 @@ High-level API
128129
129130.. c :function :: int PyBytesWriter_WriteBytes (PyBytesWriter *writer, const void *bytes, Py_ssize_t size)
130131
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.
132135
133136 If *size * is equal to ``-1 ``, call ``strlen(bytes) `` to get the
134137 string length.
@@ -138,8 +141,9 @@ High-level API
138141
139142.. c :function :: int PyBytesWriter_Format (PyBytesWriter *writer, const char *format, ...)
140143
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.
143147
144148 On success, return ``0 ``.
145149 On error, set an exception and return ``-1 ``.
@@ -153,7 +157,7 @@ Getters
153157
154158.. c :function :: void * PyBytesWriter_GetData (PyBytesWriter *writer)
155159
156- Get the writer data.
160+ Get the writer data: start of the internal buffer .
157161
158162 The pointer is valid until :c:func: `PyBytesWriter_Finish ` or
159163 :c:func: `PyBytesWriter_Discard ` is called on *writer *.
@@ -182,16 +186,22 @@ Low-level API
182186 On success, return ``0 ``.
183187 On error, set an exception and return ``-1 ``.
184188
185- *size * must be positive or zero .
189+ *size * can be negative to shrink the writer .
186190
187191.. c :function :: void * PyBytesWriter_GrowAndUpdatePointer (PyBytesWriter *writer, Py_ssize_t size, void *buf)
188192
189193 Similar to :c:func: `PyBytesWriter_Grow `, but update also the *buf *
190194 pointer.
191195
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+
192200 On error, set an exception and return ``NULL ``.
193201
194- Pseudo-code::
202+ *buf * must not be ``NULL ``.
203+
204+ Function pseudo-code::
195205
196206 Py_ssize_t pos = (char*)buf - (char*)PyBytesWriter_GetData(writer);
197207 if (PyBytesWriter_Grow(writer, size) < 0) {
@@ -207,6 +217,10 @@ Overallocation
207217overallocate the internal buffer to reduce the number of ``realloc() ``
208218calls and so reduce memory copies.
209219
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+
210224
211225Thread safety
212226-------------
@@ -273,8 +287,8 @@ Example creating the bytes string ``b"abc"``, with a fixed size of 3 bytes::
273287 return PyBytesWriter_Finish(writer);
274288 }
275289
276- GrowAndUpdatePointer() example
277- ------------------------------
290+ `` GrowAndUpdatePointer() `` example
291+ ----------------------------------
278292
279293Example using a pointer to write bytes and to track the written size.
280294
@@ -310,22 +324,84 @@ Create the bytes string ``b"Hello World"``::
310324 }
311325
312326
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+
313386Reference Implementation
314387========================
315388
316389`Pull request gh-131681 <https://github.com/python/cpython/pull/131681 >`__.
317390
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:
321393
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.
326397
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.
329405
330406
331407Backwards Compatibility
@@ -334,6 +410,10 @@ Backwards Compatibility
334410There is no impact on the backward compatibility, only new APIs are
335411added.
336412
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+
337417
338418Prior Discussions
339419=================
0 commit comments