Replace MakeFakeUniquePtr() with MatchesUniquePtr()

Borrow MatchesUniquePtr() from Chromium, instead of maintaining a
separate class that does something similar.

Change-Id: Ifb107b4e4b10487a78cbd6fa48e0885289cd6ca5
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/131251
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Commit-Queue: Lei Zhang <thestig@chromium.org>
diff --git a/core/fpdfapi/page/cpdf_pageobjectholder.cpp b/core/fpdfapi/page/cpdf_pageobjectholder.cpp
index d1249ce..ed17e5f 100644
--- a/core/fpdfapi/page/cpdf_pageobjectholder.cpp
+++ b/core/fpdfapi/page/cpdf_pageobjectholder.cpp
@@ -17,6 +17,7 @@
 #include "core/fpdfapi/parser/cpdf_document.h"
 #include "core/fxcrt/check.h"
 #include "core/fxcrt/check_op.h"
+#include "core/fxcrt/containers/unique_ptr_adapters.h"
 #include "core/fxcrt/fx_extension.h"
 #include "core/fxcrt/stl_util.h"
 
@@ -190,8 +191,8 @@
 
 std::unique_ptr<CPDF_PageObject> CPDF_PageObjectHolder::RemovePageObject(
     CPDF_PageObject* pPageObj) {
-  auto it =
-      std::ranges::find(page_object_list_, fxcrt::MakeFakeUniquePtr(pPageObj));
+  auto it = std::ranges::find_if(page_object_list_,
+                                 pdfium::MatchesUniquePtr(pPageObj));
   if (it == std::end(page_object_list_)) {
     return nullptr;
   }
diff --git a/core/fpdfdoc/cpdf_annotlist.cpp b/core/fpdfdoc/cpdf_annotlist.cpp
index 846fa97..0936b45 100644
--- a/core/fpdfdoc/cpdf_annotlist.cpp
+++ b/core/fpdfdoc/cpdf_annotlist.cpp
@@ -30,6 +30,7 @@
 #include "core/fpdfdoc/cpdf_generateap.h"
 #include "core/fpdfdoc/cpdf_interactiveform.h"
 #include "core/fxcrt/check.h"
+#include "core/fxcrt/containers/unique_ptr_adapters.h"
 
 namespace {
 
@@ -234,9 +235,7 @@
 
 bool CPDF_AnnotList::Contains(const CPDF_Annot* pAnnot) const {
   auto it = std::ranges::find_if(
-      annot_list_, [pAnnot](const std::unique_ptr<CPDF_Annot>& annot) {
-        return annot.get() == pAnnot;
-      });
+      annot_list_, pdfium::MatchesUniquePtr(const_cast<CPDF_Annot*>(pAnnot)));
   return it != annot_list_.end();
 }
 
diff --git a/core/fxcrt/BUILD.gn b/core/fxcrt/BUILD.gn
index 37ad003..3a0612f 100644
--- a/core/fxcrt/BUILD.gn
+++ b/core/fxcrt/BUILD.gn
@@ -50,6 +50,7 @@
     "component_export.h",
     "containers/adapters.h",
     "containers/contains.h",
+    "containers/unique_ptr_adapters.h",
     "data_vector.h",
     "debug/alias.cc",
     "debug/alias.h",
diff --git a/core/fxcrt/containers/unique_ptr_adapters.h b/core/fxcrt/containers/unique_ptr_adapters.h
new file mode 100644
index 0000000..a63ab35
--- /dev/null
+++ b/core/fxcrt/containers/unique_ptr_adapters.h
@@ -0,0 +1,52 @@
+// Copyright 2025 The PDFium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CORE_FXCRT_CONTAINERS_UNIQUE_PTR_ADAPTERS_H_
+#define CORE_FXCRT_CONTAINERS_UNIQUE_PTR_ADAPTERS_H_
+
+#include <memory>
+
+#include "core/fxcrt/unowned_ptr.h"
+
+// This is Chromium's base/containers/unique_ptr_adapters.h, adapted to work
+// with PDFium's codebase with the following modifications:
+//
+// - Updated include guards.
+// - Replaced namespace base with namespace pdfium.
+// - Deleted MatchesUniquePtr() and UniquePtrComparator.
+// - Switched from raw_ptr to UnownedPtr.
+
+namespace pdfium {
+
+// UniquePtrMatcher is useful for finding an element in a container of
+// unique_ptrs when you have the raw pointer.
+//
+// Example usage:
+//   std::vector<std::unique_ptr<Foo>> vector;
+//   Foo* element = ...
+//   auto iter = std::ranges::find_if(vector, MatchesUniquePtr(element));
+//
+// Example of erasing from container:
+//   EraseIf(v, MatchesUniquePtr(element));
+//
+template <class T, class Deleter = std::default_delete<T>>
+struct UniquePtrMatcher {
+  explicit UniquePtrMatcher(T* t) : t_(t) {}
+
+  bool operator()(const std::unique_ptr<T, Deleter>& o) {
+    return o.get() == t_;
+  }
+
+ private:
+  const UnownedPtr<T> t_;
+};
+
+template <class T, class Deleter = std::default_delete<T>>
+UniquePtrMatcher<T, Deleter> MatchesUniquePtr(T* t) {
+  return UniquePtrMatcher<T, Deleter>(t);
+}
+
+}  // namespace pdfium
+
+#endif  // CORE_FXCRT_CONTAINERS_UNIQUE_PTR_ADAPTERS_H_
diff --git a/core/fxcrt/stl_util.h b/core/fxcrt/stl_util.h
index f0ba040..1d2f9a5 100644
--- a/core/fxcrt/stl_util.h
+++ b/core/fxcrt/stl_util.h
@@ -7,7 +7,6 @@
 
 #include <algorithm>
 #include <iterator>
-#include <memory>
 
 #include "core/fxcrt/check_op.h"
 #include "core/fxcrt/compiler_specific.h"
@@ -15,21 +14,6 @@
 
 namespace fxcrt {
 
-// Means of generating a key for searching STL collections of std::unique_ptr
-// that avoids the side effect of deleting the pointer.
-template <class T>
-class FakeUniquePtr : public std::unique_ptr<T> {
- public:
-  using std::unique_ptr<T>::unique_ptr;
-  ~FakeUniquePtr() { std::unique_ptr<T>::release(); }
-};
-
-// Type-deducing wrapper for FakeUniquePtr<T>.
-template <class T>
-FakeUniquePtr<T> MakeFakeUniquePtr(T* arg) {
-  return FakeUniquePtr<T>(arg);
-}
-
 // Convenience routine for "int-fected" code, so that the stl collection
 // size_t size() method return values will be checked.
 template <typename ResultType, typename Collection>
diff --git a/fpdfsdk/cpdfsdk_pageview.cpp b/fpdfsdk/cpdfsdk_pageview.cpp
index 8ad3862..ed343f1 100644
--- a/fpdfsdk/cpdfsdk_pageview.cpp
+++ b/fpdfsdk/cpdfsdk_pageview.cpp
@@ -17,8 +17,7 @@
 #include "core/fpdfdoc/cpdf_interactiveform.h"
 #include "core/fxcrt/autorestorer.h"
 #include "core/fxcrt/check.h"
-#include "core/fxcrt/containers/contains.h"
-#include "core/fxcrt/stl_util.h"
+#include "core/fxcrt/containers/unique_ptr_adapters.h"
 #include "fpdfsdk/cpdfsdk_annot.h"
 #include "fpdfsdk/cpdfsdk_annotiteration.h"
 #include "fpdfsdk/cpdfsdk_annotiterator.h"
@@ -181,8 +180,8 @@
     form_fill_env_->KillFocusAnnot({});
   }
   if (pAnnot) {
-    auto it = std::ranges::find(sdkannot_array_,
-                                fxcrt::MakeFakeUniquePtr(pAnnot.Get()));
+    auto it = std::ranges::find_if(sdkannot_array_,
+                                   pdfium::MatchesUniquePtr(pAnnot.Get()));
     if (it != sdkannot_array_.end()) {
       sdkannot_array_.erase(it);
     }
@@ -647,7 +646,10 @@
 }
 
 bool CPDFSDK_PageView::IsValidSDKAnnot(const CPDFSDK_Annot* p) const {
-  return p && pdfium::Contains(sdkannot_array_, fxcrt::MakeFakeUniquePtr(p));
+  return p && std::ranges::find_if(
+                  sdkannot_array_,
+                  pdfium::MatchesUniquePtr(const_cast<CPDFSDK_Annot*>(p))) !=
+                  sdkannot_array_.end();
 }
 
 CPDFSDK_Annot* CPDFSDK_PageView::GetFocusAnnot() {
diff --git a/fpdfsdk/fpdf_annot.cpp b/fpdfsdk/fpdf_annot.cpp
index c0d1017..40c74d7 100644
--- a/fpdfsdk/fpdf_annot.cpp
+++ b/fpdfsdk/fpdf_annot.cpp
@@ -33,6 +33,7 @@
 #include "core/fpdfdoc/cpdf_interactiveform.h"
 #include "core/fxcrt/check.h"
 #include "core/fxcrt/containers/contains.h"
+#include "core/fxcrt/containers/unique_ptr_adapters.h"
 #include "core/fxcrt/fx_safe_types.h"
 #include "core/fxcrt/fx_string_wrappers.h"
 #include "core/fxcrt/numerics/safe_conversions.h"
@@ -529,7 +530,8 @@
 
   // Check that the object is already in this annotation's object list.
   CPDF_Form* pForm = pAnnot->GetForm();
-  if (!pdfium::Contains(*pForm, fxcrt::MakeFakeUniquePtr(pObj))) {
+  if (std::ranges::find_if(*pForm, pdfium::MatchesUniquePtr(pObj)) ==
+      pForm->end()) {
     return false;
   }
 
@@ -615,7 +617,8 @@
   // Note that an object that came from a different annotation must not be
   // passed here, since an object cannot belong to more than one annotation.
   CPDF_Form* pForm = pAnnot->GetForm();
-  if (pdfium::Contains(*pForm, fxcrt::MakeFakeUniquePtr(pObj))) {
+  if (std::ranges::find_if(*pForm, pdfium::MatchesUniquePtr(pObj)) !=
+      pForm->end()) {
     return false;
   }
 
diff --git a/fpdfsdk/pwl/cpwl_wnd.cpp b/fpdfsdk/pwl/cpwl_wnd.cpp
index f6d3fc6..67b84d8 100644
--- a/fpdfsdk/pwl/cpwl_wnd.cpp
+++ b/fpdfsdk/pwl/cpwl_wnd.cpp
@@ -14,7 +14,7 @@
 #include "core/fxcrt/check.h"
 #include "core/fxcrt/check_op.h"
 #include "core/fxcrt/containers/contains.h"
-#include "core/fxcrt/stl_util.h"
+#include "core/fxcrt/containers/unique_ptr_adapters.h"
 #include "core/fxge/cfx_renderdevice.h"
 #include "fpdfsdk/pwl/cpwl_scroll_bar.h"
 #include "public/fpdf_fwlevent.h"
@@ -431,7 +431,7 @@
 
 void CPWL_Wnd::RemoveChild(CPWL_Wnd* pWnd) {
   DCHECK_EQ(pWnd->parent_, this);
-  auto it = std::ranges::find(children_, MakeFakeUniquePtr(pWnd));
+  auto it = std::ranges::find_if(children_, pdfium::MatchesUniquePtr(pWnd));
   if (it == children_.end()) {
     return;
   }
diff --git a/fxjs/cjs_app.cpp b/fxjs/cjs_app.cpp
index 538bca4..e38e465 100644
--- a/fxjs/cjs_app.cpp
+++ b/fxjs/cjs_app.cpp
@@ -11,9 +11,9 @@
 #include <algorithm>
 #include <utility>
 
+#include "core/fxcrt/containers/unique_ptr_adapters.h"
 #include "core/fxcrt/fixed_size_data_vector.h"
 #include "core/fxcrt/span.h"
-#include "core/fxcrt/stl_util.h"
 #include "fpdfsdk/cpdfsdk_formfillenvironment.h"
 #include "fpdfsdk/cpdfsdk_interactiveform.h"
 #include "fxjs/cjs_document.h"
@@ -419,7 +419,11 @@
 }
 
 void CJS_App::CancelProc(GlobalTimer* pTimer) {
-  timers_.erase(fxcrt::MakeFakeUniquePtr(pTimer));
+  auto it = std::ranges::find_if(timers_, pdfium::MatchesUniquePtr(pTimer));
+  // Do this as a separate step, instead of using std::erase_if(), to avoid
+  // `pTimer` dangling. It would get deleted before MatchesUniquePtr goes out of
+  // scope.
+  timers_.erase(it);
 }
 
 void CJS_App::RunJsScript(CJS_Runtime* pRuntime, const WideString& wsScript) {
diff --git a/xfa/fwl/cfwl_listbox.cpp b/xfa/fwl/cfwl_listbox.cpp
index 74ae478..eb91d3e 100644
--- a/xfa/fwl/cfwl_listbox.cpp
+++ b/xfa/fwl/cfwl_listbox.cpp
@@ -10,6 +10,7 @@
 #include <memory>
 #include <utility>
 
+#include "core/fxcrt/containers/unique_ptr_adapters.h"
 #include "core/fxcrt/numerics/safe_conversions.h"
 #include "core/fxcrt/stl_util.h"
 #include "v8/include/cppgc/visitor.h"
@@ -893,10 +894,7 @@
 }
 
 int32_t CFWL_ListBox::GetItemIndex(CFWL_Widget* pWidget, Item* pItem) {
-  auto it = std::ranges::find_if(
-      item_array_, [pItem](const std::unique_ptr<Item>& candidate) {
-        return candidate.get() == pItem;
-      });
+  auto it = std::ranges::find_if(item_array_, pdfium::MatchesUniquePtr(pItem));
   return it != item_array_.end()
              ? checked_cast<int32_t>(it - item_array_.begin())
              : -1;