| 1086 | | Target parse(Target, Source)(ref Source s) |
|---|
| 1087 | | if (!isSomeString!Source && isSomeChar!(ElementType!Source) |
|---|
| 1088 | | && isIntegral!Target) |
|---|
| 1089 | | { |
|---|
| 1090 | | char[] accum; |
|---|
| 1091 | | foreach (c; s) |
|---|
| 1092 | | { |
|---|
| 1093 | | writeln(c); |
|---|
| 1094 | | if ("0123456789-+".indexOf(c) < 0) |
|---|
| 1095 | | { |
|---|
| 1096 | | static if (is(typeof(s.unget(c)))) s.unget(c); |
|---|
| 1097 | | break; |
|---|
| 1098 | | } |
|---|
| 1099 | | accum ~= c; |
|---|
| 1100 | | } |
|---|
| 1101 | | return parse!Target(accum); |
|---|
| 1102 | | } |
|---|
| 1103 | | |
|---|
| 1104 | | Target parse(Target, Source)(ref Source s) |
|---|
| 1105 | | if (!isSomeString!Source && isFloatingPoint!Target) |
|---|
| 1106 | | { |
|---|
| 1107 | | static assert(0); |
|---|
| 1108 | | } |
|---|
| 1109 | | |
|---|
| 1110 | | Target parse(Target, Source)(ref Source s) |
|---|
| 1111 | | if (isSomeString!Source && isFloatingPoint!Target) |
|---|
| 1112 | | { |
|---|
| 1113 | | // issue 1589 |
|---|
| 1114 | | //version (Windows) |
|---|
| 1115 | | { |
|---|
| 1116 | | if (icmp(s, "nan") == 0) |
|---|
| 1117 | | { |
|---|
| 1118 | | s = s[3 .. $]; |
|---|
| 1119 | | return Target.nan; |
|---|
| 1120 | | } |
|---|
| 1121 | | } |
|---|
| 1122 | | |
|---|
| 1123 | | auto t = s; |
|---|
| 1124 | | if (t.startsWith('+', '-')) t.popFront(); |
|---|
| 1125 | | munch(t, "0-9"); // integral part |
|---|
| 1126 | | if (t.startsWith('.')) |
|---|
| 1127 | | { |
|---|
| 1128 | | t.popFront(); // decimal point |
|---|
| 1129 | | munch(t, "0-9"); // fractionary part |
|---|
| 1130 | | } |
|---|
| 1131 | | if (t.startsWith('E', 'e')) |
|---|
| 1132 | | { |
|---|
| 1133 | | t.popFront(); |
|---|
| 1134 | | if (t.startsWith('+', '-')) t.popFront(); |
|---|
| 1135 | | munch(t, "0-9"); // exponent |
|---|
| 1136 | | } |
|---|
| 1137 | | auto len = s.length - t.length; |
|---|
| 1138 | | char sz[80] = void; |
|---|
| 1139 | | enforce(len < sz.length); |
|---|
| 1140 | | foreach (i; 0 .. len) sz[i] = s[i]; |
|---|
| 1141 | | sz[len] = 0; |
|---|
| 1142 | | |
|---|
| 1143 | | // //writefln("toFloat('%s')", s); |
|---|
| 1144 | | // auto sz = toStringz(to!(const char[])(s)); |
|---|
| 1145 | | // if (std.ctype.isspace(*sz)) |
|---|
| 1146 | | // goto Lerr; |
|---|
| 1147 | | |
|---|
| 1148 | | // // BUG: should set __locale_decpoint to "." for DMC |
|---|
| 1149 | | |
|---|
| 1150 | | setErrno(0); |
|---|
| 1151 | | char* endptr; |
|---|
| 1152 | | static if (is(Target == float)) |
|---|
| 1153 | | auto f = strtof(sz.ptr, &endptr); |
|---|
| 1154 | | else static if (is(Target == double)) |
|---|
| 1155 | | auto f = strtod(sz.ptr, &endptr); |
|---|
| 1156 | | else static if (is(Target == real)) |
|---|
| 1157 | | auto f = strtold(sz.ptr, &endptr); |
|---|
| 1158 | | else |
|---|
| 1159 | | static assert(false); |
|---|
| 1160 | | if (getErrno() == ERANGE) |
|---|
| 1161 | | { |
|---|
| 1162 | | goto Lerr; |
|---|
| 1163 | | } |
|---|
| 1164 | | assert(endptr); |
|---|
| 1165 | | if (endptr == sz.ptr) |
|---|
| 1166 | | { |
|---|
| 1167 | | // no progress |
|---|
| 1168 | | goto Lerr; |
|---|
| 1169 | | } |
|---|
| 1170 | | s = s[endptr - sz.ptr .. $]; |
|---|
| 1171 | | return f; |
|---|
| 1172 | | Lerr: |
|---|
| 1173 | | conv_error!(Source, Target)(s); |
|---|
| 1174 | | assert(0); |
|---|
| 1175 | | } |
|---|
| 1176 | | |
|---|
| 1177 | | // Target parse(Target, Source)(ref Source s) |
|---|
| 1178 | | // if (isSomeString!Source && isSomeString!Target) |
|---|
| 1179 | | // { |
|---|
| 1180 | | |
|---|
| 1181 | | // } |
|---|
| | 1092 | Target parse(Target, Source)(ref Source p) |
|---|
| | 1093 | if (isInputRange!Source && /*!isSomeString!Source && */isFloatingPoint!Target) |
|---|
| | 1094 | { |
|---|
| | 1095 | static immutable real negtab[] = |
|---|
| | 1096 | [ 1e-4096L,1e-2048L,1e-1024L,1e-512L,1e-256L,1e-128L,1e-64L,1e-32L, |
|---|
| | 1097 | 1e-16L,1e-8L,1e-4L,1e-2L,1e-1L,1.0L ]; |
|---|
| | 1098 | static immutable real postab[] = |
|---|
| | 1099 | [ 1e+4096L,1e+2048L,1e+1024L,1e+512L,1e+256L,1e+128L,1e+64L,1e+32L, |
|---|
| | 1100 | 1e+16L,1e+8L,1e+4L,1e+2L,1e+1L ]; |
|---|
| | 1101 | // static immutable string infinity = "infinity"; |
|---|
| | 1102 | // static immutable string nans = "nans"; |
|---|
| | 1103 | |
|---|
| | 1104 | while (enforce(!p.empty), isspace(p.front)) |
|---|
| | 1105 | { |
|---|
| | 1106 | p.popFront(); |
|---|
| | 1107 | } |
|---|
| | 1108 | char sign = 0; /* indicating + */ |
|---|
| | 1109 | switch (p.front) |
|---|
| | 1110 | { |
|---|
| | 1111 | case '-': sign++; goto case '+'; |
|---|
| | 1112 | case '+': p.popFront(); enforce(!p.empty); |
|---|
| | 1113 | default: {} |
|---|
| | 1114 | } |
|---|
| | 1115 | |
|---|
| | 1116 | const bool isHex = p.front == '0' |
|---|
| | 1117 | && (p.popFront(), p.front == 'x' || p.front == 'X'); |
|---|
| | 1118 | |
|---|
| | 1119 | real ldval = 0.0; |
|---|
| | 1120 | char dot = 0; /* if decimal point has been seen */ |
|---|
| | 1121 | int exp = 0; |
|---|
| | 1122 | long msdec = 0, lsdec = 0; |
|---|
| | 1123 | ulong msscale = 1; |
|---|
| | 1124 | |
|---|
| | 1125 | if (isHex) |
|---|
| | 1126 | { |
|---|
| | 1127 | int guard = 0; |
|---|
| | 1128 | int anydigits = 0; |
|---|
| | 1129 | uint ndigits = 0; |
|---|
| | 1130 | |
|---|
| | 1131 | p.popFront(); |
|---|
| | 1132 | while (!p.empty) |
|---|
| | 1133 | { |
|---|
| | 1134 | int i = p.front; |
|---|
| | 1135 | while (isxdigit(i)) |
|---|
| | 1136 | { |
|---|
| | 1137 | anydigits = 1; |
|---|
| | 1138 | i = isalpha(i) ? ((i & ~0x20) - ('A' - 10)) : i - '0'; |
|---|
| | 1139 | if (ndigits < 16) |
|---|
| | 1140 | { |
|---|
| | 1141 | msdec = msdec * 16 + i; |
|---|
| | 1142 | if (msdec) |
|---|
| | 1143 | ndigits++; |
|---|
| | 1144 | } |
|---|
| | 1145 | else if (ndigits == 16) |
|---|
| | 1146 | { |
|---|
| | 1147 | while (msdec >= 0) |
|---|
| | 1148 | { |
|---|
| | 1149 | exp--; |
|---|
| | 1150 | msdec <<= 1; |
|---|
| | 1151 | i <<= 1; |
|---|
| | 1152 | if (i & 0x10) |
|---|
| | 1153 | msdec |= 1; |
|---|
| | 1154 | } |
|---|
| | 1155 | guard = i << 4; |
|---|
| | 1156 | ndigits++; |
|---|
| | 1157 | exp += 4; |
|---|
| | 1158 | } |
|---|
| | 1159 | else |
|---|
| | 1160 | { |
|---|
| | 1161 | guard |= i; |
|---|
| | 1162 | exp += 4; |
|---|
| | 1163 | } |
|---|
| | 1164 | exp -= dot; |
|---|
| | 1165 | p.popFront(); |
|---|
| | 1166 | if (p.empty) break; |
|---|
| | 1167 | i = p.front; |
|---|
| | 1168 | } |
|---|
| | 1169 | if (i == '.' && !dot) |
|---|
| | 1170 | { p.popFront(); |
|---|
| | 1171 | dot = 4; |
|---|
| | 1172 | } |
|---|
| | 1173 | else |
|---|
| | 1174 | break; |
|---|
| | 1175 | } |
|---|
| | 1176 | |
|---|
| | 1177 | // Round up if (guard && (sticky || odd)) |
|---|
| | 1178 | if (guard & 0x80 && (guard & 0x7F || msdec & 1)) |
|---|
| | 1179 | { |
|---|
| | 1180 | msdec++; |
|---|
| | 1181 | if (msdec == 0) // overflow |
|---|
| | 1182 | { msdec = 0x8000000000000000L; |
|---|
| | 1183 | exp++; |
|---|
| | 1184 | } |
|---|
| | 1185 | } |
|---|
| | 1186 | |
|---|
| | 1187 | enforce(anydigits); // if error (no digits seen) |
|---|
| | 1188 | enforce(!p.empty && (p.front == 'p' || p.front == 'P'), |
|---|
| | 1189 | "Floating point parsing: exponent is required"); |
|---|
| | 1190 | char sexp; |
|---|
| | 1191 | int e; |
|---|
| | 1192 | |
|---|
| | 1193 | sexp = 0; |
|---|
| | 1194 | p.popFront(); |
|---|
| | 1195 | if (!p.empty) |
|---|
| | 1196 | { |
|---|
| | 1197 | switch (p.front) |
|---|
| | 1198 | { case '-': sexp++; |
|---|
| | 1199 | case '+': p.popFront(); enforce(!p.empty); |
|---|
| | 1200 | default: {} |
|---|
| | 1201 | } |
|---|
| | 1202 | } |
|---|
| | 1203 | ndigits = 0; |
|---|
| | 1204 | e = 0; |
|---|
| | 1205 | while (!p.empty && isdigit(p.front)) |
|---|
| | 1206 | { |
|---|
| | 1207 | if (e < 0x7FFFFFFF / 10 - 10) // prevent integer overflow |
|---|
| | 1208 | { |
|---|
| | 1209 | e = e * 10 + p.front - '0'; |
|---|
| | 1210 | } |
|---|
| | 1211 | p.popFront(); |
|---|
| | 1212 | ndigits = 1; |
|---|
| | 1213 | } |
|---|
| | 1214 | exp += (sexp) ? -e : e; |
|---|
| | 1215 | enforce(ndigits); // if no digits in exponent |
|---|
| | 1216 | |
|---|
| | 1217 | if (msdec) |
|---|
| | 1218 | { |
|---|
| | 1219 | int e2 = 0x3FFF + 63; |
|---|
| | 1220 | |
|---|
| | 1221 | // left justify mantissa |
|---|
| | 1222 | while (msdec >= 0) |
|---|
| | 1223 | { msdec <<= 1; |
|---|
| | 1224 | e2--; |
|---|
| | 1225 | } |
|---|
| | 1226 | |
|---|
| | 1227 | // Stuff mantissa directly into real |
|---|
| | 1228 | *cast(long *)&ldval = msdec; |
|---|
| | 1229 | (cast(ushort *)&ldval)[4] = cast(ushort) e2; |
|---|
| | 1230 | |
|---|
| | 1231 | // Exponent is power of 2, not power of 10 |
|---|
| | 1232 | ldval = ldexpl(ldval,exp); |
|---|
| | 1233 | } |
|---|
| | 1234 | goto L6; |
|---|
| | 1235 | } |
|---|
| | 1236 | else // not hex |
|---|
| | 1237 | { |
|---|
| | 1238 | if (toupper(p.front) == 'N') |
|---|
| | 1239 | { |
|---|
| | 1240 | // nan |
|---|
| | 1241 | enforce((p.popFront(), !p.empty && toupper(p.front) == 'A') |
|---|
| | 1242 | && (p.popFront(), !p.empty && toupper(p.front) == 'N')); |
|---|
| | 1243 | // skip past the last 'n' |
|---|
| | 1244 | p.popFront(); |
|---|
| | 1245 | return typeof(return).nan; |
|---|
| | 1246 | } |
|---|
| | 1247 | |
|---|
| | 1248 | bool sawDigits = false; |
|---|
| | 1249 | |
|---|
| | 1250 | while (!p.empty) |
|---|
| | 1251 | { |
|---|
| | 1252 | int i = p.front; |
|---|
| | 1253 | while (isdigit(i)) |
|---|
| | 1254 | { |
|---|
| | 1255 | sawDigits = true; /* must have at least 1 digit */ |
|---|
| | 1256 | if (msdec < (0x7FFFFFFFFFFFL-10)/10) |
|---|
| | 1257 | msdec = msdec * 10 + (i - '0'); |
|---|
| | 1258 | else if (msscale < (0xFFFFFFFF-10)/10) |
|---|
| | 1259 | { lsdec = lsdec * 10 + (i - '0'); |
|---|
| | 1260 | msscale *= 10; |
|---|
| | 1261 | } |
|---|
| | 1262 | else |
|---|
| | 1263 | { |
|---|
| | 1264 | exp++; |
|---|
| | 1265 | } |
|---|
| | 1266 | exp -= dot; |
|---|
| | 1267 | p.popFront(); |
|---|
| | 1268 | if (p.empty) break; |
|---|
| | 1269 | i = p.front; |
|---|
| | 1270 | } |
|---|
| | 1271 | if (i == '.' && !dot) |
|---|
| | 1272 | { |
|---|
| | 1273 | p.popFront(); |
|---|
| | 1274 | dot++; |
|---|
| | 1275 | } |
|---|
| | 1276 | else |
|---|
| | 1277 | { |
|---|
| | 1278 | break; |
|---|
| | 1279 | } |
|---|
| | 1280 | } |
|---|
| | 1281 | enforce(sawDigits); // if error (no digits seen) |
|---|
| | 1282 | } |
|---|
| | 1283 | if (!p.empty && (p.front == 'e' || p.front == 'E')) |
|---|
| | 1284 | { |
|---|
| | 1285 | char sexp; |
|---|
| | 1286 | int e; |
|---|
| | 1287 | |
|---|
| | 1288 | sexp = 0; |
|---|
| | 1289 | p.popFront(); |
|---|
| | 1290 | enforce(!p.empty); |
|---|
| | 1291 | switch (p.front) |
|---|
| | 1292 | { case '-': sexp++; |
|---|
| | 1293 | case '+': p.popFront(); |
|---|
| | 1294 | default: {} |
|---|
| | 1295 | } |
|---|
| | 1296 | bool sawDigits = 0; |
|---|
| | 1297 | e = 0; |
|---|
| | 1298 | while (!p.empty && isdigit(p.front)) |
|---|
| | 1299 | { |
|---|
| | 1300 | if (e < 0x7FFFFFFF / 10 - 10) // prevent integer overflow |
|---|
| | 1301 | { |
|---|
| | 1302 | e = e * 10 + p.front - '0'; |
|---|
| | 1303 | } |
|---|
| | 1304 | p.popFront(); |
|---|
| | 1305 | sawDigits = 1; |
|---|
| | 1306 | } |
|---|
| | 1307 | exp += (sexp) ? -e : e; |
|---|
| | 1308 | enforce(sawDigits); // if no digits in exponent |
|---|
| | 1309 | } |
|---|
| | 1310 | |
|---|
| | 1311 | ldval = msdec; |
|---|
| | 1312 | if (msscale != 1) /* if stuff was accumulated in lsdec */ |
|---|
| | 1313 | ldval = ldval * msscale + lsdec; |
|---|
| | 1314 | if (ldval) |
|---|
| | 1315 | { |
|---|
| | 1316 | uint u = 0; |
|---|
| | 1317 | int pow = 4096; |
|---|
| | 1318 | |
|---|
| | 1319 | while (exp > 0) |
|---|
| | 1320 | { |
|---|
| | 1321 | while (exp >= pow) |
|---|
| | 1322 | { |
|---|
| | 1323 | ldval *= postab[u]; |
|---|
| | 1324 | exp -= pow; |
|---|
| | 1325 | } |
|---|
| | 1326 | pow >>= 1; |
|---|
| | 1327 | u++; |
|---|
| | 1328 | } |
|---|
| | 1329 | while (exp < 0) |
|---|
| | 1330 | { |
|---|
| | 1331 | while (exp <= -pow) |
|---|
| | 1332 | { |
|---|
| | 1333 | ldval *= negtab[u]; |
|---|
| | 1334 | enforce(ldval != 0); // errno = ERANGE; |
|---|
| | 1335 | exp += pow; |
|---|
| | 1336 | } |
|---|
| | 1337 | pow >>= 1; |
|---|
| | 1338 | u++; |
|---|
| | 1339 | } |
|---|
| | 1340 | } |
|---|
| | 1341 | L6: // if overflow occurred |
|---|
| | 1342 | enforce(ldval != core.stdc.math.HUGE_VAL); // errno = ERANGE; |
|---|
| | 1343 | |
|---|
| | 1344 | L1: |
|---|
| | 1345 | return (sign) ? -ldval : ldval; |
|---|
| | 1346 | } |
|---|
| | 1347 | |
|---|
| | 1348 | unittest |
|---|
| | 1349 | { |
|---|
| | 1350 | struct longdouble |
|---|
| | 1351 | { |
|---|
| | 1352 | ushort value[5]; |
|---|
| | 1353 | } |
|---|
| | 1354 | |
|---|
| | 1355 | real ld; |
|---|
| | 1356 | longdouble x; |
|---|
| | 1357 | real ld1; |
|---|
| | 1358 | longdouble x1; |
|---|
| | 1359 | int i; |
|---|
| | 1360 | |
|---|
| | 1361 | string s = "0x1.FFFFFFFFFFFFFFFEp-16382"; |
|---|
| | 1362 | ld = parse!real(s); |
|---|
| | 1363 | assert(s.empty); |
|---|
| | 1364 | x = *cast(longdouble *)&ld; |
|---|
| | 1365 | ld1 = strtold("0x1.FFFFFFFFFFFFFFFEp-16382", null); |
|---|
| | 1366 | x1 = *cast(longdouble *)&ld1; |
|---|
| | 1367 | assert(x1 == x && ld1 == ld); |
|---|
| | 1368 | |
|---|
| | 1369 | // for (i = 4; i >= 0; i--) |
|---|
| | 1370 | // { |
|---|
| | 1371 | // printf("%04x ", x.value[i]); |
|---|
| | 1372 | // } |
|---|
| | 1373 | // printf("\n"); |
|---|
| | 1374 | assert(!errno); |
|---|
| | 1375 | |
|---|
| | 1376 | s = "1.0e5"; |
|---|
| | 1377 | ld = parse!real(s); |
|---|
| | 1378 | assert(s.empty); |
|---|
| | 1379 | x = *cast(longdouble *)&ld; |
|---|
| | 1380 | ld1 = strtold("1.0e5", null); |
|---|
| | 1381 | x1 = *cast(longdouble *)&ld1; |
|---|
| | 1382 | |
|---|
| | 1383 | // for (i = 4; i >= 0; i--) |
|---|
| | 1384 | // { |
|---|
| | 1385 | // printf("%04x ", x.value[i]); |
|---|
| | 1386 | // } |
|---|
| | 1387 | // printf("\n"); |
|---|
| | 1388 | } |
|---|