xref: /freebsd/contrib/llvm-project/libcxx/include/__string/char_traits.h (revision e63d20b70ee1dbee9b075f29de6f30cdcfe1abe1)
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/copy_n.h>
13 #include <__algorithm/fill_n.h>
14 #include <__algorithm/find_end.h>
15 #include <__algorithm/find_first_of.h>
16 #include <__algorithm/min.h>
17 #include <__compare/ordering.h>
18 #include <__config>
19 #include <__functional/hash.h>
20 #include <__iterator/iterator_traits.h>
21 #include <__string/constexpr_c_functions.h>
22 #include <__type_traits/is_constant_evaluated.h>
23 #include <__utility/is_pointer_in_range.h>
24 #include <cstddef>
25 #include <cstdint>
26 #include <cstdio>
27 #include <iosfwd>
28 
29 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
30 #  include <cwchar> // for wmemcpy
31 #endif
32 
33 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
34 #  pragma GCC system_header
35 #endif
36 
37 _LIBCPP_PUSH_MACROS
38 #include <__undef_macros>
39 
40 _LIBCPP_BEGIN_NAMESPACE_STD
41 
42 template <class _CharT>
43 struct char_traits;
44 /*
45 The Standard does not define the base template for char_traits because it is impossible to provide
46 a correct definition for arbitrary character types. Instead, it requires implementations to provide
47 specializations for predefined character types like `char`, `wchar_t` and others. We provide this as
48 exposition-only to document what members a char_traits specialization should provide:
49 {
50     using char_type  = _CharT;
51     using int_type   = ...;
52     using off_type   = ...;
53     using pos_type   = ...;
54     using state_type = ...;
55 
56     static void assign(char_type&, const char_type&);
57     static bool eq(char_type, char_type);
58     static bool lt(char_type, char_type);
59 
60     static int              compare(const char_type*, const char_type*, size_t);
61     static size_t           length(const char_type*);
62     static const char_type* find(const char_type*, size_t, const char_type&);
63     static char_type*       move(char_type*, const char_type*, size_t);
64     static char_type*       copy(char_type*, const char_type*, size_t);
65     static char_type*       assign(char_type*, size_t, char_type);
66 
67     static int_type  not_eof(int_type);
68     static char_type to_char_type(int_type);
69     static int_type  to_int_type(char_type);
70     static bool      eq_int_type(int_type, int_type);
71     static int_type  eof();
72 };
73 */
74 
75 //
76 // Temporary extension to provide a base template for std::char_traits.
77 // TODO(LLVM-19): Remove this class.
78 //
79 #if !defined(_LIBCPP_CHAR_TRAITS_REMOVE_BASE_SPECIALIZATION)
80 template <class _CharT>
81 struct _LIBCPP_DEPRECATED_(
82     "char_traits<T> for T not equal to char, wchar_t, char8_t, char16_t or char32_t is non-standard and is provided "
83     "for a temporary period. It will be removed in LLVM 19, so please migrate off of it.") char_traits {
84   using char_type  = _CharT;
85   using int_type   = int;
86   using off_type   = streamoff;
87   using pos_type   = streampos;
88   using state_type = mbstate_t;
89 
90   static inline void _LIBCPP_CONSTEXPR_SINCE_CXX17 _LIBCPP_HIDE_FROM_ABI
91   assign(char_type& __c1, const char_type& __c2) _NOEXCEPT {
92     __c1 = __c2;
93   }
94   static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool eq(char_type __c1, char_type __c2) _NOEXCEPT {
95     return __c1 == __c2;
96   }
97   static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool lt(char_type __c1, char_type __c2) _NOEXCEPT {
98     return __c1 < __c2;
99   }
100 
101   static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 int
102   compare(const char_type* __s1, const char_type* __s2, size_t __n) {
103     for (; __n; --__n, ++__s1, ++__s2) {
104       if (lt(*__s1, *__s2))
105         return -1;
106       if (lt(*__s2, *__s1))
107         return 1;
108     }
109     return 0;
110   }
111   _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX17 size_t length(const char_type* __s) {
112     size_t __len = 0;
113     for (; !eq(*__s, char_type(0)); ++__s)
114       ++__len;
115     return __len;
116   }
117   _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX17 const char_type*
118   find(const char_type* __s, size_t __n, const char_type& __a) {
119     for (; __n; --__n) {
120       if (eq(*__s, __a))
121         return __s;
122       ++__s;
123     }
124     return nullptr;
125   }
126   static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 char_type*
127   move(char_type* __s1, const char_type* __s2, size_t __n) {
128     if (__n == 0)
129       return __s1;
130     char_type* __r = __s1;
131     if (__s1 < __s2) {
132       for (; __n; --__n, ++__s1, ++__s2)
133         assign(*__s1, *__s2);
134     } else if (__s2 < __s1) {
135       __s1 += __n;
136       __s2 += __n;
137       for (; __n; --__n)
138         assign(*--__s1, *--__s2);
139     }
140     return __r;
141   }
142   _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX20 char_type*
143   copy(char_type* __s1, const char_type* __s2, size_t __n) {
144     _LIBCPP_ASSERT_NON_OVERLAPPING_RANGES(!std::__is_pointer_in_range(__s1, __s1 + __n, __s2),
145                                           "char_traits::copy: source and destination ranges overlap");
146     char_type* __r = __s1;
147     for (; __n; --__n, ++__s1, ++__s2)
148       assign(*__s1, *__s2);
149     return __r;
150   }
151   _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX20 char_type*
152   assign(char_type* __s, size_t __n, char_type __a) {
153     char_type* __r = __s;
154     for (; __n; --__n, ++__s)
155       assign(*__s, __a);
156     return __r;
157   }
158 
159   static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int_type not_eof(int_type __c) _NOEXCEPT {
160     return eq_int_type(__c, eof()) ? ~eof() : __c;
161   }
162   static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR char_type to_char_type(int_type __c) _NOEXCEPT {
163     return char_type(__c);
164   }
165   static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int_type to_int_type(char_type __c) _NOEXCEPT {
166     return int_type(__c);
167   }
168   static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool eq_int_type(int_type __c1, int_type __c2) _NOEXCEPT {
169     return __c1 == __c2;
170   }
171   static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int_type eof() _NOEXCEPT { return int_type(EOF); }
172 };
173 #endif // !defined(_LIBCPP_CHAR_TRAITS_REMOVE_BASE_SPECIALIZATION)
174 
175 // char_traits<char>
176 
177 template <>
178 struct _LIBCPP_TEMPLATE_VIS char_traits<char> {
179   using char_type  = char;
180   using int_type   = int;
181   using off_type   = streamoff;
182   using pos_type   = streampos;
183   using state_type = mbstate_t;
184 #if _LIBCPP_STD_VER >= 20
185   using comparison_category = strong_ordering;
186 #endif
187 
188   static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 void
189   assign(char_type& __c1, const char_type& __c2) _NOEXCEPT {
190     __c1 = __c2;
191   }
192 
193   // TODO: Make this _LIBCPP_HIDE_FROM_ABI
194   static inline _LIBCPP_HIDDEN _LIBCPP_CONSTEXPR bool eq(char_type __c1, char_type __c2) _NOEXCEPT {
195     return __c1 == __c2;
196   }
197   static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool lt(char_type __c1, char_type __c2) _NOEXCEPT {
198     return (unsigned char)__c1 < (unsigned char)__c2;
199   }
200 
201   // __constexpr_memcmp requires a trivially lexicographically comparable type, but char is not when char is a signed
202   // type
203   static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 int
204   compare(const char_type* __lhs, const char_type* __rhs, size_t __count) _NOEXCEPT {
205     if (__libcpp_is_constant_evaluated()) {
206 #ifdef _LIBCPP_COMPILER_CLANG_BASED
207       return __builtin_memcmp(__lhs, __rhs, __count);
208 #else
209       while (__count != 0) {
210         if (lt(*__lhs, *__rhs))
211           return -1;
212         if (lt(*__rhs, *__lhs))
213           return 1;
214 
215         __count -= sizeof(char_type);
216         ++__lhs;
217         ++__rhs;
218       }
219       return 0;
220 #endif // _LIBCPP_COMPILER_CLANG_BASED
221     } else {
222       return __builtin_memcmp(__lhs, __rhs, __count);
223     }
224   }
225 
226   static inline _LIBCPP_HIDE_FROM_ABI size_t _LIBCPP_CONSTEXPR_SINCE_CXX17 length(const char_type* __s) _NOEXCEPT {
227     return std::__constexpr_strlen(__s);
228   }
229 
230   static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const char_type*
231   find(const char_type* __s, size_t __n, const char_type& __a) _NOEXCEPT {
232     if (__n == 0)
233       return nullptr;
234     return std::__constexpr_memchr(__s, __a, __n);
235   }
236 
237   static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 char_type*
238   move(char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
239     return std::__constexpr_memmove(__s1, __s2, __element_count(__n));
240   }
241 
242   static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 char_type*
243   copy(char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
244     _LIBCPP_ASSERT_NON_OVERLAPPING_RANGES(!std::__is_pointer_in_range(__s1, __s1 + __n, __s2),
245                                           "char_traits::copy: source and destination ranges overlap");
246     std::copy_n(__s2, __n, __s1);
247     return __s1;
248   }
249 
250   static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 char_type*
251   assign(char_type* __s, size_t __n, char_type __a) _NOEXCEPT {
252     std::fill_n(__s, __n, __a);
253     return __s;
254   }
255 
256   static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int_type not_eof(int_type __c) _NOEXCEPT {
257     return eq_int_type(__c, eof()) ? ~eof() : __c;
258   }
259   static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR char_type to_char_type(int_type __c) _NOEXCEPT {
260     return char_type(__c);
261   }
262   static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int_type to_int_type(char_type __c) _NOEXCEPT {
263     return int_type((unsigned char)__c);
264   }
265   static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool eq_int_type(int_type __c1, int_type __c2) _NOEXCEPT {
266     return __c1 == __c2;
267   }
268   static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int_type eof() _NOEXCEPT { return int_type(EOF); }
269 };
270 
271 // char_traits<wchar_t>
272 
273 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
274 template <>
275 struct _LIBCPP_TEMPLATE_VIS char_traits<wchar_t> {
276   using char_type  = wchar_t;
277   using int_type   = wint_t;
278   using off_type   = streamoff;
279   using pos_type   = streampos;
280   using state_type = mbstate_t;
281 #  if _LIBCPP_STD_VER >= 20
282   using comparison_category = strong_ordering;
283 #  endif
284 
285   static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 void
286   assign(char_type& __c1, const char_type& __c2) _NOEXCEPT {
287     __c1 = __c2;
288   }
289   static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool eq(char_type __c1, char_type __c2) _NOEXCEPT {
290     return __c1 == __c2;
291   }
292   static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool lt(char_type __c1, char_type __c2) _NOEXCEPT {
293     return __c1 < __c2;
294   }
295 
296   static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 int
297   compare(const char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
298     if (__n == 0)
299       return 0;
300     return std::__constexpr_wmemcmp(__s1, __s2, __n);
301   }
302 
303   static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 size_t length(const char_type* __s) _NOEXCEPT {
304     return std::__constexpr_wcslen(__s);
305   }
306 
307   static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const char_type*
308   find(const char_type* __s, size_t __n, const char_type& __a) _NOEXCEPT {
309     if (__n == 0)
310       return nullptr;
311     return std::__constexpr_wmemchr(__s, __a, __n);
312   }
313 
314   static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 char_type*
315   move(char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
316     return std::__constexpr_memmove(__s1, __s2, __element_count(__n));
317   }
318 
319   static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 char_type*
320   copy(char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
321     _LIBCPP_ASSERT_NON_OVERLAPPING_RANGES(!std::__is_pointer_in_range(__s1, __s1 + __n, __s2),
322                                           "char_traits::copy: source and destination ranges overlap");
323     std::copy_n(__s2, __n, __s1);
324     return __s1;
325   }
326 
327   static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 char_type*
328   assign(char_type* __s, size_t __n, char_type __a) _NOEXCEPT {
329     std::fill_n(__s, __n, __a);
330     return __s;
331   }
332 
333   static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int_type not_eof(int_type __c) _NOEXCEPT {
334     return eq_int_type(__c, eof()) ? ~eof() : __c;
335   }
336   static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR char_type to_char_type(int_type __c) _NOEXCEPT {
337     return char_type(__c);
338   }
339   static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int_type to_int_type(char_type __c) _NOEXCEPT {
340     return int_type(__c);
341   }
342   static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool eq_int_type(int_type __c1, int_type __c2) _NOEXCEPT {
343     return __c1 == __c2;
344   }
345   static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int_type eof() _NOEXCEPT { return int_type(WEOF); }
346 };
347 #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
348 
349 #ifndef _LIBCPP_HAS_NO_CHAR8_T
350 
351 template <>
352 struct _LIBCPP_TEMPLATE_VIS char_traits<char8_t> {
353   using char_type  = char8_t;
354   using int_type   = unsigned int;
355   using off_type   = streamoff;
356   using pos_type   = u8streampos;
357   using state_type = mbstate_t;
358 #  if _LIBCPP_STD_VER >= 20
359   using comparison_category = strong_ordering;
360 #  endif
361 
362   static inline _LIBCPP_HIDE_FROM_ABI constexpr void assign(char_type& __c1, const char_type& __c2) noexcept {
363     __c1 = __c2;
364   }
365   static inline _LIBCPP_HIDE_FROM_ABI constexpr bool eq(char_type __c1, char_type __c2) noexcept {
366     return __c1 == __c2;
367   }
368   static inline _LIBCPP_HIDE_FROM_ABI constexpr bool lt(char_type __c1, char_type __c2) noexcept { return __c1 < __c2; }
369 
370   static _LIBCPP_HIDE_FROM_ABI constexpr int
371   compare(const char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
372     return std::__constexpr_memcmp(__s1, __s2, __element_count(__n));
373   }
374 
375   static _LIBCPP_HIDE_FROM_ABI constexpr size_t length(const char_type* __s) _NOEXCEPT;
376 
377   _LIBCPP_HIDE_FROM_ABI static constexpr const char_type*
378   find(const char_type* __s, size_t __n, const char_type& __a) _NOEXCEPT;
379 
380   static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 char_type*
381   move(char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
382     return std::__constexpr_memmove(__s1, __s2, __element_count(__n));
383   }
384 
385   static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 char_type*
386   copy(char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
387     _LIBCPP_ASSERT_NON_OVERLAPPING_RANGES(!std::__is_pointer_in_range(__s1, __s1 + __n, __s2),
388                                           "char_traits::copy: source and destination ranges overlap");
389     std::copy_n(__s2, __n, __s1);
390     return __s1;
391   }
392 
393   static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 char_type*
394   assign(char_type* __s, size_t __n, char_type __a) _NOEXCEPT {
395     std::fill_n(__s, __n, __a);
396     return __s;
397   }
398 
399   static inline _LIBCPP_HIDE_FROM_ABI constexpr int_type not_eof(int_type __c) noexcept {
400     return eq_int_type(__c, eof()) ? ~eof() : __c;
401   }
402   static inline _LIBCPP_HIDE_FROM_ABI constexpr char_type to_char_type(int_type __c) noexcept { return char_type(__c); }
403   static inline _LIBCPP_HIDE_FROM_ABI constexpr int_type to_int_type(char_type __c) noexcept { return int_type(__c); }
404   static inline _LIBCPP_HIDE_FROM_ABI constexpr bool eq_int_type(int_type __c1, int_type __c2) noexcept {
405     return __c1 == __c2;
406   }
407   static inline _LIBCPP_HIDE_FROM_ABI constexpr int_type eof() noexcept { return int_type(EOF); }
408 };
409 
410 // TODO use '__builtin_strlen' if it ever supports char8_t ??
411 inline constexpr size_t char_traits<char8_t>::length(const char_type* __s) _NOEXCEPT {
412   size_t __len = 0;
413   for (; !eq(*__s, char_type(0)); ++__s)
414     ++__len;
415   return __len;
416 }
417 
418 // TODO use '__builtin_char_memchr' if it ever supports char8_t ??
419 inline constexpr const char8_t*
420 char_traits<char8_t>::find(const char_type* __s, size_t __n, const char_type& __a) _NOEXCEPT {
421   for (; __n; --__n) {
422     if (eq(*__s, __a))
423       return __s;
424     ++__s;
425   }
426   return nullptr;
427 }
428 
429 #endif // _LIBCPP_HAS_NO_CHAR8_T
430 
431 template <>
432 struct _LIBCPP_TEMPLATE_VIS char_traits<char16_t> {
433   using char_type  = char16_t;
434   using int_type   = uint_least16_t;
435   using off_type   = streamoff;
436   using pos_type   = u16streampos;
437   using state_type = mbstate_t;
438 #if _LIBCPP_STD_VER >= 20
439   using comparison_category = strong_ordering;
440 #endif
441 
442   static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 void
443   assign(char_type& __c1, const char_type& __c2) _NOEXCEPT {
444     __c1 = __c2;
445   }
446   static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool eq(char_type __c1, char_type __c2) _NOEXCEPT {
447     return __c1 == __c2;
448   }
449   static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool lt(char_type __c1, char_type __c2) _NOEXCEPT {
450     return __c1 < __c2;
451   }
452 
453   _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX17 int
454   compare(const char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT;
455   _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX17 size_t length(const char_type* __s) _NOEXCEPT;
456   _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX17 const char_type*
457   find(const char_type* __s, size_t __n, const char_type& __a) _NOEXCEPT;
458 
459   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static char_type*
460   move(char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
461     return std::__constexpr_memmove(__s1, __s2, __element_count(__n));
462   }
463 
464   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static char_type*
465   copy(char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
466     _LIBCPP_ASSERT_NON_OVERLAPPING_RANGES(!std::__is_pointer_in_range(__s1, __s1 + __n, __s2),
467                                           "char_traits::copy: source and destination ranges overlap");
468     std::copy_n(__s2, __n, __s1);
469     return __s1;
470   }
471 
472   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static char_type*
473   assign(char_type* __s, size_t __n, char_type __a) _NOEXCEPT {
474     std::fill_n(__s, __n, __a);
475     return __s;
476   }
477 
478   static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int_type not_eof(int_type __c) _NOEXCEPT {
479     return eq_int_type(__c, eof()) ? ~eof() : __c;
480   }
481   static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR char_type to_char_type(int_type __c) _NOEXCEPT {
482     return char_type(__c);
483   }
484   static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int_type to_int_type(char_type __c) _NOEXCEPT {
485     return int_type(__c);
486   }
487   static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool eq_int_type(int_type __c1, int_type __c2) _NOEXCEPT {
488     return __c1 == __c2;
489   }
490   static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int_type eof() _NOEXCEPT { return int_type(0xFFFF); }
491 };
492 
493 inline _LIBCPP_CONSTEXPR_SINCE_CXX17 int
494 char_traits<char16_t>::compare(const char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
495   for (; __n; --__n, ++__s1, ++__s2) {
496     if (lt(*__s1, *__s2))
497       return -1;
498     if (lt(*__s2, *__s1))
499       return 1;
500   }
501   return 0;
502 }
503 
504 inline _LIBCPP_CONSTEXPR_SINCE_CXX17 size_t char_traits<char16_t>::length(const char_type* __s) _NOEXCEPT {
505   size_t __len = 0;
506   for (; !eq(*__s, char_type(0)); ++__s)
507     ++__len;
508   return __len;
509 }
510 
511 inline _LIBCPP_CONSTEXPR_SINCE_CXX17 const char16_t*
512 char_traits<char16_t>::find(const char_type* __s, size_t __n, const char_type& __a) _NOEXCEPT {
513   for (; __n; --__n) {
514     if (eq(*__s, __a))
515       return __s;
516     ++__s;
517   }
518   return nullptr;
519 }
520 
521 template <>
522 struct _LIBCPP_TEMPLATE_VIS char_traits<char32_t> {
523   using char_type  = char32_t;
524   using int_type   = uint_least32_t;
525   using off_type   = streamoff;
526   using pos_type   = u32streampos;
527   using state_type = mbstate_t;
528 #if _LIBCPP_STD_VER >= 20
529   using comparison_category = strong_ordering;
530 #endif
531 
532   static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 void
533   assign(char_type& __c1, const char_type& __c2) _NOEXCEPT {
534     __c1 = __c2;
535   }
536   static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool eq(char_type __c1, char_type __c2) _NOEXCEPT {
537     return __c1 == __c2;
538   }
539   static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool lt(char_type __c1, char_type __c2) _NOEXCEPT {
540     return __c1 < __c2;
541   }
542 
543   _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX17 int
544   compare(const char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT;
545   _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX17 size_t length(const char_type* __s) _NOEXCEPT;
546   _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX17 const char_type*
547   find(const char_type* __s, size_t __n, const char_type& __a) _NOEXCEPT;
548 
549   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static char_type*
550   move(char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
551     return std::__constexpr_memmove(__s1, __s2, __element_count(__n));
552   }
553 
554   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static char_type*
555   copy(char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
556     std::copy_n(__s2, __n, __s1);
557     return __s1;
558   }
559 
560   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static char_type*
561   assign(char_type* __s, size_t __n, char_type __a) _NOEXCEPT {
562     std::fill_n(__s, __n, __a);
563     return __s;
564   }
565 
566   static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int_type not_eof(int_type __c) _NOEXCEPT {
567     return eq_int_type(__c, eof()) ? ~eof() : __c;
568   }
569   static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR char_type to_char_type(int_type __c) _NOEXCEPT {
570     return char_type(__c);
571   }
572   static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int_type to_int_type(char_type __c) _NOEXCEPT {
573     return int_type(__c);
574   }
575   static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool eq_int_type(int_type __c1, int_type __c2) _NOEXCEPT {
576     return __c1 == __c2;
577   }
578   static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int_type eof() _NOEXCEPT { return int_type(0xFFFFFFFF); }
579 };
580 
581 inline _LIBCPP_CONSTEXPR_SINCE_CXX17 int
582 char_traits<char32_t>::compare(const char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
583   for (; __n; --__n, ++__s1, ++__s2) {
584     if (lt(*__s1, *__s2))
585       return -1;
586     if (lt(*__s2, *__s1))
587       return 1;
588   }
589   return 0;
590 }
591 
592 inline _LIBCPP_CONSTEXPR_SINCE_CXX17 size_t char_traits<char32_t>::length(const char_type* __s) _NOEXCEPT {
593   size_t __len = 0;
594   for (; !eq(*__s, char_type(0)); ++__s)
595     ++__len;
596   return __len;
597 }
598 
599 inline _LIBCPP_CONSTEXPR_SINCE_CXX17 const char32_t*
600 char_traits<char32_t>::find(const char_type* __s, size_t __n, const char_type& __a) _NOEXCEPT {
601   for (; __n; --__n) {
602     if (eq(*__s, __a))
603       return __s;
604     ++__s;
605   }
606   return nullptr;
607 }
608 
609 // helper fns for basic_string and string_view
610 
611 // __str_find
612 template <class _CharT, class _SizeT, class _Traits, _SizeT __npos>
613 inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI
614 __str_find(const _CharT* __p, _SizeT __sz, _CharT __c, _SizeT __pos) _NOEXCEPT {
615   if (__pos >= __sz)
616     return __npos;
617   const _CharT* __r = _Traits::find(__p + __pos, __sz - __pos, __c);
618   if (__r == nullptr)
619     return __npos;
620   return static_cast<_SizeT>(__r - __p);
621 }
622 
623 template <class _CharT, class _Traits>
624 _LIBCPP_HIDE_FROM_ABI inline _LIBCPP_CONSTEXPR_SINCE_CXX14 const _CharT* __search_substring(
625     const _CharT* __first1, const _CharT* __last1, const _CharT* __first2, const _CharT* __last2) _NOEXCEPT {
626   // Take advantage of knowing source and pattern lengths.
627   // Stop short when source is smaller than pattern.
628   const ptrdiff_t __len2 = __last2 - __first2;
629   if (__len2 == 0)
630     return __first1;
631 
632   ptrdiff_t __len1 = __last1 - __first1;
633   if (__len1 < __len2)
634     return __last1;
635 
636   // First element of __first2 is loop invariant.
637   _CharT __f2 = *__first2;
638   while (true) {
639     __len1 = __last1 - __first1;
640     // Check whether __first1 still has at least __len2 bytes.
641     if (__len1 < __len2)
642       return __last1;
643 
644     // Find __f2 the first byte matching in __first1.
645     __first1 = _Traits::find(__first1, __len1 - __len2 + 1, __f2);
646     if (__first1 == nullptr)
647       return __last1;
648 
649     // It is faster to compare from the first byte of __first1 even if we
650     // already know that it matches the first byte of __first2: this is because
651     // __first2 is most likely aligned, as it is user's "pattern" string, and
652     // __first1 + 1 is most likely not aligned, as the match is in the middle of
653     // the string.
654     if (_Traits::compare(__first1, __first2, __len2) == 0)
655       return __first1;
656 
657     ++__first1;
658   }
659 }
660 
661 template <class _CharT, class _SizeT, class _Traits, _SizeT __npos>
662 inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI
663 __str_find(const _CharT* __p, _SizeT __sz, const _CharT* __s, _SizeT __pos, _SizeT __n) _NOEXCEPT {
664   if (__pos > __sz)
665     return __npos;
666 
667   if (__n == 0) // There is nothing to search, just return __pos.
668     return __pos;
669 
670   const _CharT* __r = std::__search_substring<_CharT, _Traits>(__p + __pos, __p + __sz, __s, __s + __n);
671 
672   if (__r == __p + __sz)
673     return __npos;
674   return static_cast<_SizeT>(__r - __p);
675 }
676 
677 // __str_rfind
678 
679 template <class _CharT, class _SizeT, class _Traits, _SizeT __npos>
680 inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI
681 __str_rfind(const _CharT* __p, _SizeT __sz, _CharT __c, _SizeT __pos) _NOEXCEPT {
682   if (__sz < 1)
683     return __npos;
684   if (__pos < __sz)
685     ++__pos;
686   else
687     __pos = __sz;
688   for (const _CharT* __ps = __p + __pos; __ps != __p;) {
689     if (_Traits::eq(*--__ps, __c))
690       return static_cast<_SizeT>(__ps - __p);
691   }
692   return __npos;
693 }
694 
695 template <class _CharT, class _SizeT, class _Traits, _SizeT __npos>
696 inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI
697 __str_rfind(const _CharT* __p, _SizeT __sz, const _CharT* __s, _SizeT __pos, _SizeT __n) _NOEXCEPT {
698   __pos = std::min(__pos, __sz);
699   if (__n < __sz - __pos)
700     __pos += __n;
701   else
702     __pos = __sz;
703   const _CharT* __r = std::__find_end_classic(__p, __p + __pos, __s, __s + __n, _Traits::eq);
704   if (__n > 0 && __r == __p + __pos)
705     return __npos;
706   return static_cast<_SizeT>(__r - __p);
707 }
708 
709 // __str_find_first_of
710 template <class _CharT, class _SizeT, class _Traits, _SizeT __npos>
711 inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI
712 __str_find_first_of(const _CharT* __p, _SizeT __sz, const _CharT* __s, _SizeT __pos, _SizeT __n) _NOEXCEPT {
713   if (__pos >= __sz || __n == 0)
714     return __npos;
715   const _CharT* __r = std::__find_first_of_ce(__p + __pos, __p + __sz, __s, __s + __n, _Traits::eq);
716   if (__r == __p + __sz)
717     return __npos;
718   return static_cast<_SizeT>(__r - __p);
719 }
720 
721 // __str_find_last_of
722 template <class _CharT, class _SizeT, class _Traits, _SizeT __npos>
723 inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI
724 __str_find_last_of(const _CharT* __p, _SizeT __sz, const _CharT* __s, _SizeT __pos, _SizeT __n) _NOEXCEPT {
725   if (__n != 0) {
726     if (__pos < __sz)
727       ++__pos;
728     else
729       __pos = __sz;
730     for (const _CharT* __ps = __p + __pos; __ps != __p;) {
731       const _CharT* __r = _Traits::find(__s, __n, *--__ps);
732       if (__r)
733         return static_cast<_SizeT>(__ps - __p);
734     }
735   }
736   return __npos;
737 }
738 
739 // __str_find_first_not_of
740 template <class _CharT, class _SizeT, class _Traits, _SizeT __npos>
741 inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI
742 __str_find_first_not_of(const _CharT* __p, _SizeT __sz, const _CharT* __s, _SizeT __pos, _SizeT __n) _NOEXCEPT {
743   if (__pos < __sz) {
744     const _CharT* __pe = __p + __sz;
745     for (const _CharT* __ps = __p + __pos; __ps != __pe; ++__ps)
746       if (_Traits::find(__s, __n, *__ps) == nullptr)
747         return static_cast<_SizeT>(__ps - __p);
748   }
749   return __npos;
750 }
751 
752 template <class _CharT, class _SizeT, class _Traits, _SizeT __npos>
753 inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI
754 __str_find_first_not_of(const _CharT* __p, _SizeT __sz, _CharT __c, _SizeT __pos) _NOEXCEPT {
755   if (__pos < __sz) {
756     const _CharT* __pe = __p + __sz;
757     for (const _CharT* __ps = __p + __pos; __ps != __pe; ++__ps)
758       if (!_Traits::eq(*__ps, __c))
759         return static_cast<_SizeT>(__ps - __p);
760   }
761   return __npos;
762 }
763 
764 // __str_find_last_not_of
765 template <class _CharT, class _SizeT, class _Traits, _SizeT __npos>
766 inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI
767 __str_find_last_not_of(const _CharT* __p, _SizeT __sz, const _CharT* __s, _SizeT __pos, _SizeT __n) _NOEXCEPT {
768   if (__pos < __sz)
769     ++__pos;
770   else
771     __pos = __sz;
772   for (const _CharT* __ps = __p + __pos; __ps != __p;)
773     if (_Traits::find(__s, __n, *--__ps) == nullptr)
774       return static_cast<_SizeT>(__ps - __p);
775   return __npos;
776 }
777 
778 template <class _CharT, class _SizeT, class _Traits, _SizeT __npos>
779 inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI
780 __str_find_last_not_of(const _CharT* __p, _SizeT __sz, _CharT __c, _SizeT __pos) _NOEXCEPT {
781   if (__pos < __sz)
782     ++__pos;
783   else
784     __pos = __sz;
785   for (const _CharT* __ps = __p + __pos; __ps != __p;)
786     if (!_Traits::eq(*--__ps, __c))
787       return static_cast<_SizeT>(__ps - __p);
788   return __npos;
789 }
790 
791 template <class _Ptr>
792 inline _LIBCPP_HIDE_FROM_ABI size_t __do_string_hash(_Ptr __p, _Ptr __e) {
793   typedef typename iterator_traits<_Ptr>::value_type value_type;
794   return __murmur2_or_cityhash<size_t>()(__p, (__e - __p) * sizeof(value_type));
795 }
796 
797 _LIBCPP_END_NAMESPACE_STD
798 
799 _LIBCPP_POP_MACROS
800 
801 #endif // _LIBCPP___STRING_CHAR_TRAITS_H
802