xref: /freebsd/contrib/llvm-project/libcxx/include/__string/char_traits.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
181ad6265SDimitry Andric //===----------------------------------------------------------------------===//
281ad6265SDimitry Andric //
381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
681ad6265SDimitry Andric //
781ad6265SDimitry Andric //===----------------------------------------------------------------------===//
881ad6265SDimitry Andric 
981ad6265SDimitry Andric #ifndef _LIBCPP___STRING_CHAR_TRAITS_H
1081ad6265SDimitry Andric #define _LIBCPP___STRING_CHAR_TRAITS_H
1181ad6265SDimitry Andric 
1281ad6265SDimitry Andric #include <__algorithm/fill_n.h>
13*0fca6ea1SDimitry Andric #include <__algorithm/find.h>
1481ad6265SDimitry Andric #include <__algorithm/find_end.h>
1581ad6265SDimitry Andric #include <__algorithm/find_first_of.h>
1681ad6265SDimitry Andric #include <__algorithm/min.h>
17*0fca6ea1SDimitry Andric #include <__assert>
18bdd1243dSDimitry Andric #include <__compare/ordering.h>
1981ad6265SDimitry Andric #include <__config>
2081ad6265SDimitry Andric #include <__functional/hash.h>
21*0fca6ea1SDimitry Andric #include <__functional/identity.h>
2281ad6265SDimitry Andric #include <__iterator/iterator_traits.h>
2306c3fb27SDimitry Andric #include <__string/constexpr_c_functions.h>
24bdd1243dSDimitry Andric #include <__type_traits/is_constant_evaluated.h>
255f757f3fSDimitry Andric #include <__utility/is_pointer_in_range.h>
26bdd1243dSDimitry Andric #include <cstddef>
2781ad6265SDimitry Andric #include <cstdint>
2881ad6265SDimitry Andric #include <cstdio>
2981ad6265SDimitry Andric #include <iosfwd>
3081ad6265SDimitry Andric 
3181ad6265SDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
3281ad6265SDimitry Andric #  include <cwchar> // for wmemcpy
3381ad6265SDimitry Andric #endif
3481ad6265SDimitry Andric 
3581ad6265SDimitry Andric #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
3681ad6265SDimitry Andric #  pragma GCC system_header
3781ad6265SDimitry Andric #endif
3881ad6265SDimitry Andric 
3981ad6265SDimitry Andric _LIBCPP_PUSH_MACROS
4081ad6265SDimitry Andric #include <__undef_macros>
4181ad6265SDimitry Andric 
4281ad6265SDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD
4381ad6265SDimitry Andric 
4481ad6265SDimitry Andric template <class _CharT>
45bdd1243dSDimitry Andric struct char_traits;
46bdd1243dSDimitry Andric /*
47bdd1243dSDimitry Andric The Standard does not define the base template for char_traits because it is impossible to provide
48bdd1243dSDimitry Andric a correct definition for arbitrary character types. Instead, it requires implementations to provide
49bdd1243dSDimitry Andric specializations for predefined character types like `char`, `wchar_t` and others. We provide this as
50bdd1243dSDimitry Andric exposition-only to document what members a char_traits specialization should provide:
5181ad6265SDimitry Andric {
52bdd1243dSDimitry Andric     using char_type  = _CharT;
53bdd1243dSDimitry Andric     using int_type   = ...;
54bdd1243dSDimitry Andric     using off_type   = ...;
55bdd1243dSDimitry Andric     using pos_type   = ...;
56bdd1243dSDimitry Andric     using state_type = ...;
5781ad6265SDimitry Andric 
58bdd1243dSDimitry Andric     static void assign(char_type&, const char_type&);
59bdd1243dSDimitry Andric     static bool eq(char_type, char_type);
60bdd1243dSDimitry Andric     static bool lt(char_type, char_type);
61bdd1243dSDimitry Andric 
62bdd1243dSDimitry Andric     static int              compare(const char_type*, const char_type*, size_t);
63bdd1243dSDimitry Andric     static size_t           length(const char_type*);
64bdd1243dSDimitry Andric     static const char_type* find(const char_type*, size_t, const char_type&);
65bdd1243dSDimitry Andric     static char_type*       move(char_type*, const char_type*, size_t);
66bdd1243dSDimitry Andric     static char_type*       copy(char_type*, const char_type*, size_t);
67bdd1243dSDimitry Andric     static char_type*       assign(char_type*, size_t, char_type);
68bdd1243dSDimitry Andric 
69bdd1243dSDimitry Andric     static int_type  not_eof(int_type);
70bdd1243dSDimitry Andric     static char_type to_char_type(int_type);
71bdd1243dSDimitry Andric     static int_type  to_int_type(char_type);
72bdd1243dSDimitry Andric     static bool      eq_int_type(int_type, int_type);
73bdd1243dSDimitry Andric     static int_type  eof();
74bdd1243dSDimitry Andric };
75bdd1243dSDimitry Andric */
76bdd1243dSDimitry Andric 
7781ad6265SDimitry Andric // char_traits<char>
7881ad6265SDimitry Andric 
7981ad6265SDimitry Andric template <>
80cb14a3feSDimitry Andric struct _LIBCPP_TEMPLATE_VIS char_traits<char> {
81bdd1243dSDimitry Andric   using char_type  = char;
82bdd1243dSDimitry Andric   using int_type   = int;
83bdd1243dSDimitry Andric   using off_type   = streamoff;
84bdd1243dSDimitry Andric   using pos_type   = streampos;
85bdd1243dSDimitry Andric   using state_type = mbstate_t;
8606c3fb27SDimitry Andric #if _LIBCPP_STD_VER >= 20
87bdd1243dSDimitry Andric   using comparison_category = strong_ordering;
88bdd1243dSDimitry Andric #endif
8981ad6265SDimitry Andric 
90cb14a3feSDimitry Andric   static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 void
91cb14a3feSDimitry Andric   assign(char_type& __c1, const char_type& __c2) _NOEXCEPT {
92cb14a3feSDimitry Andric     __c1 = __c2;
93cb14a3feSDimitry Andric   }
9406c3fb27SDimitry Andric 
9506c3fb27SDimitry Andric   // TODO: Make this _LIBCPP_HIDE_FROM_ABI
96cb14a3feSDimitry Andric   static inline _LIBCPP_HIDDEN _LIBCPP_CONSTEXPR bool eq(char_type __c1, char_type __c2) _NOEXCEPT {
97cb14a3feSDimitry Andric     return __c1 == __c2;
98cb14a3feSDimitry Andric   }
99cb14a3feSDimitry Andric   static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool lt(char_type __c1, char_type __c2) _NOEXCEPT {
100cb14a3feSDimitry Andric     return (unsigned char)__c1 < (unsigned char)__c2;
101cb14a3feSDimitry Andric   }
10281ad6265SDimitry Andric 
103cb14a3feSDimitry Andric   // __constexpr_memcmp requires a trivially lexicographically comparable type, but char is not when char is a signed
104cb14a3feSDimitry Andric   // type
10506c3fb27SDimitry Andric   static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 int
10606c3fb27SDimitry Andric   compare(const char_type* __lhs, const char_type* __rhs, size_t __count) _NOEXCEPT {
10706c3fb27SDimitry Andric     if (__libcpp_is_constant_evaluated()) {
10806c3fb27SDimitry Andric #ifdef _LIBCPP_COMPILER_CLANG_BASED
10906c3fb27SDimitry Andric       return __builtin_memcmp(__lhs, __rhs, __count);
11006c3fb27SDimitry Andric #else
11106c3fb27SDimitry Andric       while (__count != 0) {
11206c3fb27SDimitry Andric         if (lt(*__lhs, *__rhs))
11306c3fb27SDimitry Andric           return -1;
11406c3fb27SDimitry Andric         if (lt(*__rhs, *__lhs))
11506c3fb27SDimitry Andric           return 1;
11606c3fb27SDimitry Andric 
11706c3fb27SDimitry Andric         __count -= sizeof(char_type);
11806c3fb27SDimitry Andric         ++__lhs;
11906c3fb27SDimitry Andric         ++__rhs;
12006c3fb27SDimitry Andric       }
121bdd1243dSDimitry Andric       return 0;
12206c3fb27SDimitry Andric #endif // _LIBCPP_COMPILER_CLANG_BASED
12306c3fb27SDimitry Andric     } else {
12406c3fb27SDimitry Andric       return __builtin_memcmp(__lhs, __rhs, __count);
12506c3fb27SDimitry Andric     }
12681ad6265SDimitry Andric   }
12781ad6265SDimitry Andric 
12806c3fb27SDimitry Andric   static inline _LIBCPP_HIDE_FROM_ABI size_t _LIBCPP_CONSTEXPR_SINCE_CXX17 length(const char_type* __s) _NOEXCEPT {
129bdd1243dSDimitry Andric     return std::__constexpr_strlen(__s);
130bdd1243dSDimitry Andric   }
13181ad6265SDimitry Andric 
132cb14a3feSDimitry Andric   static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const char_type*
133cb14a3feSDimitry Andric   find(const char_type* __s, size_t __n, const char_type& __a) _NOEXCEPT {
134bdd1243dSDimitry Andric     if (__n == 0)
135bdd1243dSDimitry Andric       return nullptr;
13606c3fb27SDimitry Andric     return std::__constexpr_memchr(__s, __a, __n);
137bdd1243dSDimitry Andric   }
138bdd1243dSDimitry Andric 
139cb14a3feSDimitry Andric   static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 char_type*
140cb14a3feSDimitry Andric   move(char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
14106c3fb27SDimitry Andric     return std::__constexpr_memmove(__s1, __s2, __element_count(__n));
14281ad6265SDimitry Andric   }
14381ad6265SDimitry Andric 
144cb14a3feSDimitry Andric   static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 char_type*
145cb14a3feSDimitry Andric   copy(char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
1465f757f3fSDimitry Andric     _LIBCPP_ASSERT_NON_OVERLAPPING_RANGES(!std::__is_pointer_in_range(__s1, __s1 + __n, __s2),
1475f757f3fSDimitry Andric                                           "char_traits::copy: source and destination ranges overlap");
148*0fca6ea1SDimitry Andric     std::__constexpr_memmove(__s1, __s2, __element_count(__n));
14981ad6265SDimitry Andric     return __s1;
15081ad6265SDimitry Andric   }
15181ad6265SDimitry Andric 
152cb14a3feSDimitry Andric   static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 char_type*
153cb14a3feSDimitry Andric   assign(char_type* __s, size_t __n, char_type __a) _NOEXCEPT {
15481ad6265SDimitry Andric     std::fill_n(__s, __n, __a);
15581ad6265SDimitry Andric     return __s;
15681ad6265SDimitry Andric   }
15781ad6265SDimitry Andric 
158cb14a3feSDimitry Andric   static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int_type not_eof(int_type __c) _NOEXCEPT {
159cb14a3feSDimitry Andric     return eq_int_type(__c, eof()) ? ~eof() : __c;
160cb14a3feSDimitry Andric   }
161cb14a3feSDimitry Andric   static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR char_type to_char_type(int_type __c) _NOEXCEPT {
162cb14a3feSDimitry Andric     return char_type(__c);
163cb14a3feSDimitry Andric   }
164cb14a3feSDimitry Andric   static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int_type to_int_type(char_type __c) _NOEXCEPT {
165cb14a3feSDimitry Andric     return int_type((unsigned char)__c);
166cb14a3feSDimitry Andric   }
167cb14a3feSDimitry Andric   static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool eq_int_type(int_type __c1, int_type __c2) _NOEXCEPT {
168cb14a3feSDimitry Andric     return __c1 == __c2;
169cb14a3feSDimitry Andric   }
170cb14a3feSDimitry Andric   static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int_type eof() _NOEXCEPT { return int_type(EOF); }
17181ad6265SDimitry Andric };
17281ad6265SDimitry Andric 
173*0fca6ea1SDimitry Andric template <class _CharT, class _IntT, _IntT _EOFVal>
174*0fca6ea1SDimitry Andric struct __char_traits_base {
175*0fca6ea1SDimitry Andric   using char_type  = _CharT;
176*0fca6ea1SDimitry Andric   using int_type   = _IntT;
177bdd1243dSDimitry Andric   using off_type   = streamoff;
178bdd1243dSDimitry Andric   using state_type = mbstate_t;
17906c3fb27SDimitry Andric #if _LIBCPP_STD_VER >= 20
180bdd1243dSDimitry Andric   using comparison_category = strong_ordering;
181bdd1243dSDimitry Andric #endif
18281ad6265SDimitry Andric 
183*0fca6ea1SDimitry Andric   // There are different aliases for the different char types, but they are all aliases to this type
184*0fca6ea1SDimitry Andric   using pos_type = fpos<mbstate_t>;
185*0fca6ea1SDimitry Andric 
186*0fca6ea1SDimitry Andric   _LIBCPP_HIDE_FROM_ABI static inline _LIBCPP_CONSTEXPR_SINCE_CXX17 void
187*0fca6ea1SDimitry Andric   assign(char_type& __lhs, const char_type& __rhs) _NOEXCEPT {
188*0fca6ea1SDimitry Andric     __lhs = __rhs;
189cb14a3feSDimitry Andric   }
19081ad6265SDimitry Andric 
191*0fca6ea1SDimitry Andric   _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR bool eq(char_type __lhs, char_type __rhs) _NOEXCEPT {
192*0fca6ea1SDimitry Andric     return __lhs == __rhs;
193*0fca6ea1SDimitry Andric   }
194*0fca6ea1SDimitry Andric 
195*0fca6ea1SDimitry Andric   _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR bool lt(char_type __lhs, char_type __rhs) _NOEXCEPT {
196*0fca6ea1SDimitry Andric     return __lhs < __rhs;
197*0fca6ea1SDimitry Andric   }
198*0fca6ea1SDimitry Andric 
199*0fca6ea1SDimitry Andric   _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX20 char_type*
200*0fca6ea1SDimitry Andric   move(char_type* __dest, const char_type* __src, size_t __n) _NOEXCEPT {
201*0fca6ea1SDimitry Andric     return std::__constexpr_memmove(__dest, __src, __element_count(__n));
202*0fca6ea1SDimitry Andric   }
203*0fca6ea1SDimitry Andric 
204*0fca6ea1SDimitry Andric   _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX20 char_type*
205*0fca6ea1SDimitry Andric   copy(char_type* __dest, const char_type* __src, size_t __n) _NOEXCEPT {
206*0fca6ea1SDimitry Andric     _LIBCPP_ASSERT_NON_OVERLAPPING_RANGES(!std::__is_pointer_in_range(__dest, __dest + __n, __src),
207*0fca6ea1SDimitry Andric                                           "char_traits::copy: source and destination ranges overlap");
208*0fca6ea1SDimitry Andric     return std::__constexpr_memmove(__dest, __src, __element_count(__n));
209*0fca6ea1SDimitry Andric   }
210*0fca6ea1SDimitry Andric 
211*0fca6ea1SDimitry Andric   _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX20 char_type*
212*0fca6ea1SDimitry Andric   assign(char_type* __str, size_t __n, char_type __fill_char) _NOEXCEPT {
213*0fca6ea1SDimitry Andric     std::fill_n(__str, __n, __fill_char);
214*0fca6ea1SDimitry Andric     return __str;
215*0fca6ea1SDimitry Andric   }
216*0fca6ea1SDimitry Andric 
217*0fca6ea1SDimitry Andric   _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR char_type to_char_type(int_type __c) _NOEXCEPT {
218*0fca6ea1SDimitry Andric     return char_type(__c);
219*0fca6ea1SDimitry Andric   }
220*0fca6ea1SDimitry Andric 
221*0fca6ea1SDimitry Andric   _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR int_type to_int_type(char_type __c) _NOEXCEPT { return int_type(__c); }
222*0fca6ea1SDimitry Andric 
223*0fca6ea1SDimitry Andric   _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR bool eq_int_type(int_type __lhs, int_type __rhs) _NOEXCEPT {
224*0fca6ea1SDimitry Andric     return __lhs == __rhs;
225*0fca6ea1SDimitry Andric   }
226*0fca6ea1SDimitry Andric 
227*0fca6ea1SDimitry Andric   _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR int_type eof() _NOEXCEPT { return _EOFVal; }
228*0fca6ea1SDimitry Andric 
229*0fca6ea1SDimitry Andric   _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR int_type not_eof(int_type __c) _NOEXCEPT {
230*0fca6ea1SDimitry Andric     return eq_int_type(__c, eof()) ? static_cast<int_type>(~eof()) : __c;
231*0fca6ea1SDimitry Andric   }
232*0fca6ea1SDimitry Andric };
233*0fca6ea1SDimitry Andric 
234*0fca6ea1SDimitry Andric // char_traits<wchar_t>
235*0fca6ea1SDimitry Andric 
236*0fca6ea1SDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
237*0fca6ea1SDimitry Andric template <>
238*0fca6ea1SDimitry Andric struct _LIBCPP_TEMPLATE_VIS char_traits<wchar_t> : __char_traits_base<wchar_t, wint_t, static_cast<wint_t>(WEOF)> {
23906c3fb27SDimitry Andric   static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 int
24006c3fb27SDimitry Andric   compare(const char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
241bdd1243dSDimitry Andric     if (__n == 0)
242bdd1243dSDimitry Andric       return 0;
243bdd1243dSDimitry Andric     return std::__constexpr_wmemcmp(__s1, __s2, __n);
244bdd1243dSDimitry Andric   }
24581ad6265SDimitry Andric 
24606c3fb27SDimitry Andric   static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 size_t length(const char_type* __s) _NOEXCEPT {
247bdd1243dSDimitry Andric     return std::__constexpr_wcslen(__s);
248bdd1243dSDimitry Andric   }
249bdd1243dSDimitry Andric 
250cb14a3feSDimitry Andric   static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const char_type*
251cb14a3feSDimitry Andric   find(const char_type* __s, size_t __n, const char_type& __a) _NOEXCEPT {
252bdd1243dSDimitry Andric     if (__n == 0)
253bdd1243dSDimitry Andric       return nullptr;
254bdd1243dSDimitry Andric     return std::__constexpr_wmemchr(__s, __a, __n);
255bdd1243dSDimitry Andric   }
25681ad6265SDimitry Andric };
25781ad6265SDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
25881ad6265SDimitry Andric 
25981ad6265SDimitry Andric #ifndef _LIBCPP_HAS_NO_CHAR8_T
26081ad6265SDimitry Andric 
26181ad6265SDimitry Andric template <>
262*0fca6ea1SDimitry Andric struct _LIBCPP_TEMPLATE_VIS char_traits<char8_t>
263*0fca6ea1SDimitry Andric     : __char_traits_base<char8_t, unsigned int, static_cast<unsigned int>(EOF)> {
264bdd1243dSDimitry Andric   static _LIBCPP_HIDE_FROM_ABI constexpr int
265*0fca6ea1SDimitry Andric   compare(const char_type* __s1, const char_type* __s2, size_t __n) noexcept {
26606c3fb27SDimitry Andric     return std::__constexpr_memcmp(__s1, __s2, __element_count(__n));
267bdd1243dSDimitry Andric   }
26881ad6265SDimitry Andric 
269*0fca6ea1SDimitry Andric   static _LIBCPP_HIDE_FROM_ABI constexpr size_t length(const char_type* __str) noexcept {
270*0fca6ea1SDimitry Andric     return std::__constexpr_strlen(__str);
271*0fca6ea1SDimitry Andric   }
27281ad6265SDimitry Andric 
273cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI static constexpr const char_type*
274*0fca6ea1SDimitry Andric   find(const char_type* __s, size_t __n, const char_type& __a) noexcept {
275*0fca6ea1SDimitry Andric     return std::__constexpr_memchr(__s, __a, __n);
27681ad6265SDimitry Andric   }
27781ad6265SDimitry Andric };
27881ad6265SDimitry Andric 
27981ad6265SDimitry Andric #endif // _LIBCPP_HAS_NO_CHAR8_T
28081ad6265SDimitry Andric 
28181ad6265SDimitry Andric template <>
282*0fca6ea1SDimitry Andric struct _LIBCPP_TEMPLATE_VIS char_traits<char16_t>
283*0fca6ea1SDimitry Andric     : __char_traits_base<char16_t, uint_least16_t, static_cast<uint_least16_t>(0xFFFF)> {
284cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX17 int
285cb14a3feSDimitry Andric   compare(const char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT;
286cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX17 size_t length(const char_type* __s) _NOEXCEPT;
287*0fca6ea1SDimitry Andric 
288cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX17 const char_type*
289*0fca6ea1SDimitry Andric   find(const char_type* __s, size_t __n, const char_type& __a) _NOEXCEPT {
290*0fca6ea1SDimitry Andric     __identity __proj;
291*0fca6ea1SDimitry Andric     const char_type* __match = std::__find(__s, __s + __n, __a, __proj);
292*0fca6ea1SDimitry Andric     if (__match == __s + __n)
293*0fca6ea1SDimitry Andric       return nullptr;
294*0fca6ea1SDimitry Andric     return __match;
29581ad6265SDimitry Andric   }
29681ad6265SDimitry Andric };
29781ad6265SDimitry Andric 
298cb14a3feSDimitry Andric inline _LIBCPP_CONSTEXPR_SINCE_CXX17 int
299cb14a3feSDimitry Andric char_traits<char16_t>::compare(const char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
300cb14a3feSDimitry Andric   for (; __n; --__n, ++__s1, ++__s2) {
30181ad6265SDimitry Andric     if (lt(*__s1, *__s2))
30281ad6265SDimitry Andric       return -1;
30381ad6265SDimitry Andric     if (lt(*__s2, *__s1))
30481ad6265SDimitry Andric       return 1;
30581ad6265SDimitry Andric   }
30681ad6265SDimitry Andric   return 0;
30781ad6265SDimitry Andric }
30881ad6265SDimitry Andric 
309cb14a3feSDimitry Andric inline _LIBCPP_CONSTEXPR_SINCE_CXX17 size_t char_traits<char16_t>::length(const char_type* __s) _NOEXCEPT {
31081ad6265SDimitry Andric   size_t __len = 0;
31181ad6265SDimitry Andric   for (; !eq(*__s, char_type(0)); ++__s)
31281ad6265SDimitry Andric     ++__len;
31381ad6265SDimitry Andric   return __len;
31481ad6265SDimitry Andric }
31581ad6265SDimitry Andric 
31681ad6265SDimitry Andric template <>
317*0fca6ea1SDimitry Andric struct _LIBCPP_TEMPLATE_VIS char_traits<char32_t>
318*0fca6ea1SDimitry Andric     : __char_traits_base<char32_t, uint_least32_t, static_cast<uint_least32_t>(0xFFFFFFFF)> {
319cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX17 int
320cb14a3feSDimitry Andric   compare(const char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT;
321cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX17 size_t length(const char_type* __s) _NOEXCEPT;
322*0fca6ea1SDimitry Andric 
323cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX17 const char_type*
324*0fca6ea1SDimitry Andric   find(const char_type* __s, size_t __n, const char_type& __a) _NOEXCEPT {
325*0fca6ea1SDimitry Andric     __identity __proj;
326*0fca6ea1SDimitry Andric     const char_type* __match = std::__find(__s, __s + __n, __a, __proj);
327*0fca6ea1SDimitry Andric     if (__match == __s + __n)
328*0fca6ea1SDimitry Andric       return nullptr;
329*0fca6ea1SDimitry Andric     return __match;
33081ad6265SDimitry Andric   }
33181ad6265SDimitry Andric };
33281ad6265SDimitry Andric 
333cb14a3feSDimitry Andric inline _LIBCPP_CONSTEXPR_SINCE_CXX17 int
334cb14a3feSDimitry Andric char_traits<char32_t>::compare(const char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
335cb14a3feSDimitry Andric   for (; __n; --__n, ++__s1, ++__s2) {
33681ad6265SDimitry Andric     if (lt(*__s1, *__s2))
33781ad6265SDimitry Andric       return -1;
33881ad6265SDimitry Andric     if (lt(*__s2, *__s1))
33981ad6265SDimitry Andric       return 1;
34081ad6265SDimitry Andric   }
34181ad6265SDimitry Andric   return 0;
34281ad6265SDimitry Andric }
34381ad6265SDimitry Andric 
344cb14a3feSDimitry Andric inline _LIBCPP_CONSTEXPR_SINCE_CXX17 size_t char_traits<char32_t>::length(const char_type* __s) _NOEXCEPT {
34581ad6265SDimitry Andric   size_t __len = 0;
34681ad6265SDimitry Andric   for (; !eq(*__s, char_type(0)); ++__s)
34781ad6265SDimitry Andric     ++__len;
34881ad6265SDimitry Andric   return __len;
34981ad6265SDimitry Andric }
35081ad6265SDimitry Andric 
35181ad6265SDimitry Andric // helper fns for basic_string and string_view
35281ad6265SDimitry Andric 
35381ad6265SDimitry Andric // __str_find
35481ad6265SDimitry Andric template <class _CharT, class _SizeT, class _Traits, _SizeT __npos>
3555f757f3fSDimitry Andric inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI
356cb14a3feSDimitry Andric __str_find(const _CharT* __p, _SizeT __sz, _CharT __c, _SizeT __pos) _NOEXCEPT {
35781ad6265SDimitry Andric   if (__pos >= __sz)
35881ad6265SDimitry Andric     return __npos;
35981ad6265SDimitry Andric   const _CharT* __r = _Traits::find(__p + __pos, __sz - __pos, __c);
36081ad6265SDimitry Andric   if (__r == nullptr)
36181ad6265SDimitry Andric     return __npos;
36281ad6265SDimitry Andric   return static_cast<_SizeT>(__r - __p);
36381ad6265SDimitry Andric }
36481ad6265SDimitry Andric 
36581ad6265SDimitry Andric template <class _CharT, class _Traits>
366cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI inline _LIBCPP_CONSTEXPR_SINCE_CXX14 const _CharT* __search_substring(
367cb14a3feSDimitry Andric     const _CharT* __first1, const _CharT* __last1, const _CharT* __first2, const _CharT* __last2) _NOEXCEPT {
36881ad6265SDimitry Andric   // Take advantage of knowing source and pattern lengths.
36981ad6265SDimitry Andric   // Stop short when source is smaller than pattern.
37081ad6265SDimitry Andric   const ptrdiff_t __len2 = __last2 - __first2;
37181ad6265SDimitry Andric   if (__len2 == 0)
37281ad6265SDimitry Andric     return __first1;
37381ad6265SDimitry Andric 
37481ad6265SDimitry Andric   ptrdiff_t __len1 = __last1 - __first1;
37581ad6265SDimitry Andric   if (__len1 < __len2)
37681ad6265SDimitry Andric     return __last1;
37781ad6265SDimitry Andric 
37881ad6265SDimitry Andric   // First element of __first2 is loop invariant.
37981ad6265SDimitry Andric   _CharT __f2 = *__first2;
38081ad6265SDimitry Andric   while (true) {
38181ad6265SDimitry Andric     __len1 = __last1 - __first1;
38281ad6265SDimitry Andric     // Check whether __first1 still has at least __len2 bytes.
38381ad6265SDimitry Andric     if (__len1 < __len2)
38481ad6265SDimitry Andric       return __last1;
38581ad6265SDimitry Andric 
38681ad6265SDimitry Andric     // Find __f2 the first byte matching in __first1.
38781ad6265SDimitry Andric     __first1 = _Traits::find(__first1, __len1 - __len2 + 1, __f2);
38881ad6265SDimitry Andric     if (__first1 == nullptr)
38981ad6265SDimitry Andric       return __last1;
39081ad6265SDimitry Andric 
39181ad6265SDimitry Andric     // It is faster to compare from the first byte of __first1 even if we
39281ad6265SDimitry Andric     // already know that it matches the first byte of __first2: this is because
39381ad6265SDimitry Andric     // __first2 is most likely aligned, as it is user's "pattern" string, and
39481ad6265SDimitry Andric     // __first1 + 1 is most likely not aligned, as the match is in the middle of
39581ad6265SDimitry Andric     // the string.
39681ad6265SDimitry Andric     if (_Traits::compare(__first1, __first2, __len2) == 0)
39781ad6265SDimitry Andric       return __first1;
39881ad6265SDimitry Andric 
39981ad6265SDimitry Andric     ++__first1;
40081ad6265SDimitry Andric   }
40181ad6265SDimitry Andric }
40281ad6265SDimitry Andric 
40381ad6265SDimitry Andric template <class _CharT, class _SizeT, class _Traits, _SizeT __npos>
4045f757f3fSDimitry Andric inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI
405cb14a3feSDimitry Andric __str_find(const _CharT* __p, _SizeT __sz, const _CharT* __s, _SizeT __pos, _SizeT __n) _NOEXCEPT {
40681ad6265SDimitry Andric   if (__pos > __sz)
40781ad6265SDimitry Andric     return __npos;
40881ad6265SDimitry Andric 
40981ad6265SDimitry Andric   if (__n == 0) // There is nothing to search, just return __pos.
41081ad6265SDimitry Andric     return __pos;
41181ad6265SDimitry Andric 
412cb14a3feSDimitry Andric   const _CharT* __r = std::__search_substring<_CharT, _Traits>(__p + __pos, __p + __sz, __s, __s + __n);
41381ad6265SDimitry Andric 
41481ad6265SDimitry Andric   if (__r == __p + __sz)
41581ad6265SDimitry Andric     return __npos;
41681ad6265SDimitry Andric   return static_cast<_SizeT>(__r - __p);
41781ad6265SDimitry Andric }
41881ad6265SDimitry Andric 
41981ad6265SDimitry Andric // __str_rfind
42081ad6265SDimitry Andric 
42181ad6265SDimitry Andric template <class _CharT, class _SizeT, class _Traits, _SizeT __npos>
4225f757f3fSDimitry Andric inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI
423cb14a3feSDimitry Andric __str_rfind(const _CharT* __p, _SizeT __sz, _CharT __c, _SizeT __pos) _NOEXCEPT {
42481ad6265SDimitry Andric   if (__sz < 1)
42581ad6265SDimitry Andric     return __npos;
42681ad6265SDimitry Andric   if (__pos < __sz)
42781ad6265SDimitry Andric     ++__pos;
42881ad6265SDimitry Andric   else
42981ad6265SDimitry Andric     __pos = __sz;
430cb14a3feSDimitry Andric   for (const _CharT* __ps = __p + __pos; __ps != __p;) {
43181ad6265SDimitry Andric     if (_Traits::eq(*--__ps, __c))
43281ad6265SDimitry Andric       return static_cast<_SizeT>(__ps - __p);
43381ad6265SDimitry Andric   }
43481ad6265SDimitry Andric   return __npos;
43581ad6265SDimitry Andric }
43681ad6265SDimitry Andric 
43781ad6265SDimitry Andric template <class _CharT, class _SizeT, class _Traits, _SizeT __npos>
4385f757f3fSDimitry Andric inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI
439cb14a3feSDimitry Andric __str_rfind(const _CharT* __p, _SizeT __sz, const _CharT* __s, _SizeT __pos, _SizeT __n) _NOEXCEPT {
4405f757f3fSDimitry Andric   __pos = std::min(__pos, __sz);
44181ad6265SDimitry Andric   if (__n < __sz - __pos)
44281ad6265SDimitry Andric     __pos += __n;
44381ad6265SDimitry Andric   else
44481ad6265SDimitry Andric     __pos = __sz;
445753f127fSDimitry Andric   const _CharT* __r = std::__find_end_classic(__p, __p + __pos, __s, __s + __n, _Traits::eq);
44681ad6265SDimitry Andric   if (__n > 0 && __r == __p + __pos)
44781ad6265SDimitry Andric     return __npos;
44881ad6265SDimitry Andric   return static_cast<_SizeT>(__r - __p);
44981ad6265SDimitry Andric }
45081ad6265SDimitry Andric 
45181ad6265SDimitry Andric // __str_find_first_of
45281ad6265SDimitry Andric template <class _CharT, class _SizeT, class _Traits, _SizeT __npos>
4535f757f3fSDimitry Andric inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI
454cb14a3feSDimitry Andric __str_find_first_of(const _CharT* __p, _SizeT __sz, const _CharT* __s, _SizeT __pos, _SizeT __n) _NOEXCEPT {
45581ad6265SDimitry Andric   if (__pos >= __sz || __n == 0)
45681ad6265SDimitry Andric     return __npos;
457cb14a3feSDimitry Andric   const _CharT* __r = std::__find_first_of_ce(__p + __pos, __p + __sz, __s, __s + __n, _Traits::eq);
45881ad6265SDimitry Andric   if (__r == __p + __sz)
45981ad6265SDimitry Andric     return __npos;
46081ad6265SDimitry Andric   return static_cast<_SizeT>(__r - __p);
46181ad6265SDimitry Andric }
46281ad6265SDimitry Andric 
46381ad6265SDimitry Andric // __str_find_last_of
46481ad6265SDimitry Andric template <class _CharT, class _SizeT, class _Traits, _SizeT __npos>
4655f757f3fSDimitry Andric inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI
466cb14a3feSDimitry Andric __str_find_last_of(const _CharT* __p, _SizeT __sz, const _CharT* __s, _SizeT __pos, _SizeT __n) _NOEXCEPT {
467cb14a3feSDimitry Andric   if (__n != 0) {
46881ad6265SDimitry Andric     if (__pos < __sz)
46981ad6265SDimitry Andric       ++__pos;
47081ad6265SDimitry Andric     else
47181ad6265SDimitry Andric       __pos = __sz;
472cb14a3feSDimitry Andric     for (const _CharT* __ps = __p + __pos; __ps != __p;) {
47381ad6265SDimitry Andric       const _CharT* __r = _Traits::find(__s, __n, *--__ps);
47481ad6265SDimitry Andric       if (__r)
47581ad6265SDimitry Andric         return static_cast<_SizeT>(__ps - __p);
47681ad6265SDimitry Andric     }
47781ad6265SDimitry Andric   }
47881ad6265SDimitry Andric   return __npos;
47981ad6265SDimitry Andric }
48081ad6265SDimitry Andric 
48181ad6265SDimitry Andric // __str_find_first_not_of
48281ad6265SDimitry Andric template <class _CharT, class _SizeT, class _Traits, _SizeT __npos>
4835f757f3fSDimitry Andric inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI
484cb14a3feSDimitry Andric __str_find_first_not_of(const _CharT* __p, _SizeT __sz, const _CharT* __s, _SizeT __pos, _SizeT __n) _NOEXCEPT {
485cb14a3feSDimitry Andric   if (__pos < __sz) {
48681ad6265SDimitry Andric     const _CharT* __pe = __p + __sz;
48781ad6265SDimitry Andric     for (const _CharT* __ps = __p + __pos; __ps != __pe; ++__ps)
48881ad6265SDimitry Andric       if (_Traits::find(__s, __n, *__ps) == nullptr)
48981ad6265SDimitry Andric         return static_cast<_SizeT>(__ps - __p);
49081ad6265SDimitry Andric   }
49181ad6265SDimitry Andric   return __npos;
49281ad6265SDimitry Andric }
49381ad6265SDimitry Andric 
49481ad6265SDimitry Andric template <class _CharT, class _SizeT, class _Traits, _SizeT __npos>
4955f757f3fSDimitry Andric inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI
496cb14a3feSDimitry Andric __str_find_first_not_of(const _CharT* __p, _SizeT __sz, _CharT __c, _SizeT __pos) _NOEXCEPT {
497cb14a3feSDimitry Andric   if (__pos < __sz) {
49881ad6265SDimitry Andric     const _CharT* __pe = __p + __sz;
49981ad6265SDimitry Andric     for (const _CharT* __ps = __p + __pos; __ps != __pe; ++__ps)
50081ad6265SDimitry Andric       if (!_Traits::eq(*__ps, __c))
50181ad6265SDimitry Andric         return static_cast<_SizeT>(__ps - __p);
50281ad6265SDimitry Andric   }
50381ad6265SDimitry Andric   return __npos;
50481ad6265SDimitry Andric }
50581ad6265SDimitry Andric 
50681ad6265SDimitry Andric // __str_find_last_not_of
50781ad6265SDimitry Andric template <class _CharT, class _SizeT, class _Traits, _SizeT __npos>
5085f757f3fSDimitry Andric inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI
509cb14a3feSDimitry Andric __str_find_last_not_of(const _CharT* __p, _SizeT __sz, const _CharT* __s, _SizeT __pos, _SizeT __n) _NOEXCEPT {
51081ad6265SDimitry Andric   if (__pos < __sz)
51181ad6265SDimitry Andric     ++__pos;
51281ad6265SDimitry Andric   else
51381ad6265SDimitry Andric     __pos = __sz;
51481ad6265SDimitry Andric   for (const _CharT* __ps = __p + __pos; __ps != __p;)
51581ad6265SDimitry Andric     if (_Traits::find(__s, __n, *--__ps) == nullptr)
51681ad6265SDimitry Andric       return static_cast<_SizeT>(__ps - __p);
51781ad6265SDimitry Andric   return __npos;
51881ad6265SDimitry Andric }
51981ad6265SDimitry Andric 
52081ad6265SDimitry Andric template <class _CharT, class _SizeT, class _Traits, _SizeT __npos>
5215f757f3fSDimitry Andric inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI
522cb14a3feSDimitry Andric __str_find_last_not_of(const _CharT* __p, _SizeT __sz, _CharT __c, _SizeT __pos) _NOEXCEPT {
52381ad6265SDimitry Andric   if (__pos < __sz)
52481ad6265SDimitry Andric     ++__pos;
52581ad6265SDimitry Andric   else
52681ad6265SDimitry Andric     __pos = __sz;
52781ad6265SDimitry Andric   for (const _CharT* __ps = __p + __pos; __ps != __p;)
52881ad6265SDimitry Andric     if (!_Traits::eq(*--__ps, __c))
52981ad6265SDimitry Andric       return static_cast<_SizeT>(__ps - __p);
53081ad6265SDimitry Andric   return __npos;
53181ad6265SDimitry Andric }
53281ad6265SDimitry Andric 
53381ad6265SDimitry Andric template <class _Ptr>
534cb14a3feSDimitry Andric inline _LIBCPP_HIDE_FROM_ABI size_t __do_string_hash(_Ptr __p, _Ptr __e) {
53581ad6265SDimitry Andric   typedef typename iterator_traits<_Ptr>::value_type value_type;
53681ad6265SDimitry Andric   return __murmur2_or_cityhash<size_t>()(__p, (__e - __p) * sizeof(value_type));
53781ad6265SDimitry Andric }
53881ad6265SDimitry Andric 
53981ad6265SDimitry Andric _LIBCPP_END_NAMESPACE_STD
54081ad6265SDimitry Andric 
54181ad6265SDimitry Andric _LIBCPP_POP_MACROS
54281ad6265SDimitry Andric 
54381ad6265SDimitry Andric #endif // _LIBCPP___STRING_CHAR_TRAITS_H
544