]> git.tdb.fi Git - libs/core.git/blob - source/strings/lexicalcast.h
25e3268126bde5d65cf19dca35d188c96dcebb5e
[libs/core.git] / source / strings / lexicalcast.h
1 #ifndef MSP_STRINGS_LEXICALCAST_H_
2 #define MSP_STRINGS_LEXICALCAST_H_
3
4 #include <sstream>
5 #include <string>
6 #include <stdexcept>
7 #include <msp/core/meta.h>
8 #include "fmt.h"
9
10 namespace Msp {
11
12 /**
13 Thrown for errors in lexical conversions
14 */
15 class lexical_error: public std::runtime_error
16 {
17 public:
18         lexical_error(const std::string &w): runtime_error(w) { }
19         virtual ~lexical_error() throw() { }
20 };
21
22
23 class format_mismatch: public lexical_error
24 {
25 public:
26         format_mismatch(const std::string &w): lexical_error(w) { }
27         virtual ~format_mismatch() throw() { }
28 };
29
30
31 /**
32 Helper class for lexical_cast to facilitate operator overloading.
33 */
34 class LexicalConverter
35 {
36 private:
37         Fmt fmt;
38         bool filled;
39         std::string buf;
40
41 public:
42         LexicalConverter(const Fmt &f): fmt(f), filled(false) { }
43         LexicalConverter(const std::string &s, const Fmt &f): fmt(f), filled(true), buf(s) { }
44
45         const Fmt &get_fmt() const { return fmt; }
46         const std::string &get() const;
47         void result(const std::string &);
48 };
49
50
51 void operator<<(LexicalConverter &, char);
52 void operator<<(LexicalConverter &, signed char);
53 void operator<<(LexicalConverter &, short);
54 void operator<<(LexicalConverter &, int);
55 void operator<<(LexicalConverter &, long);
56 void operator<<(LexicalConverter &, unsigned char);
57 void operator<<(LexicalConverter &, unsigned short);
58 void operator<<(LexicalConverter &, unsigned);
59 void operator<<(LexicalConverter &, unsigned long);
60 #ifdef __GNUC__
61 void operator<<(LexicalConverter &, long long);
62 void operator<<(LexicalConverter &, unsigned long long);
63 #endif
64 void operator<<(LexicalConverter &, bool);
65 void operator<<(LexicalConverter &, float);
66 void operator<<(LexicalConverter &, double);
67 void operator<<(LexicalConverter &, long double);
68 void operator<<(LexicalConverter &, const std::string &);
69 void operator<<(LexicalConverter &, const char *);
70 void operator<<(LexicalConverter &, const void *);
71
72 void operator>>(const LexicalConverter &, char &);
73 void operator>>(const LexicalConverter &, signed char &);
74 void operator>>(const LexicalConverter &, short &);
75 void operator>>(const LexicalConverter &, int &);
76 void operator>>(const LexicalConverter &, long &);
77 void operator>>(const LexicalConverter &, unsigned char &);
78 void operator>>(const LexicalConverter &, unsigned short &);
79 void operator>>(const LexicalConverter &, unsigned int &);
80 void operator>>(const LexicalConverter &, unsigned long &);
81 #ifdef __GNUC__
82 void operator>>(const LexicalConverter &, long long &);
83 void operator>>(const LexicalConverter &, unsigned long long &);
84 #endif
85 void operator>>(const LexicalConverter &, bool &);
86 void operator>>(const LexicalConverter &, float &);
87 void operator>>(const LexicalConverter &, double &);
88 void operator>>(const LexicalConverter &, long double &);
89 void operator>>(const LexicalConverter &, std::string &);
90
91 // Generic operators using stringstream
92
93 template<typename T>
94 struct HasFormattedOutput: Sfinae
95 {
96         static std::ostream &s;
97         static T &v;
98
99         /* The expression must depend on the template parameter, or the compiler
100         will give an error. */
101         template<typename U>
102         static Yes f(int (*)[sizeof(s<<HasFormattedOutput<U>::v)]);
103         template<typename U>
104         static No f(...);
105
106         enum { value = Evaluate<sizeof(f<T>(0))>::value };
107 };
108
109 template<typename T>
110 struct HasFormattedInput: Sfinae
111 {
112         static std::istream &s;
113         static T &v;
114
115         template<typename U>
116         static Yes f(int (*)[sizeof(s>>HasFormattedOutput<U>::v)]);
117         template<typename U>
118         static No f(...);
119
120         enum { value = Evaluate<sizeof(f<T>(0))>::value };
121 };
122
123
124 template<typename T>
125 typename EnableIf<HasFormattedOutput<T>::value, void>::Yes
126 operator<<(LexicalConverter &c, const T &v)
127 {
128         std::ostringstream ss;
129         ss<<c.get_fmt()<<v;
130         c.result(ss.str());
131 }
132
133 template<typename T>
134 typename EnableIf<HasFormattedInput<T>::value, void>::Yes
135 operator>>(const LexicalConverter &c, T &v)
136 {
137         std::istringstream ss(c.get());
138         ss.setf(std::ios_base::fmtflags(0), std::ios_base::skipws);
139         ss>>v;
140         if(ss.fail() || !ss.eof())
141                 throw lexical_error("conversion failure");
142 }
143
144 // Helper struct to provide partial template specialization
145
146 template<typename T, typename F>
147 struct LexicalCast;
148
149 template<typename T>
150 struct LexicalCast<T, std::string>
151 {
152         static T cast(const std::string &s, const Fmt &f = Fmt())
153         {
154                 LexicalConverter conv(s, f);
155                 T result;
156                 conv>>result;
157                 return result;
158         }
159 };
160
161 template<typename F>
162 struct LexicalCast<std::string, F>
163 {
164         static std::string cast(const F &v, const Fmt &f = Fmt())
165         {
166                 LexicalConverter conv(f);
167                 conv<<v;
168                 return conv.get();
169         }
170 };
171
172 template<>
173 struct LexicalCast<std::string, std::string>
174 {
175         static std::string cast(const std::string &v, const Fmt &f = Fmt())
176         {
177                 LexicalConverter conv(f);
178                 conv<<v;
179                 return conv.get();
180         }
181 };
182
183 // The main interface to the lexical conversion machinery
184
185 template<typename T, typename F>
186 inline T lexical_cast(const F &v, const Fmt &f = Fmt())
187 {
188         return LexicalCast<T, F>::cast(v, f);
189 }
190
191 } // namespace Msp
192
193 #endif