19#include <userver/utils/meta_light.hpp>
20#include <userver/utils/zstring_view.hpp>
22USERVER_NAMESPACE_BEGIN
29ThrowFromStringException(std::string_view message, std::string_view input, 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,
typeid(T));
49 const auto result = [&] {
50 if constexpr (std::is_same_v<T,
float>) {
51 return std::strtof(str, &end);
52 }
else if constexpr (std::is_same_v<T,
double>) {
53 return std::strtod(str, &end);
54 }
else if constexpr (std::is_same_v<T,
long double>) {
55 return std::strtold(str, &end);
59 if (errno == ERANGE && !(result < 1 && result > 0.0)) {
60 impl::ThrowFromStringException(
"overflow", str,
typeid(T));
64 impl::ThrowFromStringException(
"no number found", str,
typeid(T));
68 if (std::isspace(*end)) {
69 impl::ThrowFromStringException(
"trailing spaces are not allowed", str,
typeid(T));
71 impl::ThrowFromStringException(
"extra junk at the end of the string is not allowed", str,
typeid(T));
79std::enable_if_t<std::is_floating_point_v<T>, T> FromString(
const std::string& str) {
80 return impl::FromString<T>(str.c_str());
84std::enable_if_t<std::is_floating_point_v<T>, T> FromString(utils::zstring_view str) {
85 return impl::FromString<T>(str.c_str());
89std::enable_if_t<std::is_floating_point_v<T>, T> FromString(std::string_view str) {
90 static constexpr std::size_t kSmallBufferSize = 32;
92 if (str.size() >= kSmallBufferSize) {
93 return impl::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 impl::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,
typeid(T));
115 std::size_t offset = 0;
118 if (str.size() > 1 && str[0] ==
'+' && str[1] ==
'-') {
119 impl::ThrowFromStringException(
"no number found", str,
typeid(T));
121 if (str[0] ==
'+') offset = 1;
124 if (std::is_unsigned_v<T> && str[0] ==
'-') offset = 1;
127 const auto [end, error_code] = std::from_chars(str.data() + offset, str.data() + str.size(), result);
129 if (error_code == std::errc::result_out_of_range) {
130 impl::ThrowFromStringException(
"overflow", str,
typeid(T));
132 if (error_code == std::errc::invalid_argument) {
133 impl::ThrowFromStringException(
"no number found", str,
typeid(T));
136 if (std::is_unsigned_v<T> && str[0] ==
'-' && result != 0) {
137 impl::ThrowFromStringException(
"overflow", str,
typeid(T));
140 if (end != str.data() + str.size()) {
141 if (std::isspace(*end)) {
142 impl::ThrowFromStringException(
"trailing spaces are not allowed", str,
typeid(T));
144 impl::ThrowFromStringException(
"extra junk at the end of the string is not allowed", str,
typeid(T));
170 typename = std::enable_if_t<std::is_convertible_v<StringType, std::string_view>>>
172 return impl::FromString<T>(str);
175std::int64_t FromHexString(std::string_view str);