Skip to content

Commit 31c7ca7

Browse files
committed
Add PyBytesWriter_Format()
1 parent eff71b5 commit 31c7ca7

File tree

4 files changed

+90
-16
lines changed

4 files changed

+90
-16
lines changed

Include/cpython/bytesobject.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,10 @@ PyAPI_FUNC(int) PyBytesWriter_WriteBytes(
7070
PyBytesWriter *writer,
7171
const void *bytes,
7272
Py_ssize_t size);
73+
PyAPI_FUNC(int) PyBytesWriter_Format(
74+
PyBytesWriter *writer,
75+
const char *format,
76+
...);
7377

7478
PyAPI_FUNC(int) PyBytesWriter_Resize(
7579
PyBytesWriter *writer,

Lib/test/test_capi/test_bytes.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -356,11 +356,16 @@ def test_resize(self):
356356
writer.resize(len(b'number=123456'), b'456')
357357
self.assertEqual(writer.finish(), b'number=123456')
358358

359-
# def test_format(self):
360-
# # Test PyBytesWriter_Format()
361-
# writer = self.create_writer()
362-
# writer.format_i(123456)
363-
# self.assertEqual(writer.finish(), b'123456')
359+
def test_format_i(self):
360+
# Test PyBytesWriter_Format()
361+
writer = self.create_writer()
362+
writer.format_i(b'x=%i', 123456)
363+
self.assertEqual(writer.finish(), b'x=123456')
364+
365+
writer = self.create_writer()
366+
writer.format_i(b'x=%i, ', 123)
367+
writer.format_i(b'y=%i', 456)
368+
self.assertEqual(writer.finish(), b'x=123, y=456')
364369

365370

366371
if __name__ == "__main__":

Modules/_testcapi/bytes.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,27 @@ writer_write_bytes(PyObject *self_raw, PyObject *args)
151151
}
152152

153153

154+
static PyObject*
155+
writer_format_i(PyObject *self_raw, PyObject *args)
156+
{
157+
WriterObject *self = (WriterObject *)self_raw;
158+
if (writer_check(self) < 0) {
159+
return NULL;
160+
}
161+
162+
char *format;
163+
int value;
164+
if (!PyArg_ParseTuple(args, "yi", &format, &value)) {
165+
return NULL;
166+
}
167+
168+
if (PyBytesWriter_Format(self->writer, format, value) < 0) {
169+
return NULL;
170+
}
171+
Py_RETURN_NONE;
172+
}
173+
174+
154175
static PyObject*
155176
writer_resize(PyObject *self_raw, PyObject *args)
156177
{
@@ -242,6 +263,7 @@ writer_finish_with_size(PyObject *self_raw, PyObject *args)
242263

243264
static PyMethodDef writer_methods[] = {
244265
{"write_bytes", _PyCFunction_CAST(writer_write_bytes), METH_VARARGS},
266+
{"format_i", _PyCFunction_CAST(writer_format_i), METH_VARARGS},
245267
{"resize", _PyCFunction_CAST(writer_resize), METH_VARARGS},
246268
{"get_size", _PyCFunction_CAST(writer_get_size), METH_NOARGS},
247269
{"get_allocated", _PyCFunction_CAST(writer_get_allocated), METH_NOARGS},

Objects/bytesobject.c

Lines changed: 54 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -196,8 +196,10 @@ PyBytes_FromString(const char *str)
196196
return (PyObject *) op;
197197
}
198198

199-
PyObject *
200-
PyBytes_FromFormatV(const char *format, va_list vargs)
199+
200+
static char*
201+
bytes_fromformat(PyBytesWriter *writer, Py_ssize_t writer_pos,
202+
const char *format, va_list vargs)
201203
{
202204
const char *f;
203205
const char *p;
@@ -213,12 +215,8 @@ PyBytes_FromFormatV(const char *format, va_list vargs)
213215
"0xffffffffffffffff\0" (19 bytes). */
214216
char buffer[21];
215217

216-
Py_ssize_t alloc = strlen(format);
217-
PyBytesWriter *writer = PyBytesWriter_Create(alloc);
218-
if (writer == NULL) {
219-
return NULL;
220-
}
221-
char *s = PyBytesWriter_GetData(writer);
218+
char *s = PyBytesWriter_GetData(writer) + writer_pos;
219+
Py_ssize_t alloc = PyBytesWriter_GetSize(writer);
222220

223221
#define WRITE_BYTES_LEN(str, len_expr) \
224222
do { \
@@ -366,20 +364,39 @@ PyBytes_FromFormatV(const char *format, va_list vargs)
366364
default:
367365
/* invalid format string: copy unformatted string and exit */
368366
WRITE_BYTES(p);
369-
return PyBytesWriter_FinishWithEndPointer(writer, s);
367+
return s;
370368
}
371369
}
372370

373371
#undef WRITE_BYTES
374372
#undef WRITE_BYTES_LEN
375373

376-
return PyBytesWriter_FinishWithEndPointer(writer, s);
374+
return s;
377375

378376
error:
379-
PyBytesWriter_Discard(writer);
380377
return NULL;
381378
}
382379

380+
381+
PyObject *
382+
PyBytes_FromFormatV(const char *format, va_list vargs)
383+
{
384+
Py_ssize_t alloc = strlen(format);
385+
PyBytesWriter *writer = PyBytesWriter_Create(alloc);
386+
if (writer == NULL) {
387+
return NULL;
388+
}
389+
390+
char *s = bytes_fromformat(writer, 0, format, vargs);
391+
if (s == NULL) {
392+
PyBytesWriter_Discard(writer);
393+
return NULL;
394+
}
395+
396+
return PyBytesWriter_FinishWithEndPointer(writer, s);
397+
}
398+
399+
383400
PyObject *
384401
PyBytes_FromFormat(const char *format, ...)
385402
{
@@ -392,6 +409,7 @@ PyBytes_FromFormat(const char *format, ...)
392409
return ret;
393410
}
394411

412+
395413
/* Helpers for formatstring */
396414

397415
Py_LOCAL_INLINE(PyObject *)
@@ -3949,3 +3967,28 @@ PyBytesWriter_WriteBytes(PyBytesWriter *writer,
39493967
memcpy(buf + pos, bytes, size);
39503968
return 0;
39513969
}
3970+
3971+
3972+
int
3973+
PyBytesWriter_Format(PyBytesWriter *writer, const char *format, ...)
3974+
{
3975+
Py_ssize_t pos = writer->size;
3976+
Py_ssize_t format_len = strlen(format);
3977+
if (format_len > PY_SSIZE_T_MAX - pos) {
3978+
PyErr_NoMemory();
3979+
return -1;
3980+
}
3981+
Py_ssize_t alloc = pos + format_len;
3982+
3983+
if (PyBytesWriter_Resize(writer, alloc) < 0) {
3984+
return -1;
3985+
}
3986+
3987+
va_list vargs;
3988+
va_start(vargs, format);
3989+
char *buf = bytes_fromformat(writer, pos, format, vargs);
3990+
va_end(vargs);
3991+
3992+
Py_ssize_t size = buf - byteswriter_data(writer);
3993+
return PyBytesWriter_Resize(writer, size);
3994+
}

0 commit comments

Comments
 (0)