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 template class BasicStringPiece<string16>;
41 #endif
42
operator ==(const StringPiece & x,const StringPiece & y)43 bool operator==(const StringPiece& x, const StringPiece& y) {
44 if (x.size() != y.size())
45 return false;
46
47 return CharTraits<StringPiece::value_type>::compare(x.data(), y.data(),
48 x.size()) == 0;
49 }
50
operator <<(std::ostream & o,const StringPiece & piece)51 std::ostream& operator<<(std::ostream& o, const StringPiece& piece) {
52 o.write(piece.data(), static_cast<std::streamsize>(piece.size()));
53 return o;
54 }
55
56 namespace internal {
57
58 template<typename STR>
CopyToStringT(const BasicStringPiece<STR> & self,STR * target)59 void CopyToStringT(const BasicStringPiece<STR>& self, STR* target) {
60 if (self.empty())
61 target->clear();
62 else
63 target->assign(self.data(), self.size());
64 }
65
CopyToString(const StringPiece & self,std::string * target)66 void CopyToString(const StringPiece& self, std::string* target) {
67 CopyToStringT(self, target);
68 }
69
CopyToString(const StringPiece16 & self,string16 * target)70 void CopyToString(const StringPiece16& self, string16* target) {
71 CopyToStringT(self, target);
72 }
73
74 template<typename STR>
AppendToStringT(const BasicStringPiece<STR> & self,STR * target)75 void AppendToStringT(const BasicStringPiece<STR>& self, STR* target) {
76 if (!self.empty())
77 target->append(self.data(), self.size());
78 }
79
AppendToString(const StringPiece & self,std::string * target)80 void AppendToString(const StringPiece& self, std::string* target) {
81 AppendToStringT(self, target);
82 }
83
AppendToString(const StringPiece16 & self,string16 * target)84 void AppendToString(const StringPiece16& self, string16* target) {
85 AppendToStringT(self, target);
86 }
87
88 template<typename STR>
copyT(const BasicStringPiece<STR> & self,typename STR::value_type * buf,size_t n,size_t pos)89 size_t copyT(const BasicStringPiece<STR>& self,
90 typename STR::value_type* buf,
91 size_t n,
92 size_t pos) {
93 size_t ret = std::min(self.size() - pos, n);
94 memcpy(buf, self.data() + pos, ret * sizeof(typename STR::value_type));
95 return ret;
96 }
97
copy(const StringPiece & self,char * buf,size_t n,size_t pos)98 size_t copy(const StringPiece& self, char* buf, size_t n, size_t pos) {
99 return copyT(self, buf, n, pos);
100 }
101
copy(const StringPiece16 & self,char16 * buf,size_t n,size_t pos)102 size_t copy(const StringPiece16& self, char16* buf, size_t n, size_t pos) {
103 return copyT(self, buf, n, pos);
104 }
105
106 template<typename STR>
findT(const BasicStringPiece<STR> & self,const BasicStringPiece<STR> & s,size_t pos)107 size_t findT(const BasicStringPiece<STR>& self,
108 const BasicStringPiece<STR>& s,
109 size_t pos) {
110 if (pos > self.size())
111 return BasicStringPiece<STR>::npos;
112
113 typename BasicStringPiece<STR>::const_iterator result =
114 std::search(self.begin() + pos, self.end(), s.begin(), s.end());
115 const size_t xpos =
116 static_cast<size_t>(result - self.begin());
117 return xpos + s.size() <= self.size() ? xpos : BasicStringPiece<STR>::npos;
118 }
119
find(const StringPiece & self,const StringPiece & s,size_t pos)120 size_t find(const StringPiece& self, const StringPiece& s, size_t pos) {
121 return findT(self, s, pos);
122 }
123
find(const StringPiece16 & self,const StringPiece16 & s,size_t pos)124 size_t find(const StringPiece16& self, const StringPiece16& s, size_t pos) {
125 return findT(self, s, pos);
126 }
127
128 template<typename STR>
findT(const BasicStringPiece<STR> & self,typename STR::value_type c,size_t pos)129 size_t findT(const BasicStringPiece<STR>& self,
130 typename STR::value_type c,
131 size_t pos) {
132 if (pos >= self.size())
133 return BasicStringPiece<STR>::npos;
134
135 typename BasicStringPiece<STR>::const_iterator result =
136 std::find(self.begin() + pos, self.end(), c);
137 return result != self.end() ?
138 static_cast<size_t>(result - self.begin()) : BasicStringPiece<STR>::npos;
139 }
140
find(const StringPiece & self,char c,size_t pos)141 size_t find(const StringPiece& self, char c, size_t pos) {
142 return findT(self, c, pos);
143 }
144
find(const StringPiece16 & self,char16 c,size_t pos)145 size_t find(const StringPiece16& self, char16 c, size_t pos) {
146 return findT(self, c, pos);
147 }
148
149 template<typename STR>
rfindT(const BasicStringPiece<STR> & self,const BasicStringPiece<STR> & s,size_t pos)150 size_t rfindT(const BasicStringPiece<STR>& self,
151 const BasicStringPiece<STR>& s,
152 size_t pos) {
153 if (self.size() < s.size())
154 return BasicStringPiece<STR>::npos;
155
156 if (s.empty())
157 return std::min(self.size(), pos);
158
159 typename BasicStringPiece<STR>::const_iterator last =
160 self.begin() + std::min(self.size() - s.size(), pos) + s.size();
161 typename BasicStringPiece<STR>::const_iterator result =
162 std::find_end(self.begin(), last, s.begin(), s.end());
163 return result != last ?
164 static_cast<size_t>(result - self.begin()) : BasicStringPiece<STR>::npos;
165 }
166
rfind(const StringPiece & self,const StringPiece & s,size_t pos)167 size_t rfind(const StringPiece& self, const StringPiece& s, size_t pos) {
168 return rfindT(self, s, pos);
169 }
170
rfind(const StringPiece16 & self,const StringPiece16 & s,size_t pos)171 size_t rfind(const StringPiece16& self, const StringPiece16& s, size_t pos) {
172 return rfindT(self, s, pos);
173 }
174
175 template<typename STR>
rfindT(const BasicStringPiece<STR> & self,typename STR::value_type c,size_t pos)176 size_t rfindT(const BasicStringPiece<STR>& self,
177 typename STR::value_type c,
178 size_t pos) {
179 if (self.size() == 0)
180 return BasicStringPiece<STR>::npos;
181
182 for (size_t i = std::min(pos, self.size() - 1); ;
183 --i) {
184 if (self.data()[i] == c)
185 return i;
186 if (i == 0)
187 break;
188 }
189 return BasicStringPiece<STR>::npos;
190 }
191
rfind(const StringPiece & self,char c,size_t pos)192 size_t rfind(const StringPiece& self, char c, size_t pos) {
193 return rfindT(self, c, pos);
194 }
195
rfind(const StringPiece16 & self,char16 c,size_t pos)196 size_t rfind(const StringPiece16& self, char16 c, size_t pos) {
197 return rfindT(self, c, pos);
198 }
199
200 // 8-bit version using lookup table.
find_first_of(const StringPiece & self,const StringPiece & s,size_t pos)201 size_t find_first_of(const StringPiece& self,
202 const StringPiece& s,
203 size_t pos) {
204 if (self.size() == 0 || s.size() == 0)
205 return StringPiece::npos;
206
207 // Avoid the cost of BuildLookupTable() for a single-character search.
208 if (s.size() == 1)
209 return find(self, s.data()[0], pos);
210
211 bool lookup[UCHAR_MAX + 1] = { false };
212 BuildLookupTable(s, lookup);
213 for (size_t i = pos; i < self.size(); ++i) {
214 if (lookup[static_cast<unsigned char>(self.data()[i])]) {
215 return i;
216 }
217 }
218 return StringPiece::npos;
219 }
220
221 // 16-bit brute force version.
find_first_of(const StringPiece16 & self,const StringPiece16 & s,size_t pos)222 size_t find_first_of(const StringPiece16& self,
223 const StringPiece16& s,
224 size_t pos) {
225 StringPiece16::const_iterator found =
226 std::find_first_of(self.begin() + pos, self.end(), s.begin(), s.end());
227 if (found == self.end())
228 return StringPiece16::npos;
229 return found - self.begin();
230 }
231
232 // 8-bit version using lookup table.
find_first_not_of(const StringPiece & self,const StringPiece & s,size_t pos)233 size_t find_first_not_of(const StringPiece& self,
234 const StringPiece& s,
235 size_t pos) {
236 if (self.size() == 0)
237 return StringPiece::npos;
238
239 if (s.size() == 0)
240 return 0;
241
242 // Avoid the cost of BuildLookupTable() for a single-character search.
243 if (s.size() == 1)
244 return find_first_not_of(self, s.data()[0], pos);
245
246 bool lookup[UCHAR_MAX + 1] = { false };
247 BuildLookupTable(s, lookup);
248 for (size_t i = pos; i < self.size(); ++i) {
249 if (!lookup[static_cast<unsigned char>(self.data()[i])]) {
250 return i;
251 }
252 }
253 return StringPiece::npos;
254 }
255
256 // 16-bit brute-force version.
find_first_not_of(const StringPiece16 & self,const StringPiece16 & s,size_t pos)257 BASE_EXPORT size_t find_first_not_of(const StringPiece16& self,
258 const StringPiece16& s,
259 size_t pos) {
260 if (self.size() == 0)
261 return StringPiece16::npos;
262
263 for (size_t self_i = pos; self_i < self.size(); ++self_i) {
264 bool found = false;
265 for (size_t s_i = 0; s_i < s.size(); ++s_i) {
266 if (self[self_i] == s[s_i]) {
267 found = true;
268 break;
269 }
270 }
271 if (!found)
272 return self_i;
273 }
274 return StringPiece16::npos;
275 }
276
277 template<typename STR>
find_first_not_ofT(const BasicStringPiece<STR> & self,typename STR::value_type c,size_t pos)278 size_t find_first_not_ofT(const BasicStringPiece<STR>& self,
279 typename STR::value_type c,
280 size_t pos) {
281 if (self.size() == 0)
282 return BasicStringPiece<STR>::npos;
283
284 for (; pos < self.size(); ++pos) {
285 if (self.data()[pos] != c) {
286 return pos;
287 }
288 }
289 return BasicStringPiece<STR>::npos;
290 }
291
find_first_not_of(const StringPiece & self,char c,size_t pos)292 size_t find_first_not_of(const StringPiece& self,
293 char c,
294 size_t pos) {
295 return find_first_not_ofT(self, c, pos);
296 }
297
find_first_not_of(const StringPiece16 & self,char16 c,size_t pos)298 size_t find_first_not_of(const StringPiece16& self,
299 char16 c,
300 size_t pos) {
301 return find_first_not_ofT(self, c, pos);
302 }
303
304 // 8-bit version using lookup table.
find_last_of(const StringPiece & self,const StringPiece & s,size_t pos)305 size_t find_last_of(const StringPiece& self, const StringPiece& s, size_t pos) {
306 if (self.size() == 0 || s.size() == 0)
307 return StringPiece::npos;
308
309 // Avoid the cost of BuildLookupTable() for a single-character search.
310 if (s.size() == 1)
311 return rfind(self, s.data()[0], pos);
312
313 bool lookup[UCHAR_MAX + 1] = { false };
314 BuildLookupTable(s, lookup);
315 for (size_t i = std::min(pos, self.size() - 1); ; --i) {
316 if (lookup[static_cast<unsigned char>(self.data()[i])])
317 return i;
318 if (i == 0)
319 break;
320 }
321 return StringPiece::npos;
322 }
323
324 // 16-bit brute-force version.
find_last_of(const StringPiece16 & self,const StringPiece16 & s,size_t pos)325 size_t find_last_of(const StringPiece16& self,
326 const StringPiece16& s,
327 size_t pos) {
328 if (self.size() == 0)
329 return StringPiece16::npos;
330
331 for (size_t self_i = std::min(pos, self.size() - 1); ;
332 --self_i) {
333 for (size_t s_i = 0; s_i < s.size(); s_i++) {
334 if (self.data()[self_i] == s[s_i])
335 return self_i;
336 }
337 if (self_i == 0)
338 break;
339 }
340 return StringPiece16::npos;
341 }
342
343 // 8-bit version using lookup table.
find_last_not_of(const StringPiece & self,const StringPiece & s,size_t pos)344 size_t find_last_not_of(const StringPiece& self,
345 const StringPiece& s,
346 size_t pos) {
347 if (self.size() == 0)
348 return StringPiece::npos;
349
350 size_t i = std::min(pos, self.size() - 1);
351 if (s.size() == 0)
352 return i;
353
354 // Avoid the cost of BuildLookupTable() for a single-character search.
355 if (s.size() == 1)
356 return find_last_not_of(self, s.data()[0], pos);
357
358 bool lookup[UCHAR_MAX + 1] = { false };
359 BuildLookupTable(s, lookup);
360 for (; ; --i) {
361 if (!lookup[static_cast<unsigned char>(self.data()[i])])
362 return i;
363 if (i == 0)
364 break;
365 }
366 return StringPiece::npos;
367 }
368
369 // 16-bit brute-force version.
find_last_not_of(const StringPiece16 & self,const StringPiece16 & s,size_t pos)370 size_t find_last_not_of(const StringPiece16& self,
371 const StringPiece16& s,
372 size_t pos) {
373 if (self.size() == 0)
374 return StringPiece::npos;
375
376 for (size_t self_i = std::min(pos, self.size() - 1); ; --self_i) {
377 bool found = false;
378 for (size_t s_i = 0; s_i < s.size(); s_i++) {
379 if (self.data()[self_i] == s[s_i]) {
380 found = true;
381 break;
382 }
383 }
384 if (!found)
385 return self_i;
386 if (self_i == 0)
387 break;
388 }
389 return StringPiece16::npos;
390 }
391
392 template<typename STR>
find_last_not_ofT(const BasicStringPiece<STR> & self,typename STR::value_type c,size_t pos)393 size_t find_last_not_ofT(const BasicStringPiece<STR>& self,
394 typename STR::value_type c,
395 size_t pos) {
396 if (self.size() == 0)
397 return BasicStringPiece<STR>::npos;
398
399 for (size_t i = std::min(pos, self.size() - 1); ; --i) {
400 if (self.data()[i] != c)
401 return i;
402 if (i == 0)
403 break;
404 }
405 return BasicStringPiece<STR>::npos;
406 }
407
find_last_not_of(const StringPiece & self,char c,size_t pos)408 size_t find_last_not_of(const StringPiece& self,
409 char c,
410 size_t pos) {
411 return find_last_not_ofT(self, c, pos);
412 }
413
find_last_not_of(const StringPiece16 & self,char16 c,size_t pos)414 size_t find_last_not_of(const StringPiece16& self,
415 char16 c,
416 size_t pos) {
417 return find_last_not_ofT(self, c, pos);
418 }
419
420 template<typename STR>
substrT(const BasicStringPiece<STR> & self,size_t pos,size_t n)421 BasicStringPiece<STR> substrT(const BasicStringPiece<STR>& self,
422 size_t pos,
423 size_t n) {
424 if (pos > self.size()) pos = self.size();
425 if (n > self.size() - pos) n = self.size() - pos;
426 return BasicStringPiece<STR>(self.data() + pos, n);
427 }
428
substr(const StringPiece & self,size_t pos,size_t n)429 StringPiece substr(const StringPiece& self,
430 size_t pos,
431 size_t n) {
432 return substrT(self, pos, n);
433 }
434
substr(const StringPiece16 & self,size_t pos,size_t n)435 StringPiece16 substr(const StringPiece16& self,
436 size_t pos,
437 size_t n) {
438 return substrT(self, pos, n);
439 }
440
441 #if DCHECK_IS_ON()
AssertIteratorsInOrder(std::string::const_iterator begin,std::string::const_iterator end)442 void AssertIteratorsInOrder(std::string::const_iterator begin,
443 std::string::const_iterator end) {
444 DCHECK(begin <= end) << "StringPiece iterators swapped or invalid.";
445 }
AssertIteratorsInOrder(string16::const_iterator begin,string16::const_iterator end)446 void AssertIteratorsInOrder(string16::const_iterator begin,
447 string16::const_iterator end) {
448 DCHECK(begin <= end) << "StringPiece iterators swapped or invalid.";
449 }
450 #endif
451
452 } // namespace internal
453 } // namespace base
454