tint/utils: Add Hashmap equality and hashing

Allows Hashmaps to be used as keys to other hashmaps.

Change-Id: I557d99515451c55e599dda847e15ce8e2b4500c5
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/112282
Kokoro: Ben Clayton <bclayton@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
This commit is contained in:
Ben Clayton 2022-11-29 20:54:06 +00:00 committed by Dawn LUCI CQ
parent 2d108ae5ed
commit c158e845e6
2 changed files with 97 additions and 0 deletions

View File

@ -206,6 +206,31 @@ class Hashmap : public HashmapBase<KEY, VALUE, N, HASH, EQUAL> {
return out;
}
/// Equality operator
/// @param other the other Hashmap to compare this Hashmap to
/// @returns true if this Hashmap has the same key and value pairs as @p other
template <typename K, typename V, size_t N2>
bool operator==(const Hashmap<K, V, N2>& other) const {
if (this->Count() != other.Count()) {
return false;
}
for (auto it : *this) {
auto other_val = other.Find(it.key);
if (!other_val || it.value != *other_val) {
return false;
}
}
return true;
}
/// Inequality operator
/// @param other the other Hashmap to compare this Hashmap to
/// @returns false if this Hashmap has the same key and value pairs as @p other
template <typename K, typename V, size_t N2>
bool operator!=(const Hashmap<K, V, N2>& other) const {
return !(*this == other);
}
private:
Value* Lookup(const Key& key) {
if (auto [found, index] = this->IndexOf(key); found) {
@ -222,6 +247,22 @@ class Hashmap : public HashmapBase<KEY, VALUE, N, HASH, EQUAL> {
}
};
/// Hasher specialization for Hashmap
template <typename K, typename V, size_t N, typename HASH, typename EQUAL>
struct Hasher<Hashmap<K, V, N, HASH, EQUAL>> {
/// @param map the Hashmap to hash
/// @returns a hash of the map
size_t operator()(const Hashmap<K, V, N, HASH, EQUAL>& map) const {
auto hash = Hash(map.Count());
for (auto it : map) {
// Use an XOR to ensure that the non-deterministic ordering of the map still produces
// the same hash value for the same entries.
hash ^= Hash(it.key) * 31 + Hash(it.value);
}
return hash;
}
};
} // namespace tint::utils
#endif // SRC_TINT_UTILS_HASHMAP_H_

View File

@ -355,5 +355,61 @@ TEST(Hashmap, Soak) {
}
}
TEST(Hashmap, EqualitySameSize) {
Hashmap<int, std::string, 8> a;
Hashmap<int, std::string, 8> b;
EXPECT_EQ(a, b);
a.Add(1, "one");
EXPECT_NE(a, b);
b.Add(2, "two");
EXPECT_NE(a, b);
a.Add(2, "two");
EXPECT_NE(a, b);
b.Add(1, "one");
EXPECT_EQ(a, b);
}
TEST(Hashmap, EqualityDifferentSize) {
Hashmap<int, std::string, 8> a;
Hashmap<int, std::string, 4> b;
EXPECT_EQ(a, b);
a.Add(1, "one");
EXPECT_NE(a, b);
b.Add(2, "two");
EXPECT_NE(a, b);
a.Add(2, "two");
EXPECT_NE(a, b);
b.Add(1, "one");
EXPECT_EQ(a, b);
}
TEST(Hashmap, HashSameSize) {
Hashmap<int, std::string, 8> a;
Hashmap<int, std::string, 8> b;
EXPECT_EQ(Hash(a), Hash(b));
a.Add(1, "one");
EXPECT_NE(Hash(a), Hash(b));
b.Add(2, "two");
EXPECT_NE(Hash(a), Hash(b));
a.Add(2, "two");
EXPECT_NE(Hash(a), Hash(b));
b.Add(1, "one");
EXPECT_EQ(Hash(a), Hash(b));
}
TEST(Hashmap, HashDifferentSize) {
Hashmap<int, std::string, 8> a;
Hashmap<int, std::string, 4> b;
EXPECT_EQ(Hash(a), Hash(b));
a.Add(1, "one");
EXPECT_NE(Hash(a), Hash(b));
b.Add(2, "two");
EXPECT_NE(Hash(a), Hash(b));
a.Add(2, "two");
EXPECT_NE(Hash(a), Hash(b));
b.Add(1, "one");
EXPECT_EQ(Hash(a), Hash(b));
}
} // namespace
} // namespace tint::utils