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