MSTL 1.4.0
A Modern C++ Library with extended functionality, web components, and utility libraries
载入中...
搜索中...
未找到
basic_string_view.hpp
1#ifndef MSTL_CORE_STRING_BASIC_STRING_VIEW_HPP__
2#define MSTL_CORE_STRING_BASIC_STRING_VIEW_HPP__
4#include "char_traits.hpp"
5#include "char_types.hpp"
7
8template <typename CharT, typename Traits = char_traits<CharT>>
9class basic_string_view;
10
11
12template <typename Traits>
13class string_view_iterator {
14private:
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>;
18
19public:
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;
26
27private:
28 pointer data_ = nullptr;
29 size_t size_ = 0;
30 size_t idx_ = 0;
31
32 friend basic_string_view<value_type, Traits>;
33
34public:
35 constexpr string_view_iterator() noexcept = default;
36
37 constexpr string_view_iterator(const pointer data, const size_t size, const size_t off) noexcept
38 : data_(data), size_(size), idx_(off) {}
39
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));
43 return data_[idx_];
44 }
45
46 MSTL_NODISCARD constexpr pointer operator ->() const noexcept {
47 return &operator*();
48 }
49
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));
53 ++idx_;
54 return *this;
55 }
56
57 constexpr string_view_iterator operator ++(int) noexcept {
58 string_view_iterator tmp(*this);
59 ++*this;
60 return tmp;
61 }
62
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));
66 --idx_;
67 return *this;
68 }
69
70 constexpr string_view_iterator operator --(int) noexcept {
71 string_view_iterator tmp(*this);
72 --*this;
73 return tmp;
74 }
75
76 constexpr string_view_iterator& operator +=(const difference_type n) noexcept {
77 if (n < 0) {
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));
81 }
82 else if (n > 0) {
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));
86 }
87 idx_ += n;
88 return *this;
89 }
90 MSTL_NODISCARD constexpr string_view_iterator operator +(const difference_type n) const noexcept {
91 string_view_iterator tmp = *this;
92 tmp += n;
93 return tmp;
94 }
95 MSTL_NODISCARD friend constexpr string_view_iterator operator +(const difference_type n, const string_view_iterator& iter) noexcept {
96 return iter + n;
97 }
98
99 constexpr string_view_iterator& operator -=(const difference_type n) noexcept {
100 idx_ += -n;
101 return *this;
102 }
103 MSTL_NODISCARD constexpr string_view_iterator operator -(const difference_type n) const noexcept {
104 string_view_iterator tmp = *this;
105 tmp -= n;
106 return tmp;
107 }
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_);
112 }
113
114 MSTL_NODISCARD constexpr reference operator [](const difference_type n) const noexcept {
115 return *(*this + n);
116 }
117
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_;
122 }
123 MSTL_NODISCARD constexpr bool operator !=(const string_view_iterator& iter) const noexcept {
124 return !(*this == iter);
125 }
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_;
130 }
131 MSTL_NODISCARD constexpr bool operator >(const string_view_iterator& iter) const noexcept {
132 return iter < *this;
133 }
134 MSTL_NODISCARD constexpr bool operator <=(const string_view_iterator& iter) const noexcept {
135 return !(iter < *this);
136 }
137 MSTL_NODISCARD constexpr bool operator >=(const string_view_iterator& iter) const noexcept {
138 return !(*this < iter);
139 }
140};
141
142
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.");
149
150public:
152 using traits_type = Traits;
153
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;
158
159 static constexpr auto npos = static_cast<size_type>(-1);
160
161private:
162 const_pointer data_ = "";
163 size_type size_ = 0;
164
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);
168 }
169
170public:
171 constexpr basic_string_view() noexcept = default;
172
173 constexpr basic_string_view(const basic_string_view&) noexcept = default;
174 constexpr basic_string_view& operator =(const basic_string_view&) noexcept = default;
175
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) {}
180
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)
183 : data_(&*start), size_(_MSTL distance(start, finish)) {}
184
185 MSTL_CONSTEXPR20 ~basic_string_view() noexcept = default;
186
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(); }
195
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;
199 }
200 MSTL_NODISCARD constexpr size_type length() const noexcept { return size_; }
201 MSTL_NODISCARD constexpr bool empty() const noexcept { return size_ == 0; }
202
203 MSTL_NODISCARD constexpr const_pointer data() const noexcept { return data_; }
204 MSTL_NODISCARD constexpr const_pointer to_cstring() const noexcept { return this->data(); }
205
206 MSTL_NODISCARD constexpr const_reference front() const noexcept {
207 MSTL_DEBUG_VERIFY(!empty(), "cannot call front on empty string_view");
208 return data_[0];
209 }
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];
213 }
214
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.");
217 return data_[n];
218 }
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.");
221 return data_[n];
222 }
223
224 constexpr void remove_prefix(const size_type n) noexcept {
225 MSTL_DEBUG_VERIFY(size_ >= n, "cannot remove prefix longer than total size");
226 data_ += n;
227 size_ -= n;
228 }
229 constexpr void remove_suffix(const size_type n) noexcept {
230 MSTL_DEBUG_VERIFY(size_ >= n, "cannot remove suffix longer than total size");
231 size_ -= n;
232 }
233
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);
238 return count;
239 }
240
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);
245 }
246
247 MSTL_NODISCARD constexpr basic_string_view view(const size_type off, size_type count = npos) const {
248 return substr(off, count);
249 }
250
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_);
253 }
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);
256 }
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));
260 }
261 MSTL_NODISCARD constexpr int compare(const CharT* const str) const noexcept {
262 return compare(basic_string_view(str));
263 }
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));
266 }
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));
270 }
271
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_);
274 }
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);
277 }
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);
281 }
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));
284 }
285
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_);
288 }
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);
291 }
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);
295 }
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));
298 }
299
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_);
302 }
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);
305 }
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);
309 }
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));
312 }
313
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_);
316 }
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);
319 }
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);
323 }
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));
326 }
327
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_);
331 }
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);
334 }
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);
338 }
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));
341 }
342
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_);
346 }
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);
349 }
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);
353 }
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));
357 }
358
359 MSTL_CONSTEXPR20 size_type count(value_type chr, const size_type position = 0) const noexcept {
360 size_type n = 0;
361 for (size_type idx = position; idx < size_; ++idx) {
362 if (*(data() + idx) == chr) ++n;
363 }
364 return n;
365 }
366
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;
369 }
370 MSTL_NODISCARD MSTL_CONSTEXPR20 bool starts_with(value_type chr) const noexcept {
371 return !empty() && traits_type::eq(front(), chr);
372 }
373 MSTL_NODISCARD MSTL_CONSTEXPR20 bool starts_with(const_pointer str) const noexcept {
374 return this->starts_with(basic_string_view(str));
375 }
376
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;
380 }
381 MSTL_NODISCARD MSTL_CONSTEXPR20 bool ends_with(value_type chr) const noexcept {
382 return !empty() && traits_type::eq(back(), chr);
383 }
384 MSTL_NODISCARD MSTL_CONSTEXPR20 bool ends_with(const_pointer str) const noexcept {
385 return this->ends_with(basic_string_view(str));
386 }
387
388 MSTL_NODISCARD MSTL_CONSTEXPR20 bool contains(const basic_string_view view) const noexcept {
389 return this->find(view) != npos;
390 }
391 MSTL_NODISCARD MSTL_CONSTEXPR20 bool contains(value_type chr) const noexcept {
392 return this->find(chr) != npos;
393 }
394 MSTL_NODISCARD MSTL_CONSTEXPR20 bool contains(const_pointer str) const noexcept {
395 return this->find(str) != npos;
396 }
397
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); });
400 }
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); });
403 }
404 MSTL_NODISCARD MSTL_CONSTEXPR20 basic_string_view trim() const noexcept {
405 return this->trim_left().trim_right();
406 }
407
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;
412
413 const_iterator it = cbegin();
414 while (it != cend() && pred(*it))
415 ++it;
416
417 if (it != cbegin())
418 return basic_string_view(data_ + (it - cbegin()), size_ - (it - cbegin()));
419
420 return *this;
421 }
422
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;
427
428 const_reverse_iterator rit = crbegin();
429 while (rit != crend() && pred(*rit))
430 ++rit;
431
432 if (rit != crbegin())
433 return basic_string_view(data_, size_ - (rit - crbegin()));
434
435 return *this;
436 }
437
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);
442 }
443
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_);
446 }
447
448 MSTL_NODISCARD MSTL_CONSTEXPR20 bool equal_to(const CharT* str) const noexcept {
449 return equal_to(view_type(str));
450 }
451
452 constexpr void swap(basic_string_view& view) noexcept {
453 const basic_string_view tmp(view);
454 view = *this;
455 *this = tmp;
456 }
457
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; }
460
461 MSTL_NODISCARD constexpr size_t to_hash() const noexcept {
462 return _INNER FNV_hash_string(this->data(), this->length());
463 }
464};
465
467#endif // MSTL_CORE_STRING_BASIC_STRING_VIEW_HPP__
MSTL字符类型分类和转换函数
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
#define MSTL_BUILD_TYPE_ALIAS(TYPE)
快速构建标准类型别名
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反向迭代器
通用接口,同时具备可比较和可哈希功能
MSTL_NODISCARD constexpr size_t to_hash() const noexcept(noexcept(derived().to_hash()))