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