Update pdfium::Contains() from Chromium
Now that C++20 is available, sync core/fxcrt/containers/contains.h with
Chromium's base//contains/contains.h at https://crrev.com/1414269, but
with a cleaner set of #includes. Then delete template_util.h, and fix
the build by using the Contains() overload that takes a projection.
Change-Id: I27d7a7a54402e6a6edc3a8d9f7e3fdc5502f731e
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/131252
Commit-Queue: Lei Zhang <thestig@chromium.org>
Reviewed-by: Tom Sepez <tsepez@chromium.org>
diff --git a/core/fxcrt/BUILD.gn b/core/fxcrt/BUILD.gn
index 3a0612f..796a10a 100644
--- a/core/fxcrt/BUILD.gn
+++ b/core/fxcrt/BUILD.gn
@@ -119,7 +119,6 @@
"string_template.cpp",
"string_template.h",
"string_view_template.h",
- "template_util.h",
"tree_node.h",
"unowned_ptr.h",
"utf16.h",
diff --git a/core/fxcrt/containers/contains.h b/core/fxcrt/containers/contains.h
index e25f2f8..3175d49 100644
--- a/core/fxcrt/containers/contains.h
+++ b/core/fxcrt/containers/contains.h
@@ -5,108 +5,57 @@
#ifndef CORE_FXCRT_CONTAINERS_CONTAINS_H_
#define CORE_FXCRT_CONTAINERS_CONTAINS_H_
-#include <algorithm>
-#include <iterator>
-#include <type_traits>
+// 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.
+// - Replaced <type_traits> with <concepts>.
-#include "core/fxcrt/template_util.h"
+// Provides `Contains()`, a general purpose utility to check whether a container
+// contains a value. This will probe whether a `contains` or `find` member
+// function on `container` exists, and fall back to a generic linear search over
+// `container`.
+
+#include <algorithm>
+#include <concepts>
+#include <ranges>
+#include <utility>
namespace pdfium {
-namespace internal {
-
-// Small helper to detect whether a given type has a nested `key_type` typedef.
-// Used below to catch misuses of the API for associative containers.
-template <typename T, typename SFINAE = void>
-struct HasKeyType : std::false_type {};
-
-template <typename T>
-struct HasKeyType<T, std::void_t<typename T::key_type>> : std::true_type {};
-
-// Utility type traits used for specializing pdfium::Contains() below.
-template <typename Container, typename Element, typename = void>
-struct HasFindWithNpos : std::false_type {};
-
-template <typename Container, typename Element>
-struct HasFindWithNpos<
- Container,
- Element,
- std::void_t<decltype(std::declval<const Container&>().find(
- std::declval<const Element&>()) !=
- Container::npos)>> : std::true_type {};
-
-template <typename Container, typename Element, typename = void>
-struct HasFindWithEnd : std::false_type {};
-
-template <typename Container, typename Element>
-struct HasFindWithEnd<
- Container,
- Element,
- std::void_t<decltype(std::declval<const Container&>().find(
- std::declval<const Element&>()) !=
- std::declval<const Container&>().end())>>
- : std::true_type {};
-
-template <typename Container, typename Element, typename = void>
-struct HasContains : std::false_type {};
-
-template <typename Container, typename Element>
-struct HasContains<
- Container,
- Element,
- std::void_t<decltype(std::declval<const Container&>().contains(
- std::declval<const Element&>()))>> : std::true_type {};
-
-} // namespace internal
-
-// General purpose implementation to check if |container| contains |value|.
-template <typename Container,
- typename Value,
- std::enable_if_t<
- !internal::HasFindWithNpos<Container, Value>::value &&
- !internal::HasFindWithEnd<Container, Value>::value &&
- !internal::HasContains<Container, Value>::value>* = nullptr>
-bool Contains(const Container& container, const Value& value) {
- static_assert(
- !internal::HasKeyType<Container>::value,
- "Error: About to perform linear search on an associative container. "
- "Either use a more generic comparator (e.g. std::less<>) or, if a linear "
- "search is desired, provide an explicit projection parameter.");
- using std::begin;
- using std::end;
- return std::find(begin(container), end(container), value) != end(container);
+// A general purpose utility to check whether `container` contains `value`. This
+// will probe whether a `contains` or `find` member function on `container`
+// exists, and fall back to a generic linear search over `container`.
+template <typename Container, typename Value>
+constexpr bool Contains(const Container& container, const Value& value) {
+ if constexpr (requires {
+ { container.contains(value) } -> std::same_as<bool>;
+ }) {
+ return container.contains(value);
+ } else if constexpr (requires { container.find(value) != Container::npos; }) {
+ return container.find(value) != Container::npos;
+ } else if constexpr (requires { container.find(value) != container.end(); }) {
+ return container.find(value) != container.end();
+ } else {
+ static_assert(
+ !requires { typename Container::key_type; },
+ "Error: About to perform linear search on an associative container. "
+ "Either use a more generic comparator (e.g. std::less<>) or, if a "
+ "linear search is desired, provide an explicit projection parameter.");
+ return std::ranges::find(container, value) != std::ranges::end(container);
+ }
}
-// Specialized Contains() implementation for when |container| has a find()
-// member function and a static npos member, but no contains() member function.
-template <typename Container,
- typename Value,
- std::enable_if_t<internal::HasFindWithNpos<Container, Value>::value &&
- !internal::HasContains<Container, Value>::value>* =
- nullptr>
-bool Contains(const Container& container, const Value& value) {
- return container.find(value) != Container::npos;
-}
-
-// Specialized Contains() implementation for when |container| has a find()
-// and end() member function, but no contains() member function.
-template <typename Container,
- typename Value,
- std::enable_if_t<internal::HasFindWithEnd<Container, Value>::value &&
- !internal::HasContains<Container, Value>::value>* =
- nullptr>
-bool Contains(const Container& container, const Value& value) {
- return container.find(value) != container.end();
-}
-
-// Specialized Contains() implementation for when |container| has a contains()
-// member function.
-template <
- typename Container,
- typename Value,
- std::enable_if_t<internal::HasContains<Container, Value>::value>* = nullptr>
-bool Contains(const Container& container, const Value& value) {
- return container.contains(value);
+// Overload that allows callers to provide an additional projection invocable.
+// This projection will be applied to every element in `container` before
+// comparing it with `value`. This will always perform a linear search.
+template <typename Container, typename Value, typename Proj>
+constexpr bool Contains(const Container& container,
+ const Value& value,
+ Proj proj) {
+ return std::ranges::find(container, value, std::move(proj)) !=
+ std::ranges::end(container);
}
} // namespace pdfium
diff --git a/core/fxcrt/template_util.h b/core/fxcrt/template_util.h
deleted file mode 100644
index a6abcb0..0000000
--- a/core/fxcrt/template_util.h
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright 2024 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_TEMPLATE_UTIL_H_
-#define CORE_FXCRT_TEMPLATE_UTIL_H_
-
-#include <stddef.h>
-#include <iosfwd>
-#include <iterator>
-#include <type_traits>
-#include <utility>
-
-#include "build/build_config.h"
-
-namespace pdfium {
-
-template <class T>
-struct is_non_const_reference : std::false_type {};
-template <class T>
-struct is_non_const_reference<T&> : std::true_type {};
-template <class T>
-struct is_non_const_reference<const T&> : std::false_type {};
-
-namespace internal {
-
-// Uses expression SFINAE to detect whether using operator<< would work.
-template <typename T, typename = void>
-struct SupportsOstreamOperator : std::false_type {};
-template <typename T>
-struct SupportsOstreamOperator<T,
- decltype(void(std::declval<std::ostream&>()
- << std::declval<T>()))>
- : std::true_type {};
-
-// Used to detech whether the given type is an iterator. This is normally used
-// with std::enable_if to provide disambiguation for functions that take
-// templatzed iterators as input.
-template <typename T, typename = void>
-struct is_iterator : std::false_type {};
-
-template <typename T>
-struct is_iterator<
- T,
- std::void_t<typename std::iterator_traits<T>::iterator_category>>
- : std::true_type {};
-
-} // namespace internal
-
-} // namespace pdfium
-
-#endif // CORE_FXCRT_TEMPLATE_UTIL_H_
diff --git a/fxjs/xfa/cfxjse_engine.cpp b/fxjs/xfa/cfxjse_engine.cpp
index b1a589f..b1f9aac 100644
--- a/fxjs/xfa/cfxjse_engine.cpp
+++ b/fxjs/xfa/cfxjse_engine.cpp
@@ -941,7 +941,9 @@
}
void CFXJSE_Engine::AddNodesOfRunScript(CXFA_Node* pNode) {
- if (script_node_array_ && !pdfium::Contains(*script_node_array_, pNode)) {
+ if (script_node_array_ &&
+ !pdfium::Contains(*script_node_array_, pNode,
+ &cppgc::Persistent<CXFA_Node>::Get)) {
script_node_array_->emplace_back(pNode);
}
}