1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 // Copied from strings/stringpiece.cc with modifications
5
6 #include "base/strings/string_piece.h"
7
8 #include <limits.h>
9
10 #include <algorithm>
11 #include <ostream>
12
13 #include "base/logging.h"
14
15 namespace base {
16 namespace {
17
18 // For each character in characters_wanted, sets the index corresponding
19 // to the ASCII code of that character to 1 in table. This is used by
20 // the find_.*_of methods below to tell whether or not a character is in
21 // the lookup table in constant time.
22 // The argument `table' must be an array that is large enough to hold all
23 // the possible values of an unsigned char. Thus it should be be declared
24 // as follows:
25 // bool table[UCHAR_MAX + 1]
BuildLookupTable(const StringPiece & characters_wanted,bool * table)26 inline void BuildLookupTable(const StringPiece& characters_wanted,
27 bool* table) {
28 const size_t length = characters_wanted.length();
29 const char* const data = characters_wanted.data();
30 for (size_t i = 0; i < length; ++i) {
31 table[static_cast<unsigned char>(data[i])] = true;
32 }
33 }
34
35 } // namespace
36
37 // MSVC doesn't like complex extern templates and DLLs.
38 #if !defined(COMPILER_MSVC)
39 template class BasicStringPiece<std::string>;
40 #endif
41
operator ==(const StringPiece & x,const StringPiece & y)42 bool operator==(const StringPiece& x, const StringPiece& y) {
43 if (x.size() != y.size())
44 return false;
45
46 return StringPiece::wordmemcmp(x.data(), y.data(), x.size()) == 0;
47 }
48
operator <<(std::ostream & o,const StringPiece & piece)49 std::ostream& operator<<(std::ostream& o, const StringPiece& piece) {
50 o.write(piece.data(), static_cast<std::streamsize>(piece.size()));
51 return o;
52 }
53
54 namespace internal {
55
56 template<typename STR>
CopyToStringT(const BasicStringPiece<STR> & self,STR * target)57 void CopyToStringT(const BasicStringPiece<STR>& self, STR* target) {
58 if (self.empty())
59 target->clear();
60 else
61 target->assign(self.data(), self.size());
62 }
63
CopyToString(const StringPiece & self,std::string * target)64 void CopyToString(const StringPiece& self, std::string* target) {
65 CopyToStringT(self, target);
66 }
67
68 template<typename STR>
AppendToStringT(const BasicStringPiece<STR> & self,STR * target)69 void AppendToStringT(const BasicStringPiece<STR>& self, STR* target) {
70 if (!self.empty())
71 target->append(self.data(), self.size());
72 }
73
AppendToString(const StringPiece & self,std::string * target)74 void AppendToString(const StringPiece& self, std::string* target) {
75 AppendToStringT(self, target);
76 }
77
78 template<typename STR>
copyT(const BasicStringPiece<STR> & self,typename STR::value_type * buf,size_t n,size_t pos)79 size_t copyT(const BasicStringPiece<STR>& self,
80 typename STR::value_type* buf,
81 size_t n,
82 size_t pos) {
83 size_t ret = std::min(self.size() - pos, n);
84 memcpy(buf, self.data() + pos, ret * sizeof(typename STR::value_type));
85 return ret;
86 }
87
copy(const StringPiece & self,char * buf,size_t n,size_t pos)88 size_t copy(const StringPiece& self, char* buf, size_t n, size_t pos) {
89 return copyT(self, buf, n, pos);
90 }
91
92 template<typename STR>
findT(const BasicStringPiece<STR> & self,const BasicStringPiece<STR> & s,size_t pos)93 size_t findT(const BasicStringPiece<STR>& self,
94 const BasicStringPiece<STR>& s,
95 size_t pos) {
96 if (pos > self.size())
97 return BasicStringPiece<STR>::npos;
98
99 typename BasicStringPiece<STR>::const_iterator result =
100 std::search(self.begin() + pos, self.end(), s.begin(), s.end());
101 const size_t xpos =
102 static_cast<size_t>(result - self.begin());
103 return xpos + s.size() <= self.size() ? xpos : BasicStringPiece<STR>::npos;
104 }
105
find(const StringPiece & self,const StringPiece & s,size_t pos)106 size_t find(const StringPiece& self, const StringPiece& s, size_t pos) {
107 return findT(self, s, pos);
108 }
109
110 template<typename STR>
findT(const BasicStringPiece<STR> & self,typename STR::value_type c,size_t pos)111 size_t findT(const BasicStringPiece<STR>& self,
112 typename STR::value_type c,
113 size_t pos) {
114 if (pos >= self.size())
115 return BasicStringPiece<STR>::npos;
116
117 typename BasicStringPiece<STR>::const_iterator result =
118 std::find(self.begin() + pos, self.end(), c);
119 return result != self.end() ?
120 static_cast<size_t>(result - self.begin()) : BasicStringPiece<STR>::npos;
121 }
122
find(const StringPiece & self,char c,size_t pos)123 size_t find(const StringPiece& self, char c, size_t pos) {
124 return findT(self, c, pos);
125 }
126
127 template<typename STR>
rfindT(const BasicStringPiece<STR> & self,const BasicStringPiece<STR> & s,size_t pos)128 size_t rfindT(const BasicStringPiece<STR>& self,
129 const BasicStringPiece<STR>& s,
130 size_t pos) {
131 if (self.size() < s.size())
132 return BasicStringPiece<STR>::npos;
133
134 if (s.empty())
135 return std::min(self.size(), pos);
136
137 typename BasicStringPiece<STR>::const_iterator last =
138 self.begin() + std::min(self.size() - s.size(), pos) + s.size();
139 typename BasicStringPiece<STR>::const_iterator result =
140 std::find_end(self.begin(), last, s.begin(), s.end());
141 return result != last ?
142 static_cast<size_t>(result - self.begin()) : BasicStringPiece<STR>::npos;
143 }
144
rfind(const StringPiece & self,const StringPiece & s,size_t pos)145 size_t rfind(const StringPiece& self, const StringPiece& s, size_t pos) {
146 return rfindT(self, s, pos);
147 }
148
149 template<typename STR>
rfindT(const BasicStringPiece<STR> & self,typename STR::value_type c,size_t pos)150 size_t rfindT(const BasicStringPiece<STR>& self,
151 typename STR::value_type c,
152 size_t pos) {
153 if (self.size() == 0)
154 return BasicStringPiece<STR>::npos;
155
156 for (size_t i = std::min(pos, self.size() - 1); ;
157 --i) {
158 if (self.data()[i] == c)
159 return i;
160 if (i == 0)
161 break;
162 }
163 return BasicStringPiece<STR>::npos;
164 }
165
rfind(const StringPiece & self,char c,size_t pos)166 size_t rfind(const StringPiece& self, char c, size_t pos) {
167 return rfindT(self, c, pos);
168 }
169
170 // 8-bit version using lookup table.
find_first_of(const StringPiece & self,const StringPiece & s,size_t pos)171 size_t find_first_of(const StringPiece& self,
172 const StringPiece& s,
173 size_t pos) {
174 if (self.size() == 0 || s.size() == 0)
175 return StringPiece::npos;
176
177 // Avoid the cost of BuildLookupTable() for a single-character search.
178 if (s.size() == 1)
179 return find(self, s.data()[0], pos);
180
181 bool lookup[UCHAR_MAX + 1] = { false };
182 BuildLookupTable(s, lookup);
183 for (size_t i = pos; i < self.size(); ++i) {
184 if (lookup[static_cast<unsigned char>(self.data()[i])]) {
185 return i;
186 }
187 }
188 return StringPiece::npos;
189 }
190
191 // 8-bit version using lookup table.
find_first_not_of(const StringPiece & self,const StringPiece & s,size_t pos)192 size_t find_first_not_of(const StringPiece& self,
193 const StringPiece& s,
194 size_t pos) {
195 if (self.size() == 0)
196 return StringPiece::npos;
197
198 if (s.size() == 0)
199 return 0;
200
201 // Avoid the cost of BuildLookupTable() for a single-character search.
202 if (s.size() == 1)
203 return find_first_not_of(self, s.data()[0], pos);
204
205 bool lookup[UCHAR_MAX + 1] = { false };
206 BuildLookupTable(s, lookup);
207 for (size_t i = pos; i < self.size(); ++i) {
208 if (!lookup[static_cast<unsigned char>(self.data()[i])]) {
209 return i;
210 }
211 }
212 return StringPiece::npos;
213 }
214
215 template<typename STR>
find_first_not_ofT(const BasicStringPiece<STR> & self,typename STR::value_type c,size_t pos)216 size_t find_first_not_ofT(const BasicStringPiece<STR>& self,
217 typename STR::value_type c,
218 size_t pos) {
219 if (self.size() == 0)
220 return BasicStringPiece<STR>::npos;
221
222 for (; pos < self.size(); ++pos) {
223 if (self.data()[pos] != c) {
224 return pos;
225 }
226 }
227 return BasicStringPiece<STR>::npos;
228 }
229
find_first_not_of(const StringPiece & self,char c,size_t pos)230 size_t find_first_not_of(const StringPiece& self,
231 char c,
232 size_t pos) {
233 return find_first_not_ofT(self, c, pos);
234 }
235
236 // 8-bit version using lookup table.
find_last_of(const StringPiece & self,const StringPiece & s,size_t pos)237 size_t find_last_of(const StringPiece& self, const StringPiece& s, size_t pos) {
238 if (self.size() == 0 || s.size() == 0)
239 return StringPiece::npos;
240
241 // Avoid the cost of BuildLookupTable() for a single-character search.
242 if (s.size() == 1)
243 return rfind(self, s.data()[0], pos);
244
245 bool lookup[UCHAR_MAX + 1] = { false };
246 BuildLookupTable(s, lookup);
247 for (size_t i = std::min(pos, self.size() - 1); ; --i) {
248 if (lookup[static_cast<unsigned char>(self.data()[i])])
249 return i;
250 if (i == 0)
251 break;
252 }
253 return StringPiece::npos;
254 }
255
256 // 8-bit version using lookup table.
find_last_not_of(const StringPiece & self,const StringPiece & s,size_t pos)257 size_t find_last_not_of(const StringPiece& self,
258 const StringPiece& s,
259 size_t pos) {
260 if (self.size() == 0)
261 return StringPiece::npos;
262
263 size_t i = std::min(pos, self.size() - 1);
264 if (s.size() == 0)
265 return i;
266
267 // Avoid the cost of BuildLookupTable() for a single-character search.
268 if (s.size() == 1)
269 return find_last_not_of(self, s.data()[0], pos);
270
271 bool lookup[UCHAR_MAX + 1] = { false };
272 BuildLookupTable(s, lookup);
273 for (; ; --i) {
274 if (!lookup[static_cast<unsigned char>(self.data()[i])])
275 return i;
276 if (i == 0)
277 break;
278 }
279 return StringPiece::npos;
280 }
281
282 template<typename STR>
find_last_not_ofT(const BasicStringPiece<STR> & self,typename STR::value_type c,size_t pos)283 size_t find_last_not_ofT(const BasicStringPiece<STR>& self,
284 typename STR::value_type c,
285 size_t pos) {
286 if (self.size() == 0)
287 return BasicStringPiece<STR>::npos;
288
289 for (size_t i = std::min(pos, self.size() - 1); ; --i) {
290 if (self.data()[i] != c)
291 return i;
292 if (i == 0)
293 break;
294 }
295 return BasicStringPiece<STR>::npos;
296 }
297
find_last_not_of(const StringPiece & self,char c,size_t pos)298 size_t find_last_not_of(const StringPiece& self,
299 char c,
300 size_t pos) {
301 return find_last_not_ofT(self, c, pos);
302 }
303
304 template<typename STR>
substrT(const BasicStringPiece<STR> & self,size_t pos,size_t n)305 BasicStringPiece<STR> substrT(const BasicStringPiece<STR>& self,
306 size_t pos,
307 size_t n) {
308 if (pos > self.size()) pos = self.size();
309 if (n > self.size() - pos) n = self.size() - pos;
310 return BasicStringPiece<STR>(self.data() + pos, n);
311 }
312
substr(const StringPiece & self,size_t pos,size_t n)313 StringPiece substr(const StringPiece& self,
314 size_t pos,
315 size_t n) {
316 return substrT(self, pos, n);
317 }
318
319 } // namespace internal
320 } // namespace base
321