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
45template <class _CharT>
46struct char_traits;
47/*
48The Standard does not define the base template for char_traits because it is impossible to provide
49a correct definition for arbitrary character types. Instead, it requires implementations to provide
50specializations for predefined character types like `char`, `wchar_t` and others. We provide this as
51exposition-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
80template <>
81struct 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
172template <class _CharT, class _IntT, _IntT _EOFVal>
173struct __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
236template <>
237struct 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
258template <>
259struct 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
277template <>
278struct 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
293inline _LIBCPP_CONSTEXPR_SINCE_CXX17 int
294char_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
304inline _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
311template <>
312struct 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
327inline _LIBCPP_CONSTEXPR_SINCE_CXX17 int
328char_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
338inline _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
348template <class _CharT, class _SizeT, class _Traits, _SizeT __npos>
349inline _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
359template <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
397template <class _CharT, class _SizeT, class _Traits, _SizeT __npos>
398inline _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
415template <class _CharT, class _SizeT, class _Traits, _SizeT __npos>
416inline _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
431template <class _CharT, class _SizeT, class _Traits, _SizeT __npos>
432inline _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
446template <class _CharT, class _SizeT, class _Traits, _SizeT __npos>
447inline _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
458template <class _CharT, class _SizeT, class _Traits, _SizeT __npos>
459inline _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
476template <class _CharT, class _SizeT, class _Traits, _SizeT __npos>
477inline _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
488template <class _CharT, class _SizeT, class _Traits, _SizeT __npos>
489inline _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
501template <class _CharT, class _SizeT, class _Traits, _SizeT __npos>
502inline _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
514template <class _CharT, class _SizeT, class _Traits, _SizeT __npos>
515inline _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
527template <class _Ptr>
528inline _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