From 78b078f41d10f89127a08f60aaaef44c6540a551 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 20 Sep 2009 21:55:15 +0000 Subject: [PATCH] Since all the compilers support out of line template members use them and lots of other things. [SVN r56329] --- .../unordered/detail/allocator_helpers.hpp | 3 +- include/boost/unordered/detail/buckets.hpp | 325 ++--- include/boost/unordered/detail/equivalent.hpp | 271 ++++ .../boost/unordered/detail/extract_key.hpp | 25 +- include/boost/unordered/detail/fwd.hpp | 715 +++++++--- include/boost/unordered/detail/insert.hpp | 678 ---------- include/boost/unordered/detail/move.hpp | 2 + include/boost/unordered/detail/node.hpp | 157 +-- include/boost/unordered/detail/table.hpp | 1176 +++++++++-------- include/boost/unordered/detail/unique.hpp | 431 ++++++ include/boost/unordered/detail/util.hpp | 108 +- include/boost/unordered/unordered_map.hpp | 320 +++-- include/boost/unordered/unordered_set.hpp | 295 +++-- test/helpers/list.hpp | 13 +- test/unordered/erase_equiv_tests.cpp | 2 +- test/unordered/out_of_line.cpp | 2 +- 16 files changed, 2462 insertions(+), 2061 deletions(-) create mode 100644 include/boost/unordered/detail/equivalent.hpp delete mode 100644 include/boost/unordered/detail/insert.hpp create mode 100644 include/boost/unordered/detail/unique.hpp diff --git a/include/boost/unordered/detail/allocator_helpers.hpp b/include/boost/unordered/detail/allocator_helpers.hpp index 092e78af..2c642231 100644 --- a/include/boost/unordered/detail/allocator_helpers.hpp +++ b/include/boost/unordered/detail/allocator_helpers.hpp @@ -99,7 +99,8 @@ namespace boost { namespace unordered_detail { } private: allocator_array_constructor(allocator_array_constructor const&); - allocator_array_constructor& operator=(allocator_array_constructor const&); + allocator_array_constructor& operator=( + allocator_array_constructor const&); }; }} diff --git a/include/boost/unordered/detail/buckets.hpp b/include/boost/unordered/detail/buckets.hpp index 29fedd29..fed14388 100644 --- a/include/boost/unordered/detail/buckets.hpp +++ b/include/boost/unordered/detail/buckets.hpp @@ -14,23 +14,123 @@ namespace boost { namespace unordered_detail { //////////////////////////////////////////////////////////////////////////// - // Explicitly call a destructor - -#if defined(BOOST_MSVC) -# define BOOST_UNORDERED_DESTRUCT(x, type) (x)->~type(); -#else -# define BOOST_UNORDERED_DESTRUCT(x, type) boost::unordered_detail::destroy(x) - template - void destroy(T* x) { - x->~T(); + // Buckets + // TODO: Are these needed? + + template + inline BOOST_DEDUCED_TYPENAME hash_buckets::bucket_ptr + hash_buckets::get_bucket(std::size_t n) const + { + return buckets_ + static_cast(n); } -#endif - - // Constructors template - hash_buckets::hash_buckets(node_allocator const& a, std::size_t bucket_count) - : buckets_(), allocators_(a,a) + inline BOOST_DEDUCED_TYPENAME hash_buckets::bucket_ptr + hash_buckets::bucket_ptr_from_hash(std::size_t hashed) const + { + return get_bucket(hashed % bucket_count_); + } + + template + inline std::size_t hash_buckets::bucket_size(std::size_t index) const + { + if(!buckets_) return 0; + bucket_ptr ptr = get_bucket(index)->next_; + std::size_t count = 0; + while(ptr) { + ++count; + ptr = ptr->next_; + } + return count; + } + + template + inline BOOST_DEDUCED_TYPENAME hash_buckets::node_ptr + hash_buckets::bucket_begin(std::size_t n) const + { + return buckets_ ? get_bucket(n)->next_ : node_ptr(); + } + + //////////////////////////////////////////////////////////////////////////// + // Delete + + template + inline void hash_buckets::delete_node(node_ptr b) + { + node* raw_ptr = static_cast(&*b); + boost::unordered_detail::destroy(&raw_ptr->value()); + real_node_ptr n(node_alloc().address(*raw_ptr)); + node_alloc().destroy(n); + node_alloc().deallocate(n, 1); + } + + template + inline void hash_buckets::clear_bucket(bucket_ptr b) + { + node_ptr node_it = b->next_; + b->next_ = node_ptr(); + + while(node_it) { + node_ptr node_to_delete = node_it; + node_it = node_it->next_; + delete_node(node_to_delete); + } + } + + template + inline void hash_buckets::delete_buckets() + { + bucket_ptr end = this->get_bucket(this->bucket_count_); + + for(bucket_ptr begin = this->buckets_; begin != end; ++begin) { + clear_bucket(begin); + } + + // Destroy the buckets (including the sentinel bucket). + ++end; + for(bucket_ptr begin = this->buckets_; begin != end; ++begin) { + bucket_alloc().destroy(begin); + } + + bucket_alloc().deallocate(this->buckets_, this->bucket_count_ + 1); + + this->buckets_ = bucket_ptr(); + } + + template + inline std::size_t hash_buckets::delete_nodes( + node_ptr begin, node_ptr end) + { + std::size_t count = 0; + while(begin != end) { + node_ptr node = begin; + begin = begin->next_; + delete_node(node); + ++count; + } + return count; + } + + //////////////////////////////////////////////////////////////////////////// + // Constructors and Destructors + + template + inline hash_buckets::hash_buckets( + node_allocator const& a, std::size_t bucket_count) + : buckets_(), + bucket_count_(bucket_count), + allocators_(a,a) + { + } + + template + inline hash_buckets::~hash_buckets() + { + if(this->buckets_) { this->delete_buckets(); } + } + + template + inline void hash_buckets::create_buckets() { // The array constructor will clean up in the event of an // exception. @@ -38,52 +138,27 @@ namespace boost { namespace unordered_detail { constructor(bucket_alloc()); // Creates an extra bucket to act as a sentinel. - constructor.construct(bucket(), bucket_count + 1); + constructor.construct(bucket(), this->bucket_count_ + 1); // Set up the sentinel (node_ptr cast) - bucket_ptr sentinel = constructor.get() + static_cast(bucket_count); + bucket_ptr sentinel = constructor.get() + + static_cast(this->bucket_count_); sentinel->next_ = sentinel; // Only release the buckets once everything is successfully // done. this->buckets_ = constructor.release(); - this->bucket_count_ = bucket_count; } - template - hash_buckets::hash_buckets(hash_buckets& x, move_tag) - : buckets_(), allocators_(x.allocators_) - { - this->buckets_ = x.buckets_; - this->bucket_count_ = x.bucket_count_; - x.buckets_ = bucket_ptr(); - x.bucket_count_ = 0; - } - - template - hash_buckets::hash_buckets(hash_buckets& x, value_allocator const& a, move_tag) : - buckets_(), allocators_(a,a) - { - if(this->node_alloc() == x.node_alloc()) { - this->buckets_ = x.buckets_; - this->bucket_count_ = x.bucket_count_; - x.buckets_ = bucket_ptr(); - x.bucket_count_ = 0; - } - } - - template - hash_buckets::~hash_buckets() - { - if(this->buckets_) { delete_buckets(); } - } + //////////////////////////////////////////////////////////////////////////// + // Constructors and Destructors // no throw template inline void hash_buckets::move(hash_buckets& other) { BOOST_ASSERT(node_alloc() == other.node_alloc()); - delete_buckets(); + if(this->buckets_) { this->delete_buckets(); } this->buckets_ = other.buckets_; this->bucket_count_ = other.bucket_count_; other.buckets_ = bucket_ptr(); @@ -97,166 +172,6 @@ namespace boost { namespace unordered_detail { std::swap(buckets_, other.buckets_); std::swap(bucket_count_, other.bucket_count_); } - - // Buckets - - template - inline std::size_t hash_buckets::bucket_count() const - { - return bucket_count_; - } - - template - inline std::size_t hash_buckets::bucket_from_hash(std::size_t hashed) const - { - return hashed % bucket_count_; - } - - template - inline BOOST_DEDUCED_TYPENAME hash_buckets::bucket_ptr - hash_buckets::bucket_ptr_from_hash(std::size_t hashed) const - { - return buckets_ + static_cast( - bucket_from_hash(hashed)); - } - - template - inline BOOST_DEDUCED_TYPENAME hash_buckets::bucket_ptr - hash_buckets::buckets_begin() const - { - return buckets_; - } - - template - inline BOOST_DEDUCED_TYPENAME hash_buckets::bucket_ptr - hash_buckets::buckets_end() const - { - return buckets_ + static_cast(bucket_count_); - } - - template - inline std::size_t hash_buckets::bucket_size(std::size_t index) const - { - bucket_ptr ptr = (buckets_ + static_cast(index))->next_; - std::size_t count = 0; - while(ptr) { - ++count; - ptr = next_node(ptr); - } - return count; - } - - template - inline BOOST_DEDUCED_TYPENAME hash_buckets::bucket_ptr - hash_buckets::get_bucket(std::size_t n) const - { - return buckets_ + static_cast(n); - } - - template - inline BOOST_DEDUCED_TYPENAME hash_buckets::node_ptr - hash_buckets::bucket_begin(std::size_t n) const - { - return (buckets_ + static_cast(n))->next_; - } - - template - inline BOOST_DEDUCED_TYPENAME hash_buckets::node_ptr - hash_buckets::bucket_end(std::size_t) const - { - return node_ptr(); - } - - // Construct/destruct - - template - inline void hash_buckets::destruct_node(node_ptr b) - { - node* raw_ptr = static_cast(&*b); - BOOST_UNORDERED_DESTRUCT(&raw_ptr->value(), value_type); - real_node_ptr n(node_alloc().address(*raw_ptr)); - node_alloc().destroy(n); - node_alloc().deallocate(n, 1); - } - - // Delete and clear buckets - - template - inline void hash_buckets::delete_group(node_ptr first_node) - { - delete_nodes(first_node, node::next_group(first_node)); - } - - template - inline void hash_buckets::delete_nodes(node_ptr begin, node_ptr end) - { - while(begin != end) { - node_ptr node = begin; - begin = next_node(begin); - destruct_node(node); - } - } - - template - inline void hash_buckets::delete_to_bucket_end(node_ptr begin) - { - while(BOOST_UNORDERED_BORLAND_BOOL(begin)) { - node_ptr node = begin; - begin = next_node(begin); - destruct_node(node); - } - } - - template - inline void hash_buckets::clear_bucket(bucket_ptr b) - { - node_ptr node_it = b->next_; - b->next_ = node_ptr(); - - while(node_it) { - node_ptr node_to_destruct = node_it; - node_it = next_node(node_it); - destruct_node(node_to_destruct); - } - } - - template - inline void hash_buckets::delete_buckets() - { - for(bucket_ptr begin = this->buckets_begin(), end = this->buckets_end(); begin != end; ++begin) { - clear_bucket(begin); - } - - // Destroy the buckets (including the sentinel bucket). - bucket_ptr end = this->buckets_end(); - ++end; - for(bucket_ptr begin = this->buckets_begin(); begin != end; ++begin) { - bucket_alloc().destroy(begin); - } - - bucket_alloc().deallocate(this->buckets_begin(), this->bucket_count() + 1); - - this->buckets_ = bucket_ptr(); - } - - //////////////////////////////////////////////////////////////////////////// - // hash_iterator_base implementation - - template - inline void hash_iterator_base::increment(node_ptr node) { - while(!node) { - ++bucket_; - node = bucket_->next_; - } - - node_ = node; - } - - template - inline void hash_iterator_base::increment() - { - increment(next_node(node_)); - } }} #endif diff --git a/include/boost/unordered/detail/equivalent.hpp b/include/boost/unordered/detail/equivalent.hpp new file mode 100644 index 00000000..efb3a688 --- /dev/null +++ b/include/boost/unordered/detail/equivalent.hpp @@ -0,0 +1,271 @@ + +// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard. +// Copyright (C) 2005-2009 Daniel James +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_UNORDERED_DETAIL_EQUIVALENT_HPP_INCLUDED +#define BOOST_UNORDERED_DETAIL_EQUIVALENT_HPP_INCLUDED + +#include +#include + +namespace boost { namespace unordered_detail { + + //////////////////////////////////////////////////////////////////////////// + // Equality + + template + bool hash_equivalent_table + ::equals(hash_equivalent_table const& other) const + { + if(this->size_ != other.size_) return false; + if(!this->size_) return true; + + bucket_ptr end = this->get_bucket(this->bucket_count_); + for(bucket_ptr i = this->cached_begin_bucket_; i != end; ++i) + { + node_ptr it1 = i->next_; + while(BOOST_UNORDERED_BORLAND_BOOL(it1)) + { + node_ptr it2 = other.find_iterator(get_key_from_ptr(it1)); + if(!BOOST_UNORDERED_BORLAND_BOOL(it2)) return false; + + node_ptr end1 = node::next_group(it1); + node_ptr end2 = node::next_group(it2); + + do { + if(!extractor::compare_mapped( + node::get_value(it1), node::get_value(it2))) + return false; + it1 = it1->next_; + it2 = it2->next_; + } while(it1 != end1 && it2 != end2); + if(it1 != end1 || it2 != end2) return false; + } + } + + return true; + } + + //////////////////////////////////////////////////////////////////////////// + // A convenience method for adding nodes. + + template + inline BOOST_DEDUCED_TYPENAME hash_equivalent_table::node_ptr + hash_equivalent_table + ::add_node(node_constructor& a, bucket_ptr bucket, node_ptr pos) + { + node_ptr n = a.release(); + if(BOOST_UNORDERED_BORLAND_BOOL(pos)) { + node::add_after_node(n, pos); + } + else { + node::add_to_bucket(n, *bucket); + if(bucket < this->cached_begin_bucket_) + this->cached_begin_bucket_ = bucket; + } + ++this->size_; + return n; + } + + //////////////////////////////////////////////////////////////////////////// + // Insert methods + + template + inline BOOST_DEDUCED_TYPENAME + hash_equivalent_table::iterator_base + hash_equivalent_table::emplace_impl(node_constructor& a) + { + key_type const& k = get_key(a.value()); + std::size_t hash_value = this->hash_function()(k); + + if(!this->size_) { + return this->emplace_empty_impl_with_node(a, 1); + } + else { + bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value); + node_ptr position = find_iterator(bucket, k); + + // reserve has basic exception safety if the hash function + // throws, strong otherwise. + if(this->reserve_for_insert(this->size_ + 1)) + bucket = this->bucket_ptr_from_hash(hash_value); + + return iterator_base(bucket, add_node(a, bucket, position)); + } + } + + template + inline BOOST_DEDUCED_TYPENAME + hash_equivalent_table::iterator_base + hash_equivalent_table + ::emplace_hint_impl(iterator_base const& it, node_constructor& a) + { + // equal can throw, but with no effects + if (!it.node_ || !equal(get_key(a.value()), *it)) { + // Use the standard emplace if the iterator doesn't point + // to a matching key. + return emplace_impl(a); + } + else { + // Find the first node in the group - so that the node + // will be added at the end of the group. + + node_ptr start = node::first_in_group(it.node_); + + // reserve has basic exception safety if the hash function + // throws, strong otherwise. + bucket_ptr bucket = this->reserve_for_insert(this->size_ + 1) ? + get_bucket(this->bucket_index(get_key(a.value()))) : + it.bucket_; + + // Nothing after this point can throw + + return iterator_base(bucket, add_node(a, bucket, start)); + } + } + + template + inline void hash_equivalent_table + ::emplace_impl_no_rehash(node_constructor& a) + { + key_type const& k = get_key(a.value()); + bucket_ptr bucket = this->get_bucket(this->bucket_index(k)); + add_node(a, bucket, find_iterator(bucket, k)); + } + +#if defined(BOOST_UNORDERED_STD_FORWARD) + + // Emplace (equivalent key containers) + // (I'm using an overloaded emplace for both 'insert' and 'emplace') + + // if hash function throws, basic exception safety + // strong otherwise + template + template + BOOST_DEDUCED_TYPENAME hash_equivalent_table::iterator_base + hash_equivalent_table + ::emplace(Args&&... args) + { + // Create the node before rehashing in case it throws an + // exception (need strong safety in such a case). + node_constructor a(*this); + a.construct(std::forward(args)...); + + return emplace_impl(a); + } + + // Emplace (equivalent key containers) + // (I'm using an overloaded emplace for both 'insert' and 'emplace') + + // if hash function throws, basic exception safety + // strong otherwise + template + template + BOOST_DEDUCED_TYPENAME hash_equivalent_table::iterator_base + hash_equivalent_table + ::emplace_hint(iterator_base const& it, Args&&... args) + { + // Create the node before rehashing in case it throws an + // exception (need strong safety in such a case). + node_constructor a(*this); + a.construct(std::forward(args)...); + + return emplace_hint_impl(it, a); + } + +#else + +#define BOOST_UNORDERED_INSERT_IMPL(z, n, _) \ + template \ + template \ + BOOST_DEDUCED_TYPENAME hash_equivalent_table::iterator_base \ + hash_equivalent_table \ + ::emplace(BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \ + { \ + node_constructor a(*this); \ + a.construct(BOOST_UNORDERED_CALL_PARAMS(z, n)); \ + return emplace_impl(a); \ + } \ + \ + template \ + template \ + BOOST_DEDUCED_TYPENAME hash_equivalent_table::iterator_base \ + hash_equivalent_table \ + ::emplace_hint(iterator_base const& it, \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \ + { \ + node_constructor a(*this); \ + a.construct(BOOST_UNORDERED_CALL_PARAMS(z, n)); \ + return emplace_hint_impl(it, a); \ + } + + BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, + BOOST_UNORDERED_INSERT_IMPL, _) + +#undef BOOST_UNORDERED_INSERT_IMPL +#endif + + //////////////////////////////////////////////////////////////////////////// + // Insert range methods + + // if hash function throws, or inserting > 1 element, basic exception safety + // strong otherwise + template + template + inline void hash_equivalent_table + ::insert_for_range(I i, I j, forward_traversal_tag) + { + if(i == j) return; + std::size_t distance = unordered_detail::distance(i, j); + if(distance == 1) { + emplace(*i); + } + else { + node_constructor a(*this); + + // Only require basic exception safety here + if(this->size_) { + this->reserve_for_insert(this->size_ + distance); + } + else { + a.construct(*i++); + this->emplace_empty_impl_with_node(a, distance); + } + + for (; i != j; ++i) { + a.construct(*i); + emplace_impl_no_rehash(a); + } + } + } + + // if hash function throws, or inserting > 1 element, basic exception safety + // strong otherwise + template + template + inline void hash_equivalent_table + ::insert_for_range(I i, I j, boost::incrementable_traversal_tag) + { + node_constructor a(*this); + for (; i != j; ++i) { + a.construct(*i); + emplace_impl(a); + } + } + + // if hash function throws, or inserting > 1 element, basic exception safety + // strong otherwise + // TODO: Should I special case an empty container? + template + template + void hash_equivalent_table::insert_range(I i, I j) + { + BOOST_DEDUCED_TYPENAME boost::iterator_traversal::type + iterator_traversal_tag; + insert_for_range(i, j, iterator_traversal_tag); + } +}} + +#endif diff --git a/include/boost/unordered/detail/extract_key.hpp b/include/boost/unordered/detail/extract_key.hpp index 63dce95e..cba889eb 100644 --- a/include/boost/unordered/detail/extract_key.hpp +++ b/include/boost/unordered/detail/extract_key.hpp @@ -66,6 +66,11 @@ namespace unordered_detail { return no_key(); } #endif + + static bool compare_mapped(value_type const&, value_type const&) + { + return true; + } }; }; @@ -75,7 +80,9 @@ namespace unordered_detail { struct apply { typedef ValueType value_type; - typedef BOOST_DEDUCED_TYPENAME remove_const::type key_type; + typedef BOOST_DEDUCED_TYPENAME + remove_const::type + key_type; static key_type const& extract(value_type const& v) { @@ -94,19 +101,22 @@ namespace unordered_detail { } template - static key_type const& extract(std::pair const& v) + static key_type const& extract( + std::pair const& v) { return v.first; } /* template - static key_type const& extract(std::pair const& v) + static key_type const& extract( + std::pair const& v) { return v.first; } template - static key_type const& extract(std::pair const& v) + static key_type const& extract( + std::pair const& v) { return v.first; } @@ -114,7 +124,8 @@ namespace unordered_detail { #if defined(BOOST_UNORDERED_STD_FORWARD) template - static key_type const& extract(key_type const& k, Arg1 const&, Args const&...) + static key_type const& extract(key_type const& k, + Arg1 const&, Args const&...) { return k; } @@ -149,6 +160,10 @@ namespace unordered_detail { } #endif + static bool compare_mapped(value_type const& x, value_type const& y) + { + return x.second == y.second; + } }; }; }} diff --git a/include/boost/unordered/detail/fwd.hpp b/include/boost/unordered/detail/fwd.hpp index 7cd56174..15924676 100644 --- a/include/boost/unordered/detail/fwd.hpp +++ b/include/boost/unordered/detail/fwd.hpp @@ -18,6 +18,7 @@ #include #include #include +#include // This header defines most of the classes used to implement the unordered // containers. It doesn't include the insert methods as they require a lot @@ -31,8 +32,6 @@ // G = Grouped/Ungrouped // K = Key Extractor -#include - #if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) # if defined(__SGI_STL_PORT) || defined(_STLPORT_VERSION) // STLport doesn't have std::forward. @@ -45,12 +44,51 @@ #define BOOST_UNORDERED_EMPLACE_LIMIT 10 #endif +#if !defined(BOOST_UNORDERED_STD_FORWARD) + +#include +#include +#include + +#define BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ + BOOST_PP_ENUM_PARAMS_Z(z, n, class Arg) +#define BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ + BOOST_PP_ENUM_BINARY_PARAMS_Z(z, n, Arg, const& arg) +#define BOOST_UNORDERED_CALL_PARAMS(z, n) \ + BOOST_PP_ENUM_PARAMS_Z(z, n, arg) + +#endif + namespace boost { namespace unordered_detail { static const float minimum_max_load_factor = 1e-3f; - static const std::size_t default_initial_bucket_count = 11; + static const std::size_t default_bucket_count = 11; struct move_tag {}; + template + class hash_node_constructor; + struct set_extractor; + struct map_extractor; + struct no_key; + + // Explicitly call a destructor + +#if defined(BOOST_MSVC) +#pragma warning(push) +#if BOOST_MSVC >= 1400 +#pragma warning(disable:4100) // unreferenced formal parameter +#endif +#endif + + template + inline void destroy(T* x) { + x->~T(); + } + +#if defined(BOOST_MSVC) +#pragma warning(pop) +#endif + // hash_bucket template @@ -70,8 +108,11 @@ namespace boost { namespace unordered_detail { hash_bucket() : next_() {} // Only copy construct when allocating. - hash_bucket(hash_bucket const& x) : next_() - { BOOST_ASSERT(!x.next_); } + hash_bucket(hash_bucket const& x) + : next_() + { + BOOST_ASSERT(!x.next_); + } }; template @@ -84,12 +125,10 @@ namespace boost { namespace unordered_detail { static inline node_ptr& next_group(node_ptr ptr); static inline std::size_t group_count(node_ptr ptr); static inline void add_to_bucket(node_ptr n, bucket& b); - static inline void add_group_to_bucket(node_ptr n, bucket& b); static inline void add_after_node(node_ptr n, node_ptr position); static void unlink_node(bucket& b, node_ptr node); static void unlink_nodes(bucket& b, node_ptr begin, node_ptr end); static void unlink_nodes(bucket& b, node_ptr end); - static inline void unlink_group(node_ptr* b); }; template @@ -102,21 +141,20 @@ namespace boost { namespace unordered_detail { node_ptr group_prev_; grouped_node_base() : bucket(), group_prev_() {} - static inline node_ptr& group_prev(node_ptr ptr); static inline node_ptr& next_group(node_ptr ptr); + static inline node_ptr first_in_group(node_ptr n); static inline std::size_t group_count(node_ptr ptr); static inline void add_to_bucket(node_ptr n, bucket& b); - static inline void add_group_to_bucket(node_ptr n, bucket& b); static inline void add_after_node(node_ptr n, node_ptr position); static void unlink_node(bucket& b, node_ptr node); static void unlink_nodes(bucket& b, node_ptr begin, node_ptr end); static void unlink_nodes(bucket& b, node_ptr end); - static inline void unlink_group(node_ptr* b); private: static inline node_ptr split_group(node_ptr split); - static inline grouped_node_base& get(node_ptr ptr) - { return static_cast(*ptr); } + static inline grouped_node_base& get(node_ptr ptr) { + return static_cast(*ptr); + } }; struct ungrouped @@ -143,44 +181,73 @@ namespace boost { namespace unordered_detail { sizeof(value_type), ::boost::alignment_of::value>::type data_; - void* address() { return this; } - value_type& value() { return *(ValueType*) this; } + void* address() { + return this; + } + value_type& value() { + return *(ValueType*) this; + } }; // Node - - template - class hash_node : public NodeBase, public value_base + + template + class hash_node : + public G::BOOST_NESTED_TEMPLATE base::type, + public value_base { public: - typedef ValueType value_type; - typedef BOOST_DEDUCED_TYPENAME NodeBase::node_ptr node_ptr; + typedef BOOST_DEDUCED_TYPENAME A::value_type value_type; + typedef BOOST_DEDUCED_TYPENAME hash_bucket::node_ptr node_ptr; - static value_type& get_value(node_ptr p) { return static_cast(*p).value(); } + static value_type& get_value(node_ptr p) { + return static_cast(*p).value(); + } }; // Iterator Base - template + template class hash_iterator_base { public: - typedef BucketPtr bucket_ptr; - typedef BucketPtr node_ptr; + typedef A value_allocator; + typedef hash_bucket bucket; + typedef hash_node node; + typedef BOOST_DEDUCED_TYPENAME node::value_type value_type; + typedef BOOST_DEDUCED_TYPENAME node::bucket_ptr bucket_ptr; + typedef BOOST_DEDUCED_TYPENAME node::node_ptr node_ptr; bucket_ptr bucket_; node_ptr node_; hash_iterator_base() : bucket_(), node_() {} - explicit hash_iterator_base(bucket_ptr b) : bucket_(b), node_(b->next_) {} - hash_iterator_base(bucket_ptr b, node_ptr n) : bucket_(b), node_(n) {} + explicit hash_iterator_base(bucket_ptr b) + : bucket_(b), + node_(b ? b->next_ : node_ptr()) {} + hash_iterator_base(bucket_ptr b, node_ptr n) + : bucket_(b), + node_(n) {} - bool operator==(hash_iterator_base const& x) const { return node_ == x.node_; } - bool operator!=(hash_iterator_base const& x) const { return node_ != x.node_; } - bool is_end() const { return node_ == bucket_; } - node_ptr get() const { return node_; } - void increment(node_ptr node); - void increment(); + bool operator==(hash_iterator_base const& x) const { + return node_ == x.node_; } + bool operator!=(hash_iterator_base const& x) const { + return node_ != x.node_; } + value_type& operator*() const { + return node::get_value(node_); + } + + void increment_bucket(node_ptr node) { + while(!node) { + ++bucket_; + node = bucket_->next_; + } + node_ = bucket_ == node ? node_ptr() : node; + } + + void increment() { + increment_bucket(node_->next_); + } }; // hash_buckets @@ -188,9 +255,10 @@ namespace boost { namespace unordered_detail { // This is responsible for allocating and deallocating buckets and nodes. // // Notes: - // 1. For the sake exception safety the allocators themselves 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). + // 1. For the sake exception safety the allocators themselves don't allocate + // anything. + // 2. It's the callers responsibility to allocate the buckets before calling + // any of the methods (other than getters and setters). template class hash_buckets @@ -201,22 +269,19 @@ namespace boost { namespace unordered_detail { // Types typedef A value_allocator; - typedef BOOST_DEDUCED_TYPENAME A::value_type value_type; - typedef hash_bucket bucket; - typedef BOOST_DEDUCED_TYPENAME G::BOOST_NESTED_TEMPLATE base::type - node_base; - typedef hash_node node; + typedef hash_iterator_base iterator_base; + typedef BOOST_DEDUCED_TYPENAME A::value_type value_type; + typedef BOOST_DEDUCED_TYPENAME iterator_base::node node; typedef BOOST_DEDUCED_TYPENAME node::bucket_allocator bucket_allocator; typedef BOOST_DEDUCED_TYPENAME node::bucket_ptr bucket_ptr; typedef BOOST_DEDUCED_TYPENAME node::node_ptr node_ptr; - typedef BOOST_DEDUCED_TYPENAME rebind_wrap::type node_allocator; + typedef BOOST_DEDUCED_TYPENAME rebind_wrap::type + node_allocator; typedef BOOST_DEDUCED_TYPENAME node_allocator::pointer real_node_ptr; - typedef hash_iterator_base iterator_base; - // Members bucket_ptr buckets_; @@ -225,124 +290,194 @@ namespace boost { namespace unordered_detail { // Data access - bucket_allocator const& bucket_alloc() const { return allocators_.first(); } - node_allocator const& node_alloc() const { return allocators_.second(); } - bucket_allocator& bucket_alloc() { return allocators_.first(); } - node_allocator& node_alloc() { return allocators_.second(); } + bucket_allocator const& bucket_alloc() const { + return allocators_.first(); } + node_allocator const& node_alloc() const { + return allocators_.second(); } + bucket_allocator& bucket_alloc() { + return allocators_.first(); } + node_allocator& node_alloc() { + return allocators_.second(); } std::size_t max_bucket_count() const { // -1 to account for the sentinel. return prev_prime(this->bucket_alloc().max_size() - 1); } // Constructors - // - // The copy constructor doesn't copy the buckets. hash_buckets(node_allocator const& a, std::size_t n); - hash_buckets(hash_buckets& x, move_tag m); - hash_buckets(hash_buckets& x, value_allocator const& a, move_tag m); + void create_buckets(); ~hash_buckets(); // no throw void swap(hash_buckets& other); void move(hash_buckets& other); - // Buckets + // For the remaining functions, buckets_ must not be null. - std::size_t bucket_count() const; - std::size_t bucket_from_hash(std::size_t hashed) const; - bucket_ptr bucket_ptr_from_hash(std::size_t hashed) const; - bucket_ptr buckets_begin() const; - bucket_ptr buckets_end() const; - std::size_t bucket_size(std::size_t index) const; bucket_ptr get_bucket(std::size_t n) const; + bucket_ptr bucket_ptr_from_hash(std::size_t hashed) const; + std::size_t bucket_size(std::size_t index) const; node_ptr bucket_begin(std::size_t n) const; - node_ptr bucket_end(std::size_t) const; // Alloc/Dealloc - void destruct_node(node_ptr); + void delete_node(node_ptr); // void delete_buckets(); void clear_bucket(bucket_ptr); - void delete_group(node_ptr first_node); - void delete_nodes(node_ptr begin, node_ptr end); - void delete_to_bucket_end(node_ptr begin); + std::size_t delete_nodes(node_ptr begin, node_ptr end); + std::size_t delete_to_bucket_end(node_ptr begin); + }; + + template class set_hash_functions; + + template + class hash_buffered_functions + { + friend class set_hash_functions; + hash_buffered_functions& operator=(hash_buffered_functions const&); + + typedef boost::compressed_pair function_pair; + typedef BOOST_DEDUCED_TYPENAME boost::aligned_storage< + sizeof(function_pair), + ::boost::alignment_of::value>::type aligned_function; + + bool current_; // The currently active functions. + aligned_function funcs_[2]; + + function_pair const& current() const { + return *static_cast( + static_cast(&funcs_[current_])); + } + + void construct(bool which, H const& hf, P const& eq) + { + new((void*) &funcs_[which]) function_pair(hf, eq); + } + + void construct(bool which, function_pair const& f) + { + new((void*) &funcs_[which]) function_pair(f); + } + + void destroy(bool which) + { + boost::unordered_detail::destroy((function_pair*)(&funcs_[which])); + } + + public: + + hash_buffered_functions(H const& hf, P const& eq) + : current_(false) + { + construct(current_, hf, eq); + } + + hash_buffered_functions(hash_buffered_functions const& bf) + : current_(false) + { + construct(current_, bf.current()); + } + + ~hash_buffered_functions() { + destroy(current_); + } + + H const& hash_function() const { + return current().first(); + } + + P const& key_eq() const { + return current().second(); + } + }; + + template + class set_hash_functions + { + set_hash_functions(set_hash_functions const&); + set_hash_functions& operator=(set_hash_functions const&); + + typedef hash_buffered_functions buffered_functions; + buffered_functions& buffered_functions_; + bool tmp_functions_; + + public: + + set_hash_functions(buffered_functions& f, H const& h, P const& p) + : buffered_functions_(f), + tmp_functions_(!f.current_) + { + f.construct(tmp_functions_, h, p); + } + + set_hash_functions(buffered_functions& f, + buffered_functions const& other) + : buffered_functions_(f), + tmp_functions_(!f.current_) + { + f.construct(tmp_functions_, other.current()); + } + + ~set_hash_functions() + { + buffered_functions_.destroy(tmp_functions_); + } + + void commit() + { + buffered_functions_.current_ = tmp_functions_; + tmp_functions_ = !tmp_functions_; + } }; template class hash_table : - public hash_buckets - + public hash_buckets, + public hash_buffered_functions { + hash_table(hash_table const&); public: typedef H hasher; typedef P key_equal; typedef A value_allocator; typedef G grouped; typedef K key_extractor; + typedef hash_buffered_functions base; typedef hash_buckets buckets; typedef BOOST_DEDUCED_TYPENAME value_allocator::value_type value_type; - typedef BOOST_DEDUCED_TYPENAME key_extractor::BOOST_NESTED_TEMPLATE apply - extractor; + typedef BOOST_DEDUCED_TYPENAME key_extractor::BOOST_NESTED_TEMPLATE + apply extractor; typedef BOOST_DEDUCED_TYPENAME extractor::key_type key_type; typedef BOOST_DEDUCED_TYPENAME buckets::node node; typedef BOOST_DEDUCED_TYPENAME buckets::bucket bucket; typedef BOOST_DEDUCED_TYPENAME buckets::node_ptr node_ptr; typedef BOOST_DEDUCED_TYPENAME buckets::bucket_ptr bucket_ptr; - typedef BOOST_DEDUCED_TYPENAME buckets::iterator_base iterator_base; - - // Types for storing functions - - typedef boost::compressed_pair functions; - typedef bool functions_ptr; - - typedef BOOST_DEDUCED_TYPENAME boost::aligned_storage< - sizeof(functions), - ::boost::alignment_of::value>::type aligned_function; + typedef BOOST_DEDUCED_TYPENAME buckets::node_allocator node_allocator; + typedef hash_node_constructor node_constructor; + typedef std::pair iterator_pair; // Members - bool func_; // The currently active functions. - aligned_function funcs_[2]; - bucket_ptr cached_begin_bucket_; std::size_t size_; float mlf_; + // Cached data - invalid if !this->buckets_ + bucket_ptr cached_begin_bucket_; std::size_t max_load_; - - // Buffered Functions - - functions* get_functions(bool which) { - return static_cast(static_cast(&this->funcs_[which])); - } - functions const* get_functions(bool which) const { - return static_cast(static_cast(&this->funcs_[which])); - } - functions const& current() const { - return *this->get_functions(this->func_); - } - hasher const& hash_function() const { - return this->current().first(); - } - key_equal const& key_eq() const { - return this->current().second(); - } - functions_ptr buffer_functions(hash_table const& x) { - functions_ptr ptr = !func_; - *this->get_functions(ptr) = x.current(); - return ptr; - } - void set_functions(functions_ptr ptr) { - BOOST_ASSERT(ptr != func_); - func_ = ptr; - } // Helper methods + key_type const& get_key(value_type const& v) const { + return extractor::extract(v); + } + key_type const& get_key_from_ptr(node_ptr n) const { + return extractor::extract(node::get_value(n)); + } bool equal(key_type const& k, value_type const& v) const; node_ptr find_iterator(bucket_ptr bucket, key_type const& k) const; node_ptr find_iterator(key_type const& k) const; @@ -354,31 +489,40 @@ namespace boost { namespace unordered_detail { std::size_t bucket_index(key_type const& k) const; void max_load_factor(float z); std::size_t min_buckets_for_size(std::size_t n) const; - void calculate_max_load(); + std::size_t calculate_max_load(); // Constructors - hash_table(std::size_t n, hasher const& hf, key_equal const& eq, value_allocator const& a); - hash_table(hash_table const& x); - hash_table(hash_table const& x, value_allocator const& a); + hash_table(std::size_t n, hasher const& hf, key_equal const& eq, + node_allocator const& a); + hash_table(hash_table const& x, node_allocator const& a); hash_table(hash_table& x, move_tag m); - hash_table(hash_table& x, value_allocator const& a, move_tag m); - ~hash_table(); + hash_table(hash_table& x, node_allocator const& a, move_tag m); + ~hash_table() {} hash_table& operator=(hash_table const&); // Iterators - iterator_base begin() const { return iterator_base(this->cached_begin_bucket_); } - iterator_base end() const { return iterator_base(this->buckets_end()); } + iterator_base begin() const { + return this->size_ ? + iterator_base(this->cached_begin_bucket_) : + iterator_base(); + } + iterator_base end() const { + return iterator_base(); + } // Swap & Move void swap(hash_table& x); + void fast_swap(hash_table& other); + void slow_swap(hash_table& other); + void partial_swap(hash_table& other); void move(hash_table& x); // Reserve and rehash - bool reserve(std::size_t n); + void create_for_insert(std::size_t n); bool reserve_for_insert(std::size_t n); void rehash(std::size_t n); void rehash_impl(std::size_t n); @@ -393,7 +537,7 @@ namespace boost { namespace unordered_detail { std::size_t count(key_type const& k) const; iterator_base find(key_type const& k) const; value_type& at(key_type const& k) const; - std::pair equal_range(key_type const& k) const; + iterator_pair equal_range(key_type const& k) const; // Erase // @@ -407,7 +551,7 @@ namespace boost { namespace unordered_detail { // recompute_begin_bucket - void recompute_begin_bucket(); + void init_buckets(); // After an erase cached_begin_bucket_ might be left pointing to // an empty bucket, so this is called to update it @@ -424,6 +568,203 @@ namespace boost { namespace unordered_detail { // no throw float load_factor() const; + + iterator_base emplace_empty_impl_with_node( + node_constructor&, std::size_t); + }; + + template + class hash_unique_table : + public hash_table + + { + public: + typedef H hasher; + typedef P key_equal; + typedef A value_allocator; + typedef K key_extractor; + + typedef hash_table table; + typedef hash_node_constructor node_constructor; + + typedef BOOST_DEDUCED_TYPENAME table::key_type key_type; + typedef BOOST_DEDUCED_TYPENAME table::value_type value_type; + typedef BOOST_DEDUCED_TYPENAME table::node node; + typedef BOOST_DEDUCED_TYPENAME table::node_ptr node_ptr; + typedef BOOST_DEDUCED_TYPENAME table::bucket_ptr bucket_ptr; + typedef BOOST_DEDUCED_TYPENAME table::iterator_base iterator_base; + typedef BOOST_DEDUCED_TYPENAME table::extractor extractor; + + typedef std::pair emplace_return; + + // Constructors + + hash_unique_table(std::size_t n, hasher const& hf, key_equal const& eq, + value_allocator const& a) + : table(n, hf, eq, a) {} + hash_unique_table(hash_unique_table const& x) + : table(x, x.node_alloc()) {} + hash_unique_table(hash_unique_table const& x, value_allocator const& a) + : table(x, a) {} + hash_unique_table(hash_unique_table& x, move_tag m) + : table(x, m) {} + hash_unique_table(hash_unique_table& x, value_allocator const& a, + move_tag m) + : table(x, a, m) {} + ~hash_unique_table() {} + + // Insert methods + + emplace_return emplace_impl_with_node(node_constructor& a); + value_type& operator[](key_type const& k); + + // equals + + bool equals(hash_unique_table const&) const; + + node_ptr add_node(node_constructor& a, bucket_ptr bucket); + +#if defined(BOOST_UNORDERED_STD_FORWARD) + + template + emplace_return emplace(Args&&... args); + template + iterator_base emplace_hint(iterator_base const&, Args&&... args); + template + emplace_return emplace_impl(key_type const& k, Args&&... args); + template + emplace_return emplace_impl(no_key, Args&&... args); + template + emplace_return emplace_empty_impl(Args&&... args); +#else + template + emplace_return emplace(Arg0 const& arg0); + template + iterator_base emplace_hint(iterator_base const&, Arg0 const& arg0); + +#define BOOST_UNORDERED_INSERT_IMPL(z, n, _) \ + template \ + emplace_return emplace( \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n)); \ + template \ + iterator_base emplace_hint(iterator_base const& it, \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n)); \ + BOOST_UNORDERED_INSERT_IMPL2(z, n, _) + +#define BOOST_UNORDERED_INSERT_IMPL2(z, n, _) \ + template \ + emplace_return emplace_impl(key_type const& k, \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n)); \ + template \ + emplace_return emplace_impl(no_key, \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n)); \ + template \ + emplace_return emplace_empty_impl( \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n)); + + BOOST_UNORDERED_INSERT_IMPL2(1, 1, _) + + BOOST_PP_REPEAT_FROM_TO(2, BOOST_UNORDERED_EMPLACE_LIMIT, + BOOST_UNORDERED_INSERT_IMPL, _) + +#undef BOOST_UNORDERED_INSERT_IMPL +#undef BOOST_UNORDERED_INSERT_IMPL2 + +#endif + + // if hash function throws, or inserting > 1 element, basic exception + // safety strong otherwise + template + void insert_range(InputIt i, InputIt j); + template + void insert_range_impl(key_type const&, InputIt i, InputIt j); + template + void insert_range_impl(no_key, InputIt i, InputIt j); + }; + + template + class hash_equivalent_table : + public hash_table + + { + public: + typedef H hasher; + typedef P key_equal; + typedef A value_allocator; + typedef K key_extractor; + + typedef hash_table table; + typedef hash_node_constructor + node_constructor; + typedef hash_iterator_base iterator_base; + + typedef BOOST_DEDUCED_TYPENAME table::key_type key_type; + typedef BOOST_DEDUCED_TYPENAME table::value_type value_type; + typedef BOOST_DEDUCED_TYPENAME table::node node; + typedef BOOST_DEDUCED_TYPENAME table::node_ptr node_ptr; + typedef BOOST_DEDUCED_TYPENAME table::bucket_ptr bucket_ptr; + typedef BOOST_DEDUCED_TYPENAME table::extractor extractor; + + // Constructors + + hash_equivalent_table(std::size_t n, + hasher const& hf, key_equal const& eq, value_allocator const& a) + : table(n, hf, eq, a) {} + hash_equivalent_table(hash_equivalent_table const& x) + : table(x, x.node_alloc()) {} + hash_equivalent_table(hash_equivalent_table const& x, + value_allocator const& a) + : table(x, a) {} + hash_equivalent_table(hash_equivalent_table& x, move_tag m) + : table(x, m) {} + hash_equivalent_table(hash_equivalent_table& x, + value_allocator const& a, move_tag m) + : table(x, a, m) {} + ~hash_equivalent_table() {} + + // Insert methods + + iterator_base emplace_impl(node_constructor& a); + iterator_base emplace_hint_impl(iterator_base const& it, + node_constructor& a); + void emplace_impl_no_rehash(node_constructor& a); + + // equals + + bool equals(hash_equivalent_table const&) const; + + inline node_ptr add_node(node_constructor& a, + bucket_ptr bucket, node_ptr pos); + +#if defined(BOOST_UNORDERED_STD_FORWARD) + + template + iterator_base emplace(Args&&... args); + template + iterator_base emplace_hint(iterator_base const& it, Args&&... args); + +#else + +#define BOOST_UNORDERED_INSERT_IMPL(z, n, _) \ + template \ + iterator_base emplace(BOOST_UNORDERED_FUNCTION_PARAMS(z, n)); \ + \ + template \ + iterator_base emplace_hint(iterator_base const& it, \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n)); + + BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, + BOOST_UNORDERED_INSERT_IMPL, _) + +#undef BOOST_UNORDERED_INSERT_IMPL +#endif + + template + void insert_for_range(I i, I j, forward_traversal_tag); + template + void insert_for_range(I i, I j, boost::incrementable_traversal_tag); + template + void insert_range(I i, I j); }; // Iterator Access @@ -432,7 +773,9 @@ namespace boost { namespace unordered_detail { { public: template - static BOOST_DEDUCED_TYPENAME Iterator::base const& get(Iterator const& it) { + static BOOST_DEDUCED_TYPENAME Iterator::base const& + get(Iterator const& it) + { return it.base_; } }; @@ -462,25 +805,39 @@ namespace boost { namespace unordered_detail { private: typedef hash_buckets buckets; - typedef BOOST_DEDUCED_TYPENAME buckets::node_ptr ptr; + typedef BOOST_DEDUCED_TYPENAME buckets::node_ptr node_ptr; typedef BOOST_DEDUCED_TYPENAME buckets::node node; typedef hash_const_local_iterator const_local_iterator; friend class hash_const_local_iterator; - ptr ptr_; + node_ptr ptr_; public: hash_local_iterator() : ptr_() {} - explicit hash_local_iterator(ptr x) : ptr_(x) {} - BOOST_DEDUCED_TYPENAME A::reference operator*() const - { return node::get_value(ptr_); } - value_type* operator->() const { return &node::get_value(ptr_); } - hash_local_iterator& operator++() { ptr_ = next_node(ptr_); return *this; } - hash_local_iterator operator++(int) { hash_local_iterator tmp(ptr_); ptr_ = next_node(ptr_); return tmp; } - bool operator==(hash_local_iterator x) const { return ptr_ == x.ptr_; } - bool operator==(const_local_iterator x) const { return ptr_ == x.ptr_; } - bool operator!=(hash_local_iterator x) const { return ptr_ != x.ptr_; } - bool operator!=(const_local_iterator x) const { return ptr_ != x.ptr_; } + explicit hash_local_iterator(node_ptr x) : ptr_(x) {} + BOOST_DEDUCED_TYPENAME A::reference operator*() const { + return node::get_value(ptr_); + } + value_type* operator->() const { + return &node::get_value(ptr_); + } + hash_local_iterator& operator++() { + ptr_ = ptr_->next_; return *this; + } + hash_local_iterator operator++(int) { + hash_local_iterator tmp(ptr_); ptr_ = ptr_->next_; return tmp; } + bool operator==(hash_local_iterator x) const { + return ptr_ == x.ptr_; + } + bool operator==(const_local_iterator x) const { + return ptr_ == x.ptr_; + } + bool operator!=(hash_local_iterator x) const { + return ptr_ != x.ptr_; + } + bool operator!=(const_local_iterator x) const { + return ptr_ != x.ptr_; + } }; template @@ -508,14 +865,30 @@ namespace boost { namespace unordered_detail { explicit hash_const_local_iterator(ptr x) : ptr_(x) {} hash_const_local_iterator(local_iterator x) : ptr_(x.ptr_) {} BOOST_DEDUCED_TYPENAME A::const_reference - operator*() const { return node::get_value(ptr_); } - value_type const* operator->() const { return &node::get_value(ptr_); } - hash_const_local_iterator& operator++() { ptr_ = next_node(ptr_); return *this; } - hash_const_local_iterator operator++(int) { hash_const_local_iterator tmp(ptr_); ptr_ = next_node(ptr_); return tmp; } - bool operator==(local_iterator x) const { return ptr_ == x.ptr_; } - bool operator==(hash_const_local_iterator x) const { return ptr_ == x.ptr_; } - bool operator!=(local_iterator x) const { return ptr_ != x.ptr_; } - bool operator!=(hash_const_local_iterator x) const { return ptr_ != x.ptr_; } + operator*() const { + return node::get_value(ptr_); + } + value_type const* operator->() const { + return &node::get_value(ptr_); + } + hash_const_local_iterator& operator++() { + ptr_ = ptr_->next_; return *this; + } + hash_const_local_iterator operator++(int) { + hash_const_local_iterator tmp(ptr_); ptr_ = ptr_->next_; return tmp; + } + bool operator==(local_iterator x) const { + return ptr_ == x.ptr_; + } + bool operator==(hash_const_local_iterator x) const { + return ptr_ == x.ptr_; + } + bool operator!=(local_iterator x) const { + return ptr_ != x.ptr_; + } + bool operator!=(hash_const_local_iterator x) const { + return ptr_ != x.ptr_; + } }; // iterators @@ -547,15 +920,30 @@ namespace boost { namespace unordered_detail { hash_iterator() : base_() {} explicit hash_iterator(base const& x) : base_(x) {} - BOOST_DEDUCED_TYPENAME A::reference - operator*() const { return node::get_value(base_.get()); } - value_type* operator->() const { return &node::get_value(base_.get()); } - hash_iterator& operator++() { base_.increment(); return *this; } - hash_iterator operator++(int) { hash_iterator tmp(base_); base_.increment(); return tmp; } - bool operator==(hash_iterator const& x) const { return base_ == x.base_; } - bool operator==(const_iterator const& x) const { return base_ == x.base_; } - bool operator!=(hash_iterator const& x) const { return base_ != x.base_; } - bool operator!=(const_iterator const& x) const { return base_ != x.base_; } + BOOST_DEDUCED_TYPENAME A::reference operator*() const { + return *base_; + } + value_type* operator->() const { + return &*base_; + } + hash_iterator& operator++() { + base_.increment(); return *this; + } + hash_iterator operator++(int) { + hash_iterator tmp(base_); base_.increment(); return tmp; + } + bool operator==(hash_iterator const& x) const { + return base_ == x.base_; + } + bool operator==(const_iterator const& x) const { + return base_ == x.base_; + } + bool operator!=(hash_iterator const& x) const { + return base_ != x.base_; + } + bool operator!=(const_iterator const& x) const { + return base_ != x.base_; + } }; template @@ -584,15 +972,30 @@ namespace boost { namespace unordered_detail { hash_const_iterator() : base_() {} explicit hash_const_iterator(base const& x) : base_(x) {} hash_const_iterator(iterator const& x) : base_(x.base_) {} - BOOST_DEDUCED_TYPENAME A::const_reference - operator*() const { return node::get_value(base_.get()); } - value_type const* operator->() const { return &node::get_value(base_.get()); } - hash_const_iterator& operator++() { base_.increment(); return *this; } - hash_const_iterator operator++(int) { hash_const_iterator tmp(base_); base_.increment(); return tmp; } - bool operator==(iterator const& x) const { return base_ == x.base_; } - bool operator==(hash_const_iterator const& x) const { return base_ == x.base_; } - bool operator!=(iterator const& x) const { return base_ != x.base_; } - bool operator!=(hash_const_iterator const& x) const { return base_ != x.base_; } + BOOST_DEDUCED_TYPENAME A::const_reference operator*() const { + return *base_; + } + value_type const* operator->() const { + return &*base_; + } + hash_const_iterator& operator++() { + base_.increment(); return *this; + } + hash_const_iterator operator++(int) { + hash_const_iterator tmp(base_); base_.increment(); return tmp; + } + bool operator==(iterator const& x) const { + return base_ == x.base_; + } + bool operator==(hash_const_iterator const& x) const { + return base_ == x.base_; + } + bool operator!=(iterator const& x) const { + return base_ != x.base_; + } + bool operator!=(hash_const_iterator const& x) const { + return base_ != x.base_; + } }; }} diff --git a/include/boost/unordered/detail/insert.hpp b/include/boost/unordered/detail/insert.hpp deleted file mode 100644 index 28c27eb4..00000000 --- a/include/boost/unordered/detail/insert.hpp +++ /dev/null @@ -1,678 +0,0 @@ - -// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard. -// Copyright (C) 2005-2009 Daniel James -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -#ifndef BOOST_UNORDERED_DETAIL_INSERT_HPP_INCLUDED -#define BOOST_UNORDERED_DETAIL_INSERT_HPP_INCLUDED - -#include -#include - -namespace boost { namespace unordered_detail { - - //////////////////////////////////////////////////////////////////////////// - // A couple of convenience methods for adding nodes. - - // H = Has Func - // P = Predicate - // A = Value Allocator - // K = Key Extractor - - template - class hash_unique_table : - public hash_table - - { - public: - typedef H hasher; - typedef P key_equal; - typedef A value_allocator; - typedef K key_extractor; - - typedef hash_table table; - typedef hash_node_constructor node_constructor; - - typedef BOOST_DEDUCED_TYPENAME table::key_type key_type; - typedef BOOST_DEDUCED_TYPENAME table::value_type value_type; - typedef BOOST_DEDUCED_TYPENAME table::node node; - typedef BOOST_DEDUCED_TYPENAME table::node_ptr node_ptr; - typedef BOOST_DEDUCED_TYPENAME table::bucket_ptr bucket_ptr; - typedef BOOST_DEDUCED_TYPENAME table::iterator_base iterator_base; - typedef BOOST_DEDUCED_TYPENAME table::extractor extractor; - - // Constructors - - hash_unique_table(std::size_t n, hasher const& hf, key_equal const& eq, value_allocator const& a) - : table(n, hf, eq, a) {} - hash_unique_table(hash_unique_table const& x) - : table(x) {} - hash_unique_table(hash_unique_table const& x, value_allocator const& a) - : table(x, a) {} - hash_unique_table(hash_unique_table& x, move_tag m) - : table(x, m) {} - hash_unique_table(hash_unique_table& x, value_allocator const& a, move_tag m) - : table(x, a, m) {} - ~hash_unique_table() {} - - // Insert methods - - std::pair emplace_impl_with_node(node_constructor& a); - value_type& operator[](key_type const& k); - - // equals - - bool equals(hash_unique_table const&) const; - static bool group_equals(node_ptr it1, node_ptr it2, set_extractor*); - static bool group_equals(node_ptr it1, node_ptr it2, map_extractor*); - - inline node_ptr add_node(node_constructor& a, bucket_ptr bucket) - { - node_ptr n = a.release(); - node::add_to_bucket(n, *bucket); - ++this->size_; - if(bucket < this->cached_begin_bucket_) this->cached_begin_bucket_ = bucket; - return n; - } - -#if defined(BOOST_UNORDERED_STD_FORWARD) - - // Emplace (unique keys) - // (I'm using an overloaded emplace for both 'insert' and 'emplace') - - // if hash function throws, basic exception safety - // strong otherwise - template - std::pair emplace(Args&&... args) - { - return emplace_impl( - extractor::extract(std::forward(args)...), - std::forward(args)...); - } - - // Insert (unique keys) - // (I'm using an overloaded emplace for both 'insert' and 'emplace') - // I'm just ignoring hints here for now. - - // if hash function throws, basic exception safety - // strong otherwise - template - iterator_base emplace_hint(iterator_base const&, Args&&... args) - { - return emplace_impl( - extractor::extract(std::forward(args)...), - std::forward(args)...).first; - } - - template - std::pair emplace_impl(key_type const& k, Args&&... args) - { - // No side effects in this initial code - std::size_t hash_value = this->hash_function()(k); - bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value); - node_ptr pos = find_iterator(bucket, k); - - if (BOOST_UNORDERED_BORLAND_BOOL(pos)) { - // Found an existing key, return it (no throw). - return std::pair( - iterator_base(bucket, pos), false); - - } else { - // Doesn't already exist, add to bucket. - // Side effects only in this block. - - // Create the node before rehashing in case it throws an - // exception (need strong safety in such a case). - node_constructor a(*this); - a.construct(std::forward(args)...); - - // reserve has basic exception safety if the hash function - // throws, strong otherwise. - if(reserve_for_insert(this->size_ + 1)) - bucket = this->bucket_ptr_from_hash(hash_value); - - // Nothing after this point can throw. - - return std::pair(iterator_base(bucket, - add_node(a, bucket)), true); - } - } - - template - std::pair emplace_impl(no_key, Args&&... args) - { - // Construct the node regardless - in order to get the key. - // It will be discarded if it isn't used - node_constructor a(*this); - a.construct(std::forward(args)...); - return emplace_impl_with_node(a); - } -#else - template - std::pair emplace(Arg0 const& arg0) - { - return emplace_impl(extractor::extract(arg0), arg0); - } - - template - iterator_base emplace_hint(iterator_base const&, Arg0 const& arg0) - { - return emplace_impl(extractor::extract(arg0), arg0).first; - } - -#define BOOST_UNORDERED_INSERT_IMPL(z, n, _) \ - template \ - std::pair emplace( \ - BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ - ) \ - { \ - return emplace_impl(extractor::extract(arg0, arg1), \ - BOOST_UNORDERED_CALL_PARAMS(z, n)); \ - } \ - \ - template \ - iterator_base emplace_hint(iterator_base const& it, \ - BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ - ) \ - { \ - return emplace_impl(extractor::extract(arg0, arg1), \ - BOOST_UNORDERED_CALL_PARAMS(z, n)).first; \ - } \ - BOOST_UNORDERED_INSERT_IMPL2(z, n, _) - -#define BOOST_UNORDERED_INSERT_IMPL2(z, n, _) \ - template \ - std::pair emplace_impl(key_type const& k, \ - BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ - ) \ - { \ - std::size_t hash_value = this->hash_function()(k); \ - bucket_ptr bucket \ - = this->bucket_ptr_from_hash(hash_value); \ - node_ptr pos = find_iterator(bucket, k); \ - \ - if (BOOST_UNORDERED_BORLAND_BOOL(pos)) { \ - return std::pair( \ - iterator_base(bucket, pos), false); \ - } else { \ - node_constructor a(*this); \ - a.construct(BOOST_UNORDERED_CALL_PARAMS(z, n)); \ - \ - if(reserve_for_insert(this->size_ + 1)) \ - bucket = this->bucket_ptr_from_hash(hash_value); \ - \ - return std::pair(iterator_base(bucket, \ - add_node(a, bucket)), true); \ - } \ - } \ - \ - template \ - std::pair 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_UNORDERED_INSERT_IMPL2(1, 1, _) - - BOOST_PP_REPEAT_FROM_TO(2, BOOST_UNORDERED_EMPLACE_LIMIT, - BOOST_UNORDERED_INSERT_IMPL, _) - -#undef BOOST_UNORDERED_INSERT_IMPL - -#endif - - // if hash function throws, or inserting > 1 element, basic exception safety - // strong otherwise - template - void insert_range(InputIterator i, InputIterator j) - { - if(i != j) - return insert_range_impl(extractor::extract(*i), i, j); - } - - template - void insert_range_impl(key_type const&, InputIterator i, InputIterator j) - { - node_constructor a(*this); - - for (; i != j; ++i) { - // No side effects in this initial code - std::size_t hash_value = this->hash_function()(extractor::extract(*i)); - bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value); - node_ptr pos = find_iterator(bucket, extractor::extract(*i)); - - if (!BOOST_UNORDERED_BORLAND_BOOL(pos)) { - // Doesn't already exist, add to bucket. - // Side effects only in this block. - - // Create the node before rehashing in case it throws an - // exception (need strong safety in such a case). - a.construct(*i); - - // reserve has basic exception safety if the hash function - // throws, strong otherwise. - if(this->size_ + 1 >= this->max_load_) { - reserve_for_insert(this->size_ + insert_size(i, j)); - bucket = this->bucket_ptr_from_hash(hash_value); - } - - // Nothing after this point can throw. - add_node(a, bucket); - } - } - } - - template - void insert_range_impl(no_key, InputIterator i, InputIterator j) - { - node_constructor a(*this); - - for (; i != j; ++i) { - // No side effects in this initial code - a.construct(*i); - emplace_impl_with_node(a); - } - } - }; - - template - class hash_equivalent_table : - public hash_table - - { - public: - typedef H hasher; - typedef P key_equal; - typedef A value_allocator; - typedef K key_extractor; - - typedef hash_table table; - typedef hash_node_constructor node_constructor; - - typedef BOOST_DEDUCED_TYPENAME table::key_type key_type; - typedef BOOST_DEDUCED_TYPENAME table::value_type value_type; - typedef BOOST_DEDUCED_TYPENAME table::node node; - typedef BOOST_DEDUCED_TYPENAME table::node_ptr node_ptr; - typedef BOOST_DEDUCED_TYPENAME table::bucket_ptr bucket_ptr; - typedef BOOST_DEDUCED_TYPENAME table::iterator_base iterator_base; - typedef BOOST_DEDUCED_TYPENAME table::extractor extractor; - - // Constructors - - hash_equivalent_table(std::size_t n, hasher const& hf, key_equal const& eq, value_allocator const& a) - : table(n, hf, eq, a) {} - hash_equivalent_table(hash_equivalent_table const& x) - : table(x) {} - hash_equivalent_table(hash_equivalent_table const& x, value_allocator const& a) - : table(x, a) {} - hash_equivalent_table(hash_equivalent_table& x, move_tag m) - : table(x, m) {} - hash_equivalent_table(hash_equivalent_table& x, value_allocator const& a, move_tag m) - : table(x, a, m) {} - ~hash_equivalent_table() {} - - // Insert methods - - iterator_base emplace_impl(node_constructor& a); - iterator_base emplace_hint_impl(iterator_base const& it, node_constructor& a); - void emplace_impl_no_rehash(node_constructor& a); - - // equals - - bool equals(hash_equivalent_table const&) const; - static bool group_equals(node_ptr it1, node_ptr it2, set_extractor*); - static bool group_equals(node_ptr it1, node_ptr it2, map_extractor*); - - inline node_ptr add_node(node_constructor& a, bucket_ptr bucket, node_ptr pos) - { - node_ptr n = a.release(); - if(BOOST_UNORDERED_BORLAND_BOOL(pos)) { - node::add_after_node(n, pos); - } - else { - node::add_to_bucket(n, *bucket); - if(bucket < this->cached_begin_bucket_) this->cached_begin_bucket_ = bucket; - } - ++this->size_; - return n; - } - - public: - - // Insert functions - // - // basic exception safety, if hash function throws - // strong otherwise. - -#if defined(BOOST_UNORDERED_STD_FORWARD) - - // Emplace (equivalent key containers) - // (I'm using an overloaded emplace for both 'insert' and 'emplace') - - // if hash function throws, basic exception safety - // strong otherwise - template - iterator_base emplace(Args&&... args) - { - // Create the node before rehashing in case it throws an - // exception (need strong safety in such a case). - node_constructor a(*this); - a.construct(std::forward(args)...); - - return emplace_impl(a); - } - - // Emplace (equivalent key containers) - // (I'm using an overloaded emplace for both 'insert' and 'emplace') - - // if hash function throws, basic exception safety - // strong otherwise - template - iterator_base emplace_hint(iterator_base const& it, Args&&... args) - { - // Create the node before rehashing in case it throws an - // exception (need strong safety in such a case). - node_constructor a(*this); - a.construct(std::forward(args)...); - - return emplace_hint_impl(it, a); - } - -#else - -#define BOOST_UNORDERED_INSERT_IMPL(z, n, _) \ - template \ - iterator_base emplace( \ - BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ - ) \ - { \ - node_constructor a(*this); \ - a.construct(BOOST_UNORDERED_CALL_PARAMS(z, n)); \ - return emplace_impl(a); \ - } \ - \ - template \ - iterator_base emplace_hint(iterator_base const& it, \ - BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ - ) \ - { \ - node_constructor a(*this); \ - a.construct(BOOST_UNORDERED_CALL_PARAMS(z, n)); \ - return emplace_hint_impl(it, a); \ - } - - BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, - BOOST_UNORDERED_INSERT_IMPL, _) - -#undef BOOST_UNORDERED_INSERT_IMPL -#endif - - // Insert from iterator range (equivalent key containers) - - private: - - // 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) - { - std::size_t distance = unordered_detail::distance(i, j); - if(distance == 1) { - emplace(*i); - } - else { - // Only require basic exception safety here - reserve_for_insert(this->size_ + distance); - node_constructor a(*this); - - for (; i != j; ++i) { - a.construct(*i); - emplace_impl_no_rehash(a); - } - } - } - - // if hash function throws, or inserting > 1 element, basic exception safety - // strong otherwise - template - void insert_for_range(I i, I j, - boost::incrementable_traversal_tag) - { - node_constructor a(*this); - for (; i != j; ++i) { - a.construct(*i); - emplace_impl(a); - } - } - - public: - - // if hash function throws, or inserting > 1 element, basic exception safety - // strong otherwise - template - void insert_range(I i, I j) - { - BOOST_DEDUCED_TYPENAME boost::iterator_traversal::type - iterator_traversal_tag; - insert_for_range(i, j, iterator_traversal_tag); - } - }; - - //////////////////////////////////////////////////////////////////////////// - // Unique insert methods - - template - std::pair< - BOOST_DEDUCED_TYPENAME hash_unique_table::iterator_base, - bool> - hash_unique_table - ::emplace_impl_with_node(node_constructor& a) - { - // No side effects in this initial code - key_type const& k = extractor::extract(a.get()->value()); - std::size_t hash_value = this->hash_function()(k); - bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value); - node_ptr pos = find_iterator(bucket, k); - - if (BOOST_UNORDERED_BORLAND_BOOL(pos)) { - // Found an existing key, return it (no throw). - return std::pair( - iterator_base(bucket, pos), false); - } else { - // reserve has basic exception safety if the hash function - // throws, strong otherwise. - if(reserve_for_insert(this->size_ + 1)) - bucket = this->bucket_ptr_from_hash(hash_value); - - // Nothing after this point can throw. - - return std::pair(iterator_base(bucket, - add_node(a, bucket)), true); - } - } - - // if hash function throws, basic exception safety - // strong otherwise - template - BOOST_DEDUCED_TYPENAME hash_unique_table::value_type& - hash_unique_table - ::operator[](key_type const& k) - { - typedef BOOST_DEDUCED_TYPENAME value_type::second_type mapped_type; - - std::size_t hash_value = this->hash_function()(k); - bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value); - node_ptr pos = find_iterator(bucket, k); - - if (BOOST_UNORDERED_BORLAND_BOOL(pos)) { - return node::get_value(pos); - } - else { - // Side effects only in this block. - - // Create the node before rehashing in case it throws an - // exception (need strong safety in such a case). - node_constructor a(*this); - a.construct_pair(k, (mapped_type*) 0); - - // reserve has basic exception safety if the hash function - // throws, strong otherwise. - if(reserve_for_insert(this->size_ + 1)) - bucket = this->bucket_ptr_from_hash(hash_value); - - // Nothing after this point can throw. - - return node::get_value(add_node(a, bucket)); - } - } - - //////////////////////////////////////////////////////////////////////////// - // Insert methods - - template - BOOST_DEDUCED_TYPENAME hash_equivalent_table::iterator_base - hash_equivalent_table - ::emplace_impl(node_constructor& a) - { - key_type const& k = extractor::extract(a.get()->value()); - std::size_t hash_value = this->hash_function()(k); - bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value); - node_ptr position = find_iterator(bucket, k); - - // reserve has basic exception safety if the hash function - // throws, strong otherwise. - if(reserve_for_insert(this->size_ + 1)) - bucket = this->bucket_ptr_from_hash(hash_value); - - // I'm relying on node_ptr not being invalidated by - // the rehash here. - return iterator_base(bucket, add_node(a, bucket, position)); - } - - template - BOOST_DEDUCED_TYPENAME hash_equivalent_table::iterator_base - hash_equivalent_table - ::emplace_hint_impl(iterator_base const& it, node_constructor& a) - { - // equal can throw, but with no effects - if (it.is_end() || - !equal(extractor::extract(a.get()->value()), node::get_value(it.get()))) { - // Use the standard emplace if the iterator doesn't point - // to a matching key. - return emplace_impl(a); - } - else { - // Find the first node in the group - so that the node - // will be added at the end of the group. - - node_ptr start(it.node_); - while(node::next_group(start) == start) - start = node::group_prev(start); - - // reserve has basic exception safety if the hash function - // throws, strong otherwise. - bucket_ptr bucket = reserve_for_insert(this->size_ + 1) ? - get_bucket(this->bucket_index( - extractor::extract(a.get()->value()))) : it.bucket_; - - // Nothing after this point can throw - - return iterator_base(bucket, add_node(a, bucket, start)); - } - } - - template - void hash_equivalent_table - ::emplace_impl_no_rehash(node_constructor& a) - { - key_type const& k = extractor::extract(a.get()->value()); - bucket_ptr bucket = this->get_bucket(this->bucket_index(k)); - add_node(a, bucket, find_iterator(bucket, k)); - } - - //////////////////////////////////////////////////////////////////////////// - // Equalilty check - - template - inline bool hash_equivalent_table - ::group_equals(node_ptr it1, node_ptr it2, set_extractor*) - { - return node::group_count(it1) == node::group_count(it2); - } - - template - inline bool hash_equivalent_table - ::group_equals(node_ptr it1, node_ptr it2, map_extractor*) - { - node_ptr end1 = node::next_group(it1); - node_ptr end2 = node::next_group(it2); - - do { - if(node::get_value(it1).second != node::get_value(it2).second) return false; - it1 = next_node(it1); - it2 = next_node(it2); - } while(it1 != end1 && it2 != end2); - return it1 == end1 && it2 == end2; - } - - template - bool hash_equivalent_table - ::equals(hash_equivalent_table const& other) const - { - if(this->size_ != other.size_) return false; - - for(bucket_ptr i = this->cached_begin_bucket_, j = this->buckets_end(); i != j; ++i) - { - for(node_ptr it(i->next_); BOOST_UNORDERED_BORLAND_BOOL(it); it = node::next_group(it)) - { - node_ptr other_pos = other.find_iterator(extractor::extract(node::get_value(it))); - if(!BOOST_UNORDERED_BORLAND_BOOL(other_pos) || - !group_equals(it, other_pos, (K*)0)) - return false; - } - } - - return true; - } - - template - inline bool hash_unique_table - ::group_equals(node_ptr, node_ptr, set_extractor*) - { - return true; - } - - template - inline bool hash_unique_table - ::group_equals(node_ptr it1, node_ptr it2, map_extractor*) - { - return node::get_value(it1).second == node::get_value(it2).second; - } - - template - bool hash_unique_table - ::equals(hash_unique_table const& other) const - { - if(this->size_ != other.size_) return false; - - for(bucket_ptr i = this->cached_begin_bucket_, j = this->buckets_end(); i != j; ++i) - { - for(node_ptr it(i->next_); BOOST_UNORDERED_BORLAND_BOOL(it); it = node::next_group(it)) - { - node_ptr other_pos = other.find_iterator(extractor::extract(node::get_value(it))); - if(!BOOST_UNORDERED_BORLAND_BOOL(other_pos) || - !group_equals(it, other_pos, (K*)0)) - return false; - } - } - - return true; - } - -}} - -#endif diff --git a/include/boost/unordered/detail/move.hpp b/include/boost/unordered/detail/move.hpp index 317b20fd..16fd9212 100644 --- a/include/boost/unordered/detail/move.hpp +++ b/include/boost/unordered/detail/move.hpp @@ -109,6 +109,8 @@ struct move_from { explicit move_from(T& x) : source(x) { } T& source; +private: + move_from& operator=(move_from const&); }; /*************************************************************************************************/ diff --git a/include/boost/unordered/detail/node.hpp b/include/boost/unordered/detail/node.hpp index 90099f46..21645105 100644 --- a/include/boost/unordered/detail/node.hpp +++ b/include/boost/unordered/detail/node.hpp @@ -24,23 +24,6 @@ namespace boost { namespace unordered_detail { - template - inline BucketPtr& next_node(BucketPtr ptr) - { - return ptr->next_; - } - - template - inline std::size_t node_count(BucketPtr ptr, BucketPtr end) - { - std::size_t count = 0; - while(ptr != end) { - ++count; - ptr = next_node(ptr); - } - return count; - } - //////////////////////////////////////////////////////////////////////////// // ungrouped node implementation @@ -48,7 +31,7 @@ namespace boost { namespace unordered_detail { inline BOOST_DEDUCED_TYPENAME ungrouped_node_base::node_ptr& ungrouped_node_base::next_group(node_ptr ptr) { - return next_node(ptr); + return ptr->next_; } template @@ -60,35 +43,24 @@ namespace boost { namespace unordered_detail { template inline void ungrouped_node_base::add_to_bucket(node_ptr n, bucket& b) { - next_node(n) = b.next_; + n->next_ = b.next_; b.next_ = n; } template - inline void ungrouped_node_base::add_group_to_bucket(node_ptr n, bucket& b) + inline void ungrouped_node_base::add_after_node(node_ptr n, + node_ptr position) { - next_node(n) = b.next_; - b.next_ = n; - } - - template - inline void ungrouped_node_base::add_after_node(node_ptr n, node_ptr position) - { - next_node(n) = next_node(position); - next_node(position) = position; + n->next_ = position->next_; + position->next_ = position; } template - inline void ungrouped_node_base::unlink_node(bucket& b, node_ptr node) - { - unlink_nodes(b, node, next_node(node)); - } - - template - inline void ungrouped_node_base::unlink_nodes(bucket& b, node_ptr begin, node_ptr end) + inline void ungrouped_node_base::unlink_nodes(bucket& b, + node_ptr begin, node_ptr end) { node_ptr* pos = &b.next_; - while(*pos != begin) pos = &next_node(*pos); + while(*pos != begin) pos = &(*pos)->next_; *pos = end; } @@ -99,26 +71,30 @@ namespace boost { namespace unordered_detail { } template - inline void ungrouped_node_base::unlink_group(node_ptr* b) + inline void ungrouped_node_base::unlink_node(bucket& b, node_ptr node) { - *b = next_node(*b); + unlink_nodes(b, node, node->next_); } //////////////////////////////////////////////////////////////////////////// // grouped node implementation - template - inline BOOST_DEDUCED_TYPENAME grouped_node_base::node_ptr& - grouped_node_base::group_prev(node_ptr ptr) - { - return get(ptr).group_prev_; - } - + // If ptr is the first element in a group, return pointer to next group. + // Otherwise returns a pointer to ptr. template inline BOOST_DEDUCED_TYPENAME grouped_node_base::node_ptr& grouped_node_base::next_group(node_ptr ptr) { - return next_node(group_prev(ptr)); + return get(ptr).group_prev_->next_; + } + + template + inline BOOST_DEDUCED_TYPENAME grouped_node_base::node_ptr + grouped_node_base::first_in_group(node_ptr ptr) + { + while(next_group(ptr) == ptr) + ptr = get(ptr).group_prev_; + return ptr; } template @@ -128,7 +104,7 @@ namespace boost { namespace unordered_detail { std::size_t size = 0; do { ++size; - ptr = group_prev(ptr); + ptr = get(ptr).group_prev_; } while(ptr != start); return size; } @@ -136,25 +112,18 @@ namespace boost { namespace unordered_detail { template inline void grouped_node_base::add_to_bucket(node_ptr n, bucket& b) { - next_node(n) = b.next_; - group_prev(n) = n; + n->next_ = b.next_; + get(n).group_prev_ = n; b.next_ = n; } template - inline void grouped_node_base::add_group_to_bucket(node_ptr n, bucket& b) + inline void grouped_node_base::add_after_node(node_ptr n, node_ptr pos) { - next_group(n) = b.next_; - b.next_ = n; - } - - template - inline void grouped_node_base::add_after_node(node_ptr n, node_ptr position) - { - next_node(n) = next_group(position); - group_prev(n) = group_prev(position); - next_group(position) = n; - group_prev(position) = n; + n->next_ = next_group(pos); + get(n).group_prev_ = get(pos).group_prev_; + next_group(pos) = n; + get(pos).group_prev_ = n; } // Break a ciruclar list into two, with split as the beginning @@ -164,29 +133,21 @@ namespace boost { namespace unordered_detail { inline BOOST_DEDUCED_TYPENAME grouped_node_base::node_ptr grouped_node_base::split_group(node_ptr split) { - // If split is at the beginning of the group then there's - // nothing to split. - if(next_node(group_prev(split)) != split) - return split; + node_ptr first = first_in_group(split); + if(first == split) return split; - // Find the start of the group. - node_ptr start = split; - do { - start = group_prev(start); - } while(next_node(group_prev(start)) == start); + node_ptr last = get(first).group_prev_; + get(first).group_prev_ = get(split).group_prev_; + get(split).group_prev_ = last; - node_ptr last = group_prev(start); - group_prev(start) = group_prev(split); - group_prev(split) = last; - - return start; + return first; } template void grouped_node_base::unlink_node(bucket& b, node_ptr node) { - node_ptr next = next_node(node); - node_ptr* pos = &next_node(group_prev(node)); + node_ptr next = node->next_; + node_ptr* pos = &next_group(node); if(*pos != node) { // The node is at the beginning of a group. @@ -196,31 +157,37 @@ namespace boost { namespace unordered_detail { while(*pos != node) pos = &next_group(*pos); // Remove from group - if(BOOST_UNORDERED_BORLAND_BOOL(next) && group_prev(next) == node) - group_prev(next) = group_prev(node); + if(BOOST_UNORDERED_BORLAND_BOOL(next) && + get(next).group_prev_ == node) + { + get(next).group_prev_ = get(node).group_prev_; + } } - else if(BOOST_UNORDERED_BORLAND_BOOL(next) && group_prev(next) == node) { + else if(BOOST_UNORDERED_BORLAND_BOOL(next) && + get(next).group_prev_ == node) + { // The deleted node is not at the end of the group, so // change the link from the next node. - group_prev(next) = group_prev(node); + get(next).group_prev_ = get(node).group_prev_; } else { // The deleted node is at the end of the group, so the // first node in the group is pointing to it. // Find that to change its pointer. - node_ptr x = group_prev(node); - while(group_prev(x) != node) { - x = group_prev(x); + node_ptr x = get(node).group_prev_; + while(get(x).group_prev_ != node) { + x = get(x).group_prev_; } - group_prev(x) = group_prev(node); + get(x).group_prev_ = get(node).group_prev_; } *pos = next; } template - void grouped_node_base::unlink_nodes(bucket& b, node_ptr begin, node_ptr end) + void grouped_node_base::unlink_nodes(bucket& b, + node_ptr begin, node_ptr end) { - node_ptr* pos = &next_node(group_prev(begin)); + node_ptr* pos = &next_group(begin); if(*pos != begin) { // The node is at the beginning of a group. @@ -238,10 +205,10 @@ namespace boost { namespace unordered_detail { node_ptr group2 = split_group(end); if(begin == group2) { - node_ptr end1 = group_prev(group1); - node_ptr end2 = group_prev(group2); - group_prev(group1) = end2; - group_prev(group2) = end1; + node_ptr end1 = get(group1).group_prev_; + node_ptr end2 = get(group2).group_prev_; + get(group1).group_prev_ = end2; + get(group2).group_prev_ = end1; } } } @@ -254,12 +221,6 @@ namespace boost { namespace unordered_detail { split_group(end); b.next_ = end; } - - template - inline void grouped_node_base::unlink_group(node_ptr* b) - { - *b = next_group(*b); - } }} #endif diff --git a/include/boost/unordered/detail/table.hpp b/include/boost/unordered/detail/table.hpp index c3afb6b7..eb18926f 100644 --- a/include/boost/unordered/detail/table.hpp +++ b/include/boost/unordered/detail/table.hpp @@ -23,20 +23,22 @@ namespace boost { namespace unordered_detail { // strong exception safety, no side effects template - inline bool hash_table - ::equal(key_type const& k, value_type const& v) const + inline bool hash_table::equal( + key_type const& k, value_type const& v) const { - return this->key_eq()(k, extractor::extract(v)); + return this->key_eq()(k, get_key(v)); } // strong exception safety, no side effects template inline BOOST_DEDUCED_TYPENAME hash_table::node_ptr - hash_table - ::find_iterator(bucket_ptr bucket, key_type const& k) const + hash_table::find_iterator( + bucket_ptr bucket, key_type const& k) const { node_ptr it = bucket->next_; - while (BOOST_UNORDERED_BORLAND_BOOL(it) && !equal(k, node::get_value(it))) { + while (BOOST_UNORDERED_BORLAND_BOOL(it) && + !equal(k, node::get_value(it))) + { it = node::next_group(it); } @@ -44,23 +46,26 @@ namespace boost { namespace unordered_detail { } // strong exception safety, no side effects + // pre: this->buckets_ template inline BOOST_DEDUCED_TYPENAME hash_table::node_ptr - hash_table - ::find_iterator(key_type const& k) const + hash_table::find_iterator(key_type const& k) const { return find_iterator(this->get_bucket(this->bucket_index(k)), k); } // strong exception safety, no side effects template - BOOST_DEDUCED_TYPENAME hash_table::node_ptr* - hash_table - ::find_for_erase(bucket_ptr bucket, key_type const& k) const + inline BOOST_DEDUCED_TYPENAME hash_table::node_ptr* + hash_table::find_for_erase( + bucket_ptr bucket, key_type const& k) const { node_ptr* it = &bucket->next_; - while(BOOST_UNORDERED_BORLAND_BOOL(*it) && !equal(k, node::get_value(*it))) + while(BOOST_UNORDERED_BORLAND_BOOL(*it) && + !equal(k, node::get_value(*it))) + { it = &node::next_group(*it); + } return it; } @@ -70,8 +75,7 @@ namespace boost { namespace unordered_detail { // no throw template - std::size_t hash_table - ::max_size() const + std::size_t hash_table::max_size() const { using namespace std; @@ -82,27 +86,37 @@ namespace boost { namespace unordered_detail { // strong safety template - std::size_t hash_table - ::bucket_index(key_type const& k) const + inline std::size_t hash_table::bucket_index( + key_type const& k) const { // hash_function can throw: - return this->bucket_from_hash(this->hash_function()(k)); + return this->hash_function()(k) % this->bucket_count_; } + // no throw template - void hash_table - ::max_load_factor(float z) + inline std::size_t hash_table::calculate_max_load() + { + using namespace std; + + // From 6.3.1/13: + // Only resize when size >= mlf_ * count + return double_to_size_t(ceil((double) mlf_ * this->bucket_count_)); + } + + template + void hash_table::max_load_factor(float z) { BOOST_ASSERT(z > 0); mlf_ = (std::max)(z, minimum_max_load_factor); - this->calculate_max_load(); + this->max_load_ = this->calculate_max_load(); } // no throw template - std::size_t hash_table - ::min_buckets_for_size(std::size_t n) const + inline std::size_t hash_table::min_buckets_for_size( + std::size_t n) const { BOOST_ASSERT(this->mlf_ != 0); @@ -114,577 +128,27 @@ namespace boost { namespace unordered_detail { // // Or from rehash post-condition: // count > size / mlf_ - return double_to_size_t(floor(n / (double) mlf_)) + 1; - } - - // no throw - template - void hash_table - ::calculate_max_load() - { - using namespace std; - - // From 6.3.1/13: - // Only resize when size >= mlf_ * count - max_load_ = double_to_size_t(ceil((double) mlf_ * this->bucket_count())); + return next_prime(double_to_size_t(floor(n / (double) mlf_)) + 1); } //////////////////////////////////////////////////////////////////////////// - // Constructors + // recompute_begin_bucket + + // init_buckets template - hash_table - ::hash_table(std::size_t n, hasher const& hf, key_equal const& eq, value_allocator const& a) : - buckets(a, next_prime(n)), func_(false), cached_begin_bucket_(), size_(), mlf_(1.0f), max_load_(0) + inline void hash_table::init_buckets() { - std::uninitialized_fill((functions*)this->funcs_, (functions*)this->funcs_+2, - functions(hf, eq)); - this->cached_begin_bucket_ = this->buckets_end(); - this->calculate_max_load(); - } - - template - hash_table - ::hash_table(hash_table const& x) : - buckets(x.node_alloc(), next_prime(x.min_buckets_for_size(x.size_))), func_(false), cached_begin_bucket_(), size_(), mlf_(x.mlf_), max_load_(0) - { - std::uninitialized_fill((functions*)this->funcs_, (functions*)this->funcs_+2, - x.current()); - this->calculate_max_load(); - x.copy_buckets_to(*this); - this->size_ = x.size_; - this->recompute_begin_bucket(); - } - - // Copy Construct with allocator - - template - hash_table - ::hash_table(hash_table const& x, value_allocator const& a) : - buckets(a, next_prime(x.min_buckets_for_size(x.size_))), func_(false), cached_begin_bucket_(), size_(), mlf_(x.mlf_), max_load_(0) - { - std::uninitialized_fill((functions*)this->funcs_, (functions*)this->funcs_+2, - x.current()); - this->cached_begin_bucket_ = this->buckets_end(); - this->calculate_max_load(); - x.copy_buckets_to(*this); - this->size_ = x.size_; - this->recompute_begin_bucket(); - } - - // Move Construct - - template - hash_table - ::hash_table(hash_table& x, move_tag m) : - buckets(x, m), func_(false), cached_begin_bucket_(), size_(), mlf_(x.mlf_), max_load_(0) - { - this->cached_begin_bucket_ = x.cached_begin_bucket_; - this->size_ = x.size_; - x.cached_begin_bucket_ = bucket_ptr(); - x.size_ = 0; - - // TODO: Shouldn't I move the functions if poss. - std::uninitialized_fill((functions*)this->funcs_, (functions*)this->funcs_+2, - x.current()); - } - - template - hash_table - ::hash_table(hash_table& x, value_allocator const& a, move_tag m) : - buckets(x, a, m), func_(false), cached_begin_bucket_(), size_(), mlf_(x.mlf_), max_load_(0) - { - std::uninitialized_fill((functions*)this->funcs_, (functions*)this->funcs_+2, - x.current()); - - this->calculate_max_load(); // no throw - - if(!this->buckets_) { - buckets new_buckets(this->node_alloc(), x.min_buckets_for_size(x.size_)); - x.copy_buckets_to(new_buckets); - new_buckets.swap(*this); - this->size_ = x.size_; - this->recompute_begin_bucket(); - } - else { - this->cached_begin_bucket_ = x.cached_begin_bucket_; - this->size_ = x.size_; - x.cached_begin_bucket_ = bucket_ptr(); - x.size_ = 0; - } - } - - template - hash_table::~hash_table() - { - BOOST_UNORDERED_DESTRUCT(this->get_functions(false), functions); - BOOST_UNORDERED_DESTRUCT(this->get_functions(true), functions); - } - - // TODO: Reuse current nodes amd buckets? - template - hash_table& hash_table::operator=(hash_table const& x) - { - if(this != &x) { - this->clear(); // no throw - this->set_functions( - this->buffer_functions(x)); // throws, strong - this->mlf_ = x.mlf_; // no throw - buckets new_buckets(this->node_alloc(), x.min_buckets_for_size(x.size_)); - x.copy_buckets_to(new_buckets); - new_buckets.swap(*this); - this->calculate_max_load(); // no throw - this->size_ = x.size_; - this->recompute_begin_bucket(); - } - - return *this; - } - - //////////////////////////////////////////////////////////////////////////// - // Swap & Move - - // Swap - // - // Strong exception safety - // - // Can throw if hash or predicate object's copy constructor throws - // or if allocators are unequal. - - template - void hash_table - ::swap(hash_table& x) - { - // The swap code can work when swapping a container with itself - // but it triggers an assertion in buffered_functions. - // At the moment, I'd rather leave that assertion in and add a - // check here, rather than remove the assertion. I might change - // this at a later date. - if(this == &x) return; - - // These can throw, but they only affect the function objects - // that aren't in use so it is strongly exception safe, via. - // double buffering. - functions_ptr new_func_this = this->buffer_functions(x); - functions_ptr new_func_that = x.buffer_functions(*this); - - if(this->node_alloc() == x.node_alloc()) { - this->buckets::swap(x); // No throw - std::swap(this->cached_begin_bucket_, x.cached_begin_bucket_); - std::swap(this->size_, x.size_); - } - else { - // Create new buckets in separate hash_buckets objects - // which will clean up if anything throws an exception. - // (all can throw, but with no effect as these are new objects). - - buckets new_this(this->node_alloc(), x.min_buckets_for_size(x.size_)); - x.copy_buckets_to(new_this); - - buckets new_that(x.node_alloc(), this->min_buckets_for_size(this->size_)); - copy_buckets_to(new_that); - - // Modifying the data, so no throw from now on. - - this->buckets::swap(new_this); - x.buckets::swap(new_that); - std::swap(this->size_, x.size_); - this->recompute_begin_bucket(); - x.recompute_begin_bucket(); - } - - // The rest is no throw. - - std::swap(this->mlf_, x.mlf_); - - this->set_functions(new_func_this); - x.set_functions(new_func_that); - - //TODO: Test that this works: - this->calculate_max_load(); - x.calculate_max_load(); - } - - // Move - // - // Strong exception safety (might change unused function objects) - // - // Can throw if hash or predicate object's copy constructor throws - // or if allocators are unequal. - - template - void hash_table - ::move(hash_table& x) - { - // This can throw, but it only affects the function objects - // that aren't in use so it is strongly exception safe, via. - // double buffering. - functions_ptr new_func_this = this->buffer_functions(x); - - if(this->node_alloc() == x.node_alloc()) { - this->buckets::move(x); // no throw - this->size_ = x.size_; - this->cached_begin_bucket_ = x.cached_begin_bucket_; - x.size_ = 0; - x.cached_begin_bucket_ = bucket_ptr(); - } - else { - // Create new buckets in separate HASH_TABLE_DATA objects - // which will clean up if anything throws an exception. - // (all can throw, but with no effect as these are new objects). - - buckets new_this(this->node_alloc(), next_prime(x.min_buckets_for_size(x.size_))); - x.copy_buckets_to(new_this); - - // Start updating the data here, no throw from now on. - this->buckets::move(new_this); - this->size_ = x.size_; - this->recompute_begin_bucket(); - } - - // We've made it, the rest is no throw. - this->mlf_ = x.mlf_; - this->set_functions(new_func_this); - - this->calculate_max_load(); - } - - //////////////////////////////////////////////////////////////////////////// - // Reserve & Rehash - - // basic exception safety - template - inline bool hash_table - ::reserve(std::size_t n) - { - bool need_to_reserve = n >= this->max_load_; - // throws - basic: - if (need_to_reserve) rehash_impl(this->min_buckets_for_size(n)); - BOOST_ASSERT(n < this->max_load_ || n > max_size()); - return need_to_reserve; - } - - // basic exception safety - template - inline bool hash_table - ::reserve_for_insert(std::size_t n) - { - bool need_to_reserve = n >= this->max_load_; - // throws - basic: - if (need_to_reserve) { - std::size_t s = this->size_; - s = s + (s >> 1); - s = s > n ? s : n; - rehash_impl(this->min_buckets_for_size(s)); - } - BOOST_ASSERT(n < this->max_load_ || n > max_size()); - return need_to_reserve; - } - - // if hash function throws, basic exception safety - // strong otherwise. - template - void hash_table - ::rehash(std::size_t n) - { - using namespace std; - - // no throw: - std::size_t min_size = this->min_buckets_for_size(this->size_); - // basic/strong: - rehash_impl(min_size > n ? min_size : n); - - BOOST_ASSERT((float) this->bucket_count() > (float) this->size_ / this->mlf_ - && this->bucket_count() >= n); - } - - // if hash function throws, basic exception safety - // strong otherwise - - template - void hash_table - ::rehash_impl(std::size_t n) - { - n = next_prime(n); // no throw - - if (n == this->bucket_count()) // no throw - return; - - // Save the size to restore it if successful - std::size_t size = this->size_; - - // Create another buckets to move the nodes into. - buckets dst(this->node_alloc(), n);// throws, separate - - // Move the nodes to dst. - hasher const& hf = this->hash_function(); - bucket_ptr end = this->buckets_end(); - - for(; this->cached_begin_bucket_ != end; ++this->cached_begin_bucket_) { - bucket_ptr src_bucket = this->cached_begin_bucket_; - while(src_bucket->next_) { - // Move the first group of equivalent nodes in - // src_bucket to dst. - - // This next line throws iff the hash function throws. - bucket_ptr dst_bucket = dst.bucket_ptr_from_hash( - hf(extractor::extract(node::get_value(src_bucket->next_)))); - - - node_ptr n = src_bucket->next_; - this->size_ -= node::group_count(n); - node::unlink_group(&src_bucket->next_); - node::add_group_to_bucket(n, *dst_bucket); - } - } - - // Swap the new nodes back into the container and setup the local - // variables. - dst.swap(*this); // no throw - this->size_ = size; - this->recompute_begin_bucket(); // no throw - this->calculate_max_load(); // no throw - } - - //////////////////////////////////////////////////////////////////////////// - // copy_buckets_to - - // copy_buckets_to - // - // basic excpetion safety. If an exception is thrown this will - // leave dst partially filled. - - template - void hash_table - ::copy_buckets_to(buckets& dst) const - { - BOOST_ASSERT(this->buckets_ && dst.buckets_); - - hasher const& hf = this->hash_function(); - bucket_ptr end = this->buckets_end(); - - hash_node_constructor a(dst); - - // no throw: - for(bucket_ptr i = this->cached_begin_bucket_; i != end; ++i) { - // no throw: - for(node_ptr it = i->next_; it;) { - // hash function can throw. - bucket_ptr dst_bucket = dst.bucket_ptr_from_hash( - hf(extractor::extract(node::get_value(it)))); - // throws, strong - - node_ptr group_end = node::next_group(it); - - a.construct(node::get_value(it)); - node_ptr n = a.release(); - node::add_to_bucket(n, *dst_bucket); - - for(it = next_node(it); it != group_end; it = next_node(it)) { - a.construct(node::get_value(it)); - node::add_after_node(a.release(), n); - } - } - } - } - - //////////////////////////////////////////////////////////////////////////// - // Misc. key methods - - // strong exception safety - - // count - // - // strong exception safety, no side effects - - template - std::size_t hash_table - ::count(key_type const& k) const - { - if(!this->size_) return 0; - node_ptr it = find_iterator(k); // throws, strong - return BOOST_UNORDERED_BORLAND_BOOL(it) ? node::group_count(it) : 0; - } - - // find - // - // strong exception safety, no side effects - template - BOOST_DEDUCED_TYPENAME hash_table::iterator_base - hash_table - ::find(key_type const& k) const - { - if(!this->size_) return this->end(); - - bucket_ptr bucket = this->get_bucket(this->bucket_index(k)); - node_ptr it = find_iterator(bucket, k); - - if (BOOST_UNORDERED_BORLAND_BOOL(it)) - return iterator_base(bucket, it); - else - return this->end(); - } - - template - BOOST_DEDUCED_TYPENAME A::value_type& - hash_table - ::at(key_type const& k) const - { - if(!this->size_) - throw std::out_of_range("Unable to find key in unordered_map."); - - bucket_ptr bucket = this->get_bucket(this->bucket_index(k)); - node_ptr it = find_iterator(bucket, k); - - if (BOOST_UNORDERED_BORLAND_BOOL(it)) - return node::get_value(it); - else - throw std::out_of_range("Unable to find key in unordered_map."); - } - - // equal_range - // - // strong exception safety, no side effects - template - std::pair< - BOOST_DEDUCED_TYPENAME hash_table::iterator_base, - BOOST_DEDUCED_TYPENAME hash_table::iterator_base - > - hash_table - ::equal_range(key_type const& k) const - { - if(!this->size_) - return std::pair(this->end(), this->end()); - - bucket_ptr bucket = this->get_bucket(this->bucket_index(k)); - node_ptr it = find_iterator(bucket, k); - if (BOOST_UNORDERED_BORLAND_BOOL(it)) { - iterator_base first(iterator_base(bucket, it)); - iterator_base second(first); - second.increment(node::next_group(second.node_)); - return std::pair(first, second); - } - else { - return std::pair(this->end(), this->end()); - } - } - - //////////////////////////////////////////////////////////////////////////// - // Erase methods - - template - void hash_table::clear() - { - for(bucket_ptr begin = this->buckets_begin(), end = this->buckets_end(); begin != end; ++begin) { - this->clear_bucket(begin); - } - - this->cached_begin_bucket_ = this->buckets_end(); - this->size_ = 0; - } - - template - std::size_t hash_table - ::erase_key(key_type const& k) - { - // No side effects in initial section - bucket_ptr bucket = this->get_bucket(this->bucket_index(k)); - node_ptr* it = this->find_for_erase(bucket, k); - - // No throw. - return *it ? this->erase_group(it, bucket) : 0; - } - - - template - BOOST_DEDUCED_TYPENAME hash_table::iterator_base - hash_table::erase(iterator_base r) - { - BOOST_ASSERT(!r.is_end()); - iterator_base next = r; - next.increment(); - --this->size_; - node::unlink_node(*r.bucket_, r.node_); - this->destruct_node(r.node_); - // r has been invalidated but its bucket is still valid - this->recompute_begin_bucket(r.bucket_, next.bucket_); - return next; - } - - template - inline std::size_t hash_table::erase_group(node_ptr* it, bucket_ptr bucket) - { - node_ptr pos = *it; - std::size_t count = node::group_count(*it); - this->size_ -= count; - node::unlink_group(it); - this->delete_group(pos); - this->recompute_begin_bucket(bucket); - return count; - } - - template - BOOST_DEDUCED_TYPENAME hash_table::iterator_base - hash_table::erase_range(iterator_base r1, iterator_base r2) - { - if(r1 != r2) - { - BOOST_ASSERT(!r1.is_end()); - - if (r1.bucket_ == r2.bucket_) { - this->size_ -= node_count(r1.node_, r2.node_); - node::unlink_nodes(*r1.bucket_, r1.node_, r2.node_); - this->delete_nodes(r1.node_, r2.node_); - - // No need to call recompute_begin_bucket because - // the nodes are only deleted from one bucket, which - // still contains r2 after the erase. - BOOST_ASSERT(r1.bucket_->next_); - } - else { - BOOST_ASSERT(r1.bucket_ < r2.bucket_); - - this->size_ -= node_count(r1.node_, node_ptr()); - node::unlink_nodes(*r1.bucket_, r1.node_, node_ptr()); - this->delete_to_bucket_end(r1.node_); - - bucket_ptr i = r1.bucket_; - for(++i; i != r2.bucket_; ++i) { - this->size_ -= node_count(i->next_, node_ptr()); - this->clear_bucket(i); - } - - if(!r2.is_end()) { - node_ptr first = r2.bucket_->next_; - this->size_ -= node_count(r2.bucket_->next_, r2.node_); - node::unlink_nodes(*r2.bucket_, r2.node_); - this->delete_nodes(first, r2.node_); - } - - // r1 has been invalidated but its bucket is still - // valid. - this->recompute_begin_bucket(r1.bucket_, r2.bucket_); - } - } - - return r2; - } - - - template - inline void hash_table::recompute_begin_bucket() - { - if (this->size_ != 0) { - this->cached_begin_bucket_ = this->buckets_begin(); + if (this->size_) { + this->cached_begin_bucket_ = this->buckets_; while (!this->cached_begin_bucket_->next_) ++this->cached_begin_bucket_; } else { - this->cached_begin_bucket_ = this->buckets_end(); + this->cached_begin_bucket_ = this->get_bucket(this->bucket_count_); } + this->max_load_ = calculate_max_load(); } - // recompute_begin_bucket - // // After an erase cached_begin_bucket_ might be left pointing to // an empty bucket, so this is called to update it // @@ -701,7 +165,8 @@ namespace boost { namespace unordered_detail { while (!this->cached_begin_bucket_->next_) ++this->cached_begin_bucket_; } else { - this->cached_begin_bucket_ = this->buckets_end(); + this->cached_begin_bucket_ = + this->get_bucket(this->bucket_count_); } } } @@ -711,7 +176,8 @@ namespace boost { namespace unordered_detail { // no throw template - inline void hash_table::recompute_begin_bucket(bucket_ptr b1, bucket_ptr b2) + inline void hash_table::recompute_begin_bucket( + bucket_ptr b1, bucket_ptr b2) { BOOST_ASSERT(!(b1 < this->cached_begin_bucket_) && !(b2 < b1)); BOOST_ASSERT(BOOST_UNORDERED_BORLAND_BOOL(b2->next_)); @@ -729,6 +195,550 @@ namespace boost { namespace unordered_detail { / static_cast(this->bucket_count_); } + //////////////////////////////////////////////////////////////////////////// + // Constructors + + template + hash_table::hash_table(std::size_t n, + hasher const& hf, key_equal const& eq, node_allocator const& a) + : buckets(a, next_prime(n)), + base(hf, eq), + size_(), + mlf_(1.0f), + cached_begin_bucket_(), + max_load_(0) + { + } + + // Copy Construct with allocator + + template + hash_table::hash_table(hash_table const& x, + node_allocator const& a) + : buckets(a, x.min_buckets_for_size(x.size_)), + base(x), + size_(x.size_), + mlf_(x.mlf_), + cached_begin_bucket_(), + max_load_(0) + { + if(x.size_) { + x.copy_buckets_to(*this); + this->init_buckets(); + } + } + + // Move Construct + + template + hash_table::hash_table(hash_table& x, move_tag) + : buckets(x.node_alloc(), x.bucket_count_), + base(x), + size_(0), + mlf_(1.0f), + cached_begin_bucket_(), + max_load_(0) + { + this->partial_swap(x); + } + + template + hash_table::hash_table(hash_table& x, + node_allocator const& a, move_tag) + : buckets(a, x.bucket_count_), + base(x), + size_(0), + mlf_(x.mlf_), + cached_begin_bucket_(), + max_load_(0) + { + if(a == x.node_alloc()) { + this->partial_swap(x); + } + else if(x.size_) { + x.copy_buckets_to(*this); + this->size_ = x.size_; + this->init_buckets(); + } + } + + template + hash_table& hash_table::operator=( + hash_table const& x) + { + hash_table tmp(x, this->node_alloc()); + this->fast_swap(tmp); + return *this; + } + + //////////////////////////////////////////////////////////////////////////// + // Swap & Move + + // Swap + // + // Strong exception safety + // + // Can throw if hash or predicate object's copy constructor throws + // or if allocators are unequal. + + template + inline void hash_table::partial_swap(hash_table& x) + { + this->buckets::swap(x); // No throw + std::swap(this->size_, x.size_); + std::swap(this->mlf_, x.mlf_); + std::swap(this->cached_begin_bucket_, x.cached_begin_bucket_); + std::swap(this->max_load_, x.max_load_); + } + + template + inline void hash_table::fast_swap(hash_table& x) + { + // These can throw, but they only affect the function objects + // that aren't in use so it is strongly exception safe, via. + // double buffering. + { + set_hash_functions op1(*this, x); + set_hash_functions op2(x, *this); + op1.commit(); + op2.commit(); + } + this->buckets::swap(x); // No throw + std::swap(this->size_, x.size_); + std::swap(this->mlf_, x.mlf_); + std::swap(this->cached_begin_bucket_, x.cached_begin_bucket_); + std::swap(this->max_load_, x.max_load_); + } + + template + inline void hash_table::slow_swap(hash_table& x) + { + if(this == &x) return; + + { + // These can throw, but they only affect the function objects + // that aren't in use so it is strongly exception safe, via. + // double buffering. + set_hash_functions op1(*this, x); + set_hash_functions op2(x, *this); + + // Create new buckets in separate hash_buckets objects + // which will clean up if anything throws an exception. + // (all can throw, but with no effect as these are new objects). + + buckets b1(this->node_alloc(), x.min_buckets_for_size(x.size_)); + if(x.size_) x.copy_buckets_to(b1); + + buckets b2(x.node_alloc(), this->min_buckets_for_size(this->size_)); + if(this->size_) copy_buckets_to(b2); + + // Modifying the data, so no throw from now on. + + b1.swap(*this); + b2.swap(x); + op1.commit(); + op2.commit(); + } + + std::swap(this->size_, x.size_); + + if(this->buckets_) this->init_buckets(); + if(x.buckets_) x.init_buckets(); + } + + template + void hash_table::swap(hash_table& x) + { + if(this->node_alloc() == x.node_alloc()) { + if(this != &x) this->fast_swap(x); + } + else { + this->slow_swap(x); + } + } + + + // Move + // + // Strong exception safety (might change unused function objects) + // + // Can throw if hash or predicate object's copy constructor throws + // or if allocators are unequal. + + template + void hash_table::move(hash_table& x) + { + // This can throw, but it only affects the function objects + // that aren't in use so it is strongly exception safe, via. + // double buffering. + set_hash_functions new_func_this(*this, x); + + if(this->node_alloc() == x.node_alloc()) { + this->buckets::move(x); // no throw + this->size_ = x.size_; + this->cached_begin_bucket_ = x.cached_begin_bucket_; + this->max_load_ = x.max_load_; + x.size_ = 0; + } + else { + // Create new buckets in separate HASH_TABLE_DATA objects + // which will clean up if anything throws an exception. + // (all can throw, but with no effect as these are new objects). + + buckets b(this->node_alloc(), x.min_buckets_for_size(x.size_)); + if(x.size_) x.copy_buckets_to(b); + + // Start updating the data here, no throw from now on. + this->size_ = x.size_; + b.swap(*this); + this->init_buckets(); + } + + // We've made it, the rest is no throw. + this->mlf_ = x.mlf_; + new_func_this.commit(); + } + + //////////////////////////////////////////////////////////////////////////// + // Reserve & Rehash + + // basic exception safety + template + inline void hash_table::create_for_insert(std::size_t n) + { + if(n > this->bucket_count_) + this->bucket_count_ = this->min_buckets_for_size(n); + this->create_buckets(); + this->init_buckets(); + } + + // basic exception safety + template + inline bool hash_table::reserve_for_insert(std::size_t n) + { + if(n >= max_load_) { + std::size_t s = this->size_; + s = s + (s >> 1); + n = this->min_buckets_for_size(s > n ? s : n); + if(n != this->bucket_count_) { + rehash_impl(n); + return true; + } + } + + return false; + } + + // if hash function throws, basic exception safety + // strong otherwise. + // TODO: Should this always create buckets? + template + inline void hash_table + ::rehash(std::size_t n) + { + using namespace std; + + if(!this->buckets_) { + this->bucket_count_ = next_prime(n); + this->create_buckets(); + this->init_buckets(); + } + else if(n != this->bucket_count_) { + // no throw: + // TODO: Needlessly calling next_prime twice. + std::size_t min_size = this->min_buckets_for_size(this->size_); + n = next_prime(n); + n = min_size > n ? min_size : n; + + rehash_impl(n); + } + } + + // if hash function throws, basic exception safety + // strong otherwise + + // TODO: Rewrite so that it doesn't need to keep updating size_. + + template + void hash_table + ::rehash_impl(std::size_t n) + { + hasher const& hf = this->hash_function(); + std::size_t size = this->size_; + bucket_ptr end = this->get_bucket(this->bucket_count_); + + buckets dst(this->node_alloc(), n); + dst.create_buckets(); + + buckets src(this->node_alloc(), this->bucket_count_); + src.swap(*this); + this->size_ = 0; + + for(bucket_ptr bucket = this->cached_begin_bucket_; + bucket != end; ++bucket) + { + node_ptr group = bucket->next_; + while(group) { + // Move the first group of equivalent nodes in bucket to dst. + + // This next line throws iff the hash function throws. + bucket_ptr dst_bucket = dst.bucket_ptr_from_hash( + hf(get_key_from_ptr(group))); + + node_ptr& next_group = node::next_group(group); + bucket->next_ = next_group; + next_group = dst_bucket->next_; + dst_bucket->next_ = group; + group = bucket->next_; + } + } + + // Swap the new nodes back into the container and setup the local + // variables. + this->size_ = size; + dst.swap(*this); // no throw + this->init_buckets(); + } + + //////////////////////////////////////////////////////////////////////////// + // copy_buckets_to + + // copy_buckets_to + // + // basic excpetion safety. If an exception is thrown this will + // leave dst partially filled. + + template + void hash_table + ::copy_buckets_to(buckets& dst) const + { + BOOST_ASSERT(this->buckets_ && !dst.buckets_); + + hasher const& hf = this->hash_function(); + bucket_ptr end = this->get_bucket(this->bucket_count_); + + hash_node_constructor a(dst); + dst.create_buckets(); + + // no throw: + for(bucket_ptr i = this->cached_begin_bucket_; i != end; ++i) { + // no throw: + for(node_ptr it = i->next_; it;) { + // hash function can throw. + bucket_ptr dst_bucket = dst.bucket_ptr_from_hash( + hf(get_key_from_ptr(it))); + // throws, strong + + node_ptr group_end = node::next_group(it); + + a.construct(node::get_value(it)); + node_ptr n = a.release(); + node::add_to_bucket(n, *dst_bucket); + + for(it = it->next_; it != group_end; it = it->next_) { + a.construct(node::get_value(it)); + node::add_after_node(a.release(), n); + } + } + } + } + + //////////////////////////////////////////////////////////////////////////// + // Misc. key methods + + // strong exception safety + + // count + // + // strong exception safety, no side effects + + template + std::size_t hash_table::count(key_type const& k) const + { + if(!this->size_) return 0; + node_ptr it = find_iterator(k); // throws, strong + return BOOST_UNORDERED_BORLAND_BOOL(it) ? node::group_count(it) : 0; + } + + // find + // + // strong exception safety, no side effects + template + BOOST_DEDUCED_TYPENAME hash_table::iterator_base + hash_table::find(key_type const& k) const + { + if(!this->size_) return this->end(); + + bucket_ptr bucket = this->get_bucket(this->bucket_index(k)); + node_ptr it = find_iterator(bucket, k); + + if (BOOST_UNORDERED_BORLAND_BOOL(it)) + return iterator_base(bucket, it); + else + return this->end(); + } + + template + BOOST_DEDUCED_TYPENAME A::value_type& + hash_table::at(key_type const& k) const + { + if(!this->size_) + throw std::out_of_range("Unable to find key in unordered_map."); + + bucket_ptr bucket = this->get_bucket(this->bucket_index(k)); + node_ptr it = find_iterator(bucket, k); + + if (BOOST_UNORDERED_BORLAND_BOOL(it)) + return node::get_value(it); + else + throw std::out_of_range("Unable to find key in unordered_map."); + } + + // equal_range + // + // strong exception safety, no side effects + template + BOOST_DEDUCED_TYPENAME hash_table::iterator_pair + hash_table::equal_range(key_type const& k) const + { + if(!this->size_) + return iterator_pair(this->end(), this->end()); + + bucket_ptr bucket = this->get_bucket(this->bucket_index(k)); + node_ptr it = find_iterator(bucket, k); + if (BOOST_UNORDERED_BORLAND_BOOL(it)) { + iterator_base first(iterator_base(bucket, it)); + iterator_base second(first); + second.increment_bucket(node::next_group(second.node_)); + return iterator_pair(first, second); + } + else { + return iterator_pair(this->end(), this->end()); + } + } + + //////////////////////////////////////////////////////////////////////////// + // Erase methods + + template + void hash_table::clear() + { + // TODO: Is this check needed when called internally? + if(!this->size_) return; + + bucket_ptr end = this->get_bucket(this->bucket_count_); + for(bucket_ptr begin = this->buckets_; begin != end; ++begin) { + this->clear_bucket(begin); + } + + this->size_ = 0; + this->cached_begin_bucket_ = end; + } + + template + inline std::size_t hash_table::erase_group( + node_ptr* it, bucket_ptr bucket) + { + node_ptr pos = *it; + node_ptr end = node::next_group(pos); + *it = end; + std::size_t count = this->delete_nodes(pos, end); + this->size_ -= count; + this->recompute_begin_bucket(bucket); + return count; + } + + template + std::size_t hash_table + ::erase_key(key_type const& k) + { + if(!this->size_) return 0; + + // No side effects in initial section + bucket_ptr bucket = this->get_bucket(this->bucket_index(k)); + node_ptr* it = this->find_for_erase(bucket, k); + + // No throw. + return *it ? this->erase_group(it, bucket) : 0; + } + + + template + BOOST_DEDUCED_TYPENAME hash_table::iterator_base + hash_table::erase(iterator_base r) + { + BOOST_ASSERT(r.node_); + iterator_base next = r; + next.increment(); + --this->size_; + node::unlink_node(*r.bucket_, r.node_); + this->delete_node(r.node_); + // r has been invalidated but its bucket is still valid + this->recompute_begin_bucket(r.bucket_, next.bucket_); + return next; + } + + template + BOOST_DEDUCED_TYPENAME hash_table::iterator_base + hash_table::erase_range( + iterator_base r1, iterator_base r2) + { + if(r1 != r2) + { + BOOST_ASSERT(r1.node_); + if (r1.bucket_ == r2.bucket_) { + node::unlink_nodes(*r1.bucket_, r1.node_, r2.node_); + this->size_ -= this->delete_nodes(r1.node_, r2.node_); + + // No need to call recompute_begin_bucket because + // the nodes are only deleted from one bucket, which + // still contains r2 after the erase. + BOOST_ASSERT(r1.bucket_->next_); + } + else { + bucket_ptr end_bucket = r2.node_ ? + r2.bucket_ : this->get_bucket(this->bucket_count_); + BOOST_ASSERT(r1.bucket_ < end_bucket); + node::unlink_nodes(*r1.bucket_, r1.node_, node_ptr()); + this->size_ -= this->delete_nodes(r1.node_, node_ptr()); + + bucket_ptr i = r1.bucket_; + for(++i; i != end_bucket; ++i) { + this->size_ -= this->delete_nodes(i->next_, node_ptr()); + i->next_ = node_ptr(); + } + + if(r2.node_) { + node_ptr first = r2.bucket_->next_; + node::unlink_nodes(*r2.bucket_, r2.node_); + this->size_ -= this->delete_nodes(first, r2.node_); + } + + // r1 has been invalidated but its bucket is still + // valid. + this->recompute_begin_bucket(r1.bucket_, end_bucket); + } + } + + return r2; + } + + template + BOOST_DEDUCED_TYPENAME hash_table::iterator_base + hash_table::emplace_empty_impl_with_node( + node_constructor& a, std::size_t n) + { + key_type const& k = get_key(a.value()); + std::size_t hash_value = this->hash_function()(k); + if(this->buckets_) this->reserve_for_insert(n); + else this->create_for_insert(n); + bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value); + node_ptr node = a.release(); + node::add_to_bucket(node, *bucket); + ++this->size_; + this->cached_begin_bucket_ = bucket; + return iterator_base(bucket, node); + } }} #endif diff --git a/include/boost/unordered/detail/unique.hpp b/include/boost/unordered/detail/unique.hpp new file mode 100644 index 00000000..0f5cf88f --- /dev/null +++ b/include/boost/unordered/detail/unique.hpp @@ -0,0 +1,431 @@ + +// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard. +// Copyright (C) 2005-2009 Daniel James +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_UNORDERED_DETAIL_UNIQUE_HPP_INCLUDED +#define BOOST_UNORDERED_DETAIL_UNIQUE_HPP_INCLUDED + +#include +#include + +namespace boost { namespace unordered_detail { + + //////////////////////////////////////////////////////////////////////////// + // Equality + + template + bool hash_unique_table + ::equals(hash_unique_table const& other) const + { + if(this->size_ != other.size_) return false; + if(!this->size_) return true; + + bucket_ptr end = this->get_bucket(this->bucket_count_); + for(bucket_ptr i = this->cached_begin_bucket_; i != end; ++i) + { + node_ptr it1 = i->next_; + while(BOOST_UNORDERED_BORLAND_BOOL(it1)) + { + node_ptr it2 = other.find_iterator(get_key_from_ptr(it1)); + if(!BOOST_UNORDERED_BORLAND_BOOL(it2)) return false; + if(!extractor::compare_mapped( + node::get_value(it1), node::get_value(it2))) + return false; + it1 = it1->next_; + } + } + + return true; + } + + //////////////////////////////////////////////////////////////////////////// + // A convenience method for adding nodes. + + template + inline BOOST_DEDUCED_TYPENAME hash_unique_table::node_ptr + hash_unique_table::add_node(node_constructor& a, + bucket_ptr bucket) + { + node_ptr n = a.release(); + node::add_to_bucket(n, *bucket); + ++this->size_; + if(bucket < this->cached_begin_bucket_) + this->cached_begin_bucket_ = bucket; + return n; + } + + //////////////////////////////////////////////////////////////////////////// + // Insert methods + + // if hash function throws, basic exception safety + // strong otherwise + template + BOOST_DEDUCED_TYPENAME hash_unique_table::value_type& + hash_unique_table::operator[](key_type const& k) + { + typedef BOOST_DEDUCED_TYPENAME value_type::second_type mapped_type; + + std::size_t hash_value = this->hash_function()(k); + bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value); + + if(!this->buckets_) { + node_constructor a(*this); + a.construct_pair(k, (mapped_type*) 0); + return *this->emplace_empty_impl_with_node(a, 1); + } + + node_ptr pos = find_iterator(bucket, k); + + if (BOOST_UNORDERED_BORLAND_BOOL(pos)) { + return node::get_value(pos); + } + else { + // Side effects only in this block. + + // Create the node before rehashing in case it throws an + // exception (need strong safety in such a case). + node_constructor a(*this); + a.construct_pair(k, (mapped_type*) 0); + + // reserve has basic exception safety if the hash function + // throws, strong otherwise. + if(this->reserve_for_insert(this->size_ + 1)) + bucket = this->bucket_ptr_from_hash(hash_value); + + // Nothing after this point can throw. + + return node::get_value(add_node(a, bucket)); + } + } + + template + inline BOOST_DEDUCED_TYPENAME hash_unique_table::emplace_return + hash_unique_table + ::emplace_impl_with_node(node_constructor& a) + { + // No side effects in this initial code + key_type const& k = get_key(a.value()); + std::size_t hash_value = this->hash_function()(k); + bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value); + node_ptr pos = find_iterator(bucket, k); + + if (BOOST_UNORDERED_BORLAND_BOOL(pos)) { + // Found an existing key, return it (no throw). + return emplace_return(iterator_base(bucket, pos), false); + } else { + // reserve has basic exception safety if the hash function + // throws, strong otherwise. + if(this->reserve_for_insert(this->size_ + 1)) + bucket = this->bucket_ptr_from_hash(hash_value); + + // Nothing after this point can throw. + + return emplace_return( + iterator_base(bucket, add_node(a, bucket)), + true); + } + } + +#if defined(BOOST_UNORDERED_STD_FORWARD) + + template + template + inline BOOST_DEDUCED_TYPENAME hash_unique_table::emplace_return + hash_unique_table::emplace_impl(key_type const& k, + Args&&... args) + { + // No side effects in this initial code + std::size_t hash_value = this->hash_function()(k); + bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value); + node_ptr pos = find_iterator(bucket, k); + + if (BOOST_UNORDERED_BORLAND_BOOL(pos)) { + // Found an existing key, return it (no throw). + return emplace_return(iterator_base(bucket, pos), false); + + } else { + // Doesn't already exist, add to bucket. + // Side effects only in this block. + + // Create the node before rehashing in case it throws an + // exception (need strong safety in such a case). + node_constructor a(*this); + a.construct(std::forward(args)...); + + // reserve has basic exception safety if the hash function + // throws, strong otherwise. + if(this->reserve_for_insert(this->size_ + 1)) + bucket = this->bucket_ptr_from_hash(hash_value); + + // Nothing after this point can throw. + + return emplace_return( + iterator_base(bucket, add_node(a, bucket)), + true); + } + } + + template + template + inline BOOST_DEDUCED_TYPENAME hash_unique_table::emplace_return + hash_unique_table::emplace_impl(no_key, Args&&... args) + { + // Construct the node regardless - in order to get the key. + // It will be discarded if it isn't used + node_constructor a(*this); + a.construct(std::forward(args)...); + return emplace_impl_with_node(a); + } + + template + template + inline BOOST_DEDUCED_TYPENAME hash_unique_table::emplace_return + hash_unique_table::emplace_empty_impl(Args&&... args) + { + node_constructor a(*this); + a.construct(std::forward(args)...); + return emplace_return(this->emplace_empty_impl_with_node(a, 1), true); + } + +#else + +#define BOOST_UNORDERED_INSERT_IMPL(z, n, _) \ + template \ + template \ + inline BOOST_DEDUCED_TYPENAME \ + hash_unique_table::emplace_return \ + hash_unique_table::emplace_impl( \ + key_type const& k, \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \ + { \ + std::size_t hash_value = this->hash_function()(k); \ + bucket_ptr bucket \ + = this->bucket_ptr_from_hash(hash_value); \ + node_ptr pos = find_iterator(bucket, k); \ + \ + if (BOOST_UNORDERED_BORLAND_BOOL(pos)) { \ + return emplace_return(iterator_base(bucket, pos), false); \ + } else { \ + node_constructor a(*this); \ + a.construct(BOOST_UNORDERED_CALL_PARAMS(z, n)); \ + \ + if(this->reserve_for_insert(this->size_ + 1)) \ + bucket = this->bucket_ptr_from_hash(hash_value); \ + \ + return emplace_return(iterator_base(bucket, \ + add_node(a, bucket)), true); \ + } \ + } \ + \ + template \ + template \ + inline BOOST_DEDUCED_TYPENAME \ + hash_unique_table::emplace_return \ + hash_unique_table:: \ + emplace_impl(no_key, BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \ + { \ + node_constructor a(*this); \ + a.construct(BOOST_UNORDERED_CALL_PARAMS(z, n)); \ + return emplace_impl_with_node(a); \ + } \ + \ + template \ + template \ + inline BOOST_DEDUCED_TYPENAME \ + hash_unique_table::emplace_return \ + hash_unique_table:: \ + emplace_empty_impl(BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \ + { \ + node_constructor a(*this); \ + a.construct(BOOST_UNORDERED_CALL_PARAMS(z, n)); \ + return emplace_return(this->emplace_empty_impl_with_node(a, 1), true); \ + } + + BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, + BOOST_UNORDERED_INSERT_IMPL, _) + +#undef BOOST_UNORDERED_INSERT_IMPL + +#endif + +#if defined(BOOST_UNORDERED_STD_FORWARD) + + // Emplace (unique keys) + // (I'm using an overloaded emplace for both 'insert' and 'emplace') + + // if hash function throws, basic exception safety + // strong otherwise + + template + template + BOOST_DEDUCED_TYPENAME hash_unique_table::emplace_return + hash_unique_table::emplace(Args&&... args) + { + return this->size_ ? + emplace_impl( + extractor::extract(std::forward(args)...), + std::forward(args)...) : + emplace_empty_impl(std::forward(args)...); + } + + // Insert (unique keys) + // (I'm using an overloaded emplace for both 'insert' and 'emplace') + // I'm just ignoring hints here for now. + + // if hash function throws, basic exception safety + // strong otherwise + template + template + BOOST_DEDUCED_TYPENAME hash_unique_table::iterator_base + hash_unique_table::emplace_hint(iterator_base const&, + Args&&... args) + { + return this->size_ ? + emplace_impl( + extractor::extract(std::forward(args)...), + std::forward(args)...).first : + emplace_empty_impl(std::forward(args)...).first; + } + +#else + + template + template + BOOST_DEDUCED_TYPENAME hash_unique_table::emplace_return + hash_unique_table::emplace(Arg0 const& arg0) + { + return this->size_ ? + emplace_impl(extractor::extract(arg0), arg0) : + emplace_empty_impl(arg0); + } + + template + template + BOOST_DEDUCED_TYPENAME hash_unique_table::iterator_base + hash_unique_table::emplace_hint(iterator_base const&, + Arg0 const& arg0) + { + return this->size_ ? + emplace_impl(extractor::extract(arg0), arg0).first : + emplace_empty_impl(arg0).first; + } + +#define BOOST_UNORDERED_INSERT_IMPL(z, n, _) \ + template \ + template \ + BOOST_DEDUCED_TYPENAME hash_unique_table::emplace_return \ + hash_unique_table::emplace( \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \ + { \ + return this->size_ ? \ + emplace_impl(extractor::extract(arg0, arg1), \ + BOOST_UNORDERED_CALL_PARAMS(z, n)) : \ + emplace_empty_impl( \ + BOOST_UNORDERED_CALL_PARAMS(z, n)); \ + } \ + \ + template \ + template \ + BOOST_DEDUCED_TYPENAME hash_unique_table::iterator_base \ + hash_unique_table:: \ + emplace_hint(iterator_base const& it, \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \ + { \ + return this->size_ ? \ + emplace_impl(extractor::extract(arg0, arg1), \ + BOOST_UNORDERED_CALL_PARAMS(z, n)) : \ + emplace_empty_impl( \ + BOOST_UNORDERED_CALL_PARAMS(z, n)); \ + } \ + + BOOST_PP_REPEAT_FROM_TO(2, BOOST_UNORDERED_EMPLACE_LIMIT, + BOOST_UNORDERED_INSERT_IMPL, _) + +#undef BOOST_UNORDERED_INSERT_IMPL + +#endif + + //////////////////////////////////////////////////////////////////////////// + // Insert range methods + + template + template + inline void hash_unique_table::insert_range_impl( + key_type const&, InputIt i, InputIt j) + { + node_constructor a(*this); + + if(!this->size_) { + a.construct(*i); + this->emplace_empty_impl_with_node(a, 1); + ++i; + if(i == j) return; + } + + do { + // No side effects in this initial code + // Note: can't use get_key as '*i' might not be value_type. + // TODO: Check if std::pair has an appropriate constructor. If not + // that might not be true. + // TODO: Test this line better. + key_type const& k = extractor::extract(*i); + std::size_t hash_value = this->hash_function()(k); + bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value); + node_ptr pos = find_iterator(bucket, k); + + if (!BOOST_UNORDERED_BORLAND_BOOL(pos)) { + // Doesn't already exist, add to bucket. + // Side effects only in this block. + + // Create the node before rehashing in case it throws an + // exception (need strong safety in such a case). + a.construct(*i); + + // reserve has basic exception safety if the hash function + // throws, strong otherwise. + if(this->size_ + 1 >= this->max_load_) { + this->reserve_for_insert(this->size_ + insert_size(i, j)); + bucket = this->bucket_ptr_from_hash(hash_value); + } + + // Nothing after this point can throw. + add_node(a, bucket); + } + } while(++i != j); + } + + template + template + inline void hash_unique_table::insert_range_impl( + no_key, InputIt i, InputIt j) + { + node_constructor a(*this); + + if(!this->size_) { + a.construct(*i); + this->emplace_empty_impl_with_node(a, 1); + ++i; + if(i == j) return; + } + + do { + // No side effects in this initial code + a.construct(*i); + emplace_impl_with_node(a); + } while(++i != j); + } + + // if hash function throws, or inserting > 1 element, basic exception safety + // strong otherwise + template + template + void hash_unique_table::insert_range(InputIt i, InputIt j) + { + if(i != j) + return insert_range_impl(extractor::extract(*i), i, j); + } +}} + +#endif diff --git a/include/boost/unordered/detail/util.hpp b/include/boost/unordered/detail/util.hpp index b6827b27..9a70185e 100644 --- a/include/boost/unordered/detail/util.hpp +++ b/include/boost/unordered/detail/util.hpp @@ -14,22 +14,7 @@ #include #include #include -#include - -#if !defined(BOOST_UNORDERED_STD_FORWARD) - -#include -#include -#include - -#define BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ - BOOST_PP_ENUM_PARAMS_Z(z, n, class Arg) -#define BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ - BOOST_PP_ENUM_BINARY_PARAMS_Z(z, n, Arg, const& arg) -#define BOOST_UNORDERED_CALL_PARAMS(z, n) \ - BOOST_PP_ENUM_PARAMS_Z(z, n, arg) - -#endif +#include namespace boost { namespace unordered_detail { @@ -38,7 +23,8 @@ namespace boost { namespace unordered_detail { inline std::size_t double_to_size_t(double f) { - return f >= static_cast((std::numeric_limits::max)()) ? + return f >= static_cast( + (std::numeric_limits::max)()) ? (std::numeric_limits::max)() : static_cast(f); } @@ -143,7 +129,7 @@ namespace boost { namespace unordered_detail { template inline std::size_t initial_size(I i, I j, - std::size_t n = boost::unordered_detail::default_initial_bucket_count) + std::size_t n = boost::unordered_detail::default_bucket_count) { return (std::max)(static_cast(insert_size(i, j)) + 1, n); } @@ -172,29 +158,29 @@ namespace boost { namespace unordered_detail { #else -#define BOOST_UNORDERED_CONSTRUCT_IMPL(z, n, _) \ - template < \ - class T, \ - BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ - > \ - inline void construct_impl( \ - T*, void* address, \ - BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ - ) \ - { \ - new(address) T( \ - BOOST_UNORDERED_CALL_PARAMS(z, n)); \ - } \ - \ - template \ - inline void construct_impl( \ - std::pair*, void* address, \ - Key const& k, BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \ - { \ - new(address) std::pair(k, \ - Second(BOOST_UNORDERED_CALL_PARAMS(z, n))); \ +#define BOOST_UNORDERED_CONSTRUCT_IMPL(z, n, _) \ + template < \ + class T, \ + BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ + > \ + inline void construct_impl( \ + T*, void* address, \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ + ) \ + { \ + new(address) T( \ + BOOST_UNORDERED_CALL_PARAMS(z, n)); \ + } \ + \ + template \ + inline void construct_impl( \ + std::pair*, void* address, \ + Key const& k, BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \ + { \ + new(address) std::pair(k, \ + Second(BOOST_UNORDERED_CALL_PARAMS(z, n))); \ } BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, @@ -244,20 +230,20 @@ namespace boost { namespace unordered_detail { } #else -#define BOOST_UNORDERED_CONSTRUCT(z, n, _) \ - template < \ - BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ - > \ - void construct( \ - BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ - ) \ - { \ - construct_preamble(); \ - construct_impl( \ - (value_type*) 0, node_->address(), \ - BOOST_UNORDERED_CALL_PARAMS(z, n) \ - ); \ - value_constructed_ = true; \ +#define BOOST_UNORDERED_CONSTRUCT(z, n, _) \ + template < \ + BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ + > \ + void construct( \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ + ) \ + { \ + construct_preamble(); \ + construct_impl( \ + (value_type*) 0, node_->address(), \ + BOOST_UNORDERED_CALL_PARAMS(z, n) \ + ); \ + value_constructed_ = true; \ } BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, @@ -274,10 +260,10 @@ namespace boost { namespace unordered_detail { value_constructed_ = true; } - real_node_ptr get() const + value_type& value() const { BOOST_ASSERT(node_); - return node_; + return node_->value(); } // no throw @@ -297,11 +283,11 @@ namespace boost { namespace unordered_detail { // hash_node_constructor template - hash_node_constructor::~hash_node_constructor() + inline hash_node_constructor::~hash_node_constructor() { if (node_) { if (value_constructed_) { - BOOST_UNORDERED_DESTRUCT(&node_->value(), value_type); + boost::unordered_detail::destroy(&node_->value()); } if (node_constructed_) @@ -312,7 +298,7 @@ namespace boost { namespace unordered_detail { } template - void hash_node_constructor::construct_preamble() + inline void hash_node_constructor::construct_preamble() { if(!node_) { node_constructed_ = false; @@ -324,7 +310,7 @@ namespace boost { namespace unordered_detail { } else { BOOST_ASSERT(node_constructed_ && value_constructed_); - BOOST_UNORDERED_DESTRUCT(&node_->value(), value_type); + boost::unordered_detail::destroy(&node_->value()); value_constructed_ = false; } } diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 8880a029..0e89d43a 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -16,7 +16,8 @@ #include #include #include -#include +#include +#include #if !defined(BOOST_HAS_RVALUE_REFS) #include @@ -53,32 +54,41 @@ namespace boost #endif typedef BOOST_DEDUCED_TYPENAME - boost::unordered_detail::rebind_wrap::type + boost::unordered_detail::rebind_wrap< + allocator_type, value_type>::type value_allocator; - typedef boost::unordered_detail::hash_unique_table table; + typedef boost::unordered_detail::hash_unique_table table; typedef BOOST_DEDUCED_TYPENAME table::iterator_base iterator_base; public: - typedef BOOST_DEDUCED_TYPENAME value_allocator::pointer pointer; - typedef BOOST_DEDUCED_TYPENAME value_allocator::const_pointer const_pointer; - typedef BOOST_DEDUCED_TYPENAME value_allocator::reference reference; - typedef BOOST_DEDUCED_TYPENAME value_allocator::const_reference const_reference; + typedef BOOST_DEDUCED_TYPENAME + value_allocator::pointer pointer; + typedef BOOST_DEDUCED_TYPENAME + value_allocator::const_pointer const_pointer; + typedef BOOST_DEDUCED_TYPENAME + value_allocator::reference reference; + typedef BOOST_DEDUCED_TYPENAME + value_allocator::const_reference const_reference; typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; typedef boost::unordered_detail::hash_const_local_iterator< - value_allocator, boost::unordered_detail::ungrouped> const_local_iterator; + value_allocator, boost::unordered_detail::ungrouped> + const_local_iterator; typedef boost::unordered_detail::hash_local_iterator< - value_allocator, boost::unordered_detail::ungrouped> local_iterator; + value_allocator, boost::unordered_detail::ungrouped> + local_iterator; typedef boost::unordered_detail::hash_const_iterator< - value_allocator, boost::unordered_detail::ungrouped> const_iterator; + value_allocator, boost::unordered_detail::ungrouped> + const_iterator; typedef boost::unordered_detail::hash_iterator< - value_allocator, boost::unordered_detail::ungrouped> iterator; + value_allocator, boost::unordered_detail::ungrouped> + iterator; #if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) private: @@ -97,49 +107,51 @@ namespace boost // construct/destroy/copy explicit unordered_map( - size_type n = boost::unordered_detail::default_initial_bucket_count, + size_type n = boost::unordered_detail::default_bucket_count, const hasher &hf = hasher(), const key_equal &eql = key_equal(), const allocator_type &a = allocator_type()) - : table_(n, hf, eql, a) + : table_(n, hf, eql, a) { } explicit unordered_map(allocator_type const& a) - : table_(boost::unordered_detail::default_initial_bucket_count, + : table_(boost::unordered_detail::default_bucket_count, hasher(), key_equal(), a) { } unordered_map(unordered_map const& other, allocator_type const& a) - : table_(other.table_, a) + : table_(other.table_, a) { } - template - unordered_map(InputIterator f, InputIterator l) - : table_(boost::unordered_detail::initial_size(f, l), hasher(), key_equal(), allocator_type()) + template + unordered_map(InputIt f, InputIt l) + : table_(boost::unordered_detail::initial_size(f, l), + hasher(), key_equal(), allocator_type()) { table_.insert_range(f, l); } - template - unordered_map(InputIterator f, InputIterator l, + template + unordered_map(InputIt f, InputIt l, size_type n, const hasher &hf = hasher(), const key_equal &eql = key_equal()) - : table_(boost::unordered_detail::initial_size(f, l, n), hf, eql, allocator_type()) + : table_(boost::unordered_detail::initial_size(f, l, n), + hf, eql, allocator_type()) { table_.insert_range(f, l); } - template - unordered_map(InputIterator f, InputIterator l, + template + unordered_map(InputIt f, InputIt l, size_type n, const hasher &hf, const key_equal &eql, const allocator_type &a) - : table_(boost::unordered_detail::initial_size(f, l, n), hf, eql, a) + : table_(boost::unordered_detail::initial_size(f, l, n), hf, eql, a) { table_.insert_range(f, l); } @@ -148,12 +160,12 @@ namespace boost #if defined(BOOST_HAS_RVALUE_REFS) unordered_map(unordered_map&& other) - : table_(other.table_, boost::unordered_detail::move_tag()) + : table_(other.table_, boost::unordered_detail::move_tag()) { } unordered_map(unordered_map&& other, allocator_type const& a) - : table_(other.table_, a, boost::unordered_detail::move_tag()) + : table_(other.table_, a, boost::unordered_detail::move_tag()) { } @@ -163,8 +175,10 @@ namespace boost return *this; } #else - unordered_map(boost::unordered_detail::move_from > other) - : table_(other.source.table_, boost::unordered_detail::move_tag()) + unordered_map(boost::unordered_detail::move_from< + unordered_map + > other) + : table_(other.source.table_, boost::unordered_detail::move_tag()) { } @@ -179,11 +193,13 @@ namespace boost #if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) unordered_map(std::initializer_list list, - size_type n = boost::unordered_detail::default_initial_bucket_count, + size_type n = boost::unordered_detail::default_bucket_count, const hasher &hf = hasher(), const key_equal &eql = key_equal(), const allocator_type &a = allocator_type()) - : table_(boost::unordered_detail::initial_size(list.begin(), list.end(), n), hf, eql, allocator_type()) + : table_(boost::unordered_detail::initial_size( + list.begin(), list.end(), n), + hf, eql, allocator_type()) { table_.insert_range(list.begin(), list.end()); } @@ -263,7 +279,8 @@ namespace boost template iterator emplace_hint(const_iterator hint, Args&&... args) { - return iterator(table_.emplace_hint(get(hint), std::forward(args)...)); + return iterator( + table_.emplace_hint(get(hint), std::forward(args)...)); } #else @@ -273,35 +290,36 @@ namespace boost table_.emplace(v)); } - iterator emplace_hint(const_iterator hint, value_type const& v = value_type()) + iterator emplace_hint(const_iterator hint, + value_type const& v = value_type()) { return iterator(table_.emplace_hint(get(hint), v)); } -#define BOOST_UNORDERED_EMPLACE(z, n, _) \ - template < \ - BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ - > \ - std::pair emplace( \ - BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ - ) \ - { \ - return boost::unordered_detail::pair_cast( \ - table_.emplace( \ - BOOST_UNORDERED_CALL_PARAMS(z, n) \ - )); \ - } \ - \ - template < \ - BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ - > \ - iterator emplace_hint(const_iterator hint, \ - BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ - ) \ - { \ - return iterator(table_.emplace_hint(get(hint), \ - BOOST_UNORDERED_CALL_PARAMS(z, n) \ - )); \ +#define BOOST_UNORDERED_EMPLACE(z, n, _) \ + template < \ + BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ + > \ + std::pair emplace( \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ + ) \ + { \ + return boost::unordered_detail::pair_cast( \ + table_.emplace( \ + BOOST_UNORDERED_CALL_PARAMS(z, n) \ + )); \ + } \ + \ + template < \ + BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ + > \ + iterator emplace_hint(const_iterator hint, \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ + ) \ + { \ + return iterator(table_.emplace_hint(get(hint), \ + BOOST_UNORDERED_CALL_PARAMS(z, n) \ + )); \ } BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, @@ -322,8 +340,8 @@ namespace boost return iterator(table_.emplace_hint(get(hint), obj)); } - template - void insert(InputIterator first, InputIterator last) + template + void insert(InputIt first, InputIt last) { table_.insert_range(first, last); } @@ -400,14 +418,16 @@ namespace boost std::pair equal_range(const key_type& k) { - return boost::unordered_detail::pair_cast( + return boost::unordered_detail::pair_cast< + iterator, iterator>( table_.equal_range(k)); } std::pair equal_range(const key_type& k) const { - return boost::unordered_detail::pair_cast( + return boost::unordered_detail::pair_cast< + const_iterator, const_iterator>( table_.equal_range(k)); } @@ -415,7 +435,7 @@ namespace boost size_type bucket_count() const { - return table_.bucket_count(); + return table_.bucket_count_; } size_type max_bucket_count() const @@ -443,14 +463,14 @@ namespace boost return const_local_iterator(table_.bucket_begin(n)); } - local_iterator end(size_type n) + local_iterator end(size_type) { - return local_iterator(table_.bucket_end(n)); + return local_iterator(); } - const_local_iterator end(size_type n) const + const_local_iterator end(size_type) const { - return const_local_iterator(table_.bucket_end(n)); + return const_local_iterator(); } const_local_iterator cbegin(size_type n) const @@ -458,9 +478,9 @@ namespace boost return const_local_iterator(table_.bucket_begin(n)); } - const_local_iterator cend(size_type n) const + const_local_iterator cend(size_type) const { - return const_local_iterator(table_.bucket_end(n)); + return const_local_iterator(); } // hash policy @@ -486,8 +506,10 @@ namespace boost } #if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) - friend bool operator==(unordered_map const&, unordered_map const&); - friend bool operator!=(unordered_map const&, unordered_map const&); + friend bool operator==( + unordered_map const&, unordered_map const&); + friend bool operator!=( + unordered_map const&, unordered_map const&); #endif }; // class template unordered_map @@ -528,31 +550,40 @@ namespace boost private: #endif typedef BOOST_DEDUCED_TYPENAME - boost::unordered_detail::rebind_wrap::type + boost::unordered_detail::rebind_wrap< + allocator_type, value_type>::type value_allocator; - typedef boost::unordered_detail::hash_equivalent_table table; + typedef boost::unordered_detail::hash_equivalent_table table; typedef BOOST_DEDUCED_TYPENAME table::iterator_base iterator_base; public: - typedef BOOST_DEDUCED_TYPENAME value_allocator::pointer pointer; - typedef BOOST_DEDUCED_TYPENAME value_allocator::const_pointer const_pointer; - typedef BOOST_DEDUCED_TYPENAME value_allocator::reference reference; - typedef BOOST_DEDUCED_TYPENAME value_allocator::const_reference const_reference; + typedef BOOST_DEDUCED_TYPENAME + value_allocator::pointer pointer; + typedef BOOST_DEDUCED_TYPENAME + value_allocator::const_pointer const_pointer; + typedef BOOST_DEDUCED_TYPENAME + value_allocator::reference reference; + typedef BOOST_DEDUCED_TYPENAME + value_allocator::const_reference const_reference; typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; typedef boost::unordered_detail::hash_const_local_iterator< - value_allocator, boost::unordered_detail::grouped> const_local_iterator; + value_allocator, boost::unordered_detail::grouped> + const_local_iterator; typedef boost::unordered_detail::hash_local_iterator< - value_allocator, boost::unordered_detail::grouped> local_iterator; + value_allocator, boost::unordered_detail::grouped> + local_iterator; typedef boost::unordered_detail::hash_const_iterator< - value_allocator, boost::unordered_detail::grouped> const_iterator; + value_allocator, boost::unordered_detail::grouped> + const_iterator; typedef boost::unordered_detail::hash_iterator< - value_allocator, boost::unordered_detail::grouped> iterator; + value_allocator, boost::unordered_detail::grouped> + iterator; #if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) private: @@ -571,7 +602,7 @@ namespace boost // construct/destroy/copy explicit unordered_multimap( - size_type n = boost::unordered_detail::default_initial_bucket_count, + size_type n = boost::unordered_detail::default_bucket_count, const hasher &hf = hasher(), const key_equal &eql = key_equal(), const allocator_type &a = allocator_type()) @@ -580,35 +611,38 @@ namespace boost } explicit unordered_multimap(allocator_type const& a) - : table_(boost::unordered_detail::default_initial_bucket_count, + : table_(boost::unordered_detail::default_bucket_count, hasher(), key_equal(), a) { } - unordered_multimap(unordered_multimap const& other, allocator_type const& a) - : table_(other.table_, a) + unordered_multimap(unordered_multimap const& other, + allocator_type const& a) + : table_(other.table_, a) { } - template - unordered_multimap(InputIterator f, InputIterator l) - : table_(boost::unordered_detail::initial_size(f, l), hasher(), key_equal(), allocator_type()) + template + unordered_multimap(InputIt f, InputIt l) + : table_(boost::unordered_detail::initial_size(f, l), + hasher(), key_equal(), allocator_type()) { table_.insert_range(f, l); } - template - unordered_multimap(InputIterator f, InputIterator l, + template + unordered_multimap(InputIt f, InputIt l, size_type n, const hasher &hf = hasher(), const key_equal &eql = key_equal()) - : table_(boost::unordered_detail::initial_size(f, l, n), hf, eql, allocator_type()) + : table_(boost::unordered_detail::initial_size(f, l, n), + hf, eql, allocator_type()) { table_.insert_range(f, l); } - template - unordered_multimap(InputIterator f, InputIterator l, + template + unordered_multimap(InputIt f, InputIt l, size_type n, const hasher &hf, const key_equal &eql, @@ -622,12 +656,12 @@ namespace boost #if defined(BOOST_HAS_RVALUE_REFS) unordered_multimap(unordered_multimap&& other) - : table_(other.table_, boost::unordered_detail::move_tag()) + : table_(other.table_, boost::unordered_detail::move_tag()) { } unordered_multimap(unordered_multimap&& other, allocator_type const& a) - : table_(other.table_, a, boost::unordered_detail::move_tag()) + : table_(other.table_, a, boost::unordered_detail::move_tag()) { } @@ -637,8 +671,10 @@ namespace boost return *this; } #else - unordered_multimap(boost::unordered_detail::move_from > other) - : table_(other.source.table_, boost::unordered_detail::move_tag()) + unordered_multimap(boost::unordered_detail::move_from< + unordered_multimap + > other) + : table_(other.source.table_, boost::unordered_detail::move_tag()) { } @@ -653,11 +689,13 @@ namespace boost #if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) unordered_multimap(std::initializer_list list, - size_type n = boost::unordered_detail::default_initial_bucket_count, + size_type n = boost::unordered_detail::default_bucket_count, const hasher &hf = hasher(), const key_equal &eql = key_equal(), const allocator_type &a = allocator_type()) - : table_(boost::unordered_detail::initial_size(list.begin(), list.end(), n), hf, eql, allocator_type()) + : table_(boost::unordered_detail::initial_size( + list.begin(), list.end(), n), + hf, eql, allocator_type()) { table_.insert_range(list.begin(), list.end()); } @@ -736,7 +774,8 @@ namespace boost template iterator emplace_hint(const_iterator hint, Args&&... args) { - return iterator(table_.emplace_hint(get(hint), std::forward(args)...)); + return iterator(table_.emplace_hint(get(hint), + std::forward(args)...)); } #else @@ -745,36 +784,37 @@ namespace boost return iterator(table_.emplace(v)); } - iterator emplace_hint(const_iterator hint, value_type const& v = value_type()) + iterator emplace_hint(const_iterator hint, + value_type const& v = value_type()) { return iterator(table_.emplace_hint(get(hint), v)); } -#define BOOST_UNORDERED_EMPLACE(z, n, _) \ - template < \ - BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ - > \ - iterator emplace( \ - BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ - ) \ - { \ - return iterator( \ - table_.emplace( \ - BOOST_UNORDERED_CALL_PARAMS(z, n) \ - )); \ - } \ - \ - template < \ - BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ - > \ - iterator emplace_hint(const_iterator hint, \ - BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ - ) \ - { \ - return iterator(table_.emplace_hint(get(hint), \ - BOOST_UNORDERED_CALL_PARAMS(z, n) \ - )); \ +#define BOOST_UNORDERED_EMPLACE(z, n, _) \ + template < \ + BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ + > \ + iterator emplace( \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ + ) \ + { \ + return iterator( \ + table_.emplace( \ + BOOST_UNORDERED_CALL_PARAMS(z, n) \ + )); \ + } \ + \ + template < \ + BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ + > \ + iterator emplace_hint(const_iterator hint, \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ + ) \ + { \ + return iterator(table_.emplace_hint(get(hint), \ + BOOST_UNORDERED_CALL_PARAMS(z, n) \ + )); \ } BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, @@ -794,8 +834,8 @@ namespace boost return iterator(table_.emplace_hint(get(hint), obj)); } - template - void insert(InputIterator first, InputIterator last) + template + void insert(InputIt first, InputIt last) { table_.insert_range(first, last); } @@ -857,14 +897,16 @@ namespace boost std::pair equal_range(const key_type& k) { - return boost::unordered_detail::pair_cast( + return boost::unordered_detail::pair_cast< + iterator, iterator>( table_.equal_range(k)); } std::pair equal_range(const key_type& k) const { - return boost::unordered_detail::pair_cast( + return boost::unordered_detail::pair_cast< + const_iterator, const_iterator>( table_.equal_range(k)); } @@ -872,7 +914,7 @@ namespace boost size_type bucket_count() const { - return table_.bucket_count(); + return table_.bucket_count_; } size_type max_bucket_count() const @@ -900,14 +942,14 @@ namespace boost return const_local_iterator(table_.bucket_begin(n)); } - local_iterator end(size_type n) + local_iterator end(size_type) { - return local_iterator(table_.bucket_end(n)); + return local_iterator(); } - const_local_iterator end(size_type n) const + const_local_iterator end(size_type) const { - return const_local_iterator(table_.bucket_end(n)); + return const_local_iterator(); } const_local_iterator cbegin(size_type n) const @@ -915,9 +957,9 @@ namespace boost return const_local_iterator(table_.bucket_begin(n)); } - const_local_iterator cend(size_type n) const + const_local_iterator cend(size_type) const { - return const_local_iterator(table_.bucket_end(n)); + return const_local_iterator(); } // hash policy @@ -943,8 +985,10 @@ namespace boost } #if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) - friend bool operator==(unordered_multimap const&, unordered_multimap const&); - friend bool operator!=(unordered_multimap const&, unordered_multimap const&); + friend bool operator==( + unordered_multimap const&, unordered_multimap const&); + friend bool operator!=( + unordered_multimap const&, unordered_multimap const&); #endif }; // class template unordered_multimap diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index c6ef5fc7..e7d53d23 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -16,7 +16,8 @@ #include #include #include -#include +#include +#include #if !defined(BOOST_HAS_RVALUE_REFS) #include @@ -53,27 +54,34 @@ namespace boost #endif typedef BOOST_DEDUCED_TYPENAME - boost::unordered_detail::rebind_wrap::type + boost::unordered_detail::rebind_wrap< + allocator_type, value_type>::type value_allocator; - typedef boost::unordered_detail::hash_unique_table table; + typedef boost::unordered_detail::hash_unique_table table; typedef BOOST_DEDUCED_TYPENAME table::iterator_base iterator_base; public: - typedef BOOST_DEDUCED_TYPENAME value_allocator::pointer pointer; - typedef BOOST_DEDUCED_TYPENAME value_allocator::const_pointer const_pointer; - typedef BOOST_DEDUCED_TYPENAME value_allocator::reference reference; - typedef BOOST_DEDUCED_TYPENAME value_allocator::const_reference const_reference; + typedef BOOST_DEDUCED_TYPENAME + value_allocator::pointer pointer; + typedef BOOST_DEDUCED_TYPENAME + value_allocator::const_pointer const_pointer; + typedef BOOST_DEDUCED_TYPENAME + value_allocator::reference reference; + typedef BOOST_DEDUCED_TYPENAME + value_allocator::const_reference const_reference; typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; typedef boost::unordered_detail::hash_const_local_iterator< - value_allocator, boost::unordered_detail::ungrouped> const_local_iterator; + value_allocator, boost::unordered_detail::ungrouped> + const_local_iterator; typedef boost::unordered_detail::hash_const_iterator< - value_allocator, boost::unordered_detail::ungrouped> const_iterator; + value_allocator, boost::unordered_detail::ungrouped> + const_iterator; typedef const_local_iterator local_iterator; typedef const_iterator iterator; @@ -94,47 +102,49 @@ namespace boost // construct/destroy/copy explicit unordered_set( - size_type n = boost::unordered_detail::default_initial_bucket_count, + size_type n = boost::unordered_detail::default_bucket_count, const hasher &hf = hasher(), const key_equal &eql = key_equal(), const allocator_type &a = allocator_type()) - : table_(n, hf, eql, a) + : table_(n, hf, eql, a) { } explicit unordered_set(allocator_type const& a) - : table_(boost::unordered_detail::default_initial_bucket_count, + : table_(boost::unordered_detail::default_bucket_count, hasher(), key_equal(), a) { } unordered_set(unordered_set const& other, allocator_type const& a) - : table_(other.table_, a) + : table_(other.table_, a) { } - template - unordered_set(InputIterator f, InputIterator l) - : table_(boost::unordered_detail::initial_size(f, l), hasher(), key_equal(), allocator_type()) + template + unordered_set(InputIt f, InputIt l) + : table_(boost::unordered_detail::initial_size(f, l), + hasher(), key_equal(), allocator_type()) { table_.insert_range(f, l); } - template - unordered_set(InputIterator f, InputIterator l, size_type n, + template + unordered_set(InputIt f, InputIt l, size_type n, const hasher &hf = hasher(), const key_equal &eql = key_equal()) - : table_(boost::unordered_detail::initial_size(f, l, n), hf, eql, allocator_type()) + : table_(boost::unordered_detail::initial_size(f, l, n), + hf, eql, allocator_type()) { table_.insert_range(f, l); } - template - unordered_set(InputIterator f, InputIterator l, size_type n, + template + unordered_set(InputIt f, InputIt l, size_type n, const hasher &hf, const key_equal &eql, const allocator_type &a) - : table_(boost::unordered_detail::initial_size(f, l, n), hf, eql, a) + : table_(boost::unordered_detail::initial_size(f, l, n), hf, eql, a) { table_.insert_range(f, l); } @@ -143,12 +153,12 @@ namespace boost #if defined(BOOST_HAS_RVALUE_REFS) unordered_set(unordered_set&& other) - : table_(other.table_, boost::unordered_detail::move_tag()) + : table_(other.table_, boost::unordered_detail::move_tag()) { } unordered_set(unordered_set&& other, allocator_type const& a) - : table_(other.table_, a, boost::unordered_detail::move_tag()) + : table_(other.table_, a, boost::unordered_detail::move_tag()) { } @@ -158,8 +168,10 @@ namespace boost return *this; } #else - unordered_set(boost::unordered_detail::move_from > other) - : table_(other.source.table_, boost::unordered_detail::move_tag()) + unordered_set(boost::unordered_detail::move_from< + unordered_set + > other) + : table_(other.source.table_, boost::unordered_detail::move_tag()) { } @@ -174,11 +186,13 @@ namespace boost #if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) unordered_set(std::initializer_list list, - size_type n = boost::unordered_detail::default_initial_bucket_count, + size_type n = boost::unordered_detail::default_bucket_count, const hasher &hf = hasher(), const key_equal &eql = key_equal(), const allocator_type &a = allocator_type()) - : table_(boost::unordered_detail::initial_size(list.begin(), list.end(), n), hf, eql, allocator_type()) + : table_(boost::unordered_detail::initial_size( + list.begin(), list.end(), n), + hf, eql, allocator_type()) { table_.insert_range(list.begin(), list.end()); } @@ -269,35 +283,36 @@ namespace boost table_.emplace(v)); } - iterator emplace_hint(const_iterator hint, value_type const& v = value_type()) + iterator emplace_hint(const_iterator hint, + value_type const& v = value_type()) { return iterator(table_.emplace_hint(get(hint), v)); } -#define BOOST_UNORDERED_EMPLACE(z, n, _) \ - template < \ - BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ - > \ - std::pair emplace( \ - BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ - ) \ - { \ - return boost::unordered_detail::pair_cast( \ - table_.emplace( \ - BOOST_UNORDERED_CALL_PARAMS(z, n) \ - )); \ - } \ - \ - template < \ - BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ - > \ - iterator emplace_hint(const_iterator hint, \ - BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ - ) \ - { \ - return iterator(table_.emplace_hint(get(hint), \ - BOOST_UNORDERED_CALL_PARAMS(z, n) \ - )); \ +#define BOOST_UNORDERED_EMPLACE(z, n, _) \ + template < \ + BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ + > \ + std::pair emplace( \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ + ) \ + { \ + return boost::unordered_detail::pair_cast( \ + table_.emplace( \ + BOOST_UNORDERED_CALL_PARAMS(z, n) \ + )); \ + } \ + \ + template < \ + BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ + > \ + iterator emplace_hint(const_iterator hint, \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ + ) \ + { \ + return iterator(table_.emplace_hint(get(hint), \ + BOOST_UNORDERED_CALL_PARAMS(z, n) \ + )); \ } BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, @@ -318,8 +333,8 @@ namespace boost return iterator(table_.emplace_hint(get(hint), obj)); } - template - void insert(InputIterator first, InputIterator last) + template + void insert(InputIt first, InputIt last) { table_.insert_range(first, last); } @@ -376,7 +391,8 @@ namespace boost std::pair equal_range(const key_type& k) const { - return boost::unordered_detail::pair_cast( + return boost::unordered_detail::pair_cast< + const_iterator, const_iterator>( table_.equal_range(k)); } @@ -384,7 +400,7 @@ namespace boost size_type bucket_count() const { - return table_.bucket_count(); + return table_.bucket_count_; } size_type max_bucket_count() const @@ -412,14 +428,14 @@ namespace boost return const_local_iterator(table_.bucket_begin(n)); } - local_iterator end(size_type n) + local_iterator end(size_type) { - return local_iterator(table_.bucket_end(n)); + return local_iterator(); } - const_local_iterator end(size_type n) const + const_local_iterator end(size_type) const { - return const_local_iterator(table_.bucket_end(n)); + return const_local_iterator(); } const_local_iterator cbegin(size_type n) const @@ -427,9 +443,9 @@ namespace boost return const_local_iterator(table_.bucket_begin(n)); } - const_local_iterator cend(size_type n) const + const_local_iterator cend(size_type) const { - return const_local_iterator(table_.bucket_end(n)); + return const_local_iterator(); } // hash policy @@ -455,8 +471,10 @@ namespace boost } #if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) - friend bool operator==(unordered_set const&, unordered_set const&); - friend bool operator!=(unordered_set const&, unordered_set const&); + friend bool operator==( + unordered_set const&, unordered_set const&); + friend bool operator!=( + unordered_set const&, unordered_set const&); #endif }; // class template unordered_set @@ -496,27 +514,34 @@ namespace boost private: #endif typedef BOOST_DEDUCED_TYPENAME - boost::unordered_detail::rebind_wrap::type + boost::unordered_detail::rebind_wrap< + allocator_type, value_type>::type value_allocator; - typedef boost::unordered_detail::hash_equivalent_table table; + typedef boost::unordered_detail::hash_equivalent_table table; typedef BOOST_DEDUCED_TYPENAME table::iterator_base iterator_base; public: - typedef BOOST_DEDUCED_TYPENAME value_allocator::pointer pointer; - typedef BOOST_DEDUCED_TYPENAME value_allocator::const_pointer const_pointer; - typedef BOOST_DEDUCED_TYPENAME value_allocator::reference reference; - typedef BOOST_DEDUCED_TYPENAME value_allocator::const_reference const_reference; + typedef BOOST_DEDUCED_TYPENAME + value_allocator::pointer pointer; + typedef BOOST_DEDUCED_TYPENAME + value_allocator::const_pointer const_pointer; + typedef BOOST_DEDUCED_TYPENAME + value_allocator::reference reference; + typedef BOOST_DEDUCED_TYPENAME + value_allocator::const_reference const_reference; typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; typedef boost::unordered_detail::hash_const_local_iterator< - value_allocator, boost::unordered_detail::grouped> const_local_iterator; + value_allocator, boost::unordered_detail::grouped> + const_local_iterator; typedef boost::unordered_detail::hash_const_iterator< - value_allocator, boost::unordered_detail::grouped> const_iterator; + value_allocator, boost::unordered_detail::grouped> + const_iterator; typedef const_local_iterator local_iterator; typedef const_iterator iterator; @@ -537,7 +562,7 @@ namespace boost // construct/destroy/copy explicit unordered_multiset( - size_type n = boost::unordered_detail::default_initial_bucket_count, + size_type n = boost::unordered_detail::default_bucket_count, const hasher &hf = hasher(), const key_equal &eql = key_equal(), const allocator_type &a = allocator_type()) @@ -546,34 +571,37 @@ namespace boost } explicit unordered_multiset(allocator_type const& a) - : table_(boost::unordered_detail::default_initial_bucket_count, + : table_(boost::unordered_detail::default_bucket_count, hasher(), key_equal(), a) { } - unordered_multiset(unordered_multiset const& other, allocator_type const& a) - : table_(other.table_, a) + unordered_multiset(unordered_multiset const& other, + allocator_type const& a) + : table_(other.table_, a) { } - template - unordered_multiset(InputIterator f, InputIterator l) - : table_(boost::unordered_detail::initial_size(f, l), hasher(), key_equal(), allocator_type()) + template + unordered_multiset(InputIt f, InputIt l) + : table_(boost::unordered_detail::initial_size(f, l), + hasher(), key_equal(), allocator_type()) { table_.insert_range(f, l); } - template - unordered_multiset(InputIterator f, InputIterator l, size_type n, + template + unordered_multiset(InputIt f, InputIt l, size_type n, const hasher &hf = hasher(), const key_equal &eql = key_equal()) - : table_(boost::unordered_detail::initial_size(f, l, n), hf, eql, allocator_type()) + : table_(boost::unordered_detail::initial_size(f, l, n), + hf, eql, allocator_type()) { table_.insert_range(f, l); } - template - unordered_multiset(InputIterator f, InputIterator l, size_type n, + template + unordered_multiset(InputIt f, InputIt l, size_type n, const hasher &hf, const key_equal &eql, const allocator_type &a) @@ -586,12 +614,12 @@ namespace boost #if defined(BOOST_HAS_RVALUE_REFS) unordered_multiset(unordered_multiset&& other) - : table_(other.table_, boost::unordered_detail::move_tag()) + : table_(other.table_, boost::unordered_detail::move_tag()) { } unordered_multiset(unordered_multiset&& other, allocator_type const& a) - : table_(other.table_, a, boost::unordered_detail::move_tag()) + : table_(other.table_, a, boost::unordered_detail::move_tag()) { } @@ -601,8 +629,10 @@ namespace boost return *this; } #else - unordered_multiset(boost::unordered_detail::move_from > other) - : table_(other.source.table_, boost::unordered_detail::move_tag()) + unordered_multiset(boost::unordered_detail::move_from< + unordered_multiset + > other) + : table_(other.source.table_, boost::unordered_detail::move_tag()) { } @@ -617,11 +647,13 @@ namespace boost #if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) unordered_multiset(std::initializer_list list, - size_type n = boost::unordered_detail::default_initial_bucket_count, + size_type n = boost::unordered_detail::default_bucket_count, const hasher &hf = hasher(), const key_equal &eql = key_equal(), const allocator_type &a = allocator_type()) - : table_(boost::unordered_detail::initial_size(list.begin(), list.end(), n), hf, eql, allocator_type()) + : table_(boost::unordered_detail::initial_size( + list.begin(), list.end(), n), + hf, eql, allocator_type()) { table_.insert_range(list.begin(), list.end()); } @@ -700,7 +732,8 @@ namespace boost template iterator emplace_hint(const_iterator hint, Args&&... args) { - return iterator(table_.emplace_hint(get(hint), std::forward(args)...)); + return iterator(table_.emplace_hint(get(hint), + std::forward(args)...)); } #else @@ -709,33 +742,34 @@ namespace boost return iterator(table_.emplace(v)); } - iterator emplace_hint(const_iterator hint, value_type const& v = value_type()) + iterator emplace_hint(const_iterator hint, + value_type const& v = value_type()) { return iterator(table_.emplace_hint(get(hint), v)); } -#define BOOST_UNORDERED_EMPLACE(z, n, _) \ - template < \ - BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ - > \ - iterator emplace( \ - BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ - ) \ - { \ - return iterator( \ - table_.emplace(BOOST_UNORDERED_CALL_PARAMS(z, n))); \ - } \ - \ - template < \ - BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ - > \ - iterator emplace_hint(const_iterator hint, \ - BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ - ) \ - { \ - return iterator(table_.emplace_hint(get(hint), \ - BOOST_UNORDERED_CALL_PARAMS(z, n) \ - )); \ +#define BOOST_UNORDERED_EMPLACE(z, n, _) \ + template < \ + BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ + > \ + iterator emplace( \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ + ) \ + { \ + return iterator( \ + table_.emplace(BOOST_UNORDERED_CALL_PARAMS(z, n))); \ + } \ + \ + template < \ + BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ + > \ + iterator emplace_hint(const_iterator hint, \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ + ) \ + { \ + return iterator(table_.emplace_hint(get(hint), \ + BOOST_UNORDERED_CALL_PARAMS(z, n) \ + )); \ } BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, @@ -755,8 +789,8 @@ namespace boost return iterator(table_.emplace_hint(get(hint), obj)); } - template - void insert(InputIterator first, InputIterator last) + template + void insert(InputIt first, InputIt last) { table_.insert_range(first, last); } @@ -813,7 +847,8 @@ namespace boost std::pair equal_range(const key_type& k) const { - return boost::unordered_detail::pair_cast( + return boost::unordered_detail::pair_cast< + const_iterator, const_iterator>( table_.equal_range(k)); } @@ -821,7 +856,7 @@ namespace boost size_type bucket_count() const { - return table_.bucket_count(); + return table_.bucket_count_; } size_type max_bucket_count() const @@ -849,14 +884,14 @@ namespace boost return const_local_iterator(table_.bucket_begin(n)); } - local_iterator end(size_type n) + local_iterator end(size_type) { - return local_iterator(table_.bucket_end(n)); + return local_iterator(); } - const_local_iterator end(size_type n) const + const_local_iterator end(size_type) const { - return const_local_iterator(table_.bucket_end(n)); + return const_local_iterator(); } const_local_iterator cbegin(size_type n) const @@ -864,9 +899,9 @@ namespace boost return const_local_iterator(table_.bucket_begin(n)); } - const_local_iterator cend(size_type n) const + const_local_iterator cend(size_type) const { - return const_local_iterator(table_.bucket_end(n)); + return const_local_iterator(); } // hash policy @@ -892,8 +927,10 @@ namespace boost } #if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) - friend bool operator==(unordered_multiset const&, unordered_multiset const&); - friend bool operator!=(unordered_multiset const&, unordered_multiset const&); + friend bool operator==( + unordered_multiset const&, unordered_multiset const&); + friend bool operator!=( + unordered_multiset const&, unordered_multiset const&); #endif }; // class template unordered_multiset diff --git a/test/helpers/list.hpp b/test/helpers/list.hpp index f4985841..d5a8b170 100644 --- a/test/helpers/list.hpp +++ b/test/helpers/list.hpp @@ -21,14 +21,17 @@ namespace test namespace test_detail { - template struct list_node; + template class list_node; template class list_data; template class list_iterator; template class list_const_iterator; template - struct list_node + class list_node { + list_node(list_node const&); + list_node& operator=(list_node const&); + public: T value_; list_node* next_; @@ -243,8 +246,8 @@ namespace test node** merge_adjacent_ranges(node** first, node** second, node** third, Less less) { - while(true) { - while(true) { + for(;;) { + for(;;) { if(first == second) return third; if(less((*second)->value_, (*first)->value_)) break; first = &(*first)->next_; @@ -256,7 +259,7 @@ namespace test // Since the two ranges we just swapped, the order is now: // first...third...second - while(true) { + for(;;) { if(first == third) return second; if(!less((*first)->value_, (*third)->value_)) break; first = &(*first)->next_; diff --git a/test/unordered/erase_equiv_tests.cpp b/test/unordered/erase_equiv_tests.cpp index fbd56c27..a1bebf45 100644 --- a/test/unordered/erase_equiv_tests.cpp +++ b/test/unordered/erase_equiv_tests.cpp @@ -116,7 +116,7 @@ bool compare(Range1 const& x, Range2 const& y) } template -bool general_erase_range_test(Container& x, int start, int end) +bool general_erase_range_test(Container& x, std::size_t start, std::size_t end) { collide_list l(x.begin(), x.end()); l.erase(boost::next(l.begin(), start), boost::next(l.begin(), end)); diff --git a/test/unordered/out_of_line.cpp b/test/unordered/out_of_line.cpp index b8d24e1f..98262529 100644 --- a/test/unordered/out_of_line.cpp +++ b/test/unordered/out_of_line.cpp @@ -10,7 +10,7 @@ struct foo { template template -bool foo::bar(U x) { return x; } +bool foo::bar(U x) { return x ? true : false; } int main() { foo x;