summaryrefslogtreecommitdiff
path: root/absl/hash
diff options
context:
space:
mode:
authorGravatar Abseil Team <absl-team@google.com>2022-03-01 13:02:10 -0800
committerGravatar dinord <dino.radakovich@gmail.com>2022-03-02 16:54:53 -0500
commit1dd160f9f091ac30fc83326306b96827ca32c3cd (patch)
treecbfb302a3f5d30d370057f720bb06879593e0f31 /absl/hash
parent5e4ea1ce097f3571e7d87af33b6b30d11b3a211e (diff)
Export of internal Abseil changes
-- f0b7d230a90c82c6fee7adcb46a213d2582b6a7b by Martijn Vels <mvels@google.com>: Optimize substring logic now that CONCAT is removed This CL adds a static Substring() method to CordRepSubstring, and implements substring logic in cord.cc in terms of the new function. This cleans up various helper functions and logic remaining from previous complex CONCAT logic that is no longer needed. PiperOrigin-RevId: 431756805 Change-Id: I39c875b5af119916780e68598c7fc619fb2e8476 -- fa7d1bedf0e1244303844869a332c2a5dbd9ac0f by Derek Mauro <dmauro@google.com>: Allow macro expansion within ABSL_FLAG and ABSL_DECLARE_FLAG args PiperOrigin-RevId: 431721184 Change-Id: I6e19713fb541205d796f940998db5ee25178d55e -- 1b328badd92304ed1c634f23e1c191be57b7bb15 by Laramie Leavitt <lar@google.com>: Add #include for std:: types PiperOrigin-RevId: 431546757 Change-Id: I75efbcd3c77e6f53e4db66494101d30d670d988e -- e25323b299d4d3840218702860f537cdd2a3926f by Thomas Köppe <tkoeppe@google.com>: Add hashing support for pointers to member. Also add tests for function pointers to the existing "pointer" test. PiperOrigin-RevId: 431067588 Change-Id: I3686010635d9fee34c47a418b72402e10737cdbc -- ab27b012a61cf10109fd51932b3b0b05ee78f32f by Laramie Leavitt <lar@google.com>: Avoid use of std::pow in ChiSquare test. PiperOrigin-RevId: 431015830 Change-Id: Idd767ff2f51009ee171de48757207b38330ffea3 -- 28c359135d89061177958580fe4a7493802499cb by Laramie Leavitt <lar@google.com>: Add #include <type_traits> for std::false_type PiperOrigin-RevId: 431005757 Change-Id: I85a6a918778601e19512aaea744424cf39018521 -- a920730f23669479d92e3a696d65d0bc3a5b1de1 by Laramie Leavitt <lar@google.com>: #include <utility> for std::declval PiperOrigin-RevId: 431004934 Change-Id: I295237b2d44e9a15e4083698ea121b68ce0a1bb7 GitOrigin-RevId: f0b7d230a90c82c6fee7adcb46a213d2582b6a7b
Diffstat (limited to 'absl/hash')
-rw-r--r--absl/hash/hash_test.cc81
-rw-r--r--absl/hash/internal/hash.h33
2 files changed, 114 insertions, 0 deletions
diff --git a/absl/hash/hash_test.cc b/absl/hash/hash_test.cc
index 39ff8f52..ffa45e6e 100644
--- a/absl/hash/hash_test.cc
+++ b/absl/hash/hash_test.cc
@@ -185,6 +185,8 @@ TEST(HashValueTest, FloatingPoint) {
TEST(HashValueTest, Pointer) {
EXPECT_TRUE((is_hashable<int*>::value));
+ EXPECT_TRUE((is_hashable<int(*)(char, float)>::value));
+ EXPECT_TRUE((is_hashable<void(*)(int, int, ...)>::value));
int i;
int* ptr = &i;
@@ -224,6 +226,85 @@ TEST(HashValueTest, PointerAlignment) {
}
}
+TEST(HashValueTest, PointerToMember) {
+ struct Bass {
+ void q() {}
+ };
+
+ struct A : Bass {
+ virtual ~A() = default;
+ virtual void vfa() {}
+
+ static auto pq() -> void (A::*)() { return &A::q; }
+ };
+
+ struct B : Bass {
+ virtual ~B() = default;
+ virtual void vfb() {}
+
+ static auto pq() -> void (B::*)() { return &B::q; }
+ };
+
+ struct Foo : A, B {
+ void f1() {}
+ void f2() const {}
+
+ int g1() & { return 0; }
+ int g2() const & { return 0; }
+ int g3() && { return 0; }
+ int g4() const && { return 0; }
+
+ int h1() & { return 0; }
+ int h2() const & { return 0; }
+ int h3() && { return 0; }
+ int h4() const && { return 0; }
+
+ int a;
+ int b;
+
+ const int c = 11;
+ const int d = 22;
+ };
+
+ EXPECT_TRUE((is_hashable<float Foo::*>::value));
+ EXPECT_TRUE((is_hashable<double (Foo::*)(int, int)&&>::value));
+
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
+ std::make_tuple(&Foo::a, &Foo::b, static_cast<int Foo::*>(nullptr))));
+
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
+ std::make_tuple(&Foo::c, &Foo::d, static_cast<const int Foo::*>(nullptr),
+ &Foo::a, &Foo::b)));
+
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
+ &Foo::f1, static_cast<void (Foo::*)()>(nullptr))));
+
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
+ &Foo::f2, static_cast<void (Foo::*)() const>(nullptr))));
+
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
+ &Foo::g1, &Foo::h1, static_cast<int (Foo::*)() &>(nullptr))));
+
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
+ &Foo::g2, &Foo::h2, static_cast<int (Foo::*)() const &>(nullptr))));
+
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
+ &Foo::g3, &Foo::h3, static_cast<int (Foo::*)() &&>(nullptr))));
+
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
+ &Foo::g4, &Foo::h4, static_cast<int (Foo::*)() const &&>(nullptr))));
+
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
+ std::make_tuple(static_cast<void (Foo::*)()>(&Foo::vfa),
+ static_cast<void (Foo::*)()>(&Foo::vfb),
+ static_cast<void (Foo::*)()>(nullptr))));
+
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
+ std::make_tuple(static_cast<void (Foo::*)()>(Foo::A::pq()),
+ static_cast<void (Foo::*)()>(Foo::B::pq()),
+ static_cast<void (Foo::*)()>(nullptr))));
+}
+
TEST(HashValueTest, PairAndTuple) {
EXPECT_TRUE((is_hashable<std::pair<int, int>>::value));
EXPECT_TRUE((is_hashable<std::pair<const int&, const int&>>::value));
diff --git a/absl/hash/internal/hash.h b/absl/hash/internal/hash.h
index a424e014..f8103334 100644
--- a/absl/hash/internal/hash.h
+++ b/absl/hash/internal/hash.h
@@ -421,6 +421,39 @@ H AbslHashValue(H hash_state, std::nullptr_t) {
return H::combine(std::move(hash_state), static_cast<void*>(nullptr));
}
+// AbslHashValue() for hashing pointers-to-member
+template <typename H, typename T, typename C>
+H AbslHashValue(H hash_state, T C::* ptr) {
+ auto salient_ptm_size = [](std::size_t n) -> std::size_t {
+#if defined(_MSC_VER)
+ // Pointers-to-member-function on MSVC consist of one pointer plus 0, 1, 2,
+ // or 3 ints. In 64-bit mode, they are 8-byte aligned and thus can contain
+ // padding (namely when they have 1 or 3 ints). The value below is a lower
+ // bound on the number of salient, non-padding bytes that we use for
+ // hashing.
+ if (alignof(T C::*) == alignof(int)) {
+ // No padding when all subobjects have the same size as the total
+ // alignment. This happens in 32-bit mode.
+ return n;
+ } else {
+ // Padding for 1 int (size 16) or 3 ints (size 24).
+ // With 2 ints, the size is 16 with no padding, which we pessimize.
+ return n == 24 ? 20 : n == 16 ? 12 : n;
+ }
+#else
+ // On other platforms, we assume that pointers-to-members do not have
+ // padding.
+#ifdef __cpp_lib_has_unique_object_representations
+ static_assert(std::has_unique_object_representations_v<T C::*>);
+#endif // __cpp_lib_has_unique_object_representations
+ return n;
+#endif
+ };
+ return H::combine_contiguous(std::move(hash_state),
+ reinterpret_cast<unsigned char*>(&ptr),
+ salient_ptm_size(sizeof ptr));
+}
+
// -----------------------------------------------------------------------------
// AbslHashValue for Composite Types
// -----------------------------------------------------------------------------