/* * Copyright 2021 Google LLC. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #ifndef SkStringView_DEFINED #define SkStringView_DEFINED #include #include #include namespace skstd { class string_view { public: using value_type = char; using traits_type = std::char_traits; using const_pointer = const value_type*; using const_reference = const value_type&; using iterator = const_pointer; using const_iterator = iterator; using size_type = size_t; static constexpr size_type npos = size_type(-1); constexpr string_view() : fData(nullptr) , fLength(0) {} constexpr string_view(const string_view&) = default; constexpr string_view(const_pointer data, size_type length) : fData(data) , fLength(length) {} string_view(const_pointer data) : string_view(data, strlen(data)) {} string_view(const std::string& str) : string_view(str.data(), str.length()) {} constexpr string_view& operator=(const string_view&) = default; constexpr iterator begin() const { return fData; } constexpr iterator end() const { return fData + fLength; } constexpr const_reference operator[](size_type idx) const { return fData[idx]; } constexpr const_reference front() const { return fData[0]; } constexpr const_reference back() const { return fData[fLength - 1]; } constexpr const_pointer data() const { return fData; } constexpr size_type size() const { return fLength; } constexpr size_type length() const { return fLength; } constexpr bool empty() const { return fLength == 0; } constexpr bool starts_with(string_view s) const { if (s.length() > fLength) { return false; } return s.length() == 0 || !memcmp(fData, s.fData, s.length()); } constexpr bool starts_with(value_type c) const { return !this->empty() && this->front() == c; } constexpr bool ends_with(string_view s) const { if (s.length() > fLength) { return false; } return s.length() == 0 || !memcmp(this->end() - s.length(), s.fData, s.length()); } constexpr bool ends_with(value_type c) const { return !this->empty() && this->back() == c; } size_type find(string_view needle, size_type pos = 0) const { if (needle.length() == 0) { return 0; } if (this->length() < needle.length()) { return npos; } const char* match = nullptr; const char* start = this->data() + pos; const char* end = start + this->length() - needle.length() + 1; while ((match = (const char*)(memchr(start, needle[0], (size_t)(end - start))))) { if (!memcmp(match, needle.data(), needle.length())) { return (size_type)(match - this->data()); } else { start = match + 1; } } return npos; } bool contains(string_view needle) const { return this->find(needle) != npos; } constexpr string_view substr(size_type pos = 0, size_type count = npos) const { if (pos > fLength) { return {}; } return string_view{fData + pos, std::min(count, fLength - pos)}; } constexpr void swap(string_view& other) { const_pointer tempData = fData; fData = other.fData; other.fData = tempData; size_type tempLength = fLength; fLength = other.fLength; other.fLength = tempLength; } constexpr void remove_prefix(size_type n) { fData += n; fLength -= n; } constexpr void remove_suffix(size_type n) { fLength -= n; } private: const_pointer fData; size_type fLength; }; bool operator==(string_view left, string_view right); bool operator!=(string_view left, string_view right); bool operator<(string_view left, string_view right); bool operator<=(string_view left, string_view right); bool operator>(string_view left, string_view right); bool operator>=(string_view left, string_view right); } // namespace skstd namespace std { template<> struct hash { size_t operator()(const skstd::string_view& s) const { size_t result = 0; for (auto iter = s.begin(); iter != s.end(); ++iter) { result = result * 101 + (size_t) *iter; } return result; } }; } // namespace std #endif