diff options
author | erikwright@chromium.org <erikwright@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-12-13 19:19:36 +0000 |
---|---|---|
committer | erikwright@chromium.org <erikwright@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-12-13 19:19:36 +0000 |
commit | 20543ba53ab8737affb06a21149c15f772246aed (patch) | |
tree | 2e0307ffdc1d94bbb073078e358b2c0b3d44c3a9 | |
parent | ea097c60d198d83db886af424ae5b4e00785ee9e (diff) | |
download | chromium_src-20543ba53ab8737affb06a21149c15f772246aed.zip chromium_src-20543ba53ab8737affb06a21149c15f772246aed.tar.gz chromium_src-20543ba53ab8737affb06a21149c15f772246aed.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=
Review URL: http://codereview.chromium.org/8659047
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@114242 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | base/i18n/case_conversion.h | 1 | ||||
-rw-r--r-- | base/logging.h | 3 | ||||
-rw-r--r-- | base/string_piece.cc | 55 | ||||
-rw-r--r-- | base/string_piece.h | 258 | ||||
-rw-r--r-- | base/string_piece_unittest.cc | 465 | ||||
-rw-r--r-- | base/utf_offset_string_conversions.h | 6 |
6 files changed, 339 insertions, 449 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..2960702 100644 --- a/base/string_piece.cc +++ b/base/string_piece.cc @@ -10,6 +10,17 @@ namespace base { +// 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<std::string>; +template class BasicStringPiece<string16>; +#endif + typedef StringPiece::size_type size_type; bool operator==(const StringPiece& x, const StringPiece& y) { @@ -19,22 +30,25 @@ 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 { +void BasicStringPiece<std::string>::CopyToString(std::string* target) const { target->assign(!empty() ? data() : "", size()); } -void StringPiece::AppendToString(std::string* target) const { +void BasicStringPiece<std::string>::AppendToString(std::string* target) const { if (!empty()) target->append(data(), size()); } -size_type StringPiece::copy(char* buf, size_type n, size_type pos) const { +size_type BasicStringPiece<std::string>::copy(char* buf, + size_type n, + size_type pos) const { size_type ret = std::min(length_ - pos, n); memcpy(buf, ptr_ + pos, ret); return ret; } -size_type StringPiece::find(const StringPiece& s, size_type pos) const { +size_type BasicStringPiece<std::string>::find(const BasicStringPiece& s, + size_type pos) const { if (pos > length_) return npos; @@ -44,7 +58,7 @@ size_type StringPiece::find(const StringPiece& s, size_type pos) const { return xpos + s.length_ <= length_ ? xpos : npos; } -size_type StringPiece::find(char c, size_type pos) const { +size_type BasicStringPiece<std::string>::find(char c, size_type pos) const { if (pos >= length_) return npos; @@ -52,7 +66,8 @@ size_type StringPiece::find(char c, size_type pos) const { return result != ptr_ + length_ ? static_cast<size_t>(result - ptr_) : npos; } -size_type StringPiece::rfind(const StringPiece& s, size_type pos) const { +size_type BasicStringPiece<std::string>::rfind(const BasicStringPiece& s, + size_type pos) const { if (length_ < s.length_) return npos; @@ -64,7 +79,7 @@ size_type StringPiece::rfind(const StringPiece& s, size_type pos) const { return result != last ? static_cast<size_t>(result - ptr_) : npos; } -size_type StringPiece::rfind(char c, size_type pos) const { +size_type BasicStringPiece<std::string>::rfind(char c, size_type pos) const { if (length_ == 0) return npos; @@ -94,8 +109,8 @@ static inline void BuildLookupTable(const StringPiece& characters_wanted, } } -size_type StringPiece::find_first_of(const StringPiece& s, - size_type pos) const { +size_type BasicStringPiece<std::string>::find_first_of( + const BasicStringPiece& s, size_type pos) const { if (length_ == 0 || s.length_ == 0) return npos; @@ -113,8 +128,8 @@ size_type StringPiece::find_first_of(const StringPiece& s, return npos; } -size_type StringPiece::find_first_not_of(const StringPiece& s, - size_type pos) const { +size_type BasicStringPiece<std::string>::find_first_not_of( + const BasicStringPiece& s, size_type pos) const { if (length_ == 0) return npos; @@ -135,7 +150,8 @@ size_type StringPiece::find_first_not_of(const StringPiece& s, return npos; } -size_type StringPiece::find_first_not_of(char c, size_type pos) const { +size_type BasicStringPiece<std::string>::find_first_not_of( + char c, size_type pos) const { if (length_ == 0) return npos; @@ -147,7 +163,8 @@ size_type StringPiece::find_first_not_of(char c, size_type pos) const { return npos; } -size_type StringPiece::find_last_of(const StringPiece& s, size_type pos) const { +size_type BasicStringPiece<std::string>::find_last_of(const StringPiece& s, + size_type pos) const { if (length_ == 0 || s.length_ == 0) return npos; @@ -166,8 +183,8 @@ size_type StringPiece::find_last_of(const StringPiece& s, size_type pos) const { return npos; } -size_type StringPiece::find_last_not_of(const StringPiece& s, - size_type pos) const { +size_type BasicStringPiece<std::string>::find_last_not_of( + const BasicStringPiece& s, size_type pos) const { if (length_ == 0) return npos; @@ -190,7 +207,8 @@ size_type StringPiece::find_last_not_of(const StringPiece& s, return npos; } -size_type StringPiece::find_last_not_of(char c, size_type pos) const { +size_type BasicStringPiece<std::string>::find_last_not_of(char c, + size_type pos) const { if (length_ == 0) return npos; @@ -203,12 +221,11 @@ size_type StringPiece::find_last_not_of(char c, size_type pos) const { return npos; } -StringPiece StringPiece::substr(size_type pos, size_type n) const { +BasicStringPiece<std::string> BasicStringPiece<std::string>::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); } -const StringPiece::size_type StringPiece::npos = size_type(-1); - } // namespace base diff --git a/base/string_piece.h b/base/string_piece.h index 278c7b6..f80ca5b 100644 --- a/base/string_piece.h +++ b/base/string_piece.h @@ -33,39 +33,47 @@ namespace base { -class BASE_EXPORT StringPiece { +template <typename STRING_TYPE> class BasicStringPiece; + +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) { } + // 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) {} // 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; } @@ -74,20 +82,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; @@ -98,7 +102,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) { @@ -108,28 +112,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_); } @@ -140,115 +129,120 @@ 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; - - 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; - - 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); - } - 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); - } - 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; - - static int wordmemcmp(const char* p, const char* p2, size_type N) { - return memcmp(p, p2, N); + static int wordmemcmp(const value_type* p, + const value_type* p2, + size_type N) { + return STRING_TYPE::traits_type::compare(p, p2, N); } - private: - const char* ptr_; + protected: + const value_type* ptr_; size_type length_; }; -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; +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 + +} // 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: - // 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) { } + 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) {} +}; - // 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; } +// Specializes BasicStringPiece for std::string to add a few operations that +// are not needed for string16. +template <> class BASE_EXPORT 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) {} + + // Prevent the following overload of set() from hiding the definitions in the + // base class. + using internal::StringPieceDetail<std::string>::set; - void clear() { - ptr_ = NULL; - length_ = 0; - } - void set(const char16* data, size_type len) { - ptr_ = data; + void set(const void* data, size_type len) { + ptr_ = reinterpret_cast<const value_type*>(data); length_ = len; } - void set(const char16* str) { - ptr_ = str; - length_ = str ? string16::traits_type::length(str) : 0; - } - char16 operator[](size_type i) const { return ptr_[i]; } + void CopyToString(std::string* target) const; + void AppendToString(std::string* target) const; - string16 as_string16() const { - // StringPiece claims that this is bad when data() is NULL, but unittesting - // seems to say otherwise. - return string16(data(), size()); + // Does "this" start with "x" + bool starts_with(const BasicStringPiece& x) const { + return ((length_ >= x.length_) && + (wordmemcmp(ptr_, x.ptr_, x.length_) == 0)); } - iterator begin() const { return ptr_; } - iterator end() const { return ptr_ + length_; } - const_reverse_iterator rbegin() const { - return const_reverse_iterator(ptr_ + length_); - } - const_reverse_iterator rend() const { - return const_reverse_iterator(ptr_); + // 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)); } - 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; + + size_type find(const BasicStringPiece& s, size_type pos = 0) const; + size_type find(char c, size_type pos = 0) const; + size_type rfind(const BasicStringPiece& s, size_type pos = npos) const; + size_type rfind(char c, size_type pos = npos) const; - static int wordmemcmp(const char16* p, const char16* p2, size_type N) { - return string16::traits_type::compare(p, p2, N); + size_type find_first_of(const BasicStringPiece& s, size_type pos = 0) const; + size_type find_first_of(char c, size_type pos = 0) const { + return find(c, pos); } + size_type find_first_not_of(const BasicStringPiece& 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 BasicStringPiece& s, size_type pos = npos) const; + 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; + size_type find_last_not_of(char c, size_type pos = npos) const; - private: - const char16* ptr_; - size_type length_; + BasicStringPiece substr(size_type pos, size_type n = npos) const; }; +// MSVC doesn't like complex extern templates and DLLs. +#if !defined(COMPILER_MSVC) +extern template class BasicStringPiece<std::string>; +extern template class BASE_EXPORT BasicStringPiece<string16>; +#endif + +typedef BasicStringPiece<std::string> StringPiece; +typedef BasicStringPiece<string16> StringPiece16; + 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..1362d4e 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); @@ -400,6 +458,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 +557,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 < StringPiece("abcdefghijklmnopqrstuvwxzz")); - ASSERT_TRUE(abc.compare(StringPiece("abcdefghijklmnopqrstuvwxzz")) < 0); + ASSERT_TRUE(abc < BasicStringPiece<TypeParam>(alphabet_z)); + ASSERT_TRUE(abc.compare(BasicStringPiece<TypeParam>(alphabet_z)) < 0); - ASSERT_TRUE(abc > StringPiece("abcdefghijklmnopqrstuvwxyy")); - ASSERT_TRUE(abc.compare(StringPiece("abcdefghijklmnopqrstuvwxyy")) > 0); + ASSERT_TRUE(abc > BasicStringPiece<TypeParam>(alphabet_y)); + ASSERT_TRUE(abc.compare(BasicStringPiece<TypeParam>(alphabet_y)) > 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 +613,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,73 +636,20 @@ 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"); } 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 |