Photon microGUI widgets library 0.6.0
string.hpp
1#ifndef _STDEX_STRING_H
2#define _STDEX_STRING_H
3
4#if _MSC_VER > 1000
5#pragma once
6#endif // _MSC_VER > 1000
7
8// stdex includes
9#include "./core.h"
10#include "./type_traits.hpp"
11#include "./sstream.hpp"
12#include "./cstdint.hpp"
13
14// POSIX includes
15/*none*/
16
17// std includes
18#include <cstring>
19#include <cctype>
20#include <cstdlib>
21#include <cstdio>
22
23#include <iostream>
24#include <string>
25#include <climits>
26#include <cfloat>
27#include <stdexcept>
28#include <cmath>
29#include <errno.h>
30#include <limits>
31#include <cwchar>
32#include <cwctype>
33#include <cstddef> // std::size_t
34#include <iomanip> // std::setbase
35
36namespace stdex
37{
38 namespace cstddef
39 {
40 typedef std::size_t size_t;
41 }
42
43 using std::basic_string;
44 using std::char_traits;
45
46 using std::string;
47 using std::wstring;
48
49 namespace detail
50 {
51 namespace string_detail
52 {
53 namespace std_cpp11
54 {
55 namespace std_dummy
56 {
57 void strtoll(); // dummy
58 void wcstoll(); // dummy
59 void strtoull(); // dummy
60 void wcstoull(); // dummy
61 void strtold(); // dummy
62 void wcstold(); // dummy
63 float swprintf(...);
64 float snprintf(...);
65 }
66 using namespace std;
67 using namespace std_dummy;
68 }
69
70 typedef char _yes_type;
71 struct _no_type
72 {
73 char padding[8];
74 };
75
76#if defined(LLONG_MIN) || defined(LLONG_MAX)
77 typedef long long _long_long_type;
78 typedef unsigned long long _unsigned_long_long_type;
79#else
80 typedef long _long_long_type;
81 typedef unsigned long _unsigned_long_long_type;
82#endif
83
84
85 typedef _long_long_type(*_strtoll_type)(const char*, char**, int);
86
87 _yes_type _strtoll_tester(_strtoll_type);
88 _no_type _strtoll_tester(...);
89
90 typedef _long_long_type(*_wcstoll_type)(const wchar_t*, wchar_t**, int);
91
92 _yes_type _wcstoll_tester(_wcstoll_type);
93 _no_type _wcstoll_tester(...);
94
95 typedef _unsigned_long_long_type(*_strtoull_type)(const char*, char**, int);
96
97 _yes_type _strtoull_tester(_strtoull_type);
98 _no_type _strtoull_tester(...);
99
100 typedef _unsigned_long_long_type(*_wcstoull_type)(const wchar_t*, wchar_t**, int);
101
102 _yes_type _wcstoull_tester(_wcstoull_type);
103 _no_type _wcstoull_tester(...);
104
105 typedef long double(*_strtold_type)(const char*, char**);
106
107 _yes_type _strtold_tester(_strtold_type);
108 _no_type _strtold_tester(...);
109
110 typedef long double(*_wcstold_type)(const wchar_t*, wchar_t**);
111
112 _yes_type _wcstold_tester(_wcstold_type);
113 _no_type _wcstold_tester(...);
114
115
116 using std_cpp11::strtoll;
117 using std_cpp11::wcstoll;
118 using std_cpp11::strtoull;
119 using std_cpp11::wcstoull;
120 using std_cpp11::strtold;
121 using std_cpp11::wcstold;
122
123
124 struct _strtoll_present
125 {
126 static const bool value = sizeof(_strtoll_tester(&strtoll)) == sizeof(_yes_type);
127 };
128
129 struct _wcstoll_present
130 {
131 static const bool value = sizeof(_wcstoll_tester(&wcstoll)) == sizeof(_yes_type);
132 };
133
134 struct _strtoull_present
135 {
136 static const bool value = sizeof(_strtoull_tester(&strtoull)) == sizeof(_yes_type);
137 };
138
139 struct _wcstoull_present
140 {
141 static const bool value = sizeof(_wcstoull_tester(&wcstoull)) == sizeof(_yes_type);
142 };
143
144 struct _strtold_present
145 {
146 static const bool value = sizeof(_strtold_tester(&strtold)) == sizeof(_yes_type);
147 };
148
149 struct _wcstold_present
150 {
151 static const bool value = sizeof(_wcstold_tester(&wcstold)) == sizeof(_yes_type);
152 };
153
154 using std_cpp11::swprintf;
155
156 _yes_type _has_4arg_swprintf_tester(int);
157 _no_type _has_4arg_swprintf_tester(float);
158
159 struct _has_4arg_swprintf
160 {
161 static const bool value =
162 sizeof(_has_4arg_swprintf_tester(swprintf(_declptr<wchar_t>(), 42, _declptr<wchar_t>(), 0 ))) == sizeof(_yes_type);
163 };
164
165 using std_cpp11::snprintf;
166
167 _yes_type _has_4arg_snprintf_tester(int);
168 _no_type _has_4arg_snprintf_tester(float);
169
170 struct _has_4arg_snprintf
171 {
172 static const bool value =
173 sizeof(_has_4arg_snprintf_tester(
174 snprintf(_declptr<char>(), *_declptr<std::size_t>(), _declptr<const char>(), 0 )
175 )) == sizeof(_yes_type);
176 };
177
178 }
179
180 template<bool _IsSigned>
181 struct _str_to_integral_chooser_impl
182 {
183 typedef long int type;
184 static long int call(const char* str, char** endptr, int base)
185 {
186 using namespace std;
187
188 if(!str)
189 return 0;
190 errno = 0;
191
192 long int value = strtol(str, endptr, base);
193
194 // for some reason (errno thread-safety issue in pre-C++11 perhaps)
195 // some compilers do not set errno to ERANGE if
196 // str points to value too big for long int
197 // so we have to manualy check this case to disinguish between strings
198 // like LONG_MAX_STRING and SOME_REALLY_BIG_NUMBER_STRING
199 if(errno == 0 && _str_to_integral_chooser_impl::check(value))
200 {
201 ptrdiff_t length =
202 endptr ? (*endptr - str) : (str - str + strlen(str));
203 string positive_str(str, str + length);
204 bool is_negative = (value == LONG_MIN);
205
206 if(is_negative)
207 positive_str.replace(positive_str.find_first_of('-'), 1, 1, '+');
208
209 unsigned long int uvalue = strtoul(positive_str.c_str(), NULL, base);
210 unsigned long int _zero = 0;
211
212 if(errno == 0 && uvalue > static_cast<unsigned long int>(is_negative ? _zero - (numeric_limits<long int>::min)() : (numeric_limits<long int>::max)() ))
213 errno = ERANGE;// using errno is bad - m'kay?
214 }
215
216 if (errno && !value && endptr)
217 {
218 for (const char *it = str; it != *endptr; it++)
219 {
220 if (isdigit(*it) && *it != '0')
221 {
222 return LONG_MAX;
223 }
224 }
225 }
226
227 return value;
228 }
229
230 static long int call(const wchar_t* str, wchar_t** endptr, int base)
231 {
232 using namespace std;
233
234 if(!str)
235 return 0;
236 errno = 0;
237
238 long int value = wcstol(str, endptr, base);
239
240 // for some reason (errno thread-safety issue in pre-C++11 perhaps)
241 // some compilers do not set errno to ERANGE if
242 // str points to value too big for long int
243 // so we have to manualy check this case to disinguish between strings
244 // like LONG_MAX_STRING and SOME_REALLY_BIG_NUMBER_STRING
245 if(errno == 0 && _str_to_integral_chooser_impl::check(value))
246 {
247 ptrdiff_t length =
248 endptr ? (*endptr - str) : (str - str + wcslen(str));
249 wstring positive_str(str, str + length);
250 bool is_negative = (value == LONG_MIN);
251
252 if(is_negative)
253 positive_str.replace(positive_str.find_first_of(L'-'), 1, 1, L'+');
254
255 unsigned long int uvalue = wcstoul(positive_str.c_str(), NULL, base);
256 unsigned long int _zero = 0;
257
258 if(errno == 0 && uvalue > static_cast<unsigned long int>(is_negative ? _zero - (numeric_limits<long int>::min)() : (numeric_limits<long int>::max)() ))
259 errno = ERANGE;// using errno is bad - m'kay?
260 }
261
262 if (errno && !value && endptr)
263 {
264 for (const wchar_t *it = str; it != *endptr; it++)
265 {
266 if (iswdigit(*it) && *it != L'0')
267 {
268 return LONG_MAX;
269 }
270 }
271 }
272
273 return value;
274 }
275
276 static bool check(long int _value)
277 {
278#ifdef LONG_MAX
279#ifdef LONG_MIN
280 return ((_value == LONG_MAX || _value == LONG_MIN));
281#else
282 return ((_value == LONG_MAX || _value == -LONG_MAX));
283#endif
284#else
285#ifdef LONG_MIN
286 return ((_value == -LONG_MIN || _value == LONG_MIN));
287#else
288 return ((_value == (std::numeric_limits<long int>::min)() || _value == (std::numeric_limits<long int>::max)()));
289#endif
290#endif
291 }
292 };
293
294 template<bool>
295 struct _snprintf_impl
296 {
297 template<class _ArgT>
298 static int call(char* buffer, std::size_t buf_size, const char* format, _ArgT arg)
299 {
300 using namespace std;
301 return snprintf(buffer, buf_size, format, arg);
302 }
303 };
304
305 template<>
306 struct _snprintf_impl<false>
307 {
308 template<class _ArgT>
309 static int call(char* buffer, std::size_t, const char* format, _ArgT arg)
310 {
311 using namespace std;
312 return sprintf(buffer, format, arg);
313 }
314 };
315
316 template<class _ArgT>
317 inline
318 void _snprintf4_std_impl(char* buffer, std::size_t len, const char* format, _ArgT arg)
319 {
320 _snprintf_impl<string_detail::_has_4arg_snprintf::value>::call(buffer, len, format, arg);
321 }
322
323 template<>
324 struct _str_to_integral_chooser_impl<false>
325 {
326 typedef unsigned long int type;
327 static unsigned long int call(const char* str, char** endptr, int base)
328 {
329 using namespace std;
330
331 if(!str)
332 return 0;
333 errno = 0;
334
335 unsigned long int value = strtoul(str, endptr, base);
336
337 // same compiler bugs (see implementation for signed types)
338 // but there is the problem -
339 // we do not have conversion function for type bigger then unsigned long long
340 // so we can do one of two evil things:
341 // 1. ignore strings with actual ULONG_MAX values and
342 // act as standard requires in all other cases
343 // 2. assume that if errno behaves naughty
344 // all values larger than ULONG_MAX are valid ULONG_MAX
345 // first option seems like lesser evil so...
346 if(errno == 0 && _str_to_integral_chooser_impl::check(value))
347 {
348 // the best we can do is check if compiler has bug:
349 bool bug_present = true;
350#ifdef ULONG_MAX
351 string ulong_max_str;
352 {
353 char buf[512] = {0};
354 _snprintf4_std_impl(buf, sizeof(buf), "%lu", ULONG_MAX);
355
356 stringstream ss;
357 ss << setbase(base) << ULONG_MAX;
358 if(std::string(str) == ss.str())
359 return value;
360
361 ulong_max_str = string(buf);
362 }
363 const char *ulong_max_cstr = ulong_max_str.c_str();
364
365 string overflow_str(ulong_max_str.length() + 1, '0');
366 string::size_type of_size = overflow_str.length();
367
368 if(
369 (ulong_max_cstr[of_size - 2] == 'L' && ulong_max_cstr[of_size - 3] == 'U') ||
370 (ulong_max_cstr[of_size - 3] == 'L' && ulong_max_cstr[of_size - 2] == 'U')
371 )
372 {
373 memcpy(&overflow_str[0], ulong_max_cstr, of_size - 3);
374 overflow_str[of_size - 2] = 'U';
375 overflow_str[of_size - 1] = 'L';
376 }
377 else
378 {
379 memcpy(&overflow_str[0], ulong_max_cstr, of_size - 1);
380 }
381
382 unsigned long overflow_value = strtoul(overflow_str.c_str(), NULL, 10);
383
384 if(overflow_value == ULONG_MAX && errno == ERANGE)
385 bug_present = false;
386#endif
387 if(bug_present) errno = ERANGE;
388 else errno = 0;
389 }
390
391 return value;
392 }
393
394 static unsigned long int call(const wchar_t* str, wchar_t** endptr, int base)
395 {
396 using namespace std;
397
398 if(!str)
399 return 0;
400 errno = 0;
401
402 unsigned long int value = wcstoul(str, endptr, base);
403
404 // same compiler bugs (see implementation for signed types)
405 // but there is the problem -
406 // we do not have conversion function for type bigger then unsigned long long
407 // so we can do one of two evil things:
408 // 1. ignore strings with actual ULONG_MAX values and
409 // act as standard requires in all other cases
410 // 2. assume that if errno behaves naughty
411 // all values larger than ULONG_MAX are valid ULONG_MAX
412 // first option seems like lesser evil so...
413 if(errno == 0 && _str_to_integral_chooser_impl::check(value))
414 {
415 // the best we can do is check if compiler has bug:
416 bool bug_present = true;
417#ifdef ULONG_MAX
418 wstring ulong_max_str;
419 {
420 stringstream ss;
421 ss << setbase(base) << ULONG_MAX;
422 string ulong_max_str_base = ss.str();
423
424 if(wstring(str) == wstring(ulong_max_str_base.c_str(), ulong_max_str_base.c_str() + ulong_max_str_base.length()))
425 return value;
426
427 char buf[512] = {0};
428 _snprintf4_std_impl(buf, sizeof(buf), "%lu", ULONG_MAX);
429
430 wstring::size_type length = strlen(buf);
431
432 ulong_max_str = wstring(&buf[0], &buf[length]); // not so bright but will work
433 }
434 const wchar_t *ulong_max_cstr = ulong_max_str.c_str();
435
436 wstring overflow_str(ulong_max_str.length() + 1, L'0');
437 wstring::size_type of_size = overflow_str.length();
438
439 if(
440 (ulong_max_cstr[of_size - 2] == L'L' && ulong_max_cstr[of_size - 3] == L'U') ||
441 (ulong_max_cstr[of_size - 3] == L'L' && ulong_max_cstr[of_size - 2] == L'U')
442 )
443 {
444 memcpy(&overflow_str[0], ulong_max_cstr, (of_size - 3) * sizeof(wchar_t));
445 overflow_str[of_size - 2] = L'U';
446 overflow_str[of_size - 1] = L'L';
447 }
448 else
449 {
450 memcpy(&overflow_str[0], ulong_max_cstr, (of_size - 1) * sizeof(wchar_t));
451 }
452
453 unsigned long overflow_value = wcstoul(overflow_str.c_str(), NULL, 10);
454
455 if(overflow_value == ULONG_MAX && errno == ERANGE)
456 bug_present = false;
457#endif
458 if(bug_present) errno = ERANGE;
459 else errno = 0;
460 }
461
462 return value;
463 }
464
465 static bool check(unsigned long int _value)
466 {
467#ifdef ULONG_MAX
468 return ((_value == ULONG_MAX));
469#else
470 return ((_value == (std::numeric_limits<unsigned long int>::max)()));
471#endif
472 }
473 };
474
475 template<class _Tp>
476 struct _str_to_integral_chooser
477 {
478 typedef _str_to_integral_chooser_impl<is_signed<_Tp>::value> impl;
479 };
480
481 template<class _Tp, unsigned long _N>
482 struct _type_cs_len
483 {
484 enum
485 {
486 value = _type_cs_len<_Tp, _N / (unsigned long)(10)>::value + 1
487 };
488 };
489
490 template<class _Tp>
491 struct _type_cs_len<_Tp, 0>
492 {
493 enum
494 {
495 value = 1
496 };
497 };
498
499 template<class _Tp, bool _HasQuietNaN, bool _HasSignalingNaN>
500 struct _not_a_number_impl
501 {
502 static _Tp NaN() { return std::numeric_limits<_Tp>::quiet_NaN();}
503 };
504
505 template<class _Tp>
506 struct _not_a_number_impl<_Tp, false, true>
507 {
508 static _Tp NaN() { return std::numeric_limits<_Tp>::signaling_NaN(); }
509 };
510
511 template<class _Tp>
512 struct _not_a_number_impl<_Tp, false, false>
513 {
514 static _Tp NaN() { typedef _Tp type; return type(); }
515 };
516
517 template<class _Tp>
518 struct _not_a_number
519 {
520 typedef _not_a_number_impl<_Tp, std::numeric_limits<_Tp>::has_quiet_NaN, std::numeric_limits<_Tp>::has_signaling_NaN> impl;
521 };
522
523 template<class _Tp, bool _HasInfinity>
524 struct _infinity_impl
525 {
526 static _Tp inf() { return std::numeric_limits<_Tp>::infinity(); }
527 };
528
529 template<class _Tp>
530 struct _infinity_impl<_Tp, false>
531 {
532 static _Tp inf() { return (std::numeric_limits<_Tp>::max)(); }
533 };
534
535 template<class _Tp>
536 struct _infinity
537 {
538 typedef _infinity_impl<_Tp, std::numeric_limits<_Tp>::has_infinity> impl;
539 };
540
541#if defined(LLONG_MAX) || defined(LLONG_MIN)
542
543 template<bool>
544 struct _cs_to_signed_ll
545 {
546 static
547 string_detail::_long_long_type
548 call(const char *nptr, char **endptr, int base)
549 {
550 using namespace std;
551 const char *_s = nptr;
552 string_detail::_unsigned_long_long_type acc;
553 int _c;
554 string_detail::_unsigned_long_long_type cutoff;
555 int neg = 0, any, cutlim;
556
557 /*
558 * Skip white space and pick up leading +/- sign if any.
559 * If base is 0, allow 0x for hex and 0 for octal, else
560 * assume decimal; if base is already 16, allow 0x.
561 */
562 do {
563 _c = *_s++;
564 } while (isspace(_c));
565 if (_c == '-') {
566 neg = 1;
567 _c = *_s++;
568 }
569 else if (_c == '+')
570 _c = *_s++;
571 if ((base == 0 || base == 16) &&
572 _c == '0' && (*_s == 'x' || *_s == 'X')) {
573 _c = _s[1];
574 _s += 2;
575 base = 16;
576 }
577 if (base == 0)
578 base = _c == '0' ? 8 : 10;
579
580 /*
581 * Compute the cutoff value between legal numbers and illegal
582 * numbers. That is the largest legal value, divided by the
583 * base. An input number that is greater than this value, if
584 * followed by a legal input character, is too big. One that
585 * is equal to this value may be valid or not; the limit
586 * between valid and invalid numbers is then based on the last
587 * digit. For instance, if the range for longs is
588 * [-2147483648..2147483647] and the input base is 10,
589 * cutoff will be set to 214748364 and cutlim to either
590 * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated
591 * a value > 214748364, or equal but the next digit is > 7 (or 8),
592 * the number is too big, and we will return a range error.
593 *
594 * Set any if any `digits' consumed; make it negative to indicate
595 * overflow.
596 */
597 cutoff = neg ? LLONG_MIN : LLONG_MAX;
598 cutlim = cutoff % (string_detail::_unsigned_long_long_type) base;
599 cutoff /= (string_detail::_unsigned_long_long_type) base;
600 for (acc = 0, any = 0;; _c = *_s++) {
601 if (isdigit(_c))
602 _c -= '0';
603 else if (isalpha(_c))
604 _c -= isupper(_c) ? 'A' - 10 : 'a' - 10;
605 else
606 break;
607 if (_c >= base)
608 break;
609 if (any < 0 || acc > cutoff || (acc == cutoff && _c > cutlim))
610 any = -1;
611 else {
612 any = 1;
613 acc *= base;
614 acc += _c;
615 }
616 }
617 if (any < 0) {
618 acc = neg ? LLONG_MIN : LLONG_MAX;
619 errno = ERANGE;
620 }
621 else if (neg)
622 acc = static_cast<string_detail::_unsigned_long_long_type>(static_cast<string_detail::_unsigned_long_long_type >(0) - acc);
623 if (endptr != 0)
624 *endptr = (char *) (any ? _s - 1 : nptr);
625 return (acc);
626 }
627 };
628
629 template<>
630 struct _cs_to_signed_ll<true>
631 {
632 template<class _Tp>
633 static
634 string_detail::_long_long_type
635 call(const _Tp *nptr, char **endptr, int base)
636 {
637 using namespace std;
638
639 errno = 0;
640 string_detail::_long_long_type value = strtoll(nptr, endptr, base);
641
642 if (errno && !value)
643 {
644 return _cs_to_signed_ll<false>::call(nptr, endptr, base);
645 }
646
647 return value;
648 }
649 };
650
651 template<bool>
652 struct _wcs_to_signed_ll
653 {
654 static
655 string_detail::_long_long_type
656 call(const wchar_t *nptr, wchar_t **endptr, int base)
657 {
658 using namespace std;
659 const wchar_t *_s = nptr;
660 string_detail::_unsigned_long_long_type acc;
661 int _c;
662 string_detail::_unsigned_long_long_type cutoff;
663 int neg = 0, any, cutlim;
664
665 (void)&acc; (void)&cutoff;
666
667 /*
668 * Skip white space and pick up leading +/- sign if any.
669 * If base is 0, allow 0x for hex and 0 for octal, else
670 * assume decimal; if base is already 16, allow 0x.
671 */
672 _s = nptr;
673
674 do {
675 _c = *_s++;
676 } while (isspace(_c));
677 if (_c == L'-') {
678 neg = 1;
679 _c = *_s++;
680 }
681 else if (_c == L'+')
682 _c = *_s++;
683 if ((base == 0 || base == 16) &&
684 _c == L'0' && (*_s == L'x' || *_s == L'X')) {
685 _c = _s[1];
686 _s += 2;
687 base = 16;
688 }
689 if (base == 0)
690 base = _c == L'0' ? 8 : 10;
691
692 /*
693 * Compute the cutoff value between legal numbers and illegal
694 * numbers. That is the largest legal value, divided by the
695 * base. An input number that is greater than this value, if
696 * followed by a legal input character, is too big. One that
697 * is equal to this value may be valid or not; the limit
698 * between valid and invalid numbers is then based on the last
699 * digit. For instance, if the range for longs is
700 * [-2147483648..2147483647] and the input base is 10,
701 * cutoff will be set to 214748364 and cutlim to either
702 * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated
703 * a value > 214748364, or equal but the next digit is > 7 (or 8),
704 * the number is too big, and we will return a range error.
705 *
706 * Set any if any `digits' consumed; make it negative to indicate
707 * overflow.
708 */
709 cutoff = neg ? LLONG_MIN : LLONG_MAX;
710 cutlim = (int)(cutoff % base);
711 cutoff /= (string_detail::_unsigned_long_long_type) base;
712 for (acc = 0, any = 0;; _c = *_s++) {
713 if (isdigit(_c))
714 _c -= L'0';
715 else if (isalpha(_c))
716 _c -= isupper(_c) ? L'A' - 10 : L'a' - 10;
717 else
718 break;
719 if (_c >= base)
720 break;
721 if (any < 0 || acc > cutoff || (acc == cutoff && _c > cutlim))
722 any = -1;
723 else {
724 any = 1;
725 acc *= base;
726 acc += _c;
727 }
728 }
729 if (any < 0) {
730 acc = neg ? LLONG_MIN : LLONG_MAX;
731 errno = ERANGE;
732 }
733 else if (neg)
734 acc = static_cast<string_detail::_unsigned_long_long_type>(static_cast<string_detail::_unsigned_long_long_type >(0) - acc);
735 if (endptr != 0)
736 *endptr = (wchar_t *) (any ? _s - 1 : nptr);
737 return (acc);
738 }
739 };
740
741 template<>
742 struct _wcs_to_signed_ll<true>
743 {
744 template<class _Tp>
745 static
746 string_detail::_long_long_type
747 call(const _Tp *nptr, wchar_t **endptr, int base)
748 {
749 using namespace std;
750
751 errno = 0;
752 string_detail::_long_long_type value = wcstoll(nptr, endptr, base);
753
754 if (errno && !value)
755 {
756 return _wcs_to_signed_ll<false>::call(nptr, endptr, base);
757 }
758
759 return value;
760 }
761 };
762
763 template<bool>
764 struct _cs_to_unsigned_ll
765 {
766 static
767 string_detail::_unsigned_long_long_type
768 call(const char *nptr, char **endptr, int base)
769 {
770 using namespace std;
771 const char *_s = nptr;
772 string_detail::_unsigned_long_long_type acc;
773 int _c;
774 string_detail::_unsigned_long_long_type cutoff;
775 int neg = 0, any, cutlim;
776
777 /*
778 * See strtol for comments as to the logic used.
779 */
780 do {
781 _c = *_s++;
782 } while (isspace(_c));
783 if (_c == '-') {
784 neg = 1;
785 _c = *_s++;
786 }
787 else if (_c == '+')
788 _c = *_s++;
789 if ((base == 0 || base == 16) &&
790 _c == '0' && (*_s == 'x' || *_s == 'X')) {
791 _c = _s[1];
792 _s += 2;
793 base = 16;
794 }
795 if (base == 0)
796 base = _c == '0' ? 8 : 10;
797 cutoff = (string_detail::_unsigned_long_long_type) ULLONG_MAX / (string_detail::_unsigned_long_long_type) base;
798 cutlim = (string_detail::_unsigned_long_long_type) ULLONG_MAX % (string_detail::_unsigned_long_long_type) base;
799 for (acc = 0, any = 0;; _c = *_s++) {
800 if (isdigit(_c))
801 _c -= '0';
802 else if (isalpha(_c))
803 _c -= isupper(_c) ? 'A' - 10 : 'a' - 10;
804 else
805 break;
806 if (_c >= base)
807 break;
808 if (any < 0 || acc > cutoff || (acc == cutoff && _c > cutlim))
809 any = -1;
810 else {
811 any = 1;
812 acc *= base;
813 acc += _c;
814 }
815 }
816 if (any < 0) {
817 acc = ULLONG_MAX;
818 errno = ERANGE;
819 }
820 else if (neg)
821 acc = static_cast<string_detail::_unsigned_long_long_type >(static_cast<string_detail::_unsigned_long_long_type >(0) - acc);
822 if (endptr != 0)
823 *endptr = (char *) (any ? _s - 1 : nptr);
824 return (acc);
825 }
826 };
827
828 template<>
829 struct _cs_to_unsigned_ll<true>
830 {
831 template<class _Tp>
832 static
833 string_detail::_unsigned_long_long_type
834 call(const _Tp *nptr, char **endptr, int base)
835 {
836 using namespace std;
837
838 return strtoull(nptr, endptr, base);
839 }
840 };
841
842 template<bool>
843 struct _wcs_to_unsigned_ll
844 {
845 static
846 string_detail::_unsigned_long_long_type
847 call(const wchar_t *nptr, wchar_t **endptr, int base)
848 {
849 using namespace std;
850 const wchar_t *_s = nptr;
851 string_detail::_unsigned_long_long_type acc;
852 int _c;
853 string_detail::_unsigned_long_long_type cutoff;
854 int neg = 0, any, cutlim;
855
856 /*
857 * See strtol for comments as to the logic used.
858 */
859 do {
860 _c = *_s++;
861 } while (isspace(_c));
862 if (_c == L'-') {
863 neg = 1;
864 _c = *_s++;
865 }
866 else if (_c == L'+')
867 _c = *_s++;
868 if ((base == 0 || base == 16) &&
869 _c == L'0' && (*_s == L'x' || *_s == L'X')) {
870 _c = _s[1];
871 _s += 2;
872 base = 16;
873 }
874 if (base == 0)
875 base = _c == '0' ? 8 : 10;
876 cutoff = (string_detail::_unsigned_long_long_type) ULLONG_MAX / (string_detail::_unsigned_long_long_type) base;
877 cutlim = (string_detail::_unsigned_long_long_type) ULLONG_MAX % (string_detail::_unsigned_long_long_type) base;
878 for (acc = 0, any = 0;; _c = *_s++) {
879 if (isdigit(_c))
880 _c -= L'0';
881 else if (isalpha(_c))
882 _c -= isupper(_c) ? L'A' - 10 : L'a' - 10;
883 else
884 break;
885 if (_c >= base)
886 break;
887 if (any < 0 || acc > cutoff || (acc == cutoff && _c > cutlim))
888 any = -1;
889 else {
890 any = 1;
891 acc *= base;
892 acc += _c;
893 }
894 }
895 if (any < 0) {
896 acc = ULLONG_MAX;
897 errno = ERANGE;
898 }
899 else if (neg)
900 acc = static_cast<string_detail::_unsigned_long_long_type >(static_cast<string_detail::_unsigned_long_long_type >(0) - acc);
901 if (endptr != 0)
902 *endptr = (wchar_t *) (any ? _s - 1 : nptr);
903 return (acc);
904 }
905
906 };
907
908 template<>
909 struct _wcs_to_unsigned_ll<true>
910 {
911 template<class _Tp>
912 static
913 string_detail::_unsigned_long_long_type
914 call(const _Tp *nptr, wchar_t **endptr, int base)
915 {
916 using namespace std;
917
918 return wcstoull(nptr, endptr, base);
919 }
920 };
921
922
923 template<bool _IsSigned>
924 struct _str_to_integral_chooser_impl_ll
925 {
926 typedef string_detail::_long_long_type type;
927 static string_detail::_long_long_type call(const char* _str, char** endptr, int base)
928 {
929 typedef _cs_to_signed_ll<string_detail::_strtoll_present::value> impl;
930
931 return impl::call(_str, endptr, base);
932 }
933
934 static string_detail::_long_long_type call(const wchar_t* _str, wchar_t** endptr, int base)
935 {
936 typedef _wcs_to_signed_ll<string_detail::_wcstoll_present::value> impl;
937
938 return impl::call(_str, endptr, base);
939 }
940
941 static bool check(const string_detail::_long_long_type &_value)
942 {
943#ifdef LLONG_MAX
944#ifdef LLONG_MIN
945 return ((_value == LLONG_MAX || _value == LLONG_MIN));
946#else
947 return ((_value == LLONG_MAX || _value == -LLONG_MAX));
948#endif
949#else
950#ifdef LLONG_MIN
951 return ((_value == -LLONG_MIN || _value == LLONG_MIN));
952#else
953 return ((_value == (std::numeric_limits<string_detail::_long_long_type>::min)() || _value == (std::numeric_limits<string_detail::_long_long_type>::max)()));
954#endif
955#endif
956 }
957 };
958
959 template<>
960 struct _str_to_integral_chooser_impl_ll<false>
961 {
962 typedef string_detail::_unsigned_long_long_type type;
963 static string_detail::_unsigned_long_long_type call(const char* _str, char** endptr, int base)
964 {
965 typedef _cs_to_unsigned_ll<string_detail::_strtoull_present::value> impl;
966
967 return impl::call(_str, endptr, base);
968 }
969
970 static string_detail::_unsigned_long_long_type call(const wchar_t* _str, wchar_t** endptr, int base)
971 {
972 typedef _wcs_to_unsigned_ll<string_detail::_wcstoull_present::value> impl;
973
974 return impl::call(_str, endptr, base);
975 }
976
977 static bool check(const string_detail::_unsigned_long_long_type &_value)
978 {
979#ifdef ULLONG_MAX
980 return ((_value == ULLONG_MAX));
981#else
982 return ((_value == (std::numeric_limits<string_detail::_unsigned_long_long_type>::max)()));
983#endif
984 }
985 };
986
987 template<class _Tp>
988 struct _str_to_integral_chooser_ll
989 {
990 typedef _str_to_integral_chooser_impl_ll<is_signed<_Tp>::value> impl;
991 };
992
993 template<class _Tp, string_detail::_unsigned_long_long_type _N>
994 struct _type_cs_len_ll
995 {
996 enum
997 {
998 value = _type_cs_len_ll<_Tp, _N / (string_detail::_unsigned_long_long_type)(10)>::value + 1
999 };
1000 };
1001
1002 template<class _Tp>
1003 struct _type_cs_len_ll<_Tp, 0>
1004 {
1005 enum
1006 {
1007 value = 2
1008 };
1009 };
1010#endif
1011
1012
1013 template <class _Tp>
1014 inline _Tp _cs_to_integral(const char *_str, const char *&num_s_end, int base = 10)
1015 {
1016 typedef typename _str_to_integral_chooser<_Tp>::impl _str_to_integral;
1017
1018 int last_errno = errno;
1019 errno = 0;
1020 char *endptr = 0;
1021 typedef typename _str_to_integral::type large_value_type;
1022 large_value_type _value = _str_to_integral::call(_str, &endptr, base);
1023
1024 if (_str_to_integral::check(_value) && errno == ERANGE)
1025 num_s_end = 0;
1026 else if (_value > static_cast<large_value_type>((std::numeric_limits<_Tp>::max)()) || _value < static_cast<large_value_type>((std::numeric_limits<_Tp>::min)()))
1027 {
1028 _value = (std::numeric_limits<_Tp>::max)();
1029 num_s_end = 0;
1030 }
1031 else
1032 num_s_end = endptr;
1033
1034 if (errno != last_errno)
1035 errno = last_errno;
1036
1037 return _value;
1038 }
1039
1040 template <class _Tp>
1041 inline _Tp _cs_to_integral(const wchar_t *_str, const wchar_t *&num_s_end, int base = 10)
1042 {
1043 typedef typename _str_to_integral_chooser<_Tp>::impl _str_to_integral;
1044
1045 int last_errno = errno;
1046 errno = 0;
1047 wchar_t *endptr = 0;
1048 typedef typename _str_to_integral::type large_value_type;
1049 large_value_type _value = _str_to_integral::call(_str, &endptr, base);
1050
1051 if (_str_to_integral::check(_value) && errno == ERANGE)
1052 num_s_end = 0;
1053 else if (_value > static_cast<large_value_type>((std::numeric_limits<_Tp>::max)()) || _value < static_cast<large_value_type>((std::numeric_limits<_Tp>::min)()))
1054 {
1055 _value = (std::numeric_limits<_Tp>::max)();
1056 num_s_end = 0;
1057 }
1058 else
1059 num_s_end = endptr;
1060
1061 if (errno != last_errno)
1062 errno = last_errno;
1063
1064 return _value;
1065 }
1066
1067#if defined(LLONG_MAX) || defined(LLONG_MIN)
1068 template <class _Tp>
1069 inline _Tp _cs_to_integral_ll(const char *_str, const char *&num_s_end, int base)
1070 {
1071 typedef typename _str_to_integral_chooser_ll<_Tp>::impl _str_to_integral;
1072
1073 int last_errno = errno;
1074 errno = 0;
1075 char *endptr = 0;
1076 typedef typename _str_to_integral::type large_value_type;
1077 large_value_type _value = _str_to_integral::call(_str, &endptr, base);
1078
1079 if (_str_to_integral::check(_value) && errno == ERANGE)
1080 num_s_end = 0;
1081 else if (_value > static_cast<large_value_type>((std::numeric_limits<_Tp>::max)()) || _value < static_cast<large_value_type>((std::numeric_limits<_Tp>::min)()))
1082 {
1083 _value = (std::numeric_limits<_Tp>::max)();
1084 num_s_end = 0;
1085 }
1086 else
1087 num_s_end = endptr;
1088
1089 if (errno != last_errno)
1090 errno = last_errno;
1091
1092 return _value;
1093 }
1094
1095 template <class _Tp>
1096 inline _Tp _cs_to_integral_ll(const wchar_t *_str, const wchar_t *&num_s_end, int base)
1097 {
1098 typedef typename _str_to_integral_chooser_ll<_Tp>::impl _str_to_integral;
1099
1100 int last_errno = errno;
1101 errno = 0;
1102 wchar_t *endptr = 0;
1103 typedef typename _str_to_integral::type large_value_type;
1104 large_value_type _value = _str_to_integral::call(_str, &endptr, base);
1105
1106 if (_str_to_integral::check(_value) && errno == ERANGE)
1107 num_s_end = 0;
1108 else if (_value > static_cast<large_value_type>((std::numeric_limits<_Tp>::max)()) || _value < static_cast<large_value_type>((std::numeric_limits<_Tp>::min)()))
1109 {
1110 _value = (std::numeric_limits<_Tp>::max)();
1111 num_s_end = 0;
1112 }
1113 else
1114 num_s_end = endptr;
1115
1116 if (errno != last_errno)
1117 errno = last_errno;
1118
1119 return _value;
1120 }
1121#endif
1122
1123 template <class _Tp>
1124 inline long double _cs_to_floating_point(const char *_str, const char *&num_s_end)
1125 {
1126 using namespace std;
1127
1128 int last_errno = errno;
1129 errno = 0;
1130 char *endptr = 0;
1131 double _value = strtod(_str, &endptr);
1132
1133#ifdef HUGE_VAL
1134 if ((_value == HUGE_VAL || _value == -HUGE_VAL) && errno == ERANGE)
1135#else
1136 if (errno == ERANGE)
1137#endif
1138 num_s_end = 0;
1139 else if (_value > static_cast<double>((std::numeric_limits<_Tp>::max)()) || _value < static_cast<double>(-(std::numeric_limits<_Tp>::max)()))
1140 {
1141 _value = (std::numeric_limits<_Tp>::max)();
1142 num_s_end = 0;
1143 }
1144 else
1145 num_s_end = endptr;
1146
1147 if (errno != last_errno)
1148 errno = last_errno;
1149
1150 return _value;
1151 }
1152
1153 template <class _Tp>
1154 inline long double _cs_to_floating_point(const wchar_t *_str, const wchar_t *&num_s_end)
1155 {
1156 using namespace std;
1157
1158 int last_errno = errno;
1159 errno = 0;
1160 wchar_t *endptr = 0;
1161 double _value = wcstod(_str, &endptr);
1162
1163#ifdef HUGE_VAL
1164 if ((_value == HUGE_VAL || _value == -HUGE_VAL) && errno == ERANGE)
1165#else
1166 if (errno == ERANGE)
1167#endif
1168 num_s_end = 0;
1169 else if (_value > static_cast<double>((std::numeric_limits<_Tp>::max)()) || _value < static_cast<double>(-(std::numeric_limits<_Tp>::max)()))
1170 {
1171 _value = (std::numeric_limits<_Tp>::max)();
1172 num_s_end = 0;
1173 }
1174 else
1175 num_s_end = endptr;
1176
1177 if (errno != last_errno)
1178 errno = last_errno;
1179
1180 return _value;
1181 }
1182
1183
1184
1185 template<bool>
1186 struct _cs_to_floating_point_ld
1187 {
1188 template<class _Tp>
1189 static long double
1190 call(const _Tp *_str, const char *&num_s_end)
1191 {
1192 using namespace std;
1193
1194 int last_errno = errno;
1195 errno = 0;
1196 char *endptr = 0;
1197 long double _value = strtold(_str, &endptr);
1198
1199#ifdef HUGE_VALL
1200 if ((_value == HUGE_VALL || _value == -HUGE_VALL) && errno == ERANGE)
1201#else
1202 if(errno == ERANGE)
1203#endif
1204 num_s_end = 0;
1205 else
1206 num_s_end = endptr;
1207
1208 if (errno != last_errno)
1209 errno = last_errno;
1210
1211 return _value;
1212 }
1213
1214 template<class _Tp>
1215 static long double
1216 call(const _Tp *_str, const wchar_t *&num_s_end)
1217 {
1218 using namespace std;
1219
1220 int last_errno = errno;
1221 errno = 0;
1222 wchar_t *endptr = 0;
1223 long double _value = wcstold(_str, &endptr);
1224
1225#ifdef HUGE_VALL
1226 if ((_value == HUGE_VALL || _value == -HUGE_VALL) && errno == ERANGE)
1227#else
1228 if(errno == ERANGE)
1229#endif
1230 num_s_end = 0;
1231 else
1232 num_s_end = endptr;
1233
1234 if (errno != last_errno)
1235 errno = last_errno;
1236
1237 return _value;
1238 }
1239 };
1240
1241 template<>
1242 struct _cs_to_floating_point_ld<false>
1243 {
1244 static long double
1245 _a_to_floating_point(const char *_str)
1246 {
1247 using namespace std;
1248
1249 long double value;
1250
1251 if (sscanf(_str, "%Lf", &value) == EOF)
1252 {
1253
1254 long double fp_integer_part = 0.0L, fp_fractional_part = 0.0L;
1255 cstddef::size_t _i, length = strlen(_str);
1256
1257 _i = 0; // Left to right
1258 while (_str[_i] != '.') {
1259 fp_integer_part = fp_integer_part * 10.0L + (_str[_i] - '0');
1260 _i++;
1261 }
1262
1263
1264 _i = length - 1; // Right to left
1265
1266 while (!isdigit(_str[_i]) && _str[_i] != '.')
1267 _i--;
1268
1269 while (_str[_i] != '.') {
1270 fp_fractional_part = (fp_fractional_part + (_str[_i] - '0')) / 10.0L;
1271 _i--;
1272 }
1273
1274 value = fp_integer_part + fp_fractional_part;
1275 }
1276
1277 if(value > (numeric_limits<long double>::max)() || value < (numeric_limits<long double>::min)())
1278 {
1279 errno = ERANGE;
1280 value = 0.0;
1281 }
1282
1283 return value;
1284 }
1285
1286 static long double
1287 _a_to_floating_point(const wchar_t *_str)
1288 {
1289 using namespace std;
1290
1291 long double value;
1292
1293 if (swscanf(_str, L"%Lf", &value) == EOF)
1294 {
1295
1296 long double fp_integer_part = 0.0L, fp_fractional_part = 0.0L;
1297 cstddef::size_t _i, length = wcslen(_str);
1298
1299 _i = 0; // Left to right
1300 while (_str[_i] != L'.') {
1301 fp_integer_part = fp_integer_part * 10.0L + (_str[_i] - L'0');
1302 _i++;
1303 }
1304
1305
1306 _i = length - 1; // Right to left
1307
1308 while (!isdigit(_str[_i]) && _str[_i] != L'.')
1309 _i--;
1310
1311 while (_str[_i] != L'.') {
1312 fp_fractional_part = (fp_fractional_part + (_str[_i] - L'0')) / 10.0L;
1313 _i--;
1314 }
1315
1316 value = fp_integer_part + fp_fractional_part;
1317 }
1318
1319 if (value > (numeric_limits<long double>::max)() || value < (numeric_limits<long double>::min)())
1320 {
1321 errno = ERANGE;
1322 value = 0.0;
1323 }
1324
1325 return value;
1326 }
1327
1328 static long double
1329 _cs_to_long_double(const char *_str, char const **_ptr)
1330 {
1331 using namespace std;
1332
1333 const char *_p;
1334
1335 if (!_ptr)
1336 return _a_to_floating_point(_str);
1337
1338 _p = _str;
1339
1340 while (isspace(*_p))
1341 ++_p;
1342
1343 if (*_p == '+' || *_p == '-')
1344 ++_p;
1345
1346 typedef _not_a_number<long double>::impl not_a_number_impl;
1347 typedef _infinity<long double>::impl infinity_impl;
1348
1349 /* INF or INFINITY. */
1350 if ((_p[0] == 'i' || _p[0] == 'I')
1351 && (_p[1] == 'n' || _p[1] == 'N')
1352 && (_p[2] == 'f' || _p[2] == 'F'))
1353 {
1354 if ((_p[3] == 'i' || _p[3] == 'I')
1355 && (_p[4] == 'n' || _p[4] == 'N')
1356 && (_p[5] == 'i' || _p[5] == 'I')
1357 && (_p[6] == 't' || _p[6] == 'T')
1358 && (_p[7] == 'y' || _p[7] == 'Y'))
1359 {
1360 *_ptr = _p + 8;
1361 return infinity_impl::inf();
1362 }
1363 else
1364 {
1365 *_ptr = _p + 3;
1366 return infinity_impl::inf();
1367 }
1368 }
1369
1370 /* NAN or NAN(foo). */
1371 if ((_p[0] == 'n' || _p[0] == 'N')
1372 && (_p[1] == 'a' || _p[1] == 'A')
1373 && (_p[2] == 'n' || _p[2] == 'N'))
1374 {
1375 _p += 3;
1376 if (*_p == '(')
1377 {
1378 ++_p;
1379 while (*_p != '\0' && *_p != ')')
1380 ++_p;
1381 if (*_p == ')')
1382 ++_p;
1383 }
1384 *_ptr = _p;
1385 return not_a_number_impl::NaN();
1386 }
1387
1388 /* digits, with 0 or 1 periods in it. */
1389 if (isdigit(*_p) || *_p == '.')
1390 {
1391 int got_dot = 0;
1392 while (isdigit(*_p) || (!got_dot && *_p == '.'))
1393 {
1394 if (*_p == '.')
1395 got_dot = 1;
1396 ++_p;
1397 }
1398
1399 /* Exponent. */
1400 if (*_p == 'e' || *_p == 'E')
1401 {
1402 int _i;
1403 _i = 1;
1404 if (_p[_i] == '+' || _p[_i] == '-')
1405 ++_i;
1406 if (isdigit(_p[_i]))
1407 {
1408 while (isdigit(_p[_i]))
1409 ++_i;
1410 *_ptr = _p + _i;
1411 if (std::numeric_limits<long double>::max_exponent10 < _i)
1412 {
1413 errno = ERANGE;
1414 return (std::numeric_limits<long double>::max)();
1415 }
1416 return _a_to_floating_point(_str);
1417 }
1418 }
1419 *_ptr = _p;
1420 return _a_to_floating_point(_str);
1421 }
1422 /* Didn't find any digits. Doesn't look like a number. */
1423 *_ptr = _str;
1424 return not_a_number_impl::NaN();
1425 }
1426
1427 static long double
1428 _cs_to_long_double(const wchar_t *_str, wchar_t const **_ptr)
1429 {
1430 using namespace std;
1431
1432 const wchar_t *_p;
1433
1434 if (!_ptr)
1435 return _a_to_floating_point(_str);
1436
1437 _p = _str;
1438
1439 while (isspace(*_p))
1440 ++_p;
1441
1442 if (*_p == L'+' || *_p == L'-')
1443 ++_p;
1444
1445 typedef _not_a_number<long double>::impl not_a_number_impl;
1446 typedef _infinity<long double>::impl infinity_impl;
1447
1448 /* INF or INFINITY. */
1449 if ((_p[0] == L'i' || _p[0] == L'I')
1450 && (_p[1] == L'n' || _p[1] == L'N')
1451 && (_p[2] == L'f' || _p[2] == L'F'))
1452 {
1453 if ((_p[3] == L'i' || _p[3] == L'I')
1454 && (_p[4] == L'n' || _p[4] == L'N')
1455 && (_p[5] == L'i' || _p[5] == L'I')
1456 && (_p[6] == L't' || _p[6] == L'T')
1457 && (_p[7] == L'y' || _p[7] == L'Y'))
1458 {
1459 *_ptr = _p + 8;
1460 return infinity_impl::inf();
1461 }
1462 else
1463 {
1464 *_ptr = _p + 3;
1465 return infinity_impl::inf();
1466 }
1467 }
1468
1469 /* NAN or NAN(foo). */
1470 if ((_p[0] == L'n' || _p[0] == L'N')
1471 && (_p[1] == L'a' || _p[1] == L'A')
1472 && (_p[2] == L'n' || _p[2] == L'N'))
1473 {
1474 _p += 3;
1475 if (*_p == L'(')
1476 {
1477 ++_p;
1478 while (*_p != L'\0' && *_p != L')')
1479 ++_p;
1480 if (*_p == L')')
1481 ++_p;
1482 }
1483 *_ptr = _p;
1484 return not_a_number_impl::NaN();
1485 }
1486
1487 /* digits, with 0 or 1 periods in it. */
1488 if (isdigit(*_p) || *_p == L'.')
1489 {
1490 int got_dot = 0;
1491 while (isdigit(*_p) || (!got_dot && *_p == L'.'))
1492 {
1493 if (*_p == L'.')
1494 got_dot = 1;
1495 ++_p;
1496 }
1497
1498 /* Exponent. */
1499 if (*_p == L'e' || *_p == L'E')
1500 {
1501 int _i;
1502 _i = 1;
1503 if (_p[_i] == L'+' || _p[_i] == L'-')
1504 ++_i;
1505 if (isdigit(_p[_i]))
1506 {
1507 while (isdigit(_p[_i]))
1508 ++_i;
1509 *_ptr = _p + _i;
1510 if (std::numeric_limits<long double>::max_exponent10 < _i)
1511 {
1512 errno = ERANGE;
1513 return (std::numeric_limits<long double>::max)();
1514 }
1515 return _a_to_floating_point(_str);
1516 }
1517 }
1518 *_ptr = _p;
1519 return _a_to_floating_point(_str);
1520 }
1521 /* Didn't find any digits. Doesn't look like a number. */
1522 *_ptr = _str;
1523 return not_a_number_impl::NaN();
1524 }
1525
1526 static long double
1527 call(const char *_str, const char *&num_s_end)
1528 {
1529 int last_errno = errno;
1530 errno = 0;
1531 long double _value = _cs_to_long_double(_str, &num_s_end);
1532
1533 if (errno == ERANGE)
1534 num_s_end = 0;
1535
1536 if (errno != last_errno)
1537 errno = last_errno;
1538
1539 return _value;
1540 }
1541
1542 static long double
1543 call(const wchar_t *_str, const wchar_t *&num_s_end)
1544 {
1545 int last_errno = errno;
1546 errno = 0;
1547 long double _value = _cs_to_long_double(_str, &num_s_end);
1548
1549 if (errno == ERANGE)
1550 num_s_end = 0;
1551
1552 if (errno != last_errno)
1553 errno = last_errno;
1554
1555 return _value;
1556 }
1557 };
1558
1559
1560
1561
1562 template <>
1563 inline
1564 long double
1565 _cs_to_floating_point<long double>(const char *_str, const char *&num_s_end)
1566 {
1567 typedef _cs_to_floating_point_ld<string_detail::_strtold_present::value> impl;
1568
1569 return impl::call(_str, num_s_end);
1570 }
1571
1572 template <>
1573 inline
1574 long double
1575 _cs_to_floating_point<long double>(const wchar_t *_str, const wchar_t *&num_s_end)
1576 {
1577 typedef _cs_to_floating_point_ld<string_detail::_wcstold_present::value> impl;
1578
1579 return impl::call(_str, num_s_end);
1580 }
1581
1582 struct _has_4arg_swprintf:
1583 public string_detail::_has_4arg_swprintf
1584 {};
1585
1586 template<bool> struct _swprintf_impl;
1587
1588 template<>
1589 struct _swprintf_impl<true>
1590 {
1591 template<class _T1, class _T2, class _T3, class _T4>
1592 static void call(_T1 _a1, _T2 _a2, _T3 _a3, _T4 _a4)
1593 {
1594 using namespace std;
1595 swprintf(_a1, _a2, _a3, _a4);
1596 }
1597 };
1598
1599 template<>
1600 struct _swprintf_impl<false>
1601 {
1602 template<class _T1, class _T2, class _T3>
1603 static void call(_T1 _a1, cstddef::size_t, _T2 _a2, _T3 _a3)
1604 {
1605 using namespace std;
1606 swprintf(_a1, _a2, _a3);
1607 }
1608 };
1609
1610 template<class _ArgT>
1611 inline
1612 void _swprintf4_std_impl(wchar_t* ws, cstddef::size_t len, const wchar_t* format, _ArgT arg)
1613 {
1614 _swprintf_impl<_has_4arg_swprintf::value>::call(ws, len, format, arg);
1615 }
1616
1617 template<class _Tp>
1618 struct _to_string_impl
1619 {
1620 static string call(const _Tp &value)
1621 {
1622 stringstream _ss;
1623 _ss << value;
1624 string _str(_ss.str());
1625 return _str;
1626 }
1627 };
1628
1629 template<>
1630 struct _to_string_impl<char*>
1631 {
1632 static string call(const char *value)
1633 {
1634 return value;
1635 }
1636 };
1637
1638 template<int _Size>
1639 struct _to_string_impl<char[_Size]>:
1640 _to_string_impl<char*>
1641 { };
1642
1643 template<class _Tp>
1644 struct _to_wstring_impl
1645 {
1646 static wstring call(const _Tp &value)
1647 {
1648 wstringstream _ss;
1649 _ss << value;
1650 wstring _str(_ss.str());
1651 return _str;
1652 }
1653 };
1654
1655 template<>
1656 struct _to_wstring_impl<wchar_t*>
1657 {
1658 static wstring call(const wchar_t *value)
1659 {
1660 return value;
1661 }
1662 };
1663
1664 template<int _Size>
1665 struct _to_wstring_impl<wchar_t[_Size]>:
1666 _to_wstring_impl<wchar_t*>
1667 { };
1668
1669
1670 }
1671
1672
1673
1674 template <class _Tp>
1675 inline _Tp stot(const string &_str, cstddef::size_t *idx = 0, int base = 10)
1676 {
1677 const char *_eptr = _str.c_str(), *_ptr = _eptr;
1678 _Tp _value = stot<_Tp>(_ptr, _eptr, base);
1679
1680 if (_ptr == _eptr)
1681 throw(std::invalid_argument("invalid stdex::stot argument"));
1682 if(!_eptr)
1683 throw(std::out_of_range("stdex::stot argument out of range"));
1684
1685 if (idx != 0)
1686 *idx = (cstddef::size_t) (_eptr - _ptr);
1687
1688 return (_value);
1689 }
1690
1691 template <class _Tp>
1692 inline _Tp stot(const wstring &_str, cstddef::size_t *idx = 0, int base = 10)
1693 {
1694 const wchar_t *_eptr = _str.c_str(), *_ptr = _eptr;
1695 _Tp _value = stot<_Tp>(_ptr, _eptr, base);
1696
1697 if (_ptr == _eptr)
1698 throw(std::invalid_argument("invalid wide stdex::stot argument"));
1699 if (!_eptr)
1700 throw(std::out_of_range("wide stdex::stot argument out of range"));
1701
1702 if (idx != 0)
1703 *idx = (cstddef::size_t) (_eptr - _ptr);
1704
1705 return (_value);
1706 }
1707
1708 inline int stoi(const string &_str, cstddef::size_t *idx = 0, int base = 10)
1709 {
1710 const char *_eptr = _str.c_str(), *_ptr = _eptr;
1711 int _value = detail::_cs_to_integral<int>(_ptr, _eptr, base);
1712
1713 if (_ptr == _eptr)
1714 throw(std::invalid_argument("invalid stdex::stoi argument"));
1715 if (!_eptr)
1716 throw(std::out_of_range("stdex::stoi argument out of range"));
1717
1718 if (idx != 0)
1719 *idx = (cstddef::size_t) (_eptr - _ptr);
1720
1721 return (_value);
1722 }
1723
1724 inline int stoi(const wstring &_str, cstddef::size_t *idx = 0, int base = 10)
1725 {
1726 const wchar_t *_eptr = _str.c_str(), *_ptr = _eptr;
1727 int _value = detail::_cs_to_integral<int>(_ptr, _eptr, base);
1728
1729 if (_ptr == _eptr)
1730 throw(std::invalid_argument("invalid wide stdex::stoi argument"));
1731 if (!_eptr)
1732 throw(std::out_of_range("wide stdex::stoi argument out of range"));
1733
1734 if (idx != 0)
1735 *idx = (cstddef::size_t) (_eptr - _ptr);
1736
1737 return (_value);
1738 }
1739
1740 inline long stol(const string &_str, cstddef::size_t *idx = 0, int base = 10)
1741 {
1742 const char *_eptr = _str.c_str(), *_ptr = _eptr;
1743 long _value = detail::_cs_to_integral<long>(_ptr, _eptr, base);
1744
1745 if (_ptr == _eptr)
1746 throw(std::invalid_argument("invalid stdex::stol argument"));
1747 if (!_eptr)
1748 throw(std::out_of_range("stdex::stol argument out of range"));
1749
1750 if (idx != 0)
1751 *idx = (cstddef::size_t) (_eptr - _ptr);
1752
1753 return (_value);
1754 }
1755
1756 inline long stol(const wstring &_str, cstddef::size_t *idx = 0, int base = 10)
1757 {
1758 const wchar_t *_eptr = _str.c_str(), *_ptr = _eptr;
1759 long _value = detail::_cs_to_integral<long>(_ptr, _eptr, base);
1760
1761 if (_ptr == _eptr)
1762 throw(std::invalid_argument("invalid wide stdex::stol argument"));
1763 if (!_eptr)
1764 throw(std::out_of_range("wide stdex::stol argument out of range"));
1765
1766 if (idx != 0)
1767 *idx = (cstddef::size_t) (_eptr - _ptr);
1768
1769 return (_value);
1770 }
1771
1772 inline unsigned long stoul(const string &_str, cstddef::size_t *idx = 0, int base = 10)
1773 {
1774 const char *_eptr = _str.c_str(), *_ptr = _eptr;
1775 unsigned long _value = detail::_cs_to_integral<unsigned long>(_ptr, _eptr, base);
1776
1777 if (_ptr == _eptr)
1778 throw(std::invalid_argument("invalid stdex::stoul argument"));
1779 if(!_eptr)
1780 throw(std::out_of_range("stdex::stoul argument out of range"));
1781
1782 if (idx != 0)
1783 *idx = (cstddef::size_t) (_eptr - _ptr);
1784
1785 return (_value);
1786 }
1787
1788 inline unsigned long stoul(const wstring &_str, cstddef::size_t *idx = 0, int base = 10)
1789 {
1790 const wchar_t *_eptr = _str.c_str(), *_ptr = _eptr;
1791 unsigned long _value = detail::_cs_to_integral<unsigned long>(_ptr, _eptr, base);
1792
1793 if (_ptr == _eptr)
1794 throw(std::invalid_argument("invalid wide stdex::stoul argument"));
1795 if (!_eptr)
1796 throw(std::out_of_range("wide stdex::stoul argument out of range"));
1797
1798 if (idx != 0)
1799 *idx = (cstddef::size_t) (_eptr - _ptr);
1800
1801 return (_value);
1802 }
1803
1804 inline float stof(const string &_str, cstddef::size_t *idx = 0)
1805 {
1806 const char *_eptr = _str.c_str(), *_ptr = _eptr;
1807
1808 float _value = static_cast<float>(detail::_cs_to_floating_point<float>(_ptr, _eptr));
1809
1810 if (_ptr == _eptr)
1811 throw(std::invalid_argument("invalid stdex::stof argument"));
1812 if(!_eptr)
1813 throw(std::out_of_range("stdex::stof argument out of range"));
1814
1815 if (idx != 0)
1816 *idx = (cstddef::size_t) (_eptr - _ptr);
1817
1818 return (_value);
1819 }
1820
1821 inline float stof(const wstring &_str, cstddef::size_t *idx = 0)
1822 {
1823 const wchar_t *_eptr = _str.c_str(), *_ptr = _eptr;
1824
1825 float _value = static_cast<float>(detail::_cs_to_floating_point<float>(_ptr, _eptr));
1826
1827 if (_ptr == _eptr)
1828 throw(std::invalid_argument("invalid wide stdex::stof argument"));
1829 if (!_eptr)
1830 throw(std::out_of_range("wide stdex::stof argument out of range"));
1831
1832 if (idx != 0)
1833 *idx = (cstddef::size_t) (_eptr - _ptr);
1834
1835 return (_value);
1836 }
1837
1838 inline double stod(const string &_str, cstddef::size_t *idx = 0)
1839 {
1840 const char *_eptr = _str.c_str(), *_ptr = _eptr;
1841
1842 double _value = static_cast<double>(detail::_cs_to_floating_point<double>(_ptr, _eptr));
1843
1844 if (_ptr == _eptr)
1845 throw(std::invalid_argument("invalid stdex::stod argument"));
1846 if(!_eptr)
1847 throw(std::out_of_range("stdex::stod argument out of range"));
1848
1849 if (idx != 0)
1850 *idx = (cstddef::size_t) (_eptr - _ptr);
1851
1852 return (_value);
1853 }
1854
1855 inline double stod(const wstring &_str, cstddef::size_t *idx = 0)
1856 {
1857 const wchar_t *_eptr = _str.c_str(), *_ptr = _eptr;
1858
1859 double _value = static_cast<double>(detail::_cs_to_floating_point<double>(_ptr, _eptr));
1860
1861 if (_ptr == _eptr)
1862 throw(std::invalid_argument("invalid wide stdex::stod argument"));
1863 if (!_eptr)
1864 throw(std::out_of_range("wide stdex::stod argument out of range"));
1865
1866 if (idx != 0)
1867 *idx = (cstddef::size_t) (_eptr - _ptr);
1868
1869 return (_value);
1870 }
1871
1872 inline long double stold(const string &_str, cstddef::size_t *idx = 0)
1873 {
1874 const char *_eptr = _str.c_str(), *_ptr = _eptr;
1875
1876 typedef conditional<sizeof(long double) == sizeof(double), double, long double>::type type;
1877
1878 long double _value = detail::_cs_to_floating_point<type>(_ptr, _eptr);
1879
1880 if (_ptr == _eptr)
1881 throw(std::invalid_argument("invalid stdex::stold argument"));
1882 if(!_eptr)
1883 throw(std::out_of_range("stdex::stold argument out of range"));
1884
1885 if (idx != 0)
1886 *idx = (cstddef::size_t) (_eptr - _ptr);
1887
1888 return (_value);
1889 }
1890
1891 inline long double stold(const wstring &_str, cstddef::size_t *idx = 0)
1892 {
1893 const wchar_t *_eptr = _str.c_str(), *_ptr = _eptr;
1894
1895 typedef conditional<sizeof(long double) == sizeof(double), double, long double>::type type;
1896
1897 long double _value = detail::_cs_to_floating_point<type>(_ptr, _eptr);
1898
1899 if (_ptr == _eptr)
1900 throw(std::invalid_argument("invalid wide stdex::stold argument"));
1901 if (!_eptr)
1902 throw(std::out_of_range("wide stdex::stold argument out of range"));
1903
1904 if (idx != 0)
1905 *idx = (cstddef::size_t) (_eptr - _ptr);
1906
1907 return (_value);
1908 }
1909
1910#if defined(LLONG_MAX) || defined(LLONG_MIN)
1911 inline long long stoll(const string &_str, cstddef::size_t *idx = 0, int base = 10)
1912 {
1913 const char *_eptr = _str.c_str(), *_ptr = _eptr;
1914
1915 long long _value = detail::_cs_to_integral_ll<long long>(_ptr, _eptr, base);
1916
1917 if (_ptr == _eptr)
1918 throw(std::invalid_argument("invalid stdex::stoll argument"));
1919 if(!_eptr)
1920 throw(std::out_of_range("stdex::stoll argument out of range"));
1921
1922 if (idx != 0)
1923 *idx = (cstddef::size_t) (_eptr - _ptr);
1924
1925 return (_value);
1926 }
1927
1928 inline long long stoll(const wstring &_str, cstddef::size_t *idx = 0, int base = 10)
1929 {
1930 const wchar_t *_eptr = _str.c_str(), *_ptr = _eptr;
1931
1932 long long _value = detail::_cs_to_integral_ll<long long>(_ptr, _eptr, base);
1933
1934 if (_ptr == _eptr)
1935 throw(std::invalid_argument("invalid wide stdex::stoll argument"));
1936 if (!_eptr)
1937 throw(std::out_of_range("wide stdex::stoll argument out of range"));
1938
1939 if (idx != 0)
1940 *idx = (cstddef::size_t) (_eptr - _ptr);
1941
1942 return (_value);
1943 }
1944
1945 inline unsigned long long stoull(const string &_str, cstddef::size_t *idx = 0, int base = 10)
1946 {
1947 const char *_eptr = _str.c_str(), *_ptr = _eptr;
1948
1949 unsigned long long _value = detail::_cs_to_integral_ll<unsigned long long>(_ptr, _eptr, base);
1950
1951 if (_ptr == _eptr)
1952 throw(std::invalid_argument("invalid stdex::stoull argument"));
1953 if(!_eptr)
1954 throw(std::out_of_range("stdex::stoull argument out of range"));
1955
1956 if (idx != 0)
1957 *idx = (cstddef::size_t) (_eptr - _ptr);
1958
1959 return (_value);
1960 }
1961
1962 inline unsigned long long stoull(const wstring &_str, cstddef::size_t *idx = 0, int base = 10)
1963 {
1964 const wchar_t *_eptr = _str.c_str(), *_ptr = _eptr;
1965
1966 unsigned long long _value = detail::_cs_to_integral_ll<unsigned long long>(_ptr, _eptr, base);
1967
1968 if (_ptr == _eptr)
1969 throw(std::invalid_argument("invalid wide stdex::stoull argument"));
1970 if (!_eptr)
1971 throw(std::out_of_range("wide stdex::stoull argument out of range"));
1972
1973 if (idx != 0)
1974 *idx = (cstddef::size_t) (_eptr - _ptr);
1975
1976 return (_value);
1977 }
1978#endif
1979
1980 template<class _Tp>
1981 inline string to_string(const _Tp &value)
1982 {
1983 return detail::_to_string_impl<_Tp>::call(value);
1984 }
1985
1986 template<class _Tp>
1987 inline wstring to_wstring(const _Tp &value)
1988 {
1989 return detail::_to_wstring_impl<_Tp>::call(value);
1990 }
1991
1992 template<>
1993 inline string to_string<int>(const int &value)
1994 {
1995 using namespace std;
1996#ifdef INT_MAX
1997 char buf[detail::_type_cs_len<int, INT_MAX>::value];
1998#else
1999 char buf[32];
2000#endif
2001 detail::_snprintf4_std_impl(buf, sizeof(buf), "%d", value);
2002
2003 return string(buf);
2004 }
2005
2006 template<>
2007 inline wstring to_wstring<int>(const int &value)
2008 {
2009 using namespace std;
2010#ifdef INT_MAX
2011 wchar_t buf[detail::_type_cs_len<int, INT_MAX>::value * sizeof(wchar_t)];
2012#else
2013 wchar_t buf[32 * sizeof(wchar_t)];
2014#endif
2015 detail::_swprintf4_std_impl(buf, sizeof(buf) / sizeof(wchar_t), L"%d", value);
2016
2017 return wstring(buf);
2018 }
2019
2020 template<>
2021 inline string to_string<unsigned int>(const unsigned int &value)
2022 {
2023 using namespace std;
2024#ifdef UINT_MAX
2025 char buf[detail::_type_cs_len<unsigned int, UINT_MAX>::value];
2026#else
2027 char buf[32];
2028#endif
2029 detail::_snprintf4_std_impl(buf, sizeof(buf), "%u", value);
2030
2031 return string(buf);
2032 }
2033
2034 template<>
2035 inline wstring to_wstring<unsigned int>(const unsigned int &value)
2036 {
2037 using namespace std;
2038#ifdef UINT_MAX
2039 wchar_t buf[detail::_type_cs_len<unsigned int, UINT_MAX>::value * sizeof(wchar_t)];
2040#else
2041 wchar_t buf[32 * sizeof(wchar_t)];
2042#endif
2043 detail::_swprintf4_std_impl(buf, sizeof(buf) / sizeof(wchar_t), L"%u", value);
2044
2045 return wstring(buf);
2046 }
2047
2048 template<>
2049 inline string to_string<bool>(const bool &value)
2050 {
2051 if(value)
2052 return string("true");
2053 return string("false");
2054 }
2055
2056 template<>
2057 inline wstring to_wstring<bool>(const bool &value)
2058 {
2059 if (value)
2060 return wstring(L"true");
2061 return wstring(L"false");
2062 }
2063
2064 template<>
2065 inline string to_string<float>(const float &value)
2066 {
2067 using namespace std;
2068#if defined(FLT_MANT_DIG) && defined(FLT_MIN_EXP)
2069 char buf[3 + FLT_MANT_DIG - FLT_MIN_EXP];
2070#else
2071 char buf[256];
2072#endif
2073 detail::_snprintf4_std_impl(buf, sizeof(buf), "%f", value);
2074
2075 return string(buf);
2076 }
2077
2078 template<>
2079 inline wstring to_wstring<float>(const float &value)
2080 {
2081 using namespace std;
2082#if defined(FLT_MANT_DIG) && defined(FLT_MIN_EXP)
2083 wchar_t buf[(3 + FLT_MANT_DIG - FLT_MIN_EXP) * sizeof(wchar_t)];
2084#else
2085 wchar_t buf[256 * sizeof(wchar_t)];
2086#endif
2087 detail::_swprintf4_std_impl(buf, sizeof(buf) / sizeof(wchar_t), L"%f", value);
2088
2089 return wstring(buf);
2090 }
2091
2092 template<>
2093 inline string to_string<double>(const double &value)
2094 {
2095 using namespace std;
2096#if defined(DBL_MANT_DIG) && defined(DBL_MIN_EXP)
2097 char buf[3 + DBL_MANT_DIG - DBL_MIN_EXP];
2098#else
2099 char buf[2048]; // strange assumption, I know
2100#endif
2101 detail::_snprintf4_std_impl(buf, sizeof(buf), "%f", value);
2102
2103 return string(buf);
2104 }
2105
2106 template<>
2107 inline wstring to_wstring<double>(const double &value)
2108 {
2109 using namespace std;
2110#if defined(DBL_MANT_DIG) && defined(DBL_MIN_EXP)
2111 wchar_t buf[(3 + DBL_MANT_DIG - DBL_MIN_EXP) * sizeof(wchar_t)];
2112#else
2113 wchar_t buf[2048 * sizeof(wchar_t)]; // strange assumption, I know
2114#endif
2115 detail::_swprintf4_std_impl(buf, sizeof(buf) / sizeof(wchar_t), L"%f", value);
2116
2117 return wstring(buf);
2118 }
2119
2120 template<>
2121 inline string to_string<std::string>(const std::string &_str)
2122 {
2123 return _str;
2124 }
2125
2126 template<>
2127 inline wstring to_wstring<std::wstring>(const std::wstring &_str)
2128 {
2129 return _str;
2130 }
2131
2132 template<>
2133 inline
2134 enable_if<is_same<int, long>::value == (false), string>::type
2135 to_string<long>(const long &value)
2136 {
2137 using namespace std;
2138#ifdef LONG_MAX
2139 char buf[detail::_type_cs_len<long, LONG_MAX>::value];
2140#else
2141#ifdef ULONG_MAX
2142 char buf[detail::_type_cs_len<long, (ULONG_MAX / 2)>::value];
2143#else
2144 char buf[256]; // strange assumption, I know
2145#endif
2146#endif
2147 detail::_snprintf4_std_impl(buf, sizeof(buf), "%ld", value);
2148
2149 return string(buf);
2150 }
2151
2152 template<>
2153 inline
2154 enable_if<is_same<int, long>::value == (false), wstring>::type
2155 to_wstring<long>(const long &value)
2156 {
2157 using namespace std;
2158#ifdef LONG_MAX
2159 wchar_t buf[detail::_type_cs_len<long, LONG_MAX>::value * sizeof(wchar_t)];
2160#else
2161#ifdef ULONG_MAX
2162 wchar_t buf[detail::_type_cs_len<long, (ULONG_MAX / 2)>::value * sizeof(wchar_t)];
2163#else
2164 wchar_t buf[256 * sizeof(wchar_t)]; // strange assumption, I know
2165#endif
2166#endif
2167 detail::_swprintf4_std_impl(buf, sizeof(buf) / sizeof(wchar_t), L"%ld", value);
2168
2169 return wstring(buf);
2170 }
2171
2172 template<>
2173 inline
2174 enable_if<is_same<unsigned int, unsigned long>::value == (false), string>::type
2175 to_string<unsigned long>(const unsigned long &value)
2176 {
2177 using namespace std;
2178#ifdef ULONG_MAX
2179 char buf[detail::_type_cs_len<unsigned long, ULONG_MAX>::value];
2180#else
2181#ifdef LONG_MAX
2182 char buf[detail::_type_cs_len<unsigned long, (LONG_MAX * 2 + 1)>::value];
2183#else
2184 char buf[512]; // strange assumption, I know
2185#endif
2186#endif
2187 detail::_snprintf4_std_impl(buf, sizeof(buf), "%lu", value);
2188
2189 return string(buf);
2190 }
2191
2192 template<>
2193 inline
2194 enable_if<is_same<unsigned int, unsigned long>::value == (false), wstring>::type
2195 to_wstring<unsigned long>(const unsigned long &value)
2196 {
2197 using namespace std;
2198#ifdef ULONG_MAX
2199 wchar_t buf[detail::_type_cs_len<unsigned long, ULONG_MAX>::value * sizeof(wchar_t)];
2200#else
2201#ifdef LONG_MAX
2202 wchar_t buf[detail::_type_cs_len<unsigned long, (LONG_MAX * 2 + 1)>::value * sizeof(wchar_t)];
2203#else
2204 wchar_t buf[512 * sizeof(wchar_t)]; // strange assumption, I know
2205#endif
2206#endif
2207 detail::_swprintf4_std_impl(buf, sizeof(buf) / sizeof(wchar_t), L"%lu", value);
2208
2209 return wstring(buf);
2210 }
2211
2212 template<>
2213 inline
2214 enable_if<is_same<long double, double>::value == (false), string>::type
2215 to_string<long double>(const long double &value)
2216 {
2217 using namespace std;
2218#if defined(LDBL_MANT_DIG) && defined(LDBL_MIN_EXP)
2219 char buf[3 + LDBL_MANT_DIG - LDBL_MIN_EXP];
2220#else
2221 char buf[4096]; // strange assumption, I know
2222#endif
2223 detail::_snprintf4_std_impl(buf, sizeof(buf), "%Lf", value);
2224
2225 string result(buf);
2226
2227 // some compilers ignore 'f' flag of sprintf and print large values with scientific notation, as if 'e' flag was passed
2228 // so we are removing substrings like 'e-10' and trying to enforce the precision by slow and not so precise conversion:
2229
2230 cstddef::size_t e_pos = result.rfind('e');
2231 if (e_pos != string::npos)
2232 {
2233#ifdef LDBL_MAX_10_EXP
2234 char str_integer_part_reverse[LDBL_MAX_10_EXP + 3];
2235#else
2236 char str_integer_part_reverse[sizeof(buf)];
2237#endif
2238 long double fp_integer_part, fp_fractional_part;
2239 cstddef::size_t symbols_converted_n = 0;
2240 fp_fractional_part = modfl(value, &fp_integer_part);
2241 while (fp_integer_part > 0.0L)
2242 {
2243 str_integer_part_reverse[symbols_converted_n++] = '0' + (char) fmod(fp_integer_part, 10.0L);
2244 fp_integer_part = floor(fp_integer_part / 10.0L);
2245 }
2246
2247 for (cstddef::size_t _i = 0; _i < symbols_converted_n; _i++)
2248 buf[_i] = str_integer_part_reverse[symbols_converted_n - _i - 1];
2249
2250 buf[symbols_converted_n++] = '.';
2251
2252 if (fp_fractional_part > 0.0L)
2253 {
2254 while (fp_fractional_part > 0.0L)
2255 {
2256 fp_fractional_part *= 10.0L;
2257 fp_fractional_part = modfl(fp_fractional_part, &fp_integer_part);
2258 buf[symbols_converted_n++] = '0' + (char) fp_integer_part;
2259 }
2260 }
2261 else
2262 buf[symbols_converted_n++] = '0';
2263
2264 buf[symbols_converted_n] = 0; // EOS
2265
2266 result = buf;
2267 }
2268
2269 return result;
2270 }
2271
2272 template<>
2273 inline
2274 enable_if<is_same<long double, double>::value == (false), wstring>::type
2275 to_wstring<long double>(const long double &value)
2276 {
2277 using namespace std;
2278#if defined(LDBL_MANT_DIG) && defined(LDBL_MIN_EXP)
2279 wchar_t buf[(3 + LDBL_MANT_DIG - LDBL_MIN_EXP) * sizeof(wchar_t)];
2280#else
2281 wchar_t buf[4096 * sizeof(wchar_t)]; // strange assumption, I know
2282#endif
2283 detail::_swprintf4_std_impl(buf, sizeof(buf) / sizeof(wchar_t), L"%Lf", value);
2284
2285 wstring result(buf);
2286
2287 // some compilers ignore 'f' flag of swprintf and print large values with scientific notation, as if 'e' flag was passed
2288 // so we are removing substrings like 'e-10' and trying to enforce the precision by slow and not so precise conversion:
2289
2290 cstddef::size_t e_pos = result.rfind(L'e');
2291 if (e_pos != string::npos)
2292 {
2293#ifdef LDBL_MAX_10_EXP
2294 wchar_t str_integer_part_reverse[(LDBL_MAX_10_EXP + 3) * sizeof(wchar_t)];
2295#else
2296 wchar_t str_integer_part_reverse[sizeof(buf)];
2297#endif
2298 long double fp_integer_part, fp_fractional_part;
2299 cstddef::size_t symbols_converted_n = 0;
2300 fp_fractional_part = modfl(value, &fp_integer_part);
2301 while (fp_integer_part > 0.0L)
2302 {
2303 str_integer_part_reverse[symbols_converted_n++] = L'0' + (char) fmod(fp_integer_part, 10.0L);
2304 fp_integer_part = floor(fp_integer_part / 10.0L);
2305 }
2306
2307 for (cstddef::size_t _i = 0; _i < symbols_converted_n; _i++)
2308 buf[_i] = str_integer_part_reverse[symbols_converted_n - _i - 1];
2309
2310 buf[symbols_converted_n++] = L'.';
2311
2312 if (fp_fractional_part > 0.0L)
2313 {
2314 while (fp_fractional_part > 0.0L)
2315 {
2316 fp_fractional_part *= 10.0L;
2317 fp_fractional_part = modfl(fp_fractional_part, &fp_integer_part);
2318 buf[symbols_converted_n++] = L'0' + (char) fp_integer_part;
2319 }
2320 }
2321 else
2322 buf[symbols_converted_n++] = L'0';
2323
2324 buf[symbols_converted_n] = 0; // EOS
2325
2326 result = buf;
2327 }
2328
2329 return result;
2330 }
2331
2332#if defined(LLONG_MAX) || defined(LLONG_MIN)
2333
2334 template<>
2335 inline
2336 enable_if<is_same<detail::string_detail::_long_long_type, long>::value == (false), string>::type
2337 to_string<detail::string_detail::_long_long_type>(const detail::string_detail::_long_long_type &value)
2338 {
2339 using namespace std;
2340#ifdef LLONG_MAX
2341 char buf[detail::_type_cs_len_ll<detail::string_detail::_long_long_type, LLONG_MAX>::value];
2342#else
2343#ifdef ULLONG_MAX
2344 char buf[detail::_type_cs_len_ll<detail::string_detail::_long_long_type, (ULONG_MAX / 2)>::value];
2345#else
2346 char buf[1024]; // strange assumption, I know
2347#endif
2348#endif
2349 detail::_snprintf4_std_impl(buf, sizeof(buf), "%lld", value);
2350
2351 return string(buf);
2352 }
2353
2354 template<>
2355 inline
2356 enable_if<is_same<detail::string_detail::_long_long_type, long>::value == (false), wstring>::type
2357 to_wstring<detail::string_detail::_long_long_type>(const detail::string_detail::_long_long_type &value)
2358 {
2359 using namespace std;
2360#ifdef LLONG_MAX
2361 wchar_t buf[detail::_type_cs_len_ll<detail::string_detail::_long_long_type, LLONG_MAX>::value * sizeof(wchar_t)];
2362#else
2363#ifdef ULLONG_MAX
2364 wchar_t buf[detail::_type_cs_len_ll<detail::string_detail::_long_long_type, (ULONG_MAX / 2)>::value * sizeof(wchar_t)];
2365#else
2366 wchar_t buf[1024 * sizeof(wchar_t)]; // strange assumption, I know
2367#endif
2368#endif
2369 detail::_swprintf4_std_impl(buf, sizeof(buf) / sizeof(wchar_t), L"%lld", value);
2370
2371 return wstring(buf);
2372 }
2373
2374 template<>
2375 inline
2376 enable_if<is_same<detail::string_detail::_unsigned_long_long_type, unsigned long>::value == (false), string>::type
2377 to_string<detail::string_detail::_unsigned_long_long_type>(const detail::string_detail::_unsigned_long_long_type &value)
2378 {
2379 using namespace std;
2380#ifdef ULLONG_MAX
2381 char buf[detail::_type_cs_len_ll<detail::string_detail::_unsigned_long_long_type, ULLONG_MAX>::value];
2382#else
2383#ifdef LLONG_MAX
2384 char buf[detail::_type_cs_len_ll<detail::string_detail::_unsigned_long_long_type, (LLONG_MAX * 2 + 1)>::value];
2385#else
2386 char buf[1024]; // strange assumption, I know
2387#endif
2388#endif
2389 detail::_snprintf4_std_impl(buf, sizeof(buf), "%llu", value);
2390
2391 return string(buf);
2392 }
2393
2394 template<>
2395 inline
2396 enable_if<is_same<detail::string_detail::_unsigned_long_long_type, unsigned long>::value == (false), wstring>::type
2397 to_wstring<detail::string_detail::_unsigned_long_long_type>(const detail::string_detail::_unsigned_long_long_type &value)
2398 {
2399 using namespace std;
2400#ifdef ULLONG_MAX
2401 wchar_t buf[detail::_type_cs_len_ll<detail::string_detail::_unsigned_long_long_type, ULLONG_MAX>::value * sizeof(wchar_t)];
2402#else
2403#ifdef LLONG_MAX
2404 wchar_t buf[detail::_type_cs_len_ll<detail::string_detail::_unsigned_long_long_type, (LLONG_MAX * 2 + 1)>::value * sizeof(wchar_t)];
2405#else
2406 wchar_t buf[1024 * sizeof(wchar_t)]; // strange assumption, I know
2407#endif
2408#endif
2409 detail::_swprintf4_std_impl(buf, sizeof(buf) / sizeof(wchar_t), L"%llu", value);
2410
2411 return wstring(buf);
2412 }
2413#endif
2414
2415}
2416
2417#endif // _STDEX_STRING_H