diff --git a/Doc/c-api/unicode.rst b/Doc/c-api/unicode.rst index f5704cffa199a58..bebb50f4d6d58bb 100644 --- a/Doc/c-api/unicode.rst +++ b/Doc/c-api/unicode.rst @@ -1663,6 +1663,15 @@ object. On success, return ``0``. On error, set an exception, leave the writer unchanged, and return ``-1``. +.. c:function:: int PyUnicodeWriter_Fill(PyUnicodeWriter *writer, Py_ssize_t len, Py_UCS4 ch) + + Write *len* times the single Unicode character *ch* into *writer*. + + *len* must not be negative. + + On success, return ``0``. + On error, set an exception, leave the writer unchanged, and return ``-1``. + .. c:function:: int PyUnicodeWriter_Format(PyUnicodeWriter *writer, const char *format, ...) Similar to :c:func:`PyUnicode_FromFormat`, but write the output directly into *writer*. diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index c62a3ca5872eefd..a018d45ca8759fc 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -639,6 +639,7 @@ New Features * :c:func:`PyUnicodeWriter_WriteStr` * :c:func:`PyUnicodeWriter_WriteRepr` * :c:func:`PyUnicodeWriter_WriteSubstring` + * :c:func:`PyUnicodeWriter_Fill` * :c:func:`PyUnicodeWriter_Format` * :c:func:`PyUnicodeWriter_DecodeUTF8Stateful` diff --git a/Include/cpython/unicodeobject.h b/Include/cpython/unicodeobject.h index 917991371012806..0e8be484ee49e92 100644 --- a/Include/cpython/unicodeobject.h +++ b/Include/cpython/unicodeobject.h @@ -467,6 +467,10 @@ PyAPI_FUNC(int) PyUnicodeWriter_WriteUCS4( PyUnicodeWriter *writer, Py_UCS4 *str, Py_ssize_t size); +PyAPI_FUNC(int) PyUnicodeWriter_Fill( + PyUnicodeWriter *writer, + Py_ssize_t len, + Py_UCS4 ch); PyAPI_FUNC(int) PyUnicodeWriter_WriteStr( PyUnicodeWriter *writer, diff --git a/Lib/test/test_capi/test_unicode.py b/Lib/test/test_capi/test_unicode.py index 65d8242ad3fc606..af969d1a307e51a 100644 --- a/Lib/test/test_capi/test_unicode.py +++ b/Lib/test/test_capi/test_unicode.py @@ -1744,8 +1744,11 @@ def test_basic(self): # test PyUnicodeWriter_WriteRepr() writer.write_repr("repr") + # test PyUnicodeWriter_Fill() + writer.fill(3, ".") + self.assertEqual(writer.finish(), - "var=long value 'repr'") + "var=long value 'repr'...") def test_utf8(self): writer = self.create_writer(0) @@ -1867,6 +1870,17 @@ def test_substring_empty(self): writer.write_substring("abc", 1, 1) self.assertEqual(writer.finish(), '') + def test_fill(self): + writer = self.create_writer(0) + writer.fill(0, "#") + writer.write_char('(') + writer.fill(3, ".") + writer.write_char(')') + writer.fill(5, "-") + writer.write_char('.') + self.assertEqual(writer.finish(), + "(...)-----.") + @unittest.skipIf(ctypes is None, 'need ctypes') class PyUnicodeWriterFormatTest(unittest.TestCase): diff --git a/Modules/_testcapi/unicode.c b/Modules/_testcapi/unicode.c index b8ecf53f4f8b9c5..3acc3e6f5204388 100644 --- a/Modules/_testcapi/unicode.c +++ b/Modules/_testcapi/unicode.c @@ -510,6 +510,27 @@ writer_finish(PyObject *self_raw, PyObject *Py_UNUSED(args)) } +static PyObject* +writer_fill(PyObject *self_raw, PyObject *args) +{ + WriterObject *self = (WriterObject *)self_raw; + if (writer_check(self) < 0) { + return NULL; + } + + Py_ssize_t len; + int ch; + if (!PyArg_ParseTuple(args, "nC", &len, &ch)) { + return NULL; + } + + if (PyUnicodeWriter_Fill(self->writer, len, ch) < 0) { + return NULL; + } + Py_RETURN_NONE; +} + + static PyMethodDef writer_methods[] = { {"write_char", _PyCFunction_CAST(writer_write_char), METH_VARARGS}, {"write_utf8", _PyCFunction_CAST(writer_write_utf8), METH_VARARGS}, @@ -519,6 +540,7 @@ static PyMethodDef writer_methods[] = { {"write_repr", _PyCFunction_CAST(writer_write_repr), METH_VARARGS}, {"write_substring", _PyCFunction_CAST(writer_write_substring), METH_VARARGS}, {"decodeutf8stateful", _PyCFunction_CAST(writer_decodeutf8stateful), METH_VARARGS}, + {"fill", _PyCFunction_CAST(writer_fill), METH_VARARGS}, {"get_pointer", _PyCFunction_CAST(writer_get_pointer), METH_VARARGS}, {"finish", _PyCFunction_CAST(writer_finish), METH_NOARGS}, {NULL, NULL} /* sentinel */ diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index bd5bb5048fdacca..5f8e02f805640b4 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -13572,6 +13572,33 @@ PyUnicodeWriter_WriteChar(PyUnicodeWriter *writer, Py_UCS4 ch) return _PyUnicodeWriter_WriteChar((_PyUnicodeWriter*)writer, ch); } +int +PyUnicodeWriter_Fill(PyUnicodeWriter *pub_writer, Py_ssize_t len, Py_UCS4 ch) +{ + if (len < 0) { + PyErr_Format(PyExc_ValueError, "len must not be negative"); + return -1; + } + if (ch > MAX_UNICODE) { + PyErr_SetString(PyExc_ValueError, + "character must be in range(0x110000)"); + return -1; + } + + if (len == 0) { + return 0; + } + + _PyUnicodeWriter *writer = (_PyUnicodeWriter *)pub_writer; + if (_PyUnicodeWriter_Prepare(writer, len, ch) < 0) { + return -1; + } + + _PyUnicode_FastFill(writer->buffer, writer->pos, len, ch); + writer->pos += len; + return 0; +} + int _PyUnicodeWriter_WriteStr(_PyUnicodeWriter *writer, PyObject *str) {