| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | // Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
 | 
					
						
							|  |  |  | // Copyright (C) 2005-2009 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 BOOST_UNORDERED_DETAIL_ALL_HPP_INCLUDED
 | 
					
						
							|  |  |  | #define BOOST_UNORDERED_DETAIL_ALL_HPP_INCLUDED
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <cstddef>
 | 
					
						
							|  |  |  | #include <stdexcept>
 | 
					
						
							|  |  |  | #include <algorithm>
 | 
					
						
							|  |  |  | #include <boost/config/no_tr1/cmath.hpp>
 | 
					
						
							|  |  |  | #include <boost/iterator/iterator_categories.hpp>
 | 
					
						
							| 
									
										
										
										
											2010-03-31 21:42:08 +00:00
										 |  |  | #include <boost/throw_exception.hpp>
 | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-04 07:03:04 +00:00
										 |  |  | #include <boost/unordered/detail/buckets.hpp>
 | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | namespace boost { namespace unordered_detail { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ////////////////////////////////////////////////////////////////////////////
 | 
					
						
							|  |  |  |     // Helper methods
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // strong exception safety, no side effects
 | 
					
						
							| 
									
										
										
										
											2009-11-20 08:03:26 +00:00
										 |  |  |     template <class T> | 
					
						
							|  |  |  |     inline bool hash_table<T>::equal( | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |         key_type const& k, value_type const& v) const | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |         return this->key_eq()(k, get_key(v)); | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-15 22:53:33 +00:00
										 |  |  |     // strong exception safety, no side effects
 | 
					
						
							|  |  |  |     template <class T> | 
					
						
							|  |  |  |     template <class Key, class Pred> | 
					
						
							|  |  |  |     inline BOOST_DEDUCED_TYPENAME T::node_ptr | 
					
						
							|  |  |  |         hash_table<T>::find_iterator(bucket_ptr bucket, Key const& k, | 
					
						
							|  |  |  |             Pred const& eq) const | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         node_ptr it = bucket->next_; | 
					
						
							|  |  |  |         while (BOOST_UNORDERED_BORLAND_BOOL(it) && | 
					
						
							|  |  |  |             !eq(k, get_key(node::get_value(it)))) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             it = node::next_group(it); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return it; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  |     // strong exception safety, no side effects
 | 
					
						
							| 
									
										
										
										
											2009-11-20 08:03:26 +00:00
										 |  |  |     template <class T> | 
					
						
							|  |  |  |     inline BOOST_DEDUCED_TYPENAME T::node_ptr | 
					
						
							|  |  |  |         hash_table<T>::find_iterator( | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |             bucket_ptr bucket, key_type const& k) const | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  |     { | 
					
						
							|  |  |  |         node_ptr it = bucket->next_; | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |         while (BOOST_UNORDERED_BORLAND_BOOL(it) && | 
					
						
							|  |  |  |             !equal(k, node::get_value(it))) | 
					
						
							|  |  |  |         { | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  |             it = node::next_group(it); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return it; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // strong exception safety, no side effects
 | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |     // pre: this->buckets_
 | 
					
						
							| 
									
										
										
										
											2009-11-20 08:03:26 +00:00
										 |  |  |     template <class T> | 
					
						
							|  |  |  |     inline BOOST_DEDUCED_TYPENAME T::node_ptr | 
					
						
							|  |  |  |         hash_table<T>::find_iterator(key_type const& k) const | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  |     { | 
					
						
							|  |  |  |         return find_iterator(this->get_bucket(this->bucket_index(k)), k); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // strong exception safety, no side effects
 | 
					
						
							| 
									
										
										
										
											2009-11-20 08:03:26 +00:00
										 |  |  |     template <class T> | 
					
						
							|  |  |  |     inline BOOST_DEDUCED_TYPENAME T::node_ptr* | 
					
						
							|  |  |  |         hash_table<T>::find_for_erase( | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |             bucket_ptr bucket, key_type const& k) const | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  |     { | 
					
						
							|  |  |  |         node_ptr* it = &bucket->next_; | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |         while(BOOST_UNORDERED_BORLAND_BOOL(*it) && | 
					
						
							|  |  |  |             !equal(k, node::get_value(*it))) | 
					
						
							|  |  |  |         { | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  |             it = &node::next_group(*it); | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         return it; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ////////////////////////////////////////////////////////////////////////////
 | 
					
						
							|  |  |  |     // Load methods
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // no throw
 | 
					
						
							| 
									
										
										
										
											2009-11-20 08:03:26 +00:00
										 |  |  |     template <class T> | 
					
						
							|  |  |  |     std::size_t hash_table<T>::max_size() const | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  |     { | 
					
						
							|  |  |  |         using namespace std; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // size < mlf_ * count
 | 
					
						
							|  |  |  |         return double_to_size_t(ceil( | 
					
						
							|  |  |  |                 (double) this->mlf_ * this->max_bucket_count())) - 1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // strong safety
 | 
					
						
							| 
									
										
										
										
											2009-11-20 08:03:26 +00:00
										 |  |  |     template <class T> | 
					
						
							|  |  |  |     inline std::size_t hash_table<T>::bucket_index( | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |         key_type const& k) const | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  |     { | 
					
						
							|  |  |  |         // hash_function can throw:
 | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |         return this->hash_function()(k) % this->bucket_count_; | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |     // no throw
 | 
					
						
							| 
									
										
										
										
											2009-11-20 08:03:26 +00:00
										 |  |  |     template <class T> | 
					
						
							|  |  |  |     inline std::size_t hash_table<T>::calculate_max_load() | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |     { | 
					
						
							|  |  |  |         using namespace std; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // From 6.3.1/13:
 | 
					
						
							|  |  |  |         // Only resize when size >= mlf_ * count
 | 
					
						
							|  |  |  |         return double_to_size_t(ceil((double) mlf_ * this->bucket_count_)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-20 08:03:26 +00:00
										 |  |  |     template <class T> | 
					
						
							|  |  |  |     void hash_table<T>::max_load_factor(float z) | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  |     { | 
					
						
							|  |  |  |         BOOST_ASSERT(z > 0); | 
					
						
							|  |  |  |         mlf_ = (std::max)(z, minimum_max_load_factor); | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |         this->max_load_ = this->calculate_max_load(); | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // no throw
 | 
					
						
							| 
									
										
										
										
											2009-11-20 08:03:26 +00:00
										 |  |  |     template <class T> | 
					
						
							|  |  |  |     inline std::size_t hash_table<T>::min_buckets_for_size( | 
					
						
							| 
									
										
										
										
											2009-09-21 21:17:19 +00:00
										 |  |  |         std::size_t size) const | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  |     { | 
					
						
							|  |  |  |         BOOST_ASSERT(this->mlf_ != 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         using namespace std; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // From 6.3.1/13:
 | 
					
						
							|  |  |  |         // size < mlf_ * count
 | 
					
						
							|  |  |  |         // => count > size / mlf_
 | 
					
						
							|  |  |  |         //
 | 
					
						
							|  |  |  |         // Or from rehash post-condition:
 | 
					
						
							|  |  |  |         // count > size / mlf_
 | 
					
						
							| 
									
										
										
										
											2009-09-21 21:17:19 +00:00
										 |  |  |         return next_prime(double_to_size_t(floor(size / (double) mlf_)) + 1); | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ////////////////////////////////////////////////////////////////////////////
 | 
					
						
							|  |  |  |     // recompute_begin_bucket
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // init_buckets
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-20 08:03:26 +00:00
										 |  |  |     template <class T> | 
					
						
							|  |  |  |     inline void hash_table<T>::init_buckets() | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |     { | 
					
						
							|  |  |  |         if (this->size_) { | 
					
						
							|  |  |  |             this->cached_begin_bucket_ = this->buckets_; | 
					
						
							|  |  |  |             while (!this->cached_begin_bucket_->next_) | 
					
						
							|  |  |  |                 ++this->cached_begin_bucket_; | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             this->cached_begin_bucket_ = this->get_bucket(this->bucket_count_); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         this->max_load_ = calculate_max_load(); | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |     // After an erase cached_begin_bucket_ might be left pointing to
 | 
					
						
							|  |  |  |     // an empty bucket, so this is called to update it
 | 
					
						
							|  |  |  |     //
 | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  |     // no throw
 | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-20 08:03:26 +00:00
										 |  |  |     template <class T> | 
					
						
							|  |  |  |     inline void hash_table<T>::recompute_begin_bucket(bucket_ptr b) | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |         BOOST_ASSERT(!(b < this->cached_begin_bucket_)); | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |         if(b == this->cached_begin_bucket_) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             if (this->size_ != 0) { | 
					
						
							|  |  |  |                 while (!this->cached_begin_bucket_->next_) | 
					
						
							|  |  |  |                     ++this->cached_begin_bucket_; | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 this->cached_begin_bucket_ = | 
					
						
							|  |  |  |                     this->get_bucket(this->bucket_count_); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |     // This is called when a range has been erased
 | 
					
						
							|  |  |  |     //
 | 
					
						
							|  |  |  |     // no throw
 | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-20 08:03:26 +00:00
										 |  |  |     template <class T> | 
					
						
							|  |  |  |     inline void hash_table<T>::recompute_begin_bucket( | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |         bucket_ptr b1, bucket_ptr b2) | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |         BOOST_ASSERT(!(b1 < this->cached_begin_bucket_) && !(b2 < b1)); | 
					
						
							|  |  |  |         BOOST_ASSERT(BOOST_UNORDERED_BORLAND_BOOL(b2->next_)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if(b1 == this->cached_begin_bucket_ && !b1->next_) | 
					
						
							|  |  |  |             this->cached_begin_bucket_ = b2; | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |     // no throw
 | 
					
						
							| 
									
										
										
										
											2009-11-20 08:03:26 +00:00
										 |  |  |     template <class T> | 
					
						
							|  |  |  |     inline float hash_table<T>::load_factor() const | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |     { | 
					
						
							|  |  |  |         BOOST_ASSERT(this->bucket_count_ != 0); | 
					
						
							|  |  |  |         return static_cast<float>(this->size_) | 
					
						
							|  |  |  |             / static_cast<float>(this->bucket_count_); | 
					
						
							| 
									
										
										
										
											2009-10-04 10:37:56 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     ////////////////////////////////////////////////////////////////////////////
 | 
					
						
							|  |  |  |     // Constructors
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-20 08:03:26 +00:00
										 |  |  |     template <class T> | 
					
						
							|  |  |  |     hash_table<T>::hash_table(std::size_t num_buckets, | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |         hasher const& hf, key_equal const& eq, node_allocator const& a) | 
					
						
							| 
									
										
										
										
											2009-09-21 21:17:19 +00:00
										 |  |  |       : buckets(a, next_prime(num_buckets)), | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |         base(hf, eq), | 
					
						
							|  |  |  |         size_(), | 
					
						
							|  |  |  |         mlf_(1.0f), | 
					
						
							|  |  |  |         cached_begin_bucket_(), | 
					
						
							|  |  |  |         max_load_(0) | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  |     { | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Copy Construct with allocator
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-20 08:03:26 +00:00
										 |  |  |     template <class T> | 
					
						
							|  |  |  |     hash_table<T>::hash_table(hash_table const& x, | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |         node_allocator const& a) | 
					
						
							|  |  |  |       : buckets(a, x.min_buckets_for_size(x.size_)), | 
					
						
							|  |  |  |         base(x), | 
					
						
							|  |  |  |         size_(x.size_), | 
					
						
							|  |  |  |         mlf_(x.mlf_), | 
					
						
							|  |  |  |         cached_begin_bucket_(), | 
					
						
							|  |  |  |         max_load_(0) | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |         if(x.size_) { | 
					
						
							|  |  |  |             x.copy_buckets_to(*this); | 
					
						
							|  |  |  |             this->init_buckets(); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Move Construct
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-20 08:03:26 +00:00
										 |  |  |     template <class T> | 
					
						
							|  |  |  |     hash_table<T>::hash_table(hash_table& x, move_tag) | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |       : buckets(x.node_alloc(), x.bucket_count_), | 
					
						
							|  |  |  |         base(x), | 
					
						
							|  |  |  |         size_(0), | 
					
						
							|  |  |  |         mlf_(1.0f), | 
					
						
							|  |  |  |         cached_begin_bucket_(), | 
					
						
							|  |  |  |         max_load_(0) | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |         this->partial_swap(x); | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-20 08:03:26 +00:00
										 |  |  |     template <class T> | 
					
						
							|  |  |  |     hash_table<T>::hash_table(hash_table& x, | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |         node_allocator const& a, move_tag) | 
					
						
							|  |  |  |       : buckets(a, x.bucket_count_), | 
					
						
							|  |  |  |         base(x), | 
					
						
							|  |  |  |         size_(0), | 
					
						
							|  |  |  |         mlf_(x.mlf_), | 
					
						
							|  |  |  |         cached_begin_bucket_(), | 
					
						
							|  |  |  |         max_load_(0) | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |         if(a == x.node_alloc()) { | 
					
						
							|  |  |  |             this->partial_swap(x); | 
					
						
							| 
									
										
										
										
											2009-09-04 07:03:04 +00:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |         else if(x.size_) { | 
					
						
							|  |  |  |             x.copy_buckets_to(*this); | 
					
						
							| 
									
										
										
										
											2009-09-04 07:03:04 +00:00
										 |  |  |             this->size_ = x.size_; | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |             this->init_buckets(); | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-20 08:03:26 +00:00
										 |  |  |     template <class T> | 
					
						
							|  |  |  |     hash_table<T>& hash_table<T>::operator=( | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |         hash_table const& x) | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |         hash_table tmp(x, this->node_alloc()); | 
					
						
							|  |  |  |         this->fast_swap(tmp); | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  |         return *this; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ////////////////////////////////////////////////////////////////////////////
 | 
					
						
							|  |  |  |     // Swap & Move
 | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     // Swap
 | 
					
						
							|  |  |  |     //
 | 
					
						
							|  |  |  |     // Strong exception safety
 | 
					
						
							|  |  |  |     //
 | 
					
						
							|  |  |  |     // Can throw if hash or predicate object's copy constructor throws
 | 
					
						
							|  |  |  |     // or if allocators are unequal.
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-20 08:03:26 +00:00
										 |  |  |     template <class T> | 
					
						
							|  |  |  |     inline void hash_table<T>::partial_swap(hash_table& x) | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |         this->buckets::swap(x); // No throw
 | 
					
						
							|  |  |  |         std::swap(this->size_, x.size_); | 
					
						
							|  |  |  |         std::swap(this->mlf_, x.mlf_); | 
					
						
							|  |  |  |         std::swap(this->cached_begin_bucket_, x.cached_begin_bucket_); | 
					
						
							|  |  |  |         std::swap(this->max_load_, x.max_load_); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-20 08:03:26 +00:00
										 |  |  |     template <class T> | 
					
						
							|  |  |  |     inline void hash_table<T>::fast_swap(hash_table& x) | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  |         // These can throw, but they only affect the function objects
 | 
					
						
							|  |  |  |         // that aren't in use so it is strongly exception safe, via.
 | 
					
						
							|  |  |  |         // double buffering.
 | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |         { | 
					
						
							| 
									
										
										
										
											2009-11-20 08:03:26 +00:00
										 |  |  |             set_hash_functions<hasher, key_equal> op1(*this, x); | 
					
						
							|  |  |  |             set_hash_functions<hasher, key_equal> op2(x, *this); | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |             op1.commit(); | 
					
						
							|  |  |  |             op2.commit(); | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |         this->buckets::swap(x); // No throw
 | 
					
						
							|  |  |  |         std::swap(this->size_, x.size_); | 
					
						
							|  |  |  |         std::swap(this->mlf_, x.mlf_); | 
					
						
							|  |  |  |         std::swap(this->cached_begin_bucket_, x.cached_begin_bucket_); | 
					
						
							|  |  |  |         std::swap(this->max_load_, x.max_load_); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-20 08:03:26 +00:00
										 |  |  |     template <class T> | 
					
						
							|  |  |  |     inline void hash_table<T>::slow_swap(hash_table& x) | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |     { | 
					
						
							|  |  |  |         if(this == &x) return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             // These can throw, but they only affect the function objects
 | 
					
						
							|  |  |  |             // that aren't in use so it is strongly exception safe, via.
 | 
					
						
							|  |  |  |             // double buffering.
 | 
					
						
							| 
									
										
										
										
											2009-11-20 08:03:26 +00:00
										 |  |  |             set_hash_functions<hasher, key_equal> op1(*this, x); | 
					
						
							|  |  |  |             set_hash_functions<hasher, key_equal> op2(x, *this); | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |          | 
					
						
							| 
									
										
										
										
											2009-09-04 07:03:04 +00:00
										 |  |  |             // Create new buckets in separate hash_buckets objects
 | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  |             // which will clean up if anything throws an exception.
 | 
					
						
							|  |  |  |             // (all can throw, but with no effect as these are new objects).
 | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |          | 
					
						
							|  |  |  |             buckets b1(this->node_alloc(), x.min_buckets_for_size(x.size_)); | 
					
						
							|  |  |  |             if(x.size_) x.copy_buckets_to(b1); | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |             buckets b2(x.node_alloc(), this->min_buckets_for_size(this->size_)); | 
					
						
							|  |  |  |             if(this->size_) copy_buckets_to(b2); | 
					
						
							|  |  |  |          | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  |             // Modifying the data, so no throw from now on.
 | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |          | 
					
						
							|  |  |  |             b1.swap(*this); | 
					
						
							|  |  |  |             b2.swap(x); | 
					
						
							|  |  |  |             op1.commit(); | 
					
						
							|  |  |  |             op2.commit(); | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |          | 
					
						
							|  |  |  |         std::swap(this->size_, x.size_); | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |         if(this->buckets_) this->init_buckets(); | 
					
						
							|  |  |  |         if(x.buckets_) x.init_buckets(); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-20 08:03:26 +00:00
										 |  |  |     template <class T> | 
					
						
							|  |  |  |     void hash_table<T>::swap(hash_table& x) | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |     { | 
					
						
							|  |  |  |         if(this->node_alloc() == x.node_alloc()) { | 
					
						
							|  |  |  |             if(this != &x) this->fast_swap(x); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else { | 
					
						
							|  |  |  |             this->slow_swap(x); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  |      | 
					
						
							|  |  |  |     // Move
 | 
					
						
							|  |  |  |     //
 | 
					
						
							|  |  |  |     // Strong exception safety (might change unused function objects)
 | 
					
						
							|  |  |  |     //
 | 
					
						
							|  |  |  |     // Can throw if hash or predicate object's copy constructor throws
 | 
					
						
							|  |  |  |     // or if allocators are unequal.
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-20 08:03:26 +00:00
										 |  |  |     template <class T> | 
					
						
							|  |  |  |     void hash_table<T>::move(hash_table& x) | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  |     { | 
					
						
							|  |  |  |         // This can throw, but it only affects the function objects
 | 
					
						
							|  |  |  |         // that aren't in use so it is strongly exception safe, via.
 | 
					
						
							|  |  |  |         // double buffering.
 | 
					
						
							| 
									
										
										
										
											2009-11-20 08:03:26 +00:00
										 |  |  |         set_hash_functions<hasher, key_equal> new_func_this(*this, x); | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if(this->node_alloc() == x.node_alloc()) { | 
					
						
							| 
									
										
										
										
											2009-09-04 07:03:04 +00:00
										 |  |  |             this->buckets::move(x); // no throw
 | 
					
						
							|  |  |  |             this->size_ = x.size_; | 
					
						
							|  |  |  |             this->cached_begin_bucket_ = x.cached_begin_bucket_; | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |             this->max_load_ = x.max_load_; | 
					
						
							| 
									
										
										
										
											2009-09-04 07:03:04 +00:00
										 |  |  |             x.size_ = 0; | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  |         } | 
					
						
							|  |  |  |         else { | 
					
						
							|  |  |  |             // Create new buckets in separate HASH_TABLE_DATA objects
 | 
					
						
							|  |  |  |             // which will clean up if anything throws an exception.
 | 
					
						
							|  |  |  |             // (all can throw, but with no effect as these are new objects).
 | 
					
						
							|  |  |  |              | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |             buckets b(this->node_alloc(), x.min_buckets_for_size(x.size_)); | 
					
						
							|  |  |  |             if(x.size_) x.copy_buckets_to(b); | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |             // Start updating the data here, no throw from now on.
 | 
					
						
							| 
									
										
										
										
											2009-09-04 07:03:04 +00:00
										 |  |  |             this->size_ = x.size_; | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |             b.swap(*this); | 
					
						
							|  |  |  |             this->init_buckets(); | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // We've made it, the rest is no throw.
 | 
					
						
							|  |  |  |         this->mlf_ = x.mlf_; | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |         new_func_this.commit(); | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  |     } | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     ////////////////////////////////////////////////////////////////////////////
 | 
					
						
							|  |  |  |     // Reserve & Rehash
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // basic exception safety
 | 
					
						
							| 
									
										
										
										
											2009-11-20 08:03:26 +00:00
										 |  |  |     template <class T> | 
					
						
							|  |  |  |     inline void hash_table<T>::create_for_insert(std::size_t size) | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2009-09-22 22:39:00 +00:00
										 |  |  |         this->bucket_count_ = (std::max)(this->bucket_count_, | 
					
						
							|  |  |  |             this->min_buckets_for_size(size)); | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |         this->create_buckets(); | 
					
						
							|  |  |  |         this->init_buckets(); | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // basic exception safety
 | 
					
						
							| 
									
										
										
										
											2009-11-20 08:03:26 +00:00
										 |  |  |     template <class T> | 
					
						
							|  |  |  |     inline bool hash_table<T>::reserve_for_insert(std::size_t size) | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2009-09-21 21:17:19 +00:00
										 |  |  |         if(size >= max_load_) { | 
					
						
							|  |  |  |             std::size_t num_buckets | 
					
						
							| 
									
										
										
										
											2009-09-21 21:18:21 +00:00
										 |  |  |                 = this->min_buckets_for_size((std::max)(size, | 
					
						
							|  |  |  |                     this->size_ + (this->size_ >> 1))); | 
					
						
							| 
									
										
										
										
											2009-09-21 21:17:19 +00:00
										 |  |  |             if(num_buckets != this->bucket_count_) { | 
					
						
							|  |  |  |                 rehash_impl(num_buckets); | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |                 return true; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |          | 
					
						
							|  |  |  |         return false; | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // if hash function throws, basic exception safety
 | 
					
						
							|  |  |  |     // strong otherwise.
 | 
					
						
							| 
									
										
										
										
											2009-10-04 10:37:36 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-20 08:03:26 +00:00
										 |  |  |     template <class T> | 
					
						
							|  |  |  |     inline void hash_table<T>::rehash(std::size_t min_buckets) | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  |     { | 
					
						
							|  |  |  |         using namespace std; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-04 10:37:36 +00:00
										 |  |  |         if(!this->size_) { | 
					
						
							|  |  |  |             if(this->buckets_) this->delete_buckets(); | 
					
						
							| 
									
										
										
										
											2009-09-21 21:17:19 +00:00
										 |  |  |             this->bucket_count_ = next_prime(min_buckets); | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2009-09-21 21:18:01 +00:00
										 |  |  |         else { | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |             // no throw:
 | 
					
						
							| 
									
										
										
										
											2009-10-04 10:37:36 +00:00
										 |  |  |             min_buckets = next_prime((std::max)(min_buckets, | 
					
						
							|  |  |  |                     double_to_size_t(floor(this->size_ / (double) mlf_)) + 1)); | 
					
						
							| 
									
										
										
										
											2009-09-21 21:18:01 +00:00
										 |  |  |             if(min_buckets != this->bucket_count_) rehash_impl(min_buckets); | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // if hash function throws, basic exception safety
 | 
					
						
							|  |  |  |     // strong otherwise
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-20 08:03:26 +00:00
										 |  |  |     template <class T> | 
					
						
							|  |  |  |     void hash_table<T> | 
					
						
							| 
									
										
										
										
											2009-09-21 21:17:19 +00:00
										 |  |  |         ::rehash_impl(std::size_t num_buckets) | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |     {     | 
					
						
							|  |  |  |         hasher const& hf = this->hash_function(); | 
					
						
							| 
									
										
										
										
											2009-09-04 07:03:04 +00:00
										 |  |  |         std::size_t size = this->size_; | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |         bucket_ptr end = this->get_bucket(this->bucket_count_); | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-21 21:17:19 +00:00
										 |  |  |         buckets dst(this->node_alloc(), num_buckets); | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |         dst.create_buckets(); | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |         buckets src(this->node_alloc(), this->bucket_count_); | 
					
						
							|  |  |  |         src.swap(*this); | 
					
						
							|  |  |  |         this->size_ = 0; | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |         for(bucket_ptr bucket = this->cached_begin_bucket_; | 
					
						
							|  |  |  |             bucket != end; ++bucket) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             node_ptr group = bucket->next_; | 
					
						
							|  |  |  |             while(group) { | 
					
						
							|  |  |  |                 // Move the first group of equivalent nodes in bucket to dst.
 | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |                 // This next line throws iff the hash function throws.
 | 
					
						
							|  |  |  |                 bucket_ptr dst_bucket = dst.bucket_ptr_from_hash( | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |                     hf(get_key_from_ptr(group))); | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |                 node_ptr& next_group = node::next_group(group); | 
					
						
							|  |  |  |                 bucket->next_ = next_group; | 
					
						
							|  |  |  |                 next_group = dst_bucket->next_; | 
					
						
							|  |  |  |                 dst_bucket->next_ = group; | 
					
						
							|  |  |  |                 group = bucket->next_; | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2009-09-04 07:03:04 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         // Swap the new nodes back into the container and setup the local
 | 
					
						
							|  |  |  |         // variables.
 | 
					
						
							|  |  |  |         this->size_ = size; | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |         dst.swap(*this);                        // no throw
 | 
					
						
							|  |  |  |         this->init_buckets(); | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-04 07:03:04 +00:00
										 |  |  |     ////////////////////////////////////////////////////////////////////////////
 | 
					
						
							|  |  |  |     // copy_buckets_to
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  |     // copy_buckets_to
 | 
					
						
							|  |  |  |     //
 | 
					
						
							|  |  |  |     // basic excpetion safety. If an exception is thrown this will
 | 
					
						
							|  |  |  |     // leave dst partially filled.
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-20 08:03:26 +00:00
										 |  |  |     template <class T> | 
					
						
							|  |  |  |     void hash_table<T> | 
					
						
							| 
									
										
										
										
											2009-09-04 07:03:04 +00:00
										 |  |  |         ::copy_buckets_to(buckets& dst) const | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |         BOOST_ASSERT(this->buckets_ && !dst.buckets_); | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         hasher const& hf = this->hash_function(); | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |         bucket_ptr end = this->get_bucket(this->bucket_count_); | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-20 08:03:26 +00:00
										 |  |  |         node_constructor a(dst); | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |         dst.create_buckets(); | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         // no throw:
 | 
					
						
							|  |  |  |         for(bucket_ptr i = this->cached_begin_bucket_; i != end; ++i) { | 
					
						
							|  |  |  |             // no throw:
 | 
					
						
							|  |  |  |             for(node_ptr it = i->next_; it;) { | 
					
						
							|  |  |  |                 // hash function can throw.
 | 
					
						
							|  |  |  |                 bucket_ptr dst_bucket = dst.bucket_ptr_from_hash( | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |                     hf(get_key_from_ptr(it))); | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  |                 // throws, strong
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 node_ptr group_end = node::next_group(it); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 a.construct(node::get_value(it)); | 
					
						
							|  |  |  |                 node_ptr n = a.release(); | 
					
						
							| 
									
										
										
										
											2009-09-03 07:36:21 +00:00
										 |  |  |                 node::add_to_bucket(n, *dst_bucket); | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  |          | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |                 for(it = it->next_; it != group_end; it = it->next_) { | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  |                     a.construct(node::get_value(it)); | 
					
						
							| 
									
										
										
										
											2009-09-03 07:36:21 +00:00
										 |  |  |                     node::add_after_node(a.release(), n); | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ////////////////////////////////////////////////////////////////////////////
 | 
					
						
							|  |  |  |     // Misc. key methods
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // strong exception safety
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // count
 | 
					
						
							|  |  |  |     //
 | 
					
						
							|  |  |  |     // strong exception safety, no side effects
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-20 08:03:26 +00:00
										 |  |  |     template <class T> | 
					
						
							|  |  |  |     std::size_t hash_table<T>::count(key_type const& k) const | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  |     { | 
					
						
							|  |  |  |         if(!this->size_) return 0; | 
					
						
							|  |  |  |         node_ptr it = find_iterator(k); // throws, strong
 | 
					
						
							|  |  |  |         return BOOST_UNORDERED_BORLAND_BOOL(it) ? node::group_count(it) : 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // find
 | 
					
						
							|  |  |  |     //
 | 
					
						
							|  |  |  |     // strong exception safety, no side effects
 | 
					
						
							| 
									
										
										
										
											2009-11-20 08:03:26 +00:00
										 |  |  |     template <class T> | 
					
						
							|  |  |  |     BOOST_DEDUCED_TYPENAME T::iterator_base | 
					
						
							|  |  |  |         hash_table<T>::find(key_type const& k) const | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  |     { | 
					
						
							|  |  |  |         if(!this->size_) return this->end(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         bucket_ptr bucket = this->get_bucket(this->bucket_index(k)); | 
					
						
							|  |  |  |         node_ptr it = find_iterator(bucket, k); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (BOOST_UNORDERED_BORLAND_BOOL(it)) | 
					
						
							|  |  |  |             return iterator_base(bucket, it); | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |             return this->end(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-15 22:53:33 +00:00
										 |  |  |     template <class T> | 
					
						
							|  |  |  |     template <class Key, class Hash, class Pred> | 
					
						
							|  |  |  |     BOOST_DEDUCED_TYPENAME T::iterator_base hash_table<T>::find(Key const& k, | 
					
						
							|  |  |  |         Hash const& h, Pred const& eq) const | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if(!this->size_) return this->end(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         bucket_ptr bucket = this->get_bucket(h(k) % this->bucket_count_); | 
					
						
							|  |  |  |         node_ptr it = find_iterator(bucket, k, eq); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (BOOST_UNORDERED_BORLAND_BOOL(it)) | 
					
						
							|  |  |  |             return iterator_base(bucket, it); | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |             return this->end(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-20 08:03:26 +00:00
										 |  |  |     template <class T> | 
					
						
							|  |  |  |     BOOST_DEDUCED_TYPENAME T::value_type& | 
					
						
							|  |  |  |         hash_table<T>::at(key_type const& k) const | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  |     { | 
					
						
							|  |  |  |         if(!this->size_) | 
					
						
							| 
									
										
										
										
											2010-03-31 21:42:08 +00:00
										 |  |  |             boost::throw_exception(std::out_of_range("Unable to find key in unordered_map.")); | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         bucket_ptr bucket = this->get_bucket(this->bucket_index(k)); | 
					
						
							|  |  |  |         node_ptr it = find_iterator(bucket, k); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-31 21:42:08 +00:00
										 |  |  |         if (!it) | 
					
						
							|  |  |  |             boost::throw_exception(std::out_of_range("Unable to find key in unordered_map.")); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return node::get_value(it); | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // equal_range
 | 
					
						
							|  |  |  |     //
 | 
					
						
							|  |  |  |     // strong exception safety, no side effects
 | 
					
						
							| 
									
										
										
										
											2009-11-20 08:03:26 +00:00
										 |  |  |     template <class T> | 
					
						
							|  |  |  |     BOOST_DEDUCED_TYPENAME T::iterator_pair | 
					
						
							|  |  |  |         hash_table<T>::equal_range(key_type const& k) const | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  |     { | 
					
						
							|  |  |  |         if(!this->size_) | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |             return iterator_pair(this->end(), this->end()); | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         bucket_ptr bucket = this->get_bucket(this->bucket_index(k)); | 
					
						
							|  |  |  |         node_ptr it = find_iterator(bucket, k); | 
					
						
							|  |  |  |         if (BOOST_UNORDERED_BORLAND_BOOL(it)) { | 
					
						
							|  |  |  |             iterator_base first(iterator_base(bucket, it)); | 
					
						
							|  |  |  |             iterator_base second(first); | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |             second.increment_bucket(node::next_group(second.node_)); | 
					
						
							|  |  |  |             return iterator_pair(first, second); | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  |         } | 
					
						
							|  |  |  |         else { | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |             return iterator_pair(this->end(), this->end()); | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2009-09-04 07:03:04 +00:00
										 |  |  |      | 
					
						
							|  |  |  |     ////////////////////////////////////////////////////////////////////////////
 | 
					
						
							|  |  |  |     // Erase methods    
 | 
					
						
							|  |  |  |      | 
					
						
							| 
									
										
										
										
											2009-11-20 08:03:26 +00:00
										 |  |  |     template <class T> | 
					
						
							|  |  |  |     void hash_table<T>::clear() | 
					
						
							| 
									
										
										
										
											2009-09-04 07:03:04 +00:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |         if(!this->size_) return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         bucket_ptr end = this->get_bucket(this->bucket_count_); | 
					
						
							|  |  |  |         for(bucket_ptr begin = this->buckets_; begin != end; ++begin) { | 
					
						
							| 
									
										
										
										
											2009-09-04 07:03:04 +00:00
										 |  |  |             this->clear_bucket(begin); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         this->size_ = 0; | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |         this->cached_begin_bucket_ = end; | 
					
						
							| 
									
										
										
										
											2009-09-04 07:03:04 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-20 08:03:26 +00:00
										 |  |  |     template <class T> | 
					
						
							|  |  |  |     inline std::size_t hash_table<T>::erase_group( | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |         node_ptr* it, bucket_ptr bucket) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         node_ptr pos = *it; | 
					
						
							|  |  |  |         node_ptr end = node::next_group(pos); | 
					
						
							|  |  |  |         *it = end; | 
					
						
							|  |  |  |         std::size_t count = this->delete_nodes(pos, end); | 
					
						
							|  |  |  |         this->size_ -= count; | 
					
						
							|  |  |  |         this->recompute_begin_bucket(bucket); | 
					
						
							|  |  |  |         return count; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |      | 
					
						
							| 
									
										
										
										
											2009-11-20 08:03:26 +00:00
										 |  |  |     template <class T> | 
					
						
							|  |  |  |     std::size_t hash_table<T>::erase_key(key_type const& k) | 
					
						
							| 
									
										
										
										
											2009-09-04 07:03:04 +00:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |         if(!this->size_) return 0; | 
					
						
							|  |  |  |      | 
					
						
							| 
									
										
										
										
											2009-09-04 07:03:04 +00:00
										 |  |  |         // No side effects in initial section
 | 
					
						
							|  |  |  |         bucket_ptr bucket = this->get_bucket(this->bucket_index(k)); | 
					
						
							|  |  |  |         node_ptr* it = this->find_for_erase(bucket, k); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // No throw.
 | 
					
						
							|  |  |  |         return *it ? this->erase_group(it, bucket) : 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-15 22:52:52 +00:00
										 |  |  |     template <class T> | 
					
						
							|  |  |  |     void hash_table<T>::erase(iterator_base r) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         BOOST_ASSERT(r.node_); | 
					
						
							|  |  |  |         --this->size_; | 
					
						
							|  |  |  |         node::unlink_node(*r.bucket_, r.node_); | 
					
						
							|  |  |  |         this->delete_node(r.node_); | 
					
						
							|  |  |  |         // r has been invalidated but its bucket is still valid
 | 
					
						
							|  |  |  |         this->recompute_begin_bucket(r.bucket_); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2009-09-04 07:03:04 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-20 08:03:26 +00:00
										 |  |  |     template <class T> | 
					
						
							|  |  |  |     BOOST_DEDUCED_TYPENAME T::iterator_base | 
					
						
							| 
									
										
										
										
											2009-12-15 22:52:52 +00:00
										 |  |  |         hash_table<T>::erase_return_iterator(iterator_base r) | 
					
						
							| 
									
										
										
										
											2009-09-04 07:03:04 +00:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |         BOOST_ASSERT(r.node_); | 
					
						
							| 
									
										
										
										
											2009-09-04 07:03:04 +00:00
										 |  |  |         iterator_base next = r; | 
					
						
							|  |  |  |         next.increment(); | 
					
						
							|  |  |  |         --this->size_; | 
					
						
							|  |  |  |         node::unlink_node(*r.bucket_, r.node_); | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |         this->delete_node(r.node_); | 
					
						
							| 
									
										
										
										
											2009-09-04 07:03:04 +00:00
										 |  |  |         // r has been invalidated but its bucket is still valid
 | 
					
						
							|  |  |  |         this->recompute_begin_bucket(r.bucket_, next.bucket_); | 
					
						
							|  |  |  |         return next; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-20 08:03:26 +00:00
										 |  |  |     template <class T> | 
					
						
							|  |  |  |     BOOST_DEDUCED_TYPENAME T::iterator_base | 
					
						
							|  |  |  |         hash_table<T>::erase_range( | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |             iterator_base r1, iterator_base r2) | 
					
						
							| 
									
										
										
										
											2009-09-04 07:03:04 +00:00
										 |  |  |     { | 
					
						
							|  |  |  |         if(r1 != r2) | 
					
						
							|  |  |  |         { | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |             BOOST_ASSERT(r1.node_); | 
					
						
							| 
									
										
										
										
											2009-09-04 07:03:04 +00:00
										 |  |  |             if (r1.bucket_ == r2.bucket_) { | 
					
						
							|  |  |  |                 node::unlink_nodes(*r1.bucket_, r1.node_, r2.node_); | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |                 this->size_ -= this->delete_nodes(r1.node_, r2.node_); | 
					
						
							| 
									
										
										
										
											2009-09-04 07:03:04 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |                 // No need to call recompute_begin_bucket because
 | 
					
						
							|  |  |  |                 // the nodes are only deleted from one bucket, which
 | 
					
						
							|  |  |  |                 // still contains r2 after the erase.
 | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |                  BOOST_ASSERT(r1.bucket_->next_); | 
					
						
							| 
									
										
										
										
											2009-09-04 07:03:04 +00:00
										 |  |  |             } | 
					
						
							|  |  |  |             else { | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |                 bucket_ptr end_bucket = r2.node_ ? | 
					
						
							|  |  |  |                     r2.bucket_ : this->get_bucket(this->bucket_count_); | 
					
						
							|  |  |  |                 BOOST_ASSERT(r1.bucket_ < end_bucket); | 
					
						
							| 
									
										
										
										
											2009-09-04 07:03:04 +00:00
										 |  |  |                 node::unlink_nodes(*r1.bucket_, r1.node_, node_ptr()); | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |                 this->size_ -= this->delete_nodes(r1.node_, node_ptr()); | 
					
						
							| 
									
										
										
										
											2009-09-04 07:03:04 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |                 bucket_ptr i = r1.bucket_; | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |                 for(++i; i != end_bucket; ++i) { | 
					
						
							|  |  |  |                     this->size_ -= this->delete_nodes(i->next_, node_ptr()); | 
					
						
							|  |  |  |                     i->next_ = node_ptr(); | 
					
						
							| 
									
										
										
										
											2009-09-04 07:03:04 +00:00
										 |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |                 if(r2.node_) { | 
					
						
							| 
									
										
										
										
											2009-09-04 07:03:04 +00:00
										 |  |  |                     node_ptr first = r2.bucket_->next_; | 
					
						
							|  |  |  |                     node::unlink_nodes(*r2.bucket_, r2.node_); | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |                     this->size_ -= this->delete_nodes(first, r2.node_); | 
					
						
							| 
									
										
										
										
											2009-09-04 07:03:04 +00:00
										 |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 // r1 has been invalidated but its bucket is still
 | 
					
						
							|  |  |  |                 // valid.
 | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |                 this->recompute_begin_bucket(r1.bucket_, end_bucket); | 
					
						
							| 
									
										
										
										
											2009-09-04 07:03:04 +00:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return r2; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-20 08:03:26 +00:00
										 |  |  |     template <class T> | 
					
						
							|  |  |  |     BOOST_DEDUCED_TYPENAME hash_table<T>::iterator_base | 
					
						
							|  |  |  |         hash_table<T>::emplace_empty_impl_with_node( | 
					
						
							| 
									
										
										
										
											2009-09-21 21:17:19 +00:00
										 |  |  |             node_constructor& a, std::size_t size) | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |     { | 
					
						
							|  |  |  |         key_type const& k = get_key(a.value()); | 
					
						
							|  |  |  |         std::size_t hash_value = this->hash_function()(k); | 
					
						
							| 
									
										
										
										
											2009-09-21 21:17:19 +00:00
										 |  |  |         if(this->buckets_) this->reserve_for_insert(size); | 
					
						
							|  |  |  |         else this->create_for_insert(size); | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |         bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value); | 
					
						
							| 
									
										
										
										
											2009-09-21 21:17:19 +00:00
										 |  |  |         node_ptr n = a.release(); | 
					
						
							|  |  |  |         node::add_to_bucket(n, *bucket); | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |         ++this->size_; | 
					
						
							|  |  |  |         this->cached_begin_bucket_ = bucket; | 
					
						
							| 
									
										
										
										
											2009-09-21 21:17:19 +00:00
										 |  |  |         return iterator_base(bucket, n); | 
					
						
							| 
									
										
										
										
											2009-09-04 07:03:04 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2009-08-30 16:42:28 +00:00
										 |  |  | }} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #endif
 |