19#include <userver/utils/zstring_view.hpp>
21USERVER_NAMESPACE_BEGIN
27 using std::runtime_error::runtime_error;
32template <
typename T,
typename =
void>
33struct IsFromCharsConvertible : std::false_type {};
36struct IsFromCharsConvertible<
38 std::void_t<
decltype(std::from_chars(std::declval<
const char*>(), std::declval<
const char*>(), std::declval<T&>())
39 )>> : std::true_type {};
42#if defined(_GLIBCXX_RELEASE
) && _GLIBCXX_RELEASE
< 13
48inline constexpr bool kIsFromCharsConvertible = IsFromCharsConvertible<T>::value;
50[[
noreturn]]
void ThrowFromStringException(
51 std::string_view message,
52 std::string_view input,
53 std::type_index result_type
57std::enable_if_t<std::is_floating_point_v<T> && !kIsFromCharsConvertible<T>, T> FromString(utils::
zstring_view str) {
58 static_assert(!std::is_const_v<T> && !std::is_volatile_v<T>);
59 static_assert(!std::is_reference_v<T>);
62 impl::ThrowFromStringException(
"empty string", str,
typeid(T));
64 if (std::isspace(str.front())) {
65 impl::ThrowFromStringException(
"leading spaces are not allowed", str,
typeid(T));
67 if (str.size() > 2 && str[0] ==
'0' && (str[1] ==
'x' || str[1] ==
'X')) {
68 impl::ThrowFromStringException(
"extra junk at the end of the string is not allowed", str,
typeid(T));
74 const auto result = [&] {
75 if constexpr (std::is_same_v<T,
float>) {
76 return std::strtof(str.c_str(), &end);
77 }
else if constexpr (std::is_same_v<T,
double>) {
78 return std::strtod(str.c_str(), &end);
79 }
else if constexpr (std::is_same_v<T,
long double>) {
80 return std::strtold(str.c_str(), &end);
84 if (errno == ERANGE && !(result < 1 && result > 0.0)) {
85 impl::ThrowFromStringException(
"overflow", str,
typeid(T));
88 if (end == str.c_str()) {
89 impl::ThrowFromStringException(
"no number found", str,
typeid(T));
92 if (end != str.data() + str.size()) {
93 if (std::isspace(*end)) {
94 impl::ThrowFromStringException(
"trailing spaces are not allowed", str,
typeid(T));
96 impl::ThrowFromStringException(
"extra junk at the end of the string is not allowed", str,
typeid(T));
104std::enable_if_t<std::is_floating_point_v<T> && !kIsFromCharsConvertible<T>, T> FromString(
const std::string& str) {
109std::enable_if_t<std::is_floating_point_v<T> && !kIsFromCharsConvertible<T>, T> FromString(
const char* str) {
114std::enable_if_t<std::is_floating_point_v<T> && !kIsFromCharsConvertible<T>, T> FromString(std::string_view str) {
115 static constexpr std::size_t kSmallBufferSize = 32;
117 if (str.size() >= kSmallBufferSize) {
118 const std::string buffer{str};
122 char buffer[kSmallBufferSize];
123 std::copy(str.data(), str.data() + str.size(), buffer);
124 buffer[str.size()] =
'\0';
130std::enable_if_t<kIsFromCharsConvertible<T>, T> FromString(std::string_view str) {
131 static_assert(!std::is_const_v<T> && !std::is_volatile_v<T>);
132 static_assert(!std::is_reference_v<T>);
135 impl::ThrowFromStringException(
"empty string", str,
typeid(T));
137 if (std::isspace(str[0])) {
138 impl::ThrowFromStringException(
"leading spaces are not allowed", str,
typeid(T));
141 std::size_t offset = 0;
144 if (str.size() > 1 && str[0] ==
'+' && str[1] ==
'-') {
145 impl::ThrowFromStringException(
"no number found", str,
typeid(T));
152 if (std::is_unsigned_v<T> && str[0] ==
'-') {
157 const auto [end, error_code] = std::from_chars(str.data() + offset, str.data() + str.size(), result);
159 if (error_code == std::errc::result_out_of_range) {
160 impl::ThrowFromStringException(
"overflow", str,
typeid(T));
162 if (error_code == std::errc::invalid_argument) {
163 impl::ThrowFromStringException(
"no number found", str,
typeid(T));
166 if (std::is_unsigned_v<T> && str[0] ==
'-' && result != 0) {
167 impl::ThrowFromStringException(
"overflow", str,
typeid(T));
170 if (end != str.data() + str.size()) {
171 if (std::isspace(*end)) {
172 impl::ThrowFromStringException(
"trailing spaces are not allowed", str,
typeid(T));
174 impl::ThrowFromStringException(
"extra junk at the end of the string is not allowed", str,
typeid(T));
200 typename = std::enable_if_t<std::is_convertible_v<StringType, std::string_view>>>
202 return impl::FromString<T>(str);
205std::int64_t FromHexString(std::string_view str);