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