// Components for manipulating non-owning sequences of characters -*- C++ -*- // Copyright (C) 2013-2024 Free Software Foundation, Inc. // // This file is part of the GNU ISO C++ Library. This library is free // software; you can redistribute it and/or modify it under the // terms of the GNU General Public License as published by the // Free Software Foundation; either version 3, or (at your option) // any later version. // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // Under Section 7 of GPL version 3, you are granted additional // permissions described in the GCC Runtime Library Exception, version // 3.1, as published by the Free Software Foundation. // You should have received a copy of the GNU General Public License and // a copy of the GCC Runtime Library Exception along with this program; // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see // . /** @file include/string_view * This is a Standard C++ Library header. */ // // N3762 basic_string_view library // #ifndef _GLIBCXX_STRING_VIEW #define _GLIBCXX_STRING_VIEW 1 #pragma GCC system_header #define __glibcxx_want_constexpr_char_traits #define __glibcxx_want_constexpr_string_view #define __glibcxx_want_freestanding_string_view #define __glibcxx_want_string_view #define __glibcxx_want_starts_ends_with #define __glibcxx_want_string_contains #include #if __cplusplus >= 201703L #include #include #include #include #include #include #if __cplusplus >= 202002L # include #endif #if _GLIBCXX_HOSTED # include # include #endif namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION // Helper for basic_string and basic_string_view members. constexpr size_t __sv_check(size_t __size, size_t __pos, const char* __s) { if (__pos > __size) __throw_out_of_range_fmt(__N("%s: __pos (which is %zu) > __size " "(which is %zu)"), __s, __pos, __size); return __pos; } // Helper for basic_string members. // NB: __sv_limit doesn't check for a bad __pos value. constexpr size_t __sv_limit(size_t __size, size_t __pos, size_t __off) noexcept { const bool __testoff = __off < __size - __pos; return __testoff ? __off : __size - __pos; } /** * @class basic_string_view * @brief A non-owning reference to a string. * * @ingroup strings * @ingroup sequences * * @tparam _CharT Type of character * @tparam _Traits Traits for character type, defaults to * char_traits<_CharT>. * * A basic_string_view looks like this: * * @code * _CharT* _M_str * size_t _M_len * @endcode */ template> class basic_string_view { static_assert(!is_array_v<_CharT>); static_assert(is_trivial_v<_CharT> && is_standard_layout_v<_CharT>); static_assert(is_same_v<_CharT, typename _Traits::char_type>); public: // types using traits_type = _Traits; using value_type = _CharT; using pointer = value_type*; using const_pointer = const value_type*; using reference = value_type&; using const_reference = const value_type&; using const_iterator = const value_type*; using iterator = const_iterator; using const_reverse_iterator = std::reverse_iterator; using reverse_iterator = const_reverse_iterator; using size_type = size_t; using difference_type = ptrdiff_t; static constexpr size_type npos = size_type(-1); // [string.view.cons], construction and assignment constexpr basic_string_view() noexcept : _M_len{0}, _M_str{nullptr} { } constexpr basic_string_view(const basic_string_view&) noexcept = default; [[__gnu__::__nonnull__]] constexpr basic_string_view(const _CharT* __str) noexcept : _M_len{traits_type::length(__str)}, _M_str{__str} { } constexpr basic_string_view(const _CharT* __str, size_type __len) noexcept : _M_len{__len}, _M_str{__str} { } #if __cplusplus >= 202002L && __cpp_lib_concepts template _End> requires same_as, _CharT> && (!convertible_to<_End, size_type>) constexpr basic_string_view(_It __first, _End __last) noexcept(noexcept(__last - __first)) : _M_len(__last - __first), _M_str(std::to_address(__first)) { } #if __cplusplus > 202002L template> requires (!is_same_v<_DRange, basic_string_view>) && ranges::contiguous_range<_Range> && ranges::sized_range<_Range> && is_same_v, _CharT> && (!is_convertible_v<_Range, const _CharT*>) && (!requires (_DRange& __d) { __d.operator ::std::basic_string_view<_CharT, _Traits>(); }) constexpr explicit basic_string_view(_Range&& __r) noexcept(noexcept(ranges::size(__r)) && noexcept(ranges::data(__r))) : _M_len(ranges::size(__r)), _M_str(ranges::data(__r)) { } basic_string_view(nullptr_t) = delete; #endif // C++23 #endif // C++20 constexpr basic_string_view& operator=(const basic_string_view&) noexcept = default; // [string.view.iterators], iterator support [[nodiscard]] constexpr const_iterator begin() const noexcept { return this->_M_str; } [[nodiscard]] constexpr const_iterator end() const noexcept { return this->_M_str + this->_M_len; } [[nodiscard]] constexpr const_iterator cbegin() const noexcept { return this->_M_str; } [[nodiscard]] constexpr const_iterator cend() const noexcept { return this->_M_str + this->_M_len; } [[nodiscard]] constexpr const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(this->end()); } [[nodiscard]] constexpr const_reverse_iterator rend() const noexcept { return const_reverse_iterator(this->begin()); } [[nodiscard]] constexpr const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator(this->end()); } [[nodiscard]] constexpr const_reverse_iterator crend() const noexcept { return const_reverse_iterator(this->begin()); } // [string.view.capacity], capacity [[nodiscard]] constexpr size_type size() const noexcept { return this->_M_len; } [[nodiscard]] constexpr size_type length() const noexcept { return _M_len; } [[nodiscard]] constexpr size_type max_size() const noexcept { return (npos - sizeof(size_type) - sizeof(void*)) / sizeof(value_type) / 4; } [[nodiscard]] constexpr bool empty() const noexcept { return this->_M_len == 0; } // [string.view.access], element access [[nodiscard]] constexpr const_reference operator[](size_type __pos) const noexcept { __glibcxx_assert(__pos < this->_M_len); return *(this->_M_str + __pos); } [[nodiscard]] constexpr const_reference at(size_type __pos) const { if (__pos >= _M_len) __throw_out_of_range_fmt(__N("basic_string_view::at: __pos " "(which is %zu) >= this->size() " "(which is %zu)"), __pos, this->size()); return *(this->_M_str + __pos); } [[nodiscard]] constexpr const_reference front() const noexcept { __glibcxx_assert(this->_M_len > 0); return *this->_M_str; } [[nodiscard]] constexpr const_reference back() const noexcept { __glibcxx_assert(this->_M_len > 0); return *(this->_M_str + this->_M_len - 1); } [[nodiscard]] constexpr const_pointer data() const noexcept { return this->_M_str; } // [string.view.modifiers], modifiers: constexpr void remove_prefix(size_type __n) noexcept { __glibcxx_assert(this->_M_len >= __n); this->_M_str += __n; this->_M_len -= __n; } constexpr void remove_suffix(size_type __n) noexcept { __glibcxx_assert(this->_M_len >= __n); this->_M_len -= __n; } constexpr void swap(basic_string_view& __sv) noexcept { auto __tmp = *this; *this = __sv; __sv = __tmp; } // [string.view.ops], string operations: _GLIBCXX20_CONSTEXPR size_type copy(_CharT* __str, size_type __n, size_type __pos = 0) const { __glibcxx_requires_string_len(__str, __n); __pos = std::__sv_check(size(), __pos, "basic_string_view::copy"); const size_type __rlen = std::min(__n, _M_len - __pos); // _GLIBCXX_RESOLVE_LIB_DEFECTS // 2777. basic_string_view::copy should use char_traits::copy traits_type::copy(__str, data() + __pos, __rlen); return __rlen; } [[nodiscard]] constexpr basic_string_view substr(size_type __pos = 0, size_type __n = npos) const noexcept(false) { __pos = std::__sv_check(size(), __pos, "basic_string_view::substr"); const size_type __rlen = std::min(__n, _M_len - __pos); return basic_string_view{_M_str + __pos, __rlen}; } [[nodiscard]] constexpr int compare(basic_string_view __str) const noexcept { const size_type __rlen = std::min(this->_M_len, __str._M_len); int __ret = traits_type::compare(this->_M_str, __str._M_str, __rlen); if (__ret == 0) __ret = _S_compare(this->_M_len, __str._M_len); return __ret; } [[nodiscard]] constexpr int compare(size_type __pos1, size_type __n1, basic_string_view __str) const { return this->substr(__pos1, __n1).compare(__str); } [[nodiscard]] constexpr int compare(size_type __pos1, size_type __n1, basic_string_view __str, size_type __pos2, size_type __n2) const { return this->substr(__pos1, __n1).compare(__str.substr(__pos2, __n2)); } [[nodiscard, __gnu__::__nonnull__]] constexpr int compare(const _CharT* __str) const noexcept { return this->compare(basic_string_view{__str}); } [[nodiscard, __gnu__::__nonnull__]] constexpr int compare(size_type __pos1, size_type __n1, const _CharT* __str) const { return this->substr(__pos1, __n1).compare(basic_string_view{__str}); } [[nodiscard]] constexpr int compare(size_type __pos1, size_type __n1, const _CharT* __str, size_type __n2) const noexcept(false) { return this->substr(__pos1, __n1) .compare(basic_string_view(__str, __n2)); } #ifdef __cpp_lib_starts_ends_with // C++ >= 20 [[nodiscard]] constexpr bool starts_with(basic_string_view __x) const noexcept { return this->substr(0, __x.size()) == __x; } [[nodiscard]] constexpr bool starts_with(_CharT __x) const noexcept { return !this->empty() && traits_type::eq(this->front(), __x); } [[nodiscard, __gnu__::__nonnull__]] constexpr bool starts_with(const _CharT* __x) const noexcept { return this->starts_with(basic_string_view(__x)); } [[nodiscard]] constexpr bool ends_with(basic_string_view __x) const noexcept { const auto __len = this->size(); const auto __xlen = __x.size(); return __len >= __xlen && traits_type::compare(end() - __xlen, __x.data(), __xlen) == 0; } [[nodiscard]] constexpr bool ends_with(_CharT __x) const noexcept { return !this->empty() && traits_type::eq(this->back(), __x); } [[nodiscard, __gnu__::__nonnull__]] constexpr bool ends_with(const _CharT* __x) const noexcept { return this->ends_with(basic_string_view(__x)); } #endif // __cpp_lib_starts_ends_with #if __cplusplus > 202002L #if _GLIBCXX_HOSTED && !defined(__cpp_lib_string_contains) // This FTM is not freestanding as it also implies matching // support, and is omitted from the freestanding subset. # error "libstdc++ bug: string_contains not defined when it should be" #endif // HOSTED [[nodiscard]] constexpr bool contains(basic_string_view __x) const noexcept { return this->find(__x) != npos; } [[nodiscard]] constexpr bool contains(_CharT __x) const noexcept { return this->find(__x) != npos; } [[nodiscard, __gnu__::__nonnull__]] constexpr bool contains(const _CharT* __x) const noexcept { return this->find(__x) != npos; } #endif // C++23 // [string.view.find], searching [[nodiscard]] constexpr size_type find(basic_string_view __str, size_type __pos = 0) const noexcept { return this->find(__str._M_str, __pos, __str._M_len); } [[nodiscard]] constexpr size_type find(_CharT __c, size_type __pos = 0) const noexcept; [[nodiscard]] constexpr size_type find(const _CharT* __str, size_type __pos, size_type __n) const noexcept; [[nodiscard, __gnu__::__nonnull__]] constexpr size_type find(const _CharT* __str, size_type __pos = 0) const noexcept { return this->find(__str, __pos, traits_type::length(__str)); } [[nodiscard]] constexpr size_type rfind(basic_string_view __str, size_type __pos = npos) const noexcept { return this->rfind(__str._M_str, __pos, __str._M_len); } [[nodiscard]] constexpr size_type rfind(_CharT __c, size_type __pos = npos) const noexcept; [[nodiscard]] constexpr size_type rfind(const _CharT* __str, size_type __pos, size_type __n) const noexcept; [[nodiscard, __gnu__::__nonnull__]] constexpr size_type rfind(const _CharT* __str, size_type __pos = npos) const noexcept { return this->rfind(__str, __pos, traits_type::length(__str)); } [[nodiscard]] constexpr size_type find_first_of(basic_string_view __str, size_type __pos = 0) const noexcept { return this->find_first_of(__str._M_str, __pos, __str._M_len); } [[nodiscard]] constexpr size_type find_first_of(_CharT __c, size_type __pos = 0) const noexcept { return this->find(__c, __pos); } [[nodiscard]] constexpr size_type find_first_of(const _CharT* __str, size_type __pos, size_type __n) const noexcept; [[nodiscard, __gnu__::__nonnull__]] constexpr size_type find_first_of(const _CharT* __str, size_type __pos = 0) const noexcept { return this->find_first_of(__str, __pos, traits_type::length(__str)); } [[nodiscard]] constexpr size_type find_last_of(basic_string_view __str, size_type __pos = npos) const noexcept { return this->find_last_of(__str._M_str, __pos, __str._M_len); } [[nodiscard]] constexpr size_type find_last_of(_CharT __c, size_type __pos=npos) const noexcept { return this->rfind(__c, __pos); } [[nodiscard]] constexpr size_type find_last_of(const _CharT* __str, size_type __pos, size_type __n) const noexcept; [[nodiscard, __gnu__::__nonnull__]] constexpr size_type find_last_of(const _CharT* __str, size_type __pos = npos) const noexcept { return this->find_last_of(__str, __pos, traits_type::length(__str)); } [[nodiscard]] constexpr size_type find_first_not_of(basic_string_view __str, size_type __pos = 0) const noexcept { return this->find_first_not_of(__str._M_str, __pos, __str._M_len); } [[nodiscard]] constexpr size_type find_first_not_of(_CharT __c, size_type __pos = 0) const noexcept; [[nodiscard]] constexpr size_type find_first_not_of(const _CharT* __str, size_type __pos, size_type __n) const noexcept; [[nodiscard, __gnu__::__nonnull__]] constexpr size_type find_first_not_of(const _CharT* __str, size_type __pos = 0) const noexcept { return this->find_first_not_of(__str, __pos, traits_type::length(__str)); } [[nodiscard]] constexpr size_type find_last_not_of(basic_string_view __str, size_type __pos = npos) const noexcept { return this->find_last_not_of(__str._M_str, __pos, __str._M_len); } [[nodiscard]] constexpr size_type find_last_not_of(_CharT __c, size_type __pos = npos) const noexcept; [[nodiscard]] constexpr size_type find_last_not_of(const _CharT* __str, size_type __pos, size_type __n) const noexcept; [[nodiscard, __gnu__::__nonnull__]] constexpr size_type find_last_not_of(const _CharT* __str, size_type __pos = npos) const noexcept { return this->find_last_not_of(__str, __pos, traits_type::length(__str)); } private: static constexpr int _S_compare(size_type __n1, size_type __n2) noexcept { using __limits = __gnu_cxx::__int_traits; const difference_type __diff = __n1 - __n2; if (__diff > __limits::__max) return __limits::__max; if (__diff < __limits::__min) return __limits::__min; return static_cast(__diff); } size_t _M_len; const _CharT* _M_str; }; #if __cplusplus > 201703L && __cpp_lib_concepts && __cpp_deduction_guides template _End> basic_string_view(_It, _End) -> basic_string_view>; #if __cplusplus > 202002L template basic_string_view(_Range&&) -> basic_string_view>; #endif #endif // [string.view.comparison], non-member basic_string_view comparison function // Several of these functions use type_identity_t to create a non-deduced // context, so that only one argument participates in template argument // deduction and the other argument gets implicitly converted to the deduced // type (see N3766). #if __cpp_lib_three_way_comparison template [[nodiscard]] constexpr bool operator==(basic_string_view<_CharT, _Traits> __x, type_identity_t> __y) noexcept { return __x.size() == __y.size() && __x.compare(__y) == 0; } template [[nodiscard]] constexpr auto operator<=>(basic_string_view<_CharT, _Traits> __x, __type_identity_t> __y) noexcept -> decltype(__detail::__char_traits_cmp_cat<_Traits>(0)) { return __detail::__char_traits_cmp_cat<_Traits>(__x.compare(__y)); } #else template [[nodiscard]] constexpr bool operator==(basic_string_view<_CharT, _Traits> __x, __type_identity_t> __y) noexcept { return __x.size() == __y.size() && __x.compare(__y) == 0; } template [[nodiscard]] constexpr bool operator==(basic_string_view<_CharT, _Traits> __x, basic_string_view<_CharT, _Traits> __y) noexcept { return __x.size() == __y.size() && __x.compare(__y) == 0; } template [[nodiscard]] constexpr bool operator==(__type_identity_t> __x, basic_string_view<_CharT, _Traits> __y) noexcept { return __x.size() == __y.size() && __x.compare(__y) == 0; } template [[nodiscard]] constexpr bool operator!=(basic_string_view<_CharT, _Traits> __x, basic_string_view<_CharT, _Traits> __y) noexcept { return !(__x == __y); } template [[nodiscard]] constexpr bool operator!=(basic_string_view<_CharT, _Traits> __x, __type_identity_t> __y) noexcept { return !(__x == __y); } template [[nodiscard]] constexpr bool operator!=(__type_identity_t> __x, basic_string_view<_CharT, _Traits> __y) noexcept { return !(__x == __y); } template [[nodiscard]] constexpr bool operator< (basic_string_view<_CharT, _Traits> __x, basic_string_view<_CharT, _Traits> __y) noexcept { return __x.compare(__y) < 0; } template [[nodiscard]] constexpr bool operator< (basic_string_view<_CharT, _Traits> __x, __type_identity_t> __y) noexcept { return __x.compare(__y) < 0; } template [[nodiscard]] constexpr bool operator< (__type_identity_t> __x, basic_string_view<_CharT, _Traits> __y) noexcept { return __x.compare(__y) < 0; } template [[nodiscard]] constexpr bool operator> (basic_string_view<_CharT, _Traits> __x, basic_string_view<_CharT, _Traits> __y) noexcept { return __x.compare(__y) > 0; } template [[nodiscard]] constexpr bool operator> (basic_string_view<_CharT, _Traits> __x, __type_identity_t> __y) noexcept { return __x.compare(__y) > 0; } template [[nodiscard]] constexpr bool operator> (__type_identity_t> __x, basic_string_view<_CharT, _Traits> __y) noexcept { return __x.compare(__y) > 0; } template [[nodiscard]] constexpr bool operator<=(basic_string_view<_CharT, _Traits> __x, basic_string_view<_CharT, _Traits> __y) noexcept { return __x.compare(__y) <= 0; } template [[nodiscard]] constexpr bool operator<=(basic_string_view<_CharT, _Traits> __x, __type_identity_t> __y) noexcept { return __x.compare(__y) <= 0; } template [[nodiscard]] constexpr bool operator<=(__type_identity_t> __x, basic_string_view<_CharT, _Traits> __y) noexcept { return __x.compare(__y) <= 0; } template [[nodiscard]] constexpr bool operator>=(basic_string_view<_CharT, _Traits> __x, basic_string_view<_CharT, _Traits> __y) noexcept { return __x.compare(__y) >= 0; } template [[nodiscard]] constexpr bool operator>=(basic_string_view<_CharT, _Traits> __x, __type_identity_t> __y) noexcept { return __x.compare(__y) >= 0; } template [[nodiscard]] constexpr bool operator>=(__type_identity_t> __x, basic_string_view<_CharT, _Traits> __y) noexcept { return __x.compare(__y) >= 0; } #endif // three-way comparison #if _GLIBCXX_HOSTED // [string.view.io], Inserters and extractors template inline basic_ostream<_CharT, _Traits>& operator<<(basic_ostream<_CharT, _Traits>& __os, basic_string_view<_CharT,_Traits> __str) { return __ostream_insert(__os, __str.data(), __str.size()); } #endif // HOSTED // basic_string_view typedef names using string_view = basic_string_view; using wstring_view = basic_string_view; #ifdef _GLIBCXX_USE_CHAR8_T using u8string_view = basic_string_view; #endif using u16string_view = basic_string_view; using u32string_view = basic_string_view; // [string.view.hash], hash support: template struct hash; template<> struct hash : public __hash_base { [[nodiscard]] size_t operator()(const string_view& __str) const noexcept { return std::_Hash_impl::hash(__str.data(), __str.length()); } }; template<> struct __is_fast_hash> : std::false_type { }; template<> struct hash : public __hash_base { [[nodiscard]] size_t operator()(const wstring_view& __s) const noexcept { return std::_Hash_impl::hash(__s.data(), __s.length() * sizeof(wchar_t)); } }; template<> struct __is_fast_hash> : std::false_type { }; #ifdef _GLIBCXX_USE_CHAR8_T template<> struct hash : public __hash_base { [[nodiscard]] size_t operator()(const u8string_view& __str) const noexcept { return std::_Hash_impl::hash(__str.data(), __str.length()); } }; template<> struct __is_fast_hash> : std::false_type { }; #endif template<> struct hash : public __hash_base { [[nodiscard]] size_t operator()(const u16string_view& __s) const noexcept { return std::_Hash_impl::hash(__s.data(), __s.length() * sizeof(char16_t)); } }; template<> struct __is_fast_hash> : std::false_type { }; template<> struct hash : public __hash_base { [[nodiscard]] size_t operator()(const u32string_view& __s) const noexcept { return std::_Hash_impl::hash(__s.data(), __s.length() * sizeof(char32_t)); } }; template<> struct __is_fast_hash> : std::false_type { }; inline namespace literals { inline namespace string_view_literals { #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wliteral-suffix" inline constexpr basic_string_view operator""sv(const char* __str, size_t __len) noexcept { return basic_string_view{__str, __len}; } inline constexpr basic_string_view operator""sv(const wchar_t* __str, size_t __len) noexcept { return basic_string_view{__str, __len}; } #ifdef _GLIBCXX_USE_CHAR8_T inline constexpr basic_string_view operator""sv(const char8_t* __str, size_t __len) noexcept { return basic_string_view{__str, __len}; } #endif inline constexpr basic_string_view operator""sv(const char16_t* __str, size_t __len) noexcept { return basic_string_view{__str, __len}; } inline constexpr basic_string_view operator""sv(const char32_t* __str, size_t __len) noexcept { return basic_string_view{__str, __len}; } #pragma GCC diagnostic pop } // namespace string_literals } // namespace literals #if __cpp_lib_concepts namespace ranges { // Opt-in to borrowed_range concept template inline constexpr bool enable_borrowed_range> = true; // Opt-in to view concept template inline constexpr bool enable_view> = true; } #endif _GLIBCXX_END_NAMESPACE_VERSION } // namespace std #include #endif // __cplusplus <= 201402L #endif // _GLIBCXX_EXPERIMENTAL_STRING_VIEW