5757#else
5858#include < iostream>
5959#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 )
6464#endif
6565#endif
6666
@@ -82,95 +82,96 @@ namespace rh {
8282 */
8383template <std::size_t GrowthFactor>
8484class 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+ }
98108 }
99109
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;
124116 }
125117
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;
150128 }
151129
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 ;
154136 }
155137
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 ;
159145 }
160146
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+ }
163161
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+ }
167168
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.");
172173
173- std::size_t m_mask;
174+ std::size_t m_mask;
174175};
175176
176177/* *
@@ -180,64 +181,65 @@ class power_of_two_growth_policy {
180181 */
181182template <class GrowthFactor = std::ratio<3 , 2 >>
182183class 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+ }
188196 }
189197
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;
194200 }
195- }
196201
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+ }
205220 }
206221
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;
212224 }
213225
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 ;
218228 }
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- }
228229
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));
235237
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." );
239241
240- std::size_t m_mod;
242+ std::size_t m_mod;
241243};
242244
243245namespace detail {
@@ -310,7 +312,7 @@ static constexpr const std::array<std::size_t, TSL_RH_NB_PRIMES> PRIMES = {{
310312
311313template <unsigned int IPrime>
312314static constexpr std::size_t mod (std::size_t hash) {
313- return hash % PRIMES[IPrime];
315+ return hash % PRIMES[IPrime];
314316}
315317
316318// MOD_PRIME[iprime](hash) returns hash % PRIMES[iprime]. This table allows for
@@ -364,51 +366,53 @@ static constexpr const std::
364366 * * 5' in a 64 bits environment.
365367 */
366368class 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+ }
374387 }
375388
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);
382391 }
383- }
384392
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+ }
388398
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 ];
393400 }
394401
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+ }
401405
402- void clear () noexcept {
403- m_iprime = 0 ;
404- }
406+ void clear () noexcept {
407+ m_iprime = 0 ;
408+ }
405409
406- private:
407- unsigned int m_iprime;
410+ private:
411+ unsigned int m_iprime;
408412
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." );
412416};
413417
414418} // namespace rh
0 commit comments