1 | #pragma once |
2 | |
3 | #include <functional> |
4 | #include <stddef.h> |
5 | |
6 | namespace taichi::hashing { |
7 | |
8 | template <typename T> |
9 | struct Hasher { |
10 | public: |
11 | size_t operator()(T const &val) const { |
12 | return std::hash<T>{}(val); |
13 | } |
14 | }; |
15 | |
16 | namespace { |
17 | template <typename T> |
18 | inline size_t hash_value(T const &value) { |
19 | return Hasher<T>{}(value); |
20 | } |
21 | |
22 | template <typename T> |
23 | inline void hash_combine(size_t &seed, T const &value) { |
24 | // Reference: |
25 | // https://www.boost.org/doc/libs/1_55_0/doc/html/hash/reference.html#boost.hash_combine |
26 | seed ^= hash_value(value) + 0x9e3779b9 + (seed << 6) + (seed >> 2); |
27 | } |
28 | } // namespace |
29 | |
30 | template <typename T> |
31 | struct Hasher<std::vector<T>> { |
32 | public: |
33 | size_t operator()(std::vector<T> const &vec) const { |
34 | size_t ret = 0; |
35 | for (const auto &i : vec) { |
36 | hash_combine(ret, i); |
37 | } |
38 | return ret; |
39 | } |
40 | }; |
41 | |
42 | template <typename T1, typename T2> |
43 | struct Hasher<std::pair<T1, T2>> { |
44 | public: |
45 | size_t operator()(std::pair<T1, T2> const &val) const { |
46 | size_t ret = hash_value(val.first); |
47 | hash_combine(ret, val.second); |
48 | return ret; |
49 | } |
50 | }; |
51 | |
52 | namespace { |
53 | template <int N, typename... Ts> |
54 | struct TupleHasher { |
55 | size_t operator()(std::tuple<Ts...> const &val) { |
56 | size_t ret = TupleHasher<N - 1, Ts...>{}(val); |
57 | hash_combine(ret, std::get<N>(val)); |
58 | return ret; |
59 | } |
60 | }; |
61 | |
62 | template <typename... Ts> |
63 | struct TupleHasher<0, Ts...> { |
64 | size_t operator()(std::tuple<Ts...> const &val) { |
65 | return hash_value(std::get<0>(val)); |
66 | } |
67 | }; |
68 | } // namespace |
69 | |
70 | template <typename... Ts> |
71 | struct Hasher<std::tuple<Ts...>> { |
72 | public: |
73 | size_t operator()(std::tuple<Ts...> const &val) const { |
74 | return TupleHasher<std::tuple_size_v<std::tuple<Ts...>> - 1, Ts...>{}(val); |
75 | }; |
76 | }; |
77 | |
78 | } // namespace taichi::hashing |
79 | |