diff --git a/doc/changes.qbk b/doc/changes.qbk index 4837837c..abe2b812 100644 --- a/doc/changes.qbk +++ b/doc/changes.qbk @@ -175,4 +175,21 @@ C++11 support has resulted in some breaking changes: * Fix warning due to accidental odd assignment. * Slightly better error messages. +[h2 Boost 1.50.0] + +* Fix equality for `unordered_multiset` and `unordered_multimap`. +* [@http://svn.boost.org/trac/boost/ticket/6771 Ticket 6771]: + Avoid gcc's `-Wfloat-equal` warning. +* [@http://svn.boost.org/trac/boost/ticket/6784 Ticket 6784]: + Fix some Sun specific code. +* Remove some of the smaller prime number of buckets, as they may make + collisions quite probable (e.g. multiples of 5 are very common because + we used base 10). +* On old versions of Visual C++, use the container library's implementation + of `allocator_traits`, as it's more likely to work. +* On machines with 64 bit std::size_t, use power of 2 buckets, with Thomas + Wang's hash function to pick which one to use. As modulus is very slow + for 64 bit values. +* Some internal changes. + [endsect] diff --git a/include/boost/unordered/detail/allocator_helpers.hpp b/include/boost/unordered/detail/allocator_helpers.hpp index dbba5046..4f2e13d8 100644 --- a/include/boost/unordered/detail/allocator_helpers.hpp +++ b/include/boost/unordered/detail/allocator_helpers.hpp @@ -27,11 +27,34 @@ #include #if !defined(BOOST_UNORDERED_USE_ALLOCATOR_TRAITS) -#define BOOST_UNORDERED_USE_ALLOCATOR_TRAITS 0 +// An allocator_traits test is currently failing for gcc 4.7 on mingw. I think +// this is because it's an older development version. Temporarily disabling +// std::allocator_traits in order ot get clean test results. Will reactivate +// later. + +/* +# if defined(__GXX_EXPERIMENTAL_CXX0X__) && \ + (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)) +# define BOOST_UNORDERED_USE_ALLOCATOR_TRAITS 1 +# endif +*/ + +// Use container's allocator_traits for older versions of Visual C++ as I don't +// test with them. +# if defined(BOOST_MSVC) && BOOST_MSVC < 1400 +# define BOOST_UNORDERED_USE_ALLOCATOR_TRAITS 2 +# endif + #endif -#if BOOST_UNORDERED_USE_ALLOCATOR_TRAITS +#if !defined(BOOST_UNORDERED_USE_ALLOCATOR_TRAITS) +# define BOOST_UNORDERED_USE_ALLOCATOR_TRAITS 0 +#endif + +#if BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 1 # include +#elif BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 2 +# include #endif #if !defined(BOOST_NO_0X_HDR_TYPE_TRAITS) @@ -194,7 +217,7 @@ namespace boost { namespace unordered { namespace detail { // Uses the standard versions if available. // (although untested as I don't have access to a standard version yet) -#if BOOST_UNORDERED_USE_ALLOCATOR_TRAITS +#if BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 1 template struct allocator_traits : std::allocator_traits {}; @@ -206,6 +229,18 @@ namespace boost { namespace unordered { namespace detail { template rebind_alloc type; }; +#elif BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 2 + + template + struct allocator_traits : + boost::container::allocator_traits {}; + + template + struct rebind_wrap : + boost::container::allocator_traits:: + template portable_rebind_alloc + {}; + #else // TODO: Does this match std::allocator_traits::rebind_alloc? diff --git a/include/boost/unordered/detail/buckets.hpp b/include/boost/unordered/detail/buckets.hpp index 7492220b..9ee1343c 100644 --- a/include/boost/unordered/detail/buckets.hpp +++ b/include/boost/unordered/detail/buckets.hpp @@ -18,6 +18,8 @@ #include #include #include +#include +#include #if defined(BOOST_MSVC) #pragma warning(push) @@ -29,7 +31,10 @@ namespace boost { namespace unordered { namespace detail { template struct table; template struct bucket; struct ptr_bucket; - template struct buckets; + template + struct buckets; + template struct table_impl; + template struct grouped_table_impl; /////////////////////////////////////////////////////////////////// // @@ -178,13 +183,364 @@ namespace boost { namespace unordered { namespace detail { enum { extra_node = false }; }; +}}} + +namespace boost { namespace unordered { namespace iterator_detail { + + //////////////////////////////////////////////////////////////////////////// + // Iterators + // + // all no throw + + template struct iterator; + template struct c_iterator; + template + struct l_iterator; + template struct cl_iterator; + + // Local Iterators + // + // all no throw + + template + struct l_iterator + : public boost::iterator< + std::forward_iterator_tag, Value, std::ptrdiff_t, + NodePointer, Value&> + { +#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) + template + friend struct boost::unordered::iterator_detail::cl_iterator; + private: +#endif + typedef NodePointer node_pointer; + typedef boost::unordered::iterator_detail::iterator + iterator; + node_pointer ptr_; + std::size_t bucket_; + std::size_t bucket_count_; + + public: + + l_iterator() : ptr_() {} + + l_iterator(iterator x, std::size_t b, std::size_t c) + : ptr_(x.node_), bucket_(b), bucket_count_(c) {} + + Value& operator*() const { + return ptr_->value(); + } + + Value* operator->() const { + return ptr_->value_ptr(); + } + + l_iterator& operator++() { + ptr_ = static_cast(ptr_->next_); + if (ptr_ && Policy::to_bucket(bucket_count_, ptr_->hash_) + != bucket_) + ptr_ = node_pointer(); + return *this; + } + + l_iterator operator++(int) { + l_iterator tmp(*this); + ++(*this); + return tmp; + } + + bool operator==(l_iterator x) const { + return ptr_ == x.ptr_; + } + + bool operator!=(l_iterator x) const { + return ptr_ != x.ptr_; + } + }; + + template + struct cl_iterator + : public boost::iterator< + std::forward_iterator_tag, Value, std::ptrdiff_t, + ConstNodePointer, Value const&> + { + friend struct boost::unordered::iterator_detail::l_iterator + ; + private: + + typedef NodePointer node_pointer; + typedef boost::unordered::iterator_detail::iterator + iterator; + node_pointer ptr_; + std::size_t bucket_; + std::size_t bucket_count_; + + public: + + cl_iterator() : ptr_() {} + + cl_iterator(iterator x, std::size_t b, std::size_t c) : + ptr_(x.node_), bucket_(b), bucket_count_(c) {} + + cl_iterator(boost::unordered::iterator_detail::l_iterator< + NodePointer, Value, Policy> const& x) : + ptr_(x.ptr_), bucket_(x.bucket_), bucket_count_(x.bucket_count_) + {} + + Value const& + operator*() const { + return ptr_->value(); + } + + Value const* operator->() const { + return ptr_->value_ptr(); + } + + cl_iterator& operator++() { + ptr_ = static_cast(ptr_->next_); + if (ptr_ && Policy::to_bucket(bucket_count_, ptr_->hash_) + != bucket_) + ptr_ = node_pointer(); + return *this; + } + + cl_iterator operator++(int) { + cl_iterator tmp(*this); + ++(*this); + return tmp; + } + + friend bool operator==(cl_iterator const& x, cl_iterator const& y) { + return x.ptr_ == y.ptr_; + } + + friend bool operator!=(cl_iterator const& x, cl_iterator const& y) { + return x.ptr_ != y.ptr_; + } + }; + + template + struct iterator + : public boost::iterator< + std::forward_iterator_tag, Value, std::ptrdiff_t, + NodePointer, Value&> + { +#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) + template + friend struct boost::unordered::iterator_detail::c_iterator; + template + friend struct boost::unordered::iterator_detail::l_iterator; + template + friend struct boost::unordered::iterator_detail::cl_iterator; + template + friend struct boost::unordered::detail::table; + template + friend struct boost::unordered::detail::buckets; + template + friend struct boost::unordered::detail::table_impl; + template + friend struct boost::unordered::detail::grouped_table_impl; + private: +#endif + typedef NodePointer node_pointer; + node_pointer node_; + + public: + + iterator() : node_() {} + + explicit iterator(node_pointer const& x) : node_(x) {} + + Value& operator*() const { + return node_->value(); + } + + Value* operator->() const { + return &node_->value(); + } + + iterator& operator++() { + node_ = static_cast(node_->next_); + return *this; + } + + iterator operator++(int) { + iterator tmp(node_); + node_ = static_cast(node_->next_); + return tmp; + } + + bool operator==(iterator const& x) const { + return node_ == x.node_; + } + + bool operator!=(iterator const& x) const { + return node_ != x.node_; + } + }; + + template + struct c_iterator + : public boost::iterator< + std::forward_iterator_tag, Value, std::ptrdiff_t, + ConstNodePointer, Value const&> + { + friend struct boost::unordered::iterator_detail::iterator< + NodePointer, Value>; + +#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) + template + friend struct boost::unordered::detail::table; + template + friend struct boost::unordered::detail::buckets; + template + friend struct boost::unordered::detail::table_impl; + template + friend struct boost::unordered::detail::grouped_table_impl; + + private: +#endif + + typedef NodePointer node_pointer; + typedef boost::unordered::iterator_detail::iterator + iterator; + node_pointer node_; + + public: + + c_iterator() : node_() {} + + explicit c_iterator(node_pointer const& x) : node_(x) {} + + c_iterator(boost::unordered::iterator_detail::iterator< + NodePointer, Value> const& x) : node_(x.node_) {} + + Value const& operator*() const { + return node_->value(); + } + + Value const* operator->() const { + return &node_->value(); + } + + c_iterator& operator++() { + node_ = static_cast(node_->next_); + return *this; + } + + c_iterator operator++(int) { + c_iterator tmp(node_); + node_ = static_cast(node_->next_); + return tmp; + } + + friend bool operator==(c_iterator const& x, c_iterator const& y) { + return x.node_ == y.node_; + } + + friend bool operator!=(c_iterator const& x, c_iterator const& y) { + return x.node_ != y.node_; + } + }; +}}} + +namespace boost { namespace unordered { namespace detail { + + /////////////////////////////////////////////////////////////////// + // + // Hash Policy + // + // Don't really want buckets to derive from this, but will for now. + + template + struct prime_policy + { + template + static inline SizeT apply_hash(Hash const& hf, T const& x) { + return hf(x); + } + + static inline SizeT to_bucket(SizeT bucket_count, SizeT hash) { + return hash % bucket_count; + } + + static inline SizeT new_bucket_count(SizeT min) { + return boost::unordered::detail::next_prime(min); + } + + static inline SizeT prev_bucket_count(SizeT max) { + return boost::unordered::detail::prev_prime(max); + } + }; + + template + struct mix64_policy + { + template + static inline SizeT apply_hash(Hash const& hf, T const& x) { + SizeT key = hf(x); + key = (~key) + (key << 21); // key = (key << 21) - key - 1; + key = key ^ (key >> 24); + key = (key + (key << 3)) + (key << 8); // key * 265 + key = key ^ (key >> 14); + key = (key + (key << 2)) + (key << 4); // key * 21 + key = key ^ (key >> 28); + key = key + (key << 31); + return key; + } + + static inline SizeT to_bucket(SizeT bucket_count, SizeT hash) { + return hash & (bucket_count - 1); + } + + static inline SizeT new_bucket_count(SizeT min) { + if (min <= 4) return 4; + --min; + min |= min >> 1; + min |= min >> 2; + min |= min >> 4; + min |= min >> 8; + min |= min >> 16; + min |= min >> 32; + return min + 1; + } + + static inline SizeT prev_bucket_count(SizeT max) { + max |= max >> 1; + max |= max >> 2; + max |= max >> 4; + max |= max >> 8; + max |= max >> 16; + max |= max >> 32; + return (max >> 1) + 1; + } + }; + + template + struct pick_policy_impl { + typedef prime_policy type; + }; + + template <> + struct pick_policy_impl<64, 2> { + typedef mix64_policy type; + }; + + struct pick_policy : + pick_policy_impl< + std::numeric_limits::digits, + std::numeric_limits::radix> {}; /////////////////////////////////////////////////////////////////// // // Buckets - template - struct buckets + template + struct buckets : Policy { private: buckets(buckets const&); @@ -193,6 +549,7 @@ namespace boost { namespace unordered { namespace detail { typedef boost::unordered::detail::allocator_traits traits; typedef typename traits::value_type value_type; + typedef Policy policy; typedef Node node; typedef Bucket bucket; typedef typename boost::unordered::detail::rebind_wrap::type @@ -214,6 +571,16 @@ namespace boost { namespace unordered { namespace detail { typedef boost::unordered::detail::node_constructor node_constructor; + typedef boost::unordered::iterator_detail:: + iterator iterator; + typedef boost::unordered::iterator_detail:: + c_iterator c_iterator; + typedef boost::unordered::iterator_detail:: + l_iterator l_iterator; + typedef boost::unordered::iterator_detail:: + cl_iterator + cl_iterator; + // Members bucket_pointer buckets_; @@ -247,7 +614,7 @@ namespace boost { namespace unordered { namespace detail { std::size_t max_bucket_count() const { // -1 to account for the start bucket. - return boost::unordered::detail::prev_prime( + return policy::prev_bucket_count( bucket_allocator_traits::max_size(bucket_alloc()) - 1); } @@ -266,16 +633,17 @@ namespace boost { namespace unordered { namespace detail { return this->get_bucket(bucket_index)->next_; } - node_pointer get_start() const + iterator get_start() const { - return static_cast(this->get_previous_start()->next_); + return iterator(static_cast( + this->get_previous_start()->next_)); } - node_pointer get_start(std::size_t bucket_index) const + iterator get_start(std::size_t bucket_index) const { previous_pointer prev = this->get_previous_start(bucket_index); - return prev ? static_cast(prev->next_) : - node_pointer(); + return prev ? iterator(static_cast(prev->next_)) : + iterator(); } float load_factor() const @@ -288,14 +656,15 @@ namespace boost { namespace unordered { namespace detail { std::size_t bucket_size(std::size_t index) const { if (!this->size_) return 0; - node_pointer ptr = this->get_start(index); - if (!ptr) return 0; + iterator it = this->get_start(index); + if (!it.node_) return 0; std::size_t count = 0; - while(ptr && ptr->hash_ % this->bucket_count_ == index) + while(it.node_ && policy::to_bucket( + this->bucket_count_, it.node_->hash_) == index) { ++count; - ptr = static_cast(ptr->next_); + ++it; } return count; @@ -391,21 +760,22 @@ namespace boost { namespace unordered { namespace detail { //////////////////////////////////////////////////////////////////////// // Delete/destruct - inline void delete_node(node_pointer n) + inline void delete_node(c_iterator n) { - boost::unordered::detail::destroy(n->value_ptr()); - node_allocator_traits::destroy(node_alloc(), boost::addressof(*n)); - node_allocator_traits::deallocate(node_alloc(), n, 1); + boost::unordered::detail::destroy(n.node_->value_ptr()); + node_allocator_traits::destroy(node_alloc(), + boost::addressof(*n.node_)); + node_allocator_traits::deallocate(node_alloc(), n.node_, 1); --size_; } - std::size_t delete_nodes(node_pointer begin, node_pointer end) + std::size_t delete_nodes(c_iterator begin, c_iterator end) { std::size_t count = 0; while(begin != end) { - node_pointer n = begin; - begin = static_cast(begin->next_); + c_iterator n = begin; + ++begin; delete_node(n); ++count; } @@ -433,7 +803,7 @@ namespace boost { namespace unordered { namespace detail { while(prev->next_) { node_pointer n = static_cast(prev->next_); prev->next_ = n->next_; - delete_node(n); + delete_node(iterator(n)); } delete_extra_node(prev); @@ -463,7 +833,7 @@ namespace boost { namespace unordered { namespace detail { while(prev->next_) { node_pointer n = static_cast(prev->next_); prev->next_ = n->next_; - delete_node(n); + delete_node(iterator(n)); } bucket_pointer end = this->get_bucket(this->bucket_count_); @@ -487,7 +857,7 @@ namespace boost { namespace unordered { namespace detail { else { bucket_pointer next_bucket = this->get_bucket( - next->hash_ % this->bucket_count_); + policy::to_bucket(this->bucket_count_, next->hash_)); if (next_bucket != bucket) { @@ -513,7 +883,7 @@ namespace boost { namespace unordered { namespace detail { if (n == end) return; std::size_t new_bucket_index = - n->hash_ % this->bucket_count_; + policy::to_bucket(this->bucket_count_, n->hash_); if (bucket_index != new_bucket_index) { bucket_index = new_bucket_index; break; @@ -529,7 +899,7 @@ namespace boost { namespace unordered { namespace detail { if (n == end) break; std::size_t new_bucket_index = - n->hash_ % this->bucket_count_; + policy::to_bucket(this->bucket_count_, n->hash_); if (bucket_index != new_bucket_index) { bucket_index = new_bucket_index; this->get_bucket(bucket_index)->next_ = previous_pointer(); @@ -538,7 +908,8 @@ namespace boost { namespace unordered { namespace detail { // Finally fix the bucket containing the trailing node. if (n) { - this->get_bucket(n->hash_ % this->bucket_count_)->next_ + this->get_bucket( + policy::to_bucket(this->bucket_count_, n->hash_))->next_ = prev; } } diff --git a/include/boost/unordered/detail/emplace_args.hpp b/include/boost/unordered/detail/emplace_args.hpp index 0e80d3c0..be2339fe 100644 --- a/include/boost/unordered/detail/emplace_args.hpp +++ b/include/boost/unordered/detail/emplace_args.hpp @@ -160,9 +160,9 @@ BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, BOOST_UNORDERED_EARGS, // // Used for piecewise construction. -#if !BOOST_WORKAROUND(__SUNPRO_CC, <= 0x590) +#if !defined(__SUNPRO_CC) -#define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(n, namespace_) \ +# define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(n, namespace_) \ template \ void construct_from_tuple(T* ptr, namespace_::tuple<>) \ { \ @@ -172,7 +172,7 @@ BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, BOOST_UNORDERED_EARGS, BOOST_PP_REPEAT_FROM_TO(1, n, \ BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL, namespace_) -#define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL(z, n, namespace_) \ +# define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL(z, n, namespace_) \ template \ void construct_from_tuple(T* ptr, \ namespace_::tuple const& x) \ @@ -182,32 +182,26 @@ BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, BOOST_UNORDERED_EARGS, ); \ } -#define BOOST_UNORDERED_GET_TUPLE_ARG(z, n, namespace_) \ +# define BOOST_UNORDERED_GET_TUPLE_ARG(z, n, namespace_) \ namespace_::get(x) -BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, boost) - -#if !defined(BOOST_NO_0X_HDR_TUPLE) -BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, std) -#endif - -#undef BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE -#undef BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL -#undef BOOST_UNORDERED_GET_TUPLE_ARG - #else template struct length {}; - template - void construct_from_tuple_impl( - boost::unordered::detail::length<0>, T* ptr, - boost::tuple<>) - { - new ((void*) ptr) T(); - } +# define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(n, namespace_) \ + template \ + void construct_from_tuple_impl( \ + boost::unordered::detail::length<0>, T* ptr, \ + namespace_::tuple<>) \ + { \ + new ((void*) ptr) T(); \ + } \ + \ + BOOST_PP_REPEAT_FROM_TO(1, n, \ + BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL, namespace_) -#define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL(z, n, _) \ +# define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL(z, n, namespace_) \ template \ void construct_from_tuple_impl( \ boost::unordered::detail::length, T* ptr, \ @@ -218,11 +212,22 @@ BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, std) ); \ } -#define BOOST_UNORDERED_GET_TUPLE_ARG(z, n, _) \ - boost::get(x) +# define BOOST_UNORDERED_GET_TUPLE_ARG(z, n, namespace_) \ + namespace_::get(x) - BOOST_PP_REPEAT_FROM_TO(1, 10, \ - BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL, _) +#endif + +BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, boost) + +#if !defined(__SUNPRO_CC) && !defined(BOOST_NO_0X_HDR_TUPLE) + BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, std) +#endif + +#undef BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE +#undef BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL +#undef BOOST_UNORDERED_GET_TUPLE_ARG + +#if defined(__SUNPRO_CC) template void construct_from_tuple(T* ptr, Tuple const& x) @@ -233,9 +238,6 @@ BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, std) ptr, x); } -#undef BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL -#undef BOOST_UNORDERED_GET_TUPLE_ARG - #endif //////////////////////////////////////////////////////////////////////////// diff --git a/include/boost/unordered/detail/equivalent.hpp b/include/boost/unordered/detail/equivalent.hpp index 6e7e4190..ba58c8a2 100644 --- a/include/boost/unordered/detail/equivalent.hpp +++ b/include/boost/unordered/detail/equivalent.hpp @@ -136,6 +136,8 @@ namespace boost { namespace unordered { namespace detail { typedef boost::unordered::detail::grouped_table_impl table; typedef boost::unordered::detail::set_extractor extractor; + + typedef boost::unordered::detail::pick_policy::type policy; }; template @@ -160,6 +162,8 @@ namespace boost { namespace unordered { namespace detail { typedef boost::unordered::detail::grouped_table_impl table; typedef boost::unordered::detail::map_extractor extractor; + + typedef boost::unordered::detail::pick_policy::type policy; }; template @@ -169,6 +173,7 @@ namespace boost { namespace unordered { namespace detail { typedef typename table::value_type value_type; typedef typename table::bucket bucket; typedef typename table::buckets buckets; + typedef typename table::policy policy; typedef typename table::node_pointer node_pointer; typedef typename table::node_allocator node_allocator; typedef typename table::node_allocator_traits node_allocator_traits; @@ -181,6 +186,7 @@ namespace boost { namespace unordered { namespace detail { typedef typename table::node_constructor node_constructor; typedef typename table::extractor extractor; typedef typename table::iterator iterator; + typedef typename table::c_iterator c_iterator; // Constructors @@ -214,46 +220,48 @@ namespace boost { namespace unordered { namespace detail { // Accessors template - node_pointer find_node_impl( + iterator find_node_impl( std::size_t hash, Key const& k, Pred const& eq) const { - std::size_t bucket_index = hash % this->bucket_count_; - node_pointer n = this->get_start(bucket_index); + std::size_t bucket_index = + policy::to_bucket(this->bucket_count_, hash); + iterator n = this->get_start(bucket_index); for (;;) { - if (!n) return n; + if (!n.node_) return n; - std::size_t node_hash = n->hash_; + std::size_t node_hash = n.node_->hash_; if (hash == node_hash) { - if (eq(k, this->get_key(n->value()))) + if (eq(k, this->get_key(*n))) return n; } else { - if (node_hash % this->bucket_count_ != bucket_index) - return node_pointer(); + if (policy::to_bucket(this->bucket_count_, node_hash) + != bucket_index) + return iterator(); } - n = static_cast( - static_cast(n->group_prev_)->next_); + n = iterator(static_cast( + static_cast(n.node_->group_prev_)->next_)); } } std::size_t count(key_type const& k) const { - node_pointer n = this->find_node(k); - if (!n) return 0; + iterator n = this->find_node(k); + if (!n.node_) return 0; std::size_t count = 0; - node_pointer it = n; + node_pointer it = n.node_; do { it = static_cast(it->group_prev_); ++count; - } while(it != n); + } while(it != n.node_); return count; } @@ -261,12 +269,12 @@ namespace boost { namespace unordered { namespace detail { std::pair equal_range(key_type const& k) const { - node_pointer n = this->find_node(k); + iterator n = this->find_node(k); return std::make_pair( - iterator(n), iterator(n ? + n, n.node_ ? iterator( static_cast( - static_cast(n->group_prev_)->next_) : - n)); + static_cast(n.node_->group_prev_)->next_ + )) : n); } // Equality @@ -276,14 +284,14 @@ namespace boost { namespace unordered { namespace detail { if(this->size_ != other.size_) return false; if(!this->size_) return true; - for(node_pointer n1 = this->get_start(); n1;) + for(iterator n1 = this->get_start(); n1.node_;) { - node_pointer n2 = other.find_matching_node(n1); - if (!n2) return false; - node_pointer end1 = static_cast( - static_cast(n1->group_prev_)->next_); - node_pointer end2 = static_cast( - static_cast(n2->group_prev_)->next_); + iterator n2 = other.find_matching_node(n1); + if (!n2.node_) return false; + iterator end1(static_cast( + static_cast(n1.node_->group_prev_)->next_)); + iterator end2(static_cast( + static_cast(n2.node_->group_prev_)->next_)); if (!group_equals(n1, end1, n2, end2)) return false; n1 = end1; } @@ -293,25 +301,24 @@ namespace boost { namespace unordered { namespace detail { #if !defined(BOOST_UNORDERED_DEPRECATED_EQUALITY) - static bool group_equals(node_pointer n1, node_pointer end1, - node_pointer n2, node_pointer end2) + static bool group_equals(iterator n1, iterator end1, + iterator n2, iterator end2) { for(;;) { - if (n1->value() != n2->value()) - break; + if (*n1 != *n2) break; - n1 = static_cast(n1->next_); - n2 = static_cast(n2->next_); + ++n1; + ++n2; if (n1 == end1) return n2 == end2; if (n2 == end2) return false; } - for(node_pointer n1a = n1, n2a = n2;;) + for(iterator n1a = n1, n2a = n2;;) { - n1a = static_cast(n1a->next_); - n2a = static_cast(n2a->next_); + ++n1a; + ++n2a; if (n1a == end1) { @@ -322,50 +329,50 @@ namespace boost { namespace unordered { namespace detail { if (n2a == end2) return false; } - node_pointer start = n1; - for(;n1 != end2; n1 = static_cast(n1->next_)) + iterator start = n1; + for(;n1 != end1; ++n1) { - value_type const& v = n1->value(); + value_type const& v = *n1; if (find(start, n1, v)) continue; std::size_t matches = count_equal(n2, end2, v); - if (!matches || matches != 1 + count_equal( - static_cast(n1->next_), end1, v)) - return false; + if (!matches) return false; + iterator next = n1; + ++next; + if (matches != 1 + count_equal(next, end1, v)) return false; } return true; } - static bool find(node_pointer n, node_pointer end, value_type const& v) + static bool find(iterator n, iterator end, value_type const& v) { - for(;n != end; n = static_cast(n->next_)) - if (n->value() == v) + for(;n != end; ++n) + if (*n == v) return true; return false; } - static std::size_t count_equal(node_pointer n, node_pointer end, + static std::size_t count_equal(iterator n, iterator end, value_type const& v) { std::size_t count = 0; - for(;n != end; n = static_cast(n->next_)) - if (n->value() == v) ++count; + for(;n != end; ++n) + if (*n == v) ++count; return count; } #else - static bool group_equals(node_pointer n1, node_pointer end1, - node_pointer n2, node_pointer end2) + static bool group_equals(iterator n1, iterator end1, + iterator n2, iterator end2) { for(;;) { - if(!extractor::compare_mapped( - n1->value(), n2->value())) + if(!extractor::compare_mapped(*n1, *n2)) return false; - n1 = static_cast(n1->next_); - n2 = static_cast(n2->next_); + ++n1; + ++n2; if (n1 == end1) return n2 == end2; if (n2 == end2) return false; @@ -387,35 +394,37 @@ namespace boost { namespace unordered { namespace detail { pos->group_prev_ = static_cast(n); } - inline node_pointer add_node( + inline iterator add_node( node_constructor& a, std::size_t hash, - node_pointer pos) + iterator pos) { node_pointer n = a.release(); n->hash_ = hash; - if(pos) { - this->add_after_node(n, pos); + if (pos.node_) { + this->add_after_node(n, pos.node_); if (n->next_) { - std::size_t next_bucket = - static_cast(n->next_)->hash_ % - this->bucket_count_; - if (next_bucket != hash % this->bucket_count_) { + std::size_t next_bucket = policy::to_bucket( + this->bucket_count_, + static_cast(n->next_)->hash_); + if (next_bucket != + policy::to_bucket(this->bucket_count_, hash)) { this->get_bucket(next_bucket)->next_ = n; } } } else { - bucket_pointer b = this->get_bucket(hash % this->bucket_count_); + bucket_pointer b = this->get_bucket( + policy::to_bucket(this->bucket_count_, hash)); if (!b->next_) { previous_pointer start_node = this->get_previous_start(); if (start_node->next_) { - this->get_bucket( + this->get_bucket(policy::to_bucket(this->bucket_count_, static_cast(start_node->next_)->hash_ - % this->bucket_count_)->next_ = n; + ))->next_ = n; } b->next_ = start_node; @@ -429,14 +438,14 @@ namespace boost { namespace unordered { namespace detail { } } ++this->size_; - return n; + return iterator(n); } - node_pointer emplace_impl(node_constructor& a) + iterator emplace_impl(node_constructor& a) { key_type const& k = this->get_key(a.value()); - std::size_t hash = this->hash_function()(k); - node_pointer position = this->find_node(hash, k); + std::size_t hash = this->hash(k); + iterator position = this->find_node(hash, k); // reserve has basic exception safety if the hash function // throws, strong otherwise. @@ -447,9 +456,8 @@ namespace boost { namespace unordered { namespace detail { void emplace_impl_no_rehash(node_constructor& a) { key_type const& k = this->get_key(a.value()); - std::size_t hash = this->hash_function()(k); - this->add_node(a, hash, - this->find_node(hash, k)); + std::size_t hash = this->hash(k); + this->add_node(a, hash, this->find_node(hash, k)); } #if defined(BOOST_NO_RVALUE_REFERENCES) @@ -523,8 +531,9 @@ namespace boost { namespace unordered { namespace detail { { if(!this->size_) return 0; - std::size_t hash = this->hash_function()(k); - std::size_t bucket_index = hash % this->bucket_count_; + std::size_t hash = this->hash(k); + std::size_t bucket_index = + policy::to_bucket(this->bucket_count_, hash); bucket_pointer bucket = this->get_bucket(bucket_index); previous_pointer prev = bucket->next_; @@ -535,7 +544,8 @@ namespace boost { namespace unordered { namespace detail { if (!prev->next_) return 0; std::size_t node_hash = static_cast(prev->next_)->hash_; - if (node_hash % this->bucket_count_ != bucket_index) + if (policy::to_bucket(this->bucket_count_, node_hash) + != bucket_index) return 0; if (node_hash == hash && this->key_eq()(k, this->get_key( @@ -551,36 +561,38 @@ namespace boost { namespace unordered { namespace detail { node_pointer end = static_cast(end1); prev->next_ = end1; this->fix_buckets(bucket, prev, end); - return this->delete_nodes(pos, end); + return this->delete_nodes(c_iterator(pos), c_iterator(end)); } - node_pointer erase(node_pointer r) + iterator erase(c_iterator r) { - BOOST_ASSERT(r); - node_pointer next = static_cast(r->next_); + BOOST_ASSERT(r.node_); + iterator next(r.node_); + ++next; bucket_pointer bucket = this->get_bucket( - r->hash_ % this->bucket_count_); - previous_pointer prev = unlink_node(*bucket, r); + policy::to_bucket(this->bucket_count_, r.node_->hash_)); + previous_pointer prev = unlink_node(*bucket, r.node_); - this->fix_buckets(bucket, prev, next); + this->fix_buckets(bucket, prev, next.node_); this->delete_node(r); return next; } - node_pointer erase_range(node_pointer r1, node_pointer r2) + iterator erase_range(c_iterator r1, c_iterator r2) { - if (r1 == r2) return r2; + if (r1 == r2) return iterator(r2.node_); - std::size_t bucket_index = r1->hash_ % this->bucket_count_; + std::size_t bucket_index = + policy::to_bucket(this->bucket_count_, r1.node_->hash_); previous_pointer prev = unlink_nodes( - *this->get_bucket(bucket_index), r1, r2); - this->fix_buckets_range(bucket_index, prev, r1, r2); + *this->get_bucket(bucket_index), r1.node_, r2.node_); + this->fix_buckets_range(bucket_index, prev, r1.node_, r2.node_); this->delete_nodes(r1, r2); - return r2; + return iterator(r2.node_); } static previous_pointer unlink_node(bucket& b, node_pointer n) @@ -697,17 +709,18 @@ namespace boost { namespace unordered { namespace detail { node_constructor a(dst.node_alloc()); - node_pointer n = src.get_start(); + iterator n = src.get_start(); previous_pointer prev = dst.get_previous_start(); - while(n) { - std::size_t hash = n->hash_; - node_pointer group_end = + while (n.node_) { + std::size_t hash = n.node_->hash_; + iterator group_end( static_cast( - static_cast(n->group_prev_)->next_); + static_cast(n.node_->group_prev_)->next_ + )); a.construct_node(); - a.construct_value2(n->value()); + a.construct_value2(*n); node_pointer first_node = a.release(); node_pointer end = first_node; @@ -715,11 +728,10 @@ namespace boost { namespace unordered { namespace detail { prev->next_ = static_cast(first_node); ++dst.size_; - for(n = static_cast(n->next_); n != group_end; - n = static_cast(n->next_)) + for (++n; n != group_end; ++n) { a.construct_node(); - a.construct_value2(n->value()); + a.construct_value2(*n); end = a.release(); end->hash_ = hash; add_after_node(end, first_node); @@ -744,17 +756,18 @@ namespace boost { namespace unordered { namespace detail { node_constructor a(dst.node_alloc()); - node_pointer n = src.get_start(); + iterator n = src.get_start(); previous_pointer prev = dst.get_previous_start(); - while(n) { - std::size_t hash = n->hash_; - node_pointer group_end = + while (n.node_) { + std::size_t hash = n.node_->hash_; + iterator group_end( static_cast( - static_cast(n->group_prev_)->next_); + static_cast(n.node_->group_prev_)->next_ + )); a.construct_node(); - a.construct_value2(boost::move(n->value())); + a.construct_value2(boost::move(*n)); node_pointer first_node = a.release(); node_pointer end = first_node; @@ -762,11 +775,10 @@ namespace boost { namespace unordered { namespace detail { prev->next_ = static_cast(first_node); ++dst.size_; - for(n = static_cast(n->next_); n != group_end; - n = static_cast(n->next_)) + for(++n; n != group_end; ++n) { a.construct_node(); - a.construct_value2(boost::move(n->value())); + a.construct_value2(boost::move(*n)); end = a.release(); end->hash_ = hash; add_after_node(end, first_node); @@ -809,7 +821,8 @@ namespace boost { namespace unordered { namespace detail { static previous_pointer place_in_bucket(buckets& dst, previous_pointer prev, node_pointer end) { - bucket_pointer b = dst.get_bucket(end->hash_ % dst.bucket_count_); + bucket_pointer b = dst.get_bucket(policy::to_bucket( + dst.bucket_count_, end->hash_)); if (!b->next_) { b->next_ = static_cast(prev); diff --git a/include/boost/unordered/detail/fwd.hpp b/include/boost/unordered/detail/fwd.hpp index 1949b5d1..ee8966b7 100644 --- a/include/boost/unordered/detail/fwd.hpp +++ b/include/boost/unordered/detail/fwd.hpp @@ -10,41 +10,11 @@ # pragma once #endif -#include -#include -#include -#include namespace boost { namespace unordered { - template , - class P = std::equal_to, - class A = std::allocator > > - class unordered_map; - - template , - class P = std::equal_to, - class A = std::allocator > > - class unordered_multimap; - - template , - class P = std::equal_to, - class A = std::allocator > - class unordered_set; - - template , - class P = std::equal_to, - class A = std::allocator > - class unordered_multiset; - struct piecewise_construct_t {}; const piecewise_construct_t piecewise_construct = piecewise_construct_t(); } diff --git a/include/boost/unordered/detail/table.hpp b/include/boost/unordered/detail/table.hpp index 66c46084..9e2f13c5 100644 --- a/include/boost/unordered/detail/table.hpp +++ b/include/boost/unordered/detail/table.hpp @@ -11,251 +11,8 @@ #include #include #include -#include #include -namespace boost { namespace unordered { namespace iterator_detail { - - //////////////////////////////////////////////////////////////////////////// - // Iterators - // - // all no throw - - template struct iterator; - template struct c_iterator; - template struct l_iterator; - template struct cl_iterator; - - // Local Iterators - // - // all no throw - - template - struct l_iterator - : public boost::iterator< - std::forward_iterator_tag, Value, std::ptrdiff_t, - NodePointer, Value&> - { -#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) - template - friend struct boost::unordered::iterator_detail::cl_iterator; - private: -#endif - typedef NodePointer node_pointer; - node_pointer ptr_; - std::size_t bucket_; - std::size_t bucket_count_; - - public: - - l_iterator() : ptr_() {} - - l_iterator(node_pointer x, std::size_t b, std::size_t c) - : ptr_(x), bucket_(b), bucket_count_(c) {} - - Value& operator*() const { - return ptr_->value(); - } - - Value* operator->() const { - return ptr_->value_ptr(); - } - - l_iterator& operator++() { - ptr_ = static_cast(ptr_->next_); - if (ptr_ && ptr_->hash_ % bucket_count_ != bucket_) - ptr_ = node_pointer(); - return *this; - } - - l_iterator operator++(int) { - l_iterator tmp(*this); - ++(*this); - return tmp; - } - - bool operator==(l_iterator x) const { - return ptr_ == x.ptr_; - } - - bool operator!=(l_iterator x) const { - return ptr_ != x.ptr_; - } - }; - - template - struct cl_iterator - : public boost::iterator< - std::forward_iterator_tag, Value, std::ptrdiff_t, - ConstNodePointer, Value const&> - { - friend struct boost::unordered::iterator_detail::l_iterator - ; - private: - - typedef NodePointer node_pointer; - node_pointer ptr_; - std::size_t bucket_; - std::size_t bucket_count_; - - public: - - cl_iterator() : ptr_() {} - - cl_iterator(node_pointer x, std::size_t b, std::size_t c) : - ptr_(x), bucket_(b), bucket_count_(c) {} - - cl_iterator(boost::unordered::iterator_detail::l_iterator< - NodePointer, Value> const& x) : - ptr_(x.ptr_), bucket_(x.bucket_), bucket_count_(x.bucket_count_) - {} - - Value const& - operator*() const { - return ptr_->value(); - } - - Value const* operator->() const { - return ptr_->value_ptr(); - } - - cl_iterator& operator++() { - ptr_ = static_cast(ptr_->next_); - if (ptr_ && ptr_->hash_ % bucket_count_ != bucket_) - ptr_ = node_pointer(); - return *this; - } - - cl_iterator operator++(int) { - cl_iterator tmp(*this); - ++(*this); - return tmp; - } - - friend bool operator==(cl_iterator const& x, cl_iterator const& y) { - return x.ptr_ == y.ptr_; - } - - friend bool operator!=(cl_iterator const& x, cl_iterator const& y) { - return x.ptr_ != y.ptr_; - } - }; - - template - struct iterator - : public boost::iterator< - std::forward_iterator_tag, Value, std::ptrdiff_t, - NodePointer, Value&> - { -#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) - template - friend struct boost::unordered::iterator_detail::c_iterator; - private: -#endif - typedef NodePointer node_pointer; - node_pointer node_; - - public: - - iterator() : node_() {} - - explicit iterator(node_pointer const& x) : node_(x) {} - - Value& operator*() const { - return node_->value(); - } - - Value* operator->() const { - return &node_->value(); - } - - iterator& operator++() { - node_ = static_cast(node_->next_); - return *this; - } - - iterator operator++(int) { - iterator tmp(node_); - node_ = static_cast(node_->next_); - return tmp; - } - - bool operator==(iterator const& x) const { - return node_ == x.node_; - } - - bool operator!=(iterator const& x) const { - return node_ != x.node_; - } - }; - - template - struct c_iterator - : public boost::iterator< - std::forward_iterator_tag, Value, std::ptrdiff_t, - ConstNodePointer, Value const&> - { - friend struct boost::unordered::iterator_detail::iterator< - NodePointer, Value>; - -#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) - template - friend class boost::unordered::unordered_map; - template - friend class boost::unordered::unordered_multimap; - template - friend class boost::unordered::unordered_set; - template - friend class boost::unordered::unordered_multiset; - - private: -#endif - - typedef NodePointer node_pointer; - node_pointer node_; - - public: - - c_iterator() : node_() {} - - explicit c_iterator(node_pointer const& x) : node_(x) {} - - c_iterator(boost::unordered::iterator_detail::iterator< - NodePointer, Value> const& x) : node_(x.node_) {} - - Value const& operator*() const { - return node_->value(); - } - - Value const* operator->() const { - return &node_->value(); - } - - c_iterator& operator++() { - node_ = static_cast(node_->next_); - return *this; - } - - c_iterator operator++(int) { - c_iterator tmp(node_); - node_ = static_cast(node_->next_); - return tmp; - } - - friend bool operator==(c_iterator const& x, c_iterator const& y) { - return x.node_ == y.node_; - } - - friend bool operator!=(c_iterator const& x, c_iterator const& y) { - return x.node_ != y.node_; - } - }; -}}} - namespace boost { namespace unordered { namespace detail { //////////////////////////////////////////////////////////////////////////// @@ -302,7 +59,8 @@ namespace boost { namespace unordered { namespace detail { boost::unordered::detail::buckets< typename Types::allocator, typename Types::bucket, - typename Types::node>, + typename Types::node, + typename Types::policy>, boost::unordered::detail::functions< typename Types::hasher, typename Types::key_equal> @@ -318,6 +76,7 @@ namespace boost { namespace unordered { namespace detail { typedef typename Types::value_type value_type; typedef typename Types::table table_impl; typedef typename Types::link_pointer link_pointer; + typedef typename Types::policy policy; typedef boost::unordered::detail::functions< typename Types::hasher, @@ -326,22 +85,15 @@ namespace boost { namespace unordered { namespace detail { typedef boost::unordered::detail::buckets< typename Types::allocator, typename Types::bucket, - typename Types::node> buckets; + typename Types::node, + typename Types::policy> buckets; typedef typename buckets::node_allocator node_allocator; typedef typename buckets::node_allocator_traits node_allocator_traits; typedef typename buckets::node_pointer node_pointer; typedef typename buckets::const_node_pointer const_node_pointer; - typedef boost::unordered::iterator_detail:: - iterator iterator; - typedef boost::unordered::iterator_detail:: - c_iterator c_iterator; - typedef boost::unordered::iterator_detail:: - l_iterator l_iterator; - typedef boost::unordered::iterator_detail:: - cl_iterator - cl_iterator; + typedef typename table::iterator iterator; // Members @@ -384,7 +136,7 @@ namespace boost { namespace unordered { namespace detail { std::size_t min_buckets_for_size(std::size_t size) const { - BOOST_ASSERT(this->mlf_ != 0); + BOOST_ASSERT(this->mlf_ >= minimum_max_load_factor); using namespace std; @@ -395,7 +147,7 @@ namespace boost { namespace unordered { namespace detail { // Or from rehash post-condition: // count > size / mlf_ - return boost::unordered::detail::next_prime( + return policy::new_bucket_count( boost::unordered::detail::double_to_size(floor( static_cast(size) / static_cast(mlf_))) + 1); @@ -408,7 +160,7 @@ namespace boost { namespace unordered { namespace detail { hasher const& hf, key_equal const& eq, node_allocator const& a) : - buckets(a, boost::unordered::detail::next_prime(num_buckets)), + buckets(a, policy::new_bucket_count(num_buckets)), functions(hf, eq), mlf_(1.0f), max_load_(0) @@ -458,9 +210,9 @@ namespace boost { namespace unordered { namespace detail { // Iterators - node_pointer begin() const { + iterator begin() const { return !this->buckets_ ? - node_pointer() : this->get_start(); + iterator() : this->get_start(); } // Assignment @@ -586,36 +338,41 @@ namespace boost { namespace unordered { namespace detail { return extractor::extract(x); } + std::size_t hash(key_type const& k) const + { + return policy::apply_hash(this->hash_function(), k); + } + // Find Node template - node_pointer generic_find_node( + iterator generic_find_node( Key const& k, Hash const& hash_function, Pred const& eq) const { - if (!this->size_) return node_pointer(); + if (!this->size_) return iterator(); return static_cast(this)-> - find_node_impl(hash_function(k), k, eq); + find_node_impl(policy::apply_hash(hash_function, k), k, eq); } - node_pointer find_node( + iterator find_node( std::size_t hash, key_type const& k) const { - if (!this->size_) return node_pointer(); + if (!this->size_) return iterator(); return static_cast(this)-> find_node_impl(hash, k, this->key_eq()); } - node_pointer find_node(key_type const& k) const + iterator find_node(key_type const& k) const { - if (!this->size_) return node_pointer(); + if (!this->size_) return iterator(); return static_cast(this)-> - find_node_impl(this->hash_function()(k), k, this->key_eq()); + find_node_impl(this->hash(k), k, this->key_eq()); } - node_pointer find_matching_node(node_pointer n) const + iterator find_matching_node(iterator n) const { // TODO: Does this apply to C++11? // @@ -623,7 +380,7 @@ namespace boost { namespace unordered { namespace detail { // when different hash functions are used. So I can't use the hash // value from the node here. - return find_node(get_key(n->value())); + return find_node(get_key(*n)); } // Reserve and rehash @@ -666,10 +423,10 @@ namespace boost { namespace unordered { namespace detail { if(!this->size_) { if(this->buckets_) this->delete_buckets(); - this->bucket_count_ = next_prime(min_buckets); + this->bucket_count_ = policy::new_bucket_count(min_buckets); } else { - min_buckets = next_prime((std::max)(min_buckets, + min_buckets = policy::new_bucket_count((std::max)(min_buckets, boost::unordered::detail::double_to_size(floor( static_cast(this->size_) / static_cast(mlf_))) + 1)); diff --git a/include/boost/unordered/detail/unique.hpp b/include/boost/unordered/detail/unique.hpp index 9c049f78..84fef433 100644 --- a/include/boost/unordered/detail/unique.hpp +++ b/include/boost/unordered/detail/unique.hpp @@ -132,6 +132,8 @@ namespace boost { namespace unordered { namespace detail { typedef boost::unordered::detail::table_impl table; typedef boost::unordered::detail::set_extractor extractor; + + typedef boost::unordered::detail::pick_policy::type policy; }; template @@ -156,6 +158,8 @@ namespace boost { namespace unordered { namespace detail { typedef boost::unordered::detail::table_impl table; typedef boost::unordered::detail::map_extractor extractor; + + typedef boost::unordered::detail::pick_policy::type policy; }; template @@ -165,6 +169,7 @@ namespace boost { namespace unordered { namespace detail { typedef typename table::value_type value_type; typedef typename table::bucket bucket; typedef typename table::buckets buckets; + typedef typename table::policy policy; typedef typename table::node_pointer node_pointer; typedef typename table::node_allocator node_allocator; typedef typename table::node_allocator_traits node_allocator_traits; @@ -177,6 +182,7 @@ namespace boost { namespace unordered { namespace detail { typedef typename table::node_constructor node_constructor; typedef typename table::extractor extractor; typedef typename table::iterator iterator; + typedef typename table::c_iterator c_iterator; typedef std::pair emplace_return; @@ -212,44 +218,46 @@ namespace boost { namespace unordered { namespace detail { // Accessors template - node_pointer find_node_impl( + iterator find_node_impl( std::size_t hash, Key const& k, Pred const& eq) const { - std::size_t bucket_index = hash % this->bucket_count_; - node_pointer n = this->get_start(bucket_index); + std::size_t bucket_index = + policy::to_bucket(this->bucket_count_, hash); + iterator n = this->get_start(bucket_index); for (;;) { - if (!n) return n; + if (!n.node_) return n; - std::size_t node_hash = n->hash_; + std::size_t node_hash = n.node_->hash_; if (hash == node_hash) { - if (eq(k, this->get_key(n->value()))) + if (eq(k, this->get_key(*n))) return n; } else { - if (node_hash % this->bucket_count_ != bucket_index) - return node_pointer(); + if (policy::to_bucket(this->bucket_count_, node_hash) + != bucket_index) + return iterator(); } - n = static_cast(n->next_); + ++n; } } std::size_t count(key_type const& k) const { - return this->find_node(k) ? 1 : 0; + return this->find_node(k).node_ ? 1 : 0; } value_type& at(key_type const& k) const { if (this->size_) { - node_pointer it = this->find_node(k); - if (it) return it->value(); + iterator it = this->find_node(k); + if (it.node_) return *it; } boost::throw_exception( @@ -259,9 +267,10 @@ namespace boost { namespace unordered { namespace detail { std::pair equal_range(key_type const& k) const { - node_pointer n = this->find_node(k); - return std::make_pair(iterator(n), - iterator(n ? static_cast(n->next_) : n)); + iterator n = this->find_node(k); + iterator n2 = n; + if (n2.node_) ++n2; + return std::make_pair(n, n2); } // equals @@ -271,17 +280,15 @@ namespace boost { namespace unordered { namespace detail { if(this->size_ != other.size_) return false; if(!this->size_) return true; - for(node_pointer n1 = this->get_start(); n1; - n1 = static_cast(n1->next_)) + for(iterator n1 = this->get_start(); n1.node_; ++n1) { - node_pointer n2 = other.find_matching_node(n1); + iterator n2 = other.find_matching_node(n1); #if !defined(BOOST_UNORDERED_DEPRECATED_EQUALITY) - if(!n2 || n1->value() != n2->value()) + if (!n2.node_ || *n1 != *n2) return false; #else - if(!n2 || !extractor::compare_mapped( - n1->value(), n2->value())) + if (!n2.node_ || !extractor::compare_mapped(*n1, *n2)) return false; #endif } @@ -291,23 +298,24 @@ namespace boost { namespace unordered { namespace detail { // Emplace/Insert - inline node_pointer add_node( + inline iterator add_node( node_constructor& a, std::size_t hash) { node_pointer n = a.release(); n->hash_ = hash; - bucket_pointer b = this->get_bucket(hash % this->bucket_count_); + bucket_pointer b = this->get_bucket( + policy::to_bucket(this->bucket_count_, hash)); if (!b->next_) { previous_pointer start_node = this->get_previous_start(); if (start_node->next_) { - this->get_bucket( - static_cast(start_node->next_)->hash_ % - this->bucket_count_)->next_ = n; + this->get_bucket(policy::to_bucket(this->bucket_count_, + static_cast(start_node->next_)->hash_) + )->next_ = n; } b->next_ = start_node; @@ -321,17 +329,17 @@ namespace boost { namespace unordered { namespace detail { } ++this->size_; - return n; + return iterator(n); } value_type& operator[](key_type const& k) { typedef typename value_type::second_type mapped_type; - std::size_t hash = this->hash_function()(k); - node_pointer pos = this->find_node(hash, k); + std::size_t hash = this->hash(k); + iterator pos = this->find_node(hash, k); - if (pos) return pos->value(); + if (pos.node_) return *pos; // Create the node before rehashing in case it throws an // exception (need strong safety in such a case). @@ -349,7 +357,7 @@ namespace boost { namespace unordered { namespace detail { #endif this->reserve_for_insert(this->size_ + 1); - return add_node(a, hash)->value(); + return *add_node(a, hash); } #if defined(BOOST_NO_RVALUE_REFERENCES) @@ -357,7 +365,7 @@ namespace boost { namespace unordered { namespace detail { boost::unordered::detail::please_ignore_this_overload> const&) { BOOST_ASSERT(false); - return emplace_return(iterator(this->begin()), false); + return emplace_return(this->begin(), false); } #endif @@ -389,10 +397,10 @@ namespace boost { namespace unordered { namespace detail { emplace_return emplace_impl(key_type const& k, BOOST_UNORDERED_EMPLACE_ARGS) { - std::size_t hash = this->hash_function()(k); - node_pointer pos = this->find_node(hash, k); + std::size_t hash = this->hash(k); + iterator pos = this->find_node(hash, k); - if (pos) return emplace_return(iterator(pos), false); + if (pos.node_) return emplace_return(pos, false); // Create the node before rehashing in case it throws an // exception (need strong safety in such a case). @@ -403,21 +411,21 @@ namespace boost { namespace unordered { namespace detail { // reserve has basic exception safety if the hash function // throws, strong otherwise. this->reserve_for_insert(this->size_ + 1); - return emplace_return(iterator(this->add_node(a, hash)), true); + return emplace_return(this->add_node(a, hash), true); } emplace_return emplace_impl_with_node(node_constructor& a) { key_type const& k = this->get_key(a.value()); - std::size_t hash = this->hash_function()(k); - node_pointer pos = this->find_node(hash, k); + std::size_t hash = this->hash(k); + iterator pos = this->find_node(hash, k); - if (pos) return emplace_return(iterator(pos), false); + if (pos.node_) return emplace_return(pos, false); // reserve has basic exception safety if the hash function // throws, strong otherwise. this->reserve_for_insert(this->size_ + 1); - return emplace_return(iterator(this->add_node(a, hash)), true); + return emplace_return(this->add_node(a, hash), true); } template @@ -473,7 +481,7 @@ namespace boost { namespace unordered { namespace detail { void insert_range_empty(node_constructor& a, key_type const& k, InputIt i, InputIt j) { - std::size_t hash = this->hash_function()(k); + std::size_t hash = this->hash(k); a.construct_node(); a.construct_value2(*i); this->reserve_for_insert(this->size_ + @@ -486,10 +494,10 @@ namespace boost { namespace unordered { namespace detail { InputIt i, InputIt j) { // No side effects in this initial code - std::size_t hash = this->hash_function()(k); - node_pointer pos = this->find_node(hash, k); + std::size_t hash = this->hash(k); + iterator pos = this->find_node(hash, k); - if (!pos) { + if (!pos.node_) { a.construct_node(); a.construct_value2(*i); @@ -523,8 +531,9 @@ namespace boost { namespace unordered { namespace detail { { if(!this->size_) return 0; - std::size_t hash = this->hash_function()(k); - std::size_t bucket_index = hash % this->bucket_count_; + std::size_t hash = this->hash(k); + std::size_t bucket_index = + policy::to_bucket(this->bucket_count_, hash); bucket_pointer bucket = this->get_bucket(bucket_index); previous_pointer prev = bucket->next_; @@ -535,7 +544,8 @@ namespace boost { namespace unordered { namespace detail { if (!prev->next_) return 0; std::size_t node_hash = static_cast(prev->next_)->hash_; - if (node_hash % this->bucket_count_ != bucket_index) + if (policy::to_bucket(this->bucket_count_, node_hash) + != bucket_index) return 0; if (node_hash == hash && this->key_eq()(k, this->get_key( @@ -548,36 +558,38 @@ namespace boost { namespace unordered { namespace detail { node_pointer end = static_cast(pos->next_); prev->next_ = pos->next_; this->fix_buckets(bucket, prev, end); - return this->delete_nodes(pos, end); + return this->delete_nodes(c_iterator(pos), c_iterator(end)); } - node_pointer erase(node_pointer r) + iterator erase(c_iterator r) { - BOOST_ASSERT(r); - node_pointer next = static_cast(r->next_); + BOOST_ASSERT(r.node_); + iterator next(r.node_); + ++next; bucket_pointer bucket = this->get_bucket( - r->hash_ % this->bucket_count_); - previous_pointer prev = unlink_node(*bucket, r); + policy::to_bucket(this->bucket_count_, r.node_->hash_)); + previous_pointer prev = unlink_node(*bucket, r.node_); - this->fix_buckets(bucket, prev, next); + this->fix_buckets(bucket, prev, next.node_); this->delete_node(r); return next; } - node_pointer erase_range(node_pointer r1, node_pointer r2) + iterator erase_range(c_iterator r1, c_iterator r2) { - if (r1 == r2) return r2; + if (r1 == r2) return iterator(r2.node_); - std::size_t bucket_index = r1->hash_ % this->bucket_count_; + std::size_t bucket_index = + policy::to_bucket(this->bucket_count_, r1.node_->hash_); previous_pointer prev = unlink_nodes( - *this->get_bucket(bucket_index), r1, r2); - this->fix_buckets_range(bucket_index, prev, r1, r2); + *this->get_bucket(bucket_index), r1.node_, r2.node_); + this->fix_buckets_range(bucket_index, prev, r1.node_, r2.node_); this->delete_nodes(r1, r2); - return r2; + return iterator(r2.node_); } static previous_pointer unlink_node(bucket& b, node_pointer n) @@ -610,18 +622,18 @@ namespace boost { namespace unordered { namespace detail { node_constructor a(dst.node_alloc()); - node_pointer n = src.get_start(); + iterator n = src.get_start(); previous_pointer prev = dst.get_previous_start(); - while(n) { + while(n.node_) { a.construct_node(); - a.construct_value2(n->value()); + a.construct_value2(*n); node_pointer node = a.release(); - node->hash_ = n->hash_; + node->hash_ = n.node_->hash_; prev->next_ = static_cast(node); ++dst.size_; - n = static_cast(n->next_); + ++n; prev = place_in_bucket(dst, prev); } @@ -641,18 +653,18 @@ namespace boost { namespace unordered { namespace detail { node_constructor a(dst.node_alloc()); - node_pointer n = src.get_start(); + iterator n = src.get_start(); previous_pointer prev = dst.get_previous_start(); - while(n) { + while (n.node_) { a.construct_node(); - a.construct_value2(boost::move(n->value())); + a.construct_value2(boost::move(*n)); node_pointer node = a.release(); - node->hash_ = n->hash_; + node->hash_ = n.node_->hash_; prev->next_ = static_cast(node); ++dst.size_; - n = static_cast(n->next_); + ++n; prev = place_in_bucket(dst, prev); } @@ -689,7 +701,8 @@ namespace boost { namespace unordered { namespace detail { previous_pointer prev) { node_pointer n = static_cast(prev->next_); - bucket_pointer b = dst.get_bucket(n->hash_ % dst.bucket_count_); + bucket_pointer b = dst.get_bucket( + buckets::to_bucket(dst.bucket_count_, n->hash_)); if (!b->next_) { b->next_ = prev; diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 1a7ff151..7378b913 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -203,12 +203,12 @@ namespace unordered iterator begin() { - return iterator(table_.begin()); + return table_.begin(); } const_iterator begin() const { - return const_iterator(table_.begin()); + return table_.begin(); } iterator end() @@ -223,7 +223,7 @@ namespace unordered const_iterator cbegin() const { - return const_iterator(table_.begin()); + return table_.begin(); } const_iterator cend() const @@ -465,7 +465,8 @@ namespace unordered size_type bucket(const key_type& k) const { - return table_.hash_function()(k) % table_.bucket_count_; + return table::to_bucket(table_.bucket_count_, + table_.hash(k)); } local_iterator begin(size_type n) @@ -688,12 +689,12 @@ namespace unordered iterator begin() { - return iterator(table_.begin()); + return table_.begin(); } const_iterator begin() const { - return const_iterator(table_.begin()); + return table_.begin(); } iterator end() @@ -708,7 +709,7 @@ namespace unordered const_iterator cbegin() const { - return const_iterator(table_.begin()); + return table_.begin(); } const_iterator cend() const @@ -946,7 +947,8 @@ namespace unordered size_type bucket(const key_type& k) const { - return table_.hash_function()(k) % table_.bucket_count_; + return table::to_bucket(table_.bucket_count_, + table_.hash(k)); } local_iterator begin(size_type n) @@ -1139,7 +1141,7 @@ namespace unordered typename unordered_map::iterator unordered_map::erase(const_iterator position) { - return iterator(table_.erase(position.node_)); + return table_.erase(position); } template @@ -1154,7 +1156,7 @@ namespace unordered unordered_map::erase( const_iterator first, const_iterator last) { - return iterator(table_.erase_range(first.node_, last.node_)); + return table_.erase_range(first, last); } template @@ -1212,14 +1214,14 @@ namespace unordered typename unordered_map::iterator unordered_map::find(const key_type& k) { - return iterator(table_.find_node(k)); + return table_.find_node(k); } template typename unordered_map::const_iterator unordered_map::find(const key_type& k) const { - return const_iterator(table_.find_node(k)); + return table_.find_node(k); } template @@ -1231,7 +1233,7 @@ namespace unordered CompatibleHash const& hash, CompatiblePredicate const& eq) { - return iterator(table_.generic_find_node(k, hash, eq)); + return table_.generic_find_node(k, hash, eq); } template @@ -1243,7 +1245,7 @@ namespace unordered CompatibleHash const& hash, CompatiblePredicate const& eq) const { - return const_iterator(table_.generic_find_node(k, hash, eq)); + return table_.generic_find_node(k, hash, eq); } template @@ -1466,7 +1468,7 @@ namespace unordered typename unordered_multimap::iterator unordered_multimap::erase(const_iterator position) { - return iterator(table_.erase(position.node_)); + return table_.erase(position); } template @@ -1481,7 +1483,7 @@ namespace unordered unordered_multimap::erase( const_iterator first, const_iterator last) { - return iterator(table_.erase_range(first.node_, last.node_)); + return table_.erase_range(first, last); } template @@ -1518,14 +1520,14 @@ namespace unordered typename unordered_multimap::iterator unordered_multimap::find(const key_type& k) { - return iterator(table_.find_node(k)); + return table_.find_node(k); } template typename unordered_multimap::const_iterator unordered_multimap::find(const key_type& k) const { - return const_iterator(table_.find_node(k)); + return table_.find_node(k); } template @@ -1537,7 +1539,7 @@ namespace unordered CompatibleHash const& hash, CompatiblePredicate const& eq) { - return iterator(table_.generic_find_node(k, hash, eq)); + return table_.generic_find_node(k, hash, eq); } template @@ -1549,7 +1551,7 @@ namespace unordered CompatibleHash const& hash, CompatiblePredicate const& eq) const { - return const_iterator(table_.generic_find_node(k, hash, eq)); + return table_.generic_find_node(k, hash, eq); } template diff --git a/include/boost/unordered/unordered_map_fwd.hpp b/include/boost/unordered/unordered_map_fwd.hpp index 91f1e3bd..980bb3ee 100644 --- a/include/boost/unordered/unordered_map_fwd.hpp +++ b/include/boost/unordered/unordered_map_fwd.hpp @@ -10,12 +10,23 @@ # pragma once #endif +#include +#include +#include +#include #include namespace boost { namespace unordered { + template , + class P = std::equal_to, + class A = std::allocator > > + class unordered_map; + template inline bool operator==(unordered_map const&, unordered_map const&); @@ -26,6 +37,13 @@ namespace boost inline void swap(unordered_map&, unordered_map&); + template , + class P = std::equal_to, + class A = std::allocator > > + class unordered_multimap; + template inline bool operator==(unordered_multimap const&, unordered_multimap const&); diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index 384769dd..1d56c777 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -201,12 +201,12 @@ namespace unordered iterator begin() { - return iterator(table_.begin()); + return table_.begin(); } const_iterator begin() const { - return const_iterator(table_.begin()); + return table_.begin(); } iterator end() @@ -221,7 +221,7 @@ namespace unordered const_iterator cbegin() const { - return const_iterator(table_.begin()); + return table_.begin(); } const_iterator cend() const @@ -450,7 +450,8 @@ namespace unordered size_type bucket(const key_type& k) const { - return table_.hash_function()(k) % table_.bucket_count_; + return table::to_bucket(table_.bucket_count_, + table_.hash(k)); } local_iterator begin(size_type n) @@ -921,7 +922,8 @@ namespace unordered size_type bucket(const key_type& k) const { - return table_.hash_function()(k) % table_.bucket_count_; + return table::to_bucket(table_.bucket_count_, + table_.hash(k)); } local_iterator begin(size_type n) @@ -1114,7 +1116,7 @@ namespace unordered typename unordered_set::iterator unordered_set::erase(const_iterator position) { - return iterator(table_.erase(position.node_)); + return table_.erase(position); } template @@ -1129,7 +1131,7 @@ namespace unordered unordered_set::erase( const_iterator first, const_iterator last) { - return iterator(table_.erase_range(first.node_, last.node_)); + return table_.erase_range(first, last); } template @@ -1166,7 +1168,7 @@ namespace unordered typename unordered_set::const_iterator unordered_set::find(const key_type& k) const { - return const_iterator(table_.find_node(k)); + return table_.find_node(k); } template @@ -1178,7 +1180,7 @@ namespace unordered CompatibleHash const& hash, CompatiblePredicate const& eq) const { - return const_iterator(table_.generic_find_node(k, hash, eq)); + return table_.generic_find_node(k, hash, eq); } template @@ -1392,7 +1394,7 @@ namespace unordered typename unordered_multiset::iterator unordered_multiset::erase(const_iterator position) { - return iterator(table_.erase(position.node_)); + return table_.erase(position); } template @@ -1407,7 +1409,7 @@ namespace unordered unordered_multiset::erase( const_iterator first, const_iterator last) { - return iterator(table_.erase_range(first.node_, last.node_)); + return table_.erase_range(first, last); } template @@ -1444,7 +1446,7 @@ namespace unordered typename unordered_multiset::const_iterator unordered_multiset::find(const key_type& k) const { - return const_iterator(table_.find_node(k)); + return table_.find_node(k); } template @@ -1456,7 +1458,7 @@ namespace unordered CompatibleHash const& hash, CompatiblePredicate const& eq) const { - return const_iterator(table_.generic_find_node(k, hash, eq)); + return table_.generic_find_node(k, hash, eq); } template diff --git a/include/boost/unordered/unordered_set_fwd.hpp b/include/boost/unordered/unordered_set_fwd.hpp index f19c137d..0c8b6d8d 100644 --- a/include/boost/unordered/unordered_set_fwd.hpp +++ b/include/boost/unordered/unordered_set_fwd.hpp @@ -10,12 +10,22 @@ # pragma once #endif +#include +#include +#include +#include #include namespace boost { namespace unordered { + template , + class P = std::equal_to, + class A = std::allocator > + class unordered_set; + template inline bool operator==(unordered_set const&, unordered_set const&); @@ -26,6 +36,12 @@ namespace boost inline void swap(unordered_set &m1, unordered_set &m2); + template , + class P = std::equal_to, + class A = std::allocator > + class unordered_multiset; + template inline bool operator==(unordered_multiset const&, unordered_multiset const&); diff --git a/test/exception/assign_exception_tests.cpp b/test/exception/assign_exception_tests.cpp index 8e64efeb..bee732d4 100644 --- a/test/exception/assign_exception_tests.cpp +++ b/test/exception/assign_exception_tests.cpp @@ -3,8 +3,6 @@ // 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) -#include "../helpers/prefix.hpp" - #include "./containers.hpp" #include "../helpers/random_values.hpp" #include "../helpers/invariants.hpp" diff --git a/test/exception/constructor_exception_tests.cpp b/test/exception/constructor_exception_tests.cpp index aa1e02a4..3a803651 100644 --- a/test/exception/constructor_exception_tests.cpp +++ b/test/exception/constructor_exception_tests.cpp @@ -3,8 +3,6 @@ // 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) -#include "../helpers/prefix.hpp" - #include "./containers.hpp" #include "../helpers/random_values.hpp" #include "../helpers/input_iterator.hpp" diff --git a/test/exception/containers.hpp b/test/exception/containers.hpp index 23c9e495..b3a326b8 100644 --- a/test/exception/containers.hpp +++ b/test/exception/containers.hpp @@ -3,8 +3,10 @@ // 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) +#include "../helpers/prefix.hpp" #include #include +#include "../helpers/postfix.hpp" #include "../objects/exception.hpp" typedef boost::unordered_set< diff --git a/test/exception/copy_exception_tests.cpp b/test/exception/copy_exception_tests.cpp index 0d0e2e14..019410ba 100644 --- a/test/exception/copy_exception_tests.cpp +++ b/test/exception/copy_exception_tests.cpp @@ -3,8 +3,6 @@ // 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) -#include "../helpers/prefix.hpp" - #include "./containers.hpp" #include "../helpers/random_values.hpp" diff --git a/test/exception/erase_exception_tests.cpp b/test/exception/erase_exception_tests.cpp index f6eb5b42..5d40995a 100644 --- a/test/exception/erase_exception_tests.cpp +++ b/test/exception/erase_exception_tests.cpp @@ -3,8 +3,6 @@ // 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) -#include "../helpers/prefix.hpp" - #include "./containers.hpp" #include "../helpers/random_values.hpp" #include "../helpers/invariants.hpp" diff --git a/test/exception/insert_exception_tests.cpp b/test/exception/insert_exception_tests.cpp index 84278c0e..fc962cec 100644 --- a/test/exception/insert_exception_tests.cpp +++ b/test/exception/insert_exception_tests.cpp @@ -3,8 +3,6 @@ // 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) -#include "../helpers/prefix.hpp" - #include "./containers.hpp" #include #include "../helpers/random_values.hpp" diff --git a/test/exception/rehash_exception_tests.cpp b/test/exception/rehash_exception_tests.cpp index 2de210f5..2a987867 100644 --- a/test/exception/rehash_exception_tests.cpp +++ b/test/exception/rehash_exception_tests.cpp @@ -3,8 +3,6 @@ // 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) -#include "../helpers/prefix.hpp" - #include "./containers.hpp" #include #include "../helpers/random_values.hpp" diff --git a/test/exception/swap_exception_tests.cpp b/test/exception/swap_exception_tests.cpp index 570a54fa..5fcab288 100644 --- a/test/exception/swap_exception_tests.cpp +++ b/test/exception/swap_exception_tests.cpp @@ -3,8 +3,6 @@ // 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) -#include "../helpers/prefix.hpp" - #include "./containers.hpp" #include "../helpers/random_values.hpp" #include "../helpers/invariants.hpp" diff --git a/test/helpers/postfix.hpp b/test/helpers/postfix.hpp new file mode 100644 index 00000000..ca14ae71 --- /dev/null +++ b/test/helpers/postfix.hpp @@ -0,0 +1,10 @@ + +// Copyright 2012 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) + +// Include this after the boost headers, but before other test headers. + +#if defined(__GNUC__) +#pragma GCC diagnostic ignored "-Wfloat-equal" +#endif diff --git a/test/unordered/Jamfile.v2 b/test/unordered/Jamfile.v2 index 4a785224..15095a10 100644 --- a/test/unordered/Jamfile.v2 +++ b/test/unordered/Jamfile.v2 @@ -11,8 +11,8 @@ project unordered-test/unordered intel:on # Would be nice to define -Wundef, but I'm getting warnings from # Boost.Preprocessor on trunk. - gcc:"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wconversion -Wno-long-long" - darwin:"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wconversion" + gcc:"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wconversion -Wno-long-long -Wfloat-equal" + darwin:"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wconversion -Wfloat-equal" #gcc:_GLIBCXX_DEBUG #darwin:_GLIBCXX_DEBUG #msvc:on diff --git a/test/unordered/allocator_traits.cpp b/test/unordered/allocator_traits.cpp index ef7f61fe..1921f61f 100644 --- a/test/unordered/allocator_traits.cpp +++ b/test/unordered/allocator_traits.cpp @@ -90,7 +90,7 @@ void test_empty_allocator() { typedef empty_allocator allocator; typedef boost::unordered::detail::allocator_traits traits; -#if BOOST_UNORDERED_USE_ALLOCATOR_TRAITS +#if BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 1 BOOST_MPL_ASSERT((boost::is_same::type>)); #else @@ -128,8 +128,8 @@ void test_allocator1() { typedef allocator1 allocator; typedef boost::unordered::detail::allocator_traits traits; -#if BOOST_UNORDERED_USE_ALLOCATOR_TRAITS - BOOST_MPL_ASSERT((boost::is_same::type>)); #else BOOST_MPL_ASSERT((boost::is_same)); diff --git a/test/unordered/assign_tests.cpp b/test/unordered/assign_tests.cpp index 10d661d4..5079f4d5 100644 --- a/test/unordered/assign_tests.cpp +++ b/test/unordered/assign_tests.cpp @@ -4,9 +4,9 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include "../helpers/prefix.hpp" - #include #include +#include "../helpers/postfix.hpp" #include "../helpers/test.hpp" #include "../objects/test.hpp" #include "../objects/cxx11_allocator.hpp" @@ -208,9 +208,7 @@ UNORDERED_AUTO_TEST(assign_default_initializer_list) { #endif -#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) && \ - !defined(BOOST_NO_INITIALIZER_LISTS) - +#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) UNORDERED_AUTO_TEST(assign_initializer_list) { std::cerr<<"Initializer List Tests\n"; diff --git a/test/unordered/at_tests.cpp b/test/unordered/at_tests.cpp index b67900f3..111f9c2f 100644 --- a/test/unordered/at_tests.cpp +++ b/test/unordered/at_tests.cpp @@ -4,8 +4,9 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include "../helpers/prefix.hpp" - #include +#include "../helpers/postfix.hpp" + #include "../helpers/test.hpp" #include diff --git a/test/unordered/bucket_tests.cpp b/test/unordered/bucket_tests.cpp index 037e027e..c54d58d2 100644 --- a/test/unordered/bucket_tests.cpp +++ b/test/unordered/bucket_tests.cpp @@ -4,9 +4,10 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include "../helpers/prefix.hpp" - #include #include +#include "../helpers/postfix.hpp" + #include "../helpers/test.hpp" #include #include "../objects/test.hpp" diff --git a/test/unordered/compile_map.cpp b/test/unordered/compile_map.cpp index 0d8a30b7..6cd3c503 100644 --- a/test/unordered/compile_map.cpp +++ b/test/unordered/compile_map.cpp @@ -7,8 +7,8 @@ // requirements. Makes sure everything compiles and is defined correctly. #include "../helpers/prefix.hpp" - #include +#include "../helpers/postfix.hpp" #include #include "../helpers/test.hpp" diff --git a/test/unordered/compile_set.cpp b/test/unordered/compile_set.cpp index 92e808d1..f023c797 100644 --- a/test/unordered/compile_set.cpp +++ b/test/unordered/compile_set.cpp @@ -7,8 +7,8 @@ // requirements. Makes sure everything compiles and is defined correctly. #include "../helpers/prefix.hpp" - #include +#include "../helpers/postfix.hpp" #include #include "../helpers/test.hpp" diff --git a/test/unordered/constructor_tests.cpp b/test/unordered/constructor_tests.cpp index 3ccf748b..53149061 100644 --- a/test/unordered/constructor_tests.cpp +++ b/test/unordered/constructor_tests.cpp @@ -4,9 +4,10 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include "../helpers/prefix.hpp" - #include #include +#include "../helpers/postfix.hpp" + #include "../helpers/test.hpp" #include "../objects/test.hpp" #include "../helpers/random_values.hpp" @@ -442,8 +443,7 @@ UNORDERED_AUTO_TEST(test_default_initializer_list) { #endif -#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) && \ - !defined(BOOST_NO_INITIALIZER_LISTS) +#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) UNORDERED_AUTO_TEST(test_initializer_list) { std::cerr<<"Initializer List Tests\n"; diff --git a/test/unordered/copy_tests.cpp b/test/unordered/copy_tests.cpp index 0200a48e..5bbdb901 100644 --- a/test/unordered/copy_tests.cpp +++ b/test/unordered/copy_tests.cpp @@ -4,9 +4,10 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include "../helpers/prefix.hpp" - #include #include +#include "../helpers/postfix.hpp" + #include "../helpers/test.hpp" #include "../objects/test.hpp" #include "../objects/cxx11_allocator.hpp" diff --git a/test/unordered/equality_deprecated.cpp b/test/unordered/equality_deprecated.cpp index 826b11f4..af56bdea 100644 --- a/test/unordered/equality_deprecated.cpp +++ b/test/unordered/equality_deprecated.cpp @@ -6,9 +6,10 @@ #define BOOST_UNORDERED_DEPRECATED_EQUALITY #include "../helpers/prefix.hpp" - #include #include +#include "../helpers/postfix.hpp" + #include #include #include "../helpers/test.hpp" diff --git a/test/unordered/equality_tests.cpp b/test/unordered/equality_tests.cpp index bd12ba9e..b6d146c6 100644 --- a/test/unordered/equality_tests.cpp +++ b/test/unordered/equality_tests.cpp @@ -4,9 +4,10 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include "../helpers/prefix.hpp" - #include #include +#include "../helpers/postfix.hpp" + #include #include #include "../helpers/test.hpp" @@ -149,6 +150,14 @@ namespace equality_tests ((1)(2))((1001)(1)), !=, ((1001)(2))((1)(1))) } + UNORDERED_AUTO_TEST(equality_multiple_group_test) + { + UNORDERED_EQUALITY_MULTISET_TEST( + (1)(1)(1)(1001)(2001)(2001)(2)(1002)(3)(1003)(2003), ==, + (3)(1003)(2003)(1002)(2)(2001)(2001)(1)(1001)(1)(1) + ); + } + // Test that equality still works when the two containers have // different hash functions but the same equality predicate. @@ -167,7 +176,6 @@ namespace equality_tests set1.insert(20); set2.insert(10); BOOST_TEST(set1 == set2); } - } RUN_TESTS() diff --git a/test/unordered/equivalent_keys_tests.cpp b/test/unordered/equivalent_keys_tests.cpp index 994bc668..2d459a4b 100644 --- a/test/unordered/equivalent_keys_tests.cpp +++ b/test/unordered/equivalent_keys_tests.cpp @@ -4,9 +4,10 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include "../helpers/prefix.hpp" - #include #include +#include "../helpers/postfix.hpp" + #include "../helpers/test.hpp" #include #include diff --git a/test/unordered/erase_equiv_tests.cpp b/test/unordered/erase_equiv_tests.cpp index bb2e5b1b..6af1774e 100644 --- a/test/unordered/erase_equiv_tests.cpp +++ b/test/unordered/erase_equiv_tests.cpp @@ -7,8 +7,9 @@ // hairy with several tricky edge cases - so explicitly test each one. #include "../helpers/prefix.hpp" - #include +#include "../helpers/postfix.hpp" + #include "../helpers/test.hpp" #include "../helpers/list.hpp" #include diff --git a/test/unordered/erase_tests.cpp b/test/unordered/erase_tests.cpp index 6f434fb3..168e72a8 100644 --- a/test/unordered/erase_tests.cpp +++ b/test/unordered/erase_tests.cpp @@ -4,9 +4,10 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include "../helpers/prefix.hpp" - #include #include +#include "../helpers/postfix.hpp" + #include "../helpers/test.hpp" #include #include "../objects/test.hpp" diff --git a/test/unordered/find_tests.cpp b/test/unordered/find_tests.cpp index 336f2a42..2766b938 100644 --- a/test/unordered/find_tests.cpp +++ b/test/unordered/find_tests.cpp @@ -4,9 +4,10 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include "../helpers/prefix.hpp" - #include #include +#include "../helpers/postfix.hpp" + #include "../helpers/test.hpp" #include "../objects/test.hpp" #include "../helpers/random_values.hpp" diff --git a/test/unordered/fwd_map_test.cpp b/test/unordered/fwd_map_test.cpp index dc2267bf..5a943657 100644 --- a/test/unordered/fwd_map_test.cpp +++ b/test/unordered/fwd_map_test.cpp @@ -4,8 +4,8 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include "../helpers/prefix.hpp" - #include +#include "../helpers/postfix.hpp" template void call_swap(boost::unordered_map& x, diff --git a/test/unordered/fwd_set_test.cpp b/test/unordered/fwd_set_test.cpp index 4fa66b90..62067f52 100644 --- a/test/unordered/fwd_set_test.cpp +++ b/test/unordered/fwd_set_test.cpp @@ -4,8 +4,8 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include "../helpers/prefix.hpp" - #include +#include "../helpers/postfix.hpp" struct true_type { char x[100]; }; struct false_type { char x; }; diff --git a/test/unordered/incomplete_test.cpp b/test/unordered/incomplete_test.cpp index 5f355de2..035dfb6f 100644 --- a/test/unordered/incomplete_test.cpp +++ b/test/unordered/incomplete_test.cpp @@ -4,10 +4,11 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include "../helpers/prefix.hpp" - -#include #include #include +#include "../helpers/postfix.hpp" + +#include namespace x { diff --git a/test/unordered/insert_stable_tests.cpp b/test/unordered/insert_stable_tests.cpp index 86304da8..f750e50f 100644 --- a/test/unordered/insert_stable_tests.cpp +++ b/test/unordered/insert_stable_tests.cpp @@ -4,9 +4,10 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include "../helpers/prefix.hpp" - #include #include +#include "../helpers/postfix.hpp" + #include "../helpers/test.hpp" #include diff --git a/test/unordered/insert_tests.cpp b/test/unordered/insert_tests.cpp index 9db9e3f1..be8cdc30 100644 --- a/test/unordered/insert_tests.cpp +++ b/test/unordered/insert_tests.cpp @@ -4,9 +4,10 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include "../helpers/prefix.hpp" - #include #include +#include "../helpers/postfix.hpp" + #include "../helpers/test.hpp" #include #include "../objects/test.hpp" @@ -465,8 +466,7 @@ UNORDERED_TEST(map_insert_range_test2, ((default_generator)(generate_collisions)) ) -#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) && \ - !defined(BOOST_NO_INITIALIZER_LISTS) +#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) UNORDERED_AUTO_TEST(insert_initializer_list_set) { diff --git a/test/unordered/link_test_1.cpp b/test/unordered/link_test_1.cpp index 563f87ff..8df5337e 100644 --- a/test/unordered/link_test_1.cpp +++ b/test/unordered/link_test_1.cpp @@ -4,9 +4,9 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include "../helpers/prefix.hpp" - #include #include +#include "../helpers/postfix.hpp" void foo(boost::unordered_set&, boost::unordered_map&, diff --git a/test/unordered/link_test_2.cpp b/test/unordered/link_test_2.cpp index ff6432de..40ac9ebd 100644 --- a/test/unordered/link_test_2.cpp +++ b/test/unordered/link_test_2.cpp @@ -4,9 +4,9 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include "../helpers/prefix.hpp" - #include #include +#include "../helpers/postfix.hpp" void foo(boost::unordered_set& x1, boost::unordered_map& x2, diff --git a/test/unordered/load_factor_tests.cpp b/test/unordered/load_factor_tests.cpp index 8788da9b..59e91e98 100644 --- a/test/unordered/load_factor_tests.cpp +++ b/test/unordered/load_factor_tests.cpp @@ -4,9 +4,10 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include "../helpers/prefix.hpp" - #include #include +#include "../helpers/postfix.hpp" + #include "../helpers/test.hpp" #include #include "../helpers/random_values.hpp" diff --git a/test/unordered/minimal_allocator.cpp b/test/unordered/minimal_allocator.cpp index bce75751..8f485bc4 100644 --- a/test/unordered/minimal_allocator.cpp +++ b/test/unordered/minimal_allocator.cpp @@ -52,7 +52,7 @@ void test_simple_allocator() BOOST_MPL_ASSERT((boost::is_same)); -#if BOOST_UNORDERED_USE_ALLOCATOR_TRAITS +#if BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 1 BOOST_MPL_ASSERT((boost::is_same::type>)); #else diff --git a/test/unordered/move_tests.cpp b/test/unordered/move_tests.cpp index ced30486..a99171f2 100644 --- a/test/unordered/move_tests.cpp +++ b/test/unordered/move_tests.cpp @@ -4,9 +4,10 @@ // file LICENSE_1_0.txt or move at http://www.boost.org/LICENSE_1_0.txt) #include "../helpers/prefix.hpp" - #include #include +#include "../helpers/postfix.hpp" + #include "../helpers/test.hpp" #include "../objects/test.hpp" #include "../objects/cxx11_allocator.hpp" diff --git a/test/unordered/rehash_tests.cpp b/test/unordered/rehash_tests.cpp index 434389b0..dbfb84c2 100644 --- a/test/unordered/rehash_tests.cpp +++ b/test/unordered/rehash_tests.cpp @@ -4,9 +4,10 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include "../helpers/prefix.hpp" - #include #include +#include "../helpers/postfix.hpp" + #include "../helpers/test.hpp" #include "../helpers/random_values.hpp" #include "../helpers/tracker.hpp" diff --git a/test/unordered/simple_tests.cpp b/test/unordered/simple_tests.cpp index ca343542..e3d0ebe1 100644 --- a/test/unordered/simple_tests.cpp +++ b/test/unordered/simple_tests.cpp @@ -6,9 +6,10 @@ // This test checks the runtime requirements of containers. #include "../helpers/prefix.hpp" - #include #include +#include "../helpers/postfix.hpp" + #include "../helpers/test.hpp" #include #include diff --git a/test/unordered/swap_tests.cpp b/test/unordered/swap_tests.cpp index 9769af7f..9194a575 100644 --- a/test/unordered/swap_tests.cpp +++ b/test/unordered/swap_tests.cpp @@ -4,12 +4,13 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include "../helpers/prefix.hpp" +#include +#include +#include "../helpers/postfix.hpp" #include #include #include -#include -#include #include "../helpers/test.hpp" #include "../objects/test.hpp" #include "../objects/cxx11_allocator.hpp" diff --git a/test/unordered/unnecessary_copy_tests.cpp b/test/unordered/unnecessary_copy_tests.cpp index d9f85195..c8efe28f 100644 --- a/test/unordered/unnecessary_copy_tests.cpp +++ b/test/unordered/unnecessary_copy_tests.cpp @@ -1,12 +1,14 @@ -#include + // Copyright 2006-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) #include "../helpers/prefix.hpp" - #include #include +#include "../helpers/postfix.hpp" + +#include #include "../helpers/test.hpp" #if defined(BOOST_UNORDERED_VARIADIC_MOVE)