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