1 | //************************************ bs::framework - Copyright 2018 Marko Pintera **************************************// |
2 | //*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********// |
3 | #pragma once |
4 | |
5 | #include "Allocators/BsMemoryAllocator.h" |
6 | #include "Math/BsRadian.h" |
7 | |
8 | #include <string> |
9 | |
10 | namespace bs |
11 | { |
12 | /** @addtogroup String |
13 | * @{ |
14 | */ |
15 | |
16 | /** Basic string that uses framework's memory allocators. */ |
17 | template <typename T> |
18 | using BasicString = std::basic_string < T, std::char_traits<T>, StdAlloc<T> > ; |
19 | |
20 | /** Basic string stream that uses framework's memory allocators. */ |
21 | template <typename T> |
22 | using BasicStringStream = std::basic_stringstream < T, std::char_traits<T>, StdAlloc<T> > ; |
23 | |
24 | /** Wide string used primarily for handling Unicode text (UTF-32 on Linux, UTF-16 on Windows, generally). */ |
25 | using WString = BasicString<wchar_t>; |
26 | |
27 | /** Narrow string used for handling narrow encoded text (either locale specific ANSI or UTF-8). */ |
28 | using String = BasicString<char>; |
29 | |
30 | /** Wide string used UTF-16 encoded strings. */ |
31 | using U16String = BasicString<char16_t>; |
32 | |
33 | /** Wide string used UTF-32 encoded strings. */ |
34 | using U32String = BasicString<char32_t>; |
35 | |
36 | /** Wide string stream used for primarily for constructing wide strings. */ |
37 | using WStringStream = BasicStringStream<wchar_t>; |
38 | |
39 | /** Wide string stream used for primarily for constructing narrow strings. */ |
40 | using StringStream = BasicStringStream<char>; |
41 | |
42 | /** Wide string stream used for primarily for constructing UTF-16 strings. */ |
43 | using U16StringStream = BasicStringStream<char16_t>; |
44 | |
45 | /** Wide string stream used for primarily for constructing UTF-32 strings. */ |
46 | using U32StringStream = BasicStringStream<char32_t>; |
47 | |
48 | /** Equivalent to String, except it avoids any dynamic allocations until the number of elements exceeds @p Count. */ |
49 | template <int Count> |
50 | using SmallString = std::basic_string <char, std::char_traits<char>, StdAlloc<char>>; // TODO: Currently equivalent to String, need to implement the allocator |
51 | |
52 | /** @} */ |
53 | } |
54 | |
55 | #include "String/BsStringFormat.h" |
56 | |
57 | namespace bs |
58 | { |
59 | /** @addtogroup String |
60 | * @{ |
61 | */ |
62 | |
63 | /** Utility class for manipulating Strings. */ |
64 | class BS_UTILITY_EXPORT StringUtil |
65 | { |
66 | public: |
67 | /** Removes any whitespace characters from beginning or end of the string. */ |
68 | static void trim(String& str, bool left = true, bool right = true); |
69 | |
70 | /** @copydoc StringUtil::trim(String&, bool, bool) */ |
71 | static void trim(WString& str, bool left = true, bool right = true); |
72 | |
73 | /** Removes specified characters from beginning or end of the string. */ |
74 | static void trim(String& str, const String& delims, bool left = true, bool right = true); |
75 | |
76 | /** @copydoc StringUtil::trim(String&, const String&, bool, bool) */ |
77 | static void trim(WString& str, const WString& delims, bool left = true, bool right = true); |
78 | |
79 | /** |
80 | * Returns a vector of strings containing all the substrings delimited by the provided delimiter characters. |
81 | * |
82 | * @param[in] str The string to split. |
83 | * @param[in] delims (optional) Delimiter characters to split the string by. They will not |
84 | * be included in resulting substrings. |
85 | * @param[in] maxSplits (optional) The maximum number of splits to perform (0 for unlimited splits). If this |
86 | * parameters is > 0, the splitting process will stop after this many splits, left to right. |
87 | */ |
88 | static Vector<String> split(const String& str, const String& delims = "\t\n " , unsigned int maxSplits = 0); |
89 | |
90 | /** @copydoc StringUtil::split(const String&, const String&, unsigned int) */ |
91 | static Vector<WString> split(const WString& str, const WString& delims = L"\t\n " , unsigned int maxSplits = 0); |
92 | |
93 | /** |
94 | * Returns a vector of strings containing all the substrings delimited by the provided delimiter characters, or the |
95 | * double delimiters used for including normal delimiter characters in the tokenized string. |
96 | * |
97 | * @param[in] str The string to split. |
98 | * @param[in] delims (optional) Delimiter characters to split the string by. They will not |
99 | * be included in resulting substrings. |
100 | * @param[in] doubleDelims (optional) Delimiter character you may use to surround other normal delimiters, |
101 | * in order to include them in the tokensized string. |
102 | * @param[in] maxSplits (optional) The maximum number of splits to perform (0 for unlimited splits). |
103 | * If this parameters is > 0, the splitting process will stop after this many splits, |
104 | * left to right. |
105 | */ |
106 | static Vector<String> tokenise(const String& str, const String& delims = "\t\n " , |
107 | const String& doubleDelims = "\"" , unsigned int maxSplits = 0); |
108 | |
109 | /** @copydoc StringUtil::tokenise(const String&, const String&, const String&, unsigned int) */ |
110 | static Vector<WString> tokenise(const WString& str, const WString& delims = L"\t\n " , |
111 | const WString& doubleDelims = L"\"" , unsigned int maxSplits = 0); |
112 | |
113 | /** Converts all the characters in the string to lower case. Does not handle UTF8 encoded strings. */ |
114 | static void toLowerCase(String& str); |
115 | |
116 | /** Converts all the characters in the string to lower case. Does not handle UTF8 encoded strings. */ |
117 | static void toLowerCase(WString& str); |
118 | |
119 | /** Converts all the characters in the string to upper case. Does not handle UTF8 encoded strings. */ |
120 | static void toUpperCase(String& str); |
121 | |
122 | /** Converts all the characters in the string to upper case. Does not handle UTF8 encoded strings. */ |
123 | static void toUpperCase(WString& str); |
124 | |
125 | /** |
126 | * Returns whether the string begins with the pattern passed in. |
127 | * |
128 | * @param[in] str String to compare. |
129 | * @param[in] pattern Pattern to compare with. |
130 | * @param[in] lowerCase (optional) If true, the start of the string will be lower cased before comparison, and |
131 | * the pattern should also be in lower case. |
132 | */ |
133 | static bool startsWith(const String& str, const String& pattern, bool lowerCase = true); |
134 | |
135 | /** @copydoc startsWith(const String&, const String&, bool) */ |
136 | static bool startsWith(const WString& str, const WString& pattern, bool lowerCase = true); |
137 | |
138 | /** |
139 | * Returns whether the string end with the pattern passed in. |
140 | * |
141 | * @param[in] str String to compare. |
142 | * @param[in] pattern Pattern to compare with. |
143 | * @param[in] lowerCase (optional) If true, the start of the string will be lower cased before comparison, and |
144 | * the pattern should also be in lower case. |
145 | */ |
146 | static bool endsWith(const String& str, const String& pattern, bool lowerCase = true); |
147 | |
148 | /** @copydoc endsWith(const String&, const String&, bool) */ |
149 | static bool endsWith(const WString& str, const WString& pattern, bool lowerCase = true); |
150 | |
151 | /** |
152 | * Returns true if the string matches the provided pattern. Pattern may use a "*" wildcard for matching any |
153 | * characters. |
154 | * |
155 | * @param[in] str The string to test. |
156 | * @param[in] pattern Patterns to look for. |
157 | * @param[in] caseSensitive (optional) Should the match be case sensitive or not. |
158 | */ |
159 | static bool match(const String& str, const String& pattern, bool caseSensitive = true); |
160 | |
161 | /** @copydoc match(const String&, const String&, bool) */ |
162 | static bool match(const WString& str, const WString& pattern, bool caseSensitive = true); |
163 | |
164 | /** |
165 | * Replace all instances of a substring with a another substring. |
166 | * |
167 | * @param[in] source String to search. |
168 | * @param[in] replaceWhat Substring to find and replace |
169 | * @param[in] replaceWithWhat Substring to replace with (the new sub-string) |
170 | * |
171 | * @return An updated string with the substrings replaced. |
172 | */ |
173 | static const String replaceAll(const String& source, const String& replaceWhat, const String& replaceWithWhat); |
174 | |
175 | /** @copydoc replaceAll(const String&, const String&, const String&) */ |
176 | static const WString replaceAll(const WString& source, const WString& replaceWhat, const WString& replaceWithWhat); |
177 | |
178 | /** |
179 | * Compares two strings. Returns 0 if the two compare equal, <0 if the value of the left string is lower than of |
180 | * the right string, or >0 if the value of the left string is higher than the right string. |
181 | * |
182 | * @param[in] lhs Left string to compare. |
183 | * @param[in] rhs Right string to compare. |
184 | * @param[in] caseSensitive If true the comparison will consider uppercase and lowercase characters different. |
185 | * Note that case conversion does not handle UTF8 strings. |
186 | */ |
187 | template <class T> |
188 | static int compare(const BasicString<T>& lhs, const BasicString<T>& rhs, bool caseSensitive = true) |
189 | { |
190 | if (caseSensitive) |
191 | return (int)lhs.compare(rhs); |
192 | |
193 | int size = (int)std::min(lhs.size(), rhs.size()); |
194 | for (int i = 0; i < size; i++) |
195 | { |
196 | if (toupper(lhs[i]) < toupper(rhs[i])) return -1; |
197 | if (toupper(lhs[i]) > toupper(rhs[i])) return 1; |
198 | } |
199 | |
200 | return (lhs.size() < rhs.size() ? -1 : (lhs.size() == rhs.size() ? 0 : 1)); |
201 | } |
202 | |
203 | /** @copydoc StringFormat::format */ |
204 | template<class T, class... Args> |
205 | static BasicString<T> format(const BasicString<T>& source, Args&& ...args) |
206 | { |
207 | return StringFormat::format(source.c_str(), std::forward<Args>(args)...); |
208 | } |
209 | |
210 | /** @copydoc StringFormat::format */ |
211 | template<class T, class... Args> |
212 | static BasicString<T> format(const T* source, Args&& ...args) |
213 | { |
214 | return StringFormat::format(source, std::forward<Args>(args)...); |
215 | } |
216 | |
217 | /** Constant blank string, useful for returning by ref where local does not exist. */ |
218 | static const String BLANK; |
219 | |
220 | /** Constant blank wide string, useful for returning by ref where local does not exist. */ |
221 | static const WString WBLANK; |
222 | |
223 | private: |
224 | template <class T> |
225 | static Vector<BasicString<T>> splitInternal(const BasicString<T>& str, const BasicString<T>& delims, unsigned int maxSplits) |
226 | { |
227 | Vector<BasicString<T>> ret; |
228 | // Pre-allocate some space for performance |
229 | ret.reserve(maxSplits ? maxSplits+1 : 10); // 10 is guessed capacity for most case |
230 | |
231 | unsigned int numSplits = 0; |
232 | |
233 | // Use STL methods |
234 | size_t start, pos; |
235 | start = 0; |
236 | do |
237 | { |
238 | pos = str.find_first_of(delims, start); |
239 | if (pos == start) |
240 | { |
241 | // Do nothing |
242 | start = pos + 1; |
243 | } |
244 | else if (pos == BasicString<T>::npos || (maxSplits && numSplits == maxSplits)) |
245 | { |
246 | // Copy the rest of the string |
247 | ret.push_back(str.substr(start)); |
248 | break; |
249 | } |
250 | else |
251 | { |
252 | // Copy up to delimiter |
253 | ret.push_back(str.substr(start, pos - start)); |
254 | start = pos + 1; |
255 | } |
256 | // parse up to next real data |
257 | start = str.find_first_not_of(delims, start); |
258 | ++numSplits; |
259 | |
260 | } while (pos != BasicString<T>::npos); |
261 | |
262 | return ret; |
263 | } |
264 | |
265 | template <class T> |
266 | static Vector<BasicString<T>> tokeniseInternal(const BasicString<T>& str, const BasicString<T>& singleDelims, |
267 | const BasicString<T>& doubleDelims, unsigned int maxSplits) |
268 | { |
269 | Vector<BasicString<T>> ret; |
270 | // Pre-allocate some space for performance |
271 | ret.reserve(maxSplits ? maxSplits + 1 : 10); // 10 is guessed capacity for most case |
272 | |
273 | unsigned int numSplits = 0; |
274 | BasicString<T> delims = singleDelims + doubleDelims; |
275 | |
276 | // Use STL methods |
277 | size_t start, pos; |
278 | T curDoubleDelim = 0; |
279 | start = 0; |
280 | do |
281 | { |
282 | if (curDoubleDelim != 0) |
283 | { |
284 | pos = str.find(curDoubleDelim, start); |
285 | } |
286 | else |
287 | { |
288 | pos = str.find_first_of(delims, start); |
289 | } |
290 | |
291 | if (pos == start) |
292 | { |
293 | T curDelim = str.at(pos); |
294 | if (doubleDelims.find_first_of(curDelim) != BasicString<T>::npos) |
295 | { |
296 | curDoubleDelim = curDelim; |
297 | } |
298 | // Do nothing |
299 | start = pos + 1; |
300 | } |
301 | else if (pos == BasicString<T>::npos || (maxSplits && numSplits == maxSplits)) |
302 | { |
303 | if (curDoubleDelim != 0) |
304 | { |
305 | //Missing closer. Warn or throw exception? |
306 | } |
307 | // Copy the rest of the string |
308 | ret.push_back( str.substr(start) ); |
309 | break; |
310 | } |
311 | else |
312 | { |
313 | if (curDoubleDelim != 0) |
314 | { |
315 | curDoubleDelim = 0; |
316 | } |
317 | |
318 | // Copy up to delimiter |
319 | ret.push_back( str.substr(start, pos - start) ); |
320 | start = pos + 1; |
321 | } |
322 | if (curDoubleDelim == 0) |
323 | { |
324 | // parse up to next real data |
325 | start = str.find_first_not_of(singleDelims, start); |
326 | } |
327 | |
328 | ++numSplits; |
329 | |
330 | } while (pos != BasicString<T>::npos); |
331 | |
332 | return ret; |
333 | } |
334 | |
335 | template <class T> |
336 | static bool startsWithInternal(const BasicString<T>& str, const BasicString<T>& pattern, bool lowerCase) |
337 | { |
338 | size_t thisLen = str.length(); |
339 | size_t patternLen = pattern.length(); |
340 | if (thisLen < patternLen || patternLen == 0) |
341 | return false; |
342 | |
343 | BasicString<T> startOfThis = str.substr(0, patternLen); |
344 | if (lowerCase) |
345 | StringUtil::toLowerCase(startOfThis); |
346 | |
347 | return (startOfThis == pattern); |
348 | } |
349 | |
350 | template <class T> |
351 | static bool endsWithInternal(const BasicString<T>& str, const BasicString<T>& pattern, bool lowerCase) |
352 | { |
353 | size_t thisLen = str.length(); |
354 | size_t patternLen = pattern.length(); |
355 | if (thisLen < patternLen || patternLen == 0) |
356 | return false; |
357 | |
358 | BasicString<T> endOfThis = str.substr(thisLen - patternLen, patternLen); |
359 | if (lowerCase) |
360 | StringUtil::toLowerCase(endOfThis); |
361 | |
362 | return (endOfThis == pattern); |
363 | } |
364 | |
365 | template <class T> |
366 | static bool matchInternal(const BasicString<T>& str, const BasicString<T>& pattern, bool caseSensitive) |
367 | { |
368 | BasicString<T> tmpStr = str; |
369 | BasicString<T> tmpPattern = pattern; |
370 | if (!caseSensitive) |
371 | { |
372 | StringUtil::toLowerCase(tmpStr); |
373 | StringUtil::toLowerCase(tmpPattern); |
374 | } |
375 | |
376 | typename BasicString<T>::const_iterator strIt = tmpStr.begin(); |
377 | typename BasicString<T>::const_iterator patIt = tmpPattern.begin(); |
378 | typename BasicString<T>::const_iterator lastWildCardIt = tmpPattern.end(); |
379 | while (strIt != tmpStr.end() && patIt != tmpPattern.end()) |
380 | { |
381 | if (*patIt == '*') |
382 | { |
383 | lastWildCardIt = patIt; |
384 | // Skip over looking for next character |
385 | ++patIt; |
386 | if (patIt == tmpPattern.end()) |
387 | { |
388 | // Skip right to the end since * matches the entire rest of the string |
389 | strIt = tmpStr.end(); |
390 | } |
391 | else |
392 | { |
393 | // scan until we find next pattern character |
394 | while(strIt != tmpStr.end() && *strIt != *patIt) |
395 | ++strIt; |
396 | } |
397 | } |
398 | else |
399 | { |
400 | if (*patIt != *strIt) |
401 | { |
402 | if (lastWildCardIt != tmpPattern.end()) |
403 | { |
404 | // The last wildcard can match this incorrect sequence |
405 | // rewind pattern to wildcard and keep searching |
406 | patIt = lastWildCardIt; |
407 | lastWildCardIt = tmpPattern.end(); |
408 | } |
409 | else |
410 | { |
411 | // no wildwards left |
412 | return false; |
413 | } |
414 | } |
415 | else |
416 | { |
417 | ++patIt; |
418 | ++strIt; |
419 | } |
420 | } |
421 | |
422 | } |
423 | |
424 | // If we reached the end of both the pattern and the string, we succeeded |
425 | if (patIt == tmpPattern.end() && strIt == tmpStr.end()) |
426 | return true; |
427 | else |
428 | return false; |
429 | } |
430 | |
431 | template <class T> |
432 | static BasicString<T> replaceAllInternal(const BasicString<T>& source, |
433 | const BasicString<T>& replaceWhat, const BasicString<T>& replaceWithWhat) |
434 | { |
435 | BasicString<T> result = source; |
436 | typename BasicString<T>::size_type pos = 0; |
437 | while(1) |
438 | { |
439 | pos = result.find(replaceWhat,pos); |
440 | if (pos == BasicString<T>::npos) break; |
441 | result.replace(pos,replaceWhat.size(), replaceWithWhat); |
442 | pos += replaceWithWhat.size(); |
443 | } |
444 | return result; |
445 | } |
446 | }; |
447 | |
448 | /** Converts a narrow string to a wide string. */ |
449 | BS_UTILITY_EXPORT WString toWString(const String& source); |
450 | |
451 | /** Converts a narrow string to a wide string. */ |
452 | BS_UTILITY_EXPORT WString toWString(const char* source); |
453 | |
454 | /** Converts a float to a string. */ |
455 | BS_UTILITY_EXPORT WString toWString(float val, unsigned short precision = 6, |
456 | unsigned short width = 0, char fill = ' ', |
457 | std::ios::fmtflags flags = std::ios::fmtflags(0) ); |
458 | |
459 | /** Converts a double to a string. */ |
460 | BS_UTILITY_EXPORT WString toWString(double val, unsigned short precision = 6, |
461 | unsigned short width = 0, char fill = ' ', |
462 | std::ios::fmtflags flags = std::ios::fmtflags(0) ); |
463 | |
464 | /** Converts a Radian to a string. */ |
465 | BS_UTILITY_EXPORT WString toWString(Radian val, unsigned short precision = 6, |
466 | unsigned short width = 0, char fill = ' ', |
467 | std::ios::fmtflags flags = std::ios::fmtflags(0) ); |
468 | |
469 | /** Converts a Degree to a string. */ |
470 | BS_UTILITY_EXPORT WString toWString(Degree val, unsigned short precision = 6, |
471 | unsigned short width = 0, char fill = ' ', |
472 | std::ios::fmtflags flags = std::ios::fmtflags(0) ); |
473 | |
474 | /** Converts an int to a string. */ |
475 | BS_UTILITY_EXPORT WString toWString(int val, unsigned short width = 0, |
476 | char fill = ' ', |
477 | std::ios::fmtflags flags = std::ios::fmtflags(0) ); |
478 | |
479 | /** Converts an unsigned int to a string. */ |
480 | BS_UTILITY_EXPORT WString toWString(unsigned int val, |
481 | unsigned short width = 0, char fill = ' ', |
482 | std::ios::fmtflags flags = std::ios::fmtflags(0) ); |
483 | |
484 | /** Converts an 64bit integer to a string. */ |
485 | BS_UTILITY_EXPORT WString toWString(INT64 val, |
486 | unsigned short width = 0, char fill = ' ', |
487 | std::ios::fmtflags flags = std::ios::fmtflags(0) ); |
488 | |
489 | /** Converts an 64bit unsigned to a string. */ |
490 | BS_UTILITY_EXPORT WString toWString(UINT64 val, |
491 | unsigned short width = 0, char fill = ' ', |
492 | std::ios::fmtflags flags = std::ios::fmtflags(0) ); |
493 | |
494 | /** Converts an narrow char unsigned to a string. */ |
495 | BS_UTILITY_EXPORT WString toWString(char val, |
496 | unsigned short width = 0, char fill = ' ', |
497 | std::ios::fmtflags flags = std::ios::fmtflags(0)); |
498 | |
499 | /** Converts an wide bit char unsigned to a string. */ |
500 | BS_UTILITY_EXPORT WString toWString(wchar_t val, |
501 | unsigned short width = 0, char fill = ' ', |
502 | std::ios::fmtflags flags = std::ios::fmtflags(0)); |
503 | |
504 | /** |
505 | * Converts a boolean to a string. |
506 | * |
507 | * @param[in] val Value to convert. |
508 | * @param[in] yesNo (optional) If set to true, result is "yes" or "no" instead of "true" or "false". |
509 | */ |
510 | BS_UTILITY_EXPORT WString toWString(bool val, bool yesNo = false); |
511 | |
512 | /** |
513 | * Converts a 2 dimensional vector to a string. |
514 | * |
515 | * @note Format is "x y". |
516 | */ |
517 | BS_UTILITY_EXPORT WString toWString(const Vector2& val); |
518 | |
519 | /** |
520 | * Converts a 2 dimensional integer vector to a string. |
521 | * |
522 | * @note Format is "x y". |
523 | */ |
524 | BS_UTILITY_EXPORT WString toWString(const Vector2I& val); |
525 | |
526 | /** |
527 | * Converts a 3 dimensional vector to a string. |
528 | * |
529 | * @note Format is "x y z". |
530 | */ |
531 | BS_UTILITY_EXPORT WString toWString(const Vector3& val); |
532 | |
533 | /** |
534 | * Converts a 4 dimensional vector to a string. |
535 | * |
536 | * @note Format is "x y z w". |
537 | */ |
538 | BS_UTILITY_EXPORT WString toWString(const Vector4& val); |
539 | |
540 | /** |
541 | * Converts a 3x3 matrix to a string. |
542 | * |
543 | * @note Format is "00 01 02 10 11 12 20 21 22". |
544 | */ |
545 | BS_UTILITY_EXPORT WString toWString(const Matrix3& val); |
546 | |
547 | /** |
548 | * Converts a 4x4 matrix to a string. |
549 | * |
550 | * @note Format is "00 01 02 03 10 11 12 13 20 21 22 23 30 31 32 33". |
551 | */ |
552 | BS_UTILITY_EXPORT WString toWString(const Matrix4& val); |
553 | |
554 | /** |
555 | * Converts a Quaternion to a string. |
556 | * |
557 | * @note Format is "w x y z". |
558 | */ |
559 | BS_UTILITY_EXPORT WString toWString(const Quaternion& val); |
560 | |
561 | /** |
562 | * Converts a color to a string. |
563 | * |
564 | * @note Format is "r g b a". |
565 | */ |
566 | BS_UTILITY_EXPORT WString toWString(const Color& val); |
567 | |
568 | /** Converts a vector of strings into a single string where the substrings are delimited by spaces. */ |
569 | BS_UTILITY_EXPORT WString toWString(const Vector<bs::WString>& val); |
570 | |
571 | /** Converts a wide string to a narrow string. */ |
572 | BS_UTILITY_EXPORT String toString(const WString& source); |
573 | |
574 | /** Converts a wide string to a narrow string. */ |
575 | BS_UTILITY_EXPORT String toString(const wchar_t* source); |
576 | |
577 | /** Converts a float to a string. */ |
578 | BS_UTILITY_EXPORT String toString(float val, unsigned short precision = 6, |
579 | unsigned short width = 0, char fill = ' ', |
580 | std::ios::fmtflags flags = std::ios::fmtflags(0) ); |
581 | |
582 | /** Converts a double to a string. */ |
583 | BS_UTILITY_EXPORT String toString(double val, unsigned short precision = 6, |
584 | unsigned short width = 0, char fill = ' ', |
585 | std::ios::fmtflags flags = std::ios::fmtflags(0) ); |
586 | |
587 | /** Converts a Radian to a string. */ |
588 | BS_UTILITY_EXPORT String toString(Radian val, unsigned short precision = 6, |
589 | unsigned short width = 0, char fill = ' ', |
590 | std::ios::fmtflags flags = std::ios::fmtflags(0) ); |
591 | |
592 | /** Converts a Degree to a string. */ |
593 | BS_UTILITY_EXPORT String toString(Degree val, unsigned short precision = 6, |
594 | unsigned short width = 0, char fill = ' ', |
595 | std::ios::fmtflags flags = std::ios::fmtflags(0) ); |
596 | |
597 | /** Converts an int to a string. */ |
598 | BS_UTILITY_EXPORT String toString(int val, unsigned short width = 0, |
599 | char fill = ' ', |
600 | std::ios::fmtflags flags = std::ios::fmtflags(0) ); |
601 | |
602 | /** Converts an unsigned int to a string. */ |
603 | BS_UTILITY_EXPORT String toString(unsigned int val, |
604 | unsigned short width = 0, char fill = ' ', |
605 | std::ios::fmtflags flags = std::ios::fmtflags(0) ); |
606 | |
607 | /** Converts a 64bit int to a string. */ |
608 | BS_UTILITY_EXPORT String toString(INT64 val, |
609 | unsigned short width = 0, char fill = ' ', |
610 | std::ios::fmtflags flags = std::ios::fmtflags(0) ); |
611 | |
612 | /** Converts an 64bit unsigned int to a string. */ |
613 | BS_UTILITY_EXPORT String toString(UINT64 val, |
614 | unsigned short width = 0, char fill = ' ', |
615 | std::ios::fmtflags flags = std::ios::fmtflags(0) ); |
616 | |
617 | /** |
618 | * Converts a boolean to a string. |
619 | * |
620 | * @param[in] val true to value. |
621 | * @param[in] yesNo (optional) If set to true, result is "yes" or "no" instead of "true" or "false". |
622 | */ |
623 | BS_UTILITY_EXPORT String toString(bool val, bool yesNo = false); |
624 | |
625 | /** |
626 | * Converts a 2 dimensional vector to a string. |
627 | * |
628 | * @note Format is "x y". |
629 | */ |
630 | BS_UTILITY_EXPORT String toString(const Vector2& val); |
631 | |
632 | /** |
633 | * Converts a 2 dimensional integer vector to a string. |
634 | * |
635 | * @note Format is "x y". |
636 | */ |
637 | BS_UTILITY_EXPORT String toString(const Vector2I& val); |
638 | |
639 | /** |
640 | * Converts a 3 dimensional vector to a string. |
641 | * |
642 | * @note Format is "x y z". |
643 | */ |
644 | BS_UTILITY_EXPORT String toString(const Vector3& val); |
645 | |
646 | /** |
647 | * Converts a 4 dimensional vector to a string. |
648 | * |
649 | * @note Format is "x y z w". |
650 | */ |
651 | BS_UTILITY_EXPORT String toString(const Vector4& val); |
652 | |
653 | /** |
654 | * Converts a 3x3 matrix to a string. |
655 | * |
656 | * @note Format is "00 01 02 10 11 12 20 21 22". |
657 | */ |
658 | BS_UTILITY_EXPORT String toString(const Matrix3& val); |
659 | |
660 | /** |
661 | * Converts a 4x4 matrix to a string. |
662 | * |
663 | * @note Format is "00 01 02 03 10 11 12 13 20 21 22 23 30 31 32 33". |
664 | */ |
665 | BS_UTILITY_EXPORT String toString(const Matrix4& val); |
666 | |
667 | /** |
668 | * Converts a Quaternion to a string. |
669 | * |
670 | * @note Format is "w x y z". |
671 | */ |
672 | BS_UTILITY_EXPORT String toString(const Quaternion& val); |
673 | |
674 | /** |
675 | * Converts a color to a string. |
676 | * |
677 | * @note Format is "r g b a". |
678 | */ |
679 | BS_UTILITY_EXPORT String toString(const Color& val); |
680 | |
681 | /** |
682 | * Converts a vector of strings into a single string where the substrings are delimited by spaces. |
683 | */ |
684 | BS_UTILITY_EXPORT String toString(const Vector<bs::String>& val); |
685 | |
686 | /** |
687 | * Converts a String to a float. |
688 | * |
689 | * @note 0.0f if the value could not be parsed, otherwise the numeric version of the string. |
690 | */ |
691 | BS_UTILITY_EXPORT float parseFloat(const String& val, float defaultValue = 0); |
692 | |
693 | /** |
694 | * Converts a String to a whole number. |
695 | * |
696 | * @note 0 if the value could not be parsed, otherwise the numeric version of the string. |
697 | */ |
698 | BS_UTILITY_EXPORT INT32 parseINT32(const String& val, INT32 defaultValue = 0); |
699 | |
700 | /** |
701 | * Converts a String to a whole number. |
702 | * |
703 | * @note 0 if the value could not be parsed, otherwise the numeric version of the string. |
704 | */ |
705 | BS_UTILITY_EXPORT UINT32 parseUINT32(const String& val, UINT32 defaultValue = 0); |
706 | |
707 | /** |
708 | * Converts a String to a whole number. |
709 | * |
710 | * @note 0 if the value could not be parsed, otherwise the numeric version of the string. |
711 | */ |
712 | BS_UTILITY_EXPORT INT64 parseINT64(const String& val, INT64 defaultValue = 0); |
713 | |
714 | /** |
715 | * Converts a String to a whole number. |
716 | * |
717 | * @note 0 if the value could not be parsed, otherwise the numeric version of the string. |
718 | */ |
719 | BS_UTILITY_EXPORT UINT64 parseUINT64(const String& val, UINT64 defaultValue = 0); |
720 | |
721 | /** |
722 | * Converts a String to a boolean. |
723 | * |
724 | * @note Returns true if case-insensitive match of the start of the string matches "true", "yes" or "1", |
725 | * false otherwise. |
726 | */ |
727 | BS_UTILITY_EXPORT bool parseBool(const String& val, bool defaultValue = 0); |
728 | |
729 | /** Checks the String is a valid number value. */ |
730 | BS_UTILITY_EXPORT bool isNumber(const String& val); |
731 | |
732 | /** |
733 | * Converts a WString to a float. |
734 | * |
735 | * @note 0.0f if the value could not be parsed, otherwise the numeric version of the string. |
736 | */ |
737 | BS_UTILITY_EXPORT float parseFloat(const WString& val, float defaultValue = 0); |
738 | |
739 | /** |
740 | * Converts a WString to a whole number. |
741 | * |
742 | * @note 0 if the value could not be parsed, otherwise the numeric version of the string. |
743 | */ |
744 | BS_UTILITY_EXPORT INT32 parseINT32(const WString& val, INT32 defaultValue = 0); |
745 | |
746 | /** |
747 | * Converts a WString to a whole number. |
748 | * |
749 | * @note 0 if the value could not be parsed, otherwise the numeric version of the string. |
750 | */ |
751 | BS_UTILITY_EXPORT UINT32 parseUINT32(const WString& val, UINT32 defaultValue = 0); |
752 | |
753 | /** |
754 | * Converts a WString to a whole number. |
755 | * |
756 | * @note 0 if the value could not be parsed, otherwise the numeric version of the string. |
757 | */ |
758 | BS_UTILITY_EXPORT INT64 parseINT64(const WString& val, INT64 defaultValue = 0); |
759 | |
760 | /** |
761 | * Converts a WString to a whole number. |
762 | * |
763 | * @note 0 if the value could not be parsed, otherwise the numeric version of the string. |
764 | */ |
765 | BS_UTILITY_EXPORT UINT64 parseUINT64(const WString& val, UINT64 defaultValue = 0); |
766 | |
767 | /** |
768 | * Converts a WString to a boolean. |
769 | * |
770 | * @note Returns true if case-insensitive match of the start of the string |
771 | * matches "true", "yes" or "1", false otherwise. |
772 | */ |
773 | BS_UTILITY_EXPORT bool parseBool(const WString& val, bool defaultValue = 0); |
774 | |
775 | /** |
776 | * Checks the WString is a valid number value. |
777 | */ |
778 | BS_UTILITY_EXPORT bool isNumber(const WString& val); |
779 | |
780 | /** @name Internal |
781 | * @{ |
782 | */ |
783 | |
784 | /** Helper method that throws an exception regarding a data overflow. */ |
785 | void BS_UTILITY_EXPORT __string_throwDataOverflowException(); |
786 | |
787 | /** @} */ |
788 | /** @cond SPECIALIZATIONS */ |
789 | |
790 | /** |
791 | * RTTIPlainType specialization for String that allows strings be serialized as value types. |
792 | * |
793 | * @see RTTIPlainType |
794 | */ |
795 | template<> struct RTTIPlainType<String> |
796 | { |
797 | enum { id = 20 }; enum { hasDynamicSize = 1 }; |
798 | |
799 | static void toMemory(const String& data, char* memory) |
800 | { |
801 | UINT32 size = getDynamicSize(data); |
802 | |
803 | memcpy(memory, &size, sizeof(UINT32)); |
804 | memory += sizeof(UINT32); |
805 | size -= sizeof(UINT32); |
806 | memcpy(memory, data.data(), size); |
807 | } |
808 | |
809 | static UINT32 fromMemory(String& data, char* memory) |
810 | { |
811 | UINT32 size; |
812 | memcpy(&size, memory, sizeof(UINT32)); |
813 | memory += sizeof(UINT32); |
814 | |
815 | UINT32 stringSize = size - sizeof(UINT32); |
816 | char* buffer = (char*)bs_alloc(stringSize + 1); |
817 | memcpy(buffer, memory, stringSize); |
818 | buffer[stringSize] = '\0'; |
819 | data = String(buffer); |
820 | |
821 | bs_free(buffer); |
822 | |
823 | return size; |
824 | } |
825 | |
826 | static UINT32 getDynamicSize(const String& data) |
827 | { |
828 | UINT64 dataSize = data.size() * sizeof(String::value_type) + sizeof(UINT32); |
829 | |
830 | #if BS_DEBUG_MODE |
831 | if(dataSize > std::numeric_limits<UINT32>::max()) |
832 | { |
833 | __string_throwDataOverflowException(); |
834 | } |
835 | #endif |
836 | |
837 | return (UINT32)dataSize; |
838 | } |
839 | }; |
840 | |
841 | /** |
842 | * RTTIPlainType specialization for WString that allows strings be serialized as value types. |
843 | * |
844 | * @see RTTIPlainType |
845 | */ |
846 | template<> struct RTTIPlainType<WString> |
847 | { |
848 | enum { id = TID_WString }; enum { hasDynamicSize = 1 }; |
849 | |
850 | static void toMemory(const WString& data, char* memory) |
851 | { |
852 | UINT32 size = getDynamicSize(data); |
853 | |
854 | memcpy(memory, &size, sizeof(UINT32)); |
855 | memory += sizeof(UINT32); |
856 | size -= sizeof(UINT32); |
857 | memcpy(memory, data.data(), size); |
858 | } |
859 | |
860 | static UINT32 fromMemory(WString& data, char* memory) |
861 | { |
862 | UINT32 size; |
863 | memcpy(&size, memory, sizeof(UINT32)); |
864 | memory += sizeof(UINT32); |
865 | |
866 | UINT32 stringSize = size - sizeof(UINT32); |
867 | WString::value_type* buffer = (WString::value_type*)bs_alloc(stringSize + sizeof(WString::value_type)); |
868 | memcpy(buffer, memory, stringSize); |
869 | |
870 | UINT32 numChars = stringSize / sizeof(WString::value_type); |
871 | buffer[numChars] = L'\0'; |
872 | |
873 | data = WString(buffer); |
874 | |
875 | bs_free(buffer); |
876 | |
877 | return size; |
878 | } |
879 | |
880 | static UINT32 getDynamicSize(const WString& data) |
881 | { |
882 | UINT64 dataSize = data.size() * sizeof(WString::value_type) + sizeof(UINT32); |
883 | |
884 | #if BS_DEBUG_MODE |
885 | if(dataSize > std::numeric_limits<UINT32>::max()) |
886 | { |
887 | __string_throwDataOverflowException(); |
888 | } |
889 | #endif |
890 | |
891 | return (UINT32)dataSize; |
892 | } |
893 | }; |
894 | |
895 | /** @endcond */ |
896 | /** @} */ |
897 | } |
898 | |
899 | /** @cond STDLIB */ |
900 | |
901 | namespace std |
902 | { |
903 | /** Hash value generator for String. */ |
904 | template<> |
905 | struct hash<bs::String> |
906 | { |
907 | size_t operator()(const bs::String& string) const |
908 | { |
909 | size_t hash = 0; |
910 | for(size_t i = 0; i < string.size(); i++) |
911 | hash = 65599 * hash + string[i]; |
912 | return hash ^ (hash >> 16); |
913 | } |
914 | }; |
915 | |
916 | /** Hash value generator for WString. */ |
917 | template<> |
918 | struct hash<bs::WString> |
919 | { |
920 | size_t operator()(const bs::WString& string) const |
921 | { |
922 | size_t hash = 0; |
923 | for(size_t i = 0; i < string.size(); i++) |
924 | hash = 65599 * hash + string[i]; |
925 | return hash ^ (hash >> 16); |
926 | } |
927 | }; |
928 | } |
929 | |
930 | /** @endcond */ |
931 | |