]> git.tdb.fi Git - libs/core.git/blob - source/strings/lexicalcast.h
2ed0621291858c0d0f4d40fb37036fd5decc5700
[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 /**
24 Thrown when the format is unsuitable for the type being converted.
25 */
26 class format_mismatch: public lexical_error
27 {
28 public:
29         format_mismatch(const std::string &w): lexical_error(w) { }
30         virtual ~format_mismatch() throw() { }
31 };
32
33
34 /**
35 Helper class for lexical_cast to facilitate operator overloading.
36 */
37 class LexicalConverter
38 {
39 private:
40         Fmt fmt;
41         bool filled;
42         std::string buf;
43
44 public:
45         LexicalConverter(const Fmt &f): fmt(f), filled(false) { }
46         LexicalConverter(const std::string &s, const Fmt &f): fmt(f), filled(true), buf(s) { }
47
48         const Fmt &get_fmt() const { return fmt; }
49         const std::string &get() const;
50         void result(const std::string &);
51 };
52
53
54 void operator<<(LexicalConverter &, char);
55 void operator<<(LexicalConverter &, signed char);
56 void operator<<(LexicalConverter &, short);
57 void operator<<(LexicalConverter &, int);
58 void operator<<(LexicalConverter &, long);
59 void operator<<(LexicalConverter &, unsigned char);
60 void operator<<(LexicalConverter &, unsigned short);
61 void operator<<(LexicalConverter &, unsigned);
62 void operator<<(LexicalConverter &, unsigned long);
63 #ifdef __GNUC__
64 void operator<<(LexicalConverter &, long long);
65 void operator<<(LexicalConverter &, unsigned long long);
66 #endif
67 void operator<<(LexicalConverter &, bool);
68 void operator<<(LexicalConverter &, float);
69 void operator<<(LexicalConverter &, double);
70 void operator<<(LexicalConverter &, long double);
71 void operator<<(LexicalConverter &, const std::string &);
72 void operator<<(LexicalConverter &, const char *);
73 void operator<<(LexicalConverter &, const void *);
74
75 void operator>>(const LexicalConverter &, char &);
76 void operator>>(const LexicalConverter &, signed char &);
77 void operator>>(const LexicalConverter &, short &);
78 void operator>>(const LexicalConverter &, int &);
79 void operator>>(const LexicalConverter &, long &);
80 void operator>>(const LexicalConverter &, unsigned char &);
81 void operator>>(const LexicalConverter &, unsigned short &);
82 void operator>>(const LexicalConverter &, unsigned int &);
83 void operator>>(const LexicalConverter &, unsigned long &);
84 #ifdef __GNUC__
85 void operator>>(const LexicalConverter &, long long &);
86 void operator>>(const LexicalConverter &, unsigned long long &);
87 #endif
88 void operator>>(const LexicalConverter &, bool &);
89 void operator>>(const LexicalConverter &, float &);
90 void operator>>(const LexicalConverter &, double &);
91 void operator>>(const LexicalConverter &, long double &);
92 void operator>>(const LexicalConverter &, std::string &);
93
94 // Generic operators using stringstream
95
96 template<typename T>
97 struct HasFormattedOutput: Sfinae
98 {
99         static std::ostream &s;
100         static T &v;
101
102         /* The expression must depend on the template parameter, or the compiler
103         will give an error. */
104         template<typename U>
105         static Yes f(int (*)[sizeof(s<<HasFormattedOutput<U>::v)]);
106         template<typename U>
107         static No f(...);
108
109         enum { value = Evaluate<sizeof(f<T>(0))>::value };
110 };
111
112 template<typename T>
113 struct HasFormattedInput: Sfinae
114 {
115         static std::istream &s;
116         static T &v;
117
118         template<typename U>
119         static Yes f(int (*)[sizeof(s>>HasFormattedOutput<U>::v)]);
120         template<typename U>
121         static No f(...);
122
123         enum { value = Evaluate<sizeof(f<T>(0))>::value };
124 };
125
126
127 template<typename T>
128 typename EnableIf<HasFormattedOutput<T>::value, void>::Yes
129 operator<<(LexicalConverter &c, const T &v)
130 {
131         std::ostringstream ss;
132         ss<<c.get_fmt()<<v;
133         c.result(ss.str());
134 }
135
136 template<typename T>
137 typename EnableIf<HasFormattedInput<T>::value, void>::Yes
138 operator>>(const LexicalConverter &c, T &v)
139 {
140         std::istringstream ss(c.get());
141         ss.setf(std::ios_base::fmtflags(0), std::ios_base::skipws);
142         ss>>v;
143         if(ss.fail() || !ss.eof())
144                 throw lexical_error("conversion failure");
145 }
146
147 /**
148 Helper struct to provide partial template specialization.
149 */
150 template<typename T, typename F>
151 struct LexicalCast;
152
153 template<typename T>
154 struct LexicalCast<T, std::string>
155 {
156         static T cast(const std::string &s, const Fmt &f = Fmt())
157         {
158                 LexicalConverter conv(s, f);
159                 T result;
160                 conv>>result;
161                 return result;
162         }
163 };
164
165 template<typename F>
166 struct LexicalCast<std::string, F>
167 {
168         static std::string cast(const F &v, const Fmt &f = Fmt())
169         {
170                 LexicalConverter conv(f);
171                 conv<<v;
172                 return conv.get();
173         }
174 };
175
176 template<>
177 struct LexicalCast<std::string, std::string>
178 {
179         static std::string cast(const std::string &v, const Fmt &f = Fmt())
180         {
181                 LexicalConverter conv(f);
182                 conv<<v;
183                 return conv.get();
184         }
185 };
186
187 /** Perform a lexical conversion between a string and another type.  The source
188 type can normally be deduced by the compiler, so this can be used just like the
189 standard C++ casts.  A format may additionally be specified to force a specific
190 interpretation. */
191 template<typename T, typename F>
192 inline T lexical_cast(const F &v, const Fmt &f = Fmt())
193 {
194         return LexicalCast<T, F>::cast(v, f);
195 }
196
197 } // namespace Msp
198
199 #endif