Path: blob/main/contrib/llvm-project/libcxx/include/__string/char_traits.h
35233 views
//===----------------------------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#ifndef _LIBCPP___STRING_CHAR_TRAITS_H9#define _LIBCPP___STRING_CHAR_TRAITS_H1011#include <__algorithm/fill_n.h>12#include <__algorithm/find.h>13#include <__algorithm/find_end.h>14#include <__algorithm/find_first_of.h>15#include <__algorithm/min.h>16#include <__assert>17#include <__compare/ordering.h>18#include <__config>19#include <__functional/hash.h>20#include <__functional/identity.h>21#include <__iterator/iterator_traits.h>22#include <__string/constexpr_c_functions.h>23#include <__type_traits/is_constant_evaluated.h>24#include <__utility/is_pointer_in_range.h>25#include <cstddef>26#include <cstdint>27#include <cstdio>28#include <iosfwd>2930#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS31# include <cwchar> // for wmemcpy32#endif3334#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)35# pragma GCC system_header36#endif3738_LIBCPP_PUSH_MACROS39#include <__undef_macros>4041_LIBCPP_BEGIN_NAMESPACE_STD4243template <class _CharT>44struct char_traits;45/*46The Standard does not define the base template for char_traits because it is impossible to provide47a correct definition for arbitrary character types. Instead, it requires implementations to provide48specializations for predefined character types like `char`, `wchar_t` and others. We provide this as49exposition-only to document what members a char_traits specialization should provide:50{51using char_type = _CharT;52using int_type = ...;53using off_type = ...;54using pos_type = ...;55using state_type = ...;5657static void assign(char_type&, const char_type&);58static bool eq(char_type, char_type);59static bool lt(char_type, char_type);6061static int compare(const char_type*, const char_type*, size_t);62static size_t length(const char_type*);63static const char_type* find(const char_type*, size_t, const char_type&);64static char_type* move(char_type*, const char_type*, size_t);65static char_type* copy(char_type*, const char_type*, size_t);66static char_type* assign(char_type*, size_t, char_type);6768static int_type not_eof(int_type);69static char_type to_char_type(int_type);70static int_type to_int_type(char_type);71static bool eq_int_type(int_type, int_type);72static int_type eof();73};74*/7576// char_traits<char>7778template <>79struct _LIBCPP_TEMPLATE_VIS char_traits<char> {80using char_type = char;81using int_type = int;82using off_type = streamoff;83using pos_type = streampos;84using state_type = mbstate_t;85#if _LIBCPP_STD_VER >= 2086using comparison_category = strong_ordering;87#endif8889static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 void90assign(char_type& __c1, const char_type& __c2) _NOEXCEPT {91__c1 = __c2;92}9394// TODO: Make this _LIBCPP_HIDE_FROM_ABI95static inline _LIBCPP_HIDDEN _LIBCPP_CONSTEXPR bool eq(char_type __c1, char_type __c2) _NOEXCEPT {96return __c1 == __c2;97}98static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool lt(char_type __c1, char_type __c2) _NOEXCEPT {99return (unsigned char)__c1 < (unsigned char)__c2;100}101102// __constexpr_memcmp requires a trivially lexicographically comparable type, but char is not when char is a signed103// type104static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 int105compare(const char_type* __lhs, const char_type* __rhs, size_t __count) _NOEXCEPT {106if (__libcpp_is_constant_evaluated()) {107#ifdef _LIBCPP_COMPILER_CLANG_BASED108return __builtin_memcmp(__lhs, __rhs, __count);109#else110while (__count != 0) {111if (lt(*__lhs, *__rhs))112return -1;113if (lt(*__rhs, *__lhs))114return 1;115116__count -= sizeof(char_type);117++__lhs;118++__rhs;119}120return 0;121#endif // _LIBCPP_COMPILER_CLANG_BASED122} else {123return __builtin_memcmp(__lhs, __rhs, __count);124}125}126127static inline _LIBCPP_HIDE_FROM_ABI size_t _LIBCPP_CONSTEXPR_SINCE_CXX17 length(const char_type* __s) _NOEXCEPT {128return std::__constexpr_strlen(__s);129}130131static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const char_type*132find(const char_type* __s, size_t __n, const char_type& __a) _NOEXCEPT {133if (__n == 0)134return nullptr;135return std::__constexpr_memchr(__s, __a, __n);136}137138static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 char_type*139move(char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {140return std::__constexpr_memmove(__s1, __s2, __element_count(__n));141}142143static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 char_type*144copy(char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {145_LIBCPP_ASSERT_NON_OVERLAPPING_RANGES(!std::__is_pointer_in_range(__s1, __s1 + __n, __s2),146"char_traits::copy: source and destination ranges overlap");147std::__constexpr_memmove(__s1, __s2, __element_count(__n));148return __s1;149}150151static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 char_type*152assign(char_type* __s, size_t __n, char_type __a) _NOEXCEPT {153std::fill_n(__s, __n, __a);154return __s;155}156157static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int_type not_eof(int_type __c) _NOEXCEPT {158return eq_int_type(__c, eof()) ? ~eof() : __c;159}160static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR char_type to_char_type(int_type __c) _NOEXCEPT {161return char_type(__c);162}163static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int_type to_int_type(char_type __c) _NOEXCEPT {164return int_type((unsigned char)__c);165}166static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool eq_int_type(int_type __c1, int_type __c2) _NOEXCEPT {167return __c1 == __c2;168}169static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int_type eof() _NOEXCEPT { return int_type(EOF); }170};171172template <class _CharT, class _IntT, _IntT _EOFVal>173struct __char_traits_base {174using char_type = _CharT;175using int_type = _IntT;176using off_type = streamoff;177using state_type = mbstate_t;178#if _LIBCPP_STD_VER >= 20179using comparison_category = strong_ordering;180#endif181182// There are different aliases for the different char types, but they are all aliases to this type183using pos_type = fpos<mbstate_t>;184185_LIBCPP_HIDE_FROM_ABI static inline _LIBCPP_CONSTEXPR_SINCE_CXX17 void186assign(char_type& __lhs, const char_type& __rhs) _NOEXCEPT {187__lhs = __rhs;188}189190_LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR bool eq(char_type __lhs, char_type __rhs) _NOEXCEPT {191return __lhs == __rhs;192}193194_LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR bool lt(char_type __lhs, char_type __rhs) _NOEXCEPT {195return __lhs < __rhs;196}197198_LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX20 char_type*199move(char_type* __dest, const char_type* __src, size_t __n) _NOEXCEPT {200return std::__constexpr_memmove(__dest, __src, __element_count(__n));201}202203_LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX20 char_type*204copy(char_type* __dest, const char_type* __src, size_t __n) _NOEXCEPT {205_LIBCPP_ASSERT_NON_OVERLAPPING_RANGES(!std::__is_pointer_in_range(__dest, __dest + __n, __src),206"char_traits::copy: source and destination ranges overlap");207return std::__constexpr_memmove(__dest, __src, __element_count(__n));208}209210_LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX20 char_type*211assign(char_type* __str, size_t __n, char_type __fill_char) _NOEXCEPT {212std::fill_n(__str, __n, __fill_char);213return __str;214}215216_LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR char_type to_char_type(int_type __c) _NOEXCEPT {217return char_type(__c);218}219220_LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR int_type to_int_type(char_type __c) _NOEXCEPT { return int_type(__c); }221222_LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR bool eq_int_type(int_type __lhs, int_type __rhs) _NOEXCEPT {223return __lhs == __rhs;224}225226_LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR int_type eof() _NOEXCEPT { return _EOFVal; }227228_LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR int_type not_eof(int_type __c) _NOEXCEPT {229return eq_int_type(__c, eof()) ? static_cast<int_type>(~eof()) : __c;230}231};232233// char_traits<wchar_t>234235#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS236template <>237struct _LIBCPP_TEMPLATE_VIS char_traits<wchar_t> : __char_traits_base<wchar_t, wint_t, static_cast<wint_t>(WEOF)> {238static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 int239compare(const char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {240if (__n == 0)241return 0;242return std::__constexpr_wmemcmp(__s1, __s2, __n);243}244245static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 size_t length(const char_type* __s) _NOEXCEPT {246return std::__constexpr_wcslen(__s);247}248249static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const char_type*250find(const char_type* __s, size_t __n, const char_type& __a) _NOEXCEPT {251if (__n == 0)252return nullptr;253return std::__constexpr_wmemchr(__s, __a, __n);254}255};256#endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS257258#ifndef _LIBCPP_HAS_NO_CHAR8_T259260template <>261struct _LIBCPP_TEMPLATE_VIS char_traits<char8_t>262: __char_traits_base<char8_t, unsigned int, static_cast<unsigned int>(EOF)> {263static _LIBCPP_HIDE_FROM_ABI constexpr int264compare(const char_type* __s1, const char_type* __s2, size_t __n) noexcept {265return std::__constexpr_memcmp(__s1, __s2, __element_count(__n));266}267268static _LIBCPP_HIDE_FROM_ABI constexpr size_t length(const char_type* __str) noexcept {269return std::__constexpr_strlen(__str);270}271272_LIBCPP_HIDE_FROM_ABI static constexpr const char_type*273find(const char_type* __s, size_t __n, const char_type& __a) noexcept {274return std::__constexpr_memchr(__s, __a, __n);275}276};277278#endif // _LIBCPP_HAS_NO_CHAR8_T279280template <>281struct _LIBCPP_TEMPLATE_VIS char_traits<char16_t>282: __char_traits_base<char16_t, uint_least16_t, static_cast<uint_least16_t>(0xFFFF)> {283_LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX17 int284compare(const char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT;285_LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX17 size_t length(const char_type* __s) _NOEXCEPT;286287_LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX17 const char_type*288find(const char_type* __s, size_t __n, const char_type& __a) _NOEXCEPT {289__identity __proj;290const char_type* __match = std::__find(__s, __s + __n, __a, __proj);291if (__match == __s + __n)292return nullptr;293return __match;294}295};296297inline _LIBCPP_CONSTEXPR_SINCE_CXX17 int298char_traits<char16_t>::compare(const char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {299for (; __n; --__n, ++__s1, ++__s2) {300if (lt(*__s1, *__s2))301return -1;302if (lt(*__s2, *__s1))303return 1;304}305return 0;306}307308inline _LIBCPP_CONSTEXPR_SINCE_CXX17 size_t char_traits<char16_t>::length(const char_type* __s) _NOEXCEPT {309size_t __len = 0;310for (; !eq(*__s, char_type(0)); ++__s)311++__len;312return __len;313}314315template <>316struct _LIBCPP_TEMPLATE_VIS char_traits<char32_t>317: __char_traits_base<char32_t, uint_least32_t, static_cast<uint_least32_t>(0xFFFFFFFF)> {318_LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX17 int319compare(const char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT;320_LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX17 size_t length(const char_type* __s) _NOEXCEPT;321322_LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX17 const char_type*323find(const char_type* __s, size_t __n, const char_type& __a) _NOEXCEPT {324__identity __proj;325const char_type* __match = std::__find(__s, __s + __n, __a, __proj);326if (__match == __s + __n)327return nullptr;328return __match;329}330};331332inline _LIBCPP_CONSTEXPR_SINCE_CXX17 int333char_traits<char32_t>::compare(const char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {334for (; __n; --__n, ++__s1, ++__s2) {335if (lt(*__s1, *__s2))336return -1;337if (lt(*__s2, *__s1))338return 1;339}340return 0;341}342343inline _LIBCPP_CONSTEXPR_SINCE_CXX17 size_t char_traits<char32_t>::length(const char_type* __s) _NOEXCEPT {344size_t __len = 0;345for (; !eq(*__s, char_type(0)); ++__s)346++__len;347return __len;348}349350// helper fns for basic_string and string_view351352// __str_find353template <class _CharT, class _SizeT, class _Traits, _SizeT __npos>354inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI355__str_find(const _CharT* __p, _SizeT __sz, _CharT __c, _SizeT __pos) _NOEXCEPT {356if (__pos >= __sz)357return __npos;358const _CharT* __r = _Traits::find(__p + __pos, __sz - __pos, __c);359if (__r == nullptr)360return __npos;361return static_cast<_SizeT>(__r - __p);362}363364template <class _CharT, class _Traits>365_LIBCPP_HIDE_FROM_ABI inline _LIBCPP_CONSTEXPR_SINCE_CXX14 const _CharT* __search_substring(366const _CharT* __first1, const _CharT* __last1, const _CharT* __first2, const _CharT* __last2) _NOEXCEPT {367// Take advantage of knowing source and pattern lengths.368// Stop short when source is smaller than pattern.369const ptrdiff_t __len2 = __last2 - __first2;370if (__len2 == 0)371return __first1;372373ptrdiff_t __len1 = __last1 - __first1;374if (__len1 < __len2)375return __last1;376377// First element of __first2 is loop invariant.378_CharT __f2 = *__first2;379while (true) {380__len1 = __last1 - __first1;381// Check whether __first1 still has at least __len2 bytes.382if (__len1 < __len2)383return __last1;384385// Find __f2 the first byte matching in __first1.386__first1 = _Traits::find(__first1, __len1 - __len2 + 1, __f2);387if (__first1 == nullptr)388return __last1;389390// It is faster to compare from the first byte of __first1 even if we391// already know that it matches the first byte of __first2: this is because392// __first2 is most likely aligned, as it is user's "pattern" string, and393// __first1 + 1 is most likely not aligned, as the match is in the middle of394// the string.395if (_Traits::compare(__first1, __first2, __len2) == 0)396return __first1;397398++__first1;399}400}401402template <class _CharT, class _SizeT, class _Traits, _SizeT __npos>403inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI404__str_find(const _CharT* __p, _SizeT __sz, const _CharT* __s, _SizeT __pos, _SizeT __n) _NOEXCEPT {405if (__pos > __sz)406return __npos;407408if (__n == 0) // There is nothing to search, just return __pos.409return __pos;410411const _CharT* __r = std::__search_substring<_CharT, _Traits>(__p + __pos, __p + __sz, __s, __s + __n);412413if (__r == __p + __sz)414return __npos;415return static_cast<_SizeT>(__r - __p);416}417418// __str_rfind419420template <class _CharT, class _SizeT, class _Traits, _SizeT __npos>421inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI422__str_rfind(const _CharT* __p, _SizeT __sz, _CharT __c, _SizeT __pos) _NOEXCEPT {423if (__sz < 1)424return __npos;425if (__pos < __sz)426++__pos;427else428__pos = __sz;429for (const _CharT* __ps = __p + __pos; __ps != __p;) {430if (_Traits::eq(*--__ps, __c))431return static_cast<_SizeT>(__ps - __p);432}433return __npos;434}435436template <class _CharT, class _SizeT, class _Traits, _SizeT __npos>437inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI438__str_rfind(const _CharT* __p, _SizeT __sz, const _CharT* __s, _SizeT __pos, _SizeT __n) _NOEXCEPT {439__pos = std::min(__pos, __sz);440if (__n < __sz - __pos)441__pos += __n;442else443__pos = __sz;444const _CharT* __r = std::__find_end_classic(__p, __p + __pos, __s, __s + __n, _Traits::eq);445if (__n > 0 && __r == __p + __pos)446return __npos;447return static_cast<_SizeT>(__r - __p);448}449450// __str_find_first_of451template <class _CharT, class _SizeT, class _Traits, _SizeT __npos>452inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI453__str_find_first_of(const _CharT* __p, _SizeT __sz, const _CharT* __s, _SizeT __pos, _SizeT __n) _NOEXCEPT {454if (__pos >= __sz || __n == 0)455return __npos;456const _CharT* __r = std::__find_first_of_ce(__p + __pos, __p + __sz, __s, __s + __n, _Traits::eq);457if (__r == __p + __sz)458return __npos;459return static_cast<_SizeT>(__r - __p);460}461462// __str_find_last_of463template <class _CharT, class _SizeT, class _Traits, _SizeT __npos>464inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI465__str_find_last_of(const _CharT* __p, _SizeT __sz, const _CharT* __s, _SizeT __pos, _SizeT __n) _NOEXCEPT {466if (__n != 0) {467if (__pos < __sz)468++__pos;469else470__pos = __sz;471for (const _CharT* __ps = __p + __pos; __ps != __p;) {472const _CharT* __r = _Traits::find(__s, __n, *--__ps);473if (__r)474return static_cast<_SizeT>(__ps - __p);475}476}477return __npos;478}479480// __str_find_first_not_of481template <class _CharT, class _SizeT, class _Traits, _SizeT __npos>482inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI483__str_find_first_not_of(const _CharT* __p, _SizeT __sz, const _CharT* __s, _SizeT __pos, _SizeT __n) _NOEXCEPT {484if (__pos < __sz) {485const _CharT* __pe = __p + __sz;486for (const _CharT* __ps = __p + __pos; __ps != __pe; ++__ps)487if (_Traits::find(__s, __n, *__ps) == nullptr)488return static_cast<_SizeT>(__ps - __p);489}490return __npos;491}492493template <class _CharT, class _SizeT, class _Traits, _SizeT __npos>494inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI495__str_find_first_not_of(const _CharT* __p, _SizeT __sz, _CharT __c, _SizeT __pos) _NOEXCEPT {496if (__pos < __sz) {497const _CharT* __pe = __p + __sz;498for (const _CharT* __ps = __p + __pos; __ps != __pe; ++__ps)499if (!_Traits::eq(*__ps, __c))500return static_cast<_SizeT>(__ps - __p);501}502return __npos;503}504505// __str_find_last_not_of506template <class _CharT, class _SizeT, class _Traits, _SizeT __npos>507inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI508__str_find_last_not_of(const _CharT* __p, _SizeT __sz, const _CharT* __s, _SizeT __pos, _SizeT __n) _NOEXCEPT {509if (__pos < __sz)510++__pos;511else512__pos = __sz;513for (const _CharT* __ps = __p + __pos; __ps != __p;)514if (_Traits::find(__s, __n, *--__ps) == nullptr)515return static_cast<_SizeT>(__ps - __p);516return __npos;517}518519template <class _CharT, class _SizeT, class _Traits, _SizeT __npos>520inline _SizeT _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI521__str_find_last_not_of(const _CharT* __p, _SizeT __sz, _CharT __c, _SizeT __pos) _NOEXCEPT {522if (__pos < __sz)523++__pos;524else525__pos = __sz;526for (const _CharT* __ps = __p + __pos; __ps != __p;)527if (!_Traits::eq(*--__ps, __c))528return static_cast<_SizeT>(__ps - __p);529return __npos;530}531532template <class _Ptr>533inline _LIBCPP_HIDE_FROM_ABI size_t __do_string_hash(_Ptr __p, _Ptr __e) {534typedef typename iterator_traits<_Ptr>::value_type value_type;535return __murmur2_or_cityhash<size_t>()(__p, (__e - __p) * sizeof(value_type));536}537538_LIBCPP_END_NAMESPACE_STD539540_LIBCPP_POP_MACROS541542#endif // _LIBCPP___STRING_CHAR_TRAITS_H543544545