blob: 482c9fc9205c53101591725af2e2a22b2c2e41f0 [file] [log] [blame]
Vitaly Bukacbed2062015-08-17 12:54:05 -07001// 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
Alex Vakulenko674f0eb2016-01-20 08:10:48 -08008#include <limits.h>
9
Vitaly Bukacbed2062015-08-17 12:54:05 -070010#include <algorithm>
11#include <ostream>
12
Alex Vakulenko674f0eb2016-01-20 08:10:48 -080013#include "base/logging.h"
14
Vitaly Bukacbed2062015-08-17 12:54:05 -070015namespace base {
16namespace {
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]
26inline 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)
39template class BasicStringPiece<std::string>;
Vitaly Bukacbed2062015-08-17 12:54:05 -070040#endif
41
42bool 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
49std::ostream& operator<<(std::ostream& o, const StringPiece& piece) {
50 o.write(piece.data(), static_cast<std::streamsize>(piece.size()));
51 return o;
52}
53
54namespace internal {
55
56template<typename STR>
57void 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
64void CopyToString(const StringPiece& self, std::string* target) {
65 CopyToStringT(self, target);
66}
67
Vitaly Bukacbed2062015-08-17 12:54:05 -070068template<typename STR>
69void AppendToStringT(const BasicStringPiece<STR>& self, STR* target) {
70 if (!self.empty())
71 target->append(self.data(), self.size());
72}
73
74void AppendToString(const StringPiece& self, std::string* target) {
75 AppendToStringT(self, target);
76}
77
Vitaly Bukacbed2062015-08-17 12:54:05 -070078template<typename STR>
79size_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
88size_t copy(const StringPiece& self, char* buf, size_t n, size_t pos) {
89 return copyT(self, buf, n, pos);
90}
91
Vitaly Bukacbed2062015-08-17 12:54:05 -070092template<typename STR>
93size_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
106size_t find(const StringPiece& self, const StringPiece& s, size_t pos) {
107 return findT(self, s, pos);
108}
109
Vitaly Bukacbed2062015-08-17 12:54:05 -0700110template<typename STR>
111size_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
123size_t find(const StringPiece& self, char c, size_t pos) {
124 return findT(self, c, pos);
125}
126
Vitaly Bukacbed2062015-08-17 12:54:05 -0700127template<typename STR>
128size_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
145size_t rfind(const StringPiece& self, const StringPiece& s, size_t pos) {
146 return rfindT(self, s, pos);
147}
148
Vitaly Bukacbed2062015-08-17 12:54:05 -0700149template<typename STR>
150size_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
166size_t rfind(const StringPiece& self, char c, size_t pos) {
167 return rfindT(self, c, pos);
168}
169
Vitaly Bukacbed2062015-08-17 12:54:05 -0700170// 8-bit version using lookup table.
171size_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
Vitaly Bukacbed2062015-08-17 12:54:05 -0700191// 8-bit version using lookup table.
192size_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
Vitaly Bukacbed2062015-08-17 12:54:05 -0700215template<typename STR>
216size_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
230size_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
Vitaly Bukacbed2062015-08-17 12:54:05 -0700236// 8-bit version using lookup table.
237size_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
Vitaly Bukacbed2062015-08-17 12:54:05 -0700256// 8-bit version using lookup table.
257size_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
Vitaly Bukacbed2062015-08-17 12:54:05 -0700282template<typename STR>
283size_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
298size_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
Vitaly Bukacbed2062015-08-17 12:54:05 -0700304template<typename STR>
305BasicStringPiece<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
313StringPiece substr(const StringPiece& self,
314 size_t pos,
315 size_t n) {
316 return substrT(self, pos, n);
317}
318
Vitaly Bukacbed2062015-08-17 12:54:05 -0700319} // namespace internal
320} // namespace base