| 56 | |
| 57 | template <typename ResultType> |
| 58 | FromCharsResult FastStringToInt( |
| 59 | const char* first, const char* last, ResultType& value, |
| 60 | bool isNegative) noexcept |
| 61 | { |
| 62 | using UnsignedResultType = std::make_unsigned_t<ResultType>; |
| 63 | |
| 64 | const auto availableBytes = last - first; |
| 65 | |
| 66 | if (availableBytes <= 0) |
| 67 | return { first, std::errc::invalid_argument }; |
| 68 | |
| 69 | UnsignedResultType result = digitToInt(*first); |
| 70 | |
| 71 | if (result > 10) |
| 72 | return { first, std::errc::invalid_argument }; |
| 73 | |
| 74 | constexpr auto maxSafeDigits = std::numeric_limits<ResultType>::digits10; |
| 75 | |
| 76 | const char* ptr = first; |
| 77 | const char* safeLast = |
| 78 | first + std::min<decltype(availableBytes)>(availableBytes, maxSafeDigits); |
| 79 | |
| 80 | unsigned d; |
| 81 | |
| 82 | // No integer overflow here |
| 83 | while (++ptr < safeLast && (d = digitToInt(*ptr)) <= 9) |
| 84 | { |
| 85 | result = result * 10 + d; |
| 86 | } |
| 87 | |
| 88 | // But here live dragons |
| 89 | while (ptr < last && (d = digitToInt(*ptr)) <= 9) |
| 90 | { |
| 91 | if (!safeMul10Add<UnsignedResultType>(result, result, d)) |
| 92 | return { ptr, std::errc::result_out_of_range }; |
| 93 | |
| 94 | // Even if there were no unsigned overflow, |
| 95 | // signed overflow is still possible |
| 96 | if constexpr (std::is_signed_v<ResultType>) |
| 97 | { |
| 98 | const UnsignedResultType max = |
| 99 | static_cast<UnsignedResultType>( |
| 100 | std::numeric_limits<ResultType>::max()) + |
| 101 | (isNegative ? 1 : 0); |
| 102 | |
| 103 | if (result > max) |
| 104 | return { ptr, std::errc::result_out_of_range }; |
| 105 | } |
| 106 | |
| 107 | |
| 108 | ++ptr; |
| 109 | } |
| 110 | |
| 111 | if constexpr (std::is_signed_v<ResultType>) |
| 112 | { |
| 113 | value = isNegative ? |
| 114 | // Unary minus on unsigned type makes MSVC unhappy |
| 115 | static_cast<ResultType>(0 - result) : |
no test coverage detected