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