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