]> git.tdb.fi Git - libs/core.git/blob - source/lexicalcast.cpp
Rewrite lexical_cast to use internal conversion routines
[libs/core.git] / source / lexicalcast.cpp
1 /* $Id$
2
3 This file is part of libmspstrings
4 Copyright © 2006-2008 Mikko Rasa
5 Distributed under the LGPL
6 */
7
8 #include <cmath>
9 #include <limits>
10 #include "lexicalcast.h"
11
12 using namespace std;
13
14 namespace {
15
16 using namespace Msp;
17
18 template<typename T>
19 struct IsSigned
20 { enum { result=!(static_cast<T>(-1)>0) }; };
21
22 template<typename T, bool f=(sizeof(T)>sizeof(unsigned long))>
23 struct Temporary
24 { typedef unsigned long Type; };
25
26 template<typename T>
27 struct Temporary<T, true>
28 {
29 #ifdef WIN32
30         typedef __int64 Type;
31 #else
32         typedef unsigned long long Type;
33 #endif
34 };
35
36 /* Helper to avoid warnings about an unsigned type never being < 0 */
37 template<typename T, bool f=IsSigned<T>::result>
38 struct IsNegative
39 { static bool eval(T v) { return v<0; } };
40
41 template<typename T>
42 struct IsNegative<T, false>
43 { static bool eval(T) { return false; } };
44
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>
48 struct Absolute
49 { static T eval(T v) { return v<0 ? -v : v; } };
50
51 template<typename T>
52 struct Absolute<T, false>
53 { static T eval(T v) { return v; } };
54
55
56 /*** Integer conversions ***/
57
58 const char udigits[]="0123456789ABCDEF";
59 const char ldigits[]="0123456789abcdef";
60
61 template<typename T>
62 char *int_to_str(T v, const Fmt &f, char *end)
63 {
64         if(f.get_type()==Fmt::CHAR)
65         {
66                 *--end=v;
67                 return end;
68         }
69
70         char *ptr=end;
71
72         // Find out the base to use
73         unsigned base=f.get_base();
74         if(!base)
75                 base=10;
76
77         // Format the number, starting from the least significant digit
78         const char *digits=(f.get_uppercase() ? udigits : ldigits);
79         if(v)
80         {
81                 typename Temporary<T>::Type w=Absolute<T>::eval(v);
82                 while(w)
83                 {
84                         *--ptr=digits[w%base];
85                         w/=base;
86                 }
87         }
88         else
89                 *--ptr=digits[0];
90
91         char sign=(IsNegative<T>::eval(v) ? '-' : f.get_showpos() ? '+' : 0);
92         if(f.get_fill()=='0')
93         {
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
96                 ways. */
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)
99                         *--ptr='0';
100         }
101
102         if(f.get_showbase() && v!=0)
103         {
104                 // Add base indicator
105                 if(base==2)
106                         *--ptr=(f.get_uppercase() ? 'B' : 'b');
107                 else if(base==16)
108                         *--ptr=(f.get_uppercase() ? 'X' : 'x');
109                 if(base!=10)
110                         *--ptr='0';
111         }
112
113         if(sign)
114                 *--ptr=sign;
115
116         return ptr;
117 }
118
119 template<typename T>
120 string int_to_str(T v, const Fmt &f)
121 {
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);
125         delete[] buf;
126         return result;
127 }
128
129 template<typename T>
130 T str_to_int(const std::string &s, const Fmt &f)
131 {
132         if(s.empty())
133                 throw LexicalError("Empty input in integer conversion");
134
135         std::string::const_iterator i=s.begin();
136
137         // See if the input starts with a sign
138         bool neg=false;
139         if(*i=='-')
140         {
141                 if(!IsSigned<T>::result)
142                         throw LexicalError("Negative sign in unsigned integer conversion");
143                 neg=true;
144                 ++i;
145         }
146         else if(*i=='+')
147                 ++i;
148
149         // Must have some digits to convert
150         if(i==s.end())
151                 throw LexicalError("Missing digits in integer conversion");
152
153         T base=f.get_base();
154         if(!base && i!=s.end())
155         {
156                 // Automatic base detection requested, figure it out
157                 if(*i=='0' && ++i!=s.end())
158                 {
159                         if(*i=='x' || *i=='X')
160                         {
161                                 base=16;
162                                 ++i;
163                         }
164                         else if(*i=='b' || *i=='B')
165                         {
166                                 base=2;
167                                 ++i;
168                         }
169                         else
170                                 base=8;
171                 }
172                 else
173                         base=10;
174         }
175
176         // Parse the digits
177         T result=0;
178         for(; i!=s.end(); ++i)
179         {
180                 T digit=base;
181                 if(*i>='0' && *i<='9')
182                         digit=*i-'0';
183                 else if(*i>='A' && *i<='F')
184                         digit=*i-'A'+10;
185                 else if(*i>='a' && *i<='f')
186                         digit=*i-'a'+10;
187                 if(digit>=base)
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");
192                 result=next;
193         }
194
195         if(neg)
196                 result=-result;
197
198         return result;
199 }
200
201
202 /*** Boolean conversions ***/
203
204 string bool_to_str(bool b, const Fmt &f)
205 {
206         if(f.get_type()==Fmt::STR)
207                 return b ? "true" : "false";
208         else
209                 return b ? "1" : "0";
210 }
211
212 bool str_to_bool(const string &s)
213 {
214         if(s=="1" || s=="true" || s=="yes" || s=="on")
215                 return true;
216         else if(s=="0" || s=="false" || s=="no" || s=="off")
217                 return true;
218         throw LexicalError("Invalid input in boolean conversion");
219 }
220
221
222 /*** Floating-point conversions ***/
223
224 template<typename T>
225 string flt_to_str(T v, const Fmt &f)
226 {
227         if(f.get_type()==Fmt::CHAR)
228                 throw LexicalError("Character format in floating-point conversion");
229
230         Fmt::FloatMode mode=f.get_floatmode();
231         long double w=abs(v);
232         char sign=(v<0 ? '-' : f.get_showpos() ? '+' : 0);
233
234         // Handle infinity and not-a-number as special cases
235         if(!(w+w>w) && w!=0)
236         {
237                 string result;
238                 if(sign)
239                         result+=sign;
240                 if(!(w>=0))
241                         result+=(f.get_uppercase() ? "NAN" : "nan");
242                 else
243                         result+=(f.get_uppercase() ? "INF" : "inf");
244                 if(result.size()<f.get_width())
245                         result=string(f.get_width()-result.size(), ' ')+result;
246                 return result;
247         }
248
249         /* Find out the base-10 exponent.  Building up the multiplier / divisor
250         first helps with accuracy in some cases. */
251         int exp=0;
252         if(w>=10)
253         {
254                 long double div=1;
255                 while(div*10<w)
256                 {
257                         ++exp;
258                         div*=10;
259                 }
260                 w/=div;
261         }
262         else if(mode!=Fmt::FIXED && w<1 && w!=0)
263         {
264                 long double mul=1;
265                 while(w*mul<1)
266                 {
267                         --exp;
268                         mul*=10;
269                 }
270                 w*=mul;
271         }
272
273         // Decide how to format the number
274         unsigned digits;
275         unsigned point=1;
276         bool showexp=false;
277         if(mode==Fmt::FIXED)
278         {
279                 point=exp+1;
280                 digits=point+f.get_precision();
281         }
282         else if(mode==Fmt::SCI)
283         {
284                 digits=f.get_precision()+1;
285                 showexp=true;
286         }
287         else
288         {
289                 digits=max(f.get_precision(), 1U);
290                 if(exp<-4 || exp>=static_cast<int>(digits))
291                 {
292                         point=1;
293                         showexp=true;
294                 }
295                 else
296                 {
297                         point=max(exp, 0)+1;
298                         if(exp<0)
299                                 digits+=-exp;
300                 }
301         }
302
303         // Apply rounding
304         w+=5.0l/pow(10.0l, digits);
305         if(w>10)
306         {
307                 // Rounding bumped us to the next exponent, deal with it
308                 w/=10;
309                 if(mode==Fmt::AUTOFLT && exp+1==static_cast<int>(digits))
310                 {
311                         point=1;
312                         showexp=true;
313                 }
314                 if(!showexp)
315                 {
316                         ++digits;
317                         ++point;
318                 }
319                 else
320                         ++exp;
321         }
322
323         // Create a buffer and start from the end
324         unsigned size=max(f.get_width(), digits+8);
325         char *buf=new char[size];
326         char *end=buf+size;
327         char *ptr=end;
328
329         // Format exponent
330         if(showexp)
331         {
332                 ptr=int_to_str(exp, Fmt().showpos().fill('0').width(3), ptr);
333                 *--ptr=(f.get_uppercase() ? 'E' : 'e');
334         }
335
336         // Format mantissa left-to-right
337         char *eptr=ptr;
338         ptr-=digits+(point<digits || f.get_showpoint());
339         char *mptr=ptr;
340         for(unsigned i=0; i<digits; ++i)
341         {
342                 if(i==point)
343                         *mptr++='.';
344                 if(showexp || static_cast<int>(i)>=-exp)
345                 {
346                         int digit=static_cast<int>(w);
347                         *mptr++='0'+digit;
348                         w=(w-digit)*10;
349                 }
350                 else
351                         *mptr++='0';
352         }
353
354         if(f.get_showpoint())
355         {
356                 // Radix point requested but not displayed yet, add it
357                 if(digits<=point)
358                         *mptr++='.';
359         }
360         else if(mode==Fmt::AUTOFLT && digits>point)
361         {
362                 // Remove trailing zeroes from fraction and a lone radix point
363                 while(mptr[-1]=='0')
364                         --mptr;
365                 if(mptr[-1]=='.')
366                         --mptr;
367                 if(mptr!=eptr)
368                 {
369                         while(mptr!=ptr)
370                                 *--eptr=*--mptr;
371                         ptr=eptr;
372                 }
373         }
374
375         // Add filling and sign
376         if(f.get_fill()=='0')
377         {
378                 unsigned pfxlen=(sign!=0);
379                 while(end-ptr+pfxlen<f.get_width())
380                         *--ptr='0';
381         }
382         if(sign)
383                 *--ptr=sign;
384
385         string result(ptr, end);
386         delete[] buf;
387         return result;
388 }
389
390 template<typename T>
391 T str_to_flt(const string &s, const Fmt &)
392 {
393         if(s.empty())
394                 throw LexicalError("Empty input in floating-point conversion");
395
396         std::string::const_iterator i=s.begin();
397
398         // See if the input starts with a sign
399         bool neg=false;
400         if(*i=='-')
401         {
402                 neg=true;
403                 ++i;
404         }
405         else if(*i=='+')
406                 ++i;
407
408         // Must have some digits to convert
409         if(i==s.end())
410                 throw LexicalError("Missing digits in floating-point conversion");
411
412         long double v=0;
413         int exp=0;
414
415         // Parse mantissa
416         bool point_seen=false;
417         for(; i!=s.end(); ++i)
418         {
419                 if(*i=='.')
420                 {
421                         if(point_seen)
422                                 throw LexicalError("Extra point in floating-point conversion");
423                         point_seen=true;
424                 }
425                 else if(*i>='0' && *i<='9')
426                 {
427                         v=v*10+(*i-'0');
428                         if(point_seen)
429                                 --exp;
430                 }
431                 else if(*i=='e' || *i=='E')
432                 {
433                         // We have an exponent
434                         ++i;
435
436                         exp+=str_to_int<int>(string(i, s.end()), Fmt());
437                         // str_to_int has eaten the rest of the input or thrown
438                         break;
439                 }
440                 else
441                         throw LexicalError("Invalid digit in floating-point conversion");
442         }
443
444         // Scale and negate the result as needed
445         while(exp>0)
446         {
447                 v*=10;
448                 --exp;
449         }
450         while(exp<0)
451         {
452                 v/=10;
453                 ++exp;
454         }
455
456         if(neg)
457                 v=-v;
458
459         return v;
460 }
461
462
463 /*** String conversions ***/
464
465 string str_to_str(const string &s, const Fmt &f)
466 {
467         if(f.get_type()==Fmt::NUM)
468                 throw LexicalError("Numeric format in string conversion");
469         return s;
470 }
471
472 }
473
474 namespace Msp {
475
476 void LexicalConverter::result(const string &s)
477 {
478         if(s.size()<fmt.get_width())
479         {
480                 if(fmt.get_align()==Fmt::RIGHT)
481                         buf=string(fmt.get_width()-s.size(), fmt.get_fill())+s;
482                 else
483                         buf=s+string(fmt.get_width()-s.size(), fmt.get_fill());
484         }
485         else
486                 buf=s;
487 }
488
489
490 /*** operator<< ***/
491
492 void operator<<(LexicalConverter &c, char v)
493 {
494         Fmt::Type type=c.get_fmt().get_type();
495         if(type==Fmt::NUM)
496                 c.result(int_to_str(v, c.get_fmt()));
497         else
498                 c.result(string(1, v));
499 }
500
501 void operator<<(LexicalConverter &c, signed char v)
502 { c.result(int_to_str(v, c.get_fmt())); }
503
504 void operator<<(LexicalConverter &c, short v)
505 { c.result(int_to_str(v, c.get_fmt())); }
506
507 void operator<<(LexicalConverter &c, int v)
508 { c.result(int_to_str(v, c.get_fmt())); }
509
510 void operator<<(LexicalConverter &c, long v)
511 { c.result(int_to_str(v, c.get_fmt())); }
512
513 void operator<<(LexicalConverter &c, unsigned char v)
514 { c.result(int_to_str(v, c.get_fmt())); }
515
516 void operator<<(LexicalConverter &c, unsigned short v)
517 { c.result(int_to_str(v, c.get_fmt())); }
518
519 void operator<<(LexicalConverter &c, unsigned v)
520 { c.result(int_to_str(v, c.get_fmt())); }
521
522 void operator<<(LexicalConverter &c, unsigned long v)
523 { c.result(int_to_str(v, c.get_fmt())); }
524
525 #ifdef __GNUC__
526 void operator<<(LexicalConverter &c, long long v)
527 { c.result(int_to_str(v, c.get_fmt())); }
528
529 void operator<<(LexicalConverter &c, unsigned long long v)
530 { c.result(int_to_str(v, c.get_fmt())); }
531 #endif
532
533 void operator<<(LexicalConverter &c, bool v)
534 { c.result(bool_to_str(v, c.get_fmt())); }
535
536 void operator<<(LexicalConverter &c, float v)
537 { c.result(flt_to_str(v, c.get_fmt())); }
538
539 void operator<<(LexicalConverter &c, double v)
540 { c.result(flt_to_str(v, c.get_fmt())); }
541
542 void operator<<(LexicalConverter &c, long double v)
543 { c.result(flt_to_str(v, c.get_fmt())); }
544
545 void operator<<(LexicalConverter &c, const string &s)
546 { c.result(str_to_str(s, c.get_fmt())); }
547
548 void operator<<(LexicalConverter &c, const char *s)
549 { c.result(str_to_str(s, c.get_fmt())); }
550
551 void operator<<(LexicalConverter &c, const void *p)
552 { c.result(int_to_str(reinterpret_cast<unsigned long>(p), c.get_fmt())); }
553
554
555 /*** operator>> ***/
556
557 void operator>>(const LexicalConverter &c, char &v)
558 {
559         if(c.get_fmt().get_type()==Fmt::NUM)
560                 v=str_to_int<char>(c.get(), c.get_fmt());
561         else
562         {
563                 const std::string &s=c.get();
564                 if(s.empty())
565                         throw LexicalError("Empty input in character conversion");
566                 if(s.size()>1)
567                         throw LexicalError("Extra input in character conversion");
568                 v=s[0];
569         }
570 }
571
572 void operator>>(const LexicalConverter &c, signed char &v)
573 { v=str_to_int<signed char>(c.get(), c.get_fmt()); }
574
575 void operator>>(const LexicalConverter &c, short &v)
576 { v=str_to_int<short>(c.get(), c.get_fmt()); }
577
578 void operator>>(const LexicalConverter &c, int &v)
579 { v=str_to_int<int>(c.get(), c.get_fmt()); }
580
581 void operator>>(const LexicalConverter &c, long &v)
582 { v=str_to_int<long>(c.get(), c.get_fmt()); }
583
584 void operator>>(const LexicalConverter &c, unsigned char &v)
585 { v=str_to_int<unsigned char>(c.get(), c.get_fmt()); }
586
587 void operator>>(const LexicalConverter &c, unsigned short &v)
588 { v=str_to_int<unsigned short>(c.get(), c.get_fmt()); }
589
590 void operator>>(const LexicalConverter &c, unsigned int &v)
591 { v=str_to_int<unsigned int>(c.get(), c.get_fmt()); }
592
593 void operator>>(const LexicalConverter &c, unsigned long &v)
594 { v=str_to_int<unsigned long>(c.get(), c.get_fmt()); }
595
596 #ifdef __GNUC__
597 void operator>>(const LexicalConverter &c, long long &v)
598 { v=str_to_int<long long>(c.get(), c.get_fmt()); }
599
600 void operator>>(const LexicalConverter &c, unsigned long long &v)
601 { v=str_to_int<unsigned long long>(c.get(), c.get_fmt()); }
602 #endif
603
604 void operator>>(const LexicalConverter &c, bool &v)
605 { v=str_to_bool(c.get()); }
606
607 void operator>>(const LexicalConverter &c, float &v)
608 { v=str_to_flt<float>(c.get(), c.get_fmt()); }
609
610 void operator>>(const LexicalConverter &c, double &v)
611 { v=str_to_flt<double>(c.get(), c.get_fmt()); }
612
613 void operator>>(const LexicalConverter &c, long double &v)
614 { v=str_to_flt<long double>(c.get(), c.get_fmt()); }
615
616 void operator>>(const LexicalConverter &c, string &s)
617 { s=str_to_str(c.get(), c.get_fmt()); }
618
619 } // namespace Msp