NexusForce 1.0.0
A rigorously engineered full-stack C++ backend library.
载入中...
搜索中...
未找到
to_string.hpp
浏览该文件的文档.
1#ifndef NEFORCE_CORE_STRING_TO_STRING_HPP__
2#define NEFORCE_CORE_STRING_TO_STRING_HPP__
3
11
18NEFORCE_BEGIN_NAMESPACE__
19
25
34template <typename T, typename P = package_t<T>,
35 enable_if_t<is_packaged_v<T> && is_base_of_v<istringify<P>, P>, int> = 0>
36NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_string(const T& value) {
37 return to_string(package_t<T>(value));
38}
39
45NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_string(nullptr_t np) { return {"nullptr"}; }
46
55template <typename T, enable_if_t<is_pointer_v<T> && !is_cstring_v<T>, int> = 0>
56NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_string(const T& ptr) {
57 return _NEFORCE address_string(ptr);
58}
59
61NEFORCE_BEGIN_INNER__
62
63template <typename Collector>
64NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string collector_to_string(const Collector& c) {
65 if (_NEFORCE empty(c)) {
66 return {"[]"};
67 }
68
69 string result;
70 result += "[ ";
71
72 auto begin = _NEFORCE cbegin(c);
73 for (auto iter = begin; iter != _NEFORCE cend(c); ++iter) {
74 if (iter != begin) {
75 result += ", ";
76 }
77 result += to_string(*iter);
78 }
79
80 result += " ]";
81 return result;
82}
83
84NEFORCE_END_INNER__
86
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);
96}
97
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) {
101 string result;
102 if (value.begin() == value.end()) {
103 result = "[]";
104 } else {
105 result += "[ ";
106 for (auto iter = value.begin(); iter != value.end(); ++iter) {
107 if (iter != value.begin()) {
108 result += ", ";
109 }
110 result += to_string(*iter);
111 }
112 result += " ]";
113 }
114 return result;
115}
116#endif
117
123template <typename T, enable_if_t<is_unbounded_array_v<T>, int> = 0>
124NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_string(const T& /*unused*/) {
125 return {"[]"};
126}
127
134template <typename T, enable_if_t<is_bounded_array_v<T> && !is_cstring_v<T>, int> = 0>
135NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_string(const T& arr) {
136 return inner::collector_to_string(arr);
137}
138
146template <typename IfEmpty, typename T>
147NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_string(const compressed_pair<IfEmpty, T, true>& obj) {
148 return to_string(obj.value);
149}
150
158template <typename IfEmpty, typename T>
159NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_string(const compressed_pair<IfEmpty, T, false>& obj) {
160 return "{ " + to_string(obj.value) + ", " + to_string(obj.no_compressed) + " }";
161}
162
170template <typename T1, typename T2>
171NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_string(const pair<T1, T2>& obj) {
172 return "{ " + to_string(obj.first) + ", " + to_string(obj.second) + " }";
173}
174
176NEFORCE_BEGIN_INNER__
177
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));
181}
182
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);
188}
189
190template <typename... UArgs, enable_if_t<sizeof...(UArgs) == 0, int> = 0>
191NEFORCE_CONSTEXPR20 string __to_string_tuple_dispatch(const tuple<UArgs...>& /*unused*/) {
192 return {"()"};
193}
194
195template <typename... UArgs, enable_if_t<sizeof...(UArgs) != 0, int> = 0>
196NEFORCE_CONSTEXPR20 string __to_string_tuple_dispatch(const tuple<UArgs...>& t) {
197 string result;
198 result += "( ";
199 inner::__to_string_tuple_elements<decltype(t), 0>(t, result);
200 result += " )";
201 return result;
202}
203
204NEFORCE_END_INNER__
206
213template <typename... Args>
214NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_string(const tuple<Args...>& tup) {
215 return inner::__to_string_tuple_dispatch(tup);
216}
217
218
220NEFORCE_BEGIN_INNER__
221
222#ifdef NEFORCE_ARCH_BITS_32
223
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);
231 chunk /= 10;
232 }
233 }
234}
235
236template <typename CharT, typename UT>
237constexpr enable_if_t<(sizeof(UT) <= 4)> __uint_to_buff_aux(CharT*, UT&) noexcept {}
238
239#endif
240
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");
252
253#ifdef NEFORCE_ARCH_BITS_64
254 UT holder = ux;
255 do {
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));
259#else
260 inner::__uint_to_buff_aux(riter, ux);
261 auto holder = static_cast<uint32_t>(ux);
262 do {
263 *--riter = static_cast<CharT>('0' + holder % 10);
264 holder /= 10;
265 } while (holder != 0);
266#endif
267 return riter;
268}
269
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");
280
281 CharT buffer[40]; // digits10 + sign + '\0'
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);
286 if (x < 0) {
287 rnext = inner::__uint_to_buff(rnext, static_cast<UT>(static_cast<UT>(0) - unsigned_x));
288 *--rnext = '-';
289 } else {
290 rnext = inner::__uint_to_buff(rnext, unsigned_x);
291 }
292 const size_t count = buffer_end - rnext;
293 return basic_string<CharT>(rnext, count);
294}
295
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");
306
307 CharT buffer[40]; // digits10 + sign + '\0'
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);
312}
313
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);
317}
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);
321}
322
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");
338
339 if (_NEFORCE is_nan(x)) {
340 return basic_string<CharT>{"nan"};
341 }
342
343 constexpr T inf = numeric_traits<T>::infinity();
344 if (x == inf) {
345 return basic_string<CharT>{"inf"};
346 }
347 if (x == -inf) {
348 return basic_string<CharT>{"-inf"};
349 }
350
351 basic_string<CharT> result;
352
353 const bool is_negative = (x < 0);
354 if (is_negative) {
355 result += '-';
356 x = -x;
357 }
358
359 precision = _NEFORCE max(precision, 0);
360
361 bool use_scientific = false;
362 int exponent = 0;
363
364 if (force_scientific) {
365 use_scientific = true;
366 } else if (force_fixed) {
367 use_scientific = false;
368 } else {
369 use_scientific = (x != 0) && (x >= 1e6 || x < 1e-4);
370 }
371
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);
375
376 if (exponent >= 0) {
377 for (int i = 0; i < exponent; ++i) {
378 x /= static_cast<T>(10);
379 }
380 } else {
381 for (int i = 0; i < -exponent; ++i) {
382 x *= static_cast<T>(10);
383 }
384 }
385
386 if (x >= static_cast<T>(10)) {
387 x /= static_cast<T>(10);
388 ++exponent;
389 } else if (x < static_cast<T>(1) && x > static_cast<T>(0)) {
390 x *= static_cast<T>(10);
391 --exponent;
392 }
393 }
394
395 auto integer_part = static_cast<uint64_t>(x);
396 T fractional_part = x - static_cast<T>(integer_part);
397
398 uint64_t frac_int = 0;
399 uint64_t frac_scale = 1;
400
401 if (precision > 0) {
402 const int safe_precision = (precision > 18) ? 18 : precision;
403 for (int i = 0; i < safe_precision; ++i) {
404 frac_scale *= 10;
405 }
406
407 frac_int = static_cast<uint64_t>(fractional_part * static_cast<T>(frac_scale) + static_cast<T>(0.5));
408
409 if (frac_int >= frac_scale) {
410 frac_int -= frac_scale;
411 ++integer_part;
412
413 if (use_scientific && integer_part >= 10) {
414 integer_part /= 10;
415 ++exponent;
416 }
417 }
418 }
419
420 result += inner::__uint_to_string<CharT>(integer_part);
421
422 if (precision > 0) {
423 result += static_cast<CharT>('.');
424 basic_string<CharT> frac_str = inner::__uint_to_string<CharT>(frac_int);
425
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');
430 }
431 result += frac_str;
432
433 for (int i = safe_precision; i < precision; ++i) {
434 result += static_cast<CharT>('0');
435 }
436 }
437
438 if (use_scientific) {
439 result += static_cast<CharT>('e');
440 if (exponent >= 0) {
441 result += static_cast<CharT>('+');
442 } else {
443 result += static_cast<CharT>('-');
444 exponent = -exponent;
445 }
446 if (exponent < 10) {
447 result += static_cast<CharT>('0');
448 }
449 result += inner::__uint_to_string<CharT>(static_cast<uint64_t>(exponent));
450 }
451
452 return result;
453}
454
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);
465}
466
467NEFORCE_END_INNER__
469
478template <typename T, enable_if_t<is_floating_point<T>::value, int> = 0>
479NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_string_with_precision(T x, int precision, bool scientific = false) {
480 return inner::__float_to_string_with_precision<char>(x, precision, scientific, !scientific);
481}
482
490template <typename T, enable_if_t<is_floating_point<T>::value, int> = 0>
491NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_string_general(T x, int precision = 6) {
492 return inner::__float_to_string_with_precision<char>(x, precision, false, false);
493}
494
502template <typename T, enable_if_t<is_floating_point<T>::value, int> = 0>
503NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_string_fixed(T x, int precision = 6) {
504 return inner::__float_to_string_with_precision<char>(x, precision, false, true);
505}
506
514template <typename T, enable_if_t<is_floating_point<T>::value, int> = 0>
515NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_string_scientific(T x, int precision = 6) {
516 return inner::__float_to_string_with_precision<char>(x, precision, true, false);
517}
518 // StringConverts
520
521NEFORCE_END_NAMESPACE__
522#endif // NEFORCE_CORE_STRING_TO_STRING_HPP__
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)
将字符转换为普通字符串
集合器接口
可字符串化接口
数学函数库
数值类型特性检查
压缩对主模板,使用EBCO优化
存储两个值的元组对
T2 second
第二个元素
T1 first
第一个元素
类型擦除辅助函数
UTF字符包装类