[Python-checkins] r71330 - python/branches/py3k-short-float-repr/Python/pystrtod.c
eric.smith
python-checkins at python.org
Tue Apr 7 00:02:08 CEST 2009
Author: eric.smith
Date: Tue Apr 7 00:02:07 2009
New Revision: 71330
Log:
Modify format_float_short() to compute how much memory to
allocate. This removes the last hard-coded buffer in this file.
Mark: Please review this, I'm sure it could be simplified. In
particular, min_digits1 feels hackish. Also, I'm assuming max 3 digits
for the exponent, which might not be correct. Maybe we should enforce
that the abs(exponent) < 1000?
Still need to detect errors in return value from_Py_dg_dtoa and handle
that correctly.
Modified:
python/branches/py3k-short-float-repr/Python/pystrtod.c
Modified: python/branches/py3k-short-float-repr/Python/pystrtod.c
==============================================================================
--- python/branches/py3k-short-float-repr/Python/pystrtod.c (original)
+++ python/branches/py3k-short-float-repr/Python/pystrtod.c Tue Apr 7 00:02:07 2009
@@ -547,11 +547,13 @@
int always_add_sign, int add_dot_0_if_integer,
int use_alt_formatting, char **float_strings)
{
- char* p = (char *)PyMem_Malloc(512);
- char* buf = p;
+ char *buf = NULL;
+ char *p;
+ Py_ssize_t bufsize = 0;
char *digits, *digits_end;
int decpt, sign, exp_len, dec_pos, use_exp = 0;
Py_ssize_t n_digits, min_digits = 0;
+ Py_ssize_t min_digits1;
/* _Py_dg_dtoa returns a digit string (no decimal point or
exponent). Must be matched by a call to _Py_dg_freedtoa. */
@@ -563,25 +565,35 @@
/* Infinities and nans here; adapt Gay's output,
so convert Infinity to inf and NaN to nan, and
ignore sign of nan. Then return. */
+
+ /* We only need 5 bytes to hold the result "+inf\0" . */
+ bufsize = 5; /* Used later in an assert. */
+ buf = (char *)PyMem_Malloc(bufsize);
+ if (buf == NULL) {
+ PyErr_NoMemory();
+ goto exit;
+ }
+ p = buf;
+
if (digits[0] == 'i' || digits[0] == 'I') {
if (sign == 1) {
- *buf++ = '-';
+ *p++ = '-';
}
else if (always_add_sign) {
- *buf++ = '+';
+ *p++ = '+';
}
- strncpy(buf, float_strings[OFS_INF], 3);
- buf += 3;
+ strncpy(p, float_strings[OFS_INF], 3);
+ p += 3;
}
else if (digits[0] == 'n' || digits[0] == 'N') {
- strncpy(buf, float_strings[OFS_NAN], 3);
- buf += 3;
+ strncpy(p, float_strings[OFS_NAN], 3);
+ p += 3;
}
else {
/* shouldn't get here: Gay's code should always return
something starting with a digit, an 'I', or 'N' */
- strncpy(buf, "ERR", 3);
- buf += 3;
+ strncpy(p, "ERR", 3);
+ p += 3;
assert(0);
}
goto exit;
@@ -629,69 +641,111 @@
goto exit;
}
- /* Always add a negative sign, and a plus sign if always_add_sign. */
- if (sign == 1)
- *buf++ = '-';
- else if (always_add_sign)
- *buf++ = '+';
-
/* dec_pos = position of decimal point in buffer */
if (use_exp)
dec_pos = 1;
else
dec_pos = decpt;
- /* zero padding on left of digit string */
+ min_digits -= n_digits;
+ min_digits1 = (n_digits < dec_pos) ?
+ (min_digits - (dec_pos-n_digits)) : min_digits;
+
+ /* Compute an upper bound how much memory we need. This might be a few
+ chars too long, but no big deal. */
+ bufsize =
+ /* 1: Sign */
+ 1 +
+
+ /* 2: Zero padding on left of digit string */
+ (dec_pos <= 0 ? -dec_pos + 2 : 0) +
+
+ /* 3: Digits, with included decimal point */
+ (1 + n_digits) +
+
+ /* 4: And zeros on the right up to the decimal point */
+ ((n_digits < dec_pos) ? dec_pos-n_digits + 1 : 0) +
+
+ /* 5: And more trailing zeros when necessary */
+ (min_digits1 > 0 ? min_digits1 : 0) +
+
+ /* 6: Exponent "e+100", max 3 numerical digits */
+ (use_exp ? 5 : 0) +
+
+ /* Trailing 0 byte */
+ 1;
+
+ /* Now allocate the memory and initialize p to point to the start of
+ it. */
+ buf = (char *)PyMem_Malloc(bufsize);
+ if (buf == NULL) {
+ PyErr_NoMemory();
+ goto exit;
+ }
+ p = buf;
+
+ /* 1: Add a negative sign if negative, and a plus sign if non-negative
+ and always_add_sign is true. */
+ if (sign == 1)
+ *p++ = '-';
+ else if (always_add_sign)
+ *p++ = '+';
+
+ /* 2: Zero padding on left of digit string */
if (dec_pos <= 0) {
- *buf++ = '0';
- *buf++ = '.';
- memset(buf, '0', -dec_pos);
- buf -= dec_pos;
+ *p++ = '0';
+ *p++ = '.';
+ memset(p, '0', -dec_pos);
+ p -= dec_pos;
}
- /* digits, with included decimal point */
+ /* 3: Digits, with included decimal point */
if (0 < dec_pos && dec_pos <= n_digits) {
- strncpy(buf, digits, dec_pos);
- buf += dec_pos;
- *buf++ = '.';
- strncpy(buf, digits+dec_pos, n_digits-dec_pos);
- buf += n_digits-dec_pos;
+ strncpy(p, digits, dec_pos);
+ p += dec_pos;
+ *p++ = '.';
+ strncpy(p, digits+dec_pos, n_digits-dec_pos);
+ p += n_digits-dec_pos;
}
else {
- strncpy(buf, digits, n_digits);
- buf += n_digits;
+ strncpy(p, digits, n_digits);
+ p += n_digits;
}
- min_digits -= n_digits;
- /* and zeros on the right up to the decimal point */
+ /* 4: And zeros on the right up to the decimal point */
if (n_digits < dec_pos) {
- memset(buf, '0', dec_pos-n_digits);
- buf += dec_pos-n_digits;
- *buf++ = '.';
+ memset(p, '0', dec_pos-n_digits);
+ p += dec_pos-n_digits;
+ *p++ = '.';
min_digits -= dec_pos-n_digits;
}
- /* and more trailing zeros when necessary */
+ /* 5: And more trailing zeros when necessary */
if (min_digits > 0) {
- memset(buf, '0', min_digits);
- buf += min_digits;
+ memset(p, '0', min_digits);
+ p += min_digits;
}
- /* delete a trailing decimal pt unless using alternative formatting. */
- if (buf[-1] == '.' && !use_alt_formatting)
- buf--;
+ /* Delete a trailing decimal pt unless using alternative formatting. */
+ if (p[-1] == '.' && !use_alt_formatting)
+ p--;
- /* Now that we've done zero padding, add an exponent if needed. */
+ /* 6: Now that we've done zero padding, add an exponent if needed. */
if (use_exp) {
- *buf++ = float_strings[OFS_E][0];
- exp_len = sprintf(buf, "%+.02d", decpt-1);
- buf += exp_len;
+ *p++ = float_strings[OFS_E][0];
+ exp_len = sprintf(p, "%+.02d", decpt-1);
+ p += exp_len;
}
exit:
- *buf = '\0';
+ if (buf) {
+ *p = '\0';
+ /* It's too late if this fails, we've already stepped on
+ memory that isn't ours. But it's an okay debugging test. */
+ assert(p-buf < bufsize);
+ }
_Py_dg_freedtoa(digits);
- return p;
+ return buf;
}
More information about the Python-checkins
mailing list