master
  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(__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(__s, __a, __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(__s1, __s2, __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(__s1, __s2, __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(__s, __n, __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(__c, 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(__c, 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(__s1, __s2, __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(__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(__s, __a, __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(__s1, __s2, __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(__s, __a, __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(__s, __s + __n, __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(*__s1, *__s2))
297      return -1;
298    if (lt(*__s2, *__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(*__s, 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(__s, __s + __n, __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(*__s1, *__s2))
331      return -1;
332    if (lt(*__s2, *__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(*__s, 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