57
57
#else
58
58
#include < iostream>
59
59
#define TSL_RH_THROW_OR_TERMINATE (ex, msg ) \
60
- do { \
61
- std::cerr << msg << std::endl; \
62
- std::terminate (); \
63
- } while (0 )
60
+ do { \
61
+ std::cerr << msg << std::endl; \
62
+ std::terminate (); \
63
+ } while (0 )
64
64
#endif
65
65
#endif
66
66
@@ -82,95 +82,96 @@ namespace rh {
82
82
*/
83
83
template <std::size_t GrowthFactor>
84
84
class power_of_two_growth_policy {
85
- public:
86
- /* *
87
- * Called on the hash table creation and on rehash. The number of buckets for
88
- * the table is passed in parameter. This number is a minimum, the policy may
89
- * update this value with a higher value if needed (but not lower).
90
- *
91
- * If 0 is given, min_bucket_count_in_out must still be 0 after the policy
92
- * creation and bucket_for_hash must always return 0 in this case.
93
- */
94
- explicit power_of_two_growth_policy (std::size_t & min_bucket_count_in_out) {
95
- if (min_bucket_count_in_out > max_bucket_count ()) {
96
- TSL_RH_THROW_OR_TERMINATE (
97
- std::length_error, " The hash table exceeds its maximum size." );
85
+ public:
86
+ /* *
87
+ * Called on the hash table creation and on rehash. The number of buckets
88
+ * for the table is passed in parameter. This number is a minimum, the
89
+ * policy may update this value with a higher value if needed (but not
90
+ * lower).
91
+ *
92
+ * If 0 is given, min_bucket_count_in_out must still be 0 after the policy
93
+ * creation and bucket_for_hash must always return 0 in this case.
94
+ */
95
+ explicit power_of_two_growth_policy (std::size_t & min_bucket_count_in_out) {
96
+ if (min_bucket_count_in_out > max_bucket_count ()) {
97
+ TSL_RH_THROW_OR_TERMINATE (
98
+ std::length_error, " The hash table exceeds its maximum size." );
99
+ }
100
+
101
+ if (min_bucket_count_in_out > 0 ) {
102
+ min_bucket_count_in_out = round_up_to_power_of_two (
103
+ min_bucket_count_in_out);
104
+ m_mask = min_bucket_count_in_out - 1 ;
105
+ } else {
106
+ m_mask = 0 ;
107
+ }
98
108
}
99
109
100
- if (min_bucket_count_in_out > 0 ) {
101
- min_bucket_count_in_out =
102
- round_up_to_power_of_two (min_bucket_count_in_out);
103
- m_mask = min_bucket_count_in_out - 1 ;
104
- } else {
105
- m_mask = 0 ;
106
- }
107
- }
108
-
109
- /* *
110
- * Return the bucket [0, bucket_count()) to which the hash belongs.
111
- * If bucket_count() is 0, it must always return 0.
112
- */
113
- std::size_t bucket_for_hash (std::size_t hash) const noexcept {
114
- return hash & m_mask;
115
- }
116
-
117
- /* *
118
- * Return the number of buckets that should be used on next growth.
119
- */
120
- std::size_t next_bucket_count () const {
121
- if ((m_mask + 1 ) > max_bucket_count () / GrowthFactor) {
122
- TSL_RH_THROW_OR_TERMINATE (
123
- std::length_error, " The hash table exceeds its maximum size." );
110
+ /* *
111
+ * Return the bucket [0, bucket_count()) to which the hash belongs.
112
+ * If bucket_count() is 0, it must always return 0.
113
+ */
114
+ std::size_t bucket_for_hash (std::size_t hash) const noexcept {
115
+ return hash & m_mask;
124
116
}
125
117
126
- return (m_mask + 1 ) * GrowthFactor;
127
- }
128
-
129
- /* *
130
- * Return the maximum number of buckets supported by the policy.
131
- */
132
- std::size_t max_bucket_count () const {
133
- // Largest power of two.
134
- return (std::numeric_limits<std::size_t >::max () / 2 ) + 1 ;
135
- }
136
-
137
- /* *
138
- * Reset the growth policy as if it was created with a bucket count of 0.
139
- * After a clear, the policy must always return 0 when bucket_for_hash is
140
- * called.
141
- */
142
- void clear () noexcept {
143
- m_mask = 0 ;
144
- }
145
-
146
- private:
147
- static std::size_t round_up_to_power_of_two (std::size_t value) {
148
- if (is_power_of_two (value)) {
149
- return value;
118
+ /* *
119
+ * Return the number of buckets that should be used on next growth.
120
+ */
121
+ std::size_t next_bucket_count () const {
122
+ if ((m_mask + 1 ) > max_bucket_count () / GrowthFactor) {
123
+ TSL_RH_THROW_OR_TERMINATE (
124
+ std::length_error, " The hash table exceeds its maximum size." );
125
+ }
126
+
127
+ return (m_mask + 1 ) * GrowthFactor;
150
128
}
151
129
152
- if (value == 0 ) {
153
- return 1 ;
130
+ /* *
131
+ * Return the maximum number of buckets supported by the policy.
132
+ */
133
+ std::size_t max_bucket_count () const {
134
+ // Largest power of two.
135
+ return (std::numeric_limits<std::size_t >::max () / 2 ) + 1 ;
154
136
}
155
137
156
- --value;
157
- for (std::size_t i = 1 ; i < sizeof (std::size_t ) * CHAR_BIT; i *= 2 ) {
158
- value |= value >> i;
138
+ /* *
139
+ * Reset the growth policy as if it was created with a bucket count of 0.
140
+ * After a clear, the policy must always return 0 when bucket_for_hash is
141
+ * called.
142
+ */
143
+ void clear () noexcept {
144
+ m_mask = 0 ;
159
145
}
160
146
161
- return value + 1 ;
162
- }
147
+ private:
148
+ static std::size_t round_up_to_power_of_two (std::size_t value) {
149
+ if (is_power_of_two (value)) {
150
+ return value;
151
+ }
152
+
153
+ if (value == 0 ) {
154
+ return 1 ;
155
+ }
156
+
157
+ --value;
158
+ for (std::size_t i = 1 ; i < sizeof (std::size_t ) * CHAR_BIT; i *= 2 ) {
159
+ value |= value >> i;
160
+ }
163
161
164
- static constexpr bool is_power_of_two (std::size_t value) {
165
- return value != 0 && (value & (value - 1 )) == 0 ;
166
- }
162
+ return value + 1 ;
163
+ }
164
+
165
+ static constexpr bool is_power_of_two (std::size_t value) {
166
+ return value != 0 && (value & (value - 1 )) == 0 ;
167
+ }
167
168
168
- protected:
169
- static_assert (
170
- is_power_of_two (GrowthFactor) && GrowthFactor >= 2,
171
- "GrowthFactor must be a power of two >= 2.");
169
+ protected:
170
+ static_assert (
171
+ is_power_of_two (GrowthFactor) && GrowthFactor >= 2,
172
+ "GrowthFactor must be a power of two >= 2.");
172
173
173
- std::size_t m_mask;
174
+ std::size_t m_mask;
174
175
};
175
176
176
177
/* *
@@ -180,64 +181,65 @@ class power_of_two_growth_policy {
180
181
*/
181
182
template <class GrowthFactor = std::ratio<3 , 2 >>
182
183
class mod_growth_policy {
183
- public:
184
- explicit mod_growth_policy (std::size_t & min_bucket_count_in_out) {
185
- if (min_bucket_count_in_out > max_bucket_count ()) {
186
- TSL_RH_THROW_OR_TERMINATE (
187
- std::length_error, " The hash table exceeds its maximum size." );
184
+ public:
185
+ explicit mod_growth_policy (std::size_t & min_bucket_count_in_out) {
186
+ if (min_bucket_count_in_out > max_bucket_count ()) {
187
+ TSL_RH_THROW_OR_TERMINATE (
188
+ std::length_error, " The hash table exceeds its maximum size." );
189
+ }
190
+
191
+ if (min_bucket_count_in_out > 0 ) {
192
+ m_mod = min_bucket_count_in_out;
193
+ } else {
194
+ m_mod = 1 ;
195
+ }
188
196
}
189
197
190
- if (min_bucket_count_in_out > 0 ) {
191
- m_mod = min_bucket_count_in_out;
192
- } else {
193
- m_mod = 1 ;
198
+ std::size_t bucket_for_hash (std::size_t hash) const noexcept {
199
+ return hash % m_mod;
194
200
}
195
- }
196
201
197
- std::size_t bucket_for_hash (std::size_t hash) const noexcept {
198
- return hash % m_mod;
199
- }
200
-
201
- std::size_t next_bucket_count () const {
202
- if (m_mod == max_bucket_count ()) {
203
- TSL_RH_THROW_OR_TERMINATE (
204
- std::length_error, " The hash table exceeds its maximum size." );
202
+ std::size_t next_bucket_count () const {
203
+ if (m_mod == max_bucket_count ()) {
204
+ TSL_RH_THROW_OR_TERMINATE (
205
+ std::length_error, " The hash table exceeds its maximum size." );
206
+ }
207
+
208
+ const double next_bucket_count = std::ceil (
209
+ double (m_mod) * REHASH_SIZE_MULTIPLICATION_FACTOR);
210
+ if (!std::isnormal (next_bucket_count)) {
211
+ TSL_RH_THROW_OR_TERMINATE (
212
+ std::length_error, " The hash table exceeds its maximum size." );
213
+ }
214
+
215
+ if (next_bucket_count > double (max_bucket_count ())) {
216
+ return max_bucket_count ();
217
+ } else {
218
+ return std::size_t (next_bucket_count);
219
+ }
205
220
}
206
221
207
- const double next_bucket_count =
208
- std::ceil (double (m_mod) * REHASH_SIZE_MULTIPLICATION_FACTOR);
209
- if (!std::isnormal (next_bucket_count)) {
210
- TSL_RH_THROW_OR_TERMINATE (
211
- std::length_error, " The hash table exceeds its maximum size." );
222
+ std::size_t max_bucket_count () const {
223
+ return MAX_BUCKET_COUNT;
212
224
}
213
225
214
- if (next_bucket_count > double (max_bucket_count ())) {
215
- return max_bucket_count ();
216
- } else {
217
- return std::size_t (next_bucket_count);
226
+ void clear () noexcept {
227
+ m_mod = 1 ;
218
228
}
219
- }
220
-
221
- std::size_t max_bucket_count () const {
222
- return MAX_BUCKET_COUNT;
223
- }
224
-
225
- void clear () noexcept {
226
- m_mod = 1 ;
227
- }
228
229
229
- private:
230
- static constexpr double REHASH_SIZE_MULTIPLICATION_FACTOR =
231
- 1.0 * GrowthFactor::num / GrowthFactor::den;
232
- static const std::size_t MAX_BUCKET_COUNT = std::size_t (double (
233
- std::numeric_limits<std::size_t >::max() /
234
- REHASH_SIZE_MULTIPLICATION_FACTOR));
230
+ private:
231
+ static constexpr double
232
+ REHASH_SIZE_MULTIPLICATION_FACTOR = 1.0 * GrowthFactor::num /
233
+ GrowthFactor::den;
234
+ static const std::size_t MAX_BUCKET_COUNT = std::size_t (double (
235
+ std::numeric_limits<std::size_t >::max() /
236
+ REHASH_SIZE_MULTIPLICATION_FACTOR));
235
237
236
- static_assert (
237
- REHASH_SIZE_MULTIPLICATION_FACTOR >= 1.1 ,
238
- " Growth factor should be >= 1.1." );
238
+ static_assert (
239
+ REHASH_SIZE_MULTIPLICATION_FACTOR >= 1.1 ,
240
+ " Growth factor should be >= 1.1." );
239
241
240
- std::size_t m_mod;
242
+ std::size_t m_mod;
241
243
};
242
244
243
245
namespace detail {
@@ -310,7 +312,7 @@ static constexpr const std::array<std::size_t, TSL_RH_NB_PRIMES> PRIMES = {{
310
312
311
313
template <unsigned int IPrime>
312
314
static constexpr std::size_t mod (std::size_t hash) {
313
- return hash % PRIMES[IPrime];
315
+ return hash % PRIMES[IPrime];
314
316
}
315
317
316
318
// MOD_PRIME[iprime](hash) returns hash % PRIMES[iprime]. This table allows for
@@ -364,51 +366,53 @@ static constexpr const std::
364
366
* * 5' in a 64 bits environment.
365
367
*/
366
368
class prime_growth_policy {
367
- public:
368
- explicit prime_growth_policy (std::size_t & min_bucket_count_in_out) {
369
- auto it_prime = std::lower_bound (
370
- detail::PRIMES.begin (), detail::PRIMES.end (), min_bucket_count_in_out);
371
- if (it_prime == detail::PRIMES.end ()) {
372
- TSL_RH_THROW_OR_TERMINATE (
373
- std::length_error, " The hash table exceeds its maximum size." );
369
+ public:
370
+ explicit prime_growth_policy (std::size_t & min_bucket_count_in_out) {
371
+ auto it_prime = std::lower_bound (
372
+ detail::PRIMES.begin (),
373
+ detail::PRIMES.end (),
374
+ min_bucket_count_in_out);
375
+ if (it_prime == detail::PRIMES.end ()) {
376
+ TSL_RH_THROW_OR_TERMINATE (
377
+ std::length_error, " The hash table exceeds its maximum size." );
378
+ }
379
+
380
+ m_iprime = static_cast <unsigned int >(
381
+ std::distance (detail::PRIMES.begin (), it_prime));
382
+ if (min_bucket_count_in_out > 0 ) {
383
+ min_bucket_count_in_out = *it_prime;
384
+ } else {
385
+ min_bucket_count_in_out = 0 ;
386
+ }
374
387
}
375
388
376
- m_iprime = static_cast <unsigned int >(
377
- std::distance (detail::PRIMES.begin (), it_prime));
378
- if (min_bucket_count_in_out > 0 ) {
379
- min_bucket_count_in_out = *it_prime;
380
- } else {
381
- min_bucket_count_in_out = 0 ;
389
+ std::size_t bucket_for_hash (std::size_t hash) const noexcept {
390
+ return detail::MOD_PRIME[m_iprime](hash);
382
391
}
383
- }
384
392
385
- std::size_t bucket_for_hash (std::size_t hash) const noexcept {
386
- return detail::MOD_PRIME[m_iprime](hash);
387
- }
393
+ std::size_t next_bucket_count () const {
394
+ if (m_iprime + 1 >= detail::PRIMES.size ()) {
395
+ TSL_RH_THROW_OR_TERMINATE (
396
+ std::length_error, " The hash table exceeds its maximum size." );
397
+ }
388
398
389
- std::size_t next_bucket_count () const {
390
- if (m_iprime + 1 >= detail::PRIMES.size ()) {
391
- TSL_RH_THROW_OR_TERMINATE (
392
- std::length_error, " The hash table exceeds its maximum size." );
399
+ return detail::PRIMES[m_iprime + 1 ];
393
400
}
394
401
395
- return detail::PRIMES[m_iprime + 1 ];
396
- }
397
-
398
- std::size_t max_bucket_count () const {
399
- return detail::PRIMES.back ();
400
- }
402
+ std::size_t max_bucket_count () const {
403
+ return detail::PRIMES.back ();
404
+ }
401
405
402
- void clear () noexcept {
403
- m_iprime = 0 ;
404
- }
406
+ void clear () noexcept {
407
+ m_iprime = 0 ;
408
+ }
405
409
406
- private:
407
- unsigned int m_iprime;
410
+ private:
411
+ unsigned int m_iprime;
408
412
409
- static_assert (
410
- std::numeric_limits<decltype(m_iprime)>::max() >= detail::PRIMES.size(),
411
- " The type of m_iprime is not big enough." );
413
+ static_assert (
414
+ std::numeric_limits<decltype(m_iprime)>::max() >= detail::PRIMES.size(),
415
+ " The type of m_iprime is not big enough." );
412
416
};
413
417
414
418
} // namespace rh
0 commit comments