| |
| // Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard. |
| // Copyright (C) 2005-2011 Daniel James |
| // Distributed under the Boost Software License, Version 1.0. (See accompanying |
| // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
| |
| #ifndef NDNBOOST_UNORDERED_DETAIL_ALL_HPP_INCLUDED |
| #define NDNBOOST_UNORDERED_DETAIL_ALL_HPP_INCLUDED |
| |
| #include <ndnboost/unordered/detail/buckets.hpp> |
| #include <ndnboost/unordered/detail/util.hpp> |
| #include <ndnboost/type_traits/aligned_storage.hpp> |
| #include <ndnboost/type_traits/alignment_of.hpp> |
| #include <cmath> |
| |
| #if defined(NDNBOOST_MSVC) |
| #pragma warning(push) |
| #pragma warning(disable:4127) // conditional expression is constant |
| #endif |
| |
| #if defined(NDNBOOST_UNORDERED_DEPRECATED_EQUALITY) |
| |
| #if defined(__EDG__) |
| #elif defined(_MSC_VER) || defined(__BORLANDC__) || defined(__DMC__) |
| #pragma message("Warning: NDNBOOST_UNORDERED_DEPRECATED_EQUALITY is no longer supported.") |
| #elif defined(__GNUC__) || defined(__HP_aCC) || \ |
| defined(__SUNPRO_CC) || defined(__IBMCPP__) |
| #warning "NDNBOOST_UNORDERED_DEPRECATED_EQUALITY is no longer supported." |
| #endif |
| |
| #endif |
| |
| namespace ndnboost { namespace unordered { namespace detail { |
| |
| //////////////////////////////////////////////////////////////////////////// |
| // convert double to std::size_t |
| |
| inline std::size_t double_to_size(double f) |
| { |
| return f >= static_cast<double>( |
| (std::numeric_limits<std::size_t>::max)()) ? |
| (std::numeric_limits<std::size_t>::max)() : |
| static_cast<std::size_t>(f); |
| } |
| |
| // The space used to store values in a node. |
| |
| template <typename ValueType> |
| struct value_base |
| { |
| typedef ValueType value_type; |
| |
| typename ndnboost::aligned_storage< |
| sizeof(value_type), |
| ndnboost::alignment_of<value_type>::value>::type data_; |
| |
| void* address() { |
| return this; |
| } |
| |
| value_type& value() { |
| return *(ValueType*) this; |
| } |
| |
| value_type* value_ptr() { |
| return (ValueType*) this; |
| } |
| |
| private: |
| |
| value_base& operator=(value_base const&); |
| }; |
| |
| template <typename NodeAlloc> |
| struct copy_nodes |
| { |
| typedef ndnboost::unordered::detail::allocator_traits<NodeAlloc> |
| node_allocator_traits; |
| |
| node_constructor<NodeAlloc> constructor; |
| |
| explicit copy_nodes(NodeAlloc& a) : constructor(a) {} |
| |
| typename node_allocator_traits::pointer create( |
| typename node_allocator_traits::value_type::value_type const& v) |
| { |
| constructor.construct_with_value2(v); |
| return constructor.release(); |
| } |
| }; |
| |
| template <typename NodeAlloc> |
| struct move_nodes |
| { |
| typedef ndnboost::unordered::detail::allocator_traits<NodeAlloc> |
| node_allocator_traits; |
| |
| node_constructor<NodeAlloc> constructor; |
| |
| explicit move_nodes(NodeAlloc& a) : constructor(a) {} |
| |
| typename node_allocator_traits::pointer create( |
| typename node_allocator_traits::value_type::value_type& v) |
| { |
| constructor.construct_with_value2(ndnboost::move(v)); |
| return constructor.release(); |
| } |
| }; |
| |
| template <typename Buckets> |
| struct assign_nodes |
| { |
| node_holder<typename Buckets::node_allocator> holder; |
| |
| explicit assign_nodes(Buckets& b) : holder(b) {} |
| |
| typename Buckets::node_pointer create( |
| typename Buckets::value_type const& v) |
| { |
| return holder.copy_of(v); |
| } |
| }; |
| |
| template <typename Buckets> |
| struct move_assign_nodes |
| { |
| node_holder<typename Buckets::node_allocator> holder; |
| |
| explicit move_assign_nodes(Buckets& b) : holder(b) {} |
| |
| typename Buckets::node_pointer create( |
| typename Buckets::value_type& v) |
| { |
| return holder.move_copy_of(v); |
| } |
| }; |
| |
| template <typename Types> |
| struct table : |
| ndnboost::unordered::detail::functions< |
| typename Types::hasher, |
| typename Types::key_equal> |
| { |
| private: |
| table(table const&); |
| table& operator=(table const&); |
| public: |
| typedef typename Types::node node; |
| typedef typename Types::bucket bucket; |
| typedef typename Types::hasher hasher; |
| typedef typename Types::key_equal key_equal; |
| typedef typename Types::key_type key_type; |
| typedef typename Types::extractor extractor; |
| typedef typename Types::value_type value_type; |
| typedef typename Types::table table_impl; |
| typedef typename Types::link_pointer link_pointer; |
| typedef typename Types::policy policy; |
| |
| typedef ndnboost::unordered::detail::functions< |
| typename Types::hasher, |
| typename Types::key_equal> functions; |
| typedef typename functions::set_hash_functions set_hash_functions; |
| |
| typedef typename Types::allocator allocator; |
| typedef typename ndnboost::unordered::detail:: |
| rebind_wrap<allocator, node>::type node_allocator; |
| typedef typename ndnboost::unordered::detail:: |
| rebind_wrap<allocator, bucket>::type bucket_allocator; |
| typedef ndnboost::unordered::detail::allocator_traits<node_allocator> |
| node_allocator_traits; |
| typedef ndnboost::unordered::detail::allocator_traits<bucket_allocator> |
| bucket_allocator_traits; |
| typedef typename node_allocator_traits::pointer |
| node_pointer; |
| typedef typename node_allocator_traits::const_pointer |
| const_node_pointer; |
| typedef typename bucket_allocator_traits::pointer |
| bucket_pointer; |
| typedef ndnboost::unordered::detail::node_constructor<node_allocator> |
| node_constructor; |
| |
| typedef ndnboost::unordered::iterator_detail:: |
| iterator<node> iterator; |
| typedef ndnboost::unordered::iterator_detail:: |
| c_iterator<node, const_node_pointer> c_iterator; |
| typedef ndnboost::unordered::iterator_detail:: |
| l_iterator<node, policy> l_iterator; |
| typedef ndnboost::unordered::iterator_detail:: |
| cl_iterator<node, const_node_pointer, policy> cl_iterator; |
| |
| //////////////////////////////////////////////////////////////////////// |
| // Members |
| |
| ndnboost::unordered::detail::compressed<bucket_allocator, node_allocator> |
| allocators_; |
| std::size_t bucket_count_; |
| std::size_t size_; |
| float mlf_; |
| std::size_t max_load_; |
| bucket_pointer buckets_; |
| |
| //////////////////////////////////////////////////////////////////////// |
| // Data access |
| |
| bucket_allocator const& bucket_alloc() const |
| { |
| return allocators_.first(); |
| } |
| |
| node_allocator const& node_alloc() const |
| { |
| return allocators_.second(); |
| } |
| |
| bucket_allocator& bucket_alloc() |
| { |
| return allocators_.first(); |
| } |
| |
| node_allocator& node_alloc() |
| { |
| return allocators_.second(); |
| } |
| |
| std::size_t max_bucket_count() const |
| { |
| // -1 to account for the start bucket. |
| return policy::prev_bucket_count( |
| bucket_allocator_traits::max_size(bucket_alloc()) - 1); |
| } |
| |
| bucket_pointer get_bucket(std::size_t bucket_index) const |
| { |
| NDNBOOST_ASSERT(buckets_); |
| return buckets_ + static_cast<std::ptrdiff_t>(bucket_index); |
| } |
| |
| link_pointer get_previous_start() const |
| { |
| return get_bucket(bucket_count_)->first_from_start(); |
| } |
| |
| link_pointer get_previous_start(std::size_t bucket_index) const |
| { |
| return get_bucket(bucket_index)->next_; |
| } |
| |
| iterator begin() const |
| { |
| return size_ ? iterator(get_previous_start()->next_) : iterator(); |
| } |
| |
| iterator begin(std::size_t bucket_index) const |
| { |
| if (!size_) return iterator(); |
| link_pointer prev = get_previous_start(bucket_index); |
| return prev ? iterator(prev->next_) : iterator(); |
| } |
| |
| std::size_t hash_to_bucket(std::size_t hash) const |
| { |
| return policy::to_bucket(bucket_count_, hash); |
| } |
| |
| float load_factor() const |
| { |
| NDNBOOST_ASSERT(bucket_count_ != 0); |
| return static_cast<float>(size_) |
| / static_cast<float>(bucket_count_); |
| } |
| |
| std::size_t bucket_size(std::size_t index) const |
| { |
| iterator it = begin(index); |
| if (!it.node_) return 0; |
| |
| std::size_t count = 0; |
| while(it.node_ && hash_to_bucket(it.node_->hash_) == index) |
| { |
| ++count; |
| ++it; |
| } |
| |
| return count; |
| } |
| |
| //////////////////////////////////////////////////////////////////////// |
| // Load methods |
| |
| std::size_t max_size() const |
| { |
| using namespace std; |
| |
| // size < mlf_ * count |
| return ndnboost::unordered::detail::double_to_size(ceil( |
| static_cast<double>(mlf_) * |
| static_cast<double>(max_bucket_count()) |
| )) - 1; |
| } |
| |
| void recalculate_max_load() |
| { |
| using namespace std; |
| |
| // From 6.3.1/13: |
| // Only resize when size >= mlf_ * count |
| max_load_ = buckets_ ? ndnboost::unordered::detail::double_to_size(ceil( |
| static_cast<double>(mlf_) * |
| static_cast<double>(bucket_count_) |
| )) : 0; |
| |
| } |
| |
| void max_load_factor(float z) |
| { |
| NDNBOOST_ASSERT(z > 0); |
| mlf_ = (std::max)(z, minimum_max_load_factor); |
| recalculate_max_load(); |
| } |
| |
| std::size_t min_buckets_for_size(std::size_t size) const |
| { |
| NDNBOOST_ASSERT(mlf_ >= minimum_max_load_factor); |
| |
| using namespace std; |
| |
| // From 6.3.1/13: |
| // size < mlf_ * count |
| // => count > size / mlf_ |
| // |
| // Or from rehash post-condition: |
| // count > size / mlf_ |
| |
| return policy::new_bucket_count( |
| ndnboost::unordered::detail::double_to_size(floor( |
| static_cast<double>(size) / |
| static_cast<double>(mlf_))) + 1); |
| } |
| |
| //////////////////////////////////////////////////////////////////////// |
| // Constructors |
| |
| table(std::size_t num_buckets, |
| hasher const& hf, |
| key_equal const& eq, |
| node_allocator const& a) : |
| functions(hf, eq), |
| allocators_(a,a), |
| bucket_count_(policy::new_bucket_count(num_buckets)), |
| size_(0), |
| mlf_(1.0f), |
| max_load_(0), |
| buckets_() |
| {} |
| |
| table(table const& x, node_allocator const& a) : |
| functions(x), |
| allocators_(a,a), |
| bucket_count_(x.min_buckets_for_size(x.size_)), |
| size_(0), |
| mlf_(x.mlf_), |
| max_load_(0), |
| buckets_() |
| {} |
| |
| table(table& x, ndnboost::unordered::detail::move_tag m) : |
| functions(x, m), |
| allocators_(x.allocators_, m), |
| bucket_count_(x.bucket_count_), |
| size_(x.size_), |
| mlf_(x.mlf_), |
| max_load_(x.max_load_), |
| buckets_(x.buckets_) |
| { |
| x.buckets_ = bucket_pointer(); |
| x.size_ = 0; |
| x.max_load_ = 0; |
| } |
| |
| table(table& x, node_allocator const& a, |
| ndnboost::unordered::detail::move_tag m) : |
| functions(x, m), |
| allocators_(a, a), |
| bucket_count_(x.bucket_count_), |
| size_(0), |
| mlf_(x.mlf_), |
| max_load_(x.max_load_), |
| buckets_() |
| {} |
| |
| //////////////////////////////////////////////////////////////////////// |
| // Initialisation. |
| |
| void init(table const& x) |
| { |
| if (x.size_) { |
| create_buckets(bucket_count_); |
| copy_nodes<node_allocator> copy(node_alloc()); |
| table_impl::fill_buckets(x.begin(), *this, copy); |
| } |
| } |
| |
| void move_init(table& x) |
| { |
| if(node_alloc() == x.node_alloc()) { |
| move_buckets_from(x); |
| } |
| else if(x.size_) { |
| // TODO: Could pick new bucket size? |
| create_buckets(bucket_count_); |
| |
| move_nodes<node_allocator> move(node_alloc()); |
| node_holder<node_allocator> nodes(x); |
| table_impl::fill_buckets(nodes.begin(), *this, move); |
| } |
| } |
| |
| //////////////////////////////////////////////////////////////////////// |
| // Create buckets |
| |
| void create_buckets(std::size_t new_count) |
| { |
| ndnboost::unordered::detail::array_constructor<bucket_allocator> |
| constructor(bucket_alloc()); |
| |
| // Creates an extra bucket to act as the start node. |
| constructor.construct(bucket(), new_count + 1); |
| |
| if (buckets_) |
| { |
| // Copy the nodes to the new buckets, including the dummy |
| // node if there is one. |
| (constructor.get() + |
| static_cast<std::ptrdiff_t>(new_count))->next_ = |
| (buckets_ + static_cast<std::ptrdiff_t>( |
| bucket_count_))->next_; |
| destroy_buckets(); |
| } |
| else if (bucket::extra_node) |
| { |
| node_constructor a(node_alloc()); |
| a.construct(); |
| |
| (constructor.get() + |
| static_cast<std::ptrdiff_t>(new_count))->next_ = |
| a.release(); |
| } |
| |
| bucket_count_ = new_count; |
| buckets_ = constructor.release(); |
| recalculate_max_load(); |
| } |
| |
| //////////////////////////////////////////////////////////////////////// |
| // Swap and Move |
| |
| void swap_allocators(table& other, false_type) |
| { |
| // According to 23.2.1.8, if propagate_on_container_swap is |
| // false the behaviour is undefined unless the allocators |
| // are equal. |
| NDNBOOST_ASSERT(node_alloc() == other.node_alloc()); |
| } |
| |
| void swap_allocators(table& other, true_type) |
| { |
| allocators_.swap(other.allocators_); |
| } |
| |
| // Only swaps the allocators if propagate_on_container_swap |
| void swap(table& x) |
| { |
| set_hash_functions op1(*this, x); |
| set_hash_functions op2(x, *this); |
| |
| // I think swap can throw if Propagate::value, |
| // since the allocators' swap can throw. Not sure though. |
| swap_allocators(x, |
| ndnboost::unordered::detail::integral_constant<bool, |
| allocator_traits<node_allocator>:: |
| propagate_on_container_swap::value>()); |
| |
| ndnboost::swap(buckets_, x.buckets_); |
| ndnboost::swap(bucket_count_, x.bucket_count_); |
| ndnboost::swap(size_, x.size_); |
| std::swap(mlf_, x.mlf_); |
| std::swap(max_load_, x.max_load_); |
| op1.commit(); |
| op2.commit(); |
| } |
| |
| void move_buckets_from(table& other) |
| { |
| NDNBOOST_ASSERT(node_alloc() == other.node_alloc()); |
| NDNBOOST_ASSERT(!buckets_); |
| buckets_ = other.buckets_; |
| bucket_count_ = other.bucket_count_; |
| size_ = other.size_; |
| other.buckets_ = bucket_pointer(); |
| other.size_ = 0; |
| other.max_load_ = 0; |
| } |
| |
| //////////////////////////////////////////////////////////////////////// |
| // Delete/destruct |
| |
| ~table() |
| { |
| delete_buckets(); |
| } |
| |
| void delete_node(link_pointer prev) |
| { |
| node_pointer n = static_cast<node_pointer>(prev->next_); |
| prev->next_ = n->next_; |
| |
| ndnboost::unordered::detail::destroy_value_impl(node_alloc(), |
| n->value_ptr()); |
| node_allocator_traits::destroy(node_alloc(), |
| ndnboost::addressof(*n)); |
| node_allocator_traits::deallocate(node_alloc(), n, 1); |
| --size_; |
| } |
| |
| std::size_t delete_nodes(link_pointer prev, link_pointer end) |
| { |
| NDNBOOST_ASSERT(prev->next_ != end); |
| |
| std::size_t count = 0; |
| |
| do { |
| delete_node(prev); |
| ++count; |
| } while (prev->next_ != end); |
| |
| return count; |
| } |
| |
| void delete_buckets() |
| { |
| if(buckets_) { |
| if (size_) delete_nodes(get_previous_start(), link_pointer()); |
| |
| if (bucket::extra_node) { |
| node_pointer n = static_cast<node_pointer>( |
| get_bucket(bucket_count_)->next_); |
| node_allocator_traits::destroy(node_alloc(), |
| ndnboost::addressof(*n)); |
| node_allocator_traits::deallocate(node_alloc(), n, 1); |
| } |
| |
| destroy_buckets(); |
| buckets_ = bucket_pointer(); |
| max_load_ = 0; |
| } |
| |
| NDNBOOST_ASSERT(!size_); |
| } |
| |
| void clear() |
| { |
| if (!size_) return; |
| |
| delete_nodes(get_previous_start(), link_pointer()); |
| clear_buckets(); |
| |
| NDNBOOST_ASSERT(!size_); |
| } |
| |
| void clear_buckets() |
| { |
| bucket_pointer end = get_bucket(bucket_count_); |
| for(bucket_pointer it = buckets_; it != end; ++it) |
| { |
| it->next_ = node_pointer(); |
| } |
| } |
| |
| void destroy_buckets() |
| { |
| bucket_pointer end = get_bucket(bucket_count_ + 1); |
| for(bucket_pointer it = buckets_; it != end; ++it) |
| { |
| bucket_allocator_traits::destroy(bucket_alloc(), |
| ndnboost::addressof(*it)); |
| } |
| |
| bucket_allocator_traits::deallocate(bucket_alloc(), |
| buckets_, bucket_count_ + 1); |
| } |
| |
| //////////////////////////////////////////////////////////////////////// |
| // Fix buckets after delete |
| // |
| |
| std::size_t fix_bucket(std::size_t bucket_index, link_pointer prev) |
| { |
| link_pointer end = prev->next_; |
| std::size_t bucket_index2 = bucket_index; |
| |
| if (end) |
| { |
| bucket_index2 = hash_to_bucket( |
| static_cast<node_pointer>(end)->hash_); |
| |
| // If begin and end are in the same bucket, then |
| // there's nothing to do. |
| if (bucket_index == bucket_index2) return bucket_index2; |
| |
| // Update the bucket containing end. |
| get_bucket(bucket_index2)->next_ = prev; |
| } |
| |
| // Check if this bucket is now empty. |
| bucket_pointer this_bucket = get_bucket(bucket_index); |
| if (this_bucket->next_ == prev) |
| this_bucket->next_ = link_pointer(); |
| |
| return bucket_index2; |
| } |
| |
| //////////////////////////////////////////////////////////////////////// |
| // Assignment |
| |
| void assign(table const& x) |
| { |
| if (this != ndnboost::addressof(x)) |
| { |
| assign(x, |
| ndnboost::unordered::detail::integral_constant<bool, |
| allocator_traits<node_allocator>:: |
| propagate_on_container_copy_assignment::value>()); |
| } |
| } |
| |
| void assign(table const& x, false_type) |
| { |
| // Strong exception safety. |
| set_hash_functions new_func_this(*this, x); |
| new_func_this.commit(); |
| mlf_ = x.mlf_; |
| recalculate_max_load(); |
| |
| if (!size_ && !x.size_) return; |
| |
| if (x.size_ >= max_load_) { |
| create_buckets(min_buckets_for_size(x.size_)); |
| } |
| else { |
| clear_buckets(); |
| } |
| |
| // assign_nodes takes ownership of the container's elements, |
| // assigning to them if possible, and deleting any that are |
| // left over. |
| assign_nodes<table> assign(*this); |
| table_impl::fill_buckets(x.begin(), *this, assign); |
| } |
| |
| void assign(table const& x, true_type) |
| { |
| if (node_alloc() == x.node_alloc()) { |
| allocators_.assign(x.allocators_); |
| assign(x, false_type()); |
| } |
| else { |
| set_hash_functions new_func_this(*this, x); |
| |
| // Delete everything with current allocators before assigning |
| // the new ones. |
| delete_buckets(); |
| allocators_.assign(x.allocators_); |
| |
| // Copy over other data, all no throw. |
| new_func_this.commit(); |
| mlf_ = x.mlf_; |
| bucket_count_ = min_buckets_for_size(x.size_); |
| max_load_ = 0; |
| |
| // Finally copy the elements. |
| if (x.size_) { |
| create_buckets(bucket_count_); |
| copy_nodes<node_allocator> copy(node_alloc()); |
| table_impl::fill_buckets(x.begin(), *this, copy); |
| } |
| } |
| } |
| |
| void move_assign(table& x) |
| { |
| if (this != ndnboost::addressof(x)) |
| { |
| move_assign(x, |
| ndnboost::unordered::detail::integral_constant<bool, |
| allocator_traits<node_allocator>:: |
| propagate_on_container_move_assignment::value>()); |
| } |
| } |
| |
| void move_assign(table& x, true_type) |
| { |
| delete_buckets(); |
| allocators_.move_assign(x.allocators_); |
| move_assign_no_alloc(x); |
| } |
| |
| void move_assign(table& x, false_type) |
| { |
| if (node_alloc() == x.node_alloc()) { |
| delete_buckets(); |
| move_assign_no_alloc(x); |
| } |
| else { |
| set_hash_functions new_func_this(*this, x); |
| new_func_this.commit(); |
| mlf_ = x.mlf_; |
| recalculate_max_load(); |
| |
| if (!size_ && !x.size_) return; |
| |
| if (x.size_ >= max_load_) { |
| create_buckets(min_buckets_for_size(x.size_)); |
| } |
| else { |
| clear_buckets(); |
| } |
| |
| // move_assign_nodes takes ownership of the container's |
| // elements, assigning to them if possible, and deleting |
| // any that are left over. |
| move_assign_nodes<table> assign(*this); |
| node_holder<node_allocator> nodes(x); |
| table_impl::fill_buckets(nodes.begin(), *this, assign); |
| } |
| } |
| |
| void move_assign_no_alloc(table& x) |
| { |
| set_hash_functions new_func_this(*this, x); |
| // No throw from here. |
| mlf_ = x.mlf_; |
| max_load_ = x.max_load_; |
| move_buckets_from(x); |
| new_func_this.commit(); |
| } |
| |
| // Accessors |
| |
| key_type const& get_key(value_type const& x) const |
| { |
| return extractor::extract(x); |
| } |
| |
| std::size_t hash(key_type const& k) const |
| { |
| return policy::apply_hash(this->hash_function(), k); |
| } |
| |
| // Find Node |
| |
| template <typename Key, typename Hash, typename Pred> |
| iterator generic_find_node( |
| Key const& k, |
| Hash const& hf, |
| Pred const& eq) const |
| { |
| return static_cast<table_impl const*>(this)-> |
| find_node_impl(policy::apply_hash(hf, k), k, eq); |
| } |
| |
| iterator find_node( |
| std::size_t key_hash, |
| key_type const& k) const |
| { |
| return static_cast<table_impl const*>(this)-> |
| find_node_impl(key_hash, k, this->key_eq()); |
| } |
| |
| iterator find_node(key_type const& k) const |
| { |
| return static_cast<table_impl const*>(this)-> |
| find_node_impl(hash(k), k, this->key_eq()); |
| } |
| |
| iterator find_matching_node(iterator n) const |
| { |
| // TODO: Does this apply to C++11? |
| // |
| // For some stupid reason, I decided to support equality comparison |
| // when different hash functions are used. So I can't use the hash |
| // value from the node here. |
| |
| return find_node(get_key(*n)); |
| } |
| |
| // Reserve and rehash |
| |
| void reserve_for_insert(std::size_t); |
| void rehash(std::size_t); |
| void reserve(std::size_t); |
| }; |
| |
| //////////////////////////////////////////////////////////////////////////// |
| // Reserve & Rehash |
| |
| // basic exception safety |
| template <typename Types> |
| inline void table<Types>::reserve_for_insert(std::size_t size) |
| { |
| if (!buckets_) { |
| create_buckets((std::max)(bucket_count_, |
| min_buckets_for_size(size))); |
| } |
| // According to the standard this should be 'size >= max_load_', |
| // but I think this is better, defect report filed. |
| else if(size > max_load_) { |
| std::size_t num_buckets |
| = min_buckets_for_size((std::max)(size, |
| size_ + (size_ >> 1))); |
| |
| if (num_buckets != bucket_count_) |
| static_cast<table_impl*>(this)->rehash_impl(num_buckets); |
| } |
| } |
| |
| // if hash function throws, basic exception safety |
| // strong otherwise. |
| |
| template <typename Types> |
| inline void table<Types>::rehash(std::size_t min_buckets) |
| { |
| using namespace std; |
| |
| if(!size_) { |
| delete_buckets(); |
| bucket_count_ = policy::new_bucket_count(min_buckets); |
| } |
| else { |
| min_buckets = policy::new_bucket_count((std::max)(min_buckets, |
| ndnboost::unordered::detail::double_to_size(floor( |
| static_cast<double>(size_) / |
| static_cast<double>(mlf_))) + 1)); |
| |
| if(min_buckets != bucket_count_) |
| static_cast<table_impl*>(this)->rehash_impl(min_buckets); |
| } |
| } |
| |
| template <typename Types> |
| inline void table<Types>::reserve(std::size_t num_elements) |
| { |
| rehash(static_cast<std::size_t>( |
| std::ceil(static_cast<double>(num_elements) / mlf_))); |
| } |
| }}} |
| |
| #if defined(NDNBOOST_MSVC) |
| #pragma warning(pop) |
| #endif |
| |
| #endif |