1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef API_BASE_CONTAINERS_STRING_VIEW_H
17 #define API_BASE_CONTAINERS_STRING_VIEW_H
18
19 #include <cstddef>
20 #include <cstdint>
21
22 #include <base/containers/iterator.h>
23 #include <base/containers/type_traits.h>
24 #include <base/namespace.h>
25 #include <base/util/hash.h>
26
27 BASE_BEGIN_NAMESPACE()
28 template<class CharT>
29 class basic_string_view;
30
31 using string_view = BASE_NS::basic_string_view<char>;
32 using wstring_view = BASE_NS::basic_string_view<wchar_t>;
33
34 template<class CharT>
35 class basic_string_view {
36 public:
37 using value_type = CharT;
38 using pointer = value_type*;
39 using const_pointer = const value_type*;
40 using reference = value_type&;
41 using const_reference = const value_type&;
42 using const_iterator = BASE_NS::const_iterator<basic_string_view>;
43 using iterator = BASE_NS::iterator<basic_string_view>;
44 using const_reverse_iterator = BASE_NS::reverse_iterator<const_iterator>;
45 using reverse_iterator = BASE_NS::reverse_iterator<iterator>;
46 using size_type = size_t;
47 using difference_type = ptrdiff_t;
48
49 static const size_type npos = size_type(-1);
50
51 constexpr basic_string_view() noexcept = default;
52 constexpr basic_string_view(const basic_string_view& other) noexcept = default;
53 constexpr basic_string_view(const CharT* const s, size_type count);
54 constexpr basic_string_view(const CharT* const s);
55
56 ~basic_string_view() = default;
57
58 constexpr basic_string_view& operator=(const basic_string_view& view) noexcept = default;
59
60 // Iterators
61 /** returns an iterator to the beginning */
62 constexpr const_iterator begin() const noexcept;
63 constexpr const_iterator cbegin() const noexcept;
64
65 /** returns an iterator to the end */
66 constexpr const_iterator end() const noexcept;
67 constexpr const_iterator cend() const noexcept;
68
69 /** returns a reverse iterator to the beginning */
70 constexpr const_reverse_iterator rbegin() const noexcept;
71 constexpr const_reverse_iterator crbegin() const noexcept;
72
73 /** returns a reverse iterator to the end */
74 constexpr const_reverse_iterator rend() const noexcept;
75 constexpr const_reverse_iterator crend() const noexcept;
76
77 // Element access
78 /** accesses the specified character */
79 constexpr const_reference operator[](size_type pos) const;
80
81 /** accesses the specified character with bounds checking */
82 constexpr const_reference at(size_type pos) const;
83
84 /** accesses the first character */
85 constexpr const_reference front() const;
86
87 /** accesses the last character */
88 constexpr const_reference back() const;
89
90 /** returns a pointer to the first character of a view */
91 constexpr const_pointer data() const noexcept;
92
93 // Capacity
94 /** returns the number of characters */
95 constexpr size_type size() const noexcept;
96 constexpr size_type length() const noexcept;
97
98 /** returns the maximum number of characters */
99 constexpr size_type max_size() const noexcept;
100
101 /** checks whether the view is empty */
102 constexpr bool empty() const noexcept;
103
104 // Modifiers
105 /** shrinks the view by moving its start forward */
106 constexpr void remove_prefix(size_type n);
107
108 /** shrinks the view by moving its end backward */
109 constexpr void remove_suffix(size_type n);
110
111 /** swaps the contents */
112 constexpr void swap(basic_string_view& v) noexcept;
113
114 // Operations
115 /** copies characters */
116 constexpr size_type copy(CharT* dest, size_type count, size_type pos = 0) const;
117
118 /** returns a substring */
119 constexpr basic_string_view substr(size_type pos = 0, size_type count = npos) const;
120 /** compares two views */
121 constexpr int compare(basic_string_view v) const noexcept;
122 constexpr int compare(size_type pos1, size_type count1, basic_string_view v) const;
123 constexpr int compare(
124 size_type pos1, size_type count1, basic_string_view v, size_type pos2, size_type count2) const;
125 constexpr int compare(const CharT* const s) const;
126 constexpr int compare(size_type pos1, size_type count1, const CharT* const s) const;
127 constexpr int compare(size_type pos1, size_type count1, const CharT* const s, size_type count2) const;
128 /** find substring in the view */
129 constexpr size_type find(const CharT str, size_type pos = 0) const noexcept;
130 constexpr size_type find(const basic_string_view& str, size_type pos = 0) const noexcept;
131 /* find the last occurrence of a substring in the view */
132 constexpr size_type rfind(const CharT str, size_type pos = npos) const noexcept;
133 constexpr size_type rfind(const basic_string_view& str, size_type pos = npos) const noexcept;
134 /* find first occurance of characters in the view */
135 constexpr size_type find_first_of(const basic_string_view& str, size_type pos = 0) const noexcept;
136 constexpr size_type find_first_of(CharT ch, size_type pos = 0) const noexcept;
137 /* find last occurrence of characters in the view */
138 constexpr size_type find_last_of(const basic_string_view& str, size_type pos = npos) const noexcept;
139 constexpr size_type find_last_of(CharT ch, size_type pos = npos) const noexcept;
140
141 /* checks if the string view starts with the given prefix */
142 constexpr bool starts_with(basic_string_view sv) const noexcept;
143 constexpr bool starts_with(CharT ch) const noexcept;
144 constexpr bool starts_with(const CharT* s) const;
145
146 /* checks if the string view ends with the given suffix */
147 constexpr bool ends_with(basic_string_view sv) const noexcept;
148 constexpr bool ends_with(CharT ch) const noexcept;
149 constexpr bool ends_with(const CharT* s) const;
150
151 /* find first absence of characters
152 find_first_not_of
153
154 find last absence of characters
155 find_last_not_of
156 */
157 private:
158 const_pointer begin_ { nullptr };
159 size_type size_ { 0 };
160 };
161
162 template<class CharT>
constexpr_strlen(const CharT * const str)163 constexpr size_t constexpr_strlen(const CharT* const str) noexcept
164 {
165 if (!str) {
166 return 0u;
167 }
168 auto tmp = str;
169 while (*tmp) {
170 ++tmp;
171 }
172 return static_cast<size_t>(tmp - str);
173 }
174
175 template<class CharT>
basic_string_view(const CharT * const s,size_type count)176 constexpr basic_string_view<CharT>::basic_string_view(const CharT* const s, size_type count) : begin_(s), size_(count)
177 {}
178
179 template<class CharT>
basic_string_view(const CharT * const s)180 constexpr basic_string_view<CharT>::basic_string_view(const CharT* const s) : begin_(s), size_(constexpr_strlen(s))
181 {}
182
183 template<class CharT>
begin()184 constexpr typename basic_string_view<CharT>::const_iterator basic_string_view<CharT>::begin() const noexcept
185 {
186 return const_iterator(begin_);
187 }
188
189 template<class CharT>
cbegin()190 constexpr typename basic_string_view<CharT>::const_iterator basic_string_view<CharT>::cbegin() const noexcept
191 {
192 return const_iterator(begin_);
193 }
194
195 template<class CharT>
end()196 constexpr typename basic_string_view<CharT>::const_iterator basic_string_view<CharT>::end() const noexcept
197 {
198 return const_iterator(begin_ + size_);
199 }
200
201 template<class CharT>
cend()202 constexpr typename basic_string_view<CharT>::const_iterator basic_string_view<CharT>::cend() const noexcept
203 {
204 return const_iterator(begin_ + size_);
205 }
206
207 template<class CharT>
rbegin()208 constexpr typename basic_string_view<CharT>::const_reverse_iterator basic_string_view<CharT>::rbegin() const noexcept
209 {
210 return const_reverse_iterator(const_iterator(begin_ + size_));
211 }
212
213 template<class CharT>
crbegin()214 constexpr typename basic_string_view<CharT>::const_reverse_iterator basic_string_view<CharT>::crbegin() const noexcept
215 {
216 return const_reverse_iterator(const_iterator(begin_ + size_));
217 }
218
219 template<class CharT>
rend()220 constexpr typename basic_string_view<CharT>::const_reverse_iterator basic_string_view<CharT>::rend() const noexcept
221 {
222 return const_reverse_iterator(const_iterator(begin_));
223 }
224
225 template<class CharT>
crend()226 constexpr typename basic_string_view<CharT>::const_reverse_iterator basic_string_view<CharT>::crend() const noexcept
227 {
228 return const_reverse_iterator(const_iterator(begin_));
229 }
230
231 template<class CharT>
data()232 constexpr typename basic_string_view<CharT>::const_pointer basic_string_view<CharT>::data() const noexcept
233 {
234 return begin_;
235 }
236
237 template<class CharT>
238 constexpr typename basic_string_view<CharT>::const_reference basic_string_view<CharT>::operator[](size_type pos) const
239 {
240 return begin_[pos];
241 }
242
243 template<class CharT>
at(size_type pos)244 constexpr typename basic_string_view<CharT>::const_reference basic_string_view<CharT>::at(size_type pos) const
245 {
246 return begin_[pos];
247 }
248
249 template<class CharT>
front()250 constexpr typename basic_string_view<CharT>::const_reference basic_string_view<CharT>::front() const
251 {
252 // could assert that size_ > 0
253 return begin_[0];
254 }
255
256 template<class CharT>
back()257 constexpr typename basic_string_view<CharT>::const_reference basic_string_view<CharT>::back() const
258 {
259 // could assert that size_ > 0
260 return begin_[size_ - 1];
261 }
262
263 template<class CharT>
size()264 constexpr typename basic_string_view<CharT>::size_type basic_string_view<CharT>::size() const noexcept
265 {
266 return size_;
267 }
268
269 template<class CharT>
length()270 constexpr typename basic_string_view<CharT>::size_type basic_string_view<CharT>::length() const noexcept
271 {
272 return size_;
273 }
274
275 template<class CharT>
max_size()276 constexpr typename basic_string_view<CharT>::size_type basic_string_view<CharT>::max_size() const noexcept
277 {
278 return npos - 1;
279 }
280
281 template<class CharT>
empty()282 constexpr bool basic_string_view<CharT>::empty() const noexcept
283 {
284 return !size_;
285 }
286
287 template<class CharT>
remove_prefix(size_type n)288 constexpr void basic_string_view<CharT>::remove_prefix(size_type n)
289 {
290 if (n > size_) {
291 begin_ += size_;
292 size_ = 0;
293 } else {
294 size_ -= n;
295 begin_ += n;
296 }
297 }
298
299 template<class CharT>
remove_suffix(size_type n)300 constexpr void basic_string_view<CharT>::remove_suffix(size_type n)
301 {
302 if (n > size_) {
303 size_ = 0;
304 } else {
305 size_ -= n;
306 }
307 }
308
309 template<class CharT>
swap(basic_string_view & v)310 constexpr void basic_string_view<CharT>::swap(basic_string_view& v) noexcept
311 {
312 basic_string_view sv(v);
313 v = *this;
314 *this = sv;
315 }
316
317 template<class CharT>
copy(CharT * dest,size_type count,size_type pos)318 constexpr typename basic_string_view<CharT>::size_type basic_string_view<CharT>::copy(
319 CharT* dest, size_type count, size_type pos) const
320 {
321 if (pos > size_) {
322 return {}; // should throw
323 }
324 const auto left = size_ - pos;
325 const auto copy = (left < count) ? left : count;
326 const_pointer end = begin_ + pos + copy;
327 const_pointer i = begin_ + pos;
328 while (i < end) {
329 *dest++ = *i++;
330 }
331 return copy;
332 }
333
334 template<class CharT>
substr(size_type pos,size_type count)335 constexpr basic_string_view<CharT> basic_string_view<CharT>::substr(size_type pos, size_type count) const
336 {
337 if (pos > size_) {
338 return {}; // should throw
339 }
340 if (const auto left = size_ - pos; left < count) {
341 return { begin_ + pos, left };
342 } else {
343 return { begin_ + pos, count };
344 }
345 }
346
347 template<class CharT>
compare(basic_string_view v)348 constexpr int basic_string_view<CharT>::compare(basic_string_view v) const noexcept
349 {
350 const auto size = (size_ < v.size_) ? size_ : v.size_;
351 const auto* ptr1 = begin_;
352 const auto* ptr2 = v.begin_;
353 const auto* end = begin_ + size;
354 while (ptr1 != end) {
355 const auto res = static_cast<int>(*ptr1++) - static_cast<int>(*ptr2++);
356 if (res) {
357 return res;
358 }
359 }
360 if (size_ < v.size_) {
361 return -1;
362 } else if (size_ > v.size_) {
363 return 1;
364 }
365 return 0;
366 }
367
368 template<class CharT>
compare(size_type pos1,size_type count1,basic_string_view v)369 constexpr int basic_string_view<CharT>::compare(size_type pos1, size_type count1, basic_string_view v) const
370 {
371 return substr(pos1, count1).compare(v);
372 }
373
374 template<class CharT>
compare(size_type pos1,size_type count1,basic_string_view v,size_type pos2,size_type count2)375 constexpr int basic_string_view<CharT>::compare(
376 size_type pos1, size_type count1, basic_string_view v, size_type pos2, size_type count2) const
377 {
378 return substr(pos1, count1).compare(v.substr(pos2, count2));
379 }
380
381 template<class CharT>
compare(const CharT * const s)382 constexpr int basic_string_view<CharT>::compare(const CharT* const s) const
383 {
384 const auto size = size_;
385 const auto* ptr1 = begin_;
386 const auto* ptr2 = s;
387 const auto* end = begin_ + size;
388 while ((ptr1 != end) && *ptr2) {
389 const auto res = static_cast<int>(*ptr1++) - static_cast<int>(*ptr2++);
390 if (res) {
391 return res;
392 }
393 }
394 if ((ptr1 == end) && *ptr2) {
395 return -1;
396 } else if ((ptr1 != end) && !*ptr2) {
397 return 1;
398 }
399 return 0;
400 }
401
402 template<class CharT>
compare(size_type pos1,size_type count1,const CharT * const s)403 constexpr int basic_string_view<CharT>::compare(size_type pos1, size_type count1, const CharT* const s) const
404 {
405 return substr(pos1, count1).compare(s);
406 }
407
408 template<class CharT>
compare(size_type pos1,size_type count1,const CharT * const s,size_type count2)409 constexpr int basic_string_view<CharT>::compare(
410 size_type pos1, size_type count1, const CharT* const s, size_type count2) const
411 {
412 return substr(pos1, count1).compare(basic_string_view(s, count2));
413 }
414
415 template<class CharT>
416 constexpr bool operator==(const basic_string_view<CharT> lhs, const basic_string_view<CharT> rhs) noexcept
417 {
418 if (lhs.size() != rhs.size()) {
419 return false;
420 }
421 return lhs.compare(rhs) == 0;
422 }
423
424 template<class CharT, int = 1>
425 constexpr bool operator==(
426 const basic_string_view<CharT> lhs, const type_identity_t<basic_string_view<CharT>> rhs) noexcept
427 {
428 if (lhs.size() != rhs.size()) {
429 return false;
430 }
431 return lhs.compare(rhs) == 0;
432 }
433
434 template<class CharT, int = 2>
435 constexpr bool operator==(
436 const type_identity_t<basic_string_view<CharT>> lhs, const basic_string_view<CharT> rhs) noexcept
437 {
438 if (lhs.size() != rhs.size()) {
439 return false;
440 }
441 return lhs.compare(rhs) == 0;
442 }
443
444 template<class CharT>
445 constexpr bool operator!=(const basic_string_view<CharT> lhs, const basic_string_view<CharT> rhs) noexcept
446 {
447 if (lhs.size() != rhs.size()) {
448 return true;
449 }
450 return lhs.compare(rhs) != 0;
451 }
452
453 template<class CharT, int = 1>
454 constexpr bool operator!=(
455 const basic_string_view<CharT> lhs, const type_identity_t<basic_string_view<CharT>> rhs) noexcept
456 {
457 if (lhs.size() != rhs.size()) {
458 return true;
459 }
460 return lhs.compare(rhs) != 0;
461 }
462
463 template<class CharT, int = 2>
464 constexpr bool operator!=(
465 const type_identity_t<basic_string_view<CharT>> lhs, const basic_string_view<CharT> rhs) noexcept
466 {
467 if (lhs.size() != rhs.size()) {
468 return true;
469 }
470 return lhs.compare(rhs) != 0;
471 }
472
473 template<class CharT>
474 constexpr bool operator<(const basic_string_view<CharT> lhs, const basic_string_view<CharT> rhs) noexcept
475 {
476 return lhs.compare(rhs) < 0;
477 }
478
479 template<class CharT, int = 1>
480 constexpr bool operator<(
481 const basic_string_view<CharT> lhs, const type_identity_t<basic_string_view<CharT>> rhs) noexcept
482 {
483 return lhs.compare(rhs) < 0;
484 }
485
486 template<class CharT, int = 2>
487 constexpr bool operator<(
488 const type_identity_t<basic_string_view<CharT>> lhs, const basic_string_view<CharT> rhs) noexcept
489 {
490 return lhs.compare(rhs) < 0;
491 }
492
493 template<class CharT>
494 constexpr bool operator<=(const basic_string_view<CharT> lhs, const basic_string_view<CharT> rhs) noexcept
495 {
496 return lhs.compare(rhs) <= 0;
497 }
498
499 template<class CharT, int = 1>
500 constexpr bool operator<=(
501 const basic_string_view<CharT> lhs, const type_identity_t<basic_string_view<CharT>> rhs) noexcept
502 {
503 return lhs.compare(rhs) <= 0;
504 }
505
506 template<class CharT, int = 2>
507 constexpr bool operator<=(
508 const type_identity_t<basic_string_view<CharT>> lhs, const basic_string_view<CharT> rhs) noexcept
509 {
510 return lhs.compare(rhs) <= 0;
511 }
512
513 template<class CharT>
514 constexpr bool operator>(const basic_string_view<CharT> lhs, const basic_string_view<CharT> rhs) noexcept
515 {
516 return lhs.compare(rhs) > 0;
517 }
518
519 template<class CharT, int = 1>
520 constexpr bool operator>(
521 const basic_string_view<CharT> lhs, const type_identity_t<basic_string_view<CharT>> rhs) noexcept
522 {
523 return lhs.compare(rhs) > 0;
524 }
525
526 template<class CharT, int = 2>
527 constexpr bool operator>(
528 const type_identity_t<basic_string_view<CharT>> lhs, const basic_string_view<CharT> rhs) noexcept
529 {
530 return lhs.compare(rhs) > 0;
531 }
532
533 template<class CharT>
534 constexpr bool operator>=(const basic_string_view<CharT> lhs, const basic_string_view<CharT> rhs) noexcept
535 {
536 return lhs.compare(rhs) >= 0;
537 }
538
539 template<class CharT, int = 1>
540 constexpr bool operator>=(
541 const basic_string_view<CharT> lhs, const type_identity_t<basic_string_view<CharT>> rhs) noexcept
542 {
543 return lhs.compare(rhs) >= 0;
544 }
545
546 template<class CharT, int = 2>
547 constexpr bool operator>=(
548 const type_identity_t<basic_string_view<CharT>> lhs, const basic_string_view<CharT> rhs) noexcept
549 {
550 return lhs.compare(rhs) >= 0;
551 }
552
553 template<class CharT>
find(const CharT str,size_type pos)554 constexpr typename basic_string_view<CharT>::size_type basic_string_view<CharT>::find(
555 const CharT str, size_type pos) const noexcept
556 {
557 if (pos >= length()) {
558 return string_view::npos;
559 }
560
561 auto first1 = begin() + static_cast<difference_type>(pos);
562 auto end1 = end();
563
564 while (first1 != end1 && (*first1 != str)) {
565 ++first1;
566 }
567 if (first1 != end1) {
568 return static_cast<size_type>(first1 - begin());
569 } else {
570 return string_view::npos;
571 }
572 }
573
574 template<class CharT>
find(const basic_string_view & str,size_type pos)575 constexpr typename basic_string_view<CharT>::size_type basic_string_view<CharT>::find(
576 const basic_string_view& str, size_type pos) const noexcept
577 {
578 if (str.size() == 1) {
579 return find(str[0], pos);
580 }
581
582 if (pos >= length() || (pos + str.length() > length())) {
583 return string_view::npos;
584 }
585 if (str.empty()) {
586 return pos;
587 }
588
589 auto first1 = begin() + static_cast<difference_type>(pos);
590 const auto end1 = end() - (str.length() - 1U);
591 const auto first2 = str.begin();
592
593 while (first1 != end1) {
594 // look for first character
595 while (first1 != end1 && (*first1 != *first2)) {
596 ++first1;
597 }
598 if (first1 == end1) {
599 break;
600 }
601 if (substr(first1 - begin(), str.size()).compare(str) == 0) {
602 return static_cast<size_type>(first1 - begin());
603 }
604 ++first1;
605 }
606 // reached end of string - no match
607 return string_view::npos;
608 }
609
610 template<class CharT>
rfind(const CharT str,size_type pos)611 constexpr typename basic_string_view<CharT>::size_type basic_string_view<CharT>::rfind(
612 const CharT str, size_type pos) const noexcept
613 {
614 return find_last_of(str, pos);
615 }
616
617 template<class CharT>
rfind(const basic_string_view & str,size_type pos)618 constexpr typename basic_string_view<CharT>::size_type basic_string_view<CharT>::rfind(
619 const basic_string_view& str, size_type pos) const noexcept
620 {
621 const auto len = length();
622 if (len == 0) {
623 return string_view::npos;
624 }
625 const auto len2 = str.length();
626 if (len2 > len) {
627 return string_view::npos;
628 }
629 if ((pos == npos) || (pos > len)) {
630 pos = len;
631 }
632 if (len2 == 0) {
633 return pos;
634 }
635 if ((pos + len2) > len) {
636 pos = len - len2;
637 }
638 if (pos < 0) {
639 return string_view::npos;
640 }
641 const CharT* const s0 = data();
642 for (const CharT* s1 = s0 + pos;; s1--) {
643 const auto diff = basic_string_view<CharT>(s1, len2).compare(str);
644 if (diff == 0) {
645 return static_cast<size_type>(s1 - s0);
646 }
647 if (s1 == s0) {
648 break;
649 }
650 }
651 return string_view::npos;
652 }
653
654 template<class CharT>
find_first_of(const basic_string_view & str,size_type pos)655 constexpr typename basic_string_view<CharT>::size_type basic_string_view<CharT>::find_first_of(
656 const basic_string_view& str, size_type pos) const noexcept
657 {
658 const auto len = length();
659 if (len == 0) {
660 return string_view::npos;
661 }
662 if (pos >= len) {
663 return string_view::npos;
664 }
665 const CharT* s1 = data() + pos;
666 const CharT* const s2 = str.data();
667 const CharT* const s3 = s2 + str.length();
668 for (; pos < len; pos++, s1++) {
669 for (auto s = s2; s != s3; s++) {
670 if (*s == *s1) {
671 return pos;
672 }
673 }
674 }
675 return string_view::npos;
676 }
677
678 template<class CharT>
find_first_of(CharT ch,size_type pos)679 constexpr typename basic_string_view<CharT>::size_type basic_string_view<CharT>::find_first_of(
680 CharT ch, size_type pos) const noexcept
681 {
682 const auto len = length();
683 if (len == 0) {
684 return string_view::npos;
685 }
686 if (pos >= len) {
687 return string_view::npos;
688 }
689 const CharT* s1 = data() + pos;
690 for (; pos < len; pos++, s1++) {
691 if (*s1 == ch) {
692 return pos;
693 }
694 }
695 return string_view::npos;
696 }
697
698 template<class CharT>
find_last_of(const basic_string_view & str,size_type pos)699 constexpr typename basic_string_view<CharT>::size_type basic_string_view<CharT>::find_last_of(
700 const basic_string_view& str, size_type pos) const noexcept
701 {
702 const auto len = length();
703 if (len == 0) {
704 return string_view::npos;
705 }
706 if (pos >= len) {
707 pos = len - 1;
708 }
709 const CharT* s1 = data() + pos;
710 const CharT* const s2 = str.data();
711 const CharT* const s3 = s2 + str.length();
712 for (;;) {
713 for (auto s = s2; s != s3; s++) {
714 if (*s == *s1) {
715 return pos;
716 }
717 }
718 if (pos == 0) {
719 break;
720 }
721 pos--;
722 s1--;
723 }
724 return string_view::npos;
725 }
726 template<class CharT>
find_last_of(CharT ch,size_type pos)727 constexpr typename basic_string_view<CharT>::size_type basic_string_view<CharT>::find_last_of(
728 CharT ch, size_type pos) const noexcept
729 {
730 const auto len = length();
731 if (len == 0) {
732 return string_view::npos;
733 }
734 if (pos >= len) {
735 pos = len - 1;
736 }
737 const CharT* s1 = data() + pos;
738 for (;;) {
739 if (*s1 == ch) {
740 return pos;
741 }
742 if (pos == 0) {
743 break;
744 }
745 pos--;
746 s1--;
747 }
748 return string_view::npos;
749 }
750
751 template<class CharT>
starts_with(basic_string_view sv)752 constexpr bool basic_string_view<CharT>::starts_with(basic_string_view sv) const noexcept
753 {
754 return compare(0U, sv.size_, sv) == 0;
755 }
756
757 template<class CharT>
starts_with(CharT ch)758 constexpr bool basic_string_view<CharT>::starts_with(CharT ch) const noexcept
759 {
760 return (size_) && (*begin_ == ch);
761 }
762
763 template<class CharT>
starts_with(const CharT * s)764 constexpr bool basic_string_view<CharT>::starts_with(const CharT* s) const
765 {
766 if (!s) {
767 return true;
768 }
769 const auto* ptr1 = begin_;
770 const auto* ptr2 = s;
771 const auto* end = begin_ + size_;
772 while ((ptr1 != end) && *ptr2) {
773 if ((*ptr1++) != (*ptr2++)) {
774 return false;
775 }
776 }
777 return !(*ptr2);
778 }
779
780 template<class CharT>
ends_with(basic_string_view sv)781 constexpr bool basic_string_view<CharT>::ends_with(basic_string_view sv) const noexcept
782 {
783 return (size_ >= sv.size_) && (compare(size_ - sv.size_, sv.size_, sv) == 0);
784 }
785
786 template<class CharT>
ends_with(CharT ch)787 constexpr bool basic_string_view<CharT>::ends_with(CharT ch) const noexcept
788 {
789 return size_ && *(begin_ + size_ - 1U) == ch;
790 }
791
792 template<class CharT>
ends_with(const CharT * s)793 constexpr bool basic_string_view<CharT>::ends_with(const CharT* s) const
794 {
795 return ends_with(basic_string_view(s));
796 }
797
798 template<>
hash(const string_view & value)799 inline uint64_t hash(const string_view& value)
800 {
801 return BASE_NS::FNV1aHash(value.data(), value.size());
802 }
803
804 namespace literals {
805 inline namespace string_literals {
806 /// User-defined literal to allow the following syntax to construct a string_view: "myLiteral"_sv
807 [[nodiscard]] constexpr BASE_NS::string_view operator""_sv(const char* literal, const size_t length)
808 {
809 return { literal, length };
810 }
811 } // namespace string_literals
812 } // namespace literals
813 BASE_END_NAMESPACE()
814
815 #endif // API_BASE_CONTAINERS_STRING_VIEW_H