StormByte-String 1.0.0
C++26 string module of the StormByte suite
 
Loading...
Searching...
No Matches
wstring.hxx
Go to the documentation of this file.
1/*
2 * Copyright (C) 2024-2026 David C. Manuelda (StormBytePP)
3 *
4 * This file is part of StormByte-String.
5 *
6 * StormByte-String original source is dual-licensed:
7 *
8 * 1. GNU Lesser General Public License v3.0 (or later)
9 * You may redistribute and/or modify this file under the terms of the
10 * GNU Lesser General Public License as published by the Free Software
11 * Foundation, either version 3 of the License, or (at your option)
12 * any later version.
13 *
14 * 2. Commercial license
15 * Alternatively, this file may be used under the terms of a commercial
16 * license agreement with the copyright holder
17 * (David C. Manuelda <StormByte@gmail.com>).
18 *
19 * Both licenses apply only to original StormByte-String source in this
20 * repository. They do not cover other StormByte modules or any third-party
21 * material shipped with this repository (including everything under
22 * thirdparty/, and in particular the bundled StormByte Base tree),
23 * which remains under its own license.
24 *
25 * Neither license grants any patent rights. Any patent licenses required
26 * to use this software or third-party components must be obtained separately
27 * from the patent holders.
28 *
29 * StormByte-String is distributed in the hope that it will be useful,
30 * but WITHOUT ANY WARRANTY; without even the implied warranty of
31 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
32 * GNU Lesser General Public License for more details.
33 *
34 * You should have received a copy of the GNU Lesser General Public License
35 * version 3 along with StormByte-String. If not, see
36 * <https://www.gnu.org/licenses/lgpl-3.0.html>.
37 *
38 * SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-StormByte-Commercial
39 */
40
41#pragma once
42
45
46#include <compare>
47#include <cstddef>
48#include <cwctype>
49#include <functional>
50#include <iterator>
51#include <ostream>
52#include <queue>
53#include <string>
54#include <string_view>
55#include <vector>
56
61namespace StormByte {
66 namespace String {
71 class String;
72
97 public:
98 using value_type = wchar_t;
99 using const_iterator = const wchar_t*;
100 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
101
110 WString() noexcept;
111
116 explicit WString(const wchar_t* str) noexcept;
117
122 explicit WString(std::wstring_view str) noexcept;
123
128 explicit WString(WCString text) noexcept;
129
134 explicit WString(const String& other) noexcept;
135
140 WString(const WString& other) noexcept;
141
146 WString(WString&& other) noexcept;
147
151 ~WString() noexcept = default;
152
158 WString& operator=(const WString& other) noexcept;
159
165 WString& operator=(WString&& other) noexcept;
166
178 inline const_iterator begin() const noexcept {
179 return data();
180 }
181
186 inline const_iterator end() const noexcept {
187 const wchar_t* text = data();
188 return text ? text + size() : nullptr;
189 }
190
195 inline const_iterator cbegin() const noexcept {
196 return begin();
197 }
198
203 inline const_iterator cend() const noexcept {
204 return end();
205 }
206
211 inline const_reverse_iterator rbegin() const noexcept {
212 return const_reverse_iterator(end());
213 }
214
219 inline const_reverse_iterator rend() const noexcept {
220 return const_reverse_iterator(begin());
221 }
222
227 inline const_reverse_iterator crbegin() const noexcept {
228 return rbegin();
229 }
230
235 inline const_reverse_iterator crend() const noexcept {
236 return rend();
237 }
238
243 inline const wchar_t* data() const noexcept {
244 return static_cast<const wchar_t*>(m_text);
245 }
246
251 inline Size size() const noexcept {
252 return m_text.Length();
253 }
254
259 inline Size length() const noexcept {
260 return size();
261 }
262
267 inline bool empty() const noexcept {
268 return size() == 0;
269 }
270
277 inline wchar_t operator[](const Size& index) const noexcept {
278 return m_text[index];
279 }
280
285 inline explicit operator bool() const noexcept {
286 return static_cast<bool>(m_text);
287 }
288
301 inline operator std::wstring_view() const noexcept {
302 return static_cast<std::wstring_view>(m_text);
303 }
304
309 STORMBYTE_FORCE_INLINE explicit operator std::wstring() const {
310 return static_cast<std::wstring>(m_text);
311 }
312
318 inline explicit operator const wchar_t*() const noexcept {
319 return static_cast<const wchar_t*>(m_text);
320 }
321
326 explicit operator String() const noexcept;
327
332 inline const WCString& Bytes() const noexcept {
333 return m_text;
334 }
335
343 static constexpr Size npos{~0ull};
344
350 inline bool starts_with(std::wstring_view text) const noexcept {
351 return static_cast<std::wstring_view>(*this).starts_with(text);
352 }
353
359 inline bool starts_with(wchar_t ch) const noexcept {
360 return static_cast<std::wstring_view>(*this).starts_with(ch);
361 }
362
368 inline bool ends_with(std::wstring_view text) const noexcept {
369 return static_cast<std::wstring_view>(*this).ends_with(text);
370 }
371
377 inline bool ends_with(wchar_t ch) const noexcept {
378 return static_cast<std::wstring_view>(*this).ends_with(ch);
379 }
380
386 inline bool contains(std::wstring_view text) const noexcept {
387 return static_cast<std::wstring_view>(*this).contains(text);
388 }
389
395 inline bool contains(wchar_t ch) const noexcept {
396 return static_cast<std::wstring_view>(*this).contains(ch);
397 }
398
405 inline Size find(std::wstring_view text, Size pos = {}) const noexcept {
406 return FindAt(static_cast<std::wstring_view>(*this), text, pos);
407 }
408
415 inline Size find(wchar_t ch, Size pos = {}) const noexcept {
416 return FindAt(static_cast<std::wstring_view>(*this), ch, pos);
417 }
418
426 inline Size find(const wchar_t* text, Size pos, Size count) const noexcept {
427 return find(std::wstring_view(text, static_cast<std::size_t>(count)), pos);
428 }
429
436 inline Size rfind(std::wstring_view text, Size pos = npos) const noexcept {
437 return RFindAt(static_cast<std::wstring_view>(*this), text, pos);
438 }
439
446 inline Size rfind(wchar_t ch, Size pos = npos) const noexcept {
447 return RFindAt(static_cast<std::wstring_view>(*this), ch, pos);
448 }
449
457 inline Size rfind(const wchar_t* text, Size pos, Size count) const noexcept {
458 return rfind(std::wstring_view(text, static_cast<std::size_t>(count)), pos);
459 }
460
467 inline Size find_first_of(std::wstring_view text, Size pos = {}) const noexcept {
468 const std::wstring_view self = *this;
469 if (pos > Size{self.size()})
470 return npos;
471 return FromIndex(self.find_first_of(text, static_cast<std::size_t>(pos)));
472 }
473
480 inline Size find_first_of(wchar_t ch, Size pos = {}) const noexcept {
481 return find(ch, pos);
482 }
483
490 inline Size find_last_of(std::wstring_view text, Size pos = npos) const noexcept {
491 const std::wstring_view self = *this;
492 const std::size_t start = pos == npos ? std::wstring_view::npos : static_cast<std::size_t>(pos);
493 return FromIndex(self.find_last_of(text, start));
494 }
495
502 inline Size find_last_of(wchar_t ch, Size pos = npos) const noexcept {
503 return rfind(ch, pos);
504 }
505
512 inline Size find_first_not_of(std::wstring_view text, Size pos = {}) const noexcept {
513 const std::wstring_view self = *this;
514 if (pos > Size{self.size()})
515 return npos;
516 return FromIndex(self.find_first_not_of(text, static_cast<std::size_t>(pos)));
517 }
518
525 inline Size find_first_not_of(wchar_t ch, Size pos = {}) const noexcept {
526 const std::wstring_view self = *this;
527 if (pos > Size{self.size()})
528 return npos;
529 return FromIndex(self.find_first_not_of(ch, static_cast<std::size_t>(pos)));
530 }
531
538 inline Size find_last_not_of(std::wstring_view text, Size pos = npos) const noexcept {
539 const std::wstring_view self = *this;
540 const std::size_t start = pos == npos ? std::wstring_view::npos : static_cast<std::size_t>(pos);
541 return FromIndex(self.find_last_not_of(text, start));
542 }
543
550 inline Size find_last_not_of(wchar_t ch, Size pos = npos) const noexcept {
551 const std::wstring_view self = *this;
552 const std::size_t start = pos == npos ? std::wstring_view::npos : static_cast<std::size_t>(pos);
553 return FromIndex(self.find_last_not_of(ch, start));
554 }
555
562 inline WString substr(Size pos = {}, Size count = npos) const noexcept {
563 const std::wstring_view text = *this;
564 if (pos > Size{text.size()})
565 return WString();
566 const std::size_t n = count == npos ? std::wstring_view::npos : static_cast<std::size_t>(count);
567 return WString(text.substr(static_cast<std::size_t>(pos), n));
568 }
569
575 inline int compare(std::wstring_view text) const noexcept {
576 return static_cast<std::wstring_view>(*this).compare(text);
577 }
578
584 inline wchar_t front() const noexcept {
585 return (*this)[Size{0}];
586 }
587
593 inline wchar_t back() const noexcept {
594 return (*this)[size() - Size{1}];
595 }
596
609 static WString ToLower(std::wstring_view str) noexcept;
610
616 static WString ToUpper(std::wstring_view str) noexcept;
617
623 static WString SanitizeNewlines(std::wstring_view str) noexcept;
624
630 static WString RemoveWhitespace(std::wstring_view str) noexcept;
631
637 static bool IsInteger(std::wstring_view str) noexcept;
638
645 static STORMBYTE_FORCE_INLINE void Split(std::wstring_view str, std::vector<WString>& out) noexcept {
646 out.clear();
647 std::size_t i = 0;
648 while (i < str.size()) {
649 while (i < str.size() && std::iswspace(static_cast<wint_t>(str[i])) != 0)
650 ++i;
651 if (i >= str.size())
652 break;
653 std::size_t j = i;
654 while (j < str.size() && std::iswspace(static_cast<wint_t>(str[j])) == 0)
655 ++j;
656 out.emplace_back(str.substr(i, j - i));
657 i = j;
658 }
659 }
660
668 static STORMBYTE_FORCE_INLINE void Explode(std::wstring_view str, wchar_t delimiter, std::queue<WString>& out) noexcept {
669 while (!out.empty())
670 out.pop();
671 std::size_t start = 0;
672 for (std::size_t i = 0; i <= str.size(); ++i) {
673 if (i == str.size() || str[i] == delimiter) {
674 out.emplace(str.substr(start, i - start));
675 start = i + 1;
676 }
677 }
678 }
679
684 inline WString ToLower() const noexcept {
685 return ToLower(static_cast<std::wstring_view>(*this));
686 }
687
692 inline WString ToUpper() const noexcept {
693 return ToUpper(static_cast<std::wstring_view>(*this));
694 }
695
700 inline WString SanitizeNewlines() const noexcept {
701 return SanitizeNewlines(static_cast<std::wstring_view>(*this));
702 }
703
708 inline WString RemoveWhitespace() const noexcept {
709 return RemoveWhitespace(static_cast<std::wstring_view>(*this));
710 }
711
716 inline bool IsInteger() const noexcept {
717 return IsInteger(static_cast<std::wstring_view>(*this));
718 }
719
724 STORMBYTE_FORCE_INLINE std::vector<WString> Split() const noexcept {
725 std::vector<WString> out;
726 Split(static_cast<std::wstring_view>(*this), out);
727 return out;
728 }
729
735 STORMBYTE_FORCE_INLINE std::queue<WString> Explode(wchar_t delimiter) const noexcept {
736 std::queue<WString> out;
737 Explode(static_cast<std::wstring_view>(*this), delimiter, out);
738 return out;
739 }
740
753 inline bool operator==(const WString& other) const noexcept {
754 return m_text == other.m_text;
755 }
756
762 inline bool operator!=(const WString& other) const noexcept {
763 return !(*this == other);
764 }
765
771 inline bool operator==(const wchar_t* str) const noexcept {
772 return m_text == str;
773 }
774
780 inline bool operator!=(const wchar_t* str) const noexcept {
781 return !(*this == str);
782 }
783
789 inline std::strong_ordering operator<=>(const WString& other) const noexcept {
790 return m_text <=> other.m_text;
791 }
792
798 inline std::strong_ordering operator<=>(const wchar_t* str) const noexcept {
799 return m_text <=> str;
800 }
801
808 void swap(WString& other) noexcept;
809
810 private:
811 static Size FromIndex(std::size_t index) noexcept {
812 return index == std::wstring_view::npos ? npos : Size{index};
813 }
814
815 template<typename Needle>
816 static Size FindAt(std::wstring_view self, Needle needle, Size pos) noexcept {
817 if (pos > Size{self.size()})
818 return npos;
819 return FromIndex(self.find(needle, static_cast<std::size_t>(pos)));
820 }
821
822 template<typename Needle>
823 static Size RFindAt(std::wstring_view self, Needle needle, Size pos) noexcept {
824 const std::size_t start = pos == npos ? std::wstring_view::npos : static_cast<std::size_t>(pos);
825 return FromIndex(self.rfind(needle, start));
826 }
827
828 WCString m_text;
829 };
830
837 inline std::wostream& operator<<(std::wostream& stream, const WString& text) {
838 return stream << text.Bytes();
839 }
840
847 inline bool operator==(const wchar_t* str, const WString& text) noexcept {
848 return text == str;
849 }
850
857 inline bool operator!=(const wchar_t* str, const WString& text) noexcept {
858 return text != str;
859 }
860
866 inline void swap(WString& left, WString& right) noexcept {
867 left.swap(right);
868 }
869 }
870}
871
875template<>
876struct std::hash<StormByte::String::WString> {
882 std::size_t operator()(const StormByte::String::WString& text) const noexcept {
883 return std::hash<std::wstring_view>{}(static_cast<std::wstring_view>(text));
884 }
885};
Wide counterpart of String.
Definition wstring.hxx:96
STORMBYTE_FORCE_INLINE std::queue< WString > Explode(wchar_t delimiter) const noexcept
Tokens on delimiter.
Definition wstring.hxx:735
Size find(std::wstring_view text, Size pos={}) const noexcept
First occurrence of text at or after pos.
Definition wstring.hxx:405
const_reverse_iterator rbegin() const noexcept
Reverse begin.
Definition wstring.hxx:211
const_iterator cend() const noexcept
One past the last character, or null.
Definition wstring.hxx:203
int compare(std::wstring_view text) const noexcept
Same order as std::wstring_view::compare.
Definition wstring.hxx:575
bool contains(std::wstring_view text) const noexcept
Whether text occurs.
Definition wstring.hxx:386
Size find_last_not_of(std::wstring_view text, Size pos=npos) const noexcept
Last unit that is not in text, at or before pos.
Definition wstring.hxx:538
const wchar_t * data() const noexcept
Contiguous pointer; null when the buffer is null.
Definition wstring.hxx:243
WString ToUpper() const noexcept
ASCII-letter upper case of this text.
Definition wstring.hxx:692
Size find_first_not_of(std::wstring_view text, Size pos={}) const noexcept
First unit that is not in text, at or after pos.
Definition wstring.hxx:512
std::strong_ordering operator<=>(const WString &other) const noexcept
Content order.
Definition wstring.hxx:789
WString ToLower() const noexcept
ASCII-letter lower case of this text.
Definition wstring.hxx:684
static bool IsInteger(std::wstring_view str) noexcept
Optional sign plus ASCII digits.
bool operator!=(const WString &other) const noexcept
Content inequality.
Definition wstring.hxx:762
bool operator==(const wchar_t *str) const noexcept
Content equality with a wide C string.
Definition wstring.hxx:771
bool operator!=(const wchar_t *str) const noexcept
Content inequality with a wide C string.
Definition wstring.hxx:780
const_reverse_iterator rend() const noexcept
Reverse end.
Definition wstring.hxx:219
bool contains(wchar_t ch) const noexcept
Whether ch occurs.
Definition wstring.hxx:395
WString substr(Size pos={}, Size count=npos) const noexcept
Copy of a slice.
Definition wstring.hxx:562
std::strong_ordering operator<=>(const wchar_t *str) const noexcept
Content order against a wide C string.
Definition wstring.hxx:798
std::reverse_iterator< const_iterator > const_reverse_iterator
Reverse observer.
Definition wstring.hxx:100
WString SanitizeNewlines() const noexcept
CR LF to LF on this text.
Definition wstring.hxx:700
bool empty() const noexcept
Whether size is zero.
Definition wstring.hxx:267
Size find(const wchar_t *text, Size pos, Size count) const noexcept
First occurrence of count units of text.
Definition wstring.hxx:426
bool operator==(const WString &other) const noexcept
Content equality.
Definition wstring.hxx:753
static WString ToLower(std::wstring_view str) noexcept
ASCII-letter lower case; other code points copied.
void swap(WString &other) noexcept
Swaps buffers with other.
static STORMBYTE_FORCE_INLINE void Explode(std::wstring_view str, wchar_t delimiter, std::queue< WString > &out) noexcept
Tokens on delimiter.
Definition wstring.hxx:668
STORMBYTE_FORCE_INLINE std::vector< WString > Split() const noexcept
Whitespace-separated tokens.
Definition wstring.hxx:724
const wchar_t * const_iterator
Contiguous observer.
Definition wstring.hxx:99
wchar_t back() const noexcept
Last code unit.
Definition wstring.hxx:593
wchar_t operator[](const Size &index) const noexcept
Code unit at index.
Definition wstring.hxx:277
const_reverse_iterator crbegin() const noexcept
Reverse begin.
Definition wstring.hxx:227
Size find_first_of(std::wstring_view text, Size pos={}) const noexcept
First unit that is in text, at or after pos.
Definition wstring.hxx:467
static WString SanitizeNewlines(std::wstring_view str) noexcept
Turns CR LF into LF.
Size find(wchar_t ch, Size pos={}) const noexcept
First occurrence of ch at or after pos.
Definition wstring.hxx:415
Size find_last_not_of(wchar_t ch, Size pos=npos) const noexcept
Last unit other than ch, at or before pos.
Definition wstring.hxx:550
Size find_last_of(std::wstring_view text, Size pos=npos) const noexcept
Last unit that is in text, at or before pos.
Definition wstring.hxx:490
bool starts_with(std::wstring_view text) const noexcept
Whether the text begins with text.
Definition wstring.hxx:350
static WString RemoveWhitespace(std::wstring_view str) noexcept
Drops iswspace code units.
const WCString & Bytes() const noexcept
Owned code units.
Definition wstring.hxx:332
wchar_t front() const noexcept
First code unit.
Definition wstring.hxx:584
WString RemoveWhitespace() const noexcept
Drops iswspace code units from this text.
Definition wstring.hxx:708
const_reverse_iterator crend() const noexcept
Reverse end.
Definition wstring.hxx:235
Size rfind(const wchar_t *text, Size pos, Size count) const noexcept
Last occurrence of count units of text.
Definition wstring.hxx:457
static WString ToUpper(std::wstring_view str) noexcept
ASCII-letter upper case; other code points copied.
const_iterator cbegin() const noexcept
First character, or null.
Definition wstring.hxx:195
Size rfind(std::wstring_view text, Size pos=npos) const noexcept
Last occurrence of text at or before pos.
Definition wstring.hxx:436
Size find_first_not_of(wchar_t ch, Size pos={}) const noexcept
First unit other than ch, at or after pos.
Definition wstring.hxx:525
bool starts_with(wchar_t ch) const noexcept
Whether the text begins with ch.
Definition wstring.hxx:359
Size size() const noexcept
Code-unit count; 0 when null or empty.
Definition wstring.hxx:251
static STORMBYTE_FORCE_INLINE void Split(std::wstring_view str, std::vector< WString > &out) noexcept
Whitespace-separated tokens.
Definition wstring.hxx:645
bool IsInteger() const noexcept
Whether this text is an integer token.
Definition wstring.hxx:716
Size rfind(wchar_t ch, Size pos=npos) const noexcept
Last occurrence of ch at or before pos.
Definition wstring.hxx:446
bool ends_with(wchar_t ch) const noexcept
Whether the text ends with ch.
Definition wstring.hxx:377
Size find_first_of(wchar_t ch, Size pos={}) const noexcept
First ch at or after pos.
Definition wstring.hxx:480
wchar_t value_type
Code unit type.
Definition wstring.hxx:98
Size length() const noexcept
Same as size.
Definition wstring.hxx:259
WString() noexcept
Null text.
const_iterator end() const noexcept
One past the last character, or null.
Definition wstring.hxx:186
Size find_last_of(wchar_t ch, Size pos=npos) const noexcept
Last ch at or before pos.
Definition wstring.hxx:502
bool ends_with(std::wstring_view text) const noexcept
Whether the text ends with text.
Definition wstring.hxx:368
void swap(WCString &other) noexcept
void swap(String &left, String &right) noexcept
Swaps two texts.
Definition string.hxx:867
std::ostream & operator<<(std::ostream &stream, const String &text)
Writes text to stream.
Definition string.hxx:838
bool operator==(const char *str, const String &text) noexcept
Content equality.
Definition string.hxx:848
bool operator!=(const char *str, const String &text) noexcept
Content inequality.
Definition string.hxx:858
Root namespace of the StormByte suite.
String module: owned UTF-8 and wide text on top of StormByte::CString / StormByte::WCString.
STL namespace.
#define STORMBYTE_FORCE_INLINE
std::size_t operator()(const StormByte::String::WString &text) const noexcept
Hashes text.
Definition wstring.hxx:882
#define STORMBYTE_STRING_PUBLIC
Definition visibility.h:53