summaryrefslogtreecommitdiffstats
path: root/Objects/unicodeobject.c
diff options
context:
space:
mode:
authorEric Smith <eric@trueblade.com>2009-04-16 20:16:10 (GMT)
committerEric Smith <eric@trueblade.com>2009-04-16 20:16:10 (GMT)
commit0923d1d8d7e428297461ed5145f06915c462b25b (patch)
treeb1fee964b1030c99285ae9d95e7e4dfb60dcded0 /Objects/unicodeobject.c
parentb08a53a99def3fa949643974f713b5b189e21bc7 (diff)
downloadcpython-0923d1d8d7e428297461ed5145f06915c462b25b.zip
cpython-0923d1d8d7e428297461ed5145f06915c462b25b.tar.gz
cpython-0923d1d8d7e428297461ed5145f06915c462b25b.tar.bz2
The other half of Issue #1580: use short float repr where possible.
Addresses the float -> string conversion, using David Gay's code which was added in Mark Dickinson's checkin r71663. Also addresses these, which are intertwined with the short repr changes: - Issue #5772: format(1e100, '<') produces '1e+100', not '1.0e+100' - Issue #5515: 'n' formatting with commas no longer works poorly with leading zeros. - PEP 378 Format Specifier for Thousands Separator: implemented for floats.
Diffstat (limited to 'Objects/unicodeobject.c')
-rw-r--r--Objects/unicodeobject.c170
1 files changed, 33 insertions, 137 deletions
diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c
index f52c435..3cea899 100644
--- a/Objects/unicodeobject.c
+++ b/Objects/unicodeobject.c
@@ -8792,42 +8792,13 @@ getnextarg(PyObject *args, Py_ssize_t arglen, Py_ssize_t *p_argidx)
return NULL;
}
-static Py_ssize_t
-strtounicode(Py_UNICODE *buffer, const char *charbuffer)
+static void
+strtounicode(Py_UNICODE *buffer, const char *charbuffer, Py_ssize_t len)
{
register Py_ssize_t i;
- Py_ssize_t len = strlen(charbuffer);
for (i = len - 1; i >= 0; i--)
buffer[i] = (Py_UNICODE) charbuffer[i];
-
- return len;
-}
-
-static int
-doubletounicode(Py_UNICODE *buffer, size_t len, const char *format, double x)
-{
- Py_ssize_t result;
-
- PyOS_ascii_formatd((char *)buffer, len, format, x);
- result = strtounicode(buffer, (char *)buffer);
- return Py_SAFE_DOWNCAST(result, Py_ssize_t, int);
-}
-
-#if 0
-static int
-longtounicode(Py_UNICODE *buffer, size_t len, const char *format, long x)
-{
- Py_ssize_t result;
-
- PyOS_snprintf((char *)buffer, len, format, x);
- result = strtounicode(buffer, (char *)buffer);
- return Py_SAFE_DOWNCAST(result, Py_ssize_t, int);
}
-#endif
-
-/* XXX To save some code duplication, formatfloat/long/int could have been
- shared with stringobject.c, converting from 8-bit to Unicode after the
- formatting is done. */
static int
formatfloat(Py_UNICODE *buf,
@@ -8837,54 +8808,59 @@ formatfloat(Py_UNICODE *buf,
int type,
PyObject *v)
{
- /* fmt = '%#.' + `prec` + `type`
- worst case length = 3 + 10 (len of INT_MAX) + 1 = 14 (use 20)*/
- char fmt[20];
+ /* eric.smith: To minimize disturbances in PyUnicode_Format (the
+ only caller of this routine), I'm going to keep the existing
+ API to this function. That means that we'll allocate memory and
+ then copy back into the supplied buffer. But that's better than
+ all of the changes that would be required in PyUnicode_Format
+ because it does lots of memory management tricks. */
+
+ char* p = NULL;
+ int result = -1;
double x;
+ Py_ssize_t len;
x = PyFloat_AsDouble(v);
if (x == -1.0 && PyErr_Occurred())
- return -1;
+ goto done;
if (prec < 0)
prec = 6;
+
/* make sure that the decimal representation of precision really does
need at most 10 digits: platforms with sizeof(int) == 8 exist! */
if (prec > 0x7fffffffL) {
PyErr_SetString(PyExc_OverflowError,
"outrageously large precision "
"for formatted float");
- return -1;
+ goto done;
}
if (type == 'f' && fabs(x) >= 1e50)
type = 'g';
- /* 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.
-
- */
if (((type == 'g' || type == 'G') &&
buflen <= (size_t)10 + (size_t)prec) ||
- (type == 'f' && buflen <= (size_t)53 + (size_t)prec)) {
+ ((type == 'f' || type == 'F') &&
+ buflen <= (size_t)53 + (size_t)prec)) {
PyErr_SetString(PyExc_OverflowError,
"formatted float is too long (precision too large?)");
- return -1;
+ goto done;
+ }
+
+ p = PyOS_double_to_string(x, type, prec,
+ (flags & F_ALT) ? Py_DTSF_ALT : 0, NULL);
+ len = strlen(p);
+ if (len+1 >= buflen) {
+ /* Caller supplied buffer is not large enough. */
+ PyErr_NoMemory();
+ goto done;
}
- PyOS_snprintf(fmt, sizeof(fmt), "%%%s.%d%c",
- (flags&F_ALT) ? "#" : "",
- prec, type);
- return doubletounicode(buf, buflen, fmt, x);
+ strtounicode(buf, p, len);
+ result = Py_SAFE_DOWNCAST(len, Py_ssize_t, int);
+
+done:
+ PyMem_Free(p);
+ return result;
}
static PyObject*
@@ -8903,84 +8879,6 @@ formatlong(PyObject *val, int flags, int prec, int type)
return result;
}
-#if 0
-static int
-formatint(Py_UNICODE *buf,
- size_t buflen,
- int flags,
- int prec,
- int type,
- PyObject *v)
-{
- /* fmt = '%#.' + `prec` + 'l' + `type`
- * worst case length = 3 + 19 (worst len of INT_MAX on 64-bit machine)
- * + 1 + 1
- * = 24
- */
- char fmt[64]; /* plenty big enough! */
- char *sign;
- long x;
-
- x = PyLong_AsLong(v);
- if (x == -1 && PyErr_Occurred())
- return -1;
- if (x < 0 && type == 'u') {
- type = 'd';
- }
- if (x < 0 && (type == 'x' || type == 'X' || type == 'o'))
- sign = "-";
- else
- sign = "";
- if (prec < 0)
- prec = 1;
-
- /* buf = '+'/'-'/'' + '0'/'0x'/'' + '[0-9]'*max(prec, len(x in octal))
- * worst case buf = '-0x' + [0-9]*prec, where prec >= 11
- */
- if (buflen <= 14 || buflen <= (size_t)3 + (size_t)prec) {
- PyErr_SetString(PyExc_OverflowError,
- "formatted integer is too long (precision too large?)");
- return -1;
- }
-
- if ((flags & F_ALT) &&
- (type == 'x' || type == 'X' || type == 'o')) {
- /* When converting under %#o, %#x or %#X, there are a number
- * of issues that cause pain:
- * - for %#o, we want a different base marker than C
- * - when 0 is being converted, the C standard leaves off
- * the '0x' or '0X', which is inconsistent with other
- * %#x/%#X conversions and inconsistent with Python's
- * hex() function
- * - there are platforms that violate the standard and
- * convert 0 with the '0x' or '0X'
- * (Metrowerks, Compaq Tru64)
- * - there are platforms that give '0x' when converting
- * under %#X, but convert 0 in accordance with the
- * standard (OS/2 EMX)
- *
- * We can achieve the desired consistency by inserting our
- * own '0x' or '0X' prefix, and substituting %x/%X in place
- * of %#x/%#X.
- *
- * Note that this is the same approach as used in
- * formatint() in stringobject.c
- */
- PyOS_snprintf(fmt, sizeof(fmt), "%s0%c%%.%dl%c",
- sign, type, prec, type);
- }
- else {
- PyOS_snprintf(fmt, sizeof(fmt), "%s%%%s.%dl%c",
- sign, (flags&F_ALT) ? "#" : "",
- prec, type);
- }
- if (sign[0])
- return longtounicode(buf, buflen, fmt, -x);
- else
- return longtounicode(buf, buflen, fmt, x);
-}
-#endif
-
static int
formatchar(Py_UNICODE *buf,
size_t buflen,
@@ -9359,8 +9257,6 @@ PyObject *PyUnicode_Format(PyObject *format,
case 'F':
case 'g':
case 'G':
- if (c == 'F')
- c = 'f';
pbuf = formatbuf;
len = formatfloat(pbuf, sizeof(formatbuf)/sizeof(Py_UNICODE),
flags, prec, c, v);