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.
This commit is contained in:
parent
23a788b8bd
commit
b90fec5d46
Notes:
blender-bot
2023-02-14 08:38:14 +01:00
Referenced by issue #88270, GeoNodes: stack overflow crash
|
@ -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<typename T> struct DefaultHash {
|
|||
uint64_t operator()(const T &value) const
|
||||
{
|
||||
if constexpr (std::is_enum_v<T>) {
|
||||
/* 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<typename U> 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);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue