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: 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 _LIBCPP_HIDE_FROM_ABI
assignchar_traits89 assign(char_type& __c1, const char_type& __c2) _NOEXCEPT {__c1 = __c2;}
eqchar_traits90 static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool eq(char_type __c1, char_type __c2) _NOEXCEPT
91 {return __c1 == __c2;}
ltchar_traits92 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
comparechar_traits96 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
lengthchar_traits107 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
findchar_traits114 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
movechar_traits124 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
copychar_traits143 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
assignchar_traits154 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
not_eofchar_traits161 static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int_type not_eof(int_type __c) _NOEXCEPT
162 {return eq_int_type(__c, eof()) ? ~eof() : __c;}
to_char_typechar_traits163 static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR char_type to_char_type(int_type __c) _NOEXCEPT
164 {return char_type(__c);}
to_int_typechar_traits165 static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int_type to_int_type(char_type __c) _NOEXCEPT
166 {return int_type(__c);}
eq_int_typechar_traits167 static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool eq_int_type(int_type __c1, int_type __c2) _NOEXCEPT
168 {return __c1 == __c2;}
eofchar_traits169 static inline _LIBCPP_HIDE_FROM_ABI _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
__char_traits_move(_CharT * __dest,const _CharT * __source,size_t __n)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 >= 20
203 using comparison_category = strong_ordering;
204 #endif
205
206 static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17
207 void assign(char_type& __c1, const char_type& __c2) _NOEXCEPT {__c1 = __c2;}
208
209 // TODO: Make this _LIBCPP_HIDE_FROM_ABI
210 static inline _LIBCPP_HIDDEN _LIBCPP_CONSTEXPR bool eq(char_type __c1, char_type __c2) _NOEXCEPT
211 {return __c1 == __c2;}
212 static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool lt(char_type __c1, char_type __c2) _NOEXCEPT
213 {return (unsigned char)__c1 < (unsigned char)__c2;}
214
215 static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 int
216 compare(const char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
217 if (__n == 0)
218 return 0;
219 return std::__constexpr_memcmp(__s1, __s2, __n);
220 }
221
222 static inline _LIBCPP_HIDE_FROM_ABI size_t _LIBCPP_CONSTEXPR_SINCE_CXX17 length(const char_type* __s) _NOEXCEPT {
223 return std::__constexpr_strlen(__s);
224 }
225
226 static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17
227 const char_type* find(const char_type* __s, size_t __n, const char_type& __a) _NOEXCEPT {
228 if (__n == 0)
229 return nullptr;
230 return std::__constexpr_char_memchr(__s, static_cast<int>(__a), __n);
231 }
232
233 static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
234 char_type* move(char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
235 return std::__char_traits_move(__s1, __s2, __n);
236 }
237
238 static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
239 char_type* copy(char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
240 if (!__libcpp_is_constant_evaluated())
241 _LIBCPP_ASSERT(__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::__char_traits_move(__s1, __s2, __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(__s2 < __s1 || __s2 >= __s1+__n, "char_traits::copy overlapped range");
313 std::copy_n(__s2, __n, __s1);
314 return __s1;
315 }
316
317 static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
318 char_type* assign(char_type* __s, size_t __n, char_type __a) _NOEXCEPT {
319 std::fill_n(__s, __n, __a);
320 return __s;
321 }
322
323 static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int_type not_eof(int_type __c) _NOEXCEPT
324 {return eq_int_type(__c, eof()) ? ~eof() : __c;}
325 static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR char_type to_char_type(int_type __c) _NOEXCEPT
326 {return char_type(__c);}
327 static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int_type to_int_type(char_type __c) _NOEXCEPT
328 {return int_type(__c);}
329 static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool eq_int_type(int_type __c1, int_type __c2) _NOEXCEPT
330 {return __c1 == __c2;}
331 static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int_type eof() _NOEXCEPT
332 {return int_type(WEOF);}
333 };
334 #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
335
336 #ifndef _LIBCPP_HAS_NO_CHAR8_T
337
338 template <>
339 struct _LIBCPP_TEMPLATE_VIS char_traits<char8_t>
340 {
341 using char_type = char8_t;
342 using int_type = unsigned int;
343 using off_type = streamoff;
344 using pos_type = u8streampos;
345 using state_type = mbstate_t;
346 #if _LIBCPP_STD_VER >= 20
347 using comparison_category = strong_ordering;
348 #endif
349
350 static inline _LIBCPP_HIDE_FROM_ABI constexpr void assign(char_type& __c1, const char_type& __c2) noexcept
351 {__c1 = __c2;}
352 static inline _LIBCPP_HIDE_FROM_ABI constexpr bool eq(char_type __c1, char_type __c2) noexcept
353 {return __c1 == __c2;}
354 static inline _LIBCPP_HIDE_FROM_ABI constexpr bool lt(char_type __c1, char_type __c2) noexcept
355 {return __c1 < __c2;}
356
357 static _LIBCPP_HIDE_FROM_ABI constexpr int
358 compare(const char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
359 return std::__constexpr_memcmp(__s1, __s2, __n);
360 }
361
362 static _LIBCPP_HIDE_FROM_ABI constexpr
363 size_t length(const char_type* __s) _NOEXCEPT;
364
365 _LIBCPP_INLINE_VISIBILITY static constexpr
366 const char_type* find(const char_type* __s, size_t __n, const char_type& __a) _NOEXCEPT;
367
368 static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
369 char_type* move(char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
370 return std::__char_traits_move(__s1, __s2, __n);
371 }
372
373 static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
374 char_type* copy(char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
375 if (!__libcpp_is_constant_evaluated())
376 _LIBCPP_ASSERT(__s2 < __s1 || __s2 >= __s1+__n, "char_traits::copy overlapped range");
377 std::copy_n(__s2, __n, __s1);
378 return __s1;
379 }
380
381 static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
382 char_type* assign(char_type* __s, size_t __n, char_type __a) _NOEXCEPT {
383 std::fill_n(__s, __n, __a);
384 return __s;
385 }
386
387 static inline _LIBCPP_HIDE_FROM_ABI constexpr int_type not_eof(int_type __c) noexcept
388 {return eq_int_type(__c, eof()) ? ~eof() : __c;}
389 static inline _LIBCPP_HIDE_FROM_ABI constexpr char_type to_char_type(int_type __c) noexcept
390 {return char_type(__c);}
391 static inline _LIBCPP_HIDE_FROM_ABI constexpr int_type to_int_type(char_type __c) noexcept
392 {return int_type(__c);}
393 static inline _LIBCPP_HIDE_FROM_ABI constexpr bool eq_int_type(int_type __c1, int_type __c2) noexcept
394 {return __c1 == __c2;}
395 static inline _LIBCPP_HIDE_FROM_ABI constexpr int_type eof() noexcept
396 {return int_type(EOF);}
397 };
398
399 // TODO use '__builtin_strlen' if it ever supports char8_t ??
400 inline constexpr
401 size_t
402 char_traits<char8_t>::length(const char_type* __s) _NOEXCEPT
403 {
404 size_t __len = 0;
405 for (; !eq(*__s, char_type(0)); ++__s)
406 ++__len;
407 return __len;
408 }
409
410 // TODO use '__builtin_char_memchr' if it ever supports char8_t ??
411 inline constexpr
412 const char8_t*
413 char_traits<char8_t>::find(const char_type* __s, size_t __n, const char_type& __a) _NOEXCEPT
414 {
415 for (; __n; --__n)
416 {
417 if (eq(*__s, __a))
418 return __s;
419 ++__s;
420 }
421 return nullptr;
422 }
423
424 #endif // _LIBCPP_HAS_NO_CHAR8_T
425
426 template <>
427 struct _LIBCPP_TEMPLATE_VIS char_traits<char16_t>
428 {
429 using char_type = char16_t;
430 using int_type = uint_least16_t;
431 using off_type = streamoff;
432 using pos_type = u16streampos;
433 using state_type = mbstate_t;
434 #if _LIBCPP_STD_VER >= 20
435 using comparison_category = strong_ordering;
436 #endif
437
438 static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17
439 void assign(char_type& __c1, const char_type& __c2) _NOEXCEPT {__c1 = __c2;}
440 static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool eq(char_type __c1, char_type __c2) _NOEXCEPT
441 {return __c1 == __c2;}
442 static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool lt(char_type __c1, char_type __c2) _NOEXCEPT
443 {return __c1 < __c2;}
444
445 _LIBCPP_INLINE_VISIBILITY static _LIBCPP_CONSTEXPR_SINCE_CXX17
446 int compare(const char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT;
447 _LIBCPP_INLINE_VISIBILITY static _LIBCPP_CONSTEXPR_SINCE_CXX17
448 size_t length(const char_type* __s) _NOEXCEPT;
449 _LIBCPP_INLINE_VISIBILITY static _LIBCPP_CONSTEXPR_SINCE_CXX17
450 const char_type* find(const char_type* __s, size_t __n, const char_type& __a) _NOEXCEPT;
451
452 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20
453 static char_type* move(char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
454 return std::__char_traits_move(__s1, __s2, __n);
455 }
456
457 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20
458 static char_type* copy(char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
459 if (!__libcpp_is_constant_evaluated())
460 _LIBCPP_ASSERT(__s2 < __s1 || __s2 >= __s1+__n, "char_traits::copy overlapped range");
461 std::copy_n(__s2, __n, __s1);
462 return __s1;
463 }
464
465 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20
466 static char_type* assign(char_type* __s, size_t __n, char_type __a) _NOEXCEPT {
467 std::fill_n(__s, __n, __a);
468 return __s;
469 }
470
471 static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int_type not_eof(int_type __c) _NOEXCEPT
472 {return eq_int_type(__c, eof()) ? ~eof() : __c;}
473 static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR char_type to_char_type(int_type __c) _NOEXCEPT
474 {return char_type(__c);}
475 static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int_type to_int_type(char_type __c) _NOEXCEPT
476 {return int_type(__c);}
477 static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool eq_int_type(int_type __c1, int_type __c2) _NOEXCEPT
478 {return __c1 == __c2;}
479 static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int_type eof() _NOEXCEPT
480 {return int_type(0xFFFF);}
481 };
482
483 inline _LIBCPP_CONSTEXPR_SINCE_CXX17
484 int
485 char_traits<char16_t>::compare(const char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT
486 {
487 for (; __n; --__n, ++__s1, ++__s2)
488 {
489 if (lt(*__s1, *__s2))
490 return -1;
491 if (lt(*__s2, *__s1))
492 return 1;
493 }
494 return 0;
495 }
496
497 inline _LIBCPP_CONSTEXPR_SINCE_CXX17
498 size_t
499 char_traits<char16_t>::length(const char_type* __s) _NOEXCEPT
500 {
501 size_t __len = 0;
502 for (; !eq(*__s, char_type(0)); ++__s)
503 ++__len;
504 return __len;
505 }
506
507 inline _LIBCPP_CONSTEXPR_SINCE_CXX17
508 const char16_t*
509 char_traits<char16_t>::find(const char_type* __s, size_t __n, const char_type& __a) _NOEXCEPT
510 {
511 for (; __n; --__n)
512 {
513 if (eq(*__s, __a))
514 return __s;
515 ++__s;
516 }
517 return nullptr;
518 }
519
520 template <>
521 struct _LIBCPP_TEMPLATE_VIS char_traits<char32_t>
522 {
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
533 void assign(char_type& __c1, const char_type& __c2) _NOEXCEPT {__c1 = __c2;}
534 static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool eq(char_type __c1, char_type __c2) _NOEXCEPT
535 {return __c1 == __c2;}
536 static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool lt(char_type __c1, char_type __c2) _NOEXCEPT
537 {return __c1 < __c2;}
538
539 _LIBCPP_INLINE_VISIBILITY static _LIBCPP_CONSTEXPR_SINCE_CXX17
540 int compare(const char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT;
541 _LIBCPP_INLINE_VISIBILITY static _LIBCPP_CONSTEXPR_SINCE_CXX17
542 size_t length(const char_type* __s) _NOEXCEPT;
543 _LIBCPP_INLINE_VISIBILITY static _LIBCPP_CONSTEXPR_SINCE_CXX17
544 const char_type* find(const char_type* __s, size_t __n, const char_type& __a) _NOEXCEPT;
545
546 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20
547 static char_type* move(char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
548 return std::__char_traits_move(__s1, __s2, __n);
549 }
550
551 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20
552 static char_type* copy(char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
553 std::copy_n(__s2, __n, __s1);
554 return __s1;
555 }
556
557 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20
558 static char_type* assign(char_type* __s, size_t __n, char_type __a) _NOEXCEPT {
559 std::fill_n(__s, __n, __a);
560 return __s;
561 }
562
563 static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int_type not_eof(int_type __c) _NOEXCEPT
564 {return eq_int_type(__c, eof()) ? ~eof() : __c;}
565 static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR char_type to_char_type(int_type __c) _NOEXCEPT
566 {return char_type(__c);}
567 static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int_type to_int_type(char_type __c) _NOEXCEPT
568 {return int_type(__c);}
569 static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool eq_int_type(int_type __c1, int_type __c2) _NOEXCEPT
570 {return __c1 == __c2;}
571 static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int_type eof() _NOEXCEPT
572 {return int_type(0xFFFFFFFF);}
573 };
574
575 inline _LIBCPP_CONSTEXPR_SINCE_CXX17
576 int
577 char_traits<char32_t>::compare(const char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT
578 {
579 for (; __n; --__n, ++__s1, ++__s2)
580 {
581 if (lt(*__s1, *__s2))
582 return -1;
583 if (lt(*__s2, *__s1))
584 return 1;
585 }
586 return 0;
587 }
588
589 inline _LIBCPP_CONSTEXPR_SINCE_CXX17
590 size_t
591 char_traits<char32_t>::length(const char_type* __s) _NOEXCEPT
592 {
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
600 const char32_t*
601 char_traits<char32_t>::find(const char_type* __s, size_t __n, const char_type& __a) _NOEXCEPT
602 {
603 for (; __n; --__n)
604 {
605 if (eq(*__s, __a))
606 return __s;
607 ++__s;
608 }
609 return nullptr;
610 }
611
612 // helper fns for basic_string and string_view
613
614 // __str_find
615 template<class _CharT, class _SizeT, class _Traits, _SizeT __npos>
616 inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_INLINE_VISIBILITY
617 __str_find(const _CharT *__p, _SizeT __sz,
618 _CharT __c, _SizeT __pos) _NOEXCEPT
619 {
620 if (__pos >= __sz)
621 return __npos;
622 const _CharT* __r = _Traits::find(__p + __pos, __sz - __pos, __c);
623 if (__r == nullptr)
624 return __npos;
625 return static_cast<_SizeT>(__r - __p);
626 }
627
628 template <class _CharT, class _Traits>
629 _LIBCPP_HIDE_FROM_ABI inline _LIBCPP_CONSTEXPR_SINCE_CXX14 const _CharT *
630 __search_substring(const _CharT *__first1, const _CharT *__last1,
631 const _CharT *__first2, const _CharT *__last2) _NOEXCEPT {
632 // Take advantage of knowing source and pattern lengths.
633 // Stop short when source is smaller than pattern.
634 const ptrdiff_t __len2 = __last2 - __first2;
635 if (__len2 == 0)
636 return __first1;
637
638 ptrdiff_t __len1 = __last1 - __first1;
639 if (__len1 < __len2)
640 return __last1;
641
642 // First element of __first2 is loop invariant.
643 _CharT __f2 = *__first2;
644 while (true) {
645 __len1 = __last1 - __first1;
646 // Check whether __first1 still has at least __len2 bytes.
647 if (__len1 < __len2)
648 return __last1;
649
650 // Find __f2 the first byte matching in __first1.
651 __first1 = _Traits::find(__first1, __len1 - __len2 + 1, __f2);
652 if (__first1 == nullptr)
653 return __last1;
654
655 // It is faster to compare from the first byte of __first1 even if we
656 // already know that it matches the first byte of __first2: this is because
657 // __first2 is most likely aligned, as it is user's "pattern" string, and
658 // __first1 + 1 is most likely not aligned, as the match is in the middle of
659 // the string.
660 if (_Traits::compare(__first1, __first2, __len2) == 0)
661 return __first1;
662
663 ++__first1;
664 }
665 }
666
667 template<class _CharT, class _SizeT, class _Traits, _SizeT __npos>
668 inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_INLINE_VISIBILITY
669 __str_find(const _CharT *__p, _SizeT __sz,
670 const _CharT* __s, _SizeT __pos, _SizeT __n) _NOEXCEPT
671 {
672 if (__pos > __sz)
673 return __npos;
674
675 if (__n == 0) // There is nothing to search, just return __pos.
676 return __pos;
677
678 const _CharT *__r = std::__search_substring<_CharT, _Traits>(
679 __p + __pos, __p + __sz, __s, __s + __n);
680
681 if (__r == __p + __sz)
682 return __npos;
683 return static_cast<_SizeT>(__r - __p);
684 }
685
686
687 // __str_rfind
688
689 template<class _CharT, class _SizeT, class _Traits, _SizeT __npos>
690 inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_INLINE_VISIBILITY
691 __str_rfind(const _CharT *__p, _SizeT __sz,
692 _CharT __c, _SizeT __pos) _NOEXCEPT
693 {
694 if (__sz < 1)
695 return __npos;
696 if (__pos < __sz)
697 ++__pos;
698 else
699 __pos = __sz;
700 for (const _CharT* __ps = __p + __pos; __ps != __p;)
701 {
702 if (_Traits::eq(*--__ps, __c))
703 return static_cast<_SizeT>(__ps - __p);
704 }
705 return __npos;
706 }
707
708 template<class _CharT, class _SizeT, class _Traits, _SizeT __npos>
709 inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_INLINE_VISIBILITY
710 __str_rfind(const _CharT *__p, _SizeT __sz,
711 const _CharT* __s, _SizeT __pos, _SizeT __n) _NOEXCEPT
712 {
713 __pos = _VSTD::min(__pos, __sz);
714 if (__n < __sz - __pos)
715 __pos += __n;
716 else
717 __pos = __sz;
718 const _CharT* __r = std::__find_end_classic(__p, __p + __pos, __s, __s + __n, _Traits::eq);
719 if (__n > 0 && __r == __p + __pos)
720 return __npos;
721 return static_cast<_SizeT>(__r - __p);
722 }
723
724 // __str_find_first_of
725 template<class _CharT, class _SizeT, class _Traits, _SizeT __npos>
726 inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_INLINE_VISIBILITY
727 __str_find_first_of(const _CharT *__p, _SizeT __sz,
728 const _CharT* __s, _SizeT __pos, _SizeT __n) _NOEXCEPT
729 {
730 if (__pos >= __sz || __n == 0)
731 return __npos;
732 const _CharT* __r = _VSTD::__find_first_of_ce
733 (__p + __pos, __p + __sz, __s, __s + __n, _Traits::eq );
734 if (__r == __p + __sz)
735 return __npos;
736 return static_cast<_SizeT>(__r - __p);
737 }
738
739
740 // __str_find_last_of
741 template<class _CharT, class _SizeT, class _Traits, _SizeT __npos>
742 inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_INLINE_VISIBILITY
743 __str_find_last_of(const _CharT *__p, _SizeT __sz,
744 const _CharT* __s, _SizeT __pos, _SizeT __n) _NOEXCEPT
745 {
746 if (__n != 0)
747 {
748 if (__pos < __sz)
749 ++__pos;
750 else
751 __pos = __sz;
752 for (const _CharT* __ps = __p + __pos; __ps != __p;)
753 {
754 const _CharT* __r = _Traits::find(__s, __n, *--__ps);
755 if (__r)
756 return static_cast<_SizeT>(__ps - __p);
757 }
758 }
759 return __npos;
760 }
761
762
763 // __str_find_first_not_of
764 template<class _CharT, class _SizeT, class _Traits, _SizeT __npos>
765 inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_INLINE_VISIBILITY
766 __str_find_first_not_of(const _CharT *__p, _SizeT __sz,
767 const _CharT* __s, _SizeT __pos, _SizeT __n) _NOEXCEPT
768 {
769 if (__pos < __sz)
770 {
771 const _CharT* __pe = __p + __sz;
772 for (const _CharT* __ps = __p + __pos; __ps != __pe; ++__ps)
773 if (_Traits::find(__s, __n, *__ps) == nullptr)
774 return static_cast<_SizeT>(__ps - __p);
775 }
776 return __npos;
777 }
778
779
780 template<class _CharT, class _SizeT, class _Traits, _SizeT __npos>
781 inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_INLINE_VISIBILITY
782 __str_find_first_not_of(const _CharT *__p, _SizeT __sz,
783 _CharT __c, _SizeT __pos) _NOEXCEPT
784 {
785 if (__pos < __sz)
786 {
787 const _CharT* __pe = __p + __sz;
788 for (const _CharT* __ps = __p + __pos; __ps != __pe; ++__ps)
789 if (!_Traits::eq(*__ps, __c))
790 return static_cast<_SizeT>(__ps - __p);
791 }
792 return __npos;
793 }
794
795
796 // __str_find_last_not_of
797 template<class _CharT, class _SizeT, class _Traits, _SizeT __npos>
798 inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_INLINE_VISIBILITY
799 __str_find_last_not_of(const _CharT *__p, _SizeT __sz,
800 const _CharT* __s, _SizeT __pos, _SizeT __n) _NOEXCEPT
801 {
802 if (__pos < __sz)
803 ++__pos;
804 else
805 __pos = __sz;
806 for (const _CharT* __ps = __p + __pos; __ps != __p;)
807 if (_Traits::find(__s, __n, *--__ps) == nullptr)
808 return static_cast<_SizeT>(__ps - __p);
809 return __npos;
810 }
811
812
813 template<class _CharT, class _SizeT, class _Traits, _SizeT __npos>
814 inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_INLINE_VISIBILITY
815 __str_find_last_not_of(const _CharT *__p, _SizeT __sz,
816 _CharT __c, _SizeT __pos) _NOEXCEPT
817 {
818 if (__pos < __sz)
819 ++__pos;
820 else
821 __pos = __sz;
822 for (const _CharT* __ps = __p + __pos; __ps != __p;)
823 if (!_Traits::eq(*--__ps, __c))
824 return static_cast<_SizeT>(__ps - __p);
825 return __npos;
826 }
827
828 template<class _Ptr>
829 inline _LIBCPP_INLINE_VISIBILITY
830 size_t __do_string_hash(_Ptr __p, _Ptr __e)
831 {
832 typedef typename iterator_traits<_Ptr>::value_type value_type;
833 return __murmur2_or_cityhash<size_t>()(__p, (__e-__p)*sizeof(value_type));
834 }
835
836 _LIBCPP_END_NAMESPACE_STD
837
838 _LIBCPP_POP_MACROS
839
840 #endif // _LIBCPP___STRING_CHAR_TRAITS_H
841