Sun, 15 Mar 2020 11:12:38 +0200
* To<float/double> will no longer cause exceptions
* X11 numpad key 9 now works
764
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
1 | /// @file String.h This file contains string helper functions. |
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
2 | /// They work with std::string |
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
3 | |
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
4 | #pragma once |
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
5 | |
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
6 | #include <string> |
1022 | 7 | #include <cstring> |
8 | #include <string> | |
764
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
9 | #include <sstream> |
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
10 | #include <iostream> |
1339 | 11 | #include <iomanip> |
764
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
12 | #include <stdexcept> |
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
13 | #include <algorithm> |
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
14 | #include "String/Exceptions.h" |
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
15 | #include "Enum.h" |
1059 | 16 | #include "Types.h" |
17 | ||
863 | 18 | #undef decltype |
764
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
19 | |
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
20 | namespace Gorgon { |
1334 | 21 | |
22 | /// Contains string related functions and classes. This namespace is not yet utf8 aware. | |
23 | namespace String { | |
24 | ||
25 | struct CaseInsensitiveLess { | |
26 | bool operator()(const std::string &left, const std::string &right) const { | |
27 | unsigned len=(unsigned int)std::min(left.length(), right.length()); | |
28 | ||
29 | auto l=left.begin(); | |
30 | auto r=right.begin(); | |
31 | for(unsigned i=0; i<len; i++) { | |
32 | auto lc=tolower(*l); | |
33 | auto rc=tolower(*r); | |
34 | if(lc<rc) { | |
35 | return true; | |
36 | } | |
37 | else if(lc>rc) { | |
38 | return false; | |
39 | } | |
40 | ++l; | |
41 | ++r; | |
42 | } | |
43 | ||
44 | return left.length()<right.length(); | |
45 | } | |
46 | }; | |
47 | ||
48 | /// Compares two strings case insensitive. Works similar to strcmp | |
49 | inline int CaseInsensitiveCompare(const std::string &left, const std::string &right) { | |
50 | unsigned len=(unsigned int)std::min(left.length(), right.length()); | |
51 | ||
52 | auto l=left.begin(); | |
53 | auto r=right.begin(); | |
54 | for(unsigned i=0; i<len; i++) { | |
55 | auto lc=tolower(*l); | |
56 | auto rc=tolower(*r); | |
57 | if(lc<rc) { | |
58 | return -1; | |
59 | } | |
60 | else if(lc>rc) { | |
61 | return 1; | |
62 | } | |
63 | ++l; | |
64 | ++r; | |
65 | } | |
66 | ||
67 | return left.length()<right.length() ? -1 : (left.length()==right.length() ? 0 : 1); | |
68 | } | |
69 | ||
764
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
70 | |
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
71 | #ifdef DOXYGEN |
1334 | 72 | /// Converts a string to another type. Works for integral types and |
73 | /// Gorgon classes including Point, Size, etc... There is no error | |
74 | /// handling. If conversion does not work, you may end up with | |
75 | /// uninitialized object. This system will be fixed at a later point. | |
76 | template <class T_> | |
77 | T_ To(const std::string &value) { | |
78 | return T_(); | |
79 | } | |
764
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
80 | #endif |
1334 | 81 | |
82 | /// @cond | |
764
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
83 | |
1306 | 84 | |
797
5d31c4836303
* Loader for Resource::Data
cemkalyoncu <cemkalyoncu@gmail.com>
parents:
764
diff
changeset
|
85 | # define ISENUMUPGRADED decltype(gorgon__enum_tr_loc(T_()))::isupgradedenum |
1306 | 86 | |
1334 | 87 | template <class T_> |
88 | typename std::enable_if<std::is_constructible<T_, std::string>::value, T_>::type | |
89 | To(const std::string &value) { | |
90 | return T_(value); | |
91 | } | |
92 | ||
93 | template <class T_> | |
94 | typename std::enable_if<!std::is_constructible<T_, std::string>::value && !ISENUMUPGRADED, T_>::type | |
95 | To(const std::string &value) { | |
96 | std::stringstream ss(value); | |
764
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
97 | |
1334 | 98 | T_ ret; |
99 | ss>>ret; | |
764
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
100 | |
1334 | 101 | return ret; |
102 | } | |
103 | ||
104 | template <class T_> | |
105 | typename std::enable_if<std::is_constructible<T_, const char*>::value, T_>::type | |
106 | To(const char *value) { | |
107 | return T_(value); | |
108 | } | |
109 | ||
110 | template <class T_> | |
111 | typename std::enable_if<!std::is_constructible<T_, const char*>::value && std::is_constructible<T_, std::string>::value, T_>::type | |
112 | To(const char *value) { | |
113 | return T_(value); | |
114 | } | |
115 | ||
116 | template <class T_> | |
117 | typename std::enable_if<!std::is_constructible<T_, const char*>::value && | |
118 | !std::is_constructible<T_, std::string>::value && | |
119 | !ISENUMUPGRADED, | |
120 | T_>::type | |
121 | To(const char *value) { | |
122 | std::stringstream ss(value); | |
764
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
123 | |
1334 | 124 | T_ ret; |
125 | ss>>ret; | |
764
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
126 | |
1334 | 127 | return ret; |
128 | } | |
764
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
129 | |
1334 | 130 | template <> |
131 | inline char To<char>(const std::string &value) { | |
132 | char *n; | |
133 | return (char)std::strtol(value.c_str(), &n, 10); | |
134 | } | |
764
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
135 | |
1334 | 136 | template <> |
137 | inline unsigned char To<unsigned char>(const std::string &value) { | |
138 | char *n; | |
139 | return (unsigned char)std::strtol(value.c_str(), &n, 10); | |
140 | } | |
764
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
141 | |
1334 | 142 | template <> |
143 | inline short To<short>(const std::string &value) { | |
144 | char *n; | |
145 | return (short)std::strtol(value.c_str(), &n, 10); | |
146 | } | |
764
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
147 | |
1334 | 148 | template <> |
149 | inline unsigned short To<unsigned short>(const std::string &value) { | |
150 | char *n; | |
151 | return (unsigned short)std::strtol(value.c_str(), &n, 10); | |
152 | } | |
764
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
153 | |
1334 | 154 | template <> |
155 | inline int To<int>(const std::string &value) { | |
156 | char *n; | |
157 | return (int)std::strtol(value.c_str(), &n, 10); | |
158 | } | |
764
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
159 | |
1334 | 160 | template <> |
161 | inline unsigned To<unsigned>(const std::string &value) { | |
162 | char *n; | |
163 | return (unsigned)std::strtol(value.c_str(), &n, 10); | |
164 | } | |
764
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
165 | |
1334 | 166 | template <> |
167 | inline long To<long>(const std::string &value) { | |
168 | char *n; | |
169 | return (long)std::strtol(value.c_str(), &n, 10); | |
170 | } | |
764
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
171 | |
1334 | 172 | template <> |
173 | inline unsigned long To<unsigned long>(const std::string &value) { | |
174 | char *n; | |
175 | return (unsigned long)std::strtol(value.c_str(), &n, 10); | |
176 | } | |
764
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
177 | |
1334 | 178 | template <> |
179 | inline long long To<long long>(const std::string &value) { | |
180 | char *n; | |
181 | return (long long)std::strtol(value.c_str(), &n, 10); | |
182 | } | |
764
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
183 | |
1334 | 184 | template <> |
185 | inline unsigned long long To<unsigned long long>(const std::string &value) { | |
186 | char *n; | |
187 | return (unsigned long long)std::strtol(value.c_str(), &n, 10); | |
188 | } | |
764
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
189 | |
1334 | 190 | template <> |
191 | inline float To<float>(const std::string &value) { | |
1339 | 192 | if(value=="") return 0; |
193 | ||
1380
8ea1cd4f856e
* To<float/double> will no longer cause exceptions
cemkalyoncu
parents:
1339
diff
changeset
|
194 | return (float)std::strtof(value.c_str(), nullptr); |
1334 | 195 | } |
764
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
196 | |
1334 | 197 | template <> |
198 | inline double To<double>(const std::string &value) { | |
1339 | 199 | if(value=="") return 0; |
200 | ||
1380
8ea1cd4f856e
* To<float/double> will no longer cause exceptions
cemkalyoncu
parents:
1339
diff
changeset
|
201 | return std::strtod(value.c_str(), nullptr); |
1334 | 202 | } |
764
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
203 | |
1334 | 204 | template <> |
205 | inline long double To<long double>(const std::string &value) { | |
1339 | 206 | if(value=="") return 0; |
207 | ||
1380
8ea1cd4f856e
* To<float/double> will no longer cause exceptions
cemkalyoncu
parents:
1339
diff
changeset
|
208 | return std::strtold(value.c_str(), nullptr); |
1334 | 209 | } |
210 | ||
211 | template <> | |
212 | inline bool To<bool>(const std::string &value) { | |
213 | if(value=="false" || value=="no" || value=="" || To<int>(value)==0) | |
214 | return false; | |
215 | else | |
216 | return true; | |
217 | } | |
218 | ||
219 | template <> | |
220 | inline char To<char>(const char *value) { | |
1380
8ea1cd4f856e
* To<float/double> will no longer cause exceptions
cemkalyoncu
parents:
1339
diff
changeset
|
221 | return (char)std::strtol(value, nullptr, 10); |
1334 | 222 | } |
764
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
223 | |
1334 | 224 | template <> |
225 | inline unsigned char To<unsigned char>(const char *value) { | |
1380
8ea1cd4f856e
* To<float/double> will no longer cause exceptions
cemkalyoncu
parents:
1339
diff
changeset
|
226 | return (unsigned char)std::strtol(value, nullptr, 10); |
1334 | 227 | } |
764
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
228 | |
1334 | 229 | template <> |
230 | inline short To<short>(const char *value) { | |
1380
8ea1cd4f856e
* To<float/double> will no longer cause exceptions
cemkalyoncu
parents:
1339
diff
changeset
|
231 | return (short)std::strtol(value, nullptr, 10); |
1334 | 232 | } |
764
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
233 | |
1334 | 234 | template <> |
235 | inline unsigned short To<unsigned short>(const char *value) { | |
1380
8ea1cd4f856e
* To<float/double> will no longer cause exceptions
cemkalyoncu
parents:
1339
diff
changeset
|
236 | return (unsigned short)std::strtol(value, nullptr, 10); |
1334 | 237 | } |
764
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
238 | |
1334 | 239 | template <> |
240 | inline int To<int>(const char *value) { | |
1380
8ea1cd4f856e
* To<float/double> will no longer cause exceptions
cemkalyoncu
parents:
1339
diff
changeset
|
241 | return (int)std::strtol(value, nullptr, 10); |
1334 | 242 | } |
764
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
243 | |
1334 | 244 | template <> |
245 | inline unsigned To<unsigned>(const char *value) { | |
1380
8ea1cd4f856e
* To<float/double> will no longer cause exceptions
cemkalyoncu
parents:
1339
diff
changeset
|
246 | return (unsigned)std::strtol(value, nullptr, 10); |
1334 | 247 | } |
764
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
248 | |
1334 | 249 | template <> |
250 | inline long To<long>(const char *value) { | |
1380
8ea1cd4f856e
* To<float/double> will no longer cause exceptions
cemkalyoncu
parents:
1339
diff
changeset
|
251 | return (long)std::strtol(value, nullptr, 10); |
1334 | 252 | } |
764
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
253 | |
1334 | 254 | template <> |
255 | inline unsigned long To<unsigned long>(const char *value) { | |
1380
8ea1cd4f856e
* To<float/double> will no longer cause exceptions
cemkalyoncu
parents:
1339
diff
changeset
|
256 | return (unsigned long)std::strtol(value, nullptr, 10); |
1334 | 257 | } |
764
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
258 | |
1334 | 259 | template <> |
260 | inline long long To<long long>(const char *value) { | |
1380
8ea1cd4f856e
* To<float/double> will no longer cause exceptions
cemkalyoncu
parents:
1339
diff
changeset
|
261 | return (long long)std::strtol(value, nullptr, 10); |
1334 | 262 | } |
764
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
263 | |
1334 | 264 | template <> |
265 | inline unsigned long long To<unsigned long long>(const char *value) { | |
1380
8ea1cd4f856e
* To<float/double> will no longer cause exceptions
cemkalyoncu
parents:
1339
diff
changeset
|
266 | return (unsigned long long)std::strtol(value, nullptr, 10); |
1334 | 267 | } |
764
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
268 | |
1334 | 269 | template <> |
270 | inline float To<float>(const char *value) { | |
271 | return (float)std::atof(value); | |
272 | } | |
764
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
273 | |
1334 | 274 | template <> |
275 | inline double To<double>(const char *value) { | |
276 | return std::atof(value); | |
277 | } | |
764
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
278 | |
1334 | 279 | template <> |
280 | inline long double To<long double>(const char *value) { | |
281 | return std::atof(value); | |
282 | } | |
764
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
283 | |
1334 | 284 | template <> |
285 | inline bool To<bool>(const char *value) { | |
286 | return To<bool>(std::string(value)); | |
287 | } | |
922
02f6eed8821f
* Bitmap font ImportFolder, missing trim and toalpha
cemkalyoncu
parents:
912
diff
changeset
|
288 | |
1334 | 289 | /// Converts a hexadecimal number stored in the string to a given |
1380
8ea1cd4f856e
* To<float/double> will no longer cause exceptions
cemkalyoncu
parents:
1339
diff
changeset
|
290 | /// integer type. If given string is not a valid number this function |
8ea1cd4f856e
* To<float/double> will no longer cause exceptions
cemkalyoncu
parents:
1339
diff
changeset
|
291 | /// throws |
1334 | 292 | template <class T_> |
293 | T_ HexTo(const std::string &value); | |
922
02f6eed8821f
* Bitmap font ImportFolder, missing trim and toalpha
cemkalyoncu
parents:
912
diff
changeset
|
294 | |
1334 | 295 | template <> |
296 | inline int HexTo<int>(const std::string &value) { | |
297 | return std::stoi(value, nullptr, 16); | |
298 | } | |
922
02f6eed8821f
* Bitmap font ImportFolder, missing trim and toalpha
cemkalyoncu
parents:
912
diff
changeset
|
299 | |
1334 | 300 | template <> |
301 | inline long HexTo<long>(const std::string &value) { | |
302 | return std::stol(value, nullptr, 16); | |
303 | } | |
922
02f6eed8821f
* Bitmap font ImportFolder, missing trim and toalpha
cemkalyoncu
parents:
912
diff
changeset
|
304 | |
1334 | 305 | template <> |
306 | inline long long HexTo<long long>(const std::string &value) { | |
307 | return std::stoll(value, nullptr, 16); | |
308 | } | |
922
02f6eed8821f
* Bitmap font ImportFolder, missing trim and toalpha
cemkalyoncu
parents:
912
diff
changeset
|
309 | |
1334 | 310 | template <> |
311 | inline unsigned int HexTo<unsigned int>(const std::string &value) { | |
312 | return (unsigned int)std::stoul(value, nullptr, 16); | |
313 | } | |
922
02f6eed8821f
* Bitmap font ImportFolder, missing trim and toalpha
cemkalyoncu
parents:
912
diff
changeset
|
314 | |
1334 | 315 | template <> |
316 | inline unsigned long HexTo<unsigned long>(const std::string &value) { | |
317 | return std::stoul(value, nullptr, 16); | |
318 | } | |
922
02f6eed8821f
* Bitmap font ImportFolder, missing trim and toalpha
cemkalyoncu
parents:
912
diff
changeset
|
319 | |
1334 | 320 | template <> |
321 | inline unsigned long long HexTo<unsigned long long>(const std::string &value) { | |
322 | return std::stoull(value, nullptr, 16); | |
323 | } | |
324 | /// @endcond | |
764
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
325 | |
1334 | 326 | /// Pads the string to the given number of characters from the start. This function is |
327 | /// not utf aware. | |
328 | inline std::string PadStart(std::string str, std::size_t len, char pad = ' ') { | |
329 | if(len > str.size()) | |
330 | str.insert(0, len - str.size(), pad); | |
1029
46d49a1ef068
* WindowManager::Set/GetClipboardText now supports multiple formats
cemkalyoncu
parents:
1022
diff
changeset
|
331 | |
1334 | 332 | return str; |
333 | } | |
1029
46d49a1ef068
* WindowManager::Set/GetClipboardText now supports multiple formats
cemkalyoncu
parents:
1022
diff
changeset
|
334 | |
1334 | 335 | /// Pads the string to the given number of characters from the start. This function is |
336 | /// not utf aware. | |
337 | inline std::string PadEnd(std::string str, std::size_t len, char pad = ' ') { | |
338 | if(len > str.size()) | |
339 | str.insert(str.end(), len - str.size(), pad); | |
1031 | 340 | |
341 | return str; | |
1334 | 342 | } |
1029
46d49a1ef068
* WindowManager::Set/GetClipboardText now supports multiple formats
cemkalyoncu
parents:
1022
diff
changeset
|
343 | |
1334 | 344 | /// String replace that does not use regex. Works faster than regex variant. This function is |
345 | /// not utf aware. | |
346 | /// @param str is the string to process | |
347 | /// @param find is the substrings to be replaced | |
348 | /// @param replace is the string to place instead of find. Can be empty string. | |
349 | inline std::string Replace(std::string str, const std::string &find, const std::string &replace) { | |
350 | std::string::size_type l=0; | |
351 | ||
352 | auto flen=find.length(); | |
353 | auto rlen=replace.length(); | |
354 | ||
355 | if(!find.length()) return str; | |
764
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
356 | |
1334 | 357 | while( (l=str.find(find, l)) != str.npos ) { |
358 | str.erase(l, flen); | |
359 | str.insert(l, replace); | |
360 | l+=rlen; | |
361 | } | |
764
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
362 | |
1334 | 363 | return str; |
364 | } | |
764
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
365 | |
1334 | 366 | /// Strips whitespace around the given string both from start and end. This function is |
367 | /// not utf aware. | |
368 | /// @param str is the string to process | |
369 | /// @param chars is the characters to be considered as whitespace | |
370 | inline std::string Trim(std::string str, const std::string &chars=" \t\n\r") { | |
371 | if(!str.length()) return ""; | |
372 | ||
373 | const char *ptr=str.c_str(); | |
374 | while(*ptr && chars.find_first_of(*ptr)!=chars.npos) { | |
375 | ptr++; | |
376 | } | |
377 | str=str.substr(ptr-str.c_str()); | |
378 | ||
379 | while(str.length() && chars.find_first_of(str[str.length()-1])!=chars.npos) { | |
380 | str.resize(str.length()-1); | |
381 | } | |
764
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
382 | |
1334 | 383 | return str; |
384 | } | |
764
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
385 | |
1334 | 386 | /// Strips the whitespace from the start of a string. This function is |
387 | /// not utf aware. | |
388 | /// @param str is the string to process | |
389 | /// @param chars is the characters to be considered as whitespace | |
390 | inline std::string TrimStart(std::string str, const std::string &chars=" \t\n\r") { | |
391 | if(!str.length()) return ""; | |
392 | ||
393 | const char *ptr=str.c_str(); | |
394 | while(*ptr && chars.find_first_of(*ptr)!=chars.npos) { | |
395 | ptr++; | |
396 | } | |
397 | str=str.substr(ptr-str.c_str()); | |
764
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
398 | |
1334 | 399 | return str; |
400 | } | |
764
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
401 | |
1334 | 402 | /// Strips the whitespace at the end of a string. This function is |
403 | /// not utf aware. | |
404 | /// @param str is the string to process | |
405 | /// @param chars is the characters to be considered as whitespace | |
406 | inline std::string TrimEnd(std::string str, const std::string &chars=" \t\n\r") { | |
407 | while(str.length() && chars.find_first_of(str[str.length()-1])!=chars.npos) { | |
408 | str.resize(str.length()-1); | |
409 | } | |
764
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
410 | |
1334 | 411 | return str; |
412 | } | |
764
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
413 | |
1334 | 414 | /// Converts the given string to lowercase. This function is |
415 | /// not utf aware. | |
416 | inline std::string ToLower(std::string str) { | |
417 | for(auto it=str.begin();it!=str.end();++it) { | |
418 | *it=tolower(*it); | |
419 | } | |
764
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
420 | |
1334 | 421 | return str; |
422 | } | |
764
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
423 | |
1334 | 424 | /// Converts the given string to uppercase. This function is |
425 | /// not utf aware. | |
426 | inline std::string ToUpper(std::string str) { | |
427 | for(auto it=str.begin();it!=str.end();++it) { | |
428 | *it=toupper(*it); | |
429 | } | |
764
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
430 | |
1334 | 431 | return str; |
432 | } | |
764
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
433 | |
1334 | 434 | |
435 | /// @cond | |
436 | inline std::string From(char value) { | |
437 | return std::to_string(value); | |
438 | } | |
764
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
439 | |
1334 | 440 | inline std::string From(unsigned char value) { |
441 | return std::to_string(value); | |
442 | } | |
764
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
443 | |
1334 | 444 | inline std::string From(int value) { |
445 | return std::to_string(value); | |
446 | } | |
447 | ||
448 | inline std::string From(unsigned value) { | |
449 | return std::to_string(value); | |
450 | } | |
764
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
451 | |
1334 | 452 | inline std::string From(long value) { |
453 | return std::to_string(value); | |
454 | } | |
455 | ||
456 | inline std::string From(unsigned long value) { | |
457 | return std::to_string(value); | |
458 | } | |
459 | ||
460 | inline std::string From(long long value) { | |
461 | return std::to_string(value); | |
462 | } | |
463 | ||
464 | inline std::string From(unsigned long long value) { | |
465 | return std::to_string(value); | |
466 | } | |
467 | ||
468 | inline std::string From(float value) { | |
1339 | 469 | std::stringstream ss; |
470 | if(value > 1e7) { | |
471 | ss<<std::fixed<<std::setprecision(0)<<value; | |
472 | } | |
473 | else { | |
474 | ss<<std::setprecision(7)<<value; | |
475 | } | |
476 | ||
477 | return ss.str(); | |
1334 | 478 | } |
479 | ||
480 | inline std::string From(double value) { | |
1339 | 481 | std::stringstream ss; |
482 | if(value > 1e14) { | |
483 | ss<<std::fixed<<std::setprecision(0)<<value; | |
484 | } | |
485 | else { | |
486 | ss<<std::setprecision(14)<<value; | |
487 | } | |
488 | return ss.str(); | |
1334 | 489 | } |
490 | ||
491 | inline std::string From(long double value) { | |
1339 | 492 | std::stringstream ss; |
493 | if(value > 1e28l) { | |
494 | ss<<std::fixed<<std::setprecision(0)<<value; | |
495 | } | |
496 | else { | |
497 | ss<<std::setprecision(28)<<value; | |
498 | } | |
499 | return ss.str(); | |
1334 | 500 | } |
501 | ||
502 | inline std::string From(std::string value) { | |
503 | return value; | |
504 | } | |
764
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
505 | |
1334 | 506 | template<class T_> |
507 | typename std::enable_if<std::is_convertible<T_, std::string>::value, std::string>::type | |
508 | From(const T_ &item) { | |
509 | return (std::string)item; | |
510 | } | |
764
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
511 | |
1334 | 512 | template<class T_> |
513 | typename std::enable_if<!std::is_convertible<T_, std::string>::value && !decltype(gorgon__enum_tr_loc((*(T_*)nullptr)))::isupgradedenum, std::string>::type | |
514 | From(const T_ &item) { | |
515 | std::stringstream ss; | |
516 | ss<<item; | |
764
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
517 | |
1334 | 518 | return ss.str(); |
519 | } | |
520 | ||
521 | template<typename T> | |
522 | class IsStreamable | |
523 | { | |
524 | using one = char; | |
525 | struct two { | |
526 | char dummy[2]; | |
527 | }; | |
764
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
528 | |
1334 | 529 | template<class TT> |
530 | static one test(decltype(((std::ostream*)nullptr)->operator<<((TT*)nullptr))) { return one(); } | |
531 | ||
532 | static two test(...) { return two(); } | |
533 | ||
534 | public: | |
535 | static const bool Value = sizeof( test(*(std::ostream*)nullptr) )==1; | |
536 | }; | |
537 | ||
538 | inline void streamthis(std::stringstream &stream) { | |
539 | } | |
540 | ||
541 | template<class T_, class ...P_> | |
542 | void streamthis(std::stringstream &stream, const T_ &first, const P_&... rest) { | |
543 | stream<<first; | |
544 | ||
545 | streamthis(stream, rest...); | |
546 | } | |
547 | /// @endcond | |
548 | ||
549 | template<class T_> | |
550 | struct CanBeStringified { | |
551 | static const bool Value = | |
552 | IsStreamable<T_>::Value || | |
553 | std::is_convertible<T_, std::string>::value || | |
554 | decltype(gorgon__enum_tr_loc(*((typename std::decay<T_>::type*)nullptr)))::isupgradedenum; | |
555 | }; | |
556 | ||
557 | /// Streams the given parameters into a stringstream and returns the result, effectively | |
558 | /// concatinating all parameters. | |
559 | template<class ...P_> | |
560 | std::string Concat(const P_&... rest) { | |
561 | std::stringstream ss; | |
562 | streamthis(ss, rest...); | |
563 | ||
564 | ||
565 | return ss.str(); | |
566 | } | |
567 | ||
568 | /// Returns the number of bytes used by the next UTF8 codepoint | |
569 | inline int UTF8Bytes(char c) { | |
1059 | 570 | if((c & 0b10000000) == 0b00000000) return 1; |
571 | ||
572 | if((c & 0b11100000) == 0b11000000) return 2; | |
573 | ||
574 | if((c & 0b11110000) == 0b11100000) return 3; | |
575 | ||
576 | if((c & 0b11111000) == 0b11110000) return 4; | |
577 | ||
578 | //we are probably at the middle of a code point, just return | |
579 | // 1 so that the stream can sync. | |
580 | return 1; | |
581 | } | |
1334 | 582 | |
583 | inline int UnicodeUTF8Bytes(Char c) { | |
1059 | 584 | if(c < 0x80) return 1; |
585 | ||
586 | if(c < 0x800) return 2; | |
587 | ||
588 | if(c < 0x10000) return 3; | |
589 | ||
590 | if(c < 0x0010FFFF) return 4; | |
591 | ||
592 | return 3; //replacement: 0xfffd | |
593 | } | |
1304 | 594 | |
595 | inline int UnicodeGlyphCount(const std::string &s) { | |
596 | int i = 0; | |
597 | int count = 0; | |
598 | while(i < s.length()) { | |
599 | count++; | |
600 | i += UTF8Bytes(s[i]); | |
601 | } | |
602 | ||
603 | return count; | |
604 | } | |
1334 | 605 | |
606 | /// Appends a unicode code point to the string. If the given char | |
607 | /// is valid, this function will return true. Otherwise, it will place | |
608 | /// a three byte long replacement character and returns false. | |
609 | inline bool AppendUnicode(std::string &s, Char c) { | |
1059 | 610 | if(c > 0x10FFFF) { |
611 | s += "\xEF\xBF\xBD"; | |
612 | return false; | |
613 | } | |
614 | ||
615 | int bytes = UnicodeUTF8Bytes(c); | |
1333 | 616 | s.resize(s.size() + bytes); |
1059 | 617 | |
618 | auto it = s.rbegin(); | |
619 | int cur = 0; | |
620 | ||
621 | while(cur < bytes-1) { | |
622 | *it = (c & 0b00111111) | 0b10000000; | |
623 | it++; | |
624 | cur++; | |
625 | c = c >> 6; | |
626 | } | |
627 | ||
628 | if(bytes == 1) { | |
629 | *it = c; | |
630 | } | |
631 | else if(bytes == 2) { | |
632 | *it = c | 0b11000000; | |
633 | } | |
634 | else if(bytes == 3) { | |
635 | *it = c | 0b11100000; | |
636 | } | |
637 | else if(bytes == 4) { | |
638 | *it = c | 0b11110000; | |
639 | } | |
640 | else | |
641 | return false; // future proofing | |
642 | ||
643 | return true; | |
644 | } | |
1334 | 645 | |
646 | /// Appends a unicode code point to the string. If the given char | |
647 | /// is valid, this function will return true. Otherwise, it will place | |
648 | /// a three byte long replacement character and returns false. pos is | |
649 | /// the byte offset to insert the character. | |
650 | inline bool InsertUnicode(std::string &s, std::size_t pos, Char c) { | |
651 | if(c > 0x10FFFF) { | |
652 | s += "\xEF\xBF\xBD"; | |
653 | return false; | |
654 | } | |
655 | ||
656 | char data[4] = {}; | |
657 | ||
658 | int bytes = UnicodeUTF8Bytes(c); | |
659 | ||
660 | auto it = data + 3; | |
661 | int cur = 0; | |
662 | ||
663 | while(cur < bytes-1) { | |
664 | *it = (c & 0b00111111) | 0b10000000; | |
665 | it--; | |
666 | cur++; | |
667 | c = c >> 6; | |
668 | } | |
669 | ||
670 | if(bytes == 1) { | |
671 | *it = c; | |
672 | } | |
673 | else if(bytes == 2) { | |
674 | *it = c | 0b11000000; | |
675 | } | |
676 | else if(bytes == 3) { | |
677 | *it = c | 0b11100000; | |
678 | } | |
679 | else if(bytes == 4) { | |
680 | *it = c | 0b11110000; | |
681 | } | |
682 | else | |
683 | return false; // future proofing | |
684 | ||
685 | s.insert(pos, it, bytes); | |
686 | ||
687 | return true; | |
688 | } | |
846
c9cf0fba3bd6
* Complete rewrite for URI encoding module with
cemkalyoncu
parents:
830
diff
changeset
|
689 | |
1334 | 690 | /// Line ending types |
691 | enum class LineEnding { | |
692 | /// None, no line endings | |
693 | None = 0, | |
694 | ||
695 | /// line feed \\x0a | |
696 | LF = 1, | |
846
c9cf0fba3bd6
* Complete rewrite for URI encoding module with
cemkalyoncu
parents:
830
diff
changeset
|
697 | |
1334 | 698 | /// line feed \\x0a |
699 | Unix = 1, | |
700 | ||
701 | /// carriage return \\x0d | |
702 | CR = 2, | |
846
c9cf0fba3bd6
* Complete rewrite for URI encoding module with
cemkalyoncu
parents:
830
diff
changeset
|
703 | |
1334 | 704 | /// carriage return \\x0d |
705 | Mac = 2, | |
706 | ||
707 | /// \\x0d\\x0a | |
708 | CRLF = 3, | |
846
c9cf0fba3bd6
* Complete rewrite for URI encoding module with
cemkalyoncu
parents:
830
diff
changeset
|
709 | |
1334 | 710 | /// \\x0d\\x0a |
711 | Standard = 3, | |
712 | ||
713 | /// \\x0d\\x0a | |
714 | Windows = 3, | |
715 | ||
716 | /// When there are multiple types of line endings present | |
717 | Mixed = 4, | |
718 | }; | |
719 | ||
720 | /// Fixes/changes line endings. If none is supplied, all line endings will be removed. If mixed | |
721 | /// is set, nothing will be done. | |
722 | std::string FixLineEndings(const std::string &in, LineEnding type = LineEnding::Standard); | |
723 | ||
724 | //for pretty documentation | |
764
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
725 | #ifdef DOXYGEN |
1334 | 726 | /// Creates a string from the given data. Similar to to_string but allows |
727 | /// conversion of a type if it can be casted or streamed to output. Also uses | |
728 | /// std::to_string where possible. | |
729 | template<class T_> | |
730 | std::string From(const T_ &item) { return ""; } | |
764
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
731 | #endif |
1021 | 732 | |
1334 | 733 | /// Joins a list of strings to a single string using the given glue text. |
734 | template<class T_> | |
735 | std::string Join(const T_ &vec, const std::string &glue = ", ") { | |
736 | int totalsize = 0; | |
737 | int gluesize = (int)glue.size(); | |
1021 | 738 | |
1334 | 739 | for(const std::string &s : vec) { |
740 | if(totalsize) | |
741 | totalsize += gluesize; | |
1021 | 742 | |
1334 | 743 | totalsize += (int)s.size(); |
744 | } | |
1021 | 745 | |
1334 | 746 | std::string ret; |
747 | ret.resize(totalsize); | |
748 | bool first = true; | |
1021 | 749 | |
1334 | 750 | char *data = &ret[0]; |
751 | const char *gluedata = glue.data(); | |
1021 | 752 | |
1334 | 753 | for(const std::string &s : vec) { |
754 | if(!first) { | |
755 | std::memcpy(data, gluedata, gluesize); | |
756 | data += gluesize; | |
757 | } | |
758 | ||
759 | std::memcpy(data, s.data(), s.size()); | |
1021 | 760 | |
1334 | 761 | data += s.size(); |
1021 | 762 | |
1334 | 763 | first = false; |
764 | } | |
1021 | 765 | |
1334 | 766 | return ret; |
767 | } | |
768 | ||
769 | /// Extracts the part of the string up to the given marker. Extracted string and | |
770 | /// the marker is removed from the original string. If the given string does not | |
771 | /// contain marker, entire string will be extracted. It is possible to tokenize | |
772 | /// the given string using repeated calls to this function. However, its more | |
773 | /// convenient to use Tokenizer. | |
774 | /// @param original string that will be processed. This string will be modified | |
775 | /// by the program | |
776 | /// @param marker string that will be searched. | |
777 | /// @param trim if set, both extracted and the remaining part of the string | |
778 | /// @return Extracted string. Does not contain the marker. | |
779 | inline std::string Extract(std::string &original, const std::string &marker, bool trim = false) { | |
780 | auto pos=original.find(marker); | |
781 | ||
782 | if(pos==original.npos) { | |
783 | std::string ret; | |
784 | std::swap(ret, original); | |
785 | ||
786 | return ret; | |
787 | } | |
788 | ||
789 | std::string ret=original.substr(0, pos); | |
790 | original=original.substr(pos+marker.length()); | |
912 | 791 | |
792 | if(trim) { | |
793 | ret = TrimEnd(ret); | |
794 | original = TrimStart(original); | |
795 | } | |
1334 | 796 | |
797 | return ret; | |
798 | } | |
764
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
799 | |
1334 | 800 | |
801 | /// Extracts the part of the string up to the given marker. Extracted string and | |
802 | /// the marker is removed from the original string. If the given string does not | |
803 | /// contain marker, entire string will be extracted. It is possible to tokenize | |
804 | /// the given string using repeated calls to this function. However, its more | |
805 | /// convenient to use Tokenizer. | |
806 | /// @param original string that will be processed. This string will be modified | |
807 | /// by the program | |
808 | /// @param marker character that will be searched. | |
809 | /// @param trim if set, both extracted and the remaining part of the string | |
810 | /// @return Extracted string. Does not contain the marker. | |
811 | inline std::string Extract(std::string &original, char marker, bool trim = false) { | |
812 | auto pos=original.find_first_of(marker); | |
813 | ||
814 | if(pos==original.npos) { | |
815 | std::string ret; | |
816 | std::swap(ret, original); | |
817 | ||
818 | return ret; | |
819 | } | |
820 | ||
821 | std::string ret=original.substr(0, pos); | |
822 | original=original.substr(pos+1); | |
912 | 823 | |
824 | if(trim) { | |
825 | ret = TrimEnd(ret); | |
826 | original = TrimStart(original); | |
827 | } | |
1334 | 828 | |
829 | return ret; | |
830 | } | |
831 | ||
832 | enum class QuoteType { | |
833 | None, | |
834 | Single, | |
835 | Double, | |
836 | Both | |
837 | }; | |
838 | ||
839 | /// Extracts the part of the string up to the given marker. This function will | |
840 | /// skipped quoted sections of the string. Both single and double quotes can be | |
841 | /// considered, however, double quotes should match with double quotes and single | |
842 | /// quotes should match with single quotes. A different quote type inside quote | |
843 | /// region is ignored. Extracted string and the marker is removed from the original | |
844 | /// string. If the given string does not contain marker outside the quotes, | |
845 | /// entire string will be extracted. It is possible to tokenize | |
846 | /// the given string using repeated calls to this function. Unbalanced quotes will | |
847 | /// be treated ending at the end of the string. | |
848 | /// @param original string that will be processed. This string will be modified | |
849 | /// by the program | |
850 | /// @param marker string that will be searched. It is possible to specify quote as | |
851 | /// a marker. | |
852 | /// @param quotetype controls which type of quotes will be considered. | |
853 | /// @return Extracted string. Does not contain the marker. Quotes will not be removed | |
854 | inline std::string Extract_UseQuotes(std::string &original, char marker, QuoteType quotetype=QuoteType::Both) { | |
855 | int inquotes=0; | |
856 | std::size_t pos=0; | |
857 | ||
858 | for(auto &c : original) { | |
859 | if(inquotes==1) { | |
860 | if(c=='\'') { | |
861 | inquotes=0; | |
862 | } | |
863 | } | |
864 | else if(inquotes==2) { | |
865 | if(c=='"') { | |
866 | inquotes=0; | |
867 | } | |
868 | } | |
869 | else if(c==marker) { | |
870 | std::string temp=original.substr(0, pos); | |
871 | original=original.substr(pos+1); | |
872 | ||
873 | return temp; | |
874 | } | |
875 | else if(c=='\'' && (quotetype==QuoteType::Single || quotetype==QuoteType::Both)) { | |
876 | inquotes=1; | |
877 | } | |
878 | else if(c=='"' && (quotetype==QuoteType::Double || quotetype==QuoteType::Both)) { | |
879 | inquotes=2; | |
880 | } | |
881 | ||
882 | pos++; | |
883 | } | |
884 | ||
885 | std::string temp; | |
886 | std::swap(temp, original); | |
887 | ||
888 | return temp; | |
889 | } | |
764
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
890 | |
1334 | 891 | } |
764
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
892 | } |
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
893 | |
7c71952bd75b
Gorgon code base has been moved to Source/Gorgon
cengizkandemir
parents:
diff
changeset
|
894 | # undef ISENUMUPGRADED |