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(CharT const* const s, size_type count);
54     constexpr basic_string_view(CharT const* 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(CharT const* const s) const;
126     constexpr int compare(size_type pos1, size_type count1, CharT const* const s) const;
127     constexpr int compare(size_type pos1, size_type count1, CharT const* 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(CharT const * const str)163 constexpr size_t constexpr_strlen(CharT const* 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(CharT const * const s,size_type count)176 constexpr basic_string_view<CharT>::basic_string_view(CharT const* const s, size_type count) : begin_(s), size_(count)
177 {}
178 
179 template<class CharT>
basic_string_view(CharT const * const s)180 constexpr basic_string_view<CharT>::basic_string_view(CharT const* 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     auto const left = size_ - pos;
325     auto const 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 (auto const 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     auto const size = (size_ < v.size_) ? size_ : v.size_;
351     auto const* ptr1 = begin_;
352     auto const* ptr2 = v.begin_;
353     auto const* end = begin_ + size;
354     while (ptr1 != end) {
355         auto const 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(CharT const * const s)382 constexpr int basic_string_view<CharT>::compare(CharT const* const s) const
383 {
384     auto const size = size_;
385     auto const* ptr1 = begin_;
386     auto const* ptr2 = s;
387     auto const* end = begin_ + size;
388     while ((ptr1 != end) && *ptr2) {
389         auto const 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,CharT const * const s)403 constexpr int basic_string_view<CharT>::compare(size_type pos1, size_type count1, CharT const* const s) const
404 {
405     return substr(pos1, count1).compare(s);
406 }
407 
408 template<class CharT>
compare(size_type pos1,size_type count1,CharT const * const s,size_type count2)409 constexpr int basic_string_view<CharT>::compare(
410     size_type pos1, size_type count1, CharT const* 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 
586     auto first1 = begin() + static_cast<difference_type>(pos);
587     const auto end1 = end();
588     const auto first2 = str.begin();
589     const auto end2 = str.end();
590 
591     while (first1 != end1) {
592         // look for first character
593         while (first1 != end1 && (*first1 != *first2)) {
594             ++first1;
595         }
596         if (first1 != end1) {
597             // continue comparing the next characters
598             auto next1 = first1;
599             ++next1;
600             if (next1 != end1) {
601                 auto next2 = first2 + 1;
602                 while (*next1 == *next2) {
603                     ++next2;
604                     if (next2 == end2) {
605                         // reached end of searched string - found it
606                         return static_cast<size_type>(first1 - begin());
607                     }
608                     ++next1;
609                     if (next1 == end1) {
610                         // reached end of string - no match
611                         return string_view::npos;
612                     }
613                 }
614                 // try again starting from the next
615                 ++first1;
616             } else {
617                 // reached end of string - no match
618                 return string_view::npos;
619             }
620         }
621     }
622     // reached end of string - no match
623     return string_view::npos;
624 }
625 
626 template<class CharT>
rfind(const CharT str,size_type pos)627 constexpr typename basic_string_view<CharT>::size_type basic_string_view<CharT>::rfind(
628     const CharT str, size_type pos) const noexcept
629 {
630     return find_last_of(str, pos);
631 }
632 
633 template<class CharT>
rfind(const basic_string_view & str,size_type pos)634 constexpr typename basic_string_view<CharT>::size_type basic_string_view<CharT>::rfind(
635     const basic_string_view& str, size_type pos) const noexcept
636 {
637     const auto len = length();
638     if (len == 0) {
639         return string_view::npos;
640     }
641     const auto len2 = str.length();
642     if (len2 > len) {
643         return string_view::npos;
644     }
645     if ((pos == npos) || (pos > len)) {
646         pos = len;
647     }
648     if (len2 == 0) {
649         return pos;
650     }
651     if ((pos + len2) > len) {
652         pos = len - len2;
653     }
654     if (pos < 0) {
655         return string_view::npos;
656     }
657     CharT const* s1 = data() + pos;
658     const auto todo = pos;
659     for (auto it = 0u; it <= todo; it++, pos--, s1--) {
660         const auto diff = basic_string_view<CharT>(s1, len2).compare(str);
661         if (diff == 0) {
662             return pos;
663         }
664     };
665     return string_view::npos;
666 }
667 
668 template<class CharT>
find_first_of(const basic_string_view & str,size_type pos)669 constexpr typename basic_string_view<CharT>::size_type basic_string_view<CharT>::find_first_of(
670     const basic_string_view& str, size_type pos) const noexcept
671 {
672     const auto len = length();
673     if (len == 0) {
674         return string_view::npos;
675     }
676     if (pos >= len) {
677         return string_view::npos;
678     }
679     CharT const* s1 = data() + pos;
680     CharT const* const s2 = str.data();
681     CharT const* const s3 = s2 + str.length();
682     for (; pos < len; pos++, s1++) {
683         for (auto s = s2; s != s3; s++) {
684             if (*s == *s1) {
685                 return pos;
686             }
687         }
688     }
689     return string_view::npos;
690 }
691 
692 template<class CharT>
find_first_of(CharT ch,size_type pos)693 constexpr typename basic_string_view<CharT>::size_type basic_string_view<CharT>::find_first_of(
694     CharT ch, size_type pos) const noexcept
695 {
696     const auto len = length();
697     if (len == 0) {
698         return string_view::npos;
699     }
700     if (pos >= len) {
701         return string_view::npos;
702     }
703     CharT const* s1 = data() + pos;
704     for (; pos < len; pos++, s1++) {
705         if (*s1 == ch) {
706             return pos;
707         }
708     }
709     return string_view::npos;
710 }
711 
712 template<class CharT>
find_last_of(const basic_string_view & str,size_type pos)713 constexpr typename basic_string_view<CharT>::size_type basic_string_view<CharT>::find_last_of(
714     const basic_string_view& str, size_type pos) const noexcept
715 {
716     const auto len = length();
717     if (len == 0) {
718         return string_view::npos;
719     }
720     if (pos >= len) {
721         pos = len - 1;
722     }
723     CharT const* s1 = data() + pos;
724     CharT const* const s2 = str.data();
725     CharT const* const s3 = s2 + str.length();
726     for (;;) {
727         for (auto s = s2; s != s3; s++) {
728             if (*s == *s1) {
729                 return pos;
730             }
731         }
732         if (pos == 0) {
733             break;
734         }
735         pos--;
736         s1--;
737     }
738     return string_view::npos;
739 }
740 template<class CharT>
find_last_of(CharT ch,size_type pos)741 constexpr typename basic_string_view<CharT>::size_type basic_string_view<CharT>::find_last_of(
742     CharT ch, size_type pos) const noexcept
743 {
744     const auto len = length();
745     if (len == 0) {
746         return string_view::npos;
747     }
748     if (pos >= len) {
749         pos = len - 1;
750     }
751     CharT const* s1 = data() + pos;
752     for (;;) {
753         if (*s1 == ch) {
754             return pos;
755         }
756         if (pos == 0) {
757             break;
758         }
759         pos--;
760         s1--;
761     }
762     return string_view::npos;
763 }
764 
765 template<class CharT>
starts_with(basic_string_view sv)766 constexpr bool basic_string_view<CharT>::starts_with(basic_string_view sv) const noexcept
767 {
768     return compare(0U, sv.size_, sv) == 0;
769 }
770 
771 template<class CharT>
starts_with(CharT ch)772 constexpr bool basic_string_view<CharT>::starts_with(CharT ch) const noexcept
773 {
774     return (size_) && (*begin_ == ch);
775 }
776 
777 template<class CharT>
starts_with(const CharT * s)778 constexpr bool basic_string_view<CharT>::starts_with(const CharT* s) const
779 {
780     if (!s) {
781         return true;
782     }
783     auto const* ptr1 = begin_;
784     auto const* ptr2 = s;
785     auto const* end = begin_ + size_;
786     while ((ptr1 != end) && *ptr2) {
787         if ((*ptr1++) != (*ptr2++)) {
788             return false;
789         }
790     }
791     return !(*ptr2);
792 }
793 
794 template<class CharT>
ends_with(basic_string_view sv)795 constexpr bool basic_string_view<CharT>::ends_with(basic_string_view sv) const noexcept
796 {
797     return (size_ >= sv.size_) && (compare(size_ - sv.size_, sv.size_, sv) == 0);
798 }
799 
800 template<class CharT>
ends_with(CharT ch)801 constexpr bool basic_string_view<CharT>::ends_with(CharT ch) const noexcept
802 {
803     return size_ && *(begin_ + size_ - 1U) == ch;
804 }
805 
806 template<class CharT>
ends_with(const CharT * s)807 constexpr bool basic_string_view<CharT>::ends_with(const CharT* s) const
808 {
809     return ends_with(basic_string_view(s));
810 }
811 
812 template<typename T>
813 uint64_t hash(const T& b);
814 
815 template<>
hash(const string_view & value)816 inline uint64_t hash(const string_view& value)
817 {
818     return BASE_NS::FNV1aHash(value.data(), value.size());
819 }
820 BASE_END_NAMESPACE()
821 
822 #endif // API_BASE_CONTAINERS_STRING_VIEW_H