3 This file is part of libmspstrings
4 Copyright © 2006-2008 Mikko Rasa
5 Distributed under the LGPL
10 #include "lexicalcast.h"
20 { enum { result=!(static_cast<T>(-1)>0) }; };
22 template<typename T, bool f=(sizeof(T)>sizeof(unsigned long))>
24 { typedef unsigned long Type; };
27 struct Temporary<T, true>
32 typedef unsigned long long Type;
36 /* Helper to avoid warnings about an unsigned type never being < 0 */
37 template<typename T, bool f=IsSigned<T>::result>
39 { static bool eval(T v) { return v<0; } };
42 struct IsNegative<T, false>
43 { static bool eval(T) { return false; } };
45 /* Helper to avoid errors about ambiguous function calls since there are no
46 overloads of abs for unsigned types */
47 template<typename T, bool f=IsSigned<T>::result>
49 { static T eval(T v) { return v<0 ? -v : v; } };
52 struct Absolute<T, false>
53 { static T eval(T v) { return v; } };
56 /*** Integer conversions ***/
58 const char udigits[]="0123456789ABCDEF";
59 const char ldigits[]="0123456789abcdef";
62 char *int_to_str(T v, const Fmt &f, char *end)
64 if(f.get_type()==Fmt::CHAR)
72 // Find out the base to use
73 unsigned base=f.get_base();
77 // Format the number, starting from the least significant digit
78 const char *digits=(f.get_uppercase() ? udigits : ldigits);
81 typename Temporary<T>::Type w=Absolute<T>::eval(v);
84 *--ptr=digits[w%base];
91 char sign=(IsNegative<T>::eval(v) ? '-' : f.get_showpos() ? '+' : 0);
94 /* Zero-fill, taking base/sign size into account. The expression is a
95 bit ugly, but saves having to write code for creating the prefix both
97 unsigned pfxsize=((f.get_showbase() && base!=10) ? base==8 ? 1 : 2 : 0) + (sign!=0);
98 for(unsigned i=(end-ptr)+pfxsize; i<f.get_width(); ++i)
102 if(f.get_showbase() && v!=0)
104 // Add base indicator
106 *--ptr=(f.get_uppercase() ? 'B' : 'b');
108 *--ptr=(f.get_uppercase() ? 'X' : 'x');
120 string int_to_str(T v, const Fmt &f)
122 unsigned size=max(f.get_width(), max(f.get_precision(), sizeof(T)*8+3));
123 char *buf=new char[size];
124 string result(int_to_str(v, f, buf+size), buf+size);
130 T str_to_int(const std::string &s, const Fmt &f)
133 throw LexicalError("Empty input in integer conversion");
135 std::string::const_iterator i=s.begin();
137 // See if the input starts with a sign
141 if(!IsSigned<T>::result)
142 throw LexicalError("Negative sign in unsigned integer conversion");
149 // Must have some digits to convert
151 throw LexicalError("Missing digits in integer conversion");
154 if(!base && i!=s.end())
156 // Automatic base detection requested, figure it out
157 if(*i=='0' && ++i!=s.end())
159 if(*i=='x' || *i=='X')
164 else if(*i=='b' || *i=='B')
178 for(; i!=s.end(); ++i)
181 if(*i>='0' && *i<='9')
183 else if(*i>='A' && *i<='F')
185 else if(*i>='a' && *i<='f')
188 throw LexicalError("Invalid digit in integer conversion");
189 T next=result*base+digit;
190 if(next/base!=result)
191 throw LexicalError("Overflow in integer conversion");
202 /*** Boolean conversions ***/
204 string bool_to_str(bool b, const Fmt &f)
206 if(f.get_type()==Fmt::STR)
207 return b ? "true" : "false";
209 return b ? "1" : "0";
212 bool str_to_bool(const string &s)
214 if(s=="1" || s=="true" || s=="yes" || s=="on")
216 else if(s=="0" || s=="false" || s=="no" || s=="off")
218 throw LexicalError("Invalid input in boolean conversion");
222 /*** Floating-point conversions ***/
225 string flt_to_str(T v, const Fmt &f)
227 if(f.get_type()==Fmt::CHAR)
228 throw LexicalError("Character format in floating-point conversion");
230 Fmt::FloatMode mode=f.get_floatmode();
231 long double w=abs(v);
232 char sign=(v<0 ? '-' : f.get_showpos() ? '+' : 0);
234 // Handle infinity and not-a-number as special cases
241 result+=(f.get_uppercase() ? "NAN" : "nan");
243 result+=(f.get_uppercase() ? "INF" : "inf");
244 if(result.size()<f.get_width())
245 result=string(f.get_width()-result.size(), ' ')+result;
249 /* Find out the base-10 exponent. Building up the multiplier / divisor
250 first helps with accuracy in some cases. */
262 else if(mode!=Fmt::FIXED && w<1 && w!=0)
273 // Decide how to format the number
280 digits=point+f.get_precision();
282 else if(mode==Fmt::SCI)
284 digits=f.get_precision()+1;
289 digits=max(f.get_precision(), 1U);
290 if(exp<-4 || exp>=static_cast<int>(digits))
304 w+=5.0l/pow(10.0l, digits);
307 // Rounding bumped us to the next exponent, deal with it
309 if(mode==Fmt::AUTOFLT && exp+1==static_cast<int>(digits))
323 // Create a buffer and start from the end
324 unsigned size=max(f.get_width(), digits+8);
325 char *buf=new char[size];
332 ptr=int_to_str(exp, Fmt().showpos().fill('0').width(3), ptr);
333 *--ptr=(f.get_uppercase() ? 'E' : 'e');
336 // Format mantissa left-to-right
338 ptr-=digits+(point<digits || f.get_showpoint());
340 for(unsigned i=0; i<digits; ++i)
344 if(showexp || static_cast<int>(i)>=-exp)
346 int digit=static_cast<int>(w);
354 if(f.get_showpoint())
356 // Radix point requested but not displayed yet, add it
360 else if(mode==Fmt::AUTOFLT && digits>point)
362 // Remove trailing zeroes from fraction and a lone radix point
375 // Add filling and sign
376 if(f.get_fill()=='0')
378 unsigned pfxlen=(sign!=0);
379 while(end-ptr+pfxlen<f.get_width())
385 string result(ptr, end);
391 T str_to_flt(const string &s, const Fmt &)
394 throw LexicalError("Empty input in floating-point conversion");
396 std::string::const_iterator i=s.begin();
398 // See if the input starts with a sign
408 // Must have some digits to convert
410 throw LexicalError("Missing digits in floating-point conversion");
416 bool point_seen=false;
417 for(; i!=s.end(); ++i)
422 throw LexicalError("Extra point in floating-point conversion");
425 else if(*i>='0' && *i<='9')
431 else if(*i=='e' || *i=='E')
433 // We have an exponent
436 exp+=str_to_int<int>(string(i, s.end()), Fmt());
437 // str_to_int has eaten the rest of the input or thrown
441 throw LexicalError("Invalid digit in floating-point conversion");
444 // Scale and negate the result as needed
463 /*** String conversions ***/
465 string str_to_str(const string &s, const Fmt &f)
467 if(f.get_type()==Fmt::NUM)
468 throw LexicalError("Numeric format in string conversion");
476 void LexicalConverter::result(const string &s)
478 if(s.size()<fmt.get_width())
480 if(fmt.get_align()==Fmt::RIGHT)
481 buf=string(fmt.get_width()-s.size(), fmt.get_fill())+s;
483 buf=s+string(fmt.get_width()-s.size(), fmt.get_fill());
492 void operator<<(LexicalConverter &c, char v)
494 Fmt::Type type=c.get_fmt().get_type();
496 c.result(int_to_str(v, c.get_fmt()));
498 c.result(string(1, v));
501 void operator<<(LexicalConverter &c, signed char v)
502 { c.result(int_to_str(v, c.get_fmt())); }
504 void operator<<(LexicalConverter &c, short v)
505 { c.result(int_to_str(v, c.get_fmt())); }
507 void operator<<(LexicalConverter &c, int v)
508 { c.result(int_to_str(v, c.get_fmt())); }
510 void operator<<(LexicalConverter &c, long v)
511 { c.result(int_to_str(v, c.get_fmt())); }
513 void operator<<(LexicalConverter &c, unsigned char v)
514 { c.result(int_to_str(v, c.get_fmt())); }
516 void operator<<(LexicalConverter &c, unsigned short v)
517 { c.result(int_to_str(v, c.get_fmt())); }
519 void operator<<(LexicalConverter &c, unsigned v)
520 { c.result(int_to_str(v, c.get_fmt())); }
522 void operator<<(LexicalConverter &c, unsigned long v)
523 { c.result(int_to_str(v, c.get_fmt())); }
526 void operator<<(LexicalConverter &c, long long v)
527 { c.result(int_to_str(v, c.get_fmt())); }
529 void operator<<(LexicalConverter &c, unsigned long long v)
530 { c.result(int_to_str(v, c.get_fmt())); }
533 void operator<<(LexicalConverter &c, bool v)
534 { c.result(bool_to_str(v, c.get_fmt())); }
536 void operator<<(LexicalConverter &c, float v)
537 { c.result(flt_to_str(v, c.get_fmt())); }
539 void operator<<(LexicalConverter &c, double v)
540 { c.result(flt_to_str(v, c.get_fmt())); }
542 void operator<<(LexicalConverter &c, long double v)
543 { c.result(flt_to_str(v, c.get_fmt())); }
545 void operator<<(LexicalConverter &c, const string &s)
546 { c.result(str_to_str(s, c.get_fmt())); }
548 void operator<<(LexicalConverter &c, const char *s)
549 { c.result(str_to_str(s, c.get_fmt())); }
551 void operator<<(LexicalConverter &c, const void *p)
552 { c.result(int_to_str(reinterpret_cast<unsigned long>(p), c.get_fmt())); }
557 void operator>>(const LexicalConverter &c, char &v)
559 if(c.get_fmt().get_type()==Fmt::NUM)
560 v=str_to_int<char>(c.get(), c.get_fmt());
563 const std::string &s=c.get();
565 throw LexicalError("Empty input in character conversion");
567 throw LexicalError("Extra input in character conversion");
572 void operator>>(const LexicalConverter &c, signed char &v)
573 { v=str_to_int<signed char>(c.get(), c.get_fmt()); }
575 void operator>>(const LexicalConverter &c, short &v)
576 { v=str_to_int<short>(c.get(), c.get_fmt()); }
578 void operator>>(const LexicalConverter &c, int &v)
579 { v=str_to_int<int>(c.get(), c.get_fmt()); }
581 void operator>>(const LexicalConverter &c, long &v)
582 { v=str_to_int<long>(c.get(), c.get_fmt()); }
584 void operator>>(const LexicalConverter &c, unsigned char &v)
585 { v=str_to_int<unsigned char>(c.get(), c.get_fmt()); }
587 void operator>>(const LexicalConverter &c, unsigned short &v)
588 { v=str_to_int<unsigned short>(c.get(), c.get_fmt()); }
590 void operator>>(const LexicalConverter &c, unsigned int &v)
591 { v=str_to_int<unsigned int>(c.get(), c.get_fmt()); }
593 void operator>>(const LexicalConverter &c, unsigned long &v)
594 { v=str_to_int<unsigned long>(c.get(), c.get_fmt()); }
597 void operator>>(const LexicalConverter &c, long long &v)
598 { v=str_to_int<long long>(c.get(), c.get_fmt()); }
600 void operator>>(const LexicalConverter &c, unsigned long long &v)
601 { v=str_to_int<unsigned long long>(c.get(), c.get_fmt()); }
604 void operator>>(const LexicalConverter &c, bool &v)
605 { v=str_to_bool(c.get()); }
607 void operator>>(const LexicalConverter &c, float &v)
608 { v=str_to_flt<float>(c.get(), c.get_fmt()); }
610 void operator>>(const LexicalConverter &c, double &v)
611 { v=str_to_flt<double>(c.get(), c.get_fmt()); }
613 void operator>>(const LexicalConverter &c, long double &v)
614 { v=str_to_flt<long double>(c.get(), c.get_fmt()); }
616 void operator>>(const LexicalConverter &c, string &s)
617 { s=str_to_str(c.get(), c.get_fmt()); }