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