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
10namespace 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
57namespace 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
901namespace std
902{
903/** Hash value generator for String. */
904template<>
905struct 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. */
917template<>
918struct 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