From d7a3f981fdc6bf9aef306854505638db7b4b51c7 Mon Sep 17 00:00:00 2001 From: Lei Zhang Date: Mon, 6 Nov 2017 19:00:21 +0000 Subject: Improve ByteString{View}::operator<(). Make it possible to compare: 1) const char* < ByteStringView 2) ByteString < const char* 3) ByteString < ByteStringView 4) const char* < ByteString Do the same for WideString{View}. With new unit test cases. Change-Id: I31da526b1ab78b8d51ec1c99bf29046fe13754d5 Reviewed-on: https://pdfium-review.googlesource.com/17872 Commit-Queue: Lei Zhang Reviewed-by: Tom Sepez --- core/fxcrt/bytestring.cpp | 50 ++++++++++++++------ core/fxcrt/bytestring.h | 7 ++- core/fxcrt/bytestring_unittest.cpp | 95 ++++++++++++++++++++++++++++++++++++++ core/fxcrt/string_view_template.h | 5 +- core/fxcrt/widestring.cpp | 67 +++++++++++++++++---------- core/fxcrt/widestring.h | 7 ++- core/fxcrt/widestring_unittest.cpp | 95 ++++++++++++++++++++++++++++++++++++++ 7 files changed, 284 insertions(+), 42 deletions(-) diff --git a/core/fxcrt/bytestring.cpp b/core/fxcrt/bytestring.cpp index 37121a7da9..704cdd46aa 100644 --- a/core/fxcrt/bytestring.cpp +++ b/core/fxcrt/bytestring.cpp @@ -251,13 +251,39 @@ bool ByteString::operator==(const ByteString& other) const { m_pData->m_nDataLength) == 0; } -bool ByteString::operator<(const ByteString& str) const { - if (m_pData == str.m_pData) +bool ByteString::operator<(const char* ptr) const { + if (!m_pData && !ptr) return false; + if (c_str() == ptr) + return false; + + size_t len = GetLength(); + size_t other_len = ptr ? strlen(ptr) : 0; + int result = memcmp(c_str(), ptr, std::min(len, other_len)); + return result < 0 || (result == 0 && len < other_len); +} +bool ByteString::operator<(const ByteStringView& str) const { + if (!m_pData && !str.unterminated_c_str()) + return false; + if (c_str() == str.unterminated_c_str()) + return false; + + size_t len = GetLength(); + size_t other_len = str.GetLength(); int result = - memcmp(c_str(), str.c_str(), std::min(GetLength(), str.GetLength())); - return result < 0 || (result == 0 && GetLength() < str.GetLength()); + memcmp(c_str(), str.unterminated_c_str(), std::min(len, other_len)); + return result < 0 || (result == 0 && len < other_len); +} + +bool ByteString::operator<(const ByteString& other) const { + if (m_pData == other.m_pData) + return false; + + size_t len = GetLength(); + size_t other_len = other.GetLength(); + int result = memcmp(c_str(), other.c_str(), std::min(len, other_len)); + return result < 0 || (result == 0 && len < other_len); } bool ByteString::EqualNoCase(const ByteStringView& str) const { @@ -668,26 +694,22 @@ ByteString ByteString::FromUnicode(const WideString& str) { } int ByteString::Compare(const ByteStringView& str) const { - if (!m_pData) { + if (!m_pData) return str.IsEmpty() ? 0 : -1; - } + size_t this_len = m_pData->m_nDataLength; size_t that_len = str.GetLength(); size_t min_len = std::min(this_len, that_len); for (size_t i = 0; i < min_len; i++) { - if (static_cast(m_pData->m_String[i]) < str[i]) { + if (static_cast(m_pData->m_String[i]) < str[i]) return -1; - } - if (static_cast(m_pData->m_String[i]) > str[i]) { + if (static_cast(m_pData->m_String[i]) > str[i]) return 1; - } } - if (this_len < that_len) { + if (this_len < that_len) return -1; - } - if (this_len > that_len) { + if (this_len > that_len) return 1; - } return 0; } diff --git a/core/fxcrt/bytestring.h b/core/fxcrt/bytestring.h index 67fdd1d9ac..6d5843efcd 100644 --- a/core/fxcrt/bytestring.h +++ b/core/fxcrt/bytestring.h @@ -110,7 +110,9 @@ class ByteString { bool operator!=(const ByteStringView& str) const { return !(*this == str); } bool operator!=(const ByteString& other) const { return !(*this == other); } - bool operator<(const ByteString& str) const; + bool operator<(const char* ptr) const; + bool operator<(const ByteStringView& str) const; + bool operator<(const ByteString& other) const; const ByteString& operator=(const char* str); const ByteString& operator=(const ByteStringView& bstrc); @@ -209,6 +211,9 @@ inline bool operator!=(const char* lhs, const ByteString& rhs) { inline bool operator!=(const ByteStringView& lhs, const ByteString& rhs) { return rhs != lhs; } +inline bool operator<(const char* lhs, const ByteString& rhs) { + return rhs.Compare(lhs) > 0; +} inline ByteString operator+(const ByteStringView& str1, const ByteStringView& str2) { diff --git a/core/fxcrt/bytestring_unittest.cpp b/core/fxcrt/bytestring_unittest.cpp index 9812367fe8..4668fe1cc8 100644 --- a/core/fxcrt/bytestring_unittest.cpp +++ b/core/fxcrt/bytestring_unittest.cpp @@ -55,29 +55,94 @@ TEST(ByteString, OperatorLT) { ByteString a("a"); ByteString abc("abc"); ByteString def("def"); + ByteStringView v_empty; + ByteStringView v_a("a"); + ByteStringView v_abc("abc"); + ByteStringView v_def("def"); + const char* const c_null = nullptr; + const char* const c_empty = ""; + const char* const c_a = "a"; + const char* const c_abc = "abc"; + const char* const c_def = "def"; EXPECT_FALSE(empty < empty); EXPECT_FALSE(a < a); EXPECT_FALSE(abc < abc); EXPECT_FALSE(def < def); + EXPECT_FALSE(c_null < empty); + EXPECT_FALSE(c_empty < empty); + EXPECT_FALSE(c_a < a); + EXPECT_FALSE(c_abc < abc); + EXPECT_FALSE(c_def < def); + EXPECT_FALSE(empty < c_null); + EXPECT_FALSE(empty < c_empty); + EXPECT_FALSE(a < c_a); + EXPECT_FALSE(abc < c_abc); + EXPECT_FALSE(def < c_def); + EXPECT_FALSE(empty < v_empty); + EXPECT_FALSE(a < v_a); + EXPECT_FALSE(abc < v_abc); + EXPECT_FALSE(def < v_def); EXPECT_TRUE(empty < a); EXPECT_FALSE(a < empty); + EXPECT_TRUE(c_null < a); + EXPECT_TRUE(c_empty < a); + EXPECT_FALSE(c_a < empty); + EXPECT_TRUE(empty < c_a); + EXPECT_FALSE(a < c_null); + EXPECT_FALSE(a < c_empty); + EXPECT_TRUE(empty < v_a); + EXPECT_FALSE(a < v_empty); EXPECT_TRUE(empty < abc); EXPECT_FALSE(abc < empty); + EXPECT_TRUE(c_null < abc); + EXPECT_TRUE(c_empty < abc); + EXPECT_FALSE(c_abc < empty); + EXPECT_TRUE(empty < c_abc); + EXPECT_FALSE(abc < c_null); + EXPECT_FALSE(abc < c_empty); + EXPECT_TRUE(empty < v_abc); + EXPECT_FALSE(abc < v_empty); EXPECT_TRUE(empty < def); EXPECT_FALSE(def < empty); + EXPECT_TRUE(c_null < def); + EXPECT_TRUE(c_empty < def); + EXPECT_FALSE(c_def < empty); + EXPECT_TRUE(empty < c_def); + EXPECT_FALSE(def < c_null); + EXPECT_FALSE(def < c_empty); + EXPECT_TRUE(empty < v_def); + EXPECT_FALSE(def < v_empty); EXPECT_TRUE(a < abc); EXPECT_FALSE(abc < a); + EXPECT_TRUE(c_a < abc); + EXPECT_FALSE(c_abc < a); + EXPECT_TRUE(a < c_abc); + EXPECT_FALSE(abc < c_a); + EXPECT_TRUE(a < v_abc); + EXPECT_FALSE(abc < v_a); EXPECT_TRUE(a < def); EXPECT_FALSE(def < a); + EXPECT_TRUE(c_a < def); + EXPECT_FALSE(c_def < a); + EXPECT_TRUE(a < c_def); + EXPECT_FALSE(def < c_a); + EXPECT_TRUE(a < v_def); + EXPECT_FALSE(def < v_a); EXPECT_TRUE(abc < def); EXPECT_FALSE(def < abc); + EXPECT_TRUE(c_abc < def); + EXPECT_FALSE(c_def < abc); + EXPECT_TRUE(abc < c_def); + EXPECT_FALSE(def < c_abc); + EXPECT_TRUE(abc < v_def); + EXPECT_FALSE(def < v_abc); } TEST(ByteString, OperatorEQ) { @@ -1092,29 +1157,59 @@ TEST(ByteStringView, OperatorLT) { ByteStringView a("a"); ByteStringView abc("abc"); ByteStringView def("def"); + const char* const c_null = nullptr; + const char* const c_empty = ""; + const char* const c_a = "a"; + const char* const c_abc = "abc"; + const char* const c_def = "def"; EXPECT_FALSE(empty < empty); EXPECT_FALSE(a < a); EXPECT_FALSE(abc < abc); EXPECT_FALSE(def < def); + EXPECT_FALSE(c_null < empty); + EXPECT_FALSE(c_empty < empty); + EXPECT_FALSE(c_a < a); + EXPECT_FALSE(c_abc < abc); + EXPECT_FALSE(c_def < def); + EXPECT_FALSE(empty < c_null); + EXPECT_FALSE(empty < c_empty); + EXPECT_FALSE(a < c_a); + EXPECT_FALSE(abc < c_abc); + EXPECT_FALSE(def < c_def); EXPECT_TRUE(empty < a); EXPECT_FALSE(a < empty); + EXPECT_TRUE(empty < c_a); + EXPECT_FALSE(a < c_null); + EXPECT_FALSE(a < c_empty); EXPECT_TRUE(empty < abc); EXPECT_FALSE(abc < empty); + EXPECT_TRUE(empty < c_abc); + EXPECT_FALSE(abc < c_null); + EXPECT_FALSE(abc < c_empty); EXPECT_TRUE(empty < def); EXPECT_FALSE(def < empty); + EXPECT_TRUE(empty < c_def); + EXPECT_FALSE(def < c_null); + EXPECT_FALSE(def < c_empty); EXPECT_TRUE(a < abc); EXPECT_FALSE(abc < a); + EXPECT_TRUE(a < c_abc); + EXPECT_FALSE(abc < c_a); EXPECT_TRUE(a < def); EXPECT_FALSE(def < a); + EXPECT_TRUE(a < c_def); + EXPECT_FALSE(def < c_a); EXPECT_TRUE(abc < def); EXPECT_FALSE(def < abc); + EXPECT_TRUE(abc < c_def); + EXPECT_FALSE(def < c_abc); } TEST(ByteStringView, OperatorEQ) { diff --git a/core/fxcrt/string_view_template.h b/core/fxcrt/string_view_template.h index 346e5a469d..ac376ff8a0 100644 --- a/core/fxcrt/string_view_template.h +++ b/core/fxcrt/string_view_template.h @@ -227,11 +227,14 @@ template inline bool operator==(const T* lhs, const StringViewTemplate& rhs) { return rhs == lhs; } - template inline bool operator!=(const T* lhs, const StringViewTemplate& rhs) { return rhs != lhs; } +template +inline bool operator<(const T* lhs, const StringViewTemplate& rhs) { + return rhs > lhs; +} extern template class StringViewTemplate; extern template class StringViewTemplate; diff --git a/core/fxcrt/widestring.cpp b/core/fxcrt/widestring.cpp index adeb28cc16..bd504e0cac 100644 --- a/core/fxcrt/widestring.cpp +++ b/core/fxcrt/widestring.cpp @@ -434,13 +434,39 @@ bool WideString::operator==(const WideString& other) const { m_pData->m_nDataLength) == 0; } -bool WideString::operator<(const WideString& str) const { - if (m_pData == str.m_pData) +bool WideString::operator<(const wchar_t* ptr) const { + if (!m_pData && !ptr) return false; + if (c_str() == ptr) + return false; + + size_t len = GetLength(); + size_t other_len = ptr ? wcslen(ptr) : 0; + int result = wmemcmp(c_str(), ptr, std::min(len, other_len)); + return result < 0 || (result == 0 && len < other_len); +} +bool WideString::operator<(const WideStringView& str) const { + if (!m_pData && !str.unterminated_c_str()) + return false; + if (c_str() == str.unterminated_c_str()) + return false; + + size_t len = GetLength(); + size_t other_len = str.GetLength(); int result = - wmemcmp(c_str(), str.c_str(), std::min(GetLength(), str.GetLength())); - return result < 0 || (result == 0 && GetLength() < str.GetLength()); + wmemcmp(c_str(), str.unterminated_c_str(), std::min(len, other_len)); + return result < 0 || (result == 0 && len < other_len); +} + +bool WideString::operator<(const WideString& other) const { + if (m_pData == other.m_pData) + return false; + + size_t len = GetLength(); + size_t other_len = other.GetLength(); + int result = wmemcmp(c_str(), other.c_str(), std::min(len, other_len)); + return result < 0 || (result == 0 && len < other_len); } void WideString::AssignCopy(const wchar_t* pSrcData, size_t nSrcLen) { @@ -880,45 +906,36 @@ void WideString::SetAt(size_t index, wchar_t c) { int WideString::Compare(const wchar_t* lpsz) const { if (m_pData) - return wcscmp(m_pData->m_String, lpsz); + return lpsz ? wcscmp(m_pData->m_String, lpsz) : 1; return (!lpsz || lpsz[0] == 0) ? 0 : -1; } int WideString::Compare(const WideString& str) const { - if (!m_pData) { - if (!str.m_pData) { - return 0; - } - return -1; - } - if (!str.m_pData) { + if (!m_pData) + return str.m_pData ? -1 : 0; + if (!str.m_pData) return 1; - } + size_t this_len = m_pData->m_nDataLength; size_t that_len = str.m_pData->m_nDataLength; size_t min_len = std::min(this_len, that_len); for (size_t i = 0; i < min_len; i++) { - if (m_pData->m_String[i] < str.m_pData->m_String[i]) { + if (m_pData->m_String[i] < str.m_pData->m_String[i]) return -1; - } - if (m_pData->m_String[i] > str.m_pData->m_String[i]) { + if (m_pData->m_String[i] > str.m_pData->m_String[i]) return 1; - } } - if (this_len < that_len) { + if (this_len < that_len) return -1; - } - if (this_len > that_len) { + if (this_len > that_len) return 1; - } return 0; } int WideString::CompareNoCase(const wchar_t* lpsz) const { - if (!m_pData) { - return (!lpsz || lpsz[0] == 0) ? 0 : -1; - } - return FXSYS_wcsicmp(m_pData->m_String, lpsz); + if (m_pData) + return lpsz ? FXSYS_wcsicmp(m_pData->m_String, lpsz) : 1; + return (!lpsz || lpsz[0] == 0) ? 0 : -1; } size_t WideString::WStringLength(const unsigned short* str) { diff --git a/core/fxcrt/widestring.h b/core/fxcrt/widestring.h index 745fa5b2ab..01c4eedaf1 100644 --- a/core/fxcrt/widestring.h +++ b/core/fxcrt/widestring.h @@ -114,7 +114,9 @@ class WideString { bool operator!=(const WideStringView& str) const { return !(*this == str); } bool operator!=(const WideString& other) const { return !(*this == other); } - bool operator<(const WideString& str) const; + bool operator<(const wchar_t* ptr) const; + bool operator<(const WideStringView& str) const; + bool operator<(const WideString& other) const; CharType operator[](const size_t index) const { ASSERT(IsValidIndex(index)); @@ -247,6 +249,9 @@ inline bool operator!=(const wchar_t* lhs, const WideString& rhs) { inline bool operator!=(const WideStringView& lhs, const WideString& rhs) { return rhs != lhs; } +inline bool operator<(const wchar_t* lhs, const WideString& rhs) { + return rhs.Compare(lhs) > 0; +} std::wostream& operator<<(std::wostream& os, const WideString& str); std::ostream& operator<<(std::ostream& os, const WideString& str); diff --git a/core/fxcrt/widestring_unittest.cpp b/core/fxcrt/widestring_unittest.cpp index 681fb472a2..42819b3349 100644 --- a/core/fxcrt/widestring_unittest.cpp +++ b/core/fxcrt/widestring_unittest.cpp @@ -54,29 +54,94 @@ TEST(WideString, OperatorLT) { WideString a(L"a"); WideString abc(L"\x0110qq"); // Comes before despite endianness. WideString def(L"\x1001qq"); // Comes after despite endianness. + WideStringView v_empty; + WideStringView v_a(L"a"); + WideStringView v_abc(L"\x0110qq"); + WideStringView v_def(L"\x1001qq"); + const wchar_t* const c_null = nullptr; + const wchar_t* const c_empty = L""; + const wchar_t* const c_a = L"a"; + const wchar_t* const c_abc = L"\x0110qq"; + const wchar_t* const c_def = L"\x1001qq"; EXPECT_FALSE(empty < empty); EXPECT_FALSE(a < a); EXPECT_FALSE(abc < abc); EXPECT_FALSE(def < def); + EXPECT_FALSE(c_null < empty); + EXPECT_FALSE(c_empty < empty); + EXPECT_FALSE(c_a < a); + EXPECT_FALSE(c_abc < abc); + EXPECT_FALSE(c_def < def); + EXPECT_FALSE(empty < c_null); + EXPECT_FALSE(empty < c_empty); + EXPECT_FALSE(a < c_a); + EXPECT_FALSE(abc < c_abc); + EXPECT_FALSE(def < c_def); + EXPECT_FALSE(empty < v_empty); + EXPECT_FALSE(a < v_a); + EXPECT_FALSE(abc < v_abc); + EXPECT_FALSE(def < v_def); EXPECT_TRUE(empty < a); EXPECT_FALSE(a < empty); + EXPECT_TRUE(c_null < a); + EXPECT_TRUE(c_empty < a); + EXPECT_FALSE(c_a < empty); + EXPECT_TRUE(empty < c_a); + EXPECT_FALSE(a < c_null); + EXPECT_FALSE(a < c_empty); + EXPECT_TRUE(empty < v_a); + EXPECT_FALSE(a < v_empty); EXPECT_TRUE(empty < abc); EXPECT_FALSE(abc < empty); + EXPECT_TRUE(c_null < abc); + EXPECT_TRUE(c_empty < abc); + EXPECT_FALSE(c_abc < empty); + EXPECT_TRUE(empty < c_abc); + EXPECT_FALSE(abc < c_null); + EXPECT_FALSE(abc < c_empty); + EXPECT_TRUE(empty < v_abc); + EXPECT_FALSE(abc < v_empty); EXPECT_TRUE(empty < def); EXPECT_FALSE(def < empty); + EXPECT_TRUE(c_null < def); + EXPECT_TRUE(c_empty < def); + EXPECT_FALSE(c_def < empty); + EXPECT_TRUE(empty < c_def); + EXPECT_FALSE(def < c_null); + EXPECT_FALSE(def < c_empty); + EXPECT_TRUE(empty < v_def); + EXPECT_FALSE(def < v_empty); EXPECT_TRUE(a < abc); EXPECT_FALSE(abc < a); + EXPECT_TRUE(c_a < abc); + EXPECT_FALSE(c_abc < a); + EXPECT_TRUE(a < c_abc); + EXPECT_FALSE(abc < c_a); + EXPECT_TRUE(a < v_abc); + EXPECT_FALSE(abc < v_a); EXPECT_TRUE(a < def); EXPECT_FALSE(def < a); + EXPECT_TRUE(c_a < def); + EXPECT_FALSE(c_def < a); + EXPECT_TRUE(a < c_def); + EXPECT_FALSE(def < c_a); + EXPECT_TRUE(a < v_def); + EXPECT_FALSE(def < v_a); EXPECT_TRUE(abc < def); EXPECT_FALSE(def < abc); + EXPECT_TRUE(c_abc < def); + EXPECT_FALSE(c_def < abc); + EXPECT_TRUE(abc < c_def); + EXPECT_FALSE(def < c_abc); + EXPECT_TRUE(abc < v_def); + EXPECT_FALSE(def < v_abc); } TEST(WideString, OperatorEQ) { @@ -879,29 +944,59 @@ TEST(WideStringView, OperatorLT) { WideStringView a(L"a"); WideStringView abc(L"\x0110qq"); // Comes InsertAtFront despite endianness. WideStringView def(L"\x1001qq"); // Comes InsertAtBack despite endianness. + const wchar_t* const c_null = nullptr; + const wchar_t* const c_empty = L""; + const wchar_t* const c_a = L"a"; + const wchar_t* const c_abc = L"\x0110qq"; + const wchar_t* const c_def = L"\x1001qq"; EXPECT_FALSE(empty < empty); EXPECT_FALSE(a < a); EXPECT_FALSE(abc < abc); EXPECT_FALSE(def < def); + EXPECT_FALSE(c_null < empty); + EXPECT_FALSE(c_empty < empty); + EXPECT_FALSE(c_a < a); + EXPECT_FALSE(c_abc < abc); + EXPECT_FALSE(c_def < def); + EXPECT_FALSE(empty < c_null); + EXPECT_FALSE(empty < c_empty); + EXPECT_FALSE(a < c_a); + EXPECT_FALSE(abc < c_abc); + EXPECT_FALSE(def < c_def); EXPECT_TRUE(empty < a); EXPECT_FALSE(a < empty); + EXPECT_TRUE(empty < c_a); + EXPECT_FALSE(a < c_null); + EXPECT_FALSE(a < c_empty); EXPECT_TRUE(empty < abc); EXPECT_FALSE(abc < empty); + EXPECT_TRUE(empty < c_abc); + EXPECT_FALSE(abc < c_null); + EXPECT_FALSE(abc < c_empty); EXPECT_TRUE(empty < def); EXPECT_FALSE(def < empty); + EXPECT_TRUE(empty < c_def); + EXPECT_FALSE(def < c_null); + EXPECT_FALSE(def < c_empty); EXPECT_TRUE(a < abc); EXPECT_FALSE(abc < a); + EXPECT_TRUE(a < c_abc); + EXPECT_FALSE(abc < c_a); EXPECT_TRUE(a < def); EXPECT_FALSE(def < a); + EXPECT_TRUE(a < c_def); + EXPECT_FALSE(def < c_a); EXPECT_TRUE(abc < def); EXPECT_FALSE(def < abc); + EXPECT_TRUE(abc < c_def); + EXPECT_FALSE(def < c_abc); } TEST(WideStringView, OperatorEQ) { -- cgit v1.2.3