| 60 | |
| 61 | template <typename ConvResultT, typename ResultT = ConvResultT> |
| 62 | inline cxx20::expected<ResultT, Error> |
| 63 | stringToFloating(ConvResultT (&Conv)(const char *, char **), |
| 64 | std::string Value) noexcept { |
| 65 | using namespace std::literals; |
| 66 | char *EndPtr; |
| 67 | const char *CStr = Value.c_str(); |
| 68 | auto SavedErrNo = std::exchange(errno, 0); |
| 69 | const auto Result = Conv(CStr, &EndPtr); |
| 70 | std::swap(SavedErrNo, errno); |
| 71 | if (Value.empty() || *EndPtr != '\0') { |
| 72 | return cxx20::unexpected<Error>( |
| 73 | std::in_place, ErrCode::InvalidArgument, |
| 74 | fmt::format("invalid floating-point value: {}", Value)); |
| 75 | } |
| 76 | if (SavedErrNo == ERANGE) { |
| 77 | return cxx20::unexpected<Error>( |
| 78 | std::in_place, ErrCode::OutOfRange, |
| 79 | fmt::format("floating-point value out of range: {}", Value)); |
| 80 | } |
| 81 | return Result; |
| 82 | } |
| 83 | |
| 84 | template <typename T> struct Parser; |
| 85 | |