mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-12-11 14:41:50 +00:00
IntrinsicTable: De-duplicate returned Intrinsics
Much like sem::Type, it greatly simplifies downstream logic if we can compare sem::Intrinsic pointers to know if they refer to the same intrinsic overload. Change-Id: If236247cd3979bbde821d9294f304ab85ba4938e Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/58061 Kokoro: Kokoro <noreply+kokoro@google.com> Reviewed-by: David Neto <dneto@google.com>
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
#define SRC_UTILS_ENUM_SET_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
|
||||
namespace tint {
|
||||
@@ -58,6 +59,19 @@ struct EnumSet {
|
||||
/// @return true if the set contains `e`
|
||||
inline bool Contains(Enum e) { return (set & Bit(e)) != 0; }
|
||||
|
||||
/// Equality operator
|
||||
/// @param rhs the other EnumSet to compare this to
|
||||
/// @return true if this EnumSet is equal to rhs
|
||||
inline bool operator==(const EnumSet& rhs) const { return set == rhs.set; }
|
||||
|
||||
/// Inequality operator
|
||||
/// @param rhs the other EnumSet to compare this to
|
||||
/// @return true if this EnumSet is not equal to rhs
|
||||
inline bool operator!=(const EnumSet& rhs) const { return set != rhs.set; }
|
||||
|
||||
/// @return the underlying value for the EnumSet
|
||||
inline uint64_t Value() const { return set; }
|
||||
|
||||
private:
|
||||
static constexpr uint64_t Bit(Enum value) {
|
||||
return static_cast<uint64_t>(1) << static_cast<uint64_t>(value);
|
||||
@@ -76,4 +90,19 @@ struct EnumSet {
|
||||
} // namespace utils
|
||||
} // namespace tint
|
||||
|
||||
namespace std {
|
||||
|
||||
/// Custom std::hash specialization for tint::utils::EnumSet<T>
|
||||
template <typename T>
|
||||
class hash<tint::utils::EnumSet<T>> {
|
||||
public:
|
||||
/// @param e the EnumSet to create a hash for
|
||||
/// @return the hash value
|
||||
inline std::size_t operator()(const tint::utils::EnumSet<T>& e) const {
|
||||
return std::hash<uint64_t>()(e.Value());
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
||||
#endif // SRC_UTILS_ENUM_SET_H_
|
||||
|
||||
@@ -59,6 +59,30 @@ TEST(EnumSetTest, Remove) {
|
||||
EXPECT_FALSE(set.Contains(E::C));
|
||||
}
|
||||
|
||||
TEST(EnumSetTest, Equality) {
|
||||
EXPECT_TRUE(EnumSet<E>(E::A, E::B) == EnumSet<E>(E::A, E::B));
|
||||
EXPECT_FALSE(EnumSet<E>(E::A, E::B) == EnumSet<E>(E::A, E::C));
|
||||
}
|
||||
|
||||
TEST(EnumSetTest, Inequality) {
|
||||
EXPECT_FALSE(EnumSet<E>(E::A, E::B) != EnumSet<E>(E::A, E::B));
|
||||
EXPECT_TRUE(EnumSet<E>(E::A, E::B) != EnumSet<E>(E::A, E::C));
|
||||
}
|
||||
|
||||
TEST(EnumSetTest, Hash) {
|
||||
auto hash = [&](EnumSet<E> s) { return std::hash<EnumSet<E>>()(s); };
|
||||
EXPECT_EQ(hash(EnumSet<E>(E::A, E::B)), hash(EnumSet<E>(E::A, E::B)));
|
||||
EXPECT_NE(hash(EnumSet<E>(E::A, E::B)), hash(EnumSet<E>(E::A, E::C)));
|
||||
}
|
||||
|
||||
TEST(EnumSetTest, Value) {
|
||||
EXPECT_EQ(EnumSet<E>().Value(), 0u);
|
||||
EXPECT_EQ(EnumSet<E>(E::A).Value(), 1u);
|
||||
EXPECT_EQ(EnumSet<E>(E::B).Value(), 2u);
|
||||
EXPECT_EQ(EnumSet<E>(E::C).Value(), 4u);
|
||||
EXPECT_EQ(EnumSet<E>(E::A, E::C).Value(), 5u);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace utils
|
||||
} // namespace tint
|
||||
|
||||
@@ -27,8 +27,10 @@ namespace utils {
|
||||
/// @param key the map key of the item to query or add
|
||||
/// @param create a callable function-like object with the signature `V()`
|
||||
/// @return the value of the item with the given key, or the newly created item
|
||||
template <typename K, typename V, typename CREATE, typename H>
|
||||
V GetOrCreate(std::unordered_map<K, V, H>& map, K key, CREATE&& create) {
|
||||
template <typename K, typename V, typename H, typename C, typename CREATE>
|
||||
V GetOrCreate(std::unordered_map<K, V, H, C>& map,
|
||||
const K& key,
|
||||
CREATE&& create) {
|
||||
auto it = map.find(key);
|
||||
if (it != map.end()) {
|
||||
return it->second;
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <stdint.h>
|
||||
#include <cstdio>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
namespace tint {
|
||||
namespace utils {
|
||||
@@ -51,6 +52,15 @@ void HashCombine(size_t* hash, const T& value) {
|
||||
*hash ^= std::hash<T>()(value) + offset + (*hash << 6) + (*hash >> 2);
|
||||
}
|
||||
|
||||
// Helper for hashing vectors
|
||||
template <typename T>
|
||||
void HashCombine(size_t* hash, const std::vector<T>& vector) {
|
||||
HashCombine(hash, vector.size());
|
||||
for (auto& el : vector) {
|
||||
HashCombine(hash, el);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename... ARGS>
|
||||
void HashCombine(size_t* hash, const T& value, const ARGS&... args) {
|
||||
HashCombine(hash, value);
|
||||
|
||||
@@ -23,14 +23,25 @@ namespace utils {
|
||||
namespace {
|
||||
|
||||
TEST(HashTests, Basic) {
|
||||
EXPECT_EQ(Hash(123), Hash(123));
|
||||
EXPECT_NE(Hash(123), Hash(321));
|
||||
EXPECT_EQ(Hash(123, 456), Hash(123, 456));
|
||||
EXPECT_NE(Hash(123, 456), Hash(456, 123));
|
||||
EXPECT_NE(Hash(123, 456), Hash(123));
|
||||
EXPECT_EQ(Hash(123, 456, false), Hash(123, 456, false));
|
||||
EXPECT_NE(Hash(123, 456, false), Hash(123, 456));
|
||||
EXPECT_EQ(Hash(std::string("hello")), Hash(std::string("hello")));
|
||||
EXPECT_NE(Hash(std::string("hello")), Hash(std::string("world")));
|
||||
}
|
||||
|
||||
TEST(HashTests, Order) {
|
||||
EXPECT_NE(Hash(123, 456), Hash(456, 123));
|
||||
TEST(HashTests, Vector) {
|
||||
EXPECT_EQ(Hash(std::vector<int>({})), Hash(std::vector<int>({})));
|
||||
EXPECT_EQ(Hash(std::vector<int>({1, 2, 3})),
|
||||
Hash(std::vector<int>({1, 2, 3})));
|
||||
EXPECT_NE(Hash(std::vector<int>({1, 2, 3})),
|
||||
Hash(std::vector<int>({1, 2, 4})));
|
||||
EXPECT_NE(Hash(std::vector<int>({1, 2, 3})),
|
||||
Hash(std::vector<int>({1, 2, 3, 4})));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Reference in New Issue
Block a user