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