diff --git a/include/boost/unordered/detail/allocator_helpers.hpp b/include/boost/unordered/detail/allocator_helpers.hpp index 2c642231..7393df1e 100644 --- a/include/boost/unordered/detail/allocator_helpers.hpp +++ b/include/boost/unordered/detail/allocator_helpers.hpp @@ -23,7 +23,7 @@ # include #endif -namespace boost { namespace unordered_detail { +namespace boost { namespace unordered { namespace detail { // rebind_wrap // @@ -102,7 +102,7 @@ namespace boost { namespace unordered_detail { allocator_array_constructor& operator=( allocator_array_constructor const&); }; -}} +}}} #if defined(BOOST_UNORDERED_USE_ALLOCATOR_UTILITIES) # undef BOOST_UNORDERED_USE_ALLOCATOR_UTILITIES diff --git a/include/boost/unordered/detail/buckets.hpp b/include/boost/unordered/detail/buckets.hpp index 913dbcd2..ffa59560 100644 --- a/include/boost/unordered/detail/buckets.hpp +++ b/include/boost/unordered/detail/buckets.hpp @@ -7,177 +7,665 @@ #ifndef BOOST_UNORDERED_DETAIL_MANAGER_HPP_INCLUDED #define BOOST_UNORDERED_DETAIL_MANAGER_HPP_INCLUDED -#include -#include #include -#include -namespace boost { namespace unordered_detail { +namespace boost { namespace unordered { namespace detail { //////////////////////////////////////////////////////////////////////////// - // Buckets + // + // Now the main data structure: + // + // buckets buffered_functions + // | | + // +---------------+--------------+ + // | + // table + // + // T is a class which contains typedefs for all the types we need. - template - inline std::size_t hash_buckets::max_bucket_count() const { - // -1 to account for the sentinel. - return prev_prime(this->bucket_alloc().max_size() - 1); - } + // buckets + // + // This is responsible for allocating and deallocating buckets and nodes. + // + // Notes: + // 1. For the sake exception safety the consturctors don't allocate + // anything. + // 2. It's the callers responsibility to allocate the buckets before calling + // any of the methods (other than getters and setters). - template - inline BOOST_DEDUCED_TYPENAME hash_buckets::bucket_ptr - hash_buckets::get_bucket(std::size_t num) const + template + class buckets { - return buckets_ + static_cast(num); - } + buckets(buckets const&); + buckets& operator=(buckets const&); + public: + // Types - template - inline BOOST_DEDUCED_TYPENAME hash_buckets::bucket_ptr - hash_buckets::bucket_ptr_from_hash(std::size_t hashed) const - { - return get_bucket(hashed % bucket_count_); - } + typedef BOOST_DEDUCED_TYPENAME ::boost::detail::if_true:: + BOOST_NESTED_TEMPLATE then< + ::boost::unordered::detail::ungrouped_node, + ::boost::unordered::detail::grouped_node + >::type node; + + typedef A value_allocator; + typedef ::boost::unordered::detail::bucket bucket; + typedef BOOST_DEDUCED_TYPENAME A::value_type value_type; + + typedef BOOST_DEDUCED_TYPENAME bucket::bucket_allocator + bucket_allocator; + typedef BOOST_DEDUCED_TYPENAME bucket::bucket_ptr bucket_ptr; + typedef BOOST_DEDUCED_TYPENAME bucket::node_ptr node_ptr; + + typedef BOOST_DEDUCED_TYPENAME rebind_wrap::type + node_allocator; + typedef BOOST_DEDUCED_TYPENAME node_allocator::pointer real_node_ptr; + + // Members + + bucket_ptr buckets_; + std::size_t bucket_count_; + ::boost::compressed_pair allocators_; + + // 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 prev_prime(this->bucket_alloc().max_size() - 1); + } + + //////////////////////////////////////////////////////////////////////// + // Constructors and Destructors + + buckets(node_allocator const& a, std::size_t bucket_count) + : buckets_(), + bucket_count_(bucket_count), + allocators_(a,a) + { + } - template - std::size_t hash_buckets::bucket_size(std::size_t index) const - { - if(!buckets_) return 0; - bucket_ptr ptr = get_bucket(index)->next_; - std::size_t count = 0; - while(ptr) { - ++count; + inline ~buckets() + { + if(this->buckets_) { this->delete_buckets(); } + } + + void create_buckets() + { + // The array constructor will clean up in the event of an + // exception. + allocator_array_constructor + constructor(bucket_alloc()); + + // Creates an extra bucket to act as the start node. + constructor.construct(bucket(), this->bucket_count_ + 1); + + // Only release the buckets once everything is successfully + // done. + this->buckets_ = constructor.release(); + } + + // no throw + void swap(buckets& other) + { + BOOST_ASSERT(node_alloc() == other.node_alloc()); + std::swap(buckets_, other.buckets_); + std::swap(bucket_count_, other.bucket_count_); + } + + void move(buckets& other) + { + BOOST_ASSERT(node_alloc() == other.node_alloc()); + if(this->buckets_) { this->delete_buckets(); } + this->buckets_ = other.buckets_; + this->bucket_count_ = other.bucket_count_; + other.buckets_ = bucket_ptr(); + other.bucket_count_ = 0; + } + + std::size_t bucket_size(std::size_t index) const + { + if (!this->buckets_) return 0; + node_ptr ptr = this->buckets_[index].next_; + if (!ptr) return 0; ptr = ptr->next_; - } - return count; - } - - template - inline BOOST_DEDUCED_TYPENAME hash_buckets::node_ptr - hash_buckets::bucket_begin(std::size_t num) const - { - return buckets_ ? get_bucket(num)->next_ : node_ptr(); - } - - //////////////////////////////////////////////////////////////////////////// - // Delete - - template - inline void hash_buckets::delete_node(node_ptr b) - { - node* raw_ptr = static_cast(&*b); - boost::unordered_detail::destroy(raw_ptr->value_ptr()); - real_node_ptr n(node_alloc().address(*raw_ptr)); - node_alloc().destroy(n); - node_alloc().deallocate(n, 1); - } - - template - inline void hash_buckets::clear_bucket(bucket_ptr b) - { - node_ptr node_it = b->next_; - b->next_ = node_ptr(); - - while(node_it) { - node_ptr node_to_delete = node_it; - node_it = node_it->next_; - delete_node(node_to_delete); - } - } - - template - inline void hash_buckets::delete_buckets() - { - bucket_ptr end = this->get_bucket(this->bucket_count_); - - for(bucket_ptr begin = this->buckets_; begin != end; ++begin) { - clear_bucket(begin); - } - - // Destroy the buckets (including the sentinel bucket). - ++end; - for(bucket_ptr begin = this->buckets_; begin != end; ++begin) { - bucket_alloc().destroy(begin); - } - - bucket_alloc().deallocate(this->buckets_, this->bucket_count_ + 1); - - this->buckets_ = bucket_ptr(); - } - - template - inline std::size_t hash_buckets::delete_nodes( - node_ptr begin, node_ptr end) - { - std::size_t count = 0; - while(begin != end) { - node_ptr n = begin; - begin = begin->next_; - delete_node(n); - ++count; - } - return count; - } - - //////////////////////////////////////////////////////////////////////////// - // Constructors and Destructors - - template - inline hash_buckets::hash_buckets( - node_allocator const& a, std::size_t bucket_count) - : buckets_(), - bucket_count_(bucket_count), - allocators_(a,a) - { - } - - template - inline hash_buckets::~hash_buckets() - { - if(this->buckets_) { this->delete_buckets(); } - } - template - inline void hash_buckets::create_buckets() + std::size_t count = 0; + while(BOOST_UNORDERED_BORLAND_BOOL(ptr) && + node::get_hash(ptr) % this->bucket_count_ == index) + { + ++count; + ptr = ptr->next_; + } + + return count; + } + + node_ptr bucket_begin(std::size_t bucket_index) const + { + if (!this->buckets_) return node_ptr(); + bucket& b = this->buckets_[bucket_index]; + if (!b.next_) return node_ptr(); + return b.next_->next_; + } + + // For the remaining functions, buckets_ must not be null. + + bucket_ptr get_bucket(std::size_t bucket_index) const + { + return buckets_ + static_cast(bucket_index); + } + + //////////////////////////////////////////////////////////////////////// + // Delete + + void delete_node(node_ptr n) + { + node* raw_ptr = static_cast(&*n); + real_node_ptr real_ptr(node_alloc().address(*raw_ptr)); + + ::boost::unordered::detail::destroy(raw_ptr->value_ptr()); + node_alloc().destroy(real_ptr); + node_alloc().deallocate(real_ptr, 1); + } + + void delete_buckets() + { + bucket_ptr end = this->get_bucket(this->bucket_count_); + + node_ptr n = (end)->next_; + while(BOOST_UNORDERED_BORLAND_BOOL(n)) + { + node_ptr node_to_delete = n; + n = n->next_; + delete_node(node_to_delete); + } + + ++end; + for(bucket_ptr begin = this->buckets_; begin != end; ++begin) { + bucket_alloc().destroy(begin); + } + + bucket_alloc().deallocate(this->buckets_, this->bucket_count_ + 1); + + this->buckets_ = bucket_ptr(); + } + + std::size_t delete_nodes(node_ptr begin, node_ptr end) + { + std::size_t count = 0; + while(begin != end) { + node_ptr n = begin; + begin = begin->next_; + delete_node(n); + ++count; + } + return count; + } + + // This is called after erasing a node or group of nodes to fix up + // the bucket pointers. + void fix_buckets(bucket_ptr bucket, node_ptr prev, node_ptr next) + { + if (!next) + { + if (bucket->next_ == prev) bucket->next_ = node_ptr(); + } + else + { + bucket_ptr next_bucket = this->get_bucket( + node::get_hash(next) % this->bucket_count_); + if (next_bucket != bucket) + { + next_bucket->next_ = prev; + if (bucket->next_ == prev) bucket->next_ = node_ptr(); + } + } + } + + // This is called after erasing a range of nodes to fix any bucket + // pointers into that range. + void fix_buckets_range( + std::size_t bucket_index, node_ptr prev, node_ptr begin, node_ptr end) + { + node_ptr n = begin; + + // If we're not at the start of the current bucket, then + // go to the start of the next bucket. + if (this->get_bucket(bucket_index)->next_ != prev) + { + for(;;) { + n = n->next_; + if (n == end) return; + + std::size_t new_bucket_index = + node::get_hash(n) % this->bucket_count_; + if (bucket_index != new_bucket_index) { + bucket_index = new_bucket_index; + break; + } + } + } + + // Iterate through the remaining nodes, clearing out the bucket + // pointers. + this->buckets_[bucket_index].next_ = bucket_ptr(); + for(;;) { + n = n->next_; + if (n == end) break; + + std::size_t new_bucket_index = + node::get_hash(n) % this->bucket_count_; + if (bucket_index != new_bucket_index) { + bucket_index = new_bucket_index; + this->buckets_[bucket_index].next_ = bucket_ptr(); + } + }; + + // Finally fix the bucket containing the trailing node. + if (BOOST_UNORDERED_BORLAND_BOOL(n)) { + this->buckets_[node::get_hash(n) % this->bucket_count_].next_ + = prev; + } + } + + // Iterate through the nodes placing them in the correct buckets. + // pre: prev->next_ is not null. + node_ptr place_in_bucket(node_ptr prev, node_ptr end) { + bucket_ptr b = this->get_bucket(node::get_hash(prev->next_) % this->bucket_count_); + + if (!b->next_) { + b->next_ = prev; + return end; + } + else { + node_ptr next = end->next_; + end->next_ = b->next_->next_; + b->next_->next_ = prev->next_; + prev->next_ = next; + return prev; + } + } + + void copy_buckets_to(buckets&) const; + }; + + // Assigning and swapping the equality and hash function objects + // needs strong exception safety. To implement that normally we'd + // require one of them to be known to not throw and the other to + // guarantee strong exception safety. Unfortunately they both only + // have basic exception safety. So to acheive strong exception + // safety we have storage space for two copies, and assign the new + // copies to the unused space. Then switch to using that to use + // them. This is implemented in 'set_hash_functions' which + // atomically assigns the new function objects in a strongly + // exception safe manner. + + template class set_hash_functions; + + template + class buffered_functions { - // The array constructor will clean up in the event of an - // exception. - allocator_array_constructor - constructor(bucket_alloc()); + friend class set_hash_functions; + buffered_functions& operator=(buffered_functions const&); - // Creates an extra bucket to act as a sentinel. - constructor.construct(bucket(), this->bucket_count_ + 1); + typedef ::boost::compressed_pair function_pair; + typedef BOOST_DEDUCED_TYPENAME ::boost::aligned_storage< + sizeof(function_pair), + ::boost::alignment_of::value>::type aligned_function; - // Set up the sentinel (node_ptr cast) - bucket_ptr sentinel = constructor.get() + - static_cast(this->bucket_count_); - sentinel->next_ = sentinel; + bool current_; // The currently active functions. + aligned_function funcs_[2]; - // Only release the buckets once everything is successfully - // done. - this->buckets_ = constructor.release(); - } + function_pair const& current() const { + return *static_cast( + static_cast(&funcs_[current_])); + } + + void construct(bool which, H const& hf, P const& eq) + { + new((void*) &funcs_[which]) function_pair(hf, eq); + } + + void construct(bool which, function_pair const& f) + { + new((void*) &funcs_[which]) function_pair(f); + } + + void destroy(bool which) + { + ::boost::unordered::detail::destroy((function_pair*)(&funcs_[which])); + } + + public: + + buffered_functions(H const& hf, P const& eq) + : current_(false) + { + construct(current_, hf, eq); + } + + buffered_functions(buffered_functions const& bf) + : current_(false) + { + construct(current_, bf.current()); + } + + ~buffered_functions() { + destroy(current_); + } + + H const& hash_function() const { + return current().first(); + } + + P const& key_eq() const { + return current().second(); + } + }; + + template + class set_hash_functions + { + set_hash_functions(set_hash_functions const&); + set_hash_functions& operator=(set_hash_functions const&); + + typedef buffered_functions buffered_functions; + buffered_functions& buffered_functions_; + bool tmp_functions_; + + public: + + set_hash_functions(buffered_functions& f, H const& h, P const& p) + : buffered_functions_(f), + tmp_functions_(!f.current_) + { + f.construct(tmp_functions_, h, p); + } + + set_hash_functions(buffered_functions& f, + buffered_functions const& other) + : buffered_functions_(f), + tmp_functions_(!f.current_) + { + f.construct(tmp_functions_, other.current()); + } + + ~set_hash_functions() + { + buffered_functions_.destroy(tmp_functions_); + } + + void commit() + { + buffered_functions_.current_ = tmp_functions_; + tmp_functions_ = !tmp_functions_; + } + }; //////////////////////////////////////////////////////////////////////////// - // Constructors and Destructors + // Node Constructors - // no throw - template - inline void hash_buckets::move(hash_buckets& other) +#if defined(BOOST_UNORDERED_STD_FORWARD) + + template + inline void construct_impl(T*, void* address, Args&&... args) { - BOOST_ASSERT(node_alloc() == other.node_alloc()); - if(this->buckets_) { this->delete_buckets(); } - this->buckets_ = other.buckets_; - this->bucket_count_ = other.bucket_count_; - other.buckets_ = bucket_ptr(); - other.bucket_count_ = 0; + new(address) T(std::forward(args)...); } - template - inline void hash_buckets::swap(hash_buckets& other) +#if defined(BOOST_UNORDERED_CPP0X_PAIR) + template + inline void construct_impl(std::pair*, void* address, + Key&& k, Arg0&& arg0, Args&&... args) + ) { - BOOST_ASSERT(node_alloc() == other.node_alloc()); - std::swap(buckets_, other.buckets_); - std::swap(bucket_count_, other.bucket_count_); + new(address) std::pair(k, + Second(arg0, std::forward(args)...); } -}} +#endif + +#else + +#define BOOST_UNORDERED_CONSTRUCT_IMPL(z, num_params, _) \ + template < \ + class T, \ + BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params) \ + > \ + inline void construct_impl( \ + T*, void* address, \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params) \ + ) \ + { \ + new(address) T( \ + BOOST_UNORDERED_CALL_PARAMS(z, num_params)); \ + } \ + \ + template \ + inline void construct_impl( \ + std::pair*, void* address, \ + Key const& k, BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \ + { \ + new(address) std::pair(k, \ + Second(BOOST_UNORDERED_CALL_PARAMS(z, num_params))); \ + } + + BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, + BOOST_UNORDERED_CONSTRUCT_IMPL, _) + +#undef BOOST_UNORDERED_CONSTRUCT_IMPL +#endif + + /////////////////////////////////////////////////////////////////// + // + // Node construction + + template + class node_constructor + { + typedef ::boost::unordered::detail::buckets buckets; + typedef BOOST_DEDUCED_TYPENAME buckets::node node; + typedef BOOST_DEDUCED_TYPENAME buckets::real_node_ptr real_node_ptr; + typedef BOOST_DEDUCED_TYPENAME buckets::value_type value_type; + + buckets& buckets_; + real_node_ptr node_; + bool node_constructed_; + bool value_constructed_; + + public: + + node_constructor(buckets& m) : + buckets_(m), + node_(), + node_constructed_(false), + value_constructed_(false) + { + } + + ~node_constructor(); + void construct_preamble(); + +#if defined(BOOST_UNORDERED_STD_FORWARD) + template + void construct(Args&&... args) + { + construct_preamble(); + construct_impl((value_type*) 0, node_->address(), + std::forward(args)...); + value_constructed_ = true; + } +#else + +#define BOOST_UNORDERED_CONSTRUCT(z, num_params, _) \ + template < \ + BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params) \ + > \ + void construct( \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params) \ + ) \ + { \ + construct_preamble(); \ + construct_impl( \ + (value_type*) 0, node_->address(), \ + BOOST_UNORDERED_CALL_PARAMS(z, num_params) \ + ); \ + value_constructed_ = true; \ + } + + BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, + BOOST_UNORDERED_CONSTRUCT, _) + +#undef BOOST_UNORDERED_CONSTRUCT + +#endif + template + void construct_pair(K const& k, M*) + { + construct_preamble(); + new(node_->address()) value_type(k, M()); + value_constructed_ = true; + } + + value_type& value() const + { + BOOST_ASSERT(node_); + return node_->value(); + } + + // no throw + BOOST_DEDUCED_TYPENAME buckets::node_ptr release() + { + real_node_ptr p = node_; + node_ = real_node_ptr(); + // node_ptr cast + return buckets_.bucket_alloc().address(*p); + } + + private: + node_constructor(node_constructor const&); + node_constructor& operator=(node_constructor const&); + }; + + // node_constructor + + template + inline node_constructor::~node_constructor() + { + if (node_) { + if (value_constructed_) { +#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613)) + struct dummy { node x; }; +#endif + ::boost::unordered::detail::destroy(node_->value_ptr()); + } + + if (node_constructed_) + buckets_.node_alloc().destroy(node_); + + buckets_.node_alloc().deallocate(node_, 1); + } + } + + template + inline void node_constructor::construct_preamble() + { + if(!node_) { + node_constructed_ = false; + value_constructed_ = false; + + node_ = buckets_.node_alloc().allocate(1); + buckets_.node_alloc().construct(node_, node()); + node_->init(buckets_.bucket_alloc().address(*node_)); + + node_constructed_ = true; + } + else { + BOOST_ASSERT(node_constructed_ && value_constructed_); + ::boost::unordered::detail::destroy(node_->value_ptr()); + value_constructed_ = false; + } + } + + //////////////////////////////////////////////////////////////////////////// + // copy_buckets_to + // + // basic excpetion safety. If an exception is thrown this will + // leave dst partially filled and the buckets unset. + + template + void buckets::copy_buckets_to(buckets& dst) const + { + BOOST_ASSERT(!dst.buckets_); + + dst.create_buckets(); + bucket_ptr dst_start = dst.get_bucket(dst.bucket_count_); + + { + node_constructor a(dst); + + node_ptr n = this->buckets_[this->bucket_count_].next_; + node_ptr prev = dst_start; + + while(n) { + std::size_t hash = node::get_hash(n); + node_ptr group_end = node::next_group(n); + + a.construct(node::get_value(n)); + node_ptr first_node = a.release(); + node::set_hash(first_node, hash); + node_ptr end = prev->next_ = first_node; + + for(n = n->next_; n != group_end; n = n->next_) { + a.construct(node::get_value(n)); + end = a.release(); + node::set_hash(end, hash); + node::add_after_node(end, first_node); + } + + prev = dst.place_in_bucket(prev, end); + } + } + } + + /////////////////////////////////////////////////////////////////// + // + // Iterators + + // iterator_access is used to access the internal iterator without + // making it publicly available. + + class iterator_access + { + public: + template + static BOOST_DEDUCED_TYPENAME Iterator::node_ptr const& + get(Iterator const& it) + { + return it.node_; + } + }; +}}} #endif diff --git a/include/boost/unordered/detail/equivalent.hpp b/include/boost/unordered/detail/equivalent.hpp index 1c497c32..9da99ba7 100644 --- a/include/boost/unordered/detail/equivalent.hpp +++ b/include/boost/unordered/detail/equivalent.hpp @@ -7,13 +7,12 @@ #ifndef BOOST_UNORDERED_DETAIL_EQUIVALENT_HPP_INCLUDED #define BOOST_UNORDERED_DETAIL_EQUIVALENT_HPP_INCLUDED -#include #include -namespace boost { namespace unordered_detail { +namespace boost { namespace unordered { namespace detail { template - class hash_equivalent_table : public T::table + class equivalent_table : public T::table { public: typedef BOOST_DEDUCED_TYPENAME T::hasher hasher; @@ -27,48 +26,154 @@ namespace boost { namespace unordered_detail { typedef BOOST_DEDUCED_TYPENAME T::node node; typedef BOOST_DEDUCED_TYPENAME T::node_ptr node_ptr; typedef BOOST_DEDUCED_TYPENAME T::bucket_ptr bucket_ptr; - typedef BOOST_DEDUCED_TYPENAME T::iterator_base iterator_base; typedef BOOST_DEDUCED_TYPENAME T::extractor extractor; // Constructors - hash_equivalent_table(std::size_t n, + equivalent_table(std::size_t n, hasher const& hf, key_equal const& eq, value_allocator const& a) : table(n, hf, eq, a) {} - hash_equivalent_table(hash_equivalent_table const& x) + equivalent_table(equivalent_table const& x) : table(x, x.node_alloc()) {} - hash_equivalent_table(hash_equivalent_table const& x, + equivalent_table(equivalent_table const& x, value_allocator const& a) : table(x, a) {} - hash_equivalent_table(hash_equivalent_table& x, move_tag m) + equivalent_table(equivalent_table& x, move_tag m) : table(x, m) {} - hash_equivalent_table(hash_equivalent_table& x, + equivalent_table(equivalent_table& x, value_allocator const& a, move_tag m) : table(x, a, m) {} - ~hash_equivalent_table() {} + ~equivalent_table() {} + // Equality + + bool equals(equivalent_table const& other) const + { + if(this->size_ != other.size_) return false; + if(!this->size_) return true; + + for(node_ptr n1 = this->buckets_[this->bucket_count_].next_; n1;) + { + node_ptr n2 = other.find_matching_node(n1); + if(!n2) return false; + + node_ptr end1 = node::next_group(n1); + node_ptr end2 = node::next_group(n2); + + do { + if(!extractor::compare_mapped( + node::get_value(n1), node::get_value(n2))) + return false; + n1 = n1->next_; + n2 = n2->next_; + } while(n1 != end1 && n2 != end2); + if(n1 != end1 || n2 != end2) return false; + } + + return true; + } + + //////////////////////////////////////////////////////////////////////// + // A convenience method for adding nodes. + + inline node_ptr add_node( + node_constructor& a, + std::size_t bucket_index, + std::size_t hash, + node_ptr pos) + { + node_ptr n = a.release(); + node::set_hash(n, hash); + + if(BOOST_UNORDERED_BORLAND_BOOL(pos)) { + node::add_after_node(n, pos); + if (n->next_) { + std::size_t next_bucket = + node::get_hash(n->next_) % this->bucket_count_; + if (next_bucket != bucket_index) { + this->buckets_[next_bucket].next_ = n; + } + } + } + else { + bucket_ptr b = this->get_bucket(bucket_index); + + if (!b->next_) + { + bucket_ptr start_node = + this->get_bucket(this->bucket_count_); + + if (BOOST_UNORDERED_BORLAND_BOOL(start_node->next_)) { + this->buckets_[ + node::get_hash(start_node->next_) % + this->bucket_count_].next_ = n; + } + + b->next_ = start_node; + n->next_ = start_node->next_; + start_node->next_ = n; + } + else + { + n->next_ = b->next_->next_; + b->next_->next_ = n; + } + } + ++this->size_; + return n; + } + + //////////////////////////////////////////////////////////////////////// // Insert methods - iterator_base emplace_impl(node_constructor& a); - void emplace_impl_no_rehash(node_constructor& a); + node_ptr emplace_impl(node_constructor& a) + { + key_type const& k = this->get_key(a.value()); + std::size_t hash = this->hash_function()(k); + std::size_t bucket_index = hash % this->bucket_count_; + node_ptr position = this->find_node(bucket_index, hash, k); + + // reserve has basic exception safety if the hash function + // throws, strong otherwise. + if(this->reserve_for_insert(this->size_ + 1)) { + bucket_index = hash % this->bucket_count_; + } + + return add_node(a, bucket_index, hash, position); + } - // equals - - bool equals(hash_equivalent_table const&) const; - - inline node_ptr add_node(node_constructor& a, - bucket_ptr bucket, node_ptr pos); + void emplace_impl_no_rehash(node_constructor& a) + { + key_type const& k = this->get_key(a.value()); + std::size_t hash = this->hash_function()(k); + std::size_t bucket_index = hash % this->bucket_count_; + add_node(a, bucket_index, hash, + this->find_node(bucket_index, hash, k)); + } #if defined(BOOST_UNORDERED_STD_FORWARD) template - iterator_base emplace(Args&&... args); + node_ptr emplace(Args&&... args) + { + // Create the node before rehashing in case it throws an + // exception (need strong safety in such a case). + node_constructor a(*this); + a.construct(std::forward(args)...); + + return emplace_impl(a); + } #else -#define BOOST_UNORDERED_INSERT_IMPL(z, n, _) \ - template \ - iterator_base emplace(BOOST_UNORDERED_FUNCTION_PARAMS(z, n)); +#define BOOST_UNORDERED_INSERT_IMPL(z, num_params, _) \ + template \ + node_ptr emplace(BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \ + { \ + node_constructor a(*this); \ + a.construct(BOOST_UNORDERED_CALL_PARAMS(z, num_params)); \ + return emplace_impl(a); \ + } BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, BOOST_UNORDERED_INSERT_IMPL, _) @@ -76,12 +181,51 @@ namespace boost { namespace unordered_detail { #undef BOOST_UNORDERED_INSERT_IMPL #endif + //////////////////////////////////////////////////////////////////////// + // Insert range methods + + // if hash function throws, or inserting > 1 element, basic exception + // safety. Strong otherwise template - void insert_for_range(I i, I j, forward_traversal_tag); + void insert_for_range(I i, I j, forward_traversal_tag) + { + if(i == j) return; + std::size_t distance = ::boost::unordered::detail::distance(i, j); + if(distance == 1) { + emplace(*i); + } + else { + // Only require basic exception safety here + this->reserve_for_insert(this->size_ + distance); + + node_constructor a(*this); + for (; i != j; ++i) { + a.construct(*i); + emplace_impl_no_rehash(a); + } + } + } + template - void insert_for_range(I i, I j, boost::incrementable_traversal_tag); + void insert_for_range(I i, I j, ::boost::incrementable_traversal_tag) + { + node_constructor a(*this); + for (; i != j; ++i) { + a.construct(*i); + emplace_impl(a); + } + } + + // If hash function throws, or inserting > 1 element, basic exception + // safety. Strong otherwise template - void insert_range(I i, I j); + void insert_range(I i, I j) + { + BOOST_DEDUCED_TYPENAME ::boost::iterator_traversal::type + iterator_traversal_tag; + insert_for_range(i, j, iterator_traversal_tag); + } + }; template @@ -90,10 +234,10 @@ namespace boost { namespace unordered_detail { BOOST_DEDUCED_TYPENAME A::value_type, H, P, A, set_extractor, - grouped> + false> { - typedef hash_equivalent_table > impl; - typedef hash_table > table; + typedef equivalent_table > impl; + typedef table > table; }; template @@ -101,204 +245,11 @@ namespace boost { namespace unordered_detail { K, BOOST_DEDUCED_TYPENAME A::value_type, H, P, A, map_extractor, - grouped> + false> { - typedef hash_equivalent_table > impl; - typedef hash_table > table; + typedef equivalent_table > impl; + typedef table > table; }; - - //////////////////////////////////////////////////////////////////////////// - // Equality - - template - bool hash_equivalent_table - ::equals(hash_equivalent_table const& other) const - { - if(this->size_ != other.size_) return false; - if(!this->size_) return true; - - bucket_ptr end = this->get_bucket(this->bucket_count_); - for(bucket_ptr i = this->cached_begin_bucket_; i != end; ++i) - { - node_ptr it1 = i->next_; - while(BOOST_UNORDERED_BORLAND_BOOL(it1)) - { - node_ptr it2 = other.find_iterator(this->get_key_from_ptr(it1)); - if(!BOOST_UNORDERED_BORLAND_BOOL(it2)) return false; - - node_ptr end1 = node::next_group(it1); - node_ptr end2 = node::next_group(it2); - - do { - if(!extractor::compare_mapped( - node::get_value(it1), node::get_value(it2))) - return false; - it1 = it1->next_; - it2 = it2->next_; - } while(it1 != end1 && it2 != end2); - if(it1 != end1 || it2 != end2) return false; - } - } - - return true; - } - - //////////////////////////////////////////////////////////////////////////// - // A convenience method for adding nodes. - - template - inline BOOST_DEDUCED_TYPENAME hash_equivalent_table::node_ptr - hash_equivalent_table - ::add_node(node_constructor& a, bucket_ptr bucket, node_ptr pos) - { - node_ptr n = a.release(); - if(BOOST_UNORDERED_BORLAND_BOOL(pos)) { - node::add_after_node(n, pos); - } - else { - node::add_to_bucket(n, *bucket); - if(bucket < this->cached_begin_bucket_) - this->cached_begin_bucket_ = bucket; - } - ++this->size_; - return n; - } - - //////////////////////////////////////////////////////////////////////////// - // Insert methods - - template - inline BOOST_DEDUCED_TYPENAME - hash_equivalent_table::iterator_base - hash_equivalent_table::emplace_impl(node_constructor& a) - { - key_type const& k = this->get_key(a.value()); - std::size_t hash_value = this->hash_function()(k); - - if(!this->size_) { - return this->emplace_empty_impl_with_node(a, 1); - } - else { - bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value); - node_ptr position = this->find_iterator(bucket, k); - - // reserve has basic exception safety if the hash function - // throws, strong otherwise. - if(this->reserve_for_insert(this->size_ + 1)) - bucket = this->bucket_ptr_from_hash(hash_value); - - return iterator_base(bucket, add_node(a, bucket, position)); - } - } - - template - inline void hash_equivalent_table - ::emplace_impl_no_rehash(node_constructor& a) - { - key_type const& k = this->get_key(a.value()); - bucket_ptr bucket = this->get_bucket(this->bucket_index(k)); - add_node(a, bucket, this->find_iterator(bucket, k)); - } - -#if defined(BOOST_UNORDERED_STD_FORWARD) - - // Emplace (equivalent key containers) - // (I'm using an overloaded emplace for both 'insert' and 'emplace') - - // if hash function throws, basic exception safety - // strong otherwise - template - template - BOOST_DEDUCED_TYPENAME hash_equivalent_table::iterator_base - hash_equivalent_table - ::emplace(Args&&... args) - { - // Create the node before rehashing in case it throws an - // exception (need strong safety in such a case). - node_constructor a(*this); - a.construct(std::forward(args)...); - - return emplace_impl(a); - } - -#else - -#define BOOST_UNORDERED_INSERT_IMPL(z, num_params, _) \ - template \ - template \ - BOOST_DEDUCED_TYPENAME hash_equivalent_table::iterator_base \ - hash_equivalent_table \ - ::emplace(BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \ - { \ - node_constructor a(*this); \ - a.construct(BOOST_UNORDERED_CALL_PARAMS(z, num_params)); \ - return emplace_impl(a); \ - } - - BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, - BOOST_UNORDERED_INSERT_IMPL, _) - -#undef BOOST_UNORDERED_INSERT_IMPL -#endif - - //////////////////////////////////////////////////////////////////////////// - // Insert range methods - - // if hash function throws, or inserting > 1 element, basic exception safety - // strong otherwise - template - template - inline void hash_equivalent_table - ::insert_for_range(I i, I j, forward_traversal_tag) - { - if(i == j) return; - std::size_t distance = unordered_detail::distance(i, j); - if(distance == 1) { - emplace(*i); - } - else { - node_constructor a(*this); - - // Only require basic exception safety here - if(this->size_) { - this->reserve_for_insert(this->size_ + distance); - } - else { - a.construct(*i++); - this->emplace_empty_impl_with_node(a, distance); - } - - for (; i != j; ++i) { - a.construct(*i); - emplace_impl_no_rehash(a); - } - } - } - - // if hash function throws, or inserting > 1 element, basic exception safety - // strong otherwise - template - template - inline void hash_equivalent_table - ::insert_for_range(I i, I j, boost::incrementable_traversal_tag) - { - node_constructor a(*this); - for (; i != j; ++i) { - a.construct(*i); - emplace_impl(a); - } - } - - // if hash function throws, or inserting > 1 element, basic exception safety - // strong otherwise - template - template - void hash_equivalent_table::insert_range(I i, I j) - { - BOOST_DEDUCED_TYPENAME boost::iterator_traversal::type - iterator_traversal_tag; - insert_for_range(i, j, iterator_traversal_tag); - } -}} +}}} #endif diff --git a/include/boost/unordered/detail/extract_key.hpp b/include/boost/unordered/detail/extract_key.hpp index bedb175f..ad90f940 100644 --- a/include/boost/unordered/detail/extract_key.hpp +++ b/include/boost/unordered/detail/extract_key.hpp @@ -6,12 +6,11 @@ #ifndef BOOST_UNORDERED_DETAIL_EXTRACT_KEY_HPP_INCLUDED #define BOOST_UNORDERED_DETAIL_EXTRACT_KEY_HPP_INCLUDED -#include -#include -#include +#include namespace boost { -namespace unordered_detail { +namespace unordered { +namespace detail { // key extractors // @@ -75,7 +74,7 @@ namespace unordered_detail { struct map_extractor { typedef ValueType value_type; - typedef BOOST_DEDUCED_TYPENAME boost::remove_const::type key_type; + typedef BOOST_DEDUCED_TYPENAME ::boost::remove_const::type key_type; static key_type const& extract(value_type const& v) { @@ -143,6 +142,6 @@ namespace unordered_detail { return x.second == y.second; } }; -}} +}}} #endif diff --git a/include/boost/unordered/detail/fwd.hpp b/include/boost/unordered/detail/fwd.hpp deleted file mode 100644 index 471d1d2e..00000000 --- a/include/boost/unordered/detail/fwd.hpp +++ /dev/null @@ -1,932 +0,0 @@ - -// 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) - -// This contains the basic data structure, apart from the actual values. There's -// no construction or deconstruction here. So this only depends on the pointer -// type. - -#ifndef BOOST_UNORDERED_DETAIL_FWD_HPP_INCLUDED -#define BOOST_UNORDERED_DETAIL_FWD_HPP_INCLUDED - -#include -#include -#include -#include -#include -#include -#include - -// This header defines most of the classes used to implement the unordered -// containers. It doesn't include the insert methods as they require a lot -// of preprocessor metaprogramming - they are in unique.hpp and equivalent.hpp. - -// Template parameters: -// -// H = Hash Function -// P = Predicate -// A = Value Allocator -// G = Bucket group policy, 'grouped' or 'ungrouped' -// E = Key Extractor - -#if !defined(BOOST_NO_RVALUE_REFERENCES) && !defined(BOOST_NO_VARIADIC_TEMPLATES) -# if defined(__SGI_STL_PORT) || defined(_STLPORT_VERSION) - // STLport doesn't have std::forward. -# else -# define BOOST_UNORDERED_STD_FORWARD -# endif -#endif - -#if !defined(BOOST_UNORDERED_EMPLACE_LIMIT) -#define BOOST_UNORDERED_EMPLACE_LIMIT 10 -#endif - -#if !defined(BOOST_UNORDERED_STD_FORWARD) - -#include -#include -#include - -#define BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params) \ - BOOST_PP_ENUM_PARAMS_Z(z, num_params, class Arg) -#define BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params) \ - BOOST_PP_ENUM_BINARY_PARAMS_Z(z, num_params, Arg, const& arg) -#define BOOST_UNORDERED_CALL_PARAMS(z, num_params) \ - BOOST_PP_ENUM_PARAMS_Z(z, num_params, arg) - -#endif - -namespace boost { namespace unordered_detail { - - static const float minimum_max_load_factor = 1e-3f; - static const std::size_t default_bucket_count = 11; - struct move_tag {}; - - template class hash_unique_table; - template class hash_equivalent_table; - template - class hash_node_constructor; - template - struct set_extractor; - template - struct map_extractor; - struct no_key; - - // Explicitly call a destructor - -#if defined(BOOST_MSVC) -#pragma warning(push) -#pragma warning(disable:4100) // unreferenced formal parameter -#endif - - template - inline void destroy(T* x) { - x->~T(); - } - -#if defined(BOOST_MSVC) -#pragma warning(pop) -#endif - - //////////////////////////////////////////////////////////////////////////// - // - // This section implements buckets and nodes. Here's a rough - // inheritance diagram, to show how they pull together. - // - // For unordered_set/unordered_map: - // - // hash_bucket - // | - // ungrouped_node_base value_base - // | | - // +--------------+-------------+ - // | - // hash_node - // - // For unordered_multiset/unordered_multimap: - // - // hash_bucket - // | - // grouped_node_base value_base - // | | - // +--------------+-------------+ - // | - // hash_node - - // hash_bucket - // - // hash_bucket is used for both the buckets and as a base class for - // nodes. By using 'bucket_ptr' for 'node_ptr', 'next_' can point - // to either a bucket or a node. This is used later to implement a - // sentinel at the end of the bucket array. - - template - class hash_bucket - { - hash_bucket& operator=(hash_bucket const&); - public: - typedef hash_bucket bucket; - typedef BOOST_DEDUCED_TYPENAME - boost::unordered_detail::rebind_wrap::type - bucket_allocator; - typedef BOOST_DEDUCED_TYPENAME bucket_allocator::pointer bucket_ptr; - typedef bucket_ptr node_ptr; - - node_ptr next_; - - hash_bucket() : next_() {} - }; - - // In containers with equivalent keys (unordered_multimap and - // unordered_multiset) equivalent nodes are grouped together, in - // containers with unique keys (unordered_map and unordered_set) - // individual nodes are treated as groups of one. The following two - // classes implement the data structure. - - // This is used for containers with unique keys. There are no groups - // so it doesn't add any extra members, and just treats individual - // nodes as groups of one. - - template - struct ungrouped_node_base : hash_bucket { - typedef hash_bucket bucket; - typedef BOOST_DEDUCED_TYPENAME bucket::bucket_ptr bucket_ptr; - typedef BOOST_DEDUCED_TYPENAME bucket::node_ptr node_ptr; - - ungrouped_node_base() : bucket() {} - static inline node_ptr& next_group(node_ptr ptr); - static inline std::size_t group_count(node_ptr ptr); - static inline void add_to_bucket(node_ptr n, bucket& b); - static inline void add_after_node(node_ptr n, node_ptr position); - static void unlink_node(bucket& b, node_ptr n); - static void unlink_nodes(bucket& b, node_ptr begin, node_ptr end); - static void unlink_nodes(bucket& b, node_ptr end); - }; - - // This is used for containers with equivalent keys. It implements a - // circular list running in the opposite direction to the linked - // list through the nodes. - - template - struct grouped_node_base : hash_bucket - { - typedef hash_bucket bucket; - typedef BOOST_DEDUCED_TYPENAME bucket::bucket_ptr bucket_ptr; - typedef BOOST_DEDUCED_TYPENAME bucket::node_ptr node_ptr; - - node_ptr group_prev_; - - grouped_node_base() : bucket(), group_prev_() {} - static inline node_ptr& next_group(node_ptr ptr); - static inline node_ptr first_in_group(node_ptr n); - static inline std::size_t group_count(node_ptr ptr); - static inline void add_to_bucket(node_ptr n, bucket& b); - static inline void add_after_node(node_ptr n, node_ptr position); - static void unlink_node(bucket& b, node_ptr n); - static void unlink_nodes(bucket& b, node_ptr begin, node_ptr end); - static void unlink_nodes(bucket& b, node_ptr end); - - private: - static inline node_ptr split_group(node_ptr split); - static inline grouped_node_base& get(node_ptr ptr) { - return static_cast(*ptr); - } - }; - - // These two classes implement an easy way to pass around the node - // group policy classes without the messy template parameters. - // Whenever you see the template parameter 'G' it's one of these. - - struct ungrouped - { - template - struct base { - typedef ungrouped_node_base type; - }; - }; - - struct grouped - { - template - struct base { - typedef grouped_node_base type; - }; - }; - - // The space used to store values in a node. - - template - struct value_base - { - typedef ValueType value_type; - BOOST_DEDUCED_TYPENAME boost::aligned_storage< - sizeof(value_type), - ::boost::alignment_of::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&); - }; - - // Node - - template - class hash_node : - public G::BOOST_NESTED_TEMPLATE base::type, - public value_base - { - public: - typedef BOOST_DEDUCED_TYPENAME A::value_type value_type; - typedef BOOST_DEDUCED_TYPENAME hash_bucket::node_ptr node_ptr; - - static value_type& get_value(node_ptr p) { - return static_cast(*p).value(); - } - static value_type* get_value_ptr(node_ptr p) { - return static_cast(*p).value_ptr(); - } - private: - hash_node& operator=(hash_node const&); - }; - - //////////////////////////////////////////////////////////////////////////// - // - // Iterator Base - // - // This is the iterator used internally, the external iterators are - // provided by lightweight wrappers (hash_iterator and - // hast_const_iterator) which provide the full iterator interface. - - template - class hash_iterator_base - { - public: - typedef A value_allocator; - typedef hash_bucket bucket; - typedef hash_node node; - typedef BOOST_DEDUCED_TYPENAME A::value_type value_type; - typedef BOOST_DEDUCED_TYPENAME bucket::bucket_ptr bucket_ptr; - typedef BOOST_DEDUCED_TYPENAME bucket::node_ptr node_ptr; - - bucket_ptr bucket_; - node_ptr node_; - - hash_iterator_base() : bucket_(), node_() {} - explicit hash_iterator_base(bucket_ptr b) - : bucket_(b), - node_(b ? b->next_ : node_ptr()) {} - hash_iterator_base(bucket_ptr b, node_ptr n) - : bucket_(b), - node_(n) {} - - bool operator==(hash_iterator_base const& x) const { - return node_ == x.node_; } - bool operator!=(hash_iterator_base const& x) const { - return node_ != x.node_; } - value_type& operator*() const { - return node::get_value(node_); - } - - void increment_bucket(node_ptr n) { - while(!n) { - ++bucket_; - n = bucket_->next_; - } - node_ = bucket_ == n ? node_ptr() : n; - } - - void increment() { - increment_bucket(node_->next_); - } - }; - - //////////////////////////////////////////////////////////////////////////// - // - // Now the main data structure: - // - // hash_buckets hash_buffered_functions - // | | - // +-------------+--------------+ - // | - // hash_table - // - // T is a class which contains typedefs for all the types we need. - - // hash_buckets - // - // This is responsible for allocating and deallocating buckets and nodes. - // - // Notes: - // 1. For the sake exception safety the consturctors don't allocate - // anything. - // 2. It's the callers responsibility to allocate the buckets before calling - // any of the methods (other than getters and setters). - - template - class hash_buckets - { - hash_buckets(hash_buckets const&); - hash_buckets& operator=(hash_buckets const&); - public: - // Types - - typedef A value_allocator; - typedef hash_bucket bucket; - typedef hash_iterator_base iterator_base; - typedef BOOST_DEDUCED_TYPENAME A::value_type value_type; - typedef BOOST_DEDUCED_TYPENAME iterator_base::node node; - - typedef BOOST_DEDUCED_TYPENAME bucket::bucket_allocator - bucket_allocator; - typedef BOOST_DEDUCED_TYPENAME bucket::bucket_ptr bucket_ptr; - typedef BOOST_DEDUCED_TYPENAME bucket::node_ptr node_ptr; - - typedef BOOST_DEDUCED_TYPENAME rebind_wrap::type - node_allocator; - typedef BOOST_DEDUCED_TYPENAME node_allocator::pointer real_node_ptr; - - // Members - - bucket_ptr buckets_; - std::size_t bucket_count_; - boost::compressed_pair allocators_; - - // 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; - - // Constructors - - hash_buckets(node_allocator const& a, std::size_t n); - void create_buckets(); - ~hash_buckets(); - - // no throw - void swap(hash_buckets& other); - void move(hash_buckets& other); - - // For the remaining functions, buckets_ must not be null. - - bucket_ptr get_bucket(std::size_t n) const; - bucket_ptr bucket_ptr_from_hash(std::size_t hashed) const; - std::size_t bucket_size(std::size_t index) const; - node_ptr bucket_begin(std::size_t n) const; - - // Alloc/Dealloc - - void delete_node(node_ptr); - - // - void delete_buckets(); - void clear_bucket(bucket_ptr); - std::size_t delete_nodes(node_ptr begin, node_ptr end); - std::size_t delete_to_bucket_end(node_ptr begin); - }; - - // Assigning and swapping the equality and hash function objects - // needs strong exception safety. To implement that normally we'd - // require one of them to be known to not throw and the other to - // guarantee strong exception safety. Unfortunately they both only - // have basic exception safety. So to acheive strong exception - // safety we have storage space for two copies, and assign the new - // copies to the unused space. Then switch to using that to use - // them. This is implemented in 'set_hash_functions' which - // atomically assigns the new function objects in a strongly - // exception safe manner. - - template class set_hash_functions; - - template - class hash_buffered_functions - { - friend class set_hash_functions; - hash_buffered_functions& operator=(hash_buffered_functions const&); - - typedef boost::compressed_pair function_pair; - typedef BOOST_DEDUCED_TYPENAME boost::aligned_storage< - sizeof(function_pair), - ::boost::alignment_of::value>::type aligned_function; - - bool current_; // The currently active functions. - aligned_function funcs_[2]; - - function_pair const& current() const { - return *static_cast( - static_cast(&funcs_[current_])); - } - - void construct(bool which, H const& hf, P const& eq) - { - new((void*) &funcs_[which]) function_pair(hf, eq); - } - - void construct(bool which, function_pair const& f) - { - new((void*) &funcs_[which]) function_pair(f); - } - - void destroy(bool which) - { - boost::unordered_detail::destroy((function_pair*)(&funcs_[which])); - } - - public: - - hash_buffered_functions(H const& hf, P const& eq) - : current_(false) - { - construct(current_, hf, eq); - } - - hash_buffered_functions(hash_buffered_functions const& bf) - : current_(false) - { - construct(current_, bf.current()); - } - - ~hash_buffered_functions() { - destroy(current_); - } - - H const& hash_function() const { - return current().first(); - } - - P const& key_eq() const { - return current().second(); - } - }; - - template - class set_hash_functions - { - set_hash_functions(set_hash_functions const&); - set_hash_functions& operator=(set_hash_functions const&); - - typedef hash_buffered_functions buffered_functions; - buffered_functions& buffered_functions_; - bool tmp_functions_; - - public: - - set_hash_functions(buffered_functions& f, H const& h, P const& p) - : buffered_functions_(f), - tmp_functions_(!f.current_) - { - f.construct(tmp_functions_, h, p); - } - - set_hash_functions(buffered_functions& f, - buffered_functions const& other) - : buffered_functions_(f), - tmp_functions_(!f.current_) - { - f.construct(tmp_functions_, other.current()); - } - - ~set_hash_functions() - { - buffered_functions_.destroy(tmp_functions_); - } - - void commit() - { - buffered_functions_.current_ = tmp_functions_; - tmp_functions_ = !tmp_functions_; - } - }; - - // This implements almost all of the required functionality, apart - // from some things that are specific to containers with unique and - // equivalent keys which is implemented in hash_unique_table and - // hash_equivalent_table. See unique.hpp and equivalent.hpp for - // their declaration and implementation. - - template - class hash_table : public T::buckets, public T::buffered_functions - { - hash_table(hash_table const&); - public: - typedef BOOST_DEDUCED_TYPENAME T::hasher hasher; - typedef BOOST_DEDUCED_TYPENAME T::key_equal key_equal; - typedef BOOST_DEDUCED_TYPENAME T::value_allocator value_allocator; - typedef BOOST_DEDUCED_TYPENAME T::key_type key_type; - typedef BOOST_DEDUCED_TYPENAME T::value_type value_type; - typedef BOOST_DEDUCED_TYPENAME T::buffered_functions base; - typedef BOOST_DEDUCED_TYPENAME T::buckets buckets; - typedef BOOST_DEDUCED_TYPENAME T::extractor extractor; - typedef BOOST_DEDUCED_TYPENAME T::node_constructor node_constructor; - - typedef BOOST_DEDUCED_TYPENAME T::node node; - typedef BOOST_DEDUCED_TYPENAME T::bucket bucket; - typedef BOOST_DEDUCED_TYPENAME T::node_ptr node_ptr; - typedef BOOST_DEDUCED_TYPENAME T::bucket_ptr bucket_ptr; - typedef BOOST_DEDUCED_TYPENAME T::iterator_base iterator_base; - typedef BOOST_DEDUCED_TYPENAME T::node_allocator node_allocator; - typedef BOOST_DEDUCED_TYPENAME T::iterator_pair iterator_pair; - - // Members - - std::size_t size_; - float mlf_; - // Cached data - invalid if !this->buckets_ - bucket_ptr cached_begin_bucket_; - std::size_t max_load_; - - // Helper methods - - key_type const& get_key(value_type const& v) const { - return extractor::extract(v); - } - key_type const& get_key_from_ptr(node_ptr n) const { - return extractor::extract(node::get_value(n)); - } - bool equal(key_type const& k, value_type const& v) const; - template - node_ptr find_iterator(bucket_ptr bucket, Key const& k, - Pred const&) const; - node_ptr find_iterator(bucket_ptr bucket, key_type const& k) const; - node_ptr find_iterator(key_type const& k) const; - node_ptr* find_for_erase(bucket_ptr bucket, key_type const& k) const; - - // Load methods - - std::size_t max_size() const; - std::size_t bucket_index(key_type const& k) const; - void max_load_factor(float z); - std::size_t min_buckets_for_size(std::size_t n) const; - std::size_t calculate_max_load(); - - // Constructors - - hash_table(std::size_t n, hasher const& hf, key_equal const& eq, - node_allocator const& a); - hash_table(hash_table const& x, node_allocator const& a); - hash_table(hash_table& x, move_tag m); - hash_table(hash_table& x, node_allocator const& a, move_tag m); - ~hash_table() {} - hash_table& operator=(hash_table const&); - - // Iterators - - iterator_base begin() const { - return this->size_ ? - iterator_base(this->cached_begin_bucket_) : - iterator_base(); - } - iterator_base end() const { - return iterator_base(); - } - - // Swap & Move - - void swap(hash_table& x); - void fast_swap(hash_table& other); - void slow_swap(hash_table& other); - void partial_swap(hash_table& other); - void move(hash_table& x); - - // Reserve and rehash - - void create_for_insert(std::size_t n); - bool reserve_for_insert(std::size_t n); - void rehash(std::size_t n); - void rehash_impl(std::size_t n); - - // Move/copy buckets - - void move_buckets_to(buckets& dst); - void copy_buckets_to(buckets& dst) const; - - // Misc. key methods - - std::size_t count(key_type const& k) const; - iterator_base find(key_type const& k) const; - template - iterator_base find(Key const& k, Hash const& h, Pred const& eq) const; - value_type& at(key_type const& k) const; - iterator_pair equal_range(key_type const& k) const; - - // Erase - // - // no throw - - void clear(); - std::size_t erase_key(key_type const& k); - iterator_base erase_return_iterator(iterator_base r); - void erase(iterator_base r); - std::size_t erase_group(node_ptr* it, bucket_ptr bucket); - iterator_base erase_range(iterator_base r1, iterator_base r2); - - // recompute_begin_bucket - - void init_buckets(); - - // After an erase cached_begin_bucket_ might be left pointing to - // an empty bucket, so this is called to update it - // - // no throw - - void recompute_begin_bucket(bucket_ptr b); - - // This is called when a range has been erased - // - // no throw - - void recompute_begin_bucket(bucket_ptr b1, bucket_ptr b2); - - // no throw - float load_factor() const; - - iterator_base emplace_empty_impl_with_node( - node_constructor&, std::size_t); - }; - - /////////////////////////////////////////////////////////////////// - // - // Iterators - - // iterator_access is used to access the internal iterator without - // making it publicly available. - - class iterator_access - { - public: - template - static BOOST_DEDUCED_TYPENAME Iterator::base const& - get(Iterator const& it) - { - return it.base_; - } - }; - - template class hash_iterator; - template class hash_const_iterator; - template class hash_local_iterator; - template class hash_const_local_iterator; - - // Local Iterators - // - // all no throw - - template - class hash_local_iterator - : public boost::iterator < - std::forward_iterator_tag, - BOOST_DEDUCED_TYPENAME A::value_type, - std::ptrdiff_t, - BOOST_DEDUCED_TYPENAME A::pointer, - BOOST_DEDUCED_TYPENAME A::reference> - { - public: - typedef BOOST_DEDUCED_TYPENAME A::value_type value_type; - - private: - typedef hash_buckets buckets; - typedef BOOST_DEDUCED_TYPENAME buckets::node_ptr node_ptr; - typedef BOOST_DEDUCED_TYPENAME buckets::node node; - typedef hash_const_local_iterator const_local_iterator; - - friend class hash_const_local_iterator; - node_ptr ptr_; - - public: - hash_local_iterator() : ptr_() {} - explicit hash_local_iterator(node_ptr x) : ptr_(x) {} - BOOST_DEDUCED_TYPENAME A::reference operator*() const { - return node::get_value(ptr_); - } - value_type* operator->() const { - return node::get_value_ptr(ptr_); - } - hash_local_iterator& operator++() { - ptr_ = ptr_->next_; return *this; - } - hash_local_iterator operator++(int) { - hash_local_iterator tmp(ptr_); ptr_ = ptr_->next_; return tmp; } - bool operator==(hash_local_iterator x) const { - return ptr_ == x.ptr_; - } - bool operator==(const_local_iterator x) const { - return ptr_ == x.ptr_; - } - bool operator!=(hash_local_iterator x) const { - return ptr_ != x.ptr_; - } - bool operator!=(const_local_iterator x) const { - return ptr_ != x.ptr_; - } - }; - - template - class hash_const_local_iterator - : public boost::iterator < - std::forward_iterator_tag, - BOOST_DEDUCED_TYPENAME A::value_type, - std::ptrdiff_t, - BOOST_DEDUCED_TYPENAME A::const_pointer, - BOOST_DEDUCED_TYPENAME A::const_reference > - { - public: - typedef BOOST_DEDUCED_TYPENAME A::value_type value_type; - - private: - typedef hash_buckets buckets; - typedef BOOST_DEDUCED_TYPENAME buckets::node_ptr ptr; - typedef BOOST_DEDUCED_TYPENAME buckets::node node; - typedef hash_local_iterator local_iterator; - friend class hash_local_iterator; - ptr ptr_; - - public: - hash_const_local_iterator() : ptr_() {} - explicit hash_const_local_iterator(ptr x) : ptr_(x) {} - hash_const_local_iterator(local_iterator x) : ptr_(x.ptr_) {} - BOOST_DEDUCED_TYPENAME A::const_reference - operator*() const { - return node::get_value(ptr_); - } - value_type const* operator->() const { - return node::get_value_ptr(ptr_); - } - hash_const_local_iterator& operator++() { - ptr_ = ptr_->next_; return *this; - } - hash_const_local_iterator operator++(int) { - hash_const_local_iterator tmp(ptr_); ptr_ = ptr_->next_; return tmp; - } - bool operator==(local_iterator x) const { - return ptr_ == x.ptr_; - } - bool operator==(hash_const_local_iterator x) const { - return ptr_ == x.ptr_; - } - bool operator!=(local_iterator x) const { - return ptr_ != x.ptr_; - } - bool operator!=(hash_const_local_iterator x) const { - return ptr_ != x.ptr_; - } - }; - - // Iterators - // - // all no throw - - - template - class hash_iterator - : public boost::iterator < - std::forward_iterator_tag, - BOOST_DEDUCED_TYPENAME A::value_type, - std::ptrdiff_t, - BOOST_DEDUCED_TYPENAME A::pointer, - BOOST_DEDUCED_TYPENAME A::reference > - { - public: - typedef BOOST_DEDUCED_TYPENAME A::value_type value_type; - - private: - typedef hash_buckets buckets; - typedef BOOST_DEDUCED_TYPENAME buckets::node node; - typedef BOOST_DEDUCED_TYPENAME buckets::iterator_base base; - typedef hash_const_iterator const_iterator; - friend class hash_const_iterator; - base base_; - - public: - - hash_iterator() : base_() {} - explicit hash_iterator(base const& x) : base_(x) {} - BOOST_DEDUCED_TYPENAME A::reference operator*() const { - return *base_; - } - value_type* operator->() const { - return &*base_; - } - hash_iterator& operator++() { - base_.increment(); return *this; - } - hash_iterator operator++(int) { - hash_iterator tmp(base_); base_.increment(); return tmp; - } - bool operator==(hash_iterator const& x) const { - return base_ == x.base_; - } - bool operator==(const_iterator const& x) const { - return base_ == x.base_; - } - bool operator!=(hash_iterator const& x) const { - return base_ != x.base_; - } - bool operator!=(const_iterator const& x) const { - return base_ != x.base_; - } - }; - - template - class hash_const_iterator - : public boost::iterator < - std::forward_iterator_tag, - BOOST_DEDUCED_TYPENAME A::value_type, - std::ptrdiff_t, - BOOST_DEDUCED_TYPENAME A::const_pointer, - BOOST_DEDUCED_TYPENAME A::const_reference > - { - public: - typedef BOOST_DEDUCED_TYPENAME A::value_type value_type; - - private: - typedef hash_buckets buckets; - typedef BOOST_DEDUCED_TYPENAME buckets::node node; - typedef BOOST_DEDUCED_TYPENAME buckets::iterator_base base; - typedef hash_iterator iterator; - friend class hash_iterator; - friend class iterator_access; - base base_; - - public: - - hash_const_iterator() : base_() {} - explicit hash_const_iterator(base const& x) : base_(x) {} - hash_const_iterator(iterator const& x) : base_(x.base_) {} - BOOST_DEDUCED_TYPENAME A::const_reference operator*() const { - return *base_; - } - value_type const* operator->() const { - return &*base_; - } - hash_const_iterator& operator++() { - base_.increment(); return *this; - } - hash_const_iterator operator++(int) { - hash_const_iterator tmp(base_); base_.increment(); return tmp; - } - bool operator==(iterator const& x) const { - return base_ == x.base_; - } - bool operator==(hash_const_iterator const& x) const { - return base_ == x.base_; - } - bool operator!=(iterator const& x) const { - return base_ != x.base_; - } - bool operator!=(hash_const_iterator const& x) const { - return base_ != x.base_; - } - }; - - //////////////////////////////////////////////////////////////////////////// - // - // types - // - // This is used to convieniently pass around a container's typedefs - // without having 7 template parameters. - - template - struct types - { - public: - typedef K key_type; - typedef V value_type; - typedef H hasher; - typedef P key_equal; - typedef A value_allocator; - typedef E extractor; - typedef G group_type; - - typedef hash_node_constructor - node_constructor; - typedef hash_buckets buckets; - typedef hash_buffered_functions buffered_functions; - - typedef BOOST_DEDUCED_TYPENAME buckets::node node; - typedef BOOST_DEDUCED_TYPENAME buckets::bucket bucket; - typedef BOOST_DEDUCED_TYPENAME buckets::node_ptr node_ptr; - typedef BOOST_DEDUCED_TYPENAME buckets::bucket_ptr bucket_ptr; - typedef BOOST_DEDUCED_TYPENAME buckets::iterator_base iterator_base; - typedef BOOST_DEDUCED_TYPENAME buckets::node_allocator node_allocator; - - typedef std::pair iterator_pair; - }; -}} - -#endif diff --git a/include/boost/unordered/detail/move.hpp b/include/boost/unordered/detail/move.hpp index 16fd9212..49fb2a92 100644 --- a/include/boost/unordered/detail/move.hpp +++ b/include/boost/unordered/detail/move.hpp @@ -38,7 +38,8 @@ /*************************************************************************************************/ namespace boost { -namespace unordered_detail { +namespace unordered { +namespace detail { /*************************************************************************************************/ @@ -69,7 +70,7 @@ struct class_has_move_assign { /*************************************************************************************************/ template -struct has_move_assign : boost::mpl::and_, class_has_move_assign > {}; +struct has_move_assign : ::boost::mpl::and_, class_has_move_assign > {}; /*************************************************************************************************/ @@ -83,13 +84,13 @@ class test_can_convert_anything { }; /* REVISIT (sparent@adobe.com): This is a work around for Boost 1.34.1 and VC++ 2008 where - boost::is_convertible fails to compile. + ::boost::is_convertible fails to compile. */ template -struct is_convertible : boost::mpl::or_< - boost::is_same, - boost::is_convertible +struct is_convertible : ::boost::mpl::or_< + ::boost::is_same, + ::boost::is_convertible > { }; /*************************************************************************************************/ @@ -124,10 +125,10 @@ private: \brief The is_movable trait can be used to identify movable types. */ template -struct is_movable : boost::mpl::and_< - boost::is_convertible, T>, +struct is_movable : ::boost::mpl::and_< + ::boost::is_convertible, T>, move_detail::has_move_assign, - boost::mpl::not_ > + ::boost::mpl::not_ > > { }; /*************************************************************************************************/ @@ -138,7 +139,7 @@ struct is_movable : boost::mpl::and_< // unless the trait is specialized. template -struct is_movable : boost::mpl::false_ { }; +struct is_movable : ::boost::mpl::false_ { }; #endif @@ -158,10 +159,10 @@ struct is_movable : boost::mpl::false_ { }; template -struct copy_sink : boost::enable_if< - boost::mpl::and_< - boost::unordered_detail::move_detail::is_convertible, - boost::mpl::not_ > +struct copy_sink : ::boost::enable_if< + ::boost::mpl::and_< + ::boost::unordered::detail::move_detail::is_convertible, + ::boost::mpl::not_ > >, R > @@ -179,9 +180,9 @@ struct copy_sink : boost::enable_if< template -struct move_sink : boost::enable_if< - boost::mpl::and_< - boost::unordered_detail::move_detail::is_convertible, +struct move_sink : ::boost::enable_if< + ::boost::mpl::and_< + ::boost::unordered::detail::move_detail::is_convertible, is_movable >, R @@ -233,7 +234,8 @@ T& move(T& x) { #endif // BOOST_NO_SFINAE -} // namespace unordered_detail +} // namespace detail +} // namespace unordered } // namespace boost /*************************************************************************************************/ diff --git a/include/boost/unordered/detail/node.hpp b/include/boost/unordered/detail/node.hpp index 85a31410..1a500029 100644 --- a/include/boost/unordered/detail/node.hpp +++ b/include/boost/unordered/detail/node.hpp @@ -11,10 +11,7 @@ #ifndef BOOST_UNORDERED_DETAIL_NODE_HPP_INCLUDED #define BOOST_UNORDERED_DETAIL_NODE_HPP_INCLUDED -#include -#include -#include -#include +#include #if BOOST_WORKAROUND(__BORLANDC__, <= 0X0582) #define BOOST_UNORDERED_BORLAND_BOOL(x) (bool)(x) @@ -22,205 +19,342 @@ #define BOOST_UNORDERED_BORLAND_BOOL(x) x #endif -namespace boost { namespace unordered_detail { +namespace boost { namespace unordered { namespace detail { //////////////////////////////////////////////////////////////////////////// - // ungrouped node implementation + // + // This section implements buckets and nodes. Here's a rough + // inheritance diagram, to show how they pull together. + // + // For unordered_set/unordered_map: + // + // bucket value_base + // | | + // +--------------+-------------+ + // | + // ungrouped_node + // + // For unordered_multiset/unordered_multimap: + // + // bucket value_base + // | | + // +--------------+-------------+ + // | + // grouped_node + + // bucket + // + // bucket is used for both the buckets and as a base class for + // nodes. By using 'bucket_ptr' for 'node_ptr', 'next_' can point + // to either a bucket or a node. This is used later to implement a + // sentinel at the end of the bucket array. template - inline BOOST_DEDUCED_TYPENAME ungrouped_node_base::node_ptr& - ungrouped_node_base::next_group(node_ptr ptr) + class bucket { - return ptr->next_; - } - - template - inline std::size_t ungrouped_node_base::group_count(node_ptr) - { - return 1; - } - - template - inline void ungrouped_node_base::add_to_bucket(node_ptr n, bucket& b) - { - n->next_ = b.next_; - b.next_ = n; - } - - template - inline void ungrouped_node_base::add_after_node(node_ptr n, - node_ptr position) - { - n->next_ = position->next_; - position->next_ = position; - } + bucket& operator=(bucket const&); + public: + typedef BOOST_DEDUCED_TYPENAME + ::boost::unordered::detail::rebind_wrap::type + bucket_allocator; + typedef BOOST_DEDUCED_TYPENAME bucket_allocator::pointer bucket_ptr; + typedef bucket_ptr node_ptr; - template - inline void ungrouped_node_base::unlink_nodes(bucket& b, - node_ptr begin, node_ptr end) + node_ptr next_; + + bucket() : next_() {} + }; + + // The space used to store values in a node. + + template + struct value_base { - node_ptr* pos = &b.next_; - while(*pos != begin) pos = &(*pos)->next_; - *pos = end; - } + typedef ValueType value_type; + BOOST_DEDUCED_TYPENAME ::boost::aligned_storage< + sizeof(value_type), + ::boost::alignment_of::value>::type data_; - template - inline void ungrouped_node_base::unlink_nodes(bucket& b, node_ptr end) - { - b.next_ = end; - } - - template - inline void ungrouped_node_base::unlink_node(bucket& b, node_ptr n) - { - unlink_nodes(b, n, n->next_); - } - - //////////////////////////////////////////////////////////////////////////// - // grouped node implementation - - // If ptr is the first element in a group, return pointer to next group. - // Otherwise returns a pointer to ptr. - template - inline BOOST_DEDUCED_TYPENAME grouped_node_base::node_ptr& - grouped_node_base::next_group(node_ptr ptr) - { - return get(ptr).group_prev_->next_; - } - - template - inline BOOST_DEDUCED_TYPENAME grouped_node_base::node_ptr - grouped_node_base::first_in_group(node_ptr ptr) - { - while(next_group(ptr) == ptr) - ptr = get(ptr).group_prev_; - return ptr; - } - - template - inline std::size_t grouped_node_base::group_count(node_ptr ptr) - { - node_ptr start = ptr; - std::size_t size = 0; - do { - ++size; - ptr = get(ptr).group_prev_; - } while(ptr != start); - return size; - } - - template - inline void grouped_node_base::add_to_bucket(node_ptr n, bucket& b) - { - n->next_ = b.next_; - get(n).group_prev_ = n; - b.next_ = n; - } - - template - inline void grouped_node_base::add_after_node(node_ptr n, node_ptr pos) - { - n->next_ = next_group(pos); - get(n).group_prev_ = get(pos).group_prev_; - next_group(pos) = n; - get(pos).group_prev_ = n; - } - - // Break a ciruclar list into two, with split as the beginning - // of the second group (if split is at the beginning then don't - // split). - template - inline BOOST_DEDUCED_TYPENAME grouped_node_base::node_ptr - grouped_node_base::split_group(node_ptr split) - { - node_ptr first = first_in_group(split); - if(first == split) return split; - - node_ptr last = get(first).group_prev_; - get(first).group_prev_ = get(split).group_prev_; - get(split).group_prev_ = last; - - return first; - } - - template - void grouped_node_base::unlink_node(bucket& b, node_ptr n) - { - node_ptr next = n->next_; - node_ptr* pos = &next_group(n); - - if(*pos != n) { - // The node is at the beginning of a group. - - // Find the previous node pointer: - pos = &b.next_; - while(*pos != n) pos = &next_group(*pos); - - // Remove from group - if(BOOST_UNORDERED_BORLAND_BOOL(next) && - get(next).group_prev_ == n) - { - get(next).group_prev_ = get(n).group_prev_; - } + void* address() { + return this; } - else if(BOOST_UNORDERED_BORLAND_BOOL(next) && - get(next).group_prev_ == n) + value_type& value() { + return *(ValueType*) this; + } + value_type* value_ptr() { + return (ValueType*) this; + } + private: + value_base& operator=(value_base const&); + }; + + // In containers with equivalent keys (unordered_multimap and + // unordered_multiset) equivalent nodes are grouped together, in + // containers with unique keys (unordered_map and unordered_set) + // individual nodes are treated as groups of one. The following two + // classes implement the data structure. + + // This is used for containers with unique keys. There are no groups + // so it doesn't add any extra members, and just treats individual + // nodes as groups of one. + + template + struct ungrouped_node + : ::boost::unordered::detail::bucket, + value_base + { + typedef ::boost::unordered::detail::bucket bucket; + typedef BOOST_DEDUCED_TYPENAME bucket::bucket_ptr bucket_ptr; + typedef BOOST_DEDUCED_TYPENAME bucket::node_ptr node_ptr; + typedef BOOST_DEDUCED_TYPENAME A::value_type value_type; + + std::size_t hash_; + + ungrouped_node() : bucket() {} + + void init(node_ptr) {} + + static node_ptr next_group(node_ptr ptr) { - // The deleted node is not at the end of the group, so - // change the link from the next node. - get(next).group_prev_ = get(n).group_prev_; + return ptr->next_; } - else { - // The deleted node is at the end of the group, so the - // first node in the group is pointing to it. - // Find that to change its pointer. - node_ptr x = get(n).group_prev_; - while(get(x).group_prev_ != n) { - x = get(x).group_prev_; - } - get(x).group_prev_ = get(n).group_prev_; + + static node_ptr next_group2(node_ptr ptr) + { + return ptr->next_; } - *pos = next; - } + + static std::size_t group_count(node_ptr n) + { + return !n ? 0 : 1; + } + + static void add_after_node(node_ptr n, node_ptr position) + { + n->next_ = position->next_; + position->next_ = position; + } + + static node_ptr unlink_node(bucket& b, node_ptr n) + { + return unlink_nodes(b, n, n->next_); + } + + static node_ptr unlink_nodes(bucket& b, node_ptr begin, node_ptr end) + { + node_ptr prev = b.next_; + while(prev->next_ != begin) prev = prev->next_; + prev->next_ = end; + return prev; + } + + static std::size_t get_hash(node_ptr p) + { + return static_cast(*p).hash_; + } + + static void set_hash(node_ptr p, std::size_t hash) + { + static_cast(*p).hash_ = hash; + } + + static value_type& get_value(node_ptr p) + { + return static_cast(*p).value(); + } + + static value_type* get_value_ptr(node_ptr p) + { + return static_cast(*p).value_ptr(); + } + }; + + // This is used for containers with equivalent keys. It implements a + // circular list running in the opposite direction to the linked + // list through the nodes. template - void grouped_node_base::unlink_nodes(bucket& b, - node_ptr begin, node_ptr end) + struct grouped_node + : ::boost::unordered::detail::bucket, + value_base { - node_ptr* pos = &next_group(begin); + typedef ::boost::unordered::detail::bucket bucket; + typedef BOOST_DEDUCED_TYPENAME bucket::bucket_ptr bucket_ptr; + typedef BOOST_DEDUCED_TYPENAME bucket::node_ptr node_ptr; + typedef BOOST_DEDUCED_TYPENAME A::value_type value_type; - if(*pos != begin) { - // The node is at the beginning of a group. + std::size_t hash_; + node_ptr group_prev_; - // Find the previous node pointer: - pos = &b.next_; - while(*pos != begin) pos = &next_group(*pos); - - // Remove from group - if(BOOST_UNORDERED_BORLAND_BOOL(end)) split_group(end); + grouped_node() : bucket(), group_prev_() {} + void init(node_ptr n) + { + group_prev_ = n; } - else { - node_ptr group1 = split_group(begin); - if(BOOST_UNORDERED_BORLAND_BOOL(end)) { - node_ptr group2 = split_group(end); - if(begin == group2) { - node_ptr end1 = get(group1).group_prev_; - node_ptr end2 = get(group2).group_prev_; - get(group1).group_prev_ = end2; - get(group2).group_prev_ = end1; + static node_ptr next_group(node_ptr ptr) + { + return get(ptr).group_prev_->next_; + } + + static node_ptr next_group2(node_ptr ptr) + { + return get(ptr->next_).group_prev_; + } + + static std::size_t group_count(node_ptr ptr) + { + if (!ptr) return 0; + + node_ptr start = ptr; + std::size_t size = 0; + do { + ++size; + ptr = get(ptr).group_prev_; + } while(ptr != start); + return size; + } + + static void add_after_node(node_ptr n, node_ptr pos) + { + n->next_ = get(pos).group_prev_->next_; + get(n).group_prev_ = get(pos).group_prev_; + get(pos).group_prev_->next_ = n; + get(pos).group_prev_ = n; + } + + static node_ptr unlink_node(bucket& b, node_ptr n) + { + node_ptr next = n->next_; + node_ptr prev = get(n).group_prev_; + + if(prev->next_ != n) { + // The node is at the beginning of a group. + + // Find the previous node pointer: + prev = b.next_; + while(prev->next_ != n) { + prev = next_group2(prev); + } + + // Remove from group + if(BOOST_UNORDERED_BORLAND_BOOL(next) && + get(next).group_prev_ == n) + { + get(next).group_prev_ = get(n).group_prev_; } } + else if(BOOST_UNORDERED_BORLAND_BOOL(next) && + get(next).group_prev_ == n) + { + // The deleted node is not at the end of the group, so + // change the link from the next node. + get(next).group_prev_ = get(n).group_prev_; + } + else { + // The deleted node is at the end of the group, so the + // first node in the group is pointing to it. + // Find that to change its pointer. + node_ptr x = get(n).group_prev_; + while(get(x).group_prev_ != n) { + x = get(x).group_prev_; + } + get(x).group_prev_ = get(n).group_prev_; + } + prev->next_ = next; + + return prev; } - *pos = end; - } - template - void grouped_node_base::unlink_nodes(bucket& b, node_ptr end) + static node_ptr unlink_nodes(bucket& b, node_ptr begin, node_ptr end) + { + node_ptr prev = get(begin).group_prev_; + + if(prev->next_ != begin) { + // The node is at the beginning of a group. + + // Find the previous node pointer: + prev = b.next_; + while(prev->next_ != begin) prev = next_group2(prev); + + if(BOOST_UNORDERED_BORLAND_BOOL(end)) split_group(end); + } + else { + node_ptr group1 = split_group(begin); + if(BOOST_UNORDERED_BORLAND_BOOL(end)) { + node_ptr group2 = split_group(end); + + if(begin == group2) { + node_ptr end1 = get(group1).group_prev_; + node_ptr end2 = get(group2).group_prev_; + get(group1).group_prev_ = end2; + get(group2).group_prev_ = end1; + } + } + } + + prev->next_ = end; + + return prev; + } + + // Break a ciruclar list into two, with split as the beginning + // of the second group (if split is at the beginning then don't + // split). + static node_ptr split_group(node_ptr split) + { + // Find first node in group. + node_ptr first = split; + while(next_group(first) == first) + first = get(first).group_prev_; + + if(first == split) return split; + + node_ptr last = get(first).group_prev_; + get(first).group_prev_ = get(split).group_prev_; + get(split).group_prev_ = last; + + return first; + } + + static std::size_t get_hash(node_ptr p) { + return static_cast(*p).hash_; + } + static void set_hash(node_ptr p, std::size_t hash) { + static_cast(*p).hash_ = hash; + } + static value_type& get_value(node_ptr p) { + return static_cast(*p).value(); + } + static value_type* get_value_ptr(node_ptr p) { + return static_cast(*p).value_ptr(); + } + + static grouped_node& get(node_ptr ptr) { + return static_cast(*ptr); + } + }; + + // These two classes implement an easy way to pass around the node + // group policy classes without the messy template parameters. + // Whenever you see the template parameter 'G' it's one of these. + + struct ungrouped { - split_group(end); - b.next_ = end; - } -}} + template + struct node { + typedef ungrouped_node type; + }; + }; + + struct grouped + { + template + struct node { + typedef grouped_node type; + }; + }; + +}}} #endif diff --git a/include/boost/unordered/detail/table.hpp b/include/boost/unordered/detail/table.hpp index d37c0155..07acb148 100644 --- a/include/boost/unordered/detail/table.hpp +++ b/include/boost/unordered/detail/table.hpp @@ -7,439 +7,502 @@ #ifndef BOOST_UNORDERED_DETAIL_ALL_HPP_INCLUDED #define BOOST_UNORDERED_DETAIL_ALL_HPP_INCLUDED -#include -#include -#include -#include -#include -#include - #include -namespace boost { namespace unordered_detail { +namespace boost { namespace unordered { namespace detail { - //////////////////////////////////////////////////////////////////////////// - // Helper methods + // This implements almost all of the required functionality, apart + // from some things that are specific to containers with unique and + // equivalent keys which is implemented in unique_table and + // equivalent_table. See unique.hpp and equivalent.hpp for + // their declaration and implementation. - // strong exception safety, no side effects template - inline bool hash_table::equal( - key_type const& k, value_type const& v) const + class table : public T::buckets, public T::buffered_functions { - return this->key_eq()(k, get_key(v)); - } + table(table const&); + public: + typedef BOOST_DEDUCED_TYPENAME T::hasher hasher; + typedef BOOST_DEDUCED_TYPENAME T::key_equal key_equal; + typedef BOOST_DEDUCED_TYPENAME T::value_allocator value_allocator; + typedef BOOST_DEDUCED_TYPENAME T::key_type key_type; + typedef BOOST_DEDUCED_TYPENAME T::value_type value_type; + typedef BOOST_DEDUCED_TYPENAME T::buffered_functions base; + typedef BOOST_DEDUCED_TYPENAME T::buckets buckets; + typedef BOOST_DEDUCED_TYPENAME T::extractor extractor; + typedef BOOST_DEDUCED_TYPENAME T::node_constructor node_constructor; - // strong exception safety, no side effects - template - template - inline BOOST_DEDUCED_TYPENAME T::node_ptr - hash_table::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); + typedef BOOST_DEDUCED_TYPENAME T::node node; + typedef BOOST_DEDUCED_TYPENAME T::bucket bucket; + typedef BOOST_DEDUCED_TYPENAME T::node_ptr node_ptr; + typedef BOOST_DEDUCED_TYPENAME T::bucket_ptr bucket_ptr; + typedef BOOST_DEDUCED_TYPENAME T::node_allocator node_allocator; + typedef BOOST_DEDUCED_TYPENAME T::iterator_pair iterator_pair; + + // Members + + std::size_t size_; + float mlf_; + std::size_t max_load_; + + // Helper methods + + key_type const& get_key(value_type const& v) const { + return extractor::extract(v); } - return it; - } - - // strong exception safety, no side effects - template - inline BOOST_DEDUCED_TYPENAME T::node_ptr - hash_table::find_iterator( - bucket_ptr bucket, key_type const& k) const - { - node_ptr it = bucket->next_; - while (BOOST_UNORDERED_BORLAND_BOOL(it) && - !equal(k, node::get_value(it))) + private: + // pre: this->buckets_ != null + template + node_ptr find_node_impl( + std::size_t bucket_index, + std::size_t hash, + Key const& k, + Pred const& eq) const { - it = node::next_group(it); - } - - return it; - } - - // strong exception safety, no side effects - // pre: this->buckets_ - template - inline BOOST_DEDUCED_TYPENAME T::node_ptr - hash_table::find_iterator(key_type const& k) const - { - return find_iterator(this->get_bucket(this->bucket_index(k)), k); - } - - // strong exception safety, no side effects - template - inline BOOST_DEDUCED_TYPENAME T::node_ptr* - hash_table::find_for_erase( - bucket_ptr bucket, key_type const& k) const - { - node_ptr* it = &bucket->next_; - while(BOOST_UNORDERED_BORLAND_BOOL(*it) && - !equal(k, node::get_value(*it))) - { - it = &node::next_group(*it); - } - - return it; - } - - //////////////////////////////////////////////////////////////////////////// - // Load methods - - // no throw - template - std::size_t hash_table::max_size() const - { - using namespace std; - - // size < mlf_ * count - return double_to_size_t(ceil( - (double) this->mlf_ * this->max_bucket_count())) - 1; - } - - // strong safety - template - inline std::size_t hash_table::bucket_index( - key_type const& k) const - { - // hash_function can throw: - return this->hash_function()(k) % this->bucket_count_; - } - - - // no throw - template - inline std::size_t hash_table::calculate_max_load() - { - 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_)); - } - - template - void hash_table::max_load_factor(float z) - { - BOOST_ASSERT(z > 0); - mlf_ = (std::max)(z, minimum_max_load_factor); - this->max_load_ = this->calculate_max_load(); - } - - // no throw - template - inline std::size_t hash_table::min_buckets_for_size( - std::size_t size) const - { - 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_ - return next_prime(double_to_size_t(floor(size / (double) mlf_)) + 1); - } - - //////////////////////////////////////////////////////////////////////////// - // recompute_begin_bucket - - // init_buckets - - template - inline void hash_table::init_buckets() - { - 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(); - } - - // After an erase cached_begin_bucket_ might be left pointing to - // an empty bucket, so this is called to update it - // - // no throw - - template - inline void hash_table::recompute_begin_bucket(bucket_ptr b) - { - BOOST_ASSERT(!(b < this->cached_begin_bucket_)); - - 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_); + node_ptr n = this->buckets_[bucket_index].next_; + if (!n) return n; + n = n->next_; + + for (;;) + { + if (!n) return n; + std::size_t node_hash = node::get_hash(n); + if (hash == node_hash) + { + if (eq(k, get_key(node::get_value(n)))) + return n; + } + else + { + if (node_hash % this->bucket_count_ != bucket_index) + return node_ptr(); + } + n = node::next_group(n); } } - } - // This is called when a range has been erased - // - // no throw - - template - inline void hash_table::recompute_begin_bucket( - bucket_ptr b1, bucket_ptr b2) - { - 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; - } - - // no throw - template - inline float hash_table::load_factor() const - { - BOOST_ASSERT(this->bucket_count_ != 0); - return static_cast(this->size_) - / static_cast(this->bucket_count_); - } - - //////////////////////////////////////////////////////////////////////////// - // Constructors - - template - hash_table::hash_table(std::size_t num_buckets, - hasher const& hf, key_equal const& eq, node_allocator const& a) - : buckets(a, next_prime(num_buckets)), - base(hf, eq), - size_(), - mlf_(1.0f), - cached_begin_bucket_(), - max_load_(0) - { - } - - // Copy Construct with allocator - - template - hash_table::hash_table(hash_table const& x, - 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) - { - if(x.size_) { - x.copy_buckets_to(*this); - this->init_buckets(); + public: + template + node_ptr generic_find_node( + Key const& k, + Hash const& hash_function, + Pred const& eq) const + { + if (!this->size_) return node_ptr(); + std::size_t hash = hash_function(k); + return find_node_impl(hash % this->bucket_count_, hash, k, eq); + } + + node_ptr find_node( + std::size_t bucket_index, + std::size_t hash, + key_type const& k) const + { + if (!this->size_) return node_ptr(); + return find_node_impl(bucket_index, hash, k, this->key_eq()); } - } - // Move Construct + node_ptr find_node(key_type const& k) const + { + if (!this->size_) return node_ptr(); + std::size_t hash = this->hash_function()(k); + return find_node_impl(hash % this->bucket_count_, hash, k, + this->key_eq()); + } - template - hash_table::hash_table(hash_table& x, move_tag) - : buckets(x.node_alloc(), x.bucket_count_), - base(x), - size_(0), - mlf_(1.0f), - cached_begin_bucket_(), - max_load_(0) - { - this->partial_swap(x); - } + node_ptr find_matching_node(node_ptr n) const + { + // 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(node::get_value(n))); + } - template - hash_table::hash_table(hash_table& x, - node_allocator const& a, move_tag) - : buckets(a, x.bucket_count_), - base(x), - size_(0), - mlf_(x.mlf_), - cached_begin_bucket_(), - max_load_(0) - { - if(a == x.node_alloc()) { + //////////////////////////////////////////////////////////////////////// + // Load methods + + std::size_t max_size() const + { + using namespace std; + + // size < mlf_ * count + return double_to_size_t(ceil( + (double) this->mlf_ * this->max_bucket_count())) - 1; + } + + std::size_t calculate_max_load() + { + BOOST_ASSERT(this->buckets_); + + 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_)); + } + + void max_load_factor(float z) + { + BOOST_ASSERT(z > 0); + mlf_ = (std::max)(z, minimum_max_load_factor); + if (BOOST_UNORDERED_BORLAND_BOOL(this->buckets_)) + this->max_load_ = this->calculate_max_load(); + } + + std::size_t min_buckets_for_size(std::size_t size) const + { + 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_ + return next_prime(double_to_size_t(floor(size / (double) mlf_)) + 1); + } + + float load_factor() const + { + BOOST_ASSERT(this->bucket_count_ != 0); + return static_cast(this->size_) + / static_cast(this->bucket_count_); + } + + //////////////////////////////////////////////////////////////////////// + // Constructors + + table( + std::size_t num_buckets, + hasher const& hf, + key_equal const& eq, + node_allocator const& a) + : buckets(a, next_prime(num_buckets)), + base(hf, eq), + size_(), + mlf_(1.0f), + max_load_(0) + { + } + + table(table const& x, node_allocator const& a) + : buckets(a, x.min_buckets_for_size(x.size_)), + base(x), + size_(x.size_), + mlf_(x.mlf_), + max_load_(0) + { + if(x.size_) { + x.copy_buckets_to(*this); + this->max_load_ = calculate_max_load(); + } + } + + table(table& x, move_tag) + : buckets(x.node_alloc(), x.bucket_count_), + base(x), + size_(0), + mlf_(1.0f), + max_load_(0) + { this->partial_swap(x); } - else if(x.size_) { - x.copy_buckets_to(*this); - this->size_ = x.size_; - this->init_buckets(); - } - } - template - hash_table& hash_table::operator=( - hash_table const& x) - { - hash_table tmp(x, this->node_alloc()); - this->fast_swap(tmp); - return *this; - } - - //////////////////////////////////////////////////////////////////////////// - // Swap & Move - - // Swap - // - // Strong exception safety - // - // Can throw if hash or predicate object's copy constructor throws - // or if allocators are unequal. - - template - inline void hash_table::partial_swap(hash_table& x) - { - 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_); - } - - template - inline void hash_table::fast_swap(hash_table& x) - { - // These can throw, but they only affect the function objects - // that aren't in use so it is strongly exception safe, via. - // double buffering. + table(table& x, node_allocator const& a, move_tag) + : buckets(a, x.bucket_count_), + base(x), + size_(0), + mlf_(x.mlf_), + max_load_(0) { - set_hash_functions op1(*this, x); - set_hash_functions op2(x, *this); - op1.commit(); - op2.commit(); + if(a == x.node_alloc()) { + this->partial_swap(x); + } + else if(x.size_) { + x.copy_buckets_to(*this); + this->size_ = x.size_; + this->max_load_ = calculate_max_load(); + } } - 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_); - } - template - inline void hash_table::slow_swap(hash_table& x) - { - if(this == &x) return; + ~table() + {} + table& operator=(table const& x) + { + table tmp(x, this->node_alloc()); + this->fast_swap(tmp); + return *this; + } + + // Iterators + + node_ptr begin() const { + return !this->buckets_ ? + node_ptr() : this->buckets_[this->bucket_count_].next_; + } + + //////////////////////////////////////////////////////////////////////// + // Swap & Move + + void swap(table& x) + { + if(this->node_alloc() == x.node_alloc()) { + if(this != &x) this->fast_swap(x); + } + else { + this->slow_swap(x); + } + } + + void fast_swap(table& x) { // These can throw, but they only affect the function objects // that aren't in use so it is strongly exception safe, via. // double buffering. - set_hash_functions op1(*this, x); - set_hash_functions op2(x, *this); - - // Create new buckets in separate hash_buckets objects - // which will clean up if anything throws an exception. - // (all can throw, but with no effect as these are new objects). - - 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); - - // Modifying the data, so no throw from now on. - - b1.swap(*this); - b2.swap(x); - op1.commit(); - op2.commit(); + { + set_hash_functions op1(*this, x); + set_hash_functions op2(x, *this); + op1.commit(); + op2.commit(); + } + this->buckets::swap(x); // No throw + std::swap(this->size_, x.size_); + std::swap(this->mlf_, x.mlf_); + std::swap(this->max_load_, x.max_load_); } - - std::swap(this->size_, x.size_); - - if(this->buckets_) this->init_buckets(); - if(x.buckets_) x.init_buckets(); - } - - template - void hash_table::swap(hash_table& x) - { - if(this->node_alloc() == x.node_alloc()) { - if(this != &x) this->fast_swap(x); - } - else { - this->slow_swap(x); - } - } + void slow_swap(table& x) + { + if(this == &x) return; - // 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. - - template - void hash_table::move(hash_table& x) - { - // This can throw, but it only affects the function objects - // that aren't in use so it is strongly exception safe, via. - // double buffering. - set_hash_functions new_func_this(*this, x); - - if(this->node_alloc() == x.node_alloc()) { - this->buckets::move(x); // no throw - this->size_ = x.size_; - this->cached_begin_bucket_ = x.cached_begin_bucket_; - this->max_load_ = x.max_load_; - x.size_ = 0; - } - 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). + { + // These can throw, but they only affect the function objects + // that aren't in use so it is strongly exception safe, via. + // double buffering. + set_hash_functions op1(*this, x); + set_hash_functions op2(x, *this); - buckets b(this->node_alloc(), x.min_buckets_for_size(x.size_)); - if(x.size_) x.copy_buckets_to(b); - - // Start updating the data here, no throw from now on. - this->size_ = x.size_; - b.swap(*this); - this->init_buckets(); + // Create new buckets in separate buckets objects + // which will clean up if anything throws an exception. + // (all can throw, but with no effect as these are new objects). + + 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_) this->copy_buckets_to(b2); + + // Modifying the data, so no throw from now on. + + b1.swap(*this); + b2.swap(x); + op1.commit(); + op2.commit(); + } + + std::swap(this->size_, x.size_); + + this->max_load_ = !this->buckets_ ? 0 : this->calculate_max_load(); + x.max_load_ = !x.buckets_ ? 0 : x.calculate_max_load(); } - // We've made it, the rest is no throw. - this->mlf_ = x.mlf_; - new_func_this.commit(); - } + void partial_swap(table& x) + { + this->buckets::swap(x); // No throw + std::swap(this->size_, x.size_); + std::swap(this->mlf_, x.mlf_); + std::swap(this->max_load_, x.max_load_); + } + + void move(table& x) + { + // This can throw, but it only affects the function objects + // that aren't in use so it is strongly exception safe, via. + // double buffering. + set_hash_functions new_func_this(*this, x); + + if(this->node_alloc() == x.node_alloc()) { + this->buckets::move(x); // no throw + this->size_ = x.size_; + this->max_load_ = x.max_load_; + x.size_ = 0; + } + else { + // Create new buckets in separate buckets + // which will clean up if anything throws an exception. + // (all can throw, but with no effect as these are new objects). + + buckets b(this->node_alloc(), x.min_buckets_for_size(x.size_)); + if (x.size_) x.copy_buckets_to(b); + + // Start updating the data here, no throw from now on. + this->size_ = x.size_; + b.swap(*this); + this->max_load_ = x.size_ ? calculate_max_load() : 0; + } + + // We've made it, the rest is no throw. + this->mlf_ = x.mlf_; + new_func_this.commit(); + } + + //////////////////////////////////////////////////////////////////////// + // Key methods + + std::size_t count(key_type const& k) const + { + if(!this->size_) return 0; + return node::group_count(find_node(k)); + } + + value_type& at(key_type const& k) const + { + if (this->size_) { + node_ptr it = find_node(k); + if (BOOST_UNORDERED_BORLAND_BOOL(it)) + return node::get_value(it); + } + + ::boost::throw_exception( + std::out_of_range("Unable to find key in unordered_map.")); + } + + iterator_pair equal_range(key_type const& k) const + { + if(!this->size_) + return iterator_pair(node_ptr(), node_ptr()); + + node_ptr ptr = find_node(k); + return iterator_pair(ptr, !ptr ? ptr : node::next_group(ptr)); + } + + // Erase + // + // no throw + + void clear() + { + if(!this->size_) return; + + bucket_ptr end = this->get_bucket(this->bucket_count_); + + node_ptr n = (end)->next_; + while(BOOST_UNORDERED_BORLAND_BOOL(n)) + { + node_ptr node_to_delete = n; + n = n->next_; + delete_node(node_to_delete); + } + + ++end; + for(bucket_ptr begin = this->buckets_; begin != end; ++begin) { + begin->next_ = bucket_ptr(); + } + + this->size_ = 0; + } + + std::size_t erase_key(key_type const& k) + { + if(!this->size_) return 0; + + std::size_t hash = this->hash_function()(k); + std::size_t bucket_index = hash % this->bucket_count_; + bucket_ptr bucket = this->get_bucket(bucket_index); + + node_ptr prev = bucket->next_; + if (!prev) return 0; + + for (;;) + { + if (!prev->next_) return 0; + std::size_t node_hash = node::get_hash(prev->next_); + if (node_hash % this->bucket_count_ != bucket_index) + return 0; + if (node_hash == hash && + this->key_eq()(k, get_key(node::get_value(prev->next_)))) + break; + prev = node::next_group2(prev); + } + + node_ptr pos = prev->next_; + node_ptr end = node::next_group(pos); + prev->next_ = end; + + this->fix_buckets(bucket, prev, end); + + std::size_t count = this->delete_nodes(pos, end); + this->size_ -= count; + + return count; + } + + node_ptr erase(node_ptr r) + { + BOOST_ASSERT(r); + node_ptr next = r->next_; + + bucket_ptr bucket = this->get_bucket( + node::get_hash(r) % this->bucket_count_); + node_ptr prev = node::unlink_node(*bucket, r); + + this->fix_buckets(bucket, prev, next); + + this->delete_node(r); + --this->size_; + + return next; + } + + node_ptr erase_range(node_ptr r1, node_ptr r2) + { + if (r1 == r2) return r2; + + std::size_t bucket_index = node::get_hash(r1) % this->bucket_count_; + node_ptr prev = node::unlink_nodes( + this->buckets_[bucket_index], r1, r2); + this->fix_buckets_range(bucket_index, prev, r1, r2); + this->size_ -= this->delete_nodes(r1, r2); + + return r2; + } + + // Reserve and rehash + + bool reserve_for_insert(std::size_t); + void rehash(std::size_t); + void rehash_impl(std::size_t); + }; //////////////////////////////////////////////////////////////////////////// // Reserve & Rehash // basic exception safety template - inline void hash_table::create_for_insert(std::size_t size) - { - this->bucket_count_ = (std::max)(this->bucket_count_, - this->min_buckets_for_size(size)); - this->create_buckets(); - this->init_buckets(); - } - - // basic exception safety - template - inline bool hash_table::reserve_for_insert(std::size_t size) + inline bool table::reserve_for_insert(std::size_t size) { if(size >= max_load_) { - std::size_t num_buckets - = this->min_buckets_for_size((std::max)(size, - this->size_ + (this->size_ >> 1))); - if(num_buckets != this->bucket_count_) { - rehash_impl(num_buckets); - return true; + if (!this->buckets_) { + std::size_t old_bucket_count = this->bucket_count_; + this->bucket_count_ = (std::max)(this->bucket_count_, + this->min_buckets_for_size(size)); + this->create_buckets(); + this->max_load_ = calculate_max_load(); + return old_bucket_count != this->bucket_count_; + } + else { + std::size_t num_buckets + = this->min_buckets_for_size((std::max)(size, + this->size_ + (this->size_ >> 1))); + if (num_buckets != this->bucket_count_) { + rehash_impl(num_buckets); + return true; + } } } @@ -450,13 +513,14 @@ namespace boost { namespace unordered_detail { // strong otherwise. template - inline void hash_table::rehash(std::size_t min_buckets) + void table::rehash(std::size_t min_buckets) { using namespace std; if(!this->size_) { if(this->buckets_) this->delete_buckets(); this->bucket_count_ = next_prime(min_buckets); + this->max_load_ = 0; } else { // no throw: @@ -466,313 +530,308 @@ namespace boost { namespace unordered_detail { } } - // if hash function throws, basic exception safety - // strong otherwise - + // strong otherwise exception safety template - void hash_table - ::rehash_impl(std::size_t num_buckets) - { - hasher const& hf = this->hash_function(); + void table::rehash_impl(std::size_t num_buckets) + { std::size_t size = this->size_; - bucket_ptr end = this->get_bucket(this->bucket_count_); + BOOST_ASSERT(size); buckets dst(this->node_alloc(), num_buckets); dst.create_buckets(); - - buckets src(this->node_alloc(), this->bucket_count_); - src.swap(*this); - this->size_ = 0; - - 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. - - // This next line throws iff the hash function throws. - bucket_ptr dst_bucket = dst.bucket_ptr_from_hash( - hf(get_key_from_ptr(group))); - - node_ptr& next_group = node::next_group(group); - bucket->next_ = next_group; - next_group = dst_bucket->next_; - dst_bucket->next_ = group; - group = bucket->next_; - } - } - - // Swap the new nodes back into the container and setup the local - // variables. - this->size_ = size; - dst.swap(*this); // no throw - this->init_buckets(); - } - - //////////////////////////////////////////////////////////////////////////// - // copy_buckets_to - - // copy_buckets_to - // - // basic excpetion safety. If an exception is thrown this will - // leave dst partially filled. - - template - void hash_table - ::copy_buckets_to(buckets& dst) const - { - BOOST_ASSERT(this->buckets_ && !dst.buckets_); - - hasher const& hf = this->hash_function(); - bucket_ptr end = this->get_bucket(this->bucket_count_); - - node_constructor a(dst); - dst.create_buckets(); - - // 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( - hf(get_key_from_ptr(it))); - // throws, strong - - node_ptr group_end = node::next_group(it); - - a.construct(node::get_value(it)); - node_ptr n = a.release(); - node::add_to_bucket(n, *dst_bucket); - for(it = it->next_; it != group_end; it = it->next_) { - a.construct(node::get_value(it)); - node::add_after_node(a.release(), n); - } - } - } + bucket_ptr src_start = this->get_bucket(this->bucket_count_); + bucket_ptr dst_start = dst.get_bucket(dst.bucket_count_); + + dst_start->next_ = src_start->next_; + src_start->next_ = bucket_ptr(); + // No need to do this, since the following is 'no throw'. + //this->size_ = 0; + + node_ptr prev = dst_start; + while (BOOST_UNORDERED_BORLAND_BOOL(prev->next_)) + prev = dst.place_in_bucket(prev, node::next_group2(prev)); + + // Swap the new nodes back into the container and setup the + // variables. + dst.swap(*this); // no throw + this->size_ = size; + this->max_load_ = calculate_max_load(); } //////////////////////////////////////////////////////////////////////////// - // Misc. key methods - - // strong exception safety - - // count // - // strong exception safety, no side effects - - template - std::size_t hash_table::count(key_type const& k) const - { - 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 + // types // - // strong exception safety, no side effects - template - BOOST_DEDUCED_TYPENAME T::iterator_base - hash_table::find(key_type const& k) const + // This is used to convieniently pass around a container's typedefs + // without having 7 template parameters. + + template + struct types { - if(!this->size_) return this->end(); + public: + typedef K key_type; + typedef V value_type; + typedef H hasher; + typedef P key_equal; + typedef A value_allocator; + typedef E extractor; + + typedef ::boost::unordered::detail::node_constructor node_constructor; + typedef ::boost::unordered::detail::buckets buckets; + typedef ::boost::unordered::detail::buffered_functions buffered_functions; - bucket_ptr bucket = this->get_bucket(this->bucket_index(k)); - node_ptr it = find_iterator(bucket, k); + typedef BOOST_DEDUCED_TYPENAME buckets::node node; + typedef BOOST_DEDUCED_TYPENAME buckets::bucket bucket; + typedef BOOST_DEDUCED_TYPENAME buckets::node_ptr node_ptr; + typedef BOOST_DEDUCED_TYPENAME buckets::bucket_ptr bucket_ptr; + typedef BOOST_DEDUCED_TYPENAME buckets::node_allocator node_allocator; - if (BOOST_UNORDERED_BORLAND_BOOL(it)) - return iterator_base(bucket, it); - else - return this->end(); - } + typedef std::pair iterator_pair; + }; +}}} - template - template - BOOST_DEDUCED_TYPENAME T::iterator_base hash_table::find(Key const& k, - Hash const& h, Pred const& eq) const - { - if(!this->size_) return this->end(); +namespace boost { namespace unordered { namespace iterator_detail { - 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(); - } - - template - BOOST_DEDUCED_TYPENAME T::value_type& - hash_table::at(key_type const& k) const - { - if(!this->size_) - boost::throw_exception(std::out_of_range("Unable to find key in unordered_map.")); - - bucket_ptr bucket = this->get_bucket(this->bucket_index(k)); - node_ptr it = find_iterator(bucket, k); - - if (!it) - boost::throw_exception(std::out_of_range("Unable to find key in unordered_map.")); - - return node::get_value(it); - } - - // equal_range + // Iterators // - // strong exception safety, no side effects - template - BOOST_DEDUCED_TYPENAME T::iterator_pair - hash_table::equal_range(key_type const& k) const - { - if(!this->size_) - return iterator_pair(this->end(), this->end()); + // all no throw - 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); - second.increment_bucket(node::next_group(second.node_)); - return iterator_pair(first, second); + template class iterator; + template class c_iterator; + template class l_iterator; + template class cl_iterator; + + // Local Iterators + // + // all no throw + + template + class l_iterator + : public ::boost::iterator < + std::forward_iterator_tag, + BOOST_DEDUCED_TYPENAME A::value_type, + std::ptrdiff_t, + BOOST_DEDUCED_TYPENAME A::pointer, + BOOST_DEDUCED_TYPENAME A::reference> + { + public: + typedef BOOST_DEDUCED_TYPENAME A::value_type value_type; + + private: + typedef ::boost::unordered::detail::buckets buckets; + typedef BOOST_DEDUCED_TYPENAME buckets::node_ptr node_ptr; + typedef BOOST_DEDUCED_TYPENAME buckets::node node; + typedef cl_iterator const_local_iterator; + + friend class cl_iterator; + node_ptr ptr_; + std::size_t bucket_; + std::size_t bucket_count_; + + public: + l_iterator() : ptr_() {} + l_iterator(node_ptr x, std::size_t b, std::size_t c) + : ptr_(x), bucket_(b), bucket_count_(c) {} + BOOST_DEDUCED_TYPENAME A::reference operator*() const { + return node::get_value(ptr_); } - else { - return iterator_pair(this->end(), this->end()); + value_type* operator->() const { + return node::get_value_ptr(ptr_); } - } - - //////////////////////////////////////////////////////////////////////////// - // Erase methods - - template - void hash_table::clear() - { - if(!this->size_) return; - - bucket_ptr end = this->get_bucket(this->bucket_count_); - for(bucket_ptr begin = this->buckets_; begin != end; ++begin) { - this->clear_bucket(begin); + l_iterator& operator++() { + ptr_ = ptr_->next_; + if (ptr_ && node::get_hash(ptr_) % bucket_count_ != bucket_) + ptr_ = node_ptr(); + return *this; } - - this->size_ = 0; - this->cached_begin_bucket_ = end; - } - - template - inline std::size_t hash_table::erase_group( - 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; - } - - template - std::size_t hash_table::erase_key(key_type const& k) - { - if(!this->size_) return 0; - - // 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; - } - - template - void hash_table::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_); - } - - template - BOOST_DEDUCED_TYPENAME T::iterator_base - hash_table::erase_return_iterator(iterator_base r) - { - BOOST_ASSERT(r.node_); - iterator_base next = r; - next.increment(); - --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_, next.bucket_); - return next; - } - - template - BOOST_DEDUCED_TYPENAME T::iterator_base - hash_table::erase_range( - iterator_base r1, iterator_base r2) - { - if(r1 != r2) - { - BOOST_ASSERT(r1.node_); - if (r1.bucket_ == r2.bucket_) { - node::unlink_nodes(*r1.bucket_, r1.node_, r2.node_); - this->size_ -= this->delete_nodes(r1.node_, r2.node_); - - // No need to call recompute_begin_bucket because - // the nodes are only deleted from one bucket, which - // still contains r2 after the erase. - BOOST_ASSERT(r1.bucket_->next_); - } - else { - bucket_ptr end_bucket = r2.node_ ? - r2.bucket_ : this->get_bucket(this->bucket_count_); - BOOST_ASSERT(r1.bucket_ < end_bucket); - node::unlink_nodes(*r1.bucket_, r1.node_, node_ptr()); - this->size_ -= this->delete_nodes(r1.node_, node_ptr()); - - bucket_ptr i = r1.bucket_; - for(++i; i != end_bucket; ++i) { - this->size_ -= this->delete_nodes(i->next_, node_ptr()); - i->next_ = node_ptr(); - } - - if(r2.node_) { - node_ptr first = r2.bucket_->next_; - node::unlink_nodes(*r2.bucket_, r2.node_); - this->size_ -= this->delete_nodes(first, r2.node_); - } - - // r1 has been invalidated but its bucket is still - // valid. - this->recompute_begin_bucket(r1.bucket_, end_bucket); - } + l_iterator operator++(int) { + l_iterator tmp(*this); + ptr_ = ptr_->next_; + if (ptr_ && node::get_hash(ptr_) % bucket_count_ != bucket_) + ptr_ = node_ptr(); + return tmp; } + bool operator==(l_iterator x) const { + return ptr_ == x.ptr_; + } + bool operator==(const_local_iterator x) const { + return ptr_ == x.ptr_; + } + bool operator!=(l_iterator x) const { + return ptr_ != x.ptr_; + } + bool operator!=(const_local_iterator x) const { + return ptr_ != x.ptr_; + } + }; - return r2; - } - - template - BOOST_DEDUCED_TYPENAME hash_table::iterator_base - hash_table::emplace_empty_impl_with_node( - node_constructor& a, std::size_t size) + template + class cl_iterator + : public ::boost::iterator < + std::forward_iterator_tag, + BOOST_DEDUCED_TYPENAME A::value_type, + std::ptrdiff_t, + BOOST_DEDUCED_TYPENAME A::const_pointer, + BOOST_DEDUCED_TYPENAME A::const_reference > { - key_type const& k = get_key(a.value()); - std::size_t hash_value = this->hash_function()(k); - if(this->buckets_) this->reserve_for_insert(size); - else this->create_for_insert(size); - bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value); - node_ptr n = a.release(); - node::add_to_bucket(n, *bucket); - ++this->size_; - this->cached_begin_bucket_ = bucket; - return iterator_base(bucket, n); - } -}} + public: + typedef BOOST_DEDUCED_TYPENAME A::value_type value_type; + + private: + typedef ::boost::unordered::detail::buckets buckets; + typedef BOOST_DEDUCED_TYPENAME buckets::node_ptr node_ptr; + typedef BOOST_DEDUCED_TYPENAME buckets::node node; + typedef l_iterator local_iterator; + friend class l_iterator; + + node_ptr ptr_; + std::size_t bucket_; + std::size_t bucket_count_; + + public: + cl_iterator() : ptr_() {} + cl_iterator(node_ptr x, std::size_t b, std::size_t c) + : ptr_(x), bucket_(b), bucket_count_(c) {} + cl_iterator(local_iterator x) + : ptr_(x.ptr_), bucket_(x.bucket_), bucket_count_(x.bucket_count_) + {} + BOOST_DEDUCED_TYPENAME A::const_reference + operator*() const { + return node::get_value(ptr_); + } + value_type const* operator->() const { + return node::get_value_ptr(ptr_); + } + cl_iterator& operator++() { + ptr_ = ptr_->next_; + if (ptr_ && node::get_hash(ptr_) % bucket_count_ != bucket_) + ptr_ = node_ptr(); + return *this; + } + cl_iterator operator++(int) { + cl_iterator tmp(*this); + ptr_ = ptr_->next_; + if (ptr_ && node::get_hash(ptr_) % bucket_count_ != bucket_) + ptr_ = node_ptr(); + return tmp; + } + bool operator==(local_iterator x) const { + return ptr_ == x.ptr_; + } + bool operator==(cl_iterator x) const { + return ptr_ == x.ptr_; + } + bool operator!=(local_iterator x) const { + return ptr_ != x.ptr_; + } + bool operator!=(cl_iterator x) const { + return ptr_ != x.ptr_; + } + }; + + template + class iterator + : public ::boost::iterator < + std::forward_iterator_tag, + BOOST_DEDUCED_TYPENAME A::value_type, + std::ptrdiff_t, + BOOST_DEDUCED_TYPENAME A::pointer, + BOOST_DEDUCED_TYPENAME A::reference > + { + public: + typedef BOOST_DEDUCED_TYPENAME A::value_type value_type; + + private: + typedef ::boost::unordered::detail::buckets buckets; + typedef BOOST_DEDUCED_TYPENAME buckets::node node; + typedef BOOST_DEDUCED_TYPENAME buckets::node_ptr node_ptr; + typedef c_iterator const_iterator; + friend class c_iterator; + node_ptr node_; + + public: + + iterator() : node_() {} + explicit iterator(node_ptr const& x) : node_(x) {} + BOOST_DEDUCED_TYPENAME A::reference operator*() const { + return node::get_value(node_); + } + value_type* operator->() const { + return &node::get_value(node_); + } + iterator& operator++() { + node_ = node_->next_; return *this; + } + iterator operator++(int) { + iterator tmp(node_); node_ = node_->next_; return tmp; + } + bool operator==(iterator const& x) const { + return node_ == x.node_; + } + bool operator==(const_iterator const& x) const { + return node_ == x.node_; + } + bool operator!=(iterator const& x) const { + return node_ != x.node_; + } + bool operator!=(const_iterator const& x) const { + return node_ != x.node_; + } + }; + + template + class c_iterator + : public ::boost::iterator < + std::forward_iterator_tag, + BOOST_DEDUCED_TYPENAME A::value_type, + std::ptrdiff_t, + BOOST_DEDUCED_TYPENAME A::const_pointer, + BOOST_DEDUCED_TYPENAME A::const_reference > + { + public: + typedef BOOST_DEDUCED_TYPENAME A::value_type value_type; + + private: + typedef ::boost::unordered::detail::buckets buckets; + typedef BOOST_DEDUCED_TYPENAME buckets::node node; + typedef BOOST_DEDUCED_TYPENAME buckets::node_ptr node_ptr; + typedef ::boost::unordered::iterator_detail::iterator + iterator; + friend class ::boost::unordered::iterator_detail::iterator; + friend class ::boost::unordered::detail::iterator_access; + node_ptr node_; + + public: + + c_iterator() : node_() {} + explicit c_iterator(node_ptr const& x) : node_(x) {} + c_iterator(iterator const& x) : node_(x.node_) {} + BOOST_DEDUCED_TYPENAME A::const_reference operator*() const { + return node::get_value(node_); + } + value_type const* operator->() const { + return &node::get_value(node_); + } + c_iterator& operator++() { + node_ = node_->next_; return *this; + } + c_iterator operator++(int) { + c_iterator tmp(node_); node_ = node_->next_; return tmp; + } + bool operator==(iterator const& x) const { + return node_ == x.node_; + } + bool operator==(c_iterator const& x) const { + return node_ == x.node_; + } + bool operator!=(iterator const& x) const { + return node_ != x.node_; + } + bool operator!=(c_iterator const& x) const { + return node_ != x.node_; + } + }; +}}} #endif diff --git a/include/boost/unordered/detail/unique.hpp b/include/boost/unordered/detail/unique.hpp index 96fdfee6..988e3a3a 100644 --- a/include/boost/unordered/detail/unique.hpp +++ b/include/boost/unordered/detail/unique.hpp @@ -7,13 +7,12 @@ #ifndef BOOST_UNORDERED_DETAIL_UNIQUE_HPP_INCLUDED #define BOOST_UNORDERED_DETAIL_UNIQUE_HPP_INCLUDED -#include #include -namespace boost { namespace unordered_detail { +namespace boost { namespace unordered { namespace detail { template - class hash_unique_table : public T::table + class unique_table : public T::table { public: typedef BOOST_DEDUCED_TYPENAME T::hasher hasher; @@ -27,81 +26,348 @@ namespace boost { namespace unordered_detail { typedef BOOST_DEDUCED_TYPENAME T::node node; typedef BOOST_DEDUCED_TYPENAME T::node_ptr node_ptr; typedef BOOST_DEDUCED_TYPENAME T::bucket_ptr bucket_ptr; - typedef BOOST_DEDUCED_TYPENAME T::iterator_base iterator_base; typedef BOOST_DEDUCED_TYPENAME T::extractor extractor; - typedef std::pair emplace_return; + typedef std::pair emplace_return; // Constructors - hash_unique_table(std::size_t n, hasher const& hf, key_equal const& eq, + unique_table(std::size_t n, hasher const& hf, key_equal const& eq, value_allocator const& a) : table(n, hf, eq, a) {} - hash_unique_table(hash_unique_table const& x) + unique_table(unique_table const& x) : table(x, x.node_alloc()) {} - hash_unique_table(hash_unique_table const& x, value_allocator const& a) + unique_table(unique_table const& x, value_allocator const& a) : table(x, a) {} - hash_unique_table(hash_unique_table& x, move_tag m) + unique_table(unique_table& x, move_tag m) : table(x, m) {} - hash_unique_table(hash_unique_table& x, value_allocator const& a, + unique_table(unique_table& x, value_allocator const& a, move_tag m) : table(x, a, m) {} - ~hash_unique_table() {} - - // Insert methods - - emplace_return emplace_impl_with_node(node_constructor& a); - value_type& operator[](key_type const& k); + ~unique_table() {} // equals - bool equals(hash_unique_table const&) const; + bool equals(unique_table const& other) const + { + if(this->size_ != other.size_) return false; + if(!this->size_) return true; + + for(node_ptr n1 = this->get_bucket(this->bucket_count_)->next_; + n1; n1 = n1->next_) + { + node_ptr n2 = other.find_matching_node(n1); + if(!BOOST_UNORDERED_BORLAND_BOOL(n2)) return false; + if(!extractor::compare_mapped( + node::get_value(n1), node::get_value(n2))) + return false; + } + + return true; + } + + //////////////////////////////////////////////////////////////////////// + // A convenience method for adding nodes. + + node_ptr add_node( + node_constructor& a, + std::size_t bucket_index, + std::size_t hash) + { + bucket_ptr b = this->get_bucket(bucket_index); + node_ptr n = a.release(); + node::set_hash(n, hash); + + if (!b->next_) + { + bucket_ptr start_node = this->get_bucket(this->bucket_count_); + + if (start_node->next_) { + this->buckets_[ + node::get_hash(start_node->next_) % this->bucket_count_ + ].next_ = n; + } + + b->next_ = start_node; + n->next_ = start_node->next_; + start_node->next_ = n; + } + else + { + n->next_ = b->next_->next_; + b->next_->next_ = n; + } + + ++this->size_; + return n; + } + + //////////////////////////////////////////////////////////////////////////// + // Insert methods + + // if hash function throws, basic exception safety + // strong otherwise + + value_type& operator[](key_type const& k) + { + typedef BOOST_DEDUCED_TYPENAME value_type::second_type mapped_type; + + std::size_t hash = this->hash_function()(k); + std::size_t bucket_index = hash % this->bucket_count_; + node_ptr pos = this->find_node(bucket_index, hash, k); + + if (BOOST_UNORDERED_BORLAND_BOOL(pos)) { + return node::get_value(pos); + } + + // Create the node before rehashing in case it throws an + // exception (need strong safety in such a case). + node_constructor a(*this); + a.construct_pair(k, (mapped_type*) 0); + + // reserve has basic exception safety if the hash function + // throws, strong otherwise. + if(this->reserve_for_insert(this->size_ + 1)) + bucket_index = hash % this->bucket_count_; + + // Nothing after this point can throw. + + return node::get_value(add_node(a, bucket_index, hash)); + } + + emplace_return emplace_impl_with_node(node_constructor& a) + { + // No side effects in this initial code + key_type const& k = this->get_key(a.value()); + std::size_t hash = this->hash_function()(k); + std::size_t bucket_index = hash % this->bucket_count_; + node_ptr pos = this->find_node(bucket_index, hash, k); + + if (BOOST_UNORDERED_BORLAND_BOOL(pos)) { + // Found an existing key, return it (no throw). + return emplace_return(pos, false); + } + + // reserve has basic exception safety if the hash function + // throws, strong otherwise. + if(this->reserve_for_insert(this->size_ + 1)) + bucket_index = hash % this->bucket_count_; + + // Nothing after this point can throw. + + return emplace_return(add_node(a, bucket_index, hash), true); + } + + emplace_return insert(value_type const& v) + { + key_type const& k = extractor::extract(v); + std::size_t hash = this->hash_function()(k); + std::size_t bucket_index = hash % this->bucket_count_; + node_ptr pos = this->find_node(bucket_index, hash, k); + + if (BOOST_UNORDERED_BORLAND_BOOL(pos)) { + // Found an existing key, return it (no throw). + return emplace_return(pos, false); + } + + // Isn't in table, add to bucket. + + // Create the node before rehashing in case it throws an + // exception (need strong safety in such a case). + node_constructor a(*this); + a.construct(v); + + // reserve has basic exception safety if the hash function + // throws, strong otherwise. + if(this->reserve_for_insert(this->size_ + 1)) + bucket_index = hash % this->bucket_count_; + + // Nothing after this point can throw. + + return emplace_return(add_node(a, bucket_index, hash), true); + } + - node_ptr add_node(node_constructor& a, bucket_ptr bucket); - #if defined(BOOST_UNORDERED_STD_FORWARD) template - emplace_return emplace(Args&&... args); + emplace_return emplace(Args&&... args) + { + return emplace_impl( + extractor::extract(std::forward(args)...), + std::forward(args)...); + } + template - emplace_return emplace_impl(key_type const& k, Args&&... args); + emplace_return emplace_impl(key_type const& k, Args&&... args) + { + // No side effects in this initial code + std::size_t hash = this->hash_function()(k); + std::size_t bucket_index = hash % this->bucket_count_; + node_ptr pos = this->find_node(bucket_index, hash, k); + + if (BOOST_UNORDERED_BORLAND_BOOL(pos)) { + // Found an existing key, return it (no throw). + return emplace_return(pos, false); + } + + // Doesn't already exist, add to bucket. + // Side effects only in this block. + + // Create the node before rehashing in case it throws an + // exception (need strong safety in such a case). + node_constructor a(*this); + a.construct(std::forward(args)...); + + // reserve has basic exception safety if the hash function + // throws, strong otherwise. + if(this->reserve_for_insert(this->size_ + 1)) + bucket_index = hash % this->bucket_count_; + + // Nothing after this point can throw. + + return emplace_return(add_node(a, bucket_index, hash), true); + } + template - emplace_return emplace_impl(no_key, Args&&... args); - template - emplace_return emplace_empty_impl(Args&&... args); + emplace_return emplace_impl(no_key, Args&&... args) + { + // Construct the node regardless - in order to get the key. + // It will be discarded if it isn't used + node_constructor a(*this); + a.construct(std::forward(args)...); + return emplace_impl_with_node(a); + } #else -#define BOOST_UNORDERED_INSERT_IMPL(z, n, _) \ - template \ - emplace_return emplace( \ - BOOST_UNORDERED_FUNCTION_PARAMS(z, n)); \ - template \ - emplace_return emplace_impl(key_type const& k, \ - BOOST_UNORDERED_FUNCTION_PARAMS(z, n)); \ - template \ - emplace_return emplace_impl(no_key, \ - BOOST_UNORDERED_FUNCTION_PARAMS(z, n)); \ - template \ - emplace_return emplace_empty_impl( \ - BOOST_UNORDERED_FUNCTION_PARAMS(z, n)); + template + emplace_return emplace(Arg0 const& arg0) + { + return emplace_impl(extractor::extract(arg0), arg0); + } +#define BOOST_UNORDERED_INSERT1_IMPL(z, n, _) \ + template \ + emplace_return emplace( \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \ + { \ + return emplace_impl(extractor::extract(arg0, arg1), \ + BOOST_UNORDERED_CALL_PARAMS(z, n)); \ + } + +#define BOOST_UNORDERED_INSERT2_IMPL(z, n, _) \ + template \ + emplace_return emplace_impl(key_type const& k, \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \ + { \ + std::size_t hash = this->hash_function()(k); \ + std::size_t bucket_index = hash % this->bucket_count_; \ + node_ptr pos = this->find_node(bucket_index, hash, k); \ + \ + if (BOOST_UNORDERED_BORLAND_BOOL(pos)) { \ + return emplace_return(pos, false); \ + } else { \ + node_constructor a(*this); \ + a.construct(BOOST_UNORDERED_CALL_PARAMS(z, n)); \ + \ + if(this->reserve_for_insert(this->size_ + 1)) \ + bucket_index = hash % this->bucket_count_; \ + \ + return emplace_return( \ + add_node(a, bucket_index, hash), \ + true); \ + } \ + } \ + \ + template \ + emplace_return emplace_impl(no_key, \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \ + { \ + node_constructor a(*this); \ + a.construct(BOOST_UNORDERED_CALL_PARAMS(z, n)); \ + return emplace_impl_with_node(a); \ + } + + BOOST_PP_REPEAT_FROM_TO(2, BOOST_UNORDERED_EMPLACE_LIMIT, + BOOST_UNORDERED_INSERT1_IMPL, _) BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, - BOOST_UNORDERED_INSERT_IMPL, _) + BOOST_UNORDERED_INSERT2_IMPL, _) -#undef BOOST_UNORDERED_INSERT_IMPL +#undef BOOST_UNORDERED_INSERT1_IMPL +#undef BOOST_UNORDERED_INSERT2_IMPL #endif + //////////////////////////////////////////////////////////////////////// + // Insert range methods + // // if hash function throws, or inserting > 1 element, basic exception // safety strong otherwise + template - void insert_range(InputIt i, InputIt j); + void insert_range(InputIt i, InputIt j) + { + if(i != j) + return insert_range_impl(extractor::extract(*i), i, j); + } + template - void insert_range_impl(key_type const&, InputIt i, InputIt j); + void insert_range_impl(key_type const&, InputIt i, InputIt j) + { + node_constructor a(*this); + + do { + // Note: can't use get_key as '*i' might not be value_type - it + // could be a pair with first_types as key_type without const or a + // different second_type. + // + // TODO: Might be worth storing the value_type instead of the key + // here. Could be more efficient if '*i' is expensive. Could be + // less efficient if copying the full value_type is expensive. + insert_range_impl2(a, extractor::extract(*i), i, j); + } while(++i != j); + } + template - void insert_range_impl2(node_constructor&, key_type const&, InputIt i, InputIt j); + void insert_range_impl2(node_constructor& a, key_type const& k, + InputIt i, InputIt j) + { + // No side effects in this initial code + std::size_t hash = this->hash_function()(k); + std::size_t bucket_index = hash % this->bucket_count_; + node_ptr pos = this->find_node(bucket_index, hash, k); + + if (!BOOST_UNORDERED_BORLAND_BOOL(pos)) { + // Doesn't already exist, add to bucket. + // Side effects only in this block. + + // Create the node before rehashing in case it throws an + // exception (need strong safety in such a case). + a.construct(*i); + + // reserve has basic exception safety if the hash function + // throws, strong otherwise. + if(this->size_ + 1 >= this->max_load_) { + this->reserve_for_insert(this->size_ + insert_size(i, j)); + bucket_index = hash % this->bucket_count_; + } + + // Nothing after this point can throw. + add_node(a, bucket_index, hash); + } + } + template - void insert_range_impl(no_key, InputIt i, InputIt j); + void insert_range_impl(no_key, InputIt i, InputIt j) + { + node_constructor a(*this); + + do { + // No side effects in this initial code + a.construct(*i); + emplace_impl_with_node(a); + } while(++i != j); + } }; template @@ -110,10 +376,10 @@ namespace boost { namespace unordered_detail { BOOST_DEDUCED_TYPENAME A::value_type, H, P, A, set_extractor, - ungrouped> + true> { - typedef hash_unique_table > impl; - typedef hash_table > table; + typedef ::boost::unordered::detail::unique_table > impl; + typedef ::boost::unordered::detail::table > table; }; template @@ -121,393 +387,11 @@ namespace boost { namespace unordered_detail { K, BOOST_DEDUCED_TYPENAME A::value_type, H, P, A, map_extractor, - ungrouped> + true> { - typedef hash_unique_table > impl; - typedef hash_table > table; + typedef ::boost::unordered::detail::unique_table > impl; + typedef ::boost::unordered::detail::table > table; }; - - //////////////////////////////////////////////////////////////////////////// - // Equality - - template - bool hash_unique_table - ::equals(hash_unique_table const& other) const - { - if(this->size_ != other.size_) return false; - if(!this->size_) return true; - - bucket_ptr end = this->get_bucket(this->bucket_count_); - for(bucket_ptr i = this->cached_begin_bucket_; i != end; ++i) - { - node_ptr it1 = i->next_; - while(BOOST_UNORDERED_BORLAND_BOOL(it1)) - { - node_ptr it2 = other.find_iterator(this->get_key_from_ptr(it1)); - if(!BOOST_UNORDERED_BORLAND_BOOL(it2)) return false; - if(!extractor::compare_mapped( - node::get_value(it1), node::get_value(it2))) - return false; - it1 = it1->next_; - } - } - - return true; - } - - //////////////////////////////////////////////////////////////////////////// - // A convenience method for adding nodes. - - template - inline BOOST_DEDUCED_TYPENAME hash_unique_table::node_ptr - hash_unique_table::add_node(node_constructor& a, - bucket_ptr bucket) - { - node_ptr n = a.release(); - node::add_to_bucket(n, *bucket); - ++this->size_; - if(bucket < this->cached_begin_bucket_) - this->cached_begin_bucket_ = bucket; - return n; - } - - //////////////////////////////////////////////////////////////////////////// - // Insert methods - - // if hash function throws, basic exception safety - // strong otherwise - template - BOOST_DEDUCED_TYPENAME hash_unique_table::value_type& - hash_unique_table::operator[](key_type const& k) - { - typedef BOOST_DEDUCED_TYPENAME value_type::second_type mapped_type; - - std::size_t hash_value = this->hash_function()(k); - bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value); - - if(!this->buckets_) { - node_constructor a(*this); - a.construct_pair(k, (mapped_type*) 0); - return *this->emplace_empty_impl_with_node(a, 1); - } - - node_ptr pos = this->find_iterator(bucket, k); - - if (BOOST_UNORDERED_BORLAND_BOOL(pos)) { - return node::get_value(pos); - } - else { - // Side effects only in this block. - - // Create the node before rehashing in case it throws an - // exception (need strong safety in such a case). - node_constructor a(*this); - a.construct_pair(k, (mapped_type*) 0); - - // reserve has basic exception safety if the hash function - // throws, strong otherwise. - if(this->reserve_for_insert(this->size_ + 1)) - bucket = this->bucket_ptr_from_hash(hash_value); - - // Nothing after this point can throw. - - return node::get_value(add_node(a, bucket)); - } - } - - template - inline BOOST_DEDUCED_TYPENAME hash_unique_table::emplace_return - hash_unique_table::emplace_impl_with_node(node_constructor& a) - { - // No side effects in this initial code - key_type const& k = this->get_key(a.value()); - std::size_t hash_value = this->hash_function()(k); - bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value); - node_ptr pos = this->find_iterator(bucket, k); - - if (BOOST_UNORDERED_BORLAND_BOOL(pos)) { - // Found an existing key, return it (no throw). - return emplace_return(iterator_base(bucket, pos), false); - } else { - // reserve has basic exception safety if the hash function - // throws, strong otherwise. - if(this->reserve_for_insert(this->size_ + 1)) - bucket = this->bucket_ptr_from_hash(hash_value); - - // Nothing after this point can throw. - - return emplace_return( - iterator_base(bucket, add_node(a, bucket)), - true); - } - } - -#if defined(BOOST_UNORDERED_STD_FORWARD) - - template - template - inline BOOST_DEDUCED_TYPENAME hash_unique_table::emplace_return - hash_unique_table::emplace_impl(key_type const& k, - Args&&... args) - { - // No side effects in this initial code - std::size_t hash_value = this->hash_function()(k); - bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value); - node_ptr pos = this->find_iterator(bucket, k); - - if (BOOST_UNORDERED_BORLAND_BOOL(pos)) { - // Found an existing key, return it (no throw). - return emplace_return(iterator_base(bucket, pos), false); - - } else { - // Doesn't already exist, add to bucket. - // Side effects only in this block. - - // Create the node before rehashing in case it throws an - // exception (need strong safety in such a case). - node_constructor a(*this); - a.construct(std::forward(args)...); - - // reserve has basic exception safety if the hash function - // throws, strong otherwise. - if(this->reserve_for_insert(this->size_ + 1)) - bucket = this->bucket_ptr_from_hash(hash_value); - - // Nothing after this point can throw. - - return emplace_return( - iterator_base(bucket, add_node(a, bucket)), - true); - } - } - - template - template - inline BOOST_DEDUCED_TYPENAME hash_unique_table::emplace_return - hash_unique_table::emplace_impl(no_key, Args&&... args) - { - // Construct the node regardless - in order to get the key. - // It will be discarded if it isn't used - node_constructor a(*this); - a.construct(std::forward(args)...); - return emplace_impl_with_node(a); - } - - template - template - inline BOOST_DEDUCED_TYPENAME hash_unique_table::emplace_return - hash_unique_table::emplace_empty_impl(Args&&... args) - { - node_constructor a(*this); - a.construct(std::forward(args)...); - return emplace_return(this->emplace_empty_impl_with_node(a, 1), true); - } - -#else - -#define BOOST_UNORDERED_INSERT_IMPL(z, num_params, _) \ - template \ - template \ - inline BOOST_DEDUCED_TYPENAME \ - hash_unique_table::emplace_return \ - hash_unique_table::emplace_impl( \ - key_type const& k, \ - BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \ - { \ - std::size_t hash_value = this->hash_function()(k); \ - bucket_ptr bucket \ - = this->bucket_ptr_from_hash(hash_value); \ - node_ptr pos = this->find_iterator(bucket, k); \ - \ - if (BOOST_UNORDERED_BORLAND_BOOL(pos)) { \ - return emplace_return(iterator_base(bucket, pos), false); \ - } else { \ - node_constructor a(*this); \ - a.construct(BOOST_UNORDERED_CALL_PARAMS(z, num_params)); \ - \ - if(this->reserve_for_insert(this->size_ + 1)) \ - bucket = this->bucket_ptr_from_hash(hash_value); \ - \ - return emplace_return(iterator_base(bucket, \ - add_node(a, bucket)), true); \ - } \ - } \ - \ - template \ - template \ - inline BOOST_DEDUCED_TYPENAME \ - hash_unique_table::emplace_return \ - hash_unique_table:: \ - emplace_impl(no_key, \ - BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \ - { \ - node_constructor a(*this); \ - a.construct(BOOST_UNORDERED_CALL_PARAMS(z, num_params)); \ - return emplace_impl_with_node(a); \ - } \ - \ - template \ - template \ - inline BOOST_DEDUCED_TYPENAME \ - hash_unique_table::emplace_return \ - hash_unique_table:: \ - emplace_empty_impl( \ - BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \ - { \ - node_constructor a(*this); \ - a.construct(BOOST_UNORDERED_CALL_PARAMS(z, num_params)); \ - return emplace_return(this->emplace_empty_impl_with_node(a, 1), true); \ - } - - BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, - BOOST_UNORDERED_INSERT_IMPL, _) - -#undef BOOST_UNORDERED_INSERT_IMPL - -#endif - -#if defined(BOOST_UNORDERED_STD_FORWARD) - - // Emplace (unique keys) - // (I'm using an overloaded emplace for both 'insert' and 'emplace') - - // if hash function throws, basic exception safety - // strong otherwise - - template - template - BOOST_DEDUCED_TYPENAME hash_unique_table::emplace_return - hash_unique_table::emplace(Args&&... args) - { - return this->size_ ? - emplace_impl( - extractor::extract(std::forward(args)...), - std::forward(args)...) : - emplace_empty_impl(std::forward(args)...); - } - -#else - - template - template - BOOST_DEDUCED_TYPENAME hash_unique_table::emplace_return - hash_unique_table::emplace(Arg0 const& arg0) - { - return this->size_ ? - emplace_impl(extractor::extract(arg0), arg0) : - emplace_empty_impl(arg0); - } - -#define BOOST_UNORDERED_INSERT_IMPL(z, num_params, _) \ - template \ - template \ - BOOST_DEDUCED_TYPENAME hash_unique_table::emplace_return \ - hash_unique_table::emplace( \ - BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \ - { \ - return this->size_ ? \ - emplace_impl(extractor::extract(arg0, arg1), \ - BOOST_UNORDERED_CALL_PARAMS(z, num_params)) : \ - emplace_empty_impl( \ - BOOST_UNORDERED_CALL_PARAMS(z, num_params)); \ - } - - BOOST_PP_REPEAT_FROM_TO(2, BOOST_UNORDERED_EMPLACE_LIMIT, - BOOST_UNORDERED_INSERT_IMPL, _) - -#undef BOOST_UNORDERED_INSERT_IMPL - -#endif - - //////////////////////////////////////////////////////////////////////////// - // Insert range methods - - template - template - inline void hash_unique_table::insert_range_impl2( - node_constructor& a, key_type const& k, InputIt i, InputIt j) - { - // No side effects in this initial code - std::size_t hash_value = this->hash_function()(k); - bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value); - node_ptr pos = this->find_iterator(bucket, k); - - if (!BOOST_UNORDERED_BORLAND_BOOL(pos)) { - // Doesn't already exist, add to bucket. - // Side effects only in this block. - - // Create the node before rehashing in case it throws an - // exception (need strong safety in such a case). - a.construct(*i); - - // reserve has basic exception safety if the hash function - // throws, strong otherwise. - if(this->size_ + 1 >= this->max_load_) { - this->reserve_for_insert(this->size_ + insert_size(i, j)); - bucket = this->bucket_ptr_from_hash(hash_value); - } - - // Nothing after this point can throw. - add_node(a, bucket); - } - } - - template - template - inline void hash_unique_table::insert_range_impl( - key_type const&, InputIt i, InputIt j) - { - node_constructor a(*this); - - if(!this->size_) { - a.construct(*i); - this->emplace_empty_impl_with_node(a, 1); - ++i; - if(i == j) return; - } - - do { - // Note: can't use get_key as '*i' might not be value_type - it - // could be a pair with first_types as key_type without const or a - // different second_type. - // - // TODO: Might be worth storing the value_type instead of the key - // here. Could be more efficient if '*i' is expensive. Could be - // less efficient if copying the full value_type is expensive. - insert_range_impl2(a, extractor::extract(*i), i, j); - } while(++i != j); - } - - template - template - inline void hash_unique_table::insert_range_impl( - no_key, InputIt i, InputIt j) - { - node_constructor a(*this); - - if(!this->size_) { - a.construct(*i); - this->emplace_empty_impl_with_node(a, 1); - ++i; - if(i == j) return; - } - - do { - // No side effects in this initial code - a.construct(*i); - emplace_impl_with_node(a); - } while(++i != j); - } - - // if hash function throws, or inserting > 1 element, basic exception safety - // strong otherwise - template - template - void hash_unique_table::insert_range(InputIt i, InputIt j) - { - if(i != j) - return insert_range_impl(extractor::extract(*i), i, j); - } -}} +}}} #endif diff --git a/include/boost/unordered/detail/util.hpp b/include/boost/unordered/detail/util.hpp index 989883e0..801df188 100644 --- a/include/boost/unordered/detail/util.hpp +++ b/include/boost/unordered/detail/util.hpp @@ -7,16 +7,93 @@ #ifndef BOOST_UNORDERED_DETAIL_UTIL_HPP_INCLUDED #define BOOST_UNORDERED_DETAIL_UTIL_HPP_INCLUDED -#include -#include #include +#include +#include +#include #include +#include +#include +#include +#include +#include +#include #include +#include +#include +#include +#include +#include +#include #include #include -#include -namespace boost { namespace unordered_detail { +// Template parameters: +// +// H = Hash Function +// P = Predicate +// A = Value Allocator +// G = Bucket group policy, 'grouped' or 'ungrouped' +// E = Key Extractor + +#if !defined(BOOST_NO_RVALUE_REFERENCES) && \ + !defined(BOOST_NO_VARIADIC_TEMPLATES) +# if defined(__SGI_STL_PORT) || defined(_STLPORT_VERSION) + // STLport doesn't have std::forward. +# else +# define BOOST_UNORDERED_STD_FORWARD +# endif +#endif + +#if !defined(BOOST_UNORDERED_EMPLACE_LIMIT) +#define BOOST_UNORDERED_EMPLACE_LIMIT 10 +#endif + +#if !defined(BOOST_UNORDERED_STD_FORWARD) + +#include +#include +#include + +#define BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params) \ + BOOST_PP_ENUM_PARAMS_Z(z, num_params, class Arg) +#define BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params) \ + BOOST_PP_ENUM_BINARY_PARAMS_Z(z, num_params, Arg, const& arg) +#define BOOST_UNORDERED_CALL_PARAMS(z, num_params) \ + BOOST_PP_ENUM_PARAMS_Z(z, num_params, arg) + +#endif + +namespace boost { namespace unordered { namespace detail { + + static const float minimum_max_load_factor = 1e-3f; + static const std::size_t default_bucket_count = 11; + struct move_tag {}; + + template class unique_table; + template class equivalent_table; + template class node_constructor; + template + struct set_extractor; + template + struct map_extractor; + struct no_key; + + // Explicitly call a destructor + +#if defined(BOOST_MSVC) +#pragma warning(push) +#pragma warning(disable:4100) // unreferenced formal parameter +#endif + + template + inline void destroy(T* x) { + x->~T(); + } + +#if defined(BOOST_MSVC) +#pragma warning(pop) +#endif //////////////////////////////////////////////////////////////////////////// // convert double to std::size_t @@ -95,12 +172,19 @@ namespace boost { namespace unordered_detail { //////////////////////////////////////////////////////////////////////////// // pair_cast - because some libraries don't have the full pair constructors. +#if 0 template inline std::pair pair_cast(std::pair const& x) { return std::pair(Dst1(x.first), Dst2(x.second)); } +#define BOOST_UNORDERED_PAIR_CAST(First, Last, Argument) \ + ::boost::unordered::detail::pair_cast(Argument) +#else +#define BOOST_UNORDERED_PAIR_CAST(First, Last, Argument) \ + Argument +#endif //////////////////////////////////////////////////////////////////////////// // insert_size/initial_size @@ -116,13 +200,13 @@ namespace boost { namespace unordered_detail { #endif template - inline std::size_t insert_size(I i, I j, boost::forward_traversal_tag) + inline std::size_t insert_size(I i, I j, ::boost::forward_traversal_tag) { return std::distance(i, j); } template - inline std::size_t insert_size(I, I, boost::incrementable_traversal_tag) + inline std::size_t insert_size(I, I, ::boost::incrementable_traversal_tag) { return 1; } @@ -130,202 +214,18 @@ namespace boost { namespace unordered_detail { template inline std::size_t insert_size(I i, I j) { - BOOST_DEDUCED_TYPENAME boost::iterator_traversal::type + BOOST_DEDUCED_TYPENAME ::boost::iterator_traversal::type iterator_traversal_tag; return insert_size(i, j, iterator_traversal_tag); } template inline std::size_t initial_size(I i, I j, - std::size_t num_buckets = boost::unordered_detail::default_bucket_count) + std::size_t num_buckets = ::boost::unordered::detail::default_bucket_count) { return (std::max)(static_cast(insert_size(i, j)) + 1, num_buckets); } - - //////////////////////////////////////////////////////////////////////////// - // Node Constructors - -#if defined(BOOST_UNORDERED_STD_FORWARD) - - template - inline void construct_impl(T*, void* address, Args&&... args) - { - new(address) T(std::forward(args)...); - } - -#if defined(BOOST_UNORDERED_CPP0X_PAIR) - template - inline void construct_impl(std::pair*, void* address, - Key&& k, Arg0&& arg0, Args&&... args) - ) - { - new(address) std::pair(k, - Second(arg0, std::forward(args)...); - } -#endif - -#else - -#define BOOST_UNORDERED_CONSTRUCT_IMPL(z, num_params, _) \ - template < \ - class T, \ - BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params) \ - > \ - inline void construct_impl( \ - T*, void* address, \ - BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params) \ - ) \ - { \ - new(address) T( \ - BOOST_UNORDERED_CALL_PARAMS(z, num_params)); \ - } \ - \ - template \ - inline void construct_impl( \ - std::pair*, void* address, \ - Key const& k, BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \ - { \ - new(address) std::pair(k, \ - Second(BOOST_UNORDERED_CALL_PARAMS(z, num_params))); \ - } - - BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, - BOOST_UNORDERED_CONSTRUCT_IMPL, _) - -#undef BOOST_UNORDERED_CONSTRUCT_IMPL -#endif - - // hash_node_constructor - // - // Used to construct nodes in an exception safe manner. - - template - class hash_node_constructor - { - typedef hash_buckets buckets; - typedef BOOST_DEDUCED_TYPENAME buckets::node node; - typedef BOOST_DEDUCED_TYPENAME buckets::real_node_ptr real_node_ptr; - typedef BOOST_DEDUCED_TYPENAME buckets::value_type value_type; - - buckets& buckets_; - real_node_ptr node_; - bool node_constructed_; - bool value_constructed_; - - public: - - hash_node_constructor(buckets& m) : - buckets_(m), - node_(), - node_constructed_(false), - value_constructed_(false) - { - } - - ~hash_node_constructor(); - void construct_preamble(); - -#if defined(BOOST_UNORDERED_STD_FORWARD) - template - void construct(Args&&... args) - { - construct_preamble(); - construct_impl((value_type*) 0, node_->address(), - std::forward(args)...); - value_constructed_ = true; - } -#else - -#define BOOST_UNORDERED_CONSTRUCT(z, num_params, _) \ - template < \ - BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params) \ - > \ - void construct( \ - BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params) \ - ) \ - { \ - construct_preamble(); \ - construct_impl( \ - (value_type*) 0, node_->address(), \ - BOOST_UNORDERED_CALL_PARAMS(z, num_params) \ - ); \ - value_constructed_ = true; \ - } - - BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, - BOOST_UNORDERED_CONSTRUCT, _) - -#undef BOOST_UNORDERED_CONSTRUCT - -#endif - template - void construct_pair(K const& k, M*) - { - construct_preamble(); - new(node_->address()) value_type(k, M()); - value_constructed_ = true; - } - - value_type& value() const - { - BOOST_ASSERT(node_); - return node_->value(); - } - - // no throw - BOOST_DEDUCED_TYPENAME buckets::node_ptr release() - { - real_node_ptr p = node_; - node_ = real_node_ptr(); - // node_ptr cast - return buckets_.bucket_alloc().address(*p); - } - - private: - hash_node_constructor(hash_node_constructor const&); - hash_node_constructor& operator=(hash_node_constructor const&); - }; - - // hash_node_constructor - - template - inline hash_node_constructor::~hash_node_constructor() - { - if (node_) { - if (value_constructed_) { -#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613)) - struct dummy { hash_node x; }; -#endif - boost::unordered_detail::destroy(node_->value_ptr()); - } - - if (node_constructed_) - buckets_.node_alloc().destroy(node_); - - buckets_.node_alloc().deallocate(node_, 1); - } - } - - template - inline void hash_node_constructor::construct_preamble() - { - if(!node_) { - node_constructed_ = false; - value_constructed_ = false; - - node_ = buckets_.node_alloc().allocate(1); - buckets_.node_alloc().construct(node_, node()); - node_constructed_ = true; - } - else { - BOOST_ASSERT(node_constructed_ && value_constructed_); - boost::unordered_detail::destroy(node_->value_ptr()); - value_constructed_ = false; - } - } -}} +}}} #endif diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 86a6fc63..8b9e5e6e 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -54,15 +54,15 @@ namespace boost #endif typedef BOOST_DEDUCED_TYPENAME - boost::unordered_detail::rebind_wrap< + ::boost::unordered::detail::rebind_wrap< allocator_type, value_type>::type value_allocator; - typedef boost::unordered_detail::map types; typedef BOOST_DEDUCED_TYPENAME types::impl table; - typedef BOOST_DEDUCED_TYPENAME types::iterator_base iterator_base; + typedef BOOST_DEDUCED_TYPENAME types::node_ptr node_ptr; public: @@ -78,18 +78,14 @@ namespace boost typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; - typedef boost::unordered_detail::hash_const_local_iterator< - value_allocator, boost::unordered_detail::ungrouped> - const_local_iterator; - typedef boost::unordered_detail::hash_local_iterator< - value_allocator, boost::unordered_detail::ungrouped> - local_iterator; - typedef boost::unordered_detail::hash_const_iterator< - value_allocator, boost::unordered_detail::ungrouped> - const_iterator; - typedef boost::unordered_detail::hash_iterator< - value_allocator, boost::unordered_detail::ungrouped> - iterator; + typedef ::boost::unordered::iterator_detail::cl_iterator< + value_allocator, true> const_local_iterator; + typedef ::boost::unordered::iterator_detail::l_iterator< + value_allocator, true> local_iterator; + typedef ::boost::unordered::iterator_detail::c_iterator< + value_allocator, true> const_iterator; + typedef ::boost::unordered::iterator_detail::iterator< + value_allocator, true> iterator; #if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) private: @@ -97,10 +93,10 @@ namespace boost table table_; - BOOST_DEDUCED_TYPENAME types::iterator_base const& + BOOST_DEDUCED_TYPENAME types::node_ptr const& get(const_iterator const& it) { - return boost::unordered_detail::iterator_access::get(it); + return ::boost::unordered::detail::iterator_access::get(it); } public: @@ -108,120 +104,59 @@ namespace boost // construct/destroy/copy explicit unordered_map( - size_type n = boost::unordered_detail::default_bucket_count, - const hasher &hf = hasher(), - const key_equal &eql = key_equal(), - const allocator_type &a = allocator_type()) - : table_(n, hf, eql, a) - { - } + size_type = ::boost::unordered::detail::default_bucket_count, + const hasher& = hasher(), + const key_equal& = key_equal(), + const allocator_type& = allocator_type()); - explicit unordered_map(allocator_type const& a) - : table_(boost::unordered_detail::default_bucket_count, - hasher(), key_equal(), a) - { - } + explicit unordered_map(allocator_type const&); - unordered_map(unordered_map const& other, allocator_type const& a) - : table_(other.table_, a) - { - } + unordered_map(unordered_map const&, allocator_type const&); template - unordered_map(InputIt f, InputIt l) - : table_(boost::unordered_detail::initial_size(f, l), - hasher(), key_equal(), allocator_type()) - { - table_.insert_range(f, l); - } + unordered_map(InputIt f, InputIt l); template - unordered_map(InputIt f, InputIt l, - size_type n, - const hasher &hf = hasher(), - const key_equal &eql = key_equal()) - : table_(boost::unordered_detail::initial_size(f, l, n), - hf, eql, allocator_type()) - { - table_.insert_range(f, l); - } + unordered_map( + InputIt, InputIt, + size_type, + const hasher& = hasher(), + const key_equal& = key_equal()); template - unordered_map(InputIt f, InputIt l, - size_type n, - const hasher &hf, - const key_equal &eql, - const allocator_type &a) - : table_(boost::unordered_detail::initial_size(f, l, n), hf, eql, a) - { - table_.insert_range(f, l); - } - - ~unordered_map() {} + unordered_map( + InputIt, InputIt, + size_type, + const hasher&, + const key_equal&, + const allocator_type&); + + ~unordered_map(); #if !defined(BOOST_NO_RVALUE_REFERENCES) - unordered_map(unordered_map const& other) - : table_(other.table_) - { - } - - unordered_map(unordered_map&& other) - : table_(other.table_, boost::unordered_detail::move_tag()) - { - } - - unordered_map(unordered_map&& other, allocator_type const& a) - : table_(other.table_, a, boost::unordered_detail::move_tag()) - { - } - - unordered_map& operator=(unordered_map const& x) - { - table_ = x.table_; - return *this; - } - - unordered_map& operator=(unordered_map&& x) - { - table_.move(x.table_); - return *this; - } + unordered_map(unordered_map const&); + unordered_map(unordered_map&&); + unordered_map(unordered_map&&, allocator_type const&); + unordered_map& operator=(unordered_map const&); + unordered_map& operator=(unordered_map&&); #else - unordered_map(boost::unordered_detail::move_from< - unordered_map - > other) - : table_(other.source.table_, boost::unordered_detail::move_tag()) - { - } - + unordered_map(::boost::unordered::detail::move_from< + unordered_map + >); #if !BOOST_WORKAROUND(__BORLANDC__, < 0x0593) - unordered_map& operator=(unordered_map x) - { - table_.move(x.table_); - return *this; - } + unordered_map& operator=(unordered_map); #endif #endif #if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) - unordered_map(std::initializer_list list, - size_type n = boost::unordered_detail::default_bucket_count, - const hasher &hf = hasher(), - const key_equal &eql = key_equal(), - const allocator_type &a = allocator_type()) - : table_(boost::unordered_detail::initial_size( - list.begin(), list.end(), n), - hf, eql, a) - { - table_.insert_range(list.begin(), list.end()); - } + unordered_map( + std::initializer_list, + size_type = ::boost::unordered::detail::default_bucket_count, + const hasher& = hasher(), + const key_equal&l = key_equal(), + const allocator_type& = allocator_type()); - unordered_map& operator=(std::initializer_list list) - { - table_.clear(); - table_.insert_range(list.begin(), list.end()); - return *this; - } + unordered_map& operator=(std::initializer_list); #endif allocator_type get_allocator() const @@ -241,10 +176,7 @@ namespace boost return table_.size_; } - size_type max_size() const - { - return table_.max_size(); - } + size_type max_size() const; // iterators @@ -260,12 +192,12 @@ namespace boost iterator end() { - return iterator(table_.end()); + return iterator(); } const_iterator end() const { - return const_iterator(table_.end()); + return const_iterator(); } const_iterator cbegin() const @@ -275,38 +207,21 @@ namespace boost const_iterator cend() const { - return const_iterator(table_.end()); + return const_iterator(); } // modifiers #if defined(BOOST_UNORDERED_STD_FORWARD) template - std::pair emplace(Args&&... args) - { - return boost::unordered_detail::pair_cast( - table_.emplace(std::forward(args)...)); - } - + std::pair emplace(Args&&...); template - iterator emplace_hint(const_iterator, Args&&... args) - { - return iterator(table_.emplace(std::forward(args)...).first); - } + iterator emplace_hint(const_iterator, Args&&...); #else #if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100)) - std::pair emplace(value_type const& v = value_type()) - { - return boost::unordered_detail::pair_cast( - table_.emplace(v)); - } - - iterator emplace_hint(const_iterator, - value_type const& v = value_type()) - { - return iterator(table_.emplace(v).first); - } + std::pair emplace(value_type const& = value_type()); + iterator emplace_hint(const_iterator, value_type const& = value_type()); #endif #define BOOST_UNORDERED_EMPLACE(z, n, _) \ @@ -315,24 +230,14 @@ namespace boost > \ std::pair emplace( \ BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ - ) \ - { \ - return boost::unordered_detail::pair_cast( \ - table_.emplace( \ - BOOST_UNORDERED_CALL_PARAMS(z, n) \ - )); \ - } \ + ); \ \ template < \ BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ > \ iterator emplace_hint(const_iterator, \ BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ - ) \ - { \ - return iterator(table_.emplace( \ - BOOST_UNORDERED_CALL_PARAMS(z, n)).first); \ - } + ); BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, BOOST_UNORDERED_EMPLACE, _) @@ -341,144 +246,57 @@ namespace boost #endif - std::pair insert(const value_type& obj) - { - return boost::unordered_detail::pair_cast( - table_.emplace(obj)); - } - - iterator insert(const_iterator, const value_type& obj) - { - return iterator(table_.emplace(obj).first); - } - - template - void insert(InputIt first, InputIt last) - { - table_.insert_range(first, last); - } + std::pair insert(const value_type&); + iterator insert(const_iterator, const value_type&); + template void insert(InputIt, InputIt); #if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) - void insert(std::initializer_list list) - { - table_.insert_range(list.begin(), list.end()); - } + void insert(std::initializer_list); #endif - iterator erase(const_iterator position) - { - return iterator(table_.erase_return_iterator(get(position))); - } + iterator erase(const_iterator); + size_type erase(const key_type&); + iterator erase(const_iterator, const_iterator); + void quick_erase(const_iterator it) { erase(it); } + void erase_return_void(const_iterator it) { erase(it); } - size_type erase(const key_type& k) - { - return table_.erase_key(k); - } - - iterator erase(const_iterator first, const_iterator last) - { - return iterator(table_.erase_range(get(first), get(last))); - } - - void quick_erase(const_iterator position) - { - table_.erase(get(position)); - } - - void erase_return_void(const_iterator position) - { - table_.erase(get(position)); - } - - void clear() - { - table_.clear(); - } - - void swap(unordered_map& other) - { - table_.swap(other.table_); - } + void clear(); + void swap(unordered_map&); // observers - hasher hash_function() const - { - return table_.hash_function(); - } + hasher hash_function() const; + key_equal key_eq() const; - key_equal key_eq() const - { - return table_.key_eq(); - } - - mapped_type& operator[](const key_type &k) - { - return table_[k].second; - } - - mapped_type& at(const key_type& k) - { - return table_.at(k).second; - } - - mapped_type const& at(const key_type& k) const - { - return table_.at(k).second; - } + mapped_type& operator[](const key_type&); + mapped_type& at(const key_type&); + mapped_type const& at(const key_type&) const; // lookup - iterator find(const key_type& k) - { - return iterator(table_.find(k)); - } - - const_iterator find(const key_type& k) const - { - return const_iterator(table_.find(k)); - } + iterator find(const key_type&); + const_iterator find(const key_type&) const; template iterator find( - CompatibleKey const& k, - CompatibleHash const& hash, - CompatiblePredicate const& eq) - { - return iterator(table_.find(k, hash, eq)); - } + CompatibleKey const&, + CompatibleHash const&, + CompatiblePredicate const&); template const_iterator find( - CompatibleKey const& k, - CompatibleHash const& hash, - CompatiblePredicate const& eq) const - { - return iterator(table_.find(k, hash, eq)); - } + CompatibleKey const&, + CompatibleHash const&, + CompatiblePredicate const&) const; - size_type count(const key_type& k) const - { - return table_.count(k); - } + size_type count(const key_type&) const; std::pair - equal_range(const key_type& k) - { - return boost::unordered_detail::pair_cast< - iterator, iterator>( - table_.equal_range(k)); - } - + equal_range(const key_type&); std::pair - equal_range(const key_type& k) const - { - return boost::unordered_detail::pair_cast< - const_iterator, const_iterator>( - table_.equal_range(k)); - } + equal_range(const key_type&) const; // bucket interface @@ -492,24 +310,23 @@ namespace boost return table_.max_bucket_count(); } - size_type bucket_size(size_type n) const - { - return table_.bucket_size(n); - } + size_type bucket_size(size_type n) const; size_type bucket(const key_type& k) const { - return table_.bucket_index(k); + return table_.hash_function()(k) % table_.bucket_count_; } local_iterator begin(size_type n) { - return local_iterator(table_.bucket_begin(n)); + return local_iterator( + table_.bucket_begin(n), n, table_.bucket_count_); } const_local_iterator begin(size_type n) const { - return const_local_iterator(table_.bucket_begin(n)); + return const_local_iterator( + table_.bucket_begin(n), n, table_.bucket_count_); } local_iterator end(size_type) @@ -524,7 +341,8 @@ namespace boost const_local_iterator cbegin(size_type n) const { - return const_local_iterator(table_.bucket_begin(n)); + return const_local_iterator( + table_.bucket_begin(n), n, table_.bucket_count_); } const_local_iterator cend(size_type) const @@ -534,64 +352,23 @@ namespace boost // hash policy - float load_factor() const - { - return table_.load_factor(); - } - float max_load_factor() const { return table_.mlf_; } - void max_load_factor(float m) - { - table_.max_load_factor(m); - } + float load_factor() const; + void max_load_factor(float); + void rehash(size_type n); - void rehash(size_type n) - { - table_.rehash(n); - } - #if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) - friend bool operator==( - unordered_map const&, unordered_map const&); - friend bool operator!=( - unordered_map const&, unordered_map const&); + friend bool operator==( + unordered_map const&, unordered_map const&); + friend bool operator!=( + unordered_map const&, unordered_map const&); #endif }; // class template unordered_map - template - inline bool operator==(unordered_map const& m1, - unordered_map const& m2) - { -#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613)) - struct dummy { unordered_map x; }; -#endif - return m1.table_.equals(m2.table_); - } - - template - inline bool operator!=(unordered_map const& m1, - unordered_map const& m2) - { -#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613)) - struct dummy { unordered_map x; }; -#endif - return !m1.table_.equals(m2.table_); - } - - template - inline void swap(unordered_map &m1, - unordered_map &m2) - { -#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613)) - struct dummy { unordered_map x; }; -#endif - m1.swap(m2); - } - template class unordered_multimap { @@ -609,15 +386,15 @@ namespace boost #endif typedef BOOST_DEDUCED_TYPENAME - boost::unordered_detail::rebind_wrap< + ::boost::unordered::detail::rebind_wrap< allocator_type, value_type>::type value_allocator; - typedef boost::unordered_detail::multimap types; typedef BOOST_DEDUCED_TYPENAME types::impl table; - typedef BOOST_DEDUCED_TYPENAME types::iterator_base iterator_base; + typedef BOOST_DEDUCED_TYPENAME types::node_ptr node_ptr; public: @@ -633,18 +410,14 @@ namespace boost typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; - typedef boost::unordered_detail::hash_const_local_iterator< - value_allocator, boost::unordered_detail::grouped> - const_local_iterator; - typedef boost::unordered_detail::hash_local_iterator< - value_allocator, boost::unordered_detail::grouped> - local_iterator; - typedef boost::unordered_detail::hash_const_iterator< - value_allocator, boost::unordered_detail::grouped> - const_iterator; - typedef boost::unordered_detail::hash_iterator< - value_allocator, boost::unordered_detail::grouped> - iterator; + typedef ::boost::unordered::iterator_detail::cl_iterator< + value_allocator, false> const_local_iterator; + typedef ::boost::unordered::iterator_detail::l_iterator< + value_allocator, false> local_iterator; + typedef ::boost::unordered::iterator_detail::c_iterator< + value_allocator, false> const_iterator; + typedef ::boost::unordered::iterator_detail::iterator< + value_allocator, false> iterator; #if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) private: @@ -652,10 +425,10 @@ namespace boost table table_; - BOOST_DEDUCED_TYPENAME types::iterator_base const& + BOOST_DEDUCED_TYPENAME types::node_ptr const& get(const_iterator const& it) { - return boost::unordered_detail::iterator_access::get(it); + return ::boost::unordered::detail::iterator_access::get(it); } public: @@ -663,121 +436,60 @@ namespace boost // construct/destroy/copy explicit unordered_multimap( - size_type n = boost::unordered_detail::default_bucket_count, - const hasher &hf = hasher(), - const key_equal &eql = key_equal(), - const allocator_type &a = allocator_type()) - : table_(n, hf, eql, a) - { - } + size_type = ::boost::unordered::detail::default_bucket_count, + const hasher& = hasher(), + const key_equal& = key_equal(), + const allocator_type& = allocator_type()); - explicit unordered_multimap(allocator_type const& a) - : table_(boost::unordered_detail::default_bucket_count, - hasher(), key_equal(), a) - { - } + explicit unordered_multimap(allocator_type const&); - unordered_multimap(unordered_multimap const& other, - allocator_type const& a) - : table_(other.table_, a) - { - } + unordered_multimap(unordered_multimap const&, allocator_type const&); template - unordered_multimap(InputIt f, InputIt l) - : table_(boost::unordered_detail::initial_size(f, l), - hasher(), key_equal(), allocator_type()) - { - table_.insert_range(f, l); - } + unordered_multimap(InputIt, InputIt); template - unordered_multimap(InputIt f, InputIt l, - size_type n, - const hasher &hf = hasher(), - const key_equal &eql = key_equal()) - : table_(boost::unordered_detail::initial_size(f, l, n), - hf, eql, allocator_type()) - { - table_.insert_range(f, l); - } + unordered_multimap( + InputIt, InputIt, + size_type, + const hasher& = hasher(), + const key_equal& = key_equal()); template - unordered_multimap(InputIt f, InputIt l, - size_type n, - const hasher &hf, - const key_equal &eql, - const allocator_type &a) - : table_(boost::unordered_detail::initial_size(f, l, n), hf, eql, a) - { - table_.insert_range(f, l); - } + unordered_multimap( + InputIt, InputIt, + size_type, + const hasher&, + const key_equal&, + const allocator_type&); - ~unordered_multimap() {} + ~unordered_multimap(); #if !defined(BOOST_NO_RVALUE_REFERENCES) - unordered_multimap(unordered_multimap const& other) - : table_(other.table_) - { - } - - unordered_multimap(unordered_multimap&& other) - : table_(other.table_, boost::unordered_detail::move_tag()) - { - } - - unordered_multimap(unordered_multimap&& other, allocator_type const& a) - : table_(other.table_, a, boost::unordered_detail::move_tag()) - { - } - - unordered_multimap& operator=(unordered_multimap const& x) - { - table_ = x.table_; - return *this; - } - - unordered_multimap& operator=(unordered_multimap&& x) - { - table_.move(x.table_); - return *this; - } + unordered_multimap(unordered_multimap const&); + unordered_multimap(unordered_multimap&&); + unordered_multimap(unordered_multimap&&, allocator_type const&); + unordered_multimap& operator=(unordered_multimap const&); + unordered_multimap& operator=(unordered_multimap&&); #else - unordered_multimap(boost::unordered_detail::move_from< - unordered_multimap - > other) - : table_(other.source.table_, boost::unordered_detail::move_tag()) - { - } + unordered_multimap(::boost::unordered::detail::move_from< + unordered_multimap + >); #if !BOOST_WORKAROUND(__BORLANDC__, < 0x0593) - unordered_multimap& operator=(unordered_multimap x) - { - table_.move(x.table_); - return *this; - } + unordered_multimap& operator=(unordered_multimap); #endif #endif #if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) - unordered_multimap(std::initializer_list list, - size_type n = boost::unordered_detail::default_bucket_count, - const hasher &hf = hasher(), - const key_equal &eql = key_equal(), - const allocator_type &a = allocator_type()) - : table_(boost::unordered_detail::initial_size( - list.begin(), list.end(), n), - hf, eql, a) - { - table_.insert_range(list.begin(), list.end()); - } + unordered_multimap( + std::initializer_list, + size_type = ::boost::unordered::detail::default_bucket_count, + const hasher& = hasher(), + const key_equal&l = key_equal(), + const allocator_type& = allocator_type()); - unordered_multimap& operator=(std::initializer_list list) - { - table_.clear(); - table_.insert_range(list.begin(), list.end()); - return *this; - } + unordered_multimap& operator=(std::initializer_list); #endif allocator_type get_allocator() const @@ -797,10 +509,7 @@ namespace boost return table_.size_; } - size_type max_size() const - { - return table_.max_size(); - } + size_type max_size() const; // iterators @@ -816,12 +525,12 @@ namespace boost iterator end() { - return iterator(table_.end()); + return iterator(); } const_iterator end() const { - return const_iterator(table_.end()); + return const_iterator(); } const_iterator cbegin() const @@ -831,36 +540,21 @@ namespace boost const_iterator cend() const { - return const_iterator(table_.end()); + return const_iterator(); } // modifiers #if defined(BOOST_UNORDERED_STD_FORWARD) template - iterator emplace(Args&&... args) - { - return iterator(table_.emplace(std::forward(args)...)); - } - + iterator emplace(Args&&...); template - iterator emplace_hint(const_iterator, Args&&... args) - { - return iterator(table_.emplace(std::forward(args)...)); - } + iterator emplace_hint(const_iterator, Args&&...); #else #if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100)) - iterator emplace(value_type const& v = value_type()) - { - return iterator(table_.emplace(v)); - } - - iterator emplace_hint(const_iterator, - value_type const& v = value_type()) - { - return iterator(table_.emplace(v)); - } + iterator emplace(value_type const& = value_type()); + iterator emplace_hint(const_iterator, value_type const& = value_type()); #endif #define BOOST_UNORDERED_EMPLACE(z, n, _) \ @@ -869,25 +563,14 @@ namespace boost > \ iterator emplace( \ BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ - ) \ - { \ - return iterator( \ - table_.emplace( \ - BOOST_UNORDERED_CALL_PARAMS(z, n) \ - )); \ - } \ + ); \ \ template < \ BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ > \ iterator emplace_hint(const_iterator, \ BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ - ) \ - { \ - return iterator(table_.emplace( \ - BOOST_UNORDERED_CALL_PARAMS(z, n) \ - )); \ - } + ); BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, BOOST_UNORDERED_EMPLACE, _) @@ -896,128 +579,54 @@ namespace boost #endif - iterator insert(const value_type& obj) - { - return iterator(table_.emplace(obj)); - } - - iterator insert(const_iterator, const value_type& obj) - { - return iterator(table_.emplace(obj)); - } - + iterator insert(const value_type&); + iterator insert(const_iterator, const value_type&); template - void insert(InputIt first, InputIt last) - { - table_.insert_range(first, last); - } + void insert(InputIt, InputIt); #if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) - void insert(std::initializer_list list) - { - table_.insert_range(list.begin(), list.end()); - } + void insert(std::initializer_list); #endif - iterator erase(const_iterator position) - { - return iterator(table_.erase_return_iterator(get(position))); - } + iterator erase(const_iterator); + size_type erase(const key_type&); + iterator erase(const_iterator, const_iterator); + void quick_erase(const_iterator position) { erase(position); } + void erase_return_void(const_iterator position) { erase(position); } - size_type erase(const key_type& k) - { - return table_.erase_key(k); - } - - iterator erase(const_iterator first, const_iterator last) - { - return iterator(table_.erase_range(get(first), get(last))); - } - - void quick_erase(const_iterator position) - { - table_.erase(get(position)); - } - - void erase_return_void(const_iterator position) - { - table_.erase(get(position)); - } - - void clear() - { - table_.clear(); - } - - void swap(unordered_multimap& other) - { - table_.swap(other.table_); - } + void clear(); + void swap(unordered_multimap&); // observers - hasher hash_function() const - { - return table_.hash_function(); - } - - key_equal key_eq() const - { - return table_.key_eq(); - } + hasher hash_function() const; + key_equal key_eq() const; // lookup - iterator find(const key_type& k) - { - return iterator(table_.find(k)); - } - - const_iterator find(const key_type& k) const - { - return const_iterator(table_.find(k)); - } + iterator find(const key_type&); + const_iterator find(const key_type&) const; template iterator find( - CompatibleKey const& k, - CompatibleHash const& hash, - CompatiblePredicate const& eq) - { - return iterator(table_.find(k, hash, eq)); - } + CompatibleKey const&, + CompatibleHash const&, + CompatiblePredicate const&); template const_iterator find( - CompatibleKey const& k, - CompatibleHash const& hash, - CompatiblePredicate const& eq) const - { - return iterator(table_.find(k, hash, eq)); - } + CompatibleKey const&, + CompatibleHash const&, + CompatiblePredicate const&) const; - size_type count(const key_type& k) const - { - return table_.count(k); - } + size_type count(const key_type&) const; std::pair - equal_range(const key_type& k) - { - return boost::unordered_detail::pair_cast< - iterator, iterator>( - table_.equal_range(k)); - } - + equal_range(const key_type&); std::pair - equal_range(const key_type& k) const - { - return boost::unordered_detail::pair_cast< - const_iterator, const_iterator>( - table_.equal_range(k)); - } + equal_range(const key_type&) const; // bucket interface @@ -1031,24 +640,23 @@ namespace boost return table_.max_bucket_count(); } - size_type bucket_size(size_type n) const - { - return table_.bucket_size(n); - } + size_type bucket_size(size_type) const; size_type bucket(const key_type& k) const { - return table_.bucket_index(k); + return table_.hash_function()(k) % table_.bucket_count_; } local_iterator begin(size_type n) { - return local_iterator(table_.bucket_begin(n)); + return local_iterator( + table_.bucket_begin(n), n, table_.bucket_count_); } const_local_iterator begin(size_type n) const { - return const_local_iterator(table_.bucket_begin(n)); + return const_local_iterator( + table_.bucket_begin(n), n, table_.bucket_count_); } local_iterator end(size_type) @@ -1063,7 +671,8 @@ namespace boost const_local_iterator cbegin(size_type n) const { - return const_local_iterator(table_.bucket_begin(n)); + return const_local_iterator( + table_.bucket_begin(n), n, table_.bucket_count_); } const_local_iterator cend(size_type) const @@ -1073,37 +682,879 @@ namespace boost // hash policy - float load_factor() const - { - return table_.load_factor(); - } - float max_load_factor() const { return table_.mlf_; } - void max_load_factor(float m) - { - table_.max_load_factor(m); - } - - void rehash(size_type n) - { - table_.rehash(n); - } + float load_factor() const; + void max_load_factor(float); + void rehash(size_type); #if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) - friend bool operator==( + friend bool operator==( unordered_multimap const&, unordered_multimap const&); - friend bool operator!=( + friend bool operator!=( unordered_multimap const&, unordered_multimap const&); #endif }; // class template unordered_multimap +//////////////////////////////////////////////////////////////////////////////// + template - inline bool operator==(unordered_multimap const& m1, - unordered_multimap const& m2) + unordered_map::unordered_map( + size_type n, const hasher &hf, const key_equal &eql, + const allocator_type &a) + : table_(n, hf, eql, a) + { + } + + template + unordered_map::unordered_map(allocator_type const& a) + : table_(::boost::unordered::detail::default_bucket_count, + hasher(), key_equal(), a) + { + } + + template + unordered_map::unordered_map( + unordered_map const& other, allocator_type const& a) + : table_(other.table_, a) + { + } + + template + template + unordered_map::unordered_map(InputIt f, InputIt l) + : table_(::boost::unordered::detail::initial_size(f, l), + hasher(), key_equal(), allocator_type()) + { + table_.insert_range(f, l); + } + + template + template + unordered_map::unordered_map( + InputIt f, InputIt l, + size_type n, + const hasher &hf, + const key_equal &eql) + : table_(::boost::unordered::detail::initial_size(f, l, n), + hf, eql, allocator_type()) + { + table_.insert_range(f, l); + } + + template + template + unordered_map::unordered_map( + InputIt f, InputIt l, + size_type n, + const hasher &hf, + const key_equal &eql, + const allocator_type &a) + : table_(::boost::unordered::detail::initial_size(f, l, n), hf, eql, a) + { + table_.insert_range(f, l); + } + + template + unordered_map::~unordered_map() {} + +#if !defined(BOOST_NO_RVALUE_REFERENCES) + template + unordered_map::unordered_map(unordered_map const& other) + : table_(other.table_) + { + } + + template + unordered_map::unordered_map(unordered_map&& other) + : table_(other.table_, ::boost::unordered::detail::move_tag()) + { + } + + template + unordered_map::unordered_map( + unordered_map&& other, allocator_type const& a) + : table_(other.table_, a, ::boost::unordered::detail::move_tag()) + { + } + + template + unordered_map& unordered_map:: + operator=(unordered_map const& x) + { + table_ = x.table_; + return *this; + } + + template + unordered_map& unordered_map:: + operator=(unordered_map&& x) + { + table_.move(x.table_); + return *this; + } +#else + template + unordered_map::unordered_map( + ::boost::unordered::detail::move_from > + other) + : table_(other.source.table_, ::boost::unordered::detail::move_tag()) + { + } + +#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0593) + template + unordered_map& unordered_map:: + operator=(unordered_map x) + { + table_.move(x.table_); + return *this; + } +#endif +#endif + +#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) + template + unordered_map::unordered_map( + std::initializer_list list, size_type n, + const hasher &hf, const key_equal &eql, const allocator_type &a) + : table_( + ::boost::unordered::detail::initial_size( + list.begin(), list.end(), n), + hf, eql, a) + { + table_.insert_range(list.begin(), list.end()); + } + + template + unordered_map& unordered_map::operator=( + std::initializer_list list) + { + table_.clear(); + table_.insert_range(list.begin(), list.end()); + return *this; + } +#endif + + // size and capacity + + template + std::size_t unordered_map::max_size() const + { + return table_.max_size(); + } + + // modifiers + +#if defined(BOOST_UNORDERED_STD_FORWARD) + template + template + std::pair::iterator, bool> + unordered_map::emplace(Args&&... args) + { + return BOOST_UNORDERED_PAIR_CAST(iterator, bool, + table_.emplace(std::forward(args)...)); + } + + template + template + BOOST_DEDUCED_TYPENAME unordered_map::iterator + unordered_map::emplace_hint(const_iterator, Args&&... args) + { + return iterator(table_.emplace(std::forward(args)...).first); + } +#else + +#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100)) + template + std::pair::iterator, bool> + unordered_map::emplace(value_type const& v) + { + return BOOST_UNORDERED_PAIR_CAST(iterator, bool, table_.emplace(v)); + } + + template + BOOST_DEDUCED_TYPENAME unordered_map::iterator + unordered_map::emplace_hint( + const_iterator, value_type const& v) + { + return iterator(table_.emplace(v).first); + } +#endif + +#define BOOST_UNORDERED_EMPLACE(z, n, _) \ + template \ + template < \ + BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ + > \ + std::pair< \ + BOOST_DEDUCED_TYPENAME unordered_map::iterator, \ + bool> \ + unordered_map::emplace( \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \ + { \ + return \ + BOOST_UNORDERED_PAIR_CAST(iterator, bool, \ + table_.emplace( \ + BOOST_UNORDERED_CALL_PARAMS(z, n))); \ + } \ + \ + template \ + template < \ + BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ + > \ + BOOST_DEDUCED_TYPENAME unordered_map::iterator \ + unordered_map::emplace_hint( \ + const_iterator, \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ + ) \ + { \ + return iterator(table_.emplace( \ + BOOST_UNORDERED_CALL_PARAMS(z, n)).first); \ + } + + BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, + BOOST_UNORDERED_EMPLACE, _) + +#undef BOOST_UNORDERED_EMPLACE + +#endif + + template + std::pair::iterator, bool> + unordered_map::insert(const value_type& obj) + { + return BOOST_UNORDERED_PAIR_CAST(iterator, bool, table_.insert(obj)); + } + + template + BOOST_DEDUCED_TYPENAME unordered_map::iterator + unordered_map::insert(const_iterator, const value_type& obj) + { + return iterator(table_.emplace(obj).first); + } + + template + template + void unordered_map::insert(InputIt first, InputIt last) + { + table_.insert_range(first, last); + } + +#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) + template + void unordered_map::insert( + std::initializer_list list) + { + table_.insert_range(list.begin(), list.end()); + } +#endif + + template + BOOST_DEDUCED_TYPENAME unordered_map::iterator + unordered_map::erase(const_iterator position) + { + return iterator(table_.erase(get(position))); + } + + template + BOOST_DEDUCED_TYPENAME unordered_map::size_type + unordered_map::erase(const key_type& k) + { + return table_.erase_key(k); + } + + template + BOOST_DEDUCED_TYPENAME unordered_map::iterator + unordered_map::erase( + const_iterator first, const_iterator last) + { + return iterator(table_.erase_range(get(first), get(last))); + } + + template + void unordered_map::clear() + { + table_.clear(); + } + + template + void unordered_map::swap(unordered_map& other) + { + table_.swap(other.table_); + } + + // observers + + template + BOOST_DEDUCED_TYPENAME unordered_map::hasher + unordered_map::hash_function() const + { + return table_.hash_function(); + } + + template + BOOST_DEDUCED_TYPENAME unordered_map::key_equal + unordered_map::key_eq() const + { + return table_.key_eq(); + } + + template + BOOST_DEDUCED_TYPENAME unordered_map::mapped_type& + unordered_map::operator[](const key_type &k) + { + return table_[k].second; + } + + template + BOOST_DEDUCED_TYPENAME unordered_map::mapped_type& + unordered_map::at(const key_type& k) + { + return table_.at(k).second; + } + + template + BOOST_DEDUCED_TYPENAME unordered_map::mapped_type const& + unordered_map::at(const key_type& k) const + { + return table_.at(k).second; + } + + // lookup + + template + BOOST_DEDUCED_TYPENAME unordered_map::iterator + unordered_map::find(const key_type& k) + { + return iterator(table_.find_node(k)); + } + + template + BOOST_DEDUCED_TYPENAME unordered_map::const_iterator + unordered_map::find(const key_type& k) const + { + return const_iterator(table_.find_node(k)); + } + + template + template + BOOST_DEDUCED_TYPENAME unordered_map::iterator + unordered_map::find( + CompatibleKey const& k, + CompatibleHash const& hash, + CompatiblePredicate const& eq) + { + return iterator(table_.generic_find_node(k, hash, eq)); + } + + template + template + BOOST_DEDUCED_TYPENAME unordered_map::const_iterator + unordered_map::find( + CompatibleKey const& k, + CompatibleHash const& hash, + CompatiblePredicate const& eq) const + { + return const_iterator(table_.generic_find_node(k, hash, eq)); + } + + template + BOOST_DEDUCED_TYPENAME unordered_map::size_type + unordered_map::count(const key_type& k) const + { + return table_.count(k); + } + + template + std::pair< + BOOST_DEDUCED_TYPENAME unordered_map::iterator, + BOOST_DEDUCED_TYPENAME unordered_map::iterator> + unordered_map::equal_range(const key_type& k) + { + return BOOST_UNORDERED_PAIR_CAST(iterator, iterator, + table_.equal_range(k)); + } + + template + std::pair< + BOOST_DEDUCED_TYPENAME unordered_map::const_iterator, + BOOST_DEDUCED_TYPENAME unordered_map::const_iterator> + unordered_map::equal_range(const key_type& k) const + { + return BOOST_UNORDERED_PAIR_CAST(const_iterator, const_iterator, + table_.equal_range(k)); + } + + template + BOOST_DEDUCED_TYPENAME unordered_map::size_type + unordered_map::bucket_size(size_type n) const + { + return table_.bucket_size(n); + } + + // hash policy + + template + float unordered_map::load_factor() const + { + return table_.load_factor(); + } + + template + void unordered_map::max_load_factor(float m) + { + table_.max_load_factor(m); + } + + template + void unordered_map::rehash(size_type n) + { + table_.rehash(n); + } + + template + inline bool operator==( + unordered_map const& m1, + unordered_map const& m2) + { +#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613)) + struct dummy { unordered_map x; }; +#endif + return m1.table_.equals(m2.table_); + } + + template + inline bool operator!=( + unordered_map const& m1, + unordered_map const& m2) + { +#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613)) + struct dummy { unordered_map x; }; +#endif + return !m1.table_.equals(m2.table_); + } + + template + inline void swap( + unordered_map &m1, + unordered_map &m2) + { +#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613)) + struct dummy { unordered_map x; }; +#endif + m1.swap(m2); + } + +//////////////////////////////////////////////////////////////////////////////// + + template + unordered_multimap::unordered_multimap( + size_type n, const hasher &hf, const key_equal &eql, + const allocator_type &a) + : table_(n, hf, eql, a) + { + } + + template + unordered_multimap::unordered_multimap(allocator_type const& a) + : table_(::boost::unordered::detail::default_bucket_count, + hasher(), key_equal(), a) + { + } + + template + unordered_multimap::unordered_multimap( + unordered_multimap const& other, allocator_type const& a) + : table_(other.table_, a) + { + } + + template + template + unordered_multimap::unordered_multimap(InputIt f, InputIt l) + : table_(::boost::unordered::detail::initial_size(f, l), + hasher(), key_equal(), allocator_type()) + { + table_.insert_range(f, l); + } + + template + template + unordered_multimap::unordered_multimap( + InputIt f, InputIt l, + size_type n, + const hasher &hf, + const key_equal &eql) + : table_(::boost::unordered::detail::initial_size(f, l, n), + hf, eql, allocator_type()) + { + table_.insert_range(f, l); + } + + template + template + unordered_multimap::unordered_multimap( + InputIt f, InputIt l, + size_type n, + const hasher &hf, + const key_equal &eql, + const allocator_type &a) + : table_(::boost::unordered::detail::initial_size(f, l, n), hf, eql, a) + { + table_.insert_range(f, l); + } + + template + unordered_multimap::~unordered_multimap() {} + +#if !defined(BOOST_NO_RVALUE_REFERENCES) + template + unordered_multimap::unordered_multimap( + unordered_multimap const& other) + : table_(other.table_) + { + } + + template + unordered_multimap::unordered_multimap( + unordered_multimap&& other) + : table_(other.table_, ::boost::unordered::detail::move_tag()) + { + } + + template + unordered_multimap::unordered_multimap( + unordered_multimap&& other, allocator_type const& a) + : table_(other.table_, a, ::boost::unordered::detail::move_tag()) + { + } + + template + unordered_multimap& unordered_multimap:: + operator=(unordered_multimap const& x) + { + table_ = x.table_; + return *this; + } + + template + unordered_multimap& unordered_multimap:: + operator=(unordered_multimap&& x) + { + table_.move(x.table_); + return *this; + } + +#else + + template + unordered_multimap::unordered_multimap( + ::boost::unordered::detail::move_from< + unordered_multimap > other) + : table_(other.source.table_, ::boost::unordered::detail::move_tag()) + { + } + +#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0593) + template + unordered_multimap& unordered_multimap:: + operator=(unordered_multimap x) + { + table_.move(x.table_); + return *this; + } +#endif +#endif + +#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) + template + unordered_multimap::unordered_multimap( + std::initializer_list list, size_type n, + const hasher &hf, const key_equal &eql, const allocator_type &a) + : table_( + ::boost::unordered::detail::initial_size( + list.begin(), list.end(), n), + hf, eql, a) + { + table_.insert_range(list.begin(), list.end()); + } + + template + unordered_multimap& unordered_multimap::operator=( + std::initializer_list list) + { + table_.clear(); + table_.insert_range(list.begin(), list.end()); + return *this; + } +#endif + + // size and capacity + + template + std::size_t unordered_multimap::max_size() const + { + return table_.max_size(); + } + + // modifiers + +#if defined(BOOST_UNORDERED_STD_FORWARD) + + template + template + BOOST_DEDUCED_TYPENAME unordered_multimap::iterator + unordered_multimap::emplace(Args&&... args) + { + return iterator(table_.emplace(std::forward(args)...)); + } + + template + template + BOOST_DEDUCED_TYPENAME unordered_multimap::iterator + unordered_multimap::emplace_hint( + const_iterator, Args&&... args) + { + return iterator(table_.emplace(std::forward(args)...)); + } + +#else + +#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100)) + template + BOOST_DEDUCED_TYPENAME unordered_multimap::iterator + unordered_multimap::emplace(value_type const& v) + { + return iterator(table_.emplace(v)); + } + + template + BOOST_DEDUCED_TYPENAME unordered_multimap::iterator + unordered_multimap::emplace_hint( + const_iterator, value_type const& v) + { + return iterator(table_.emplace(v)); + } +#endif + +#define BOOST_UNORDERED_EMPLACE(z, n, _) \ + template \ + template < \ + BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ + > \ + BOOST_DEDUCED_TYPENAME unordered_multimap::iterator \ + unordered_multimap::emplace( \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \ + { \ + return iterator(table_.emplace( \ + BOOST_UNORDERED_CALL_PARAMS(z, n))); \ + } \ + \ + template \ + template < \ + BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ + > \ + BOOST_DEDUCED_TYPENAME unordered_multimap::iterator \ + unordered_multimap::emplace_hint( \ + const_iterator, \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \ + { \ + return iterator(table_.emplace( \ + BOOST_UNORDERED_CALL_PARAMS(z, n))); \ + } + + BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, + BOOST_UNORDERED_EMPLACE, _) + +#undef BOOST_UNORDERED_EMPLACE + +#endif + + template + BOOST_DEDUCED_TYPENAME unordered_multimap::iterator + unordered_multimap::insert(const value_type& obj) + { + return iterator(table_.emplace(obj)); + } + + template + BOOST_DEDUCED_TYPENAME unordered_multimap::iterator + unordered_multimap::insert( + const_iterator, const value_type& obj) + { + return iterator(table_.emplace(obj)); + } + + template + template + void unordered_multimap::insert(InputIt first, InputIt last) + { + table_.insert_range(first, last); + } + +#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) + template + void unordered_multimap::insert( + std::initializer_list list) + { + table_.insert_range(list.begin(), list.end()); + } +#endif + + template + BOOST_DEDUCED_TYPENAME unordered_multimap::iterator + unordered_multimap::erase(const_iterator position) + { + return iterator(table_.erase(get(position))); + } + + template + BOOST_DEDUCED_TYPENAME unordered_multimap::size_type + unordered_multimap::erase(const key_type& k) + { + return table_.erase_key(k); + } + + template + BOOST_DEDUCED_TYPENAME unordered_multimap::iterator + unordered_multimap::erase( + const_iterator first, const_iterator last) + { + return iterator(table_.erase_range(get(first), get(last))); + } + + template + void unordered_multimap::clear() + { + table_.clear(); + } + + template + void unordered_multimap::swap(unordered_multimap& other) + { + table_.swap(other.table_); + } + + // observers + + template + BOOST_DEDUCED_TYPENAME unordered_multimap::hasher + unordered_multimap::hash_function() const + { + return table_.hash_function(); + } + + template + BOOST_DEDUCED_TYPENAME unordered_multimap::key_equal + unordered_multimap::key_eq() const + { + return table_.key_eq(); + } + + // lookup + + template + BOOST_DEDUCED_TYPENAME unordered_multimap::iterator + unordered_multimap::find(const key_type& k) + { + return iterator(table_.find_node(k)); + } + + template + BOOST_DEDUCED_TYPENAME unordered_multimap::const_iterator + unordered_multimap::find(const key_type& k) const + { + return const_iterator(table_.find_node(k)); + } + + template + template + BOOST_DEDUCED_TYPENAME unordered_multimap::iterator + unordered_multimap::find( + CompatibleKey const& k, + CompatibleHash const& hash, + CompatiblePredicate const& eq) + { + return iterator(table_.generic_find_node(k, hash, eq)); + } + + template + template + BOOST_DEDUCED_TYPENAME unordered_multimap::const_iterator + unordered_multimap::find( + CompatibleKey const& k, + CompatibleHash const& hash, + CompatiblePredicate const& eq) const + { + return const_iterator(table_.generic_find_node(k, hash, eq)); + } + + template + BOOST_DEDUCED_TYPENAME unordered_multimap::size_type + unordered_multimap::count(const key_type& k) const + { + return table_.count(k); + } + + template + std::pair< + BOOST_DEDUCED_TYPENAME unordered_multimap::iterator, + BOOST_DEDUCED_TYPENAME unordered_multimap::iterator> + unordered_multimap::equal_range(const key_type& k) + { + return BOOST_UNORDERED_PAIR_CAST(iterator, iterator, + table_.equal_range(k)); + } + + template + std::pair< + BOOST_DEDUCED_TYPENAME unordered_multimap::const_iterator, + BOOST_DEDUCED_TYPENAME unordered_multimap::const_iterator> + unordered_multimap::equal_range(const key_type& k) const + { + return BOOST_UNORDERED_PAIR_CAST(const_iterator, const_iterator, + table_.equal_range(k)); + } + + template + BOOST_DEDUCED_TYPENAME unordered_multimap::size_type + unordered_multimap::bucket_size(size_type n) const + { + return table_.bucket_size(n); + } + + // hash policy + + template + float unordered_multimap::load_factor() const + { + return table_.load_factor(); + } + + template + void unordered_multimap::max_load_factor(float m) + { + table_.max_load_factor(m); + } + + template + void unordered_multimap::rehash(size_type n) + { + table_.rehash(n); + } + + template + inline bool operator==( + unordered_multimap const& m1, + unordered_multimap const& m2) { #if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613)) struct dummy { unordered_multimap x; }; @@ -1112,8 +1563,9 @@ namespace boost } template - inline bool operator!=(unordered_multimap const& m1, - unordered_multimap const& m2) + inline bool operator!=( + unordered_multimap const& m1, + unordered_multimap const& m2) { #if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613)) struct dummy { unordered_multimap x; }; @@ -1122,8 +1574,9 @@ namespace boost } template - inline void swap(unordered_multimap &m1, - unordered_multimap &m2) + inline void swap( + unordered_multimap &m1, + unordered_multimap &m2) { #if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613)) struct dummy { unordered_multimap x; }; @@ -1131,6 +1584,7 @@ namespace boost m1.swap(m2); } + } // namespace boost #if defined(BOOST_MSVC) diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index 89d1c1cf..fae9a000 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -54,15 +54,15 @@ namespace boost #endif typedef BOOST_DEDUCED_TYPENAME - boost::unordered_detail::rebind_wrap< + ::boost::unordered::detail::rebind_wrap< allocator_type, value_type>::type value_allocator; - typedef boost::unordered_detail::set types; typedef BOOST_DEDUCED_TYPENAME types::impl table; - typedef BOOST_DEDUCED_TYPENAME types::iterator_base iterator_base; + typedef BOOST_DEDUCED_TYPENAME types::node_ptr node_ptr; public: @@ -78,12 +78,10 @@ namespace boost typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; - typedef boost::unordered_detail::hash_const_local_iterator< - value_allocator, boost::unordered_detail::ungrouped> - const_local_iterator; - typedef boost::unordered_detail::hash_const_iterator< - value_allocator, boost::unordered_detail::ungrouped> - const_iterator; + typedef ::boost::unordered::iterator_detail::cl_iterator< + value_allocator, true> const_local_iterator; + typedef ::boost::unordered::iterator_detail::c_iterator< + value_allocator, true> const_iterator; typedef const_local_iterator local_iterator; typedef const_iterator iterator; @@ -93,10 +91,10 @@ namespace boost table table_; - BOOST_DEDUCED_TYPENAME types::iterator_base const& + BOOST_DEDUCED_TYPENAME types::node_ptr const& get(const_iterator const& it) { - return boost::unordered_detail::iterator_access::get(it); + return ::boost::unordered::detail::iterator_access::get(it); } public: @@ -104,118 +102,59 @@ namespace boost // construct/destroy/copy explicit unordered_set( - size_type n = boost::unordered_detail::default_bucket_count, - const hasher &hf = hasher(), - const key_equal &eql = key_equal(), - const allocator_type &a = allocator_type()) - : table_(n, hf, eql, a) - { - } + size_type = ::boost::unordered::detail::default_bucket_count, + const hasher& = hasher(), + const key_equal& = key_equal(), + const allocator_type& = allocator_type()); - explicit unordered_set(allocator_type const& a) - : table_(boost::unordered_detail::default_bucket_count, - hasher(), key_equal(), a) - { - } + explicit unordered_set(allocator_type const&); - unordered_set(unordered_set const& other, allocator_type const& a) - : table_(other.table_, a) - { - } + unordered_set(unordered_set const&, allocator_type const&); template - unordered_set(InputIt f, InputIt l) - : table_(boost::unordered_detail::initial_size(f, l), - hasher(), key_equal(), allocator_type()) - { - table_.insert_range(f, l); - } + unordered_set(InputIt f, InputIt l); template - unordered_set(InputIt f, InputIt l, size_type n, - const hasher &hf = hasher(), - const key_equal &eql = key_equal()) - : table_(boost::unordered_detail::initial_size(f, l, n), - hf, eql, allocator_type()) - { - table_.insert_range(f, l); - } + unordered_set( + InputIt, InputIt, + size_type, + const hasher& = hasher(), + const key_equal& = key_equal()); + + template + unordered_set( + InputIt, InputIt, + size_type, + const hasher&, + const key_equal&, + const allocator_type&); - template - unordered_set(InputIt f, InputIt l, size_type n, - const hasher &hf, - const key_equal &eql, - const allocator_type &a) - : table_(boost::unordered_detail::initial_size(f, l, n), hf, eql, a) - { - table_.insert_range(f, l); - } - - ~unordered_set() {} + ~unordered_set(); #if !defined(BOOST_NO_RVALUE_REFERENCES) - unordered_set(unordered_set const& other) - : table_(other.table_) - { - } - - unordered_set(unordered_set&& other) - : table_(other.table_, boost::unordered_detail::move_tag()) - { - } - - unordered_set(unordered_set&& other, allocator_type const& a) - : table_(other.table_, a, boost::unordered_detail::move_tag()) - { - } - - unordered_set& operator=(unordered_set const& x) - { - table_ = x.table_; - return *this; - } - - unordered_set& operator=(unordered_set&& x) - { - table_.move(x.table_); - return *this; - } + unordered_set(unordered_set const&); + unordered_set(unordered_set&&); + unordered_set(unordered_set&&, allocator_type const&); + unordered_set& operator=(unordered_set const&); + unordered_set& operator=(unordered_set&&); #else - unordered_set(boost::unordered_detail::move_from< - unordered_set - > other) - : table_(other.source.table_, boost::unordered_detail::move_tag()) - { - } - + unordered_set(::boost::unordered::detail::move_from< + unordered_set + >); #if !BOOST_WORKAROUND(__BORLANDC__, < 0x0593) - unordered_set& operator=(unordered_set x) - { - table_.move(x.table_); - return *this; - } + unordered_set& operator=(unordered_set); #endif #endif #if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) - unordered_set(std::initializer_list list, - size_type n = boost::unordered_detail::default_bucket_count, - const hasher &hf = hasher(), - const key_equal &eql = key_equal(), - const allocator_type &a = allocator_type()) - : table_(boost::unordered_detail::initial_size( - list.begin(), list.end(), n), - hf, eql, a) - { - table_.insert_range(list.begin(), list.end()); - } + unordered_set( + std::initializer_list, + size_type = ::boost::unordered::detail::default_bucket_count, + const hasher& = hasher(), + const key_equal&l = key_equal(), + const allocator_type& = allocator_type()); - unordered_set& operator=(std::initializer_list list) - { - table_.clear(); - table_.insert_range(list.begin(), list.end()); - return *this; - } + unordered_set& operator=(std::initializer_list); #endif allocator_type get_allocator() const @@ -235,10 +174,7 @@ namespace boost return table_.size_; } - size_type max_size() const - { - return table_.max_size(); - } + size_type max_size() const; // iterators @@ -254,12 +190,12 @@ namespace boost iterator end() { - return iterator(table_.end()); + return iterator(); } const_iterator end() const { - return const_iterator(table_.end()); + return const_iterator(); } const_iterator cbegin() const @@ -269,37 +205,20 @@ namespace boost const_iterator cend() const { - return const_iterator(table_.end()); + return const_iterator(); } // modifiers #if defined(BOOST_UNORDERED_STD_FORWARD) template - std::pair emplace(Args&&... args) - { - return boost::unordered_detail::pair_cast( - table_.emplace(std::forward(args)...)); - } - + std::pair emplace(Args&&...); template - iterator emplace_hint(const_iterator, Args&&... args) - { - return iterator(table_.emplace(std::forward(args)...).first); - } + iterator emplace_hint(const_iterator, Args&&...); #else - std::pair emplace(value_type const& v = value_type()) - { - return boost::unordered_detail::pair_cast( - table_.emplace(v)); - } - - iterator emplace_hint(const_iterator, - value_type const& v = value_type()) - { - return iterator(table_.emplace(v).first); - } + std::pair emplace(value_type const& = value_type()); + iterator emplace_hint(const_iterator, value_type const& = value_type()); #define BOOST_UNORDERED_EMPLACE(z, n, _) \ template < \ @@ -307,24 +226,14 @@ namespace boost > \ std::pair emplace( \ BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ - ) \ - { \ - return boost::unordered_detail::pair_cast( \ - table_.emplace( \ - BOOST_UNORDERED_CALL_PARAMS(z, n) \ - )); \ - } \ + ); \ \ template < \ BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ > \ iterator emplace_hint(const_iterator, \ BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ - ) \ - { \ - return iterator(table_.emplace( \ - BOOST_UNORDERED_CALL_PARAMS(z, n)).first); \ - } + ); BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, BOOST_UNORDERED_EMPLACE, _) @@ -333,105 +242,42 @@ namespace boost #endif - std::pair insert(const value_type& obj) - { - return boost::unordered_detail::pair_cast( - table_.emplace(obj)); - } - - iterator insert(const_iterator, const value_type& obj) - { - return iterator(table_.emplace(obj).first); - } - - template - void insert(InputIt first, InputIt last) - { - table_.insert_range(first, last); - } + std::pair insert(const value_type&); + iterator insert(const_iterator, const value_type&); + template void insert(InputIt, InputIt); #if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) - void insert(std::initializer_list list) - { - table_.insert_range(list.begin(), list.end()); - } + void insert(std::initializer_list); #endif - iterator erase(const_iterator position) - { - return iterator(table_.erase_return_iterator(get(position))); - } + iterator erase(const_iterator); + size_type erase(const key_type&); + iterator erase(const_iterator, const_iterator); + void quick_erase(const_iterator it) { erase(it); } + void erase_return_void(const_iterator it) { erase(it); } - size_type erase(const key_type& k) - { - return table_.erase_key(k); - } - - iterator erase(const_iterator first, const_iterator last) - { - return iterator(table_.erase_range(get(first), get(last))); - } - - void quick_erase(const_iterator position) - { - table_.erase(get(position)); - } - - void erase_return_void(const_iterator position) - { - table_.erase(get(position)); - } - - void clear() - { - table_.clear(); - } - - void swap(unordered_set& other) - { - table_.swap(other.table_); - } + void clear(); + void swap(unordered_set&); // observers - hasher hash_function() const - { - return table_.hash_function(); - } - - key_equal key_eq() const - { - return table_.key_eq(); - } + hasher hash_function() const; + key_equal key_eq() const; // lookup - const_iterator find(const key_type& k) const - { - return const_iterator(table_.find(k)); - } + const_iterator find(const key_type&) const; template const_iterator find( - CompatibleKey const& k, - CompatibleHash const& hash, - CompatiblePredicate const& eq) const - { - return iterator(table_.find(k, hash, eq)); - } - size_type count(const key_type& k) const - { - return table_.count(k); - } + CompatibleKey const&, + CompatibleHash const&, + CompatiblePredicate const&) const; + size_type count(const key_type&) const; std::pair - equal_range(const key_type& k) const - { - return boost::unordered_detail::pair_cast< - const_iterator, const_iterator>( - table_.equal_range(k)); - } + equal_range(const key_type&) const; // bucket interface @@ -445,24 +291,23 @@ namespace boost return table_.max_bucket_count(); } - size_type bucket_size(size_type n) const - { - return table_.bucket_size(n); - } + size_type bucket_size(size_type n) const; size_type bucket(const key_type& k) const { - return table_.bucket_index(k); + return table_.hash_function()(k) % table_.bucket_count_; } local_iterator begin(size_type n) { - return local_iterator(table_.bucket_begin(n)); + return local_iterator( + table_.bucket_begin(n), n, table_.bucket_count_); } const_local_iterator begin(size_type n) const { - return const_local_iterator(table_.bucket_begin(n)); + return const_local_iterator( + table_.bucket_begin(n), n, table_.bucket_count_); } local_iterator end(size_type) @@ -477,7 +322,8 @@ namespace boost const_local_iterator cbegin(size_type n) const { - return const_local_iterator(table_.bucket_begin(n)); + return const_local_iterator( + table_.bucket_begin(n), n, table_.bucket_count_); } const_local_iterator cend(size_type) const @@ -487,64 +333,23 @@ namespace boost // hash policy - float load_factor() const - { - return table_.load_factor(); - } - float max_load_factor() const { return table_.mlf_; } - void max_load_factor(float m) - { - table_.max_load_factor(m); - } - - void rehash(size_type n) - { - table_.rehash(n); - } + float load_factor() const; + void max_load_factor(float); + void rehash(size_type n); #if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) - friend bool operator==( - unordered_set const&, unordered_set const&); - friend bool operator!=( - unordered_set const&, unordered_set const&); + friend bool operator==( + unordered_set const&, unordered_set const&); + friend bool operator!=( + unordered_set const&, unordered_set const&); #endif }; // class template unordered_set - template - inline bool operator==(unordered_set const& m1, - unordered_set const& m2) - { -#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613)) - struct dummy { unordered_set x; }; -#endif - return m1.table_.equals(m2.table_); - } - - template - inline bool operator!=(unordered_set const& m1, - unordered_set const& m2) - { -#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613)) - struct dummy { unordered_set x; }; -#endif - return !m1.table_.equals(m2.table_); - } - - template - inline void swap(unordered_set &m1, - unordered_set &m2) - { -#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613)) - struct dummy { unordered_set x; }; -#endif - m1.swap(m2); - } - template class unordered_multiset { @@ -561,15 +366,15 @@ namespace boost #endif typedef BOOST_DEDUCED_TYPENAME - boost::unordered_detail::rebind_wrap< + ::boost::unordered::detail::rebind_wrap< allocator_type, value_type>::type value_allocator; - typedef boost::unordered_detail::multiset types; typedef BOOST_DEDUCED_TYPENAME types::impl table; - typedef BOOST_DEDUCED_TYPENAME types::iterator_base iterator_base; + typedef BOOST_DEDUCED_TYPENAME types::node_ptr node_ptr; public: @@ -585,12 +390,10 @@ namespace boost typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; - typedef boost::unordered_detail::hash_const_local_iterator< - value_allocator, boost::unordered_detail::grouped> - const_local_iterator; - typedef boost::unordered_detail::hash_const_iterator< - value_allocator, boost::unordered_detail::grouped> - const_iterator; + typedef ::boost::unordered::iterator_detail::cl_iterator< + value_allocator, false> const_local_iterator; + typedef ::boost::unordered::iterator_detail::c_iterator< + value_allocator, false> const_iterator; typedef const_local_iterator local_iterator; typedef const_iterator iterator; @@ -600,10 +403,10 @@ namespace boost table table_; - BOOST_DEDUCED_TYPENAME types::iterator_base const& + BOOST_DEDUCED_TYPENAME types::node_ptr const& get(const_iterator const& it) { - return boost::unordered_detail::iterator_access::get(it); + return ::boost::unordered::detail::iterator_access::get(it); } public: @@ -611,119 +414,60 @@ namespace boost // construct/destroy/copy explicit unordered_multiset( - size_type n = boost::unordered_detail::default_bucket_count, - const hasher &hf = hasher(), - const key_equal &eql = key_equal(), - const allocator_type &a = allocator_type()) - : table_(n, hf, eql, a) - { - } + size_type = ::boost::unordered::detail::default_bucket_count, + const hasher& = hasher(), + const key_equal& = key_equal(), + const allocator_type& = allocator_type()); - explicit unordered_multiset(allocator_type const& a) - : table_(boost::unordered_detail::default_bucket_count, - hasher(), key_equal(), a) - { - } + explicit unordered_multiset(allocator_type const&); - unordered_multiset(unordered_multiset const& other, - allocator_type const& a) - : table_(other.table_, a) - { - } + unordered_multiset(unordered_multiset const&, allocator_type const&); template - unordered_multiset(InputIt f, InputIt l) - : table_(boost::unordered_detail::initial_size(f, l), - hasher(), key_equal(), allocator_type()) - { - table_.insert_range(f, l); - } + unordered_multiset(InputIt, InputIt); template - unordered_multiset(InputIt f, InputIt l, size_type n, - const hasher &hf = hasher(), - const key_equal &eql = key_equal()) - : table_(boost::unordered_detail::initial_size(f, l, n), - hf, eql, allocator_type()) - { - table_.insert_range(f, l); - } + unordered_multiset( + InputIt, InputIt, + size_type, + const hasher& = hasher(), + const key_equal& = key_equal()); template - unordered_multiset(InputIt f, InputIt l, size_type n, - const hasher &hf, - const key_equal &eql, - const allocator_type &a) - : table_(boost::unordered_detail::initial_size(f, l, n), hf, eql, a) - { - table_.insert_range(f, l); - } + unordered_multiset( + InputIt, InputIt, + size_type, + const hasher&, + const key_equal&, + const allocator_type&); - ~unordered_multiset() {} + ~unordered_multiset(); #if !defined(BOOST_NO_RVALUE_REFERENCES) - unordered_multiset(unordered_multiset const& other) - : table_(other.table_) - { - } - - unordered_multiset(unordered_multiset&& other) - : table_(other.table_, boost::unordered_detail::move_tag()) - { - } - - unordered_multiset(unordered_multiset&& other, allocator_type const& a) - : table_(other.table_, a, boost::unordered_detail::move_tag()) - { - } - - unordered_multiset& operator=(unordered_multiset const& x) - { - table_ = x.table_; - return *this; - } - - unordered_multiset& operator=(unordered_multiset&& x) - { - table_.move(x.table_); - return *this; - } + unordered_multiset(unordered_multiset const&); + unordered_multiset(unordered_multiset&&); + unordered_multiset(unordered_multiset&&, allocator_type const&); + unordered_multiset& operator=(unordered_multiset const&); + unordered_multiset& operator=(unordered_multiset&&); #else - unordered_multiset(boost::unordered_detail::move_from< - unordered_multiset - > other) - : table_(other.source.table_, boost::unordered_detail::move_tag()) - { - } + unordered_multiset(::boost::unordered::detail::move_from< + unordered_multiset + >); #if !BOOST_WORKAROUND(__BORLANDC__, < 0x0593) - unordered_multiset& operator=(unordered_multiset x) - { - table_.move(x.table_); - return *this; - } + unordered_multiset& operator=(unordered_multiset); #endif #endif #if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) - unordered_multiset(std::initializer_list list, - size_type n = boost::unordered_detail::default_bucket_count, - const hasher &hf = hasher(), - const key_equal &eql = key_equal(), - const allocator_type &a = allocator_type()) - : table_(boost::unordered_detail::initial_size( - list.begin(), list.end(), n), - hf, eql, a) - { - table_.insert_range(list.begin(), list.end()); - } + unordered_multiset( + std::initializer_list, + size_type = ::boost::unordered::detail::default_bucket_count, + const hasher& = hasher(), + const key_equal&l = key_equal(), + const allocator_type& = allocator_type()); - unordered_multiset& operator=(std::initializer_list list) - { - table_.clear(); - table_.insert_range(list.begin(), list.end()); - return *this; - } + unordered_multiset& operator=(std::initializer_list); #endif allocator_type get_allocator() const @@ -743,10 +487,7 @@ namespace boost return table_.size_; } - size_type max_size() const - { - return table_.max_size(); - } + size_type max_size() const; // iterators @@ -762,12 +503,12 @@ namespace boost iterator end() { - return iterator(table_.end()); + return iterator(); } const_iterator end() const { - return const_iterator(table_.end()); + return const_iterator(); } const_iterator cbegin() const @@ -777,35 +518,20 @@ namespace boost const_iterator cend() const { - return const_iterator(table_.end()); + return const_iterator(); } // modifiers #if defined(BOOST_UNORDERED_STD_FORWARD) template - iterator emplace(Args&&... args) - { - return iterator(table_.emplace(std::forward(args)...)); - } - + iterator emplace(Args&&...); template - iterator emplace_hint(const_iterator, Args&&... args) - { - return iterator(table_.emplace(std::forward(args)...)); - } + iterator emplace_hint(const_iterator, Args&&...); #else - iterator emplace(value_type const& v = value_type()) - { - return iterator(table_.emplace(v)); - } - - iterator emplace_hint(const_iterator, - value_type const& v = value_type()) - { - return iterator(table_.emplace(v)); - } + iterator emplace(value_type const& = value_type()); + iterator emplace_hint(const_iterator, value_type const& = value_type()); #define BOOST_UNORDERED_EMPLACE(z, n, _) \ template < \ @@ -813,23 +539,14 @@ namespace boost > \ iterator emplace( \ BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ - ) \ - { \ - return iterator( \ - table_.emplace(BOOST_UNORDERED_CALL_PARAMS(z, n))); \ - } \ + ); \ \ template < \ BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ > \ iterator emplace_hint(const_iterator, \ BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ - ) \ - { \ - return iterator(table_.emplace( \ - BOOST_UNORDERED_CALL_PARAMS(z, n) \ - )); \ - } + ); BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, BOOST_UNORDERED_EMPLACE, _) @@ -838,105 +555,43 @@ namespace boost #endif - iterator insert(const value_type& obj) - { - return iterator(table_.emplace(obj)); - } - - iterator insert(const_iterator, const value_type& obj) - { - return iterator(table_.emplace(obj)); - } - + iterator insert(const value_type&); + iterator insert(const_iterator, const value_type&); template - void insert(InputIt first, InputIt last) - { - table_.insert_range(first, last); - } + void insert(InputIt, InputIt); #if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) - void insert(std::initializer_list list) - { - table_.insert_range(list.begin(), list.end()); - } + void insert(std::initializer_list); #endif - iterator erase(const_iterator position) - { - return iterator(table_.erase_return_iterator(get(position))); - } + iterator erase(const_iterator); + size_type erase(const key_type&); + iterator erase(const_iterator, const_iterator); + void quick_erase(const_iterator position) { erase(position); } + void erase_return_void(const_iterator position) { erase(position); } - size_type erase(const key_type& k) - { - return table_.erase_key(k); - } - - iterator erase(const_iterator first, const_iterator last) - { - return iterator(table_.erase_range(get(first), get(last))); - } - - void quick_erase(const_iterator position) - { - table_.erase(get(position)); - } - - void erase_return_void(const_iterator position) - { - table_.erase(get(position)); - } - - void clear() - { - table_.clear(); - } - - void swap(unordered_multiset& other) - { - table_.swap(other.table_); - } + void clear(); + void swap(unordered_multiset&); // observers - hasher hash_function() const - { - return table_.hash_function(); - } - - key_equal key_eq() const - { - return table_.key_eq(); - } + hasher hash_function() const; + key_equal key_eq() const; // lookup - const_iterator find(const key_type& k) const - { - return const_iterator(table_.find(k)); - } + const_iterator find(const key_type&) const; template const_iterator find( - CompatibleKey const& k, - CompatibleHash const& hash, - CompatiblePredicate const& eq) const - { - return iterator(table_.find(k, hash, eq)); - } - - size_type count(const key_type& k) const - { - return table_.count(k); - } + CompatibleKey const&, + CompatibleHash const&, + CompatiblePredicate const&) const; + size_type count(const key_type&) const; std::pair - equal_range(const key_type& k) const - { - return boost::unordered_detail::pair_cast< - const_iterator, const_iterator>( - table_.equal_range(k)); - } + equal_range(const key_type&) const; // bucket interface @@ -950,24 +605,23 @@ namespace boost return table_.max_bucket_count(); } - size_type bucket_size(size_type n) const - { - return table_.bucket_size(n); - } + size_type bucket_size(size_type) const; size_type bucket(const key_type& k) const { - return table_.bucket_index(k); + return table_.hash_function()(k) % table_.bucket_count_; } local_iterator begin(size_type n) { - return local_iterator(table_.bucket_begin(n)); + return local_iterator( + table_.bucket_begin(n), n, table_.bucket_count_); } const_local_iterator begin(size_type n) const { - return const_local_iterator(table_.bucket_begin(n)); + return const_local_iterator( + table_.bucket_begin(n), n, table_.bucket_count_); } local_iterator end(size_type) @@ -982,7 +636,8 @@ namespace boost const_local_iterator cbegin(size_type n) const { - return const_local_iterator(table_.bucket_begin(n)); + return const_local_iterator( + table_.bucket_begin(n), n, table_.bucket_count_); } const_local_iterator cend(size_type) const @@ -992,37 +647,791 @@ namespace boost // hash policy - float load_factor() const - { - return table_.load_factor(); - } - float max_load_factor() const { return table_.mlf_; } - void max_load_factor(float m) - { - table_.max_load_factor(m); - } - - void rehash(size_type n) - { - table_.rehash(n); - } + float load_factor() const; + void max_load_factor(float); + void rehash(size_type); #if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) - friend bool operator==( - unordered_multiset const&, unordered_multiset const&); - friend bool operator!=( - unordered_multiset const&, unordered_multiset const&); + friend bool operator==( + unordered_multiset const&, unordered_multiset const&); + friend bool operator!=( + unordered_multiset const&, unordered_multiset const&); #endif }; // class template unordered_multiset +//////////////////////////////////////////////////////////////////////////////// + template - inline bool operator==(unordered_multiset const& m1, - unordered_multiset const& m2) + unordered_set::unordered_set( + size_type n, const hasher &hf, const key_equal &eql, + const allocator_type &a) + : table_(n, hf, eql, a) + { + } + + template + unordered_set::unordered_set(allocator_type const& a) + : table_(::boost::unordered::detail::default_bucket_count, + hasher(), key_equal(), a) + { + } + + template + unordered_set::unordered_set( + unordered_set const& other, allocator_type const& a) + : table_(other.table_, a) + { + } + + template + template + unordered_set::unordered_set(InputIt f, InputIt l) + : table_(::boost::unordered::detail::initial_size(f, l), + hasher(), key_equal(), allocator_type()) + { + table_.insert_range(f, l); + } + + template + template + unordered_set::unordered_set( + InputIt f, InputIt l, + size_type n, + const hasher &hf, + const key_equal &eql) + : table_(::boost::unordered::detail::initial_size(f, l, n), + hf, eql, allocator_type()) + { + table_.insert_range(f, l); + } + + template + template + unordered_set::unordered_set( + InputIt f, InputIt l, + size_type n, + const hasher &hf, + const key_equal &eql, + const allocator_type &a) + : table_(::boost::unordered::detail::initial_size(f, l, n), hf, eql, a) + { + table_.insert_range(f, l); + } + + template + unordered_set::~unordered_set() {} + +#if !defined(BOOST_NO_RVALUE_REFERENCES) + template + unordered_set::unordered_set(unordered_set const& other) + : table_(other.table_) + { + } + + template + unordered_set::unordered_set(unordered_set&& other) + : table_(other.table_, ::boost::unordered::detail::move_tag()) + { + } + + template + unordered_set::unordered_set( + unordered_set&& other, allocator_type const& a) + : table_(other.table_, a, ::boost::unordered::detail::move_tag()) + { + } + + template + unordered_set& unordered_set:: + operator=(unordered_set const& x) + { + table_ = x.table_; + return *this; + } + + template + unordered_set& unordered_set:: + operator=(unordered_set&& x) + { + table_.move(x.table_); + return *this; + } +#else + template + unordered_set::unordered_set( + ::boost::unordered::detail::move_from > + other) + : table_(other.source.table_, ::boost::unordered::detail::move_tag()) + { + } + +#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0593) + template + unordered_set& unordered_set:: + operator=(unordered_set x) + { + table_.move(x.table_); + return *this; + } +#endif +#endif + +#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) + template + unordered_set::unordered_set( + std::initializer_list list, size_type n, + const hasher &hf, const key_equal &eql, const allocator_type &a) + : table_( + ::boost::unordered::detail::initial_size( + list.begin(), list.end(), n), + hf, eql, a) + { + table_.insert_range(list.begin(), list.end()); + } + + template + unordered_set& unordered_set::operator=( + std::initializer_list list) + { + table_.clear(); + table_.insert_range(list.begin(), list.end()); + return *this; + } +#endif + + // size and capacity + + template + std::size_t unordered_set::max_size() const + { + return table_.max_size(); + } + + // modifiers + +#if defined(BOOST_UNORDERED_STD_FORWARD) + template + template + std::pair::iterator, bool> + unordered_set::emplace(Args&&... args) + { + return BOOST_UNORDERED_PAIR_CAST(iterator, bool, + table_.emplace(std::forward(args)...)); + } + + template + template + BOOST_DEDUCED_TYPENAME unordered_set::iterator + unordered_set::emplace_hint(const_iterator, Args&&... args) + { + return iterator(table_.emplace(std::forward(args)...).first); + } +#else + + template + std::pair::iterator, bool> + unordered_set::emplace(value_type const& v) + { + return BOOST_UNORDERED_PAIR_CAST(iterator, bool, table_.emplace(v)); + } + + template + BOOST_DEDUCED_TYPENAME unordered_set::iterator + unordered_set::emplace_hint( + const_iterator, value_type const& v) + { + return iterator(table_.emplace(v).first); + } + +#define BOOST_UNORDERED_EMPLACE(z, n, _) \ + template \ + template < \ + BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ + > \ + std::pair< \ + BOOST_DEDUCED_TYPENAME unordered_set::iterator, \ + bool> \ + unordered_set::emplace( \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \ + { \ + return \ + BOOST_UNORDERED_PAIR_CAST(iterator, bool, \ + table_.emplace( \ + BOOST_UNORDERED_CALL_PARAMS(z, n))); \ + } \ + \ + template \ + template < \ + BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ + > \ + BOOST_DEDUCED_TYPENAME unordered_set::iterator \ + unordered_set::emplace_hint( \ + const_iterator, \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ + ) \ + { \ + return iterator(table_.emplace( \ + BOOST_UNORDERED_CALL_PARAMS(z, n)).first); \ + } + + BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, + BOOST_UNORDERED_EMPLACE, _) + +#undef BOOST_UNORDERED_EMPLACE + +#endif + + template + std::pair::iterator, bool> + unordered_set::insert(const value_type& obj) + { + return BOOST_UNORDERED_PAIR_CAST(iterator, bool, table_.insert(obj)); + } + + template + BOOST_DEDUCED_TYPENAME unordered_set::iterator + unordered_set::insert(const_iterator, const value_type& obj) + { + return iterator(table_.emplace(obj).first); + } + + template + template + void unordered_set::insert(InputIt first, InputIt last) + { + table_.insert_range(first, last); + } + +#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) + template + void unordered_set::insert(std::initializer_list list) + { + table_.insert_range(list.begin(), list.end()); + } +#endif + + template + BOOST_DEDUCED_TYPENAME unordered_set::iterator + unordered_set::erase(const_iterator position) + { + return iterator(table_.erase(get(position))); + } + + template + BOOST_DEDUCED_TYPENAME unordered_set::size_type + unordered_set::erase(const key_type& k) + { + return table_.erase_key(k); + } + + template + BOOST_DEDUCED_TYPENAME unordered_set::iterator + unordered_set::erase(const_iterator first, const_iterator last) + { + return iterator(table_.erase_range(get(first), get(last))); + } + + template + void unordered_set::clear() + { + table_.clear(); + } + + template + void unordered_set::swap(unordered_set& other) + { + table_.swap(other.table_); + } + + // observers + + template + BOOST_DEDUCED_TYPENAME unordered_set::hasher + unordered_set::hash_function() const + { + return table_.hash_function(); + } + + template + BOOST_DEDUCED_TYPENAME unordered_set::key_equal + unordered_set::key_eq() const + { + return table_.key_eq(); + } + + // lookup + + template + BOOST_DEDUCED_TYPENAME unordered_set::const_iterator + unordered_set::find(const key_type& k) const + { + return const_iterator(table_.find_node(k)); + } + + template + template + BOOST_DEDUCED_TYPENAME unordered_set::const_iterator + unordered_set::find( + CompatibleKey const& k, + CompatibleHash const& hash, + CompatiblePredicate const& eq) const + { + return const_iterator(table_.generic_find_node(k, hash, eq)); + } + + template + BOOST_DEDUCED_TYPENAME unordered_set::size_type + unordered_set::count(const key_type& k) const + { + return table_.count(k); + } + + template + std::pair< + BOOST_DEDUCED_TYPENAME unordered_set::const_iterator, + BOOST_DEDUCED_TYPENAME unordered_set::const_iterator> + unordered_set::equal_range(const key_type& k) const + { + return BOOST_UNORDERED_PAIR_CAST(const_iterator, const_iterator, + table_.equal_range(k)); + } + + template + BOOST_DEDUCED_TYPENAME unordered_set::size_type + unordered_set::bucket_size(size_type n) const + { + return table_.bucket_size(n); + } + + // hash policy + + template + float unordered_set::load_factor() const + { + return table_.load_factor(); + } + + template + void unordered_set::max_load_factor(float m) + { + table_.max_load_factor(m); + } + + template + void unordered_set::rehash(size_type n) + { + table_.rehash(n); + } + + template + inline bool operator==( + unordered_set const& m1, + unordered_set const& m2) + { +#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613)) + struct dummy { unordered_set x; }; +#endif + return m1.table_.equals(m2.table_); + } + + template + inline bool operator!=( + unordered_set const& m1, + unordered_set const& m2) + { +#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613)) + struct dummy { unordered_set x; }; +#endif + return !m1.table_.equals(m2.table_); + } + + template + inline void swap( + unordered_set &m1, + unordered_set &m2) + { +#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613)) + struct dummy { unordered_set x; }; +#endif + m1.swap(m2); + } + +//////////////////////////////////////////////////////////////////////////////// + + template + unordered_multiset::unordered_multiset( + size_type n, const hasher &hf, const key_equal &eql, + const allocator_type &a) + : table_(n, hf, eql, a) + { + } + + template + unordered_multiset::unordered_multiset(allocator_type const& a) + : table_(::boost::unordered::detail::default_bucket_count, + hasher(), key_equal(), a) + { + } + + template + unordered_multiset::unordered_multiset( + unordered_multiset const& other, allocator_type const& a) + : table_(other.table_, a) + { + } + + template + template + unordered_multiset::unordered_multiset(InputIt f, InputIt l) + : table_(::boost::unordered::detail::initial_size(f, l), + hasher(), key_equal(), allocator_type()) + { + table_.insert_range(f, l); + } + + template + template + unordered_multiset::unordered_multiset( + InputIt f, InputIt l, + size_type n, + const hasher &hf, + const key_equal &eql) + : table_(::boost::unordered::detail::initial_size(f, l, n), + hf, eql, allocator_type()) + { + table_.insert_range(f, l); + } + + template + template + unordered_multiset::unordered_multiset( + InputIt f, InputIt l, + size_type n, + const hasher &hf, + const key_equal &eql, + const allocator_type &a) + : table_(::boost::unordered::detail::initial_size(f, l, n), hf, eql, a) + { + table_.insert_range(f, l); + } + + template + unordered_multiset::~unordered_multiset() {} + +#if !defined(BOOST_NO_RVALUE_REFERENCES) + template + unordered_multiset::unordered_multiset( + unordered_multiset const& other) + : table_(other.table_) + { + } + + template + unordered_multiset::unordered_multiset( + unordered_multiset&& other) + : table_(other.table_, ::boost::unordered::detail::move_tag()) + { + } + + template + unordered_multiset::unordered_multiset( + unordered_multiset&& other, allocator_type const& a) + : table_(other.table_, a, ::boost::unordered::detail::move_tag()) + { + } + + template + unordered_multiset& unordered_multiset:: + operator=(unordered_multiset const& x) + { + table_ = x.table_; + return *this; + } + + template + unordered_multiset& unordered_multiset:: + operator=(unordered_multiset&& x) + { + table_.move(x.table_); + return *this; + } + +#else + + template + unordered_multiset::unordered_multiset( + ::boost::unordered::detail::move_from > + other) + : table_(other.source.table_, ::boost::unordered::detail::move_tag()) + { + } + +#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0593) + template + unordered_multiset& unordered_multiset:: + operator=(unordered_multiset x) + { + table_.move(x.table_); + return *this; + } +#endif +#endif + +#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) + template + unordered_multiset::unordered_multiset( + std::initializer_list list, size_type n, + const hasher &hf, const key_equal &eql, const allocator_type &a) + : table_( + ::boost::unordered::detail::initial_size( + list.begin(), list.end(), n), + hf, eql, a) + { + table_.insert_range(list.begin(), list.end()); + } + + template + unordered_multiset& unordered_multiset::operator=( + std::initializer_list list) + { + table_.clear(); + table_.insert_range(list.begin(), list.end()); + return *this; + } +#endif + + // size and capacity + + template + std::size_t unordered_multiset::max_size() const + { + return table_.max_size(); + } + + // modifiers + +#if defined(BOOST_UNORDERED_STD_FORWARD) + + template + template + BOOST_DEDUCED_TYPENAME unordered_multiset::iterator + unordered_multiset::emplace(Args&&... args) + { + return iterator(table_.emplace(std::forward(args)...)); + } + + template + template + BOOST_DEDUCED_TYPENAME unordered_multiset::iterator + unordered_multiset::emplace_hint( + const_iterator, Args&&... args) + { + return iterator(table_.emplace(std::forward(args)...)); + } + +#else + + template + BOOST_DEDUCED_TYPENAME unordered_multiset::iterator + unordered_multiset::emplace(value_type const& v) + { + return iterator(table_.emplace(v)); + } + + template + BOOST_DEDUCED_TYPENAME unordered_multiset::iterator + unordered_multiset::emplace_hint( + const_iterator, value_type const& v) + { + return iterator(table_.emplace(v)); + } + +#define BOOST_UNORDERED_EMPLACE(z, n, _) \ + template \ + template < \ + BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ + > \ + BOOST_DEDUCED_TYPENAME unordered_multiset::iterator \ + unordered_multiset::emplace( \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \ + { \ + return iterator(table_.emplace( \ + BOOST_UNORDERED_CALL_PARAMS(z, n))); \ + } \ + \ + template \ + template < \ + BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ + > \ + BOOST_DEDUCED_TYPENAME unordered_multiset::iterator \ + unordered_multiset::emplace_hint( \ + const_iterator, \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \ + { \ + return iterator(table_.emplace( \ + BOOST_UNORDERED_CALL_PARAMS(z, n))); \ + } + + BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, + BOOST_UNORDERED_EMPLACE, _) + +#undef BOOST_UNORDERED_EMPLACE + +#endif + + template + BOOST_DEDUCED_TYPENAME unordered_multiset::iterator + unordered_multiset::insert(const value_type& obj) + { + return iterator(table_.emplace(obj)); + } + + template + BOOST_DEDUCED_TYPENAME unordered_multiset::iterator + unordered_multiset::insert(const_iterator, const value_type& obj) + { + return iterator(table_.emplace(obj)); + } + + template + template + void unordered_multiset::insert(InputIt first, InputIt last) + { + table_.insert_range(first, last); + } + +#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) + template + void unordered_multiset::insert(std::initializer_list list) + { + table_.insert_range(list.begin(), list.end()); + } +#endif + + template + BOOST_DEDUCED_TYPENAME unordered_multiset::iterator + unordered_multiset::erase(const_iterator position) + { + return iterator(table_.erase(get(position))); + } + + template + BOOST_DEDUCED_TYPENAME unordered_multiset::size_type + unordered_multiset::erase(const key_type& k) + { + return table_.erase_key(k); + } + + template + BOOST_DEDUCED_TYPENAME unordered_multiset::iterator + unordered_multiset::erase(const_iterator first, const_iterator last) + { + return iterator(table_.erase_range(get(first), get(last))); + } + + template + void unordered_multiset::clear() + { + table_.clear(); + } + + template + void unordered_multiset::swap(unordered_multiset& other) + { + table_.swap(other.table_); + } + + // observers + + template + BOOST_DEDUCED_TYPENAME unordered_multiset::hasher + unordered_multiset::hash_function() const + { + return table_.hash_function(); + } + + template + BOOST_DEDUCED_TYPENAME unordered_multiset::key_equal + unordered_multiset::key_eq() const + { + return table_.key_eq(); + } + + // lookup + + template + BOOST_DEDUCED_TYPENAME unordered_multiset::const_iterator + unordered_multiset::find(const key_type& k) const + { + return const_iterator(table_.find_node(k)); + } + + template + template + BOOST_DEDUCED_TYPENAME unordered_multiset::const_iterator + unordered_multiset::find( + CompatibleKey const& k, + CompatibleHash const& hash, + CompatiblePredicate const& eq) const + { + return const_iterator(table_.generic_find_node(k, hash, eq)); + } + + template + BOOST_DEDUCED_TYPENAME unordered_multiset::size_type + unordered_multiset::count(const key_type& k) const + { + return table_.count(k); + } + + template + std::pair< + BOOST_DEDUCED_TYPENAME unordered_multiset::const_iterator, + BOOST_DEDUCED_TYPENAME unordered_multiset::const_iterator> + unordered_multiset::equal_range(const key_type& k) const + { + return BOOST_UNORDERED_PAIR_CAST(const_iterator, const_iterator, + table_.equal_range(k)); + } + + template + BOOST_DEDUCED_TYPENAME unordered_multiset::size_type + unordered_multiset::bucket_size(size_type n) const + { + return table_.bucket_size(n); + } + + // hash policy + + template + float unordered_multiset::load_factor() const + { + return table_.load_factor(); + } + + template + void unordered_multiset::max_load_factor(float m) + { + table_.max_load_factor(m); + } + + template + void unordered_multiset::rehash(size_type n) + { + table_.rehash(n); + } + + template + inline bool operator==( + unordered_multiset const& m1, + unordered_multiset const& m2) { #if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613)) struct dummy { unordered_multiset x; }; @@ -1031,8 +1440,9 @@ namespace boost } template - inline bool operator!=(unordered_multiset const& m1, - unordered_multiset const& m2) + inline bool operator!=( + unordered_multiset const& m1, + unordered_multiset const& m2) { #if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613)) struct dummy { unordered_multiset x; }; @@ -1041,8 +1451,9 @@ namespace boost } template - inline void swap(unordered_multiset &m1, - unordered_multiset &m2) + inline void swap( + unordered_multiset &m1, + unordered_multiset &m2) { #if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613)) struct dummy { unordered_multiset x; }; diff --git a/test/helpers/invariants.hpp b/test/helpers/invariants.hpp index a83d76be..2acb30e2 100644 --- a/test/helpers/invariants.hpp +++ b/test/helpers/invariants.hpp @@ -65,37 +65,32 @@ namespace test std::cerr<(*lit), key); ++lit) continue; - // if(lit == lend) - // BOOST_ERROR("Unable to find element with a local_iterator"); - // unsigned int count2 = 0; - // for(; lit != lend && eq(get_key(*lit), key); ++lit) ++count2; - // if(count != count2) - // BOOST_ERROR("Element count doesn't match local_iterator."); - // for(; lit != lend; ++lit) { - // if(eq(get_key(*lit), key)) { - // BOOST_ERROR("Non-adjacent element with equivalent key " - // "in bucket."); - // break; - // } - // } + // Check that the keys are in the correct bucket and are + // adjacent in the bucket. + BOOST_DEDUCED_TYPENAME X::size_type bucket = x1.bucket(key); + BOOST_DEDUCED_TYPENAME X::const_local_iterator + lit = x1.begin(bucket), lend = x1.end(bucket); + for(; lit != lend && !eq(get_key(*lit), key); ++lit) continue; + if(lit == lend) + BOOST_ERROR("Unable to find element with a local_iterator"); + unsigned int count2 = 0; + for(; lit != lend && eq(get_key(*lit), key); ++lit) ++count2; + if(count != count2) + BOOST_ERROR("Element count doesn't match local_iterator."); + for(; lit != lend; ++lit) { + if(eq(get_key(*lit), key)) { + BOOST_ERROR("Non-adjacent element with equivalent key " + "in bucket."); + break; + } + } }; // Finally, check that size matches up. - if(x1.size() != size) + if(x1.size() != size) { BOOST_ERROR("x1.size() doesn't match actual size."); + std::cout<(size) / static_cast(x1.bucket_count()); using namespace std; diff --git a/test/helpers/memory.hpp b/test/helpers/memory.hpp index 84c1787b..1402cfe4 100644 --- a/test/helpers/memory.hpp +++ b/test/helpers/memory.hpp @@ -70,7 +70,7 @@ namespace test template > struct memory_tracker { typedef BOOST_DEDUCED_TYPENAME - boost::unordered_detail::rebind_wrap >::type allocator_type;