| 476 | |
| 477 | template<class T> |
| 478 | T get_integer_impl2(const std::string &str) { |
| 479 | try { |
| 480 | // Most integers are integers, fast path |
| 481 | return common::integer_cast<T>(str); |
| 482 | } catch (const std::exception &) { |
| 483 | } |
| 484 | // But if not, we try maximally adhere to standard. |
| 485 | // We parse example values below as integers without losing precision |
| 486 | // 20000000000000000000000000000000E-31 |
| 487 | // 0.000000000000000000000000000000003E33 |
| 488 | // 92233720368547758060E-1 |
| 489 | // 0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001811234E206 |
| 490 | try { |
| 491 | std::string ip; |
| 492 | std::string fp; |
| 493 | std::string ep; |
| 494 | size_t zpos = 0; // fast detect of ip == "0" || ip == "-0" |
| 495 | split_number_to_parts(str, zpos, ip, fp, ep); |
| 496 | if (!ep.empty()) { |
| 497 | int ex = common::integer_cast<int>(ep); |
| 498 | // If fp not empty or number is zero, cannot shift right |
| 499 | if (fp.empty() && (ip.size() != zpos + 1 || ip[zpos] != '0')) { |
| 500 | for (; ex < 0; ++ex) { |
| 501 | // Can only shift if right digit is zero |
| 502 | if (ip.empty() || ip.back() != '0') |
| 503 | throw std::runtime_error("Number must be whole"); |
| 504 | ip.pop_back(); |
| 505 | } |
| 506 | } |
| 507 | for (; ex > 0; --ex) { |
| 508 | if (!fp.empty()) { |
| 509 | // If ip is zero, replace right digit with fractional digit |
| 510 | if (ip.size() == zpos + 1 && ip[zpos] == '0') |
| 511 | ip.pop_back(); |
| 512 | ip.push_back(fp[0]); |
| 513 | fp.erase(fp.begin()); |
| 514 | } else { |
| 515 | // If ip is zero and fp empty, result is zero |
| 516 | if (ip.size() == zpos + 1 && ip[zpos] == '0') |
| 517 | break; |
| 518 | ip.push_back('0'); |
| 519 | } |
| 520 | if (ip.size() > 100) // Arbitrary limit to stop loop |
| 521 | throw std::runtime_error("Number too large"); |
| 522 | } |
| 523 | } |
| 524 | if (!fp.empty()) |
| 525 | throw std::runtime_error("Number must be whole"); |
| 526 | if (ip == "-0") |
| 527 | ip = "0"; |
| 528 | return common::integer_cast<T>(ip); |
| 529 | } catch (const std::exception &ex) { |
| 530 | throw std::out_of_range("Json number (" + str + ") can not be converted because " + common::what(ex)); |
| 531 | } |
| 532 | } |
| 533 | JsonValue::Integer JsonValue::get_integer() const { |
| 534 | if (type != NUMBER) |
| 535 | throw std::runtime_error("JsonValue type is not NUMBER"); |
nothing calls this directly
no test coverage detected