robin_growth_policy.h
Go to the documentation of this file.
1 
24 #ifndef TSL_ROBIN_GROWTH_POLICY_H
25 #define TSL_ROBIN_GROWTH_POLICY_H
26 
27 #include <algorithm>
28 #include <array>
29 #include <climits>
30 #include <cmath>
31 #include <cstddef>
32 #include <cstdint>
33 #include <iterator>
34 #include <limits>
35 #include <ratio>
36 #include <stdexcept>
37 
38 // A change of the major version indicates an API and/or ABI break (change of
39 // in-memory layout of the data structure)
40 #define TSL_RH_VERSION_MAJOR 1
41 // A change of the minor version indicates the addition of a feature without
42 // impact on the API/ABI
43 #define TSL_RH_VERSION_MINOR 3
44 // A change of the patch version indicates a bugfix without additional
45 // functionality
46 #define TSL_RH_VERSION_PATCH 0
47 
48 #ifdef TSL_DEBUG
49 #define tsl_rh_assert(expr) assert(expr)
50 #else
51 #define tsl_rh_assert(expr) (static_cast<void>(0))
52 #endif
53 
58 #if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || \
59  (defined(_MSC_VER) && defined(_CPPUNWIND))) && \
60  !defined(TSL_NO_EXCEPTIONS)
61 #define TSL_RH_THROW_OR_TERMINATE(ex, msg) throw ex(msg)
62 #else
63 #define TSL_RH_NO_EXCEPTIONS
64 #ifdef TSL_DEBUG
65 #include <iostream>
66 #define TSL_RH_THROW_OR_TERMINATE(ex, msg) \
67  do { \
68  std::cerr << msg << std::endl; \
69  std::terminate(); \
70  } while (0)
71 #else
72 #define TSL_RH_THROW_OR_TERMINATE(ex, msg) std::terminate()
73 #endif
74 #endif
75 
76 #if defined(__GNUC__) || defined(__clang__)
77 #define TSL_RH_LIKELY(exp) (__builtin_expect(!!(exp), true))
78 #else
79 #define TSL_RH_LIKELY(exp) (exp)
80 #endif
81 
82 #define TSL_RH_UNUSED(x) static_cast<void>(x)
83 
84 namespace tsl {
85 namespace rh {
86 
94 template <std::size_t GrowthFactor>
96  public:
105  explicit power_of_two_growth_policy(std::size_t& min_bucket_count_in_out) {
106  if (min_bucket_count_in_out > max_bucket_count()) {
107  TSL_RH_THROW_OR_TERMINATE(std::length_error,
108  "The hash table exceeds its maximum size.");
109  }
110 
111  if (min_bucket_count_in_out > 0) {
112  min_bucket_count_in_out =
113  round_up_to_power_of_two(min_bucket_count_in_out);
114  m_mask = min_bucket_count_in_out - 1;
115  } else {
116  m_mask = 0;
117  }
118  }
119 
124  std::size_t bucket_for_hash(std::size_t hash) const noexcept {
125  return hash & m_mask;
126  }
127 
131  std::size_t next_bucket_count() const {
132  if ((m_mask + 1) > max_bucket_count() / GrowthFactor) {
133  TSL_RH_THROW_OR_TERMINATE(std::length_error,
134  "The hash table exceeds its maximum size.");
135  }
136 
137  return (m_mask + 1) * GrowthFactor;
138  }
139 
143  std::size_t max_bucket_count() const {
144  // Largest power of two.
145  return (std::numeric_limits<std::size_t>::max() / 2) + 1;
146  }
147 
153  void clear() noexcept { m_mask = 0; }
154 
155  private:
156  static std::size_t round_up_to_power_of_two(std::size_t value) {
157  if (is_power_of_two(value)) {
158  return value;
159  }
160 
161  if (value == 0) {
162  return 1;
163  }
164 
165  --value;
166  for (std::size_t i = 1; i < sizeof(std::size_t) * CHAR_BIT; i *= 2) {
167  value |= value >> i;
168  }
169 
170  return value + 1;
171  }
172 
173  static constexpr bool is_power_of_two(std::size_t value) {
174  return value != 0 && (value & (value - 1)) == 0;
175  }
176 
177  protected:
178  static_assert(is_power_of_two(GrowthFactor) && GrowthFactor >= 2,
179  "GrowthFactor must be a power of two >= 2.");
180 
181  std::size_t m_mask;
182 };
183 
189 template <class GrowthFactor = std::ratio<3, 2>>
191  public:
192  explicit mod_growth_policy(std::size_t& min_bucket_count_in_out) {
193  if (min_bucket_count_in_out > max_bucket_count()) {
194  TSL_RH_THROW_OR_TERMINATE(std::length_error,
195  "The hash table exceeds its maximum size.");
196  }
197 
198  if (min_bucket_count_in_out > 0) {
199  m_mod = min_bucket_count_in_out;
200  } else {
201  m_mod = 1;
202  }
203  }
204 
205  std::size_t bucket_for_hash(std::size_t hash) const noexcept {
206  return hash % m_mod;
207  }
208 
209  std::size_t next_bucket_count() const {
210  if (m_mod == max_bucket_count()) {
211  TSL_RH_THROW_OR_TERMINATE(std::length_error,
212  "The hash table exceeds its maximum size.");
213  }
214 
215  const double next_bucket_count =
216  std::ceil(double(m_mod) * REHASH_SIZE_MULTIPLICATION_FACTOR);
217  if (!std::isnormal(next_bucket_count)) {
218  TSL_RH_THROW_OR_TERMINATE(std::length_error,
219  "The hash table exceeds its maximum size.");
220  }
221 
222  if (next_bucket_count > double(max_bucket_count())) {
223  return max_bucket_count();
224  } else {
225  return std::size_t(next_bucket_count);
226  }
227  }
228 
229  std::size_t max_bucket_count() const { return MAX_BUCKET_COUNT; }
230 
231  void clear() noexcept { m_mod = 1; }
232 
233  private:
234  static constexpr double REHASH_SIZE_MULTIPLICATION_FACTOR =
235  1.0 * GrowthFactor::num / GrowthFactor::den;
236  static const std::size_t MAX_BUCKET_COUNT =
237  std::size_t(double(std::numeric_limits<std::size_t>::max() /
239 
240  static_assert(REHASH_SIZE_MULTIPLICATION_FACTOR >= 1.1,
241  "Growth factor should be >= 1.1.");
242 
243  std::size_t m_mod;
244 };
245 
246 namespace detail {
247 
248 #if SIZE_MAX >= ULLONG_MAX
249 #define TSL_RH_NB_PRIMES 51
250 #elif SIZE_MAX >= ULONG_MAX
251 #define TSL_RH_NB_PRIMES 40
252 #else
253 #define TSL_RH_NB_PRIMES 23
254 #endif
255 
256 static constexpr const std::array<std::size_t, TSL_RH_NB_PRIMES> PRIMES = {{
257  1u,
258  5u,
259  17u,
260  29u,
261  37u,
262  53u,
263  67u,
264  79u,
265  97u,
266  131u,
267  193u,
268  257u,
269  389u,
270  521u,
271  769u,
272  1031u,
273  1543u,
274  2053u,
275  3079u,
276  6151u,
277  12289u,
278  24593u,
279  49157u,
280 #if SIZE_MAX >= ULONG_MAX
281  98317ul,
282  196613ul,
283  393241ul,
284  786433ul,
285  1572869ul,
286  3145739ul,
287  6291469ul,
288  12582917ul,
289  25165843ul,
290  50331653ul,
291  100663319ul,
292  201326611ul,
293  402653189ul,
294  805306457ul,
295  1610612741ul,
296  3221225473ul,
297  4294967291ul,
298 #endif
299 #if SIZE_MAX >= ULLONG_MAX
300  6442450939ull,
301  12884901893ull,
302  25769803751ull,
303  51539607551ull,
304  103079215111ull,
305  206158430209ull,
306  412316860441ull,
307  824633720831ull,
308  1649267441651ull,
309  3298534883309ull,
310  6597069766657ull,
311 #endif
312 }};
313 
314 template <unsigned int IPrime>
315 static constexpr std::size_t mod(std::size_t hash) {
316  return hash % PRIMES[IPrime];
317 }
318 
319 // MOD_PRIME[iprime](hash) returns hash % PRIMES[iprime]. This table allows for
320 // faster modulo as the compiler can optimize the modulo code better with a
321 // constant known at the compilation.
322 static constexpr const std::array<std::size_t (*)(std::size_t),
325  &mod<0>, &mod<1>, &mod<2>, &mod<3>, &mod<4>, &mod<5>,
326  &mod<6>, &mod<7>, &mod<8>, &mod<9>, &mod<10>, &mod<11>,
327  &mod<12>, &mod<13>, &mod<14>, &mod<15>, &mod<16>, &mod<17>,
328  &mod<18>, &mod<19>, &mod<20>, &mod<21>, &mod<22>,
329 #if SIZE_MAX >= ULONG_MAX
330  &mod<23>, &mod<24>, &mod<25>, &mod<26>, &mod<27>, &mod<28>,
331  &mod<29>, &mod<30>, &mod<31>, &mod<32>, &mod<33>, &mod<34>,
332  &mod<35>, &mod<36>, &mod<37>, &mod<38>, &mod<39>,
333 #endif
334 #if SIZE_MAX >= ULLONG_MAX
335  &mod<40>, &mod<41>, &mod<42>, &mod<43>, &mod<44>, &mod<45>,
336  &mod<46>, &mod<47>, &mod<48>, &mod<49>, &mod<50>,
337 #endif
338  }};
339 
340 } // namespace detail
341 
370  public:
371  explicit prime_growth_policy(std::size_t& min_bucket_count_in_out) {
372  auto it_prime = std::lower_bound(
373  detail::PRIMES.begin(), detail::PRIMES.end(), min_bucket_count_in_out);
374  if (it_prime == detail::PRIMES.end()) {
375  TSL_RH_THROW_OR_TERMINATE(std::length_error,
376  "The hash table exceeds its maximum size.");
377  }
378 
379  m_iprime = static_cast<unsigned int>(
380  std::distance(detail::PRIMES.begin(), it_prime));
381  if (min_bucket_count_in_out > 0) {
382  min_bucket_count_in_out = *it_prime;
383  } else {
384  min_bucket_count_in_out = 0;
385  }
386  }
387 
388  std::size_t bucket_for_hash(std::size_t hash) const noexcept {
389  return detail::MOD_PRIME[m_iprime](hash);
390  }
391 
392  std::size_t next_bucket_count() const {
393  if (m_iprime + 1 >= detail::PRIMES.size()) {
394  TSL_RH_THROW_OR_TERMINATE(std::length_error,
395  "The hash table exceeds its maximum size.");
396  }
397 
398  return detail::PRIMES[m_iprime + 1];
399  }
400 
401  std::size_t max_bucket_count() const { return detail::PRIMES.back(); }
402 
403  void clear() noexcept { m_iprime = 0; }
404 
405  private:
406  unsigned int m_iprime;
407 
408  static_assert(std::numeric_limits<decltype(m_iprime)>::max() >=
409  detail::PRIMES.size(),
410  "The type of m_iprime is not big enough.");
411 };
412 
413 } // namespace rh
414 } // namespace tsl
415 
416 #endif
tsl::rh::prime_growth_policy::prime_growth_policy
prime_growth_policy(std::size_t &min_bucket_count_in_out)
Definition: robin_growth_policy.h:371
tsl::rh::mod_growth_policy::MAX_BUCKET_COUNT
static const std::size_t MAX_BUCKET_COUNT
Definition: robin_growth_policy.h:236
tsl::rh::prime_growth_policy
Definition: robin_growth_policy.h:369
tsl::rh::power_of_two_growth_policy::m_mask
std::size_t m_mask
Definition: robin_growth_policy.h:179
tsl
Definition: robin_growth_policy.h:84
tsl::rh::mod_growth_policy::REHASH_SIZE_MULTIPLICATION_FACTOR
static constexpr double REHASH_SIZE_MULTIPLICATION_FACTOR
Definition: robin_growth_policy.h:234
tsl::rh::detail::mod
static constexpr std::size_t mod(std::size_t hash)
Definition: robin_growth_policy.h:315
tsl::rh::detail::MOD_PRIME
static constexpr const std::array< std::size_t(*)(std::size_t), TSL_RH_NB_PRIMES > MOD_PRIME
Definition: robin_growth_policy.h:324
tsl::rh::power_of_two_growth_policy::power_of_two_growth_policy
power_of_two_growth_policy(std::size_t &min_bucket_count_in_out)
Definition: robin_growth_policy.h:105
tsl::rh::detail::PRIMES
static constexpr const std::array< std::size_t, TSL_RH_NB_PRIMES > PRIMES
Definition: robin_growth_policy.h:256
tsl::rh::mod_growth_policy::mod_growth_policy
mod_growth_policy(std::size_t &min_bucket_count_in_out)
Definition: robin_growth_policy.h:192
tsl::rh::power_of_two_growth_policy::next_bucket_count
std::size_t next_bucket_count() const
Definition: robin_growth_policy.h:131
tsl::rh::power_of_two_growth_policy::max_bucket_count
std::size_t max_bucket_count() const
Definition: robin_growth_policy.h:143
tsl::rh::prime_growth_policy::bucket_for_hash
std::size_t bucket_for_hash(std::size_t hash) const noexcept
Definition: robin_growth_policy.h:388
tsl::rh::power_of_two_growth_policy::clear
void clear() noexcept
Definition: robin_growth_policy.h:153
tsl::rh::power_of_two_growth_policy::round_up_to_power_of_two
static std::size_t round_up_to_power_of_two(std::size_t value)
Definition: robin_growth_policy.h:156
tsl::rh::mod_growth_policy::m_mod
std::size_t m_mod
Definition: robin_growth_policy.h:241
TSL_RH_THROW_OR_TERMINATE
#define TSL_RH_THROW_OR_TERMINATE(ex, msg)
Definition: robin_growth_policy.h:72
tsl::rh::mod_growth_policy::clear
void clear() noexcept
Definition: robin_growth_policy.h:231
tsl::rh::prime_growth_policy::m_iprime
unsigned int m_iprime
Definition: robin_growth_policy.h:406
tsl::rh::power_of_two_growth_policy::is_power_of_two
static constexpr bool is_power_of_two(std::size_t value)
Definition: robin_growth_policy.h:173
tsl::rh::prime_growth_policy::next_bucket_count
std::size_t next_bucket_count() const
Definition: robin_growth_policy.h:392
tsl::rh::power_of_two_growth_policy::bucket_for_hash
std::size_t bucket_for_hash(std::size_t hash) const noexcept
Definition: robin_growth_policy.h:124
tsl::rh::power_of_two_growth_policy
Definition: robin_growth_policy.h:95
TSL_RH_NB_PRIMES
#define TSL_RH_NB_PRIMES
Definition: robin_growth_policy.h:249
tsl::rh::mod_growth_policy::max_bucket_count
std::size_t max_bucket_count() const
Definition: robin_growth_policy.h:229
tsl::rh::prime_growth_policy::max_bucket_count
std::size_t max_bucket_count() const
Definition: robin_growth_policy.h:401
tsl::rh::mod_growth_policy::bucket_for_hash
std::size_t bucket_for_hash(std::size_t hash) const noexcept
Definition: robin_growth_policy.h:205
tsl::rh::mod_growth_policy
Definition: robin_growth_policy.h:190
tsl::rh::mod_growth_policy::next_bucket_count
std::size_t next_bucket_count() const
Definition: robin_growth_policy.h:209
tsl::rh::prime_growth_policy::clear
void clear() noexcept
Definition: robin_growth_policy.h:403


mp2p_icp
Author(s): Jose-Luis Blanco-Claraco
autogenerated on Wed Jun 26 2024 02:47:09