diff --git a/include/boost/unordered/detail/allocator_helpers.hpp b/include/boost/unordered/detail/allocator_helpers.hpp index 4aaefc69..9895fb8c 100644 --- a/include/boost/unordered/detail/allocator_helpers.hpp +++ b/include/boost/unordered/detail/allocator_helpers.hpp @@ -23,6 +23,7 @@ #include #include #include +#include #if BOOST_UNORDERED_USE_ALLOCATOR_TRAITS # include @@ -454,14 +455,14 @@ namespace boost { namespace unordered { namespace detail { }; #endif - // allocator_array_constructor + // array_constructor // // Allocate and construct an array in an exception safe manner, and // clean up if an exception is thrown before the container takes charge // of it. template - struct allocator_array_constructor + struct array_constructor { typedef typename allocator_traits::pointer pointer; @@ -471,14 +472,14 @@ namespace boost { namespace unordered { namespace detail { pointer constructed_; std::size_t length_; - allocator_array_constructor(Allocator& a) + array_constructor(Allocator& a) : alloc_(a), ptr_(), constructed_(), length_(0) { constructed_ = pointer(); ptr_ = pointer(); } - ~allocator_array_constructor() { + ~array_constructor() { if (ptr_) { for(pointer p = ptr_; p != constructed_; ++p) allocator_traits::destroy(alloc_, @@ -512,9 +513,9 @@ namespace boost { namespace unordered { namespace detail { return p; } private: - allocator_array_constructor(allocator_array_constructor const&); - allocator_array_constructor& operator=( - allocator_array_constructor const&); + array_constructor(array_constructor const&); + array_constructor& operator=( + array_constructor const&); }; }}} diff --git a/include/boost/unordered/detail/buckets.hpp b/include/boost/unordered/detail/buckets.hpp index fdb30b70..08d74b56 100644 --- a/include/boost/unordered/detail/buckets.hpp +++ b/include/boost/unordered/detail/buckets.hpp @@ -7,65 +7,209 @@ #ifndef BOOST_UNORDERED_DETAIL_MANAGER_HPP_INCLUDED #define BOOST_UNORDERED_DETAIL_MANAGER_HPP_INCLUDED -#include +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include + +#if defined(BOOST_MSVC) +#pragma warning(push) +#pragma warning(disable:4127) // conditional expression is constant +#endif namespace boost { namespace unordered { namespace detail { - - //////////////////////////////////////////////////////////////////////////// - // - // Now the main data structure: - // - // buckets functions - // | | - // +---------------+--------------+ - // | - // table - // - // T is a class which contains typedefs for all the types we need. - - // 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 buckets + template struct table; + template struct bucket; + struct ptr_bucket; + template struct buckets; + + /////////////////////////////////////////////////////////////////// + // + // Node construction + + template + struct node_constructor { + private: + + typedef NodeAlloc node_allocator; + typedef ::boost::unordered::detail::allocator_traits node_allocator_traits; + typedef typename node_allocator_traits::value_type node; + typedef typename node_allocator_traits::pointer node_pointer; + typedef typename node::value_type value_type; + + node_allocator& alloc_; + node_pointer node_; + bool node_constructed_; + bool value_constructed_; + + public: + + node_constructor(node_allocator& n) : + alloc_(n), + node_(), + node_constructed_(false), + value_constructed_(false) + { + } + + ~node_constructor(); + + void construct_node(); + + template + void construct_value(BOOST_UNORDERED_EMPLACE_ARGS) + { + BOOST_ASSERT(node_ && node_constructed_ && !value_constructed_); + ::boost::unordered::detail::construct_impl( + node_->value_ptr(), + BOOST_UNORDERED_EMPLACE_FORWARD); + value_constructed_ = true; + } + + template + void construct_value2(BOOST_FWD_REF(A0) a0) + { + BOOST_ASSERT(node_ && node_constructed_ && !value_constructed_); + ::boost::unordered::detail::construct_impl2( + node_->value_ptr(), boost::forward(a0)); + value_constructed_ = true; + } + + value_type const& value() const { + BOOST_ASSERT(node_ && node_constructed_ && value_constructed_); + return node_->value(); + } + + // no throw + node_pointer release() + { + node_pointer p = node_; + node_ = node_pointer(); + return p; + } + + private: + node_constructor(node_constructor const&); + node_constructor& operator=(node_constructor const&); + }; + + template + node_constructor::~node_constructor() + { + if (node_) { + if (value_constructed_) { + ::boost::unordered::detail::destroy(node_->value_ptr()); + } + + if (node_constructed_) { + node_allocator_traits::destroy(alloc_, boost::addressof(*node_)); + } + + node_allocator_traits::deallocate(alloc_, node_, 1); + } + } + + template + void node_constructor::construct_node() + { + if(!node_) { + node_constructed_ = false; + value_constructed_ = false; + + node_ = node_allocator_traits::allocate(alloc_, 1); + + node_allocator_traits::construct(alloc_, boost::addressof(*node_), node()); + node_->init(static_cast(node_)); + node_constructed_ = true; + } + else { + BOOST_ASSERT(node_constructed_); + + if (value_constructed_) + { + ::boost::unordered::detail::destroy(node_->value_ptr()); + value_constructed_ = false; + } + } + } + + /////////////////////////////////////////////////////////////////// + // + // Bucket + + template + struct bucket + { + typedef NodePointer previous_pointer; + previous_pointer next_; + + bucket() : next_() {} + + previous_pointer first_from_start() + { + return next_; + } + + enum { extra_node = true }; + }; + + struct ptr_bucket + { + typedef ptr_bucket* previous_pointer; + previous_pointer next_; + + ptr_bucket() : next_(0) {} + + previous_pointer first_from_start() + { + return this; + } + + enum { extra_node = false }; + }; + + /////////////////////////////////////////////////////////////////// + // + // Buckets + + template + struct buckets + { + private: buckets(buckets const&); buckets& operator=(buckets const&); public: - // Types + typedef ::boost::unordered::detail::allocator_traits traits; + typedef typename traits::value_type value_type; + typedef typename traits::void_pointer void_pointer; - typedef 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 typename allocator_traits::value_type value_type; - - typedef typename bucket::bucket_allocator bucket_allocator; - typedef typename allocator_traits::pointer bucket_ptr; - typedef typename bucket::node_ptr node_ptr; - - typedef typename rebind_wrap::type - node_allocator; - typedef typename allocator_traits::pointer real_node_ptr; + typedef Node node; + typedef Bucket bucket; + typedef typename ::boost::unordered::detail::rebind_wrap::type node_allocator; + typedef typename ::boost::unordered::detail::rebind_wrap::type bucket_allocator; + typedef ::boost::unordered::detail::allocator_traits node_allocator_traits; + typedef ::boost::unordered::detail::allocator_traits bucket_allocator_traits; + typedef typename node_allocator_traits::pointer node_pointer; + typedef typename node_allocator_traits::const_pointer const_node_pointer; + typedef typename bucket_allocator_traits::pointer bucket_pointer; + typedef typename bucket::previous_pointer previous_pointer; + typedef ::boost::unordered::detail::node_constructor node_constructor; // Members - bucket_ptr buckets_; + bucket_pointer buckets_; std::size_t bucket_count_; std::size_t size_; - compressed_pair allocators_; - + ::boost::unordered::detail::compressed allocators_; + // Data access bucket_allocator const& bucket_alloc() const @@ -91,22 +235,71 @@ namespace boost { namespace unordered { namespace detail { std::size_t max_bucket_count() const { // -1 to account for the start bucket. - return prev_prime(allocator_traits::max_size(bucket_alloc()) - 1); + return prev_prime(bucket_allocator_traits::max_size(bucket_alloc()) - 1); + } + + bucket_pointer get_bucket(std::size_t bucket_index) const + { + return buckets_ + static_cast(bucket_index); + } + + previous_pointer get_previous_start() const + { + return this->get_bucket(this->bucket_count_)->first_from_start(); + } + + previous_pointer get_previous_start(std::size_t bucket_index) const + { + return this->get_bucket(bucket_index)->next_; + } + + node_pointer get_start() const + { + return static_cast(this->get_previous_start()->next_); + } + + node_pointer get_start(std::size_t bucket_index) const + { + previous_pointer prev = this->get_previous_start(bucket_index); + return prev ? static_cast(prev->next_) : node_pointer(); + } + + float load_factor() const + { + BOOST_ASSERT(this->bucket_count_ != 0); + return static_cast(this->size_) + / static_cast(this->bucket_count_); + } + + std::size_t bucket_size(std::size_t index) const + { + if (!this->size_) return 0; + node_pointer ptr = this->get_start(index); + if (!ptr) return 0; + + std::size_t count = 0; + while(ptr && ptr->hash_ % this->bucket_count_ == index) + { + ++count; + ptr = static_cast(ptr->next_); + } + + return count; } //////////////////////////////////////////////////////////////////////// - // Constructors and Destructors + // Constructors - buckets(node_allocator const& a, std::size_t bucket_count) - : buckets_(), + buckets(node_allocator const& a, std::size_t bucket_count) : + buckets_(), bucket_count_(bucket_count), size_(), allocators_(a,a) { } - buckets(buckets& b, move_tag m) - : buckets_(), + buckets(buckets& b, ::boost::unordered::detail::move_tag m) : + buckets_(), bucket_count_(b.bucket_count_), size_(), allocators_(b.allocators_, m) @@ -114,36 +307,44 @@ namespace boost { namespace unordered { namespace detail { swap(b); } - template - buckets(table& x, move_tag m) - : buckets_(), + template + buckets(::boost::unordered::detail::table& x, + ::boost::unordered::detail::move_tag m) : + buckets_(), bucket_count_(x.bucket_count_), + size_(), allocators_(x.allocators_, m) { swap(x); - x.size_ = 0; - } - - inline ~buckets() - { - if(this->buckets_) { this->delete_buckets(); } } + //////////////////////////////////////////////////////////////////////// + // Create buckets + // (never called in constructor to avoid exception issues) + void create_buckets() { - // The array constructor will clean up in the event of an - // exception. - allocator_array_constructor + ::boost::unordered::detail::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. + if (bucket::extra_node) + { + node_constructor a(this->node_alloc()); + a.construct_node(); + + (constructor.get() + static_cast(this->bucket_count_))->next_ = + a.release(); + } + this->buckets_ = constructor.release(); } - + + //////////////////////////////////////////////////////////////////////// + // Swap and Move + void swap(buckets& other, false_type = false_type()) { BOOST_ASSERT(node_alloc() == other.node_alloc()); @@ -167,168 +368,113 @@ namespace boost { namespace unordered { namespace detail { this->buckets_ = other.buckets_; this->bucket_count_ = other.bucket_count_; this->size_ = other.size_; - other.buckets_ = bucket_ptr(); + other.buckets_ = bucket_pointer(); other.bucket_count_ = 0; other.size_ = 0; } - std::size_t bucket_size(std::size_t index) const + //////////////////////////////////////////////////////////////////////// + // Delete/destruct + + inline void delete_node(node_pointer n) + { + ::boost::unordered::detail::destroy(n->value_ptr()); + node_allocator_traits::destroy(node_alloc(), boost::addressof(*n)); + node_allocator_traits::deallocate(node_alloc(), n, 1); + --size_; + } + + std::size_t delete_nodes(node_pointer begin, node_pointer end) { - if (!this->size_) return 0; - node_ptr ptr = this->buckets_[index].next_; - if (!ptr) return 0; - ptr = ptr->next_; - std::size_t count = 0; - while(BOOST_UNORDERED_BORLAND_BOOL(ptr) && - node::get_hash(ptr) % this->bucket_count_ == index) - { + + while(begin != end) { + node_pointer n = begin; + begin = static_cast(begin->next_); + delete_node(n); ++count; - ptr = ptr->next_; } - + return count; } - node_ptr bucket_begin(std::size_t bucket_index) const - { - if (!this->size_) return node_ptr(); - bucket& b = this->buckets_[bucket_index]; - if (!b.next_) return node_ptr(); - return b.next_->next_; + inline void delete_extra_node(bucket_pointer) {} + + inline void delete_extra_node(node_pointer n) { + node_allocator_traits::destroy(node_alloc(), boost::addressof(*n)); + node_allocator_traits::deallocate(node_alloc(), n, 1); } - // For the remaining functions, buckets_ must not be null. - - bucket_ptr get_bucket(std::size_t bucket_index) const + inline ~buckets() { - return buckets_ + static_cast(bucket_index); - } - - float load_factor() const - { - BOOST_ASSERT(this->bucket_count_ != 0); - return static_cast(this->size_) - / static_cast(this->bucket_count_); - } - - //////////////////////////////////////////////////////////////////////// - // Delete - - void delete_node(node_ptr n) - { - node* raw_ptr = static_cast(boost::addressof(*n)); - real_node_ptr real_ptr(node_alloc().address(*raw_ptr)); - - ::boost::unordered::detail::destroy(raw_ptr->value_ptr()); - allocator_traits::destroy(node_alloc(), raw_ptr); - allocator_traits::deallocate(node_alloc(), real_ptr, 1); - - --this->size_; + this->delete_buckets(); } 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) { - allocator_traits::destroy(bucket_alloc(), - boost::addressof(*begin)); - } - - allocator_traits::deallocate(bucket_alloc(), this->buckets_, this->bucket_count_ + 1); - - this->buckets_ = bucket_ptr(); - BOOST_ASSERT(this->size_ == 0); - } + if(this->buckets_) { + previous_pointer prev = this->get_previous_start(); - 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; + while(prev->next_) { + node_pointer n = static_cast(prev->next_); + prev->next_ = n->next_; + delete_node(n); + } + + delete_extra_node(prev); + + bucket_pointer end = this->get_bucket(this->bucket_count_ + 1); + for(bucket_pointer it = this->buckets_; it != end; ++it) + { + bucket_allocator_traits::destroy(bucket_alloc(), boost::addressof(*it)); + } + + bucket_allocator_traits::deallocate(bucket_alloc(), this->buckets_, this->bucket_count_ + 1); + + this->buckets_ = bucket_pointer(); } - return count; + + BOOST_ASSERT(!this->size_); } 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)) + + previous_pointer prev = this->get_previous_start(); + + while(prev->next_) { + node_pointer n = static_cast(prev->next_); + prev->next_ = n->next_; + delete_node(n); + } + + bucket_pointer end = this->get_bucket(this->bucket_count_); + for(bucket_pointer it = this->buckets_; it != end; ++it) { - node_ptr node_to_delete = n; - n = n->next_; - this->delete_node(node_to_delete); + it->next_ = node_pointer(); } - - ++end; - for(bucket_ptr begin = this->buckets_; begin != end; ++begin) { - begin->next_ = bucket_ptr(); - } - - this->size_ = 0; - } - 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); - - 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->delete_nodes(r1, r2); - - return r2; + BOOST_ASSERT(!this->size_); } // 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) + void fix_buckets(bucket_pointer bucket, previous_pointer prev, node_pointer next) { if (!next) { - if (bucket->next_ == prev) bucket->next_ = node_ptr(); + if (bucket->next_ == prev) bucket->next_ = node_pointer(); } else { - bucket_ptr next_bucket = this->get_bucket( - node::get_hash(next) % this->bucket_count_); + bucket_pointer next_bucket = this->get_bucket( + next->hash_ % this->bucket_count_); + if (next_bucket != bucket) { next_bucket->next_ = prev; - if (bucket->next_ == prev) bucket->next_ = node_ptr(); + if (bucket->next_ == prev) bucket->next_ = node_pointer(); } } } @@ -336,20 +482,20 @@ namespace boost { namespace unordered { namespace detail { // 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) + std::size_t bucket_index, previous_pointer prev, node_pointer begin, node_pointer end) { - node_ptr n = begin; + node_pointer 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_; + n = static_cast(n->next_); if (n == end) return; std::size_t new_bucket_index = - node::get_hash(n) % this->bucket_count_; + n->hash_ % this->bucket_count_; if (bucket_index != new_bucket_index) { bucket_index = new_bucket_index; break; @@ -359,49 +505,30 @@ namespace boost { namespace unordered { namespace detail { // Iterate through the remaining nodes, clearing out the bucket // pointers. - this->buckets_[bucket_index].next_ = bucket_ptr(); + this->get_bucket(bucket_index)->next_ = previous_pointer(); for(;;) { - n = n->next_; + n = static_cast(n->next_); if (n == end) break; std::size_t new_bucket_index = - node::get_hash(n) % this->bucket_count_; + n->hash_ % this->bucket_count_; if (bucket_index != new_bucket_index) { bucket_index = new_bucket_index; - this->buckets_[bucket_index].next_ = bucket_ptr(); + this->get_bucket(bucket_index)->next_ = previous_pointer(); } }; // Finally fix the bucket containing the trailing node. - if (BOOST_UNORDERED_BORLAND_BOOL(n)) { - this->buckets_[node::get_hash(n) % this->bucket_count_].next_ + if (n) { + this->get_bucket(n->hash_ % 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; - void move_buckets_to(buckets&) const; - void rehash_impl(std::size_t); }; + //////////////////////////////////////////////////////////////////////////// + // Functions + // 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 @@ -421,7 +548,8 @@ namespace boost { namespace unordered { namespace detail { friend class set_hash_functions; functions& operator=(functions const&); - typedef compressed_pair function_pair; + typedef compressed function_pair; + typedef typename ::boost::aligned_storage< sizeof(function_pair), ::boost::alignment_of::value>::type aligned_function; @@ -512,517 +640,10 @@ namespace boost { namespace unordered { namespace detail { tmp_functions_ = !tmp_functions_; } }; - - //////////////////////////////////////////////////////////////////////////// - // - // Value Construction - -#define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(n, namespace_) \ - template \ - void construct_from_tuple(T* ptr, namespace_::tuple<>) \ - { \ - new ((void*) ptr) T(); \ - } \ - \ - BOOST_PP_REPEAT_FROM_TO(1, n, \ - BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL, namespace_) - -#define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL(z, n, namespace_) \ - template\ - void construct_from_tuple(T* ptr, \ - namespace_::tuple const& x) \ - { \ - new ((void*) ptr) T( \ - BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_GET_TUPLE_ARG, namespace_) \ - ); \ - } - -#define BOOST_UNORDERED_GET_TUPLE_ARG(z, n, namespace_) \ - namespace_::get(x) - -BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, boost) - -#if !defined(BOOST_NO_0X_HDR_TUPLE) -BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, std) -#elif defined(BOOST_HAS_TR1_TUPLE) -BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, std::tr1) -#endif - -#if defined(BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT) - template - struct emulation1 { - static choice1::type check(choice1, std::pair const&); - static choice2::type check(choice2, A const&); - - enum { value = sizeof(check(choose(), make())) == sizeof(choice2::type) }; - }; -#endif - -#if defined(BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT) - template - struct check3_base { - static choice1::type check(choice1, boost::unordered::piecewise_construct_t); - static choice2::type check(choice2, A const&); - static choice3::type check(choice3, ...); - }; -#else - template - struct check3_base { - static choice1::type check(choice1, boost::unordered::piecewise_construct_t); - static choice3::type check(choice3, ...); - }; -#endif - - template - struct piecewise3 { - enum { value = - sizeof(check3_base::check(choose(), make())) == - sizeof(choice1::type) }; - }; - - template - struct emulation3 { - enum { value = - sizeof(check3_base::check(choose(), make())) == - sizeof(choice2::type) }; - }; - - template - struct normal3 { - enum { value = - sizeof(check3_base::check(choose(), make())) == - sizeof(choice3::type) }; - }; - - template - struct pair_construct1 {}; - template - struct normal_construct1 { typedef void type; }; - -#if defined(BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT) - template - struct pair_construct1, Arg1> - : enable_if, void> {}; - - template - struct normal_construct1, Arg1> - : disable_if, void> {}; -#endif - - template - struct piecewise_construct3 {}; - template - struct piecewise_construct3, Arg1> - : enable_if, void> {}; - - template - struct pair_construct3 {}; - template - struct pair_construct3, Arg1> - : enable_if, void> {}; - - template - struct normal_construct3 { typedef void type; }; - template - struct normal_construct3, Arg1> - : enable_if, void> {}; - - template - struct pair_construct_n {}; - template - struct normal_construct_n { typedef void type; }; - -#if defined(BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT) - template - struct pair_construct_n > { typedef void type; }; - template - struct normal_construct_n > {}; -#endif - - template - inline void construct_impl(void* address) - { - new(address) T(); - } - - template - inline typename normal_construct1::type - construct_impl(void* address, BOOST_FWD_REF(Arg1) arg1) - { - new(address) T( - boost::forward(arg1) - ); - } - - template - inline typename pair_construct1::type - construct_impl(void* address, BOOST_FWD_REF(Arg1) arg1) - { - new((void*)(&static_cast(address)->first)) - typename T::first_type( - boost::forward(arg1)); - new((void*)(&static_cast(address)->second)) - typename T::second_type(); - } - - template - inline void construct_impl(void* address, BOOST_FWD_REF(Arg1) arg1, - BOOST_FWD_REF(Arg2) arg2) - { - new(address) T( - boost::forward(arg1), - boost::forward(arg2)); - } - - template - inline typename piecewise_construct3::type - construct_impl(void* address, BOOST_FWD_REF(Arg1), - BOOST_FWD_REF(Arg2) arg2, BOOST_FWD_REF(Arg3) arg3) - { - construct_from_tuple(&static_cast(address)->first, arg2); - construct_from_tuple(&static_cast(address)->second, arg3); - } - - template - inline typename pair_construct3::type - construct_impl(void* address, BOOST_FWD_REF(Arg1) arg1, - BOOST_FWD_REF(Arg2) arg2, BOOST_FWD_REF(Arg3) arg3) - { - new((void*)(&static_cast(address)->first)) - typename T::first_type( - boost::forward(arg1)); - new((void*)(&static_cast(address)->second)) - typename T::second_type( - boost::forward(arg2), - boost::forward(arg3)); - } - - template - inline typename normal_construct3::type - construct_impl(void* address, BOOST_FWD_REF(Arg1) arg1, - BOOST_FWD_REF(Arg2) arg2, BOOST_FWD_REF(Arg3) arg3) - { - new(address) T( - boost::forward(arg1), - boost::forward(arg2), - boost::forward(arg3)); - } - -#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE) - - template - inline typename normal_construct_n::type - construct_impl(void* address, Arg1&& arg1, Arg2&& arg2, Arg3&& arg3, - Arg4&& arg4, Args&&... args) - { - new(address) T( - std::forward(arg1), - std::forward(arg2), - std::forward(arg3), - std::forward(arg4), - std::forward(args)...); - } - - template - inline typename pair_construct_n::type - construct_impl(void* address, Arg1&& arg1, Arg2&& arg2, Arg3&& arg3, - Arg4&& arg4, Args&&... args) - { - new((void*)(&static_cast(address)->first)) - typename T::first_type( - std::forward(arg1)); - new((void*)(&static_cast(address)->second)) - typename T::second_type( - std::forward(arg2), - std::forward(arg3), - std::forward(arg4), - std::forward(args)...); - } - -#else - -#define BOOST_UNORDERED_CONSTRUCT_IMPL(z, num_params, _) \ - template < \ - class T, \ - BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params) \ - > \ - inline typename normal_construct_n::type \ - construct_impl(void* address, \ - BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \ - { \ - new(address) T( \ - BOOST_UNORDERED_CALL_PARAMS(z, num_params)); \ - } - - BOOST_PP_REPEAT_FROM_TO(4, BOOST_UNORDERED_EMPLACE_LIMIT, - BOOST_UNORDERED_CONSTRUCT_IMPL, _) - -#define BOOST_UNORDERED_CONSTRUCT_PAIR_IMPL(z, num_params, _) \ - template \ - inline typename pair_construct_n::type \ - construct_impl(void* address, BOOST_FWD_REF(Key) key, \ - BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \ - { \ - new((void*)(&static_cast(address)->first)) \ - typename T::first_type( \ - boost::forward(key)); \ - new((void*)(&static_cast(address)->second)) \ - typename T::second_type( \ - BOOST_UNORDERED_CALL_PARAMS(z, num_params)); \ - } - - BOOST_PP_REPEAT_FROM_TO(3, BOOST_UNORDERED_EMPLACE_LIMIT, - BOOST_UNORDERED_CONSTRUCT_PAIR_IMPL, _) - -#undef BOOST_UNORDERED_CONSTRUCT_IMPL -#endif - - /////////////////////////////////////////////////////////////////// - // - // Node construction - - template - class node_constructor - { - typedef ::boost::unordered::detail::buckets buckets; - typedef typename buckets::node node; - typedef typename buckets::real_node_ptr real_node_ptr; - typedef typename buckets::value_type value_type; - typedef typename buckets::node_allocator node_allocator; - - 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_MOVE) - template - void construct(Args&&... args) - { - construct_preamble(); - construct_impl(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(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 - 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_) - allocator_traits::destroy(buckets_.node_alloc(), - boost::addressof(*node_)); - - allocator_traits::deallocate(buckets_.node_alloc(), node_, 1); - } - } - - template - inline void node_constructor::construct_preamble() - { - if(!node_) { - node_constructed_ = false; - value_constructed_ = false; - - node_ = allocator_traits::allocate(buckets_.node_alloc(), 1); - allocator_traits::construct(buckets_.node_alloc(), - boost::addressof(*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 exception 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; - ++dst.size_; - - 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); - ++dst.size_; - } - - prev = dst.place_in_bucket(prev, end); - } - } - } - - //////////////////////////////////////////////////////////////////////////// - // move_buckets_to - // - // Basic exception safety. The source nodes are left in an unusable state - // if an exception throws. - - template - void buckets::move_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(boost::move(node::get_value(n))); - node_ptr first_node = a.release(); - node::set_hash(first_node, hash); - node_ptr end = prev->next_ = first_node; - ++dst.size_; - - for(n = n->next_; n != group_end; n = n->next_) { - a.construct(boost::move(node::get_value(n))); - end = a.release(); - node::set_hash(end, hash); - node::add_after_node(end, first_node); - ++dst.size_; - } - - prev = dst.place_in_bucket(prev, end); - } - } - } - - // strong otherwise exception safety - template - void buckets::rehash_impl(std::size_t num_buckets) - { - BOOST_ASSERT(this->size_); - - buckets dst(this->node_alloc(), num_buckets); - dst.create_buckets(); - - 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(); - dst.size_ = this->size_; - 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 - } }}} +#if defined(BOOST_MSVC) +#pragma warning(pop) +#endif + #endif diff --git a/include/boost/unordered/detail/emplace_args.hpp b/include/boost/unordered/detail/emplace_args.hpp new file mode 100644 index 00000000..f65f4107 --- /dev/null +++ b/include/boost/unordered/detail/emplace_args.hpp @@ -0,0 +1,548 @@ + +// Copyright (C) 2011 Daniel James. +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/libs/unordered for documentation + +#ifndef BOOST_UNORDERED_EMPLACE_ARGS_HPP +#define BOOST_UNORDERED_EMPLACE_ARGS_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if !defined(BOOST_NO_0X_HDR_TUPLE) +#include +#elif defined(BOOST_HAS_TR1_TUPLE) +#include +#endif + +#if defined(BOOST_MSVC) +#pragma warning(push) +#pragma warning(disable:4512) // assignment operator could not be generated. +#pragma warning(disable:4345) // behavior change: an object of POD type + // constructed with an initializer of the form () + // will be default-initialized. +#endif + +#define BOOST_UNORDERED_EMPLACE_LIMIT 10 + +#if 0 && !defined(BOOST_NO_RVALUE_REFERENCES) && \ + !defined(BOOST_NO_VARIADIC_TEMPLATES) +# if defined(__SGI_STL_PORT) || defined(_STLPORT_VERSION) +# elif defined(__STD_RWCOMPILER_H__) || defined(_RWSTD_VER) +# elif defined(_LIBCPP_VERSION) +# define BOOST_UNORDERED_STD_FORWARD_MOVE +# elif defined(__GLIBCPP__) || defined(__GLIBCXX__) +# if defined(__GLIBCXX__) && __GLIBCXX__ >= 20090804 +# define BOOST_UNORDERED_STD_FORWARD_MOVE +# endif +# elif defined(__STL_CONFIG_H) +# elif defined(__MSL_CPP__) +# elif defined(__IBMCPP__) +# elif defined(MSIPL_COMPILE_H) +# elif (defined(_YVALS) && !defined(__IBMCPP__)) || defined(_CPPLIB_VER) + // Visual C++. A version check would be a good idea. +# define BOOST_UNORDERED_STD_FORWARD_MOVE +# endif +#endif + +namespace boost { namespace unordered { namespace detail { + +#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE) + +#define BOOST_UNORDERED_EMPLACE_TEMPLATE typename... Args +#define BOOST_UNORDERED_EMPLACE_ARGS Args&&... args +#define BOOST_UNORDERED_EMPLACE_FORWARD std::forward(args)... + +#else + +#define BOOST_UNORDERED_EMPLACE_TEMPLATE typename Args +#define BOOST_UNORDERED_EMPLACE_ARGS Args const& args +#define BOOST_UNORDERED_EMPLACE_FORWARD args + +#define BOOST_UNORDERED_FWD_PARAM(z, n, a) \ + BOOST_FWD_REF(BOOST_PP_CAT(A, n)) BOOST_PP_CAT(a, n) + +#define BOOST_UNORDERED_CALL_FORWARD(z, i, a) \ + boost::forward(BOOST_PP_CAT(a,i)) + +#define BOOST_UNORDERED_EARGS(z, n, _) \ + template \ + struct BOOST_PP_CAT(emplace_args, n) \ + { \ + BOOST_PP_REPEAT_##z(n, BOOST_UNORDERED_EARGS_MEMBER, _) \ + BOOST_PP_CAT(emplace_args, n) ( \ + BOOST_PP_ENUM_BINARY_PARAMS_Z(z, n, B, a) \ + ) : BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_EARGS_INIT, _) \ + {} \ + \ + }; \ + \ + template \ + inline BOOST_PP_CAT(emplace_args, n) < \ + BOOST_PP_ENUM_PARAMS_Z(z, n, A) \ + > create_emplace_args( \ + BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a) \ + ) \ + { \ + BOOST_PP_CAT(emplace_args, n) < \ + BOOST_PP_ENUM_PARAMS_Z(z, n, A) \ + > e(BOOST_PP_ENUM_PARAMS_Z(z, n, a)); \ + return e; \ + } + +#if defined(BOOST_NO_RVALUE_REFERENCES) + +#define BOOST_UNORDERED_EARGS_MEMBER(z, n, _) \ + typedef BOOST_FWD_REF(BOOST_PP_CAT(A, n)) BOOST_PP_CAT(B, n); \ + BOOST_PP_CAT(B, n) BOOST_PP_CAT(a, n); + +#define BOOST_UNORDERED_EARGS_INIT(z, n, _) \ + BOOST_PP_CAT(a, n)( \ + boost::forward(BOOST_PP_CAT(a, n))) + +#else + +#define BOOST_UNORDERED_EARGS_MEMBER(z, n, _) \ + typedef typename boost::add_lvalue_reference::type \ + BOOST_PP_CAT(B, n); \ + BOOST_PP_CAT(B, n) BOOST_PP_CAT(a, n); + +#define BOOST_UNORDERED_EARGS_INIT(z, n, _) \ + BOOST_PP_CAT(a, n)(BOOST_PP_CAT(a, n)) + +#endif + +BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, BOOST_UNORDERED_EARGS, + _) + +#undef BOOST_UNORDERED_DEFINE_EMPLACE_ARGS +#undef BOOST_UNORDERED_EARGS_MEMBER +#undef BOOST_UNORDERED_EARGS_INIT + +#endif + + //////////////////////////////////////////////////////////////////////////// + // rvalue parameters when type can't be a BOOST_RV_REF(T) parameter + // e.g. for int + +#if !defined(BOOST_NO_RVALUE_REFERENCES) +# define BOOST_UNORDERED_RV_REF(T) BOOST_RV_REF(T) +#else + struct please_ignore_this_overload { + typedef please_ignore_this_overload type; + }; + + template + struct rv_ref_impl { + typedef BOOST_RV_REF(T) type; + }; + + template + struct rv_ref : + boost::detail::if_true< + boost::is_class::value + >::BOOST_NESTED_TEMPLATE then < + rv_ref_impl, + please_ignore_this_overload + >::type + {}; + +# define BOOST_UNORDERED_RV_REF(T) \ + typename ::boost::unordered::detail::rv_ref::type +#endif + + //////////////////////////////////////////////////////////////////////////// + // + // Value Construction + +#define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(n, namespace_) \ + template \ + void construct_from_tuple(T* ptr, namespace_::tuple<>) \ + { \ + new ((void*) ptr) T(); \ + } \ + \ + BOOST_PP_REPEAT_FROM_TO(1, n, \ + BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL, namespace_) + +#define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL(z, n, namespace_) \ + template \ + void construct_from_tuple(T* ptr, \ + namespace_::tuple const& x) \ + { \ + new ((void*) ptr) T( \ + BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_GET_TUPLE_ARG, namespace_) \ + ); \ + } + +#define BOOST_UNORDERED_GET_TUPLE_ARG(z, n, namespace_) \ + namespace_::get(x) + +BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, boost) + +#if !defined(BOOST_NO_0X_HDR_TUPLE) +BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, std) +#elif defined(BOOST_HAS_TR1_TUPLE) +BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, std::tr1) +#endif + +#undef BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE +#undef BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL +#undef BOOST_UNORDERED_GET_TUPLE_ARG + +#if defined(BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT) + template + struct emulation1 { + static choice1::type check(choice1, std::pair const&); + static choice2::type check(choice2, A const&); + static choice3::type check(choice3, ...); + + enum { value = + sizeof(check(choose(), make())) == sizeof(choice2::type) }; + }; +#endif + +#if defined(BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT) + template + struct check3_base { + static choice1::type check(choice1, + boost::unordered::piecewise_construct_t); + static choice2::type check(choice2, A const&); + static choice3::type check(choice3, ...); + }; +#else + template + struct check3_base { + static choice1::type check(choice1, + boost::unordered::piecewise_construct_t); + static choice3::type check(choice3, ...); + }; +#endif + + template + struct piecewise3 { + enum { value = + sizeof(check3_base::check(choose(), make())) == + sizeof(choice1::type) }; + }; + + template + struct emulation3 { + enum { value = + sizeof(check3_base::check(choose(), make())) == + sizeof(choice2::type) }; + }; + + template + struct normal3 { + enum { value = + sizeof(check3_base::check(choose(), make())) == + sizeof(choice3::type) }; + }; + + template + struct pair_construct1 {}; + template + struct normal_construct1 { typedef void type; }; + +#if defined(BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT) + template + struct pair_construct1, A0> + : enable_if, void> {}; + + template + struct normal_construct1, A0> + : disable_if, void> {}; +#endif + + template + struct piecewise_construct3 {}; + template + struct piecewise_construct3, A0> + : enable_if, void> {}; + + template + struct pair_construct3 {}; + template + struct pair_construct3, A0> + : enable_if, void> {}; + + template + struct normal_construct3 { typedef void type; }; + template + struct normal_construct3, A0> + : enable_if, void> {}; + + template + struct pair_construct_n {}; + template + struct normal_construct_n { typedef void type; }; + +#if defined(BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT) + template + struct pair_construct_n > { typedef void type; }; + template + struct normal_construct_n > {}; +#endif + + template + inline typename normal_construct1::type + construct_impl2(void* address, BOOST_FWD_REF(A0) a0) + { + new(address) T( + boost::forward(a0) + ); + } + +#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE) + +//////////////////////////////////////////////////////////////////////////////// +// Construct from variadic parameters + + template + inline void construct_impl(void* address) + { + new(address) T(); + } + + template + inline typename normal_construct1::type + construct_impl(void* address, A0&& a0) + { + new(address) T( + boost::forward(a0) + ); + } + + template + inline typename pair_construct1::type + construct_impl(void* address, A0&& a0) + { + new((void*)(&static_cast(address)->first)) + typename T::first_type( + boost::forward(a0)); + new((void*)(&static_cast(address)->second)) + typename T::second_type(); + } + + template + inline void construct_impl(void* address, A0&& a0, A1&& a1) + { + new(address) T( + boost::forward(a0), + boost::forward(a1)); + } + + template + inline typename piecewise_construct3::type + construct_impl(void* address, A0&&, A1&& a1, A2&& a2) + { + construct_from_tuple( + boost::addressof(static_cast(address)->first), a1); + construct_from_tuple( + boost::addressof(static_cast(address)->second), a2); + } + + template + inline typename pair_construct3::type + construct_impl(void* address, A0&& a0, A1&& a1, A2&& a2) + { + new((void*)(&static_cast(address)->first)) + typename T::first_type( + boost::forward(a0)); + new((void*)(&static_cast(address)->second)) + typename T::second_type( + boost::forward(a1), + boost::forward(a2)); + } + + template + inline typename normal_construct3::type + construct_impl(void* address, A0&& a0, A1&& a1, A2&& a2) + { + new(address) T( + boost::forward(a0), + boost::forward(a1), + boost::forward(a2)); + } + + template + inline typename normal_construct_n::type + construct_impl(void* address, A0&& a0, A1&& a1, A2&& a2, + A3&& a3, Args&&... args) + { + new(address) T( + std::forward(a0), + std::forward(a1), + std::forward(a2), + std::forward(a3), + std::forward(args)...); + } + + template + inline typename pair_construct_n::type + construct_impl(void* address, A0&& a0, A1&& a1, A2&& a2, + A3&& a3, Args&&... args) + { + new((void*)(&static_cast(address)->first)) + typename T::first_type( + std::forward(a0)); + new((void*)(&static_cast(address)->second)) + typename T::second_type( + std::forward(a1), + std::forward(a2), + std::forward(a3), + std::forward(args)...); + } + +#else + +//////////////////////////////////////////////////////////////////////////////// +// Construct with emplace_args + + template + inline typename normal_construct1::type + construct_impl(void* address, + ::boost::unordered::detail::emplace_args1 const& args) + { + new(address) T( + boost::forward(args.a0) + ); + } + + template + inline typename pair_construct1::type + construct_impl(void* address, A0 const& a0) + { + new((void*)(&static_cast(address)->first)) + typename T::first_type( + boost::forward(a0)); + new((void*)(&static_cast(address)->second)) + typename T::second_type(); + } + + template + inline typename pair_construct1::type + construct_impl(void* address, + ::boost::unordered::detail::emplace_args1 const& args) + { + new((void*)(&static_cast(address)->first)) + typename T::first_type( + boost::forward(args.a0)); + new((void*)(&static_cast(address)->second)) + typename T::second_type(); + } + + template + inline void construct_impl(void* address, + ::boost::unordered::detail::emplace_args2 const& args) + { + new(address) T( + boost::forward(args.a0), + boost::forward(args.a1)); + } + + template + inline typename piecewise_construct3::type + construct_impl(void* address, + ::boost::unordered::detail::emplace_args3 const& args) + { + construct_from_tuple( + boost::addressof(static_cast(address)->first), args.a1); + construct_from_tuple( + boost::addressof(static_cast(address)->second), args.a2); + } + + template + inline typename pair_construct3::type + construct_impl(void* address, + ::boost::unordered::detail::emplace_args3 const& args) + { + new((void*)(&static_cast(address)->first)) + typename T::first_type( + boost::forward(args.a0)); + new((void*)(&static_cast(address)->second)) + typename T::second_type( + boost::forward(args.a1), + boost::forward(args.a2)); + } + + template + inline typename normal_construct3::type + construct_impl(void* address, + ::boost::unordered::detail::emplace_args3 const& args) + { + new(address) T( + boost::forward(args.a0), + boost::forward(args.a1), + boost::forward(args.a2)); + } + +#define BOOST_UNORDERED_CONSTRUCT_IMPL(z, num_params, _) \ + template < \ + typename T, \ + BOOST_PP_ENUM_PARAMS_Z(z, num_params, typename A) \ + > \ + inline typename normal_construct_n::type \ + construct_impl(void* address, \ + ::boost::unordered::detail::BOOST_PP_CAT(emplace_args,num_params) < \ + BOOST_PP_ENUM_PARAMS_Z(z, num_params, A) \ + > const& args) \ + { \ + new(address) T( \ + BOOST_PP_ENUM_##z(num_params, BOOST_UNORDERED_CALL_FORWARD, \ + args.a)); \ + } + + BOOST_PP_REPEAT_FROM_TO(4, BOOST_UNORDERED_EMPLACE_LIMIT, + BOOST_UNORDERED_CONSTRUCT_IMPL, _) + +#define BOOST_UNORDERED_CONSTRUCT_PAIR_IMPL(z, num_params, _) \ + template \ + inline typename pair_construct_n::type \ + construct_impl(void* address, \ + ::boost::unordered::detail::BOOST_PP_CAT(emplace_args,num_params) < \ + BOOST_PP_ENUM_PARAMS_Z(z, num_params, A) \ + > const& args) \ + { \ + new((void*)(&static_cast(address)->first)) \ + typename T::first_type( \ + boost::forward(args.a0)); \ + new((void*)(&static_cast(address)->second)) \ + typename T::second_type( \ + BOOST_PP_ENUM_SHIFTED_##z(num_params, \ + BOOST_UNORDERED_CALL_FORWARD, args.a)); \ + } + + BOOST_PP_REPEAT_FROM_TO(4, BOOST_UNORDERED_EMPLACE_LIMIT, + BOOST_UNORDERED_CONSTRUCT_PAIR_IMPL, _) + +#undef BOOST_UNORDERED_CONSTRUCT_IMPL +#undef BOOST_UNORDERED_CONSTRUCT_PAIR_IMPL +#endif + +}}} + +#if defined(BOOST_MSVC) +#pragma warning(pop) +#endif + +#endif diff --git a/include/boost/unordered/detail/equivalent.hpp b/include/boost/unordered/detail/equivalent.hpp index 423029d7..6260835a 100644 --- a/include/boost/unordered/detail/equivalent.hpp +++ b/include/boost/unordered/detail/equivalent.hpp @@ -7,60 +7,274 @@ #ifndef BOOST_UNORDERED_DETAIL_EQUIVALENT_HPP_INCLUDED #define BOOST_UNORDERED_DETAIL_EQUIVALENT_HPP_INCLUDED +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include +#include #include namespace boost { namespace unordered { namespace detail { - template - class equivalent_table : public T::table_base - { - public: - typedef typename T::hasher hasher; - typedef typename T::key_equal key_equal; - typedef typename T::value_allocator value_allocator; - typedef typename T::key_type key_type; - typedef typename T::value_type value_type; - typedef typename T::table_base table_base; - typedef typename T::node_constructor node_constructor; - typedef typename T::node_allocator node_allocator; + template struct grouped_node; + template struct grouped_ptr_node; + template struct grouped_table_impl; - typedef typename T::node node; - typedef typename T::node_ptr node_ptr; - typedef typename T::bucket_ptr bucket_ptr; - typedef typename T::extractor extractor; + template + struct grouped_node : + ::boost::unordered::detail::value_base + { + typedef VoidPointer link_pointer; + + link_pointer next_; + link_pointer group_prev_; + std::size_t hash_; + + grouped_node() : + next_(), + group_prev_(), + hash_(0) + {} + + void init(link_pointer self) + { + group_prev_ = self; + } + }; + + template + struct grouped_ptr_node : + ::boost::unordered::detail::value_base, + ::boost::unordered::detail::ptr_bucket + { + typedef ::boost::unordered::detail::ptr_bucket bucket_base; + typedef ptr_bucket* link_pointer; + + link_pointer group_prev_; + std::size_t hash_; + + grouped_ptr_node() : + bucket_base(), + group_prev_(0), + hash_(0) + {} + + void init(link_pointer self) + { + group_prev_ = self; + } + }; + + // If the allocator uses raw pointers use grouped_ptr_node + // Otherwise use grouped_node. + + template + struct pick_grouped_node2 + { + typedef ::boost::unordered::detail::grouped_node node; + + typedef typename ::boost::unordered::detail::allocator_traits< + typename ::boost::unordered::detail::rebind_wrap::type + >::pointer node_pointer; + + typedef ::boost::unordered::detail::bucket bucket; + typedef VoidPointer link_pointer; + }; + + template + struct pick_grouped_node2*, + ::boost::unordered::detail::ptr_bucket*> + { + typedef ::boost::unordered::detail::grouped_ptr_node node; + typedef ::boost::unordered::detail::ptr_bucket bucket; + typedef bucket* link_pointer; + }; + + template + struct pick_grouped_node + { + typedef ::boost::unordered::detail::allocator_traits< + typename ::boost::unordered::detail::rebind_wrap >::type + > tentative_node_traits; + + typedef ::boost::unordered::detail::allocator_traits< + typename ::boost::unordered::detail::rebind_wrap::type + > tentative_bucket_traits; + + typedef pick_grouped_node2 pick; + + typedef typename pick::node node; + typedef typename pick::bucket bucket; + typedef typename pick::link_pointer link_pointer; + }; + + template + struct multiset + { + typedef multiset types; + + typedef A allocator; + typedef H hasher; + typedef P key_equal; + + typedef ::boost::unordered::detail::allocator_traits traits; + typedef typename traits::value_type value_type; + typedef typename traits::void_pointer void_pointer; + typedef value_type key_type; + + typedef typename ::boost::unordered::detail::pick_grouped_node::node node; + typedef typename ::boost::unordered::detail::pick_grouped_node::bucket bucket; + typedef typename ::boost::unordered::detail::pick_grouped_node::link_pointer link_pointer; + typedef ::boost::unordered::detail::grouped_table_impl table; + + typedef ::boost::unordered::detail::set_extractor extractor; + }; + + template + struct multimap + { + typedef multimap types; + + typedef A allocator; + typedef H hasher; + typedef P key_equal; + typedef K key_type; + + typedef ::boost::unordered::detail::allocator_traits traits; + typedef typename traits::value_type value_type; + typedef typename traits::void_pointer void_pointer; + + typedef typename ::boost::unordered::detail::pick_grouped_node::node node; + typedef typename ::boost::unordered::detail::pick_grouped_node::bucket bucket; + typedef typename ::boost::unordered::detail::pick_grouped_node::link_pointer link_pointer; + typedef ::boost::unordered::detail::grouped_table_impl table; + + typedef ::boost::unordered::detail::map_extractor extractor; + }; + + template + struct grouped_table_impl : ::boost::unordered::detail::table + { + typedef ::boost::unordered::detail::table table; + typedef typename table::value_type value_type; + typedef typename table::bucket bucket; + typedef typename table::buckets buckets; + typedef typename table::node_pointer node_pointer; + typedef typename table::node_allocator node_allocator; + typedef typename table::node_allocator_traits node_allocator_traits; + typedef typename table::bucket_pointer bucket_pointer; + typedef typename table::link_pointer link_pointer; + typedef typename table::previous_pointer previous_pointer; + typedef typename table::hasher hasher; + typedef typename table::key_equal key_equal; + typedef typename table::key_type key_type; + typedef typename table::node_constructor node_constructor; + typedef typename table::extractor extractor; // Constructors - equivalent_table(std::size_t n, - hasher const& hf, key_equal const& eq, value_allocator const& a) - : table_base(n, hf, eq, a) {} - equivalent_table(equivalent_table const& x) - : table_base(x, - allocator_traits:: + grouped_table_impl(std::size_t n, + hasher const& hf, + key_equal const& eq, + node_allocator const& a) + : table(n, hf, eq, a) + {} + + grouped_table_impl(grouped_table_impl const& x) + : table(x, node_allocator_traits:: select_on_container_copy_construction(x.node_alloc())) {} - equivalent_table(equivalent_table const& x, - value_allocator const& a) - : table_base(x, a) {} - equivalent_table(equivalent_table& x, move_tag m) - : table_base(x, m) {} - equivalent_table(equivalent_table& x, - value_allocator const& a, move_tag m) - : table_base(x, a, m) {} - ~equivalent_table() {} + + grouped_table_impl(grouped_table_impl const& x, + node_allocator const& a) + : table(x, a) + {} + + grouped_table_impl(grouped_table_impl& x, + ::boost::unordered::detail::move_tag m) + : table(x, m) + {} + + grouped_table_impl(grouped_table_impl& x, + node_allocator const& a, + ::boost::unordered::detail::move_tag m) + : table(x, a, m) + {} + + // Accessors + + template + node_pointer find_node_impl( + std::size_t hash, + Key const& k, + Pred const& eq) const + { + std::size_t bucket_index = hash % this->bucket_count_; + node_pointer n = this->get_start(bucket_index); + + for (;;) + { + if (!n) return n; + + std::size_t node_hash = n->hash_; + if (hash == node_hash) + { + if (eq(k, this->get_key(n->value()))) + return n; + } + else + { + if (node_hash % this->bucket_count_ != bucket_index) + return node_pointer(); + } + + n = static_cast(static_cast(n->group_prev_)->next_); + } + } + + std::size_t count(key_type const& k) const + { + node_pointer n = this->find_node(k); + if (!n) return 0; + + std::size_t count = 0; + node_pointer it = n; + do { + it = static_cast(it->group_prev_); + ++count; + } while(it != n); + + return count; + } + + std::pair + equal_range(key_type const& k) const + { + node_pointer n = this->find_node(k); + return std::make_pair(n, + n ? static_cast( + static_cast(n->group_prev_)->next_) : n); + } // Equality - bool equals(equivalent_table const& other) const + bool equals(grouped_table_impl 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;) + for(node_pointer n1 = this->get_start(); n1;) { - node_ptr n2 = other.find_matching_node(n1); + node_pointer n2 = other.find_matching_node(n1); if (!n2) return false; - node_ptr end1 = node::next_group(n1); - node_ptr end2 = node::next_group(n2); + node_pointer end1 = static_cast(static_cast(n1->group_prev_)->next_); + node_pointer end2 = static_cast(static_cast(n2->group_prev_)->next_); if (!group_equals(n1, end1, n2, end2)) return false; n1 = end1; } @@ -70,60 +284,77 @@ namespace boost { namespace unordered { namespace detail { #if !defined(BOOST_UNORDERED_DEPRECATED_EQUALITY) - static bool group_equals(node_ptr n1, node_ptr end1, - node_ptr n2, node_ptr end2) + static bool group_equals(node_pointer n1, node_pointer end1, + node_pointer n2, node_pointer end2) { for(;;) { - if (node::get_value(n1) != node::get_value(n2)) + if (n1->value() != n2->value()) break; - n1 = n1->next_; - n2 = n2->next_; + n1 = static_cast(n1->next_); + n2 = static_cast(n2->next_); if (n1 == end1) return n2 == end2; if (n2 == end2) return false; } - for(node_ptr n1a = n1, n2a = n2;;) + for(node_pointer n1a = n1, n2a = n2;;) { - n1a = n1a->next_; - n2a = n2a->next_; + n1a = static_cast(n1a->next_); + n2a = static_cast(n2a->next_); if (n1a == end1) { if (n2a == end2) break; else return false; } + if (n2a == end2) return false; } - node_ptr start = n1; - for(;n1 != end2; n1 = n1->next_) + node_pointer start = n1; + for(;n1 != end2; n1 = static_cast(n1->next_)) { - value_type const& v = node::get_value(n1); + value_type const& v = n1->value(); if (find(start, n1, v)) continue; std::size_t matches = count_equal(n2, end2, v); - if (!matches || matches != 1 + count_equal(n1->next_, end1, v)) + if (!matches || matches != 1 + count_equal(static_cast(n1->next_), end1, v)) return false; } return true; } + static bool find(node_pointer n, node_pointer end, value_type const& v) + { + for(;n != end; n = static_cast(n->next_)) + if (n->value() == v) + return true; + return false; + } + + static std::size_t count_equal(node_pointer n, node_pointer end, value_type const& v) + { + std::size_t count = 0; + for(;n != end; n = static_cast(n->next_)) + if (n->value() == v) ++count; + return count; + } + #else - static bool group_equals(node_ptr n1, node_ptr end1, - node_ptr n2, node_ptr end2) + static bool group_equals(node_pointer n1, node_pointer end1, + node_pointer n2, node_pointer end2) { for(;;) { if(!extractor::compare_mapped( - node::get_value(n1), node::get_value(n2))) + n1->value(), n2->value())) return false; - n1 = n1->next_; - n2 = n2->next_; + n1 = static_cast(n1->next_); + n2 = static_cast(n2->next_); if (n1 == end1) return n2 == end2; if (n2 == end2) return false; @@ -132,205 +363,447 @@ namespace boost { namespace unordered { namespace detail { #endif - static bool find(node_ptr n, node_ptr end, value_type const& v) + // Emplace/Insert + + static inline void add_after_node( + node_pointer n, + node_pointer pos) { - for(;n != end; n = n->next_) - if (node::get_value(n) == v) - return true; - return false; - } - - static std::size_t count_equal(node_ptr n, node_ptr end, value_type const& v) - { - std::size_t count = 0; - for(;n != end; n = n->next_) - if (node::get_value(n) == v) ++count; - return count; + n->next_ = static_cast(pos->group_prev_)->next_; + n->group_prev_ = pos->group_prev_; + static_cast(pos->group_prev_)->next_ = static_cast(n); + pos->group_prev_ = static_cast(n); } - //////////////////////////////////////////////////////////////////////// - // A convenience method for adding nodes. - - inline node_ptr add_node( + inline node_pointer add_node( node_constructor& a, - std::size_t bucket_index, std::size_t hash, - node_ptr pos) + node_pointer pos) { - node_ptr n = a.release(); - node::set_hash(n, hash); - - if(BOOST_UNORDERED_BORLAND_BOOL(pos)) { - node::add_after_node(n, pos); + node_pointer n = a.release(); + n->hash_ = hash; + if(pos) { + this->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; + static_cast(n->next_)->hash_ % + this->bucket_count_; + if (next_bucket != hash % this->bucket_count_) { + this->get_bucket(next_bucket)->next_ = n; } } } else { - bucket_ptr b = this->get_bucket(bucket_index); - + bucket_pointer b = this->get_bucket(hash % this->bucket_count_); + if (!b->next_) { - bucket_ptr start_node = - this->get_bucket(this->bucket_count_); + previous_pointer start_node = this->get_previous_start(); - if (BOOST_UNORDERED_BORLAND_BOOL(start_node->next_)) { - this->buckets_[ - node::get_hash(start_node->next_) % - this->bucket_count_].next_ = n; + if (start_node->next_) { + this->get_bucket( + static_cast(start_node->next_)->hash_ % + this->bucket_count_)->next_ = n; } b->next_ = start_node; n->next_ = start_node->next_; - start_node->next_ = n; + start_node->next_ = static_cast(n); } else { n->next_ = b->next_->next_; - b->next_->next_ = n; + b->next_->next_ = static_cast(n); } } ++this->size_; return n; } - //////////////////////////////////////////////////////////////////////// - // Insert methods - - node_ptr emplace_impl(node_constructor& a) + node_pointer 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); - + node_pointer position = this->find_node(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); + this->reserve_for_insert(this->size_ + 1); + return this->add_node(a, hash, position); } 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)); + this->add_node(a, hash, + this->find_node(hash, k)); } #if defined(BOOST_NO_RVALUE_REFERENCES) - node_ptr emplace(please_ignore_this_overload const&) + node_pointer emplace(::boost::unordered::detail::emplace_args1< + ::boost::unordered::detail::please_ignore_this_overload> const&) { BOOST_ASSERT(false); return this->begin(); } #endif -#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE) - - template - node_ptr emplace(Args&&... args) + template + node_pointer emplace(BOOST_UNORDERED_EMPLACE_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)...); - + node_constructor a(this->node_alloc()); + a.construct_node(); + a.construct_value(BOOST_UNORDERED_EMPLACE_FORWARD); + return emplace_impl(a); } -#else - -#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, _) - -#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) + typename ::boost::unordered::detail::enable_if_forward::type + insert_range(I i, I j) { if(i == j) return; + std::size_t distance = ::boost::unordered::detail::distance(i, j); if(distance == 1) { - emplace(*i); + node_constructor a(this->node_alloc()); + a.construct_node(); + a.construct_value2(*i); + emplace_impl(a); } else { // Only require basic exception safety here this->reserve_for_insert(this->size_ + distance); - node_constructor a(*this); + node_constructor a(this->node_alloc()); for (; i != j; ++i) { - a.construct(*i); + a.construct_node(); + a.construct_value2(*i); emplace_impl_no_rehash(a); } } } template - void insert_for_range(I i, I j, ::boost::incrementable_traversal_tag) + typename ::boost::unordered::detail::disable_if_forward::type + insert_range(I i, I j) { - node_constructor a(*this); + node_constructor a(this->node_alloc()); for (; i != j; ++i) { - a.construct(*i); + a.construct_node(); + a.construct_value2(*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) + //////////////////////////////////////////////////////////////////////////// + // Erase + // + // no throw + + std::size_t erase_key(key_type const& k) { - insert_for_range(i, j, - BOOST_DEDUCED_TYPENAME ::boost::iterator_traversal::type()); + if(!this->size_) return 0; + + std::size_t hash = this->hash_function()(k); + std::size_t bucket_index = hash % this->bucket_count_; + bucket_pointer bucket = this->get_bucket(bucket_index); + + previous_pointer prev = bucket->next_; + if (!prev) return 0; + + for (;;) + { + if (!prev->next_) return 0; + std::size_t node_hash = static_cast(prev->next_)->hash_; + if (node_hash % this->bucket_count_ != bucket_index) + return 0; + if (node_hash == hash && + this->key_eq()(k, this->get_key(static_cast(prev->next_)->value()))) + break; + prev = static_cast( + static_cast(prev->next_)->group_prev_); + } + + node_pointer pos = static_cast(prev->next_); + link_pointer end1 = static_cast(pos->group_prev_)->next_; + node_pointer end = static_cast(end1); + prev->next_ = end1; + this->fix_buckets(bucket, prev, end); + return this->delete_nodes(pos, end); } - }; + node_pointer erase(node_pointer r) + { + BOOST_ASSERT(r); + node_pointer next = static_cast(r->next_); - template - struct multiset : public types< - typename allocator_traits::value_type, - typename allocator_traits::value_type, - H, P, A, - set_extractor::value_type>, - false> - { - typedef equivalent_table > impl; - typedef table > table_base; - }; + bucket_pointer bucket = this->get_bucket( + r->hash_ % this->bucket_count_); + previous_pointer prev = unlink_node(*bucket, r); - template - struct multimap : public types< - K, typename allocator_traits::value_type, - H, P, A, - map_extractor::value_type>, - false> - { - typedef equivalent_table > impl; - typedef table > table_base; + this->fix_buckets(bucket, prev, next); + + this->delete_node(r); + + return next; + } + + node_pointer erase_range(node_pointer r1, node_pointer r2) + { + if (r1 == r2) return r2; + + std::size_t bucket_index = r1->hash_ % this->bucket_count_; + previous_pointer prev = unlink_nodes( + *this->get_bucket(bucket_index), r1, r2); + this->fix_buckets_range(bucket_index, prev, r1, r2); + this->delete_nodes(r1, r2); + + return r2; + } + + static previous_pointer unlink_node(bucket& b, node_pointer n) + { + node_pointer next = static_cast(n->next_); + previous_pointer prev = static_cast(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 = static_cast(static_cast(prev->next_)->group_prev_); + } + + // Remove from group + if (next && next->group_prev_ == static_cast(n)) + { + next->group_prev_ = n->group_prev_; + } + } + else if (next && next->group_prev_ == static_cast(n)) + { + // The deleted node is not at the end of the group, so + // change the link from the next node. + next->group_prev_ = 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_pointer x = static_cast(n->group_prev_); + while(x->group_prev_ != static_cast(n)) { + x = static_cast(x->group_prev_); + } + x->group_prev_ = n->group_prev_; + } + + prev->next_ = static_cast(next); + return prev; + } + + static previous_pointer unlink_nodes(bucket& b, node_pointer begin, node_pointer end) + { + previous_pointer prev = static_cast(begin->group_prev_); + + if(prev->next_ != static_cast(begin)) { +std::cout << "A" << std::endl; + // The node is at the beginning of a group. + + // Find the previous node pointer: + prev = b.next_; + while(prev->next_ != static_cast(begin)) + prev = static_cast( + static_cast(prev->next_)->group_prev_); + + if (end) split_group(end); + } + else { +std::cout << "B" << std::endl; + node_pointer group1 = split_group(begin); + + if (end) { + node_pointer group2 = split_group(end); + + if(begin == group2) { + link_pointer end1 = group1->group_prev_; + link_pointer end2 = group2->group_prev_; + group1->group_prev_ = end2; + group2->group_prev_ = end1; + } + } + } + + prev->next_ = static_cast(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_pointer split_group(node_pointer split) + { + // Find first node in group. + node_pointer first = split; + while (static_cast(first->group_prev_)->next_ == static_cast(first)) + first = static_cast(first->group_prev_); + + if(first == split) return split; + + link_pointer last = first->group_prev_; + first->group_prev_ = split->group_prev_; + split->group_prev_ = last; + + return first; + } + + //////////////////////////////////////////////////////////////////////////// + // copy_buckets_to + // + // Basic exception safety. If an exception is thrown this will + // leave dst partially filled and the buckets unset. + + static void copy_buckets_to(buckets const& src, buckets& dst) + { + BOOST_ASSERT(!dst.buckets_); + + dst.create_buckets(); + + node_constructor a(dst.node_alloc()); + + node_pointer n = src.get_start(); + previous_pointer prev = dst.get_previous_start(); + + while(n) { + std::size_t hash = n->hash_; + node_pointer group_end = + static_cast( + static_cast(n->group_prev_)->next_); + + a.construct_node(); + a.construct_value2(n->value()); + + node_pointer first_node = a.release(); + node_pointer end = first_node; + first_node->hash_ = hash; + prev->next_ = static_cast(first_node); + ++dst.size_; + + for(n = static_cast(n->next_); n != group_end; + n = static_cast(n->next_)) + { + a.construct_node(); + a.construct_value2(n->value()); + end = a.release(); + end->hash_ = hash; + add_after_node(end, first_node); + ++dst.size_; + } + + prev = place_in_bucket(dst, prev, end); + } + } + + //////////////////////////////////////////////////////////////////////////// + // move_buckets_to + // + // Basic exception safety. The source nodes are left in an unusable state + // if an exception throws. + + static void move_buckets_to(buckets& src, buckets& dst) + { + BOOST_ASSERT(!dst.buckets_); + + dst.create_buckets(); + + node_constructor a(dst.node_alloc()); + + node_pointer n = src.get_start(); + previous_pointer prev = dst.get_previous_start(); + + while(n) { + std::size_t hash = n->hash_; + node_pointer group_end = + static_cast( + static_cast(n->group_prev_)->next_); + + a.construct_node(); + a.construct_value2(boost::move(n->value())); + + node_pointer first_node = a.release(); + node_pointer end = first_node; + first_node->hash_ = hash; + prev->next_ = static_cast(first_node); + ++dst.size_; + + for(n = static_cast(n->next_); n != group_end; + n = static_cast(n->next_)) + { + a.construct_node(); + a.construct_value2(boost::move(n->value())); + end = a.release(); + end->hash_ = hash; + add_after_node(end, first_node); + ++dst.size_; + } + + prev = place_in_bucket(dst, prev, end); + } + } + + // strong otherwise exception safety + void rehash_impl(std::size_t num_buckets) + { + BOOST_ASSERT(this->size_); + + buckets dst(this->node_alloc(), num_buckets); + dst.create_buckets(); + + previous_pointer src_start = this->get_previous_start(); + previous_pointer dst_start = dst.get_previous_start(); + + dst_start->next_ = src_start->next_; + src_start->next_ = link_pointer(); + dst.size_ = this->size_; + this->size_ = 0; + + previous_pointer prev = dst_start; + while (prev->next_) + prev = place_in_bucket(dst, prev, + static_cast( + static_cast(prev->next_)->group_prev_)); + + // Swap the new nodes back into the container and setup the + // variables. + dst.swap(*this); // no throw + } + + // Iterate through the nodes placing them in the correct buckets. + // pre: prev->next_ is not null. + static previous_pointer place_in_bucket(buckets& dst, previous_pointer prev, node_pointer end) + { + bucket_pointer b = dst.get_bucket(end->hash_ % dst.bucket_count_); + + if (!b->next_) { + b->next_ = static_cast(prev); + return static_cast(end); + } + else { + link_pointer next = end->next_; + end->next_ = b->next_->next_; + b->next_->next_ = prev->next_; + prev->next_ = next; + return prev; + } + } }; }}} diff --git a/include/boost/unordered/detail/table.hpp b/include/boost/unordered/detail/table.hpp index 9780d918..25db5c6f 100644 --- a/include/boost/unordered/detail/table.hpp +++ b/include/boost/unordered/detail/table.hpp @@ -8,117 +8,327 @@ #define BOOST_UNORDERED_DETAIL_ALL_HPP_INCLUDED #include +#include +#include +#include +#include +#include + +namespace boost { namespace unordered { namespace iterator_detail { + + //////////////////////////////////////////////////////////////////////////// + // Iterators + // + // all no throw + + template struct iterator; + template struct c_iterator; + template struct l_iterator; + template struct cl_iterator; + + // Local Iterators + // + // all no throw + + template + struct l_iterator + : public ::boost::iterator< + std::forward_iterator_tag, Value, std::ptrdiff_t, + NodePointer, Value&> + { +#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) + template + friend struct ::boost::unordered::iterator_detail::cl_iterator; + private: +#endif + typedef NodePointer node_pointer; + node_pointer ptr_; + std::size_t bucket_; + std::size_t bucket_count_; + + public: + + l_iterator() : ptr_() {} + + l_iterator(node_pointer x, std::size_t b, std::size_t c) + : ptr_(x), bucket_(b), bucket_count_(c) {} + + Value& operator*() const { + return ptr_->value(); + } + + Value* operator->() const { + return ptr_->value_ptr(); + } + + l_iterator& operator++() { + ptr_ = static_cast(ptr_->next_); + if (ptr_ && ptr_->hash_ % bucket_count_ != bucket_) + ptr_ = node_pointer(); + return *this; + } + + l_iterator operator++(int) { + l_iterator tmp(*this); + ++(*this); + return tmp; + } + + bool operator==(l_iterator x) const { + return ptr_ == x.ptr_; + } + + bool operator!=(l_iterator x) const { + return ptr_ != x.ptr_; + } + }; + + template + struct cl_iterator + : public ::boost::iterator< + std::forward_iterator_tag, Value, std::ptrdiff_t, + ConstNodePointer, Value const&> + { + friend struct ::boost::unordered::iterator_detail::l_iterator + ; + private: + + typedef NodePointer node_pointer; + node_pointer ptr_; + std::size_t bucket_; + std::size_t bucket_count_; + + public: + + cl_iterator() : ptr_() {} + + cl_iterator(node_pointer x, std::size_t b, std::size_t c) + : ptr_(x), bucket_(b), bucket_count_(c) {} + + cl_iterator(boost::unordered::iterator_detail::l_iterator const& x) + : ptr_(x.ptr_), bucket_(x.bucket_), bucket_count_(x.bucket_count_) + {} + + Value const& + operator*() const { + return ptr_->value(); + } + + Value const* operator->() const { + return ptr_->value_ptr(); + } + + cl_iterator& operator++() { + ptr_ = static_cast(ptr_->next_); + if (ptr_ && ptr_->hash_ % bucket_count_ != bucket_) + ptr_ = node_pointer(); + return *this; + } + + cl_iterator operator++(int) { + cl_iterator tmp(*this); + ++(*this); + return tmp; + } + + friend bool operator==(cl_iterator const& x, cl_iterator const& y) { + return x.ptr_ == y.ptr_; + } + + friend bool operator!=(cl_iterator const& x, cl_iterator const& y) { + return x.ptr_ != y.ptr_; + } + }; + + template + struct iterator + : public ::boost::iterator< + std::forward_iterator_tag, Value, std::ptrdiff_t, + NodePointer, Value&> + { +#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) + template + friend struct ::boost::unordered::iterator_detail::c_iterator; + private: +#endif + typedef NodePointer node_pointer; + node_pointer node_; + + public: + + iterator() : node_() {} + + explicit iterator(node_pointer const& x) : node_(x) {} + + Value& operator*() const { + return node_->value(); + } + + Value* operator->() const { + return &node_->value(); + } + + iterator& operator++() { + node_ = node_ = static_cast(node_->next_); return *this; + } + + iterator operator++(int) { + iterator tmp(node_); node_ = node_ = static_cast(node_->next_); return tmp; + } + + bool operator==(iterator const& x) const { + return node_ == x.node_; + } + + bool operator!=(iterator const& x) const { + return node_ != x.node_; + } + }; + + template + struct c_iterator + : public ::boost::iterator< + std::forward_iterator_tag, Value, std::ptrdiff_t, + ConstNodePointer, Value const&> + { + friend struct ::boost::unordered::iterator_detail::iterator; + +#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) + template + friend class ::boost::unordered::unordered_map; + template + friend class ::boost::unordered::unordered_multimap; + template + friend class ::boost::unordered::unordered_set; + template + friend class ::boost::unordered::unordered_multiset; + + private: +#endif + + typedef NodePointer node_pointer; + node_pointer node_; + + public: + + c_iterator() : node_() {} + + explicit c_iterator(node_pointer const& x) : node_(x) {} + + c_iterator(boost::unordered::iterator_detail::iterator const& x) : node_(x.node_) {} + + Value const& operator*() const { + return node_->value(); + } + + Value const* operator->() const { + return &node_->value(); + } + + c_iterator& operator++() { + node_ = static_cast(node_->next_); return *this; + } + + c_iterator operator++(int) { + c_iterator tmp(node_); node_ = node_ = static_cast(node_->next_); return tmp; + } + + friend bool operator==(c_iterator const& x, c_iterator const& y) { + return x.node_ == y.node_; + } + + friend bool operator!=(c_iterator const& x, c_iterator const& y) { + return x.node_ != y.node_; + } + }; +}}} namespace boost { namespace unordered { namespace detail { - // 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. + //////////////////////////////////////////////////////////////////////////// + // convert double to std::size_t - template - class table : public T::buckets, public T::functions + inline std::size_t double_to_size_t(double f) { - table(table const&); - table& operator=(table const&); - public: - typedef typename T::hasher hasher; - typedef typename T::key_equal key_equal; - typedef typename T::value_allocator value_allocator; - typedef typename T::key_type key_type; - typedef typename T::value_type value_type; - typedef typename T::functions functions; - typedef typename T::buckets buckets; - typedef typename T::extractor extractor; - typedef typename T::node_constructor node_constructor; + return f >= static_cast( + (std::numeric_limits::max)()) ? + (std::numeric_limits::max)() : + static_cast(f); + } - typedef typename T::node node; - typedef typename T::bucket bucket; - typedef typename T::node_ptr node_ptr; - typedef typename T::bucket_ptr bucket_ptr; - typedef typename T::node_allocator node_allocator; - typedef typename T::iterator_pair iterator_pair; + // The space used to store values in a node. - // Members - - float mlf_; - std::size_t max_load_; // Only use if this->buckets_. + template + struct value_base + { + typedef ValueType value_type; - // Helper methods + typename ::boost::aligned_storage< + sizeof(value_type), + ::boost::alignment_of::value>::type data_; - key_type const& get_key(value_type const& v) const { - return extractor::extract(v); + void* address() { + return this; + } + + value_type& value() { + return *(ValueType*) this; + } + + value_type* value_ptr() { + return (ValueType*) this; } 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 - { - 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); - } - } + value_base& operator=(value_base const&); + }; + + template + struct table : + ::boost::unordered::detail::buckets< + typename Types::allocator, + typename Types::bucket, + typename Types::node>, + ::boost::unordered::detail::functions< + typename Types::hasher, + typename Types::key_equal> + { + private: + table(table const&); + table& operator=(table const&); 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 this->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 this->find_node_impl(bucket_index, hash, k, this->key_eq()); - } + typedef typename Types::hasher hasher; + typedef typename Types::key_equal key_equal; + typedef typename Types::key_type key_type; + typedef typename Types::extractor extractor; + typedef typename Types::value_type value_type; + typedef typename Types::table table_impl; + typedef typename Types::link_pointer link_pointer; - node_ptr find_node(key_type const& k) const - { - if (!this->size_) return node_ptr(); - std::size_t hash = this->hash_function()(k); - return this->find_node_impl(hash % this->bucket_count_, hash, k, - this->key_eq()); - } + typedef ::boost::unordered::detail::functions< + typename Types::hasher, + typename Types::key_equal> functions; - 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))); - } + typedef ::boost::unordered::detail::buckets< + typename Types::allocator, + typename Types::bucket, + typename Types::node> buckets; + + typedef typename buckets::node_allocator node_allocator; + typedef typename buckets::node_allocator_traits node_allocator_traits; + typedef typename buckets::node_pointer node_pointer; + typedef typename buckets::const_node_pointer const_node_pointer; + + typedef ::boost::unordered::iterator_detail::iterator iterator; + typedef ::boost::unordered::iterator_detail::c_iterator c_iterator; + typedef ::boost::unordered::iterator_detail::l_iterator l_iterator; + typedef ::boost::unordered::iterator_detail::cl_iterator cl_iterator; + + // Members + + float mlf_; + std::size_t max_load_; // Only use if this->buckets_. //////////////////////////////////////////////////////////////////////// // Load methods @@ -128,7 +338,7 @@ namespace boost { namespace unordered { namespace detail { using namespace std; // size < mlf_ * count - return double_to_size_t(ceil( + return ::boost::unordered::detail::double_to_size_t(ceil( static_cast(this->mlf_) * static_cast(this->max_bucket_count()) )) - 1; @@ -140,18 +350,17 @@ namespace boost { namespace unordered { namespace detail { // From 6.3.1/13: // Only resize when size >= mlf_ * count - return double_to_size_t(ceil( + return ::boost::unordered::detail::double_to_size_t(ceil( static_cast(this->mlf_) * static_cast(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_)) + if (this->buckets_) this->max_load_ = this->calculate_max_load(); } @@ -167,9 +376,11 @@ namespace boost { namespace unordered { namespace detail { // // Or from rehash post-condition: // count > size / mlf_ - return next_prime(double_to_size_t(floor( - static_cast(size) / - static_cast(mlf_))) + 1); + + return ::boost::unordered::detail::next_prime( + ::boost::unordered::detail::double_to_size_t(floor( + static_cast(size) / + static_cast(mlf_))) + 1); } //////////////////////////////////////////////////////////////////////// @@ -178,75 +389,79 @@ namespace boost { namespace unordered { namespace detail { table(std::size_t num_buckets, hasher const& hf, key_equal const& eq, - node_allocator const& a) - : buckets(a, next_prime(num_buckets)), + node_allocator const& a) : + buckets(a, ::boost::unordered::detail::next_prime(num_buckets)), functions(hf, eq), mlf_(1.0f), max_load_(0) - { - } + {} - table(table const& x, node_allocator const& a) - : buckets(a, x.min_buckets_for_size(x.size_)), + table(table const& x, node_allocator const& a) : + buckets(a, x.min_buckets_for_size(x.size_)), functions(x), mlf_(x.mlf_), max_load_(0) { if(x.size_) { - x.copy_buckets_to(*this); + table_impl::copy_buckets_to(x, *this); this->max_load_ = calculate_max_load(); } } - table(table& x, move_tag m) - : buckets(x, m), + // TODO: Why calculate_max_load? + table(table& x, ::boost::unordered::detail::move_tag m) : + buckets(x, m), functions(x), mlf_(x.mlf_), - max_load_(calculate_max_load()) {} + max_load_(calculate_max_load()) + {} + // TODO: Why not calculate_max_load? // TODO: Why do I use x's bucket count? - table(table& x, node_allocator const& a, move_tag m) - : buckets(a, x.bucket_count_), + table(table& x, node_allocator const& a, + ::boost::unordered::detail::move_tag m) : + buckets(a, x.bucket_count_), functions(x), mlf_(x.mlf_), max_load_(x.max_load_) { if(a == x.node_alloc()) { - this->buckets::swap(x, false_type()); + this->buckets::swap(x, boost::unordered::detail::false_type()); } else if(x.size_) { // Use a temporary table because move_buckets_to leaves the // source container in a complete mess. + buckets tmp(x, m); - tmp.move_buckets_to(*this); + table_impl::move_buckets_to(tmp, *this); this->max_load_ = calculate_max_load(); } } - ~table() - {} - // Iterators - node_ptr begin() const { + node_pointer begin() const { return !this->buckets_ ? - node_ptr() : this->buckets_[this->bucket_count_].next_; + node_pointer() : this->get_start(); } + // Assignment + void assign(table const& x) { - assign(x, integral_constant:: - propagate_on_container_copy_assignment::value>()); + assign(x, + ::boost::unordered::detail::integral_constant:: + propagate_on_container_copy_assignment::value>()); } - void assign(table const& x, false_type) + void assign(table const& x, boost::unordered::detail::false_type) { table tmp(x, this->node_alloc()); - this->swap(tmp, false_type()); + this->swap(tmp, boost::unordered::detail::false_type()); } - void assign(table const& x, true_type) + void assign(table const& x, boost::unordered::detail::true_type) { table tmp(x, x.node_alloc()); // Need to delete before setting the allocator so that buckets @@ -254,24 +469,25 @@ namespace boost { namespace unordered { namespace detail { if(this->buckets_) this->delete_buckets(); // TODO: Can allocator assignment throw? this->allocators_.assign(x.allocators_); - this->swap(tmp, false_type()); + this->swap(tmp, boost::unordered::detail::false_type()); } void move_assign(table& x) { - move_assign(x, integral_constant:: - propagate_on_container_move_assignment::value>()); + move_assign(x, + ::boost::unordered::detail::integral_constant:: + propagate_on_container_move_assignment::value>()); } - - void move_assign(table& x, true_type) + + void move_assign(table& x, boost::unordered::detail::true_type) { if(this->buckets_) this->delete_buckets(); this->allocators_.move_assign(x.allocators_); move_assign_no_alloc(x); } - void move_assign(table& x, false_type) + void move_assign(table& x, boost::unordered::detail::false_type) { if(this->node_alloc() == x.node_alloc()) { if(this->buckets_) this->delete_buckets(); @@ -283,7 +499,7 @@ namespace boost { namespace unordered { namespace detail { if (x.size_) { buckets b(this->node_alloc(), x.min_buckets_for_size(x.size_)); buckets tmp(x, move_tag()); - tmp.move_buckets_to(b); + table_impl::move_buckets_to(tmp, b); b.swap(*this); } else { @@ -311,7 +527,8 @@ namespace boost { namespace unordered { namespace detail { void swap(table& x) { - swap(x, integral_constant:: propagate_on_container_swap::value>()); } @@ -339,110 +556,88 @@ namespace boost { namespace unordered { namespace detail { std::swap(this->max_load_, x.max_load_); } - //////////////////////////////////////////////////////////////////////// - // Key methods + // Accessors - std::size_t count(key_type const& k) const + key_type const& get_key(value_type const& x) const { - if(!this->size_) return 0; - return node::group_count(find_node(k)); + return extractor::extract(x); } - value_type& at(key_type const& k) const + // Find Node + + template + node_pointer generic_find_node( + Key const& k, + Hash const& hash_function, + Pred const& eq) 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.")); + if (!this->size_) return node_pointer(); + return static_cast(this)-> + find_node_impl(hash_function(k), k, eq); } - iterator_pair equal_range(key_type const& k) const + node_pointer find_node( + std::size_t hash, + 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)); + if (!this->size_) return node_pointer(); + return static_cast(this)-> + find_node_impl(hash, k, this->key_eq()); } - // Erase - // - // no throw - - std::size_t erase_key(key_type const& k) + node_pointer find_node(key_type const& k) const { - if(!this->size_) return 0; + if (!this->size_) return node_pointer(); + return static_cast(this)-> + find_node_impl(this->hash_function()(k), k, this->key_eq()); + } + + node_pointer find_matching_node(node_pointer n) const + { + // TODO: Does this apply to C++11? + // + // For some stupid reason, I decided to support equality comparison + // when different hash functions are used. So I can't use the hash + // value from the node here. - 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); - return this->delete_nodes(pos, end); + return find_node(get_key(n->value())); } // Reserve and rehash - bool reserve_for_insert(std::size_t); + void reserve_for_insert(std::size_t); void rehash(std::size_t); }; - + //////////////////////////////////////////////////////////////////////////// // Reserve & Rehash // basic exception safety - template - inline bool table::reserve_for_insert(std::size_t size) + template + inline void table::reserve_for_insert(std::size_t size) { 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_; + this->max_load_ = this->calculate_max_load(); } else 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_) { - this->rehash_impl(num_buckets); - this->max_load_ = calculate_max_load(); - return true; + static_cast(this)->rehash_impl(num_buckets); + this->max_load_ = this->calculate_max_load(); } } - - return false; } // if hash function throws, basic exception safety // strong otherwise. - template - void table::rehash(std::size_t min_buckets) + template + void table::rehash(std::size_t min_buckets) { using namespace std; @@ -451,306 +646,17 @@ namespace boost { namespace unordered { namespace detail { this->bucket_count_ = next_prime(min_buckets); } else { - // no throw: min_buckets = next_prime((std::max)(min_buckets, - double_to_size_t(floor( + ::boost::unordered::detail::double_to_size_t(floor( static_cast(this->size_) / static_cast(mlf_))) + 1)); + if(min_buckets != this->bucket_count_) { - this->rehash_impl(min_buckets); - this->max_load_ = calculate_max_load(); + static_cast(this)->rehash_impl(min_buckets); + this->max_load_ = this->calculate_max_load(); } } } - - //////////////////////////////////////////////////////////////////////////// - // - // 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 ::boost::unordered::detail::node_constructor node_constructor; - typedef ::boost::unordered::detail::buckets buckets; - typedef ::boost::unordered::detail::functions functions; - - typedef typename buckets::node node; - typedef typename buckets::bucket bucket; - typedef typename buckets::node_ptr node_ptr; - typedef typename buckets::bucket_ptr bucket_ptr; - typedef typename buckets::node_allocator node_allocator; - - typedef std::pair iterator_pair; - }; -}}} - -namespace boost { namespace unordered { namespace iterator_detail { - - // Iterators - // - // all no throw - - 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, - typename boost::unordered::detail::allocator_traits::value_type, - std::ptrdiff_t, - typename boost::unordered::detail::allocator_traits::pointer, - typename boost::unordered::detail::allocator_traits::value_type&> - { - public: - typedef typename boost::unordered::detail::allocator_traits::value_type value_type; - - private: - typedef ::boost::unordered::detail::buckets buckets; - typedef typename buckets::node_ptr node_ptr; - typedef 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) {} - typename boost::unordered::detail::allocator_traits::value_type& operator*() const { - return node::get_value(ptr_); - } - value_type* operator->() const { - return node::get_value_ptr(ptr_); - } - l_iterator& operator++() { - ptr_ = ptr_->next_; - if (ptr_ && node::get_hash(ptr_) % bucket_count_ != bucket_) - ptr_ = node_ptr(); - return *this; - } - 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_; - } - }; - - template - class cl_iterator - : public ::boost::iterator < - std::forward_iterator_tag, - typename boost::unordered::detail::allocator_traits::value_type, - std::ptrdiff_t, - typename boost::unordered::detail::allocator_traits::const_pointer, - typename boost::unordered::detail::allocator_traits::value_type const& > - { - public: - typedef typename boost::unordered::detail::allocator_traits::value_type value_type; - - private: - typedef ::boost::unordered::detail::buckets buckets; - typedef typename buckets::node_ptr node_ptr; - typedef 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_) - {} - typename boost::unordered::detail::allocator_traits::value_type const& - 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, - typename boost::unordered::detail::allocator_traits::value_type, - std::ptrdiff_t, - typename boost::unordered::detail::allocator_traits::pointer, - typename boost::unordered::detail::allocator_traits::value_type& > - { - public: - typedef typename boost::unordered::detail::allocator_traits::value_type value_type; - - private: - typedef ::boost::unordered::detail::buckets buckets; - typedef typename buckets::node node; - typedef 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) {} - typename boost::unordered::detail::allocator_traits::value_type& 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, - typename boost::unordered::detail::allocator_traits::value_type, - std::ptrdiff_t, - typename boost::unordered::detail::allocator_traits::const_pointer, - typename boost::unordered::detail::allocator_traits::value_type const& > - { - public: - typedef typename boost::unordered::detail::allocator_traits::value_type value_type; - - private: - typedef ::boost::unordered::detail::buckets buckets; - typedef typename buckets::node node; - typedef typename buckets::node_ptr node_ptr; - typedef ::boost::unordered::iterator_detail::iterator - iterator; - friend class ::boost::unordered::iterator_detail::iterator; - -#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) - template - friend class ::boost::unordered::unordered_map; - template - friend class ::boost::unordered::unordered_multimap; - template - friend class ::boost::unordered::unordered_set; - template - friend class ::boost::unordered::unordered_multiset; -#else - public: -#endif - - node_ptr node_; - - public: - - c_iterator() : node_() {} - explicit c_iterator(node_ptr const& x) : node_(x) {} - c_iterator(iterator const& x) : node_(x.node_) {} - typename boost::unordered::detail::allocator_traits::value_type const& 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 e0deb5f4..fa56592a 100644 --- a/include/boost/unordered/detail/unique.hpp +++ b/include/boost/unordered/detail/unique.hpp @@ -7,66 +7,277 @@ #ifndef BOOST_UNORDERED_DETAIL_UNIQUE_HPP_INCLUDED #define BOOST_UNORDERED_DETAIL_UNIQUE_HPP_INCLUDED +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include +#include #include +#include +#include namespace boost { namespace unordered { namespace detail { - template - class unique_table : public T::table_base - { - public: - typedef typename T::hasher hasher; - typedef typename T::key_equal key_equal; - typedef typename T::value_allocator value_allocator; - typedef typename T::key_type key_type; - typedef typename T::value_type value_type; - typedef typename T::table_base table_base; - typedef typename T::node_constructor node_constructor; - typedef typename T::node_allocator node_allocator; + template struct node; + template struct ptr_node; + template struct table_impl; - typedef typename T::node node; - typedef typename T::node_ptr node_ptr; - typedef typename T::bucket_ptr bucket_ptr; - typedef typename T::extractor extractor; - - typedef std::pair emplace_return; + template + struct node : + ::boost::unordered::detail::value_base + { + typedef VoidPointer link_pointer; + + link_pointer next_; + std::size_t hash_; + + node() : + next_(), + hash_(0) + {} + + void init(link_pointer) + { + } + }; + + template + struct ptr_node : + ::boost::unordered::detail::value_base, + ::boost::unordered::detail::ptr_bucket + { + typedef ::boost::unordered::detail::ptr_bucket bucket_base; + typedef ptr_bucket* link_pointer; + + std::size_t hash_; + + ptr_node() : + bucket_base(), + hash_(0) + {} + + void init(link_pointer) + { + } + }; + + // If the allocator uses raw pointers use ptr_node + // Otherwise use node. + + template + struct pick_node2 + { + typedef ::boost::unordered::detail::node node; + + typedef typename ::boost::unordered::detail::allocator_traits< + typename ::boost::unordered::detail::rebind_wrap::type + >::pointer node_pointer; + + typedef ::boost::unordered::detail::bucket bucket; + typedef VoidPointer link_pointer; + }; + + template + struct pick_node2*, + ::boost::unordered::detail::ptr_bucket*> + { + typedef ::boost::unordered::detail::ptr_node node; + typedef ::boost::unordered::detail::ptr_bucket bucket; + typedef bucket* link_pointer; + }; + + template + struct pick_node + { + typedef ::boost::unordered::detail::allocator_traits< + typename ::boost::unordered::detail::rebind_wrap >::type + > tentative_node_traits; + + typedef ::boost::unordered::detail::allocator_traits< + typename ::boost::unordered::detail::rebind_wrap::type + > tentative_bucket_traits; + + typedef pick_node2 pick; + + typedef typename pick::node node; + typedef typename pick::bucket bucket; + typedef typename pick::link_pointer link_pointer; + }; + + template + struct set + { + typedef set types; + + typedef A allocator; + typedef H hasher; + typedef P key_equal; + + typedef ::boost::unordered::detail::allocator_traits traits; + typedef typename traits::value_type value_type; + typedef typename traits::void_pointer void_pointer; + typedef value_type key_type; + + typedef typename ::boost::unordered::detail::pick_node::node node; + typedef typename ::boost::unordered::detail::pick_node::bucket bucket; + typedef typename ::boost::unordered::detail::pick_node::link_pointer link_pointer; + typedef ::boost::unordered::detail::table_impl table; + + typedef ::boost::unordered::detail::set_extractor extractor; + }; + + template + struct map + { + typedef map types; + + typedef A allocator; + typedef H hasher; + typedef P key_equal; + typedef K key_type; + + typedef ::boost::unordered::detail::allocator_traits traits; + typedef typename traits::value_type value_type; + typedef typename traits::void_pointer void_pointer; + + typedef typename ::boost::unordered::detail::pick_node::node node; + typedef typename ::boost::unordered::detail::pick_node::bucket bucket; + typedef typename ::boost::unordered::detail::pick_node::link_pointer link_pointer; + typedef ::boost::unordered::detail::table_impl table; + + typedef ::boost::unordered::detail::map_extractor extractor; + }; + + template + struct table_impl : ::boost::unordered::detail::table + { + typedef ::boost::unordered::detail::table table; + typedef typename table::value_type value_type; + typedef typename table::bucket bucket; + typedef typename table::buckets buckets; + typedef typename table::node_pointer node_pointer; + typedef typename table::node_allocator node_allocator; + typedef typename table::node_allocator_traits node_allocator_traits; + typedef typename table::bucket_pointer bucket_pointer; + typedef typename table::link_pointer link_pointer; + typedef typename table::previous_pointer previous_pointer; + typedef typename table::hasher hasher; + typedef typename table::key_equal key_equal; + typedef typename table::key_type key_type; + typedef typename table::node_constructor node_constructor; + typedef typename table::extractor extractor; + + typedef std::pair emplace_return; // Constructors - unique_table(std::size_t n, hasher const& hf, key_equal const& eq, - value_allocator const& a) - : table_base(n, hf, eq, a) {} - unique_table(unique_table const& x) - : table_base(x, - allocator_traits:: + table_impl(std::size_t n, + hasher const& hf, + key_equal const& eq, + node_allocator const& a) + : table(n, hf, eq, a) + {} + + table_impl(table_impl const& x) + : table(x, node_allocator_traits:: select_on_container_copy_construction(x.node_alloc())) {} - unique_table(unique_table const& x, value_allocator const& a) - : table_base(x, a) {} - unique_table(unique_table& x, move_tag m) - : table_base(x, m) {} - unique_table(unique_table& x, value_allocator const& a, - move_tag m) - : table_base(x, a, m) {} - ~unique_table() {} + + table_impl(table_impl const& x, + node_allocator const& a) + : table(x, a) + {} + + table_impl(table_impl& x, + ::boost::unordered::detail::move_tag m) + : table(x, m) + {} + + table_impl(table_impl& x, + node_allocator const& a, + ::boost::unordered::detail::move_tag m) + : table(x, a, m) + {} + + // Accessors + + template + node_pointer find_node_impl( + std::size_t hash, + Key const& k, + Pred const& eq) const + { + std::size_t bucket_index = hash % this->bucket_count_; + node_pointer n = this->get_start(bucket_index); + + for (;;) + { + if (!n) return n; + + std::size_t node_hash = n->hash_; + if (hash == node_hash) + { + if (eq(k, this->get_key(n->value()))) + return n; + } + else + { + if (node_hash % this->bucket_count_ != bucket_index) + return node_pointer(); + } + + n = static_cast(n->next_); + } + } + + std::size_t count(key_type const& k) const + { + return this->find_node(k) ? 1 : 0; + } + + value_type& at(key_type const& k) const + { + if (this->size_) { + node_pointer it = this->find_node(k); + if (it) return it->value(); + } + + ::boost::throw_exception( + std::out_of_range("Unable to find key in unordered_map.")); + } + + std::pair + equal_range(key_type const& k) const + { + node_pointer n = this->find_node(k); + return std::make_pair(n, + n ? static_cast(n->next_) : n); + } // equals - bool equals(unique_table const& other) const + bool equals(table_impl 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_) + for(node_pointer n1 = this->get_start(); n1; + n1 = static_cast(n1->next_)) { - node_ptr n2 = other.find_matching_node(n1); + node_pointer n2 = other.find_matching_node(n1); #if !defined(BOOST_UNORDERED_DEPRECATED_EQUALITY) - if(!n2 || node::get_value(n1) != node::get_value(n2)) + if(!n2 || n1->value() != n2->value()) return false; #else if(!n2 || !extractor::compare_mapped( - node::get_value(n1), node::get_value(n2))) + n1->value(), n2->value())) return false; #endif } @@ -74,247 +285,147 @@ namespace boost { namespace unordered { namespace detail { return true; } - //////////////////////////////////////////////////////////////////////// - // A convenience method for adding nodes. + // Emplace/Insert - node_ptr add_node( + inline node_pointer add_node( node_constructor& a, - std::size_t bucket_index, - std::size_t hash) + std::size_t hash) { - bucket_ptr b = this->get_bucket(bucket_index); - node_ptr n = a.release(); - node::set_hash(n, hash); + node_pointer n = a.release(); + n->hash_ = hash; + bucket_pointer b = this->get_bucket(hash % this->bucket_count_); + if (!b->next_) { - bucket_ptr start_node = this->get_bucket(this->bucket_count_); + previous_pointer start_node = this->get_previous_start(); if (start_node->next_) { - this->buckets_[ - node::get_hash(start_node->next_) % this->bucket_count_ - ].next_ = n; + this->get_bucket( + static_cast(start_node->next_)->hash_ % + this->bucket_count_)->next_ = n; } - + b->next_ = start_node; n->next_ = start_node->next_; - start_node->next_ = n; + start_node->next_ = static_cast(n); } else { n->next_ = b->next_->next_; - b->next_->next_ = n; + b->next_->next_ = static_cast(n); } - + ++this->size_; return n; } - //////////////////////////////////////////////////////////////////////////// - // Insert methods - - // if hash function throws, basic exception safety - // strong otherwise - value_type& operator[](key_type const& k) { typedef 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); + node_pointer pos = this->find_node(hash, k); - if (BOOST_UNORDERED_BORLAND_BOOL(pos)) { - return node::get_value(pos); - } + if (pos) return pos->value(); // 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); + node_constructor a(this->node_alloc()); + a.construct_node(); +#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE) + a.construct_value(boost::unordered::piecewise_construct, + boost::make_tuple(k), boost::make_tuple()); +#else + a.construct_value( + boost::unordered::detail::create_emplace_args( + boost::unordered::piecewise_construct, + boost::make_tuple(k), + boost::make_tuple())); +#endif - // 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)); + this->reserve_for_insert(this->size_ + 1); + return add_node(a, hash)->value(); } - 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); - } - - #if defined(BOOST_NO_RVALUE_REFERENCES) - emplace_return emplace(please_ignore_this_overload const&) + emplace_return emplace(::boost::unordered::detail::emplace_args1< + ::boost::unordered::detail::please_ignore_this_overload> const&) { BOOST_ASSERT(false); return emplace_return(this->begin(), false); } #endif -#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE) - - template - emplace_return emplace(Args&&... args) + template + emplace_return emplace(BOOST_UNORDERED_EMPLACE_ARGS) { +#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE) return emplace_impl( - extractor::extract(std::forward(args)...), - std::forward(args)...); + extractor::extract(BOOST_UNORDERED_EMPLACE_FORWARD), + BOOST_UNORDERED_EMPLACE_FORWARD); + +#else + return emplace_impl( + extractor::extract(args.a0, args.a1), + BOOST_UNORDERED_EMPLACE_FORWARD); +#endif } - template - emplace_return emplace_impl(key_type const& k, Args&&... args) +#if !defined(BOOST_UNORDERED_STD_FORWARD_MOVE) + template + emplace_return emplace( + boost::unordered::detail::emplace_args1 const& args) + { + return emplace_impl(extractor::extract(args.a0), args); + } +#endif + + template + emplace_return emplace_impl(key_type const& k, + BOOST_UNORDERED_EMPLACE_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); + node_pointer pos = this->find_node(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. + if (pos) return emplace_return(pos, false); // 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)...); + node_constructor a(this->node_alloc()); + a.construct_node(); + a.construct_value(BOOST_UNORDERED_EMPLACE_FORWARD); // 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); + this->reserve_for_insert(this->size_ + 1); + return emplace_return(this->add_node(a, hash), true); } - template - emplace_return emplace_impl(no_key, Args&&... args) + emplace_return emplace_impl_with_node(node_constructor& a) { - // 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)...); + key_type const& k = this->get_key(a.value()); + std::size_t hash = this->hash_function()(k); + node_pointer pos = this->find_node(hash, k); + + if (pos) return emplace_return(pos, false); + + // reserve has basic exception safety if the hash function + // throws, strong otherwise. + this->reserve_for_insert(this->size_ + 1); + return emplace_return(this->add_node(a, hash), true); + } + + template + emplace_return emplace_impl(no_key, BOOST_UNORDERED_EMPLACE_ARGS) + { + // Don't have a key, so construct the node first in order + // to be able to lookup the position. + node_constructor a(this->node_alloc()); + a.construct_node(); + a.construct_value(BOOST_UNORDERED_EMPLACE_FORWARD); return emplace_impl_with_node(a); } -#else - - template - emplace_return emplace(BOOST_FWD_REF(Arg0) arg0) - { - return emplace_impl( - extractor::extract(boost::forward(arg0)), - boost::forward(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_INSERT2_IMPL, _) - -#undef BOOST_UNORDERED_INSERT1_IMPL -#undef BOOST_UNORDERED_INSERT2_IMPL - -#endif //////////////////////////////////////////////////////////////////////// // Insert range methods @@ -330,14 +441,14 @@ namespace boost { namespace unordered { namespace detail { } template - void insert_range_impl(key_type const&, InputIt i, InputIt j) + void insert_range_impl(key_type const& k, InputIt i, InputIt j) { - node_constructor a(*this); + node_constructor a(this->node_alloc()); // Special case for empty buckets so that we can use // max_load_ (which isn't valid when buckets_ is null). if (!this->buckets_) { - insert_range_empty(a, extractor::extract(*i), i, j); + insert_range_empty(a, k, i, j); if (++i == j) return; } @@ -358,9 +469,11 @@ namespace boost { namespace unordered { namespace detail { InputIt i, InputIt j) { std::size_t hash = this->hash_function()(k); - a.construct(*i); - this->reserve_for_insert(this->size_ + insert_size(i, j)); - add_node(a, hash % this->bucket_count_, hash); + a.construct_node(); + a.construct_value2(*i); + this->reserve_for_insert(this->size_ + + ::boost::unordered::detail::insert_size(i, j)); + this->add_node(a, hash); } template @@ -369,63 +482,216 @@ namespace boost { namespace unordered { namespace detail { { // 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); + node_pointer pos = this->find_node(hash, k); - if (!BOOST_UNORDERED_BORLAND_BOOL(pos)) { - // Doesn't already exist, add to bucket. - // Side effects only in this block. + if (!pos) { + a.construct_node(); + a.construct_value2(*i); - // 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_; - } + if(this->size_ + 1 >= this->max_load_) + this->reserve_for_insert(this->size_ + + ::boost::unordered::detail::insert_size(i, j)); // Nothing after this point can throw. - add_node(a, bucket_index, hash); + this->add_node(a, hash); } } template void insert_range_impl(no_key, InputIt i, InputIt j) { - node_constructor a(*this); + node_constructor a(this->node_alloc()); do { - // No side effects in this initial code - a.construct(*i); + a.construct_node(); + a.construct_value2(*i); emplace_impl_with_node(a); } while(++i != j); } - }; - template - struct set : public types< - typename allocator_traits::value_type, - typename allocator_traits::value_type, - H, P, A, - set_extractor::value_type>, - true> - { - typedef ::boost::unordered::detail::unique_table > impl; - typedef ::boost::unordered::detail::table > table_base; - }; + //////////////////////////////////////////////////////////////////////////// + // Erase + // + // no throw - template - struct map : public types< - K, typename allocator_traits::value_type, - H, P, A, - map_extractor::value_type>, - true> - { - typedef ::boost::unordered::detail::unique_table > impl; - typedef ::boost::unordered::detail::table > table_base; + 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_pointer bucket = this->get_bucket(bucket_index); + + previous_pointer prev = bucket->next_; + if (!prev) return 0; + + for (;;) + { + if (!prev->next_) return 0; + std::size_t node_hash = static_cast(prev->next_)->hash_; + if (node_hash % this->bucket_count_ != bucket_index) + return 0; + if (node_hash == hash && + this->key_eq()(k, this->get_key(static_cast(prev->next_)->value()))) + break; + prev = static_cast(prev->next_); + } + + node_pointer pos = static_cast(prev->next_); + node_pointer end = static_cast(pos->next_); + prev->next_ = pos->next_; + this->fix_buckets(bucket, prev, end); + return this->delete_nodes(pos, end); + } + + node_pointer erase(node_pointer r) + { + BOOST_ASSERT(r); + node_pointer next = static_cast(r->next_); + + bucket_pointer bucket = this->get_bucket( + r->hash_ % this->bucket_count_); + previous_pointer prev = unlink_node(*bucket, r); + + this->fix_buckets(bucket, prev, next); + + this->delete_node(r); + + return next; + } + + node_pointer erase_range(node_pointer r1, node_pointer r2) + { + if (r1 == r2) return r2; + + std::size_t bucket_index = r1->hash_ % this->bucket_count_; + previous_pointer prev = unlink_nodes( + *this->get_bucket(bucket_index), r1, r2); + this->fix_buckets_range(bucket_index, prev, r1, r2); + this->delete_nodes(r1, r2); + + return r2; + } + + static previous_pointer unlink_node(bucket& b, node_pointer n) + { + return unlink_nodes(b, n, static_cast(n->next_)); + } + + static previous_pointer unlink_nodes(bucket& b, node_pointer begin, node_pointer end) + { + previous_pointer prev = b.next_; + link_pointer begin_void = static_cast(begin); + while(prev->next_ != begin_void) prev = static_cast(prev->next_); + prev->next_ = static_cast(end); + return prev; + } + + //////////////////////////////////////////////////////////////////////////// + // copy_buckets_to + // + // Basic exception safety. If an exception is thrown this will + // leave dst partially filled and the buckets unset. + + static void copy_buckets_to(buckets const& src, buckets& dst) + { + BOOST_ASSERT(!dst.buckets_); + + dst.create_buckets(); + + node_constructor a(dst.node_alloc()); + + node_pointer n = src.get_start(); + previous_pointer prev = dst.get_previous_start(); + + while(n) { + a.construct_node(); + a.construct_value2(n->value()); + + node_pointer node = a.release(); + node->hash_ = n->hash_; + prev->next_ = static_cast(node); + ++dst.size_; + n = static_cast(n->next_); + + prev = place_in_bucket(dst, prev); + } + } + + //////////////////////////////////////////////////////////////////////////// + // move_buckets_to + // + // Basic exception safety. The source nodes are left in an unusable state + // if an exception throws. + + static void move_buckets_to(buckets& src, buckets& dst) + { + BOOST_ASSERT(!dst.buckets_); + + dst.create_buckets(); + + node_constructor a(dst.node_alloc()); + + node_pointer n = src.get_start(); + previous_pointer prev = dst.get_previous_start(); + + while(n) { + a.construct_node(); + a.construct_value2(boost::move(n->value())); + + node_pointer node = a.release(); + node->hash_ = n->hash_; + prev->next_ = static_cast(node); + ++dst.size_; + n = static_cast(n->next_); + + prev = place_in_bucket(dst, prev); + } + } + + // strong otherwise exception safety + void rehash_impl(std::size_t num_buckets) + { + BOOST_ASSERT(this->size_); + + buckets dst(this->node_alloc(), num_buckets); + dst.create_buckets(); + + previous_pointer src_start = this->get_previous_start(); + previous_pointer dst_start = dst.get_previous_start(); + + dst_start->next_ = src_start->next_; + src_start->next_ = link_pointer(); + dst.size_ = this->size_; + this->size_ = 0; + + previous_pointer prev = dst.get_previous_start(); + while (prev->next_) + prev = place_in_bucket(dst, prev); + + // Swap the new nodes back into the container and setup the + // variables. + dst.swap(*this); // no throw + } + + // Iterate through the nodes placing them in the correct buckets. + // pre: prev->next_ is not null. + static previous_pointer place_in_bucket(buckets& dst, previous_pointer prev) + { + node_pointer n = static_cast(prev->next_); + bucket_pointer b = dst.get_bucket(n->hash_ % dst.bucket_count_); + + if (!b->next_) { + b->next_ = prev; + return static_cast(n); + } + else { + prev->next_ = n->next_; + n->next_ = b->next_->next_; + b->next_->next_ = static_cast(n); + return prev; + } + } }; }}} diff --git a/include/boost/unordered/detail/util.hpp b/include/boost/unordered/detail/util.hpp index fa0dd552..250b7808 100644 --- a/include/boost/unordered/detail/util.hpp +++ b/include/boost/unordered/detail/util.hpp @@ -7,156 +7,50 @@ #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 -#if defined(BOOST_NO_RVALUE_REFERENCES) -#include +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once #endif -#include + +#include +#include +#include +#include +#include #include -#include #include #include -#include -#include -#include -#include -#include -#if !defined(BOOST_NO_0X_HDR_TUPLE) || defined(BOOST_HAS_TR1_TUPLE) -#include -#endif -#include - -// 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) -# elif defined(__STD_RWCOMPILER_H__) || defined(_RWSTD_VER) -# elif defined(_LIBCPP_VERSION) -# define BOOST_UNORDERED_STD_FORWARD_MOVE -# elif defined(__GLIBCPP__) || defined(__GLIBCXX__) -# if defined(__GLIBCXX__) && __GLIBCXX__ >= 20090804 -# define BOOST_UNORDERED_STD_FORWARD_MOVE -# endif -# elif defined(__STL_CONFIG_H) -# elif defined(__MSL_CPP__) -# elif defined(__IBMCPP__) -# elif defined(MSIPL_COMPILE_H) -# elif (defined(_YVALS) && !defined(__IBMCPP__)) || defined(_CPPLIB_VER) - // Visual C++. A version check would be a good idea. -# define BOOST_UNORDERED_STD_FORWARD_MOVE -# endif -#endif - -#if !defined(BOOST_UNORDERED_EMPLACE_LIMIT) -#define BOOST_UNORDERED_EMPLACE_LIMIT 10 -#endif - -#if defined(__SUNPRO_CC) -#define BOOST_UNORDERED_USE_RV_REF 0 -#else -#define BOOST_UNORDERED_USE_RV_REF 1 -#endif - -#if !defined(BOOST_UNORDERED_STD_FORWARD_MOVE) - -#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_##z(num_params, BOOST_UNORDERED_FUNCTION_PARAMS2, _) -#define BOOST_UNORDERED_FUNCTION_PARAMS2(z, i, _) \ - BOOST_FWD_REF(Arg##i) arg##i - -#define BOOST_UNORDERED_CALL_PARAMS(z, num_params) \ - BOOST_PP_ENUM_##z(num_params, BOOST_UNORDERED_CALL_PARAMS2, _) -#define BOOST_UNORDERED_CALL_PARAMS2(z, i, _) \ - boost::forward(arg##i) - -#endif +#include 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 {}; - struct empty_emplace {}; - template class unique_table; - template class equivalent_table; - template class node_constructor; - template - struct set_extractor; - template - struct map_extractor; - struct no_key; + //////////////////////////////////////////////////////////////////////////// + // iterator SFINAE -#if !defined(BOOST_NO_RVALUE_REFERENCES) - -#define BOOST_UNORDERED_RV_REF(T) BOOST_RV_REF(T) - -#else - - struct please_ignore_this_overload { - typedef please_ignore_this_overload type; - }; - - template - struct rv_ref_impl { - typedef BOOST_RV_REF(T) type; - }; - - template - struct rv_ref : - boost::detail::if_true< - boost::is_class::value - >::BOOST_NESTED_TEMPLATE then < - rv_ref_impl, - please_ignore_this_overload - >::type + template + struct is_forward : + ::boost::is_convertible< + typename ::boost::iterator_traversal::type, + ::boost::forward_traversal_tag> {}; -#define BOOST_UNORDERED_RV_REF(T) \ - typename ::boost::unordered::detail::rv_ref::type + template + struct enable_if_forward : + ::boost::enable_if_c< + ::boost::unordered::detail::is_forward::value, + ReturnType> + {}; -#endif - - //////////////////////////////////////////////////////////////////////////// - // convert double to std::size_t - - inline std::size_t double_to_size_t(double f) - { - return f >= static_cast( - (std::numeric_limits::max)()) ? - (std::numeric_limits::max)() : - static_cast(f); - } + template + struct disable_if_forward : + ::boost::disable_if_c< + ::boost::unordered::detail::is_forward::value, + ReturnType> + {}; //////////////////////////////////////////////////////////////////////////// // primes @@ -225,45 +119,48 @@ namespace boost { namespace unordered { namespace detail { // insert_size/initial_size #if !defined(BOOST_NO_STD_DISTANCE) + using ::std::distance; + #else + template inline std::size_t distance(ForwardIterator i, ForwardIterator j) { std::size_t x; std::distance(i, j, x); return x; } + #endif template - inline std::size_t insert_size(I i, I j, ::boost::forward_traversal_tag) + inline typename + ::boost::unordered::detail::enable_if_forward::type + insert_size(I i, I j) { return std::distance(i, j); } template - inline std::size_t insert_size(I, I, ::boost::incrementable_traversal_tag) + inline typename + ::boost::unordered::detail::disable_if_forward::type + insert_size(I, I) { return 1; } - template - inline std::size_t insert_size(I i, I j) - { - return insert_size(i, j, - typename ::boost::iterator_traversal::type()); - } - template inline std::size_t initial_size(I i, I j, std::size_t num_buckets = ::boost::unordered::detail::default_bucket_count) { - return (std::max)(static_cast(insert_size(i, j)) + 1, + // TODO: Why +1? + return (std::max)( + ::boost::unordered::detail::insert_size(i, j) + 1, num_buckets); } //////////////////////////////////////////////////////////////////////////// - // compressed_pair + // compressed template struct compressed_base : private T @@ -298,7 +195,7 @@ namespace boost { namespace unordered { namespace detail { {}; template - struct compressed_pair + struct compressed : private generate_base::type, private generate_base::type { @@ -325,28 +222,28 @@ namespace boost { namespace unordered { namespace detail { } template - compressed_pair(First const& x1, Second const& x2) + compressed(First const& x1, Second const& x2) : base1(x1), base2(x2) {} - compressed_pair(compressed_pair const& x) + compressed(compressed const& x) : base1(x.first()), base2(x.second()) {} - compressed_pair(compressed_pair& x, move_tag m) + compressed(compressed& x, move_tag m) : base1(x.first(), m), base2(x.second(), m) {} - void assign(compressed_pair const& x) + void assign(compressed const& x) { first() = x.first(); second() = x.second(); } - void move_assign(compressed_pair& x) + void move_assign(compressed& x) { first() = boost::move(x.first()); second() = boost::move(x.second()); } - void swap(compressed_pair& x) + void swap(compressed& x) { boost::swap(first(), x.first()); boost::swap(second(), x.second()); @@ -355,7 +252,7 @@ namespace boost { namespace unordered { namespace detail { private: // Prevent assignment just to make use of assign or // move_assign explicit. - compressed_pair& operator=(compressed_pair const&); + compressed& operator=(compressed const&); }; }}} diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index aa261e88..7335c0d7 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -14,10 +14,12 @@ #endif #include -#include #include #include #include +#include +#include +#include #if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) #include @@ -40,7 +42,9 @@ namespace unordered class unordered_map { BOOST_COPYABLE_AND_MOVABLE(unordered_map) + public: + typedef K key_type; typedef std::pair value_type; typedef T mapped_type; @@ -48,20 +52,18 @@ namespace unordered typedef P key_equal; typedef A allocator_type; -#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) private: -#endif typedef typename ::boost::unordered::detail::rebind_wrap< allocator_type, value_type>::type value_allocator; - typedef ::boost::unordered::detail::allocator_traits allocator_traits; - typedef ::boost::unordered::detail::map types; - typedef typename types::impl table; + typedef ::boost::unordered::detail::allocator_traits + allocator_traits; - typedef typename types::node_ptr node_ptr; + typedef ::boost::unordered::detail::map + types; + typedef typename types::table table; public: @@ -74,24 +76,18 @@ namespace unordered typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; - 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; + typedef typename table::cl_iterator const_local_iterator; + typedef typename table::l_iterator local_iterator; + typedef typename table::c_iterator const_iterator; + typedef typename table::iterator iterator; -#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) private: -#endif table table_; public: - // construct/destroy/copy + // constructors explicit unordered_map( size_type = ::boost::unordered::detail::default_bucket_count, @@ -101,17 +97,15 @@ namespace unordered explicit unordered_map(allocator_type const&); - unordered_map(unordered_map const&, allocator_type const&); - template - unordered_map(InputIt f, InputIt l); + unordered_map(InputIt, InputIt); template unordered_map( InputIt, InputIt, size_type, const hasher& = hasher(), - const key_equal& = key_equal()); + const key_equal& = key_equal()); template unordered_map( @@ -120,23 +114,12 @@ namespace unordered const hasher&, const key_equal&, const allocator_type&); - - ~unordered_map(); - unordered_map& operator=( - BOOST_COPY_ASSIGN_REF(unordered_map) x) - { - table_.assign(x.table_); - return *this; - } + // copy/move constructors unordered_map(unordered_map const&); - unordered_map& operator=(BOOST_RV_REF(unordered_map) x) - { - table_.move_assign(x.table_); - return *this; - } + unordered_map(unordered_map const&, allocator_type const&); unordered_map(BOOST_RV_REF(unordered_map) other) : table_(other.table_, ::boost::unordered::detail::move_tag()) @@ -154,7 +137,27 @@ namespace unordered const hasher& = hasher(), const key_equal&l = key_equal(), const allocator_type& = allocator_type()); +#endif + // Destructor + + ~unordered_map(); + + // Assign + + unordered_map& operator=(BOOST_COPY_ASSIGN_REF(unordered_map) x) + { + table_.assign(x.table_); + return *this; + } + + unordered_map& operator=(BOOST_RV_REF(unordered_map) x) + { + table_.move_assign(x.table_); + return *this; + } + +#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) unordered_map& operator=(std::initializer_list); #endif @@ -209,54 +212,98 @@ namespace unordered return const_iterator(); } - // modifiers + // emplace #if defined(BOOST_UNORDERED_STD_FORWARD_MOVE) template - std::pair emplace(Args&&...); + std::pair emplace(Args&&... args) + { + return table_.emplace(std::forward(args)...); + } + template - iterator emplace_hint(const_iterator, Args&&...); + iterator emplace_hint(const_iterator, Args&&... args) + { + return iterator(table_.emplace(std::forward(args)...).first); + } #else -#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100)) - std::pair emplace( - boost::unordered::detail::empty_emplace - = boost::unordered::detail::empty_emplace(), - value_type v = value_type() - ); - iterator emplace_hint(const_iterator, - boost::unordered::detail::empty_emplace - = boost::unordered::detail::empty_emplace(), - value_type v = value_type() - ); -#endif +#define BOOST_UNORDERED_EMPLACE(z, n, _) \ + template < \ + BOOST_PP_ENUM_PARAMS_Z(z, n, typename A) \ + > \ + std::pair emplace( \ + BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a) \ + ) \ + { \ + return table_.emplace( \ + ::boost::unordered::detail::create_emplace_args( \ + BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, \ + a) \ + )); \ + } \ + \ + template < \ + BOOST_PP_ENUM_PARAMS_Z(z, n, typename A) \ + > \ + iterator emplace_hint( \ + const_iterator, \ + BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a) \ + ) \ + { \ + return iterator(table_.emplace( \ + ::boost::unordered::detail::create_emplace_args( \ + BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, \ + a) \ + )).first); \ + } -#define BOOST_UNORDERED_EMPLACE(z, n, _) \ - template < \ - BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ - > \ - std::pair emplace( \ - BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ - ); \ - \ - template < \ - BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ - > \ - iterator emplace_hint(const_iterator, \ - BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ - ); - - BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, - BOOST_UNORDERED_EMPLACE, _) + BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, BOOST_UNORDERED_EMPLACE, _) #undef BOOST_UNORDERED_EMPLACE +#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100)) + + std::pair emplace( + boost::unordered::detail::empty_emplace + = boost::unordered::detail::empty_emplace(), + value_type v = value_type()) + { + return this->emplace(boost::move(v)); + } + + iterator emplace_hint(const_iterator hint, + boost::unordered::detail::empty_emplace + = boost::unordered::detail::empty_emplace(), + value_type v = value_type() + ) + { + return this->emplace_hint(hint, boost::move(v)); + } + #endif - std::pair insert(value_type const&); - std::pair insert(BOOST_RV_REF(value_type)); - iterator insert(const_iterator, value_type const&); - iterator insert(const_iterator, BOOST_RV_REF(value_type)); +#endif + + std::pair insert(value_type const& x) + { + return this->emplace(x); + } + + std::pair insert(BOOST_RV_REF(value_type) x) + { + return this->emplace(boost::move(x)); + } + + iterator insert(const_iterator hint, value_type const& x) + { + return this->emplace_hint(hint, x); + } + + iterator insert(const_iterator hint, BOOST_RV_REF(value_type) x) + { + return this->emplace_hint(hint, boost::move(x)); + } template void insert(InputIt, InputIt); @@ -320,7 +367,7 @@ namespace unordered return table_.max_bucket_count(); } - size_type bucket_size(size_type n) const; + size_type bucket_size(size_type) const; size_type bucket(const key_type& k) const { @@ -329,14 +376,16 @@ namespace unordered local_iterator begin(size_type n) { - return local_iterator( - table_.bucket_begin(n), n, table_.bucket_count_); + return table_.size_ ? local_iterator( + table_.get_start(n), n, table_.bucket_count_) : + local_iterator(); } const_local_iterator begin(size_type n) const { - return const_local_iterator( - table_.bucket_begin(n), n, table_.bucket_count_); + return table_.size_ ? const_local_iterator( + table_.get_start(n), n, table_.bucket_count_) : + const_local_iterator(); } local_iterator end(size_type) @@ -351,8 +400,9 @@ namespace unordered const_local_iterator cbegin(size_type n) const { - return const_local_iterator( - table_.bucket_begin(n), n, table_.bucket_count_); + return table_.size_ ? const_local_iterator( + table_.get_start(n), n, table_.bucket_count_) : + const_local_iterator(); } const_local_iterator cend(size_type) const @@ -369,7 +419,7 @@ namespace unordered float load_factor() const; void max_load_factor(float); - void rehash(size_type n); + void rehash(size_type); #if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) friend bool operator==( @@ -383,6 +433,7 @@ namespace unordered class unordered_multimap { BOOST_COPYABLE_AND_MOVABLE(unordered_multimap) + public: typedef K key_type; @@ -392,21 +443,18 @@ namespace unordered typedef P key_equal; typedef A allocator_type; -#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) private: -#endif typedef typename ::boost::unordered::detail::rebind_wrap< allocator_type, value_type>::type value_allocator; + typedef ::boost::unordered::detail::allocator_traits allocator_traits; - typedef ::boost::unordered::detail::multimap types; - typedef typename types::impl table; - - typedef typename types::node_ptr node_ptr; + typedef ::boost::unordered::detail::multimap + types; + typedef typename types::table table; public: @@ -419,24 +467,18 @@ namespace unordered typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; - 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; + typedef typename table::cl_iterator const_local_iterator; + typedef typename table::l_iterator local_iterator; + typedef typename table::c_iterator const_iterator; + typedef typename table::iterator iterator; -#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) private: -#endif table table_; public: - // construct/destroy/copy + // constructors explicit unordered_multimap( size_type = ::boost::unordered::detail::default_bucket_count, @@ -446,8 +488,6 @@ namespace unordered explicit unordered_multimap(allocator_type const&); - unordered_multimap(unordered_multimap const&, allocator_type const&); - template unordered_multimap(InputIt, InputIt); @@ -466,22 +506,11 @@ namespace unordered const key_equal&, const allocator_type&); - ~unordered_multimap(); - - unordered_multimap& operator=( - BOOST_COPY_ASSIGN_REF(unordered_multimap) x) - { - table_.assign(x.table_); - return *this; - } + // copy/move constructors unordered_multimap(unordered_multimap const&); - unordered_multimap& operator=(BOOST_RV_REF(unordered_multimap) x) - { - table_.move_assign(x.table_); - return *this; - } + unordered_multimap(unordered_multimap const&, allocator_type const&); unordered_multimap(BOOST_RV_REF(unordered_multimap) other) : table_(other.table_, ::boost::unordered::detail::move_tag()) @@ -499,7 +528,27 @@ namespace unordered const hasher& = hasher(), const key_equal&l = key_equal(), const allocator_type& = allocator_type()); +#endif + // Destructor + + ~unordered_multimap(); + + // Assign + + unordered_multimap& operator=(BOOST_COPY_ASSIGN_REF(unordered_multimap) x) + { + table_.assign(x.table_); + return *this; + } + + unordered_multimap& operator=(BOOST_RV_REF(unordered_multimap) x) + { + table_.move_assign(x.table_); + return *this; + } + +#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) unordered_multimap& operator=(std::initializer_list); #endif @@ -554,54 +603,98 @@ namespace unordered return const_iterator(); } - // modifiers + // emplace #if defined(BOOST_UNORDERED_STD_FORWARD_MOVE) template - iterator emplace(Args&&...); + iterator emplace(Args&&... args) + { + return iterator(table_.emplace(std::forward(args)...)); + } + template - iterator emplace_hint(const_iterator, Args&&...); + iterator emplace_hint(const_iterator, Args&&... args) + { + return iterator(table_.emplace(std::forward(args)...)); + } #else -#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100)) - iterator emplace( - boost::unordered::detail::empty_emplace - = boost::unordered::detail::empty_emplace(), - value_type v = value_type() - ); - iterator emplace_hint(const_iterator, - boost::unordered::detail::empty_emplace - = boost::unordered::detail::empty_emplace(), - value_type v = value_type() - ); -#endif +#define BOOST_UNORDERED_EMPLACE(z, n, _) \ + template < \ + BOOST_PP_ENUM_PARAMS_Z(z, n, typename A) \ + > \ + iterator emplace( \ + BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a) \ + ) \ + { \ + return iterator(table_.emplace( \ + ::boost::unordered::detail::create_emplace_args( \ + BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, \ + a) \ + ))); \ + } \ + \ + template < \ + BOOST_PP_ENUM_PARAMS_Z(z, n, typename A) \ + > \ + iterator emplace_hint( \ + const_iterator, \ + BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a) \ + ) \ + { \ + return iterator(table_.emplace( \ + ::boost::unordered::detail::create_emplace_args( \ + BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, \ + a) \ + ))); \ + } -#define BOOST_UNORDERED_EMPLACE(z, n, _) \ - template < \ - BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ - > \ - iterator emplace( \ - BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ - ); \ - \ - template < \ - BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ - > \ - iterator emplace_hint(const_iterator, \ - BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ - ); - - BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, - BOOST_UNORDERED_EMPLACE, _) + BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, BOOST_UNORDERED_EMPLACE, _) #undef BOOST_UNORDERED_EMPLACE +#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100)) + + iterator emplace( + boost::unordered::detail::empty_emplace + = boost::unordered::detail::empty_emplace(), + value_type v = value_type()) + { + return iterator(this->emplace(boost::move(v))); + } + + iterator emplace_hint(const_iterator hint, + boost::unordered::detail::empty_emplace + = boost::unordered::detail::empty_emplace(), + value_type v = value_type() + ) + { + return iterator(this->emplace_hint(hint, boost::move(v))); + } + #endif - iterator insert(value_type const&); - iterator insert(BOOST_RV_REF(value_type)); - iterator insert(const_iterator, value_type const&); - iterator insert(const_iterator, BOOST_RV_REF(value_type)); +#endif + + iterator insert(value_type const& x) + { + return this->emplace(x); + } + + iterator insert(BOOST_RV_REF(value_type) x) + { + return this->emplace(boost::move(x)); + } + + iterator insert(const_iterator hint, value_type const& x) + { + return this->emplace_hint(hint, x); + } + + iterator insert(const_iterator hint, BOOST_RV_REF(value_type) x) + { + return this->emplace_hint(hint, boost::move(x)); + } template void insert(InputIt, InputIt); @@ -612,8 +705,8 @@ namespace unordered 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); } + void quick_erase(const_iterator it) { erase(it); } + void erase_return_void(const_iterator it) { erase(it); } void clear(); void swap(unordered_multimap&); @@ -670,14 +763,16 @@ namespace unordered local_iterator begin(size_type n) { - return local_iterator( - table_.bucket_begin(n), n, table_.bucket_count_); + return table_.size_ ? local_iterator( + table_.get_start(n), n, table_.bucket_count_) : + local_iterator(); } const_local_iterator begin(size_type n) const { - return const_local_iterator( - table_.bucket_begin(n), n, table_.bucket_count_); + return table_.size_ ? const_local_iterator( + table_.get_start(n), n, table_.bucket_count_) : + const_local_iterator(); } local_iterator end(size_type) @@ -692,8 +787,9 @@ namespace unordered const_local_iterator cbegin(size_type n) const { - return const_local_iterator( - table_.bucket_begin(n), n, table_.bucket_count_); + return table_.size_ ? const_local_iterator( + table_.get_start(n), n, table_.bucket_count_) : + const_local_iterator(); } const_local_iterator cend(size_type) const @@ -714,9 +810,9 @@ namespace unordered #if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) friend bool operator==( - unordered_multimap const&, unordered_multimap const&); + unordered_multimap const&, unordered_multimap const&); friend bool operator!=( - unordered_multimap const&, unordered_multimap const&); + unordered_multimap const&, unordered_multimap const&); #endif }; // class template unordered_multimap @@ -783,7 +879,8 @@ namespace unordered unordered_map::~unordered_map() {} template - unordered_map::unordered_map(unordered_map const& other) + unordered_map::unordered_map( + unordered_map const& other) : table_(other.table_) { } @@ -834,109 +931,6 @@ namespace unordered // modifiers -#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE) - template - template - std::pair::iterator, bool> - unordered_map::emplace(Args&&... args) - { - return table_.emplace(std::forward(args)...); - } - - template - template - 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( - boost::unordered::detail::empty_emplace, - value_type v - ) - { - return table_.emplace(boost::move(v)); - } - - template - typename unordered_map::iterator - unordered_map::emplace_hint(const_iterator, - boost::unordered::detail::empty_emplace, - value_type v - ) - { - return iterator(table_.emplace(boost::move(v)).first); - } -#endif - -#define BOOST_UNORDERED_EMPLACE(z, n, _) \ - template \ - template < \ - BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ - > \ - std::pair::iterator, bool> \ - unordered_map::emplace( \ - BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \ - { \ - return table_.emplace(BOOST_UNORDERED_CALL_PARAMS(z, n)); \ - } \ - \ - template \ - template < \ - BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ - > \ - 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(value_type const& obj) - { - return table_.emplace(obj); - } - - template - typename unordered_map::iterator - unordered_map::insert(const_iterator, - value_type const& obj) - { - return iterator(table_.emplace(obj).first); - } - - template - std::pair::iterator, bool> - unordered_map::insert(BOOST_RV_REF(value_type) obj) - { - return table_.emplace(boost::move(obj)); - } - - template - typename unordered_map::iterator - unordered_map::insert(const_iterator, - BOOST_RV_REF(value_type) obj) - { - return iterator(table_.emplace(boost::move(obj)).first); - } - template template void unordered_map::insert(InputIt first, InputIt last) @@ -1230,6 +1224,7 @@ namespace unordered #endif #if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) + template unordered_multimap::unordered_multimap( std::initializer_list list, size_type n, @@ -1250,6 +1245,7 @@ namespace unordered table_.insert_range(list.begin(), list.end()); return *this; } + #endif // size and capacity @@ -1262,112 +1258,6 @@ namespace unordered // modifiers -#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE) - - template - template - typename unordered_multimap::iterator - unordered_multimap::emplace(Args&&... args) - { - return iterator(table_.emplace(std::forward(args)...)); - } - - template - template - 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 - typename unordered_multimap::iterator - unordered_multimap::emplace( - boost::unordered::detail::empty_emplace, - value_type v - ) - { - return iterator(table_.emplace(boost::move(v))); - } - - template - typename unordered_multimap::iterator - unordered_multimap::emplace_hint(const_iterator, - boost::unordered::detail::empty_emplace, - value_type v - ) - { - return iterator(table_.emplace(boost::move(v))); - } -#endif - -#define BOOST_UNORDERED_EMPLACE(z, n, _) \ - template \ - template < \ - BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ - > \ - 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) \ - > \ - 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 - typename unordered_multimap::iterator - unordered_multimap::insert(value_type const& obj) - { - return iterator(table_.emplace(obj)); - } - - template - typename unordered_multimap::iterator - unordered_multimap::insert( - const_iterator, value_type const& obj) - { - return iterator(table_.emplace(obj)); - } - - template - typename unordered_multimap::iterator - unordered_multimap::insert(BOOST_RV_REF(value_type) obj) - { - return iterator(table_.emplace(boost::move(obj))); - } - - template - typename unordered_multimap::iterator - unordered_multimap::insert( - const_iterator, BOOST_RV_REF(value_type) obj) - { - return iterator(table_.emplace(boost::move(obj))); - } - template template void unordered_multimap::insert(InputIt first, InputIt last) diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index 1d1b346d..34cc2da7 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -14,10 +14,12 @@ #endif #include -#include #include #include #include +#include +#include +#include #if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) #include @@ -48,21 +50,18 @@ namespace unordered typedef P key_equal; typedef A allocator_type; -#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) private: -#endif typedef typename ::boost::unordered::detail::rebind_wrap< allocator_type, value_type>::type value_allocator; + typedef ::boost::unordered::detail::allocator_traits allocator_traits; - typedef ::boost::unordered::detail::set types; - typedef typename types::impl table; - - typedef typename types::node_ptr node_ptr; + typedef ::boost::unordered::detail::set + types; + typedef typename types::table table; public: @@ -75,22 +74,18 @@ namespace unordered typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; - 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; + typedef typename table::cl_iterator const_local_iterator; + typedef typename table::cl_iterator local_iterator; + typedef typename table::c_iterator const_iterator; + typedef typename table::c_iterator iterator; -#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) private: -#endif table table_; public: - // construct/destroy/copy + // constructors explicit unordered_set( size_type = ::boost::unordered::detail::default_bucket_count, @@ -100,17 +95,15 @@ namespace unordered explicit unordered_set(allocator_type const&); - unordered_set(unordered_set const&, allocator_type const&); - template - unordered_set(InputIt f, InputIt l); + unordered_set(InputIt, InputIt); template unordered_set( InputIt, InputIt, size_type, const hasher& = hasher(), - const key_equal& = key_equal()); + const key_equal& = key_equal()); template unordered_set( @@ -119,23 +112,12 @@ namespace unordered const hasher&, const key_equal&, const allocator_type&); - - ~unordered_set(); - unordered_set& operator=( - BOOST_COPY_ASSIGN_REF(unordered_set) x) - { - table_.assign(x.table_); - return *this; - } + // copy/move constructors unordered_set(unordered_set const&); - unordered_set& operator=(BOOST_RV_REF(unordered_set) x) - { - table_.move_assign(x.table_); - return *this; - } + unordered_set(unordered_set const&, allocator_type const&); unordered_set(BOOST_RV_REF(unordered_set) other) : table_(other.table_, ::boost::unordered::detail::move_tag()) @@ -153,7 +135,27 @@ namespace unordered const hasher& = hasher(), const key_equal&l = key_equal(), const allocator_type& = allocator_type()); +#endif + // Destructor + + ~unordered_set(); + + // Assign + + unordered_set& operator=(BOOST_COPY_ASSIGN_REF(unordered_set) x) + { + table_.assign(x.table_); + return *this; + } + + unordered_set& operator=(BOOST_RV_REF(unordered_set) x) + { + table_.move_assign(x.table_); + return *this; + } + +#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) unordered_set& operator=(std::initializer_list); #endif @@ -208,52 +210,99 @@ namespace unordered return const_iterator(); } - // modifiers + // emplace #if defined(BOOST_UNORDERED_STD_FORWARD_MOVE) template - std::pair emplace(Args&&...); + std::pair emplace(Args&&... args) + { + return table_.emplace(std::forward(args)...); + } + template - iterator emplace_hint(const_iterator, Args&&...); + iterator emplace_hint(const_iterator, Args&&... args) + { + return iterator(table_.emplace(std::forward(args)...).first); + } #else +#define BOOST_UNORDERED_EMPLACE(z, n, _) \ + template < \ + BOOST_PP_ENUM_PARAMS_Z(z, n, typename A) \ + > \ + std::pair emplace( \ + BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a) \ + ) \ + { \ + return table_.emplace( \ + ::boost::unordered::detail::create_emplace_args( \ + BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, \ + a) \ + )); \ + } \ + \ + template < \ + BOOST_PP_ENUM_PARAMS_Z(z, n, typename A) \ + > \ + iterator emplace_hint( \ + const_iterator, \ + BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a) \ + ) \ + { \ + return iterator(table_.emplace( \ + ::boost::unordered::detail::create_emplace_args( \ + BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, \ + a) \ + )).first); \ + } + + BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, BOOST_UNORDERED_EMPLACE, _) + +#undef BOOST_UNORDERED_EMPLACE + +#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100)) + std::pair emplace( boost::unordered::detail::empty_emplace = boost::unordered::detail::empty_emplace(), - value_type v = value_type() - ); - iterator emplace_hint(const_iterator, + value_type v = value_type()) + { + return this->emplace(boost::move(v)); + } + + iterator emplace_hint(const_iterator hint, boost::unordered::detail::empty_emplace = boost::unordered::detail::empty_emplace(), value_type v = value_type() - ); - -#define BOOST_UNORDERED_EMPLACE(z, n, _) \ - template < \ - BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ - > \ - std::pair emplace( \ - BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ - ); \ - \ - template < \ - BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ - > \ - iterator emplace_hint(const_iterator, \ - BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ - ); - - BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, - BOOST_UNORDERED_EMPLACE, _) - -#undef BOOST_UNORDERED_EMPLACE + ) + { + return iterator(this->emplace_hint(hint, boost::move(v))); + } #endif - std::pair insert(value_type const&); - std::pair insert(BOOST_UNORDERED_RV_REF(value_type)); - iterator insert(const_iterator, value_type const&); - iterator insert(const_iterator, BOOST_UNORDERED_RV_REF(value_type)); +#endif + + std::pair insert(value_type const& x) + { + return this->emplace(x); + } + + std::pair insert(BOOST_UNORDERED_RV_REF(value_type) x) + { + return this->emplace(boost::move(x)); + } + + iterator insert(const_iterator hint, value_type const& x) + { + return this->emplace_hint(hint, x); + } + + iterator insert(const_iterator hint, BOOST_UNORDERED_RV_REF(value_type) x) + { + return this->emplace_hint(hint, boost::move(x)); + } + template void insert(InputIt, InputIt); #if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) @@ -286,6 +335,7 @@ namespace unordered CompatiblePredicate const&) const; size_type count(const key_type&) const; + std::pair equal_range(const key_type&) const; @@ -301,7 +351,7 @@ namespace unordered return table_.max_bucket_count(); } - size_type bucket_size(size_type n) const; + size_type bucket_size(size_type) const; size_type bucket(const key_type& k) const { @@ -310,14 +360,16 @@ namespace unordered local_iterator begin(size_type n) { - return local_iterator( - table_.bucket_begin(n), n, table_.bucket_count_); + return table_.size_ ? local_iterator( + table_.get_start(n), n, table_.bucket_count_) : + local_iterator(); } const_local_iterator begin(size_type n) const { - return const_local_iterator( - table_.bucket_begin(n), n, table_.bucket_count_); + return table_.size_ ? const_local_iterator( + table_.get_start(n), n, table_.bucket_count_) : + const_local_iterator(); } local_iterator end(size_type) @@ -332,8 +384,9 @@ namespace unordered const_local_iterator cbegin(size_type n) const { - return const_local_iterator( - table_.bucket_begin(n), n, table_.bucket_count_); + return table_.size_ ? const_local_iterator( + table_.get_start(n), n, table_.bucket_count_) : + const_local_iterator(); } const_local_iterator cend(size_type) const @@ -350,7 +403,7 @@ namespace unordered float load_factor() const; void max_load_factor(float); - void rehash(size_type n); + void rehash(size_type); #if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) friend bool operator==( @@ -372,21 +425,18 @@ namespace unordered typedef P key_equal; typedef A allocator_type; -#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) private: -#endif typedef typename ::boost::unordered::detail::rebind_wrap< allocator_type, value_type>::type value_allocator; + typedef ::boost::unordered::detail::allocator_traits allocator_traits; - typedef ::boost::unordered::detail::multiset types; - typedef typename types::impl table; - - typedef typename types::node_ptr node_ptr; + typedef ::boost::unordered::detail::multiset + types; + typedef typename types::table table; public: @@ -399,22 +449,18 @@ namespace unordered typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; - 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; + typedef typename table::cl_iterator const_local_iterator; + typedef typename table::cl_iterator local_iterator; + typedef typename table::c_iterator const_iterator; + typedef typename table::c_iterator iterator; -#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) private: -#endif table table_; public: - // construct/destroy/copy + // constructors explicit unordered_multiset( size_type = ::boost::unordered::detail::default_bucket_count, @@ -424,8 +470,6 @@ namespace unordered explicit unordered_multiset(allocator_type const&); - unordered_multiset(unordered_multiset const&, allocator_type const&); - template unordered_multiset(InputIt, InputIt); @@ -444,22 +488,11 @@ namespace unordered const key_equal&, const allocator_type&); - ~unordered_multiset(); - - unordered_multiset& operator=( - BOOST_COPY_ASSIGN_REF(unordered_multiset) x) - { - table_.assign(x.table_); - return *this; - } + // copy/move constructors unordered_multiset(unordered_multiset const&); - unordered_multiset& operator=(BOOST_RV_REF(unordered_multiset) x) - { - table_.move_assign(x.table_); - return *this; - } + unordered_multiset(unordered_multiset const&, allocator_type const&); unordered_multiset(BOOST_RV_REF(unordered_multiset) other) : table_(other.table_, ::boost::unordered::detail::move_tag()) @@ -477,7 +510,27 @@ namespace unordered const hasher& = hasher(), const key_equal&l = key_equal(), const allocator_type& = allocator_type()); +#endif + // Destructor + + ~unordered_multiset(); + + // Assign + + unordered_multiset& operator=(BOOST_COPY_ASSIGN_REF(unordered_multiset) x) + { + table_.assign(x.table_); + return *this; + } + + unordered_multiset& operator=(BOOST_RV_REF(unordered_multiset) x) + { + table_.move_assign(x.table_); + return *this; + } + +#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) unordered_multiset& operator=(std::initializer_list); #endif @@ -532,55 +585,100 @@ namespace unordered return const_iterator(); } - // modifiers + // emplace #if defined(BOOST_UNORDERED_STD_FORWARD_MOVE) template - iterator emplace(Args&&...); + iterator emplace(Args&&... args) + { + return iterator(table_.emplace(std::forward(args)...)); + } + template - iterator emplace_hint(const_iterator, Args&&...); + iterator emplace_hint(const_iterator, Args&&... args) + { + return iterator(table_.emplace(std::forward(args)...)); + } #else +#define BOOST_UNORDERED_EMPLACE(z, n, _) \ + template < \ + BOOST_PP_ENUM_PARAMS_Z(z, n, typename A) \ + > \ + iterator emplace( \ + BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a) \ + ) \ + { \ + return iterator(table_.emplace( \ + ::boost::unordered::detail::create_emplace_args( \ + BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, \ + a) \ + ))); \ + } \ + \ + template < \ + BOOST_PP_ENUM_PARAMS_Z(z, n, typename A) \ + > \ + iterator emplace_hint( \ + const_iterator, \ + BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a) \ + ) \ + { \ + return iterator(table_.emplace( \ + ::boost::unordered::detail::create_emplace_args( \ + BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, \ + a) \ + ))); \ + } + + BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, BOOST_UNORDERED_EMPLACE, _) + +#undef BOOST_UNORDERED_EMPLACE + +#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100)) + iterator emplace( boost::unordered::detail::empty_emplace = boost::unordered::detail::empty_emplace(), - value_type v = value_type() - ); - iterator emplace_hint(const_iterator, + value_type v = value_type()) + { + return this->emplace(boost::move(v)); + } + + iterator emplace_hint(const_iterator hint, boost::unordered::detail::empty_emplace = boost::unordered::detail::empty_emplace(), value_type v = value_type() - ); - -#define BOOST_UNORDERED_EMPLACE(z, n, _) \ - template < \ - BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ - > \ - iterator emplace( \ - BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ - ); \ - \ - template < \ - BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ - > \ - iterator emplace_hint(const_iterator, \ - BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ - ); - - BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, - BOOST_UNORDERED_EMPLACE, _) - -#undef BOOST_UNORDERED_EMPLACE + ) + { + return this->emplace_hint(hint, boost::move(v)); + } #endif - iterator insert(value_type const&); - iterator insert(BOOST_UNORDERED_RV_REF(value_type)); - iterator insert(const_iterator, value_type const&); - iterator insert(const_iterator, BOOST_UNORDERED_RV_REF(value_type)); +#endif - template - void insert(InputIt, InputIt); + iterator insert(value_type const& x) + { + return this->emplace(x); + } + + iterator insert(BOOST_UNORDERED_RV_REF(value_type) x) + { + return this->emplace(boost::move(x)); + } + + iterator insert(const_iterator hint, value_type const& x) + { + return this->emplace_hint(hint, x); + } + + iterator insert(const_iterator hint, BOOST_UNORDERED_RV_REF(value_type) x) + { + return this->emplace_hint(hint, boost::move(x)); + } + + template void insert(InputIt, InputIt); #if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) void insert(std::initializer_list); @@ -589,8 +687,8 @@ namespace unordered 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); } + void quick_erase(const_iterator it) { erase(it); } + void erase_return_void(const_iterator it) { erase(it); } void clear(); void swap(unordered_multiset&); @@ -612,6 +710,7 @@ namespace unordered CompatiblePredicate const&) const; size_type count(const key_type&) const; + std::pair equal_range(const key_type&) const; @@ -636,14 +735,16 @@ namespace unordered local_iterator begin(size_type n) { - return local_iterator( - table_.bucket_begin(n), n, table_.bucket_count_); + return table_.size_ ? local_iterator( + table_.get_start(n), n, table_.bucket_count_) : + local_iterator(); } const_local_iterator begin(size_type n) const { - return const_local_iterator( - table_.bucket_begin(n), n, table_.bucket_count_); + return table_.size_ ? const_local_iterator( + table_.get_start(n), n, table_.bucket_count_) : + const_local_iterator(); } local_iterator end(size_type) @@ -658,8 +759,9 @@ namespace unordered const_local_iterator cbegin(size_type n) const { - return const_local_iterator( - table_.bucket_begin(n), n, table_.bucket_count_); + return table_.size_ ? const_local_iterator( + table_.get_start(n), n, table_.bucket_count_) : + const_local_iterator(); } const_local_iterator cend(size_type) const @@ -749,7 +851,8 @@ namespace unordered unordered_set::~unordered_set() {} template - unordered_set::unordered_set(unordered_set const& other) + unordered_set::unordered_set( + unordered_set const& other) : table_(other.table_) { } @@ -800,107 +903,6 @@ namespace unordered // modifiers -#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE) - template - template - std::pair::iterator, bool> - unordered_set::emplace(Args&&... args) - { - return table_.emplace(std::forward(args)...); - } - - template - template - 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( - boost::unordered::detail::empty_emplace, - value_type v - ) - { - return table_.emplace(boost::move(v)); - } - - template - typename unordered_set::iterator - unordered_set::emplace_hint(const_iterator, - boost::unordered::detail::empty_emplace, - value_type v - ) - { - return iterator(table_.emplace(boost::move(v)).first); - } - -#define BOOST_UNORDERED_EMPLACE(z, n, _) \ - template \ - template < \ - BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ - > \ - std::pair::iterator, bool> \ - unordered_set::emplace( \ - BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \ - { \ - return table_.emplace(BOOST_UNORDERED_CALL_PARAMS(z, n)); \ - } \ - \ - template \ - template < \ - BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ - > \ - 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(value_type const& obj) - { - return table_.emplace(obj); - } - - template - typename unordered_set::iterator - unordered_set::insert(const_iterator, - value_type const& obj) - { - return iterator(table_.emplace(obj).first); - } - - template - std::pair::iterator, bool> - unordered_set::insert(BOOST_UNORDERED_RV_REF(value_type) obj) - { - return table_.emplace(boost::move(obj)); - } - - template - typename unordered_set::iterator - unordered_set::insert(const_iterator, - BOOST_UNORDERED_RV_REF(value_type) obj) - { - return iterator(table_.emplace(boost::move(obj)).first); - } - template template void unordered_set::insert(InputIt first, InputIt last) @@ -910,7 +912,8 @@ namespace unordered #if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) template - void unordered_set::insert(std::initializer_list list) + void unordered_set::insert( + std::initializer_list list) { table_.insert_range(list.begin(), list.end()); } @@ -932,7 +935,8 @@ namespace unordered template typename unordered_set::iterator - unordered_set::erase(const_iterator first, const_iterator last) + unordered_set::erase( + const_iterator first, const_iterator last) { return iterator(table_.erase_range(first.node_, last.node_)); } @@ -1143,6 +1147,7 @@ namespace unordered #endif #if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) + template unordered_multiset::unordered_multiset( std::initializer_list list, size_type n, @@ -1163,6 +1168,7 @@ namespace unordered table_.insert_range(list.begin(), list.end()); return *this; } + #endif // size and capacity @@ -1175,110 +1181,6 @@ namespace unordered // modifiers -#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE) - - template - template - typename unordered_multiset::iterator - unordered_multiset::emplace(Args&&... args) - { - return iterator(table_.emplace(std::forward(args)...)); - } - - template - template - typename unordered_multiset::iterator - unordered_multiset::emplace_hint( - const_iterator, Args&&... args) - { - return iterator(table_.emplace(std::forward(args)...)); - } - -#else - - template - typename unordered_multiset::iterator - unordered_multiset::emplace( - boost::unordered::detail::empty_emplace, - value_type v - ) - { - return iterator(table_.emplace(boost::move(v))); - } - - template - typename unordered_multiset::iterator - unordered_multiset::emplace_hint(const_iterator, - boost::unordered::detail::empty_emplace, - value_type v - ) - { - return iterator(table_.emplace(boost::move(v))); - } - -#define BOOST_UNORDERED_EMPLACE(z, n, _) \ - template \ - template < \ - BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ - > \ - 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) \ - > \ - 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 - typename unordered_multiset::iterator - unordered_multiset::insert(value_type const& obj) - { - return iterator(table_.emplace(obj)); - } - - template - typename unordered_multiset::iterator - unordered_multiset::insert(const_iterator, - value_type const& obj) - { - return iterator(table_.emplace(obj)); - } - - template - typename unordered_multiset::iterator - unordered_multiset::insert(BOOST_UNORDERED_RV_REF(value_type) obj) - { - return iterator(table_.emplace(boost::move(obj))); - } - - template - typename unordered_multiset::iterator - unordered_multiset::insert(const_iterator, - BOOST_UNORDERED_RV_REF(value_type) obj) - { - return iterator(table_.emplace(boost::move(obj))); - } - template template void unordered_multiset::insert(InputIt first, InputIt last) @@ -1439,7 +1341,6 @@ namespace unordered #endif m1.swap(m2); } - } // namespace unordered } // namespace boost diff --git a/test/objects/minimal.hpp b/test/objects/minimal.hpp index 6589760d..5b7ae246 100644 --- a/test/objects/minimal.hpp +++ b/test/objects/minimal.hpp @@ -202,17 +202,67 @@ namespace minimal template class ptr; template class const_ptr; + struct void_ptr + { +#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) + template + friend class ptr; + private: +#endif + + void* ptr_; + + public: + void_ptr() : ptr_(0) {} + + template + explicit void_ptr(ptr const& x) : ptr_(x.ptr_) {} + + // I'm not using the safe bool idiom because the containers should be + // able to cope with bool conversions. + operator bool() const { return !!ptr_; } + + bool operator==(void_ptr const& x) const { return ptr_ == x.ptr_; } + bool operator!=(void_ptr const& x) const { return ptr_ != x.ptr_; } + }; + + class void_const_ptr + { +#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) + template + friend class const_ptr; + private: +#endif + + void* ptr_; + + public: + void_const_ptr() : ptr_(0) {} + + template + explicit void_const_ptr(const_ptr const& x) : ptr_(x.ptr_) {} + + // I'm not using the safe bool idiom because the containers should be + // able to cope with bool conversions. + operator bool() const { return !!ptr_; } + + bool operator==(void_const_ptr const& x) const { return ptr_ == x.ptr_; } + bool operator!=(void_const_ptr const& x) const { return ptr_ != x.ptr_; } + }; + template class ptr { friend class allocator; friend class const_ptr; + friend struct void_ptr; T* ptr_; ptr(T* x) : ptr_(x) {} public: ptr() : ptr_(0) {} + explicit ptr(void_ptr const& x) : ptr_((T*) x.ptr_) {} T& operator*() const { return *ptr_; } T* operator->() const { return ptr_; } @@ -234,13 +284,6 @@ namespace minimal bool operator>(ptr const& x) const { return ptr_ > x.ptr_; } bool operator<=(ptr const& x) const { return ptr_ <= x.ptr_; } bool operator>=(ptr const& x) const { return ptr_ >= x.ptr_; } - - bool operator==(const_ptr const& x) const { return ptr_ == x.ptr_; } - bool operator!=(const_ptr const& x) const { return ptr_ != x.ptr_; } - bool operator<(const_ptr const& x) const { return ptr_ < x.ptr_; } - bool operator>(const_ptr const& x) const { return ptr_ > x.ptr_; } - bool operator<=(const_ptr const& x) const { return ptr_ <= x.ptr_; } - bool operator>=(const_ptr const& x) const { return ptr_ >= x.ptr_; } private: // TODO: //ampersand_operator_used operator&() const { return ampersand_operator_used(); } @@ -250,6 +293,7 @@ namespace minimal class const_ptr { friend class allocator; + friend struct const_void_ptr; T const* ptr_; @@ -257,6 +301,7 @@ namespace minimal public: const_ptr() : ptr_(0) {} const_ptr(ptr const& x) : ptr_(x.ptr_) {} + explicit const_ptr(void_const_ptr const& x) : ptr_((T const*) x.ptr_) {} T const& operator*() const { return *ptr_; } T const* operator->() const { return ptr_; } @@ -270,13 +315,6 @@ namespace minimal bool operator!() const { return !ptr_; } operator bool() const { return !!ptr_; } - bool operator==(ptr const& x) const { return ptr_ == x.ptr_; } - bool operator!=(ptr const& x) const { return ptr_ != x.ptr_; } - bool operator<(ptr const& x) const { return ptr_ < x.ptr_; } - bool operator>(ptr const& x) const { return ptr_ > x.ptr_; } - bool operator<=(ptr const& x) const { return ptr_ <= x.ptr_; } - bool operator>=(ptr const& x) const { return ptr_ >= x.ptr_; } - bool operator==(const_ptr const& x) const { return ptr_ == x.ptr_; } bool operator!=(const_ptr const& x) const { return ptr_ != x.ptr_; } bool operator<(const_ptr const& x) const { return ptr_ < x.ptr_; } @@ -294,6 +332,8 @@ namespace minimal public: typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; + typedef void_ptr void_pointer; + typedef void_const_ptr void_const_pointer; typedef ptr pointer; typedef const_ptr const_pointer; typedef T& reference; diff --git a/test/unordered/assign_tests.cpp b/test/unordered/assign_tests.cpp index 2e0d71ad..10d661d4 100644 --- a/test/unordered/assign_tests.cpp +++ b/test/unordered/assign_tests.cpp @@ -57,9 +57,12 @@ void assign_tests1(T*, T y; y.max_load_factor(x.max_load_factor() / 20); + float mlf = x.max_load_factor(); y = x; + tracker.compare(x); tracker.compare(y); - BOOST_TEST(x.max_load_factor() == y.max_load_factor()); + BOOST_TEST(x.max_load_factor() == mlf); + BOOST_TEST(y.max_load_factor() == mlf); } } diff --git a/test/unordered/compile_set.cpp b/test/unordered/compile_set.cpp index 602e1968..92e808d1 100644 --- a/test/unordered/compile_set.cpp +++ b/test/unordered/compile_set.cpp @@ -128,7 +128,7 @@ UNORDERED_AUTO_TEST(test1) std::equal_to equal_to; int value = 0; - std::cout<<"Test unordered_set.\n"; + std::cout<<"Test unordered_set." << std::endl; boost::unordered_set set; @@ -145,7 +145,7 @@ UNORDERED_AUTO_TEST(test1) unordered_set_test(set2, value); unordered_copyable_test(set2, value, value, hash, equal_to); - std::cout<<"Test unordered_multiset.\n"; + std::cout<<"Test unordered_multiset." << std::endl; boost::unordered_multiset multiset; diff --git a/test/unordered/compile_tests.hpp b/test/unordered/compile_tests.hpp index 429166d3..b82eadb8 100644 --- a/test/unordered/compile_tests.hpp +++ b/test/unordered/compile_tests.hpp @@ -413,6 +413,7 @@ void unordered_copyable_test(X& x, Key& k, T& t, Hash& hf, Pred& eq) BOOST_DEDUCED_TYPENAME X::value_type* j = 0; X(i, j, 10, hf, eq); + X a5(i, j, 10, hf, eq); X(i, j, 10, hf); X a6(i, j, 10, hf); diff --git a/test/unordered/constructor_tests.cpp b/test/unordered/constructor_tests.cpp index 40f2aacd..3ccf748b 100644 --- a/test/unordered/constructor_tests.cpp +++ b/test/unordered/constructor_tests.cpp @@ -15,8 +15,6 @@ #include "../helpers/input_iterator.hpp" #include "../helpers/invariants.hpp" -#include - namespace constructor_tests { test::seed_t seed(356730); diff --git a/test/unordered/incomplete_test.cpp b/test/unordered/incomplete_test.cpp index 08455600..5f355de2 100644 --- a/test/unordered/incomplete_test.cpp +++ b/test/unordered/incomplete_test.cpp @@ -5,6 +5,7 @@ #include "../helpers/prefix.hpp" +#include #include #include diff --git a/test/unordered/unnecessary_copy_tests.cpp b/test/unordered/unnecessary_copy_tests.cpp index b033b0df..f13090f1 100644 --- a/test/unordered/unnecessary_copy_tests.cpp +++ b/test/unordered/unnecessary_copy_tests.cpp @@ -245,9 +245,11 @@ namespace unnecessary_copy_tests x.emplace(); #if defined(BOOST_UNORDERED_STD_FORWARD_MOVE) COPY_COUNT(1); MOVE_COUNT(0); -#else +#elif !defined(BOOST_NO_RVALUE_REFERENCES) // source_cost doesn't make much sense here, but it seems to fit. COPY_COUNT(1); MOVE_COUNT(source_cost); +#else + COPY_COUNT(1); MOVE_COUNT(1 + source_cost); #endif #endif @@ -357,7 +359,6 @@ namespace unnecessary_copy_tests (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ > 2) || \ (defined(BOOST_MSVC) && BOOST_MSVC >= 1600 ) || \ (!defined(__GNUC__) && !defined(BOOST_MSVC)) - count_copies part; reset(); std::pair a_ref(part, part);