How to Implement Custom Hash Functions in Abseil C++: A Complete Guide
To implement custom hash functions in Abseil, define a templated free function AbslHashValue that combines your type's fields using H::combine() and returns the updated hash state.
The Abseil C++ library provides a high-performance hashing framework centered around absl::Hash and the HashState machinery. To make your custom types compatible with Abseil's hash containers like absl::flat_hash_map, you must implement the AbslHashValue customization point. This approach allows you to integrate user-defined types without modifying the library itself, ensuring optimal performance and compatibility across the Abseil ecosystem.
The AbslHashValue Customization Point
The Abseil hashing framework uses AbslHashValue as its primary extension mechanism. This templated free function allows you to define how your type's fields contribute to the hash computation.
The algorithm follows three conceptual steps:
- Receive a hash state — The framework passes an
Hobject (typicallyabsl::HashState) into your function. - Combine each member — Call
H::combine(std::move(state), member...)for every field you want to include. - Return the updated state — The returned
His then used byabsl::Hashto produce the finalsize_tvalue.
Because AbslHashValue is a template, it works with any hash-state implementation, including internal types like absl::HashStateImpl, ensuring forward compatibility with the library's internal and external hash utilities.
Step-by-Step Implementation
Basic Struct Example
For a simple struct with primitive fields, implement AbslHashValue as a free function in the same namespace as your type:
#include "absl/hash/hash.h"
struct Point {
int x;
int y;
};
template <typename H>
H AbslHashValue(H h, const Point& p) {
return H::combine(std::move(h), p.x, p.y);
}
This enables Point to work immediately with absl::flat_hash_set<Point> and absl::flat_hash_map<Point, T>.
Complex Types with Containers
When hashing classes containing standard library containers, AbslHashValue handles the recursive combination automatically:
#include <string>
#include <vector>
#include "absl/hash/hash.h"
class Person {
public:
std::string name;
std::vector<int> favorite_numbers;
};
template <typename H>
H AbslHashValue(H h, const Person& p) {
h = H::combine(std::move(h), p.name);
for (int n : p.favorite_numbers) {
h = H::combine(std::move(h), n);
}
return h;
}
The H::combine method automatically dispatches to existing hash implementations for std::string and int, handling the variable-length vector iteration manually.
Bridging std::hash and absl::Hash
You can make your type compatible with both the C++ standard library and Abseil by forwarding std::hash to absl::Hash:
namespace std {
template <>
struct hash<Point> {
size_t operator()(const Point& p) const noexcept {
return absl::Hash<Point>{}(p);
}
};
}
This pattern allows seamless use in both std::unordered_map and absl::flat_hash_map.
Internal Mechanics and Source Files
According to the abseil-cpp source code, the hashing infrastructure resides in specific locations:
absl/hash/hash.h: Defines the publicabsl::Hashclass template and declares theAbslHashValuecustomization point.absl/hash/internal/hash.h: Contains the low-levelHashStateandHashStateImplclasses that implement the actual mixing logic.absl/hash/internal/city.h: Houses CityHash-derived mixing primitives used by the default hash state to distribute entropy.
When absl::Hash<T>{}(value) is invoked, the library calls your AbslHashValue implementation, which feeds data into the cryptographic-strength mixing algorithms defined in the internal headers. Your custom function integrates directly with these components without requiring access to private implementation details.
Summary
- Implement custom hash functions in Abseil by defining a templated
AbslHashValuefunction for your type. - Use
H::combine()to fold each field into the hash state, returning the final state object. - Place
AbslHashValuein the same namespace as your type to ensure Argument-Dependent Lookup (ADL) works correctly. - Forward
std::hashspecializations toabsl::Hashfor dual compatibility with standard and Abseil containers. - Reference implementation details in
absl/hash/hash.handabsl/hash/internal/hash.hfor advanced customization.
Frequently Asked Questions
Why should I use AbslHashValue instead of specializing std::hash?
Using AbslHashValue provides better integration with Abseil's entire hashing ecosystem, including absl::flat_hash_map and absl::node_hash_set. It also allows you to maintain a single definition that works for both absl::Hash and std::hash by forwarding the latter to the former, ensuring consistent hashing behavior across all containers while respecting the library's mixing and strength guarantees.
Can I use AbslHashValue with Abseil's flat_hash_map containers?
Yes. Once you define AbslHashValue for your type, it becomes immediately usable as a key in absl::flat_hash_map, absl::flat_hash_set, absl::node_hash_map, and absl::node_hash_set. The containers automatically detect and use your custom hash implementation through the absl::Hash mechanism.
How does H::combine handle different field types?
The H::combine method uses overload resolution to recursively hash each argument. It works with primitive types, standard library containers, and user-defined types that have their own AbslHashValue implementations. The function efficiently mixes entropy from each field into the running hash state using CityHash-derived algorithms implemented in absl/hash/internal/city.h.
Where is the hash state implementation defined in the Abseil source code?
The hash state implementation is primarily defined in absl/hash/internal/hash.h, which contains the HashState and HashStateImpl classes. The public interface in absl/hash/hash.h delegates to these internal implementations, which handle the low-level mixing and entropy distribution using primitives from absl/hash/internal/city.h.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →