Comment move behavior for fxcrt string and pointer types.
Then add tests to ensure it is always so.
- Tidy some friending while at it.
Bug: chromium:1039257
Change-Id: I579828a6d269801122645bc345136530a4b3fe96
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/64650
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Tom Sepez <tsepez@chromium.org>
diff --git a/core/fxcrt/bytestring.h b/core/fxcrt/bytestring.h
index f939213..11c372b 100644
--- a/core/fxcrt/bytestring.h
+++ b/core/fxcrt/bytestring.h
@@ -23,10 +23,6 @@
namespace fxcrt {
-class ByteString_Assign_Test;
-class ByteString_Concat_Test;
-class StringPool_ByteString_Test;
-
// A mutable string with shared buffers using copy-on-write semantics that
// avoids the cost of std::string's iterator stability guarantees.
class ByteString {
@@ -43,6 +39,8 @@
ByteString();
ByteString(const ByteString& other);
+
+ // Move-construct a ByteString. After construction, |other| is empty.
ByteString(ByteString&& other) noexcept;
// Deliberately implicit to avoid calling on every string literal.
@@ -134,6 +132,8 @@
ByteString& operator=(const char* str);
ByteString& operator=(ByteStringView str);
ByteString& operator=(const ByteString& that);
+
+ // Move-assign a ByteString. After assignment, |that| is empty.
ByteString& operator=(ByteString&& that);
ByteString& operator+=(char ch);
@@ -211,8 +211,9 @@
RetainPtr<StringData> m_pData;
- friend ByteString_Assign_Test;
- friend ByteString_Concat_Test;
+ friend class ByteString_Assign_Test;
+ friend class ByteString_Concat_Test;
+ friend class ByteString_Construct_Test;
friend class StringPool_ByteString_Test;
};
diff --git a/core/fxcrt/bytestring_unittest.cpp b/core/fxcrt/bytestring_unittest.cpp
index f40784b..d0eab1a 100644
--- a/core/fxcrt/bytestring_unittest.cpp
+++ b/core/fxcrt/bytestring_unittest.cpp
@@ -60,6 +60,27 @@
#endif
}
+TEST(ByteString, Construct) {
+ {
+ // Copy-construct.
+ ByteString string1("abc");
+ ByteString string2(string1);
+ EXPECT_EQ("abc", string1);
+ EXPECT_EQ("abc", string2);
+ EXPECT_EQ(2, string1.ReferenceCountForTesting());
+ EXPECT_EQ(2, string2.ReferenceCountForTesting());
+ }
+ {
+ // Move-construct.
+ ByteString string1("abc");
+ ByteString string2(std::move(string1));
+ EXPECT_TRUE(string1.IsEmpty());
+ EXPECT_EQ("abc", string2);
+ EXPECT_EQ(0, string1.ReferenceCountForTesting());
+ EXPECT_EQ(1, string2.ReferenceCountForTesting());
+ }
+}
+
TEST(ByteString, Assign) {
{
// Copy-assign.
@@ -84,6 +105,8 @@
EXPECT_EQ(1, string2.ReferenceCountForTesting());
string1 = std::move(string2);
+ EXPECT_EQ("abc", string1);
+ EXPECT_TRUE(string2.IsEmpty());
EXPECT_EQ(1, string1.ReferenceCountForTesting());
EXPECT_EQ(0, string2.ReferenceCountForTesting());
}
diff --git a/core/fxcrt/retain_ptr.h b/core/fxcrt/retain_ptr.h
index 4507d69..916a12e 100644
--- a/core/fxcrt/retain_ptr.h
+++ b/core/fxcrt/retain_ptr.h
@@ -31,6 +31,8 @@
RetainPtr() = default;
RetainPtr(const RetainPtr& that) : RetainPtr(that.Get()) {}
+
+ // Move-construct a RetainPtr. After construction, |that| will be NULL.
RetainPtr(RetainPtr&& that) noexcept { Swap(that); }
// Deliberately implicit to allow returning nullptrs.
@@ -65,6 +67,7 @@
return *this;
}
+ // Move-assign a RetainPtr. After assignment, |that| will be NULL.
RetainPtr& operator=(RetainPtr&& that) {
m_pObj.reset(that.Leak());
return *this;
diff --git a/core/fxcrt/unowned_ptr.h b/core/fxcrt/unowned_ptr.h
index 5a8ee3d..f7ff480 100644
--- a/core/fxcrt/unowned_ptr.h
+++ b/core/fxcrt/unowned_ptr.h
@@ -49,6 +49,8 @@
public:
constexpr UnownedPtr() noexcept = default;
constexpr UnownedPtr(const UnownedPtr& that) noexcept = default;
+
+ // Move-construct an UnownedPtr. After construction, |that| will be NULL.
constexpr UnownedPtr(UnownedPtr&& that) noexcept : m_pObj(that.Release()) {}
template <typename U>
@@ -76,6 +78,7 @@
return *this;
}
+ // Move-assign an UnownedPtr. After assignment, |that| will be NULL.
UnownedPtr& operator=(UnownedPtr&& that) noexcept {
if (*this != that)
Reset(that.Release());
diff --git a/core/fxcrt/unowned_ptr_unittest.cpp b/core/fxcrt/unowned_ptr_unittest.cpp
index f1979ef..fa884d4 100644
--- a/core/fxcrt/unowned_ptr_unittest.cpp
+++ b/core/fxcrt/unowned_ptr_unittest.cpp
@@ -120,6 +120,7 @@
auto owned = pdfium::MakeUnique<Clink>();
outer = owned.get();
UnownedPtr<Clink> inner(std::move(outer));
+ EXPECT_EQ(nullptr, outer.Get());
}
}
@@ -130,6 +131,7 @@
outer = owned.get();
UnownedPtr<Clink> inner;
inner = std::move(outer);
+ EXPECT_EQ(nullptr, outer.Get());
}
}
diff --git a/core/fxcrt/widestring.h b/core/fxcrt/widestring.h
index 3373067..a9b10ce 100644
--- a/core/fxcrt/widestring.h
+++ b/core/fxcrt/widestring.h
@@ -23,9 +23,6 @@
namespace fxcrt {
class ByteString;
-class StringPool_WideString_Test;
-class WideString_Assign_Test;
-class WideString_ConcatInPlace_Test;
// A mutable string with shared buffers using copy-on-write semantics that
// avoids the cost of std::string's iterator stability guarantees.
@@ -41,6 +38,8 @@
WideString();
WideString(const WideString& other);
+
+ // Move-construct a WideString. After construction, |other| is empty.
WideString(WideString&& other) noexcept;
// Deliberately implicit to avoid calling on every string literal.
@@ -116,6 +115,8 @@
WideString& operator=(const wchar_t* str);
WideString& operator=(WideStringView str);
WideString& operator=(const WideString& that);
+
+ // Move-assign a WideString. After assignment, |that| is empty.
WideString& operator=(WideString&& that);
WideString& operator+=(const wchar_t* str);
@@ -227,9 +228,10 @@
RetainPtr<StringData> m_pData;
- friend WideString_ConcatInPlace_Test;
- friend WideString_Assign_Test;
- friend StringPool_WideString_Test;
+ friend class WideString_Assign_Test;
+ friend class WideString_ConcatInPlace_Test;
+ friend class WideString_Construct_Test;
+ friend class StringPool_WideString_Test;
};
inline WideString operator+(WideStringView str1, WideStringView str2) {
diff --git a/core/fxcrt/widestring_unittest.cpp b/core/fxcrt/widestring_unittest.cpp
index f64aada..8d25476 100644
--- a/core/fxcrt/widestring_unittest.cpp
+++ b/core/fxcrt/widestring_unittest.cpp
@@ -57,6 +57,27 @@
#endif
}
+TEST(WideString, Construct) {
+ {
+ // Copy-construct.
+ WideString string1(L"abc");
+ WideString string2(string1);
+ EXPECT_EQ(L"abc", string1);
+ EXPECT_EQ(L"abc", string2);
+ EXPECT_EQ(2, string1.ReferenceCountForTesting());
+ EXPECT_EQ(2, string2.ReferenceCountForTesting());
+ }
+ {
+ // Move-construct.
+ WideString string1(L"abc");
+ WideString string2(std::move(string1));
+ EXPECT_TRUE(string1.IsEmpty());
+ EXPECT_EQ(L"abc", string2);
+ EXPECT_EQ(0, string1.ReferenceCountForTesting());
+ EXPECT_EQ(1, string2.ReferenceCountForTesting());
+ }
+}
+
TEST(WideString, Assign) {
{
// Copy-assign.
@@ -81,6 +102,8 @@
EXPECT_EQ(1, string2.ReferenceCountForTesting());
string1 = std::move(string2);
+ EXPECT_EQ(L"abc", string1);
+ EXPECT_TRUE(string2.IsEmpty());
EXPECT_EQ(1, string1.ReferenceCountForTesting());
EXPECT_EQ(0, string2.ReferenceCountForTesting());
}