99template <std::
size_t GrowthFactor>
112 PXR_TSL_RH_THROW_OR_TERMINATE(std::length_error,
113 "The hash table exceeds its maximum size.");
116 if (min_bucket_count_in_out > 0) {
117 min_bucket_count_in_out =
118 round_up_to_power_of_two(min_bucket_count_in_out);
119 m_mask = min_bucket_count_in_out - 1;
130 return hash & m_mask;
138 PXR_TSL_RH_THROW_OR_TERMINATE(std::length_error,
139 "The hash table exceeds its maximum size.");
142 return (m_mask + 1) * GrowthFactor;
150 return (std::numeric_limits<std::size_t>::max() / 2) + 1;
158 void clear() noexcept { m_mask = 0; }
161 static std::size_t round_up_to_power_of_two(std::size_t value) {
162 if (is_power_of_two(value)) {
171 for (std::size_t i = 1; i <
sizeof(std::size_t) * CHAR_BIT; i *= 2) {
178 static constexpr bool is_power_of_two(std::size_t value) {
179 return value != 0 && (value & (value - 1)) == 0;
183 static_assert(is_power_of_two(GrowthFactor) && GrowthFactor >= 2,
184 "GrowthFactor must be a power of two >= 2.");
194template <
class GrowthFactor = std::ratio<3, 2>>
198 if (min_bucket_count_in_out > max_bucket_count()) {
199 PXR_TSL_RH_THROW_OR_TERMINATE(std::length_error,
200 "The hash table exceeds its maximum size.");
203 if (min_bucket_count_in_out > 0) {
204 m_mod = min_bucket_count_in_out;
210 std::size_t bucket_for_hash(std::size_t hash)
const noexcept {
214 std::size_t next_bucket_count()
const {
215 if (m_mod == max_bucket_count()) {
216 PXR_TSL_RH_THROW_OR_TERMINATE(std::length_error,
217 "The hash table exceeds its maximum size.");
220 const double next_bucket_count =
221 std::ceil(
double(m_mod) * REHASH_SIZE_MULTIPLICATION_FACTOR);
222 if (!std::isnormal(next_bucket_count)) {
223 PXR_TSL_RH_THROW_OR_TERMINATE(std::length_error,
224 "The hash table exceeds its maximum size.");
227 if (next_bucket_count >
double(max_bucket_count())) {
228 return max_bucket_count();
230 return std::size_t(next_bucket_count);
234 std::size_t max_bucket_count()
const {
return MAX_BUCKET_COUNT; }
236 void clear()
noexcept { m_mod = 1; }
239 static constexpr double REHASH_SIZE_MULTIPLICATION_FACTOR =
240 1.0 * GrowthFactor::num / GrowthFactor::den;
241 static const std::size_t MAX_BUCKET_COUNT =
242 std::size_t(
double(std::numeric_limits<std::size_t>::max() /
243 REHASH_SIZE_MULTIPLICATION_FACTOR));
245 static_assert(REHASH_SIZE_MULTIPLICATION_FACTOR >= 1.1,
246 "Growth factor should be >= 1.1.");
253#if SIZE_MAX >= ULLONG_MAX
254#define PXR_TSL_RH_NB_PRIMES 51
255#elif SIZE_MAX >= ULONG_MAX
256#define PXR_TSL_RH_NB_PRIMES 40
258#define PXR_TSL_RH_NB_PRIMES 23
261static constexpr const std::array<std::size_t, PXR_TSL_RH_NB_PRIMES> PRIMES = {{
285#if SIZE_MAX >= ULONG_MAX
304#if SIZE_MAX >= ULLONG_MAX
319template <
unsigned int IPrime>
320static constexpr std::size_t mod(std::size_t hash) {
321 return hash % PRIMES[IPrime];
327static constexpr const std::array<std::size_t (*)(std::size_t),
328 PXR_TSL_RH_NB_PRIMES>
330 &mod<0>, &mod<1>, &mod<2>, &mod<3>, &mod<4>, &mod<5>,
331 &mod<6>, &mod<7>, &mod<8>, &mod<9>, &mod<10>, &mod<11>,
332 &mod<12>, &mod<13>, &mod<14>, &mod<15>, &mod<16>, &mod<17>,
333 &mod<18>, &mod<19>, &mod<20>, &mod<21>, &mod<22>,
334#if SIZE_MAX >= ULONG_MAX
335 &mod<23>, &mod<24>, &mod<25>, &mod<26>, &mod<27>, &mod<28>,
336 &mod<29>, &mod<30>, &mod<31>, &mod<32>, &mod<33>, &mod<34>,
337 &mod<35>, &mod<36>, &mod<37>, &mod<38>, &mod<39>,
339#if SIZE_MAX >= ULLONG_MAX
340 &mod<40>, &mod<41>, &mod<42>, &mod<43>, &mod<44>, &mod<45>,
341 &mod<46>, &mod<47>, &mod<48>, &mod<49>, &mod<50>,
377 auto it_prime = std::lower_bound(
378 detail::PRIMES.begin(), detail::PRIMES.end(), min_bucket_count_in_out);
379 if (it_prime == detail::PRIMES.end()) {
380 PXR_TSL_RH_THROW_OR_TERMINATE(std::length_error,
381 "The hash table exceeds its maximum size.");
384 m_iprime =
static_cast<unsigned int>(
385 std::distance(detail::PRIMES.begin(), it_prime));
386 if (min_bucket_count_in_out > 0) {
387 min_bucket_count_in_out = *it_prime;
389 min_bucket_count_in_out = 0;
393 std::size_t bucket_for_hash(std::size_t hash)
const noexcept {
394 return detail::MOD_PRIME[m_iprime](hash);
397 std::size_t next_bucket_count()
const {
398 if (m_iprime + 1 >= detail::PRIMES.size()) {
399 PXR_TSL_RH_THROW_OR_TERMINATE(std::length_error,
400 "The hash table exceeds its maximum size.");
403 return detail::PRIMES[m_iprime + 1];
406 std::size_t max_bucket_count()
const {
return detail::PRIMES.back(); }
408 void clear()
noexcept { m_iprime = 0; }
411 unsigned int m_iprime;
413 static_assert(std::numeric_limits<
decltype(m_iprime)>::max() >=
414 detail::PRIMES.size(),
415 "The type of m_iprime is not big enough.");