Line data Source code
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 749 : void assign(char_type& __c1, const char_type& __c2) _NOEXCEPT {__c1 = __c2;}
208 111678 : static inline _LIBCPP_CONSTEXPR bool eq(char_type __c1, char_type __c2) _NOEXCEPT
209 111678 : {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 13597 : static _LIBCPP_CONSTEXPR_SINCE_CXX17 int compare(const char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
214 13597 : if (__n == 0)
215 10 : return 0;
216 13587 : return std::__constexpr_memcmp(__s1, __s2, __n);
217 13597 : }
218 :
219 23365 : static inline size_t _LIBCPP_CONSTEXPR_SINCE_CXX17 length(const char_type* __s) _NOEXCEPT {
220 23365 : return std::__constexpr_strlen(__s);
221 0 : }
222 :
223 : static _LIBCPP_CONSTEXPR_SINCE_CXX17
224 24207 : const char_type* find(const char_type* __s, size_t __n, const char_type& __a) _NOEXCEPT {
225 24207 : if (__n == 0)
226 0 : return nullptr;
227 24207 : return std::__constexpr_char_memchr(__s, static_cast<int>(__a), __n);
228 24207 : }
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 37593 : static inline _LIBCPP_CONSTEXPR char_type to_char_type(int_type __c) _NOEXCEPT
252 37593 : {return char_type(__c);}
253 37582 : static inline _LIBCPP_CONSTEXPR int_type to_int_type(char_type __c) _NOEXCEPT
254 37582 : {return int_type((unsigned char)__c);}
255 37718 : static inline _LIBCPP_CONSTEXPR bool eq_int_type(int_type __c1, int_type __c2) _NOEXCEPT
256 37718 : {return __c1 == __c2;}
257 37721 : static inline _LIBCPP_CONSTEXPR int_type eof() _NOEXCEPT
258 37721 : {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 13945 : __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 13945 : const ptrdiff_t __len2 = __last2 - __first2;
631 13945 : if (__len2 == 0)
632 0 : return __first1;
633 :
634 13945 : ptrdiff_t __len1 = __last1 - __first1;
635 13945 : if (__len1 < __len2)
636 686 : return __last1;
637 :
638 : // First element of __first2 is loop invariant.
639 13259 : _CharT __f2 = *__first2;
640 13263 : while (true) {
641 13263 : __len1 = __last1 - __first1;
642 : // Check whether __first1 still has at least __len2 bytes.
643 13263 : if (__len1 < __len2)
644 1 : return __last1;
645 :
646 : // Find __f2 the first byte matching in __first1.
647 13262 : __first1 = _Traits::find(__first1, __len1 - __len2 + 1, __f2);
648 13262 : if (__first1 == nullptr)
649 13208 : 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 54 : if (_Traits::compare(__first1, __first2, __len2) == 0)
657 50 : return __first1;
658 :
659 4 : ++__first1;
660 : }
661 13945 : }
662 :
663 : template<class _CharT, class _SizeT, class _Traits, _SizeT __npos>
664 : inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_INLINE_VISIBILITY
665 13945 : __str_find(const _CharT *__p, _SizeT __sz,
666 : const _CharT* __s, _SizeT __pos, _SizeT __n) _NOEXCEPT
667 : {
668 13945 : if (__pos > __sz)
669 0 : return __npos;
670 :
671 13945 : if (__n == 0) // There is nothing to search, just return __pos.
672 0 : return __pos;
673 :
674 13945 : const _CharT *__r = std::__search_substring<_CharT, _Traits>(
675 13945 : __p + __pos, __p + __sz, __s, __s + __n);
676 :
677 13945 : if (__r == __p + __sz)
678 13895 : return __npos;
679 50 : return static_cast<_SizeT>(__r - __p);
680 13945 : }
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 12296 : __str_find_first_of(const _CharT *__p, _SizeT __sz,
724 : const _CharT* __s, _SizeT __pos, _SizeT __n) _NOEXCEPT
725 : {
726 12296 : if (__pos >= __sz || __n == 0)
727 1 : return __npos;
728 12295 : const _CharT* __r = _VSTD::__find_first_of_ce
729 12295 : (__p + __pos, __p + __sz, __s, __s + __n, _Traits::eq );
730 12295 : if (__r == __p + __sz)
731 5255 : return __npos;
732 7040 : return static_cast<_SizeT>(__r - __p);
733 12296 : }
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 3209 : __str_find_first_not_of(const _CharT *__p, _SizeT __sz,
763 : const _CharT* __s, _SizeT __pos, _SizeT __n) _NOEXCEPT
764 : {
765 3209 : if (__pos < __sz)
766 : {
767 3208 : const _CharT* __pe = __p + __sz;
768 10197 : for (const _CharT* __ps = __p + __pos; __ps != __pe; ++__ps)
769 10197 : if (_Traits::find(__s, __n, *__ps) == nullptr)
770 3208 : return static_cast<_SizeT>(__ps - __p);
771 0 : }
772 1 : return __npos;
773 3209 : }
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 749 : __str_find_last_not_of(const _CharT *__p, _SizeT __sz,
796 : const _CharT* __s, _SizeT __pos, _SizeT __n) _NOEXCEPT
797 : {
798 749 : if (__pos < __sz)
799 0 : ++__pos;
800 : else
801 749 : __pos = __sz;
802 749 : for (const _CharT* __ps = __p + __pos; __ps != __p;)
803 748 : if (_Traits::find(__s, __n, *--__ps) == nullptr)
804 748 : return static_cast<_SizeT>(__ps - __p);
805 1 : return __npos;
806 749 : }
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
|