NexusForce 1.0.0
A rigorously engineered full-stack C++ backend library.
载入中...
搜索中...
未找到
to_numerics.hpp
浏览该文件的文档.
1#ifndef NEFORCE_CORE_STRING_TO_NUMERICS_HPP__
2#define NEFORCE_CORE_STRING_TO_NUMERICS_HPP__
3
11
15#ifdef max
16# undef max
17#endif
18#ifdef min
19# undef min
20#endif
21NEFORCE_BEGIN_NAMESPACE__
22
24NEFORCE_BEGIN_INNER__
25
37template <typename T>
38constexpr enable_if_t<is_signed_v<T>, T> str_to_ints(const string_view sv, char** endptr, int base) {
39 using UT = make_unsigned_t<T>;
40
41 const char* start = sv.data();
42 const size_t len = sv.size();
43 const char* end = start + len;
44
45 if (len == 0) {
46 if (endptr != nullptr) {
47 *endptr = const_cast<char*>(start);
48 }
49 return 0;
50 }
51
52 const char* p = start;
53 while (p != end && is_space(*p)) {
54 ++p;
55 }
56 const char* start_conversion = p;
57
58 int sign = 1;
59 if (p != end && *p == '+') {
60 ++p;
61 } else if (p != end && *p == '-') {
62 sign = -1;
63 ++p;
64 }
65
66 if (base != 0 && (base < 2 || base > 36)) {
67 if (endptr != nullptr) {
68 *endptr = const_cast<char*>(start_conversion);
69 }
70 return 0;
71 }
72
73 if (base == 0) {
74 if (p != end && *p == '0') {
75 if (p + 1 != end && (*(p + 1) == 'x' || *(p + 1) == 'X')) {
76 base = 16;
77 p += 2;
78 } else {
79 base = 8;
80 }
81 } else {
82 base = 10;
83 }
84 } else if (base == 16 && p + 1 < end && *p == '0' && (*(p + 1) == 'x' || *(p + 1) == 'X')) {
85 p += 2;
86 }
87
88 const UT umax = static_cast<UT>(numeric_traits<T>::max());
89 const UT umin_abs = static_cast<UT>(numeric_traits<T>::max()) + static_cast<UT>(1);
90 const UT limit = (sign > 0) ? umax : umin_abs;
91 const UT cutoff = limit / static_cast<UT>(base);
92 const UT cutlim = limit % static_cast<UT>(base);
93
94 UT result = 0;
95 bool any_converted = false;
96 bool overflow = false;
97
98 while (p != end) {
99 UT digit(0);
100 const char c = *p;
101 if (c >= '0' && c <= '9') {
102 digit = static_cast<UT>(c - '0');
103 } else if (c >= 'a' && c <= 'z') {
104 digit = static_cast<UT>(c - 'a') + static_cast<UT>(10);
105 } else if (c >= 'A' && c <= 'Z') {
106 digit = static_cast<UT>(c - 'A') + static_cast<UT>(10);
107 } else {
108 break;
109 }
110 if (digit >= static_cast<UT>(base)) {
111 break;
112 }
113
114 any_converted = true;
115 if (!overflow) {
116 if (result > cutoff || (result == cutoff && digit > cutlim)) {
117 overflow = true;
118 } else {
119 result = result * static_cast<UT>(base) + digit;
120 }
121 }
122 ++p;
123 }
124
125 if (endptr != nullptr) {
126 *endptr = any_converted ? const_cast<char*>(p) : const_cast<char*>(start_conversion);
127 }
128
129 if (!any_converted) {
130 return 0;
131 }
132
133 if (overflow) {
134 return (sign > 0) ? numeric_traits<T>::max() : numeric_traits<T>::min();
135 }
136
137 if (sign > 0) {
138 return static_cast<T>(result);
139 }
140 if (result == umin_abs) {
141 return numeric_traits<T>::min();
142 }
143 return static_cast<T>(~result + static_cast<UT>(1));
144}
145
157template <typename T>
158constexpr enable_if_t<is_unsigned_v<T>, T> str_to_uints(const string_view sv, char** endptr, int base) {
159 const char* start = sv.data();
160 const size_t len = sv.size();
161 const char* end = start + len;
162
163 if (len == 0) {
164 if (endptr != nullptr) {
165 *endptr = const_cast<char*>(start);
166 }
167 return 0;
168 }
169
170 const char* p = start;
171 while (p != end && is_space(*p)) {
172 ++p;
173 }
174 const char* start_conversion = p;
175
176 int sign = 1;
177 if (p != end && *p == '+') {
178 ++p;
179 } else if (p != end && *p == '-') {
180 sign = -1;
181 ++p;
182 }
183
184 if (base != 0 && (base < 2 || base > 36)) {
185 if (endptr != nullptr) {
186 *endptr = const_cast<char*>(start_conversion);
187 }
188 return 0;
189 }
190
191 if (base == 0) {
192 if (p != end && *p == '0') {
193 if (p + 1 != end && (*(p + 1) == 'x' || *(p + 1) == 'X')) {
194 base = 16;
195 p += 2;
196 } else {
197 base = 8;
198 }
199 } else {
200 base = 10;
201 }
202 }
203
204 if (base == 16 && p + 1 < end && *p == '0' && (*(p + 1) == 'x' || *(p + 1) == 'X')) {
205 p += 2;
206 }
207
208 const T cutoff = numeric_traits<T>::max() / base;
209 const T cutlim = numeric_traits<T>::max() % base;
210 T result(0);
211 bool any_converted = false;
212 bool overflow = false;
213
214 while (p != end) {
215 T digit(0);
216 const char c = *p;
217 if (c >= '0' && c <= '9') {
218 digit = static_cast<T>(c - '0');
219 } else if (c >= 'a' && c <= 'z') {
220 digit = static_cast<T>(c - 'a') + static_cast<T>(10);
221 } else if (c >= 'A' && c <= 'Z') {
222 digit = static_cast<T>(c - 'A') + static_cast<T>(10);
223 } else {
224 break;
225 }
226 if (digit >= static_cast<T>(base)) {
227 break;
228 }
229
230 any_converted = true;
231 if (!overflow) {
232 if (result > cutoff || (result == cutoff && digit > cutlim)) {
233 overflow = true;
234 } else {
235 result = result * static_cast<T>(base) + digit;
236 }
237 }
238 ++p;
239 }
240
241 if (endptr != nullptr) {
242 *endptr = any_converted ? const_cast<char*>(p) : const_cast<char*>(start_conversion);
243 }
244
245 if (!any_converted) {
246 return static_cast<T>(0);
247 }
248 if (overflow) {
249 return numeric_traits<T>::max();
250 }
251
252 if (sign < 0) {
253 // for unsigned, negative sign yields two's complement wrap,
254 // but we follow C standard: strtoul("-1", ...) returns ULLONG_MAX.
255 // So just cast via signed negation then to unsigned.
256 return static_cast<T>(static_cast<typename make_signed<T>::type>(0) -
257 static_cast<typename make_signed<T>::type>(result));
258 }
259 return result;
260}
261
270template <typename T>
271NEFORCE_CONST_FUNCTION constexpr T fast_pow10(int exp) {
272 constexpr T pow10_table[] = {1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10,
273 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21,
274 1e22, 1e23, 1e24, 1e25, 1e26, 1e27, 1e28, 1e29, 1e30, 1e31, 1e32};
275 constexpr T neg_pow10_table[] = {1e0, 1e-1, 1e-2, 1e-3, 1e-4, 1e-5, 1e-6, 1e-7, 1e-8, 1e-9, 1e-10,
276 1e-11, 1e-12, 1e-13, 1e-14, 1e-15, 1e-16, 1e-17, 1e-18, 1e-19, 1e-20, 1e-21,
277 1e-22, 1e-23, 1e-24, 1e-25, 1e-26, 1e-27, 1e-28, 1e-29, 1e-30, 1e-31, 1e-32};
278 constexpr int max_table_exp = 32;
279
280 if (exp >= 0 && exp <= max_table_exp) {
281 // NOLINTNEXTLINE(clang-analyzer-security.ArrayBound)
282 return pow10_table[exp];
283 }
284 if (exp < 0 && -exp <= max_table_exp) {
285 // NOLINTNEXTLINE(clang-analyzer-security.ArrayBound)
286 return neg_pow10_table[-exp];
287 }
288
289 if (exp >= 0) {
290 return static_cast<T>(_NEFORCE power(T(10), static_cast<uint32_t>(exp)));
291 }
292 return static_cast<T>(1) / static_cast<T>(_NEFORCE power(T(10), static_cast<uint32_t>(-exp)));
293}
294
305template <typename T>
306constexpr enable_if_t<is_floating_point_v<T>, T> str_to_floats(const string_view sv, char** endptr) {
307 const char* start = sv.data();
308 const size_t len = sv.size();
309 const char* end = start + len;
310
311 if (len == 0) {
312 if (endptr) {
313 *endptr = const_cast<char*>(start);
314 }
315 return static_cast<T>(0);
316 }
317
318 const char* p = start;
319 while (p != end && is_space(*p)) {
320 ++p;
321 }
322 const char* start_conversion = p;
323
324 int sign = 1;
325 if (p != end && *p == '+') {
326 ++p;
327 } else if (p != end && *p == '-') {
328 sign = -1;
329 ++p;
330 }
331
332 const char* p_start = p;
333
334 if (p != end && (p[0] == 'i' || p[0] == 'I')) {
335 bool is_inf = false;
336
337 if (p + 8 <= end) {
338 if ((p[1] == 'n' || p[1] == 'N') && (p[2] == 'f' || p[2] == 'F') && (p[3] == 'i' || p[3] == 'I') &&
339 (p[4] == 'n' || p[4] == 'N') && (p[5] == 'i' || p[5] == 'I') && (p[6] == 't' || p[6] == 'T') &&
340 (p[7] == 'y' || p[7] == 'Y')) {
341 if (p + 8 == end || !is_alpha_or_digit(p[8])) {
342 p += 8;
343 is_inf = true;
344 }
345 }
346 }
347
348 if (!is_inf && p + 3 <= end) {
349 if ((p[1] == 'n' || p[1] == 'N') && (p[2] == 'f' || p[2] == 'F')) {
350 if (p + 3 == end || !is_alpha_or_digit(p[3])) {
351 p += 3;
352 is_inf = true;
353 }
354 }
355 }
356
357 if (is_inf) {
358 if (endptr) {
359 *endptr = const_cast<char*>(p);
360 }
361 const T inf_val = numeric_traits<T>::infinity();
362 return (sign < 0) ? -inf_val : inf_val;
363 }
364 }
365
366 if (p != end && (p[0] == 'n' || p[0] == 'N')) {
367 if (p + 3 <= end) {
368 const char c1 = p[1], c2 = p[2];
369 if ((c1 == 'a' || c1 == 'A') && (c2 == 'n' || c2 == 'N')) {
370 const bool terminated = (p + 3 == end) || !is_alpha_or_digit(p[3]);
371 if (terminated) {
372 p += 3;
373 if (p != end && *p == '(') {
374 ++p;
375 while (p != end && *p != ')') {
376 ++p;
377 }
378 if (p != end && *p == ')') {
379 ++p;
380 }
381 }
382 if (endptr) {
383 *endptr = const_cast<char*>(p);
384 }
385 return numeric_traits<T>::quiet_nan();
386 }
387 }
388 }
389 }
390
391 p = p_start;
392
393 T significand = 0;
394 int exponent = 0;
395 int digits_count = 0;
396 bool has_digits = false;
397
398 while (p != end && *p >= '0' && *p <= '9') {
399 has_digits = true;
400 if (digits_count < numeric_traits<T>::max_digits10) {
401 significand = significand * static_cast<T>(10) + static_cast<T>(*p - '0');
402 } else {
403 exponent++;
404 }
405 digits_count++;
406 ++p;
407 }
408
409 if (p != end && *p == '.') {
410 ++p;
411 while (p != end && *p >= '0' && *p <= '9') {
412 has_digits = true;
413 if (digits_count < numeric_traits<T>::max_digits10) {
414 significand = significand * static_cast<T>(10) + static_cast<T>(*p - '0');
415 exponent--;
416 }
417 digits_count++;
418 ++p;
419 }
420 }
421
422 if (!has_digits) {
423 if (endptr) {
424 *endptr = const_cast<char*>(start_conversion);
425 }
426 return static_cast<T>(0);
427 }
428
429 if (p != end && (*p == 'e' || *p == 'E')) {
430 const char* e_pos = p;
431 ++p;
432
433 int exp_sign = 1;
434 if (p != end && *p == '+') {
435 ++p;
436 } else if (p != end && *p == '-') {
437 exp_sign = -1;
438 ++p;
439 }
440
441 if (p != end && *p >= '0' && *p <= '9') {
442 int exp_val = 0;
443 while (p != end && *p >= '0' && *p <= '9') {
444 if (exp_val < 100000) {
445 exp_val = exp_val * 10 + (*p - '0');
446 }
447 ++p;
448 }
449 exponent += exp_sign * exp_val;
450 } else {
451 p = e_pos;
452 }
453 }
454
455 T result = significand;
456
457 if (exponent != 0) {
458 constexpr int max_exp = numeric_traits<T>::max_exponent10 + 50;
459 constexpr int min_exp = numeric_traits<T>::min_exponent10 - 50;
460 constexpr int max_table_exp = 32;
461
462 if (exponent > max_exp || exponent > max_table_exp) {
463 if (endptr) {
464 *endptr = const_cast<char*>(p);
465 }
466 return (sign > 0) ? numeric_traits<T>::infinity() : -numeric_traits<T>::infinity();
467 } else if (exponent < min_exp || exponent < -max_table_exp) {
468 if (endptr) {
469 *endptr = const_cast<char*>(p);
470 }
471 return static_cast<T>(0);
472 } else {
473 result *= fast_pow10<T>(exponent);
474 }
475 }
476
477 const T inf = numeric_traits<T>::infinity();
478 if (result == inf || result == -inf) {
479 if (endptr) {
480 *endptr = const_cast<char*>(p);
481 }
482 return (sign > 0) ? inf : -inf;
483 }
484
485 result = (sign > 0) ? result : -result;
486
487 if (endptr) {
488 *endptr = const_cast<char*>(p);
489 }
490 return result;
491}
492
493NEFORCE_END_INNER__
495
501
509NEFORCE_NODISCARD constexpr float32_t to_float32(const string_view sv, size_t* idx = nullptr) {
510 char* endptr = nullptr;
511 const float32_t num = inner::str_to_floats<float32_t>(sv, &endptr);
512 if (sv.data() == endptr) {
513 NEFORCE_THROW_EXCEPTION(typecast_exception("Convert from string failed."));
514 }
515 if (idx != nullptr) {
516 *idx = static_cast<size_t>(endptr - sv.data());
517 }
518 return num;
519}
520
528NEFORCE_NODISCARD constexpr float64_t to_float64(const string_view sv, size_t* idx = nullptr) {
529 char* endptr = nullptr;
530 const float64_t num = inner::str_to_floats<float64_t>(sv, &endptr);
531 if (sv.data() == endptr) {
532 NEFORCE_THROW_EXCEPTION(typecast_exception("Convert from string failed."));
533 }
534 if (idx != nullptr) {
535 *idx = static_cast<size_t>(endptr - sv.data());
536 }
537 return num;
538}
539
547NEFORCE_NODISCARD constexpr decimal_t to_decimal(const string_view sv, size_t* idx = nullptr) {
548 char* endptr = nullptr;
549 const decimal_t num = inner::str_to_floats<decimal_t>(sv, &endptr);
550 if (sv.data() == endptr) {
551 NEFORCE_THROW_EXCEPTION(typecast_exception("Convert from string failed."));
552 }
553 if (idx != nullptr) {
554 *idx = static_cast<size_t>(endptr - sv.data());
555 }
556 return num;
557}
558
567NEFORCE_NODISCARD constexpr int64_t to_int64(const string_view sv, size_t* idx = nullptr, const int base = 10) {
568 char* endptr = nullptr;
569 const int64_t num = inner::str_to_ints<int64_t>(sv, &endptr, base);
570 if (sv.data() == endptr) {
571 NEFORCE_THROW_EXCEPTION(typecast_exception("Convert from string failed."));
572 }
573 if (idx != nullptr) {
574 *idx = static_cast<size_t>(endptr - sv.data());
575 }
576 return num;
577}
578
587NEFORCE_NODISCARD constexpr uint64_t to_uint64(const string_view sv, size_t* idx = nullptr, const int base = 10) {
588 char* endptr = nullptr;
589 const uint64_t num = inner::str_to_uints<uint64_t>(sv, &endptr, base);
590 if (sv.data() == endptr) {
591 NEFORCE_THROW_EXCEPTION(typecast_exception("Convert from string failed."));
592 }
593 if (idx != nullptr) {
594 *idx = static_cast<size_t>(endptr - sv.data());
595 }
596 return num;
597}
598
607NEFORCE_NODISCARD constexpr int32_t to_int32(const string_view sv, size_t* idx = nullptr, const int base = 10) {
608 char* endptr = nullptr;
609 const int32_t num = inner::str_to_ints<int32_t>(sv, &endptr, base);
610 if (sv.data() == endptr) {
611 NEFORCE_THROW_EXCEPTION(typecast_exception("Convert from string failed."));
612 }
613 if (idx != nullptr) {
614 *idx = static_cast<size_t>(endptr - sv.data());
615 }
616 return num;
617}
618
627NEFORCE_NODISCARD constexpr uint32_t to_uint32(const string_view sv, size_t* idx = nullptr, const int base = 10) {
628 char* endptr = nullptr;
629 const uint32_t num = inner::str_to_uints<uint32_t>(sv, &endptr, base);
630 if (sv.data() == endptr) {
631 NEFORCE_THROW_EXCEPTION(typecast_exception("Convert from string failed."));
632 }
633 if (idx != nullptr) {
634 *idx = static_cast<size_t>(endptr - sv.data());
635 }
636 return num;
637}
638
647NEFORCE_NODISCARD constexpr int16_t to_int16(const string_view sv, size_t* idx = nullptr, const int base = 10) {
648 const int32_t val = to_int32(sv, idx, base);
649 if (val > static_cast<int32_t>(numeric_traits<int16_t>::max()) ||
650 val < static_cast<int32_t>(numeric_traits<int16_t>::min())) {
651 NEFORCE_THROW_EXCEPTION(typecast_exception("Value out of int16_t range."));
652 }
653 return static_cast<int16_t>(val);
654}
655
664NEFORCE_NODISCARD constexpr uint16_t to_uint16(const string_view sv, size_t* idx = nullptr, const int base = 10) {
665 const uint32_t val = to_uint32(sv, idx, base);
666 if (val > static_cast<uint32_t>(numeric_traits<uint16_t>::max())) {
667 NEFORCE_THROW_EXCEPTION(typecast_exception("Value out of uint16_t range."));
668 }
669 return static_cast<uint16_t>(val);
670}
671
680NEFORCE_NODISCARD constexpr int8_t to_int8(const string_view sv, size_t* idx = nullptr, const int base = 10) {
681 const int32_t val = to_int32(sv, idx, base);
682 if (val > static_cast<int32_t>(numeric_traits<int8_t>::max()) ||
683 val < static_cast<int32_t>(numeric_traits<int8_t>::min())) {
684 NEFORCE_THROW_EXCEPTION(typecast_exception("Value out of int8_t range."));
685 }
686 return static_cast<int8_t>(val);
687}
688
697NEFORCE_NODISCARD constexpr uint8_t to_uint8(const string_view sv, size_t* idx = nullptr, const int base = 10) {
698 const uint32_t val = to_uint32(sv, idx, base);
699 if (val > static_cast<uint32_t>(numeric_traits<uint8_t>::max())) {
700 NEFORCE_THROW_EXCEPTION(typecast_exception("Value out of uint8_t range."));
701 }
702 return static_cast<uint8_t>(val);
703}
704
713NEFORCE_NODISCARD constexpr uint128_t to_uint128(const string_view sv, size_t* idx = nullptr, const int base = 10) {
714 char* endptr = nullptr;
715 const uint128_t num = inner::str_to_uints<uint128_t>(sv, &endptr, base);
716 if (sv.data() == endptr) {
717 NEFORCE_THROW_EXCEPTION(typecast_exception("Convert from string failed."));
718 }
719 if (idx != nullptr) {
720 *idx = static_cast<size_t>(endptr - sv.data());
721 }
722 return num;
723}
724
733NEFORCE_NODISCARD constexpr int128_t to_int128(const string_view sv, size_t* idx = nullptr, const int base = 10) {
734 char* endptr = nullptr;
735 const int128_t num = inner::str_to_ints<int128_t>(sv, &endptr, base);
736 if (sv.data() == endptr) {
737 NEFORCE_THROW_EXCEPTION(typecast_exception("Convert from string failed."));
738 }
739 if (idx != nullptr) {
740 *idx = static_cast<size_t>(endptr - sv.data());
741 }
742 return num;
743}
744 // StringConverts
746
747NEFORCE_BEGIN_LITERALS__
748
754
762NEFORCE_NODISCARD constexpr uint128_t operator""_u128(const char* str, const size_t len) {
763 return to_uint128(string_view{str, len});
764}
765
773NEFORCE_NODISCARD constexpr int128_t operator""_i128(const char* str, const size_t len) {
774 return to_int128(string_view{str, len});
775}
776 // UserLiterals
778
779NEFORCE_END_LITERALS__
780
781NEFORCE_END_NAMESPACE__
782#endif // NEFORCE_CORE_STRING_TO_NUMERICS_HPP__
constexpr const_pointer data() const noexcept
获取底层数据指针
static constexpr T max() noexcept
获取类型的最大值
static constexpr T min() noexcept
获取类型的最小值
constexpr bool is_alpha_or_digit(const CharT c) noexcept
检查字符是否为字母或数字
constexpr bool is_space(const CharT c) noexcept
检查字符是否为空白字符
constexpr const T & min(const T &a, const T &b, Compare comp) noexcept(noexcept(comp(b, a)))
返回两个值中的较小者
long int64_t
64位有符号整数类型
float float32_t
32位单精度浮点数类型
unsigned int uint32_t
32位无符号整数类型
unsigned long uint64_t
64位无符号整数类型
long double decimal_t
扩展精度浮点数类型
unsigned char uint8_t
8位无符号整数类型
int int32_t
32位有符号整数类型
double float64_t
64位双精度浮点数类型
unsigned short uint16_t
16位无符号整数类型
short int16_t
16位有符号整数类型
signed char int8_t
8位有符号整数类型
constexpr int sign(const T &value) noexcept
获取数值的符号
constexpr T power(const T &x, uint32_t n) noexcept
幂运算
constexpr int32_t to_int32(const string_view sv, size_t *idx=nullptr, const int base=10)
将字符串转换为32位有符号整数
constexpr float32_t to_float32(const string_view sv, size_t *idx=nullptr)
将字符串转换为32位浮点数
constexpr uint16_t to_uint16(const string_view sv, size_t *idx=nullptr, const int base=10)
将字符串转换为16位无符号整数
constexpr float64_t to_float64(const string_view sv, size_t *idx=nullptr)
将字符串转换为64位浮点数
constexpr int128_t to_int128(const string_view sv, size_t *idx=nullptr, const int base=10)
将字符串转换为128位有符号整数
constexpr uint32_t to_uint32(const string_view sv, size_t *idx=nullptr, const int base=10)
将字符串转换为32位无符号整数
constexpr int64_t to_int64(const string_view sv, size_t *idx=nullptr, const int base=10)
将字符串转换为64位有符号整数
constexpr uint128_t to_uint128(const string_view sv, size_t *idx=nullptr, const int base=10)
将字符串转换为128位无符号整数
constexpr int8_t to_int8(const string_view sv, size_t *idx=nullptr, const int base=10)
将字符串转换为8位有符号整数
constexpr uint64_t to_uint64(const string_view sv, size_t *idx=nullptr, const int base=10)
将字符串转换为64位无符号整数
constexpr decimal_t to_decimal(const string_view sv, size_t *idx=nullptr)
将字符串转换为decimal浮点数
constexpr uint8_t to_uint8(const string_view sv, size_t *idx=nullptr, const int base=10)
将字符串转换为8位无符号整数
constexpr int16_t to_int16(const string_view sv, size_t *idx=nullptr, const int base=10)
将字符串转换为16位有符号整数
basic_string_view< char > string_view
字符字符串视图
constexpr decltype(auto) end(Container &cont) noexcept(noexcept(cont.end()))
获取容器的结束迭代器
128位整数类型实现
数学函数库
字符串视图类型别名和实用函数
128位有符号整数类型
128位无符号整数类型