@@ -84,24 +84,58 @@ struct str_hash {
8484 }
8585};
8686
87- namespace detail_array_hash {
88-
89- static constexpr bool is_power_of_two (std::size_t value) {
90- return value != 0 && (value & (value - 1 )) == 0 ;
91- }
9287
93- // TODO could be faster
94- static std::size_t round_up_to_power_of_two (std::size_t value) {
95- if (is_power_of_two (value)) {
96- return value;
88+
89+ template <std::size_t GrowthFactor>
90+ class power_of_two_growth_policy {
91+ public:
92+ power_of_two_growth_policy (std::size_t & min_bucket_count_in_out) {
93+ const std::size_t min_bucket_count = MIN_BUCKETS_SIZE;
94+
95+ min_bucket_count_in_out = std::max (min_bucket_count, min_bucket_count_in_out);
96+ min_bucket_count_in_out = round_up_to_power_of_two (min_bucket_count_in_out);
9797 }
9898
99- std::size_t power = 1 ;
100- while (power < value) {
101- power <<= 1 ;
99+ std::size_t bucket_for_hash (std::size_t hash, std::size_t bucket_count) const {
100+ return hash & (bucket_count-1 );
102101 }
103102
104- return power;
103+ std::size_t next_bucket_count (std::size_t bucket_count) const {
104+ return bucket_count * GrowthFactor;
105+ }
106+
107+ private:
108+ // TODO could be faster
109+ static std::size_t round_up_to_power_of_two (std::size_t value) {
110+ if (is_power_of_two (value)) {
111+ return value;
112+ }
113+
114+ std::size_t power = 1 ;
115+ while (power < value) {
116+ power <<= 1 ;
117+ }
118+
119+ return power;
120+ }
121+
122+ static constexpr bool is_power_of_two (std::size_t value) {
123+ return value != 0 && (value & (value - 1 )) == 0 ;
124+ }
125+
126+ private:
127+ static_assert (GrowthFactor >= 2 && is_power_of_two(GrowthFactor), " GrowthFactor must be a power of two >= 2." );
128+
129+ static const std::size_t MIN_BUCKETS_SIZE = 2 ;
130+ };
131+
132+
133+
134+
135+ namespace detail_array_hash {
136+
137+ static constexpr bool is_power_of_two (std::size_t value) {
138+ return value != 0 && (value & (value - 1 )) == 0 ;
105139}
106140
107141/* *
@@ -632,8 +666,9 @@ template<class CharT,
632666 class Traits ,
633667 bool StoreNullTerminator,
634668 class KeySizeT ,
635- class IndexSizeT >
636- class array_hash : private value_container <T>, private Hash {
669+ class IndexSizeT ,
670+ class GrowthPolicy >
671+ class array_hash : private value_container <T>, private Hash, private GrowthPolicy {
637672private:
638673 template <typename U>
639674 using has_value = typename std::integral_constant<bool , !std::is_same<U, void >::value>;
@@ -903,9 +938,10 @@ class array_hash : private value_container<T>, private Hash {
903938public:
904939 array_hash (size_type bucket_count,
905940 const Hash& hash,
906- float max_load_factor): Hash(hash), m_buckets(round_up_to_power_of_two( bucket_count)),
941+ float max_load_factor): Hash(hash), GrowthPolicy( bucket_count), m_buckets( 0 ),
907942 m_nb_elements (0 ), m_max_load_factor(max_load_factor)
908943 {
944+ m_buckets.resize (bucket_count);
909945 }
910946
911947 array_hash (const array_hash& other) = default;
@@ -915,6 +951,7 @@ class array_hash : private value_container<T>, private Hash {
915951 std::is_nothrow_move_constructible<std::vector<array_bucket>>::value)
916952 : value_container<T>(std::move(other)),
917953 Hash(std::move(other)),
954+ GrowthPolicy(std::move(other)),
918955 m_buckets(std::move(other.m_buckets)),
919956 m_nb_elements(other.m_nb_elements),
920957 m_max_load_factor(other.m_max_load_factor)
@@ -1078,6 +1115,7 @@ class array_hash : private value_container<T>, private Hash {
10781115
10791116 swap (static_cast <value_container<T>&>(*this ), static_cast <value_container<T>&>(other));
10801117 swap (static_cast <Hash&>(*this ), static_cast <Hash&>(other));
1118+ swap (static_cast <GrowthPolicy&>(*this ), static_cast <GrowthPolicy&>(other));
10811119 swap (m_buckets, other.m_buckets );
10821120 swap (m_nb_elements, other.m_nb_elements );;
10831121 swap (m_max_load_factor, other.m_max_load_factor );
@@ -1217,11 +1255,11 @@ class array_hash : private value_container<T>, private Hash {
12171255 }
12181256
12191257 std::size_t bucket_for_hash (std::size_t hash) const {
1220- return hash & ( m_buckets.size () - 1 );
1258+ return GrowthPolicy::bucket_for_hash ( hash, m_buckets.size ());
12211259 }
12221260
12231261 std::size_t bucket_for_hash (std::size_t hash, size_type bucket_count) const {
1224- return hash & ( bucket_count - 1 );
1262+ return GrowthPolicy::bucket_for_hash ( hash, bucket_count);
12251263 }
12261264
12271265 typename std::vector<array_bucket>::iterator first_non_empty_bucket_iterator () noexcept {
@@ -1323,11 +1361,7 @@ class array_hash : private value_container<T>, private Hash {
13231361
13241362 void rehash_if_needed () {
13251363 if (load_factor () > m_max_load_factor) {
1326- if (bucket_count () > max_bucket_count ()/2 ) {
1327- throw std::length_error (" Insertion impossible, too much values in the map." );
1328- }
1329-
1330- rehash_impl (bucket_count ()*2 );
1364+ rehash_impl (GrowthPolicy::next_bucket_count (m_buckets.size ()));
13311365 }
13321366 }
13331367
@@ -1383,13 +1417,7 @@ class array_hash : private value_container<T>, private Hash {
13831417 }
13841418
13851419 void rehash_impl (size_type bucket_count) {
1386- const size_type old_bucket_count = bucket_count;
1387- bucket_count = round_up_to_power_of_two (bucket_count);
1388-
1389- // Unsigned overflow, we can't rehash.
1390- if (bucket_count < old_bucket_count) {
1391- throw std::length_error (" Can't insert value, too much values in the map." );
1392- }
1420+ GrowthPolicy new_growth_policy (bucket_count);
13931421
13941422 if (bucket_count == this ->bucket_count ()) {
13951423 return ;
@@ -1426,6 +1454,8 @@ class array_hash : private value_container<T>, private Hash {
14261454 ivalue++;
14271455 }
14281456
1457+ static_assert (noexcept (std::swap (static_cast <GrowthPolicy&>(*this ), new_growth_policy)), " " );
1458+ std::swap (static_cast <GrowthPolicy&>(*this ), new_growth_policy);
14291459 m_buckets.swap (new_buckets);
14301460
14311461 try {
@@ -1435,7 +1465,9 @@ class array_hash : private value_container<T>, private Hash {
14351465 }
14361466 catch (...) {
14371467 // Rollback
1468+ std::swap (static_cast <GrowthPolicy&>(*this ), new_growth_policy);
14381469 m_buckets.swap (new_buckets);
1470+
14391471 throw ;
14401472 }
14411473 }
0 commit comments