[Python-checkins] r54144 - sandbox/trunk/pep3101/README.txt sandbox/trunk/pep3101/unicodeformat.c

eric.smith python-checkins at python.org
Tue Mar 6 04:27:49 CET 2007


Author: eric.smith
Date: Tue Mar  6 04:27:46 2007
New Revision: 54144

Modified:
   sandbox/trunk/pep3101/README.txt
   sandbox/trunk/pep3101/unicodeformat.c
Log:
Refactored so that format_locale_number() and format_float() share the same code, except for the call in the middle that does the actual formatting.

Modified: sandbox/trunk/pep3101/README.txt
==============================================================================
--- sandbox/trunk/pep3101/README.txt	(original)
+++ sandbox/trunk/pep3101/README.txt	Tue Mar  6 04:27:46 2007
@@ -61,8 +61,6 @@
     - Add capability to control exception handling to pep_differences
       and to code:  1) ability to dump exceptions into string, 2)
       ability to re-do lower exceptions or "pile-on"
-    - Refactor format_locale_number() and format_float() to avoid
-      massive code duplication.
     - Test suite needs to test different locales for 'n' formatting.
 
 

Modified: sandbox/trunk/pep3101/unicodeformat.c
==============================================================================
--- sandbox/trunk/pep3101/unicodeformat.c	(original)
+++ sandbox/trunk/pep3101/unicodeformat.c	Tue Mar  6 04:27:46 2007
@@ -1504,48 +1504,55 @@
     return 1;
 }
 
+/* state that needs to be passed between _format_float_phase1() and
+   _format_float_phase2() */
+typedef struct {
+    /* 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;
+
+/* use type instead of format->type, so that it can be overridden by
+   format_locale_number() */
 static int
-format_float(PyObject *fieldobj, FmtState *fs,
-             const InternalFormatSpec *format)
+_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. */
 
-    /* fmt = '%.' + `prec` + `type` + '%%'
-       worst case length = 2 + 10 (len of INT_MAX) + 1 + 2 = 15 (use 20)*/
-    char fmt[20];
-
-    double x;
-    CH_TYPE type = format->type;
     Py_ssize_t precision = format->precision;
-    CH_TYPE *buf;
-    int buflen;
-    int len;
     char* trailing = "";
 
     /* 'F' is the same as 'f', per the PEP */
     if (type == 'F')
         type = 'f';
 
-    x = PyFloat_AsDouble(fieldobj);
-    if (x == -1.0 && PyErr_Occurred())
+    state->x = PyFloat_AsDouble(fieldobj);
+    if (state->x == -1.0 && PyErr_Occurred()) {
+        printf("not a float\n");
 	return 0;
+    }
 
     if (type == '%') {
         type = 'f';
-        x *= 100;
+        state->x *= 100;
         trailing = "%%";
     }
 
     if (precision < 0)
 	precision = 6;
-    if (type == 'f' && (fabs(x) / 1e25) >= 1e25)
+    if (type == 'f' && (fabs(state->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(fmt, sizeof(fmt), "%%.%d%c%s", precision, (char)type, trailing);
+    PyOS_snprintf(state->fmt, sizeof(state->fmt), "%%.%d%c%s", precision,
+                  (char)type, trailing);
 
     /* this is taken from unicodeobject.c, except we don't force a
        limit here, we dynamically allocate instead */
@@ -1568,108 +1575,60 @@
     /* 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 */
-    buflen = 54 + precision;
-    if (output_allocate(fs, buflen, &buf) == 0)
+    state->buflen = 54 + precision;
+    if (output_allocate(fs, state->buflen, &state->buf) == 0)
         return 0;
-    PyOS_ascii_formatd((char *)buf, buflen, fmt, x);
-
-#if C_UNICODE
-    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(buf);
-#endif
-
-    /* shrink the buffer down to how many characters we actually
-       wrote.  this is cheap, just pointer arithmetic */
-    output_shrink(fs, buflen - len);
 
     return 1;
 }
 
-/* this code is really the same as format_exponent, except it calls
-   PyOS_snprintf() instead of PyOS_ascii_formatd().  it needs to be
-   refactored to avoid all of the duplicate code. */
+
 static int
-format_locale_number(PyObject *fieldobj, FmtState *fs,
-              const InternalFormatSpec *format)
+_format_float_phase2(FloatState *state, FmtState *fs)
 {
-    /* first, do the conversion as 8-bit chars, using the platform's
-       snprintf.  then, if needed, convert to unicode. */
-
-    /* fmt = '%.' + `prec` + `type` + '%%'
-       worst case length = 2 + 10 (len of INT_MAX) + 1 + 2 = 15 (use 20)*/
-    char fmt[20];
-
-    double x;
-    CH_TYPE type = 'f';
-    Py_ssize_t precision = format->precision;
-    CH_TYPE *buf;
-    int buflen;
     int len;
-    char* trailing = "";
-
-    /* 'F' is the same as 'f', per the PEP */
-    if (type == 'F')
-        type = 'f';
-
-    x = PyFloat_AsDouble(fieldobj);
-    if (x == -1.0 && PyErr_Occurred())
-	return 0;
-
-    if (precision < 0)
-	precision = 6;
-    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(fmt, sizeof(fmt), "%%.%d%c%s", precision, (char)type, trailing);
-
-    /* this is taken from unicodeobject.c, except we don't force a
-       limit here, we dynamically allocate instead */
-    /* Worst case length calc to ensure no buffer overrun:
-
-       'g' formats:
-	 fmt = %#.<prec>g
-	 buf = '-' + [0-9]*prec + '.' + 'e+' + (longest exp
-	    for any double rep.)
-	 len = 1 + prec + 1 + 2 + 5 = 9 + prec
-
-       'f' formats:
-	 buf = '-' + [0-9]*x + '.' + [0-9]*prec (with x < 50)
-	 len = 1 + 50 + 1 + prec = 52 + prec
-
-       If prec=0 the effective precision is 1 (the leading digit is
-       always given), therefore increase the length by one.
-
-    */
-    /* 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 */
-    buflen = 54 + precision;
-    if (output_allocate(fs, buflen, &buf) == 0)
-        return 0;
-    PyOS_snprintf((char *)buf, buflen, fmt, x);
 
 #if C_UNICODE
-    len = strtounicode(buf, (char*)buf, -1);
+    len = strtounicode(state->buf, (char*)state->buf, -1);
 #else
     /* compute the length.  I believe this is done because the return
        value from snprintf above is unreliable */
-    len = strlen(buf);
+    len = strlen(state->buf);
 #endif
 
     /* shrink the buffer down to how many characters we actually
        wrote.  this is cheap, just pointer arithmetic */
-    output_shrink(fs, buflen - len);
+    output_shrink(fs, state->buflen - len);
 
     return 1;
 }
 
 static int
+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);
+}
+
+/* this code is really the same as format_exponent, except it calls
+   PyOS_snprintf() instead of PyOS_ascii_formatd(). */
+static int
+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);
+}
+
+static int
 format_repr(PyObject *fieldobj, FmtState *fs,
             const InternalFormatSpec *format)
 {


More information about the Python-checkins mailing list