From 431c5b76e59151340ded705dac7ae3a2b7f07c4f Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 5 Nov 2005 16:57:31 +0000 Subject: [PATCH] Better results for max_size/max_bucket_count and some fixes for intel in strict mode. [SVN r2730] --- include/boost/unordered/detail/hash_table.hpp | 53 +++++++++++++++---- 1 file changed, 42 insertions(+), 11 deletions(-) diff --git a/include/boost/unordered/detail/hash_table.hpp b/include/boost/unordered/detail/hash_table.hpp index fe0e3838..9638e15e 100644 --- a/include/boost/unordered/detail/hash_table.hpp +++ b/include/boost/unordered/detail/hash_table.hpp @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -64,6 +65,13 @@ namespace boost { swap(x, y); } + std::size_t float_to_size_t(float f) + { + return f > (std::numeric_limits::max)() ? + (std::numeric_limits::max)() : + static_cast(f); + } + // prime number list, accessor static const std::size_t prime_list[] = { @@ -83,6 +91,15 @@ namespace boost { return *bound; } + // no throw + inline std::size_t prev_prime(std::size_t n) { + std::size_t const* bound = + std::upper_bound(prime_list,prime_list + 28, n); + if(bound != prime_list) + bound--; + return *bound; + } + // pair_cast - used to convert between pair types. template @@ -1126,7 +1143,9 @@ namespace boost { // no throw size_type max_size() const { - return this->node_alloc_.max_size(); + // size < mlf_ * count + return float_to_size_t(ceil( + max_bucket_count() * mlf_)) - 1; } // strong safety @@ -1151,7 +1170,8 @@ namespace boost { // no throw size_type max_bucket_count() const { - return this->bucket_alloc_.max_size(); + // -1 to account for the end marker. + return prev_prime(this->bucket_alloc_.max_size() - 1); } private: @@ -1179,8 +1199,7 @@ namespace boost { // From 6.3.1/13: // Only resize when size >= mlf_ * count - max_load_ = static_cast( - ceil(mlf_ * this->bucket_count_)); + max_load_ = float_to_size_t(ceil(mlf_ * this->bucket_count_)); } // basic exception safety @@ -1189,6 +1208,7 @@ namespace boost { bool need_to_reserve = n >= max_load_; // throws - basic: if (need_to_reserve) rehash_impl(min_buckets_for_size(n)); + BOOST_ASSERT(n < max_load_); return need_to_reserve; } @@ -1201,8 +1221,12 @@ namespace boost { } // no throw + // + // TODO: the argument is a hint. So don't use it if it's + // unreasonably small. void max_load_factor(float z) { + BOOST_ASSERT(z > 0); mlf_ = z; calculate_max_load(); } @@ -1357,11 +1381,18 @@ namespace boost { { // Effects only in this block: + // Create the node before rehashing in case it throws. + // throws, no side effects: + node_constructor a(this->node_alloc_, this->bucket_alloc_); + a.construct(value_type(k, mapped_type())); + if (reserve(size() + 1)) // basic/strong bucket = get_bucket(k); // throws, strong - return *this->create_node( // throws, strong - value_type(k, mapped_type()), - bucket); + + link_ptr node = a.release(); + this->link_node(node, bucket); + + return *local_iterator_base(node); } } @@ -1423,9 +1454,9 @@ namespace boost { // I'm relying on local_iterator_base not being invalidated by // the rehash here. if(position.not_finished()) - link_node(node, position); + this->link_node(node, position); else - link_node(node, bucket); + this->link_node(node, bucket); return iterator_base(bucket, node); } @@ -1446,7 +1477,7 @@ namespace boost { get_bucket(extract_key(v)) : it.bucket_; link_ptr node = a.release(); - link_node(node, it.local()); + this->link_node(node, it.local()); return iterator_base(base, node); } @@ -1489,7 +1520,7 @@ namespace boost { bucket = this->buckets_ + this->index_from_hash(hash_value); link_ptr node = a.release(); - link_node(node, bucket); + this->link_node(node, bucket); return std::pair( iterator_base(bucket, node), true); // throws, strong