16 #define STRING_CONV_HAVE_CHAR_CONV
19 #if defined __has_include
20 #if __has_include(<charconv>)
22 #ifdef __cpp_lib_to_chars
23 #define STRING_CONV_HAVE_CHAR_CONV
29namespace adtf::base::string_conversion
32enum class float_format
43#ifdef STRING_CONV_HAVE_CHAR_CONV
46inline std::string float_to_string(T value, float_format format)
48 std::chars_format target_format = std::chars_format::fixed;
51 case float_format::general: target_format = std::chars_format::general;
break;
52 case float_format::fixed: target_format = std::chars_format::fixed;
break;
53 case float_format::scientific: target_format = std::chars_format::scientific;
break;
54 case float_format::hex: target_format = std::chars_format::hex;
break;
57 std::array<char, std::numeric_limits<T>::max_exponent10 + 2> buffer{};
58 const auto conversion_result = std::to_chars(buffer.data(), buffer.data() + buffer.size(), value, target_format);
59 if (conversion_result.ec != std::errc())
61 throw std::runtime_error(
"cannot convert number to string: " +
62 std::make_error_code(conversion_result.ec).message());
66 return std::string(buffer.data(), conversion_result.ptr);
71inline T string_to_float(std::string_view value)
74 const auto conversion_result = std::from_chars(value.data(), value.data() + value.size(), result);
75 if (conversion_result.ec != std::errc())
77 throw std::runtime_error(
"cannot convert string '" + std::string(value) +
78 "' to number: " + std::make_error_code(conversion_result.ec).message());
86inline std::string float_to_string(T value, float_format format)
88 std::ostringstream oStream;
89 oStream.imbue(std::locale::classic());
93 case float_format::general:
break;
94 case float_format::fixed: oStream << std::fixed;
break;
95 case float_format::scientific: oStream << std::scientific;
break;
96 case float_format::hex: oStream << std::hexfloat;
break;
101 return oStream.str();
105inline T string_to_float(std::string_view value)
108 std::istringstream oStream{std::string(value)};
109 oStream.imbue(std::locale::classic());
113 throw std::invalid_argument(
"not a number");
120inline std::pair<int, size_t> get_base(std::string_view value)
122 const size_t nSignLength = (!value.empty() && (value.front() ==
'-' || value.front() ==
'+')) ? 1 : 0;
123 const std::string_view strDigits = value.substr(nSignLength);
125 if (strDigits.size() > 1 && strDigits[0] ==
'0')
127 if (strDigits[1] ==
'x' || strDigits[1] ==
'X')
130 return {16, nSignLength + 2};
132 if (strDigits[1] ==
'b' || strDigits[1] ==
'B')
135 return {2, nSignLength + 2};
137 if (strDigits[1] >=
'0' && strDigits[1] <=
'7')
140 return {8, nSignLength + 1};
144 return {10, nSignLength};
150inline std::string to_string(T value, float_format = float_format::fixed)
152 return std::to_string(value);
156inline std::string to_string(
float value, float_format format)
158 return detail::float_to_string(value, format);
162inline std::string to_string(
double value, float_format format)
164 return detail::float_to_string(value, format);
192 bool negative =
false;
195 const auto base_helper = detail::get_base(value);
196 base = base_helper.first;
203 if (base_helper.second > 0)
205 negative = !value.empty() && value.front() ==
'-';
206 value = value.substr(base_helper.second);
210#ifdef STRING_CONV_HAVE_CHAR_CONV
211 const auto fnConvert = [&](std::string_view value,
auto& result,
int base)
213 const auto conversion_result = std::from_chars(value.data(), value.data() + value.size(), result,
base);
214 if (conversion_result.ec != std::errc())
216 const auto strMessage =
"cannot convert string '" + std::string(value) +
217 "' to number: " + std::make_error_code(conversion_result.ec).message();
219 if (conversion_result.ec == std::errc::result_out_of_range)
221 throw std::out_of_range(strMessage);
224 throw std::runtime_error(strMessage);
228 const auto fnConvert = [&](std::string_view value,
auto& result,
int base)
230 using U = std::decay_t<
decltype(result)>;
233 if constexpr (std::is_signed_v<U>)
235 const auto helper = std::stoll(std::string(value), 0,
base);
236 if (helper > (std::numeric_limits<U>::max)() || helper < std::numeric_limits<U>::lowest())
238 throw std::out_of_range(
"out of range");
240 result =
static_cast<U
>(helper);
244 const auto helper = std::stoull(std::string(value), 0,
base);
245 if (helper > (std::numeric_limits<U>::max)())
247 throw std::out_of_range(
"out of range");
249 result =
static_cast<U
>(helper);
252 catch (
const std::out_of_range& oError)
254 const auto strMessage =
"cannot convert string '" + std::string(value) +
"' to number: " + oError.what();
255 throw std::out_of_range(strMessage);
262 if constexpr (std::is_signed_v<T>)
268 using unsigned_t = std::make_unsigned_t<T>;
269 unsigned_t magnitude = 0;
270 fnConvert(value, magnitude,
base);
272 const unsigned_t max_magnitude =
static_cast<unsigned_t
>((std::numeric_limits<T>::max)()) + 1;
273 if (magnitude > max_magnitude)
275 throw std::out_of_range(
"cannot convert string '" + std::string(value) +
"' to number: " +
276 std::make_error_code(std::errc::result_out_of_range).message());
279 result =
static_cast<T
>(0 - magnitude);
283 throw std::runtime_error(
"cannot convert string '" + std::string(value) +
284 "' to number: negative value is not representable as an unsigned type");
289 fnConvert(value, result,
base);
296inline float to_number(std::string_view value,
int )
298 return detail::string_to_float<float>(value);
302inline double to_number(std::string_view value,
int )
304 return detail::string_to_float<double>(value);
Namespace for the ADTF Base SDK.
Definition adtf_base_type_traits.h:13
T to_number(std::string_view value, int base=0)
Definition string_conversion.h:188