17#include <userver/utils/expected.hpp>
18#include <userver/utils/zstring_view.hpp>
20USERVER_NAMESPACE_BEGIN
43 return "leading spaces are not allowed";
45 return "extra junk at the end of the string is not allowed";
47 return "no number found";
70template <
typename T,
typename =
void>
71struct IsFromCharsConvertible : std::false_type {};
74struct IsFromCharsConvertible<
76 std::void_t<
decltype(std::from_chars(std::declval<
const char*>(), std::declval<
const char*>(), std::declval<T&>())
77 )>> : std::true_type {};
80#if defined(_GLIBCXX_RELEASE
) && _GLIBCXX_RELEASE
< 13
86inline constexpr bool kIsFromCharsConvertible = IsFromCharsConvertible<T>::value;
88[[
noreturn]]
void ThrowFromStringException(
90 std::string_view input,
91 const std::type_info& result_type
95std::enable_if_t<std::is_floating_point_v<T> && !kIsFromCharsConvertible<T>, expected<T,
FromStringErrorCode>>
97 static_assert(!std::is_const_v<T> && !std::is_volatile_v<T>);
98 static_assert(!std::is_reference_v<T>);
103 if (std::isspace(str.front())) {
106 if (str.size() > 2 && str[0] ==
'0' && (str[1] ==
'x' || str[1] ==
'X')) {
113 const auto result = [&] {
114 if constexpr (std::is_same_v<T,
float>) {
115 return std::strtof(str.c_str(), &end);
116 }
else if constexpr (std::is_same_v<T,
double>) {
117 return std::strtod(str.c_str(), &end);
118 }
else if constexpr (std::is_same_v<T,
long double>) {
119 return std::strtold(str.c_str(), &end);
123 if (errno == ERANGE && !(result < 1 && result > 0.0)) {
127 if (end == str.c_str()) {
131 if (end != str.data() + str.size()) {
139std::enable_if_t<std::is_floating_point_v<T> && !kIsFromCharsConvertible<T>, expected<T,
FromStringErrorCode>>
140FromString(
const std::string& str)
noexcept {
145std::enable_if_t<std::is_floating_point_v<T> && !kIsFromCharsConvertible<T>, expected<T,
FromStringErrorCode>>
146FromString(
const char* str)
noexcept {
151std::enable_if_t<std::is_floating_point_v<T> && !kIsFromCharsConvertible<T>, expected<T,
FromStringErrorCode>>
152FromString(std::string_view str)
noexcept {
153 static constexpr std::size_t kSmallBufferSize = 32;
155 if (str.size() >= kSmallBufferSize) {
156 const std::string buffer{str};
160 char buffer[kSmallBufferSize];
161 std::copy(str.data(), str.data() + str.size(), buffer);
162 buffer[str.size()] =
'\0';
168std::enable_if_t<kIsFromCharsConvertible<T>, expected<T,
FromStringErrorCode>> FromString(std::string_view str
170 static_assert(!std::is_const_v<T> && !std::is_volatile_v<T>);
171 static_assert(!std::is_reference_v<T>);
176 if (std::isspace(str[0])) {
180 std::size_t offset = 0;
183 if (str.size() > 1 && str[0] ==
'+' && str[1] ==
'-') {
191 if (std::is_unsigned_v<T> && str[0] ==
'-') {
196 const auto [end, error_code] = std::from_chars(str.data() + offset, str.data() + str.size(), result);
198 if (error_code == std::errc::result_out_of_range) {
201 if (error_code == std::errc::invalid_argument) {
205 if (std::is_unsigned_v<T> && str[0] ==
'-' && result != 0) {
209 if (end != str.data() + str.size()) {
235 typename = std::enable_if_t<std::is_convertible_v<StringType, std::string_view>>>
237 const auto result =
impl::FromString<T>(str);
240 return result.value();
242 impl::ThrowFromStringException(result.error(), str,
typeid(T));
260 typename = std::enable_if_t<std::is_convertible_v<StringType, std::string_view>>>
262 return impl::FromString<T>(str);
265std::int64_t FromHexString(std::string_view str);