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