MSTL 1.4.0
A Modern C++ Library with extended functionality, web components, and utility libraries
载入中...
搜索中...
未找到
to_numerics.hpp
1#ifndef MSTL_CORE_STRING_TO_NUMERICS_HPP__
2#define MSTL_CORE_STRING_TO_NUMERICS_HPP__
3#include "../string/string_view.hpp"
4#include "../numeric/math.hpp"
6#include "../config/undef_cmacro.hpp"
8
10
11template <typename T, enable_if_t<is_signed_v<T>, int> = 0>
12constexpr T str_to_ints(const string_view sv, char** endptr, int base) {
13 const char* start = sv.data();
14 const size_t len = sv.size();
15 const char* end = start + len;
16
17 if (len == 0) {
18 if (endptr) *endptr = const_cast<char*>(start);
19 return 0;
20 }
21
22 const char* p = start;
23 while (p != end && is_space(*p)) ++p;
24 const char* start_conversion = p;
25
26 int sign = 1;
27 if (p != end && *p == '+') {
28 ++p;
29 } else if (p != end && *p == '-') {
30 sign = -1;
31 ++p;
32 }
33
34 if (base != 0 && (base < 2 || base > 36)) {
35 if (endptr) *endptr = const_cast<char*>(start_conversion);
36 return 0;
37 }
38
39 if (base == 0) {
40 if (p != end && *p == '0') {
41 if (p + 1 != end && (*(p + 1) == 'x' || *(p + 1) == 'X')) {
42 base = 16;
43 p += 2;
44 } else {
45 base = 8;
46 }
47 } else {
48 base = 10;
49 }
50 }
51
52 if (base == 16 && p + 1 < end && *p == '0' && (*(p + 1) == 'x' || *(p + 1) == 'X')) {
53 p += 2;
54 }
55
56 const T cutoff = numeric_traits<T>::min() / base;
57 const T cutlim = numeric_traits<T>::min() % base;
58 T result = 0;
59 bool any_converted = false;
60 bool overflow = false;
61
62 while (p != end) {
63 int digit = 0;
64 const char c = *p;
65 if (c >= '0' && c <= '9') {
66 digit = c - '0';
67 } else if (c >= 'a' && c <= 'z') {
68 digit = c - 'a' + 10;
69 } else if (c >= 'A' && c <= 'Z') {
70 digit = c - 'A' + 10;
71 } else {
72 break;
73 }
74 if (digit >= base) break;
75
76 any_converted = true;
77 if (!overflow) {
78 if (result < cutoff || (result == cutoff && digit > -cutlim)) {
79 overflow = true;
80 } else {
81 result = result * base - digit;
82 }
83 }
84 ++p;
85 }
86
87 if (endptr) {
88 *endptr = any_converted ? const_cast<char*>(p) : const_cast<char*>(start_conversion);
89 }
90
91 if (!any_converted) return 0;
92 if (overflow)
93 return (sign > 0) ? numeric_traits<T>::max() : numeric_traits<T>::min();
94
95 if (sign > 0) {
96 if (result == numeric_traits<T>::min())
98 return -result;
99 }
100 return result;
101}
102
103template <typename T, enable_if_t<is_unsigned_v<T>, int> = 0>
104constexpr T str_to_uints(const string_view sv, char** endptr, int base) {
105 const char* start = sv.data();
106 const size_t len = sv.size();
107 const char* end = start + len;
108
109 if (len == 0) {
110 if (endptr) *endptr = const_cast<char*>(start);
111 return 0;
112 }
113
114 const char* p = start;
115 while (p != end && is_space(*p)) ++p;
116 const char* start_conversion = p;
117
118 int sign = 1;
119 if (p != end && *p == '+') {
120 ++p;
121 } else if (p != end && *p == '-') {
122 sign = -1;
123 ++p;
124 }
125
126 if (base != 0 && (base < 2 || base > 36)) {
127 if (endptr) *endptr = const_cast<char*>(start_conversion);
128 return 0;
129 }
130
131 if (base == 0) {
132 if (p != end && *p == '0') {
133 if (p + 1 != end && (*(p + 1) == 'x' || *(p + 1) == 'X')) {
134 base = 16;
135 p += 2;
136 } else {
137 base = 8;
138 }
139 } else {
140 base = 10;
141 }
142 }
143
144 if (base == 16 && p + 1 < end && *p == '0' && (*(p + 1) == 'x' || *(p + 1) == 'X')) {
145 p += 2;
146 }
147
148 const T cutoff = numeric_traits<T>::max() / base;
149 const T cutlim = numeric_traits<T>::max() % base;
150 T result = 0;
151 bool any_converted = false;
152 bool overflow = false;
153
154 while (p != end) {
155 unsigned int digit = 0;
156 const char c = *p;
157 if (c >= '0' && c <= '9') {
158 digit = c - '0';
159 } else if (c >= 'a' && c <= 'z') {
160 digit = c - 'a' + 10;
161 } else if (c >= 'A' && c <= 'Z') {
162 digit = c - 'A' + 10;
163 } else {
164 break;
165 }
166 if (digit >= static_cast<unsigned int>(base)) break;
167
168 any_converted = true;
169 if (!overflow) {
170 if (result > cutoff || (result == cutoff && digit > cutlim)) {
171 overflow = true;
172 } else {
173 result = result * base + digit;
174 }
175 }
176 ++p;
177 }
178
179 if (endptr) {
180 *endptr = any_converted ? const_cast<char*>(p) : const_cast<char*>(start_conversion);
181 }
182
183 if (!any_converted) return 0;
184 if (overflow) return numeric_traits<T>::max();
185
186 if (sign < 0) {
187 // for unsigned, negative sign yields two's complement wrap,
188 // but we follow C standard: strtoul("-1", ...) returns ULLONG_MAX.
189 // So just cast via signed negation then to unsigned.
190 return static_cast<T>(-static_cast<make_signed_t<T>>(result));
191 }
192 return result;
193}
194
195template <typename T>
196MSTL_CONST_FUNCTION constexpr T fast_pow10(int exp) {
197 constexpr T pow10_table[] = {
198 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
199 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
200 1e20, 1e21, 1e22, 1e23, 1e24, 1e25, 1e26, 1e27, 1e28, 1e29,
201 1e30, 1e31, 1e32
202 };
203
204 constexpr T neg_pow10_table[] = {
205 1e0, 1e-1, 1e-2, 1e-3, 1e-4, 1e-5, 1e-6, 1e-7, 1e-8, 1e-9,
206 1e-10, 1e-11, 1e-12, 1e-13, 1e-14, 1e-15, 1e-16, 1e-17, 1e-18, 1e-19,
207 1e-20, 1e-21, 1e-22, 1e-23, 1e-24, 1e-25, 1e-26, 1e-27, 1e-28, 1e-29,
208 1e-30, 1e-31, 1e-32
209 };
210 constexpr int max_table_exp = 32;
211
212 if (exp >= 0 && exp <= max_table_exp) {
213 return pow10_table[exp];
214 }
215 if (exp < 0 && -exp <= max_table_exp) {
216 return neg_pow10_table[-exp];
217 }
218 return static_cast<T>(_MSTL power(10.0, exp));
219}
220
221template <typename T>
222constexpr T str_to_floats(const string_view sv, char** endptr) {
223 const char* start = sv.data();
224 const size_t len = sv.size();
225 const char* end = start + len;
226
227 if (len == 0) {
228 if (endptr) *endptr = const_cast<char*>(start);
229 return static_cast<T>(0);
230 }
231
232 const char* p = start;
233 while (p != end && _MSTL is_space(*p)) ++p;
234 const char* start_conversion = p;
235
236 int sign = 1;
237 if (p != end && *p == '+') {
238 ++p;
239 } else if (p != end && *p == '-') {
240 sign = -1;
241 ++p;
242 }
243
244 const char* p_start = p;
245
246 if (p != end && (p[0] == 'i' || p[0] == 'I')) {
247 if (p + 3 <= end) {
248 const char c1 = p[1], c2 = p[2];
249 if ((c1 == 'n' || c1 == 'N') && (c2 == 'f' || c2 == 'F')) {
250 if (p + 3 == end || !is_alpha_or_digit(p[3])) {
251 p += 3;
252 T inf_val = numeric_traits<T>::infinity();
253 if (endptr) *endptr = const_cast<char*>(p);
254 return (sign < 0) ? -inf_val : inf_val;
255 }
256 }
257 }
258 }
259
260 if (p != end && (p[0] == 'n' || p[0] == 'N')) {
261 if (p + 3 <= end) {
262 const char c1 = p[1], c2 = p[2];
263 if ((c1 == 'a' || c1 == 'A') && (c2 == 'n' || c2 == 'N')) {
264 if (p + 3 == end || !is_alpha_or_digit(p[3])) {
265 p += 3;
266 if (p != end && *p == '(') {
267 ++p;
268 while (p != end && *p != ')') ++p;
269 if (p != end && *p == ')') ++p;
270 }
271 if (endptr) *endptr = const_cast<char*>(p);
273 }
274 }
275 }
276 }
277
278 p = p_start;
279
280 T significand = 0;
281 int exponent = 0;
282 int digits_count = 0;
283 bool has_digits = false;
284
285 while (p != end && *p >= '0' && *p <= '9') {
286 has_digits = true;
287 if (digits_count < numeric_traits<T>::digits10) {
288 significand = significand * 10 + (*p - '0');
289 } else {
290 exponent++;
291 }
292 digits_count++;
293 ++p;
294 }
295
296 if (p != end && *p == '.') {
297 ++p;
298 while (p != end && *p >= '0' && *p <= '9') {
299 has_digits = true;
300 if (digits_count < numeric_traits<T>::digits10) {
301 significand = significand * 10 + (*p - '0');
302 exponent--;
303 }
304 digits_count++;
305 ++p;
306 }
307 }
308
309 if (!has_digits) {
310 if (endptr) *endptr = const_cast<char*>(start_conversion);
311 return static_cast<T>(0);
312 }
313
314 if (p != end && (*p == 'e' || *p == 'E')) {
315 ++p;
316 int exp_sign = 1;
317 if (p != end && *p == '+') {
318 ++p;
319 } else if (p != end && *p == '-') {
320 exp_sign = -1;
321 ++p;
322 }
323
324 if (p != end && *p >= '0' && *p <= '9') {
325 int exp_val = 0;
326 while (p != end && *p >= '0' && *p <= '9') {
327 if (exp_val < 10000) {
328 exp_val = exp_val * 10 + (*p - '0');
329 }
330 ++p;
331 }
332 exponent += exp_sign * exp_val;
333 } else {
334 --p;
335 if (p != start_conversion && (p[-1] == '+' || p[-1] == '-')) --p;
336 }
337 }
338
339 T result = significand;
340
341 if (exponent != 0) {
342 if (exponent > 400) {
343 if (endptr) *endptr = const_cast<char*>(p);
344 return sign * numeric_traits<T>::max();
345 } else if (exponent < -400) {
346 if (endptr) *endptr = const_cast<char*>(p);
347 return T(0);
348 } else {
349 result *= fast_pow10<T>(exponent);
350 }
351 }
352
353 result *= sign;
354 const T inf = numeric_traits<T>::infinity();
355 if (result == inf || result == -inf) {
356 result = sign * numeric_traits<T>::max();
357 }
358
359 if (endptr) *endptr = const_cast<char*>(p);
360 return result;
361}
362
364
365constexpr int64_t strtoll(const string_view sv, char** endptr, const int base) {
366 return _INNER str_to_ints<int64_t>(sv, endptr, base);
367}
368constexpr long strtol(const string_view sv, char** endptr, const int base) {
369 return _INNER str_to_ints<long>(sv, endptr, base);
370}
371
372constexpr uint64_t strtoull(const string_view sv, char** endptr, const int base) {
373 return _INNER str_to_uints<uint64_t>(sv, endptr, base);
374}
375constexpr unsigned long strtoul(const string_view sv, char** endptr, const int base) {
376 return _INNER str_to_uints<unsigned long>(sv, endptr, base);
377}
378
379constexpr float strtof(const string_view sv, char** endptr) {
380 return _INNER str_to_floats<float>(sv, endptr);
381}
382constexpr double strtod(const string_view sv, char** endptr) {
383 return _INNER str_to_floats<double>(sv, endptr);
384}
385constexpr long double strtold(const string_view sv, char** endptr) {
386 return _INNER str_to_floats<long double>(sv, endptr);
387}
388
389
390MSTL_NODISCARD constexpr float32_t
391to_float32(const string_view sv, size_t* idx = nullptr) {
392 char* endptr = nullptr;
393 const float32_t num = _MSTL strtof(sv, &endptr);
394 if (sv.data() == endptr) {
395 throw_exception(typecast_exception("Convert from string failed."));
396 }
397 if (idx) *idx = static_cast<size_t>(endptr - sv.data());
398 return num;
399}
400
401MSTL_NODISCARD constexpr float64_t
402to_float64(const string_view sv, size_t* idx = nullptr) {
403 char* endptr = nullptr;
404 const float64_t num = _MSTL strtod(sv, &endptr);
405 if (sv.data() == endptr) {
406 throw_exception(typecast_exception("Convert from string failed."));
407 }
408 if (idx) *idx = static_cast<size_t>(endptr - sv.data());
409 return num;
410}
411
412MSTL_NODISCARD constexpr decimal_t
413to_decimal(const string_view sv, size_t* idx = nullptr) {
414 char* endptr = nullptr;
415 const decimal_t num = _MSTL strtold(sv, &endptr);
416 if (sv.data() == endptr) {
417 throw_exception(typecast_exception("Convert from string failed."));
418 }
419 if (idx) *idx = static_cast<size_t>(endptr - sv.data());
420 return num;
421}
422
423MSTL_NODISCARD constexpr int64_t
424to_int64(const string_view sv, size_t* idx = nullptr, const int base = 10) {
425 char* endptr = nullptr;
426 const int64_t num = _MSTL strtoll(sv, &endptr, base);
427 if (sv.data() == endptr) {
428 throw_exception(typecast_exception("Convert from string failed."));
429 }
430 if (idx) *idx = static_cast<size_t>(endptr - sv.data());
431 return num;
432}
433
434MSTL_NODISCARD constexpr uint64_t
435to_uint64(const string_view sv, size_t* idx = nullptr, const int base = 10) {
436 char* endptr = nullptr;
437 const uint64_t num = _MSTL strtoull(sv, &endptr, base);
438 if (sv.data() == endptr) {
439 throw_exception(typecast_exception("Convert from string failed."));
440 }
441 if (idx) *idx = static_cast<size_t>(endptr - sv.data());
442 return num;
443}
444
445MSTL_NODISCARD constexpr int32_t
446to_int32(const string_view sv, size_t* idx = nullptr, const int base = 10) {
447 char* endptr = nullptr;
448 const int32_t num = _MSTL strtol(sv, &endptr, base);
449 if (sv.data() == endptr) {
450 throw_exception(typecast_exception("Convert from string failed."));
451 }
452 if (idx) *idx = static_cast<size_t>(endptr - sv.data());
453 return num;
454}
455
456MSTL_NODISCARD constexpr uint32_t
457to_uint32(const string_view sv, size_t* idx = nullptr, const int base = 10) {
458 char* endptr = nullptr;
459 const uint32_t num = _MSTL strtoul(sv, &endptr, base);
460 if (sv.data() == endptr) {
461 throw_exception(typecast_exception("Convert from string failed."));
462 }
463 if (idx) *idx = static_cast<size_t>(endptr - sv.data());
464 return num;
465}
466
467MSTL_NODISCARD constexpr int16_t
468to_int16(const string_view sv, size_t* idx = nullptr, const int base = 10) {
469 return static_cast<int16_t>(to_int32(sv, idx, base));
470}
471
472MSTL_NODISCARD constexpr uint16_t
473to_uint16(const string_view sv, size_t* idx = nullptr, const int base = 10) {
474 return static_cast<uint16_t>(to_uint32(sv, idx, base));
475}
476
477MSTL_NODISCARD constexpr int8_t
478to_int8(const string_view sv, size_t* idx = nullptr, const int base = 10) {
479 return static_cast<int8_t>(to_int32(sv, idx, base));
480}
481
482MSTL_NODISCARD constexpr uint8_t
483to_uint8(const string_view sv, size_t* idx = nullptr, const int base = 10) {
484 return static_cast<uint8_t>(to_uint32(sv, idx, base));
485}
486
488
489#endif // MSTL_CORE_STRING_TO_NUMERICS_HPP__
数值类型极限特性主模板
static MSTL_NODISCARD constexpr T infinity() noexcept
获取正无穷大表示
static MSTL_NODISCARD constexpr T quiet_nan() noexcept
获取安静nan表示
static MSTL_NODISCARD constexpr T min() noexcept
获取类型的最小值
static MSTL_NODISCARD constexpr T max() noexcept
获取类型的最大值
MSTL异常处理框架
MSTL_PURE_FUNCTION MSTL_CONSTEXPR14 bool is_space(const CharT c) noexcept
检查字符是否为空白字符
MSTL_CONST_FUNCTION MSTL_CONSTEXPR14 bool is_alpha_or_digit(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位有符号整数类型
MSTL_CONSTEXPR14 int sign(const T &value) noexcept
获取数值的符号
MSTL_CONST_FUNCTION MSTL_CONSTEXPR14 T power(const T &x, uint32_t n) noexcept
幂运算
#define _MSTL
全局命名空间MSTL前缀
#define MSTL_END_INNER__
结束inner命名空间
#define _INNER
inner命名空间前缀
#define MSTL_END_NAMESPACE__
结束全局命名空间MSTL
#define MSTL_BEGIN_NAMESPACE__
开始全局命名空间MSTL
#define MSTL_BEGIN_INNER__
开始inner命名空间
typename make_signed< T >::type make_signed_t
make_signed的便捷别名
MSTL_NODISCARD MSTL_ALWAYS_INLINE constexpr decltype(auto) end(Container &cont) noexcept(noexcept(cont.end()))
获取容器的结束迭代器
MSTL数学函数库
类型转换异常