1 /*
2  * Copyright 2021 Google LLC.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #ifndef SkStringView_DEFINED
9 #define SkStringView_DEFINED
10 
11 #include "include/core/SkTypes.h"
12 
13 #include <algorithm>
14 #include <cstring>
15 #include <string>
16 
17 namespace skstd {
18 
19 class string_view {
20 public:
21     using value_type = char;
22     using traits_type = std::char_traits<value_type>;
23     using const_pointer = const value_type*;
24     using const_reference = const value_type&;
25     using iterator = const_pointer;
26     using const_iterator = iterator;
27     using size_type = size_t;
28     static constexpr size_type npos = size_type(-1);
29 
string_view()30     constexpr string_view()
31         : fData(nullptr)
32         , fLength(0) {}
33 
34     constexpr string_view(const string_view&) = default;
35 
string_view(const_pointer data, size_type length)36     constexpr string_view(const_pointer data, size_type length)
37         : fData(data)
38         , fLength(length) {}
39 
string_view(const_pointer data)40     string_view(const_pointer data)
41         : string_view(data, strlen(data)) {}
42 
string_view(const std::string& str)43     string_view(const std::string& str)
44         : string_view(str.data(), str.length()) {}
45 
46     constexpr string_view& operator=(const string_view&) = default;
47 
begin() const48     constexpr iterator begin() const {
49         return fData;
50     }
51 
end() const52     constexpr iterator end() const {
53         return fData + fLength;
54     }
55 
operator [](size_type idx) const56     constexpr const_reference operator[](size_type idx) const {
57         return fData[idx];
58     }
59 
front() const60     constexpr const_reference front() const {
61         return fData[0];
62     }
63 
back() const64     constexpr const_reference back() const {
65         return fData[fLength - 1];
66     }
67 
data() const68     constexpr const_pointer data() const {
69         return fData;
70     }
71 
size() const72     constexpr size_type size() const {
73         return fLength;
74     }
75 
length() const76     constexpr size_type length() const {
77         return fLength;
78     }
79 
empty() const80     constexpr bool empty() const {
81         return fLength == 0;
82     }
83 
starts_with(string_view s) const84     constexpr bool starts_with(string_view s) const {
85         if (s.length() > fLength) {
86             return false;
87         }
88         return s.length() == 0 || !memcmp(fData, s.fData, s.length());
89     }
90 
starts_with(value_type c) const91     constexpr bool starts_with(value_type c) const {
92         return !this->empty() && this->front() == c;
93     }
94 
ends_with(string_view s) const95     constexpr bool ends_with(string_view s) const {
96         if (s.length() > fLength) {
97             return false;
98         }
99         return s.length() == 0 || !memcmp(this->end() - s.length(), s.fData, s.length());
100     }
101 
ends_with(value_type c) const102     constexpr bool ends_with(value_type c) const {
103         return !this->empty() && this->back() == c;
104     }
105 
find(string_view needle, size_type pos = 0) const106     size_type find(string_view needle, size_type pos = 0) const {
107         if (needle.length() == 0) {
108             return 0;
109         }
110         if (this->length() < needle.length()) {
111             return npos;
112         }
113         const char* match = nullptr;
114         const char* start = this->data() + pos;
115         const char* end = start + this->length() - needle.length() + 1;
116         while ((match = (const char*)(memchr(start, needle[0], (size_t)(end - start))))) {
117             if (!memcmp(match, needle.data(), needle.length())) {
118                 return (size_type)(match - this->data());
119             } else {
120                 start = match + 1;
121             }
122         }
123         return npos;
124     }
125 
contains(string_view needle) const126     bool contains(string_view needle) const {
127         return this->find(needle) != npos;
128     }
129 
substr(size_type pos = 0, size_type count = npos) const130     constexpr string_view substr(size_type pos = 0, size_type count = npos) const {
131         if (pos > fLength) {
132             return {};
133         }
134         return string_view{fData + pos, std::min(count, fLength - pos)};
135     }
136 
swap(string_view& other)137     constexpr void swap(string_view& other) {
138         const_pointer tempData = fData;
139         fData = other.fData;
140         other.fData = tempData;
141 
142         size_type tempLength = fLength;
143         fLength = other.fLength;
144         other.fLength = tempLength;
145     }
146 
remove_prefix(size_type n)147     constexpr void remove_prefix(size_type n) {
148         fData += n;
149         fLength -= n;
150     }
151 
remove_suffix(size_type n)152     constexpr void remove_suffix(size_type n) {
153         fLength -= n;
154     }
155 
156 private:
157     const_pointer fData;
158     size_type fLength;
159 };
160 
161 SK_API bool operator==(string_view left, string_view right);
162 
163 SK_API bool operator!=(string_view left, string_view right);
164 
165 SK_API bool operator<(string_view left, string_view right);
166 
167 SK_API bool operator<=(string_view left, string_view right);
168 
169 SK_API bool operator>(string_view left, string_view right);
170 
171 SK_API bool operator>=(string_view left, string_view right);
172 
173 } // namespace skstd
174 
175 namespace std {
176     template<> struct hash<skstd::string_view> {
operator ()std::hash177         size_t operator()(const skstd::string_view& s) const {
178             size_t result = 0;
179             for (auto iter = s.begin(); iter != s.end(); ++iter) {
180                 result = result * 101 + (size_t) *iter;
181             }
182             return result;
183         }
184     };
185 } // namespace std
186 
187 #endif
188