NexusForce 1.0.0
A Modern C++ Library with extended functionality, web components, and utility libraries
载入中...
搜索中...
未找到
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
98template <typename T, enable_if_t<is_base_of_v<ranges::view_base<T>, T>, int> = 0>
99NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_string(const T& value) {
100 string result;
101 if (value.begin() == value.end()) {
102 result = "[]";
103 } else {
104 result += "[ ";
105 for (auto iter = value.begin(); iter != value.end(); ++iter) {
106 if (iter != value.begin()) {
107 result += ", ";
108 }
109 result += to_string(*iter);
110 }
111 result += " ]";
112 }
113 return result;
114}
115
121template <typename T, enable_if_t<is_unbounded_array_v<T>, int> = 0>
122NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_string(const T&) {
123 return {"[]"};
124}
125
132template <typename T, enable_if_t<is_bounded_array_v<T> && !is_cstring_v<T>, int> = 0>
133NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_string(const T& arr) {
134 return inner::collector_to_string(arr);
135}
136
144template <typename IfEmpty, typename T>
145NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_string(const compressed_pair<IfEmpty, T, true>& obj) {
146 return to_string(obj.value);
147}
148
156template <typename IfEmpty, typename T>
157NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_string(const compressed_pair<IfEmpty, T, false>& obj) {
158 return "{ " + to_string(obj.value) + ", " + to_string(obj.no_compressed) + " }";
159}
160
168template <typename T1, typename T2>
169NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_string(const pair<T1, T2>& obj) {
170 return "{ " + to_string(obj.first) + ", " + to_string(obj.second) + " }";
171}
172
174NEFORCE_BEGIN_INNER__
175
176template <typename Tuple, size_t I, enable_if_t<I == tuple_size_v<Tuple> - 1, int> = 0>
177NEFORCE_CONSTEXPR20 void __to_string_tuple_elements(const Tuple& t, string& result) {
178 result += to_string(_NEFORCE get<I>(t));
179}
180
181template <typename Tuple, size_t I,
182 enable_if_t<I<tuple_size_v<Tuple> - 1, int> = 0> NEFORCE_CONSTEXPR20 void __to_string_tuple_elements(
183 const Tuple& t, string& result) {
184 result += to_string(_NEFORCE get<I>(t)) + ", ";
185 inner::__to_string_tuple_elements<Tuple, I + 1>(t, result);
186}
187
188template <typename... UArgs, enable_if_t<sizeof...(UArgs) == 0, int> = 0>
189NEFORCE_CONSTEXPR20 string __to_string_tuple_dispatch(const tuple<UArgs...>&) {
190 return {"()"};
191}
192
193template <typename... UArgs, enable_if_t<sizeof...(UArgs) != 0, int> = 0>
194NEFORCE_CONSTEXPR20 string __to_string_tuple_dispatch(const tuple<UArgs...>& t) {
195 string result;
196 result += "( ";
197 inner::__to_string_tuple_elements<decltype(t), 0>(t, result);
198 result += " )";
199 return result;
200}
201
202NEFORCE_END_INNER__
204
211template <typename... Args>
212NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_string(const tuple<Args...>& tup) {
213 return inner::__to_string_tuple_dispatch(tup);
214}
215
216
217#ifndef NEFORCE_STANDARD_17
219NEFORCE_BEGIN_INNER__
220template <typename T>
221string to_string_concat(T&& t) {
222 return to_string(_NEFORCE forward<T>(t));
223}
224template <typename First, typename... Rest>
225string to_string_concat(First&& first, Rest&&... rest) {
226 return to_string(_NEFORCE forward<First>(first)) + to_string_concat(_NEFORCE forward<Rest>(rest)...);
227}
228NEFORCE_END_INNER__
230#endif
231
238template <typename... Args, enable_if_t<(sizeof...(Args) > 1), int> = 0>
239NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_string(Args&&... args) {
240#ifdef NEFORCE_STANDARD_17
241 return (to_string(_NEFORCE forward<Args>(args)) + ...);
242#else
243 return inner::to_string_concat(_NEFORCE forward<Args>(args)...);
244#endif
245}
246
248NEFORCE_BEGIN_INNER__
249
250#ifdef NEFORCE_ARCH_BITS_32
251
252template <typename CharT, typename UT>
253constexpr enable_if_t<(sizeof(UT) > 4)> __uint_to_buff_aux(CharT* riter, UT& ux) noexcept {
254 while (ux > static_cast<UT>(0xFFFFFFFFU)) {
255 auto chunk = static_cast<uint32_t>(ux % static_cast<UT>(1000000000));
256 ux /= static_cast<UT>(1000000000);
257 for (int idx = 0; idx != 9; ++idx) {
258 *--riter = static_cast<CharT>('0' + chunk % 10);
259 chunk /= 10;
260 }
261 }
262}
263
264template <typename CharT, typename UT>
265constexpr enable_if_t<(sizeof(UT) <= 4)> __uint_to_buff_aux(CharT*, UT&) noexcept {}
266
267#endif
268
277template <typename CharT, typename UT>
278NEFORCE_NODISCARD constexpr CharT* __uint_to_buff(CharT* riter, UT ux) noexcept {
279 static_assert(is_unsigned_v<UT>, "UT must be a unsigned integer type");
280
281#ifdef NEFORCE_ARCH_BITS_64
282 UT holder = ux;
283#else
284 inner::__uint_to_buff_aux(riter, ux);
285 auto holder = static_cast<uint32_t>(ux);
286#endif
287 do {
288 *--riter = static_cast<CharT>('0' + holder % static_cast<UT>(10));
289 holder /= static_cast<UT>(10);
290 } while (static_cast<UT>(holder) != static_cast<UT>(0));
291 return riter;
292}
293
301template <typename CharT, typename T>
302NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 basic_string<CharT> __int_to_string(const T x) {
303 static_assert(is_integral_v<T>, "T must be a integral type");
304
305 CharT buffer[21];
306 CharT* const buffer_end = buffer + 21;
307 CharT* rnext = buffer_end;
308 using UT = make_unsigned_t<T>;
309 const auto unsigned_x = static_cast<UT>(x);
310 if (x < 0) {
311 rnext = inner::__uint_to_buff(rnext, static_cast<UT>(0 - unsigned_x));
312 *--rnext = '-';
313 } else {
314 rnext = inner::__uint_to_buff(rnext, unsigned_x);
315 }
316 const size_t count = buffer_end - rnext;
317 return basic_string<CharT>(rnext, count);
318}
319
327template <typename CharT, typename T>
328NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 basic_string<CharT> __uint_to_string(T x) {
329 static_assert(is_unsigned_v<T>, "T must be a integral type");
330
331 CharT buffer[numeric_traits<uintmax_t>::digits10 + 2]; // digits10 + sign + '\0'
332 constexpr size_t buffer_size = extent_v<decltype(buffer)>;
333 CharT* const buffer_end = buffer + buffer_size;
334 CharT* const rnext = inner::__uint_to_buff(buffer_end, x);
335 const size_t count = buffer_end - rnext;
336 return basic_string<CharT>(rnext, count);
337}
338
346NEFORCE_CONSTEXPR20 string __uint_to_string_base(uint64_t value, const int base, const bool uppercase) {
347 if (value == 0) {
348 return "0";
349 }
350
351 string result;
352 result.reserve(20);
353
354 constexpr auto digits_lower = "0123456789abcdef";
355 constexpr auto digits_upper = "0123456789ABCDEF";
356 const auto digits = uppercase ? digits_upper : digits_lower;
357
358 while (value > 0) {
359 const uint64_t remainder = value % base;
360 value /= base;
361 result.push_back(digits[remainder]);
362 }
363
364 result.reverse();
365 return result;
366}
367
368template <typename T, enable_if_t<disjunction_v<conjunction<is_standard_integral<T>, is_signed<T>>>, int> = 0>
369NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string __int_to_string_dispatch(const T x) {
370 return inner::__int_to_string<char>(x);
371}
372template <typename T, enable_if_t<disjunction_v<conjunction<is_standard_integral<T>, is_unsigned<T>>>, int> = 0>
373NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string __int_to_string_dispatch(const T x) {
374 return inner::__uint_to_string<char>(x);
375}
376
387template <typename CharT, typename T>
388NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 basic_string<CharT>
389__float_to_string_with_precision(T x, int precision = 6, const bool force_scientific = false,
390 const bool force_fixed = false) {
391 static_assert(is_floating_point_v<T>, "T must be a floating point type");
392
393 if (_NEFORCE is_nan(x)) {
394 return basic_string<CharT>{"nan"};
395 }
396
397 constexpr T inf = numeric_traits<T>::infinity();
398 if (x == inf) {
399 return basic_string<CharT>{"inf"};
400 }
401 if (x == -inf) {
402 return basic_string<CharT>{"-inf"};
403 }
404
405 basic_string<CharT> result;
406
407 const bool is_negative = (x < 0);
408 if (is_negative) {
409 result += '-';
410 x = -x;
411 }
412
413 if (precision < 0) {
414 precision = 0;
415 }
416
417 bool use_scientific = false;
418 int exponent = 0;
419
420 if (force_scientific) {
421 use_scientific = true;
422 } else if (force_fixed) {
423 use_scientific = false;
424 } else {
425 use_scientific = (x != 0) && (x >= 1e6 || x < 1e-4);
426 }
427
428 if (use_scientific && x != 0) {
429 const double log_val = logarithm_10(static_cast<double>(x));
430 exponent = static_cast<int>(log_val >= 0 ? log_val : log_val - 1.0);
431
432 if (exponent >= 0) {
433 for (int i = 0; i < exponent; ++i) {
434 x /= static_cast<T>(10);
435 }
436 } else {
437 for (int i = 0; i < -exponent; ++i) {
438 x *= static_cast<T>(10);
439 }
440 }
441
442 if (x >= static_cast<T>(10)) {
443 x /= static_cast<T>(10);
444 ++exponent;
445 } else if (x < static_cast<T>(1) && x > static_cast<T>(0)) {
446 x *= static_cast<T>(10);
447 --exponent;
448 }
449 }
450
451 auto integer_part = static_cast<uint64_t>(x);
452 T fractional_part = x - static_cast<T>(integer_part);
453
454 uint64_t frac_int = 0;
455 uint64_t frac_scale = 1;
456
457 if (precision > 0) {
458 const int safe_precision = (precision > 18) ? 18 : precision;
459 for (int i = 0; i < safe_precision; ++i) {
460 frac_scale *= 10;
461 }
462
463 frac_int = static_cast<uint64_t>(fractional_part * static_cast<T>(frac_scale) + static_cast<T>(0.5));
464
465 if (frac_int >= frac_scale) {
466 frac_int -= frac_scale;
467 ++integer_part;
468
469 if (use_scientific && integer_part >= 10) {
470 integer_part /= 10;
471 ++exponent;
472 }
473 }
474 }
475
476 result += inner::__uint_to_string<CharT>(integer_part);
477
478 if (precision > 0) {
479 result += static_cast<CharT>('.');
480 basic_string<CharT> frac_str = inner::__uint_to_string<CharT>(frac_int);
481
482 const int safe_precision = (precision > 18) ? 18 : precision;
483 const int leading_zeros = safe_precision - static_cast<int>(frac_str.size());
484 for (int i = 0; i < leading_zeros; ++i) {
485 result += static_cast<CharT>('0');
486 }
487 result += frac_str;
488
489 for (int i = safe_precision; i < precision; ++i) {
490 result += static_cast<CharT>('0');
491 }
492 }
493
494 if (use_scientific) {
495 result += static_cast<CharT>('e');
496 if (exponent >= 0) {
497 result += static_cast<CharT>('+');
498 } else {
499 result += static_cast<CharT>('-');
500 exponent = -exponent;
501 }
502 if (exponent < 10) {
503 result += static_cast<CharT>('0');
504 }
505 result += inner::__uint_to_string<CharT>(static_cast<uint64_t>(exponent));
506 }
507
508 return result;
509}
510
518template <typename CharT, typename T, enable_if_t<is_floating_point<T>::value, int> = 0>
519NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 basic_string<CharT> __float_to_string(T x) {
520 return inner::__float_to_string_with_precision<CharT>(x, 6, false, false);
521}
522
523NEFORCE_END_INNER__
525
534template <typename T, enable_if_t<is_floating_point<T>::value, int> = 0>
535NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_string_with_precision(T x, int precision, bool scientific = false) {
536 return inner::__float_to_string_with_precision<char>(x, precision, scientific, !scientific);
537}
538
546template <typename T, enable_if_t<is_floating_point<T>::value, int> = 0>
547NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_string_general(T x, int precision = 6) {
548 return inner::__float_to_string_with_precision<char>(x, precision, false, false);
549}
550
558template <typename T, enable_if_t<is_floating_point<T>::value, int> = 0>
559NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_string_fixed(T x, int precision = 6) {
560 return inner::__float_to_string_with_precision<char>(x, precision, false, true);
561}
562
570template <typename T, enable_if_t<is_floating_point<T>::value, int> = 0>
571NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_string_scientific(T x, int precision = 6) {
572 return inner::__float_to_string_with_precision<char>(x, precision, true, false);
573}
574 // StringConverts
576
577NEFORCE_END_NAMESPACE__
578#endif // NEFORCE_CORE_STRING_TO_STRING_HPP__
基础字符串模板
NEFORCE_CONSTEXPR20 void reserve(const size_type n)
预留容量
NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type size() const noexcept
获取字符数
NEFORCE_CONSTEXPR20 void push_back(value_type value)
在末尾插入字符
NEFORCE_CONSTEXPR20 void reverse() noexcept
反转字符串
数值类型极限特性主模板
static NEFORCE_NODISCARD constexpr T infinity() noexcept
获取正无穷大表示
NEFORCE_NODISCARD constexpr T && forward(remove_reference_t< T > &x) noexcept
完美转发左值
NEFORCE_INLINE17 constexpr size_t extent_v
extent的便捷变量模板
NEFORCE_ALWAYS_INLINE enable_if_t< is_void_v< T >, future_result_t< T > > get(future< T > &f)
通用future结果获取函数
NEFORCE_INLINE17 constexpr bool is_floating_point_v
is_floating_point的便捷变量模板
NEFORCE_INLINE17 constexpr bool is_integral_v
is_integral的便捷变量模板
typename package< T >::type package_t
package的便捷别名
NEFORCE_INLINE17 constexpr bool is_unsigned_v
is_unsigned的便捷变量模板
unsigned int uint32_t
32位无符号整数类型
unsigned long long uint64_t
64位无符号整数类型
decltype(nullptr) nullptr_t
空指针类型
constexpr iter_difference_t< Iterator > count(Iterator first, Iterator last, const T &value)
统计范围内等于指定值的元素数量
NEFORCE_PURE_FUNCTION NEFORCE_CONSTEXPR14 decimal_t logarithm_10(const decimal_t x)
计算以10为底的对数
NEFORCE_CONST_FUNCTION NEFORCE_CONSTEXPR14 decimal_t remainder(const decimal_t x, const decimal_t y) noexcept
计算余数
NEFORCE_CONST_FUNCTION constexpr bool is_nan(const T x) noexcept
检查浮点数是否为NaN
NEFORCE_CONST_FUNCTION constexpr bool is_negative(const T x) noexcept
检查浮点数是否为负数
typename make_unsigned< T >::type make_unsigned_t
make_unsigned的便捷别名
NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_string_with_precision(T x, int precision, bool scientific=false)
将浮点数转换为字符串(带精度控制)
NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_string_fixed(T x, int precision=6)
将浮点数转换为字符串(固定小数格式)
NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_string(const T &value)
将可包装类型转换为字符串
NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_string_scientific(T x, int precision=6)
将浮点数转换为字符串(科学计数法格式)
NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_string_general(T x, int precision=6)
将浮点数转换为字符串(通用格式)
NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string address_string(const void *p)
将指针转换为十六进制地址字符串
NEFORCE_NODISCARD NEFORCE_ALWAYS_INLINE constexpr decltype(auto) begin(Container &cont) noexcept(noexcept(cont.begin()))
获取容器的起始迭代器
NEFORCE_NODISCARD NEFORCE_ALWAYS_INLINE constexpr bool empty(const Container &cont) noexcept(noexcept(cont.empty()))
检查容器是否为空
NEFORCE_NODISCARD NEFORCE_ALWAYS_INLINE constexpr decltype(auto) cbegin(const Container &cont) noexcept(noexcept(cont.cbegin()))
获取const容器的const起始迭代器
NEFORCE_NODISCARD NEFORCE_ALWAYS_INLINE constexpr decltype(auto) cend(const Container &cont) noexcept(noexcept(cont.cend()))
获取const容器的const结束迭代器
typename enable_if< Test, T >::type enable_if_t
enable_if的便捷别名
集合器接口
可字符串化接口
数学函数库
数值类型特性检查
压缩对主模板,使用EBCO优化
存储两个值的元组对
T2 second
第二个元素
T1 first
第一个元素
类型擦除辅助函数
UTF字符包装类