/src/s2geometry/src/s2/util/gtl/hashtable_common.h
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright 2010 Google Inc. All Rights Reserved. |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | | // you may not use this file except in compliance with the License. |
5 | | // You may obtain a copy of the License at |
6 | | // |
7 | | // http://www.apache.org/licenses/LICENSE-2.0 |
8 | | // |
9 | | // Unless required by applicable law or agreed to in writing, software |
10 | | // distributed under the License is distributed on an "AS-IS" BASIS, |
11 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | | // See the License for the specific language governing permissions and |
13 | | // limitations under the License. |
14 | | // |
15 | | |
16 | | // All rights reserved. |
17 | | // |
18 | | // Redistribution and use in source and binary forms, with or without |
19 | | // modification, are permitted provided that the following conditions are |
20 | | // met: |
21 | | // |
22 | | // * Redistributions of source code must retain the above copyright |
23 | | // notice, this list of conditions and the following disclaimer. |
24 | | // * Redistributions in binary form must reproduce the above |
25 | | // copyright notice, this list of conditions and the following disclaimer |
26 | | // in the documentation and/or other materials provided with the |
27 | | // distribution. |
28 | | // * Neither the name of Google Inc. nor the names of its |
29 | | // contributors may be used to endorse or promote products derived from |
30 | | // this software without specific prior written permission. |
31 | | // |
32 | | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
33 | | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
34 | | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
35 | | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
36 | | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
37 | | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
38 | | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
39 | | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
40 | | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
41 | | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
42 | | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
43 | | |
44 | | // --- |
45 | | |
46 | | #ifndef S2_UTIL_GTL_HASHTABLE_COMMON_H_ |
47 | | #define S2_UTIL_GTL_HASHTABLE_COMMON_H_ |
48 | | |
49 | | #include <cassert> |
50 | | #include <cstddef> |
51 | | |
52 | | #include <algorithm> |
53 | | |
54 | | #include <stdexcept> // For length_error |
55 | | |
56 | | // Settings contains parameters for growing and shrinking the table. |
57 | | // It also packages zero-size functor (ie. hasher). One invariant |
58 | | // enforced in enlarge_size() is that we never allow all slots |
59 | | // occupied. (This is unlikely to matter to users, because using |
60 | | // a load near 1 is slow and not recommended. It allows other code |
61 | | // to assume there is at least one empty bucket.) |
62 | | // |
63 | | // It does some munging of the hash value in cases where we think |
64 | | // (fear) the original hash function might not be very good. In |
65 | | // particular, the default hash of pointers is the identity hash, |
66 | | // so probably all the low bits are 0. We identify when we think |
67 | | // we're hashing a pointer, and chop off the low bits. Note this |
68 | | // isn't perfect: even when the key is a pointer, we can't tell |
69 | | // for sure that the hash is the identity hash. If it's not, this |
70 | | // is needless work (and possibly, though not likely, harmful). |
71 | | |
72 | | template <typename Key, typename HashFunc, typename SizeType, |
73 | | int HT_MIN_BUCKETS> |
74 | | class sh_hashtable_settings : public HashFunc { |
75 | | public: |
76 | | typedef Key key_type; |
77 | | typedef HashFunc hasher; |
78 | | typedef SizeType size_type; |
79 | | |
80 | | public: |
81 | | sh_hashtable_settings(const hasher& hf, const float ht_occupancy_flt, |
82 | | const float ht_empty_flt) |
83 | 0 | : hasher(hf), |
84 | 0 | enlarge_threshold_(0), |
85 | 0 | shrink_threshold_(0), |
86 | 0 | consider_shrink_(false), |
87 | 0 | use_empty_(false), |
88 | 0 | use_deleted_(false), |
89 | 0 | num_ht_copies_(0) { |
90 | 0 | set_enlarge_factor(ht_occupancy_flt); |
91 | 0 | set_shrink_factor(ht_empty_flt); |
92 | 0 | } |
93 | | |
94 | | template <class K> |
95 | 0 | size_type hash(const K& v) const { |
96 | | // We munge the hash value when we don't trust hasher::operator(). It is |
97 | | // very important that we use hash_munger<Key> instead of hash_munger<K>. |
98 | | // Within a given hashtable, all hash values must be munged in the same way. |
99 | 0 | return hash_munger<Key>::MungedHash(hasher::operator()(v)); |
100 | 0 | } |
101 | | |
102 | 0 | float enlarge_factor() const { return enlarge_factor_; } |
103 | 0 | void set_enlarge_factor(float f) { enlarge_factor_ = f; } |
104 | 0 | float shrink_factor() const { return shrink_factor_; } |
105 | 0 | void set_shrink_factor(float f) { shrink_factor_ = f; } |
106 | | |
107 | 0 | size_type enlarge_threshold() const { return enlarge_threshold_; } |
108 | 0 | void set_enlarge_threshold(size_type t) { enlarge_threshold_ = t; } |
109 | 0 | size_type shrink_threshold() const { return shrink_threshold_; } |
110 | 0 | void set_shrink_threshold(size_type t) { shrink_threshold_ = t; } |
111 | | |
112 | 0 | size_type enlarge_size(size_type x) const { |
113 | 0 | return std::min<size_type>(x - 1, x * enlarge_factor_); |
114 | 0 | } |
115 | 0 | size_type shrink_size(size_type x) const { |
116 | 0 | return static_cast<size_type>(x * shrink_factor_); |
117 | 0 | } |
118 | | |
119 | 0 | bool consider_shrink() const { return consider_shrink_; } |
120 | 0 | void set_consider_shrink(bool t) { consider_shrink_ = t; } |
121 | | |
122 | 0 | bool use_empty() const { return use_empty_; } |
123 | 0 | void set_use_empty(bool t) { use_empty_ = t; } |
124 | | |
125 | 0 | bool use_deleted() const { return use_deleted_; } |
126 | 0 | void set_use_deleted(bool t) { use_deleted_ = t; } |
127 | | |
128 | | size_type num_ht_copies() const { |
129 | | return static_cast<size_type>(num_ht_copies_); |
130 | | } |
131 | 0 | void inc_num_ht_copies() { ++num_ht_copies_; } |
132 | | |
133 | | // Reset the enlarge and shrink thresholds |
134 | 0 | void reset_thresholds(size_type num_buckets) { |
135 | 0 | set_enlarge_threshold(enlarge_size(num_buckets)); |
136 | 0 | set_shrink_threshold(shrink_size(num_buckets)); |
137 | | // whatever caused us to reset already considered |
138 | 0 | set_consider_shrink(false); |
139 | 0 | } |
140 | | |
141 | | // Caller is responsible for calling reset_threshold right after |
142 | | // set_resizing_parameters. |
143 | | void set_resizing_parameters(float shrink, float grow) { |
144 | | assert(shrink >= 0.0); |
145 | | assert(grow <= 1.0); |
146 | | if (shrink > grow / 2.0f) |
147 | | shrink = grow / 2.0f; // otherwise we thrash hashtable size |
148 | | set_shrink_factor(shrink); |
149 | | set_enlarge_factor(grow); |
150 | | } |
151 | | |
152 | | // This is the smallest size a hashtable can be without being too crowded. |
153 | | // If you like, you can give a min #buckets as well as a min #elts. |
154 | | // This is guaranteed to return a power of two. |
155 | 0 | size_type min_buckets(size_type num_elts, size_type min_buckets_wanted) { |
156 | 0 | float enlarge = enlarge_factor(); |
157 | 0 | size_type sz = HT_MIN_BUCKETS; // min buckets allowed |
158 | 0 | while (sz < min_buckets_wanted || |
159 | 0 | num_elts >= static_cast<size_type>(sz * enlarge)) { |
160 | | // This just prevents overflowing size_type, since sz can exceed |
161 | | // max_size() here. |
162 | 0 | if (static_cast<size_type>(sz * 2) < sz) { |
163 | 0 | throw std::length_error("resize overflow"); // protect against overflow |
164 | 0 | } |
165 | 0 | sz *= 2; |
166 | 0 | } |
167 | 0 | return sz; |
168 | 0 | } |
169 | | |
170 | | private: |
171 | | template <class HashKey> |
172 | | class hash_munger { |
173 | | public: |
174 | 0 | static size_t MungedHash(size_t hash) { return hash; } |
175 | | }; |
176 | | // This matches when the hashtable key is a pointer. |
177 | | template <class HashKey> |
178 | | class hash_munger<HashKey*> { |
179 | | public: |
180 | | static size_t MungedHash(size_t hash) { |
181 | | // TODO(user): consider rotating instead: |
182 | | // static const int shift = (sizeof(void *) == 4) ? 2 : 3; |
183 | | // return (hash << (sizeof(hash) * 8) - shift)) | (hash >> shift); |
184 | | // This matters if we ever change sparse/dense_hash_* to compare |
185 | | // hashes before comparing actual values. It's speedy on x86. |
186 | | return hash / sizeof(void*); // get rid of known-0 bits |
187 | | } |
188 | | }; |
189 | | |
190 | | size_type enlarge_threshold_; // table.size() * enlarge_factor |
191 | | size_type shrink_threshold_; // table.size() * shrink_factor |
192 | | float enlarge_factor_; // how full before resize |
193 | | float shrink_factor_; // how empty before resize |
194 | | // consider_shrink=true if we should try to shrink before next insert |
195 | | bool consider_shrink_; |
196 | | bool use_empty_; // used only by densehashtable, not sparsehashtable |
197 | | bool use_deleted_; // false until delkey has been set |
198 | | // num_ht_copies is a counter incremented every Copy/Move |
199 | | unsigned int num_ht_copies_; |
200 | | }; |
201 | | |
202 | | // This traits class checks whether T::is_transparent exists and names a type. |
203 | | // |
204 | | // struct Foo { using is_transparent = void; }; |
205 | | // struct Bar {}; |
206 | | // static_assert(sh_is_transparent<Foo>::value, "Foo is transparent."); |
207 | | // staitc_assert(!sh_is_transparent<Bar>::value, "Bar is not transparent."); |
208 | | template <class T> |
209 | | struct sh_is_transparent { |
210 | | private: |
211 | | struct No {}; |
212 | | struct Yes { |
213 | | No x[2]; |
214 | | }; |
215 | | |
216 | | template <class U> |
217 | | static Yes Test(typename U::is_transparent*); |
218 | | template <class U> |
219 | | static No Test(...); |
220 | | |
221 | | public: |
222 | | enum { value = sizeof(Test<T>(nullptr)) == sizeof(Yes) }; |
223 | | }; |
224 | | |
225 | | |
226 | | #endif // S2_UTIL_GTL_HASHTABLE_COMMON_H_ |