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 [[__nodiscard__]] static inline _LIBCPP_HIDDEN _LIBCPP_CONSTEXPR bool eq(char_type __c1, char_type __c2) _NOEXCEPT {
98 return __c1 == __c2;
99 }
100 [[__nodiscard__]] static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool
101 lt(char_type __c1, char_type __c2) _NOEXCEPT {
102 return (unsigned char)__c1 < (unsigned char)__c2;
103 }
104
105 // __constexpr_memcmp requires a trivially lexicographically comparable type, but char is not when char is a signed
106 // type
107 [[__nodiscard__]] static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 int
108 compare(const char_type* __lhs, const char_type* __rhs, size_t __count) _NOEXCEPT {
109 if (__libcpp_is_constant_evaluated()) {
110#ifdef _LIBCPP_COMPILER_CLANG_BASED
111 return __builtin_memcmp(__lhs, __rhs, __count);
112#else
113 while (__count != 0) {
114 if (lt(*__lhs, *__rhs))
115 return -1;
116 if (lt(*__rhs, *__lhs))
117 return 1;
118
119 __count -= sizeof(char_type);
120 ++__lhs;
121 ++__rhs;
122 }
123 return 0;
124#endif // _LIBCPP_COMPILER_CLANG_BASED
125 } else {
126 return __builtin_memcmp(__lhs, __rhs, __count);
127 }
128 }
129
130 [[__nodiscard__]] static inline _LIBCPP_HIDE_FROM_ABI size_t _LIBCPP_CONSTEXPR_SINCE_CXX17
131 length(const char_type* __s) _NOEXCEPT {
132 return std::__constexpr_strlen(str: __s);
133 }
134
135 [[__nodiscard__]] static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const char_type*
136 find(const char_type* __s, size_t __n, const char_type& __a) _NOEXCEPT {
137 return std::__constexpr_memchr(str: __s, value: __a, count: __n);
138 }
139
140 static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 char_type*
141 move(char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
142 return std::__constexpr_memmove(dest: __s1, src: __s2, n: __element_count(__n));
143 }
144
145 static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 char_type*
146 copy(char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
147 _LIBCPP_ASSERT_NON_OVERLAPPING_RANGES(!std::__is_pointer_in_range(__s1, __s1 + __n, __s2),
148 "char_traits::copy: source and destination ranges overlap");
149 std::__constexpr_memmove(dest: __s1, src: __s2, n: __element_count(__n));
150 return __s1;
151 }
152
153 static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 char_type*
154 assign(char_type* __s, size_t __n, char_type __a) _NOEXCEPT {
155 std::fill_n(first: __s, __n, value: __a);
156 return __s;
157 }
158
159 [[__nodiscard__]] static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int_type not_eof(int_type __c) _NOEXCEPT {
160 return eq_int_type(c1: __c, c2: eof()) ? ~eof() : __c;
161 }
162 [[__nodiscard__]] static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR char_type
163 to_char_type(int_type __c) _NOEXCEPT {
164 return char_type(__c);
165 }
166 [[__nodiscard__]] static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int_type
167 to_int_type(char_type __c) _NOEXCEPT {
168 return int_type((unsigned char)__c);
169 }
170 [[__nodiscard__]] static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool
171 eq_int_type(int_type __c1, int_type __c2) _NOEXCEPT {
172 return __c1 == __c2;
173 }
174 [[__nodiscard__]] static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int_type eof() _NOEXCEPT {
175 return int_type(EOF);
176 }
177};
178
179template <class _CharT, class _IntT, _IntT _EOFVal>
180struct __char_traits_base {
181 using char_type = _CharT;
182 using int_type = _IntT;
183 using off_type = streamoff;
184 using state_type = mbstate_t;
185#if _LIBCPP_STD_VER >= 20
186 using comparison_category = strong_ordering;
187#endif
188
189 // There are different aliases for the different char types, but they are all aliases to this type
190 using pos_type = fpos<mbstate_t>;
191
192 _LIBCPP_HIDE_FROM_ABI static inline _LIBCPP_CONSTEXPR_SINCE_CXX17 void
193 assign(char_type& __lhs, const char_type& __rhs) _NOEXCEPT {
194 __lhs = __rhs;
195 }
196
197 [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR bool eq(char_type __lhs, char_type __rhs) _NOEXCEPT {
198 return __lhs == __rhs;
199 }
200
201 [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR bool lt(char_type __lhs, char_type __rhs) _NOEXCEPT {
202 return __lhs < __rhs;
203 }
204
205 _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX20 char_type*
206 move(char_type* __dest, const char_type* __src, size_t __n) _NOEXCEPT {
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 copy(char_type* __dest, const char_type* __src, size_t __n) _NOEXCEPT {
212 _LIBCPP_ASSERT_NON_OVERLAPPING_RANGES(!std::__is_pointer_in_range(__dest, __dest + __n, __src),
213 "char_traits::copy: source and destination ranges overlap");
214 return std::__constexpr_memmove(__dest, __src, __element_count(__n));
215 }
216
217 _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX20 char_type*
218 assign(char_type* __str, size_t __n, char_type __fill_char) _NOEXCEPT {
219 std::fill_n(__str, __n, __fill_char);
220 return __str;
221 }
222
223 [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR char_type to_char_type(int_type __c) _NOEXCEPT {
224 return char_type(__c);
225 }
226
227 [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR int_type to_int_type(char_type __c) _NOEXCEPT {
228 return int_type(__c);
229 }
230
231 [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR bool
232 eq_int_type(int_type __lhs, int_type __rhs) _NOEXCEPT {
233 return __lhs == __rhs;
234 }
235
236 [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR int_type eof() _NOEXCEPT { return _EOFVal; }
237
238 [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR int_type not_eof(int_type __c) _NOEXCEPT {
239 return eq_int_type(lhs: __c, rhs: eof()) ? static_cast<int_type>(~eof()) : __c;
240 }
241};
242
243// char_traits<wchar_t>
244
245#if _LIBCPP_HAS_WIDE_CHARACTERS
246template <>
247struct char_traits<wchar_t> : __char_traits_base<wchar_t, wint_t, static_cast<wint_t>(WEOF)> {
248 [[__nodiscard__]] static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 int
249 compare(const char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
250 if (__n == 0)
251 return 0;
252 return std::__constexpr_wmemcmp(lhs: __s1, rhs: __s2, count: __n);
253 }
254
255 [[__nodiscard__]] static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 size_t
256 length(const char_type* __s) _NOEXCEPT {
257 return std::__constexpr_wcslen(str: __s);
258 }
259
260 [[__nodiscard__]] static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const char_type*
261 find(const char_type* __s, size_t __n, const char_type& __a) _NOEXCEPT {
262 return std::__constexpr_wmemchr(str: __s, value: __a, count: __n);
263 }
264};
265#endif // _LIBCPP_HAS_WIDE_CHARACTERS
266
267#if _LIBCPP_HAS_CHAR8_T
268
269template <>
270struct char_traits<char8_t> : __char_traits_base<char8_t, unsigned int, static_cast<unsigned int>(EOF)> {
271 [[nodiscard]] static _LIBCPP_HIDE_FROM_ABI constexpr int
272 compare(const char_type* __s1, const char_type* __s2, size_t __n) noexcept {
273 return std::__constexpr_memcmp(lhs: __s1, rhs: __s2, n: __element_count(__n));
274 }
275
276 [[nodiscard]] static _LIBCPP_HIDE_FROM_ABI constexpr size_t length(const char_type* __str) noexcept {
277 return std::__constexpr_strlen(__str);
278 }
279
280 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr const char_type*
281 find(const char_type* __s, size_t __n, const char_type& __a) noexcept {
282 return std::__constexpr_memchr(str: __s, value: __a, count: __n);
283 }
284};
285
286#endif // _LIBCPP_HAS_CHAR8_T
287
288template <>
289struct char_traits<char16_t> : __char_traits_base<char16_t, uint_least16_t, static_cast<uint_least16_t>(0xFFFF)> {
290 [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX17 int
291 compare(const char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT;
292 _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX17 size_t length(const char_type* __s) _NOEXCEPT;
293
294 [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX17 const char_type*
295 find(const char_type* __s, size_t __n, const char_type& __a) _NOEXCEPT {
296 __identity __proj;
297 const char_type* __match = std::__find(first: __s, last: __s + __n, value: __a, __proj);
298 if (__match == __s + __n)
299 return nullptr;
300 return __match;
301 }
302};
303
304[[__nodiscard__]] inline _LIBCPP_CONSTEXPR_SINCE_CXX17 int
305char_traits<char16_t>::compare(const char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
306 for (; __n; --__n, ++__s1, ++__s2) {
307 if (lt(lhs: *__s1, rhs: *__s2))
308 return -1;
309 if (lt(lhs: *__s2, rhs: *__s1))
310 return 1;
311 }
312 return 0;
313}
314
315[[__nodiscard__]] inline _LIBCPP_CONSTEXPR_SINCE_CXX17 size_t
316char_traits<char16_t>::length(const char_type* __s) _NOEXCEPT {
317 size_t __len = 0;
318 for (; !eq(lhs: *__s, rhs: char_type(0)); ++__s)
319 ++__len;
320 return __len;
321}
322
323template <>
324struct char_traits<char32_t> : __char_traits_base<char32_t, uint_least32_t, static_cast<uint_least32_t>(0xFFFFFFFF)> {
325 [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX17 int
326 compare(const char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT;
327 _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX17 size_t length(const char_type* __s) _NOEXCEPT;
328
329 [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX17 const char_type*
330 find(const char_type* __s, size_t __n, const char_type& __a) _NOEXCEPT {
331 __identity __proj;
332 const char_type* __match = std::__find(first: __s, last: __s + __n, value: __a, __proj);
333 if (__match == __s + __n)
334 return nullptr;
335 return __match;
336 }
337};
338
339[[__nodiscard__]] inline _LIBCPP_CONSTEXPR_SINCE_CXX17 int
340char_traits<char32_t>::compare(const char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
341 for (; __n; --__n, ++__s1, ++__s2) {
342 if (lt(lhs: *__s1, rhs: *__s2))
343 return -1;
344 if (lt(lhs: *__s2, rhs: *__s1))
345 return 1;
346 }
347 return 0;
348}
349
350[[__nodiscard__]] inline _LIBCPP_CONSTEXPR_SINCE_CXX17 size_t
351char_traits<char32_t>::length(const char_type* __s) _NOEXCEPT {
352 size_t __len = 0;
353 for (; !eq(lhs: *__s, rhs: char_type(0)); ++__s)
354 ++__len;
355 return __len;
356}
357
358// helper fns for basic_string and string_view
359
360// __str_find
361template <class _CharT, class _SizeT, class _Traits, _SizeT __npos>
362inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI
363__str_find(const _CharT* __p, _SizeT __sz, _CharT __c, _SizeT __pos) _NOEXCEPT {
364 if (__pos > __sz)
365 return __npos;
366 const _CharT* __r = _Traits::find(__p + __pos, __sz - __pos, __c);
367 if (__r == nullptr)
368 return __npos;
369 return static_cast<_SizeT>(__r - __p);
370}
371
372template <class _CharT, class _Traits>
373_LIBCPP_HIDE_FROM_ABI inline _LIBCPP_CONSTEXPR_SINCE_CXX14 const _CharT* __search_substring(
374 const _CharT* __first1, const _CharT* __last1, const _CharT* __first2, const _CharT* __last2) _NOEXCEPT {
375 // Take advantage of knowing source and pattern lengths.
376 // Stop short when source is smaller than pattern.
377 const ptrdiff_t __len2 = __last2 - __first2;
378 if (__len2 == 0)
379 return __first1;
380
381 ptrdiff_t __len1 = __last1 - __first1;
382 if (__len1 < __len2)
383 return __last1;
384
385 if (__builtin_constant_p(__len2 == 1) && __len2 == 1) {
386 auto __res = _Traits::find(__first1, __len1, *__first2);
387 if (__res == nullptr)
388 return __last1;
389 return __res;
390 }
391
392 // First element of __first2 is loop invariant.
393 _CharT __f2 = *__first2;
394 while (true) {
395 __len1 = __last1 - __first1;
396 // Check whether __first1 still has at least __len2 bytes.
397 if (__len1 < __len2)
398 return __last1;
399
400 // Find __f2 the first byte matching in __first1.
401 __first1 = _Traits::find(__first1, __len1 - __len2 + 1, __f2);
402 if (__first1 == nullptr)
403 return __last1;
404
405 // It is faster to compare from the first byte of __first1 even if we
406 // already know that it matches the first byte of __first2: this is because
407 // __first2 is most likely aligned, as it is user's "pattern" string, and
408 // __first1 + 1 is most likely not aligned, as the match is in the middle of
409 // the string.
410 if (_Traits::compare(__first1, __first2, __len2) == 0)
411 return __first1;
412
413 ++__first1;
414 }
415}
416
417template <class _CharT, class _SizeT, class _Traits, _SizeT __npos>
418inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI
419__str_find(const _CharT* __p, _SizeT __sz, const _CharT* __s, _SizeT __pos, _SizeT __n) _NOEXCEPT {
420 if (__pos > __sz)
421 return __npos;
422
423 if (__n == 0) // There is nothing to search, just return __pos.
424 return __pos;
425
426 const _CharT* __r = std::__search_substring<_CharT, _Traits>(__p + __pos, __p + __sz, __s, __s + __n);
427
428 if (__r == __p + __sz)
429 return __npos;
430 return static_cast<_SizeT>(__r - __p);
431}
432
433// __str_rfind
434
435template <class _CharT, class _SizeT, class _Traits, _SizeT __npos>
436inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI
437__str_rfind(const _CharT* __p, _SizeT __sz, _CharT __c, _SizeT __pos) _NOEXCEPT {
438 if (__sz < 1)
439 return __npos;
440 if (__pos < __sz)
441 ++__pos;
442 else
443 __pos = __sz;
444 for (const _CharT* __ps = __p + __pos; __ps != __p;) {
445 if (_Traits::eq(*--__ps, __c))
446 return static_cast<_SizeT>(__ps - __p);
447 }
448 return __npos;
449}
450
451template <class _CharT, class _SizeT, class _Traits, _SizeT __npos>
452inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI
453__str_rfind(const _CharT* __p, _SizeT __sz, const _CharT* __s, _SizeT __pos, _SizeT __n) _NOEXCEPT {
454 __pos = std::min(__pos, __sz);
455 if (__n < __sz - __pos)
456 __pos += __n;
457 else
458 __pos = __sz;
459 const _CharT* __r = std::__find_end_classic(__p, __p + __pos, __s, __s + __n, _Traits::eq);
460 if (__n > 0 && __r == __p + __pos)
461 return __npos;
462 return static_cast<_SizeT>(__r - __p);
463}
464
465// __str_find_first_of
466template <class _CharT, class _SizeT, class _Traits, _SizeT __npos>
467inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI
468__str_find_first_of(const _CharT* __p, _SizeT __sz, const _CharT* __s, _SizeT __pos, _SizeT __n) _NOEXCEPT {
469 if (__pos >= __sz || __n == 0)
470 return __npos;
471 const _CharT* __r = std::__find_first_of_ce(__p + __pos, __p + __sz, __s, __s + __n, _Traits::eq);
472 if (__r == __p + __sz)
473 return __npos;
474 return static_cast<_SizeT>(__r - __p);
475}
476
477// __str_find_last_of
478template <class _CharT, class _SizeT, class _Traits, _SizeT __npos>
479inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI
480__str_find_last_of(const _CharT* __p, _SizeT __sz, const _CharT* __s, _SizeT __pos, _SizeT __n) _NOEXCEPT {
481 if (__n != 0) {
482 if (__pos < __sz)
483 ++__pos;
484 else
485 __pos = __sz;
486 for (const _CharT* __ps = __p + __pos; __ps != __p;) {
487 const _CharT* __r = _Traits::find(__s, __n, *--__ps);
488 if (__r)
489 return static_cast<_SizeT>(__ps - __p);
490 }
491 }
492 return __npos;
493}
494
495// __str_find_first_not_of
496template <class _CharT, class _SizeT, class _Traits, _SizeT __npos>
497inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI
498__str_find_first_not_of(const _CharT* __p, _SizeT __sz, const _CharT* __s, _SizeT __pos, _SizeT __n) _NOEXCEPT {
499 if (__pos < __sz) {
500 const _CharT* __pe = __p + __sz;
501 for (const _CharT* __ps = __p + __pos; __ps != __pe; ++__ps)
502 if (_Traits::find(__s, __n, *__ps) == nullptr)
503 return static_cast<_SizeT>(__ps - __p);
504 }
505 return __npos;
506}
507
508template <class _CharT, class _SizeT, class _Traits, _SizeT __npos>
509inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI
510__str_find_first_not_of(const _CharT* __p, _SizeT __sz, _CharT __c, _SizeT __pos) _NOEXCEPT {
511 if (__pos < __sz) {
512 const _CharT* __pe = __p + __sz;
513 for (const _CharT* __ps = __p + __pos; __ps != __pe; ++__ps)
514 if (!_Traits::eq(*__ps, __c))
515 return static_cast<_SizeT>(__ps - __p);
516 }
517 return __npos;
518}
519
520// __str_find_last_not_of
521template <class _CharT, class _SizeT, class _Traits, _SizeT __npos>
522inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI
523__str_find_last_not_of(const _CharT* __p, _SizeT __sz, const _CharT* __s, _SizeT __pos, _SizeT __n) _NOEXCEPT {
524 if (__pos < __sz)
525 ++__pos;
526 else
527 __pos = __sz;
528 for (const _CharT* __ps = __p + __pos; __ps != __p;)
529 if (_Traits::find(__s, __n, *--__ps) == nullptr)
530 return static_cast<_SizeT>(__ps - __p);
531 return __npos;
532}
533
534template <class _CharT, class _SizeT, class _Traits, _SizeT __npos>
535inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI
536__str_find_last_not_of(const _CharT* __p, _SizeT __sz, _CharT __c, _SizeT __pos) _NOEXCEPT {
537 if (__pos < __sz)
538 ++__pos;
539 else
540 __pos = __sz;
541 for (const _CharT* __ps = __p + __pos; __ps != __p;)
542 if (!_Traits::eq(*--__ps, __c))
543 return static_cast<_SizeT>(__ps - __p);
544 return __npos;
545}
546
547template <class _Ptr>
548inline _LIBCPP_HIDE_FROM_ABI size_t __do_string_hash(_Ptr __p, _Ptr __e) {
549 typedef typename iterator_traits<_Ptr>::value_type value_type;
550 return std::__hash_memory(__p, (__e - __p) * sizeof(value_type));
551}
552
553_LIBCPP_END_NAMESPACE_STD
554
555_LIBCPP_POP_MACROS
556
557#endif // _LIBCPP___STRING_CHAR_TRAITS_H
558