18#include <userver/utils/expected.hpp>
19#include <userver/utils/zstring_view.hpp>
21USERVER_NAMESPACE_BEGIN
44 return "leading spaces are not allowed";
46 return "extra junk at the end of the string is not allowed";
48 return "no number found";
72concept IsFromCharsConvertible =
73 requires(T& v) { std::from_chars(std::declval<
const char*>(), std::declval<
const char*>(), v); } &&
74#if defined(_GLIBCXX_RELEASE
) && _GLIBCXX_RELEASE
< 13
76 !std::same_as<T,
long double>
82[[noreturn]]
void ThrowFromStringException(
84 std::string_view input,
85 const std::type_info& result_type
89requires(std::is_floating_point_v<T> && !IsFromCharsConvertible<T>)
91 static_assert(!std::is_const_v<T> && !std::is_volatile_v<T>);
92 static_assert(!std::is_reference_v<T>);
97 if (std::isspace(str.front())) {
100 if (str.size() > 2 && str[0] ==
'0' && (str[1] ==
'x' || str[1] ==
'X')) {
107 const auto result = [&] {
108 if constexpr (std::is_same_v<T,
float>) {
109 return std::strtof(str.c_str(), &end);
110 }
else if constexpr (std::is_same_v<T,
double>) {
111 return std::strtod(str.c_str(), &end);
112 }
else if constexpr (std::is_same_v<T,
long double>) {
113 return std::strtold(str.c_str(), &end);
117 if (errno == ERANGE && !(result < 1 && result > 0.0)) {
121 if (end == str.c_str()) {
125 if (end != str.data() + str.size()) {
133requires(std::is_floating_point_v<T> && !IsFromCharsConvertible<T>)
139requires(std::is_floating_point_v<T> && !IsFromCharsConvertible<T>)
145requires(std::is_floating_point_v<T> && !IsFromCharsConvertible<T>)
147 static constexpr std::size_t kSmallBufferSize = 32;
149 if (str.size() >= kSmallBufferSize) {
150 const std::string buffer{str};
154 char buffer[kSmallBufferSize];
155 std::ranges::copy(str, buffer);
156 buffer[str.size()] =
'\0';
161template <IsFromCharsConvertible T>
163 static_assert(!std::is_const_v<T> && !std::is_volatile_v<T>);
164 static_assert(!std::is_reference_v<T>);
169 if (std::isspace(str[0])) {
173 std::size_t offset = 0;
176 if (str.size() > 1 && str[0] ==
'+' && str[1] ==
'-') {
184 if (std::is_unsigned_v<T> && str[0] ==
'-') {
189 const auto [end, error_code] = std::from_chars(str.data() + offset, str.data() + str.size(), result);
191 if (error_code == std::errc::result_out_of_range) {
194 if (error_code == std::errc::invalid_argument) {
198 if (std::is_unsigned_v<T> && str[0] ==
'-' && result != 0) {
202 if (end != str.data() + str.size()) {
225template <
typename T,
typename StringType>
226requires std::is_convertible_v<StringType, std::string_view>
228 const auto result = impl::FromString<T>(str);
231 return result.value();
233 impl::ThrowFromStringException(result.error(), str,
typeid(T));
248template <
typename T,
typename StringType>
249requires std::is_convertible_v<StringType, std::string_view>
251 return impl::FromString<T>(str);
254std::int64_t FromHexString(std::string_view str);