Back-fill some functionality for CFX_UnownedPtr

Add Release() method, type-convertible compares and assigns, and
right hand vs. left hand comparisons.

Change-Id: I96b1112e328802143d314aa6c92948f26583fa90
Reviewed-on: https://pdfium-review.googlesource.com/5731
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Tom Sepez <tsepez@chromium.org>
diff --git a/core/fxcrt/cfx_unowned_ptr.h b/core/fxcrt/cfx_unowned_ptr.h
index d91833a..da1875c 100644
--- a/core/fxcrt/cfx_unowned_ptr.h
+++ b/core/fxcrt/cfx_unowned_ptr.h
@@ -10,8 +10,6 @@
 #include <type_traits>
 #include <utility>
 
-#include "core/fxcrt/fx_memory.h"
-
 template <class T>
 class CFX_UnownedPtr {
  public:
@@ -25,21 +23,16 @@
   // NOLINTNEXTLINE(runtime/explicit)
   CFX_UnownedPtr(std::nullptr_t ptr) {}
 
-#if defined(MEMORY_TOOL_REPLACES_ALLOCATOR)
   ~CFX_UnownedPtr() { Probe(); }
-#endif
 
   CFX_UnownedPtr& operator=(T* that) {
-#if defined(MEMORY_TOOL_REPLACES_ALLOCATOR)
     Probe();
-#endif
     m_pObj = that;
     return *this;
   }
+
   CFX_UnownedPtr& operator=(const CFX_UnownedPtr& that) {
-#if defined(MEMORY_TOOL_REPLACES_ALLOCATOR)
     Probe();
-#endif
     if (*this != that)
       m_pObj = that.Get();
     return *this;
@@ -48,27 +41,53 @@
   bool operator==(const CFX_UnownedPtr& that) const {
     return Get() == that.Get();
   }
-  bool operator==(const T* that) const { return Get() == that; }
   bool operator!=(const CFX_UnownedPtr& that) const { return !(*this == that); }
-  bool operator!=(const T* that) const { return !(*this == that); }
   bool operator<(const CFX_UnownedPtr& that) const {
     return std::less<T*>()(Get(), that.Get());
   }
 
+  template <typename U>
+  bool operator==(const U* that) const {
+    return Get() == that;
+  }
+
+  template <typename U>
+  bool operator!=(const U* that) const {
+    return !(*this == that);
+  }
+
   T* Get() const { return m_pObj; }
+
+  T* Release() {
+    Probe();
+    T* pTemp = nullptr;
+    std::swap(pTemp, m_pObj);
+    return pTemp;
+  }
+
   explicit operator bool() const { return !!m_pObj; }
   T& operator*() const { return *m_pObj; }
   T* operator->() const { return m_pObj; }
 
  private:
+  inline void Probe() {
 #if defined(MEMORY_TOOL_REPLACES_ALLOCATOR)
-  void Probe() {
     if (m_pObj)
       reinterpret_cast<const volatile uint8_t*>(m_pObj)[0];
-  }
 #endif
+  }
 
   T* m_pObj = nullptr;
 };
 
+template <typename T, typename U>
+inline bool operator==(const U* lhs, const CFX_UnownedPtr<T>& rhs) {
+  return rhs == lhs;
+}
+
+template <typename T, typename U>
+inline bool operator!=(const U* lhs, const CFX_UnownedPtr<T>& rhs) {
+  return rhs != lhs;
+}
+
 #endif  // CORE_FXCRT_CFX_UNOWNED_PTR_H_
diff --git a/core/fxcrt/cfx_unowned_ptr_unittest.cpp b/core/fxcrt/cfx_unowned_ptr_unittest.cpp
index 586c4bb..6218679 100644
--- a/core/fxcrt/cfx_unowned_ptr_unittest.cpp
+++ b/core/fxcrt/cfx_unowned_ptr_unittest.cpp
@@ -34,6 +34,15 @@
   delete ptr2;
 }
 
+void ReleaseDangling() {
+  Clink* ptr1 = new Clink();
+  Clink* ptr2 = new Clink();
+  ptr2->next_ = ptr1;
+  delete ptr1;
+  ptr2->next_.Release();
+  delete ptr2;
+}
+
 }  // namespace
 
 TEST(fxcrt, UnownedPtrOk) {
@@ -69,6 +78,23 @@
 #endif
 }
 
+TEST(fxcrt, UnownedReleaseOk) {
+  Clink* ptr1 = new Clink();
+  Clink* ptr2 = new Clink();
+  ptr2->next_ = ptr1;
+  ptr2->next_.Release();
+  delete ptr1;
+  delete ptr2;
+}
+
+TEST(fxcrt, UnownedReleaseNotOk) {
+#if defined(MEMORY_TOOL_REPLACES_ALLOCATOR)
+  EXPECT_DEATH(ReleaseDangling(), "");
+#else
+  ReleaseDangling();
+#endif
+}
+
 TEST(fxcrt, UnownedOperatorEQ) {
   int foo;
   CFX_UnownedPtr<int> ptr1;
@@ -78,6 +104,7 @@
   EXPECT_TRUE(ptr1 == ptr2);
 
   CFX_UnownedPtr<int> ptr3(&foo);
+  EXPECT_TRUE(&foo == ptr3);
   EXPECT_TRUE(ptr3 == &foo);
   EXPECT_FALSE(ptr1 == ptr3);
 
@@ -94,6 +121,7 @@
   EXPECT_FALSE(ptr1 != ptr2);
 
   CFX_UnownedPtr<int> ptr3(&foo);
+  EXPECT_FALSE(&foo != ptr3);
   EXPECT_FALSE(ptr3 != &foo);
   EXPECT_TRUE(ptr1 != ptr3);