Make UnownedPtr and RetainPtr more similar to each other.
The remaining difference is that UnownedPtr<T> has operator=(T*),
which prevents one test from compiling until it is removed (which
will create a lot of code churn).
-- add new assignment operators.
-- add new tests and simplify existing ones.
-- add some "noexcepts" and "defaults"
-- template/untemplate some methods.
-- add MakeUnowned() helper.
Change-Id: I1189fa2df8d9f5f704c2e6532ca4b481c6c922ec
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/98411
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Tom Sepez <tsepez@chromium.org>
diff --git a/core/fxcrt/retain_ptr.h b/core/fxcrt/retain_ptr.h
index 99d73fd..eda9517 100644
--- a/core/fxcrt/retain_ptr.h
+++ b/core/fxcrt/retain_ptr.h
@@ -27,20 +27,20 @@
template <class T>
class RetainPtr {
public:
- RetainPtr() = default;
+ RetainPtr() noexcept = default;
// Deliberately implicit to allow returning nullptrs.
// NOLINTNEXTLINE(runtime/explicit)
RetainPtr(std::nullptr_t ptr) {}
- explicit RetainPtr(T* pObj) : m_pObj(pObj) {
+ explicit RetainPtr(T* pObj) noexcept : m_pObj(pObj) {
if (m_pObj)
m_pObj->Retain();
}
// Copy-construct a RetainPtr.
// Required in addition to copy conversion constructor below.
- RetainPtr(const RetainPtr& that) : RetainPtr(that.Get()) {}
+ RetainPtr(const RetainPtr& that) noexcept : RetainPtr(that.Get()) {}
// Move-construct a RetainPtr. After construction, |that| will be NULL.
// Required in addition to move conversion constructor below.
@@ -60,6 +60,7 @@
Unleak(that.Leak());
}
+ // Copy-assign a RetainPtr.
RetainPtr& operator=(const RetainPtr& that) {
if (*this != that)
Reset(that.Get());
@@ -72,6 +73,8 @@
return *this;
}
+ ~RetainPtr() = default;
+
template <class U>
RetainPtr<U> As() const {
return RetainPtr<U>(static_cast<U*>(Get()));
@@ -168,7 +171,8 @@
return RetainPtr<T>(new T(std::forward<Args>(args)...));
}
-// Type-deducing wrapper to make a RetainPtr from an ordinary pointer.
+// Type-deducing wrapper to make a RetainPtr from an ordinary pointer,
+// since equivalent constructor is explicit.
template <typename T>
RetainPtr<T> WrapRetain(T* that) {
return RetainPtr<T>(that);
diff --git a/core/fxcrt/retain_ptr_unittest.cpp b/core/fxcrt/retain_ptr_unittest.cpp
index e3ca7e4..2fdd993 100644
--- a/core/fxcrt/retain_ptr_unittest.cpp
+++ b/core/fxcrt/retain_ptr_unittest.cpp
@@ -298,10 +298,8 @@
RetainPtr<PseudoRetainable> ptr1(&obj);
{
RetainPtr<const PseudoRetainable> ptr2;
- EXPECT_EQ(&obj, ptr1.Get());
- EXPECT_FALSE(ptr2.Get());
ptr2 = std::move(ptr1);
- EXPECT_FALSE(ptr1.Get());
+ EXPECT_FALSE(ptr1);
EXPECT_EQ(&obj, ptr2.Get());
EXPECT_EQ(1, obj.retain_count());
EXPECT_EQ(0, obj.release_count());
diff --git a/core/fxcrt/unowned_ptr.h b/core/fxcrt/unowned_ptr.h
index 6eca3c8..f9946f0 100644
--- a/core/fxcrt/unowned_ptr.h
+++ b/core/fxcrt/unowned_ptr.h
@@ -51,21 +51,39 @@
// Deliberately implicit to allow returning nullptrs.
// NOLINTNEXTLINE(runtime/explicit)
- constexpr UnownedPtr(std::nullptr_t ptr) noexcept {}
+ constexpr UnownedPtr(std::nullptr_t ptr) {}
- template <typename U>
- explicit constexpr UnownedPtr(U* pObj) noexcept : m_pObj(pObj) {}
+ explicit constexpr UnownedPtr(T* pObj) noexcept : m_pObj(pObj) {}
- constexpr UnownedPtr(const UnownedPtr& that) noexcept = default;
+ // Copy-construct an UnownedPtr.
+ // Required in addition to copy conversion constructor below.
+ constexpr UnownedPtr(const UnownedPtr& that) noexcept : m_pObj(that.Get()) {}
// Move-construct an UnownedPtr. After construction, |that| will be NULL.
+ // Required in addition to move conversion constructor below.
constexpr UnownedPtr(UnownedPtr&& that) noexcept : m_pObj(that.Release()) {}
+ // Copy conversion constructor.
+ template <class U,
+ typename = typename std::enable_if<
+ std::is_convertible<U*, T*>::value>::type>
+ UnownedPtr(const UnownedPtr<U>& that) : UnownedPtr(that.Get()) {}
+
+ // Move-conversion constructor.
+ template <class U,
+ typename = typename std::enable_if<
+ std::is_convertible<U*, T*>::value>::type>
+ UnownedPtr(UnownedPtr<U>&& that) noexcept {
+ Reset(that.Release());
+ }
+
+ // Assing an UnownedPtr from a raw ptr.
UnownedPtr& operator=(T* that) noexcept {
Reset(that);
return *this;
}
+ // Copy-assign an UnownedPtr.
UnownedPtr& operator=(const UnownedPtr& that) noexcept {
if (*this != that)
Reset(that.Get());
@@ -132,4 +150,15 @@
using fxcrt::UnownedPtr;
+namespace pdfium {
+
+// Type-deducing wrapper to make an UnownedPtr from an ordinary pointer,
+// since equivalent constructor is explicit.
+template <typename T>
+UnownedPtr<T> WrapUnowned(T* that) {
+ return UnownedPtr<T>(that);
+}
+
+} // namespace pdfium
+
#endif // CORE_FXCRT_UNOWNED_PTR_H_
diff --git a/core/fxcrt/unowned_ptr_unittest.cpp b/core/fxcrt/unowned_ptr_unittest.cpp
index 7862e5e..532d9c4 100644
--- a/core/fxcrt/unowned_ptr_unittest.cpp
+++ b/core/fxcrt/unowned_ptr_unittest.cpp
@@ -64,6 +64,11 @@
} // namespace
+TEST(UnownedPtr, Null) {
+ UnownedPtr<Clink> ptr;
+ EXPECT_FALSE(ptr.Get());
+}
+
TEST(UnownedPtr, PtrOk) {
auto ptr1 = std::make_unique<Clink>();
{
@@ -80,6 +85,22 @@
#endif
}
+TEST(UnownedPtr, CopyCtor) {
+ std::unique_ptr<Clink> obj = std::make_unique<Clink>();
+ UnownedPtr<Clink> ptr1(obj.get());
+ UnownedPtr<Clink> ptr2(ptr1);
+ EXPECT_TRUE(ptr2);
+ EXPECT_TRUE(ptr1);
+}
+
+TEST(UnownedPtr, CopyConversionCtor) {
+ std::unique_ptr<Clink> obj = std::make_unique<Clink>();
+ UnownedPtr<Clink> ptr1(obj.get());
+ UnownedPtr<const Clink> ptr2(ptr1);
+ EXPECT_TRUE(ptr2);
+ EXPECT_TRUE(ptr1);
+}
+
TEST(UnownedPtr, ResetOk) {
auto ptr1 = std::make_unique<Clink>();
{
@@ -130,17 +151,31 @@
outer = owned.get();
UnownedPtr<Clink> inner(std::move(outer));
EXPECT_FALSE(outer.Get());
+ EXPECT_EQ(owned.get(), inner.Get());
}
}
-TEST(UnownedPtr, MoveAssignOk) {
+TEST(UnownedPtr, MoveConversionCtorOk) {
UnownedPtr<Clink> outer;
{
auto owned = std::make_unique<Clink>();
outer = owned.get();
+ UnownedPtr<const Clink> inner(std::move(outer));
+ EXPECT_FALSE(outer.Get());
+ }
+}
+
+TEST(UnownedPtr, MoveConversionAssignOk) {
+ UnownedPtr<Clink> outer;
+ {
+ auto owned = std::make_unique<Clink>();
+ outer = owned.get();
+ // TODO(tsepez): disambiguate ctors and actually const-convert.
+ // UnownedPtr<const Clink> inner;
UnownedPtr<Clink> inner;
inner = std::move(outer);
- EXPECT_FALSE(outer.Get());
+ EXPECT_FALSE(outer);
+ EXPECT_EQ(owned.get(), inner.Get());
}
}