Canonicalize pointer keys in SwissTable FindLargeKey.

For pointer-keyed SwissTable containers using the default `HashEq<T*>::Hash` and `HashEq<T*>::Eq`, convert lookup keys implicitly convertible to `const T*` to `const T*` in `FindLargeKey<K>`. This shares `find_large` and `find_or_prepare_insert_large` instantiations across `T*`, `const T*`, `void*`, and derived-pointer lookups on the same container.

PiperOrigin-RevId: 1005017417
diff --git a/absl/container/internal/raw_hash_set.h b/absl/container/internal/raw_hash_set.h
index b7fb4d1..5d1115a 100644
--- a/absl/container/internal/raw_hash_set.h
+++ b/absl/container/internal/raw_hash_set.h
@@ -4018,14 +4018,26 @@
  private:
   friend struct RawHashSetTestOnlyAccess;
 
+  template <class K, class KeyType = key_type>
+  struct IsConvertibleToKeyPtr : std::false_type {};
+
+  template <class K, class T>
+  struct IsConvertibleToKeyPtr<K, T*>
+      : std::bool_constant<
+            std::is_same_v<hasher, typename HashEq<T*>::Hash> &&
+            std::is_same_v<key_equal, typename HashEq<T*>::Eq> &&
+            std::is_convertible_v<const absl::remove_cvref_t<K>&, const T*>> {};
+
   // For string-like keys, we convert to string_view when calling find*_large()
   // operations to (a) avoid repeatedly (i) branching on SSO or (ii) calling
-  // strlen(), (b) share code between the string-like types. Note that we don't
-  // pass FindLargeKey to find*_small() to avoid unnecessarily constructing
-  // string_view for small empty tables. Note: we use type_identity_t and
-  // static_asserts to ensure that the key type in find*_large is FindLargeKey.
-  // (type_identity_t ensures that the template argument is not deduced and must
-  // be specified explicitly.)
+  // strlen(), (b) share code between the string-like types. For pointer keys,
+  // we similarly convert to `const T*` to share code between `T*`, `const T*`,
+  // and derived-pointer lookups. Note that we don't pass FindLargeKey to
+  // find*_small() to avoid unnecessarily constructing string_view for small
+  // empty tables. Note: we use type_identity_t and static_asserts to ensure
+  // that the key type in find*_large is FindLargeKey. (type_identity_t ensures
+  // that the template argument is not deduced and must be specified
+  // explicitly.)
   template <class K>
   using FindLargeKey =
       type_traits_internal::AddConstRefIfExpensiveToCopy<std::conditional_t<
@@ -4033,7 +4045,10 @@
               std::is_same_v<key_equal, absl::container_internal::StringEq> &&
               std::is_convertible_v<const absl::remove_cvref_t<K>&,
                                     absl::string_view>,
-          absl::string_view, absl::remove_cvref_t<K>>>;
+          absl::string_view,
+          std::conditional_t<IsConvertibleToKeyPtr<K>::value,
+                             const std::remove_pointer_t<key_type>*,
+                             absl::remove_cvref_t<K>>>>;
 
   // Prefetch the heap-allocated memory region to resolve potential TLB and
   // cache misses. This is intended to overlap with execution of calculating the
diff --git a/absl/container/internal/raw_hash_set_test.cc b/absl/container/internal/raw_hash_set_test.cc
index 60fb142..a51ab9b 100644
--- a/absl/container/internal/raw_hash_set_test.cc
+++ b/absl/container/internal/raw_hash_set_test.cc
@@ -91,6 +91,8 @@
   static size_t CountTombstones(const C& c) {
     return c.common().TombstonesCount();
   }
+  template <typename C, typename K>
+  using FindLargeKey = typename C::template FindLargeKey<K>;
 };
 
 namespace {
@@ -5485,6 +5487,31 @@
   EXPECT_EQ(t.capacity(), kTargetCapacity);
 }
 
+TEST(Table, FindLargeKeyPointerCanonicalization) {
+  struct Base {};
+  struct Derived : Base {};
+
+  using Set = absl::flat_hash_set<int*>;
+  static_assert(
+      std::is_same_v<RawHashSetTestOnlyAccess::FindLargeKey<Set, int*>,
+                     const int*>);
+  static_assert(
+      std::is_same_v<
+          RawHashSetTestOnlyAccess::FindLargeKey<Set, std::unique_ptr<int>>,
+          const std::unique_ptr<int>&>);
+
+  using BaseSet = absl::flat_hash_set<const Base*>;
+  static_assert(
+      std::is_same_v<RawHashSetTestOnlyAccess::FindLargeKey<BaseSet, Derived*>,
+                     const Base*>);
+
+  using CustomSet =
+      absl::flat_hash_set<int*, absl::Hash<int*>, std::equal_to<int*>>;
+  static_assert(
+      std::is_same_v<RawHashSetTestOnlyAccess::FindLargeKey<CustomSet, int*>,
+                     int*>);
+}
+
 }  // namespace
 }  // namespace container_internal
 ABSL_NAMESPACE_END