Tip of the Week #152: AbslHashValue and You

Originally posted as TotW #152 on June 21, 2018

By Matt Kulukundis

I love Mozart, but I often make a terrible hash of it.Simon Rattle

The absl::Hash framework is now the default hash implementation for the Swisstable family of hash tables (absl::{flat,node}_hash_{set,map}). All types hashable by this framework will automatically be useable as keys in Swisstables.

How Do I Use It?

Let’s say we have a simple Song struct (let’s agree that a song can be uniquely identified by these fields):

struct Song {
  std::string name;
  std::string artist;
  absl::Duration duration;
};

and we want to be able to store an absl::flat_hash_set<Song> or an absl::flat_hash_map<Song, CopyrightOwner>. All we have to do is add a simple friend function like:

struct Song {
  std::string name;
  std::string artist;
  absl::Duration duration;

  template <typename H>
  friend H AbslHashValue(H h, const Song& s) {
    return H::combine(std::move(h), s.name, s.artist, s.duration);
  }

  // operator == and != omitted for brevity.
};

and everything will work!

How Do I Test It?

We provide absl::VerifyTypeImplementsAbslHashCorrectly to verify that a type implements its overload correctly. This function has a few requirements:

  • The type must implement the == operator correctly.
  • The caller must provide instances of the type that include any interesting representations for their type. (For example, a type with a small size optimization should include equivalent instances that use the small size optimization and that do not.)
TEST(MyType, SupportsAbslHash) {
  EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly({
      MyType(),
      MyType(1, 2),
      MyType(2, 3),
      MyType(0, 0),
  }));
}

absl::VerifyTypeImplementsAbslHashCorrectly also supports testing heterogenous lookup and custom equality operators.

Intrigued and want to know more? Read the absl::Hash docs.


Subscribe to the Abseil Blog