1#ifndef NEFORCE_CORE_STRING_TO_NUMERICS_HPP__
2#define NEFORCE_CORE_STRING_TO_NUMERICS_HPP__
21NEFORCE_BEGIN_NAMESPACE__
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>;
41 const char* start = sv.data();
42 const size_t len = sv.size();
43 const char*
end = start + len;
46 if (endptr !=
nullptr) {
47 *endptr =
const_cast<char*
>(start);
52 const char* p = start;
56 const char* start_conversion = p;
59 if (p != end && *p ==
'+') {
61 }
else if (p != end && *p ==
'-') {
66 if (base != 0 && (base < 2 || base > 36)) {
67 if (endptr !=
nullptr) {
68 *endptr =
const_cast<char*
>(start_conversion);
74 if (p != end && *p ==
'0') {
75 if (p + 1 != end && (*(p + 1) ==
'x' || *(p + 1) ==
'X')) {
84 }
else if (base == 16 && p + 1 < end && *p ==
'0' && (*(p + 1) ==
'x' || *(p + 1) ==
'X')) {
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);
95 bool any_converted =
false;
96 bool overflow =
false;
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);
110 if (digit >=
static_cast<UT
>(base)) {
114 any_converted =
true;
116 if (result > cutoff || (result == cutoff && digit > cutlim)) {
119 result = result *
static_cast<UT
>(base) + digit;
125 if (endptr !=
nullptr) {
126 *endptr = any_converted ?
const_cast<char*
>(p) : const_cast<char*>(start_conversion);
129 if (!any_converted) {
134 return (sign > 0) ? numeric_traits<T>::max() : numeric_traits<T>::
min();
138 return static_cast<T
>(result);
140 if (result == umin_abs) {
141 return numeric_traits<T>::min();
143 return static_cast<T
>(~result +
static_cast<UT
>(1));
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;
164 if (endptr !=
nullptr) {
165 *endptr =
const_cast<char*
>(start);
170 const char* p = start;
174 const char* start_conversion = p;
177 if (p != end && *p ==
'+') {
179 }
else if (p != end && *p ==
'-') {
184 if (base != 0 && (base < 2 || base > 36)) {
185 if (endptr !=
nullptr) {
186 *endptr =
const_cast<char*
>(start_conversion);
192 if (p != end && *p ==
'0') {
193 if (p + 1 != end && (*(p + 1) ==
'x' || *(p + 1) ==
'X')) {
204 if (base == 16 && p + 1 < end && *p ==
'0' && (*(p + 1) ==
'x' || *(p + 1) ==
'X')) {
208 const T cutoff = numeric_traits<T>::max() / base;
209 const T cutlim = numeric_traits<T>::max() % base;
211 bool any_converted =
false;
212 bool overflow =
false;
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);
226 if (digit >=
static_cast<T
>(base)) {
230 any_converted =
true;
232 if (result > cutoff || (result == cutoff && digit > cutlim)) {
235 result = result *
static_cast<T
>(base) + digit;
241 if (endptr !=
nullptr) {
242 *endptr = any_converted ?
const_cast<char*
>(p) : const_cast<char*>(start_conversion);
245 if (!any_converted) {
246 return static_cast<T
>(0);
249 return numeric_traits<T>::max();
256 return static_cast<T
>(
static_cast<typename make_signed<T>::type
>(0) -
257 static_cast<typename make_signed<T>::type
>(result));
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;
280 if (exp >= 0 && exp <= max_table_exp) {
282 return pow10_table[exp];
284 if (exp < 0 && -exp <= max_table_exp) {
286 return neg_pow10_table[-exp];
290 return static_cast<T
>(_NEFORCE
power(T(10),
static_cast<uint32_t>(exp)));
292 return static_cast<T
>(1) /
static_cast<T
>(_NEFORCE
power(T(10),
static_cast<uint32_t>(-exp)));
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;
313 *endptr =
const_cast<char*
>(start);
315 return static_cast<T
>(0);
318 const char* p = start;
322 const char* start_conversion = p;
325 if (p != end && *p ==
'+') {
327 }
else if (p != end && *p ==
'-') {
332 const char* p_start = p;
334 if (p != end && (p[0] ==
'i' || p[0] ==
'I')) {
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')) {
348 if (!is_inf && p + 3 <= end) {
349 if ((p[1] ==
'n' || p[1] ==
'N') && (p[2] ==
'f' || p[2] ==
'F')) {
359 *endptr =
const_cast<char*
>(p);
361 const T inf_val = numeric_traits<T>::infinity();
362 return (sign < 0) ? -inf_val : inf_val;
366 if (p != end && (p[0] ==
'n' || p[0] ==
'N')) {
368 const char c1 = p[1], c2 = p[2];
369 if ((c1 ==
'a' || c1 ==
'A') && (c2 ==
'n' || c2 ==
'N')) {
373 if (p != end && *p ==
'(') {
375 while (p != end && *p !=
')') {
378 if (p != end && *p ==
')') {
383 *endptr =
const_cast<char*
>(p);
385 return numeric_traits<T>::quiet_nan();
395 int digits_count = 0;
396 bool has_digits =
false;
398 while (p != end && *p >=
'0' && *p <=
'9') {
400 if (digits_count < numeric_traits<T>::max_digits10) {
401 significand = significand *
static_cast<T
>(10) +
static_cast<T
>(*p -
'0');
409 if (p != end && *p ==
'.') {
411 while (p != end && *p >=
'0' && *p <=
'9') {
413 if (digits_count < numeric_traits<T>::max_digits10) {
414 significand = significand *
static_cast<T
>(10) +
static_cast<T
>(*p -
'0');
424 *endptr =
const_cast<char*
>(start_conversion);
426 return static_cast<T
>(0);
429 if (p != end && (*p ==
'e' || *p ==
'E')) {
430 const char* e_pos = p;
434 if (p != end && *p ==
'+') {
436 }
else if (p != end && *p ==
'-') {
441 if (p != end && *p >=
'0' && *p <=
'9') {
443 while (p != end && *p >=
'0' && *p <=
'9') {
444 if (exp_val < 100000) {
445 exp_val = exp_val * 10 + (*p -
'0');
449 exponent += exp_sign * exp_val;
455 T result = significand;
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;
462 if (exponent > max_exp || exponent > max_table_exp) {
464 *endptr =
const_cast<char*
>(p);
466 return (sign > 0) ? numeric_traits<T>::infinity() : -numeric_traits<T>::infinity();
467 }
else if (exponent < min_exp || exponent < -max_table_exp) {
469 *endptr =
const_cast<char*
>(p);
471 return static_cast<T
>(0);
473 result *= fast_pow10<T>(exponent);
477 const T inf = numeric_traits<T>::infinity();
478 if (result == inf || result == -inf) {
480 *endptr =
const_cast<char*
>(p);
482 return (sign > 0) ? inf : -inf;
485 result = (
sign > 0) ? result : -result;
488 *endptr =
const_cast<char*
>(p);
510 char* endptr =
nullptr;
511 const float32_t num = inner::str_to_floats<float32_t>(sv, &endptr);
512 if (sv.
data() == endptr) {
515 if (idx !=
nullptr) {
516 *idx =
static_cast<size_t>(endptr - sv.
data());
529 char* endptr =
nullptr;
530 const float64_t num = inner::str_to_floats<float64_t>(sv, &endptr);
531 if (sv.
data() == endptr) {
534 if (idx !=
nullptr) {
535 *idx =
static_cast<size_t>(endptr - sv.
data());
548 char* endptr =
nullptr;
549 const decimal_t num = inner::str_to_floats<decimal_t>(sv, &endptr);
550 if (sv.
data() == endptr) {
553 if (idx !=
nullptr) {
554 *idx =
static_cast<size_t>(endptr - sv.
data());
568 char* endptr =
nullptr;
569 const int64_t num = inner::str_to_ints<int64_t>(sv, &endptr, base);
570 if (sv.
data() == endptr) {
573 if (idx !=
nullptr) {
574 *idx =
static_cast<size_t>(endptr - sv.
data());
588 char* endptr =
nullptr;
589 const uint64_t num = inner::str_to_uints<uint64_t>(sv, &endptr, base);
590 if (sv.
data() == endptr) {
593 if (idx !=
nullptr) {
594 *idx =
static_cast<size_t>(endptr - sv.
data());
608 char* endptr =
nullptr;
609 const int32_t num = inner::str_to_ints<int32_t>(sv, &endptr, base);
610 if (sv.
data() == endptr) {
613 if (idx !=
nullptr) {
614 *idx =
static_cast<size_t>(endptr - sv.
data());
628 char* endptr =
nullptr;
629 const uint32_t num = inner::str_to_uints<uint32_t>(sv, &endptr, base);
630 if (sv.
data() == endptr) {
633 if (idx !=
nullptr) {
634 *idx =
static_cast<size_t>(endptr - sv.
data());
653 return static_cast<int16_t>(val);
686 return static_cast<int8_t>(val);
702 return static_cast<uint8_t>(val);
714 char* endptr =
nullptr;
715 const uint128_t num = inner::str_to_uints<uint128_t>(sv, &endptr, base);
716 if (sv.
data() == endptr) {
719 if (idx !=
nullptr) {
720 *idx =
static_cast<size_t>(endptr - sv.
data());
734 char* endptr =
nullptr;
735 const int128_t num = inner::str_to_ints<int128_t>(sv, &endptr, base);
736 if (sv.
data() == endptr) {
739 if (idx !=
nullptr) {
740 *idx =
static_cast<size_t>(endptr - sv.
data());
747NEFORCE_BEGIN_LITERALS__
762NEFORCE_NODISCARD
constexpr uint128_t operator""_u128(
const char* str,
const size_t len) {
773NEFORCE_NODISCARD
constexpr int128_t operator""_i128(
const char* str,
const size_t len) {
779NEFORCE_END_LITERALS__
781NEFORCE_END_NAMESPACE__
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)))
返回两个值中的较小者
float float32_t
32位单精度浮点数类型
unsigned int uint32_t
32位无符号整数类型
unsigned long uint64_t
64位无符号整数类型
long double decimal_t
扩展精度浮点数类型
unsigned char uint8_t
8位无符号整数类型
double float64_t
64位双精度浮点数类型
unsigned short uint16_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()))
获取容器的结束迭代器