14#include <system_error>
17namespace dimval::detail {
21 std::string_view number;
22 std::string_view tail;
26[[nodiscard]]
inline std::expected<SplitResult, ParseError>
27split_number_and_tail(std::string_view s) {
31 return std::unexpected{
32 ParseError{ParseErrorCode::Empty, std::string{orig}, 0,
"empty input"}};
36 if (i < s.size() && (s[i] ==
'+' || s[i] ==
'-')) {
39 bool seen_digit =
false;
40 while (i < s.size() && s[i] >=
'0' && s[i] <=
'9') {
44 if (i < s.size() && s[i] ==
'.') {
46 while (i < s.size() && s[i] >=
'0' && s[i] <=
'9') {
51 if (i < s.size() && (s[i] ==
'e' || s[i] ==
'E')) {
53 if (i < s.size() && (s[i] ==
'+' || s[i] ==
'-')) {
56 while (i < s.size() && s[i] >=
'0' && s[i] <=
'9') {
61 return std::unexpected{
62 ParseError{ParseErrorCode::InvalidNumber, std::string{orig}, 0,
"no digits in input"}};
65 out.number = s.substr(0, i);
66 out.tail = trim(s.substr(i));
72[[nodiscard]]
inline std::expected<T, ParseError> parse_number(
const std::string_view num,
73 const std::string_view orig_input) {
74 if constexpr (std::is_integral_v<T>) {
76 const auto*
const first = num.data();
77 const auto*
const last = first + num.size();
78 if (
auto res = std::from_chars(first, last, out);
79 res.ec != std::errc{} || res.ptr != last) {
80 return std::unexpected{ParseError{ParseErrorCode::InvalidNumber,
81 std::string{orig_input},
83 "failed to parse number"}};
90 const std::string buf{num};
93 const double d = std::strtod(buf.c_str(), &endp);
94 if (endp != buf.c_str() + buf.size() || errno != 0) {
95 return std::unexpected{ParseError{ParseErrorCode::InvalidNumber,
96 std::string{orig_input},
98 "failed to parse number"}};
100 return static_cast<T
>(d);
Common concepts, error types, and small utilities used across dimval.
Detailed error report from a parse_*_value call.
Definition core.hpp:30
Split "<number><whitespace><tail>" into (number string, tail).
Definition parse_detail.hpp:20
std::size_t number_end
index in original input where the number ended
Definition parse_detail.hpp:23