Commit 4c7e7c7d by Abseil Team Committed by Copybara-Service

Type erased hash_slot_fn that depends only on key types (and hash function).

PiperOrigin-RevId: 603148301
Change-Id: Ie2e5702995c9e1ef4d5aaab23bc89a1eb5007a86
parent 780bfc19
...@@ -357,6 +357,7 @@ cc_library( ...@@ -357,6 +357,7 @@ cc_library(
copts = ABSL_DEFAULT_COPTS, copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS, linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [ deps = [
":container_memory",
":hash_function_defaults", ":hash_function_defaults",
":node_slot_policy", ":node_slot_policy",
":raw_hash_set", ":raw_hash_set",
...@@ -504,6 +505,7 @@ cc_test( ...@@ -504,6 +505,7 @@ cc_test(
copts = ABSL_TEST_COPTS, copts = ABSL_TEST_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS, linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [ deps = [
":container_memory",
":hash_policy_traits", ":hash_policy_traits",
"@com_google_googletest//:gtest", "@com_google_googletest//:gtest",
"@com_google_googletest//:gtest_main", "@com_google_googletest//:gtest_main",
...@@ -714,6 +716,7 @@ cc_binary( ...@@ -714,6 +716,7 @@ cc_binary(
tags = ["benchmark"], tags = ["benchmark"],
visibility = ["//visibility:private"], visibility = ["//visibility:private"],
deps = [ deps = [
":container_memory",
":hash_function_defaults", ":hash_function_defaults",
":raw_hash_set", ":raw_hash_set",
"//absl/base:raw_logging_internal", "//absl/base:raw_logging_internal",
...@@ -753,6 +756,7 @@ cc_test( ...@@ -753,6 +756,7 @@ cc_test(
copts = ABSL_TEST_COPTS, copts = ABSL_TEST_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS, linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [ deps = [
":container_memory",
":raw_hash_set", ":raw_hash_set",
":tracked", ":tracked",
"//absl/base:config", "//absl/base:config",
......
...@@ -401,6 +401,7 @@ absl_cc_library( ...@@ -401,6 +401,7 @@ absl_cc_library(
COPTS COPTS
${ABSL_DEFAULT_COPTS} ${ABSL_DEFAULT_COPTS}
DEPS DEPS
absl::container_memory
absl::core_headers absl::core_headers
absl::hash_function_defaults absl::hash_function_defaults
absl::node_slot_policy absl::node_slot_policy
...@@ -560,6 +561,7 @@ absl_cc_test( ...@@ -560,6 +561,7 @@ absl_cc_test(
COPTS COPTS
${ABSL_TEST_COPTS} ${ABSL_TEST_COPTS}
DEPS DEPS
absl::container_memory
absl::hash_policy_traits absl::hash_policy_traits
GTest::gmock_main GTest::gmock_main
) )
...@@ -776,6 +778,7 @@ absl_cc_test( ...@@ -776,6 +778,7 @@ absl_cc_test(
${ABSL_TEST_COPTS} ${ABSL_TEST_COPTS}
DEPS DEPS
absl::config absl::config
absl::container_memory
absl::raw_hash_set absl::raw_hash_set
absl::tracked absl::tracked
GTest::gmock_main GTest::gmock_main
......
...@@ -593,6 +593,13 @@ struct FlatHashMapPolicy { ...@@ -593,6 +593,13 @@ struct FlatHashMapPolicy {
std::forward<Args>(args)...); std::forward<Args>(args)...);
} }
template <class Hash>
static constexpr HashSlotFn get_hash_slot_fn() {
return memory_internal::IsLayoutCompatible<K, V>::value
? &TypeErasedApplyToSlotFn<Hash, K>
: nullptr;
}
static size_t space_used(const slot_type*) { return 0; } static size_t space_used(const slot_type*) { return 0; }
static std::pair<const K, V>& element(slot_type* slot) { return slot->value; } static std::pair<const K, V>& element(slot_type* slot) { return slot->value; }
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#ifndef ABSL_CONTAINER_FLAT_HASH_SET_H_ #ifndef ABSL_CONTAINER_FLAT_HASH_SET_H_
#define ABSL_CONTAINER_FLAT_HASH_SET_H_ #define ABSL_CONTAINER_FLAT_HASH_SET_H_
#include <cstddef>
#include <memory> #include <memory>
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
...@@ -492,6 +493,11 @@ struct FlatHashSetPolicy { ...@@ -492,6 +493,11 @@ struct FlatHashSetPolicy {
} }
static size_t space_used(const T*) { return 0; } static size_t space_used(const T*) { return 0; }
template <class Hash>
static constexpr HashSlotFn get_hash_slot_fn() {
return &TypeErasedApplyToSlotFn<Hash, T>;
}
}; };
} // namespace container_internal } // namespace container_internal
......
...@@ -464,6 +464,26 @@ struct map_slot_policy { ...@@ -464,6 +464,26 @@ struct map_slot_policy {
} }
}; };
// Type erased function for computing hash of the slot.
using HashSlotFn = size_t (*)(const void* hash_fn, void* slot);
// Type erased function to apply `Fn` to data inside of the `slot`.
// The data is expected to have type `T`.
template <class Fn, class T>
size_t TypeErasedApplyToSlotFn(const void* fn, void* slot) {
const auto* f = static_cast<const Fn*>(fn);
return (*f)(*static_cast<const T*>(slot));
}
// Type erased function to apply `Fn` to data inside of the `*slot_ptr`.
// The data is expected to have type `T`.
template <class Fn, class T>
size_t TypeErasedDerefAndApplyToSlotFn(const void* fn, void* slot_ptr) {
const auto* f = static_cast<const Fn*>(fn);
const T* slot = *static_cast<const T**>(slot_ptr);
return (*f)(*slot);
}
} // namespace container_internal } // namespace container_internal
ABSL_NAMESPACE_END ABSL_NAMESPACE_END
} // namespace absl } // namespace absl
......
...@@ -298,6 +298,20 @@ TEST(MapSlotPolicy, DestroyReturnsTrue) { ...@@ -298,6 +298,20 @@ TEST(MapSlotPolicy, DestroyReturnsTrue) {
} }
} }
TEST(ApplyTest, TypeErasedApplyToSlotFn) {
size_t x = 7;
auto fn = [](size_t v) { return v * 2; };
EXPECT_EQ((TypeErasedApplyToSlotFn<decltype(fn), size_t>(&fn, &x)), 14);
}
TEST(ApplyTest, TypeErasedDerefAndApplyToSlotFn) {
size_t x = 7;
auto fn = [](size_t v) { return v * 2; };
size_t* x_ptr = &x;
EXPECT_EQ(
(TypeErasedDerefAndApplyToSlotFn<decltype(fn), size_t>(&fn, &x_ptr)), 14);
}
} // namespace } // namespace
} // namespace container_internal } // namespace container_internal
ABSL_NAMESPACE_END ABSL_NAMESPACE_END
......
...@@ -148,6 +148,41 @@ struct hash_policy_traits : common_policy_traits<Policy> { ...@@ -148,6 +148,41 @@ struct hash_policy_traits : common_policy_traits<Policy> {
static auto value(T* elem) -> decltype(P::value(elem)) { static auto value(T* elem) -> decltype(P::value(elem)) {
return P::value(elem); return P::value(elem);
} }
using HashSlotFn = size_t (*)(const void* hash_fn, void* slot);
template <class Hash>
static constexpr HashSlotFn get_hash_slot_fn() {
// get_hash_slot_fn may return nullptr to signal that non type erased function
// should be used. GCC warns against comparing function address with nullptr.
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic push
// silent error: the address of * will never be NULL [-Werror=address]
#pragma GCC diagnostic ignored "-Waddress"
#endif
return Policy::template get_hash_slot_fn<Hash>() == nullptr
? &hash_slot_fn_non_type_erased<Hash>
: Policy::template get_hash_slot_fn<Hash>();
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic pop
#endif
}
private:
template <class Hash>
struct HashElement {
template <class K, class... Args>
size_t operator()(const K& key, Args&&...) const {
return h(key);
}
const Hash& h;
};
template <class Hash>
static size_t hash_slot_fn_non_type_erased(const void* hash_fn, void* slot) {
return Policy::apply(HashElement<Hash>{*static_cast<const Hash*>(hash_fn)},
Policy::element(static_cast<slot_type*>(slot)));
}
}; };
} // namespace container_internal } // namespace container_internal
......
...@@ -14,12 +14,14 @@ ...@@ -14,12 +14,14 @@
#include "absl/container/internal/hash_policy_traits.h" #include "absl/container/internal/hash_policy_traits.h"
#include <cstddef>
#include <functional> #include <functional>
#include <memory> #include <memory>
#include <new> #include <new>
#include "gmock/gmock.h" #include "gmock/gmock.h"
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "absl/container/internal/container_memory.h"
namespace absl { namespace absl {
ABSL_NAMESPACE_BEGIN ABSL_NAMESPACE_BEGIN
...@@ -42,6 +44,11 @@ struct PolicyWithoutOptionalOps { ...@@ -42,6 +44,11 @@ struct PolicyWithoutOptionalOps {
static int apply(int v) { return apply_impl(v); } static int apply(int v) { return apply_impl(v); }
static std::function<int(int)> apply_impl; static std::function<int(int)> apply_impl;
static std::function<Slot&(Slot*)> value; static std::function<Slot&(Slot*)> value;
template <class Hash>
static constexpr HashSlotFn get_hash_slot_fn() {
return nullptr;
}
}; };
std::function<int(int)> PolicyWithoutOptionalOps::apply_impl; std::function<int(int)> PolicyWithoutOptionalOps::apply_impl;
...@@ -74,6 +81,63 @@ TEST_F(Test, value) { ...@@ -74,6 +81,63 @@ TEST_F(Test, value) {
EXPECT_EQ(&b, &hash_policy_traits<PolicyWithoutOptionalOps>::value(&a)); EXPECT_EQ(&b, &hash_policy_traits<PolicyWithoutOptionalOps>::value(&a));
} }
struct Hash {
size_t operator()(Slot a) const { return static_cast<size_t>(a) * 5; }
};
struct PolicyNoHashFn {
using slot_type = Slot;
using key_type = Slot;
using init_type = Slot;
static size_t* apply_called_count;
static Slot& element(Slot* slot) { return *slot; }
template <typename Fn>
static size_t apply(const Fn& fn, int v) {
++(*apply_called_count);
return fn(v);
}
template <class Hash>
static constexpr HashSlotFn get_hash_slot_fn() {
return nullptr;
}
};
size_t* PolicyNoHashFn::apply_called_count;
struct PolicyCustomHashFn : PolicyNoHashFn {
template <class Hash>
static constexpr HashSlotFn get_hash_slot_fn() {
return &TypeErasedApplyToSlotFn<Hash, int>;
}
};
TEST(HashTest, PolicyNoHashFn_get_hash_slot_fn) {
size_t apply_called_count = 0;
PolicyNoHashFn::apply_called_count = &apply_called_count;
Hash hasher;
Slot value = 7;
auto* fn = hash_policy_traits<PolicyNoHashFn>::get_hash_slot_fn<Hash>();
EXPECT_NE(fn, nullptr);
EXPECT_EQ(fn(&hasher, &value), hasher(value));
EXPECT_EQ(apply_called_count, 1);
}
TEST(HashTest, PolicyCustomHashFn_get_hash_slot_fn) {
size_t apply_called_count = 0;
PolicyNoHashFn::apply_called_count = &apply_called_count;
Hash hasher;
Slot value = 7;
auto* fn = hash_policy_traits<PolicyCustomHashFn>::get_hash_slot_fn<Hash>();
EXPECT_EQ(fn, PolicyCustomHashFn::get_hash_slot_fn<Hash>());
EXPECT_EQ(fn(&hasher, &value), hasher(value));
EXPECT_EQ(apply_called_count, 0);
}
} // namespace } // namespace
} // namespace container_internal } // namespace container_internal
ABSL_NAMESPACE_END ABSL_NAMESPACE_END
......
...@@ -140,7 +140,7 @@ static inline void* PrevSlot(void* slot, size_t slot_size) { ...@@ -140,7 +140,7 @@ static inline void* PrevSlot(void* slot, size_t slot_size) {
return reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(slot) - slot_size); return reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(slot) - slot_size);
} }
void DropDeletesWithoutResize(CommonFields& common, void DropDeletesWithoutResize(CommonFields& common, const void* hash_fn,
const PolicyFunctions& policy, void* tmp_space) { const PolicyFunctions& policy, void* tmp_space) {
void* set = &common; void* set = &common;
void* slot_array = common.slot_array(); void* slot_array = common.slot_array();
...@@ -175,7 +175,7 @@ void DropDeletesWithoutResize(CommonFields& common, ...@@ -175,7 +175,7 @@ void DropDeletesWithoutResize(CommonFields& common,
++i, slot_ptr = NextSlot(slot_ptr, slot_size)) { ++i, slot_ptr = NextSlot(slot_ptr, slot_size)) {
assert(slot_ptr == SlotAddress(slot_array, i, slot_size)); assert(slot_ptr == SlotAddress(slot_array, i, slot_size));
if (!IsDeleted(ctrl[i])) continue; if (!IsDeleted(ctrl[i])) continue;
const size_t hash = (*hasher)(set, slot_ptr); const size_t hash = (*hasher)(hash_fn, slot_ptr);
const FindInfo target = find_first_non_full(common, hash); const FindInfo target = find_first_non_full(common, hash);
const size_t new_i = target.offset; const size_t new_i = target.offset;
total_probe_length += target.probe_length; total_probe_length += target.probe_length;
......
...@@ -1802,7 +1802,7 @@ struct PolicyFunctions { ...@@ -1802,7 +1802,7 @@ struct PolicyFunctions {
size_t slot_size; size_t slot_size;
// Returns the hash of the pointed-to slot. // Returns the hash of the pointed-to slot.
size_t (*hash_slot)(void* set, void* slot); size_t (*hash_slot)(const void* hash_fn, void* slot);
// Transfer the contents of src_slot to dst_slot. // Transfer the contents of src_slot to dst_slot.
void (*transfer)(void* set, void* dst_slot, void* src_slot); void (*transfer)(void* set, void* dst_slot, void* src_slot);
...@@ -1847,7 +1847,7 @@ ABSL_ATTRIBUTE_NOINLINE void TransferRelocatable(void*, void* dst, void* src) { ...@@ -1847,7 +1847,7 @@ ABSL_ATTRIBUTE_NOINLINE void TransferRelocatable(void*, void* dst, void* src) {
} }
// Type-erased version of raw_hash_set::drop_deletes_without_resize. // Type-erased version of raw_hash_set::drop_deletes_without_resize.
void DropDeletesWithoutResize(CommonFields& common, void DropDeletesWithoutResize(CommonFields& common, const void* hash_fn,
const PolicyFunctions& policy, void* tmp_space); const PolicyFunctions& policy, void* tmp_space);
// A SwissTable. // A SwissTable.
...@@ -2989,7 +2989,7 @@ class raw_hash_set { ...@@ -2989,7 +2989,7 @@ class raw_hash_set {
inline void drop_deletes_without_resize() { inline void drop_deletes_without_resize() {
// Stack-allocate space for swapping elements. // Stack-allocate space for swapping elements.
alignas(slot_type) unsigned char tmp[sizeof(slot_type)]; alignas(slot_type) unsigned char tmp[sizeof(slot_type)];
DropDeletesWithoutResize(common(), GetPolicyFunctions(), tmp); DropDeletesWithoutResize(common(), &hash_ref(), GetPolicyFunctions(), tmp);
} }
// Called whenever the table *might* need to conditionally grow. // Called whenever the table *might* need to conditionally grow.
...@@ -3238,13 +3238,6 @@ class raw_hash_set { ...@@ -3238,13 +3238,6 @@ class raw_hash_set {
return settings_.template get<3>(); return settings_.template get<3>();
} }
// Make type-specific functions for this type's PolicyFunctions struct.
static size_t hash_slot_fn(void* set, void* slot) {
auto* h = static_cast<raw_hash_set*>(set);
return PolicyTraits::apply(
HashElement{h->hash_ref()},
PolicyTraits::element(static_cast<slot_type*>(slot)));
}
static void transfer_slot_fn(void* set, void* dst, void* src) { static void transfer_slot_fn(void* set, void* dst, void* src) {
auto* h = static_cast<raw_hash_set*>(set); auto* h = static_cast<raw_hash_set*>(set);
h->transfer(static_cast<slot_type*>(dst), static_cast<slot_type*>(src)); h->transfer(static_cast<slot_type*>(dst), static_cast<slot_type*>(src));
...@@ -3266,7 +3259,7 @@ class raw_hash_set { ...@@ -3266,7 +3259,7 @@ class raw_hash_set {
static const PolicyFunctions& GetPolicyFunctions() { static const PolicyFunctions& GetPolicyFunctions() {
static constexpr PolicyFunctions value = { static constexpr PolicyFunctions value = {
sizeof(slot_type), sizeof(slot_type),
&raw_hash_set::hash_slot_fn, PolicyTraits::template get_hash_slot_fn<hasher>(),
PolicyTraits::transfer_uses_memcpy() PolicyTraits::transfer_uses_memcpy()
? TransferRelocatable<sizeof(slot_type)> ? TransferRelocatable<sizeof(slot_type)>
: &raw_hash_set::transfer_slot_fn, : &raw_hash_set::transfer_slot_fn,
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include "gmock/gmock.h" #include "gmock/gmock.h"
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "absl/base/config.h" #include "absl/base/config.h"
#include "absl/container/internal/container_memory.h"
#include "absl/container/internal/raw_hash_set.h" #include "absl/container/internal/raw_hash_set.h"
#include "absl/container/internal/tracked.h" #include "absl/container/internal/tracked.h"
...@@ -133,7 +134,7 @@ class CheckedAlloc { ...@@ -133,7 +134,7 @@ class CheckedAlloc {
}; };
struct Identity { struct Identity {
int32_t operator()(int32_t v) const { return v; } size_t operator()(int32_t v) const { return static_cast<size_t>(v); }
}; };
struct Policy { struct Policy {
...@@ -178,6 +179,11 @@ struct Policy { ...@@ -178,6 +179,11 @@ struct Policy {
} }
static slot_type& element(slot_type* slot) { return *slot; } static slot_type& element(slot_type* slot) { return *slot; }
template <class Hash>
static constexpr HashSlotFn get_hash_slot_fn() {
return nullptr;
}
}; };
template <int Spec> template <int Spec>
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <vector> #include <vector>
#include "absl/base/internal/raw_logging.h" #include "absl/base/internal/raw_logging.h"
#include "absl/container/internal/container_memory.h"
#include "absl/container/internal/hash_function_defaults.h" #include "absl/container/internal/hash_function_defaults.h"
#include "absl/container/internal/raw_hash_set.h" #include "absl/container/internal/raw_hash_set.h"
#include "absl/strings/str_format.h" #include "absl/strings/str_format.h"
...@@ -59,6 +60,11 @@ struct IntPolicy { ...@@ -59,6 +60,11 @@ struct IntPolicy {
static auto apply(F&& f, int64_t x) -> decltype(std::forward<F>(f)(x, x)) { static auto apply(F&& f, int64_t x) -> decltype(std::forward<F>(f)(x, x)) {
return std::forward<F>(f)(x, x); return std::forward<F>(f)(x, x);
} }
template <class Hash>
static constexpr HashSlotFn get_hash_slot_fn() {
return nullptr;
}
}; };
class StringPolicy { class StringPolicy {
...@@ -117,6 +123,11 @@ class StringPolicy { ...@@ -117,6 +123,11 @@ class StringPolicy {
return apply_impl(std::forward<F>(f), return apply_impl(std::forward<F>(f),
PairArgs(std::forward<Args>(args)...)); PairArgs(std::forward<Args>(args)...));
} }
template <class Hash>
static constexpr HashSlotFn get_hash_slot_fn() {
return nullptr;
}
}; };
struct StringHash : container_internal::hash_default_hash<absl::string_view> { struct StringHash : container_internal::hash_default_hash<absl::string_view> {
......
...@@ -70,6 +70,11 @@ struct Policy { ...@@ -70,6 +70,11 @@ struct Policy {
-> decltype(std::forward<F>(f)(arg, arg)) { -> decltype(std::forward<F>(f)(arg, arg)) {
return std::forward<F>(f)(arg, arg); return std::forward<F>(f)(arg, arg);
} }
template <class Hash>
static constexpr auto get_hash_slot_fn() {
return nullptr;
}
}; };
absl::BitGen& GlobalBitGen() { absl::BitGen& GlobalBitGen() {
......
...@@ -405,6 +405,11 @@ struct ValuePolicy { ...@@ -405,6 +405,11 @@ struct ValuePolicy {
return absl::container_internal::DecomposeValue( return absl::container_internal::DecomposeValue(
std::forward<F>(f), std::forward<Args>(args)...); std::forward<F>(f), std::forward<Args>(args)...);
} }
template <class Hash>
static constexpr HashSlotFn get_hash_slot_fn() {
return nullptr;
}
}; };
using IntPolicy = ValuePolicy<int64_t>; using IntPolicy = ValuePolicy<int64_t>;
...@@ -468,6 +473,11 @@ class StringPolicy { ...@@ -468,6 +473,11 @@ class StringPolicy {
return apply_impl(std::forward<F>(f), return apply_impl(std::forward<F>(f),
PairArgs(std::forward<Args>(args)...)); PairArgs(std::forward<Args>(args)...));
} }
template <class Hash>
static constexpr HashSlotFn get_hash_slot_fn() {
return nullptr;
}
}; };
struct StringHash : absl::Hash<absl::string_view> { struct StringHash : absl::Hash<absl::string_view> {
...@@ -923,6 +933,11 @@ struct DecomposePolicy { ...@@ -923,6 +933,11 @@ struct DecomposePolicy {
static auto apply(F&& f, const T& x) -> decltype(std::forward<F>(f)(x, x)) { static auto apply(F&& f, const T& x) -> decltype(std::forward<F>(f)(x, x)) {
return std::forward<F>(f)(x, x); return std::forward<F>(f)(x, x);
} }
template <class Hash>
static constexpr HashSlotFn get_hash_slot_fn() {
return nullptr;
}
}; };
template <typename Hash, typename Eq> template <typename Hash, typename Eq>
...@@ -1083,7 +1098,7 @@ size_t MaxDensitySize(size_t n) { ...@@ -1083,7 +1098,7 @@ size_t MaxDensitySize(size_t n) {
} }
struct Modulo1000Hash { struct Modulo1000Hash {
size_t operator()(int x) const { return x % 1000; } size_t operator()(int64_t x) const { return static_cast<size_t>(x) % 1000; }
}; };
struct Modulo1000HashTable struct Modulo1000HashTable
...@@ -2664,7 +2679,7 @@ using RawHashSetAlloc = raw_hash_set<IntPolicy, hash_default_hash<int64_t>, ...@@ -2664,7 +2679,7 @@ using RawHashSetAlloc = raw_hash_set<IntPolicy, hash_default_hash<int64_t>,
TEST(Table, AllocatorPropagation) { TestAllocPropagation<RawHashSetAlloc>(); } TEST(Table, AllocatorPropagation) { TestAllocPropagation<RawHashSetAlloc>(); }
struct CountedHash { struct CountedHash {
size_t operator()(int value) const { size_t operator()(int64_t value) const {
++count; ++count;
return static_cast<size_t>(value); return static_cast<size_t>(value);
} }
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#ifndef ABSL_CONTAINER_NODE_HASH_MAP_H_ #ifndef ABSL_CONTAINER_NODE_HASH_MAP_H_
#define ABSL_CONTAINER_NODE_HASH_MAP_H_ #define ABSL_CONTAINER_NODE_HASH_MAP_H_
#include <cstddef>
#include <tuple> #include <tuple>
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
...@@ -590,6 +591,13 @@ class NodeHashMapPolicy ...@@ -590,6 +591,13 @@ class NodeHashMapPolicy
static Value& value(value_type* elem) { return elem->second; } static Value& value(value_type* elem) { return elem->second; }
static const Value& value(const value_type* elem) { return elem->second; } static const Value& value(const value_type* elem) { return elem->second; }
template <class Hash>
static constexpr HashSlotFn get_hash_slot_fn() {
return memory_internal::IsLayoutCompatible<Key, Value>::value
? &TypeErasedDerefAndApplyToSlotFn<Hash, Key>
: nullptr;
}
}; };
} // namespace container_internal } // namespace container_internal
......
...@@ -35,10 +35,12 @@ ...@@ -35,10 +35,12 @@
#ifndef ABSL_CONTAINER_NODE_HASH_SET_H_ #ifndef ABSL_CONTAINER_NODE_HASH_SET_H_
#define ABSL_CONTAINER_NODE_HASH_SET_H_ #define ABSL_CONTAINER_NODE_HASH_SET_H_
#include <cstddef>
#include <type_traits> #include <type_traits>
#include "absl/algorithm/container.h" #include "absl/algorithm/container.h"
#include "absl/base/macros.h" #include "absl/base/macros.h"
#include "absl/container/internal/container_memory.h"
#include "absl/container/internal/hash_function_defaults.h" // IWYU pragma: export #include "absl/container/internal/hash_function_defaults.h" // IWYU pragma: export
#include "absl/container/internal/node_slot_policy.h" #include "absl/container/internal/node_slot_policy.h"
#include "absl/container/internal/raw_hash_set.h" // IWYU pragma: export #include "absl/container/internal/raw_hash_set.h" // IWYU pragma: export
...@@ -487,6 +489,11 @@ struct NodeHashSetPolicy ...@@ -487,6 +489,11 @@ struct NodeHashSetPolicy
} }
static size_t element_space_used(const T*) { return sizeof(T); } static size_t element_space_used(const T*) { return sizeof(T); }
template <class Hash>
static constexpr HashSlotFn get_hash_slot_fn() {
return &TypeErasedDerefAndApplyToSlotFn<Hash, T>;
}
}; };
} // namespace container_internal } // namespace container_internal
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment