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
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
219#ifndef NEFORCE_STANDARD_17
221NEFORCE_BEGIN_INNER__
222template <typename T>
223string to_string_concat(T&& t) {
224 return to_string(_NEFORCE forward<T>(t));
225}
226template <typename First, typename... Rest>
227string to_string_concat(First&& first, Rest&&... rest) {
228 return to_string(_NEFORCE forward<First>(first)) + to_string_concat(_NEFORCE forward<Rest>(rest)...);
229}
230NEFORCE_END_INNER__
232#endif
233
240template <typename... Args, enable_if_t<(sizeof...(Args) > 1), int> = 0>
241NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_string(Args&&... args) {
242#ifdef NEFORCE_STANDARD_17
243 return (to_string(_NEFORCE forward<Args>(args)) + ...);
244#else
245 return inner::to_string_concat(_NEFORCE forward<Args>(args)...);
246#endif
247}
248
250NEFORCE_BEGIN_INNER__
251
252#ifdef NEFORCE_ARCH_BITS_32
253
254template <typename CharT, typename UT>
255constexpr enable_if_t<(sizeof(UT) > 4)> __uint_to_buff_aux(CharT*& riter, UT& ux) {
256 while (ux > static_cast<UT>(0xFFFFFFFFU)) {
257 auto chunk = static_cast<uint32_t>(ux % static_cast<UT>(1000000000));
258 ux /= static_cast<UT>(1000000000);
259 for (int idx = 0; idx != 9; ++idx) {
260 *--riter = static_cast<CharT>('0' + chunk % 10);
261 chunk /= 10;
262 }
263 }
264}
265
266template <typename CharT, typename UT>
267constexpr enable_if_t<(sizeof(UT) <= 4)> __uint_to_buff_aux(CharT*, UT&) noexcept {}
268
269#endif
270
279template <typename CharT, typename UT>
280NEFORCE_NODISCARD constexpr CharT* __uint_to_buff(CharT* riter, UT ux) {
281 static_assert(is_unsigned_v<UT>, "UT must be a unsigned integer type");
282
283#ifdef NEFORCE_ARCH_BITS_64
284 UT holder = ux;
285 do {
286 *--riter = static_cast<CharT>(static_cast<UT>('0') + holder % static_cast<UT>(10));
287 holder /= static_cast<UT>(10);
288 } while (holder != static_cast<UT>(0));
289#else
290 inner::__uint_to_buff_aux(riter, ux);
291 auto holder = static_cast<uint32_t>(ux);
292 do {
293 *--riter = static_cast<CharT>('0' + holder % 10);
294 holder /= 10;
295 } while (holder != 0);
296#endif
297 return riter;
298}
299
307template <typename CharT, typename T>
308NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 basic_string<CharT> __int_to_string(const T x) {
309 static_assert(is_integral_v<T>, "T must be a integral type");
310
311 CharT buffer[40]; // digits10 + sign + '\0'
312 CharT* const buffer_end = buffer + 40;
313 CharT* rnext = buffer_end;
314 using UT = make_unsigned_t<T>;
315 const auto unsigned_x = static_cast<UT>(x);
316 if (x < 0) {
317 rnext = inner::__uint_to_buff(rnext, static_cast<UT>(static_cast<UT>(0) - unsigned_x));
318 *--rnext = '-';
319 } else {
320 rnext = inner::__uint_to_buff(rnext, unsigned_x);
321 }
322 const size_t count = buffer_end - rnext;
323 return basic_string<CharT>(rnext, count);
324}
325
333template <typename CharT, typename T>
334NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 basic_string<CharT> __uint_to_string(T x) {
335 static_assert(is_unsigned_v<T>, "T must be a integral type");
336
337 CharT buffer[40]; // digits10 + sign + '\0'
338 CharT* const buffer_end = buffer + 40;
339 CharT* const rnext = inner::__uint_to_buff(buffer_end, x);
340 const size_t count = buffer_end - rnext;
341 return basic_string<CharT>(rnext, count);
342}
343
344template <typename T, enable_if_t<is_signed_v<T>, int> = 0>
345NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string __int_to_string_dispatch(T x) {
346 return inner::__int_to_string<char>(x);
347}
348template <typename T, enable_if_t<is_unsigned_v<T>, int> = 0>
349NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string __int_to_string_dispatch(T x) {
350 return inner::__uint_to_string<char>(x);
351}
352
363template <typename CharT, typename T>
364NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 basic_string<CharT>
365__float_to_string_with_precision(T x, int precision = 6, const bool force_scientific = false,
366 const bool force_fixed = false) {
367 static_assert(is_floating_point_v<T>, "T must be a floating point type");
368
369 if (_NEFORCE is_nan(x)) {
370 return basic_string<CharT>{"nan"};
371 }
372
373 constexpr T inf = numeric_traits<T>::infinity();
374 if (x == inf) {
375 return basic_string<CharT>{"inf"};
376 }
377 if (x == -inf) {
378 return basic_string<CharT>{"-inf"};
379 }
380
381 basic_string<CharT> result;
382
383 const bool is_negative = (x < 0);
384 if (is_negative) {
385 result += '-';
386 x = -x;
387 }
388
389 precision = _NEFORCE max(precision, 0);
390
391 bool use_scientific = false;
392 int exponent = 0;
393
394 if (force_scientific) {
395 use_scientific = true;
396 } else if (force_fixed) {
397 use_scientific = false;
398 } else {
399 use_scientific = (x != 0) && (x >= 1e6 || x < 1e-4);
400 }
401
402 if (use_scientific && x != 0) {
403 const double log_val = logarithm_10(static_cast<double>(x));
404 exponent = static_cast<int>(log_val >= 0 ? log_val : log_val - 1.0);
405
406 if (exponent >= 0) {
407 for (int i = 0; i < exponent; ++i) {
408 x /= static_cast<T>(10);
409 }
410 } else {
411 for (int i = 0; i < -exponent; ++i) {
412 x *= static_cast<T>(10);
413 }
414 }
415
416 if (x >= static_cast<T>(10)) {
417 x /= static_cast<T>(10);
418 ++exponent;
419 } else if (x < static_cast<T>(1) && x > static_cast<T>(0)) {
420 x *= static_cast<T>(10);
421 --exponent;
422 }
423 }
424
425 auto integer_part = static_cast<uint64_t>(x);
426 T fractional_part = x - static_cast<T>(integer_part);
427
428 uint64_t frac_int = 0;
429 uint64_t frac_scale = 1;
430
431 if (precision > 0) {
432 const int safe_precision = (precision > 18) ? 18 : precision;
433 for (int i = 0; i < safe_precision; ++i) {
434 frac_scale *= 10;
435 }
436
437 frac_int = static_cast<uint64_t>(fractional_part * static_cast<T>(frac_scale) + static_cast<T>(0.5));
438
439 if (frac_int >= frac_scale) {
440 frac_int -= frac_scale;
441 ++integer_part;
442
443 if (use_scientific && integer_part >= 10) {
444 integer_part /= 10;
445 ++exponent;
446 }
447 }
448 }
449
450 result += inner::__uint_to_string<CharT>(integer_part);
451
452 if (precision > 0) {
453 result += static_cast<CharT>('.');
454 basic_string<CharT> frac_str = inner::__uint_to_string<CharT>(frac_int);
455
456 const int safe_precision = (precision > 18) ? 18 : precision;
457 const int leading_zeros = safe_precision - static_cast<int>(frac_str.size());
458 for (int i = 0; i < leading_zeros; ++i) {
459 result += static_cast<CharT>('0');
460 }
461 result += frac_str;
462
463 for (int i = safe_precision; i < precision; ++i) {
464 result += static_cast<CharT>('0');
465 }
466 }
467
468 if (use_scientific) {
469 result += static_cast<CharT>('e');
470 if (exponent >= 0) {
471 result += static_cast<CharT>('+');
472 } else {
473 result += static_cast<CharT>('-');
474 exponent = -exponent;
475 }
476 if (exponent < 10) {
477 result += static_cast<CharT>('0');
478 }
479 result += inner::__uint_to_string<CharT>(static_cast<uint64_t>(exponent));
480 }
481
482 return result;
483}
484
492template <typename CharT, typename T, enable_if_t<is_floating_point<T>::value, int> = 0>
493NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 basic_string<CharT> __float_to_string(T x) {
494 return inner::__float_to_string_with_precision<CharT>(x, 6, false, false);
495}
496
497NEFORCE_END_INNER__
499
508template <typename T, enable_if_t<is_floating_point<T>::value, int> = 0>
509NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_string_with_precision(T x, int precision, bool scientific = false) {
510 return inner::__float_to_string_with_precision<char>(x, precision, scientific, !scientific);
511}
512
520template <typename T, enable_if_t<is_floating_point<T>::value, int> = 0>
521NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_string_general(T x, int precision = 6) {
522 return inner::__float_to_string_with_precision<char>(x, precision, false, false);
523}
524
532template <typename T, enable_if_t<is_floating_point<T>::value, int> = 0>
533NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_string_fixed(T x, int precision = 6) {
534 return inner::__float_to_string_with_precision<char>(x, precision, false, true);
535}
536
544template <typename T, enable_if_t<is_floating_point<T>::value, int> = 0>
545NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_string_scientific(T x, int precision = 6) {
546 return inner::__float_to_string_with_precision<char>(x, precision, true, false);
547}
548 // StringConverts
550
551NEFORCE_END_NAMESPACE__
552#endif // NEFORCE_CORE_STRING_TO_STRING_HPP__
基础字符串模板
constexpr size_type size() const noexcept
获取字符数
static constexpr T infinity() noexcept
获取正无穷大表示
constexpr T && forward(remove_reference_t< T > &x) noexcept
完美转发左值
enable_if_t< is_void_v< T >, future_result_t< T > > get(future< T > &f)
通用future结果获取函数
constexpr bool is_integral_v
is_integral的便捷变量模板
constexpr bool is_floating_point_v
is_floating_point的便捷变量模板
constexpr bool is_unsigned_v
is_unsigned的便捷变量模板
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 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
检查浮点数是否为负数
typename make_unsigned< T >::type make_unsigned_t
make_unsigned的便捷别名
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_scientific(T x, int precision=6)
将浮点数转换为字符串(科学计数法格式)
constexpr string to_string_fixed(T x, int precision=6)
将浮点数转换为字符串(固定小数格式)
constexpr string to_string(const T &value)
将可包装类型转换为字符串
constexpr string address_string(const void *p)
将指针转换为十六进制地址字符串
constexpr decltype(auto) begin(Container &cont) noexcept(noexcept(cont.begin()))
获取容器的起始迭代器
constexpr bool empty(const Container &cont) noexcept(noexcept(cont.empty()))
检查容器是否为空
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结束迭代器
typename enable_if< Test, T >::type enable_if_t
enable_if的便捷别名
集合器接口
可字符串化接口
数学函数库
数值类型特性检查
压缩对主模板,使用EBCO优化
存储两个值的元组对
T2 second
第二个元素
T1 first
第一个元素
类型擦除辅助函数
UTF字符包装类