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