19#include <userver/utils/meta_light.hpp>
21USERVER_NAMESPACE_BEGIN
27[[noreturn]]
void ThrowFromStringException(std::string_view message,
28 std::string_view input,
29 std::type_index resultType);
32std::enable_if_t<std::is_floating_point_v<T>, T> FromString(
const char* str) {
33 static_assert(!std::is_const_v<T> && !std::is_volatile_v<T>);
34 static_assert(!std::is_reference_v<T>);
37 impl::ThrowFromStringException(
"nullptr string",
"<null>",
typeid(T));
40 impl::ThrowFromStringException(
"empty string", str,
typeid(T));
42 if (std::isspace(str[0])) {
43 impl::ThrowFromStringException(
"leading spaces are not allowed", str,
50 const auto result = [&] {
51 if constexpr (std::is_same_v<T,
float>) {
52 return std::strtof(str, &end);
53 }
else if constexpr (std::is_same_v<T,
double>) {
54 return std::strtod(str, &end);
55 }
else if constexpr (std::is_same_v<T,
long double>) {
56 return std::strtold(str, &end);
60 if (errno == ERANGE && !(result < 1 && result > 0.0)) {
61 impl::ThrowFromStringException(
"overflow", str,
typeid(T));
65 impl::ThrowFromStringException(
"no number found", str,
typeid(T));
69 if (std::isspace(*end)) {
70 impl::ThrowFromStringException(
"trailing spaces are not allowed", str,
73 impl::ThrowFromStringException(
74 "extra junk at the end of the string is not allowed", str,
typeid(T));
82std::enable_if_t<std::is_floating_point_v<T>, T> FromString(
83 const std::string& str) {
84 return FromString<T>(str.data());
88std::enable_if_t<std::is_floating_point_v<T>, T> FromString(
89 std::string_view str) {
90 static constexpr std::size_t kSmallBufferSize = 32;
92 if (str.size() >= kSmallBufferSize) {
93 return FromString<T>(std::string{str});
96 char buffer[kSmallBufferSize];
97 std::copy(str.data(), str.data() + str.size(), buffer);
98 buffer[str.size()] =
'\0';
100 return FromString<T>(buffer);
104std::enable_if_t<meta::kIsInteger<T>, T> FromString(std::string_view str) {
105 static_assert(!std::is_const_v<T> && !std::is_volatile_v<T>);
106 static_assert(!std::is_reference_v<T>);
109 impl::ThrowFromStringException(
"empty string", str,
typeid(T));
111 if (std::isspace(str[0])) {
112 impl::ThrowFromStringException(
"leading spaces are not allowed", str,
116 std::size_t offset = 0;
119 if (str.size() > 1 && str[0] ==
'+' && str[1] ==
'-') {
120 impl::ThrowFromStringException(
"no number found", str,
typeid(T));
122 if (str[0] ==
'+') offset = 1;
125 if (std::is_unsigned_v<T> && str[0] ==
'-') offset = 1;
128 const auto [end, error_code] =
129 std::from_chars(str.data() + offset, str.data() + str.size(), result);
131 if (error_code == std::errc::result_out_of_range) {
132 impl::ThrowFromStringException(
"overflow", str,
typeid(T));
134 if (error_code == std::errc::invalid_argument) {
135 impl::ThrowFromStringException(
"no number found", str,
typeid(T));
138 if (std::is_unsigned_v<T> && str[0] ==
'-' && result != 0) {
139 impl::ThrowFromStringException(
"overflow", str,
typeid(T));
142 if (end != str.data() + str.size()) {
143 if (std::isspace(*end)) {
144 impl::ThrowFromStringException(
"trailing spaces are not allowed", str,
147 impl::ThrowFromStringException(
148 "extra junk at the end of the string is not allowed", str,
typeid(T));
171template <
typename T,
typename StringType,
175 return impl::FromString<T>(str);
178std::int64_t FromHexString(
const std::string& str);