xref: /aosp_15_r20/external/pytorch/c10/util/hash.h (revision da0073e96a02ea20f0ac840b70461e3646d07c45)
1*da0073e9SAndroid Build Coastguard Worker #pragma once
2*da0073e9SAndroid Build Coastguard Worker 
3*da0073e9SAndroid Build Coastguard Worker #include <c10/util/Exception.h>
4*da0073e9SAndroid Build Coastguard Worker #include <cstddef>
5*da0073e9SAndroid Build Coastguard Worker #include <functional>
6*da0073e9SAndroid Build Coastguard Worker #include <iomanip>
7*da0073e9SAndroid Build Coastguard Worker #include <ios>
8*da0073e9SAndroid Build Coastguard Worker #include <sstream>
9*da0073e9SAndroid Build Coastguard Worker #include <string>
10*da0073e9SAndroid Build Coastguard Worker #include <tuple>
11*da0073e9SAndroid Build Coastguard Worker #include <type_traits>
12*da0073e9SAndroid Build Coastguard Worker #include <utility>
13*da0073e9SAndroid Build Coastguard Worker #include <vector>
14*da0073e9SAndroid Build Coastguard Worker 
15*da0073e9SAndroid Build Coastguard Worker #include <c10/util/ArrayRef.h>
16*da0073e9SAndroid Build Coastguard Worker #include <c10/util/complex.h>
17*da0073e9SAndroid Build Coastguard Worker 
18*da0073e9SAndroid Build Coastguard Worker namespace c10 {
19*da0073e9SAndroid Build Coastguard Worker 
20*da0073e9SAndroid Build Coastguard Worker // NOTE: hash_combine and SHA1 hashing is based on implementation from Boost
21*da0073e9SAndroid Build Coastguard Worker //
22*da0073e9SAndroid Build Coastguard Worker // Boost Software License - Version 1.0 - August 17th, 2003
23*da0073e9SAndroid Build Coastguard Worker //
24*da0073e9SAndroid Build Coastguard Worker // Permission is hereby granted, free of charge, to any person or organization
25*da0073e9SAndroid Build Coastguard Worker // obtaining a copy of the software and accompanying documentation covered by
26*da0073e9SAndroid Build Coastguard Worker // this license (the "Software") to use, reproduce, display, distribute,
27*da0073e9SAndroid Build Coastguard Worker // execute, and transmit the Software, and to prepare derivative works of the
28*da0073e9SAndroid Build Coastguard Worker // Software, and to permit third-parties to whom the Software is furnished to
29*da0073e9SAndroid Build Coastguard Worker // do so, all subject to the following:
30*da0073e9SAndroid Build Coastguard Worker //
31*da0073e9SAndroid Build Coastguard Worker // The copyright notices in the Software and this entire statement, including
32*da0073e9SAndroid Build Coastguard Worker // the above license grant, this restriction and the following disclaimer,
33*da0073e9SAndroid Build Coastguard Worker // must be included in all copies of the Software, in whole or in part, and
34*da0073e9SAndroid Build Coastguard Worker // all derivative works of the Software, unless such copies or derivative
35*da0073e9SAndroid Build Coastguard Worker // works are solely in the form of machine-executable object code generated by
36*da0073e9SAndroid Build Coastguard Worker // a source language processor.
37*da0073e9SAndroid Build Coastguard Worker //
38*da0073e9SAndroid Build Coastguard Worker // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
39*da0073e9SAndroid Build Coastguard Worker // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
40*da0073e9SAndroid Build Coastguard Worker // FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
41*da0073e9SAndroid Build Coastguard Worker // SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
42*da0073e9SAndroid Build Coastguard Worker // FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
43*da0073e9SAndroid Build Coastguard Worker // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
44*da0073e9SAndroid Build Coastguard Worker // DEALINGS IN THE SOFTWARE.
45*da0073e9SAndroid Build Coastguard Worker 
hash_combine(size_t seed,size_t value)46*da0073e9SAndroid Build Coastguard Worker inline size_t hash_combine(size_t seed, size_t value) {
47*da0073e9SAndroid Build Coastguard Worker   return seed ^ (value + 0x9e3779b9 + (seed << 6u) + (seed >> 2u));
48*da0073e9SAndroid Build Coastguard Worker }
49*da0073e9SAndroid Build Coastguard Worker 
50*da0073e9SAndroid Build Coastguard Worker // Creates the SHA1 hash of a string. A 160-bit hash.
51*da0073e9SAndroid Build Coastguard Worker // Based on the implementation in Boost (see notice above).
52*da0073e9SAndroid Build Coastguard Worker // Note that SHA1 hashes are no longer considered cryptographically
53*da0073e9SAndroid Build Coastguard Worker //   secure, but are the standard hash for generating unique ids.
54*da0073e9SAndroid Build Coastguard Worker // Usage:
55*da0073e9SAndroid Build Coastguard Worker //   // Let 'code' be a std::string
56*da0073e9SAndroid Build Coastguard Worker //   c10::sha1 sha1_hash{code};
57*da0073e9SAndroid Build Coastguard Worker //   const auto hash_code = sha1_hash.str();
58*da0073e9SAndroid Build Coastguard Worker // TODO: Compare vs OpenSSL and/or CryptoPP implementations
59*da0073e9SAndroid Build Coastguard Worker struct sha1 {
60*da0073e9SAndroid Build Coastguard Worker   typedef unsigned int(digest_type)[5];
61*da0073e9SAndroid Build Coastguard Worker 
62*da0073e9SAndroid Build Coastguard Worker   sha1(const std::string& s = "") {
63*da0073e9SAndroid Build Coastguard Worker     if (!s.empty()) {
64*da0073e9SAndroid Build Coastguard Worker       reset();
65*da0073e9SAndroid Build Coastguard Worker       process_bytes(s.c_str(), s.size());
66*da0073e9SAndroid Build Coastguard Worker     }
67*da0073e9SAndroid Build Coastguard Worker   }
68*da0073e9SAndroid Build Coastguard Worker 
resetsha169*da0073e9SAndroid Build Coastguard Worker   void reset() {
70*da0073e9SAndroid Build Coastguard Worker     h_[0] = 0x67452301;
71*da0073e9SAndroid Build Coastguard Worker     h_[1] = 0xEFCDAB89;
72*da0073e9SAndroid Build Coastguard Worker     h_[2] = 0x98BADCFE;
73*da0073e9SAndroid Build Coastguard Worker     h_[3] = 0x10325476;
74*da0073e9SAndroid Build Coastguard Worker     h_[4] = 0xC3D2E1F0;
75*da0073e9SAndroid Build Coastguard Worker 
76*da0073e9SAndroid Build Coastguard Worker     block_byte_index_ = 0;
77*da0073e9SAndroid Build Coastguard Worker     bit_count_low = 0;
78*da0073e9SAndroid Build Coastguard Worker     bit_count_high = 0;
79*da0073e9SAndroid Build Coastguard Worker   }
80*da0073e9SAndroid Build Coastguard Worker 
strsha181*da0073e9SAndroid Build Coastguard Worker   std::string str() {
82*da0073e9SAndroid Build Coastguard Worker     unsigned int digest[5];
83*da0073e9SAndroid Build Coastguard Worker     get_digest(digest);
84*da0073e9SAndroid Build Coastguard Worker 
85*da0073e9SAndroid Build Coastguard Worker     std::ostringstream buf;
86*da0073e9SAndroid Build Coastguard Worker     for (unsigned int i : digest) {
87*da0073e9SAndroid Build Coastguard Worker       buf << std::hex << std::setfill('0') << std::setw(8) << i;
88*da0073e9SAndroid Build Coastguard Worker     }
89*da0073e9SAndroid Build Coastguard Worker 
90*da0073e9SAndroid Build Coastguard Worker     return buf.str();
91*da0073e9SAndroid Build Coastguard Worker   }
92*da0073e9SAndroid Build Coastguard Worker 
93*da0073e9SAndroid Build Coastguard Worker  private:
left_rotatesha194*da0073e9SAndroid Build Coastguard Worker   unsigned int left_rotate(unsigned int x, std::size_t n) {
95*da0073e9SAndroid Build Coastguard Worker     return (x << n) ^ (x >> (32 - n));
96*da0073e9SAndroid Build Coastguard Worker   }
97*da0073e9SAndroid Build Coastguard Worker 
process_block_implsha198*da0073e9SAndroid Build Coastguard Worker   void process_block_impl() {
99*da0073e9SAndroid Build Coastguard Worker     unsigned int w[80];
100*da0073e9SAndroid Build Coastguard Worker 
101*da0073e9SAndroid Build Coastguard Worker     for (std::size_t i = 0; i < 16; ++i) {
102*da0073e9SAndroid Build Coastguard Worker       w[i] = (block_[i * 4 + 0] << 24);
103*da0073e9SAndroid Build Coastguard Worker       w[i] |= (block_[i * 4 + 1] << 16);
104*da0073e9SAndroid Build Coastguard Worker       w[i] |= (block_[i * 4 + 2] << 8);
105*da0073e9SAndroid Build Coastguard Worker       w[i] |= (block_[i * 4 + 3]);
106*da0073e9SAndroid Build Coastguard Worker     }
107*da0073e9SAndroid Build Coastguard Worker 
108*da0073e9SAndroid Build Coastguard Worker     for (std::size_t i = 16; i < 80; ++i) {
109*da0073e9SAndroid Build Coastguard Worker       w[i] = left_rotate((w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]), 1);
110*da0073e9SAndroid Build Coastguard Worker     }
111*da0073e9SAndroid Build Coastguard Worker 
112*da0073e9SAndroid Build Coastguard Worker     unsigned int a = h_[0];
113*da0073e9SAndroid Build Coastguard Worker     unsigned int b = h_[1];
114*da0073e9SAndroid Build Coastguard Worker     unsigned int c = h_[2];
115*da0073e9SAndroid Build Coastguard Worker     unsigned int d = h_[3];
116*da0073e9SAndroid Build Coastguard Worker     unsigned int e = h_[4];
117*da0073e9SAndroid Build Coastguard Worker 
118*da0073e9SAndroid Build Coastguard Worker     for (std::size_t i = 0; i < 80; ++i) {
119*da0073e9SAndroid Build Coastguard Worker       unsigned int f = 0;
120*da0073e9SAndroid Build Coastguard Worker       unsigned int k = 0;
121*da0073e9SAndroid Build Coastguard Worker 
122*da0073e9SAndroid Build Coastguard Worker       if (i < 20) {
123*da0073e9SAndroid Build Coastguard Worker         f = (b & c) | (~b & d);
124*da0073e9SAndroid Build Coastguard Worker         k = 0x5A827999;
125*da0073e9SAndroid Build Coastguard Worker       } else if (i < 40) {
126*da0073e9SAndroid Build Coastguard Worker         f = b ^ c ^ d;
127*da0073e9SAndroid Build Coastguard Worker         k = 0x6ED9EBA1;
128*da0073e9SAndroid Build Coastguard Worker       } else if (i < 60) {
129*da0073e9SAndroid Build Coastguard Worker         f = (b & c) | (b & d) | (c & d);
130*da0073e9SAndroid Build Coastguard Worker         k = 0x8F1BBCDC;
131*da0073e9SAndroid Build Coastguard Worker       } else {
132*da0073e9SAndroid Build Coastguard Worker         f = b ^ c ^ d;
133*da0073e9SAndroid Build Coastguard Worker         k = 0xCA62C1D6;
134*da0073e9SAndroid Build Coastguard Worker       }
135*da0073e9SAndroid Build Coastguard Worker 
136*da0073e9SAndroid Build Coastguard Worker       unsigned temp = left_rotate(a, 5) + f + e + k + w[i];
137*da0073e9SAndroid Build Coastguard Worker       e = d;
138*da0073e9SAndroid Build Coastguard Worker       d = c;
139*da0073e9SAndroid Build Coastguard Worker       c = left_rotate(b, 30);
140*da0073e9SAndroid Build Coastguard Worker       b = a;
141*da0073e9SAndroid Build Coastguard Worker       a = temp;
142*da0073e9SAndroid Build Coastguard Worker     }
143*da0073e9SAndroid Build Coastguard Worker 
144*da0073e9SAndroid Build Coastguard Worker     h_[0] += a;
145*da0073e9SAndroid Build Coastguard Worker     h_[1] += b;
146*da0073e9SAndroid Build Coastguard Worker     h_[2] += c;
147*da0073e9SAndroid Build Coastguard Worker     h_[3] += d;
148*da0073e9SAndroid Build Coastguard Worker     h_[4] += e;
149*da0073e9SAndroid Build Coastguard Worker   }
150*da0073e9SAndroid Build Coastguard Worker 
process_byte_implsha1151*da0073e9SAndroid Build Coastguard Worker   void process_byte_impl(unsigned char byte) {
152*da0073e9SAndroid Build Coastguard Worker     block_[block_byte_index_++] = byte;
153*da0073e9SAndroid Build Coastguard Worker 
154*da0073e9SAndroid Build Coastguard Worker     if (block_byte_index_ == 64) {
155*da0073e9SAndroid Build Coastguard Worker       block_byte_index_ = 0;
156*da0073e9SAndroid Build Coastguard Worker       process_block_impl();
157*da0073e9SAndroid Build Coastguard Worker     }
158*da0073e9SAndroid Build Coastguard Worker   }
159*da0073e9SAndroid Build Coastguard Worker 
process_bytesha1160*da0073e9SAndroid Build Coastguard Worker   void process_byte(unsigned char byte) {
161*da0073e9SAndroid Build Coastguard Worker     process_byte_impl(byte);
162*da0073e9SAndroid Build Coastguard Worker 
163*da0073e9SAndroid Build Coastguard Worker     // size_t max value = 0xFFFFFFFF
164*da0073e9SAndroid Build Coastguard Worker     // if (bit_count_low + 8 >= 0x100000000) { // would overflow
165*da0073e9SAndroid Build Coastguard Worker     // if (bit_count_low >= 0x100000000-8) {
166*da0073e9SAndroid Build Coastguard Worker     if (bit_count_low < 0xFFFFFFF8) {
167*da0073e9SAndroid Build Coastguard Worker       bit_count_low += 8;
168*da0073e9SAndroid Build Coastguard Worker     } else {
169*da0073e9SAndroid Build Coastguard Worker       bit_count_low = 0;
170*da0073e9SAndroid Build Coastguard Worker 
171*da0073e9SAndroid Build Coastguard Worker       if (bit_count_high <= 0xFFFFFFFE) {
172*da0073e9SAndroid Build Coastguard Worker         ++bit_count_high;
173*da0073e9SAndroid Build Coastguard Worker       } else {
174*da0073e9SAndroid Build Coastguard Worker         TORCH_CHECK(false, "sha1 too many bytes");
175*da0073e9SAndroid Build Coastguard Worker       }
176*da0073e9SAndroid Build Coastguard Worker     }
177*da0073e9SAndroid Build Coastguard Worker   }
178*da0073e9SAndroid Build Coastguard Worker 
process_blocksha1179*da0073e9SAndroid Build Coastguard Worker   void process_block(void const* bytes_begin, void const* bytes_end) {
180*da0073e9SAndroid Build Coastguard Worker     unsigned char const* begin = static_cast<unsigned char const*>(bytes_begin);
181*da0073e9SAndroid Build Coastguard Worker     unsigned char const* end = static_cast<unsigned char const*>(bytes_end);
182*da0073e9SAndroid Build Coastguard Worker     for (; begin != end; ++begin) {
183*da0073e9SAndroid Build Coastguard Worker       process_byte(*begin);
184*da0073e9SAndroid Build Coastguard Worker     }
185*da0073e9SAndroid Build Coastguard Worker   }
186*da0073e9SAndroid Build Coastguard Worker 
process_bytessha1187*da0073e9SAndroid Build Coastguard Worker   void process_bytes(void const* buffer, std::size_t byte_count) {
188*da0073e9SAndroid Build Coastguard Worker     unsigned char const* b = static_cast<unsigned char const*>(buffer);
189*da0073e9SAndroid Build Coastguard Worker     process_block(b, b + byte_count);
190*da0073e9SAndroid Build Coastguard Worker   }
191*da0073e9SAndroid Build Coastguard Worker 
get_digestsha1192*da0073e9SAndroid Build Coastguard Worker   void get_digest(digest_type& digest) {
193*da0073e9SAndroid Build Coastguard Worker     // append the bit '1' to the message
194*da0073e9SAndroid Build Coastguard Worker     process_byte_impl(0x80);
195*da0073e9SAndroid Build Coastguard Worker 
196*da0073e9SAndroid Build Coastguard Worker     // append k bits '0', where k is the minimum number >= 0
197*da0073e9SAndroid Build Coastguard Worker     // such that the resulting message length is congruent to 56 (mod 64)
198*da0073e9SAndroid Build Coastguard Worker     // check if there is enough space for padding and bit_count
199*da0073e9SAndroid Build Coastguard Worker     if (block_byte_index_ > 56) {
200*da0073e9SAndroid Build Coastguard Worker       // finish this block
201*da0073e9SAndroid Build Coastguard Worker       while (block_byte_index_ != 0) {
202*da0073e9SAndroid Build Coastguard Worker         process_byte_impl(0);
203*da0073e9SAndroid Build Coastguard Worker       }
204*da0073e9SAndroid Build Coastguard Worker 
205*da0073e9SAndroid Build Coastguard Worker       // one more block
206*da0073e9SAndroid Build Coastguard Worker       while (block_byte_index_ < 56) {
207*da0073e9SAndroid Build Coastguard Worker         process_byte_impl(0);
208*da0073e9SAndroid Build Coastguard Worker       }
209*da0073e9SAndroid Build Coastguard Worker     } else {
210*da0073e9SAndroid Build Coastguard Worker       while (block_byte_index_ < 56) {
211*da0073e9SAndroid Build Coastguard Worker         process_byte_impl(0);
212*da0073e9SAndroid Build Coastguard Worker       }
213*da0073e9SAndroid Build Coastguard Worker     }
214*da0073e9SAndroid Build Coastguard Worker 
215*da0073e9SAndroid Build Coastguard Worker     // append length of message (before pre-processing)
216*da0073e9SAndroid Build Coastguard Worker     // as a 64-bit big-endian integer
217*da0073e9SAndroid Build Coastguard Worker     process_byte_impl(
218*da0073e9SAndroid Build Coastguard Worker         static_cast<unsigned char>((bit_count_high >> 24) & 0xFF));
219*da0073e9SAndroid Build Coastguard Worker     process_byte_impl(
220*da0073e9SAndroid Build Coastguard Worker         static_cast<unsigned char>((bit_count_high >> 16) & 0xFF));
221*da0073e9SAndroid Build Coastguard Worker     process_byte_impl(static_cast<unsigned char>((bit_count_high >> 8) & 0xFF));
222*da0073e9SAndroid Build Coastguard Worker     process_byte_impl(static_cast<unsigned char>((bit_count_high) & 0xFF));
223*da0073e9SAndroid Build Coastguard Worker     process_byte_impl(static_cast<unsigned char>((bit_count_low >> 24) & 0xFF));
224*da0073e9SAndroid Build Coastguard Worker     process_byte_impl(static_cast<unsigned char>((bit_count_low >> 16) & 0xFF));
225*da0073e9SAndroid Build Coastguard Worker     process_byte_impl(static_cast<unsigned char>((bit_count_low >> 8) & 0xFF));
226*da0073e9SAndroid Build Coastguard Worker     process_byte_impl(static_cast<unsigned char>((bit_count_low) & 0xFF));
227*da0073e9SAndroid Build Coastguard Worker 
228*da0073e9SAndroid Build Coastguard Worker     // get final digest
229*da0073e9SAndroid Build Coastguard Worker     digest[0] = h_[0];
230*da0073e9SAndroid Build Coastguard Worker     digest[1] = h_[1];
231*da0073e9SAndroid Build Coastguard Worker     digest[2] = h_[2];
232*da0073e9SAndroid Build Coastguard Worker     digest[3] = h_[3];
233*da0073e9SAndroid Build Coastguard Worker     digest[4] = h_[4];
234*da0073e9SAndroid Build Coastguard Worker   }
235*da0073e9SAndroid Build Coastguard Worker 
236*da0073e9SAndroid Build Coastguard Worker   unsigned int h_[5]{};
237*da0073e9SAndroid Build Coastguard Worker   unsigned char block_[64]{};
238*da0073e9SAndroid Build Coastguard Worker   std::size_t block_byte_index_{};
239*da0073e9SAndroid Build Coastguard Worker   std::size_t bit_count_low{};
240*da0073e9SAndroid Build Coastguard Worker   std::size_t bit_count_high{};
241*da0073e9SAndroid Build Coastguard Worker };
242*da0073e9SAndroid Build Coastguard Worker 
twang_mix64(uint64_t key)243*da0073e9SAndroid Build Coastguard Worker constexpr uint64_t twang_mix64(uint64_t key) noexcept {
244*da0073e9SAndroid Build Coastguard Worker   key = (~key) + (key << 21); // key *= (1 << 21) - 1; key -= 1;
245*da0073e9SAndroid Build Coastguard Worker   key = key ^ (key >> 24);
246*da0073e9SAndroid Build Coastguard Worker   key = key + (key << 3) + (key << 8); // key *= 1 + (1 << 3) + (1 << 8)
247*da0073e9SAndroid Build Coastguard Worker   key = key ^ (key >> 14);
248*da0073e9SAndroid Build Coastguard Worker   key = key + (key << 2) + (key << 4); // key *= 1 + (1 << 2) + (1 << 4)
249*da0073e9SAndroid Build Coastguard Worker   key = key ^ (key >> 28);
250*da0073e9SAndroid Build Coastguard Worker   key = key + (key << 31); // key *= 1 + (1 << 31)
251*da0073e9SAndroid Build Coastguard Worker   return key;
252*da0073e9SAndroid Build Coastguard Worker }
253*da0073e9SAndroid Build Coastguard Worker 
254*da0073e9SAndroid Build Coastguard Worker ////////////////////////////////////////////////////////////////////////////////
255*da0073e9SAndroid Build Coastguard Worker // c10::hash implementation
256*da0073e9SAndroid Build Coastguard Worker ////////////////////////////////////////////////////////////////////////////////
257*da0073e9SAndroid Build Coastguard Worker 
258*da0073e9SAndroid Build Coastguard Worker namespace _hash_detail {
259*da0073e9SAndroid Build Coastguard Worker 
260*da0073e9SAndroid Build Coastguard Worker // Use template argument deduction to shorten calls to c10::hash
261*da0073e9SAndroid Build Coastguard Worker template <typename T>
262*da0073e9SAndroid Build Coastguard Worker size_t simple_get_hash(const T& o);
263*da0073e9SAndroid Build Coastguard Worker 
264*da0073e9SAndroid Build Coastguard Worker template <typename T, typename V>
265*da0073e9SAndroid Build Coastguard Worker using type_if_not_enum = std::enable_if_t<!std::is_enum_v<T>, V>;
266*da0073e9SAndroid Build Coastguard Worker 
267*da0073e9SAndroid Build Coastguard Worker // Use SFINAE to dispatch to std::hash if possible, cast enum types to int
268*da0073e9SAndroid Build Coastguard Worker // automatically, and fall back to T::hash otherwise. NOTE: C++14 added support
269*da0073e9SAndroid Build Coastguard Worker // for hashing enum types to the standard, and some compilers implement it even
270*da0073e9SAndroid Build Coastguard Worker // when C++14 flags aren't specified. This is why we have to disable this
271*da0073e9SAndroid Build Coastguard Worker // overload if T is an enum type (and use the one below in this case).
272*da0073e9SAndroid Build Coastguard Worker template <typename T>
273*da0073e9SAndroid Build Coastguard Worker auto dispatch_hash(const T& o)
274*da0073e9SAndroid Build Coastguard Worker     -> decltype(std::hash<T>()(o), type_if_not_enum<T, size_t>()) {
275*da0073e9SAndroid Build Coastguard Worker   return std::hash<T>()(o);
276*da0073e9SAndroid Build Coastguard Worker }
277*da0073e9SAndroid Build Coastguard Worker 
278*da0073e9SAndroid Build Coastguard Worker template <typename T>
dispatch_hash(const T & o)279*da0073e9SAndroid Build Coastguard Worker std::enable_if_t<std::is_enum_v<T>, size_t> dispatch_hash(const T& o) {
280*da0073e9SAndroid Build Coastguard Worker   using R = std::underlying_type_t<T>;
281*da0073e9SAndroid Build Coastguard Worker   return std::hash<R>()(static_cast<R>(o));
282*da0073e9SAndroid Build Coastguard Worker }
283*da0073e9SAndroid Build Coastguard Worker 
284*da0073e9SAndroid Build Coastguard Worker template <typename T>
285*da0073e9SAndroid Build Coastguard Worker auto dispatch_hash(const T& o) -> decltype(T::hash(o), size_t()) {
286*da0073e9SAndroid Build Coastguard Worker   return T::hash(o);
287*da0073e9SAndroid Build Coastguard Worker }
288*da0073e9SAndroid Build Coastguard Worker 
289*da0073e9SAndroid Build Coastguard Worker } // namespace _hash_detail
290*da0073e9SAndroid Build Coastguard Worker 
291*da0073e9SAndroid Build Coastguard Worker // Hasher struct
292*da0073e9SAndroid Build Coastguard Worker template <typename T>
293*da0073e9SAndroid Build Coastguard Worker struct hash {
operatorhash294*da0073e9SAndroid Build Coastguard Worker   size_t operator()(const T& o) const {
295*da0073e9SAndroid Build Coastguard Worker     return _hash_detail::dispatch_hash(o);
296*da0073e9SAndroid Build Coastguard Worker   };
297*da0073e9SAndroid Build Coastguard Worker };
298*da0073e9SAndroid Build Coastguard Worker 
299*da0073e9SAndroid Build Coastguard Worker // Specialization for std::tuple
300*da0073e9SAndroid Build Coastguard Worker template <typename... Types>
301*da0073e9SAndroid Build Coastguard Worker struct hash<std::tuple<Types...>> {
302*da0073e9SAndroid Build Coastguard Worker   template <size_t idx, typename... Ts>
303*da0073e9SAndroid Build Coastguard Worker   struct tuple_hash {
304*da0073e9SAndroid Build Coastguard Worker     size_t operator()(const std::tuple<Ts...>& t) const {
305*da0073e9SAndroid Build Coastguard Worker       return hash_combine(
306*da0073e9SAndroid Build Coastguard Worker           _hash_detail::simple_get_hash(std::get<idx>(t)),
307*da0073e9SAndroid Build Coastguard Worker           tuple_hash<idx - 1, Ts...>()(t));
308*da0073e9SAndroid Build Coastguard Worker     }
309*da0073e9SAndroid Build Coastguard Worker   };
310*da0073e9SAndroid Build Coastguard Worker 
311*da0073e9SAndroid Build Coastguard Worker   template <typename... Ts>
312*da0073e9SAndroid Build Coastguard Worker   struct tuple_hash<0, Ts...> {
313*da0073e9SAndroid Build Coastguard Worker     size_t operator()(const std::tuple<Ts...>& t) const {
314*da0073e9SAndroid Build Coastguard Worker       return _hash_detail::simple_get_hash(std::get<0>(t));
315*da0073e9SAndroid Build Coastguard Worker     }
316*da0073e9SAndroid Build Coastguard Worker   };
317*da0073e9SAndroid Build Coastguard Worker 
318*da0073e9SAndroid Build Coastguard Worker   size_t operator()(const std::tuple<Types...>& t) const {
319*da0073e9SAndroid Build Coastguard Worker     return tuple_hash<sizeof...(Types) - 1, Types...>()(t);
320*da0073e9SAndroid Build Coastguard Worker   }
321*da0073e9SAndroid Build Coastguard Worker };
322*da0073e9SAndroid Build Coastguard Worker 
323*da0073e9SAndroid Build Coastguard Worker template <typename T1, typename T2>
324*da0073e9SAndroid Build Coastguard Worker struct hash<std::pair<T1, T2>> {
325*da0073e9SAndroid Build Coastguard Worker   size_t operator()(const std::pair<T1, T2>& pair) const {
326*da0073e9SAndroid Build Coastguard Worker     std::tuple<T1, T2> tuple = std::make_tuple(pair.first, pair.second);
327*da0073e9SAndroid Build Coastguard Worker     return _hash_detail::simple_get_hash(tuple);
328*da0073e9SAndroid Build Coastguard Worker   }
329*da0073e9SAndroid Build Coastguard Worker };
330*da0073e9SAndroid Build Coastguard Worker 
331*da0073e9SAndroid Build Coastguard Worker template <typename T>
332*da0073e9SAndroid Build Coastguard Worker struct hash<c10::ArrayRef<T>> {
333*da0073e9SAndroid Build Coastguard Worker   size_t operator()(c10::ArrayRef<T> v) const {
334*da0073e9SAndroid Build Coastguard Worker     size_t seed = 0;
335*da0073e9SAndroid Build Coastguard Worker     for (const auto& elem : v) {
336*da0073e9SAndroid Build Coastguard Worker       seed = hash_combine(seed, _hash_detail::simple_get_hash(elem));
337*da0073e9SAndroid Build Coastguard Worker     }
338*da0073e9SAndroid Build Coastguard Worker     return seed;
339*da0073e9SAndroid Build Coastguard Worker   }
340*da0073e9SAndroid Build Coastguard Worker };
341*da0073e9SAndroid Build Coastguard Worker 
342*da0073e9SAndroid Build Coastguard Worker // Specialization for std::vector
343*da0073e9SAndroid Build Coastguard Worker template <typename T>
344*da0073e9SAndroid Build Coastguard Worker struct hash<std::vector<T>> {
345*da0073e9SAndroid Build Coastguard Worker   size_t operator()(const std::vector<T>& v) const {
346*da0073e9SAndroid Build Coastguard Worker     return hash<c10::ArrayRef<T>>()(v);
347*da0073e9SAndroid Build Coastguard Worker   }
348*da0073e9SAndroid Build Coastguard Worker };
349*da0073e9SAndroid Build Coastguard Worker 
350*da0073e9SAndroid Build Coastguard Worker namespace _hash_detail {
351*da0073e9SAndroid Build Coastguard Worker 
352*da0073e9SAndroid Build Coastguard Worker template <typename T>
353*da0073e9SAndroid Build Coastguard Worker size_t simple_get_hash(const T& o) {
354*da0073e9SAndroid Build Coastguard Worker   return c10::hash<T>()(o);
355*da0073e9SAndroid Build Coastguard Worker }
356*da0073e9SAndroid Build Coastguard Worker 
357*da0073e9SAndroid Build Coastguard Worker } // namespace _hash_detail
358*da0073e9SAndroid Build Coastguard Worker 
359*da0073e9SAndroid Build Coastguard Worker // Use this function to actually hash multiple things in one line.
360*da0073e9SAndroid Build Coastguard Worker // Dispatches to c10::hash, so it can hash containers.
361*da0073e9SAndroid Build Coastguard Worker // Example:
362*da0073e9SAndroid Build Coastguard Worker //
363*da0073e9SAndroid Build Coastguard Worker // static size_t hash(const MyStruct& s) {
364*da0073e9SAndroid Build Coastguard Worker //   return get_hash(s.member1, s.member2, s.member3);
365*da0073e9SAndroid Build Coastguard Worker // }
366*da0073e9SAndroid Build Coastguard Worker template <typename... Types>
367*da0073e9SAndroid Build Coastguard Worker size_t get_hash(const Types&... args) {
368*da0073e9SAndroid Build Coastguard Worker   return c10::hash<decltype(std::tie(args...))>()(std::tie(args...));
369*da0073e9SAndroid Build Coastguard Worker }
370*da0073e9SAndroid Build Coastguard Worker 
371*da0073e9SAndroid Build Coastguard Worker // Specialization for c10::complex
372*da0073e9SAndroid Build Coastguard Worker template <typename T>
373*da0073e9SAndroid Build Coastguard Worker struct hash<c10::complex<T>> {
374*da0073e9SAndroid Build Coastguard Worker   size_t operator()(const c10::complex<T>& c) const {
375*da0073e9SAndroid Build Coastguard Worker     return get_hash(c.real(), c.imag());
376*da0073e9SAndroid Build Coastguard Worker   }
377*da0073e9SAndroid Build Coastguard Worker };
378*da0073e9SAndroid Build Coastguard Worker 
379*da0073e9SAndroid Build Coastguard Worker } // namespace c10
380