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
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) {
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) {
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 uint32_t digit = 0;
100 const char c = *p;
101 if (c >= '0' && c <= '9') {
102 digit = static_cast<uint32_t>(c - '0');
103 } else if (c >= 'a' && c <= 'z') {
104 digit = static_cast<uint32_t>(c - 'a' + 10);
105 } else if (c >= 'A' && c <= 'Z') {
106 digit = static_cast<uint32_t>(c - 'A' + 10);
107 } else {
108 break;
109 }
110 if (digit >= static_cast<uint32_t>(base)) {
111 break;
112 }
113
114 any_converted = true;
115 if (!overflow) {
116 if (result > cutoff || (result == cutoff && static_cast<UT>(digit) > cutlim)) {
117 overflow = true;
118 } else {
119 result = result * static_cast<UT>(base) + static_cast<UT>(digit);
120 }
121 }
122 ++p;
123 }
124
125 if (endptr) {
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 } else {
140 if (result == umin_abs) {
141 return numeric_traits<T>::min();
142 }
143 return static_cast<T>(~result + static_cast<UT>(1));
144 }
145}
146
158template <typename T>
159constexpr enable_if_t<is_unsigned_v<T>, T> str_to_uints(const string_view sv, char** endptr, int base) {
160 const char* start = sv.data();
161 const size_t len = sv.size();
162 const char* end = start + len;
163
164 if (len == 0) {
165 if (endptr) {
166 *endptr = const_cast<char*>(start);
167 }
168 return 0;
169 }
170
171 const char* p = start;
172 while (p != end && is_space(*p)) {
173 ++p;
174 }
175 const char* start_conversion = p;
176
177 int sign = 1;
178 if (p != end && *p == '+') {
179 ++p;
180 } else if (p != end && *p == '-') {
181 sign = -1;
182 ++p;
183 }
184
185 if (base != 0 && (base < 2 || base > 36)) {
186 if (endptr) {
187 *endptr = const_cast<char*>(start_conversion);
188 }
189 return 0;
190 }
191
192 if (base == 0) {
193 if (p != end && *p == '0') {
194 if (p + 1 != end && (*(p + 1) == 'x' || *(p + 1) == 'X')) {
195 base = 16;
196 p += 2;
197 } else {
198 base = 8;
199 }
200 } else {
201 base = 10;
202 }
203 }
204
205 if (base == 16 && p + 1 < end && *p == '0' && (*(p + 1) == 'x' || *(p + 1) == 'X')) {
206 p += 2;
207 }
208
209 const T cutoff = numeric_traits<T>::max() / base;
210 const T cutlim = numeric_traits<T>::max() % base;
211 T result = 0;
212 bool any_converted = false;
213 bool overflow = false;
214
215 while (p != end) {
216 unsigned int digit = 0;
217 const char c = *p;
218 if (c >= '0' && c <= '9') {
219 digit = c - '0';
220 } else if (c >= 'a' && c <= 'z') {
221 digit = c - 'a' + 10;
222 } else if (c >= 'A' && c <= 'Z') {
223 digit = c - 'A' + 10;
224 } else {
225 break;
226 }
227 if (digit >= static_cast<unsigned int>(base)) {
228 break;
229 }
230
231 any_converted = true;
232 if (!overflow) {
233 if (result > cutoff || (result == cutoff && digit > cutlim)) {
234 overflow = true;
235 } else {
236 result = result * base + digit;
237 }
238 }
239 ++p;
240 }
241
242 if (endptr) {
243 *endptr = any_converted ? const_cast<char*>(p) : const_cast<char*>(start_conversion);
244 }
245
246 if (!any_converted) {
247 return 0;
248 }
249 if (overflow) {
250 return numeric_traits<T>::max();
251 }
252
253 if (sign < 0) {
254 // for unsigned, negative sign yields two's complement wrap,
255 // but we follow C standard: strtoul("-1", ...) returns ULLONG_MAX.
256 // So just cast via signed negation then to unsigned.
257 return static_cast<T>(-static_cast<make_signed_t<T>>(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 return pow10_table[exp];
282 }
283 if (exp < 0 && -exp <= max_table_exp) {
284 return neg_pow10_table[-exp];
285 }
286 return static_cast<T>(power(10.0, exp));
287}
288
299template <typename T>
300constexpr enable_if_t<is_floating_point_v<T>, T> str_to_floats(const string_view sv, char** endptr) {
301 const char* start = sv.data();
302 const size_t len = sv.size();
303 const char* end = start + len;
304
305 if (len == 0) {
306 if (endptr) {
307 *endptr = const_cast<char*>(start);
308 }
309 return static_cast<T>(0);
310 }
311
312 const char* p = start;
313 while (p != end && is_space(*p)) {
314 ++p;
315 }
316 const char* start_conversion = p;
317
318 int sign = 1;
319 if (p != end && *p == '+') {
320 ++p;
321 } else if (p != end && *p == '-') {
322 sign = -1;
323 ++p;
324 }
325
326 const char* p_start = p;
327
328 if (p != end && (p[0] == 'i' || p[0] == 'I')) {
329 if (p + 3 <= end) {
330 const char c1 = p[1], c2 = p[2];
331 if ((c1 == 'n' || c1 == 'N') && (c2 == 'f' || c2 == 'F')) {
332 const bool terminated = (p + 3 == end) || !is_alpha_or_digit(p[3]);
333 if (terminated) {
334 p += 3;
335 if (endptr) {
336 *endptr = const_cast<char*>(p);
337 }
338 const T inf_val = numeric_traits<T>::infinity();
339 return (sign < 0) ? -inf_val : inf_val;
340 }
341 }
342 }
343 }
344
345 if (p != end && (p[0] == 'n' || p[0] == 'N')) {
346 if (p + 3 <= end) {
347 const char c1 = p[1], c2 = p[2];
348 if ((c1 == 'a' || c1 == 'A') && (c2 == 'n' || c2 == 'N')) {
349 const bool terminated = (p + 3 == end) || !is_alpha_or_digit(p[3]);
350 if (terminated) {
351 p += 3;
352 if (p != end && *p == '(') {
353 ++p;
354 while (p != end && *p != ')') {
355 ++p;
356 }
357 if (p != end && *p == ')') {
358 ++p;
359 }
360 }
361 if (endptr) {
362 *endptr = const_cast<char*>(p);
363 }
365 }
366 }
367 }
368 }
369
370 p = p_start;
371
372 T significand = 0;
373 int exponent = 0;
374 int digits_count = 0;
375 bool has_digits = false;
376
377 while (p != end && *p >= '0' && *p <= '9') {
378 has_digits = true;
379 if (digits_count < numeric_traits<T>::digits10) {
380 significand = significand * static_cast<T>(10) + static_cast<T>(*p - '0');
381 } else {
382 exponent++;
383 }
384 digits_count++;
385 ++p;
386 }
387
388 if (p != end && *p == '.') {
389 ++p;
390 while (p != end && *p >= '0' && *p <= '9') {
391 has_digits = true;
392 if (digits_count < numeric_traits<T>::digits10) {
393 significand = significand * static_cast<T>(10) + static_cast<T>(*p - '0');
394 exponent--;
395 }
396 digits_count++;
397 ++p;
398 }
399 }
400
401 if (!has_digits) {
402 if (endptr) {
403 *endptr = const_cast<char*>(start_conversion);
404 }
405 return static_cast<T>(0);
406 }
407
408 if (p != end && (*p == 'e' || *p == 'E')) {
409 const char* e_pos = p;
410 ++p;
411
412 int exp_sign = 1;
413 if (p != end && *p == '+') {
414 ++p;
415 } else if (p != end && *p == '-') {
416 exp_sign = -1;
417 ++p;
418 }
419
420 if (p != end && *p >= '0' && *p <= '9') {
421 int exp_val = 0;
422 while (p != end && *p >= '0' && *p <= '9') {
423 if (exp_val < 100000) {
424 exp_val = exp_val * 10 + (*p - '0');
425 }
426 ++p;
427 }
428 exponent += exp_sign * exp_val;
429 } else {
430 p = e_pos;
431 }
432 }
433
434 T result = significand;
435
436 if (exponent != 0) {
437 constexpr int max_exp = numeric_traits<T>::max_exponent10 + 50;
438 constexpr int min_exp = numeric_traits<T>::min_exponent10 - 50;
439
440 if (exponent > max_exp) {
441 if (endptr) {
442 *endptr = const_cast<char*>(p);
443 }
444 return (sign > 0) ? numeric_traits<T>::infinity() : -numeric_traits<T>::infinity();
445 } else if (exponent < min_exp) {
446 if (endptr) {
447 *endptr = const_cast<char*>(p);
448 }
449 return static_cast<T>(0);
450 } else {
451 result *= fast_pow10<T>(exponent);
452 }
453 }
454
455 const T inf = numeric_traits<T>::infinity();
456 if (result == inf || result == -inf) {
457 if (endptr) {
458 *endptr = const_cast<char*>(p);
459 }
460 return (sign > 0) ? inf : -inf;
461 }
462
463 result = (sign > 0) ? result : -result;
464
465 if (endptr) {
466 *endptr = const_cast<char*>(p);
467 }
468 return result;
469}
470
471NEFORCE_END_INNER__
473
479
487NEFORCE_NODISCARD constexpr float32_t to_float32(const string_view sv, size_t* idx = nullptr) {
488 char* endptr = nullptr;
489 const float32_t num = inner::str_to_floats<float>(sv, &endptr);
490 if (sv.data() == endptr) {
491 NEFORCE_THROW_EXCEPTION(typecast_exception("Convert from string failed."));
492 }
493 if (idx) {
494 *idx = static_cast<size_t>(endptr - sv.data());
495 }
496 return num;
497}
498
506NEFORCE_NODISCARD constexpr float64_t to_float64(const string_view sv, size_t* idx = nullptr) {
507 char* endptr = nullptr;
508 const float64_t num = inner::str_to_floats<double>(sv, &endptr);
509 if (sv.data() == endptr) {
510 NEFORCE_THROW_EXCEPTION(typecast_exception("Convert from string failed."));
511 }
512 if (idx) {
513 *idx = static_cast<size_t>(endptr - sv.data());
514 }
515 return num;
516}
517
525NEFORCE_NODISCARD constexpr decimal_t to_decimal(const string_view sv, size_t* idx = nullptr) {
526 char* endptr = nullptr;
527 const decimal_t num = inner::str_to_floats<long double>(sv, &endptr);
528 if (sv.data() == endptr) {
529 NEFORCE_THROW_EXCEPTION(typecast_exception("Convert from string failed."));
530 }
531 if (idx) {
532 *idx = static_cast<size_t>(endptr - sv.data());
533 }
534 return num;
535}
536
545NEFORCE_NODISCARD constexpr int64_t to_int64(const string_view sv, size_t* idx = nullptr, const int base = 10) {
546 char* endptr = nullptr;
547 const int64_t num = inner::str_to_ints<int64_t>(sv, &endptr, base);
548 if (sv.data() == endptr) {
549 NEFORCE_THROW_EXCEPTION(typecast_exception("Convert from string failed."));
550 }
551 if (idx) {
552 *idx = static_cast<size_t>(endptr - sv.data());
553 }
554 return num;
555}
556
565NEFORCE_NODISCARD constexpr uint64_t to_uint64(const string_view sv, size_t* idx = nullptr, const int base = 10) {
566 char* endptr = nullptr;
567 const uint64_t num = inner::str_to_uints<uint64_t>(sv, &endptr, base);
568 if (sv.data() == endptr) {
569 NEFORCE_THROW_EXCEPTION(typecast_exception("Convert from string failed."));
570 }
571 if (idx) {
572 *idx = static_cast<size_t>(endptr - sv.data());
573 }
574 return num;
575}
576
585NEFORCE_NODISCARD constexpr int32_t to_int32(const string_view sv, size_t* idx = nullptr, const int base = 10) {
586 char* endptr = nullptr;
587 const int32_t num = inner::str_to_ints<int>(sv, &endptr, base);
588 if (sv.data() == endptr) {
589 NEFORCE_THROW_EXCEPTION(typecast_exception("Convert from string failed."));
590 }
591 if (idx) {
592 *idx = static_cast<size_t>(endptr - sv.data());
593 }
594 return num;
595}
596
605NEFORCE_NODISCARD constexpr uint32_t to_uint32(const string_view sv, size_t* idx = nullptr, const int base = 10) {
606 char* endptr = nullptr;
607 const uint32_t num = inner::str_to_uints<uint32_t>(sv, &endptr, base);
608 if (sv.data() == endptr) {
609 NEFORCE_THROW_EXCEPTION(typecast_exception("Convert from string failed."));
610 }
611 if (idx) {
612 *idx = static_cast<size_t>(endptr - sv.data());
613 }
614 return num;
615}
616
625NEFORCE_NODISCARD constexpr int16_t to_int16(const string_view sv, size_t* idx = nullptr, const int base = 10) {
626 const int32_t val = to_int32(sv, idx, base);
627 if (val > static_cast<int32_t>(numeric_traits<int16_t>::max()) ||
628 val < static_cast<int32_t>(numeric_traits<int16_t>::min())) {
629 NEFORCE_THROW_EXCEPTION(typecast_exception("Value out of int16_t range."));
630 }
631 return static_cast<int16_t>(val);
632}
633
642NEFORCE_NODISCARD constexpr uint16_t to_uint16(const string_view sv, size_t* idx = nullptr, const int base = 10) {
643 const uint32_t val = to_uint32(sv, idx, base);
644 if (val > static_cast<uint32_t>(numeric_traits<uint16_t>::max())) {
645 NEFORCE_THROW_EXCEPTION(typecast_exception("Value out of uint16_t range."));
646 }
647 return static_cast<uint16_t>(val);
648}
649
658NEFORCE_NODISCARD constexpr int8_t to_int8(const string_view sv, size_t* idx = nullptr, const int base = 10) {
659 const int32_t val = to_int32(sv, idx, base);
660 if (val > static_cast<int32_t>(numeric_traits<int8_t>::max()) ||
661 val < static_cast<int32_t>(numeric_traits<int8_t>::min())) {
662 NEFORCE_THROW_EXCEPTION(typecast_exception("Value out of int8_t range."));
663 }
664 return static_cast<int8_t>(val);
665}
666
675NEFORCE_NODISCARD constexpr uint8_t to_uint8(const string_view sv, size_t* idx = nullptr, const int base = 10) {
676 const uint32_t val = to_uint32(sv, idx, base);
677 if (val > static_cast<uint32_t>(numeric_traits<uint8_t>::max())) {
678 NEFORCE_THROW_EXCEPTION(typecast_exception("Value out of uint8_t range."));
679 }
680 return static_cast<uint8_t>(val);
681}
682 // StringConverts
684
685NEFORCE_END_NAMESPACE__
686#endif // NEFORCE_CORE_STRING_TO_NUMERICS_HPP__
NEFORCE_NODISCARD constexpr size_type size() const noexcept
获取字符串长度
NEFORCE_NODISCARD constexpr const_pointer data() const noexcept
获取底层数据指针
数值类型极限特性主模板
static NEFORCE_NODISCARD constexpr T quiet_nan() noexcept
获取安静nan表示
static NEFORCE_NODISCARD constexpr T min() noexcept
获取类型的最小值
static NEFORCE_NODISCARD constexpr T max() noexcept
获取类型的最大值
static NEFORCE_NODISCARD constexpr T infinity() noexcept
获取正无穷大表示
异常处理框架
NEFORCE_CONST_FUNCTION NEFORCE_CONSTEXPR14 bool is_alpha_or_digit(const CharT c) noexcept
检查字符是否为字母或数字
NEFORCE_PURE_FUNCTION NEFORCE_CONSTEXPR14 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位有符号整数类型
NEFORCE_CONST_FUNCTION NEFORCE_CONSTEXPR14 T power(const T &x, uint32_t n) noexcept
幂运算
NEFORCE_CONSTEXPR14 int sign(const T &value) noexcept
获取数值的符号
typename make_unsigned< T >::type make_unsigned_t
make_unsigned的便捷别名
typename make_signed< T >::type make_signed_t
make_signed的便捷别名
NEFORCE_NODISCARD constexpr decimal_t to_decimal(const string_view sv, size_t *idx=nullptr)
将字符串转换为decimal浮点数
NEFORCE_NODISCARD constexpr uint16_t to_uint16(const string_view sv, size_t *idx=nullptr, const int base=10)
将字符串转换为16位无符号整数
NEFORCE_NODISCARD constexpr float64_t to_float64(const string_view sv, size_t *idx=nullptr)
将字符串转换为64位浮点数
NEFORCE_NODISCARD constexpr float32_t to_float32(const string_view sv, size_t *idx=nullptr)
将字符串转换为32位浮点数
NEFORCE_NODISCARD constexpr uint32_t to_uint32(const string_view sv, size_t *idx=nullptr, const int base=10)
将字符串转换为32位无符号整数
NEFORCE_NODISCARD constexpr int64_t to_int64(const string_view sv, size_t *idx=nullptr, const int base=10)
将字符串转换为64位有符号整数
NEFORCE_NODISCARD constexpr int8_t to_int8(const string_view sv, size_t *idx=nullptr, const int base=10)
将字符串转换为8位有符号整数
NEFORCE_NODISCARD constexpr int16_t to_int16(const string_view sv, size_t *idx=nullptr, const int base=10)
将字符串转换为16位有符号整数
NEFORCE_NODISCARD constexpr int32_t to_int32(const string_view sv, size_t *idx=nullptr, const int base=10)
将字符串转换为32位有符号整数
NEFORCE_NODISCARD constexpr uint64_t to_uint64(const string_view sv, size_t *idx=nullptr, const int base=10)
将字符串转换为64位无符号整数
NEFORCE_NODISCARD constexpr uint8_t to_uint8(const string_view sv, size_t *idx=nullptr, const int base=10)
将字符串转换为8位无符号整数
basic_string_view< char > string_view
字符字符串视图
NEFORCE_NODISCARD NEFORCE_ALWAYS_INLINE constexpr decltype(auto) end(Container &cont) noexcept(noexcept(cont.end()))
获取容器的结束迭代器
typename enable_if< Test, T >::type enable_if_t
enable_if的便捷别名
数学函数库
字符串视图类型别名和实用函数
类型转换异常