diff options
author | erikwright@chromium.org <erikwright@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-12-22 21:54:49 +0000 |
---|---|---|
committer | erikwright@chromium.org <erikwright@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-12-22 21:54:49 +0000 |
commit | b1ecd2fc7a6c45987c91051ff480dc6115d3a4dc (patch) | |
tree | 6b88220639a7390004385a28d8d17125aeb6c2e5 /base | |
parent | 11ac5c5d92903ad8e0f970442fe3d85151ea6fa8 (diff) | |
download | chromium_src-b1ecd2fc7a6c45987c91051ff480dc6115d3a4dc.zip chromium_src-b1ecd2fc7a6c45987c91051ff480dc6115d3a4dc.tar.gz chromium_src-b1ecd2fc7a6c45987c91051ff480dc6115d3a4dc.tar.bz2 |
Extract common code from StringPiece and StringPiece16 into a templated base class. Convert copy-and-pasted unit tests into TYPED_TESTs.
The motivation is that I wish to add constructors for string::iterator ranges and I don't want to do it twice.
The motivation for adding the string::iterator range constructors is to reduce the number of overloads in string_number_conversions.h .
BUG=87634
TEST=
Committed: http://src.chromium.org/viewvc/chrome?view=rev&revision=114242
Review URL: http://codereview.chromium.org/8659047
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@115616 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base')
-rw-r--r-- | base/i18n/case_conversion.h | 1 | ||||
-rw-r--r-- | base/logging.h | 3 | ||||
-rw-r--r-- | base/string_piece.cc | 218 | ||||
-rw-r--r-- | base/string_piece.h | 359 | ||||
-rw-r--r-- | base/string_piece_unittest.cc | 486 | ||||
-rw-r--r-- | base/utf_offset_string_conversions.h | 6 |
6 files changed, 549 insertions, 524 deletions
diff --git a/base/i18n/case_conversion.h b/base/i18n/case_conversion.h index be321d4..c8d84f8 100644 --- a/base/i18n/case_conversion.h +++ b/base/i18n/case_conversion.h @@ -7,6 +7,7 @@ #pragma once #include "base/i18n/base_i18n_export.h" +#include "base/string16.h" #include "base/string_piece.h" namespace base { diff --git a/base/logging.h b/base/logging.h index 94a82ad..9c660fa 100644 --- a/base/logging.h +++ b/base/logging.h @@ -983,7 +983,8 @@ inline std::ostream& operator<<(std::ostream& out, const std::wstring& wstr) { namespace base { -class StringPiece; +template <typename STRING_TYPE> class BasicStringPiece; +typedef BasicStringPiece<std::string> StringPiece; // Allows StringPiece to be logged. BASE_EXPORT std::ostream& operator<<(std::ostream& o, const StringPiece& piece); diff --git a/base/string_piece.cc b/base/string_piece.cc index bf6291c..27f0013 100644 --- a/base/string_piece.cc +++ b/base/string_piece.cc @@ -10,7 +10,15 @@ namespace base { -typedef StringPiece::size_type size_type; +// MSVC doesn't like complex extern templates and DLLs. +#if !defined(COMPILER_MSVC) +namespace internal { +template class StringPieceDetail<std::string>; +template class StringPieceDetail<string16>; +} // namespace internal + +template class BasicStringPiece<string16>; +#endif bool operator==(const StringPiece& x, const StringPiece& y) { if (x.size() != y.size()) @@ -19,62 +27,80 @@ bool operator==(const StringPiece& x, const StringPiece& y) { return StringPiece::wordmemcmp(x.data(), y.data(), x.size()) == 0; } -void StringPiece::CopyToString(std::string* target) const { - target->assign(!empty() ? data() : "", size()); +namespace internal { +void CopyToString(const StringPiece& self, std::string* target) { + target->assign(!self.empty() ? self.data() : "", self.size()); } -void StringPiece::AppendToString(std::string* target) const { - if (!empty()) - target->append(data(), size()); +void AppendToString(const StringPiece& self, std::string* target) { + if (!self.empty()) + target->append(self.data(), self.size()); } -size_type StringPiece::copy(char* buf, size_type n, size_type pos) const { - size_type ret = std::min(length_ - pos, n); - memcpy(buf, ptr_ + pos, ret); +StringPiece::size_type copy(const StringPiece& self, + char* buf, + StringPiece::size_type n, + StringPiece::size_type pos) { + StringPiece::size_type ret = std::min(self.size() - pos, n); + memcpy(buf, self.data() + pos, ret); return ret; } -size_type StringPiece::find(const StringPiece& s, size_type pos) const { - if (pos > length_) - return npos; +StringPiece::size_type find(const StringPiece& self, + const StringPiece& s, + StringPiece::size_type pos) { + if (pos > self.size()) + return StringPiece::npos; - const char* result = std::search(ptr_ + pos, ptr_ + length_, - s.ptr_, s.ptr_ + s.length_); - const size_type xpos = result - ptr_; - return xpos + s.length_ <= length_ ? xpos : npos; + StringPiece::const_iterator result = + std::search(self.begin() + pos, self.end(), s.begin(), s.end()); + const StringPiece::size_type xpos = + static_cast<size_t>(result - self.begin()); + return xpos + s.size() <= self.size() ? xpos : StringPiece::npos; } -size_type StringPiece::find(char c, size_type pos) const { - if (pos >= length_) - return npos; +StringPiece::size_type find(const StringPiece& self, + char c, + StringPiece::size_type pos) { + if (pos >= self.size()) + return StringPiece::npos; - const char* result = std::find(ptr_ + pos, ptr_ + length_, c); - return result != ptr_ + length_ ? static_cast<size_t>(result - ptr_) : npos; + StringPiece::const_iterator result = + std::find(self.begin() + pos, self.end(), c); + return result != self.end() ? + static_cast<size_t>(result - self.begin()) : StringPiece::npos; } -size_type StringPiece::rfind(const StringPiece& s, size_type pos) const { - if (length_ < s.length_) - return npos; +StringPiece::size_type rfind(const StringPiece& self, + const StringPiece& s, + StringPiece::size_type pos) { + if (self.size() < s.size()) + return StringPiece::npos; if (s.empty()) - return std::min(length_, pos); + return std::min(self.size(), pos); - const char* last = ptr_ + std::min(length_ - s.length_, pos) + s.length_; - const char* result = std::find_end(ptr_, last, s.ptr_, s.ptr_ + s.length_); - return result != last ? static_cast<size_t>(result - ptr_) : npos; + StringPiece::const_iterator last = + self.begin() + std::min(self.size() - s.size(), pos) + s.size(); + StringPiece::const_iterator result = + std::find_end(self.begin(), last, s.begin(), s.end()); + return result != last ? + static_cast<size_t>(result - self.begin()) : StringPiece::npos; } -size_type StringPiece::rfind(char c, size_type pos) const { - if (length_ == 0) - return npos; +StringPiece::size_type rfind(const StringPiece& self, + char c, + StringPiece::size_type pos) { + if (self.size() == 0) + return StringPiece::npos; - for (size_type i = std::min(pos, length_ - 1); ; --i) { - if (ptr_[i] == c) + for (StringPiece::size_type i = std::min(pos, self.size() - 1); ; --i) { + if (self.data()[i] == c) return i; if (i == 0) break; } - return npos; + return StringPiece::npos; } // For each character in characters_wanted, sets the index corresponding @@ -87,128 +113,138 @@ size_type StringPiece::rfind(char c, size_type pos) const { // bool table[UCHAR_MAX + 1] static inline void BuildLookupTable(const StringPiece& characters_wanted, bool* table) { - const size_type length = characters_wanted.length(); + const StringPiece::size_type length = characters_wanted.length(); const char* const data = characters_wanted.data(); - for (size_type i = 0; i < length; ++i) { + for (StringPiece::size_type i = 0; i < length; ++i) { table[static_cast<unsigned char>(data[i])] = true; } } -size_type StringPiece::find_first_of(const StringPiece& s, - size_type pos) const { - if (length_ == 0 || s.length_ == 0) - return npos; +StringPiece::size_type find_first_of(const StringPiece& self, + const StringPiece& s, + StringPiece::size_type pos) { + if (self.size() == 0 || s.size() == 0) + return StringPiece::npos; // Avoid the cost of BuildLookupTable() for a single-character search. - if (s.length_ == 1) - return find_first_of(s.ptr_[0], pos); + if (s.size() == 1) + return find(self, s.data()[0], pos); bool lookup[UCHAR_MAX + 1] = { false }; BuildLookupTable(s, lookup); - for (size_type i = pos; i < length_; ++i) { - if (lookup[static_cast<unsigned char>(ptr_[i])]) { + for (StringPiece::size_type i = pos; i < self.size(); ++i) { + if (lookup[static_cast<unsigned char>(self.data()[i])]) { return i; } } - return npos; + return StringPiece::npos; } -size_type StringPiece::find_first_not_of(const StringPiece& s, - size_type pos) const { - if (length_ == 0) - return npos; +StringPiece::size_type find_first_not_of(const StringPiece& self, + const StringPiece& s, + StringPiece::size_type pos) { + if (self.size() == 0) + return StringPiece::npos; - if (s.length_ == 0) + if (s.size() == 0) return 0; // Avoid the cost of BuildLookupTable() for a single-character search. - if (s.length_ == 1) - return find_first_not_of(s.ptr_[0], pos); + if (s.size() == 1) + return find_first_not_of(self, s.data()[0], pos); bool lookup[UCHAR_MAX + 1] = { false }; BuildLookupTable(s, lookup); - for (size_type i = pos; i < length_; ++i) { - if (!lookup[static_cast<unsigned char>(ptr_[i])]) { + for (StringPiece::size_type i = pos; i < self.size(); ++i) { + if (!lookup[static_cast<unsigned char>(self.data()[i])]) { return i; } } - return npos; + return StringPiece::npos; } -size_type StringPiece::find_first_not_of(char c, size_type pos) const { - if (length_ == 0) - return npos; +StringPiece::size_type find_first_not_of(const StringPiece& self, + char c, + StringPiece::size_type pos) { + if (self.size() == 0) + return StringPiece::npos; - for (; pos < length_; ++pos) { - if (ptr_[pos] != c) { + for (; pos < self.size(); ++pos) { + if (self.data()[pos] != c) { return pos; } } - return npos; + return StringPiece::npos; } -size_type StringPiece::find_last_of(const StringPiece& s, size_type pos) const { - if (length_ == 0 || s.length_ == 0) - return npos; +StringPiece::size_type find_last_of(const StringPiece& self, + const StringPiece& s, + StringPiece::size_type pos) { + if (self.size() == 0 || s.size() == 0) + return StringPiece::npos; // Avoid the cost of BuildLookupTable() for a single-character search. - if (s.length_ == 1) - return find_last_of(s.ptr_[0], pos); + if (s.size() == 1) + return rfind(self, s.data()[0], pos); bool lookup[UCHAR_MAX + 1] = { false }; BuildLookupTable(s, lookup); - for (size_type i = std::min(pos, length_ - 1); ; --i) { - if (lookup[static_cast<unsigned char>(ptr_[i])]) + for (StringPiece::size_type i = std::min(pos, self.size() - 1); ; --i) { + if (lookup[static_cast<unsigned char>(self.data()[i])]) return i; if (i == 0) break; } - return npos; + return StringPiece::npos; } -size_type StringPiece::find_last_not_of(const StringPiece& s, - size_type pos) const { - if (length_ == 0) - return npos; +StringPiece::size_type find_last_not_of(const StringPiece& self, + const StringPiece& s, + StringPiece::size_type pos) { + if (self.size() == 0) + return StringPiece::npos; - size_type i = std::min(pos, length_ - 1); - if (s.length_ == 0) + StringPiece::size_type i = std::min(pos, self.size() - 1); + if (s.size() == 0) return i; // Avoid the cost of BuildLookupTable() for a single-character search. - if (s.length_ == 1) - return find_last_not_of(s.ptr_[0], pos); + if (s.size() == 1) + return find_last_not_of(self, s.data()[0], pos); bool lookup[UCHAR_MAX + 1] = { false }; BuildLookupTable(s, lookup); for (; ; --i) { - if (!lookup[static_cast<unsigned char>(ptr_[i])]) + if (!lookup[static_cast<unsigned char>(self.data()[i])]) return i; if (i == 0) break; } - return npos; + return StringPiece::npos; } -size_type StringPiece::find_last_not_of(char c, size_type pos) const { - if (length_ == 0) - return npos; +StringPiece::size_type find_last_not_of(const StringPiece& self, + char c, + StringPiece::size_type pos) { + if (self.size() == 0) + return StringPiece::npos; - for (size_type i = std::min(pos, length_ - 1); ; --i) { - if (ptr_[i] != c) + for (StringPiece::size_type i = std::min(pos, self.size() - 1); ; --i) { + if (self.data()[i] != c) return i; if (i == 0) break; } - return npos; + return StringPiece::npos; } -StringPiece StringPiece::substr(size_type pos, size_type n) const { - if (pos > length_) pos = length_; - if (n > length_ - pos) n = length_ - pos; - return StringPiece(ptr_ + pos, n); +StringPiece substr(const StringPiece& self, + StringPiece::size_type pos, + StringPiece::size_type n) { + if (pos > self.size()) pos = self.size(); + if (n > self.size() - pos) n = self.size() - pos; + return StringPiece(self.data() + pos, n); } -const StringPiece::size_type StringPiece::npos = size_type(-1); - +} // namespace internal } // namespace base diff --git a/base/string_piece.h b/base/string_piece.h index 5e420c1..e68302e 100644 --- a/base/string_piece.h +++ b/base/string_piece.h @@ -33,43 +33,51 @@ namespace base { -class BASE_EXPORT StringPiece { +template <typename STRING_TYPE> class BasicStringPiece; +typedef BasicStringPiece<std::string> StringPiece; +typedef BasicStringPiece<string16> StringPiece16; + +namespace internal { + +// Defines the types, methods, operators, and data members common to both +// StringPiece and StringPiece16. Do not refer to this class directly, but +// rather to BasicStringPiece, StringPiece, or StringPiece16. +template <typename STRING_TYPE> class StringPieceDetail { public: // standard STL container boilerplate typedef size_t size_type; - typedef char value_type; - typedef const char* pointer; - typedef const char& reference; - typedef const char& const_reference; + typedef typename STRING_TYPE::value_type value_type; + typedef const value_type* pointer; + typedef const value_type& reference; + typedef const value_type& const_reference; typedef ptrdiff_t difference_type; - typedef const char* const_iterator; - typedef const char* iterator; + typedef const value_type* const_iterator; typedef std::reverse_iterator<const_iterator> const_reverse_iterator; - typedef std::reverse_iterator<iterator> reverse_iterator; static const size_type npos; public: // We provide non-explicit singleton constructors so users can pass // in a "const char*" or a "string" wherever a "StringPiece" is - // expected. - StringPiece() : ptr_(NULL), length_(0) { } - StringPiece(const char* str) - : ptr_(str), length_((str == NULL) ? 0 : strlen(str)) { } - StringPiece(const std::string& str) - : ptr_(str.data()), length_(str.size()) { } - StringPiece(const char* offset, size_type len) - : ptr_(offset), length_(len) { } - StringPiece(const std::string::const_iterator& begin, - const std::string::const_iterator& end) - : ptr_((end > begin) ? &(*begin) : NULL), - length_((end > begin) ? (size_type)(end - begin) : 0) { } + // expected (likewise for char16, string16, StringPiece16). + StringPieceDetail() : ptr_(NULL), length_(0) {} + StringPieceDetail(const value_type* str) + : ptr_(str), + length_((str == NULL) ? 0 : STRING_TYPE::traits_type::length(str)) {} + StringPieceDetail(const STRING_TYPE& str) + : ptr_(str.data()), length_(str.size()) {} + StringPieceDetail(const value_type* offset, size_type len) + : ptr_(offset), length_(len) {} + StringPieceDetail(const typename STRING_TYPE::const_iterator& begin, + const typename STRING_TYPE::const_iterator& end) + : ptr_((end > begin) ? &(*begin) : NULL), + length_((end > begin) ? (size_type)(end - begin) : 0) {} // data() may return a pointer to a buffer with embedded NULs, and the // returned buffer may or may not be null terminated. Therefore it is // typically a mistake to pass data() to a routine that expects a NUL // terminated string. - const char* data() const { return ptr_; } + const value_type* data() const { return ptr_; } size_type size() const { return length_; } size_type length() const { return length_; } bool empty() const { return length_ == 0; } @@ -78,20 +86,16 @@ class BASE_EXPORT StringPiece { ptr_ = NULL; length_ = 0; } - void set(const char* data, size_type len) { + void set(const value_type* data, size_type len) { ptr_ = data; length_ = len; } - void set(const char* str) { + void set(const value_type* str) { ptr_ = str; - length_ = str ? strlen(str) : 0; - } - void set(const void* data, size_type len) { - ptr_ = reinterpret_cast<const char*>(data); - length_ = len; + length_ = str ? STRING_TYPE::traits_type::length(str) : 0; } - char operator[](size_type i) const { return ptr_[i]; } + value_type operator[](size_type i) const { return ptr_[i]; } void remove_prefix(size_type n) { ptr_ += n; @@ -102,7 +106,7 @@ class BASE_EXPORT StringPiece { length_ -= n; } - int compare(const StringPiece& x) const { + int compare(const BasicStringPiece<STRING_TYPE>& x) const { int r = wordmemcmp( ptr_, x.ptr_, (length_ < x.length_ ? length_ : x.length_)); if (r == 0) { @@ -112,28 +116,13 @@ class BASE_EXPORT StringPiece { return r; } - std::string as_string() const { + STRING_TYPE as_string() const { // std::string doesn't like to take a NULL pointer even with a 0 size. - return std::string(!empty() ? data() : "", size()); - } - - void CopyToString(std::string* target) const; - void AppendToString(std::string* target) const; - - // Does "this" start with "x" - bool starts_with(const StringPiece& x) const { - return ((length_ >= x.length_) && - (wordmemcmp(ptr_, x.ptr_, x.length_) == 0)); + return empty() ? STRING_TYPE() : STRING_TYPE(data(), size()); } - // Does "this" end with "x" - bool ends_with(const StringPiece& x) const { - return ((length_ >= x.length_) && - (wordmemcmp(ptr_ + (length_-x.length_), x.ptr_, x.length_) == 0)); - } - - iterator begin() const { return ptr_; } - iterator end() const { return ptr_ + length_; } + const_iterator begin() const { return ptr_; } + const_iterator end() const { return ptr_ + length_; } const_reverse_iterator rbegin() const { return const_reverse_iterator(ptr_ + length_); } @@ -144,119 +133,219 @@ class BASE_EXPORT StringPiece { size_type max_size() const { return length_; } size_type capacity() const { return length_; } - size_type copy(char* buf, size_type n, size_type pos = 0) const; + static int wordmemcmp(const value_type* p, + const value_type* p2, + size_type N) { + return STRING_TYPE::traits_type::compare(p, p2, N); + } - size_type find(const StringPiece& s, size_type pos = 0) const; - size_type find(char c, size_type pos = 0) const; - size_type rfind(const StringPiece& s, size_type pos = npos) const; - size_type rfind(char c, size_type pos = npos) const; + protected: + const value_type* ptr_; + size_type length_; +}; - size_type find_first_of(const StringPiece& s, size_type pos = 0) const; - size_type find_first_of(char c, size_type pos = 0) const { - return find(c, pos); +template <typename STRING_TYPE> +const typename StringPieceDetail<STRING_TYPE>::size_type +StringPieceDetail<STRING_TYPE>::npos = + typename StringPieceDetail<STRING_TYPE>::size_type(-1); + +// MSVC doesn't like complex extern templates and DLLs. +#if !defined(COMPILER_MSVC) +extern template class BASE_EXPORT StringPieceDetail<std::string>; +extern template class BASE_EXPORT StringPieceDetail<string16>; +#endif + +BASE_EXPORT void CopyToString(const StringPiece& self, std::string* target); +BASE_EXPORT void AppendToString(const StringPiece& self, std::string* target); +BASE_EXPORT StringPieceDetail<std::string>::size_type copy( + const StringPiece& self, + char* buf, + StringPieceDetail<std::string>::size_type n, + StringPieceDetail<std::string>::size_type pos); +BASE_EXPORT StringPieceDetail<std::string>::size_type find( + const StringPiece& self, + const StringPiece& s, + StringPieceDetail<std::string>::size_type pos); +BASE_EXPORT StringPieceDetail<std::string>::size_type find( + const StringPiece& self, + char c, + StringPieceDetail<std::string>::size_type pos); +BASE_EXPORT StringPieceDetail<std::string>::size_type rfind( + const StringPiece& self, + const StringPiece& s, + StringPieceDetail<std::string>::size_type pos); +BASE_EXPORT StringPieceDetail<std::string>::size_type rfind( + const StringPiece& self, + char c, + StringPieceDetail<std::string>::size_type pos); +BASE_EXPORT StringPieceDetail<std::string>::size_type find_first_of( + const StringPiece& self, + const StringPiece& s, + StringPieceDetail<std::string>::size_type pos); +BASE_EXPORT StringPieceDetail<std::string>::size_type find_first_not_of( + const StringPiece& self, + const StringPiece& s, + StringPieceDetail<std::string>::size_type pos); +BASE_EXPORT StringPieceDetail<std::string>::size_type find_first_not_of( + const StringPiece& self, + char c, + StringPieceDetail<std::string>::size_type pos); +BASE_EXPORT StringPieceDetail<std::string>::size_type find_last_of( + const StringPiece& self, + const StringPiece& s, + StringPieceDetail<std::string>::size_type pos); +BASE_EXPORT StringPieceDetail<std::string>::size_type find_last_of( + const StringPiece& self, + char c, + StringPieceDetail<std::string>::size_type pos); +BASE_EXPORT StringPieceDetail<std::string>::size_type find_last_not_of( + const StringPiece& self, + const StringPiece& s, + StringPieceDetail<std::string>::size_type pos); +BASE_EXPORT StringPieceDetail<std::string>::size_type find_last_not_of( + const StringPiece& self, + char c, + StringPieceDetail<std::string>::size_type pos); +BASE_EXPORT StringPiece substr(const StringPiece& self, + StringPieceDetail<std::string>::size_type pos, + StringPieceDetail<std::string>::size_type n); +} // namespace internal + +// Defines the template type that is instantiated as either StringPiece or +// StringPiece16. +template <typename STRING_TYPE> class BasicStringPiece : + public internal::StringPieceDetail<STRING_TYPE> { + public: + typedef typename internal::StringPieceDetail<STRING_TYPE>::value_type + value_type; + typedef typename internal::StringPieceDetail<STRING_TYPE>::size_type + size_type; + + BasicStringPiece() {} + BasicStringPiece(const value_type*str) + : internal::StringPieceDetail<STRING_TYPE>(str) {} + BasicStringPiece(const STRING_TYPE& str) + : internal::StringPieceDetail<STRING_TYPE>(str) {} + BasicStringPiece(const value_type* offset, size_type len) + : internal::StringPieceDetail<STRING_TYPE>(offset, len) {} + BasicStringPiece(const typename STRING_TYPE::const_iterator& begin, + const typename STRING_TYPE::const_iterator& end) + : internal::StringPieceDetail<STRING_TYPE>(begin, end) {} +}; + +// Specializes BasicStringPiece for std::string to add a few operations that +// are not needed for string16. +template <> class BasicStringPiece<std::string> : + public internal::StringPieceDetail<std::string> { + public: + BasicStringPiece() {} + BasicStringPiece(const char* str) + : internal::StringPieceDetail<std::string>(str) {} + BasicStringPiece(const std::string& str) + : internal::StringPieceDetail<std::string>(str) {} + BasicStringPiece(const char* offset, size_type len) + : internal::StringPieceDetail<std::string>(offset, len) {} + BasicStringPiece(const std::string::const_iterator& begin, + const std::string::const_iterator& end) + : internal::StringPieceDetail<std::string>(begin, end) {} + + // Prevent the following overload of set() from hiding the definitions in the + // base class. + using internal::StringPieceDetail<std::string>::set; + + void set(const void* data, size_type len) { + ptr_ = reinterpret_cast<const value_type*>(data); + length_ = len; } - size_type find_first_not_of(const StringPiece& s, size_type pos = 0) const; - size_type find_first_not_of(char c, size_type pos = 0) const; - size_type find_last_of(const StringPiece& s, size_type pos = npos) const; - size_type find_last_of(char c, size_type pos = npos) const { - return rfind(c, pos); + + void CopyToString(std::string* target) const { + internal::CopyToString(*this, target); } - size_type find_last_not_of(const StringPiece& s, size_type pos = npos) const; - size_type find_last_not_of(char c, size_type pos = npos) const; - StringPiece substr(size_type pos, size_type n = npos) const; + void AppendToString(std::string* target) const { + internal::AppendToString(*this, target); + } - static int wordmemcmp(const char* p, const char* p2, size_type N) { - return memcmp(p, p2, N); + // Does "this" start with "x" + bool starts_with(const BasicStringPiece& x) const { + return ((length_ >= x.length_) && + (wordmemcmp(ptr_, x.ptr_, x.length_) == 0)); } - private: - const char* ptr_; - size_type length_; -}; + // Does "this" end with "x" + bool ends_with(const BasicStringPiece& x) const { + return ((length_ >= x.length_) && + (wordmemcmp(ptr_ + (length_-x.length_), x.ptr_, x.length_) == 0)); + } -class BASE_EXPORT StringPiece16 { - public: - // standard STL container boilerplate - typedef size_t size_type; - typedef char16 value_type; - typedef const char16* pointer; - typedef const char16& reference; - typedef const char16& const_reference; - typedef ptrdiff_t difference_type; - typedef const char16* const_iterator; - typedef const char16* iterator; - typedef std::reverse_iterator<const_iterator> const_reverse_iterator; - typedef std::reverse_iterator<iterator> reverse_iterator; + size_type copy(char* buf, size_type n, size_type pos = 0) const { + return internal::copy(*this, buf, n, pos); + } - public: - // We provide non-explicit singleton constructors so users can pass - // in a "const char16*" or a "string16" wherever a "StringPiece16" is - // expected. - StringPiece16() : ptr_(NULL), length_(0) { } - StringPiece16(const char16* str) - : ptr_(str), - length_((str == NULL) ? 0 : string16::traits_type::length(str)) { } - StringPiece16(const string16& str) - : ptr_(str.data()), length_(str.size()) { } - StringPiece16(const char16* offset, size_type len) - : ptr_(offset), length_(len) { } - StringPiece16(const string16::const_iterator& begin, - const string16::const_iterator& end) - : ptr_((end > begin) ? &(*begin) : NULL), - length_((end > begin) ? (size_type)(end - begin) : 0) { } + size_type find(const BasicStringPiece& s, size_type pos = 0) const { + return internal::find(*this, s, pos); + } - // data() may return a pointer to a buffer with embedded NULs, and the - // returned buffer may or may not be null terminated. Therefore it is - // typically a mistake to pass data() to a routine that expects a NUL - // terminated string. - const char16* data() const { return ptr_; } - size_type size() const { return length_; } - size_type length() const { return length_; } - bool empty() const { return length_ == 0; } + size_type find(char c, size_type pos = 0) const { + return internal::find(*this, c, pos); + } - void clear() { - ptr_ = NULL; - length_ = 0; + size_type rfind(const BasicStringPiece& s, size_type pos = npos) const { + return internal::rfind(*this, s, pos); } - void set(const char16* data, size_type len) { - ptr_ = data; - length_ = len; + + size_type rfind(char c, size_type pos = npos) const { + return internal::rfind(*this, c, pos); } - void set(const char16* str) { - ptr_ = str; - length_ = str ? string16::traits_type::length(str) : 0; + + size_type find_first_of(const BasicStringPiece& s, size_type pos = 0) const { + return internal::find_first_of(*this, s, pos); } - char16 operator[](size_type i) const { return ptr_[i]; } + size_type find_first_of(char c, size_type pos = 0) const { + return find(c, pos); + } - string16 as_string16() const { - // StringPiece claims that this is bad when data() is NULL, but unittesting - // seems to say otherwise. - return string16(data(), size()); + size_type find_first_not_of(const BasicStringPiece& s, + size_type pos = 0) const { + return internal::find_first_not_of(*this, s, pos); } - iterator begin() const { return ptr_; } - iterator end() const { return ptr_ + length_; } - const_reverse_iterator rbegin() const { - return const_reverse_iterator(ptr_ + length_); + size_type find_first_not_of(char c, size_type pos = 0) const { + return internal::find_first_not_of(*this, c, pos); } - const_reverse_iterator rend() const { - return const_reverse_iterator(ptr_); + + size_type find_last_of(const BasicStringPiece& s, + size_type pos = npos) const { + return internal::find_last_of(*this, s, pos); } - size_type max_size() const { return length_; } - size_type capacity() const { return length_; } + size_type find_last_of(char c, size_type pos = npos) const { + return rfind(c, pos); + } + + size_type find_last_not_of(const BasicStringPiece& s, + size_type pos = npos) const { + return internal::find_last_not_of(*this, s, pos); + } - static int wordmemcmp(const char16* p, const char16* p2, size_type N) { - return string16::traits_type::compare(p, p2, N); + size_type find_last_not_of(char c, size_type pos = npos) const { + return internal::find_last_not_of(*this, c, pos); } - private: - const char16* ptr_; - size_type length_; + BasicStringPiece substr(size_type pos, size_type n = npos) const { + return internal::substr(*this, pos, n); + } }; +// MSVC doesn't like complex extern templates and DLLs. +#if !defined(COMPILER_MSVC) +// We can't explicitly declare the std::string instantiation here because it was +// already instantiated when specialized, above. Not only is it a no-op, but +// currently it also crashes Clang (see http://crbug.com/107412). +extern template class BASE_EXPORT BasicStringPiece<string16>; +#endif + BASE_EXPORT bool operator==(const StringPiece& x, const StringPiece& y); inline bool operator!=(const StringPiece& x, const StringPiece& y) { diff --git a/base/string_piece_unittest.cc b/base/string_piece_unittest.cc index 694c43b..a29fe74 100644 --- a/base/string_piece_unittest.cc +++ b/base/string_piece_unittest.cc @@ -11,14 +11,52 @@ namespace base { -TEST(StringPieceTest, CheckComparisonOperators) { -#define CMP_Y(op, x, y) \ - ASSERT_TRUE( (StringPiece((x)) op StringPiece((y)))); \ - ASSERT_TRUE( (StringPiece((x)).compare(StringPiece((y))) op 0)) +template <typename T> +class CommonStringPieceTest : public ::testing::Test { + public: + static const T as_string(const char* input) { + return T(input); + } + static const T& as_string(const T& input) { + return input; + } +}; + +template <> +class CommonStringPieceTest<string16> : public ::testing::Test { + public: + static const string16 as_string(const char* input) { + return ASCIIToUTF16(input); + } + static const string16 as_string(const std::string& input) { + return ASCIIToUTF16(input); + } +}; + +typedef ::testing::Types<std::string, string16> SupportedStringTypes; + +TYPED_TEST_CASE(CommonStringPieceTest, SupportedStringTypes); + +TYPED_TEST(CommonStringPieceTest, CheckComparisonOperators) { +#define CMP_Y(op, x, y) \ + { \ + TypeParam lhs(TestFixture::as_string(x)); \ + TypeParam rhs(TestFixture::as_string(y)); \ + ASSERT_TRUE( (BasicStringPiece<TypeParam>((lhs.c_str())) op \ + BasicStringPiece<TypeParam>((rhs.c_str())))); \ + ASSERT_TRUE( (BasicStringPiece<TypeParam>((lhs.c_str())).compare( \ + BasicStringPiece<TypeParam>((rhs.c_str()))) op 0)); \ + } -#define CMP_N(op, x, y) \ - ASSERT_FALSE(StringPiece((x)) op StringPiece((y))); \ - ASSERT_FALSE(StringPiece((x)).compare(StringPiece((y))) op 0) +#define CMP_N(op, x, y) \ + { \ + TypeParam lhs(TestFixture::as_string(x)); \ + TypeParam rhs(TestFixture::as_string(y)); \ + ASSERT_FALSE( (BasicStringPiece<TypeParam>((lhs.c_str())) op \ + BasicStringPiece<TypeParam>((rhs.c_str())))); \ + ASSERT_FALSE( (BasicStringPiece<TypeParam>((lhs.c_str())).compare( \ + BasicStringPiece<TypeParam>((rhs.c_str()))) op 0)); \ + } CMP_Y(==, "", ""); CMP_Y(==, "a", "a"); @@ -94,34 +132,40 @@ TEST(StringPieceTest, CheckComparisonOperators) { #undef CMP_N } -TEST(StringPieceTest, CheckSTL) { - StringPiece a("abcdefghijklmnopqrstuvwxyz"); - StringPiece b("abc"); - StringPiece c("xyz"); - StringPiece d("foobar"); - StringPiece e; - std::string temp("123"); - temp += '\0'; - temp += "456"; - StringPiece f(temp); - - ASSERT_EQ(a[6], 'g'); - ASSERT_EQ(b[0], 'a'); - ASSERT_EQ(c[2], 'z'); - ASSERT_EQ(f[3], '\0'); - ASSERT_EQ(f[5], '5'); - - ASSERT_EQ(*d.data(), 'f'); - ASSERT_EQ(d.data()[5], 'r'); +TYPED_TEST(CommonStringPieceTest, CheckSTL) { + TypeParam alphabet(TestFixture::as_string("abcdefghijklmnopqrstuvwxyz")); + TypeParam abc(TestFixture::as_string("abc")); + TypeParam xyz(TestFixture::as_string("xyz")); + TypeParam foobar(TestFixture::as_string("foobar")); + + BasicStringPiece<TypeParam> a(alphabet); + BasicStringPiece<TypeParam> b(abc); + BasicStringPiece<TypeParam> c(xyz); + BasicStringPiece<TypeParam> d(foobar); + BasicStringPiece<TypeParam> e; + TypeParam temp(TestFixture::as_string("123")); + temp += static_cast<typename TypeParam::value_type>(0); + temp += TestFixture::as_string("456"); + BasicStringPiece<TypeParam> f(temp); + + ASSERT_EQ(a[6], static_cast<typename TypeParam::value_type>('g')); + ASSERT_EQ(b[0], static_cast<typename TypeParam::value_type>('a')); + ASSERT_EQ(c[2], static_cast<typename TypeParam::value_type>('z')); + ASSERT_EQ(f[3], static_cast<typename TypeParam::value_type>('\0')); + ASSERT_EQ(f[5], static_cast<typename TypeParam::value_type>('5')); + + ASSERT_EQ(*d.data(), static_cast<typename TypeParam::value_type>('f')); + ASSERT_EQ(d.data()[5], static_cast<typename TypeParam::value_type>('r')); ASSERT_TRUE(e.data() == NULL); - ASSERT_EQ(*a.begin(), 'a'); - ASSERT_EQ(*(b.begin() + 2), 'c'); - ASSERT_EQ(*(c.end() - 1), 'z'); + ASSERT_EQ(*a.begin(), static_cast<typename TypeParam::value_type>('a')); + ASSERT_EQ(*(b.begin() + 2), static_cast<typename TypeParam::value_type>('c')); + ASSERT_EQ(*(c.end() - 1), static_cast<typename TypeParam::value_type>('z')); - ASSERT_EQ(*a.rbegin(), 'z'); - ASSERT_EQ(*(b.rbegin() + 2), 'a'); - ASSERT_EQ(*(c.rend() - 1), 'x'); + ASSERT_EQ(*a.rbegin(), static_cast<typename TypeParam::value_type>('z')); + ASSERT_EQ(*(b.rbegin() + 2), + static_cast<typename TypeParam::value_type>('a')); + ASSERT_EQ(*(c.rend() - 1), static_cast<typename TypeParam::value_type>('x')); ASSERT_TRUE(a.rbegin() + 26 == a.rend()); ASSERT_EQ(a.size(), 26U); @@ -146,6 +190,20 @@ TEST(StringPieceTest, CheckSTL) { ASSERT_GE(a.max_size(), a.capacity()); ASSERT_GE(a.capacity(), a.size()); +} + +// STL stuff only supported by the std::string version +TEST(StringPieceTest, CheckSTL) { + StringPiece a("abcdefghijklmnopqrstuvwxyz"); + StringPiece b("abc"); + StringPiece c("xyz"); + StringPiece d("foobar"); + d.clear(); + StringPiece e; + std::string temp("123"); + temp += '\0'; + temp += "456"; + StringPiece f(temp); char buf[4] = { '%', '%', '%', '%' }; ASSERT_EQ(a.copy(buf, 4), 4U); @@ -259,6 +317,9 @@ TEST(StringPieceTest, CheckSTL) { ASSERT_EQ(d.rfind('o', 4), StringPiece::npos); ASSERT_EQ(e.rfind('o', 7), StringPiece::npos); + ASSERT_EQ( + StringPiece("one,two:three;four").find_first_of(StringPiece(",:"), 1), + 3U); ASSERT_EQ(a.find_first_of(b), 0U); ASSERT_EQ(a.find_first_of(b, 0), 0U); ASSERT_EQ(a.find_first_of(b, 1), 1U); @@ -400,6 +461,53 @@ TEST(StringPieceTest, CheckSTL) { ASSERT_EQ(d.substr(99, 99), e); } +TYPED_TEST(CommonStringPieceTest, CheckCustom) { + TypeParam foobar(TestFixture::as_string("foobar")); + BasicStringPiece<TypeParam> a(foobar); + TypeParam s1(TestFixture::as_string("123")); + s1 += static_cast<typename TypeParam::value_type>('\0'); + s1 += TestFixture::as_string("456"); + BasicStringPiece<TypeParam> b(s1); + BasicStringPiece<TypeParam> e; + TypeParam s2; + + // remove_prefix + BasicStringPiece<TypeParam> c(a); + c.remove_prefix(3); + ASSERT_EQ(c, TestFixture::as_string("bar")); + c = a; + c.remove_prefix(0); + ASSERT_EQ(c, a); + c.remove_prefix(c.size()); + ASSERT_EQ(c, e); + + // remove_suffix + c = a; + c.remove_suffix(3); + ASSERT_EQ(c, TestFixture::as_string("foo")); + c = a; + c.remove_suffix(0); + ASSERT_EQ(c, a); + c.remove_suffix(c.size()); + ASSERT_EQ(c, e); + + // set + c.set(foobar.c_str()); + ASSERT_EQ(c, a); + c.set(foobar.c_str(), 6); + ASSERT_EQ(c, a); + c.set(foobar.c_str(), 0); + ASSERT_EQ(c, e); + c.set(foobar.c_str(), 7); // Note, has an embedded NULL + ASSERT_NE(c, a); + + // as_string + TypeParam s3(a.as_string().c_str(), 7); // Note, has an embedded NULL + ASSERT_TRUE(c == s3); + TypeParam s4(e.as_string()); + ASSERT_TRUE(s4.empty()); +} + TEST(StringPieceTest, CheckCustom) { StringPiece a("foobar"); std::string s1("123"); @@ -452,74 +560,50 @@ TEST(StringPieceTest, CheckCustom) { ASSERT_TRUE(!b.ends_with(a)); ASSERT_TRUE(!e.ends_with(a)); - // remove_prefix - StringPiece c(a); - c.remove_prefix(3); - ASSERT_EQ(c, "bar"); - c = a; - c.remove_prefix(0); - ASSERT_EQ(c, a); - c.remove_prefix(c.size()); - ASSERT_EQ(c, e); - - // remove_suffix - c = a; - c.remove_suffix(3); - ASSERT_EQ(c, "foo"); - c = a; - c.remove_suffix(0); - ASSERT_EQ(c, a); - c.remove_suffix(c.size()); - ASSERT_EQ(c, e); - - // set - c.set("foobar", 6); - ASSERT_EQ(c, a); - c.set("foobar", 0); - ASSERT_EQ(c, e); - c.set("foobar", 7); - ASSERT_NE(c, a); - - c.set("foobar"); - ASSERT_EQ(c, a); - + StringPiece c; c.set(static_cast<const void*>("foobar"), 6); ASSERT_EQ(c, a); c.set(static_cast<const void*>("foobar"), 0); ASSERT_EQ(c, e); c.set(static_cast<const void*>("foobar"), 7); ASSERT_NE(c, a); - - // as_string - std::string s3(a.as_string().c_str(), 7); - ASSERT_EQ(c, s3); - std::string s4(e.as_string()); - ASSERT_TRUE(s4.empty()); } -TEST(StringPieceTest, CheckNULL) { +TYPED_TEST(CommonStringPieceTest, CheckNULL) { // we used to crash here, but now we don't. - StringPiece s(NULL); - ASSERT_EQ(s.data(), (const char*)NULL); + BasicStringPiece<TypeParam> s(NULL); + ASSERT_EQ(s.data(), (const typename TypeParam::value_type*)NULL); ASSERT_EQ(s.size(), 0U); s.set(NULL); - ASSERT_EQ(s.data(), (const char*)NULL); + ASSERT_EQ(s.data(), (const typename TypeParam::value_type*)NULL); ASSERT_EQ(s.size(), 0U); + + TypeParam str = s.as_string(); + ASSERT_EQ(str.length(), 0U); + ASSERT_EQ(str, TypeParam()); } -TEST(StringPieceTest, CheckComparisons2) { - StringPiece abc("abcdefghijklmnopqrstuvwxyz"); +TYPED_TEST(CommonStringPieceTest, CheckComparisons2) { + TypeParam alphabet(TestFixture::as_string("abcdefghijklmnopqrstuvwxyz")); + TypeParam alphabet_z(TestFixture::as_string("abcdefghijklmnopqrstuvwxyzz")); + TypeParam alphabet_y(TestFixture::as_string("abcdefghijklmnopqrstuvwxyy")); + BasicStringPiece<TypeParam> abc(alphabet); // check comparison operations on strings longer than 4 bytes. - ASSERT_TRUE(abc == StringPiece("abcdefghijklmnopqrstuvwxyz")); - ASSERT_TRUE(abc.compare(StringPiece("abcdefghijklmnopqrstuvwxyz")) == 0); + ASSERT_TRUE(abc == BasicStringPiece<TypeParam>(alphabet)); + ASSERT_TRUE(abc.compare(BasicStringPiece<TypeParam>(alphabet)) == 0); + + ASSERT_TRUE(abc < BasicStringPiece<TypeParam>(alphabet_z)); + ASSERT_TRUE(abc.compare(BasicStringPiece<TypeParam>(alphabet_z)) < 0); - ASSERT_TRUE(abc < StringPiece("abcdefghijklmnopqrstuvwxzz")); - ASSERT_TRUE(abc.compare(StringPiece("abcdefghijklmnopqrstuvwxzz")) < 0); + ASSERT_TRUE(abc > BasicStringPiece<TypeParam>(alphabet_y)); + ASSERT_TRUE(abc.compare(BasicStringPiece<TypeParam>(alphabet_y)) > 0); +} - ASSERT_TRUE(abc > StringPiece("abcdefghijklmnopqrstuvwxyy")); - ASSERT_TRUE(abc.compare(StringPiece("abcdefghijklmnopqrstuvwxyy")) > 0); +// Test operations only supported by std::string version. +TEST(StringPieceTest, CheckComparisons2) { + StringPiece abc("abcdefghijklmnopqrstuvwxyz"); // starts_with ASSERT_TRUE(abc.starts_with(abc)); @@ -532,169 +616,22 @@ TEST(StringPieceTest, CheckComparisons2) { ASSERT_TRUE(abc.ends_with("nopqrstuvwxyz")); } -TEST(StringPieceTest, StringCompareNotAmbiguous) { - ASSERT_TRUE("hello" == std::string("hello")); - ASSERT_TRUE("hello" < std::string("world")); +TYPED_TEST(CommonStringPieceTest, StringCompareNotAmbiguous) { + ASSERT_TRUE(TestFixture::as_string("hello").c_str() == + TestFixture::as_string("hello")); + ASSERT_TRUE(TestFixture::as_string("hello").c_str() < + TestFixture::as_string("world")); } -TEST(StringPieceTest, HeterogenousStringPieceEquals) { - ASSERT_TRUE(StringPiece("hello") == std::string("hello")); - ASSERT_TRUE("hello" == StringPiece("hello")); -} +TYPED_TEST(CommonStringPieceTest, HeterogenousStringPieceEquals) { + TypeParam hello(TestFixture::as_string("hello")); -TEST(StringPiece16Test, CheckComparisonOperators) { - ASSERT_TRUE(StringPiece16(string16()) == - StringPiece16(string16())); - ASSERT_TRUE(StringPiece16(ASCIIToUTF16("a")) == - StringPiece16(ASCIIToUTF16("a"))); - ASSERT_TRUE(StringPiece16(ASCIIToUTF16("aa")) == - StringPiece16(ASCIIToUTF16("aa"))); - ASSERT_FALSE(StringPiece16(ASCIIToUTF16("a")) == - StringPiece16(string16())); - ASSERT_FALSE(StringPiece16(string16()) == - StringPiece16(ASCIIToUTF16("a"))); - ASSERT_FALSE(StringPiece16(ASCIIToUTF16("a")) == - StringPiece16(ASCIIToUTF16("b"))); - ASSERT_FALSE(StringPiece16(ASCIIToUTF16("a")) == - StringPiece16(ASCIIToUTF16("aa"))); - ASSERT_FALSE(StringPiece16(ASCIIToUTF16("aa")) == - StringPiece16(ASCIIToUTF16("a"))); - - ASSERT_FALSE(StringPiece16(string16()) != - StringPiece16(string16())); - ASSERT_FALSE(StringPiece16(ASCIIToUTF16("a")) != - StringPiece16(ASCIIToUTF16("a"))); - ASSERT_FALSE(StringPiece16(ASCIIToUTF16("aa")) != - StringPiece16(ASCIIToUTF16("aa"))); - ASSERT_TRUE(StringPiece16(ASCIIToUTF16("a")) != - StringPiece16(string16())); - ASSERT_TRUE(StringPiece16(string16()) != - StringPiece16(ASCIIToUTF16("a"))); - ASSERT_TRUE(StringPiece16(ASCIIToUTF16("a")) != - StringPiece16(ASCIIToUTF16("b"))); - ASSERT_TRUE(StringPiece16(ASCIIToUTF16("a")) != - StringPiece16(ASCIIToUTF16("aa"))); - ASSERT_TRUE(StringPiece16(ASCIIToUTF16("aa")) != - StringPiece16(ASCIIToUTF16("a"))); - - ASSERT_TRUE(StringPiece16(ASCIIToUTF16("a")) < - StringPiece16(ASCIIToUTF16("b"))); - ASSERT_TRUE(StringPiece16(ASCIIToUTF16("a")) < - StringPiece16(ASCIIToUTF16("aa"))); - ASSERT_TRUE(StringPiece16(ASCIIToUTF16("aa")) < - StringPiece16(ASCIIToUTF16("b"))); - ASSERT_TRUE(StringPiece16(ASCIIToUTF16("aa")) < - StringPiece16(ASCIIToUTF16("bb"))); - ASSERT_FALSE(StringPiece16(ASCIIToUTF16("a")) < - StringPiece16(ASCIIToUTF16("a"))); - ASSERT_FALSE(StringPiece16(ASCIIToUTF16("b")) < - StringPiece16(ASCIIToUTF16("a"))); - ASSERT_FALSE(StringPiece16(ASCIIToUTF16("aa")) < - StringPiece16(ASCIIToUTF16("a"))); - ASSERT_FALSE(StringPiece16(ASCIIToUTF16("b")) < - StringPiece16(ASCIIToUTF16("aa"))); - ASSERT_FALSE(StringPiece16(ASCIIToUTF16("bb")) < - StringPiece16(ASCIIToUTF16("aa"))); - - ASSERT_TRUE(StringPiece16(ASCIIToUTF16("a")) <= - StringPiece16(ASCIIToUTF16("a"))); - ASSERT_TRUE(StringPiece16(ASCIIToUTF16("a")) <= - StringPiece16(ASCIIToUTF16("b"))); - ASSERT_TRUE(StringPiece16(ASCIIToUTF16("a")) <= - StringPiece16(ASCIIToUTF16("aa"))); - ASSERT_TRUE(StringPiece16(ASCIIToUTF16("aa")) <= - StringPiece16(ASCIIToUTF16("b"))); - ASSERT_TRUE(StringPiece16(ASCIIToUTF16("aa")) <= - StringPiece16(ASCIIToUTF16("bb"))); - ASSERT_FALSE(StringPiece16(ASCIIToUTF16("b")) <= - StringPiece16(ASCIIToUTF16("a"))); - ASSERT_FALSE(StringPiece16(ASCIIToUTF16("aa")) <= - StringPiece16(ASCIIToUTF16("a"))); - ASSERT_FALSE(StringPiece16(ASCIIToUTF16("b")) <= - StringPiece16(ASCIIToUTF16("aa"))); - ASSERT_FALSE(StringPiece16(ASCIIToUTF16("bb")) <= - StringPiece16(ASCIIToUTF16("aa"))); - - ASSERT_TRUE(StringPiece16(ASCIIToUTF16("a")) <= - StringPiece16(ASCIIToUTF16("a"))); - ASSERT_TRUE(StringPiece16(ASCIIToUTF16("a")) <= - StringPiece16(ASCIIToUTF16("b"))); - ASSERT_TRUE(StringPiece16(ASCIIToUTF16("a")) <= - StringPiece16(ASCIIToUTF16("aa"))); - ASSERT_TRUE(StringPiece16(ASCIIToUTF16("aa")) <= - StringPiece16(ASCIIToUTF16("b"))); - ASSERT_TRUE(StringPiece16(ASCIIToUTF16("aa")) <= - StringPiece16(ASCIIToUTF16("bb"))); - ASSERT_FALSE(StringPiece16(ASCIIToUTF16("b")) <= - StringPiece16(ASCIIToUTF16("a"))); - ASSERT_FALSE(StringPiece16(ASCIIToUTF16("aa")) <= - StringPiece16(ASCIIToUTF16("a"))); - ASSERT_FALSE(StringPiece16(ASCIIToUTF16("b")) <= - StringPiece16(ASCIIToUTF16("aa"))); - ASSERT_FALSE(StringPiece16(ASCIIToUTF16("bb")) <= - StringPiece16(ASCIIToUTF16("aa"))); - - ASSERT_FALSE(StringPiece16(ASCIIToUTF16("a")) >= - StringPiece16(ASCIIToUTF16("b"))); - ASSERT_FALSE(StringPiece16(ASCIIToUTF16("a")) >= - StringPiece16(ASCIIToUTF16("aa"))); - ASSERT_FALSE(StringPiece16(ASCIIToUTF16("aa")) >= - StringPiece16(ASCIIToUTF16("b"))); - ASSERT_FALSE(StringPiece16(ASCIIToUTF16("aa")) >= - StringPiece16(ASCIIToUTF16("bb"))); - ASSERT_TRUE(StringPiece16(ASCIIToUTF16("a")) >= - StringPiece16(ASCIIToUTF16("a"))); - ASSERT_TRUE(StringPiece16(ASCIIToUTF16("b")) >= - StringPiece16(ASCIIToUTF16("a"))); - ASSERT_TRUE(StringPiece16(ASCIIToUTF16("aa")) >= - StringPiece16(ASCIIToUTF16("a"))); - ASSERT_TRUE(StringPiece16(ASCIIToUTF16("b")) >= - StringPiece16(ASCIIToUTF16("aa"))); - ASSERT_TRUE(StringPiece16(ASCIIToUTF16("bb")) >= - StringPiece16(ASCIIToUTF16("aa"))); - - ASSERT_FALSE(StringPiece16(ASCIIToUTF16("a")) > - StringPiece16(ASCIIToUTF16("a"))); - ASSERT_FALSE(StringPiece16(ASCIIToUTF16("a")) > - StringPiece16(ASCIIToUTF16("b"))); - ASSERT_FALSE(StringPiece16(ASCIIToUTF16("a")) > - StringPiece16(ASCIIToUTF16("aa"))); - ASSERT_FALSE(StringPiece16(ASCIIToUTF16("aa")) > - StringPiece16(ASCIIToUTF16("b"))); - ASSERT_FALSE(StringPiece16(ASCIIToUTF16("aa")) > - StringPiece16(ASCIIToUTF16("bb"))); - ASSERT_TRUE(StringPiece16(ASCIIToUTF16("b")) > - StringPiece16(ASCIIToUTF16("a"))); - ASSERT_TRUE(StringPiece16(ASCIIToUTF16("aa")) > - StringPiece16(ASCIIToUTF16("a"))); - ASSERT_TRUE(StringPiece16(ASCIIToUTF16("b")) > - StringPiece16(ASCIIToUTF16("aa"))); - ASSERT_TRUE(StringPiece16(ASCIIToUTF16("bb")) > - StringPiece16(ASCIIToUTF16("aa"))); - - string16 x; - for (int i = 0; i < 256; i++) { - x += 'a'; - string16 y = x; - ASSERT_EQ(StringPiece16(x), StringPiece16(y)); - for (int j = 0; j < i; j++) { - string16 z = x; - z[j] = 'b'; // Differs in position 'j' - ASSERT_NE(StringPiece16(x), StringPiece16(z)); - } - } + ASSERT_TRUE(BasicStringPiece<TypeParam>(hello) == hello); + ASSERT_TRUE(hello.c_str() == BasicStringPiece<TypeParam>(hello)); } +// string16-specific stuff TEST(StringPiece16Test, CheckSTL) { - string16 first = ASCIIToUTF16("abcdefghijklmnopqrstuvwxyz"); - StringPiece16 a(first); - string16 second = ASCIIToUTF16("abc"); - StringPiece16 b(second.c_str()); - string16 third = ASCIIToUTF16("xyz"); - StringPiece16 c(third.c_str(), third.size()); - string16 fourth = ASCIIToUTF16("foobarrandomstuff"); - StringPiece16 d(fourth.c_str(), 6); - StringPiece16 e; // Check some non-ascii characters. string16 fifth(ASCIIToUTF16("123")); fifth.push_back(0x0000); @@ -702,74 +639,39 @@ TEST(StringPiece16Test, CheckSTL) { fifth.push_back(0xdffe); StringPiece16 f(fifth); - ASSERT_EQ(a[6], 'g'); - ASSERT_EQ(b[0], 'a'); - ASSERT_EQ(c[2], 'z'); ASSERT_EQ(f[3], '\0'); ASSERT_EQ(f[5], static_cast<char16>(0xdffe)); - ASSERT_EQ(*d.data(), 'f'); - ASSERT_EQ(d.data()[5], 'r'); - ASSERT_TRUE(e.data() == NULL); - - ASSERT_EQ(*a.begin(), 'a'); - ASSERT_EQ(*(b.begin() + 2), 'c'); - ASSERT_EQ(*(c.end() - 1), 'z'); - - ASSERT_EQ(*a.rbegin(), 'z'); - ASSERT_EQ(*(b.rbegin() + 2), 'a'); - ASSERT_EQ(*(c.rend() - 1), 'x'); - ASSERT_TRUE(a.rbegin() + 26 == a.rend()); - - ASSERT_EQ(a.size(), 26U); - ASSERT_EQ(b.size(), 3U); - ASSERT_EQ(c.size(), 3U); - ASSERT_EQ(d.size(), 6U); - ASSERT_EQ(e.size(), 0U); ASSERT_EQ(f.size(), 6U); - - ASSERT_TRUE(!d.empty()); - ASSERT_TRUE(d.begin() != d.end()); - ASSERT_TRUE(d.begin() + 6 == d.end()); - - ASSERT_TRUE(e.empty()); - ASSERT_TRUE(e.begin() == e.end()); - - d.clear(); - ASSERT_EQ(d.size(), 0U); - ASSERT_TRUE(d.empty()); - ASSERT_TRUE(d.data() == NULL); - ASSERT_TRUE(d.begin() == d.end()); - - ASSERT_GE(a.max_size(), a.capacity()); - ASSERT_GE(a.capacity(), a.size()); } -TEST(StringPiece16Test, CheckNULL) { - StringPiece16 s(NULL); - ASSERT_EQ(s.data(), (const char16*)NULL); - ASSERT_EQ(s.size(), 0U); - s.set(NULL); - ASSERT_EQ(s.data(), (const char16*)NULL); - ASSERT_EQ(s.size(), 0U); - - string16 str = s.as_string16(); - ASSERT_EQ(s.data(), (const char16*)NULL); - ASSERT_EQ(s.size(), 0U); -} - -TEST(StringPiece16Test, HeterogenousStringPieceEquals) { - ASSERT_TRUE(StringPiece16(ASCIIToUTF16("hello")) == ASCIIToUTF16("hello")); -} TEST(StringPiece16Test, CheckConversion) { // Make sure that we can convert from UTF8 to UTF16 and back. We use a two // byte character (G clef) to test this. ASSERT_EQ( UTF16ToUTF8( - StringPiece16(UTF8ToUTF16("\xf0\x9d\x84\x9e")).as_string16()), + StringPiece16(UTF8ToUTF16("\xf0\x9d\x84\x9e")).as_string()), "\xf0\x9d\x84\x9e"); } +TYPED_TEST(CommonStringPieceTest, CheckConstructors) { + TypeParam str(TestFixture::as_string("hello world")); + TypeParam empty; + + ASSERT_TRUE(str == BasicStringPiece<TypeParam>(str)); + ASSERT_TRUE(str == BasicStringPiece<TypeParam>(str.c_str())); + ASSERT_TRUE(TestFixture::as_string("hello") == + BasicStringPiece<TypeParam>(str.c_str(), 5)); + ASSERT_TRUE(empty == BasicStringPiece<TypeParam>(str.c_str(), 0)); + ASSERT_TRUE(empty == BasicStringPiece<TypeParam>(NULL)); + ASSERT_TRUE(empty == BasicStringPiece<TypeParam>(NULL, 0)); + ASSERT_TRUE(empty == BasicStringPiece<TypeParam>()); + ASSERT_TRUE(str == BasicStringPiece<TypeParam>(str.begin(), str.end())); + ASSERT_TRUE(empty == BasicStringPiece<TypeParam>(str.begin(), str.begin())); + ASSERT_TRUE(empty == BasicStringPiece<TypeParam>(empty)); + ASSERT_TRUE(empty == BasicStringPiece<TypeParam>(empty.begin(), empty.end())); +} + } // namespace base diff --git a/base/utf_offset_string_conversions.h b/base/utf_offset_string_conversions.h index c2faf3a..97b641e 100644 --- a/base/utf_offset_string_conversions.h +++ b/base/utf_offset_string_conversions.h @@ -11,11 +11,7 @@ #include "base/base_export.h" #include "base/string16.h" - -namespace base { -class StringPiece; -class StringPiece16; -} +#include "base/string_piece.h" // Like the conversions in utf_string_conversions.h, but also takes one or more // offsets (|offset[s]_for_adjustment|) into the source strings, each offset |