michael@0: // Copyright (c) 2012 The Chromium Authors. All rights reserved. michael@0: // Use of this source code is governed by a BSD-style license that can be michael@0: // found in the LICENSE file. michael@0: // Copied from strings/stringpiece.cc with modifications michael@0: michael@0: #include "base/strings/string_piece.h" michael@0: michael@0: #include michael@0: #include michael@0: michael@0: namespace base { michael@0: michael@0: // MSVC doesn't like complex extern templates and DLLs. michael@0: #if !defined(COMPILER_MSVC) michael@0: namespace internal { michael@0: template class StringPieceDetail; michael@0: template class StringPieceDetail; michael@0: } // namespace internal michael@0: michael@0: template class BasicStringPiece; michael@0: #endif michael@0: michael@0: bool operator==(const StringPiece& x, const StringPiece& y) { michael@0: if (x.size() != y.size()) michael@0: return false; michael@0: michael@0: return StringPiece::wordmemcmp(x.data(), y.data(), x.size()) == 0; michael@0: } michael@0: michael@0: std::ostream& operator<<(std::ostream& o, const StringPiece& piece) { michael@0: o.write(piece.data(), static_cast(piece.size())); michael@0: return o; michael@0: } michael@0: michael@0: namespace internal { michael@0: void CopyToString(const StringPiece& self, std::string* target) { michael@0: target->assign(!self.empty() ? self.data() : "", self.size()); michael@0: } michael@0: michael@0: void AppendToString(const StringPiece& self, std::string* target) { michael@0: if (!self.empty()) michael@0: target->append(self.data(), self.size()); michael@0: } michael@0: michael@0: StringPiece::size_type copy(const StringPiece& self, michael@0: char* buf, michael@0: StringPiece::size_type n, michael@0: StringPiece::size_type pos) { michael@0: StringPiece::size_type ret = std::min(self.size() - pos, n); michael@0: memcpy(buf, self.data() + pos, ret); michael@0: return ret; michael@0: } michael@0: michael@0: StringPiece::size_type find(const StringPiece& self, michael@0: const StringPiece& s, michael@0: StringPiece::size_type pos) { michael@0: if (pos > self.size()) michael@0: return StringPiece::npos; michael@0: michael@0: StringPiece::const_iterator result = michael@0: std::search(self.begin() + pos, self.end(), s.begin(), s.end()); michael@0: const StringPiece::size_type xpos = michael@0: static_cast(result - self.begin()); michael@0: return xpos + s.size() <= self.size() ? xpos : StringPiece::npos; michael@0: } michael@0: michael@0: StringPiece::size_type find(const StringPiece& self, michael@0: char c, michael@0: StringPiece::size_type pos) { michael@0: if (pos >= self.size()) michael@0: return StringPiece::npos; michael@0: michael@0: StringPiece::const_iterator result = michael@0: std::find(self.begin() + pos, self.end(), c); michael@0: return result != self.end() ? michael@0: static_cast(result - self.begin()) : StringPiece::npos; michael@0: } michael@0: michael@0: StringPiece::size_type rfind(const StringPiece& self, michael@0: const StringPiece& s, michael@0: StringPiece::size_type pos) { michael@0: if (self.size() < s.size()) michael@0: return StringPiece::npos; michael@0: michael@0: if (s.empty()) michael@0: return std::min(self.size(), pos); michael@0: michael@0: StringPiece::const_iterator last = michael@0: self.begin() + std::min(self.size() - s.size(), pos) + s.size(); michael@0: StringPiece::const_iterator result = michael@0: std::find_end(self.begin(), last, s.begin(), s.end()); michael@0: return result != last ? michael@0: static_cast(result - self.begin()) : StringPiece::npos; michael@0: } michael@0: michael@0: StringPiece::size_type rfind(const StringPiece& self, michael@0: char c, michael@0: StringPiece::size_type pos) { michael@0: if (self.size() == 0) michael@0: return StringPiece::npos; michael@0: michael@0: for (StringPiece::size_type i = std::min(pos, self.size() - 1); ; --i) { michael@0: if (self.data()[i] == c) michael@0: return i; michael@0: if (i == 0) michael@0: break; michael@0: } michael@0: return StringPiece::npos; michael@0: } michael@0: michael@0: // For each character in characters_wanted, sets the index corresponding michael@0: // to the ASCII code of that character to 1 in table. This is used by michael@0: // the find_.*_of methods below to tell whether or not a character is in michael@0: // the lookup table in constant time. michael@0: // The argument `table' must be an array that is large enough to hold all michael@0: // the possible values of an unsigned char. Thus it should be be declared michael@0: // as follows: michael@0: // bool table[UCHAR_MAX + 1] michael@0: static inline void BuildLookupTable(const StringPiece& characters_wanted, michael@0: bool* table) { michael@0: const StringPiece::size_type length = characters_wanted.length(); michael@0: const char* const data = characters_wanted.data(); michael@0: for (StringPiece::size_type i = 0; i < length; ++i) { michael@0: table[static_cast(data[i])] = true; michael@0: } michael@0: } michael@0: michael@0: StringPiece::size_type find_first_of(const StringPiece& self, michael@0: const StringPiece& s, michael@0: StringPiece::size_type pos) { michael@0: if (self.size() == 0 || s.size() == 0) michael@0: return StringPiece::npos; michael@0: michael@0: // Avoid the cost of BuildLookupTable() for a single-character search. michael@0: if (s.size() == 1) michael@0: return find(self, s.data()[0], pos); michael@0: michael@0: bool lookup[UCHAR_MAX + 1] = { false }; michael@0: BuildLookupTable(s, lookup); michael@0: for (StringPiece::size_type i = pos; i < self.size(); ++i) { michael@0: if (lookup[static_cast(self.data()[i])]) { michael@0: return i; michael@0: } michael@0: } michael@0: return StringPiece::npos; michael@0: } michael@0: michael@0: StringPiece::size_type find_first_not_of(const StringPiece& self, michael@0: const StringPiece& s, michael@0: StringPiece::size_type pos) { michael@0: if (self.size() == 0) michael@0: return StringPiece::npos; michael@0: michael@0: if (s.size() == 0) michael@0: return 0; michael@0: michael@0: // Avoid the cost of BuildLookupTable() for a single-character search. michael@0: if (s.size() == 1) michael@0: return find_first_not_of(self, s.data()[0], pos); michael@0: michael@0: bool lookup[UCHAR_MAX + 1] = { false }; michael@0: BuildLookupTable(s, lookup); michael@0: for (StringPiece::size_type i = pos; i < self.size(); ++i) { michael@0: if (!lookup[static_cast(self.data()[i])]) { michael@0: return i; michael@0: } michael@0: } michael@0: return StringPiece::npos; michael@0: } michael@0: michael@0: StringPiece::size_type find_first_not_of(const StringPiece& self, michael@0: char c, michael@0: StringPiece::size_type pos) { michael@0: if (self.size() == 0) michael@0: return StringPiece::npos; michael@0: michael@0: for (; pos < self.size(); ++pos) { michael@0: if (self.data()[pos] != c) { michael@0: return pos; michael@0: } michael@0: } michael@0: return StringPiece::npos; michael@0: } michael@0: michael@0: StringPiece::size_type find_last_of(const StringPiece& self, michael@0: const StringPiece& s, michael@0: StringPiece::size_type pos) { michael@0: if (self.size() == 0 || s.size() == 0) michael@0: return StringPiece::npos; michael@0: michael@0: // Avoid the cost of BuildLookupTable() for a single-character search. michael@0: if (s.size() == 1) michael@0: return rfind(self, s.data()[0], pos); michael@0: michael@0: bool lookup[UCHAR_MAX + 1] = { false }; michael@0: BuildLookupTable(s, lookup); michael@0: for (StringPiece::size_type i = std::min(pos, self.size() - 1); ; --i) { michael@0: if (lookup[static_cast(self.data()[i])]) michael@0: return i; michael@0: if (i == 0) michael@0: break; michael@0: } michael@0: return StringPiece::npos; michael@0: } michael@0: michael@0: StringPiece::size_type find_last_not_of(const StringPiece& self, michael@0: const StringPiece& s, michael@0: StringPiece::size_type pos) { michael@0: if (self.size() == 0) michael@0: return StringPiece::npos; michael@0: michael@0: StringPiece::size_type i = std::min(pos, self.size() - 1); michael@0: if (s.size() == 0) michael@0: return i; michael@0: michael@0: // Avoid the cost of BuildLookupTable() for a single-character search. michael@0: if (s.size() == 1) michael@0: return find_last_not_of(self, s.data()[0], pos); michael@0: michael@0: bool lookup[UCHAR_MAX + 1] = { false }; michael@0: BuildLookupTable(s, lookup); michael@0: for (; ; --i) { michael@0: if (!lookup[static_cast(self.data()[i])]) michael@0: return i; michael@0: if (i == 0) michael@0: break; michael@0: } michael@0: return StringPiece::npos; michael@0: } michael@0: michael@0: StringPiece::size_type find_last_not_of(const StringPiece& self, michael@0: char c, michael@0: StringPiece::size_type pos) { michael@0: if (self.size() == 0) michael@0: return StringPiece::npos; michael@0: michael@0: for (StringPiece::size_type i = std::min(pos, self.size() - 1); ; --i) { michael@0: if (self.data()[i] != c) michael@0: return i; michael@0: if (i == 0) michael@0: break; michael@0: } michael@0: return StringPiece::npos; michael@0: } michael@0: michael@0: StringPiece substr(const StringPiece& self, michael@0: StringPiece::size_type pos, michael@0: StringPiece::size_type n) { michael@0: if (pos > self.size()) pos = self.size(); michael@0: if (n > self.size() - pos) n = self.size() - pos; michael@0: return StringPiece(self.data() + pos, n); michael@0: } michael@0: michael@0: } // namespace internal michael@0: } // namespace base