Convert.h
1/* Copyright (C) 2013 Marc Boris Duerner
2
3 This library is free software; you can redistribute it and/or
4 modify it under the terms of the GNU Lesser General Public
5 License as published by the Free Software Foundation; either
6 version 2.1 of the License, or (at your option) any later version.
7
8 As a special exception, you may use this file as part of a free
9 software library without restriction. Specifically, if other files
10 instantiate templates or use macros or inline functions from this
11 file, or you compile this file and link it with other files to
12 produce an executable, this file does not by itself cause the
13 resulting executable to be covered by the GNU General Public
14 License. This exception does not however invalidate any other
15 reasons why the executable file might be covered by the GNU Library
16 General Public License.
17
18 This library is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 Lesser General Public License for more details.
22
23 You should have received a copy of the GNU Lesser General Public
24 License along with this library; if not, write to the Free Software
25 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
26 MA 02110-1301 USA
27*/
28
29#ifndef Pt_Convert_h
30#define Pt_Convert_h
31
32#include <Pt/Api.h>
33#include <Pt/ConversionError.h>
34#include <Pt/TypeTraits.h>
35
36#include <string>
37#include <limits>
38#include <algorithm>
39#include <iterator>
40#include <cctype>
41#include <cmath>
42#include <cassert>
43
44namespace Pt {
45
46template <bool signedX, bool signedY>
47struct LessThanMin
48{
49 template <class X, class Y>
50 static bool check(X x, Y y_min)
51 { return x < y_min; }
52};
53
54
55template <>
56struct LessThanMin<false, true>
57{
58 template <class X, class Y>
59 static bool check(X, Y)
60 { return false; }
61};
62
63
64template <>
65struct LessThanMin<true, false>
66{
67 template <class X, class Y>
68 static bool check(X x, Y)
69 { return x < 0; }
70};
71
72
73template <bool signedX, bool signedY>
74struct GreaterThanMax
75{
76 // both signed or both unsigned
77 template <class X, class Y>
78 static bool check(X x, Y ymax)
79 { return x > ymax; }
80};
81
82
83template <>
84struct GreaterThanMax<false, true>
85{
86 // x is unsigned, y is signed
87 template <class X, class Y>
88 static bool check(X x, Y ymax)
89 {
90 return x > static_cast<X>(ymax);
91 }
92};
93
94
95template <>
96struct GreaterThanMax<true, false>
97{
98 // x is signed, y is unsigned
99 template <class X, class Y>
100 static bool check(X x, Y ymax)
101 {
102 return x > 0 && static_cast<Y>(x) > ymax;
103 }
104};
105
106
111template<typename R, typename T>
112inline R narrow(T from)
113{
114 typedef std::numeric_limits<T> SourceTraits;
115 typedef std::numeric_limits<R> ResultTraits;
116
117 const bool fromSigned = SourceTraits::is_signed;
118 const bool toSigned = ResultTraits::is_signed;
119
120 if( LessThanMin<fromSigned, toSigned>::check( from, ResultTraits::min() )
121 || GreaterThanMax<fromSigned, toSigned>::check( from, ResultTraits::max() ) )
122 {
123 throw ConversionError("numeric conversion failed");
124 }
125
126 return static_cast<R>(from);
127}
128
129
134template <typename OutIterT, typename T, typename FormatT>
135inline OutIterT formatInt(OutIterT it, T i, const FormatT& fmt);
136
141template <typename OutIterT, typename T>
142inline OutIterT formatInt(OutIterT it, T i);
143
148template <typename CharT, typename T, typename FormatT>
149inline CharT* formatInt(CharT* buf, std::size_t buflen, T si, const FormatT& fmt);
150
151
156template <typename OutIterT, typename T, typename FormatT>
157OutIterT formatFloat(OutIterT it, T d,
158 const FormatT& fmt, int precision, bool fixed = false);
159
164template <typename OutIterT, typename T>
165OutIterT formatFloat(OutIterT it, T d);
166
171template <typename OutIterT, typename T>
172OutIterT formatFloat(OutIterT it, T d, int precision, bool fixed = false);
173
174
179template <typename InIterT, typename T, typename FormatT>
180InIterT parseInt(InIterT it, InIterT end, T& n, const FormatT& fmt, bool& ok);
181
186template <typename InIterT, typename T, typename FormatT>
187InIterT parseInt(InIterT it, InIterT end, T& n, const FormatT& fmt)
188{
189 bool ok = false;
190
191 InIterT r = parseInt(it, end, n, fmt, ok);
192 if( ! ok )
193 throw ConversionError("conversion failed");
194
195 return r;
196}
197
202template <typename InIterT, typename T>
203InIterT parseInt(InIterT it, InIterT end, T& n, bool& ok);
204
209template <typename InIterT, typename T>
210InIterT parseInt(InIterT it, InIterT end, T& n)
211{
212 bool ok = false;
213
214 InIterT r = parseInt(it, end, n, ok);
215 if( ! ok )
216 throw ConversionError("conversion failed");
217
218 return r;
219}
220
225template <typename T, typename InIter>
226T parseInt(InIter it, InIter end)
227{
228 T n = T();
229 bool ok = false;
230
231 InIter r = parseInt(it, end, n, ok);
232 if( ! ok || r != end )
233 throw ConversionError("conversion failed");
234
235 return n;
236}
237
238
243template <typename InIterT, typename T, typename FormatT>
244InIterT parseFloat(InIterT it, InIterT end, T& n, const FormatT& fmt, bool& ok);
245
250template <typename InIterT, typename T, typename FormatT>
251InIterT parseFloat(InIterT it, InIterT end, T& n, const FormatT& fmt)
252{
253 bool ok = false;
254
255 InIterT r = parseFloat(it, end, n, fmt, ok);
256 if( ! ok )
257 throw ConversionError("conversion failed");
258
259 return r;
260}
261
266template <typename InIterT, typename T>
267InIterT parseFloat(InIterT it, InIterT end, T& n, bool& ok);
268
273template <typename InIterT, typename T>
274InIterT parseFloat(InIterT it, InIterT end, T& n)
275{
276 bool ok = false;
277
278 InIterT r = parseFloat(it, end, n, ok);
279 if( ! ok )
280 throw ConversionError("conversion failed");
281
282 return r;
283}
284
285
286template <typename CharType>
287struct NumberFormat
288{
289 typedef CharType CharT;
290
291 static bool isSpace(CharT ch)
292 { return (ch == 0x20) || (ch > 0x08 && ch < 0x0e); }
293
294 static CharT plus()
295 { return '+'; }
296
297 static CharT minus()
298 { return '-'; }
299};
300
301
302template <typename CharType>
303struct DecimalFormat : public NumberFormat<CharType>
304{
305 typedef CharType CharT;
306
307 static const unsigned base = 10;
308
311 static CharT toChar(unsigned char n)
312 {
313 return '0' + n;
314 }
315
318 static bool isDigit(CharT ch)
319 {
320 typename std::char_traits<CharT>::int_type cc = std::char_traits<CharT>::to_int_type(ch);
321 return cc > 47 && cc < 58;
322 }
323
326 static unsigned toDigit(CharT ch)
327 {
328 typename std::char_traits<CharT>::int_type cc = std::char_traits<CharT>::to_int_type(ch);
329 return static_cast<unsigned>(cc - 48);
330 }
331};
332
333
334template <typename CharType>
335struct OctalFormat : public NumberFormat<CharType>
336{
337 typedef CharType CharT;
338
339 static const unsigned base = 8;
340
343 static CharT toChar(unsigned char n)
344 {
345 return '0' + n;
346 }
347
350 static bool isDigit(CharT ch)
351 {
352 typename std::char_traits<CharT>::int_type cc = std::char_traits<CharT>::to_int_type(ch);
353 return cc > 47 && cc < 56;
354 }
355
358 static unsigned toDigit(CharT ch)
359 {
360 typename std::char_traits<CharT>::int_type cc = std::char_traits<CharT>::to_int_type(ch);
361
362 // let negatives overrun
363 return static_cast<unsigned>(cc - 48);
364 }
365};
366
367
368template <typename CharType>
369struct HexFormat : public NumberFormat<CharType>
370{
371 typedef CharType CharT;
372
373 static const unsigned base = 16;
374
377 static CharT toChar(unsigned char n)
378 {
379 n &= 0x1F; // prevent overrun
380 static const char* digtab = "0123456789abcdef";
381 return digtab[n];
382 }
383
386 static bool isDigit(CharT ch)
387 {
388 typename std::char_traits<CharT>::int_type cc = std::char_traits<CharT>::to_int_type(ch);
389 return (cc > 47 && cc < 59) || (cc > 64 && cc < 71) || (cc > 96 && cc < 103);
390 }
391
394 static unsigned toDigit(CharT ch)
395 {
396 static const unsigned char chartab[64] =
397 {
398 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
399 0xFF,10,11,12,13,14,15,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
400 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
401 0xFF,10,11,12,13,14,15,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
402 };
403
404 typename std::char_traits<CharT>::int_type cc = std::char_traits<CharT>::to_int_type(ch);
405
406 unsigned idx = static_cast<unsigned>(cc - 48);
407 return chartab[ idx ];
408 }
409};
410
411
412template <typename CharType>
413struct BinaryFormat : public NumberFormat<CharType>
414{
415 typedef CharType CharT;
416
417 static const unsigned base = 2;
418
421 static CharT toChar(unsigned char n)
422 {
423 return '0' + n;
424 }
425
428 static bool isDigit(CharT ch)
429 {
430 typename std::char_traits<CharT>::int_type cc = std::char_traits<CharT>::to_int_type(ch);
431 return cc > 47 && cc < 50;
432 }
433
436 static unsigned toDigit(CharT ch)
437 {
438 typename std::char_traits<CharT>::int_type cc = std::char_traits<CharT>::to_int_type(ch);
439 return static_cast<unsigned>(cc - 48);
440 }
441};
442
443
444template <typename CharType>
445struct FloatFormat : public DecimalFormat<CharType>
446{
447 typedef CharType CharT;
448
449 static CharT point()
450 { return '.'; }
451
452 static CharT e()
453 { return 'e'; }
454
455 static bool isE(CharT ch)
456 { return ch == 'E' || ch == 'e'; }
457
458 static bool isNan(CharT ch, unsigned pos, bool& isNan)
459 {
460 switch(pos)
461 {
462 case 0: return ch == 'n' || ch == 'N';
463 case 1: return ch == 'a' || ch == 'A';
464 case 2: isNan = ch == 'n' || ch == 'N'; return isNan;
465 }
466
467 return (ch > 46 && ch < 58) || (ch > 64 && ch < 91) || (ch > 96 && ch < 123);
468 }
469
470 static bool isInfinity(CharT ch, unsigned pos, bool& isInf)
471 {
472 switch(pos)
473 {
474 case 0: return ch == 'i' || ch == 'I';
475 case 1: return ch == 'n' || ch == 'N';
476 case 2: isInf = ch == 'f' || ch == 'F'; return isInf;
477 case 3: return ch == 'i' || ch == 'I';
478 case 4: return ch == 'n' || ch == 'N';
479 case 5: return ch == 'i' || ch == 'I';
480 case 6: return ch == 't' || ch == 'T';
481 case 7: isInf = ch == 'y' || ch == 'Y'; return isInf;
482 }
483
484 return false;
485 }
486
487 static const CharT* nan()
488 {
489 static const CharT nanstr[] = { 'n', 'a', 'n', 0 };
490 return nanstr;
491 }
492
493 static const CharT* infinity()
494 {
495 static const CharT nanstr[] = { 'i', 'n', 'f', 0 };
496 return nanstr;
497 }
498};
499
500
501inline unsigned char getAbs(char i, bool& isNeg)
502{
503 isNeg = i < 0;
504 unsigned char u = isNeg ? -i : static_cast<unsigned char>(i);
505 return u;
506}
507
508
509inline unsigned char getAbs(unsigned char i, bool& isNeg)
510{
511 isNeg = false;
512 return i;
513}
514
515
516inline unsigned short getAbs(short i, bool& isNeg)
517{
518 isNeg = i < 0;
519 unsigned short u = isNeg ? -i : static_cast<unsigned short>(i);
520 return u;
521}
522
523
524inline unsigned short getAbs(unsigned short i, bool& isNeg)
525{
526 isNeg = false;
527 return i;
528}
529
530
531inline unsigned int getAbs(int i, bool& isNeg)
532{
533 isNeg = i < 0;
534 unsigned int u = isNeg ? -i : static_cast<unsigned int>(i);
535 return u;
536}
537
538
539inline unsigned int getAbs(unsigned int i, bool& isNeg)
540{
541 isNeg = false;
542 return i;
543}
544
545
546inline unsigned long getAbs(long i, bool& isNeg)
547{
548 isNeg = i < 0;
549 unsigned long u = isNeg ? -i : static_cast<unsigned long>(i);
550 return u;
551}
552
553
554inline unsigned long getAbs(unsigned long i, bool& isNeg)
555{
556 isNeg = false;
557 return i;
558}
559
560
561inline unsigned long long getAbs(long long i, bool& isNeg)
562{
563 isNeg = i < 0;
564 unsigned long long u = isNeg ? -i : static_cast<unsigned long long>(i);
565 return u;
566}
567
568
569inline unsigned long long getAbs(unsigned long long i, bool& isNeg)
570{
571 isNeg = false;
572 return i;
573}
574
575
576template <typename CharT, typename T, typename FormatT>
577inline CharT* formatInt(CharT* buf, std::size_t buflen, T si, const FormatT& fmt)
578{
579 typedef typename IntTraits<T>::Unsigned UnsignedInt;
580
581 CharT* end = buf + buflen;
582 CharT* cur = end;
583
584 const unsigned base = fmt.base;
585
586 bool isNeg = false;
587 UnsignedInt u = getAbs(si, isNeg);
588
589 do
590 {
591 unsigned char lsd = static_cast<unsigned char>(u % base);
592 u /= base;
593 --cur;
594 *cur = fmt.toChar(lsd);
595 }
596 while(u != 0 && cur != buf);
597
598 if(cur == buf)
599 return buf;
600
601 if(isNeg)
602 {
603 --cur;
604 *cur = fmt.minus();
605 }
606
607 return cur;
608}
609
610
611template <typename CharT, typename T>
612inline CharT* formatInt(CharT* buf, std::size_t buflen, T i, const BinaryFormat<CharT>& fmt)
613{
614 CharT* end = buf + buflen;
615 CharT* cur = end;
616 T mask = 1;
617
618 do
619 {
620 --cur;
621 unsigned char d = static_cast<unsigned char>(i & mask);
622 *cur = fmt.toChar(d);
623 i = i >> 1;
624 }
625 while(i != 0 && cur != buf);
626
627 if(cur == buf)
628 return buf;
629
630 return cur;
631}
632
633
634template <typename OutIterT, typename T, typename FormatT>
635inline OutIterT formatInt(OutIterT it, T i, const FormatT& fmt)
636{
637 // large enough even for binary and a sign
638 const std::size_t buflen = (sizeof(T) * 8) + 1;
639 typename FormatT::CharT buf[buflen];
640 typename FormatT::CharT* p = Pt::formatInt(buf, buflen, i, fmt);
641
642 typename FormatT::CharT* end = buf + buflen;
643 for(; p != end; ++p)
644 *it++ = *p;
645
646 return it;
647}
648
649
650template <typename OutIterT, typename T>
651inline OutIterT formatInt(OutIterT it, T i)
652{
653 DecimalFormat<char> fmt;
654 return formatInt(it, i, fmt);
655}
656
657
658template <typename CharT, typename T, typename FormatT>
659inline int formatFloat(CharT* fraction, int fractSize, int& intpart, int& exp, T n,
660 const FormatT& fmt, int precision, bool fixed)
661{
662 intpart = 0;
663 exp = 0;
664
665 if(n == T(0.0) || n != n)
666 return 0;
667
668 const bool neg = n < 0;
669 if(n < 0)
670 n = -n;
671
672 if( n == std::numeric_limits<T>::infinity() )
673 return 0;
674
675 exp = static_cast<int>( std::floor( std::log10(n) ) );
676
677 // precision for fixed notation is the maximum number of digits after the
678 // decimal point, otherwise the maximum number of significant digits
679 if(fixed)
680 precision += exp + 1;
681
682 if(precision > fractSize)
683 precision = fractSize;
684
685 // intpart is first significant digit
686 --precision;
687
688 // move remaining significant digits before dot and add 0.5 to round
689 // last significant digit. This might increase the exponent, for which
690 // we check later.
691 n *= std::pow(T(10.0), precision - exp);
692 n += 0.5;
693
694 int places = 0;
695 bool trailZero = true;
696 for(int d = precision - 1; d >= 0; --d)
697 {
698 T p = n / T(10.0);
699 T q = std::floor(p) * T(10.0);
700 int digit = static_cast<int>( std::floor(n - q) );
701 n = p;
702
703 // ignore trailing zeros
704 trailZero = trailZero && (digit == 0);
705
706 if( trailZero )
707 continue;
708
709 CharT c = fmt.toChar( static_cast<unsigned char>(digit) );
710 assert(d < fractSize);
711 fraction[d] = c;
712
713 ++places;
714 }
715
716 intpart = static_cast<int>( std::floor(n) );
717
718 // check if rounding increased the exponent
719 if(intpart == 10)
720 {
721 ++exp;
722 intpart = 1;
723 }
724
725 if(neg)
726 intpart = -intpart;
727
728 return places;
729}
730
731
732template <typename OutIterT, typename T, typename FormatT>
733inline OutIterT formatFloat(OutIterT it, T d,
734 const FormatT& fmt, int precision, bool fixed)
735{
736 typedef typename FormatT::CharT CharT;
737 CharT zero = fmt.toChar(0);
738
739 // 1. Test for not-a-number with d != d
740 if( d != d )
741 {
742 for(const CharT* nanstr = fmt.nan(); *nanstr != 0; ++nanstr)
743 {
744 *it = *nanstr;
745 ++it;
746 }
747
748 return it;
749 }
750
751 // 2. check sign
752 if(d < 0.0)
753 {
754 *it = fmt.minus();
755 ++it;
756 }
757
758 T num = std::fabs(d);
759
760 // 3. Test for infinity
761 if( num == std::numeric_limits<T>::infinity() )
762 {
763 for(const CharT* infstr = fmt.infinity(); *infstr != 0; ++infstr)
764 {
765 *it = *infstr;
766 ++it;
767 }
768
769 return it;
770 }
771
772 const int bufsize = std::numeric_limits<T>::digits10;
773 CharT fract[bufsize];
774 int i = 0;
775 int e = 0;
776 int fractSize = Pt::formatFloat(fract, bufsize, i, e, num, fmt, precision, fixed);
777 int fillSize = fractSize;
778
779 int n = 0;
780 if(e >= 0)
781 {
782 *it++ = fmt.toChar(i);
783
784 for(; n < e; ++n)
785 *it++ = (n < fractSize) ? fract[n] : zero;
786
787 *it++ = fmt.point();
788
789 // show at least one digit after decimal point
790 *it++ = (n < fractSize) ? fract[n] : zero;
791 ++n;
792
793 // fill zeros to fixed precision
794 if(fixed)
795 fillSize = n + precision - 1;
796 }
797 else // e < 0
798 {
799 *it++ = zero;
800 *it++ = fmt.point();
801
802 if(fixed)
803 {
804 e = std::max(-precision, e);
805 fillSize = precision + e;
806 }
807
808 while(++e < 0)
809 *it++ = zero;
810
811 *it++ = fmt.toChar(i);
812 }
813
814 for(; n < fillSize; ++n)
815 *it++ = (n < fractSize) ? fract[n] : zero;
816
817 return it;
818}
819
820
821template <typename OutIterT, typename T>
822inline OutIterT formatFloat(OutIterT it, T d)
823{
824 const int precision = std::numeric_limits<T>::digits10;
825 FloatFormat<char> fmt;
826 return formatFloat(it, d, fmt, precision);
827}
828
829
830template <typename OutIterT, typename T>
831OutIterT formatFloat(OutIterT it, T d, int precision, bool fixed)
832{
833 FloatFormat<char> fmt;
834 return formatFloat(it, d, fmt, precision, fixed);
835}
836
837
838template <typename InIterT, typename FormatT>
839InIterT getWhitespace(InIterT it, InIterT end, const FormatT& fmt)
840{
841 while( it != end && fmt.isSpace(*it) )
842 ++it;
843
844 return it;
845}
846
847
848template <typename InIterT, typename FormatT>
849InIterT getSign(InIterT it, InIterT end, bool& pos, const FormatT& fmt)
850{
851 pos = true;
852
853 if(it == end)
854 return it;
855
856 if( *it == fmt.minus() )
857 {
858 pos = false;
859 ++it;
860 }
861 else if( *it == fmt.plus() )
862 {
863 ++it;
864 }
865
866 return it;
867}
868
869
870template <typename InIterT, typename T, typename FormatT>
871InIterT parseInt(InIterT it, InIterT end, T& n, const FormatT& fmt, bool& ok)
872{
873 typedef typename IntTraits<T>::Unsigned UnsignedInt;
874 typedef typename IntTraits<T>::Signed SignedInt;
875
876 n = 0;
877 ok = false;
878 UnsignedInt max = static_cast<UnsignedInt>( std::numeric_limits<T>::max() );
879
880 it = getWhitespace(it, end, fmt);
881
882 bool pos = false;
883 it = getSign(it, end, pos, fmt);
884
885 if (it == end)
886 return it;
887
888 bool isNeg = ! pos;
889 if( isNeg )
890 {
891 // return if minus sign was parsed for unsigned type
892 if( isNeg != std::numeric_limits<T>::is_signed)
893 return it;
894
895 // abs(min) is max for negative signed types
896 SignedInt smin = std::numeric_limits<T>::min();
897 max = static_cast<UnsignedInt>(-smin);
898 }
899
900 // parse number
901 UnsignedInt u = 0;
902 const UnsignedInt base = fmt.base;
903 unsigned d = 0;
904 while(it != end)
905 {
906 if( ! fmt.isDigit(*it) )
907 break;
908
909 d = fmt.toDigit(*it);
910
911 if ( u != 0u && base > (max/u) )
912 return it;
913
914 u *= base;
915
916 if(static_cast<UnsignedInt>(d) > max - u)
917 return it;
918
919 u += static_cast<UnsignedInt>(d);
920 ++it;
921 }
922
923 if( isNeg )
924 n = static_cast<T>(u * -1);
925 else
926 n = static_cast<T>(u);
927
928 ok = true;
929 return it;
930}
931
932
933template <typename InIterT, typename T>
934InIterT parseInt(InIterT it, InIterT end, T& n, bool& ok)
935{
936 typedef typename std::iterator_traits<InIterT>::value_type CharType;
937 return parseInt(it, end, n, DecimalFormat<CharType>(), ok );
938}
939
940
941template <typename InIterT, typename T, typename FormatT>
942InIterT parseFloat(InIterT it, InIterT end, T& n, const FormatT& fmt, bool& ok)
943{
944 typedef typename FormatT::CharT CharT;
945 CharT zero = fmt.toChar(0);
946 n = 0.0;
947 ok = false;
948
949 it = getWhitespace(it, end, fmt);
950
951 bool pos = false;
952 it = getSign(it, end, pos, fmt);
953
954 if(it == end)
955 return it;
956
957 unsigned strpos = 0;
958 if( fmt.isNan(*it, strpos, ok) )
959 {
960 while( ++it != end && fmt.isNan(*it, ++strpos, ok) )
961 ;
962
963 if(ok)
964 n = std::numeric_limits<T>::quiet_NaN();
965
966 return it;
967 }
968
969 strpos = 0;
970 if( fmt.isInfinity(*it, strpos, ok) )
971 {
972 while( ++it != end && fmt.isInfinity(*it, ++strpos, ok) )
973 ;
974
975 if(ok)
976 {
977 n = pos ? std::numeric_limits<T>::infinity()
978 : std::numeric_limits<T>::infinity() * -1;
979 }
980
981 return it;
982 }
983
984 if(it == end)
985 return it;
986
987 // integral part
988 bool withFractional = false;
989 for( ; it != end; ++it)
990 {
991 if( *it == fmt.point() )
992 {
993 withFractional = true;
994 ++it;
995 break;
996 }
997
998 if( ! fmt.isDigit(*it) )
999 break;
1000
1001 unsigned digit = fmt.toDigit(*it);
1002
1003 n *= 10;
1004 n += digit;
1005 }
1006
1007 // it is ok, if fraction is missing
1008 if(it == end)
1009 {
1010 if( ! pos )
1011 n *= -1;
1012
1013 ok = true;
1014 return it;
1015 }
1016
1017 T base = 10.0;
1018 if(withFractional)
1019 {
1020 // fractional part, ignore 0 digits after dot
1021 unsigned short fractDigits = 0;
1022 std::size_t maxDigits = std::numeric_limits<unsigned short>::max() - std::numeric_limits<T>::digits10;
1023 while(it != end && *it == zero)
1024 {
1025 if( fractDigits > maxDigits )
1026 return it;
1027
1028 ++fractDigits;
1029 ++it;
1030 }
1031
1032 // fractional part, parse like integer, skip insignificant digits
1033 unsigned short significants = 0;
1034 T fraction = 0.0;
1035 for( ; it != end; ++it)
1036 {
1037 if( ! fmt.isDigit(*it) )
1038 break;
1039
1040 unsigned digit = fmt.toDigit(*it);
1041
1042 if( significants <= std::numeric_limits<T>::digits10 )
1043 {
1044 fraction *= 10;
1045 fraction += digit;
1046
1047 ++fractDigits;
1048 ++significants;
1049 }
1050 }
1051
1052 // fractional part, scale down
1053 fraction /= std::pow(base, T(fractDigits));
1054 n += fraction;
1055 }
1056
1057 // exponent [e|E][+|-][0-9]*
1058 if(it != end && fmt.isE(*it) )
1059 {
1060 if(++it == end)
1061 return it;
1062
1063 long exp = 0;
1064 it = parseInt(it, end, exp, fmt, ok);
1065 if( ! ok )
1066 return it;
1067
1068 n *= std::pow(base, T(exp));
1069 }
1070
1071 if( ! pos )
1072 n *= -1;
1073
1074 ok = true;
1075 return it;
1076}
1077
1078
1079template <typename InIterT, typename T>
1080InIterT parseFloat(InIterT it, InIterT end, T& n, bool& ok)
1081{
1082 typedef typename std::iterator_traits<InIterT>::value_type CharType;
1083 return parseFloat( it, end, n, FloatFormat<CharType>(), ok);
1084}
1085
1086} // namespace Pt
1087
1088#endif
ConversionError(const std::string &msg)
Construct with error message.
R narrow(T from)
Checked numeric conversion.
Definition Convert.h:112
OutIterT formatInt(OutIterT it, T i, const FormatT &fmt)
Formats an integer in a given format.
Definition Convert.h:635
InIterT parseFloat(InIterT it, InIterT end, T &n, const FormatT &fmt, bool &ok)
Parses a floating point value in a given format.
Definition Convert.h:942
OutIterT formatFloat(OutIterT it, T d, const FormatT &fmt, int precision, bool fixed=false)
Formats a floating point value in a given format.
Definition Convert.h:733
InIterT parseInt(InIterT it, InIterT end, T &n, const FormatT &fmt, bool &ok)
Parses an integer value in a given format.
Definition Convert.h:871
Core module.
Definition Allocator.h:33