1#ifndef MSTL_CORE_STRING_BASIC_STRING_VIEW_HPP__
2#define MSTL_CORE_STRING_BASIC_STRING_VIEW_HPP__
4#include "char_traits.hpp"
8template <
typename CharT,
typename Traits =
char_traits<CharT>>
9class basic_string_view;
12template <
typename Traits>
13class string_view_iterator {
15 using container_type = basic_string_view<typename Traits::char_type, Traits>;
16 using iterator = string_view_iterator<Traits>;
17 using const_iterator = string_view_iterator<Traits>;
20 using iterator_category = contiguous_iterator_tag;
21 using value_type =
typename container_type::value_type;
22 using reference =
typename container_type::const_reference;
23 using pointer =
typename container_type::const_pointer;
24 using difference_type =
typename container_type::difference_type;
25 using size_type =
typename container_type::size_type;
28 pointer data_ =
nullptr;
32 friend basic_string_view<value_type, Traits>;
35 constexpr string_view_iterator() noexcept = default;
37 constexpr string_view_iterator(const pointer
data, const
size_t size, const
size_t off) noexcept
38 : data_(
data), size_(
size), idx_(off) {}
40 MSTL_NODISCARD
constexpr reference operator *() const noexcept {
41 MSTL_DEBUG_VERIFY(data_, __MSTL_DEBUG_MESG_OPERATE_NULLPTR(string_view_iterator, __MSTL_DEBUG_TAG_DEREFERENCE));
42 MSTL_DEBUG_VERIFY(idx_ < size_, __MSTL_DEBUG_MESG_OUT_OF_RANGE(string_view_iterator, __MSTL_DEBUG_TAG_DEREFERENCE));
46 MSTL_NODISCARD
constexpr pointer operator ->() const noexcept {
50 constexpr string_view_iterator& operator ++() noexcept {
51 MSTL_DEBUG_VERIFY(data_, __MSTL_DEBUG_MESG_OPERATE_NULLPTR(string_view_iterator, __MSTL_DEBUG_TAG_INCREMENT));
52 MSTL_DEBUG_VERIFY(idx_ < size_, __MSTL_DEBUG_MESG_OUT_OF_RANGE(string_view_iterator, __MSTL_DEBUG_TAG_INCREMENT));
57 constexpr string_view_iterator operator ++(
int)
noexcept {
58 string_view_iterator tmp(*
this);
63 constexpr string_view_iterator& operator --() noexcept {
64 MSTL_DEBUG_VERIFY(data_, __MSTL_DEBUG_MESG_OPERATE_NULLPTR(string_view_iterator, __MSTL_DEBUG_TAG_DECREMENT));
65 MSTL_DEBUG_VERIFY(idx_ != 0, __MSTL_DEBUG_MESG_OUT_OF_RANGE(string_view_iterator, __MSTL_DEBUG_TAG_DECREMENT));
70 constexpr string_view_iterator operator --(
int)
noexcept {
71 string_view_iterator tmp(*
this);
76 constexpr string_view_iterator& operator +=(
const difference_type n)
noexcept {
78 MSTL_DEBUG_VERIFY(data_ || n == 0, __MSTL_DEBUG_MESG_OPERATE_NULLPTR(vector_iterator, __MSTL_DEBUG_TAG_DECREMENT));
79 MSTL_DEBUG_VERIFY(idx_ >=
static_cast<size_t>(0) -
static_cast<size_t>(n),
80 __MSTL_DEBUG_MESG_OUT_OF_RANGE(vector_iterator, __MSTL_DEBUG_TAG_DECREMENT));
83 MSTL_DEBUG_VERIFY(data_ || n == 0, __MSTL_DEBUG_MESG_OPERATE_NULLPTR(vector_iterator, __MSTL_DEBUG_TAG_INCREMENT));
84 MSTL_DEBUG_VERIFY(size_ - idx_ >=
static_cast<size_t>(n),
85 __MSTL_DEBUG_MESG_OUT_OF_RANGE(vector_iterator, __MSTL_DEBUG_TAG_INCREMENT));
90 MSTL_NODISCARD
constexpr string_view_iterator operator +(
const difference_type n)
const noexcept {
91 string_view_iterator tmp = *
this;
95 MSTL_NODISCARD
friend constexpr string_view_iterator operator +(
const difference_type n,
const string_view_iterator& iter)
noexcept {
99 constexpr string_view_iterator& operator -=(
const difference_type n)
noexcept {
103 MSTL_NODISCARD
constexpr string_view_iterator operator -(
const difference_type n)
const noexcept {
104 string_view_iterator tmp = *
this;
108 MSTL_NODISCARD
constexpr difference_type operator -(
const string_view_iterator& iter)
const noexcept {
109 MSTL_DEBUG_VERIFY(data_ == iter.data_ && size_ == iter.size_,
110 __MSTL_DEBUG_MESG_CONTAINER_INCOMPATIBLE(string_view_iterator));
111 return static_cast<difference_type
>(idx_ - iter.idx_);
114 MSTL_NODISCARD
constexpr reference operator [](
const difference_type n)
const noexcept {
118 MSTL_NODISCARD
constexpr bool operator ==(
const string_view_iterator& iter)
const noexcept {
119 MSTL_DEBUG_VERIFY(data_ == iter.data_ && size_ == iter.size_,
120 __MSTL_DEBUG_MESG_CONTAINER_INCOMPATIBLE(string_view_iterator));
121 return idx_ == iter.idx_;
123 MSTL_NODISCARD
constexpr bool operator !=(
const string_view_iterator& iter)
const noexcept {
124 return !(*
this == iter);
126 MSTL_NODISCARD
constexpr bool operator <(
const string_view_iterator& iter)
const noexcept {
127 MSTL_DEBUG_VERIFY(data_ == iter.data_ && size_ == iter.size_,
128 __MSTL_DEBUG_MESG_CONTAINER_INCOMPATIBLE(string_view_iterator));
129 return idx_ < iter.idx_;
131 MSTL_NODISCARD
constexpr bool operator >(
const string_view_iterator& iter)
const noexcept {
134 MSTL_NODISCARD
constexpr bool operator <=(
const string_view_iterator& iter)
const noexcept {
135 return !(iter < *
this);
137 MSTL_NODISCARD
constexpr bool operator >=(
const string_view_iterator& iter)
const noexcept {
138 return !(*
this < iter);
143template <
typename CharT,
typename Traits>
144class basic_string_view :
public icommon<basic_string_view<CharT, Traits>> {
145 static_assert(is_same_v<CharT, typename Traits::char_type>,
146 "char type of basic string view should be same with char traits.");
147 static_assert(!is_array_v<CharT> && is_trivial_v<CharT> && is_standard_layout_v<CharT>,
148 "basic string view only contains non-array trivial standard-layout types.");
152 using traits_type = Traits;
154 using const_iterator = string_view_iterator<Traits>;
155 using iterator = const_iterator;
156 using const_reverse_iterator =
_MSTL reverse_iterator<const_iterator>;
157 using reverse_iterator = const_reverse_iterator;
159 static constexpr auto npos =
static_cast<size_type
>(-1);
162 const_pointer data_ =
"";
165 MSTL_NODISCARD MSTL_ALWAYS_INLINE
166 constexpr size_type clamp_size(
const size_type position,
const size_type size)
const noexcept {
167 return _MSTL min(size, size_ - position);
171 constexpr basic_string_view() noexcept = default;
173 constexpr basic_string_view(const basic_string_view&) noexcept = default;
174 constexpr basic_string_view& operator =(const basic_string_view&) noexcept = default;
176 constexpr basic_string_view(const_pointer str) noexcept
177 : data_(str), size_(Traits::length(str)) {}
178 constexpr basic_string_view(const_pointer str,
const size_type n) noexcept
179 : data_(str), size_(n) {}
181 template <
typename Iterator, enable_if_t<is_same_v<iter_value_t<Iterator>, value_type>,
int> = 0>
182 constexpr basic_string_view(Iterator start, Iterator finish)
185 MSTL_CONSTEXPR20 ~basic_string_view() noexcept = default;
187 MSTL_NODISCARD constexpr const_iterator begin() const noexcept {
return const_iterator(data_, size_, 0); }
188 MSTL_NODISCARD
constexpr const_iterator end() const noexcept {
return const_iterator(data_, size_, size_); }
189 MSTL_NODISCARD
constexpr const_iterator cbegin() const noexcept {
return begin(); }
190 MSTL_NODISCARD
constexpr const_iterator cend() const noexcept {
return end(); }
191 MSTL_NODISCARD
constexpr const_reverse_iterator rbegin() const noexcept {
return const_reverse_iterator(end()); }
192 MSTL_NODISCARD
constexpr const_reverse_iterator rend() const noexcept {
return const_reverse_iterator(begin()); }
193 MSTL_NODISCARD
constexpr const_reverse_iterator crbegin() const noexcept {
return rbegin(); }
194 MSTL_NODISCARD
constexpr const_reverse_iterator crend() const noexcept {
return rend(); }
196 MSTL_NODISCARD
constexpr size_type size() const noexcept {
return size_; }
197 MSTL_NODISCARD
constexpr size_type max_size() const noexcept {
198 return (npos -
sizeof(size_type) -
sizeof(
void*)) /
sizeof(value_type) / 4;
200 MSTL_NODISCARD
constexpr size_type length() const noexcept {
return size_; }
201 MSTL_NODISCARD
constexpr bool empty() const noexcept {
return size_ == 0; }
203 MSTL_NODISCARD
constexpr const_pointer data() const noexcept {
return data_; }
204 MSTL_NODISCARD
constexpr const_pointer to_cstring() const noexcept {
return this->data(); }
206 MSTL_NODISCARD
constexpr const_reference front() const noexcept {
207 MSTL_DEBUG_VERIFY(!empty(),
"cannot call front on empty string_view");
210 MSTL_NODISCARD
constexpr const_reference back() const noexcept {
211 MSTL_DEBUG_VERIFY(!empty(),
"cannot call back on empty string_view");
212 return data_[size_ - 1];
215 MSTL_NODISCARD
constexpr const_reference operator [](
const size_type n)
const noexcept {
216 MSTL_DEBUG_VERIFY(n < size_,
"basic string view index out of ranges.");
219 MSTL_NODISCARD
constexpr const_reference at(
const size_type n)
const {
220 MSTL_DEBUG_VERIFY(n < size_,
"basic string view index out of ranges.");
224 constexpr void remove_prefix(
const size_type n)
noexcept {
225 MSTL_DEBUG_VERIFY(size_ >= n,
"cannot remove prefix longer than total size");
229 constexpr void remove_suffix(
const size_type n)
noexcept {
230 MSTL_DEBUG_VERIFY(size_ >= n,
"cannot remove suffix longer than total size");
234 constexpr size_type copy(CharT*
const str, size_type count,
const size_type off = 0)
const {
235 MSTL_DEBUG_VERIFY(off < size_,
"basic string view index out of ranges.");
236 count = clamp_size(off, count);
237 Traits::copy(str, data_ + off, count);
241 MSTL_NODISCARD
constexpr basic_string_view substr(
const size_type off = 0, size_type count = npos)
const {
242 MSTL_DEBUG_VERIFY(off < size_,
"basic string view index out of ranges.");
243 count = clamp_size(off, count);
244 return basic_string_view(data_ + off, count);
247 MSTL_NODISCARD
constexpr basic_string_view view(
const size_type off, size_type count = npos)
const {
248 return substr(off, count);
251 MSTL_NODISCARD
constexpr int compare(
const basic_string_view view)
const noexcept {
252 return (char_traits_compare<Traits>)(data_, size_, view.data_, view.size_);
254 MSTL_NODISCARD
constexpr int compare(
const size_type off,
const size_type n,
const basic_string_view view)
const {
255 return substr(off, n).compare(view);
257 MSTL_NODISCARD
constexpr int compare(
const size_type off,
const size_type n,
const basic_string_view view,
258 const size_type roff,
const size_type count)
const {
259 return substr(off, n).compare(view.substr(roff, count));
261 MSTL_NODISCARD
constexpr int compare(
const CharT*
const str)
const noexcept {
262 return compare(basic_string_view(str));
264 MSTL_NODISCARD
constexpr int compare(
const size_type off,
const size_type n,
const CharT*
const str)
const {
265 return substr(off, n).compare(basic_string_view(str));
267 MSTL_NODISCARD
constexpr int compare(
const size_type off,
const size_type n,
268 const CharT*
const str,
const size_type count)
const {
269 return substr(off, n).compare(basic_string_view(str, count));
272 MSTL_NODISCARD
constexpr size_type find(
const basic_string_view view,
const size_type n = 0) const noexcept {
273 return (char_traits_find<Traits>)(data_, size_, n, view.data_, view.size_);
275 MSTL_NODISCARD
constexpr size_type find(
const CharT chr,
const size_type n = 0) const noexcept {
276 return (char_traits_find_char<Traits>)(data_, size_, n, chr);
278 MSTL_NODISCARD
constexpr size_type find(
const CharT*
const str,
279 const size_type off,
const size_type count)
const noexcept {
280 return (char_traits_find<Traits>)(data_, size_, off, str, count);
282 MSTL_NODISCARD
constexpr size_type find(
const CharT*
const str,
const size_type off = 0) const noexcept {
283 return (char_traits_find<Traits>)(data_, size_, off, str, Traits::length(str));
286 MSTL_NODISCARD
constexpr size_type rfind(
const basic_string_view view,
const size_type off = npos)
const noexcept {
287 return (char_traits_rfind<Traits>)(data_, size_, off, view.data_, view.size_);
289 MSTL_NODISCARD
constexpr size_type rfind(
const CharT chr,
const size_type n = npos)
const noexcept {
290 return (char_traits_rfind_char<Traits>)(data_, size_, n, chr);
292 MSTL_NODISCARD
constexpr size_type rfind(
const CharT*
const str,
const size_type off,
293 const size_type n)
const noexcept {
294 return (char_traits_rfind<Traits>)(data_, size_, off, str, n);
296 MSTL_NODISCARD
constexpr size_type rfind(
const CharT*
const str,
const size_type off = npos)
const noexcept {
297 return (char_traits_rfind<Traits>)(data_, size_, off, str, Traits::length(str));
300 MSTL_NODISCARD
constexpr size_type find_first_of(
const basic_string_view view,
const size_type off = 0) const noexcept {
301 return (char_traits_find_first_of<Traits>)(data_, size_, off, view.data_, view.size_);
303 MSTL_NODISCARD
constexpr size_type find_first_of(
const CharT chr,
const size_type off = 0) const noexcept {
304 return (char_traits_find_char<Traits>)(data_, size_, off, chr);
306 MSTL_NODISCARD
constexpr size_type find_first_of(
const CharT*
const str,
const size_type off,
307 const size_type n)
const noexcept {
308 return (char_traits_find_first_of<Traits>)(data_, size_, off, str, n);
310 MSTL_NODISCARD
constexpr size_type find_first_of(
const CharT*
const str,
const size_type off = 0) const noexcept {
311 return (char_traits_find_first_of<Traits>)(data_, size_, off, str, Traits::length(str));
314 MSTL_NODISCARD
constexpr size_type find_last_of(
const basic_string_view view,
const size_type off = npos)
const noexcept {
315 return (char_traits_find_last_of<Traits>)(data_, size_, off, view.data_, view.size_);
317 MSTL_NODISCARD
constexpr size_type find_last_of(
const CharT chr,
const size_type off = npos)
const noexcept {
318 return (char_traits_rfind_char<Traits>)(data_, size_, off, chr);
320 MSTL_NODISCARD
constexpr size_type find_last_of(
const CharT*
const str,
const size_type off,
321 const size_type n)
const noexcept {
322 return (char_traits_find_last_of<Traits>)(data_, size_, off, str, n);
324 MSTL_NODISCARD
constexpr size_type find_last_of(
const CharT*
const str,
const size_type off = npos)
const noexcept {
325 return (char_traits_find_last_of<Traits>)(data_, size_, off, str, Traits::length(str));
328 MSTL_NODISCARD
constexpr size_type find_first_not_of(
const basic_string_view view,
329 const size_type off = 0) const noexcept {
330 return (char_traits_find_first_not_of<Traits>)(data_, size_, off, view.data_, view.size_);
332 MSTL_NODISCARD
constexpr size_type find_first_not_of(
const CharT chr,
const size_type off = 0) const noexcept {
333 return (char_traits_find_not_char<Traits>)(data_, size_, off, chr);
335 MSTL_NODISCARD
constexpr size_type find_first_not_of(
const CharT*
const str,
const size_type off,
336 const size_type n)
const noexcept {
337 return (char_traits_find_first_not_of<Traits>)(data_, size_, off, str, n);
339 MSTL_NODISCARD
constexpr size_type find_first_not_of(
const CharT*
const str,
const size_type off = 0) const noexcept {
340 return (char_traits_find_first_not_of<Traits>)(data_, size_, off, str, Traits::length(str));
343 MSTL_NODISCARD
constexpr size_type find_last_not_of(
const basic_string_view view,
344 const size_type off = npos)
const noexcept {
345 return (char_traits_find_last_not_of<Traits>)(data_, size_, off, view.data_, view.size_);
347 MSTL_NODISCARD
constexpr size_type find_last_not_of(
const CharT chr,
const size_type off = npos)
const noexcept {
348 return (char_traits_rfind_not_char<Traits>)(data_, size_, off, chr);
350 MSTL_NODISCARD
constexpr size_type find_last_not_of(
const CharT*
const str,
const size_type off,
351 const size_type n)
const noexcept {
352 return (char_traits_find_last_not_of<Traits>)(data_, size_, off, str, n);
354 MSTL_NODISCARD
constexpr size_type find_last_not_of(
const CharT*
const str,
355 const size_type off = npos)
const noexcept {
356 return (char_traits_find_last_not_of<Traits>)(data_, size_, off, str, Traits::length(str));
359 MSTL_CONSTEXPR20 size_type count(value_type chr,
const size_type position = 0) const noexcept {
361 for (size_type idx = position; idx < size_; ++idx) {
362 if (*(data() + idx) == chr) ++n;
367 MSTL_NODISCARD MSTL_CONSTEXPR20
bool starts_with(
const basic_string_view view)
const noexcept {
368 return view.size() <= size_ && traits_type::compare(data(), view.data(), view.size()) == 0;
370 MSTL_NODISCARD MSTL_CONSTEXPR20
bool starts_with(value_type chr)
const noexcept {
371 return !empty() && traits_type::eq(front(), chr);
373 MSTL_NODISCARD MSTL_CONSTEXPR20
bool starts_with(const_pointer str)
const noexcept {
374 return this->starts_with(basic_string_view(str));
377 MSTL_NODISCARD MSTL_CONSTEXPR20
bool ends_with(
const basic_string_view view)
const noexcept {
378 const size_type view_size = view.size();
379 return view_size <= size_ && traits_type::compare(data_ + size_ - view_size, view.data(), view_size) == 0;
381 MSTL_NODISCARD MSTL_CONSTEXPR20
bool ends_with(value_type chr)
const noexcept {
382 return !empty() && traits_type::eq(back(), chr);
384 MSTL_NODISCARD MSTL_CONSTEXPR20
bool ends_with(const_pointer str)
const noexcept {
385 return this->ends_with(basic_string_view(str));
388 MSTL_NODISCARD MSTL_CONSTEXPR20
bool contains(
const basic_string_view view)
const noexcept {
389 return this->find(view) != npos;
391 MSTL_NODISCARD MSTL_CONSTEXPR20
bool contains(value_type chr)
const noexcept {
392 return this->find(chr) != npos;
394 MSTL_NODISCARD MSTL_CONSTEXPR20
bool contains(const_pointer str)
const noexcept {
395 return this->find(str) != npos;
398 MSTL_NODISCARD MSTL_CONSTEXPR20 basic_string_view trim_left() const noexcept {
399 return this->trim_left_if([](value_type ch) {
return _MSTL is_space(ch); });
401 MSTL_NODISCARD MSTL_CONSTEXPR20 basic_string_view trim_right() const noexcept {
402 return this->trim_right_if([](value_type ch) {
return _MSTL is_space(ch); });
404 MSTL_NODISCARD MSTL_CONSTEXPR20 basic_string_view trim() const noexcept {
405 return this->trim_left().trim_right();
408 template <
typename Predicate>
409 MSTL_NODISCARD MSTL_CONSTEXPR20 basic_string_view trim_left_if(Predicate pred)
const
410 noexcept(
noexcept(pred(*cbegin()))) {
411 if (empty())
return *
this;
413 const_iterator it = cbegin();
414 while (it != cend() && pred(*it))
418 return basic_string_view(data_ + (it - cbegin()), size_ - (it - cbegin()));
423 template <
typename Predicate>
424 MSTL_NODISCARD MSTL_CONSTEXPR20 basic_string_view trim_right_if(Predicate pred)
const
425 noexcept(
noexcept(pred(*crbegin()))) {
426 if (empty())
return *
this;
428 const_reverse_iterator rit = crbegin();
429 while (rit != crend() && pred(*rit))
432 if (rit != crbegin())
433 return basic_string_view(data_, size_ - (rit - crbegin()));
438 template <
typename Predicate>
439 MSTL_NODISCARD MSTL_CONSTEXPR20 basic_string_view trim_if(Predicate pred)
const
440 noexcept(
noexcept(this->trim_right_if(pred)) &&
noexcept(this->trim_left_if(pred))) {
441 return this->trim_left_if(pred).trim_right_if(pred);
444 MSTL_NODISCARD MSTL_CONSTEXPR20
bool equal_to(
const basic_string_view str)
const noexcept {
445 return (char_traits_equal<Traits>)(data_, size_, str.data_, str.size_);
448 MSTL_NODISCARD MSTL_CONSTEXPR20
bool equal_to(
const CharT* str)
const noexcept {
449 return equal_to(view_type(str));
452 constexpr void swap(basic_string_view& view)
noexcept {
453 const basic_string_view tmp(view);
458 MSTL_NODISCARD
constexpr bool operator ==(
const basic_string_view& rhs)
const noexcept {
return this->equal_to(rhs); }
459 MSTL_NODISCARD
constexpr bool operator <(
const basic_string_view& rhs)
const noexcept {
return this->compare(rhs) < 0; }
461 MSTL_NODISCARD
constexpr size_t to_hash() const noexcept {
462 return _INNER FNV_hash_string(this->data(), this->length());
MSTL_PURE_FUNCTION MSTL_CONSTEXPR14 bool is_space(const CharT c) noexcept
检查字符是否为空白字符
constexpr const T & min(const T &a, const T &b, Compare comp) noexcept(noexcept(comp(b, a)))
返回两个值中的较小者
constexpr iter_difference_t< Iterator > distance(Iterator first, Iterator last)
计算两个迭代器之间的距离
#define _MSTL
全局命名空间MSTL前缀
#define _INNER
inner命名空间前缀
#define MSTL_END_NAMESPACE__
结束全局命名空间MSTL
#define MSTL_BEGIN_NAMESPACE__
开始全局命名空间MSTL
void swap()=delete
删除无参数的swap重载
MSTL_NODISCARD MSTL_ALWAYS_INLINE constexpr decltype(auto) size(const Container &cont) noexcept(noexcept(cont.size()))
获取容器的大小
MSTL_NODISCARD MSTL_ALWAYS_INLINE constexpr decltype(auto) data(Container &cont) noexcept(noexcept(cont.data()))
获取容器的底层数据指针
MSTL_NODISCARD constexpr size_t to_hash() const noexcept(noexcept(derived().to_hash()))