#pragma once /** * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0. */ /** * To keep ABI compatability, we use CRT's own string view implementation even for C++ 17. */ #include #include #include #include #include #include #if __cplusplus >= 201703L || (defined(_MSC_LANG) && _MSC_LANG >= 201703L) # include #endif namespace Aws { namespace Crt { template > class basic_string_view { 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 = static_cast(-1); // constructors and assignment constexpr basic_string_view() noexcept : m_size{0}, m_data{nullptr} {} constexpr basic_string_view(const basic_string_view &) noexcept = default; constexpr basic_string_view(const CharT *s) noexcept : m_size{traits_type::length(s)}, m_data{s} {} constexpr basic_string_view(const CharT *s, size_type length) noexcept : m_size{length}, m_data{s} {} basic_string_view &operator=(const basic_string_view &) noexcept = default; #if __cplusplus >= 201703L || (defined(_MSC_LANG) && _MSC_LANG >= 201703L) constexpr basic_string_view(const std::basic_string_view &other) noexcept : m_size(other.size()), m_data(other.data()) { } basic_string_view &operator=(const std::basic_string_view &other) noexcept { m_data = other->data(); m_size = other->size(); return *this; } #endif // iterators constexpr const_iterator begin() const noexcept { return this->m_data; } constexpr const_iterator end() const noexcept { return this->m_data + this->m_size; } constexpr const_iterator cbegin() const noexcept { return this->m_data; } constexpr const_iterator cend() const noexcept { return this->m_data + this->m_size; } constexpr const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(this->end()); } constexpr const_reverse_iterator rend() const noexcept { return const_reverse_iterator(this->begin()); } constexpr const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator(this->end()); } constexpr const_reverse_iterator crend() const noexcept { return const_reverse_iterator(this->begin()); } constexpr size_type size() const noexcept { return this->m_size; } constexpr size_type length() const noexcept { return m_size; } constexpr size_type max_size() const noexcept { return (std::numeric_limits::max)(); } constexpr bool empty() const noexcept { return this->m_size == 0; } // element accessors const_reference operator[](size_type pos) const noexcept { assert(pos < m_size); return *(this->m_data + pos); } const_reference at(size_type pos) const { assert(pos < m_size); return *(this->m_data + pos); } const_reference front() const noexcept { assert(m_size > 0); return *this->m_data; } const_reference back() const noexcept { assert(m_size > 0); return *(this->m_data + this->m_size - 1); } constexpr const_pointer data() const noexcept { return this->m_data; } // modifiers void remove_prefix(size_type n) noexcept { assert(this->m_size >= n); this->m_data += n; this->m_size -= n; } void remove_suffix(size_type n) noexcept { this->m_size -= n; } void swap(basic_string_view &other) noexcept { auto tmp = *this; *this = other; other = tmp; } // string operations size_type copy(CharT *s, size_type n, size_type pos = 0) const { assert(pos <= size()); const size_type copyLen = (std::min)(n, m_size - pos); traits_type::copy(s, data() + pos, copyLen); return copyLen; } basic_string_view substr(size_type pos = 0, size_type n = npos) const noexcept(false) { assert(pos <= size()); const size_type copyLen = (std::min)(n, m_size - pos); return basic_string_view{m_data + pos, copyLen}; } int compare(const basic_string_view &s) const noexcept { const size_type compareLen = (std::min)(this->m_size, s.m_size); int ret = traits_type::compare(this->m_data, s.m_data, compareLen); if (ret == 0) { ret = _s_compare(this->m_size, s.m_size); } return ret; } constexpr int compare(size_type pos1, size_type n1, const basic_string_view &s) const { return this->substr(pos1, n1).compare(s); } constexpr int compare( size_type pos1, size_type n1, const basic_string_view &s, size_type pos2, size_type n2) const { return this->substr(pos1, n1).compare(s.substr(pos2, n2)); } constexpr int compare(const CharT *s) const noexcept { return this->compare(basic_string_view{s}); } constexpr int compare(size_type pos1, size_type n1, const CharT *s) const { return this->substr(pos1, n1).compare(basic_string_view{s}); } constexpr int compare(size_type pos1, size_type n1, const CharT *s, size_type n2) const noexcept(false) { return this->substr(pos1, n1).compare(basic_string_view(s, n2)); } constexpr bool starts_with(const basic_string_view &other) const noexcept { return this->substr(0, other.size()) == other; } constexpr bool starts_with(CharT c) const noexcept { return !this->empty() && traits_type::eq(this->front(), c); } constexpr bool starts_with(const CharT *s) const noexcept { return this->starts_with(basic_string_view(s)); } constexpr bool ends_with(const basic_string_view &other) const noexcept { return this->m_size >= other.m_size && this->compare(this->m_size - other.m_size, npos, other) == 0; } constexpr bool ends_with(CharT c) const noexcept { return !this->empty() && traits_type::eq(this->back(), c); } constexpr bool ends_with(const CharT *s) const noexcept { return this->ends_with(basic_string_view(s)); } // find utilities constexpr size_type find(const basic_string_view &s, size_type pos = 0) const noexcept { return this->find(s.m_data, pos, s.m_size); } size_type find(CharT c, size_type pos = 0) const noexcept { if (pos >= m_size) { return npos; } const CharT *r = Traits::find(m_data + pos, m_size - pos, c); if (r == nullptr) { return npos; } return static_cast(r - m_data); } size_type find(const CharT *s, size_type pos, size_type n) const noexcept { if (n && !s) { return npos; } if (pos > m_size) { return npos; } if (n == 0) { return pos; } const CharT *r = _s_search_substr(m_data + pos, m_data + m_size, s, s + n); if (r == m_data + m_size) { return npos; } return static_cast(r - m_data); } constexpr size_type find(const CharT *s, size_type pos = 0) const noexcept { return this->find(s, pos, traits_type::length(s)); } size_type rfind(basic_string_view s, size_type pos = npos) const noexcept { if (s.m_size && !s.m_data) { return npos; } return this->rfind(s.m_data, pos, s.m_size); } size_type rfind(CharT c, size_type pos = npos) const noexcept { if (m_size <= 0) { return npos; } if (pos < m_size) { ++pos; } else { pos = m_size; } for (const CharT *ptr = m_data + pos; ptr != m_data;) { if (Traits::eq(*--ptr, c)) { return static_cast(ptr - m_data); } } return npos; } size_type rfind(const CharT *s, size_type pos, size_type n) const noexcept { if (n && !s) { return npos; } pos = (std::min)(pos, m_size); if (n < m_size - pos) { pos += n; } else { pos = m_size; } const CharT *r = _s_find_end(m_data, m_data + pos, s, s + n); if (n > 0 && r == m_data + pos) { return npos; } return static_cast(r - m_data); } constexpr size_type rfind(const CharT *s, size_type pos = npos) const noexcept { return this->rfind(s, pos, traits_type::length(s)); } constexpr size_type find_first_of(basic_string_view s, size_type pos = 0) const noexcept { return this->find_first_of(s.m_data, pos, s.m_size); } constexpr size_type find_first_of(CharT c, size_type pos = 0) const noexcept { return this->find(c, pos); } size_type find_first_of(const CharT *s, size_type pos, size_type n) const noexcept { if (pos >= m_size || !n || !s) { return npos; } const CharT *r = _s_find_first_of_ce(m_data + pos, m_data + m_size, s, s + n); if (r == m_data + m_size) { return npos; } return static_cast(r - m_data); } constexpr size_type find_first_of(const CharT *s, size_type pos = 0) const noexcept { return this->find_first_of(s, pos, traits_type::length(s)); } constexpr size_type find_last_of(basic_string_view s, size_type pos = npos) const noexcept { return this->find_last_of(s.m_data, pos, s.m_size); } constexpr size_type find_last_of(CharT c, size_type pos = npos) const noexcept { return this->rfind(c, pos); } size_type find_last_of(const CharT *s, size_type pos, size_type n) const noexcept { if (!n || s == nullptr) { return npos; } if (pos < m_size) { ++pos; } else { pos = m_size; } for (const CharT *ptr = m_data + pos; ptr != m_data;) { const CharT *r = Traits::find(s, n, *--ptr); if (r) { return static_cast(ptr - m_data); } } return npos; } constexpr size_type find_last_of(const CharT *s, size_type pos = npos) const noexcept { return this->find_last_of(s, pos, traits_type::length(s)); } size_type find_first_not_of(basic_string_view s, size_type pos = 0) const noexcept { if (s.m_size && !s.m_data) { return npos; } return this->find_first_not_of(s.m_data, pos, s.m_size); } size_type find_first_not_of(CharT c, size_type pos = 0) const noexcept { if (!m_data || pos >= m_size) { return npos; } const CharT *pend = m_data + m_size; for (const CharT *ptr = m_data + pos; ptr != pend; ++ptr) { if (!Traits::eq(*ptr, c)) { return static_cast(ptr - m_data); } } return npos; } size_type find_first_not_of(const CharT *s, size_type pos, size_type n) const noexcept { if (n && s == nullptr) { return npos; } if (m_data == nullptr || pos >= m_size) { return npos; } const CharT *pend = m_data + m_size; for (const CharT *ptr = m_data + pos; ptr != pend; ++ptr) { if (Traits::find(s, n, *ptr) == 0) { return static_cast(ptr - m_data); } } return npos; } constexpr size_type find_first_not_of(const CharT *s, size_type pos = 0) const noexcept { return this->find_first_not_of(s, pos, traits_type::length(s)); } size_type find_last_not_of(basic_string_view s, size_type pos = npos) const noexcept { if (s.m_size && !s.m_data) { return npos; } return this->find_last_not_of(s.m_data, pos, s.m_size); } size_type find_last_not_of(CharT c, size_type pos = npos) const noexcept { if (pos < m_size) { ++pos; } else { pos = m_size; } for (const CharT *ptr = m_data + pos; ptr != m_data;) { if (!Traits::eq(*--ptr, c)) { return static_cast(ptr - m_data); } } return npos; } size_type find_last_not_of(const CharT *s, size_type pos, size_type n) const noexcept { if (n && !s) { return npos; } if (pos < m_size) { ++pos; } else { pos = m_size; } for (const CharT *ptr = m_data + pos; ptr != m_data;) { if (Traits::find(s, n, *--ptr) == 0) { return static_cast(ptr - m_data); } } return npos; } constexpr size_type find_last_not_of(const CharT *s, size_type pos = npos) const noexcept { return this->find_last_not_of(s, pos, traits_type::length(s)); } private: static int _s_compare(size_type n1, size_type n2) noexcept { const difference_type diff = n1 - n2; if (diff > (std::numeric_limits::max)()) { return (std::numeric_limits::max)(); } if (diff < (std::numeric_limits::min)()) { return (std::numeric_limits::min)(); } return static_cast(diff); } static const CharT *_s_search_substr( const CharT *first1, const CharT *last1, const CharT *first2, const CharT *last2) { const ptrdiff_t length2 = last2 - first2; if (length2 == 0) { return first1; } ptrdiff_t length1 = last1 - first1; if (length1 < length2) { return last1; } while (true) { length1 = last1 - first1; if (length1 < length2) { return last1; } first1 = Traits::find(first1, length1 - length2 + 1, *first2); if (first1 == 0) { return last1; } if (Traits::compare(first1, first2, length2) == 0) { return first1; } ++first1; } } static const CharT *_s_find_end( const CharT *first1, const CharT *last1, const CharT *first2, const CharT *last2) { const CharT *r = last1; if (first2 == last2) { return r; } while (true) { while (true) { if (first1 == last1) { return r; } if (Traits::eq(*first1, *first2)) { break; } ++first1; } const CharT *m1 = first1; const CharT *m2 = first2; while (true) { if (++m2 == last2) { r = first1; ++first1; break; } if (++m1 == last1) { return r; } if (!Traits::eq(*m1, *m2)) { ++first1; break; } } } } static const CharT *_s_find_first_of_ce( const CharT *first1, const CharT *last1, const CharT *first2, const CharT *last2) { for (; first1 != last1; ++first1) { for (const CharT *ptr = first2; ptr != last2; ++ptr) { if (Traits::eq(*first1, *ptr)) { return first1; } } } return last1; } size_type m_size; const CharT *m_data; }; // operator == template bool operator==( const basic_string_view &lhs, const basic_string_view &rhs) noexcept { return (lhs.size() != rhs.size()) ? false : lhs.compare(rhs) == 0; } template bool operator==( const basic_string_view &lhs, typename std::common_type>::type &rhs) noexcept { return (lhs.size() != rhs.size()) ? false : lhs.compare(rhs) == 0; } template bool operator==( typename std::common_type>::type &lhs, const basic_string_view &rhs) noexcept { return (lhs.size() != rhs.size()) ? false : lhs.compare(rhs) == 0; } // operator != template bool operator!=( const basic_string_view &lhs, const basic_string_view &rhs) noexcept { return (lhs.size() != rhs.size()) ? true : lhs.compare(rhs) != 0; } template bool operator!=( const basic_string_view &lhs, typename std::common_type>::type &rhs) noexcept { return (lhs.size() != rhs.size()) ? true : lhs.compare(rhs) != 0; } template bool operator!=( typename std::common_type>::type &lhs, const basic_string_view &rhs) noexcept { return (lhs.size() != rhs.size()) ? true : lhs.compare(rhs) != 0; } // operator < template bool operator<( const basic_string_view &lhs, const basic_string_view &rhs) noexcept { return lhs.compare(rhs) < 0; } template constexpr bool operator<( const basic_string_view &lhs, typename std::common_type>::type &rhs) noexcept { return lhs.compare(rhs) < 0; } template constexpr bool operator<( typename std::common_type>::type &lhs, const basic_string_view &rhs) noexcept { return lhs.compare(rhs) < 0; } // operator > template constexpr bool operator>( const basic_string_view &lhs, const basic_string_view &rhs) noexcept { return lhs.compare(rhs) > 0; } template constexpr bool operator>( const basic_string_view &lhs, typename std::common_type>::type &rhs) noexcept { return lhs.compare(rhs) > 0; } template constexpr bool operator>( typename std::common_type>::type &lhs, const basic_string_view &rhs) noexcept { return lhs.compare(rhs) > 0; } // operator <= template constexpr bool operator<=( const basic_string_view &lhs, const basic_string_view &rhs) noexcept { return lhs.compare(rhs) <= 0; } template constexpr bool operator<=( const basic_string_view &lhs, typename std::common_type>::type &rhs) noexcept { return lhs.compare(rhs) <= 0; } template constexpr bool operator<=( typename std::common_type>::type &lhs, const basic_string_view &rhs) noexcept { return lhs.compare(rhs) <= 0; } // operator >= template constexpr bool operator>=( const basic_string_view &lhs, const basic_string_view &rhs) noexcept { return lhs.compare(rhs) >= 0; } template constexpr bool operator>=( const basic_string_view &lhs, typename std::common_type>::type &rhs) noexcept { return lhs.compare(rhs) >= 0; } template constexpr bool operator>=( typename std::common_type>::type &lhs, const basic_string_view &rhs) noexcept { return lhs.compare(rhs) >= 0; } typedef basic_string_view string_view; typedef basic_string_view u16string_view; typedef basic_string_view u32string_view; typedef basic_string_view wstring_view; inline namespace literals { inline namespace string_view_literals { inline basic_string_view operator"" _sv(const char *s, size_t length) noexcept { return basic_string_view(s, length); } inline basic_string_view operator"" _sv(const wchar_t *s, size_t length) noexcept { return basic_string_view(s, length); } inline basic_string_view operator"" _sv(const char16_t *s, size_t length) noexcept { return basic_string_view(s, length); } inline basic_string_view operator"" _sv(const char32_t *s, size_t length) noexcept { return basic_string_view(s, length); } } // namespace string_view_literals } // namespace literals using StringView = string_view; } // namespace Crt } // namespace Aws // hash namespace std { template struct hash> { size_t operator()(const Aws::Crt::basic_string_view &val) const noexcept; }; template size_t hash>::operator()( const Aws::Crt::basic_string_view &val) const noexcept { auto str = std::basic_string(val.data(), val.size()); return std::hash>()(str); } } // namespace std