19#include <userver/utils/zstring_view.hpp>
21USERVER_NAMESPACE_BEGIN
27template <
typename T,
typename =
void>
28struct IsFromCharsConvertible : std::false_type {};
31struct IsFromCharsConvertible<
33 std::void_t<
decltype(std::from_chars(std::declval<
const char*>(), std::declval<
const char*>(), std::declval<T&>())
34 )>> : std::true_type {};
37inline constexpr bool kIsFromCharsConvertible = IsFromCharsConvertible<T>::value;
40ThrowFromStringException(std::string_view message, std::string_view input, std::type_index result_type);
43std::enable_if_t<std::is_floating_point_v<T> && !kIsFromCharsConvertible<T>, T> FromString(
utils::
zstring_view str) {
44 static_assert(!std::is_const_v<T> && !std::is_volatile_v<T>);
45 static_assert(!std::is_reference_v<T>);
48 impl::ThrowFromStringException(
"empty string", str,
typeid(T));
50 if (std::isspace(str.front())) {
51 impl::ThrowFromStringException(
"leading spaces are not allowed", str,
typeid(T));
53 if (str.size() > 2 && str[0] ==
'0' && (str[1] ==
'x' || str[1] ==
'X')) {
54 impl::ThrowFromStringException(
"extra junk at the end of the string is not allowed", str,
typeid(T));
60 const auto result = [&] {
61 if constexpr (std::is_same_v<T,
float>) {
62 return std::strtof(str.c_str(), &end);
63 }
else if constexpr (std::is_same_v<T,
double>) {
64 return std::strtod(str.c_str(), &end);
65 }
else if constexpr (std::is_same_v<T,
long double>) {
66 return std::strtold(str.c_str(), &end);
70 if (errno == ERANGE && !(result < 1 && result > 0.0)) {
71 impl::ThrowFromStringException(
"overflow", str,
typeid(T));
74 if (end == str.c_str()) {
75 impl::ThrowFromStringException(
"no number found", str,
typeid(T));
78 if (end != str.data() + str.size()) {
79 if (std::isspace(*end)) {
80 impl::ThrowFromStringException(
"trailing spaces are not allowed", str,
typeid(T));
82 impl::ThrowFromStringException(
"extra junk at the end of the string is not allowed", str,
typeid(T));
90std::enable_if_t<std::is_floating_point_v<T> && !kIsFromCharsConvertible<T>, T> FromString(
const std::string& str) {
95std::enable_if_t<std::is_floating_point_v<T> && !kIsFromCharsConvertible<T>, T> FromString(
const char* str) {
100std::enable_if_t<std::is_floating_point_v<T> && !kIsFromCharsConvertible<T>, T> FromString(std::string_view str) {
101 static constexpr std::size_t kSmallBufferSize = 32;
103 if (str.size() >= kSmallBufferSize) {
104 const std::string buffer{str};
108 char buffer[kSmallBufferSize];
109 std::copy(str.data(), str.data() + str.size(), buffer);
110 buffer[str.size()] =
'\0';
116std::enable_if_t<kIsFromCharsConvertible<T>, T> FromString(std::string_view str) {
117 static_assert(!std::is_const_v<T> && !std::is_volatile_v<T>);
118 static_assert(!std::is_reference_v<T>);
121 impl::ThrowFromStringException(
"empty string", str,
typeid(T));
123 if (std::isspace(str[0])) {
124 impl::ThrowFromStringException(
"leading spaces are not allowed", str,
typeid(T));
127 std::size_t offset = 0;
130 if (str.size() > 1 && str[0] ==
'+' && str[1] ==
'-') {
131 impl::ThrowFromStringException(
"no number found", str,
typeid(T));
133 if (str[0] ==
'+') offset = 1;
136 if (std::is_unsigned_v<T> && str[0] ==
'-') offset = 1;
139 const auto [end, error_code] = std::from_chars(str.data() + offset, str.data() + str.size(), result);
141 if (error_code == std::errc::result_out_of_range) {
142 impl::ThrowFromStringException(
"overflow", str,
typeid(T));
144 if (error_code == std::errc::invalid_argument) {
145 impl::ThrowFromStringException(
"no number found", str,
typeid(T));
148 if (std::is_unsigned_v<T> && str[0] ==
'-' && result != 0) {
149 impl::ThrowFromStringException(
"overflow", str,
typeid(T));
152 if (end != str.data() + str.size()) {
153 if (std::isspace(*end)) {
154 impl::ThrowFromStringException(
"trailing spaces are not allowed", str,
typeid(T));
156 impl::ThrowFromStringException(
"extra junk at the end of the string is not allowed", str,
typeid(T));
182 typename = std::enable_if_t<std::is_convertible_v<StringType, std::string_view>>>
184 return impl::FromString<T>(str);
187std::int64_t FromHexString(std::string_view str);