1#ifndef NEFORCE_CORE_STRING_TO_STRING_HPP__
2#define NEFORCE_CORE_STRING_TO_STRING_HPP__
18NEFORCE_BEGIN_NAMESPACE__
34template <
typename T,
typename P = package_t<T>,
35 enable_if_t<is_packaged_v<T> && is_base_of_v<i
stringify<P>, P>,
int> = 0>
36NEFORCE_NODISCARD NEFORCE_CONSTEXPR20
string to_string(
const T& value) {
55template <
typename T, enable_if_t<is_po
inter_v<T> && !is_c
string_v<T>,
int> = 0>
56NEFORCE_NODISCARD NEFORCE_CONSTEXPR20
string to_string(
const T& ptr) {
63template <
typename Collector>
64NEFORCE_NODISCARD NEFORCE_CONSTEXPR20
string collector_to_string(
const Collector& c) {
65 if (_NEFORCE empty(c)) {
73 for (
auto iter = begin; iter != _NEFORCE
cend(c); ++iter) {
93template <
typename T, enable_if_t<is_base_of_v<icollector<T>, T>,
int> = 0>
94NEFORCE_NODISCARD NEFORCE_CONSTEXPR20
string to_string(
const T& c) {
95 return inner::collector_to_string(c);
98#ifdef NEFORCE_STANDARD_20
99template <
typename T, enable_if_t<is_base_of_v<ranges::view_base<T>, T>,
int> = 0>
100NEFORCE_NODISCARD NEFORCE_CONSTEXPR20
string to_string(
const T& value) {
102 if (value.begin() == value.end()) {
106 for (
auto iter = value.begin(); iter != value.end(); ++iter) {
107 if (iter != value.begin()) {
123template <
typename T, enable_if_t<is_unbounded_array_v<T>,
int> = 0>
124NEFORCE_NODISCARD NEFORCE_CONSTEXPR20
string to_string(
const T& ) {
134template <
typename T, enable_if_t<is_bounded_array_v<T> && !is_c
string_v<T>,
int> = 0>
135NEFORCE_NODISCARD NEFORCE_CONSTEXPR20
string to_string(
const T& arr) {
136 return inner::collector_to_string(arr);
146template <
typename IfEmpty,
typename T>
158template <
typename IfEmpty,
typename T>
170template <
typename T1,
typename T2>
178template <
typename Tuple,
size_t I, enable_if_t<I == tuple_size_v<Tuple> - 1,
int> = 0>
179NEFORCE_CONSTEXPR20
void __to_string_tuple_elements(
const Tuple& t,
string& result) {
180 result += to_string(_NEFORCE get<I>(t));
183template <
typename Tuple,
size_t I,
184 enable_if_t<I<tuple_size_v<Tuple> - 1,
int> = 0> NEFORCE_CONSTEXPR20
void __to_string_tuple_elements(
185 const Tuple& t,
string& result) {
186 result +=
to_string(_NEFORCE get<I>(t)) +
", ";
187 inner::__to_string_tuple_elements<Tuple, I + 1>(t, result);
190template <
typename... UArgs,
enable_if_t<
sizeof...(UArgs) == 0,
int> = 0>
191NEFORCE_CONSTEXPR20
string __to_string_tuple_dispatch(
const tuple<UArgs...>& ) {
195template <
typename... UArgs,
enable_if_t<
sizeof...(UArgs) != 0,
int> = 0>
196NEFORCE_CONSTEXPR20
string __to_string_tuple_dispatch(
const tuple<UArgs...>& t) {
199 inner::__to_string_tuple_elements<decltype(t), 0>(t, result);
213template <
typename... Args>
214NEFORCE_NODISCARD NEFORCE_CONSTEXPR20
string to_string(
const tuple<Args...>& tup) {
215 return inner::__to_string_tuple_dispatch(tup);
222#ifdef NEFORCE_ARCH_BITS_32
224template <
typename CharT,
typename UT>
225constexpr enable_if_t<(
sizeof(UT) > 4)> __uint_to_buff_aux(CharT*& riter, UT& ux) {
226 while (ux >
static_cast<UT
>(0xFFFFFFFFU)) {
227 auto chunk =
static_cast<uint32_t
>(ux %
static_cast<UT
>(1000000000));
228 ux /=
static_cast<UT
>(1000000000);
229 for (
int idx = 0; idx != 9; ++idx) {
230 *--riter =
static_cast<CharT
>(
'0' + chunk % 10);
236template <
typename CharT,
typename UT>
237constexpr enable_if_t<(
sizeof(UT) <= 4)> __uint_to_buff_aux(CharT*, UT&)
noexcept {}
249template <
typename CharT,
typename UT>
250NEFORCE_NODISCARD
constexpr CharT* __uint_to_buff(CharT* riter, UT ux) {
251 static_assert(is_unsigned_v<UT>,
"UT must be a unsigned integer type");
253#ifdef NEFORCE_ARCH_BITS_64
256 *--riter =
static_cast<CharT
>(
static_cast<UT
>(
'0') + holder %
static_cast<UT
>(10));
257 holder /=
static_cast<UT
>(10);
258 }
while (holder !=
static_cast<UT
>(0));
260 inner::__uint_to_buff_aux(riter, ux);
261 auto holder =
static_cast<uint32_t>(ux);
263 *--riter =
static_cast<CharT
>(
'0' + holder % 10);
265 }
while (holder != 0);
277template <
typename CharT,
typename T>
278NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 basic_string<CharT> __int_to_string(
const T x) {
279 static_assert(is_integral_v<T>,
"T must be a integral type");
282 CharT*
const buffer_end = buffer + 40;
283 CharT* rnext = buffer_end;
284 using UT = make_unsigned_t<T>;
285 const auto unsigned_x =
static_cast<UT
>(x);
287 rnext = inner::__uint_to_buff(rnext,
static_cast<UT
>(
static_cast<UT
>(0) - unsigned_x));
290 rnext = inner::__uint_to_buff(rnext, unsigned_x);
292 const size_t count = buffer_end - rnext;
293 return basic_string<CharT>(rnext, count);
303template <
typename CharT,
typename T>
304NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 basic_string<CharT> __uint_to_string(T x) {
305 static_assert(is_unsigned_v<T>,
"T must be a integral type");
308 CharT*
const buffer_end = buffer + 40;
309 CharT*
const rnext = inner::__uint_to_buff(buffer_end, x);
310 const size_t count = buffer_end - rnext;
311 return basic_string<CharT>(rnext, count);
314template <
typename T, enable_if_t<is_
signed_v<T>,
int> = 0>
315NEFORCE_NODISCARD NEFORCE_CONSTEXPR20
string __int_to_string_dispatch(T x) {
316 return inner::__int_to_string<char>(x);
318template <
typename T, enable_if_t<is_
unsigned_v<T>,
int> = 0>
319NEFORCE_NODISCARD NEFORCE_CONSTEXPR20
string __int_to_string_dispatch(T x) {
320 return inner::__uint_to_string<char>(x);
333template <
typename CharT,
typename T>
334NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 basic_string<CharT>
335__float_to_string_with_precision(T x,
int precision = 6,
const bool force_scientific =
false,
336 const bool force_fixed =
false) {
337 static_assert(is_floating_point_v<T>,
"T must be a floating point type");
340 return basic_string<CharT>{
"nan"};
343 constexpr T inf = numeric_traits<T>::infinity();
345 return basic_string<CharT>{
"inf"};
348 return basic_string<CharT>{
"-inf"};
351 basic_string<CharT> result;
359 precision = _NEFORCE
max(precision, 0);
361 bool use_scientific =
false;
364 if (force_scientific) {
365 use_scientific =
true;
366 }
else if (force_fixed) {
367 use_scientific =
false;
369 use_scientific = (x != 0) && (x >= 1e6 || x < 1e-4);
372 if (use_scientific && x != 0) {
373 const double log_val =
logarithm_10(
static_cast<double>(x));
374 exponent =
static_cast<int>(log_val >= 0 ? log_val : log_val - 1.0);
377 for (
int i = 0; i < exponent; ++i) {
378 x /=
static_cast<T
>(10);
381 for (
int i = 0; i < -exponent; ++i) {
382 x *=
static_cast<T
>(10);
386 if (x >=
static_cast<T
>(10)) {
387 x /=
static_cast<T
>(10);
389 }
else if (x <
static_cast<T
>(1) && x >
static_cast<T
>(0)) {
390 x *=
static_cast<T
>(10);
395 auto integer_part =
static_cast<uint64_t>(x);
396 T fractional_part = x -
static_cast<T
>(integer_part);
402 const int safe_precision = (precision > 18) ? 18 : precision;
403 for (
int i = 0; i < safe_precision; ++i) {
407 frac_int =
static_cast<uint64_t>(fractional_part *
static_cast<T
>(frac_scale) +
static_cast<T
>(0.5));
409 if (frac_int >= frac_scale) {
410 frac_int -= frac_scale;
413 if (use_scientific && integer_part >= 10) {
420 result += inner::__uint_to_string<CharT>(integer_part);
423 result +=
static_cast<CharT
>(
'.');
424 basic_string<CharT> frac_str = inner::__uint_to_string<CharT>(frac_int);
426 const int safe_precision = (precision > 18) ? 18 : precision;
427 const int leading_zeros = safe_precision -
static_cast<int>(frac_str.size());
428 for (
int i = 0; i < leading_zeros; ++i) {
429 result +=
static_cast<CharT
>(
'0');
433 for (
int i = safe_precision; i < precision; ++i) {
434 result +=
static_cast<CharT
>(
'0');
438 if (use_scientific) {
439 result +=
static_cast<CharT
>(
'e');
441 result +=
static_cast<CharT
>(
'+');
443 result +=
static_cast<CharT
>(
'-');
444 exponent = -exponent;
447 result +=
static_cast<CharT
>(
'0');
449 result += inner::__uint_to_string<CharT>(
static_cast<uint64_t>(exponent));
462template <typename CharT, typename T, enable_if_t<is_floating_point<T>::value,
int> = 0>
463NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 basic_string<CharT> __float_to_string(T x) {
464 return inner::__float_to_string_with_precision<CharT>(x, 6,
false,
false);
478template <typename T, enable_if_t<is_floating_point<T>::value,
int> = 0>
480 return inner::__float_to_string_with_precision<char>(x, precision, scientific, !scientific);
490template <typename T, enable_if_t<is_floating_point<T>::value,
int> = 0>
492 return inner::__float_to_string_with_precision<char>(x, precision,
false,
false);
502template <typename T, enable_if_t<is_floating_point<T>::value,
int> = 0>
504 return inner::__float_to_string_with_precision<char>(x, precision,
false,
true);
514template <typename T, enable_if_t<is_floating_point<T>::value,
int> = 0>
516 return inner::__float_to_string_with_precision<char>(x, precision,
true,
false);
521NEFORCE_END_NAMESPACE__
typename package< T >::type package_t
package的便捷别名
constexpr const T & max(const T &a, const T &b, Compare comp) noexcept(noexcept(comp(a, b)))
返回两个值中的较大者
unsigned int uint32_t
32位无符号整数类型
unsigned long uint64_t
64位无符号整数类型
decltype(nullptr) nullptr_t
空指针类型
constexpr iter_difference_t< Iterator > count(Iterator first, Iterator last, const T &value)
统计范围内等于指定值的元素数量
constexpr decimal_t logarithm_10(const decimal_t x)
计算以10为底的对数
constexpr bool is_nan(const T x) noexcept
检查浮点数是否为NaN
constexpr bool is_negative(const T x) noexcept
检查浮点数是否为负数
constexpr string to_string_with_precision(T x, int precision, bool scientific=false)
将浮点数转换为字符串(带精度控制)
constexpr string to_string_general(T x, int precision=6)
将浮点数转换为字符串(通用格式)
constexpr string to_string_fixed(T x, int precision=6)
将浮点数转换为字符串(固定小数格式)
constexpr string to_string_scientific(T x, int precision=6)
将浮点数转换为字符串(科学计数法格式)
constexpr string address_string(const void *p)
将指针转换为十六进制地址字符串
constexpr decltype(auto) cbegin(const Container &cont) noexcept(noexcept(cont.cbegin()))
获取const容器的const起始迭代器
constexpr decltype(auto) cend(const Container &cont) noexcept(noexcept(cont.cend()))
获取const容器的const结束迭代器
constexpr decltype(auto) begin(Container &cont) noexcept(noexcept(cont.begin()))
获取容器的起始迭代器
typename enable_if< Test, T >::type enable_if_t
enable_if的便捷别名
constexpr string to_string(const CharT &c)
将字符转换为普通字符串