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