gem5  [DEVELOP-FOR-23.0]
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
hash_helpers.hh
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2023 Arteris, Inc. and its applicable licensors and
3  * affiliates.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are
8  * met: redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer;
10  * redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution;
13  * neither the name of the copyright holders 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
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #ifndef BASE_STL_HELPERS_HASH_HELPERS_HH
31 #define BASE_STL_HELPERS_HASH_HELPERS_HH
32 
33 #include <functional>
34 #include <numeric>
35 #include <tuple>
36 #include <type_traits>
37 #include <unordered_map>
38 #include <unordered_set>
39 #include <utility>
40 
41 #include "base/type_traits.hh"
42 
43 #include <functional>
44 #include <tuple>
45 #include <type_traits>
46 #include <utility>
47 
49 {
50 
51 namespace hash_impl
52 {
53 // The math in hash_combine and hash_refine functions are inspired from Jon
54 // Maiga's work hosted at https://github.com/jonmaiga/mx3 under the CC0
55 // license. It makes use of two components: a stream mixer for combination and
56 // a scalar mixer for refinement.
57 // The stream mixer is a lighter weight function with lower entropy used to
58 // combine hash values while the scalar mixer is a high entropy function that
59 // increases the overall hashing quality.
60 // The tradeoff of not using hash_refine has not been thoroughtly tested and is
61 // only done based on Maiga's return on exprerience.
62 static constexpr uint64_t C = 0xbea225f9eb34556d;
63 template<typename... T>
64 constexpr size_t hash_combine(T... hashes) {
65  // gcc reports unused variable if T is the empty pack
66  [[maybe_unused]] auto combine = [](uint64_t a, uint64_t b) {
67  b *= C;
68  b ^= b >> 39;
69  a += b * C;
70  a *= C;
71  return a;
72  };
73  // The following couple of expressions is equivalent to a hypothetical
74  // functional "acc = hashes.fold_left(0, combine)". The comma operator
75  // effectively repeats the expression in the second level parenthesis for
76  // each argument in the parameter pack hashes, in order. Thus, final value
77  // of acc is the recursive combination of all hashes.
78  uint64_t acc{0};
79  ((acc = combine(acc, static_cast<uint64_t>(hashes))), ...);
80  return static_cast<size_t>(acc);
81 }
82 
83 constexpr size_t hash_refine(size_t x) {
84  x ^= x >> 32;
85  x *= C;
86  x ^= x >> 29;
87  x *= C;
88  x ^= x >> 32;
89  x *= C;
90  x ^= x >> 29;
91  return static_cast<size_t>(x);
92 }
93 
94 // SFINAE-enabled hash functor
95 template<typename T, typename = void>
96 struct hash;
97 
98 // Reuse std::hash whenever possible
99 template<typename T>
100 struct hash<T, std::enable_if_t<is_std_hash_enabled_v<T>>>: std::hash<T>
101 {};
102 
103 // Enable type deduction for hash object construction
104 template<typename T>
105 constexpr auto make_hash_for(const T&) {
106  return hash<T>();
107 }
108 
109 // Compute a hash without the hassle of constructing a hash functor
110 template<typename T>
111 constexpr auto hash_value(const T& v) {
112  return make_hash_for(v)(v);
113 }
114 
115 // Hash for tuple
116 template<typename... T>
117 struct hash<std::tuple<T...>>
118 {
119  constexpr size_t operator()(const std::tuple<T...>& t) const {
120  if constexpr (sizeof...(T) == 0) {
121  return 0;
122  } else {
123  return std::apply([](const auto&... e){
124  return hash_refine(hash_combine(hash_value(e)...));
125  }, t);
126  }
127  }
128 };
129 
130 // Hash for pairs (based on hash for 2-uple)
131 template<typename T, typename U>
132 struct hash<std::pair<T, U>>
133 {
134  constexpr size_t operator()(const std::pair<T, U>& p) const {
135  return hash_value(std::tie(p.first, p.second));
136  }
137 };
138 
139 // Hash for any iterable of stl_helpers::hash-enabled types.
140 template<typename T>
141 struct hash<T, std::enable_if_t<
142  !is_std_hash_enabled_v<T> && is_iterable_v<T>>>
143 {
144  constexpr size_t operator()(const T& t) const {
145  auto b = begin(t);
146  auto e = end(t);
147  if (b == e) return 0;
148  // Equivalent to hypothetical functional style
149  // return t.map(hash_value).reduce(hash_combine)
150  auto h = std::accumulate(next(b), e, hash_value(*b),
151  [](const auto& acc, const auto& val) {
152  return hash_combine(acc, hash_value(val));
153  });
154  return hash_refine(h);
155  }
156 };
157 
158 template<typename, typename = void>
159 constexpr bool is_hash_enabled = false;
160 
161 template <typename T>
162 constexpr bool is_hash_enabled<T,
163  std::void_t<decltype(hash<T>()(std::declval<T>()))>> = true;
164 
165 } // namespace hash_impl
166 
167 // Export useful hash_impl functions
168 using hash_impl::hash;
172 
173 /*
174  * Provide unordered_map and unordered_set with stl_helpers::hash functions.
175  * These aliases enable clean use of stl_helpers::hash as default Hash template
176  * parameter. The reason for not using an alias is that template type aliases
177  * with default template arguments do not behave well with template parameter
178  * deductions in certain situations. One must remember that std::unordered_X
179  * is not a polymorphic type and as such, gem5::stl_helpers::unordered_X shall
180  * never be owned as a std::unordered_X.
181  */
182 template<
183  typename Key,
184  typename T,
185  typename Hash = hash<Key>,
186  typename KeyEqual = std::equal_to<Key>,
187  typename Allocator = std::allocator< std::pair<const Key, T> >>
188 struct unordered_map: std::unordered_map<Key, T, Hash, KeyEqual, Allocator>
189 {};
190 
191 template<
192  typename Key,
193  typename Hash = hash<Key>,
194  typename KeyEqual = std::equal_to<Key>,
195  typename Allocator = std::allocator<Key>>
196 struct unordered_set: std::unordered_set<Key, Hash, KeyEqual, Allocator>
197 {};
198 
199 } // namespace gem5::stl_helpers
200 
201 #endif // BASE_STL_HELPERS_HASH_HELPERS_HH
gem5::stl_helpers::unordered_set
Definition: hash_helpers.hh:196
gem5::stl_helpers::hash_impl::hash< std::tuple< T... > >::operator()
constexpr size_t operator()(const std::tuple< T... > &t) const
Definition: hash_helpers.hh:119
gem5::stl_helpers::hash_impl::hash_combine
constexpr size_t hash_combine(T... hashes)
Definition: hash_helpers.hh:64
gem5::stl_helpers::unordered_map
Definition: hash_helpers.hh:188
gem5::stl_helpers::hash_impl::make_hash_for
constexpr auto make_hash_for(const T &)
Definition: hash_helpers.hh:105
gem5::ArmISA::e
Bitfield< 9 > e
Definition: misc_types.hh:65
gem5::X86ISA::val
Bitfield< 63 > val
Definition: misc.hh:776
gem5::ArmISA::a
Bitfield< 8 > a
Definition: misc_types.hh:66
gem5::stl_helpers::hash_impl::hash< T, std::enable_if_t< !is_std_hash_enabled_v< T > &&is_iterable_v< T > > >::operator()
constexpr size_t operator()(const T &t) const
Definition: hash_helpers.hh:144
gem5::stl_helpers::hash_impl::C
static constexpr uint64_t C
Definition: hash_helpers.hh:62
gem5::stl_helpers::hash_impl::is_hash_enabled
constexpr bool is_hash_enabled
Definition: hash_helpers.hh:159
gem5::ArmISA::b
Bitfield< 7 > b
Definition: misc_types.hh:438
gem5::VegaISA::t
Bitfield< 51 > t
Definition: pagetable.hh:56
gem5::VegaISA::p
Bitfield< 54 > p
Definition: pagetable.hh:70
gem5::VegaISA::x
Bitfield< 4 > x
Definition: pagetable.hh:61
gem5::stl_helpers::hash_impl::hash_refine
constexpr size_t hash_refine(size_t x)
Definition: hash_helpers.hh:83
std::pair
STL pair class.
Definition: stl.hh:58
gem5::stl_helpers::hash_impl::hash_value
constexpr auto hash_value(const T &v)
Definition: hash_helpers.hh:111
gem5::VegaISA::v
Bitfield< 0 > v
Definition: pagetable.hh:65
gem5::stl_helpers::hash_impl::hash< std::pair< T, U > >::operator()
constexpr size_t operator()(const std::pair< T, U > &p) const
Definition: hash_helpers.hh:134
gem5::stl_helpers::hash_impl::hash
Definition: hash_helpers.hh:96
std
Overload hash function for BasicBlockRange type.
Definition: misc.hh:2909
type_traits.hh
gem5::stl_helpers
Definition: hash_helpers.hh:48

Generated on Sun Jul 30 2023 01:56:51 for gem5 by doxygen 1.8.17