1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
|
#pragma once
#include <functional>
#include <vector>
namespace torch {
// NOTE: hash_combine is based on implementation from Boost
//
// Boost Software License - Version 1.0 - August 17th, 2003
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
//
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
inline size_t hash_combine(size_t seed, size_t value) {
return seed ^ (value + 0x9e3779b9 + (seed << 6) + (seed >> 2));
}
////////////////////////////////////////////////////////////////////////////////
// torch::hash implementation
////////////////////////////////////////////////////////////////////////////////
namespace _hash_detail {
// Use template argument deduction to shorten calls to torch::hash
template<typename T>
size_t simple_get_hash(const T& o);
template<typename T, typename V>
using type_if_not_enum = typename std::enable_if<!std::is_enum<T>::value, V>::type;
// Use SFINAE to dispatch to std::hash if possible, cast enum types to int automatically,
// and fall back to T::hash otherwise.
// NOTE: C++14 added support for hashing enum types to the standard, and some compilers
// implement it even when C++14 flags aren't specified. This is why we have to disable
// this overload if T is an enum type (and use the one below in this case).
template<typename T>
auto dispatch_hash(const T& o) -> decltype(std::hash<T>()(o), type_if_not_enum<T, size_t>()) {
return std::hash<T>()(o);
}
template<typename T>
typename std::enable_if<std::is_enum<T>::value, size_t>::type dispatch_hash(const T& o) {
using R = typename std::underlying_type<T>::type;
return std::hash<R>()(static_cast<R>(o));
}
template<typename T>
auto dispatch_hash(const T& o) -> decltype(T::hash(o), size_t()) {
return T::hash(o);
}
} // namespace _hash_detail
// Hasher struct
template<typename T>
struct hash {
size_t operator()(const T& o) const {
return _hash_detail::dispatch_hash(o);
};
};
// Specialization for std::tuple
template<typename... Types>
struct hash<std::tuple<Types...>> {
template<size_t idx, typename... Ts>
struct tuple_hash {
size_t operator()(const std::tuple<Ts...>& t) const {
return hash_combine(_hash_detail::simple_get_hash(std::get<idx>(t)),
tuple_hash<idx-1, Ts...>()(t));
}
};
template<typename... Ts>
struct tuple_hash<0, Ts...> {
size_t operator()(const std::tuple<Ts...>& t) const {
return _hash_detail::simple_get_hash(std::get<0>(t));
}
};
size_t operator()(const std::tuple<Types...>& t) const {
return tuple_hash<sizeof...(Types)-1, Types...>()(t);
}
};
// Specialization for std::vector
template<typename T>
struct hash<std::vector<T>> {
size_t operator()(const std::vector<T>& v) const {
size_t seed = 0;
for (const auto & elem : v) {
seed = hash_combine(seed, _hash_detail::simple_get_hash(elem));
}
return seed;
}
};
namespace _hash_detail {
template<typename T>
size_t simple_get_hash(const T& o) {
return torch::hash<T>()(o);
}
} // namespace _hash_detail
// Use this function to actually hash multiple things in one line.
// Dispatches to torch::hash, so it can hash containers.
// Example:
//
// static size_t hash(const MyStruct& s) {
// return get_hash(s.member1, s.member2, s.member3);
// }
template<typename... Types>
size_t get_hash(const Types&... args) {
return torch::hash<decltype(std::tie(args...))>()(std::tie(args...));
}
} // namespace torch
|