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