xref: /freebsd/contrib/llvm-project/libcxx/include/__string/char_traits.h (revision a18b956b73cee784e5c422d20fd0e4dabebd7eee)
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 <__type_traits/is_constant_evaluated.h>
22 #include <cstddef>
23 #include <cstdint>
24 #include <cstdio>
25 #include <cstring>
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: Remove in LLVM 18.
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
89         assign(char_type& __c1, const char_type& __c2) _NOEXCEPT {__c1 = __c2;}
90     static inline _LIBCPP_CONSTEXPR bool eq(char_type __c1, char_type __c2) _NOEXCEPT
91         {return __c1 == __c2;}
92     static inline _LIBCPP_CONSTEXPR bool lt(char_type __c1, char_type __c2) _NOEXCEPT
93         {return __c1 < __c2;}
94 
95     static _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_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(__s2 < __s1 || __s2 >= __s1+__n, "char_traits::copy overlapped range");
146         }
147         char_type* __r = __s1;
148         for (; __n; --__n, ++__s1, ++__s2)
149             assign(*__s1, *__s2);
150         return __r;
151     }
152     _LIBCPP_INLINE_VISIBILITY
153     static _LIBCPP_CONSTEXPR_SINCE_CXX20
154     char_type*       assign(char_type* __s, size_t __n, char_type __a) {
155         char_type* __r = __s;
156         for (; __n; --__n, ++__s)
157             assign(*__s, __a);
158         return __r;
159     }
160 
161     static inline _LIBCPP_CONSTEXPR int_type  not_eof(int_type __c) _NOEXCEPT
162         {return eq_int_type(__c, eof()) ? ~eof() : __c;}
163     static inline _LIBCPP_CONSTEXPR char_type to_char_type(int_type __c) _NOEXCEPT
164         {return char_type(__c);}
165     static inline _LIBCPP_CONSTEXPR int_type  to_int_type(char_type __c) _NOEXCEPT
166         {return int_type(__c);}
167     static inline _LIBCPP_CONSTEXPR bool      eq_int_type(int_type __c1, int_type __c2) _NOEXCEPT
168         {return __c1 == __c2;}
169     static inline _LIBCPP_CONSTEXPR int_type  eof() _NOEXCEPT
170         {return int_type(EOF);}
171 };
172 
173 template <class _CharT>
174 _LIBCPP_HIDE_FROM_ABI static inline _LIBCPP_CONSTEXPR_SINCE_CXX20
175 _CharT* __char_traits_move(_CharT* __dest, const _CharT* __source, size_t __n) _NOEXCEPT
176 {
177 #ifdef _LIBCPP_COMPILER_GCC
178   if (__libcpp_is_constant_evaluated()) {
179     if (__n == 0)
180       return __dest;
181     _CharT* __allocation = new _CharT[__n];
182     std::copy_n(__source, __n, __allocation);
183     std::copy_n(static_cast<const _CharT*>(__allocation), __n, __dest);
184     delete[] __allocation;
185     return __dest;
186   }
187 #endif
188   ::__builtin_memmove(__dest, __source, __n * sizeof(_CharT));
189   return __dest;
190 }
191 
192 // char_traits<char>
193 
194 template <>
195 struct _LIBCPP_TEMPLATE_VIS char_traits<char>
196 {
197     using char_type           = char;
198     using int_type            = int;
199     using off_type            = streamoff;
200     using pos_type            = streampos;
201     using state_type          = mbstate_t;
202 #if _LIBCPP_STD_VER > 17
203     using comparison_category = strong_ordering;
204 #endif
205 
206     static inline _LIBCPP_CONSTEXPR_SINCE_CXX17
207     void assign(char_type& __c1, const char_type& __c2) _NOEXCEPT {__c1 = __c2;}
208     static inline _LIBCPP_CONSTEXPR bool eq(char_type __c1, char_type __c2) _NOEXCEPT
209             {return __c1 == __c2;}
210     static inline _LIBCPP_CONSTEXPR bool lt(char_type __c1, char_type __c2) _NOEXCEPT
211         {return (unsigned char)__c1 < (unsigned char)__c2;}
212 
213   static _LIBCPP_CONSTEXPR_SINCE_CXX17 int compare(const char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
214     if (__n == 0)
215       return 0;
216     return std::__constexpr_memcmp(__s1, __s2, __n);
217   }
218 
219   static inline size_t _LIBCPP_CONSTEXPR_SINCE_CXX17 length(const char_type* __s)  _NOEXCEPT {
220     return std::__constexpr_strlen(__s);
221   }
222 
223   static _LIBCPP_CONSTEXPR_SINCE_CXX17
224   const char_type* find(const char_type* __s, size_t __n, const char_type& __a) _NOEXCEPT {
225     if (__n == 0)
226         return nullptr;
227     return std::__constexpr_char_memchr(__s, static_cast<int>(__a), __n);
228   }
229 
230     static inline _LIBCPP_CONSTEXPR_SINCE_CXX20
231     char_type* move(char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
232         return std::__char_traits_move(__s1, __s2, __n);
233     }
234 
235     static inline _LIBCPP_CONSTEXPR_SINCE_CXX20
236     char_type* copy(char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
237         if (!__libcpp_is_constant_evaluated())
238             _LIBCPP_ASSERT(__s2 < __s1 || __s2 >= __s1+__n, "char_traits::copy overlapped range");
239         std::copy_n(__s2, __n, __s1);
240         return __s1;
241     }
242 
243     static inline _LIBCPP_CONSTEXPR_SINCE_CXX20
244     char_type* assign(char_type* __s, size_t __n, char_type __a) _NOEXCEPT {
245         std::fill_n(__s, __n, __a);
246         return __s;
247     }
248 
249     static inline _LIBCPP_CONSTEXPR int_type  not_eof(int_type __c) _NOEXCEPT
250         {return eq_int_type(__c, eof()) ? ~eof() : __c;}
251     static inline _LIBCPP_CONSTEXPR char_type to_char_type(int_type __c) _NOEXCEPT
252         {return char_type(__c);}
253     static inline _LIBCPP_CONSTEXPR int_type to_int_type(char_type __c) _NOEXCEPT
254         {return int_type((unsigned char)__c);}
255     static inline _LIBCPP_CONSTEXPR bool eq_int_type(int_type __c1, int_type __c2) _NOEXCEPT
256         {return __c1 == __c2;}
257     static inline _LIBCPP_CONSTEXPR int_type  eof() _NOEXCEPT
258         {return int_type(EOF);}
259 };
260 
261 // char_traits<wchar_t>
262 
263 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
264 template <>
265 struct _LIBCPP_TEMPLATE_VIS char_traits<wchar_t>
266 {
267     using char_type           = wchar_t;
268     using int_type            = wint_t;
269     using off_type            = streamoff;
270     using pos_type            = streampos;
271     using state_type          = mbstate_t;
272 #if _LIBCPP_STD_VER > 17
273     using comparison_category = strong_ordering;
274 #endif
275 
276     static inline _LIBCPP_CONSTEXPR_SINCE_CXX17
277     void assign(char_type& __c1, const char_type& __c2) _NOEXCEPT {__c1 = __c2;}
278     static inline _LIBCPP_CONSTEXPR bool eq(char_type __c1, char_type __c2) _NOEXCEPT
279         {return __c1 == __c2;}
280     static inline _LIBCPP_CONSTEXPR bool lt(char_type __c1, char_type __c2) _NOEXCEPT
281         {return __c1 < __c2;}
282 
283   static _LIBCPP_CONSTEXPR_SINCE_CXX17 int compare(const char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
284     if (__n == 0)
285         return 0;
286     return std::__constexpr_wmemcmp(__s1, __s2, __n);
287   }
288 
289   static _LIBCPP_CONSTEXPR_SINCE_CXX17 size_t length(const char_type* __s) _NOEXCEPT {
290     return std::__constexpr_wcslen(__s);
291   }
292 
293   static _LIBCPP_CONSTEXPR_SINCE_CXX17
294   const char_type* find(const char_type* __s, size_t __n, const char_type& __a) _NOEXCEPT {
295     if (__n == 0)
296         return nullptr;
297     return std::__constexpr_wmemchr(__s, __a, __n);
298   }
299 
300     static inline _LIBCPP_CONSTEXPR_SINCE_CXX20
301     char_type* move(char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
302         return std::__char_traits_move(__s1, __s2, __n);
303     }
304 
305     static inline _LIBCPP_CONSTEXPR_SINCE_CXX20
306     char_type* copy(char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
307         if (!__libcpp_is_constant_evaluated())
308             _LIBCPP_ASSERT(__s2 < __s1 || __s2 >= __s1+__n, "char_traits::copy overlapped range");
309         std::copy_n(__s2, __n, __s1);
310         return __s1;
311     }
312 
313     static inline _LIBCPP_CONSTEXPR_SINCE_CXX20
314     char_type* assign(char_type* __s, size_t __n, char_type __a) _NOEXCEPT {
315         std::fill_n(__s, __n, __a);
316         return __s;
317     }
318 
319     static inline _LIBCPP_CONSTEXPR int_type  not_eof(int_type __c) _NOEXCEPT
320         {return eq_int_type(__c, eof()) ? ~eof() : __c;}
321     static inline _LIBCPP_CONSTEXPR char_type to_char_type(int_type __c) _NOEXCEPT
322         {return char_type(__c);}
323     static inline _LIBCPP_CONSTEXPR int_type to_int_type(char_type __c) _NOEXCEPT
324         {return int_type(__c);}
325     static inline _LIBCPP_CONSTEXPR bool eq_int_type(int_type __c1, int_type __c2) _NOEXCEPT
326         {return __c1 == __c2;}
327     static inline _LIBCPP_CONSTEXPR int_type eof() _NOEXCEPT
328         {return int_type(WEOF);}
329 };
330 #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
331 
332 #ifndef _LIBCPP_HAS_NO_CHAR8_T
333 
334 template <>
335 struct _LIBCPP_TEMPLATE_VIS char_traits<char8_t>
336 {
337     using char_type           = char8_t;
338     using int_type            = unsigned int;
339     using off_type            = streamoff;
340     using pos_type            = u8streampos;
341     using state_type          = mbstate_t;
342 #if _LIBCPP_STD_VER > 17
343     using comparison_category = strong_ordering;
344 #endif
345 
346     static inline constexpr void assign(char_type& __c1, const char_type& __c2) noexcept
347         {__c1 = __c2;}
348     static inline constexpr bool eq(char_type __c1, char_type __c2) noexcept
349         {return __c1 == __c2;}
350     static inline constexpr bool lt(char_type __c1, char_type __c2) noexcept
351         {return __c1 < __c2;}
352 
353   static _LIBCPP_HIDE_FROM_ABI constexpr int
354   compare(const char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
355       return std::__constexpr_memcmp(__s1, __s2, __n);
356   }
357 
358     static constexpr
359     size_t           length(const char_type* __s) _NOEXCEPT;
360 
361     _LIBCPP_INLINE_VISIBILITY static constexpr
362     const char_type* find(const char_type* __s, size_t __n, const char_type& __a) _NOEXCEPT;
363 
364     static _LIBCPP_CONSTEXPR_SINCE_CXX20
365     char_type*       move(char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
366         return std::__char_traits_move(__s1, __s2, __n);
367     }
368 
369     static _LIBCPP_CONSTEXPR_SINCE_CXX20
370     char_type*       copy(char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
371         if (!__libcpp_is_constant_evaluated())
372             _LIBCPP_ASSERT(__s2 < __s1 || __s2 >= __s1+__n, "char_traits::copy overlapped range");
373         std::copy_n(__s2, __n, __s1);
374         return __s1;
375     }
376 
377     static _LIBCPP_CONSTEXPR_SINCE_CXX20
378     char_type*       assign(char_type* __s, size_t __n, char_type __a) _NOEXCEPT {
379         std::fill_n(__s, __n, __a);
380         return __s;
381     }
382 
383     static inline constexpr int_type  not_eof(int_type __c) noexcept
384         {return eq_int_type(__c, eof()) ? ~eof() : __c;}
385     static inline constexpr char_type to_char_type(int_type __c) noexcept
386         {return char_type(__c);}
387     static inline constexpr int_type to_int_type(char_type __c) noexcept
388         {return int_type(__c);}
389     static inline constexpr bool eq_int_type(int_type __c1, int_type __c2) noexcept
390         {return __c1 == __c2;}
391     static inline constexpr int_type eof() noexcept
392         {return int_type(EOF);}
393 };
394 
395 // TODO use '__builtin_strlen' if it ever supports char8_t ??
396 inline constexpr
397 size_t
398 char_traits<char8_t>::length(const char_type* __s) _NOEXCEPT
399 {
400     size_t __len = 0;
401     for (; !eq(*__s, char_type(0)); ++__s)
402         ++__len;
403     return __len;
404 }
405 
406 // TODO use '__builtin_char_memchr' if it ever supports char8_t ??
407 inline constexpr
408 const char8_t*
409 char_traits<char8_t>::find(const char_type* __s, size_t __n, const char_type& __a) _NOEXCEPT
410 {
411     for (; __n; --__n)
412     {
413         if (eq(*__s, __a))
414             return __s;
415         ++__s;
416     }
417     return nullptr;
418 }
419 
420 #endif // _LIBCPP_HAS_NO_CHAR8_T
421 
422 template <>
423 struct _LIBCPP_TEMPLATE_VIS char_traits<char16_t>
424 {
425     using char_type           = char16_t;
426     using int_type            = uint_least16_t;
427     using off_type            = streamoff;
428     using pos_type            = u16streampos;
429     using state_type          = mbstate_t;
430 #if _LIBCPP_STD_VER > 17
431     using comparison_category = strong_ordering;
432 #endif
433 
434     static inline _LIBCPP_CONSTEXPR_SINCE_CXX17
435     void assign(char_type& __c1, const char_type& __c2) _NOEXCEPT {__c1 = __c2;}
436     static inline _LIBCPP_CONSTEXPR bool eq(char_type __c1, char_type __c2) _NOEXCEPT
437         {return __c1 == __c2;}
438     static inline _LIBCPP_CONSTEXPR bool lt(char_type __c1, char_type __c2) _NOEXCEPT
439         {return __c1 < __c2;}
440 
441     _LIBCPP_INLINE_VISIBILITY static _LIBCPP_CONSTEXPR_SINCE_CXX17
442     int              compare(const char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT;
443     _LIBCPP_INLINE_VISIBILITY static _LIBCPP_CONSTEXPR_SINCE_CXX17
444     size_t           length(const char_type* __s) _NOEXCEPT;
445     _LIBCPP_INLINE_VISIBILITY static _LIBCPP_CONSTEXPR_SINCE_CXX17
446     const char_type* find(const char_type* __s, size_t __n, const char_type& __a) _NOEXCEPT;
447 
448     _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20
449     static char_type*       move(char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
450         return std::__char_traits_move(__s1, __s2, __n);
451     }
452 
453     _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20
454     static char_type*       copy(char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
455         if (!__libcpp_is_constant_evaluated())
456             _LIBCPP_ASSERT(__s2 < __s1 || __s2 >= __s1+__n, "char_traits::copy overlapped range");
457         std::copy_n(__s2, __n, __s1);
458         return __s1;
459     }
460 
461     _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20
462     static char_type*       assign(char_type* __s, size_t __n, char_type __a) _NOEXCEPT {
463         std::fill_n(__s, __n, __a);
464         return __s;
465     }
466 
467     static inline _LIBCPP_CONSTEXPR int_type  not_eof(int_type __c) _NOEXCEPT
468         {return eq_int_type(__c, eof()) ? ~eof() : __c;}
469     static inline _LIBCPP_CONSTEXPR char_type to_char_type(int_type __c) _NOEXCEPT
470         {return char_type(__c);}
471     static inline _LIBCPP_CONSTEXPR int_type to_int_type(char_type __c) _NOEXCEPT
472         {return int_type(__c);}
473     static inline _LIBCPP_CONSTEXPR bool eq_int_type(int_type __c1, int_type __c2) _NOEXCEPT
474         {return __c1 == __c2;}
475     static inline _LIBCPP_CONSTEXPR int_type eof() _NOEXCEPT
476         {return int_type(0xFFFF);}
477 };
478 
479 inline _LIBCPP_CONSTEXPR_SINCE_CXX17
480 int
481 char_traits<char16_t>::compare(const char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT
482 {
483     for (; __n; --__n, ++__s1, ++__s2)
484     {
485         if (lt(*__s1, *__s2))
486             return -1;
487         if (lt(*__s2, *__s1))
488             return 1;
489     }
490     return 0;
491 }
492 
493 inline _LIBCPP_CONSTEXPR_SINCE_CXX17
494 size_t
495 char_traits<char16_t>::length(const char_type* __s) _NOEXCEPT
496 {
497     size_t __len = 0;
498     for (; !eq(*__s, char_type(0)); ++__s)
499         ++__len;
500     return __len;
501 }
502 
503 inline _LIBCPP_CONSTEXPR_SINCE_CXX17
504 const char16_t*
505 char_traits<char16_t>::find(const char_type* __s, size_t __n, const char_type& __a) _NOEXCEPT
506 {
507     for (; __n; --__n)
508     {
509         if (eq(*__s, __a))
510             return __s;
511         ++__s;
512     }
513     return nullptr;
514 }
515 
516 template <>
517 struct _LIBCPP_TEMPLATE_VIS char_traits<char32_t>
518 {
519     using char_type           = char32_t;
520     using int_type            = uint_least32_t;
521     using off_type            = streamoff;
522     using pos_type            = u32streampos;
523     using state_type          = mbstate_t;
524 #if _LIBCPP_STD_VER > 17
525     using comparison_category = strong_ordering;
526 #endif
527 
528     static inline _LIBCPP_CONSTEXPR_SINCE_CXX17
529     void assign(char_type& __c1, const char_type& __c2) _NOEXCEPT {__c1 = __c2;}
530     static inline _LIBCPP_CONSTEXPR bool eq(char_type __c1, char_type __c2) _NOEXCEPT
531         {return __c1 == __c2;}
532     static inline _LIBCPP_CONSTEXPR bool lt(char_type __c1, char_type __c2) _NOEXCEPT
533         {return __c1 < __c2;}
534 
535     _LIBCPP_INLINE_VISIBILITY static _LIBCPP_CONSTEXPR_SINCE_CXX17
536     int              compare(const char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT;
537     _LIBCPP_INLINE_VISIBILITY static _LIBCPP_CONSTEXPR_SINCE_CXX17
538     size_t           length(const char_type* __s) _NOEXCEPT;
539     _LIBCPP_INLINE_VISIBILITY static _LIBCPP_CONSTEXPR_SINCE_CXX17
540     const char_type* find(const char_type* __s, size_t __n, const char_type& __a) _NOEXCEPT;
541 
542     _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20
543     static char_type*       move(char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
544         return std::__char_traits_move(__s1, __s2, __n);
545     }
546 
547     _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20
548     static char_type*       copy(char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
549         std::copy_n(__s2, __n, __s1);
550         return __s1;
551     }
552 
553     _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20
554     static char_type*       assign(char_type* __s, size_t __n, char_type __a) _NOEXCEPT {
555         std::fill_n(__s, __n, __a);
556         return __s;
557     }
558 
559     static inline _LIBCPP_CONSTEXPR int_type  not_eof(int_type __c) _NOEXCEPT
560         {return eq_int_type(__c, eof()) ? ~eof() : __c;}
561     static inline _LIBCPP_CONSTEXPR char_type to_char_type(int_type __c) _NOEXCEPT
562         {return char_type(__c);}
563     static inline _LIBCPP_CONSTEXPR int_type to_int_type(char_type __c) _NOEXCEPT
564         {return int_type(__c);}
565     static inline _LIBCPP_CONSTEXPR bool eq_int_type(int_type __c1, int_type __c2) _NOEXCEPT
566         {return __c1 == __c2;}
567     static inline _LIBCPP_CONSTEXPR int_type eof() _NOEXCEPT
568         {return int_type(0xFFFFFFFF);}
569 };
570 
571 inline _LIBCPP_CONSTEXPR_SINCE_CXX17
572 int
573 char_traits<char32_t>::compare(const char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT
574 {
575     for (; __n; --__n, ++__s1, ++__s2)
576     {
577         if (lt(*__s1, *__s2))
578             return -1;
579         if (lt(*__s2, *__s1))
580             return 1;
581     }
582     return 0;
583 }
584 
585 inline _LIBCPP_CONSTEXPR_SINCE_CXX17
586 size_t
587 char_traits<char32_t>::length(const char_type* __s) _NOEXCEPT
588 {
589     size_t __len = 0;
590     for (; !eq(*__s, char_type(0)); ++__s)
591         ++__len;
592     return __len;
593 }
594 
595 inline _LIBCPP_CONSTEXPR_SINCE_CXX17
596 const char32_t*
597 char_traits<char32_t>::find(const char_type* __s, size_t __n, const char_type& __a) _NOEXCEPT
598 {
599     for (; __n; --__n)
600     {
601         if (eq(*__s, __a))
602             return __s;
603         ++__s;
604     }
605     return nullptr;
606 }
607 
608 // helper fns for basic_string and string_view
609 
610 // __str_find
611 template<class _CharT, class _SizeT, class _Traits, _SizeT __npos>
612 inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_INLINE_VISIBILITY
613 __str_find(const _CharT *__p, _SizeT __sz,
614              _CharT __c, _SizeT __pos) _NOEXCEPT
615 {
616     if (__pos >= __sz)
617         return __npos;
618     const _CharT* __r = _Traits::find(__p + __pos, __sz - __pos, __c);
619     if (__r == nullptr)
620         return __npos;
621     return static_cast<_SizeT>(__r - __p);
622 }
623 
624 template <class _CharT, class _Traits>
625 _LIBCPP_HIDE_FROM_ABI inline _LIBCPP_CONSTEXPR_SINCE_CXX14 const _CharT *
626 __search_substring(const _CharT *__first1, const _CharT *__last1,
627                    const _CharT *__first2, const _CharT *__last2) _NOEXCEPT {
628   // Take advantage of knowing source and pattern lengths.
629   // Stop short when source is smaller than pattern.
630   const ptrdiff_t __len2 = __last2 - __first2;
631   if (__len2 == 0)
632     return __first1;
633 
634   ptrdiff_t __len1 = __last1 - __first1;
635   if (__len1 < __len2)
636     return __last1;
637 
638   // First element of __first2 is loop invariant.
639   _CharT __f2 = *__first2;
640   while (true) {
641     __len1 = __last1 - __first1;
642     // Check whether __first1 still has at least __len2 bytes.
643     if (__len1 < __len2)
644       return __last1;
645 
646     // Find __f2 the first byte matching in __first1.
647     __first1 = _Traits::find(__first1, __len1 - __len2 + 1, __f2);
648     if (__first1 == nullptr)
649       return __last1;
650 
651     // It is faster to compare from the first byte of __first1 even if we
652     // already know that it matches the first byte of __first2: this is because
653     // __first2 is most likely aligned, as it is user's "pattern" string, and
654     // __first1 + 1 is most likely not aligned, as the match is in the middle of
655     // the string.
656     if (_Traits::compare(__first1, __first2, __len2) == 0)
657       return __first1;
658 
659     ++__first1;
660   }
661 }
662 
663 template<class _CharT, class _SizeT, class _Traits, _SizeT __npos>
664 inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_INLINE_VISIBILITY
665 __str_find(const _CharT *__p, _SizeT __sz,
666        const _CharT* __s, _SizeT __pos, _SizeT __n) _NOEXCEPT
667 {
668     if (__pos > __sz)
669         return __npos;
670 
671     if (__n == 0) // There is nothing to search, just return __pos.
672         return __pos;
673 
674     const _CharT *__r = std::__search_substring<_CharT, _Traits>(
675         __p + __pos, __p + __sz, __s, __s + __n);
676 
677     if (__r == __p + __sz)
678         return __npos;
679     return static_cast<_SizeT>(__r - __p);
680 }
681 
682 
683 // __str_rfind
684 
685 template<class _CharT, class _SizeT, class _Traits, _SizeT __npos>
686 inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_INLINE_VISIBILITY
687 __str_rfind(const _CharT *__p, _SizeT __sz,
688               _CharT __c, _SizeT __pos) _NOEXCEPT
689 {
690     if (__sz < 1)
691         return __npos;
692     if (__pos < __sz)
693         ++__pos;
694     else
695         __pos = __sz;
696     for (const _CharT* __ps = __p + __pos; __ps != __p;)
697     {
698         if (_Traits::eq(*--__ps, __c))
699             return static_cast<_SizeT>(__ps - __p);
700     }
701     return __npos;
702 }
703 
704 template<class _CharT, class _SizeT, class _Traits, _SizeT __npos>
705 inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_INLINE_VISIBILITY
706 __str_rfind(const _CharT *__p, _SizeT __sz,
707         const _CharT* __s, _SizeT __pos, _SizeT __n) _NOEXCEPT
708 {
709     __pos = _VSTD::min(__pos, __sz);
710     if (__n < __sz - __pos)
711         __pos += __n;
712     else
713         __pos = __sz;
714     const _CharT* __r = std::__find_end_classic(__p, __p + __pos, __s, __s + __n, _Traits::eq);
715     if (__n > 0 && __r == __p + __pos)
716         return __npos;
717     return static_cast<_SizeT>(__r - __p);
718 }
719 
720 // __str_find_first_of
721 template<class _CharT, class _SizeT, class _Traits, _SizeT __npos>
722 inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_INLINE_VISIBILITY
723 __str_find_first_of(const _CharT *__p, _SizeT __sz,
724                 const _CharT* __s, _SizeT __pos, _SizeT __n) _NOEXCEPT
725 {
726     if (__pos >= __sz || __n == 0)
727         return __npos;
728     const _CharT* __r = _VSTD::__find_first_of_ce
729         (__p + __pos, __p + __sz, __s, __s + __n, _Traits::eq );
730     if (__r == __p + __sz)
731         return __npos;
732     return static_cast<_SizeT>(__r - __p);
733 }
734 
735 
736 // __str_find_last_of
737 template<class _CharT, class _SizeT, class _Traits, _SizeT __npos>
738 inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_INLINE_VISIBILITY
739 __str_find_last_of(const _CharT *__p, _SizeT __sz,
740                const _CharT* __s, _SizeT __pos, _SizeT __n) _NOEXCEPT
741     {
742     if (__n != 0)
743     {
744         if (__pos < __sz)
745             ++__pos;
746         else
747             __pos = __sz;
748         for (const _CharT* __ps = __p + __pos; __ps != __p;)
749         {
750             const _CharT* __r = _Traits::find(__s, __n, *--__ps);
751             if (__r)
752                 return static_cast<_SizeT>(__ps - __p);
753         }
754     }
755     return __npos;
756 }
757 
758 
759 // __str_find_first_not_of
760 template<class _CharT, class _SizeT, class _Traits, _SizeT __npos>
761 inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_INLINE_VISIBILITY
762 __str_find_first_not_of(const _CharT *__p, _SizeT __sz,
763                     const _CharT* __s, _SizeT __pos, _SizeT __n) _NOEXCEPT
764 {
765     if (__pos < __sz)
766     {
767         const _CharT* __pe = __p + __sz;
768         for (const _CharT* __ps = __p + __pos; __ps != __pe; ++__ps)
769             if (_Traits::find(__s, __n, *__ps) == nullptr)
770                 return static_cast<_SizeT>(__ps - __p);
771     }
772     return __npos;
773 }
774 
775 
776 template<class _CharT, class _SizeT, class _Traits, _SizeT __npos>
777 inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_INLINE_VISIBILITY
778 __str_find_first_not_of(const _CharT *__p, _SizeT __sz,
779                           _CharT __c, _SizeT __pos) _NOEXCEPT
780 {
781     if (__pos < __sz)
782     {
783         const _CharT* __pe = __p + __sz;
784         for (const _CharT* __ps = __p + __pos; __ps != __pe; ++__ps)
785             if (!_Traits::eq(*__ps, __c))
786                 return static_cast<_SizeT>(__ps - __p);
787     }
788     return __npos;
789 }
790 
791 
792 // __str_find_last_not_of
793 template<class _CharT, class _SizeT, class _Traits, _SizeT __npos>
794 inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_INLINE_VISIBILITY
795 __str_find_last_not_of(const _CharT *__p, _SizeT __sz,
796                    const _CharT* __s, _SizeT __pos, _SizeT __n) _NOEXCEPT
797 {
798     if (__pos < __sz)
799         ++__pos;
800     else
801         __pos = __sz;
802     for (const _CharT* __ps = __p + __pos; __ps != __p;)
803         if (_Traits::find(__s, __n, *--__ps) == nullptr)
804             return static_cast<_SizeT>(__ps - __p);
805     return __npos;
806 }
807 
808 
809 template<class _CharT, class _SizeT, class _Traits, _SizeT __npos>
810 inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_INLINE_VISIBILITY
811 __str_find_last_not_of(const _CharT *__p, _SizeT __sz,
812                          _CharT __c, _SizeT __pos) _NOEXCEPT
813 {
814     if (__pos < __sz)
815         ++__pos;
816     else
817         __pos = __sz;
818     for (const _CharT* __ps = __p + __pos; __ps != __p;)
819         if (!_Traits::eq(*--__ps, __c))
820             return static_cast<_SizeT>(__ps - __p);
821     return __npos;
822 }
823 
824 template<class _Ptr>
825 inline _LIBCPP_INLINE_VISIBILITY
826 size_t __do_string_hash(_Ptr __p, _Ptr __e)
827 {
828     typedef typename iterator_traits<_Ptr>::value_type value_type;
829     return __murmur2_or_cityhash<size_t>()(__p, (__e-__p)*sizeof(value_type));
830 }
831 
832 _LIBCPP_END_NAMESPACE_STD
833 
834 _LIBCPP_POP_MACROS
835 
836 #endif // _LIBCPP___STRING_CHAR_TRAITS_H
837