Austin Eng | cc2516a | 2023-10-17 20:57:54 +0000 | [diff] [blame] | 1 | // Copyright 2021 The Dawn & Tint Authors |
Ryan Harrison | dbc13af | 2022-02-21 15:19:07 +0000 | [diff] [blame] | 2 | // |
Austin Eng | cc2516a | 2023-10-17 20:57:54 +0000 | [diff] [blame] | 3 | // Redistribution and use in source and binary forms, with or without |
| 4 | // modification, are permitted provided that the following conditions are met: |
Ryan Harrison | dbc13af | 2022-02-21 15:19:07 +0000 | [diff] [blame] | 5 | // |
Austin Eng | cc2516a | 2023-10-17 20:57:54 +0000 | [diff] [blame] | 6 | // 1. Redistributions of source code must retain the above copyright notice, this |
| 7 | // list of conditions and the following disclaimer. |
Ryan Harrison | dbc13af | 2022-02-21 15:19:07 +0000 | [diff] [blame] | 8 | // |
Austin Eng | cc2516a | 2023-10-17 20:57:54 +0000 | [diff] [blame] | 9 | // 2. Redistributions in binary form must reproduce the above copyright notice, |
| 10 | // this list of conditions and the following disclaimer in the documentation |
| 11 | // and/or other materials provided with the distribution. |
| 12 | // |
| 13 | // 3. Neither the name of the copyright holder nor the names of its |
| 14 | // contributors may be used to endorse or promote products derived from |
| 15 | // this software without specific prior written permission. |
| 16 | // |
| 17 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| 18 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 19 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| 20 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE |
| 21 | // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| 22 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
| 23 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
| 24 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
| 25 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 26 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
Ryan Harrison | dbc13af | 2022-02-21 15:19:07 +0000 | [diff] [blame] | 27 | |
dan sinclair | 22b4dd2 | 2023-07-21 00:40:07 +0000 | [diff] [blame] | 28 | #ifndef SRC_TINT_UTILS_MATH_HASH_H_ |
| 29 | #define SRC_TINT_UTILS_MATH_HASH_H_ |
Ryan Harrison | dbc13af | 2022-02-21 15:19:07 +0000 | [diff] [blame] | 30 | |
| 31 | #include <stdint.h> |
| 32 | #include <cstdio> |
| 33 | #include <functional> |
Ben Clayton | b703afc | 2023-05-05 18:55:15 +0000 | [diff] [blame] | 34 | #include <string> |
Ben Clayton | b066468 | 2022-05-19 17:59:19 +0000 | [diff] [blame] | 35 | #include <tuple> |
Ben Clayton | 046abc0 | 2022-04-28 13:08:22 +0000 | [diff] [blame] | 36 | #include <utility> |
Ben Clayton | 0c7c23b | 2022-08-31 23:51:48 +0000 | [diff] [blame] | 37 | #include <variant> |
Ryan Harrison | dbc13af | 2022-02-21 15:19:07 +0000 | [diff] [blame] | 38 | #include <vector> |
| 39 | |
dan sinclair | 22b4dd2 | 2023-07-21 00:40:07 +0000 | [diff] [blame] | 40 | #include "src/tint/utils/math/crc32.h" |
Ben Clayton | 3bc20e3 | 2022-07-21 19:34:05 +0000 | [diff] [blame] | 41 | |
dan sinclair | bae54e7 | 2023-07-28 15:01:54 +0000 | [diff] [blame] | 42 | namespace tint { |
Ben Clayton | 76aec25 | 2024-02-05 20:49:36 +0000 | [diff] [blame] | 43 | |
Ryan Harrison | dbc13af | 2022-02-21 15:19:07 +0000 | [diff] [blame] | 44 | namespace detail { |
| 45 | |
Ben Clayton | 4dcbdda | 2023-09-20 14:51:34 +0000 | [diff] [blame] | 46 | template <typename T, typename = void> |
| 47 | struct HasHashCodeMember : std::false_type {}; |
| 48 | |
| 49 | template <typename T> |
| 50 | struct HasHashCodeMember< |
| 51 | T, |
| 52 | std::enable_if_t<std::is_member_function_pointer_v<decltype(&T::HashCode)>>> : std::true_type { |
| 53 | }; |
| 54 | |
Ryan Harrison | dbc13af | 2022-02-21 15:19:07 +0000 | [diff] [blame] | 55 | } // namespace detail |
| 56 | |
Ben Clayton | 76aec25 | 2024-02-05 20:49:36 +0000 | [diff] [blame] | 57 | /// The type of a hash code |
| 58 | using HashCode = uint32_t; |
| 59 | |
Ben Clayton | e3f2005 | 2022-08-23 16:10:35 +0000 | [diff] [blame] | 60 | /// Forward declarations (see below) |
Ben Clayton | b066468 | 2022-05-19 17:59:19 +0000 | [diff] [blame] | 61 | template <typename... ARGS> |
Ben Clayton | 76aec25 | 2024-02-05 20:49:36 +0000 | [diff] [blame] | 62 | HashCode Hash(const ARGS&... values); |
Ben Clayton | b066468 | 2022-05-19 17:59:19 +0000 | [diff] [blame] | 63 | |
Ben Clayton | e3f2005 | 2022-08-23 16:10:35 +0000 | [diff] [blame] | 64 | template <typename... ARGS> |
Ben Clayton | 76aec25 | 2024-02-05 20:49:36 +0000 | [diff] [blame] | 65 | HashCode HashCombine(HashCode hash, const ARGS&... values); |
Ryan Harrison | dbc13af | 2022-02-21 15:19:07 +0000 | [diff] [blame] | 66 | |
Ben Clayton | e3f2005 | 2022-08-23 16:10:35 +0000 | [diff] [blame] | 67 | /// A STL-compatible hasher that does a more thorough job than most implementations of std::hash. |
| 68 | /// Hasher has been optimized for a better quality hash at the expense of increased computation |
| 69 | /// costs. |
Ben Clayton | 4dcbdda | 2023-09-20 14:51:34 +0000 | [diff] [blame] | 70 | /// Hasher is specialized for various core Tint data types. The default implementation will use a |
Ben Clayton | 76aec25 | 2024-02-05 20:49:36 +0000 | [diff] [blame] | 71 | /// `HashCode HashCode()` method on the `T` type, and will fallback to `std::hash<T>` if |
Ben Clayton | 4dcbdda | 2023-09-20 14:51:34 +0000 | [diff] [blame] | 72 | /// `T::HashCode` is missing. |
Ryan Harrison | dbc13af | 2022-02-21 15:19:07 +0000 | [diff] [blame] | 73 | template <typename T> |
Ben Clayton | e3f2005 | 2022-08-23 16:10:35 +0000 | [diff] [blame] | 74 | struct Hasher { |
| 75 | /// @param value the value to hash |
| 76 | /// @returns a hash of the value |
Ben Clayton | 76aec25 | 2024-02-05 20:49:36 +0000 | [diff] [blame] | 77 | HashCode operator()(const T& value) const { |
Ben Clayton | 4dcbdda | 2023-09-20 14:51:34 +0000 | [diff] [blame] | 78 | if constexpr (detail::HasHashCodeMember<T>::value) { |
Ben Clayton | de9f523 | 2023-11-13 13:46:36 +0000 | [diff] [blame] | 79 | auto hash = value.HashCode(); |
Ben Clayton | 76aec25 | 2024-02-05 20:49:36 +0000 | [diff] [blame] | 80 | static_assert(std::is_same_v<decltype(hash), HashCode>, |
| 81 | "T::HashCode() must return HashCode"); |
Ben Clayton | de9f523 | 2023-11-13 13:46:36 +0000 | [diff] [blame] | 82 | return hash; |
Ben Clayton | 4dcbdda | 2023-09-20 14:51:34 +0000 | [diff] [blame] | 83 | } else { |
Ben Clayton | 76aec25 | 2024-02-05 20:49:36 +0000 | [diff] [blame] | 84 | return static_cast<HashCode>(std::hash<T>()(value)); |
Ben Clayton | 4dcbdda | 2023-09-20 14:51:34 +0000 | [diff] [blame] | 85 | } |
| 86 | } |
Ben Clayton | e3f2005 | 2022-08-23 16:10:35 +0000 | [diff] [blame] | 87 | }; |
| 88 | |
| 89 | /// Hasher specialization for pointers |
Ben Clayton | e3f2005 | 2022-08-23 16:10:35 +0000 | [diff] [blame] | 90 | template <typename T> |
| 91 | struct Hasher<T*> { |
| 92 | /// @param ptr the pointer to hash |
| 93 | /// @returns a hash of the pointer |
Ben Clayton | 76aec25 | 2024-02-05 20:49:36 +0000 | [diff] [blame] | 94 | HashCode operator()(T* ptr) const { |
| 95 | auto hash = reinterpret_cast<uintptr_t>(ptr); |
Ben Clayton | f2b86aa | 2022-12-13 14:46:02 +0000 | [diff] [blame] | 96 | #ifdef TINT_HASH_SEED |
| 97 | hash ^= static_cast<uint32_t>(TINT_HASH_SEED); |
| 98 | #endif |
Ben Clayton | 76aec25 | 2024-02-05 20:49:36 +0000 | [diff] [blame] | 99 | if constexpr (sizeof(hash) > 4) { |
| 100 | return static_cast<HashCode>(hash >> 4 | hash >> 32); |
| 101 | } else { |
| 102 | return static_cast<HashCode>(hash >> 4); |
| 103 | } |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 104 | } |
Ben Clayton | e3f2005 | 2022-08-23 16:10:35 +0000 | [diff] [blame] | 105 | }; |
Ryan Harrison | dbc13af | 2022-02-21 15:19:07 +0000 | [diff] [blame] | 106 | |
Ben Clayton | e3f2005 | 2022-08-23 16:10:35 +0000 | [diff] [blame] | 107 | /// Hasher specialization for std::vector |
| 108 | template <typename T> |
| 109 | struct Hasher<std::vector<T>> { |
| 110 | /// @param vector the vector to hash |
| 111 | /// @returns a hash of the vector |
Ben Clayton | 76aec25 | 2024-02-05 20:49:36 +0000 | [diff] [blame] | 112 | HashCode operator()(const std::vector<T>& vector) const { |
Ben Clayton | e3f2005 | 2022-08-23 16:10:35 +0000 | [diff] [blame] | 113 | auto hash = Hash(vector.size()); |
| 114 | for (auto& el : vector) { |
| 115 | hash = HashCombine(hash, el); |
| 116 | } |
| 117 | return hash; |
| 118 | } |
| 119 | }; |
| 120 | |
Ben Clayton | e3f2005 | 2022-08-23 16:10:35 +0000 | [diff] [blame] | 121 | /// Hasher specialization for std::tuple |
Ben Clayton | b066468 | 2022-05-19 17:59:19 +0000 | [diff] [blame] | 122 | template <typename... TYPES> |
Ben Clayton | e3f2005 | 2022-08-23 16:10:35 +0000 | [diff] [blame] | 123 | struct Hasher<std::tuple<TYPES...>> { |
| 124 | /// @param tuple the tuple to hash |
| 125 | /// @returns a hash of the tuple |
Ben Clayton | 76aec25 | 2024-02-05 20:49:36 +0000 | [diff] [blame] | 126 | HashCode operator()(const std::tuple<TYPES...>& tuple) const { |
Ben Clayton | e3f2005 | 2022-08-23 16:10:35 +0000 | [diff] [blame] | 127 | return std::apply(Hash<TYPES...>, tuple); |
| 128 | } |
| 129 | }; |
Ben Clayton | b066468 | 2022-05-19 17:59:19 +0000 | [diff] [blame] | 130 | |
Ben Clayton | 7883a0c | 2023-04-20 23:51:53 +0000 | [diff] [blame] | 131 | /// Hasher specialization for std::pair |
| 132 | template <typename A, typename B> |
| 133 | struct Hasher<std::pair<A, B>> { |
| 134 | /// @param tuple the tuple to hash |
| 135 | /// @returns a hash of the tuple |
Ben Clayton | 76aec25 | 2024-02-05 20:49:36 +0000 | [diff] [blame] | 136 | HashCode operator()(const std::pair<A, B>& tuple) const { |
| 137 | return std::apply(Hash<A, B>, tuple); |
| 138 | } |
Ben Clayton | 7883a0c | 2023-04-20 23:51:53 +0000 | [diff] [blame] | 139 | }; |
| 140 | |
| 141 | /// Hasher specialization for std::variant |
Ben Clayton | 0c7c23b | 2022-08-31 23:51:48 +0000 | [diff] [blame] | 142 | template <typename... TYPES> |
| 143 | struct Hasher<std::variant<TYPES...>> { |
| 144 | /// @param variant the variant to hash |
| 145 | /// @returns a hash of the tuple |
Ben Clayton | 76aec25 | 2024-02-05 20:49:36 +0000 | [diff] [blame] | 146 | HashCode operator()(const std::variant<TYPES...>& variant) const { |
Ben Clayton | 0c7c23b | 2022-08-31 23:51:48 +0000 | [diff] [blame] | 147 | return std::visit([](auto&& val) { return Hash(val); }, variant); |
| 148 | } |
| 149 | }; |
| 150 | |
Ben Clayton | b703afc | 2023-05-05 18:55:15 +0000 | [diff] [blame] | 151 | /// Hasher specialization for std::string, which also supports hashing of const char* and |
| 152 | /// std::string_view without first constructing a std::string. |
| 153 | template <> |
| 154 | struct Hasher<std::string> { |
| 155 | /// @param str the string to hash |
| 156 | /// @returns a hash of the string |
Ben Clayton | 76aec25 | 2024-02-05 20:49:36 +0000 | [diff] [blame] | 157 | HashCode operator()(const std::string& str) const { |
| 158 | return static_cast<HashCode>(std::hash<std::string_view>()(std::string_view(str))); |
Ben Clayton | b703afc | 2023-05-05 18:55:15 +0000 | [diff] [blame] | 159 | } |
| 160 | |
| 161 | /// @param str the string to hash |
| 162 | /// @returns a hash of the string |
Ben Clayton | 76aec25 | 2024-02-05 20:49:36 +0000 | [diff] [blame] | 163 | HashCode operator()(const char* str) const { |
| 164 | return static_cast<HashCode>(std::hash<std::string_view>()(std::string_view(str))); |
Ben Clayton | b703afc | 2023-05-05 18:55:15 +0000 | [diff] [blame] | 165 | } |
| 166 | |
| 167 | /// @param str the string to hash |
| 168 | /// @returns a hash of the string |
Ben Clayton | 76aec25 | 2024-02-05 20:49:36 +0000 | [diff] [blame] | 169 | HashCode operator()(const std::string_view& str) const { |
| 170 | return static_cast<HashCode>(std::hash<std::string_view>()(str)); |
Ben Clayton | b703afc | 2023-05-05 18:55:15 +0000 | [diff] [blame] | 171 | } |
| 172 | }; |
| 173 | |
Ben Clayton | 0740cf8 | 2023-07-28 21:40:41 +0000 | [diff] [blame] | 174 | /// @param args the arguments to hash |
Ben Clayton | e3f2005 | 2022-08-23 16:10:35 +0000 | [diff] [blame] | 175 | /// @returns a hash of the variadic list of arguments. |
| 176 | /// The returned hash is dependent on the order of the arguments. |
Ryan Harrison | dbc13af | 2022-02-21 15:19:07 +0000 | [diff] [blame] | 177 | template <typename... ARGS> |
Ben Clayton | 76aec25 | 2024-02-05 20:49:36 +0000 | [diff] [blame] | 178 | HashCode Hash(const ARGS&... args) { |
Ben Clayton | e3f2005 | 2022-08-23 16:10:35 +0000 | [diff] [blame] | 179 | if constexpr (sizeof...(ARGS) == 0) { |
| 180 | return 0; |
| 181 | } else if constexpr (sizeof...(ARGS) == 1) { |
| 182 | using T = std::tuple_element_t<0, std::tuple<ARGS...>>; |
| 183 | return Hasher<T>()(args...); |
| 184 | } else { |
Ben Clayton | 76aec25 | 2024-02-05 20:49:36 +0000 | [diff] [blame] | 185 | HashCode hash = 102931; // seed with an arbitrary prime |
Ben Clayton | e3f2005 | 2022-08-23 16:10:35 +0000 | [diff] [blame] | 186 | return HashCombine(hash, args...); |
| 187 | } |
| 188 | } |
| 189 | |
Ben Clayton | 0740cf8 | 2023-07-28 21:40:41 +0000 | [diff] [blame] | 190 | /// @param hash the hash value to combine with |
| 191 | /// @param values the values to hash |
Ben Clayton | e3f2005 | 2022-08-23 16:10:35 +0000 | [diff] [blame] | 192 | /// @returns a hash of the variadic list of arguments. |
| 193 | /// The returned hash is dependent on the order of the arguments. |
| 194 | template <typename... ARGS> |
Ben Clayton | 76aec25 | 2024-02-05 20:49:36 +0000 | [diff] [blame] | 195 | HashCode HashCombine(HashCode hash, const ARGS&... values) { |
| 196 | #ifdef TINT_HASH_SEED |
| 197 | constexpr uint32_t offset = 0x7f4a7c16 ^ static_cast<uint32_t>(TINT_HASH_SEED); |
| 198 | #else |
| 199 | constexpr uint32_t offset = 0x7f4a7c16; |
| 200 | #endif |
| 201 | |
Ben Clayton | 51d88eb | 2022-12-13 16:53:31 +0000 | [diff] [blame] | 202 | ((hash ^= Hash(values) + (offset ^ (hash >> 2))), ...); |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 203 | return hash; |
Ryan Harrison | dbc13af | 2022-02-21 15:19:07 +0000 | [diff] [blame] | 204 | } |
| 205 | |
Ben Clayton | b703afc | 2023-05-05 18:55:15 +0000 | [diff] [blame] | 206 | /// A STL-compatible equal_to implementation that specializes for types. |
| 207 | template <typename T> |
| 208 | struct EqualTo { |
| 209 | /// @param lhs the left hand side value |
| 210 | /// @param rhs the right hand side value |
| 211 | /// @returns true if the two values are equal |
| 212 | constexpr bool operator()(const T& lhs, const T& rhs) const { |
| 213 | return std::equal_to<T>()(lhs, rhs); |
| 214 | } |
| 215 | }; |
| 216 | |
| 217 | /// A specialization for EqualTo for std::string, which supports additional comparision with |
| 218 | /// std::string_view and const char*. |
| 219 | template <> |
| 220 | struct EqualTo<std::string> { |
| 221 | /// @param lhs the left hand side value |
| 222 | /// @param rhs the right hand side value |
| 223 | /// @returns true if the two values are equal |
| 224 | bool operator()(const std::string& lhs, const std::string& rhs) const { return lhs == rhs; } |
| 225 | |
| 226 | /// @param lhs the left hand side value |
| 227 | /// @param rhs the right hand side value |
| 228 | /// @returns true if the two values are equal |
| 229 | bool operator()(const std::string& lhs, const char* rhs) const { return lhs == rhs; } |
| 230 | |
| 231 | /// @param lhs the left hand side value |
| 232 | /// @param rhs the right hand side value |
| 233 | /// @returns true if the two values are equal |
| 234 | bool operator()(const std::string& lhs, std::string_view rhs) const { return lhs == rhs; } |
| 235 | |
| 236 | /// @param lhs the left hand side value |
| 237 | /// @param rhs the right hand side value |
| 238 | /// @returns true if the two values are equal |
| 239 | bool operator()(const char* lhs, const std::string& rhs) const { return lhs == rhs; } |
| 240 | |
| 241 | /// @param lhs the left hand side value |
| 242 | /// @param rhs the right hand side value |
| 243 | /// @returns true if the two values are equal |
| 244 | bool operator()(std::string_view lhs, const std::string& rhs) const { return lhs == rhs; } |
| 245 | }; |
| 246 | |
Ben Clayton | 046abc0 | 2022-04-28 13:08:22 +0000 | [diff] [blame] | 247 | /// Wrapper for a hashable type enabling the wrapped value to be used as a key |
| 248 | /// for an unordered_map or unordered_set. |
| 249 | template <typename T> |
| 250 | struct UnorderedKeyWrapper { |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 251 | /// The wrapped value |
Ben Clayton | 9418152 | 2022-11-09 20:55:33 +0000 | [diff] [blame] | 252 | T value; |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 253 | /// The hash of value |
Ben Clayton | 76aec25 | 2024-02-05 20:49:36 +0000 | [diff] [blame] | 254 | HashCode hash; |
Ben Clayton | 046abc0 | 2022-04-28 13:08:22 +0000 | [diff] [blame] | 255 | |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 256 | /// Constructor |
| 257 | /// @param v the value to wrap |
| 258 | explicit UnorderedKeyWrapper(const T& v) : value(v), hash(Hash(v)) {} |
Ben Clayton | 046abc0 | 2022-04-28 13:08:22 +0000 | [diff] [blame] | 259 | |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 260 | /// Move constructor |
| 261 | /// @param v the value to wrap |
| 262 | explicit UnorderedKeyWrapper(T&& v) : value(std::move(v)), hash(Hash(value)) {} |
Ben Clayton | 046abc0 | 2022-04-28 13:08:22 +0000 | [diff] [blame] | 263 | |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 264 | /// @returns true if this wrapper comes before other |
| 265 | /// @param other the RHS of the operator |
| 266 | bool operator<(const UnorderedKeyWrapper& other) const { return hash < other.hash; } |
Ben Clayton | 046abc0 | 2022-04-28 13:08:22 +0000 | [diff] [blame] | 267 | |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 268 | /// @returns true if this wrapped value is equal to the other wrapped value |
| 269 | /// @param other the RHS of the operator |
| 270 | bool operator==(const UnorderedKeyWrapper& other) const { return value == other.value; } |
Ben Clayton | 046abc0 | 2022-04-28 13:08:22 +0000 | [diff] [blame] | 271 | }; |
| 272 | |
dan sinclair | bae54e7 | 2023-07-28 15:01:54 +0000 | [diff] [blame] | 273 | } // namespace tint |
Ryan Harrison | dbc13af | 2022-02-21 15:19:07 +0000 | [diff] [blame] | 274 | |
Ben Clayton | 046abc0 | 2022-04-28 13:08:22 +0000 | [diff] [blame] | 275 | namespace std { |
| 276 | |
dan sinclair | bae54e7 | 2023-07-28 15:01:54 +0000 | [diff] [blame] | 277 | /// Custom std::hash specialization for tint::UnorderedKeyWrapper |
Ben Clayton | 046abc0 | 2022-04-28 13:08:22 +0000 | [diff] [blame] | 278 | template <typename T> |
dan sinclair | bae54e7 | 2023-07-28 15:01:54 +0000 | [diff] [blame] | 279 | class hash<tint::UnorderedKeyWrapper<T>> { |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 280 | public: |
| 281 | /// @param w the UnorderedKeyWrapper |
| 282 | /// @return the hash value |
dan sinclair | bae54e7 | 2023-07-28 15:01:54 +0000 | [diff] [blame] | 283 | inline std::size_t operator()(const tint::UnorderedKeyWrapper<T>& w) const { return w.hash; } |
Ben Clayton | 046abc0 | 2022-04-28 13:08:22 +0000 | [diff] [blame] | 284 | }; |
| 285 | |
| 286 | } // namespace std |
| 287 | |
dan sinclair | 22b4dd2 | 2023-07-21 00:40:07 +0000 | [diff] [blame] | 288 | #endif // SRC_TINT_UTILS_MATH_HASH_H_ |