17 #include <boost/version.hpp>
24 #include <string_view>
29 #if BOOST_VERSION >= 108500 && __has_include(<boost/charconv.hpp>)
30 #define USE_BOOST_CHARCONV
31 #elif defined(_GLIBCXX_RELEASE) && _GLIBCXX_RELEASE >= 11
32 #define USE_STD_CHARCONV
33 #elif defined(_MSC_VER) && _MSC_VER >= 1924
34 #define USE_STD_CHARCONV
35 #elif defined(_LIBCPP_VERSION) && _LIBCPP_VERSION >= 14000
36 #define USE_FALLBACK_CHARCONV
38 #error No charconv implementation found.
41 #ifdef USE_BOOST_CHARCONV
42 #include <boost/charconv.hpp>
43 namespace charconv_impl = boost::charconv;
45 namespace charconv_impl = std;
55 template<
typename... T>
67 #ifndef USE_FALLBACK_CHARCONV
88 while(!v.empty() && std::isspace(v.front())) {
91 if(v.size() >= 2 && v[0] ==
'+' && v[1] !=
'-' ) {
98 template<
typename TNum>
101 std::array<char, utils::charconv::buffer_size<TNum>>
buffer;
118 if(ec != std::errc()) {
120 assert(!
"Error in charconv_buffer, buffer not large enough");
142 inline double stod(std::string_view str) {
146 if(ec == std::errc::invalid_argument) {
147 throw std::invalid_argument(
"Failed to convert string to double: input contains invalid characters or is not a valid number.");
148 }
else if(ec == std::errc::result_out_of_range) {
149 throw std::out_of_range(
"Failed to convert string to double: input value is out of the representable range for a double.");
156 inline int stoi(std::string_view str) {
160 if(ec == std::errc::invalid_argument) {
161 throw std::invalid_argument(
"Failed to convert string to int: input contains invalid characters or is not a valid number.");
162 }
else if(ec == std::errc::result_out_of_range) {
163 throw std::out_of_range(
"Failed to convert string to int: input value is out of the representable range for an int.");
168 #ifdef __cpp_concepts
169 template<std::
integral T>
170 inline auto from_chars(std::string_view str,
int base = 10) -> utils::optional<T>
173 inline auto from_chars(std::string_view str,
int base = 10) -> std::enable_if_t<std::is_integral_v<T>, utils::optional<T>>
179 return ec == std::errc{} ? utils::make_optional(result) : utils::nullopt;
182 #ifdef __cpp_concepts
183 template<std::
floating_po
int T>
195 return ec == std::errc{} ? utils::make_optional(result) : utils::nullopt;
static std::string _(const char *str)
std::enable_if_t< std::is_integral_v< T >, std::from_chars_result > from_chars(const char *first, const char *last, T &value, int base=10)
charconv_impl::from_chars_result from_chars_result
charconv_impl::chars_format chars_format
to_chars_result to_chars(char *first, char *last, T &&... value)
charconv_impl::to_chars_result to_chars_result
constexpr std::size_t buffer_size
auto from_chars(std::string_view str, int base=10) -> std::enable_if_t< std::is_integral_v< T >, utils::optional< T >>
int stoi(std::string_view str)
Same interface as std::stoi and meant as a drop in replacement, except:
void trim_for_from_chars(std::string_view &v)
double stod(std::string_view str)
Same interface as std::stod and meant as a drop in replacement, except:
auto from_chars(std::string_view str, utils::charconv::chars_format fmt=utils::charconv::chars_format::general) -> std::enable_if_t< std::is_floating_point_v< T >, utils::optional< T >>
std::string_view get_view() const
std::string to_string() const
std::array< char, utils::charconv::buffer_size< TNum > > buffer
charconv_buffer(TNum num)