Closed
Description
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: