Bug 5811 – [patch] std.conv.parse isFloatingPoint!Target doesn't parse "inf"/"-inf" with input ranges

Status
RESOLVED
Resolution
DUPLICATE
Severity
normal
Priority
P2
Component
phobos
Product
D
Version
D2
Platform
Other
OS
Windows
Creation time
2011-04-03T17:58:00Z
Last change time
2011-08-09T19:07:34Z
Keywords
patch
Assigned to
nobody
Creator
sandford

Comments

Comment #0 by sandford — 2011-04-03T17:58:52Z
I ran into a problem with parse!real(r), when r was a strict input range, r contained "inf" or "-inf" and "inf" wasn't the only item parsed from the stream. The patch simply consists of moving inf detection from the sign detection switch to right after the nan detection section, which I copy/paste/modified to inf. [Patch] DMD 2.052 (line 1301 in Github at time of posting) Target parse(Target, Source)(ref Source p) if (isInputRange!Source && /*!isSomeString!Source && */isFloatingPoint!Target) { static immutable real negtab[14] = [ 1e-4096L,1e-2048L,1e-1024L,1e-512L,1e-256L,1e-128L,1e-64L,1e-32L, 1e-16L,1e-8L,1e-4L,1e-2L,1e-1L,1.0L ]; static immutable real postab[13] = [ 1e+4096L,1e+2048L,1e+1024L,1e+512L,1e+256L,1e+128L,1e+64L,1e+32L, 1e+16L,1e+8L,1e+4L,1e+2L,1e+1L ]; // static immutable string infinity = "infinity"; // static immutable string nans = "nans"; ConvException bailOut(string f = __FILE__, size_t n = __LINE__) (string msg = null) { if (!msg) msg = "Floating point conversion error"; return new ConvException(text(f, ":", n, ": ", msg, " for input \"", p, "\".")); } for (;;) { enforce(!p.empty, bailOut()); if (!isspace(p.front)) break; p.popFront(); } char sign = 0; /* indicating + */ switch (p.front) { case '-': sign++; p.popFront(); enforce(!p.empty, bailOut()); break; case '+': p.popFront(); enforce(!p.empty, bailOut()); break; default: {} } bool isHex = false; bool startsWithZero = p.front == '0'; if(startsWithZero) { p.popFront(); if(p.empty) { return (sign) ? -0 : 0; } isHex = p.front == 'x' || p.front == 'X'; } real ldval = 0.0; char dot = 0; /* if decimal point has been seen */ int exp = 0; long msdec = 0, lsdec = 0; ulong msscale = 1; if (isHex) { int guard = 0; int anydigits = 0; uint ndigits = 0; p.popFront(); while (!p.empty) { int i = p.front; while (isxdigit(i)) { anydigits = 1; i = isalpha(i) ? ((i & ~0x20) - ('A' - 10)) : i - '0'; if (ndigits < 16) { msdec = msdec * 16 + i; if (msdec) ndigits++; } else if (ndigits == 16) { while (msdec >= 0) { exp--; msdec <<= 1; i <<= 1; if (i & 0x10) msdec |= 1; } guard = i << 4; ndigits++; exp += 4; } else { guard |= i; exp += 4; } exp -= dot; p.popFront(); if (p.empty) break; i = p.front; } if (i == '.' && !dot) { p.popFront(); dot = 4; } else break; } // Round up if (guard && (sticky || odd)) if (guard & 0x80 && (guard & 0x7F || msdec & 1)) { msdec++; if (msdec == 0) // overflow { msdec = 0x8000000000000000L; exp++; } } enforce(anydigits, bailOut()); enforce(!p.empty && (p.front == 'p' || p.front == 'P'), bailOut("Floating point parsing: exponent is required")); char sexp; int e; sexp = 0; p.popFront(); if (!p.empty) { switch (p.front) { case '-': sexp++; case '+': p.popFront(); enforce(!p.empty, new ConvException("Error converting input" " to floating point")); default: {} } } ndigits = 0; e = 0; while (!p.empty && isdigit(p.front)) { if (e < 0x7FFFFFFF / 10 - 10) // prevent integer overflow { e = e * 10 + p.front - '0'; } p.popFront(); ndigits = 1; } exp += (sexp) ? -e : e; enforce(ndigits, new ConvException("Error converting input" " to floating point")); if (msdec) { int e2 = 0x3FFF + 63; // left justify mantissa while (msdec >= 0) { msdec <<= 1; e2--; } // Stuff mantissa directly into real *cast(long *)&ldval = msdec; (cast(ushort *)&ldval)[4] = cast(ushort) e2; // Exponent is power of 2, not power of 10 ldval = ldexpl(ldval,exp); } goto L6; } else // not hex { if (toupper(p.front) == 'N' && !startsWithZero) { // nan enforce((p.popFront(), !p.empty && toupper(p.front) == 'A') && (p.popFront(), !p.empty && toupper(p.front) == 'N'), new ConvException("error converting input to floating point")); // skip past the last 'n' p.popFront(); return typeof(return).nan; } if (toupper(p.front) == 'I' && !startsWithZero) { // inf enforce((p.popFront(), !p.empty && toupper(p.front) == 'N') && (p.popFront(), !p.empty && toupper(p.front) == 'F'), new ConvException("error converting input to floating point")); // skip past the last 'n' p.popFront(); return sign ? -Target.infinity : Target.infinity; } bool sawDigits = startsWithZero; while (!p.empty) { int i = p.front; while (isdigit(i)) { sawDigits = true; /* must have at least 1 digit */ if (msdec < (0x7FFFFFFFFFFFL-10)/10) msdec = msdec * 10 + (i - '0'); else if (msscale < (0xFFFFFFFF-10)/10) { lsdec = lsdec * 10 + (i - '0'); msscale *= 10; } else { exp++; } exp -= dot; p.popFront(); if (p.empty) break; i = p.front; } if (i == '.' && !dot) { p.popFront(); dot++; } else { break; } } enforce(sawDigits, new ConvException("no digits seen")); } if (!p.empty && (p.front == 'e' || p.front == 'E')) { char sexp; int e; sexp = 0; p.popFront(); enforce(!p.empty, new ConvException("Unexpected end of input")); switch (p.front) { case '-': sexp++; case '+': p.popFront(); default: {} } bool sawDigits = 0; e = 0; while (!p.empty && isdigit(p.front)) { if (e < 0x7FFFFFFF / 10 - 10) // prevent integer overflow { e = e * 10 + p.front - '0'; } p.popFront(); sawDigits = 1; } exp += (sexp) ? -e : e; enforce(sawDigits, new ConvException("No digits seen.")); } ldval = msdec; if (msscale != 1) /* if stuff was accumulated in lsdec */ ldval = ldval * msscale + lsdec; if (ldval) { uint u = 0; int pow = 4096; while (exp > 0) { while (exp >= pow) { ldval *= postab[u]; exp -= pow; } pow >>= 1; u++; } while (exp < 0) { while (exp <= -pow) { ldval *= negtab[u]; enforce(ldval != 0, new ConvException("Range error")); exp += pow; } pow >>= 1; u++; } } L6: // if overflow occurred enforce(ldval != core.stdc.math.HUGE_VAL, new ConvException("Range error")); L1: return (sign) ? -ldval : ldval; }
Comment #1 by k.hara.pg — 2011-08-09T19:07:34Z
This problem was already fixed. *** This issue has been marked as a duplicate of issue 3369 ***