1 | //===----------------------------------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #ifndef _LIBCPP___STRING_CHAR_TRAITS_H |
10 | #define _LIBCPP___STRING_CHAR_TRAITS_H |
11 | |
12 | #include <__algorithm/fill_n.h> |
13 | #include <__algorithm/find.h> |
14 | #include <__algorithm/find_end.h> |
15 | #include <__algorithm/find_first_of.h> |
16 | #include <__algorithm/min.h> |
17 | #include <__assert> |
18 | #include <__compare/ordering.h> |
19 | #include <__config> |
20 | #include <__cstddef/ptrdiff_t.h> |
21 | #include <__functional/hash.h> |
22 | #include <__functional/identity.h> |
23 | #include <__iterator/iterator_traits.h> |
24 | #include <__std_mbstate_t.h> |
25 | #include <__string/constexpr_c_functions.h> |
26 | #include <__type_traits/is_constant_evaluated.h> |
27 | #include <__utility/is_pointer_in_range.h> |
28 | #include <cstdint> |
29 | #include <cstdio> |
30 | #include <iosfwd> |
31 | |
32 | #if _LIBCPP_HAS_WIDE_CHARACTERS |
33 | # include <cwchar> // for wmemcpy |
34 | #endif |
35 | |
36 | #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) |
37 | # pragma GCC system_header |
38 | #endif |
39 | |
40 | _LIBCPP_PUSH_MACROS |
41 | #include <__undef_macros> |
42 | |
43 | _LIBCPP_BEGIN_NAMESPACE_STD |
44 | |
45 | template <class _CharT> |
46 | struct char_traits; |
47 | /* |
48 | The Standard does not define the base template for char_traits because it is impossible to provide |
49 | a correct definition for arbitrary character types. Instead, it requires implementations to provide |
50 | specializations for predefined character types like `char`, `wchar_t` and others. We provide this as |
51 | exposition-only to document what members a char_traits specialization should provide: |
52 | { |
53 | using char_type = _CharT; |
54 | using int_type = ...; |
55 | using off_type = ...; |
56 | using pos_type = ...; |
57 | using state_type = ...; |
58 | |
59 | static void assign(char_type&, const char_type&); |
60 | static bool eq(char_type, char_type); |
61 | static bool lt(char_type, char_type); |
62 | |
63 | static int compare(const char_type*, const char_type*, size_t); |
64 | static size_t length(const char_type*); |
65 | static const char_type* find(const char_type*, size_t, const char_type&); |
66 | static char_type* move(char_type*, const char_type*, size_t); |
67 | static char_type* copy(char_type*, const char_type*, size_t); |
68 | static char_type* assign(char_type*, size_t, char_type); |
69 | |
70 | static int_type not_eof(int_type); |
71 | static char_type to_char_type(int_type); |
72 | static int_type to_int_type(char_type); |
73 | static bool eq_int_type(int_type, int_type); |
74 | static int_type eof(); |
75 | }; |
76 | */ |
77 | |
78 | // char_traits<char> |
79 | |
80 | template <> |
81 | struct char_traits<char> { |
82 | using char_type = char; |
83 | using int_type = int; |
84 | using off_type = streamoff; |
85 | using pos_type = streampos; |
86 | using state_type = mbstate_t; |
87 | #if _LIBCPP_STD_VER >= 20 |
88 | using comparison_category = strong_ordering; |
89 | #endif |
90 | |
91 | static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 void |
92 | assign(char_type& __c1, const char_type& __c2) _NOEXCEPT { |
93 | __c1 = __c2; |
94 | } |
95 | |
96 | // TODO: Make this _LIBCPP_HIDE_FROM_ABI |
97 | static inline _LIBCPP_HIDDEN _LIBCPP_CONSTEXPR bool eq(char_type __c1, char_type __c2) _NOEXCEPT { |
98 | return __c1 == __c2; |
99 | } |
100 | static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool lt(char_type __c1, char_type __c2) _NOEXCEPT { |
101 | return (unsigned char)__c1 < (unsigned char)__c2; |
102 | } |
103 | |
104 | // __constexpr_memcmp requires a trivially lexicographically comparable type, but char is not when char is a signed |
105 | // type |
106 | static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 int |
107 | compare(const char_type* __lhs, const char_type* __rhs, size_t __count) _NOEXCEPT { |
108 | if (__libcpp_is_constant_evaluated()) { |
109 | #ifdef _LIBCPP_COMPILER_CLANG_BASED |
110 | return __builtin_memcmp(__lhs, __rhs, __count); |
111 | #else |
112 | while (__count != 0) { |
113 | if (lt(*__lhs, *__rhs)) |
114 | return -1; |
115 | if (lt(*__rhs, *__lhs)) |
116 | return 1; |
117 | |
118 | __count -= sizeof(char_type); |
119 | ++__lhs; |
120 | ++__rhs; |
121 | } |
122 | return 0; |
123 | #endif // _LIBCPP_COMPILER_CLANG_BASED |
124 | } else { |
125 | return __builtin_memcmp(__lhs, __rhs, __count); |
126 | } |
127 | } |
128 | |
129 | static inline _LIBCPP_HIDE_FROM_ABI size_t _LIBCPP_CONSTEXPR_SINCE_CXX17 length(const char_type* __s) _NOEXCEPT { |
130 | return std::__constexpr_strlen(str: __s); |
131 | } |
132 | |
133 | static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const char_type* |
134 | find(const char_type* __s, size_t __n, const char_type& __a) _NOEXCEPT { |
135 | return std::__constexpr_memchr(str: __s, value: __a, count: __n); |
136 | } |
137 | |
138 | static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 char_type* |
139 | move(char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT { |
140 | return std::__constexpr_memmove(dest: __s1, src: __s2, n: __element_count(__n)); |
141 | } |
142 | |
143 | static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 char_type* |
144 | copy(char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT { |
145 | _LIBCPP_ASSERT_NON_OVERLAPPING_RANGES(!std::__is_pointer_in_range(__s1, __s1 + __n, __s2), |
146 | "char_traits::copy: source and destination ranges overlap" ); |
147 | std::__constexpr_memmove(dest: __s1, src: __s2, n: __element_count(__n)); |
148 | return __s1; |
149 | } |
150 | |
151 | static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 char_type* |
152 | assign(char_type* __s, size_t __n, char_type __a) _NOEXCEPT { |
153 | std::fill_n(first: __s, __n, value: __a); |
154 | return __s; |
155 | } |
156 | |
157 | static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int_type not_eof(int_type __c) _NOEXCEPT { |
158 | return eq_int_type(c1: __c, c2: eof()) ? ~eof() : __c; |
159 | } |
160 | static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR char_type to_char_type(int_type __c) _NOEXCEPT { |
161 | return char_type(__c); |
162 | } |
163 | static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int_type to_int_type(char_type __c) _NOEXCEPT { |
164 | return int_type((unsigned char)__c); |
165 | } |
166 | static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool eq_int_type(int_type __c1, int_type __c2) _NOEXCEPT { |
167 | return __c1 == __c2; |
168 | } |
169 | static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int_type eof() _NOEXCEPT { return int_type(EOF); } |
170 | }; |
171 | |
172 | template <class _CharT, class _IntT, _IntT _EOFVal> |
173 | struct __char_traits_base { |
174 | using char_type = _CharT; |
175 | using int_type = _IntT; |
176 | using off_type = streamoff; |
177 | using state_type = mbstate_t; |
178 | #if _LIBCPP_STD_VER >= 20 |
179 | using comparison_category = strong_ordering; |
180 | #endif |
181 | |
182 | // There are different aliases for the different char types, but they are all aliases to this type |
183 | using pos_type = fpos<mbstate_t>; |
184 | |
185 | _LIBCPP_HIDE_FROM_ABI static inline _LIBCPP_CONSTEXPR_SINCE_CXX17 void |
186 | assign(char_type& __lhs, const char_type& __rhs) _NOEXCEPT { |
187 | __lhs = __rhs; |
188 | } |
189 | |
190 | _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR bool eq(char_type __lhs, char_type __rhs) _NOEXCEPT { |
191 | return __lhs == __rhs; |
192 | } |
193 | |
194 | _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR bool lt(char_type __lhs, char_type __rhs) _NOEXCEPT { |
195 | return __lhs < __rhs; |
196 | } |
197 | |
198 | _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX20 char_type* |
199 | move(char_type* __dest, const char_type* __src, size_t __n) _NOEXCEPT { |
200 | return std::__constexpr_memmove(__dest, __src, __element_count(__n)); |
201 | } |
202 | |
203 | _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX20 char_type* |
204 | copy(char_type* __dest, const char_type* __src, size_t __n) _NOEXCEPT { |
205 | _LIBCPP_ASSERT_NON_OVERLAPPING_RANGES(!std::__is_pointer_in_range(__dest, __dest + __n, __src), |
206 | "char_traits::copy: source and destination ranges overlap" ); |
207 | return std::__constexpr_memmove(__dest, __src, __element_count(__n)); |
208 | } |
209 | |
210 | _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX20 char_type* |
211 | assign(char_type* __str, size_t __n, char_type __fill_char) _NOEXCEPT { |
212 | std::fill_n(__str, __n, __fill_char); |
213 | return __str; |
214 | } |
215 | |
216 | _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR char_type to_char_type(int_type __c) _NOEXCEPT { |
217 | return char_type(__c); |
218 | } |
219 | |
220 | _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR int_type to_int_type(char_type __c) _NOEXCEPT { return int_type(__c); } |
221 | |
222 | _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR bool eq_int_type(int_type __lhs, int_type __rhs) _NOEXCEPT { |
223 | return __lhs == __rhs; |
224 | } |
225 | |
226 | _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR int_type eof() _NOEXCEPT { return _EOFVal; } |
227 | |
228 | _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR int_type not_eof(int_type __c) _NOEXCEPT { |
229 | return eq_int_type(lhs: __c, rhs: eof()) ? static_cast<int_type>(~eof()) : __c; |
230 | } |
231 | }; |
232 | |
233 | // char_traits<wchar_t> |
234 | |
235 | #if _LIBCPP_HAS_WIDE_CHARACTERS |
236 | template <> |
237 | struct char_traits<wchar_t> : __char_traits_base<wchar_t, wint_t, static_cast<wint_t>(WEOF)> { |
238 | static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 int |
239 | compare(const char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT { |
240 | if (__n == 0) |
241 | return 0; |
242 | return std::__constexpr_wmemcmp(lhs: __s1, rhs: __s2, count: __n); |
243 | } |
244 | |
245 | static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 size_t length(const char_type* __s) _NOEXCEPT { |
246 | return std::__constexpr_wcslen(str: __s); |
247 | } |
248 | |
249 | static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const char_type* |
250 | find(const char_type* __s, size_t __n, const char_type& __a) _NOEXCEPT { |
251 | return std::__constexpr_wmemchr(str: __s, value: __a, count: __n); |
252 | } |
253 | }; |
254 | #endif // _LIBCPP_HAS_WIDE_CHARACTERS |
255 | |
256 | #if _LIBCPP_HAS_CHAR8_T |
257 | |
258 | template <> |
259 | struct char_traits<char8_t> : __char_traits_base<char8_t, unsigned int, static_cast<unsigned int>(EOF)> { |
260 | static _LIBCPP_HIDE_FROM_ABI constexpr int |
261 | compare(const char_type* __s1, const char_type* __s2, size_t __n) noexcept { |
262 | return std::__constexpr_memcmp(lhs: __s1, rhs: __s2, n: __element_count(__n)); |
263 | } |
264 | |
265 | static _LIBCPP_HIDE_FROM_ABI constexpr size_t length(const char_type* __str) noexcept { |
266 | return std::__constexpr_strlen(__str); |
267 | } |
268 | |
269 | _LIBCPP_HIDE_FROM_ABI static constexpr const char_type* |
270 | find(const char_type* __s, size_t __n, const char_type& __a) noexcept { |
271 | return std::__constexpr_memchr(str: __s, value: __a, count: __n); |
272 | } |
273 | }; |
274 | |
275 | #endif // _LIBCPP_HAS_CHAR8_T |
276 | |
277 | template <> |
278 | struct char_traits<char16_t> : __char_traits_base<char16_t, uint_least16_t, static_cast<uint_least16_t>(0xFFFF)> { |
279 | _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX17 int |
280 | compare(const char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT; |
281 | _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX17 size_t length(const char_type* __s) _NOEXCEPT; |
282 | |
283 | _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX17 const char_type* |
284 | find(const char_type* __s, size_t __n, const char_type& __a) _NOEXCEPT { |
285 | __identity __proj; |
286 | const char_type* __match = std::__find(first: __s, last: __s + __n, value: __a, __proj); |
287 | if (__match == __s + __n) |
288 | return nullptr; |
289 | return __match; |
290 | } |
291 | }; |
292 | |
293 | inline _LIBCPP_CONSTEXPR_SINCE_CXX17 int |
294 | char_traits<char16_t>::compare(const char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT { |
295 | for (; __n; --__n, ++__s1, ++__s2) { |
296 | if (lt(lhs: *__s1, rhs: *__s2)) |
297 | return -1; |
298 | if (lt(lhs: *__s2, rhs: *__s1)) |
299 | return 1; |
300 | } |
301 | return 0; |
302 | } |
303 | |
304 | inline _LIBCPP_CONSTEXPR_SINCE_CXX17 size_t char_traits<char16_t>::length(const char_type* __s) _NOEXCEPT { |
305 | size_t __len = 0; |
306 | for (; !eq(lhs: *__s, rhs: char_type(0)); ++__s) |
307 | ++__len; |
308 | return __len; |
309 | } |
310 | |
311 | template <> |
312 | struct char_traits<char32_t> : __char_traits_base<char32_t, uint_least32_t, static_cast<uint_least32_t>(0xFFFFFFFF)> { |
313 | _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX17 int |
314 | compare(const char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT; |
315 | _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX17 size_t length(const char_type* __s) _NOEXCEPT; |
316 | |
317 | _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX17 const char_type* |
318 | find(const char_type* __s, size_t __n, const char_type& __a) _NOEXCEPT { |
319 | __identity __proj; |
320 | const char_type* __match = std::__find(first: __s, last: __s + __n, value: __a, __proj); |
321 | if (__match == __s + __n) |
322 | return nullptr; |
323 | return __match; |
324 | } |
325 | }; |
326 | |
327 | inline _LIBCPP_CONSTEXPR_SINCE_CXX17 int |
328 | char_traits<char32_t>::compare(const char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT { |
329 | for (; __n; --__n, ++__s1, ++__s2) { |
330 | if (lt(lhs: *__s1, rhs: *__s2)) |
331 | return -1; |
332 | if (lt(lhs: *__s2, rhs: *__s1)) |
333 | return 1; |
334 | } |
335 | return 0; |
336 | } |
337 | |
338 | inline _LIBCPP_CONSTEXPR_SINCE_CXX17 size_t char_traits<char32_t>::length(const char_type* __s) _NOEXCEPT { |
339 | size_t __len = 0; |
340 | for (; !eq(lhs: *__s, rhs: char_type(0)); ++__s) |
341 | ++__len; |
342 | return __len; |
343 | } |
344 | |
345 | // helper fns for basic_string and string_view |
346 | |
347 | // __str_find |
348 | template <class _CharT, class _SizeT, class _Traits, _SizeT __npos> |
349 | inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI |
350 | __str_find(const _CharT* __p, _SizeT __sz, _CharT __c, _SizeT __pos) _NOEXCEPT { |
351 | if (__pos > __sz) |
352 | return __npos; |
353 | const _CharT* __r = _Traits::find(__p + __pos, __sz - __pos, __c); |
354 | if (__r == nullptr) |
355 | return __npos; |
356 | return static_cast<_SizeT>(__r - __p); |
357 | } |
358 | |
359 | template <class _CharT, class _Traits> |
360 | _LIBCPP_HIDE_FROM_ABI inline _LIBCPP_CONSTEXPR_SINCE_CXX14 const _CharT* __search_substring( |
361 | const _CharT* __first1, const _CharT* __last1, const _CharT* __first2, const _CharT* __last2) _NOEXCEPT { |
362 | // Take advantage of knowing source and pattern lengths. |
363 | // Stop short when source is smaller than pattern. |
364 | const ptrdiff_t __len2 = __last2 - __first2; |
365 | if (__len2 == 0) |
366 | return __first1; |
367 | |
368 | ptrdiff_t __len1 = __last1 - __first1; |
369 | if (__len1 < __len2) |
370 | return __last1; |
371 | |
372 | // First element of __first2 is loop invariant. |
373 | _CharT __f2 = *__first2; |
374 | while (true) { |
375 | __len1 = __last1 - __first1; |
376 | // Check whether __first1 still has at least __len2 bytes. |
377 | if (__len1 < __len2) |
378 | return __last1; |
379 | |
380 | // Find __f2 the first byte matching in __first1. |
381 | __first1 = _Traits::find(__first1, __len1 - __len2 + 1, __f2); |
382 | if (__first1 == nullptr) |
383 | return __last1; |
384 | |
385 | // It is faster to compare from the first byte of __first1 even if we |
386 | // already know that it matches the first byte of __first2: this is because |
387 | // __first2 is most likely aligned, as it is user's "pattern" string, and |
388 | // __first1 + 1 is most likely not aligned, as the match is in the middle of |
389 | // the string. |
390 | if (_Traits::compare(__first1, __first2, __len2) == 0) |
391 | return __first1; |
392 | |
393 | ++__first1; |
394 | } |
395 | } |
396 | |
397 | template <class _CharT, class _SizeT, class _Traits, _SizeT __npos> |
398 | inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI |
399 | __str_find(const _CharT* __p, _SizeT __sz, const _CharT* __s, _SizeT __pos, _SizeT __n) _NOEXCEPT { |
400 | if (__pos > __sz) |
401 | return __npos; |
402 | |
403 | if (__n == 0) // There is nothing to search, just return __pos. |
404 | return __pos; |
405 | |
406 | const _CharT* __r = std::__search_substring<_CharT, _Traits>(__p + __pos, __p + __sz, __s, __s + __n); |
407 | |
408 | if (__r == __p + __sz) |
409 | return __npos; |
410 | return static_cast<_SizeT>(__r - __p); |
411 | } |
412 | |
413 | // __str_rfind |
414 | |
415 | template <class _CharT, class _SizeT, class _Traits, _SizeT __npos> |
416 | inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI |
417 | __str_rfind(const _CharT* __p, _SizeT __sz, _CharT __c, _SizeT __pos) _NOEXCEPT { |
418 | if (__sz < 1) |
419 | return __npos; |
420 | if (__pos < __sz) |
421 | ++__pos; |
422 | else |
423 | __pos = __sz; |
424 | for (const _CharT* __ps = __p + __pos; __ps != __p;) { |
425 | if (_Traits::eq(*--__ps, __c)) |
426 | return static_cast<_SizeT>(__ps - __p); |
427 | } |
428 | return __npos; |
429 | } |
430 | |
431 | template <class _CharT, class _SizeT, class _Traits, _SizeT __npos> |
432 | inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI |
433 | __str_rfind(const _CharT* __p, _SizeT __sz, const _CharT* __s, _SizeT __pos, _SizeT __n) _NOEXCEPT { |
434 | __pos = std::min(__pos, __sz); |
435 | if (__n < __sz - __pos) |
436 | __pos += __n; |
437 | else |
438 | __pos = __sz; |
439 | const _CharT* __r = std::__find_end_classic(__p, __p + __pos, __s, __s + __n, _Traits::eq); |
440 | if (__n > 0 && __r == __p + __pos) |
441 | return __npos; |
442 | return static_cast<_SizeT>(__r - __p); |
443 | } |
444 | |
445 | // __str_find_first_of |
446 | template <class _CharT, class _SizeT, class _Traits, _SizeT __npos> |
447 | inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI |
448 | __str_find_first_of(const _CharT* __p, _SizeT __sz, const _CharT* __s, _SizeT __pos, _SizeT __n) _NOEXCEPT { |
449 | if (__pos >= __sz || __n == 0) |
450 | return __npos; |
451 | const _CharT* __r = std::__find_first_of_ce(__p + __pos, __p + __sz, __s, __s + __n, _Traits::eq); |
452 | if (__r == __p + __sz) |
453 | return __npos; |
454 | return static_cast<_SizeT>(__r - __p); |
455 | } |
456 | |
457 | // __str_find_last_of |
458 | template <class _CharT, class _SizeT, class _Traits, _SizeT __npos> |
459 | inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI |
460 | __str_find_last_of(const _CharT* __p, _SizeT __sz, const _CharT* __s, _SizeT __pos, _SizeT __n) _NOEXCEPT { |
461 | if (__n != 0) { |
462 | if (__pos < __sz) |
463 | ++__pos; |
464 | else |
465 | __pos = __sz; |
466 | for (const _CharT* __ps = __p + __pos; __ps != __p;) { |
467 | const _CharT* __r = _Traits::find(__s, __n, *--__ps); |
468 | if (__r) |
469 | return static_cast<_SizeT>(__ps - __p); |
470 | } |
471 | } |
472 | return __npos; |
473 | } |
474 | |
475 | // __str_find_first_not_of |
476 | template <class _CharT, class _SizeT, class _Traits, _SizeT __npos> |
477 | inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI |
478 | __str_find_first_not_of(const _CharT* __p, _SizeT __sz, const _CharT* __s, _SizeT __pos, _SizeT __n) _NOEXCEPT { |
479 | if (__pos < __sz) { |
480 | const _CharT* __pe = __p + __sz; |
481 | for (const _CharT* __ps = __p + __pos; __ps != __pe; ++__ps) |
482 | if (_Traits::find(__s, __n, *__ps) == nullptr) |
483 | return static_cast<_SizeT>(__ps - __p); |
484 | } |
485 | return __npos; |
486 | } |
487 | |
488 | template <class _CharT, class _SizeT, class _Traits, _SizeT __npos> |
489 | inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI |
490 | __str_find_first_not_of(const _CharT* __p, _SizeT __sz, _CharT __c, _SizeT __pos) _NOEXCEPT { |
491 | if (__pos < __sz) { |
492 | const _CharT* __pe = __p + __sz; |
493 | for (const _CharT* __ps = __p + __pos; __ps != __pe; ++__ps) |
494 | if (!_Traits::eq(*__ps, __c)) |
495 | return static_cast<_SizeT>(__ps - __p); |
496 | } |
497 | return __npos; |
498 | } |
499 | |
500 | // __str_find_last_not_of |
501 | template <class _CharT, class _SizeT, class _Traits, _SizeT __npos> |
502 | inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI |
503 | __str_find_last_not_of(const _CharT* __p, _SizeT __sz, const _CharT* __s, _SizeT __pos, _SizeT __n) _NOEXCEPT { |
504 | if (__pos < __sz) |
505 | ++__pos; |
506 | else |
507 | __pos = __sz; |
508 | for (const _CharT* __ps = __p + __pos; __ps != __p;) |
509 | if (_Traits::find(__s, __n, *--__ps) == nullptr) |
510 | return static_cast<_SizeT>(__ps - __p); |
511 | return __npos; |
512 | } |
513 | |
514 | template <class _CharT, class _SizeT, class _Traits, _SizeT __npos> |
515 | inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI |
516 | __str_find_last_not_of(const _CharT* __p, _SizeT __sz, _CharT __c, _SizeT __pos) _NOEXCEPT { |
517 | if (__pos < __sz) |
518 | ++__pos; |
519 | else |
520 | __pos = __sz; |
521 | for (const _CharT* __ps = __p + __pos; __ps != __p;) |
522 | if (!_Traits::eq(*--__ps, __c)) |
523 | return static_cast<_SizeT>(__ps - __p); |
524 | return __npos; |
525 | } |
526 | |
527 | template <class _Ptr> |
528 | inline _LIBCPP_HIDE_FROM_ABI size_t __do_string_hash(_Ptr __p, _Ptr __e) { |
529 | typedef typename iterator_traits<_Ptr>::value_type value_type; |
530 | return std::__hash_memory(__p, (__e - __p) * sizeof(value_type)); |
531 | } |
532 | |
533 | _LIBCPP_END_NAMESPACE_STD |
534 | |
535 | _LIBCPP_POP_MACROS |
536 | |
537 | #endif // _LIBCPP___STRING_CHAR_TRAITS_H |
538 | |