]> granicus.if.org Git - python/commitdiff
Issue #16147: PyUnicode_FromFormatV() doesn't need anymore to allocate a buffer
authorVictor Stinner <victor.stinner@gmail.com>
Sat, 6 Oct 2012 21:48:20 +0000 (23:48 +0200)
committerVictor Stinner <victor.stinner@gmail.com>
Sat, 6 Oct 2012 21:48:20 +0000 (23:48 +0200)
on the heap to format numbers.

Lib/test/test_unicode.py
Objects/unicodeobject.c

index 42df721eb0ece4f618cb011b4914ad6f67606b1a..2c416a3c47cc554c60eb011733216c80880fc2dc 100644 (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))
index e6fe1fba4e2a9c5ba9ffe91287a2fe2d33c8b8e0..0ed38fef8f554efdfb4dae831d04a55325ed8003 100644 (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 (_PyUnicodeWriter_Prepare(writer, fill, fillchar) == -1)
+                return NULL;
+            if (PyUnicode_Fill(writer->buffer, writer->pos, fill, fillchar) == -1)
+                return NULL;
+            writer->pos += fill;
         }
-        if (!err && precision > len) {
+        if (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 (_PyUnicodeWriter_Prepare(writer, fill, '0') == -1)
+                return NULL;
+            if (PyUnicode_Fill(writer->buffer, writer->pos, fill, '0') == -1)
+                return NULL;
+            writer->pos += fill;
         }
-        if (err)
+        if (_PyUnicodeWriter_WriteCstr(writer, buffer, len) == -1)
             return NULL;
-
         break;
     }