From 643b48a3b4362a932c0e41afce62deb55adf825b Mon Sep 17 00:00:00 2001 From: Dennis Kormalev Date: Wed, 7 Feb 2024 08:39:23 -0800 Subject: Add absl_container_hash-based HashEq specialization SwissTable provides support for heterogeneous lookup in associative containers through transparent Hash and Eq types. However, it is not possible for user types to provide additional specializations to allow their types to use this functionality. This CL brings ability for user types to specify their own transparent absl_container_hash and (optionally) absl_container_eq inner types to achieve the same functionality. PiperOrigin-RevId: 604994859 Change-Id: I302486d292c9a18b7d4c77033227008f5539e354 --- absl/container/internal/hash_function_defaults.h | 69 +++++++++++++++++++++++- 1 file changed, 68 insertions(+), 1 deletion(-) (limited to 'absl/container/internal/hash_function_defaults.h') diff --git a/absl/container/internal/hash_function_defaults.h b/absl/container/internal/hash_function_defaults.h index a3613b4b..0f07bcfe 100644 --- a/absl/container/internal/hash_function_defaults.h +++ b/absl/container/internal/hash_function_defaults.h @@ -45,14 +45,16 @@ #ifndef ABSL_CONTAINER_INTERNAL_HASH_FUNCTION_DEFAULTS_H_ #define ABSL_CONTAINER_INTERNAL_HASH_FUNCTION_DEFAULTS_H_ -#include #include +#include #include #include #include #include "absl/base/config.h" +#include "absl/container/internal/common.h" #include "absl/hash/hash.h" +#include "absl/meta/type_traits.h" #include "absl/strings/cord.h" #include "absl/strings/string_view.h" @@ -188,6 +190,71 @@ struct HashEq> : HashEq {}; template struct HashEq> : HashEq {}; +template +struct HasAbslContainerHash : std::false_type {}; + +template +struct HasAbslContainerHash> + : std::true_type {}; + +template +struct HasAbslContainerEq : std::false_type {}; + +template +struct HasAbslContainerEq> + : std::true_type {}; + +template +struct AbslContainerEq { + using type = std::equal_to<>; +}; + +template +struct AbslContainerEq< + T, typename std::enable_if_t::value>> { + using type = typename T::absl_container_eq; +}; + +template +struct AbslContainerHash { + using type = void; +}; + +template +struct AbslContainerHash< + T, typename std::enable_if_t::value>> { + using type = typename T::absl_container_hash; +}; + +// HashEq specialization for user types that provide `absl_container_hash` and +// (optionally) `absl_container_eq`. This specialization allows user types to +// provide heterogeneous lookup without requiring to explicitly specify Hash/Eq +// type arguments in unordered Abseil containers. +// +// Both `absl_container_hash` and `absl_container_eq` should be transparent +// (have inner is_transparent type). While there is no technical reason to +// restrict to transparent-only types, there is also no feasible use case when +// it shouldn't be transparent - it is easier to relax the requirement later if +// such a case arises rather than restricting it. +// +// If type provides only `absl_container_hash` then `eq` part will be +// `std::equal_to`. +// +// User types are not allowed to provide only a `Eq` part as there is no +// feasible use case for this behavior - if Hash should be a default one then Eq +// should be an equivalent to the `std::equal_to`. +template +struct HashEq::value>> { + using Hash = typename AbslContainerHash::type; + using Eq = typename AbslContainerEq::type; + static_assert(IsTransparent::value, + "absl_container_hash must be transparent. To achieve it add a " + "`using is_transparent = void;` clause to this type."); + static_assert(IsTransparent::value, + "absl_container_eq must be transparent. To achieve it add a " + "`using is_transparent = void;` clause to this type."); +}; + // This header's visibility is restricted. If you need to access the default // hasher please use the container's ::hasher alias instead. // -- cgit v1.2.3