Issue #16147: PyUnicode_FromFormatV() doesn't need anymore to allocate a buffer

on the heap to format numbers.
This commit is contained in:
Victor Stinner 2012-10-06 23:48:20 +02:00
parent ff5a848db5
commit 15a1136547
2 changed files with 26 additions and 48 deletions

View File

@ -1716,9 +1716,10 @@ class UnicodeTest(string_tests.CommonTest,
# Test PyUnicode_FromFormat()
def test_from_format(self):
support.import_module('ctypes')
from ctypes import (pythonapi, py_object,
from ctypes import (
pythonapi, py_object, sizeof,
c_int, c_long, c_longlong, c_ssize_t,
c_uint, c_ulong, c_ulonglong, c_size_t)
c_uint, c_ulong, c_ulonglong, c_size_t, c_void_p)
name = "PyUnicode_FromFormat"
_PyUnicode_FromFormat = getattr(pythonapi, name)
_PyUnicode_FromFormat.restype = py_object
@ -1769,6 +1770,15 @@ class UnicodeTest(string_tests.CommonTest,
self.assertEqual(PyUnicode_FromFormat(b'%llu', c_ulonglong(123)), '123')
self.assertEqual(PyUnicode_FromFormat(b'%zu', c_size_t(123)), '123')
# test long output
min_longlong = -(2 ** (8 * sizeof(c_longlong) - 1))
max_longlong = -min_longlong - 1
self.assertEqual(PyUnicode_FromFormat(b'%lld', c_longlong(min_longlong)), str(min_longlong))
self.assertEqual(PyUnicode_FromFormat(b'%lld', c_longlong(max_longlong)), str(max_longlong))
max_ulonglong = 2 ** (8 * sizeof(c_ulonglong)) - 1
self.assertEqual(PyUnicode_FromFormat(b'%llu', c_ulonglong(max_ulonglong)), str(max_ulonglong))
PyUnicode_FromFormat(b'%p', c_void_p(-1))
# test padding (width and/or precision)
self.assertEqual(PyUnicode_FromFormat(b'%010i', c_int(123)), '123'.rjust(10, '0'))
self.assertEqual(PyUnicode_FromFormat(b'%100i', c_int(123)), '123'.rjust(100))

View File

@ -2328,10 +2328,7 @@ makefmt(char *fmt, int longflag, int longlongflag, int size_tflag,
*fmt = '\0';
}
/* maximum number of characters required for output of %ld. 21 characters
allows for 64-bit integers (in decimal) and an optional sign. */
#define MAX_LONG_CHARS 21
/* maximum number of characters required for output of %lld.
/* maximum number of characters required for output of %lld or %p.
We need at most ceil(log10(256)*SIZEOF_LONG_LONG) digits,
plus 1 for the sign. 53/22 is an upper bound for log10(256). */
#define MAX_LONG_LONG_CHARS (2 + (SIZEOF_LONG_LONG*53-1) / 22)
@ -2436,19 +2433,7 @@ unicode_fromformat_arg(_PyUnicodeWriter *writer,
{
/* used by sprintf */
char fmt[10]; /* should be enough for "%0lld\0" */
char small_buffer[MAX_LONG_CHARS];
char *buffer;
int err;
if (sizeof(small_buffer) - 1 < precision) {
buffer = PyMem_Malloc(precision + 1);
if (buffer == NULL) {
PyErr_NoMemory();
return NULL;
}
}
else
buffer = small_buffer;
char buffer[MAX_LONG_LONG_CHARS];
if (*f == 'u') {
makefmt(fmt, longflag, longlongflag, size_tflag, *f);
@ -2492,45 +2477,28 @@ unicode_fromformat_arg(_PyUnicodeWriter *writer,
}
assert(len >= 0);
err = 0;
if (precision < len)
precision = len;
if (width > precision) {
Py_UCS4 fillchar;
fill = width - precision;
fillchar = zeropad?'0':' ';
if (_PyUnicodeWriter_Prepare(writer, fill, fillchar) != -1) {
if (PyUnicode_Fill(writer->buffer, writer->pos, fill, fillchar) == -1)
err = 1;
}
else
err = 1;
if (!err)
writer->pos += fill;
}
if (!err && precision > len) {
fill = precision - len;
if (_PyUnicodeWriter_Prepare(writer, fill, '0') != -1) {
if (PyUnicode_Fill(writer->buffer, writer->pos, fill, '0') == -1)
err = 1;
}
else
err = 1;
if (!err)
writer->pos += fill;
}
if (!err) {
if (_PyUnicodeWriter_WriteCstr(writer, buffer, len) == -1)
err = 1;
}
if (buffer != small_buffer) {
PyMem_Free(buffer);
buffer = small_buffer;
}
if (err)
if (_PyUnicodeWriter_Prepare(writer, fill, fillchar) == -1)
return NULL;
if (PyUnicode_Fill(writer->buffer, writer->pos, fill, fillchar) == -1)
return NULL;
writer->pos += fill;
}
if (precision > len) {
fill = precision - len;
if (_PyUnicodeWriter_Prepare(writer, fill, '0') == -1)
return NULL;
if (PyUnicode_Fill(writer->buffer, writer->pos, fill, '0') == -1)
return NULL;
writer->pos += fill;
}
if (_PyUnicodeWriter_WriteCstr(writer, buffer, len) == -1)
return NULL;
break;
}