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