[Python-checkins] r54137 - sandbox/trunk/pep3101/test_simpleformat.py sandbox/trunk/pep3101/unicodeformat.c
eric.smith
python-checkins at python.org
Mon Mar 5 13:05:30 CET 2007
Author: eric.smith
Date: Mon Mar 5 13:05:29 2007
New Revision: 54137
Modified:
sandbox/trunk/pep3101/test_simpleformat.py
sandbox/trunk/pep3101/unicodeformat.c
Log:
Completed all floating point formats, with tests.
Modified: sandbox/trunk/pep3101/test_simpleformat.py
==============================================================================
--- sandbox/trunk/pep3101/test_simpleformat.py (original)
+++ sandbox/trunk/pep3101/test_simpleformat.py Mon Mar 5 13:05:29 2007
@@ -125,7 +125,7 @@
self.formatEquals("a", "{0:c}", ord("a"))
self.formatEquals("8_08b", "{0:08b}", 8)
self.formatEquals(" 8", "{0: >3d}", 8)
- self.formatEquals("0.1515_.0%", "{0:.0%}", .1515)
+ self.formatEquals("15%", "{0:.0%}", .1515)
def test_string_specifiers(self):
self.formatEqualsWithUnicode("abc", "{0:.3s}", "abc")
@@ -232,6 +232,22 @@
# XXX this should raise, but instead gives a DeprecationWarning
#self.formatRaises(TypeError, "{0:c}", 3.14)
+ def test_exponent_specifiers(self):
+ self.formatEqualsWithUnicodeUC("3.141500e+00", "{0:e}", 3.1415)
+ self.formatEqualsWithUnicodeUC("3.1415000000e+00", "{0:.10e}", 3.1415)
+
+ def test_fixed_specifiers(self):
+ self.formatEqualsWithUnicode("3.141500", "{0:f}", 3.1415)
+ self.formatEqualsWithUnicode("3.1415000000", "{0:.10f}", 3.1415)
+ self.formatEqualsWithUnicode("3.1415e+200", "{0:f}", 3.1415e200)
+ self.formatEqualsWithUnicode("3.1415e+200", "{0:F}", 3.1415e200)
+
+ def test_general_specifiers(self):
+ self.formatEqualsWithUnicodeUC("3.1415", "{0:g}", 3.1415)
+ self.formatEqualsWithUnicodeUC("3.1415", "{0:.10g}", 3.1415)
+ self.formatEqualsWithUnicodeUC("3.1415e+200", "{0:g}", 3.1415e200)
+ self.formatEqualsWithUnicodeUC("3.1415e+200", "{0:g}", 3.1415e200)
+
def test_missing_type_specifier(self):
# make sure floats use 'g', ints and longs 'd', and everything else 's'
pass
Modified: sandbox/trunk/pep3101/unicodeformat.c
==============================================================================
--- sandbox/trunk/pep3101/unicodeformat.c (original)
+++ sandbox/trunk/pep3101/unicodeformat.c Mon Mar 5 13:05:29 2007
@@ -60,9 +60,10 @@
#define MAX_SIZE_INCREMENT 3200
#if PYTHON_API_VERSION < 1013
-#define PySet_Discard PyDict_DelItem
-#define PySet_New PyDict_Copy
-#define PySet_GET_SIZE PyDict_Size
+#define PySet_Discard PyDict_DelItem
+#define PySet_New PyDict_Copy
+#define PySet_GET_SIZE PyDict_Size
+#define PyOS_ascii_formatd PyOS_snprintf
#endif
@@ -74,7 +75,6 @@
+ 1 + 1 = 24 */
#define MAXLEN_INT_STRING 64
-
/************************************************************************/
/*********** Global data structures and forward declarations *********/
/************************************************************************/
@@ -1142,8 +1142,8 @@
#if C_UNICODE
len = strtounicode(*pbuf, start, -1);
#else
- /* compute the length. I believe this is done because the return value from
- snprintf above is unreliable */
+ /* compute the length. I believe this is done because the return
+ value from snprintf above is unreliable */
len = strlen(start);
#endif
@@ -1207,7 +1207,7 @@
}
static int
-format_decimal(PyObject *fieldobj, FmtState *fs,
+format_integer(PyObject *fieldobj, FmtState *fs,
const InternalFormatSpec *format)
{
CH_TYPE *p_buf;
@@ -1322,7 +1322,8 @@
}
/* set the total length of the string */
- n_total = n_lpadding + n_lsign + n_spadding + n_digits + n_rsign + n_rpadding;
+ n_total = n_lpadding + n_lsign + n_spadding + n_digits
+ + n_rsign + n_rpadding;
assert(n_total >= n_allocated);
/* because we're going to reallocate, our pointers might be
@@ -1355,17 +1356,20 @@
overwrite some of that space */
/* short circuit test, in case we don't have to move anything */
if (p_buf + (n_lpadding + n_lsign + n_spadding) != p_digits)
- memmove(p_buf + (n_lpadding + n_lsign + n_spadding), p_digits, n_digits * sizeof(CH_TYPE));
+ memmove(p_buf + (n_lpadding + n_lsign + n_spadding), p_digits,
+ n_digits * sizeof(CH_TYPE));
if (n_lpadding) {
- CH_TYPE_FILL(p_buf, format->fill_char == '\0' ? ' ' : format->fill_char, n_lpadding);
+ CH_TYPE_FILL(p_buf, format->fill_char == '\0' ? ' ' : format->fill_char,
+ n_lpadding);
p_buf += n_lpadding;
}
if (n_lsign == 1) {
*p_buf++ = lsign;
}
if (n_spadding) {
- CH_TYPE_FILL(p_buf, format->fill_char == '\0' ? ' ' : format->fill_char, n_spadding);
+ CH_TYPE_FILL(p_buf, format->fill_char == '\0' ? ' ' : format->fill_char,
+ n_spadding);
p_buf += n_spadding;
}
p_buf += n_digits;
@@ -1373,7 +1377,8 @@
*p_buf++ = rsign;
}
if (n_rpadding) {
- CH_TYPE_FILL(p_buf, format->fill_char == '\0' ? ' ' : format->fill_char, n_rpadding);
+ CH_TYPE_FILL(p_buf, format->fill_char == '\0' ? ' ' : format->fill_char,
+ n_rpadding);
p_buf += n_rpadding;
}
@@ -1381,24 +1386,87 @@
}
static int
-format_exponent(PyObject *fieldobj, FmtState *fs,
- const InternalFormatSpec *format)
-{
- return format_DUMMY(fieldobj, fs);
-}
-
-static int
-format_fixed(PyObject *fieldobj, FmtState *fs,
+format_float(PyObject *fieldobj, FmtState *fs,
const InternalFormatSpec *format)
{
- return format_DUMMY(fieldobj, fs);
-}
+ /* first, do the conversion as 8-bit chars, using the platform's
+ snprintf. then, if needed, convert to unicode. */
-static int
-format_general(PyObject *fieldobj, FmtState *fs,
- const InternalFormatSpec *format)
-{
- return format_DUMMY(fieldobj, fs);
+ /* 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())
+ return 0;
+
+ if (type == '%') {
+ type = 'f';
+ x *= 100;
+ trailing = "%%";
+ }
+
+ 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_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;
}
static int
@@ -1448,13 +1516,6 @@
return ok;
}
-static int
-format_percentage(PyObject *fieldobj, FmtState *fs,
- const InternalFormatSpec *format)
-{
- return format_DUMMY(fieldobj, fs);
-}
-
/* returns a pointer to our conversion function, or NULL if invalid */
Py_LOCAL_INLINE(FormatFunction)
format_function(CH_TYPE c)
@@ -1462,23 +1523,23 @@
switch (c) {
case 'b': return format_binary; /* base-2 */
case 'c': return format_char; /* as character */
- case 'd': return format_decimal; /* decimal integer */
- case 'e': return format_exponent; /* exponential notation */
- case 'E': return format_exponent; /* exponential notation
- with uppercase 'E' */
- case 'f': return format_fixed; /* fixed-point */
- case 'F': return format_fixed; /* fixed-point with uppercase */
- case 'g': return format_general; /* general number notation */
- case 'G': return format_general; /* general number notation
- with uppercase 'E' */
case 'n': return format_locale_number; /* number in locale-specific
format */
- case 'o': return format_decimal; /* octal */
+ case 'd': /* decimal integer */
+ case 'o': /* octal */
+ case 'x': /* base 16 */
+ case 'X': return format_integer; /* base 16 uppercase */
case 'r': return format_repr; /* in repr() format */
case 's': return format_string; /* convert using str() */
- case 'x': return format_decimal; /* base 16 */
- case 'X': return format_decimal; /* base 16 uppercase */
- case '%': return format_percentage; /* as percentage */
+ case 'e': /* exponential notation */
+ case 'E': /* exponential notation
+ with uppercase 'E' */
+ case 'f': /* fixed-point */
+ case 'F': /* fixed-point with uppercase */
+ case 'g': /* general number notation */
+ case 'G': /* general number notation
+ with uppercase 'E' */
+ case '%': return format_float; /* as percentage */
default:
return NULL;
}
@@ -1727,7 +1788,7 @@
static int
do_markup(FmtState *fs)
{
- CH_TYPE c, *start, *ptr, *end;
+ CH_TYPE c = 0, *start, *ptr, *end;
Py_ssize_t count;
int syntaxmode, escape, at_end;
More information about the Python-checkins
mailing list