From b90fec5d46624d40f35764de629a0e28e7478101 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Thu, 13 May 2021 14:14:14 +0200 Subject: BLI: simplify supporting heterogeneous lookup for new types Heterogeneous lookup is useful when constructing a key in a map/set is relatively expensive (e.g. `std::string`). When doing lookups in the map/set, one usually does not want to construct the type to avoid overhead. Instead, heterogeneous lookup allows for using a different type (such as `StringRef`) as key. This change makes it easier to implement heterogeneous lookup for custom types. Before, one had to specialize `blender::DefaultHash`. Now, one just has to implement a `static uint64_t hash_as(value)` on the type itself. One still has to provide the equality operator in addition to the hash function of course. --- source/blender/blenlib/BLI_hash.hh | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) (limited to 'source') diff --git a/source/blender/blenlib/BLI_hash.hh b/source/blender/blenlib/BLI_hash.hh index 4022c2baa1f..fbed321534c 100644 --- a/source/blender/blenlib/BLI_hash.hh +++ b/source/blender/blenlib/BLI_hash.hh @@ -85,9 +85,12 @@ namespace blender { /** - * If there is no other specialization of #DefaultHash for a given type, try to call `hash()` on - * the value. If there is no such method, this will result in a compiler error. Usually that means - * that you have to implement a hash function using one of three strategies listed above. + * If there is no other specialization of #DefaultHash for a given type, look for a hash function + * on the type itself. Implementing a `hash()` method on a type is often significantly easier than + * specializing #DefaultHash. + * + * To support heterogeneous lookup, a type can also implement a static `hash_as(const OtherType &)` + * function. * * In the case of an enum type, the default hash is just to cast the enum value to an integer. */ @@ -95,12 +98,25 @@ template struct DefaultHash { uint64_t operator()(const T &value) const { if constexpr (std::is_enum_v) { + /* For enums use the value as hash directly. */ return (uint64_t)value; } else { + /* Try to call the `hash()` function on the value. */ + /* If this results in a compiler error, no hash function for the type has been found. */ return value.hash(); } } + + template uint64_t operator()(const U &value) const + { + /* Try calling the static `T::hash_as(value)` function with the given value. The returned hash + * should be "compatible" with `T::hash()`. Usually that means that if `value` is converted to + * `T` its hash does not change. */ + /* If this results in a compiler error, no hash function for the heterogeneous lookup has been + * found. */ + return T::hash_as(value); + } }; /** -- cgit v1.2.3