diff --git a/Doc/c-api/unicode.rst b/Doc/c-api/unicode.rst index 43e3d2fef23..3a8b38b636a 100644 --- a/Doc/c-api/unicode.rst +++ b/Doc/c-api/unicode.rst @@ -564,6 +564,21 @@ APIs: .. versionadded:: 3.3 +.. c:function:: int PyUnicode_Fill(PyObject *unicode, Py_ssize_t start, \ + Py_ssize_t length, Py_UCS4 fill_char) + + Fill a string with a character: write *fill_char* into + ``unicode[start:start+length]``. + + Fail if *fill_char* is bigger than the string maximum character, or if the + string has more than 1 reference. + + Return the number of written character, or return ``-1`` and raise an + exception on error. + + .. versionadded:: 3.3 + + .. c:function:: int PyUnicode_WriteChar(PyObject *unicode, Py_ssize_t index, \ Py_UCS4 character) diff --git a/Include/unicodeobject.h b/Include/unicodeobject.h index dfd594e0150..6255dc325d9 100644 --- a/Include/unicodeobject.h +++ b/Include/unicodeobject.h @@ -623,11 +623,11 @@ PyAPI_FUNC(PyObject*) _PyUnicode_Copy( #endif /* Copy character from one unicode object into another, this function performs - character conversion when necessary and falls back to memcpy if possible. + character conversion when necessary and falls back to memcpy() if possible. - Fail if to is too small (smaller than how_many or smaller than + Fail if to is too small (smaller than *how_many* or smaller than len(from)-from_start), or if kind(from[from_start:from_start+how_many]) > - kind(to), or if to has more than 1 reference. + kind(to), or if *to* has more than 1 reference. Return the number of written character, or return -1 and raise an exception on error. @@ -650,6 +650,23 @@ PyAPI_FUNC(Py_ssize_t) PyUnicode_CopyCharacters( ); #endif +/* Fill a string with a character: write fill_char into + unicode[start:start+length]. + + Fail if fill_char is bigger than the string maximum character, or if the + string has more than 1 reference. + + Return the number of written character, or return -1 and raise an exception + on error. */ +#ifndef Py_LIMITED_API +PyAPI_FUNC(Py_ssize_t) PyUnicode_Fill( + PyObject *unicode, + Py_ssize_t start, + Py_ssize_t length, + Py_UCS4 fill_char + ); +#endif + /* Create a Unicode Object from the Py_UNICODE buffer u of the given size. diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 9a9703a4458..5ca2c533e52 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -9818,6 +9818,41 @@ PyUnicode_Join(PyObject *separator, PyObject *seq) } \ } while (0) +Py_ssize_t +PyUnicode_Fill(PyObject *unicode, Py_ssize_t start, Py_ssize_t length, + Py_UCS4 fill_char) +{ + Py_ssize_t maxlen; + enum PyUnicode_Kind kind; + void *data; + + if (!PyUnicode_Check(unicode)) { + PyErr_BadInternalCall(); + return -1; + } + if (PyUnicode_READY(unicode) == -1) + return -1; + if (unicode_check_modifiable(unicode)) + return -1; + + if (fill_char > PyUnicode_MAX_CHAR_VALUE(unicode)) { + PyErr_SetString(PyExc_ValueError, + "fill character is bigger than " + "the string maximum character"); + return -1; + } + + maxlen = PyUnicode_GET_LENGTH(unicode) - start; + length = Py_MIN(maxlen, length); + if (length <= 0) + return 0; + + kind = PyUnicode_KIND(unicode); + data = PyUnicode_DATA(unicode); + FILL(kind, data, fill_char, start, length); + return length; +} + static PyObject * pad(PyObject *self, Py_ssize_t left, diff --git a/Python/formatter_unicode.c b/Python/formatter_unicode.c index 6deb3cd7fe8..ef0151192b7 100644 --- a/Python/formatter_unicode.c +++ b/Python/formatter_unicode.c @@ -317,15 +317,6 @@ calc_padding(Py_ssize_t nchars, Py_ssize_t width, Py_UCS4 align, *n_rpadding = *n_total - nchars - *n_lpadding; } -static void -unicode_fill(PyObject *str, Py_ssize_t start, Py_ssize_t end, Py_UCS4 ch) -{ - int kind = PyUnicode_KIND(str); - void *data = PyUnicode_DATA(str); - while (start < end) - PyUnicode_WRITE(kind, data, start++, ch); -} - /* Do the padding, and return a pointer to where the caller-supplied content goes. */ static Py_ssize_t @@ -335,12 +326,12 @@ fill_padding(PyObject *s, Py_ssize_t start, Py_ssize_t nchars, { /* Pad on left. */ if (n_lpadding) - unicode_fill(s, start, start + n_lpadding, fill_char); + PyUnicode_Fill(s, start, start + n_lpadding, fill_char); /* Pad on right. */ if (n_rpadding) - unicode_fill(s, start + nchars + n_lpadding, - start + nchars + n_lpadding + n_rpadding, fill_char); + PyUnicode_Fill(s, start + nchars + n_lpadding, + start + nchars + n_lpadding + n_rpadding, fill_char); /* Pointer to the user content. */ return start + n_lpadding; @@ -557,7 +548,7 @@ fill_number(PyObject *out, Py_ssize_t pos, const NumberFieldWidths *spec, #endif if (spec->n_lpadding) { - unicode_fill(out, pos, pos + spec->n_lpadding, fill_char); + PyUnicode_Fill(out, pos, pos + spec->n_lpadding, fill_char); pos += spec->n_lpadding; } if (spec->n_sign == 1) { @@ -581,7 +572,7 @@ fill_number(PyObject *out, Py_ssize_t pos, const NumberFieldWidths *spec, pos += spec->n_prefix; } if (spec->n_spadding) { - unicode_fill(out, pos, pos + spec->n_spadding, fill_char); + PyUnicode_Fill(out, pos, pos + spec->n_spadding, fill_char); pos += spec->n_spadding; } @@ -640,7 +631,7 @@ fill_number(PyObject *out, Py_ssize_t pos, const NumberFieldWidths *spec, } if (spec->n_rpadding) { - unicode_fill(out, pos, pos + spec->n_rpadding, fill_char); + PyUnicode_Fill(out, pos, pos + spec->n_rpadding, fill_char); pos += spec->n_rpadding; } return 0;