From 547e1411669c119f5cc5b22f7bf3f92c7b1cb19d Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 16 Apr 2011 18:47:33 +0000 Subject: [PATCH] Unordered: Overhaul the implementation. Store nodes in a single linked list, with hash values so that their buckets can be found when needed. Iterators now only have to store a pointer to the node and don't have to iterate over empty buckets to reach the next node. This allows the container to meet the iterator requirements - fixing the speed issues with `equal_range` and `erase`. Also, define iterators in their own namespace, so that they don't accidentally pull in detail functions via ADL. I've simplified the code slightly by removing some of the special cases for empty containers. Renamed a few things as well and other minor changes that were made as I went along. [SVN r71327] --- .../unordered/detail/allocator_helpers.hpp | 4 +- include/boost/unordered/detail/buckets.hpp | 786 ++++++-- include/boost/unordered/detail/equivalent.hpp | 401 ++-- .../boost/unordered/detail/extract_key.hpp | 11 +- include/boost/unordered/detail/fwd.hpp | 932 --------- include/boost/unordered/detail/move.hpp | 38 +- include/boost/unordered/detail/node.hpp | 494 +++-- include/boost/unordered/detail/table.hpp | 1411 +++++++------- include/boost/unordered/detail/unique.hpp | 748 ++++---- include/boost/unordered/detail/util.hpp | 286 +-- include/boost/unordered/unordered_map.hpp | 1662 +++++++++++------ include/boost/unordered/unordered_set.hpp | 1491 +++++++++------ test/helpers/invariants.hpp | 49 +- test/helpers/memory.hpp | 2 +- 14 files changed, 4330 insertions(+), 3985 deletions(-) delete mode 100644 include/boost/unordered/detail/fwd.hpp 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;