[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