• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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