[Bf-blender-cvs] [b90fec5d466] master: BLI: simplify supporting heterogeneous lookup for new types

Jacques Lucke noreply at git.blender.org
Thu May 13 14:20:19 CEST 2021


Commit: b90fec5d46624d40f35764de629a0e28e7478101
Author: Jacques Lucke
Date:   Thu May 13 14:14:14 2021 +0200
Branches: master
https://developer.blender.org/rBb90fec5d46624d40f35764de629a0e28e7478101

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.

===================================================================

M	source/blender/blenlib/BLI_hash.hh

===================================================================

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<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);
+  }
 };
 
 /**



More information about the Bf-blender-cvs mailing list