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 <algorithm> 9 #include <ostream> 10 11 namespace base { 12 13 // MSVC doesn't like complex extern templates and DLLs. 14 #if !defined(COMPILER_MSVC) 15 namespace internal { 16 template class StringPieceDetail<std::string>; 17 template class StringPieceDetail<string16>; 18 } // namespace internal 19 20 template class BasicStringPiece<string16>; 21 #endif 22 23 bool operator==(const StringPiece& x, const StringPiece& y) { 24 if (x.size() != y.size()) 25 return false; 26 27 return StringPiece::wordmemcmp(x.data(), y.data(), x.size()) == 0; 28 } 29 30 std::ostream& operator<<(std::ostream& o, const StringPiece& piece) { 31 o.write(piece.data(), static_cast<std::streamsize>(piece.size())); 32 return o; 33 } 34 35 namespace internal { 36 void CopyToString(const StringPiece& self, std::string* target) { 37 target->assign(!self.empty() ? self.data() : "", self.size()); 38 } 39 40 void AppendToString(const StringPiece& self, std::string* target) { 41 if (!self.empty()) 42 target->append(self.data(), self.size()); 43 } 44 45 StringPiece::size_type copy(const StringPiece& self, 46 char* buf, 47 StringPiece::size_type n, 48 StringPiece::size_type pos) { 49 StringPiece::size_type ret = std::min(self.size() - pos, n); 50 memcpy(buf, self.data() + pos, ret); 51 return ret; 52 } 53 54 StringPiece::size_type find(const StringPiece& self, 55 const StringPiece& s, 56 StringPiece::size_type pos) { 57 if (pos > self.size()) 58 return StringPiece::npos; 59 60 StringPiece::const_iterator result = 61 std::search(self.begin() + pos, self.end(), s.begin(), s.end()); 62 const StringPiece::size_type xpos = 63 static_cast<size_t>(result - self.begin()); 64 return xpos + s.size() <= self.size() ? xpos : StringPiece::npos; 65 } 66 67 StringPiece::size_type find(const StringPiece& self, 68 char c, 69 StringPiece::size_type pos) { 70 if (pos >= self.size()) 71 return StringPiece::npos; 72 73 StringPiece::const_iterator result = 74 std::find(self.begin() + pos, self.end(), c); 75 return result != self.end() ? 76 static_cast<size_t>(result - self.begin()) : StringPiece::npos; 77 } 78 79 StringPiece::size_type rfind(const StringPiece& self, 80 const StringPiece& s, 81 StringPiece::size_type pos) { 82 if (self.size() < s.size()) 83 return StringPiece::npos; 84 85 if (s.empty()) 86 return std::min(self.size(), pos); 87 88 StringPiece::const_iterator last = 89 self.begin() + std::min(self.size() - s.size(), pos) + s.size(); 90 StringPiece::const_iterator result = 91 std::find_end(self.begin(), last, s.begin(), s.end()); 92 return result != last ? 93 static_cast<size_t>(result - self.begin()) : StringPiece::npos; 94 } 95 96 StringPiece::size_type rfind(const StringPiece& self, 97 char c, 98 StringPiece::size_type pos) { 99 if (self.size() == 0) 100 return StringPiece::npos; 101 102 for (StringPiece::size_type i = std::min(pos, self.size() - 1); ; --i) { 103 if (self.data()[i] == c) 104 return i; 105 if (i == 0) 106 break; 107 } 108 return StringPiece::npos; 109 } 110 111 // For each character in characters_wanted, sets the index corresponding 112 // to the ASCII code of that character to 1 in table. This is used by 113 // the find_.*_of methods below to tell whether or not a character is in 114 // the lookup table in constant time. 115 // The argument `table' must be an array that is large enough to hold all 116 // the possible values of an unsigned char. Thus it should be be declared 117 // as follows: 118 // bool table[UCHAR_MAX + 1] 119 static inline void BuildLookupTable(const StringPiece& characters_wanted, 120 bool* table) { 121 const StringPiece::size_type length = characters_wanted.length(); 122 const char* const data = characters_wanted.data(); 123 for (StringPiece::size_type i = 0; i < length; ++i) { 124 table[static_cast<unsigned char>(data[i])] = true; 125 } 126 } 127 128 StringPiece::size_type find_first_of(const StringPiece& self, 129 const StringPiece& s, 130 StringPiece::size_type pos) { 131 if (self.size() == 0 || s.size() == 0) 132 return StringPiece::npos; 133 134 // Avoid the cost of BuildLookupTable() for a single-character search. 135 if (s.size() == 1) 136 return find(self, s.data()[0], pos); 137 138 bool lookup[UCHAR_MAX + 1] = { false }; 139 BuildLookupTable(s, lookup); 140 for (StringPiece::size_type i = pos; i < self.size(); ++i) { 141 if (lookup[static_cast<unsigned char>(self.data()[i])]) { 142 return i; 143 } 144 } 145 return StringPiece::npos; 146 } 147 148 StringPiece::size_type find_first_not_of(const StringPiece& self, 149 const StringPiece& s, 150 StringPiece::size_type pos) { 151 if (self.size() == 0) 152 return StringPiece::npos; 153 154 if (s.size() == 0) 155 return 0; 156 157 // Avoid the cost of BuildLookupTable() for a single-character search. 158 if (s.size() == 1) 159 return find_first_not_of(self, s.data()[0], pos); 160 161 bool lookup[UCHAR_MAX + 1] = { false }; 162 BuildLookupTable(s, lookup); 163 for (StringPiece::size_type i = pos; i < self.size(); ++i) { 164 if (!lookup[static_cast<unsigned char>(self.data()[i])]) { 165 return i; 166 } 167 } 168 return StringPiece::npos; 169 } 170 171 StringPiece::size_type find_first_not_of(const StringPiece& self, 172 char c, 173 StringPiece::size_type pos) { 174 if (self.size() == 0) 175 return StringPiece::npos; 176 177 for (; pos < self.size(); ++pos) { 178 if (self.data()[pos] != c) { 179 return pos; 180 } 181 } 182 return StringPiece::npos; 183 } 184 185 StringPiece::size_type find_last_of(const StringPiece& self, 186 const StringPiece& s, 187 StringPiece::size_type pos) { 188 if (self.size() == 0 || s.size() == 0) 189 return StringPiece::npos; 190 191 // Avoid the cost of BuildLookupTable() for a single-character search. 192 if (s.size() == 1) 193 return rfind(self, s.data()[0], pos); 194 195 bool lookup[UCHAR_MAX + 1] = { false }; 196 BuildLookupTable(s, lookup); 197 for (StringPiece::size_type i = std::min(pos, self.size() - 1); ; --i) { 198 if (lookup[static_cast<unsigned char>(self.data()[i])]) 199 return i; 200 if (i == 0) 201 break; 202 } 203 return StringPiece::npos; 204 } 205 206 StringPiece::size_type find_last_not_of(const StringPiece& self, 207 const StringPiece& s, 208 StringPiece::size_type pos) { 209 if (self.size() == 0) 210 return StringPiece::npos; 211 212 StringPiece::size_type i = std::min(pos, self.size() - 1); 213 if (s.size() == 0) 214 return i; 215 216 // Avoid the cost of BuildLookupTable() for a single-character search. 217 if (s.size() == 1) 218 return find_last_not_of(self, s.data()[0], pos); 219 220 bool lookup[UCHAR_MAX + 1] = { false }; 221 BuildLookupTable(s, lookup); 222 for (; ; --i) { 223 if (!lookup[static_cast<unsigned char>(self.data()[i])]) 224 return i; 225 if (i == 0) 226 break; 227 } 228 return StringPiece::npos; 229 } 230 231 StringPiece::size_type find_last_not_of(const StringPiece& self, 232 char c, 233 StringPiece::size_type pos) { 234 if (self.size() == 0) 235 return StringPiece::npos; 236 237 for (StringPiece::size_type i = std::min(pos, self.size() - 1); ; --i) { 238 if (self.data()[i] != c) 239 return i; 240 if (i == 0) 241 break; 242 } 243 return StringPiece::npos; 244 } 245 246 StringPiece substr(const StringPiece& self, 247 StringPiece::size_type pos, 248 StringPiece::size_type n) { 249 if (pos > self.size()) pos = self.size(); 250 if (n > self.size() - pos) n = self.size() - pos; 251 return StringPiece(self.data() + pos, n); 252 } 253 254 } // namespace internal 255 } // namespace base 256