[Python-checkins] r54146 - sandbox/trunk/pep3101/unicodeformat.c

eric.smith python-checkins at python.org
Tue Mar 6 05:04:01 CET 2007


Author: eric.smith
Date: Tue Mar  6 05:03:49 2007
New Revision: 54146

Modified:
   sandbox/trunk/pep3101/unicodeformat.c
Log:
Refactored float formatting, again.  This time it's simpler by using a callback, instead of the two-phase version I used last time.

Modified: sandbox/trunk/pep3101/unicodeformat.c
==============================================================================
--- sandbox/trunk/pep3101/unicodeformat.c	(original)
+++ sandbox/trunk/pep3101/unicodeformat.c	Tue Mar  6 05:03:49 2007
@@ -66,7 +66,6 @@
 #define PySet_Discard        PyDict_DelItem
 #define PySet_New            PyDict_Copy
 #define PySet_GET_SIZE       PyDict_Size
-#define PyOS_ascii_formatd   PyOS_snprintf
 #endif
 
 
@@ -1505,54 +1504,65 @@
     return 1;
 }
 
-/* state that needs to be passed between _format_float_phase1() and
-   _format_float_phase2() */
-typedef struct {
+/* the callback function to call to do the actual float formatting.
+   it matches the definition of PyOS_ascii_formatd */
+typedef char*
+(*DoubleSnprintfFunction)(char *buffer, size_t buf_len,
+                          const char *format, double d);
+
+/* just a wrapper to make PyOS_snprintf look like DoubleSnprintfFunction */
+static char*
+snprintf_double(char *buffer, size_t buf_len, const char *format, double d)
+{
+    PyOS_snprintf(buffer, buf_len, format, d);
+    return NULL;
+}
+
+/* use type instead of format->type, so that it can be overridden by
+   format_locale_number() */
+static int
+_format_float(CH_TYPE type, PyObject *fieldobj, FmtState *fs,
+              const InternalFormatSpec *format,
+              DoubleSnprintfFunction snprintf)
+{
     /* fmt = '%.' + `prec` + `type` + '%%'
        worst case length = 2 + 10 (len of INT_MAX) + 1 + 2 = 15 (use 20)*/
     char fmt[20];
     CH_TYPE *buf;
     int buflen;
     double x;
-} FloatState;
+    int len;
+    Py_ssize_t precision = format->precision;
+    char* trailing = "";
 
-/* use type instead of format->type, so that it can be overridden by
-   format_locale_number() */
-static int
-_format_float_phase1(FloatState *state, CH_TYPE type, PyObject *fieldobj,
-                     FmtState *fs, const InternalFormatSpec *format)
-{
     /* first, do the conversion as 8-bit chars, using the platform's
        snprintf.  then, if needed, convert to unicode. */
 
-    Py_ssize_t precision = format->precision;
-    char* trailing = "";
-
     /* 'F' is the same as 'f', per the PEP */
     if (type == 'F')
         type = 'f';
 
-    state->x = PyFloat_AsDouble(fieldobj);
-    if (state->x == -1.0 && PyErr_Occurred()) {
+    x = PyFloat_AsDouble(fieldobj);
+    if (x == -1.0 && PyErr_Occurred()) {
         printf("not a float\n");
 	return 0;
     }
 
     if (type == '%') {
         type = 'f';
-        state->x *= 100;
+        x *= 100;
         trailing = "%%";
     }
 
     if (precision < 0)
 	precision = 6;
-    if (type == 'f' && (fabs(state->x) / 1e25) >= 1e25)
+    if (type == 'f' && (fabs(x) / 1e25) >= 1e25)
 	type = 'g';
 
     /* cast "type", because if we're in unicode we need to pass a
        8-bit char.  this is safe, because we've restricted what "type"
        can be */
-    PyOS_snprintf(state->fmt, sizeof(state->fmt), "%%.%d%c%s", precision,
+    PyOS_snprintf(fmt, sizeof(fmt), "%%.%d%c%s", precision,
                   (char)type, trailing);
 
     /* this is taken from unicodeobject.c, except we don't force a
@@ -1576,30 +1586,24 @@
     /* so, allocate the precision plus 54 chars (we add one additional
        for the trailing percent).  do this allocation as the native
        type, because we're going to convert to unicode anyway */
-    state->buflen = 54 + precision;
-    if (output_allocate(fs, state->buflen, &state->buf) == 0)
+    buflen = 54 + precision;
+    if (output_allocate(fs, buflen, &buf) == 0)
         return 0;
 
-    return 1;
-}
-
-
-static int
-_format_float_phase2(FloatState *state, FmtState *fs)
-{
-    int len;
+    /* call the passed in function to do the actual formatting */
+    snprintf((char*)buf, buflen, fmt, x);
 
 #if C_UNICODE
-    len = strtounicode(state->buf, (char*)state->buf, -1);
+    len = strtounicode(buf, (char*)buf, -1);
 #else
     /* compute the length.  I believe this is done because the return
        value from snprintf above is unreliable */
-    len = strlen(state->buf);
+    len = strlen(buf);
 #endif
 
     /* shrink the buffer down to how many characters we actually
        wrote.  this is cheap, just pointer arithmetic */
-    output_shrink(fs, state->buflen - len);
+    output_shrink(fs, buflen - len);
 
     return 1;
 }
@@ -1608,11 +1612,13 @@
 format_float(PyObject *fieldobj, FmtState *fs,
              const InternalFormatSpec *format)
 {
-    FloatState state;
-    if (_format_float_phase1(&state, format->type, fieldobj, fs, format) == 0)
-        return 0;
-    PyOS_ascii_formatd((char *)state.buf, state.buflen, state.fmt, state.x);
-    return _format_float_phase2(&state, fs);
+    return _format_float(format->type, fieldobj, fs, format,
+#if PYTHON_API_VERSION < 1013
+                         snprintf_double
+#else
+                         PyOS_ascii_formatd
+#endif
+        );
 }
 
 /* this code is really the same as format_exponent, except it calls
@@ -1621,12 +1627,7 @@
 format_locale_number(PyObject *fieldobj, FmtState *fs,
                      const InternalFormatSpec *format)
 {
-    FloatState state;
-    if (_format_float_phase1(&state, 'f', fieldobj, fs, format) == 0) {
-        return 0;
-    }
-    PyOS_snprintf((char *)state.buf, state.buflen, state.fmt, state.x);
-    return _format_float_phase2(&state, fs);
+    return _format_float('f', fieldobj, fs, format, snprintf_double);
 }
 
 static int


More information about the Python-checkins mailing list