TGUI 1.13
Loading...
Searching...
No Matches
String.hpp
1
2//
3// TGUI - Texus' Graphical User Interface
4// Copyright (C) 2012-2026 Bruno Van de Velde (vdv_b@tgui.eu)
5//
6// This software is provided 'as-is', without any express or implied warranty.
7// In no event will the authors be held liable for any damages arising from the use of this software.
8//
9// Permission is granted to anyone to use this software for any purpose,
10// including commercial applications, and to alter it and redistribute it freely,
11// subject to the following restrictions:
12//
13// 1. The origin of this software must not be misrepresented;
14// you must not claim that you wrote the original software.
15// If you use this software in a product, an acknowledgment
16// in the product documentation would be appreciated but is not required.
17//
18// 2. Altered source versions must be plainly marked as such,
19// and must not be misrepresented as being the original software.
20//
21// 3. This notice may not be removed or altered from any source distribution.
22//
24
25#ifndef TGUI_STRING_HPP
26#define TGUI_STRING_HPP
27
28#include <TGUI/Config.hpp>
29
30#include <TGUI/StringView.hpp>
31#include <TGUI/Utf.hpp>
32
33#include <cstring>
34#include <initializer_list>
35#include <iomanip>
36#include <locale>
37#include <ostream>
38#include <sstream>
39#include <string>
40#include <type_traits>
41#include <vector>
42
43#if TGUI_HAS_WINDOW_BACKEND_SFML
44 #include <SFML/System/String.hpp>
45#endif
46
48
49namespace tgui
50{
56 [[nodiscard]] TGUI_API bool isWhitespace(char character);
57
63 [[nodiscard]] TGUI_API bool isWhitespace(char32_t character);
64
70 [[nodiscard]] TGUI_API bool isAlpha(char32_t character);
71
77 [[nodiscard]] TGUI_API bool isDigit(char32_t character);
78
93 class TGUI_API String
94 {
95 private:
96 std::u32string m_string;
97
98 // Helper to check if template parameter is a string_view
99 template <typename StringViewType>
100 using IsStringViewType = std::enable_if_t<
101 std::is_same_v<StringViewType, std::string_view>
102#if defined(__cpp_lib_char8_t) && (__cpp_lib_char8_t >= 201811L)
103 || std::is_same_v<StringViewType, std::u8string_view>
104#endif
105 || std::is_same_v<StringViewType, std::wstring_view> || std::is_same_v<StringViewType, std::u16string_view>
106 || std::is_same_v<StringViewType, std::u32string_view>,
107 void>;
108
109 // Helper to check if iterator is either from std::u32string or std::u32string_view.
110 // When compiling with Emscipten (which used Clang 23), those iterators are the same
111 // and we can't have a seperate function for each.
112 template <typename IteratorType>
113 using IsU32Iterator = std::enable_if_t<std::is_convertible_v<IteratorType, std::u32string::const_iterator>
114 || std::is_convertible_v<IteratorType, StringView::const_iterator>,
115 void>;
116
117 public:
118 static constexpr auto npos = std::u32string_view::npos;
119
120 using iterator = std::u32string::iterator;
121 using const_iterator = std::u32string::const_iterator;
122 using reverse_iterator = std::u32string::reverse_iterator;
123 using const_reverse_iterator = std::u32string::const_reverse_iterator;
124
125 using value_type = char32_t;
126 using reference = char32_t&;
127 using const_reference = const char32_t&;
128
129 public:
137 [[nodiscard]] bool attemptToInt(int& result) const;
138
146 [[nodiscard]] bool attemptToUInt(unsigned int& result) const;
147
155 [[nodiscard]] bool attemptToFloat(float& result) const;
156
164 [[nodiscard]] int toInt(int defaultValue = 0) const;
165
173 [[nodiscard]] unsigned int toUInt(unsigned int defaultValue = 0) const;
174
182 [[nodiscard]] float toFloat(float defaultValue = 0) const;
183
189 [[nodiscard]] String trim() const;
190
196 [[nodiscard]] String toLower() const;
197
203 [[nodiscard]] String toUpper() const;
204
212 [[nodiscard]] bool equalIgnoreCase(const String& other) const;
213
214#ifndef TGUI_REMOVE_DEPRECATED_CODE
224 TGUI_DEPRECATED("Use starts_with instead") [[nodiscard]] bool startsWith(const String& substring) const;
225#endif
226
234 [[nodiscard]] bool startsWithIgnoreCase(const String& substring) const;
235
236#ifndef TGUI_REMOVE_DEPRECATED_CODE
246 TGUI_DEPRECATED("Use ends_with instead") [[nodiscard]] bool endsWith(const String& substring) const;
247#endif
248
256 [[nodiscard]] bool endsWithIgnoreCase(const String& substring) const;
257
266 String& replace(const String& searchFor, const String& replaceWith);
267
273 void remove(const String& substring);
274
281 [[nodiscard]] std::vector<String> split(const String& delimiter, bool trim = false) const;
282
289 [[nodiscard]] static String join(const std::vector<String>& segments, const String& separator);
290
298 template <typename T>
299 [[nodiscard]] static String fromNumber(T value)
300 {
301 // If the value is a floating point then we can't use std::to_string because its result depends on the locale.
302 // If the value is an 8-bit type (e.g. uint8_t and int8_t) then using std::ostringstream results in the wrong result,
303 // as it will be interpreted as a character instead of a number.
304 if constexpr (std::is_integral_v<T>)
305 {
306 return {std::to_string(value)};
307 }
308 else
309 {
310 std::ostringstream oss;
311 oss.imbue(std::locale::classic());
312 oss << value;
313 return {oss.str()};
314 }
315 }
316
325 template <typename T>
326 [[nodiscard]] static String fromNumberRounded(T value, unsigned int decimals)
327 {
328 // Precision is ignored by std::ostringstream for integers, so we use std::to_string for integers instead.
329 // If the value is an 8-bit type (e.g. uint8_t and int8_t) then using std::ostringstream results in the wrong result,
330 // as it will be interpreted as a character instead of a number. Which is why this separate branch for integers exists.
331 if constexpr (std::is_integral_v<T>)
332 return {std::to_string(value)};
333 else
334 {
335 std::ostringstream oss;
336 oss.imbue(std::locale::classic());
337 oss << std::fixed << std::setprecision(static_cast<int>(decimals));
338 oss << value;
339 return {oss.str()};
340 }
341 }
342
344
345 public:
346 String() = default;
347
348 String(const std::string& str);
349 String(const std::wstring& str);
350 String(const std::u16string& str);
351 String(const std::u32string& str);
352
353 String(std::u32string&& str) :
354 m_string{std::move(str)}
355 {
356 }
357
358 String(char ansiChar);
359 String(wchar_t wideChar);
360 String(char16_t utfChar);
361 String(char32_t utfChar);
362
363 String(const char* str);
364 String(const wchar_t* str);
365 String(const char16_t* str);
366 String(const char32_t* str) :
367 m_string{str}
368 {
369 }
370
371 // Constructor to initialize the string from a number (integer or float)
372 template <typename T, typename = typename std::enable_if_t<std::is_arithmetic_v<T>, T>>
373 explicit String(T number) :
374 String{fromNumber(number)}
375 {
376 }
377
378 String(std::size_t count, char ch);
379 String(std::size_t count, wchar_t ch);
380 String(std::size_t count, char16_t ch);
381 String(std::size_t count, char32_t ch);
382
383 String(const std::string& str, std::size_t pos);
384 String(const std::wstring& str, std::size_t pos);
385 String(const std::u16string& str, std::size_t pos);
386 String(const std::u32string& str, std::size_t pos);
387
388 String(const std::string& str, std::size_t pos, std::size_t count);
389 String(const std::wstring& str, std::size_t pos, std::size_t count);
390 String(const std::u16string& str, std::size_t pos, std::size_t count);
391 String(const std::u32string& str, std::size_t pos, std::size_t count);
392
393 String(const char* str, std::size_t count);
394 String(const wchar_t* str, std::size_t count);
395 String(const char16_t* str, std::size_t count);
396 String(const char32_t* str, std::size_t count);
397
398 explicit String(std::initializer_list<char> chars);
399 explicit String(std::initializer_list<wchar_t> chars);
400 explicit String(std::initializer_list<char16_t> chars);
401 explicit String(std::initializer_list<char32_t> chars);
402
403 // Constructors using iterators have to be explicit to prevent {"1", "2"} to be ambiguous between String and std::vector<String>.
404 // The reason these constructors were considered a candicate to clang is due to a private constructor in the iterator class.
405 // We can't accept string_view::const_iterator iterators, because it would lead to the same kind of ambiguity even when the
406 // constructor is marked explicit (in GCC but not MSVC if we define the function normally, in MSVC but not GCC if we use a template).
407 explicit String(std::string::const_iterator first, std::string::const_iterator last);
408 explicit String(std::wstring::const_iterator first, std::wstring::const_iterator last);
409 explicit String(std::u16string::const_iterator first, std::u16string::const_iterator last);
410 explicit String(std::u32string::const_iterator first, std::u32string::const_iterator last);
411
412 template <typename StringViewType, typename = IsStringViewType<StringViewType>>
413 explicit String(const StringViewType& stringView) :
414 String(stringView.data(), stringView.size())
415 {
416 }
417
418 template <typename StringViewType, typename = IsStringViewType<StringViewType>>
419 explicit String(const StringViewType& stringView, std::size_t pos, std::size_t count) :
420 String(stringView.data() + pos, count)
421 {
422 }
423
424#if TGUI_HAS_WINDOW_BACKEND_SFML
425 // This constructor has to be explicit or it will cause MSVC to no longer compile code that performs sf::String + std::string
426 explicit String(const sf::String& str) :
427 #if SFML_VERSION_MAJOR >= 3
428 m_string{str.toUtf32()}
429 #else
430 m_string{reinterpret_cast<const char32_t*>(str.toUtf32().c_str())}
431 #endif
432 {
433 }
434
435 #if (SFML_VERSION_MAJOR < 3) || (SFML_VERSION_MAJOR == 3 && SFML_VERSION_MINOR < 1)
436 // When compiling with C++17, the conversion to sf::String is done with the StringView operator for SFML 3.1 or higher
437 explicit operator sf::String() const
438 {
439 return sf::String::fromUtf32(m_string.cbegin(), m_string.cend());
440 }
441 #endif
442#endif // TGUI_HAS_WINDOW_BACKEND_SFML
443
444 explicit operator std::string() const;
445 explicit operator std::wstring() const;
446 explicit operator std::u16string() const;
447 explicit operator const std::u32string&() const
448 {
449 return m_string;
450 }
451
452 operator StringView() const noexcept
453 {
454 return m_string;
455 }
456
457 [[nodiscard]] std::string toStdString() const;
458 [[nodiscard]] std::wstring toWideString() const;
459 [[nodiscard]] std::u16string toUtf16() const;
460 [[nodiscard]] const std::u32string& toUtf32() const
461 {
462 return m_string;
463 }
464
465 String& assign(std::size_t count, char ch);
466 String& assign(std::size_t count, wchar_t ch);
467 String& assign(std::size_t count, char16_t ch);
468 String& assign(std::size_t count, char32_t ch);
469
470 String& assign(StringView sv);
471 String& assign(const char32_t* str);
472 String& assign(const std::u32string& str);
473 String& assign(const String& str);
474
475 String& assign(StringView sv, std::size_t pos, std::size_t count = npos);
476 String& assign(const std::string& str, std::size_t pos, std::size_t count = npos);
477 String& assign(const std::wstring& str, std::size_t pos, std::size_t count = npos);
478 String& assign(const std::u16string& str, std::size_t pos, std::size_t count = npos);
479 String& assign(const std::u32string& str, std::size_t pos, std::size_t count = npos);
480 String& assign(const String& str, std::size_t pos, std::size_t count = npos);
481
482 String& assign(std::u32string&& str);
483 String& assign(String&& str);
484
485 String& assign(const char* str, std::size_t count);
486 String& assign(const wchar_t* str, std::size_t count);
487 String& assign(const char16_t* str, std::size_t count);
488 String& assign(const char32_t* str, std::size_t count);
489
490 String& assign(std::initializer_list<char> chars);
491 String& assign(std::initializer_list<wchar_t> chars);
492 String& assign(std::initializer_list<char16_t> chars);
493 String& assign(std::initializer_list<char32_t> chars);
494
495 String& assign(std::string::const_iterator first, std::string::const_iterator last);
496 String& assign(std::wstring::const_iterator first, std::wstring::const_iterator last);
497 String& assign(std::u16string::const_iterator first, std::u16string::const_iterator last);
498
499 template <typename IteratorType, typename = IsU32Iterator<IteratorType>>
500 String& assign(IteratorType first, IteratorType last)
501 {
502 m_string.assign(first, last);
503 return *this;
504 }
505
506 [[nodiscard]] reference at(std::size_t pos);
507 [[nodiscard]] const_reference at(std::size_t pos) const;
508
509 [[nodiscard]] const_reference operator[](std::size_t index) const;
510 [[nodiscard]] reference operator[](std::size_t index);
511
512 [[nodiscard]] reference front();
513 [[nodiscard]] const_reference front() const;
514
515 [[nodiscard]] reference back();
516 [[nodiscard]] const_reference back() const;
517
518 [[nodiscard]] const char32_t* data() const noexcept
519 {
520 return m_string.data();
521 }
522
523 [[nodiscard]] char32_t* data() noexcept
524 {
525 return m_string.data();
526 }
527
528 [[nodiscard]] const char32_t* c_str() const noexcept
529 {
530 return m_string.c_str();
531 }
532
533 [[nodiscard]] iterator begin() noexcept;
534 [[nodiscard]] const_iterator begin() const noexcept;
535 [[nodiscard]] const_iterator cbegin() const noexcept;
536
537 [[nodiscard]] iterator end() noexcept;
538 [[nodiscard]] const_iterator end() const noexcept;
539 [[nodiscard]] const_iterator cend() const noexcept;
540
541 [[nodiscard]] reverse_iterator rbegin() noexcept;
542 [[nodiscard]] const_reverse_iterator rbegin() const noexcept;
543 [[nodiscard]] const_reverse_iterator crbegin() const noexcept;
544
545 [[nodiscard]] reverse_iterator rend() noexcept;
546 [[nodiscard]] const_reverse_iterator rend() const noexcept;
547 [[nodiscard]] const_reverse_iterator crend() const noexcept;
548
549 [[nodiscard]] bool empty() const noexcept
550 {
551 return m_string.empty();
552 }
553
554 [[nodiscard]] std::size_t size() const noexcept
555 {
556 return m_string.size();
557 }
558
559 [[nodiscard]] std::size_t length() const noexcept
560 {
561 return m_string.length();
562 }
563
564 [[nodiscard]] std::size_t max_size() const noexcept;
565
566 void reserve(std::size_t newCap);
567 [[nodiscard]] std::size_t capacity() const noexcept;
568 void shrink_to_fit();
569
570 void clear() noexcept;
571
572 String& insert(std::size_t index, std::size_t count, char ch);
573 String& insert(std::size_t index, std::size_t count, wchar_t ch);
574 String& insert(std::size_t index, std::size_t count, char16_t ch);
575 String& insert(std::size_t index, std::size_t count, char32_t ch);
576
577 String& insert(std::size_t index, StringView sv);
578 String& insert(std::size_t index, const char32_t* str);
579 String& insert(std::size_t index, const std::u32string& str);
580 String& insert(std::size_t index, const String& str);
581
582 String& insert(std::size_t index, StringView sv, std::size_t pos, std::size_t count = npos);
583 String& insert(std::size_t index, const std::string& str, std::size_t pos, std::size_t count = npos);
584 String& insert(std::size_t index, const std::wstring& str, std::size_t pos, std::size_t count = npos);
585 String& insert(std::size_t index, const std::u16string& str, std::size_t pos, std::size_t count = npos);
586 String& insert(std::size_t index, const std::u32string& str, std::size_t pos, std::size_t count = npos);
587 String& insert(std::size_t index, const String& str, std::size_t pos, std::size_t count = npos);
588
589 String& insert(std::size_t index, const char* str, std::size_t count);
590 String& insert(std::size_t index, const wchar_t* str, std::size_t count);
591 String& insert(std::size_t index, const char16_t* str, std::size_t count);
592 String& insert(std::size_t index, const char32_t* str, std::size_t count);
593
594 iterator insert(const_iterator pos, char ch);
595 iterator insert(const_iterator pos, wchar_t ch);
596 iterator insert(const_iterator pos, char16_t ch);
597 iterator insert(const_iterator pos, char32_t ch);
598
599 iterator insert(const_iterator pos, std::size_t count, char ch);
600 iterator insert(const_iterator pos, std::size_t count, wchar_t ch);
601 iterator insert(const_iterator pos, std::size_t count, char16_t ch);
602 iterator insert(const_iterator pos, std::size_t count, char32_t ch);
603
604 iterator insert(const_iterator pos, std::initializer_list<char> chars);
605 iterator insert(const_iterator pos, std::initializer_list<wchar_t> chars);
606 iterator insert(const_iterator pos, std::initializer_list<char16_t> chars);
607 iterator insert(const_iterator pos, std::initializer_list<char32_t> chars);
608
609 iterator insert(const_iterator pos, std::string::const_iterator first, std::string::const_iterator last);
610 iterator insert(const_iterator pos, std::wstring::const_iterator first, std::wstring::const_iterator last);
611 iterator insert(const_iterator pos, std::u16string::const_iterator first, std::u16string::const_iterator last);
612
613 template <typename IteratorType, typename = IsU32Iterator<IteratorType>>
614 String& insert(const_iterator pos, IteratorType first, IteratorType last)
615 {
616 m_string.insert(pos, first, last);
617 return *this;
618 }
619
620 String& erase(std::size_t index = 0, std::size_t count = npos);
621
622 iterator erase(const_iterator position);
623 iterator erase(const_iterator first, const_iterator last);
624
625 void push_back(char ch);
626 void push_back(wchar_t ch);
627 void push_back(char16_t ch);
628 void push_back(char32_t ch);
629
630 void pop_back();
631
632 String& append(std::size_t count, char ch);
633 String& append(std::size_t count, wchar_t ch);
634 String& append(std::size_t count, char16_t ch);
635 String& append(std::size_t count, char32_t ch);
636
637 String& append(StringView sv);
638 String& append(const char32_t* str);
639 String& append(const std::u32string& str);
640 String& append(const String& str);
641
642 String& append(StringView sv, std::size_t pos, std::size_t count = npos);
643 String& append(const std::string& str, std::size_t pos, std::size_t count = npos);
644 String& append(const std::wstring& str, std::size_t pos, std::size_t count = npos);
645 String& append(const std::u16string& str, std::size_t pos, std::size_t count = npos);
646 String& append(const std::u32string& str, std::size_t pos, std::size_t count = npos);
647 String& append(const String& str, std::size_t pos, std::size_t count = npos);
648
649 String& append(const char* str, std::size_t count);
650 String& append(const wchar_t* str, std::size_t count);
651 String& append(const char16_t* str, std::size_t count);
652 String& append(const char32_t* str, std::size_t count);
653
654 String& append(std::string::const_iterator first, std::string::const_iterator last);
655 String& append(std::wstring::const_iterator first, std::wstring::const_iterator last);
656 String& append(std::u16string::const_iterator first, std::u16string::const_iterator last);
657
658 template <typename IteratorType, typename = IsU32Iterator<IteratorType>>
659 String& append(IteratorType first, IteratorType last)
660 {
661 m_string.append(first, last);
662 return *this;
663 }
664
665 String& append(std::initializer_list<char> chars);
666 String& append(std::initializer_list<wchar_t> chars);
667 String& append(std::initializer_list<char16_t> chars);
668 String& append(std::initializer_list<char32_t> chars);
669
670 String& operator+=(const String& str);
671
672 [[nodiscard]] int compare(StringView sv) const noexcept;
673 [[nodiscard]] int compare(const char32_t* s) const;
674 [[nodiscard]] int compare(const std::u32string& str) const noexcept;
675 [[nodiscard]] int compare(const String& str) const noexcept;
676
677 [[nodiscard]] int compare(std::size_t pos1, std::size_t count1, StringView sv) const;
678 [[nodiscard]] int compare(std::size_t pos1, std::size_t count1, const char32_t* s) const;
679 [[nodiscard]] int compare(std::size_t pos1, std::size_t count1, const std::u32string& str) const;
680 [[nodiscard]] int compare(std::size_t pos1, std::size_t count1, const String& str) const;
681
682 [[nodiscard]] int compare(std::size_t pos1, std::size_t count1, StringView sv, std::size_t pos2, std::size_t count2 = npos) const;
683 [[nodiscard]] int compare(std::size_t pos1,
684 std::size_t count1,
685 const std::string& str,
686 std::size_t pos2,
687 std::size_t count2 = npos) const;
688 [[nodiscard]] int compare(std::size_t pos1,
689 std::size_t count1,
690 const std::wstring& str,
691 std::size_t pos2,
692 std::size_t count2 = npos) const;
693 [[nodiscard]] int compare(std::size_t pos1,
694 std::size_t count1,
695 const std::u16string& str,
696 std::size_t pos2,
697 std::size_t count2 = npos) const;
698 [[nodiscard]] int compare(std::size_t pos1,
699 std::size_t count1,
700 const std::u32string& str,
701 std::size_t pos2,
702 std::size_t count2 = npos) const;
703 [[nodiscard]] int compare(std::size_t pos1, std::size_t count1, const String& str, std::size_t pos2, std::size_t count2 = npos) const;
704
705 [[nodiscard]] int compare(std::size_t pos1, std::size_t count1, const char* s, std::size_t count2) const;
706 [[nodiscard]] int compare(std::size_t pos1, std::size_t count1, const wchar_t* s, std::size_t count2) const;
707 [[nodiscard]] int compare(std::size_t pos1, std::size_t count1, const char16_t* s, std::size_t count2) const;
708 [[nodiscard]] int compare(std::size_t pos1, std::size_t count1, const char32_t* s, std::size_t count2) const;
709
710 String& replace(std::size_t pos, std::size_t count, StringView sv);
711 String& replace(std::size_t pos, std::size_t count, const char32_t* cstr);
712 String& replace(std::size_t pos, std::size_t count, const std::u32string& str);
713 String& replace(std::size_t pos, std::size_t count, const String& str);
714
715 String& replace(const_iterator first, const_iterator last, StringView sv);
716 String& replace(const_iterator first, const_iterator last, const char32_t* cstr);
717 String& replace(const_iterator first, const_iterator last, const std::u32string& str);
718 String& replace(const_iterator first, const_iterator last, const String& str);
719
720 String& replace(std::size_t pos, std::size_t count, StringView sv, std::size_t pos2, std::size_t count2 = npos);
721 String& replace(std::size_t pos, std::size_t count, const std::string& str, std::size_t pos2, std::size_t count2 = npos);
722 String& replace(std::size_t pos, std::size_t count, const std::wstring& str, std::size_t pos2, std::size_t count2 = npos);
723 String& replace(std::size_t pos, std::size_t count, const std::u16string& str, std::size_t pos2, std::size_t count2 = npos);
724 String& replace(std::size_t pos, std::size_t count, const std::u32string& str, std::size_t pos2, std::size_t count2 = npos);
725 String& replace(std::size_t pos, std::size_t count, const String& str, std::size_t pos2, std::size_t count2 = npos);
726
727 String& replace(const_iterator first, const_iterator last, std::string::const_iterator first2, std::string::const_iterator last2);
728 String& replace(const_iterator first, const_iterator last, std::wstring::const_iterator first2, std::wstring::const_iterator last2);
729 String& replace(const_iterator first,
730 const_iterator last,
731 std::u16string::const_iterator first2,
732 std::u16string::const_iterator last2);
733
734 template <typename IteratorType, typename = IsU32Iterator<IteratorType>>
735 String& replace(const_iterator first, const_iterator last, IteratorType first2, IteratorType last2)
736 {
737 m_string.replace(first, last, first2, last2);
738 return *this;
739 }
740
741 String& replace(std::size_t pos, std::size_t count, const char* cstr, std::size_t count2);
742 String& replace(std::size_t pos, std::size_t count, const wchar_t* cstr, std::size_t count2);
743 String& replace(std::size_t pos, std::size_t count, const char16_t* cstr, std::size_t count2);
744 String& replace(std::size_t pos, std::size_t count, const char32_t* cstr, std::size_t count2);
745
746 String& replace(const_iterator first, const_iterator last, const char* cstr, std::size_t count2);
747 String& replace(const_iterator first, const_iterator last, const wchar_t* cstr, std::size_t count2);
748 String& replace(const_iterator first, const_iterator last, const char16_t* cstr, std::size_t count2);
749 String& replace(const_iterator first, const_iterator last, const char32_t* cstr, std::size_t count2);
750
751 String& replace(std::size_t pos, std::size_t count, std::size_t count2, char ch);
752 String& replace(std::size_t pos, std::size_t count, std::size_t count2, wchar_t ch);
753 String& replace(std::size_t pos, std::size_t count, std::size_t count2, char16_t ch);
754 String& replace(std::size_t pos, std::size_t count, std::size_t count2, char32_t ch);
755
756 String& replace(const_iterator first, const_iterator last, std::size_t count2, char ch);
757 String& replace(const_iterator first, const_iterator last, std::size_t count2, wchar_t ch);
758 String& replace(const_iterator first, const_iterator last, std::size_t count2, char16_t ch);
759 String& replace(const_iterator first, const_iterator last, std::size_t count2, char32_t ch);
760
761 String& replace(const_iterator first, const_iterator last, std::initializer_list<char> chars);
762 String& replace(const_iterator first, const_iterator last, std::initializer_list<wchar_t> chars);
763 String& replace(const_iterator first, const_iterator last, std::initializer_list<char16_t> chars);
764 String& replace(const_iterator first, const_iterator last, std::initializer_list<char32_t> chars);
765
766 [[nodiscard]] String substr(std::size_t pos = 0, std::size_t count = npos) const;
767
768 std::size_t copy(char32_t* dest, std::size_t count, std::size_t pos = 0) const;
769
770 void resize(std::size_t count);
771 void resize(std::size_t count, char ch);
772 void resize(std::size_t count, wchar_t ch);
773 void resize(std::size_t count, char16_t ch);
774 void resize(std::size_t count, char32_t ch);
775
776 void swap(String& other) noexcept;
777
778 [[nodiscard]] bool contains(char c) const noexcept;
779 [[nodiscard]] bool contains(wchar_t c) const noexcept;
780 [[nodiscard]] bool contains(char16_t c) const noexcept;
781 [[nodiscard]] bool contains(char32_t c) const noexcept;
782
783 [[nodiscard]] bool contains(StringView sv) const noexcept;
784 [[nodiscard]] bool contains(const char32_t* s) const;
785 [[nodiscard]] bool contains(const std::u32string& s) const;
786 [[nodiscard]] bool contains(const String& s) const;
787
788 [[nodiscard]] std::size_t find(StringView sv, std::size_t pos = 0) const noexcept;
789 [[nodiscard]] std::size_t find(const char32_t* s, std::size_t pos = 0) const;
790 [[nodiscard]] std::size_t find(const std::u32string& str, std::size_t pos = 0) const noexcept;
791 [[nodiscard]] std::size_t find(const String& str, std::size_t pos = 0) const noexcept;
792
793 [[nodiscard]] std::size_t find(const char* s, std::size_t pos, std::size_t count) const;
794 [[nodiscard]] std::size_t find(const wchar_t* s, std::size_t pos, std::size_t count) const;
795 [[nodiscard]] std::size_t find(const char16_t* s, std::size_t pos, std::size_t count) const;
796 [[nodiscard]] std::size_t find(const char32_t* s, std::size_t pos, std::size_t count) const;
797
798 [[nodiscard]] std::size_t find(char ch, std::size_t pos = 0) const noexcept;
799 [[nodiscard]] std::size_t find(wchar_t ch, std::size_t pos = 0) const noexcept;
800 [[nodiscard]] std::size_t find(char16_t ch, std::size_t pos = 0) const noexcept;
801 [[nodiscard]] std::size_t find(char32_t ch, std::size_t pos = 0) const noexcept;
802
803 [[nodiscard]] std::size_t find_first_of(StringView sv, std::size_t pos = 0) const noexcept;
804 [[nodiscard]] std::size_t find_first_of(const char32_t* s, std::size_t pos = 0) const;
805 [[nodiscard]] std::size_t find_first_of(const std::u32string& str, std::size_t pos = 0) const noexcept;
806 [[nodiscard]] std::size_t find_first_of(const String& str, std::size_t pos = 0) const noexcept;
807
808 [[nodiscard]] std::size_t find_first_of(const char* s, std::size_t pos, std::size_t count) const;
809 [[nodiscard]] std::size_t find_first_of(const wchar_t* s, std::size_t pos, std::size_t count) const;
810 [[nodiscard]] std::size_t find_first_of(const char16_t* s, std::size_t pos, std::size_t count) const;
811 [[nodiscard]] std::size_t find_first_of(const char32_t* s, std::size_t pos, std::size_t count) const;
812
813 [[nodiscard]] std::size_t find_first_of(char ch, std::size_t pos = 0) const noexcept;
814 [[nodiscard]] std::size_t find_first_of(wchar_t ch, std::size_t pos = 0) const noexcept;
815 [[nodiscard]] std::size_t find_first_of(char16_t ch, std::size_t pos = 0) const noexcept;
816 [[nodiscard]] std::size_t find_first_of(char32_t ch, std::size_t pos = 0) const noexcept;
817
818 [[nodiscard]] std::size_t find_first_not_of(StringView sv, std::size_t pos = 0) const noexcept;
819 [[nodiscard]] std::size_t find_first_not_of(const char32_t* s, std::size_t pos = 0) const;
820 [[nodiscard]] std::size_t find_first_not_of(const std::u32string& str, std::size_t pos = 0) const noexcept;
821 [[nodiscard]] std::size_t find_first_not_of(const String& str, std::size_t pos = 0) const noexcept;
822
823 [[nodiscard]] std::size_t find_first_not_of(const char* s, std::size_t pos, std::size_t count) const;
824 [[nodiscard]] std::size_t find_first_not_of(const wchar_t* s, std::size_t pos, std::size_t count) const;
825 [[nodiscard]] std::size_t find_first_not_of(const char16_t* s, std::size_t pos, std::size_t count) const;
826 [[nodiscard]] std::size_t find_first_not_of(const char32_t* s, std::size_t pos, std::size_t count) const;
827
828 [[nodiscard]] std::size_t find_first_not_of(char ch, std::size_t pos = 0) const noexcept;
829 [[nodiscard]] std::size_t find_first_not_of(wchar_t ch, std::size_t pos = 0) const noexcept;
830 [[nodiscard]] std::size_t find_first_not_of(char16_t ch, std::size_t pos = 0) const noexcept;
831 [[nodiscard]] std::size_t find_first_not_of(char32_t ch, std::size_t pos = 0) const noexcept;
832
833 [[nodiscard]] std::size_t rfind(StringView sv, std::size_t pos = npos) const noexcept;
834 [[nodiscard]] std::size_t rfind(const char32_t* s, std::size_t pos = npos) const;
835 [[nodiscard]] std::size_t rfind(const std::u32string& str, std::size_t pos = npos) const noexcept;
836 [[nodiscard]] std::size_t rfind(const String& str, std::size_t pos = npos) const noexcept;
837
838 [[nodiscard]] std::size_t rfind(const char* s, std::size_t pos, std::size_t count) const;
839 [[nodiscard]] std::size_t rfind(const wchar_t* s, std::size_t pos, std::size_t count) const;
840 [[nodiscard]] std::size_t rfind(const char16_t* s, std::size_t pos, std::size_t count) const;
841 [[nodiscard]] std::size_t rfind(const char32_t* s, std::size_t pos, std::size_t count) const;
842
843 [[nodiscard]] std::size_t rfind(char ch, std::size_t pos = npos) const noexcept;
844 [[nodiscard]] std::size_t rfind(wchar_t ch, std::size_t pos = npos) const noexcept;
845 [[nodiscard]] std::size_t rfind(char16_t ch, std::size_t pos = npos) const noexcept;
846 [[nodiscard]] std::size_t rfind(char32_t ch, std::size_t pos = npos) const noexcept;
847
848 [[nodiscard]] std::size_t find_last_of(StringView sv, std::size_t pos = npos) const noexcept;
849 [[nodiscard]] std::size_t find_last_of(const char32_t* s, std::size_t pos = npos) const;
850 [[nodiscard]] std::size_t find_last_of(const std::u32string& str, std::size_t pos = npos) const noexcept;
851 [[nodiscard]] std::size_t find_last_of(const String& str, std::size_t pos = npos) const noexcept;
852
853 [[nodiscard]] std::size_t find_last_of(const char* s, std::size_t pos, std::size_t count) const;
854 [[nodiscard]] std::size_t find_last_of(const wchar_t* s, std::size_t pos, std::size_t count) const;
855 [[nodiscard]] std::size_t find_last_of(const char16_t* s, std::size_t pos, std::size_t count) const;
856 [[nodiscard]] std::size_t find_last_of(const char32_t* s, std::size_t pos, std::size_t count) const;
857
858 [[nodiscard]] std::size_t find_last_of(char ch, std::size_t pos = npos) const noexcept;
859 [[nodiscard]] std::size_t find_last_of(wchar_t ch, std::size_t pos = npos) const noexcept;
860 [[nodiscard]] std::size_t find_last_of(char16_t ch, std::size_t pos = npos) const noexcept;
861 [[nodiscard]] std::size_t find_last_of(char32_t ch, std::size_t pos = npos) const noexcept;
862
863 [[nodiscard]] std::size_t find_last_not_of(StringView sv, std::size_t pos = npos) const noexcept;
864 [[nodiscard]] std::size_t find_last_not_of(const char32_t* s, std::size_t pos = npos) const;
865 [[nodiscard]] std::size_t find_last_not_of(const std::u32string& str, std::size_t pos = npos) const noexcept;
866 [[nodiscard]] std::size_t find_last_not_of(const String& str, std::size_t pos = npos) const noexcept;
867
868 [[nodiscard]] std::size_t find_last_not_of(const char* s, std::size_t pos, std::size_t count) const;
869 [[nodiscard]] std::size_t find_last_not_of(const wchar_t* s, std::size_t pos, std::size_t count) const;
870 [[nodiscard]] std::size_t find_last_not_of(const char16_t* s, std::size_t pos, std::size_t count) const;
871 [[nodiscard]] std::size_t find_last_not_of(const char32_t* s, std::size_t pos, std::size_t count) const;
872
873 [[nodiscard]] std::size_t find_last_not_of(char ch, std::size_t pos = npos) const noexcept;
874 [[nodiscard]] std::size_t find_last_not_of(wchar_t ch, std::size_t pos = npos) const noexcept;
875 [[nodiscard]] std::size_t find_last_not_of(char16_t ch, std::size_t pos = npos) const noexcept;
876 [[nodiscard]] std::size_t find_last_not_of(char32_t ch, std::size_t pos = npos) const noexcept;
877
878 [[nodiscard]] inline bool starts_with(StringView sv) const noexcept;
879 [[nodiscard]] inline bool starts_with(const char32_t* s) const;
880 [[nodiscard]] inline bool starts_with(const std::u32string& s) const;
881 [[nodiscard]] inline bool starts_with(const String& s) const;
882
883 [[nodiscard]] inline bool starts_with(char ch) const noexcept;
884 [[nodiscard]] inline bool starts_with(wchar_t ch) const noexcept;
885 [[nodiscard]] inline bool starts_with(char16_t ch) const noexcept;
886 [[nodiscard]] inline bool starts_with(char32_t ch) const noexcept;
887
888 [[nodiscard]] inline bool ends_with(StringView sv) const noexcept;
889 [[nodiscard]] inline bool ends_with(const char32_t* s) const;
890 [[nodiscard]] inline bool ends_with(const std::u32string& s) const;
891 [[nodiscard]] inline bool ends_with(const String& s) const;
892
893 [[nodiscard]] inline bool ends_with(char ch) const noexcept;
894 [[nodiscard]] inline bool ends_with(wchar_t ch) const noexcept;
895 [[nodiscard]] inline bool ends_with(char16_t ch) const noexcept;
896 [[nodiscard]] inline bool ends_with(char32_t ch) const noexcept;
897
898 [[nodiscard]] std::size_t count(char ch, std::size_t pos = 0) const noexcept;
899 [[nodiscard]] std::size_t count(wchar_t ch, std::size_t pos = 0) const noexcept;
900 [[nodiscard]] std::size_t count(char16_t ch, std::size_t pos = 0) const noexcept;
901 [[nodiscard]] std::size_t count(char32_t ch, std::size_t pos = 0) const noexcept;
902
903 inline friend bool operator==(const String& left, StringView right);
904 inline friend bool operator==(const String& left, const char32_t* right);
905 inline friend bool operator==(const String& left, const std::u32string& right);
906 inline friend bool operator==(const String& left, const String& right);
907
908 inline friend bool operator!=(const String& left, StringView right);
909 inline friend bool operator!=(const String& left, const char32_t* right);
910 inline friend bool operator!=(const String& left, const std::u32string& right);
911 inline friend bool operator!=(const String& left, const String& right);
912
913 inline friend bool operator<(const String& left, StringView right);
914 inline friend bool operator<(const String& left, const char32_t* right);
915 inline friend bool operator<(const String& left, const std::u32string& right);
916 inline friend bool operator<(const String& left, const String& right);
917
918 inline friend bool operator<=(const String& left, StringView right);
919 inline friend bool operator<=(const String& left, const char32_t* right);
920 inline friend bool operator<=(const String& left, const std::u32string& right);
921 inline friend bool operator<=(const String& left, const String& right);
922
923 inline friend bool operator>(const String& left, StringView right);
924 inline friend bool operator>(const String& left, const char32_t* right);
925 inline friend bool operator>(const String& left, const std::u32string& right);
926 inline friend bool operator>(const String& left, const String& right);
927
928 inline friend bool operator>=(const String& left, StringView right);
929 inline friend bool operator>=(const String& left, const char32_t* right);
930 inline friend bool operator>=(const String& left, const std::u32string& right);
931 inline friend bool operator>=(const String& left, const String& right);
932
933 inline friend String operator+(const String& left, const String& right);
934 inline friend String operator+(const String& left, String&& right);
935 inline friend String operator+(String&& left, const String& right);
936 inline friend String operator+(String&& left, String&& right);
937
938#if defined(__cpp_lib_char8_t) && (__cpp_lib_char8_t >= 201811L)
939 inline String(const std::u8string& str);
940 inline String(char8_t utfChar);
941 inline String(const char8_t* str);
942 inline String(std::size_t count, char8_t ch);
943 inline String(const std::u8string& str, std::size_t pos);
944 inline String(const std::u8string& str, std::size_t pos, std::size_t count);
945 inline String(const char8_t* str, std::size_t count);
946 inline explicit String(std::initializer_list<char8_t> chars);
947 inline explicit String(std::u8string::const_iterator first, std::u8string::const_iterator last);
948
949 inline explicit operator std::u8string() const;
950
951 [[nodiscard]] inline std::u8string toUtf8() const;
952
953 inline String& assign(std::size_t count, char8_t ch);
954 inline String& assign(const std::u8string& str, std::size_t pos, std::size_t count = npos);
955 inline String& assign(const char8_t* str, std::size_t count);
956 inline String& assign(std::initializer_list<char8_t> chars);
957 inline String& assign(std::u8string::const_iterator first, std::u8string::const_iterator last);
958
959 inline String& insert(std::size_t index, std::size_t count, char8_t ch);
960 inline String& insert(std::size_t index, const std::u8string& str, std::size_t pos, std::size_t count = npos);
961 inline String& insert(std::size_t index, const char8_t* str, std::size_t count);
962 inline iterator insert(const_iterator pos, char8_t ch);
963 inline iterator insert(const_iterator pos, std::size_t count, char8_t ch);
964 inline iterator insert(const_iterator pos, std::initializer_list<char8_t> chars);
965 inline iterator insert(const_iterator pos, std::u8string::const_iterator first, std::u8string::const_iterator last);
966
967 inline String& append(std::size_t count, char8_t ch);
968 inline String& append(const std::u8string& str, std::size_t pos, std::size_t count = npos);
969 inline String& append(const char8_t* str, std::size_t count);
970 inline String& append(std::initializer_list<char8_t> chars);
971 inline String& append(std::u8string::const_iterator first, std::u8string::const_iterator last);
972
973 [[nodiscard]] inline int compare(std::size_t pos1,
974 std::size_t count1,
975 const std::u8string& str,
976 std::size_t pos2,
977 std::size_t count2 = npos) const;
978 [[nodiscard]] inline int compare(std::size_t pos1, std::size_t count1, const char8_t* s, std::size_t count2) const;
979
980 inline String& replace(std::size_t pos, std::size_t count, const std::u8string& str, std::size_t pos2, std::size_t count2 = npos);
981 inline String& replace(const_iterator first,
982 const_iterator last,
983 std::u8string::const_iterator first2,
984 std::u8string::const_iterator last2);
985 inline String& replace(std::size_t pos, std::size_t count, const char8_t* cstr, std::size_t count2);
986 inline String& replace(const_iterator first, const_iterator last, const char8_t* cstr, std::size_t count2);
987 inline String& replace(std::size_t pos, std::size_t count, std::size_t count2, char8_t ch);
988 inline String& replace(const_iterator first, const_iterator last, std::size_t count2, char8_t ch);
989 inline String& replace(const_iterator first, const_iterator last, std::initializer_list<char8_t> chars);
990
991 inline void resize(std::size_t count, char8_t ch);
992
993 [[nodiscard]] inline bool contains(char8_t c) const noexcept;
994
995 [[nodiscard]] inline std::size_t find(const char8_t* s, std::size_t pos, std::size_t count) const;
996 [[nodiscard]] inline std::size_t find(char8_t ch, std::size_t pos = 0) const noexcept;
997
998 [[nodiscard]] inline std::size_t find_first_of(const char8_t* s, std::size_t pos, std::size_t count) const;
999 [[nodiscard]] inline std::size_t find_first_of(char8_t ch, std::size_t pos = 0) const noexcept;
1000
1001 [[nodiscard]] inline std::size_t find_first_not_of(const char8_t* s, std::size_t pos, std::size_t count) const;
1002 [[nodiscard]] inline std::size_t find_first_not_of(char8_t ch, std::size_t pos = 0) const noexcept;
1003
1004 [[nodiscard]] inline std::size_t rfind(const char8_t* s, std::size_t pos, std::size_t count) const;
1005 [[nodiscard]] inline std::size_t rfind(char8_t ch, std::size_t pos = npos) const noexcept;
1006
1007 [[nodiscard]] inline std::size_t find_last_of(const char8_t* s, std::size_t pos, std::size_t count) const;
1008 [[nodiscard]] inline std::size_t find_last_of(char8_t ch, std::size_t pos = npos) const noexcept;
1009
1010 [[nodiscard]] inline std::size_t find_last_not_of(const char8_t* s, std::size_t pos, std::size_t count) const;
1011 [[nodiscard]] inline std::size_t find_last_not_of(char8_t ch, std::size_t pos = npos) const noexcept;
1012
1013 [[nodiscard]] inline bool starts_with(char8_t ch) const noexcept;
1014 [[nodiscard]] inline bool ends_with(char8_t ch) const noexcept;
1015#endif
1016 };
1017
1019
1020 inline bool String::starts_with(StringView sv) const noexcept
1021 {
1022 return viewStartsWith(StringView(m_string), sv);
1023 }
1024
1025 inline bool String::starts_with(const char32_t* s) const
1026 {
1027 return viewStartsWith(StringView(m_string), StringView(s));
1028 }
1029
1030 inline bool String::starts_with(const std::u32string& s) const
1031 {
1032 return viewStartsWith(StringView(m_string), StringView(s));
1033 }
1034
1035 inline bool String::starts_with(const String& s) const
1036 {
1037 return viewStartsWith(StringView(m_string), StringView(s));
1038 }
1039
1040 inline bool String::starts_with(char ch) const noexcept
1041 {
1042 return viewStartsWith(StringView(m_string), static_cast<char32_t>(ch));
1043 }
1044
1045 inline bool String::starts_with(wchar_t ch) const noexcept
1046 {
1047 return viewStartsWith(StringView(m_string), static_cast<char32_t>(ch));
1048 }
1049
1050 inline bool String::starts_with(char16_t ch) const noexcept
1051 {
1052 return viewStartsWith(StringView(m_string), static_cast<char32_t>(ch));
1053 }
1054
1055 inline bool String::starts_with(char32_t ch) const noexcept
1056 {
1057 return viewStartsWith(StringView(m_string), ch);
1058 }
1059
1060 inline bool String::ends_with(StringView sv) const noexcept
1061 {
1062 return viewEndsWith(StringView(m_string), sv);
1063 }
1064
1065 inline bool String::ends_with(const char32_t* s) const
1066 {
1067 return viewEndsWith(StringView(m_string), StringView(s));
1068 }
1069
1070 inline bool String::ends_with(const std::u32string& s) const
1071 {
1072 return viewEndsWith(StringView(m_string), StringView(s));
1073 }
1074
1075 inline bool String::ends_with(const String& s) const
1076 {
1077 return viewEndsWith(StringView(m_string), StringView(s));
1078 }
1079
1080 inline bool String::ends_with(char ch) const noexcept
1081 {
1082 return viewEndsWith(StringView(m_string), static_cast<char32_t>(ch));
1083 }
1084
1085 inline bool String::ends_with(wchar_t ch) const noexcept
1086 {
1087 return viewEndsWith(StringView(m_string), static_cast<char32_t>(ch));
1088 }
1089
1090 inline bool String::ends_with(char16_t ch) const noexcept
1091 {
1092 return viewEndsWith(StringView(m_string), static_cast<char32_t>(ch));
1093 }
1094
1095 inline bool String::ends_with(char32_t ch) const noexcept
1096 {
1097 return viewEndsWith(StringView(m_string), ch);
1098 }
1099
1100 [[nodiscard]] inline bool operator==(const String& left, StringView right)
1101 {
1102 return StringView(left) == right;
1103 }
1104
1105 [[nodiscard]] inline bool operator==(const String& left, const char32_t* right)
1106 {
1107 return StringView(left) == right;
1108 }
1109
1110 [[nodiscard]] inline bool operator==(const String& left, const std::u32string& right)
1111 {
1112 return StringView(left) == right;
1113 }
1114
1115 [[nodiscard]] inline bool operator==(const String& left, const String& right)
1116 {
1117 return left.m_string == right.m_string;
1118 }
1119
1120 [[nodiscard]] inline bool operator!=(const String& left, StringView right)
1121 {
1122 return StringView(left) != right;
1123 }
1124
1125 [[nodiscard]] inline bool operator!=(const String& left, const char32_t* right)
1126 {
1127 return StringView(left) != right;
1128 }
1129
1130 [[nodiscard]] inline bool operator!=(const String& left, const std::u32string& right)
1131 {
1132 return StringView(left) != right;
1133 }
1134
1135 [[nodiscard]] inline bool operator!=(const String& left, const String& right)
1136 {
1137 return left.m_string != right.m_string;
1138 }
1139
1140 [[nodiscard]] inline bool operator<(const String& left, StringView right)
1141 {
1142 return StringView(left) < right;
1143 }
1144
1145 [[nodiscard]] inline bool operator<(const String& left, const char32_t* right)
1146 {
1147 return StringView(left) < right;
1148 }
1149
1150 [[nodiscard]] inline bool operator<(const String& left, const std::u32string& right)
1151 {
1152 return StringView(left) < right;
1153 }
1154
1155 [[nodiscard]] inline bool operator<(const String& left, const String& right)
1156 {
1157 return left.m_string < right.m_string;
1158 }
1159
1160 [[nodiscard]] inline bool operator<=(const String& left, StringView right)
1161 {
1162 return StringView(left) <= right;
1163 }
1164
1165 [[nodiscard]] inline bool operator<=(const String& left, const char32_t* right)
1166 {
1167 return StringView(left) <= right;
1168 }
1169
1170 [[nodiscard]] inline bool operator<=(const String& left, const std::u32string& right)
1171 {
1172 return StringView(left) <= right;
1173 }
1174
1175 [[nodiscard]] inline bool operator<=(const String& left, const String& right)
1176 {
1177 return left.m_string <= right.m_string;
1178 }
1179
1180 [[nodiscard]] inline bool operator>(const String& left, StringView right)
1181 {
1182 return StringView(left) > right;
1183 }
1184
1185 [[nodiscard]] inline bool operator>(const String& left, const char32_t* right)
1186 {
1187 return StringView(left) > right;
1188 }
1189
1190 [[nodiscard]] inline bool operator>(const String& left, const std::u32string& right)
1191 {
1192 return StringView(left) > right;
1193 }
1194
1195 [[nodiscard]] inline bool operator>(const String& left, const String& right)
1196 {
1197 return left.m_string > right.m_string;
1198 }
1199
1200 [[nodiscard]] inline bool operator>=(const String& left, StringView right)
1201 {
1202 return StringView(left) >= right;
1203 }
1204
1205 [[nodiscard]] inline bool operator>=(const String& left, const char32_t* right)
1206 {
1207 return StringView(left) >= right;
1208 }
1209
1210 [[nodiscard]] inline bool operator>=(const String& left, const std::u32string& right)
1211 {
1212 return StringView(left) >= right;
1213 }
1214
1215 [[nodiscard]] inline bool operator>=(const String& left, const String& right)
1216 {
1217 return left.m_string >= right.m_string;
1218 }
1219
1220 [[nodiscard]] inline String operator+(const String& left, const String& right)
1221 {
1222 return {left.m_string + right.m_string};
1223 }
1224 [[nodiscard]] inline String operator+(String&& left, String&& right)
1225 {
1226 return {std::move(left.m_string) + std::move(right.m_string)};
1227 }
1228 [[nodiscard]] inline String operator+(String&& left, const String& right)
1229 {
1230 return {std::move(left.m_string) + right.m_string};
1231 }
1232 [[nodiscard]] inline String operator+(const String& left, String&& right)
1233 {
1234 return {left.m_string + std::move(right.m_string)};
1235 }
1236
1237 // We don't provide operator<< implmentations for basic_ostream<charX_t> streams because
1238 // even clang 15 can't compile them when using libc++.
1239 // We could define them for VS, GCC and for clang with libstdc++, but there is no real use for them.
1240 TGUI_API std::ostream& operator<<(std::ostream& os, const String& str);
1241 TGUI_API std::wostream& operator<<(std::wostream& wos, const String& str);
1242
1243 TGUI_API std::istream& operator>>(std::istream& is, String& str);
1244 TGUI_API std::wistream& operator>>(std::wistream& wis, String& str);
1245
1246 // UTF-8 function are defined in the header so that they can be enabled/disabled based on
1247 // the compiler settings without having to recompile TGUI with a different C++ standard.
1248#if defined(__cpp_lib_char8_t) && (__cpp_lib_char8_t >= 201811L)
1249 inline String::String(const std::u8string& str) :
1250 m_string(utf::convertUtf8toUtf32(str.begin(), str.end()))
1251 {
1252 }
1253
1254 inline String::String(char8_t utfChar) :
1255 m_string(1, static_cast<char32_t>(utfChar))
1256 {
1257 }
1258
1259 inline String::String(const char8_t* str) :
1260 String{utf::convertUtf8toUtf32(str, str + std::char_traits<char8_t>::length(str))}
1261 {
1262 }
1263
1264 inline String::String(std::size_t count, char8_t ch) :
1265 m_string(count, static_cast<char32_t>(ch))
1266 {
1267 }
1268
1269 inline String::String(const std::u8string& str, std::size_t pos) :
1270 String{std::u8string(str, pos)}
1271 {
1272 }
1273
1274 inline String::String(const std::u8string& str, std::size_t pos, std::size_t count) :
1275 String{std::u8string(str, pos, count)}
1276 {
1277 }
1278
1279 inline String::String(const char8_t* str, std::size_t count) :
1280 String{std::u8string{str, count}}
1281 {
1282 }
1283
1284 inline String::String(std::initializer_list<char8_t> chars) :
1285 String(std::u8string(chars.begin(), chars.end()))
1286 {
1287 }
1288
1289 inline String::String(std::u8string::const_iterator first, std::u8string::const_iterator last) :
1290 String{std::u8string(first, last)}
1291 {
1292 }
1293
1294 inline String::operator std::u8string() const
1295 {
1296 return utf::convertUtf32toUtf8(m_string);
1297 }
1298
1299 inline std::u8string String::toUtf8() const
1300 {
1301 return utf::convertUtf32toUtf8(m_string);
1302 }
1303
1304 inline String& String::assign(const std::u8string& str, std::size_t pos, std::size_t count)
1305 {
1306 m_string.assign(String{str, pos, count}.m_string);
1307 return *this;
1308 }
1309
1310 inline String& String::assign(const char8_t* str, std::size_t count)
1311 {
1312 m_string.assign(String{str, count}.m_string);
1313 return *this;
1314 }
1315
1316 inline String& String::assign(std::size_t count, char8_t ch)
1317 {
1318 m_string.assign(count, static_cast<char32_t>(ch));
1319 return *this;
1320 }
1321
1322 inline String& String::assign(std::initializer_list<char8_t> chars)
1323 {
1324 m_string.assign(String{chars}.m_string);
1325 return *this;
1326 }
1327
1328 inline String& String::assign(std::u8string::const_iterator first, std::u8string::const_iterator last)
1329 {
1330 m_string.assign(String{first, last}.m_string);
1331 return *this;
1332 }
1333
1334 inline String& String::insert(std::size_t index, std::size_t count, char8_t ch)
1335 {
1336 m_string.insert(index, count, static_cast<char32_t>(ch));
1337 return *this;
1338 }
1339
1340 inline String& String::insert(std::size_t index, const std::u8string& str, std::size_t pos, std::size_t count)
1341 {
1342 m_string.insert(index, String{str, pos, count}.m_string);
1343 return *this;
1344 }
1345
1346 inline String& String::insert(std::size_t index, const char8_t* str, std::size_t count)
1347 {
1348 m_string.insert(index, String{str, count}.m_string);
1349 return *this;
1350 }
1351
1352 inline String::iterator String::insert(String::const_iterator pos, char8_t ch)
1353 {
1354 return m_string.insert(pos, static_cast<char32_t>(ch));
1355 }
1356
1357 inline String::iterator String::insert(String::const_iterator pos, std::size_t count, char8_t ch)
1358 {
1359 return m_string.insert(pos, count, static_cast<char32_t>(ch));
1360 }
1361
1362 inline String::iterator String::insert(String::const_iterator pos, std::initializer_list<char8_t> chars)
1363 {
1364 const std::u32string tmpStr(utf::convertUtf8toUtf32(chars.begin(), chars.end()));
1365 return m_string.insert(pos, tmpStr.begin(), tmpStr.end());
1366 }
1367
1368 inline String::iterator String::insert(String::const_iterator pos, std::u8string::const_iterator first, std::u8string::const_iterator last)
1369 {
1370 const std::u32string tmpStr(utf::convertUtf8toUtf32(first, last));
1371 return m_string.insert(pos, tmpStr.begin(), tmpStr.end());
1372 }
1373
1374 inline String& String::append(std::size_t count, char8_t ch)
1375 {
1376 m_string.append(count, static_cast<char32_t>(ch));
1377 return *this;
1378 }
1379
1380 inline String& String::append(const std::u8string& str, std::size_t pos, std::size_t count)
1381 {
1382 m_string.append(String{str, pos, count}.m_string);
1383 return *this;
1384 }
1385
1386 inline String& String::append(const char8_t* str, std::size_t count)
1387 {
1388 m_string.append(String{str, count}.m_string);
1389 return *this;
1390 }
1391
1392 inline String& String::append(std::initializer_list<char8_t> chars)
1393 {
1394 m_string.append(String{chars}.m_string);
1395 return *this;
1396 }
1397
1398 inline String& String::append(std::u8string::const_iterator first, std::u8string::const_iterator last)
1399 {
1400 m_string.append(String{first, last}.m_string);
1401 return *this;
1402 }
1403
1404 inline int String::compare(std::size_t pos1, std::size_t count1, const std::u8string& str, std::size_t pos2, std::size_t count2) const
1405 {
1406 return m_string.compare(pos1, count1, String{str, pos2, count2}.m_string);
1407 }
1408
1409 inline int String::compare(std::size_t pos1, std::size_t count1, const char8_t* s, std::size_t count2) const
1410 {
1411 return m_string.compare(pos1, count1, String{s, count2}.m_string);
1412 }
1413
1414 inline String& String::replace(std::size_t pos, std::size_t count, const std::u8string& str, std::size_t pos2, std::size_t count2)
1415 {
1416 m_string.replace(pos, count, String{str, pos2, count2}.m_string);
1417 return *this;
1418 }
1419
1420 inline String& String::replace(const_iterator first,
1421 const_iterator last,
1422 std::u8string::const_iterator first2,
1423 std::u8string::const_iterator last2)
1424 {
1425 m_string.replace(first, last, String{first2, last2}.m_string);
1426 return *this;
1427 }
1428
1429 inline String& String::replace(std::size_t pos, std::size_t count, const char8_t* cstr, std::size_t count2)
1430 {
1431 m_string.replace(pos, count, String{cstr, count2}.m_string);
1432 return *this;
1433 }
1434
1435 inline String& String::replace(const_iterator first, const_iterator last, const char8_t* cstr, std::size_t count2)
1436 {
1437 m_string.replace(first, last, String{cstr, count2}.m_string);
1438 return *this;
1439 }
1440
1441 inline String& String::replace(std::size_t pos, std::size_t count, std::size_t count2, char8_t ch)
1442 {
1443 m_string.replace(pos, count, String(count2, ch).m_string);
1444 return *this;
1445 }
1446
1447 inline String& String::replace(const_iterator first, const_iterator last, std::size_t count2, char8_t ch)
1448 {
1449 m_string.replace(first, last, String(count2, ch).m_string);
1450 return *this;
1451 }
1452
1453 inline String& String::replace(const_iterator first, const_iterator last, std::initializer_list<char8_t> chars)
1454 {
1455 m_string.replace(first, last, String{chars}.m_string);
1456 return *this;
1457 }
1458
1459 inline void String::resize(std::size_t count, char8_t ch)
1460 {
1461 m_string.resize(count, static_cast<char32_t>(ch));
1462 }
1463
1464 inline bool String::contains(char8_t c) const noexcept
1465 {
1466 return contains(static_cast<char32_t>(c));
1467 }
1468
1469 inline std::size_t String::find(const char8_t* s, std::size_t pos, std::size_t count) const
1470 {
1471 return m_string.find(String{s, count}.m_string, pos);
1472 }
1473
1474 inline std::size_t String::find(char8_t ch, std::size_t pos) const noexcept
1475 {
1476 return m_string.find(static_cast<char32_t>(ch), pos);
1477 }
1478
1479 inline std::size_t String::find_first_of(const char8_t* s, std::size_t pos, std::size_t count) const
1480 {
1481 return m_string.find_first_of(String{s, count}.m_string, pos);
1482 }
1483
1484 inline std::size_t String::find_first_of(char8_t ch, std::size_t pos) const noexcept
1485 {
1486 return m_string.find_first_of(static_cast<char32_t>(ch), pos);
1487 }
1488
1489 inline std::size_t String::find_first_not_of(const char8_t* s, std::size_t pos, std::size_t count) const
1490 {
1491 return m_string.find_first_not_of(String{s, count}.m_string, pos);
1492 }
1493
1494 inline std::size_t String::find_first_not_of(char8_t ch, std::size_t pos) const noexcept
1495 {
1496 return m_string.find_first_not_of(static_cast<char32_t>(ch), pos);
1497 }
1498
1499 inline std::size_t String::rfind(const char8_t* s, std::size_t pos, std::size_t count) const
1500 {
1501 return m_string.rfind(String{s, count}.m_string, pos);
1502 }
1503
1504 inline std::size_t String::rfind(char8_t ch, std::size_t pos) const noexcept
1505 {
1506 return m_string.rfind(static_cast<char32_t>(ch), pos);
1507 }
1508
1509 inline std::size_t String::find_last_of(const char8_t* s, std::size_t pos, std::size_t count) const
1510 {
1511 return m_string.find_last_of(String{s, count}.m_string, pos);
1512 }
1513
1514 inline std::size_t String::find_last_of(char8_t ch, std::size_t pos) const noexcept
1515 {
1516 return m_string.find_last_of(static_cast<char32_t>(ch), pos);
1517 }
1518
1519 inline std::size_t String::find_last_not_of(const char8_t* s, std::size_t pos, std::size_t count) const
1520 {
1521 return m_string.find_last_not_of(String{s, count}.m_string, pos);
1522 }
1523
1524 inline std::size_t String::find_last_not_of(char8_t ch, std::size_t pos) const noexcept
1525 {
1526 return m_string.find_last_not_of(static_cast<char32_t>(ch), pos);
1527 }
1528
1529 inline bool String::starts_with(char8_t ch) const noexcept
1530 {
1531 return viewStartsWith(StringView(m_string), static_cast<char32_t>(ch));
1532 }
1533
1534 inline bool String::ends_with(char8_t ch) const noexcept
1535 {
1536 return viewEndsWith(StringView(m_string), static_cast<char32_t>(ch));
1537 }
1538#endif
1539} // namespace tgui
1540
1541#endif // TGUI_STRING_HPP
Wrapper class to store strings.
Definition String.hpp:94
bool endsWithIgnoreCase(const String &substring) const
Checks whether the last part of the string matches the given substring, case-insensitive.
bool attemptToFloat(float &result) const
Converts the string to a float.
float toFloat(float defaultValue=0) const
Converts the string to a float.
bool equalIgnoreCase(const String &other) const
Compares this string to another and checks if they are equal if ASCII letters would have been lowerca...
bool startsWith(const String &substring) const
Checks whether the first part of the string matches the given substring.
static String fromNumber(T value)
Construct the string from a number.
Definition String.hpp:299
static String join(const std::vector< String > &segments, const String &separator)
Joins multiple string segments into a single string.
bool endsWith(const String &substring) const
Checks whether the last part of the string matches the given substring.
bool attemptToUInt(unsigned int &result) const
Converts the string to an unsigned int.
String trim() const
Returns a string with the whitespace at the start and end of this string removed.
bool startsWithIgnoreCase(const String &substring) const
Checks whether the first part of the string matches the given substring, case-insensitive.
unsigned int toUInt(unsigned int defaultValue=0) const
Converts the string to an unsigned int.
static String fromNumberRounded(T value, unsigned int decimals)
Construct the string from a floating point number, keeping only a certain amount of decimals behind t...
Definition String.hpp:326
int toInt(int defaultValue=0) const
Converts the string to an integer.
void remove(const String &substring)
Removes all occurrences of the given substring.
std::vector< String > split(const String &delimiter, bool trim=false) const
Splits the string into multiple substrings given the delimiter that separates them.
String toLower() const
Converts the ASCII characters in the string to lowercase.
bool attemptToInt(int &result) const
Converts the string to an integer.
String & replace(const String &searchFor, const String &replaceWith)
Replaces all occurrences of a substring with a replacement string.
String toUpper() const
Converts the ASCII characters in the string to uppercase.
Namespace that contains all TGUI functions and classes.
Definition AbsoluteOrRelativeValue.hpp:37
bool viewStartsWith(CharStringView viewToLookInto, CharStringView viewToLookFor)
Checks whether the view starts with the given substring.
Definition StringView.hpp:213
TGUI_API bool isWhitespace(char character)
Checks if a character is a whitespace character (e.g. space, tab, carriage return,...
bool viewEndsWith(CharStringView viewToLookInto, CharStringView viewToLookFor)
Checks whether the view ends with the given substring.
Definition StringView.hpp:242
TGUI_API bool isDigit(char32_t character)
Checks whether a character is digit (only 0 to 9 are considered digits, no unicode characters are).
TGUI_API bool isAlpha(char32_t character)
Checks whether a character is an alphabetic character.