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