[C API] PEP 782: Add PyBytesWriter API · Issue #129813 · python/cpython (original) (raw)
Feature or enhancement
Proposal:
I propose adding a PyBytesWriter API to create bytes
objects.
- Efficient API thanks to overallocation in
PyBytesWriter_Extend()
and usage of a "small buffer" of (around) 256 bytes - Avoid creating incomplete/inconsistent
bytes
objects. - Avoid mutating immutable
bytes
.
API:
typedef struct PyBytesWriter PyBytesWriter;
PyAPI_FUNC(void*) PyBytesWriter_Create( PyBytesWriter **writer, Py_ssize_t alloc); PyAPI_FUNC(void) PyBytesWriter_Discard( PyBytesWriter writer); PyAPI_FUNC(PyObject) PyBytesWriter_Finish( PyBytesWriter *writer, void *buf);
PyAPI_FUNC(Py_ssize_t) PyBytesWriter_GetRemaining( PyBytesWriter *writer, void buf); PyAPI_FUNC(void) PyBytesWriter_Extend( PyBytesWriter *writer, void buf, Py_ssize_t extend); PyAPI_FUNC(void) PyBytesWriter_WriteBytes( PyBytesWriter *writer, void *buf, const void bytes, Py_ssize_t size); PyAPI_FUNC(void) PyBytesWriter_Format( PyBytesWriter *writer, void *buf, const char *format, ...);
Simple example creating the string b"abc"
:
PyObject* create_abc(void) { PyBytesWriter *writer; char *str = PyBytesWriter_Create(&writer, 3); if (writer == NULL) return NULL;
memcpy(str, "abc", 3);
str += 3;
return PyBytesWriter_Finish(writer, str);
}
Example formatting an integer in decimal, the size is not known in advance::
PyObject* format_int(int value) { PyBytesWriter *writer; char *str = PyBytesWriter_Create(&writer, 20); if (writer == NULL) return NULL;
str += PyOS_snprintf(str, 20, "%i", value);
return PyBytesWriter_Finish(writer, str);
}
Note: using PyBytesWriter_Format()
would make this code simpler.
Example using PyBytesWriter_Extend()
,smilar to bytes.center()
with a different API: spaces are number of whitespaces added to the left and to the right:
static PyObject * byteswriter_center_example(Py_ssize_t spaces, char *str, Py_ssize_t str_size) { PyBytesWriter *writer; char *buf = PyBytesWriter_Create(&writer, spaces * 2); if (buf == NULL) { goto error; } assert(PyBytesWriter_GetRemaining(writer, buf) == spaces * 2);
// Add left spaces
memset(buf, ' ', spaces);
buf += spaces;
assert(PyBytesWriter_GetRemaining(writer, buf) == spaces);
// Copy string
buf = PyBytesWriter_Extend(writer, buf, str_size);
if (buf == NULL) {
goto error;
}
assert(PyBytesWriter_GetRemaining(writer, buf) == spaces + str_size);
memcpy(buf, str, str_size);
buf += str_size;
assert(PyBytesWriter_GetRemaining(writer, buf) == spaces);
// Add right spaces
memset(buf, ' ', spaces);
buf += spaces;
assert(PyBytesWriter_GetRemaining(writer, buf) == 0);
return PyBytesWriter_Finish(writer, buf);
error: PyBytesWriter_Discard(writer); return NULL; }
Has this already been discussed elsewhere?
No response given
Links to previous discussion of this feature:
My previous attempt in July/August 2024: