diff options
author | Dennis Kormalev <denk@google.com> | 2024-02-07 08:39:23 -0800 |
---|---|---|
committer | Copybara-Service <copybara-worker@google.com> | 2024-02-07 08:40:46 -0800 |
commit | 643b48a3b4362a932c0e41afce62deb55adf825b (patch) | |
tree | 5e5b68000ddde6fe775e2379b18e7dfa0ad98e11 /absl/container/internal/hash_function_defaults.h | |
parent | e22f9c1fdd00f2ad3cfdd1dd7a67145eadc3b21c (diff) |
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
Diffstat (limited to 'absl/container/internal/hash_function_defaults.h')
-rw-r--r-- | absl/container/internal/hash_function_defaults.h | 69 |
1 files changed, 68 insertions, 1 deletions
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 <stdint.h> #include <cstddef> +#include <functional> #include <memory> #include <string> #include <type_traits> #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<std::unique_ptr<T, D>> : HashEq<T*> {}; template <class T> struct HashEq<std::shared_ptr<T>> : HashEq<T*> {}; +template <typename T, typename E = void> +struct HasAbslContainerHash : std::false_type {}; + +template <typename T> +struct HasAbslContainerHash<T, absl::void_t<typename T::absl_container_hash>> + : std::true_type {}; + +template <typename T, typename E = void> +struct HasAbslContainerEq : std::false_type {}; + +template <typename T> +struct HasAbslContainerEq<T, absl::void_t<typename T::absl_container_eq>> + : std::true_type {}; + +template <typename T, typename E = void> +struct AbslContainerEq { + using type = std::equal_to<>; +}; + +template <typename T> +struct AbslContainerEq< + T, typename std::enable_if_t<HasAbslContainerEq<T>::value>> { + using type = typename T::absl_container_eq; +}; + +template <typename T, typename E = void> +struct AbslContainerHash { + using type = void; +}; + +template <typename T> +struct AbslContainerHash< + T, typename std::enable_if_t<HasAbslContainerHash<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<void>`. +// +// 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<T>`. +template <typename T> +struct HashEq<T, typename std::enable_if_t<HasAbslContainerHash<T>::value>> { + using Hash = typename AbslContainerHash<T>::type; + using Eq = typename AbslContainerEq<T>::type; + static_assert(IsTransparent<Hash>::value, + "absl_container_hash must be transparent. To achieve it add a " + "`using is_transparent = void;` clause to this type."); + static_assert(IsTransparent<Eq>::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. // |