TGUI 1.9.0
Loading...
Searching...
No Matches
StringView.hpp
1
2//
3// TGUI - Texus' Graphical User Interface
4// Copyright (C) 2012-2025 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_VIEW_HPP
26#define TGUI_STRING_VIEW_HPP
27
28#if !TGUI_EXPERIMENTAL_USE_STD_MODULE
29 #include <string>
30 #include <cctype> // tolower
31 #include <algorithm> // equal, min
32
33 #if TGUI_COMPILED_WITH_CPP_VER >= 17
34 #include <string_view>
35 #endif
36#endif
37
39
40#if TGUI_COMPILED_WITH_CPP_VER >= 17
41namespace tgui
42{
43 inline namespace literals
44 {
45 inline namespace string_view_literals
46 {
47 // Allow using operator ""sv
48 // Note that this only affects code placed inside the tgui namespace.
49 using namespace std::literals::string_view_literals;
50 }
51 }
52}
53#endif
54
55TGUI_MODULE_EXPORT namespace tgui
56{
57#if TGUI_COMPILED_WITH_CPP_VER >= 17
58 using StringView = std::u32string_view;
59 using CharStringView = std::string_view;
60#else
61 template <typename Type>
62 struct TypeIdentity
63 {
64 using type = Type;
65 };
66
67 template<typename Type>
68 using TypeIdentity_t = typename TypeIdentity<Type>::type;
69
70 template <typename CharType>
71 class StringViewImpl
72 {
73 public:
74 using const_iterator = const CharType*;
75
76 constexpr StringViewImpl() = default;
77 constexpr StringViewImpl(const StringViewImpl& other) = default;
78
79 constexpr StringViewImpl(const CharType* str, std::size_t strLength) :
80 m_string(str),
81 m_length(strLength)
82 {
83 }
84
85 constexpr StringViewImpl(const CharType* str) :
86 m_string(str),
87 m_length(std::char_traits<CharType>::length(str))
88 {
89 }
90
91 constexpr StringViewImpl(const std::basic_string<CharType>& str) :
92 m_string(str.data()),
93 m_length(str.length())
94 {
95 }
96
97 TGUI_NODISCARD constexpr const_iterator begin() const noexcept
98 {
99 return m_string;
100 }
101 TGUI_NODISCARD constexpr const_iterator cbegin() const noexcept
102 {
103 return m_string;
104 }
105
106 TGUI_NODISCARD constexpr const_iterator end() const noexcept
107 {
108 return m_string + static_cast<std::ptrdiff_t>(m_length);
109 }
110 TGUI_NODISCARD constexpr const_iterator cend() const noexcept
111 {
112 return m_string + static_cast<std::ptrdiff_t>(m_length);
113 }
114
115 TGUI_NODISCARD constexpr const CharType& operator[](std::size_t index) const
116 {
117 return m_string[index];
118 }
119
120 TGUI_NODISCARD constexpr const CharType& front() const
121 {
122 return m_string[0];
123 }
124
125 TGUI_NODISCARD constexpr const CharType& back() const
126 {
127 return m_string[m_length-1];
128 }
129
130 TGUI_NODISCARD constexpr const CharType* data() const noexcept
131 {
132 return m_string;
133 }
134
135 TGUI_NODISCARD constexpr std::size_t size() const noexcept
136 {
137 return m_length;
138 }
139 TGUI_NODISCARD constexpr std::size_t length() const noexcept
140 {
141 return m_length;
142 }
143
144 TGUI_NODISCARD constexpr bool empty() const noexcept
145 {
146 return (m_length == 0);
147 }
148
149 TGUI_NODISCARD constexpr StringViewImpl substr(std::size_t pos = 0, std::size_t count = std::u32string::npos) const
150 {
151 if (count != std::u32string::npos)
152 return StringViewImpl(&m_string[pos], count);
153 else
154 return StringViewImpl(&m_string[pos], m_length - pos);
155 }
156
157 TGUI_NODISCARD constexpr int compare(StringViewImpl strView) const noexcept
158 {
159 const std::size_t rlen = std::min(length(), strView.length());
160 const int ret = std::char_traits<CharType>::compare(data(), strView.data(), rlen);
161 if (ret != 0)
162 return ret;
163
164 if (length() < strView.length())
165 return -1;
166 else if (length() > strView.length())
167 return 1;
168 else
169 return 0;
170 }
171
172 TGUI_NODISCARD constexpr std::size_t find(StringViewImpl strView, std::size_t pos = 0) const noexcept
173 {
174 if (empty() || (strView.length() > m_length))
175 return std::u32string::npos;
176
177 if (strView.empty())
178 return pos;
179
180 for (std::size_t i = pos; i <= m_length - strView.length(); ++i)
181 {
182 if (m_string[i] != strView[0])
183 continue;
184
185 bool found = true;
186 for (std::size_t j = 1; j < strView.length(); ++j)
187 {
188 if (m_string[i+j] != strView[j])
189 {
190 found = false;
191 break;
192 }
193 }
194
195 if (found)
196 return i;
197 }
198
199 return std::u32string::npos;
200 }
201
202 TGUI_NODISCARD constexpr std::size_t find(CharType ch, std::size_t pos = 0) const noexcept
203 {
204 return find(StringViewImpl(&ch, 1), pos);
205 }
206 TGUI_NODISCARD constexpr std::size_t find(const CharType* str, std::size_t pos, std::size_t count) const
207 {
208 return find(StringViewImpl(str, count), pos);
209 }
210 TGUI_NODISCARD constexpr std::size_t find(const CharType* str, std::size_t pos = 0) const
211 {
212 return find(StringViewImpl(str), pos);
213 }
214
215 private:
216 const CharType* m_string = nullptr;
217 std::size_t m_length = 0;
218 };
219
220 template <typename CharType>
221 TGUI_NODISCARD constexpr bool operator==(StringViewImpl<CharType> lhs, TypeIdentity_t<StringViewImpl<CharType>> rhs) noexcept
222 {
223 return lhs.compare(rhs) == 0;
224 }
225
226 template <typename CharType>
227 TGUI_NODISCARD constexpr bool operator!=(StringViewImpl<CharType> lhs, TypeIdentity_t<StringViewImpl<CharType>> rhs) noexcept
228 {
229 return lhs.compare(rhs) != 0;
230 }
231
232 template <typename CharType>
233 TGUI_NODISCARD constexpr bool operator<(StringViewImpl<CharType> lhs, TypeIdentity_t<StringViewImpl<CharType>> rhs) noexcept
234 {
235 return lhs.compare(rhs) < 0;
236 }
237
238 template <typename CharType>
239 TGUI_NODISCARD constexpr bool operator<=(StringViewImpl<CharType> lhs, TypeIdentity_t<StringViewImpl<CharType>> rhs) noexcept
240 {
241 return lhs.compare(rhs) <= 0;
242 }
243
244 template <typename CharType>
245 TGUI_NODISCARD constexpr bool operator>(StringViewImpl<CharType> lhs, TypeIdentity_t<StringViewImpl<CharType>> rhs) noexcept
246 {
247 return lhs.compare(rhs) > 0;
248 }
249
250 template <typename CharType>
251 TGUI_NODISCARD constexpr bool operator>=(StringViewImpl<CharType> lhs, TypeIdentity_t<StringViewImpl<CharType>> rhs) noexcept
252 {
253 return lhs.compare(rhs) >= 0;
254 }
255
256 using StringView = StringViewImpl<char32_t>;
257 using CharStringView = StringViewImpl<char>;
258
259 // Allow using operator ""sv
260 // Note that this only affects code placed inside the tgui namespace.
261#if defined(__clang__)
262# pragma clang diagnostic push
263# pragma clang diagnostic ignored "-Wuser-defined-literals"
264#elif defined(__GNUC__)
265# pragma GCC diagnostic push
266# pragma GCC diagnostic ignored "-Wliteral-suffix"
267#elif defined (_MSC_VER)
268# pragma warning(push)
269# pragma warning(disable: 4455) // literal suffix identifiers that do not start with an underscore are reserved
270#endif
271 inline namespace literals
272 {
273 inline namespace string_view_literals
274 {
275 inline constexpr StringViewImpl<char> operator""sv(const char* str, size_t len) noexcept
276 {
277 return StringViewImpl<char>{str, len};
278 }
279
280 inline constexpr StringViewImpl<wchar_t> operator""sv(const wchar_t* str, size_t len) noexcept
281 {
282 return StringViewImpl<wchar_t>{str, len};
283 }
284
285 inline constexpr StringViewImpl<char16_t> operator""sv(const char16_t* str, size_t len) noexcept
286 {
287 return StringViewImpl<char16_t>{str, len};
288 }
289
290 inline constexpr StringViewImpl<char32_t> operator""sv(const char32_t* str, size_t len) noexcept
291 {
292 return StringViewImpl<char32_t>{str, len};
293 }
294 }
295 }
296#if defined(__clang__)
297# pragma clang diagnostic pop
298#elif defined(__GNUC__)
299# pragma GCC diagnostic pop
300#elif defined (_MSC_VER)
301# pragma warning(pop)
302#endif
303
304#endif // TGUI_COMPILED_WITH_CPP_VER
305
314 TGUI_NODISCARD inline bool viewEqualIgnoreCase(CharStringView view1, CharStringView view2)
315 {
316 return std::equal(view1.begin(), view1.end(), view2.begin(), view2.end(),
317 [](char char1, char char2)
318 {
319 if (char1 == char2)
320 return true;
321 else
322 return std::tolower(static_cast<unsigned char>(char1)) == std::tolower(static_cast<unsigned char>(char2));
323 }
324 );
325 }
326
335 TGUI_NODISCARD inline bool viewEqualIgnoreCase(StringView view1, StringView view2)
336 {
337 return std::equal(view1.begin(), view1.end(), view2.begin(), view2.end(),
338 [](char32_t char1, char32_t char2)
339 {
340 if (char1 == char2)
341 return true;
342 else if ((char1 < 128) && (char2 < 128))
343 return std::tolower(static_cast<unsigned char>(char1)) == std::tolower(static_cast<unsigned char>(char2));
344 else
345 return false;
346 }
347 );
348 }
349
350#if TGUI_COMPILED_WITH_CPP_VER >= 17 && defined(__cpp_lib_starts_ends_with) && (__cpp_lib_starts_ends_with >= 201711L)
359 TGUI_NODISCARD inline bool viewStartsWith(CharStringView viewToLookInto, CharStringView viewToLookFor)
360 {
361 return viewToLookInto.starts_with(viewToLookFor);
362 }
363
372 TGUI_NODISCARD inline bool viewStartsWith(CharStringView viewToLookInto, char charToLookFor)
373 {
374 return viewToLookInto.starts_with(charToLookFor);
375 }
376
385 TGUI_NODISCARD inline bool viewEndsWith(CharStringView viewToLookInto, CharStringView viewToLookFor)
386 {
387 return viewToLookInto.ends_with(viewToLookFor);
388 }
389
398 TGUI_NODISCARD inline bool viewEndsWith(CharStringView viewToLookInto, char charToLookFor)
399 {
400 return viewToLookInto.ends_with(charToLookFor);
401 }
402
411 TGUI_NODISCARD inline bool viewStartsWith(StringView viewToLookInto, StringView viewToLookFor)
412 {
413 return viewToLookInto.starts_with(viewToLookFor);
414 }
415
424 TGUI_NODISCARD inline bool viewStartsWith(StringView viewToLookInto, char32_t charToLookFor)
425 {
426 return viewToLookInto.starts_with(charToLookFor);
427 }
428
437 TGUI_NODISCARD inline bool viewEndsWith(StringView viewToLookInto, StringView viewToLookFor)
438 {
439 return viewToLookInto.ends_with(viewToLookFor);
440 }
441
450 TGUI_NODISCARD inline bool viewEndsWith(StringView viewToLookInto, char32_t charToLookFor)
451 {
452 return viewToLookInto.ends_with(charToLookFor);
453 }
454#else
463 TGUI_NODISCARD inline bool viewStartsWith(CharStringView viewToLookInto, CharStringView viewToLookFor)
464 {
465 if (viewToLookFor.length() > viewToLookInto.length())
466 return false;
467
468 return viewToLookInto.substr(0, viewToLookFor.length()) == viewToLookFor;
469 }
470
479 TGUI_NODISCARD inline bool viewStartsWith(CharStringView viewToLookInto, char charToLookFor)
480 {
481 return !viewToLookInto.empty() && (viewToLookInto.front() == charToLookFor);
482 }
483
492 TGUI_NODISCARD inline bool viewEndsWith(CharStringView viewToLookInto, CharStringView viewToLookFor)
493 {
494 if (viewToLookFor.length() > viewToLookInto.length())
495 return false;
496
497 return CharStringView(viewToLookInto.data() + (viewToLookInto.length() - viewToLookFor.length()), viewToLookFor.length()).compare(viewToLookFor) == 0;
498 }
499
508 TGUI_NODISCARD inline bool viewEndsWith(CharStringView viewToLookInto, char charToLookFor)
509 {
510 return !viewToLookInto.empty() && (viewToLookInto.back() == charToLookFor);
511 }
512
521 TGUI_NODISCARD inline bool viewStartsWith(StringView viewToLookInto, StringView viewToLookFor)
522 {
523 if (viewToLookFor.length() > viewToLookInto.length())
524 return false;
525
526 return viewToLookInto.substr(0, viewToLookFor.length()) == viewToLookFor;
527 }
528
537 TGUI_NODISCARD inline bool viewStartsWith(StringView viewToLookInto, char32_t charToLookFor)
538 {
539 return !viewToLookInto.empty() && (viewToLookInto.front() == charToLookFor);
540 }
541
550 TGUI_NODISCARD inline bool viewEndsWith(StringView viewToLookInto, StringView viewToLookFor)
551 {
552 if (viewToLookFor.length() > viewToLookInto.length())
553 return false;
554
555 return StringView(viewToLookInto.data() + (viewToLookInto.length() - viewToLookFor.length()), viewToLookFor.length()).compare(viewToLookFor) == 0;
556 }
557
566 TGUI_NODISCARD inline bool viewEndsWith(StringView viewToLookInto, char32_t charToLookFor)
567 {
568 return !viewToLookInto.empty() && (viewToLookInto.back() == charToLookFor);
569 }
570#endif
571}
572
574
575#endif // TGUI_STRING_VIEW_HPP
Namespace that contains all TGUI functions and classes.
Definition AbsoluteOrRelativeValue.hpp:38
bool viewStartsWith(CharStringView viewToLookInto, CharStringView viewToLookFor)
Checks whether the view starts with the given substring.
Definition StringView.hpp:463
bool viewEqualIgnoreCase(CharStringView view1, CharStringView view2)
Returns whether two view are equal if letters would have been lowercase.
Definition StringView.hpp:314
bool viewEndsWith(CharStringView viewToLookInto, CharStringView viewToLookFor)
Checks whether the view ends with the given substring.
Definition StringView.hpp:492