Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r73987 - in branches/release: boost/unordered boost/unordered/detail libs/unordered libs/unordered/doc libs/unordered/test/exception libs/unordered/test/helpers libs/unordered/test/objects libs/unordered/test/unordered
From: dnljms_at_[hidden]
Date: 2011-08-21 15:19:16


Author: danieljames
Date: 2011-08-21 15:19:12 EDT (Sun, 21 Aug 2011)
New Revision: 73987
URL: http://svn.boost.org/trac/boost/changeset/73987

Log:
Unordered: Merge to release.

Using Boost.Move and better C++11 support.

Added:
   branches/release/boost/unordered/detail/fwd.hpp
      - copied, changed from r72401, /trunk/boost/unordered/detail/fwd.hpp
   branches/release/libs/unordered/doc/compliance.qbk
      - copied unchanged from r73985, /trunk/libs/unordered/doc/compliance.qbk
   branches/release/libs/unordered/doc/ref.php
      - copied, changed from r73582, /trunk/libs/unordered/doc/ref.php
   branches/release/libs/unordered/test/objects/cxx11_allocator.hpp
      - copied unchanged from r73985, /trunk/libs/unordered/test/objects/cxx11_allocator.hpp
Removed:
   branches/release/boost/unordered/detail/move.hpp
Properties modified:
   branches/release/boost/unordered/ (props changed)
   branches/release/libs/unordered/ (props changed)
Text files modified:
   branches/release/boost/unordered/detail/allocator_helpers.hpp | 273 +++++
   branches/release/boost/unordered/detail/buckets.hpp | 877 +++++++++++++++++--
   branches/release/boost/unordered/detail/equivalent.hpp | 463 +++++-----
   branches/release/boost/unordered/detail/extract_key.hpp | 31
   branches/release/boost/unordered/detail/fwd.hpp | 37
   branches/release/boost/unordered/detail/node.hpp | 470 +++++++---
   branches/release/boost/unordered/detail/table.hpp | 1282 ++++++++++++++---------------
   branches/release/boost/unordered/detail/unique.hpp | 728 +++++++---------
   branches/release/boost/unordered/detail/util.hpp | 358 ++++---
   branches/release/boost/unordered/unordered_map.hpp | 1730 +++++++++++++++++++++++++--------------
   branches/release/boost/unordered/unordered_map_fwd.hpp | 66
   branches/release/boost/unordered/unordered_set.hpp | 1523 ++++++++++++++++++++++------------
   branches/release/boost/unordered/unordered_set_fwd.hpp | 64
   branches/release/libs/unordered/doc/changes.qbk | 17
   branches/release/libs/unordered/doc/rationale.qbk | 2
   branches/release/libs/unordered/doc/ref.php | 1
   branches/release/libs/unordered/doc/ref.xml | 128 +-
   branches/release/libs/unordered/doc/unordered.qbk | 1
   branches/release/libs/unordered/test/exception/swap_exception_tests.cpp | 14
   branches/release/libs/unordered/test/helpers/count.hpp | 7
   branches/release/libs/unordered/test/helpers/invariants.hpp | 49
   branches/release/libs/unordered/test/helpers/memory.hpp | 37
   branches/release/libs/unordered/test/objects/exception.hpp | 22
   branches/release/libs/unordered/test/objects/minimal.hpp | 144 ++
   branches/release/libs/unordered/test/objects/test.hpp | 31
   branches/release/libs/unordered/test/unordered/Jamfile.v2 | 2
   branches/release/libs/unordered/test/unordered/assign_tests.cpp | 87 +
   branches/release/libs/unordered/test/unordered/bucket_tests.cpp | 2
   branches/release/libs/unordered/test/unordered/compile_map.cpp | 100 +
   branches/release/libs/unordered/test/unordered/compile_set.cpp | 192 +++
   branches/release/libs/unordered/test/unordered/compile_tests.hpp | 203 +++
   branches/release/libs/unordered/test/unordered/constructor_tests.cpp | 43
   branches/release/libs/unordered/test/unordered/copy_tests.cpp | 81 +
   branches/release/libs/unordered/test/unordered/equality_tests.cpp | 8
   branches/release/libs/unordered/test/unordered/erase_tests.cpp | 14
   branches/release/libs/unordered/test/unordered/find_tests.cpp | 4
   branches/release/libs/unordered/test/unordered/insert_tests.cpp | 23
   branches/release/libs/unordered/test/unordered/move_tests.cpp | 139 +++
   branches/release/libs/unordered/test/unordered/swap_tests.cpp | 137 ++
   branches/release/libs/unordered/test/unordered/unnecessary_copy_tests.cpp | 139 ++
   40 files changed, 6142 insertions(+), 3387 deletions(-)

Modified: branches/release/boost/unordered/detail/allocator_helpers.hpp
==============================================================================
--- branches/release/boost/unordered/detail/allocator_helpers.hpp (original)
+++ branches/release/boost/unordered/detail/allocator_helpers.hpp 2011-08-21 15:19:12 EDT (Sun, 21 Aug 2011)
@@ -1,9 +1,12 @@
 
-// Copyright 2005-2009 Daniel James.
+// Copyright 2005-2011 Daniel James.
+// Copyright 2009 Pablo Halpern.
+//
 // 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)
-
-// A couple of templates to make using allocators easier.
+//
+// Written by Daniel James using some code from Pablo Halpern's
+// allocator traits implementation.
 
 #ifndef BOOST_UNORDERED_DETAIL_ALLOCATOR_UTILITIES_HPP_INCLUDED
 #define BOOST_UNORDERED_DETAIL_ALLOCATOR_UTILITIES_HPP_INCLUDED
@@ -13,6 +16,8 @@
 #endif
 
 #include <boost/config.hpp>
+#include <boost/detail/select_type.hpp>
+#include <boost/utility/enable_if.hpp>
 
 #if (defined(BOOST_NO_STD_ALLOCATOR) || defined(BOOST_DINKUMWARE_STDLIB)) \
     && !defined(__BORLANDC__)
@@ -23,24 +28,257 @@
 # include <boost/detail/allocator_utilities.hpp>
 #endif
 
-namespace boost { namespace unordered_detail {
+#if BOOST_UNORDERED_USE_ALLOCATOR_TRAITS
+# include <memory>
+#endif
+
+#if !defined(BOOST_NO_0X_HDR_TYPE_TRAITS)
+#include <type_traits>
+namespace boost { namespace unordered { namespace detail {
+ using std::integral_constant;
+ using std::true_type;
+ using std::false_type;
+}}}
+#else
+namespace boost { namespace unordered { namespace detail {
+ template <typename T, T Value>
+ struct integral_constant { enum { value = Value }; };
+ typedef integral_constant<bool, true> true_type;
+ typedef integral_constant<bool, false> false_type;
+}}}
+#endif
+
+// TODO: Use std::addressof if available?
+#include <boost/utility/addressof.hpp>
 
+namespace boost { namespace unordered { namespace detail {
+
+#if BOOST_UNORDERED_USE_ALLOCATOR_TRAITS
+ template <typename Alloc>
+ struct allocator_traits : std::allocator_traits<Alloc> {};
+
+ template <typename Alloc, typename T>
+ struct rebind_wrap
+ {
+ typedef typename allocator_traits<Alloc>::rebind_alloc<T> type;
+ };
+#else
     // rebind_wrap
     //
     // Rebind allocators. For some problematic libraries, use rebind_to
     // from <boost/detail/allocator_utilities.hpp>.
 
-#if defined(BOOST_UNORDERED_USE_ALLOCATOR_UTILITIES)
- template <class Alloc, class T>
+# if defined(BOOST_UNORDERED_USE_ALLOCATOR_UTILITIES)
+ template <typename Alloc, typename T>
     struct rebind_wrap : ::boost::detail::allocator::rebind_to<Alloc, T> {};
-#else
- template <class Alloc, class T>
+# else
+ template <typename Alloc, typename T>
     struct rebind_wrap
     {
         typedef BOOST_DEDUCED_TYPENAME
             Alloc::BOOST_NESTED_TEMPLATE rebind<T>::other
             type;
     };
+# endif
+
+ struct convertible_from_anything
+ {
+ template<typename T> convertible_from_anything(T const&);
+ };
+
+ typedef char (&no_type)[1];
+ typedef char (&yes_type)[2];
+
+ template <typename T> struct sfinae {
+ typedef yes_type type;
+ };
+
+ // Infrastructure for providing a default type for Tp::tname if absent.
+ #define BOOST_DEFAULT_TYPE_TMPLT(tname) \
+ template <typename Tp, typename Default> \
+ struct default_type_ ## tname { \
+ template <typename T> \
+ static BOOST_DEDUCED_TYPENAME sfinae< \
+ BOOST_DEDUCED_TYPENAME T::tname>::type test(int); \
+ template <typename T> \
+ static no_type test(long); \
+ \
+ enum { value = sizeof(test<Tp>(0)) == sizeof(yes_type) }; \
+ \
+ struct DefaultWrap { typedef Default tname; }; \
+ \
+ typedef BOOST_DEDUCED_TYPENAME \
+ boost::detail::if_true<value>:: \
+ BOOST_NESTED_TEMPLATE then<Tp, DefaultWrap> \
+ ::type::tname type; \
+ }
+
+ #define BOOST_DEFAULT_TYPE(T,tname, arg) \
+ BOOST_DEDUCED_TYPENAME default_type_ ## tname<T, arg>::type
+
+ BOOST_DEFAULT_TYPE_TMPLT(pointer);
+ BOOST_DEFAULT_TYPE_TMPLT(const_pointer);
+ BOOST_DEFAULT_TYPE_TMPLT(void_pointer);
+ BOOST_DEFAULT_TYPE_TMPLT(const_void_pointer);
+ BOOST_DEFAULT_TYPE_TMPLT(difference_type);
+ BOOST_DEFAULT_TYPE_TMPLT(size_type);
+ BOOST_DEFAULT_TYPE_TMPLT(propagate_on_container_copy_assignment);
+ BOOST_DEFAULT_TYPE_TMPLT(propagate_on_container_move_assignment);
+ BOOST_DEFAULT_TYPE_TMPLT(propagate_on_container_swap);
+
+#if !defined(BOOST_NO_SFINAE_EXPR) || BOOST_WORKAROUND(BOOST_MSVC, >= 1500)
+ // Specialization is only needed for Visual C++. Without it SFINAE doesn't
+ // kick in.
+ template <unsigned int>
+ struct expr_sfinae;
+
+ template <>
+ struct expr_sfinae<sizeof(yes_type)> {
+ typedef yes_type type;
+ };
+
+ template <typename T>
+ struct has_select_on_container_copy_construction
+ {
+ // This needs to be a template for Visual C++.
+ template <typename T2>
+ static yes_type to_yes_type(const T2&);
+
+ template <typename T2>
+ static typename expr_sfinae<sizeof(to_yes_type(
+ ((T2 const*)0)->select_on_container_copy_construction()
+ ))>::type check(T2*);
+
+ static no_type check(void*);
+
+ enum { value = sizeof(check((T*) 0)) == sizeof(yes_type) };
+ };
+#else
+ template <typename T>
+ struct has_select_on_container_copy_construction
+ {
+ typedef T (T::*SelectFunc)() const;
+
+ template <SelectFunc e> struct sfinae { typedef yes_type type; };
+
+ template <class U>
+ static typename sfinae<&U::select_on_container_copy_construction>::type
+ test(int);
+ template <class U>
+ static no_type test(...);
+
+ enum { value = sizeof(test<T>(1)) == sizeof(yes_type) };
+ };
+
+#endif
+
+ template <typename Alloc>
+ inline BOOST_DEDUCED_TYPENAME boost::enable_if<
+ has_select_on_container_copy_construction<Alloc>, Alloc
+ >::type call_select_on_container_copy_construction(const Alloc& rhs)
+ {
+ return rhs.select_on_container_copy_construction();
+ }
+
+ template <typename Alloc>
+ inline BOOST_DEDUCED_TYPENAME boost::disable_if<
+ has_select_on_container_copy_construction<Alloc>, Alloc
+ >::type call_select_on_container_copy_construction(const Alloc& rhs)
+ {
+ return rhs;
+ }
+
+ template <typename Alloc>
+ struct allocator_traits
+ {
+ typedef Alloc allocator_type;
+ typedef typename Alloc::value_type value_type;
+
+ typedef BOOST_DEFAULT_TYPE(Alloc, pointer, value_type*)
+ pointer;
+
+ // For now always use the allocator's const_pointer.
+
+ //typedef BOOST_DEFAULT_TYPE(Alloc, const_pointer,
+ // BOOST_DEDUCED_TYPENAME pointer_traits<pointer>::
+ // BOOST_NESTED_TEMPLATE rebind<const value_type>::other)
+ // const_pointer;
+
+ typedef BOOST_DEFAULT_TYPE(Alloc, const_pointer, value_type const*)
+ const_pointer;
+
+ // I'm not using void pointers for now.
+
+ //typedef BOOST_DEFAULT_TYPE(Alloc, void_pointer,
+ // BOOST_NESTED_TEMPLATE pointer_traits<pointer>::
+ // BOOST_NESTED_TEMPLATE rebind<void>::other)
+ // void_pointer;
+
+ //typedef BOOST_DEFAULT_TYPE(Alloc, const_void_pointer,
+ // BOOST_DEDUCED_TYPENAME pointer_traits<pointer>::
+ // BOOST_NESTED_TEMPLATE rebind<const void>::other)
+ // const_void_pointer;
+
+ typedef BOOST_DEFAULT_TYPE(Alloc, difference_type, std::ptrdiff_t)
+ difference_type;
+
+ typedef BOOST_DEFAULT_TYPE(Alloc, size_type, std::size_t)
+ size_type;
+
+ // TODO: rebind_alloc and rebind_traits
+
+ static pointer allocate(Alloc& a, size_type n)
+ { return a.allocate(n); }
+
+ // I never use this, so I'll just comment it out for now.
+ //
+ //static pointer allocate(Alloc& a, size_type n, const_void_pointer hint)
+ // { return DEFAULT_FUNC(allocate, pointer)(a, n, hint); }
+
+ static void deallocate(Alloc& a, pointer p, size_type n)
+ { a.deallocate(p, n); }
+
+ // Only support the basic copy constructor
+
+ // template <typename T, typename... Args>
+ // static void construct(Alloc& a, T* p, Args&&... args) {
+ // DEFAULT_FUNC(construct,void)(a, p, std::forward<Args>(args)...);
+ // }
+
+ template <typename T>
+ static void construct(Alloc& a, T* p, T const& x) {
+ a.construct(p, x);
+ }
+
+ template <typename T>
+ static void destroy(Alloc& a, T* p) {
+ // DEFAULT_FUNC(destroy,void)(a, p);
+ a.destroy(p);
+ }
+
+ static size_type max_size(const Alloc& a)
+ { return a.max_size(); }
+
+ // Allocator propagation on construction
+
+ static Alloc select_on_container_copy_construction(Alloc const& rhs)
+ {
+ return boost::unordered::detail::
+ call_select_on_container_copy_construction(rhs);
+ }
+
+ // Allocator propagation on assignment and swap.
+ // Return true if lhs is modified.
+ typedef BOOST_DEFAULT_TYPE(
+ Alloc, propagate_on_container_copy_assignment, false_type)
+ propagate_on_container_copy_assignment;
+ typedef BOOST_DEFAULT_TYPE(
+ Alloc,propagate_on_container_move_assignment, false_type)
+ propagate_on_container_move_assignment;
+ typedef BOOST_DEFAULT_TYPE(
+ Alloc,propagate_on_container_swap,false_type)
+ propagate_on_container_swap;
+ };
 #endif
 
     // allocator_array_constructor
@@ -49,10 +287,11 @@
     // clean up if an exception is thrown before the container takes charge
     // of it.
 
- template <class Allocator>
+ template <typename Allocator>
     struct allocator_array_constructor
     {
- typedef BOOST_DEDUCED_TYPENAME Allocator::pointer pointer;
+ typedef BOOST_DEDUCED_TYPENAME allocator_traits<Allocator>::pointer
+ pointer;
 
         Allocator& alloc_;
         pointer ptr_;
@@ -69,21 +308,23 @@
         ~allocator_array_constructor() {
             if (ptr_) {
                 for(pointer p = ptr_; p != constructed_; ++p)
- alloc_.destroy(p);
+ allocator_traits<Allocator>::destroy(alloc_,
+ boost::addressof(*p));
 
- alloc_.deallocate(ptr_, length_);
+ allocator_traits<Allocator>::deallocate(alloc_, ptr_, length_);
             }
         }
 
- template <class V>
+ template <typename V>
         void construct(V const& v, std::size_t l)
         {
             BOOST_ASSERT(!ptr_);
             length_ = l;
- ptr_ = alloc_.allocate(length_);
+ ptr_ = allocator_traits<Allocator>::allocate(alloc_, length_);
             pointer end = ptr_ + static_cast<std::ptrdiff_t>(length_);
             for(constructed_ = ptr_; constructed_ != end; ++constructed_)
- alloc_.construct(constructed_, v);
+ allocator_traits<Allocator>::construct(alloc_,
+ boost::addressof(*constructed_), v);
         }
 
         pointer get() const
@@ -102,7 +343,7 @@
         allocator_array_constructor& operator=(
             allocator_array_constructor const&);
     };
-}}
+}}}
 
 #if defined(BOOST_UNORDERED_USE_ALLOCATOR_UTILITIES)
 # undef BOOST_UNORDERED_USE_ALLOCATOR_UTILITIES

Modified: branches/release/boost/unordered/detail/buckets.hpp
==============================================================================
--- branches/release/boost/unordered/detail/buckets.hpp (original)
+++ branches/release/boost/unordered/detail/buckets.hpp 2011-08-21 15:19:12 EDT (Sun, 21 Aug 2011)
@@ -1,183 +1,808 @@
 
 // Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
-// Copyright (C) 2005-2009 Daniel James
+// Copyright (C) 2005-2011 Daniel James
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 
 #ifndef BOOST_UNORDERED_DETAIL_MANAGER_HPP_INCLUDED
 #define BOOST_UNORDERED_DETAIL_MANAGER_HPP_INCLUDED
 
-#include <boost/config.hpp>
-#include <boost/assert.hpp>
 #include <boost/unordered/detail/node.hpp>
-#include <boost/unordered/detail/util.hpp>
 
-namespace boost { namespace unordered_detail {
+namespace boost { namespace unordered { namespace detail {
     
     ////////////////////////////////////////////////////////////////////////////
- // Buckets
+ //
+ // Now the main data structure:
+ //
+ // buckets<A, Unique> functions<H, P>
+ // | |
+ // +---------------+--------------+
+ // |
+ // table<T>
+ //
+ // T is a class which contains typedefs for all the types we need.
     
- template <class A, class G>
- inline std::size_t hash_buckets<A, G>::max_bucket_count() const {
- // -1 to account for the sentinel.
- return prev_prime(this->bucket_alloc().max_size() - 1);
- }
+ // buckets
+ //
+ // This is responsible for allocating and deallocating buckets and nodes.
+ //
+ // Notes:
+ // 1. For the sake exception safety the consturctors don't allocate
+ // anything.
+ // 2. It's the callers responsibility to allocate the buckets before calling
+ // any of the methods (other than getters and setters).
+
+ template <class A, bool Unique>
+ class buckets
+ {
+ buckets(buckets const&);
+ buckets& operator=(buckets const&);
+ public:
+ // Types
+
+ typedef BOOST_DEDUCED_TYPENAME ::boost::detail::if_true<Unique>::
+ BOOST_NESTED_TEMPLATE then<
+ ::boost::unordered::detail::ungrouped_node<A>,
+ ::boost::unordered::detail::grouped_node<A>
+ >::type node;
+
+ typedef A value_allocator;
+ typedef ::boost::unordered::detail::bucket<A> bucket;
+ typedef BOOST_DEDUCED_TYPENAME allocator_traits<A>::value_type value_type;
+
+ typedef BOOST_DEDUCED_TYPENAME bucket::bucket_allocator
+ bucket_allocator;
+ typedef BOOST_DEDUCED_TYPENAME allocator_traits<bucket_allocator>::pointer bucket_ptr;
+ typedef BOOST_DEDUCED_TYPENAME bucket::node_ptr node_ptr;
+
+ typedef BOOST_DEDUCED_TYPENAME rebind_wrap<value_allocator, node>::type
+ node_allocator;
+ typedef BOOST_DEDUCED_TYPENAME allocator_traits<node_allocator>::pointer real_node_ptr;
+
+ // Members
+
+ bucket_ptr buckets_;
+ std::size_t bucket_count_;
+ std::size_t size_;
+ compressed_pair<bucket_allocator, node_allocator> allocators_;
+
+ // Data access
+
+ bucket_allocator const& bucket_alloc() const
+ {
+ return allocators_.first();
+ }
 
- template <class A, class G>
- inline BOOST_DEDUCED_TYPENAME hash_buckets<A, G>::bucket_ptr
- hash_buckets<A, G>::get_bucket(std::size_t num) const
- {
- return buckets_ + static_cast<std::ptrdiff_t>(num);
- }
+ node_allocator const& node_alloc() const
+ {
+ return allocators_.second();
+ }
 
- template <class A, class G>
- inline BOOST_DEDUCED_TYPENAME hash_buckets<A, G>::bucket_ptr
- hash_buckets<A, G>::bucket_ptr_from_hash(std::size_t hashed) const
- {
- return get_bucket(hashed % bucket_count_);
- }
+ bucket_allocator& bucket_alloc()
+ {
+ return allocators_.first();
+ }
+
+ node_allocator& node_alloc()
+ {
+ return allocators_.second();
+ }
+
+ std::size_t max_bucket_count() const
+ {
+ // -1 to account for the start bucket.
+ return prev_prime(allocator_traits<bucket_allocator>::max_size(bucket_alloc()) - 1);
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ // Constructors and Destructors
+
+ buckets(node_allocator const& a, std::size_t bucket_count)
+ : buckets_(),
+ bucket_count_(bucket_count),
+ size_(),
+ allocators_(a,a)
+ {
+ }
+
+ buckets(buckets& b, move_tag m)
+ : buckets_(),
+ bucket_count_(b.bucket_count_),
+ size_(),
+ allocators_(b.allocators_, m)
+ {
+ swap(b);
+ }
+
+ template <typename T>
+ buckets(table<T>& x, move_tag m)
+ : buckets_(),
+ bucket_count_(x.bucket_count_),
+ allocators_(x.allocators_, m)
+ {
+ swap(x);
+ x.size_ = 0;
+ }
+
+ inline ~buckets()
+ {
+ if(this->buckets_) { this->delete_buckets(); }
+ }
+
+ void create_buckets()
+ {
+ // The array constructor will clean up in the event of an
+ // exception.
+ allocator_array_constructor<bucket_allocator>
+ constructor(bucket_alloc());
     
- template <class A, class G>
- std::size_t hash_buckets<A, G>::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;
+ // Creates an extra bucket to act as the start node.
+ constructor.construct(bucket(), this->bucket_count_ + 1);
+
+ // Only release the buckets once everything is successfully
+ // done.
+ this->buckets_ = constructor.release();
+ }
+
+ void swap(buckets& other, false_type = false_type())
+ {
+ BOOST_ASSERT(node_alloc() == other.node_alloc());
+ std::swap(buckets_, other.buckets_);
+ std::swap(bucket_count_, other.bucket_count_);
+ std::swap(size_, other.size_);
+ }
+
+ void swap(buckets& other, true_type)
+ {
+ allocators_.swap(other.allocators_);
+ std::swap(buckets_, other.buckets_);
+ std::swap(bucket_count_, other.bucket_count_);
+ std::swap(size_, other.size_);
+ }
+
+ void move_buckets_from(buckets& other)
+ {
+ BOOST_ASSERT(node_alloc() == other.node_alloc());
+ BOOST_ASSERT(!this->buckets_);
+ this->buckets_ = other.buckets_;
+ this->bucket_count_ = other.bucket_count_;
+ this->size_ = other.size_;
+ other.buckets_ = bucket_ptr();
+ other.bucket_count_ = 0;
+ other.size_ = 0;
+ }
+
+ std::size_t bucket_size(std::size_t index) const
+ {
+ if (!this->size_) return 0;
+ node_ptr ptr = this->buckets_[index].next_;
+ if (!ptr) return 0;
             ptr = ptr->next_;
+
+ std::size_t count = 0;
+ while(BOOST_UNORDERED_BORLAND_BOOL(ptr) &&
+ node::get_hash(ptr) % this->bucket_count_ == index)
+ {
+ ++count;
+ ptr = ptr->next_;
+ }
+
+ return count;
         }
- return count;
- }
 
- template <class A, class G>
- inline BOOST_DEDUCED_TYPENAME hash_buckets<A, G>::node_ptr
- hash_buckets<A, G>::bucket_begin(std::size_t num) const
- {
- return buckets_ ? get_bucket(num)->next_ : node_ptr();
- }
+ node_ptr bucket_begin(std::size_t bucket_index) const
+ {
+ if (!this->size_) return node_ptr();
+ bucket& b = this->buckets_[bucket_index];
+ if (!b.next_) return node_ptr();
+ return b.next_->next_;
+ }
 
- ////////////////////////////////////////////////////////////////////////////
- // Delete
+ // For the remaining functions, buckets_ must not be null.
+
+ bucket_ptr get_bucket(std::size_t bucket_index) const
+ {
+ return buckets_ + static_cast<std::ptrdiff_t>(bucket_index);
+ }
 
- template <class A, class G>
- inline void hash_buckets<A, G>::delete_node(node_ptr b)
- {
- node* raw_ptr = static_cast<node*>(&*b);
- boost::unordered_detail::destroy(raw_ptr->value_ptr());
- real_node_ptr n(node_alloc().address(*raw_ptr));
- node_alloc().destroy(n);
- node_alloc().deallocate(n, 1);
- }
+ float load_factor() const
+ {
+ BOOST_ASSERT(this->bucket_count_ != 0);
+ return static_cast<float>(this->size_)
+ / static_cast<float>(this->bucket_count_);
+ }
 
- template <class A, class G>
- inline void hash_buckets<A, G>::clear_bucket(bucket_ptr b)
- {
- node_ptr node_it = b->next_;
- b->next_ = node_ptr();
+ ////////////////////////////////////////////////////////////////////////
+ // Delete
+
+ void delete_node(node_ptr n)
+ {
+ node* raw_ptr = static_cast<node*>(boost::addressof(*n));
+ real_node_ptr real_ptr(node_alloc().address(*raw_ptr));
+
+ ::boost::unordered::detail::destroy(raw_ptr->value_ptr());
+ allocator_traits<node_allocator>::destroy(node_alloc(), raw_ptr);
+ allocator_traits<node_allocator>::deallocate(node_alloc(), real_ptr, 1);
 
- while(node_it) {
- node_ptr node_to_delete = node_it;
- node_it = node_it->next_;
- delete_node(node_to_delete);
+ --this->size_;
+ }
+
+ void delete_buckets()
+ {
+ bucket_ptr end = this->get_bucket(this->bucket_count_);
+ node_ptr n = (end)->next_;
+ while(BOOST_UNORDERED_BORLAND_BOOL(n))
+ {
+ node_ptr node_to_delete = n;
+ n = n->next_;
+ delete_node(node_to_delete);
+ }
+
+ ++end;
+ for(bucket_ptr begin = this->buckets_; begin != end; ++begin) {
+ allocator_traits<bucket_allocator>::destroy(bucket_alloc(),
+ boost::addressof(*begin));
+ }
+
+ allocator_traits<bucket_allocator>::deallocate(bucket_alloc(), this->buckets_, this->bucket_count_ + 1);
+
+ this->buckets_ = bucket_ptr();
+ BOOST_ASSERT(this->size_ == 0);
         }
- }
 
- template <class A, class G>
- inline void hash_buckets<A, G>::delete_buckets()
- {
- bucket_ptr end = this->get_bucket(this->bucket_count_);
+ std::size_t delete_nodes(node_ptr begin, node_ptr end)
+ {
+ std::size_t count = 0;
+ while(begin != end) {
+ node_ptr n = begin;
+ begin = begin->next_;
+ delete_node(n);
+ ++count;
+ }
+ return count;
+ }
 
- for(bucket_ptr begin = this->buckets_; begin != end; ++begin) {
- clear_bucket(begin);
+ void clear()
+ {
+ if(!this->size_) return;
+
+ bucket_ptr end = this->get_bucket(this->bucket_count_);
+
+ node_ptr n = (end)->next_;
+ while(BOOST_UNORDERED_BORLAND_BOOL(n))
+ {
+ node_ptr node_to_delete = n;
+ n = n->next_;
+ this->delete_node(node_to_delete);
+ }
+
+ ++end;
+ for(bucket_ptr begin = this->buckets_; begin != end; ++begin) {
+ begin->next_ = bucket_ptr();
+ }
+
+ this->size_ = 0;
         }
 
- // Destroy the buckets (including the sentinel bucket).
- ++end;
- for(bucket_ptr begin = this->buckets_; begin != end; ++begin) {
- bucket_alloc().destroy(begin);
+ node_ptr erase(node_ptr r)
+ {
+ BOOST_ASSERT(r);
+ node_ptr next = r->next_;
+
+ bucket_ptr bucket = this->get_bucket(
+ node::get_hash(r) % this->bucket_count_);
+ node_ptr prev = node::unlink_node(*bucket, r);
+
+ this->fix_buckets(bucket, prev, next);
+
+ this->delete_node(r);
+
+ return next;
         }
 
- bucket_alloc().deallocate(this->buckets_, this->bucket_count_ + 1);
+ node_ptr erase_range(node_ptr r1, node_ptr r2)
+ {
+ if (r1 == r2) return r2;
+
+ std::size_t bucket_index = node::get_hash(r1) % this->bucket_count_;
+ node_ptr prev = node::unlink_nodes(
+ this->buckets_[bucket_index], r1, r2);
+ this->fix_buckets_range(bucket_index, prev, r1, r2);
+ this->delete_nodes(r1, r2);
+
+ return r2;
+ }
 
- this->buckets_ = bucket_ptr();
- }
+ // This is called after erasing a node or group of nodes to fix up
+ // the bucket pointers.
+ void fix_buckets(bucket_ptr bucket, node_ptr prev, node_ptr next)
+ {
+ if (!next)
+ {
+ if (bucket->next_ == prev) bucket->next_ = node_ptr();
+ }
+ else
+ {
+ bucket_ptr next_bucket = this->get_bucket(
+ node::get_hash(next) % this->bucket_count_);
+ if (next_bucket != bucket)
+ {
+ next_bucket->next_ = prev;
+ if (bucket->next_ == prev) bucket->next_ = node_ptr();
+ }
+ }
+ }
 
- template <class A, class G>
- inline std::size_t hash_buckets<A, G>::delete_nodes(
- node_ptr begin, node_ptr end)
- {
- std::size_t count = 0;
- while(begin != end) {
+ // This is called after erasing a range of nodes to fix any bucket
+ // pointers into that range.
+ void fix_buckets_range(
+ std::size_t bucket_index, node_ptr prev, node_ptr begin, node_ptr end)
+ {
             node_ptr n = begin;
- begin = begin->next_;
- delete_node(n);
- ++count;
+
+ // If we're not at the start of the current bucket, then
+ // go to the start of the next bucket.
+ if (this->get_bucket(bucket_index)->next_ != prev)
+ {
+ for(;;) {
+ n = n->next_;
+ if (n == end) return;
+
+ std::size_t new_bucket_index =
+ node::get_hash(n) % this->bucket_count_;
+ if (bucket_index != new_bucket_index) {
+ bucket_index = new_bucket_index;
+ break;
+ }
+ }
+ }
+
+ // Iterate through the remaining nodes, clearing out the bucket
+ // pointers.
+ this->buckets_[bucket_index].next_ = bucket_ptr();
+ for(;;) {
+ n = n->next_;
+ if (n == end) break;
+
+ std::size_t new_bucket_index =
+ node::get_hash(n) % this->bucket_count_;
+ if (bucket_index != new_bucket_index) {
+ bucket_index = new_bucket_index;
+ this->buckets_[bucket_index].next_ = bucket_ptr();
+ }
+ };
+
+ // Finally fix the bucket containing the trailing node.
+ if (BOOST_UNORDERED_BORLAND_BOOL(n)) {
+ this->buckets_[node::get_hash(n) % this->bucket_count_].next_
+ = prev;
+ }
         }
- return count;
- }
+
+ // Iterate through the nodes placing them in the correct buckets.
+ // pre: prev->next_ is not null.
+ node_ptr place_in_bucket(node_ptr prev, node_ptr end) {
+ bucket_ptr b = this->get_bucket(node::get_hash(prev->next_) % this->bucket_count_);
+
+ if (!b->next_) {
+ b->next_ = prev;
+ return end;
+ }
+ else {
+ node_ptr next = end->next_;
+ end->next_ = b->next_->next_;
+ b->next_->next_ = prev->next_;
+ prev->next_ = next;
+ return prev;
+ }
+ }
+
+ void copy_buckets_to(buckets&) const;
+ void move_buckets_to(buckets&) const;
+ void rehash_impl(std::size_t);
+ };
+
+ // Assigning and swapping the equality and hash function objects
+ // needs strong exception safety. To implement that normally we'd
+ // require one of them to be known to not throw and the other to
+ // guarantee strong exception safety. Unfortunately they both only
+ // have basic exception safety. So to acheive strong exception
+ // safety we have storage space for two copies, and assign the new
+ // copies to the unused space. Then switch to using that to use
+ // them. This is implemented in 'set_hash_functions' which
+ // atomically assigns the new function objects in a strongly
+ // exception safe manner.
+
+ template <class H, class P> class set_hash_functions;
+
+ template <class H, class P>
+ class functions
+ {
+ friend class set_hash_functions<H, P>;
+ functions& operator=(functions const&);
+
+ typedef compressed_pair<H, P> function_pair;
+ typedef BOOST_DEDUCED_TYPENAME ::boost::aligned_storage<
+ sizeof(function_pair),
+ ::boost::alignment_of<function_pair>::value>::type aligned_function;
+
+ bool current_; // The currently active functions.
+ aligned_function funcs_[2];
+
+ function_pair const& current() const {
+ return *static_cast<function_pair const*>(
+ static_cast<void const*>(&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:
+
+ functions(H const& hf, P const& eq)
+ : current_(false)
+ {
+ construct(current_, hf, eq);
+ }
+
+ functions(functions const& bf)
+ : current_(false)
+ {
+ construct(current_, bf.current());
+ }
+
+ ~functions() {
+ destroy(current_);
+ }
+
+ H const& hash_function() const {
+ return current().first();
+ }
+
+ P const& key_eq() const {
+ return current().second();
+ }
+ };
+
+ template <class H, class P>
+ class set_hash_functions
+ {
+ set_hash_functions(set_hash_functions const&);
+ set_hash_functions& operator=(set_hash_functions const&);
+
+ functions<H,P>& functions_;
+ bool tmp_functions_;
+
+ public:
+
+ set_hash_functions(functions<H,P>& f, H const& h, P const& p)
+ : functions_(f),
+ tmp_functions_(!f.current_)
+ {
+ f.construct(tmp_functions_, h, p);
+ }
+
+ set_hash_functions(functions<H,P>& f, functions<H,P> const& other)
+ : functions_(f),
+ tmp_functions_(!f.current_)
+ {
+ f.construct(tmp_functions_, other.current());
+ }
+
+ ~set_hash_functions()
+ {
+ functions_.destroy(tmp_functions_);
+ }
+
+ void commit()
+ {
+ functions_.current_ = tmp_functions_;
+ tmp_functions_ = !tmp_functions_;
+ }
+ };
 
     ////////////////////////////////////////////////////////////////////////////
- // Constructors and Destructors
+ // Node Constructors
+
+#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
 
- template <class A, class G>
- inline hash_buckets<A, G>::hash_buckets(
- node_allocator const& a, std::size_t bucket_count)
- : buckets_(),
- bucket_count_(bucket_count),
- allocators_(a,a)
+ template <class T, class... Args>
+ inline void construct_impl(T*, void* address, Args&&... args)
     {
+ new(address) T(std::forward<Args>(args)...);
     }
 
- template <class A, class G>
- inline hash_buckets<A, G>::~hash_buckets()
- {
- if(this->buckets_) { this->delete_buckets(); }
+#else
+
+#define BOOST_UNORDERED_CONSTRUCT_IMPL(z, num_params, _) \
+ template < \
+ class T, \
+ BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params) \
+ > \
+ inline void construct_impl( \
+ T*, void* address, \
+ BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params) \
+ ) \
+ { \
+ new(address) T( \
+ BOOST_UNORDERED_CALL_PARAMS(z, num_params)); \
+ } \
+ \
+ template <class First, class Second, class Key, \
+ BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params) \
+ > \
+ inline void construct_impl( \
+ std::pair<First, Second>*, void* address, \
+ Key const& k, BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \
+ { \
+ new(address) std::pair<First, Second>(k, \
+ Second(BOOST_UNORDERED_CALL_PARAMS(z, num_params))); \
     }
+
+ BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
+ BOOST_UNORDERED_CONSTRUCT_IMPL, _)
+
+#undef BOOST_UNORDERED_CONSTRUCT_IMPL
+#endif
+
+ ///////////////////////////////////////////////////////////////////
+ //
+ // Node construction
+
+ template <class Alloc, bool Unique>
+ class node_constructor
+ {
+ typedef ::boost::unordered::detail::buckets<Alloc, Unique> buckets;
+ typedef BOOST_DEDUCED_TYPENAME buckets::node node;
+ typedef BOOST_DEDUCED_TYPENAME buckets::real_node_ptr real_node_ptr;
+ typedef BOOST_DEDUCED_TYPENAME buckets::value_type value_type;
+ typedef BOOST_DEDUCED_TYPENAME buckets::node_allocator node_allocator;
+
+ buckets& buckets_;
+ real_node_ptr node_;
+ bool node_constructed_;
+ bool value_constructed_;
+
+ public:
+
+ node_constructor(buckets& m) :
+ buckets_(m),
+ node_(),
+ node_constructed_(false),
+ value_constructed_(false)
+ {
+ }
+
+ ~node_constructor();
+ void construct_preamble();
+
+#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
+ template <class... Args>
+ void construct(Args&&... args)
+ {
+ construct_preamble();
+ construct_impl((value_type*) 0, node_->address(),
+ std::forward<Args>(args)...);
+ value_constructed_ = true;
+ }
+#else
+
+#define BOOST_UNORDERED_CONSTRUCT(z, num_params, _) \
+ template < \
+ BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params) \
+ > \
+ void construct( \
+ BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params) \
+ ) \
+ { \
+ construct_preamble(); \
+ construct_impl( \
+ (value_type*) 0, node_->address(), \
+ BOOST_UNORDERED_CALL_PARAMS(z, num_params) \
+ ); \
+ value_constructed_ = true; \
+ }
+
+ BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
+ BOOST_UNORDERED_CONSTRUCT, _)
+
+#undef BOOST_UNORDERED_CONSTRUCT
+
+#endif
+ template <class K, class M>
+ void construct_pair(K const& k, M*)
+ {
+ construct_preamble();
+ new(node_->address()) value_type(k, M());
+ value_constructed_ = true;
+ }
+
+ value_type& value() const
+ {
+ BOOST_ASSERT(node_);
+ return node_->value();
+ }
+
+ // no throw
+ BOOST_DEDUCED_TYPENAME buckets::node_ptr release()
+ {
+ real_node_ptr p = node_;
+ node_ = real_node_ptr();
+ // node_ptr cast
+ return buckets_.bucket_alloc().address(*p);
+ }
+
+ private:
+ node_constructor(node_constructor const&);
+ node_constructor& operator=(node_constructor const&);
+ };
     
- template <class A, class G>
- inline void hash_buckets<A, G>::create_buckets()
+ // node_constructor
+
+ template <class Alloc, bool Unique>
+ inline node_constructor<Alloc, Unique>::~node_constructor()
     {
- // The array constructor will clean up in the event of an
- // exception.
- allocator_array_constructor<bucket_allocator>
- constructor(bucket_alloc());
+ if (node_) {
+ if (value_constructed_) {
+#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613))
+ struct dummy { node<Alloc, Grouped> x; };
+#endif
+ ::boost::unordered::detail::destroy(node_->value_ptr());
+ }
 
- // Creates an extra bucket to act as a sentinel.
- constructor.construct(bucket(), this->bucket_count_ + 1);
+ if (node_constructed_)
+ allocator_traits<node_allocator>::destroy(buckets_.node_alloc(),
+ boost::addressof(*node_));
 
- // Set up the sentinel (node_ptr cast)
- bucket_ptr sentinel = constructor.get() +
- static_cast<std::ptrdiff_t>(this->bucket_count_);
- sentinel->next_ = sentinel;
+ allocator_traits<node_allocator>::deallocate(buckets_.node_alloc(), node_, 1);
+ }
+ }
+
+ template <class Alloc, bool Unique>
+ inline void node_constructor<Alloc, Unique>::construct_preamble()
+ {
+ if(!node_) {
+ node_constructed_ = false;
+ value_constructed_ = false;
+
+ node_ = allocator_traits<node_allocator>::allocate(buckets_.node_alloc(), 1);
+ allocator_traits<node_allocator>::construct(buckets_.node_alloc(),
+ boost::addressof(*node_), node());
+ node_->init(buckets_.bucket_alloc().address(*node_));
 
- // Only release the buckets once everything is successfully
- // done.
- this->buckets_ = constructor.release();
+ node_constructed_ = true;
+ }
+ else {
+ BOOST_ASSERT(node_constructed_ && value_constructed_);
+ ::boost::unordered::detail::destroy(node_->value_ptr());
+ value_constructed_ = false;
+ }
     }
 
     ////////////////////////////////////////////////////////////////////////////
- // Constructors and Destructors
+ // copy_buckets_to
+ //
+ // basic exception safety. If an exception is thrown this will
+ // leave dst partially filled and the buckets unset.
 
- // no throw
- template <class A, class G>
- inline void hash_buckets<A, G>::move(hash_buckets& other)
+ template <class A, bool Unique>
+ void buckets<A, Unique>::copy_buckets_to(buckets& dst) const
     {
- BOOST_ASSERT(node_alloc() == other.node_alloc());
- if(this->buckets_) { this->delete_buckets(); }
- this->buckets_ = other.buckets_;
- this->bucket_count_ = other.bucket_count_;
- other.buckets_ = bucket_ptr();
- other.bucket_count_ = 0;
+ BOOST_ASSERT(!dst.buckets_);
+
+ dst.create_buckets();
+ bucket_ptr dst_start = dst.get_bucket(dst.bucket_count_);
+
+ {
+ node_constructor<A, Unique> a(dst);
+
+ node_ptr n = this->buckets_[this->bucket_count_].next_;
+ node_ptr prev = dst_start;
+
+ while(n) {
+ std::size_t hash = node::get_hash(n);
+ node_ptr group_end = node::next_group(n);
+
+ a.construct(node::get_value(n));
+ node_ptr first_node = a.release();
+ node::set_hash(first_node, hash);
+ node_ptr end = prev->next_ = first_node;
+ ++dst.size_;
+
+ for(n = n->next_; n != group_end; n = n->next_) {
+ a.construct(node::get_value(n));
+ end = a.release();
+ node::set_hash(end, hash);
+ node::add_after_node(end, first_node);
+ ++dst.size_;
+ }
+
+ prev = dst.place_in_bucket(prev, end);
+ }
+ }
     }
 
- template <class A, class G>
- inline void hash_buckets<A, G>::swap(hash_buckets<A, G>& other)
+ ////////////////////////////////////////////////////////////////////////////
+ // move_buckets_to
+ //
+ // Basic exception safety. The source nodes are left in an unusable state
+ // if an exception throws.
+
+ template <class A, bool Unique>
+ void buckets<A, Unique>::move_buckets_to(buckets& dst) const
     {
- BOOST_ASSERT(node_alloc() == other.node_alloc());
- std::swap(buckets_, other.buckets_);
- std::swap(bucket_count_, other.bucket_count_);
+ BOOST_ASSERT(!dst.buckets_);
+
+ dst.create_buckets();
+ bucket_ptr dst_start = dst.get_bucket(dst.bucket_count_);
+
+ {
+ node_constructor<A, Unique> a(dst);
+
+ node_ptr n = this->buckets_[this->bucket_count_].next_;
+ node_ptr prev = dst_start;
+
+ while(n) {
+ std::size_t hash = node::get_hash(n);
+ node_ptr group_end = node::next_group(n);
+
+ a.construct(boost::move(node::get_value(n)));
+ node_ptr first_node = a.release();
+ node::set_hash(first_node, hash);
+ node_ptr end = prev->next_ = first_node;
+ ++dst.size_;
+
+ for(n = n->next_; n != group_end; n = n->next_) {
+ a.construct(boost::move(node::get_value(n)));
+ end = a.release();
+ node::set_hash(end, hash);
+ node::add_after_node(end, first_node);
+ ++dst.size_;
+ }
+
+ prev = dst.place_in_bucket(prev, end);
+ }
+ }
+ }
+
+ // strong otherwise exception safety
+ template <class A, bool Unique>
+ void buckets<A, Unique>::rehash_impl(std::size_t num_buckets)
+ {
+ BOOST_ASSERT(this->size_);
+
+ buckets dst(this->node_alloc(), num_buckets);
+ dst.create_buckets();
+
+ bucket_ptr src_start = this->get_bucket(this->bucket_count_);
+ bucket_ptr dst_start = dst.get_bucket(dst.bucket_count_);
+
+ dst_start->next_ = src_start->next_;
+ src_start->next_ = bucket_ptr();
+ dst.size_ = this->size_;
+ this->size_ = 0;
+
+ node_ptr prev = dst_start;
+ while (BOOST_UNORDERED_BORLAND_BOOL(prev->next_))
+ prev = dst.place_in_bucket(prev, node::next_group2(prev));
+
+ // Swap the new nodes back into the container and setup the
+ // variables.
+ dst.swap(*this); // no throw
     }
-}}
+}}}
 
 #endif

Modified: branches/release/boost/unordered/detail/equivalent.hpp
==============================================================================
--- branches/release/boost/unordered/detail/equivalent.hpp (original)
+++ branches/release/boost/unordered/detail/equivalent.hpp 2011-08-21 15:19:12 EDT (Sun, 21 Aug 2011)
@@ -1,19 +1,18 @@
 
 // Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
-// Copyright (C) 2005-2009 Daniel James
+// Copyright (C) 2005-2011 Daniel James
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 
 #ifndef BOOST_UNORDERED_DETAIL_EQUIVALENT_HPP_INCLUDED
 #define BOOST_UNORDERED_DETAIL_EQUIVALENT_HPP_INCLUDED
 
-#include <boost/unordered/detail/table.hpp>
 #include <boost/unordered/detail/extract_key.hpp>
 
-namespace boost { namespace unordered_detail {
+namespace boost { namespace unordered { namespace detail {
 
     template <class T>
- class hash_equivalent_table : public T::table
+ class equivalent_table : public T::table_base
     {
     public:
         typedef BOOST_DEDUCED_TYPENAME T::hasher hasher;
@@ -21,284 +20,288 @@
         typedef BOOST_DEDUCED_TYPENAME T::value_allocator value_allocator;
         typedef BOOST_DEDUCED_TYPENAME T::key_type key_type;
         typedef BOOST_DEDUCED_TYPENAME T::value_type value_type;
- typedef BOOST_DEDUCED_TYPENAME T::table table;
+ typedef BOOST_DEDUCED_TYPENAME T::table_base table_base;
         typedef BOOST_DEDUCED_TYPENAME T::node_constructor node_constructor;
+ typedef BOOST_DEDUCED_TYPENAME T::node_allocator node_allocator;
 
         typedef BOOST_DEDUCED_TYPENAME T::node node;
         typedef BOOST_DEDUCED_TYPENAME T::node_ptr node_ptr;
         typedef BOOST_DEDUCED_TYPENAME T::bucket_ptr bucket_ptr;
- typedef BOOST_DEDUCED_TYPENAME T::iterator_base iterator_base;
         typedef BOOST_DEDUCED_TYPENAME T::extractor extractor;
 
         // Constructors
 
- hash_equivalent_table(std::size_t n,
+ equivalent_table(std::size_t n,
             hasher const& hf, key_equal const& eq, value_allocator const& a)
- : table(n, hf, eq, a) {}
- hash_equivalent_table(hash_equivalent_table const& x)
- : table(x, x.node_alloc()) {}
- hash_equivalent_table(hash_equivalent_table const& x,
+ : table_base(n, hf, eq, a) {}
+ equivalent_table(equivalent_table const& x)
+ : table_base(x,
+ allocator_traits<node_allocator>::
+ select_on_container_copy_construction(x.node_alloc())) {}
+ equivalent_table(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,
+ : table_base(x, a) {}
+ equivalent_table(equivalent_table& x, move_tag m)
+ : table_base(x, m) {}
+ equivalent_table(equivalent_table& x,
             value_allocator const& a, move_tag m)
- : table(x, a, m) {}
- ~hash_equivalent_table() {}
+ : table_base(x, a, m) {}
+ ~equivalent_table() {}
 
- // Insert methods
-
- iterator_base emplace_impl(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 <class... Args>
- iterator_base emplace(Args&&... args);
+ // Equality
 
-#else
-
-#define BOOST_UNORDERED_INSERT_IMPL(z, n, _) \
- template <BOOST_UNORDERED_TEMPLATE_ARGS(z, n)> \
- iterator_base emplace(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 <class I>
- void insert_for_range(I i, I j, forward_traversal_tag);
- template <class I>
- void insert_for_range(I i, I j, boost::incrementable_traversal_tag);
- template <class I>
- void insert_range(I i, I j);
- };
-
- template <class H, class P, class A>
- struct multiset : public types<
- BOOST_DEDUCED_TYPENAME A::value_type,
- BOOST_DEDUCED_TYPENAME A::value_type,
- H, P, A,
- set_extractor<BOOST_DEDUCED_TYPENAME A::value_type>,
- grouped>
- {
- typedef hash_equivalent_table<multiset<H, P, A> > impl;
- typedef hash_table<multiset<H, P, A> > table;
- };
-
- template <class K, class H, class P, class A>
- struct multimap : public types<
- K, BOOST_DEDUCED_TYPENAME A::value_type,
- H, P, A,
- map_extractor<K, BOOST_DEDUCED_TYPENAME A::value_type>,
- grouped>
- {
- typedef hash_equivalent_table<multimap<K, H, P, A> > impl;
- typedef hash_table<multimap<K, H, P, A> > table;
- };
-
- ////////////////////////////////////////////////////////////////////////////
- // Equality
-
- template <class T>
- bool hash_equivalent_table<T>
- ::equals(hash_equivalent_table<T> 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)
+ bool equals(equivalent_table const& other) const
         {
- node_ptr it1 = i->next_;
- while(BOOST_UNORDERED_BORLAND_BOOL(it1))
+ if(this->size_ != other.size_) return false;
+ if(!this->size_) return true;
+
+ for(node_ptr n1 = this->buckets_[this->bucket_count_].next_; n1;)
             {
- node_ptr it2 = other.find_iterator(this->get_key_from_ptr(it1));
- if(!BOOST_UNORDERED_BORLAND_BOOL(it2)) return false;
-
- node_ptr end1 = node::next_group(it1);
- node_ptr end2 = node::next_group(it2);
-
- do {
- if(!extractor::compare_mapped(
- node::get_value(it1), node::get_value(it2)))
- return false;
- it1 = it1->next_;
- it2 = it2->next_;
- } while(it1 != end1 && it2 != end2);
- if(it1 != end1 || it2 != end2) return false;
+ node_ptr n2 = other.find_matching_node(n1);
+ if (!n2) return false;
+ node_ptr end1 = node::next_group(n1);
+ node_ptr end2 = node::next_group(n2);
+ if (!group_equals(n1, end1, n2, end2)) return false;
+ n1 = end1;
             }
+
+ return true;
         }
+
+ static bool group_equals(node_ptr n1, node_ptr end1,
+ node_ptr n2, node_ptr end2)
+ {
+ for(;;)
+ {
+ if (node::get_value(n1) != node::get_value(n2))
+ break;
 
- return true;
- }
+ n1 = n1->next_;
+ n2 = n2->next_;
+
+ if (n1 == end1) return n2 == end2;
+ if (n2 == end2) return false;
+ }
+
+ for(node_ptr n1a = n1, n2a = n2;;)
+ {
+ n1a = n1a->next_;
+ n2a = n2a->next_;
 
- ////////////////////////////////////////////////////////////////////////////
- // A convenience method for adding nodes.
+ if (n1a == end1)
+ {
+ if (n2a == end2) break;
+ else return false;
+ }
+ if (n2a == end2) return false;
+ }
 
- template <class T>
- inline BOOST_DEDUCED_TYPENAME hash_equivalent_table<T>::node_ptr
- hash_equivalent_table<T>
- ::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;
- }
+ node_ptr start = n1;
+ for(;n1 != end2; n1 = n1->next_)
+ {
+ value_type const& v = node::get_value(n1);
+ if (find(start, n1, v)) continue;
+ std::size_t matches = count_equal(n2, end2, v);
+ if (!matches || matches != 1 + count_equal(n1->next_, end1, v))
+ return false;
+ }
+
+ return true;
+ }
+
+ static bool find(node_ptr n, node_ptr end, value_type const& v)
+ {
+ for(;n != end; n = n->next_)
+ if (node::get_value(n) == v)
+ return true;
+ return false;
+ }
+
+ static std::size_t count_equal(node_ptr n, node_ptr end, value_type const& v)
+ {
+ std::size_t count = 0;
+ for(;n != end; n = n->next_)
+ if (node::get_value(n) == v) ++count;
+ return count;
+ }
 
- ////////////////////////////////////////////////////////////////////////////
- // Insert methods
+ ////////////////////////////////////////////////////////////////////////
+ // A convenience method for adding nodes.
 
- template <class T>
- inline BOOST_DEDUCED_TYPENAME
- hash_equivalent_table<T>::iterator_base
- hash_equivalent_table<T>::emplace_impl(node_constructor& a)
- {
- key_type const& k = this->get_key(a.value());
- std::size_t hash_value = this->hash_function()(k);
-
- if(!this->size_) {
- return this->emplace_empty_impl_with_node(a, 1);
+ inline node_ptr add_node(
+ node_constructor& a,
+ std::size_t bucket_index,
+ std::size_t hash,
+ node_ptr pos)
+ {
+ node_ptr n = a.release();
+ node::set_hash(n, hash);
+
+ if(BOOST_UNORDERED_BORLAND_BOOL(pos)) {
+ node::add_after_node(n, pos);
+ if (n->next_) {
+ std::size_t next_bucket =
+ node::get_hash(n->next_) % this->bucket_count_;
+ if (next_bucket != bucket_index) {
+ this->buckets_[next_bucket].next_ = n;
+ }
+ }
+ }
+ else {
+ bucket_ptr b = this->get_bucket(bucket_index);
+
+ if (!b->next_)
+ {
+ bucket_ptr start_node =
+ this->get_bucket(this->bucket_count_);
+
+ if (BOOST_UNORDERED_BORLAND_BOOL(start_node->next_)) {
+ this->buckets_[
+ node::get_hash(start_node->next_) %
+ this->bucket_count_].next_ = n;
+ }
+
+ b->next_ = start_node;
+ n->next_ = start_node->next_;
+ start_node->next_ = n;
+ }
+ else
+ {
+ n->next_ = b->next_->next_;
+ b->next_->next_ = n;
+ }
+ }
+ ++this->size_;
+ return n;
         }
- else {
- bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value);
- node_ptr position = this->find_iterator(bucket, k);
 
+ ////////////////////////////////////////////////////////////////////////
+ // Insert methods
+
+ node_ptr emplace_impl(node_constructor& a)
+ {
+ key_type const& k = this->get_key(a.value());
+ std::size_t hash = this->hash_function()(k);
+ std::size_t bucket_index = hash % this->bucket_count_;
+ node_ptr position = this->find_node(bucket_index, hash, k);
+
             // reserve has basic exception safety if the hash function
             // throws, strong otherwise.
- if(this->reserve_for_insert(this->size_ + 1))
- bucket = this->bucket_ptr_from_hash(hash_value);
-
- return iterator_base(bucket, add_node(a, bucket, position));
- }
- }
+ if(this->reserve_for_insert(this->size_ + 1)) {
+ bucket_index = hash % this->bucket_count_;
+ }
     
- template <class T>
- inline void hash_equivalent_table<T>
- ::emplace_impl_no_rehash(node_constructor& a)
- {
- key_type const& k = this->get_key(a.value());
- bucket_ptr bucket = this->get_bucket(this->bucket_index(k));
- add_node(a, bucket, this->find_iterator(bucket, k));
- }
-
-#if defined(BOOST_UNORDERED_STD_FORWARD)
+ return add_node(a, bucket_index, hash, position);
+ }
 
- // Emplace (equivalent key containers)
- // (I'm using an overloaded emplace for both 'insert' and 'emplace')
+ void emplace_impl_no_rehash(node_constructor& a)
+ {
+ key_type const& k = this->get_key(a.value());
+ std::size_t hash = this->hash_function()(k);
+ std::size_t bucket_index = hash % this->bucket_count_;
+ add_node(a, bucket_index, hash,
+ this->find_node(bucket_index, hash, k));
+ }
 
- // if hash function throws, basic exception safety
- // strong otherwise
- template <class T>
- template <class... Args>
- BOOST_DEDUCED_TYPENAME hash_equivalent_table<T>::iterator_base
- hash_equivalent_table<T>
- ::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>(args)...);
+#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
 
- return emplace_impl(a);
- }
+ template <class... Args>
+ node_ptr emplace(Args&&... args)
+ {
+ // Create the node before rehashing in case it throws an
+ // exception (need strong safety in such a case).
+ node_constructor a(*this);
+ a.construct(std::forward<Args>(args)...);
+
+ return emplace_impl(a);
+ }
 
 #else
 
 #define BOOST_UNORDERED_INSERT_IMPL(z, num_params, _) \
- template <class T> \
- template <BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params)> \
- BOOST_DEDUCED_TYPENAME hash_equivalent_table<T>::iterator_base \
- hash_equivalent_table<T> \
- ::emplace(BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \
- { \
- node_constructor a(*this); \
- a.construct(BOOST_UNORDERED_CALL_PARAMS(z, num_params)); \
- return emplace_impl(a); \
- }
+ template <BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params)> \
+ node_ptr emplace(BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \
+ { \
+ node_constructor a(*this); \
+ a.construct(BOOST_UNORDERED_CALL_PARAMS(z, num_params)); \
+ return emplace_impl(a); \
+ }
 
- BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
- BOOST_UNORDERED_INSERT_IMPL, _)
+ 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 <class T>
- template <class I>
- inline void hash_equivalent_table<T>
- ::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);
+ ////////////////////////////////////////////////////////////////////////
+ // Insert range methods
 
- // Only require basic exception safety here
- if(this->size_) {
- this->reserve_for_insert(this->size_ + distance);
+ // if hash function throws, or inserting > 1 element, basic exception
+ // safety. Strong otherwise
+ template <class I>
+ void insert_for_range(I i, I j, forward_traversal_tag)
+ {
+ if(i == j) return;
+ std::size_t distance = ::boost::unordered::detail::distance(i, j);
+ if(distance == 1) {
+ emplace(*i);
             }
             else {
- a.construct(*i++);
- this->emplace_empty_impl_with_node(a, distance);
+ // Only require basic exception safety here
+ this->reserve_for_insert(this->size_ + distance);
+
+ node_constructor a(*this);
+ for (; i != j; ++i) {
+ a.construct(*i);
+ emplace_impl_no_rehash(a);
+ }
             }
+ }
 
+ template <class I>
+ 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_no_rehash(a);
+ emplace_impl(a);
             }
         }
- }
 
- // if hash function throws, or inserting > 1 element, basic exception safety
- // strong otherwise
- template <class T>
- template <class I>
- inline void hash_equivalent_table<T>
- ::insert_for_range(I i, I j, boost::incrementable_traversal_tag)
- {
- node_constructor a(*this);
- for (; i != j; ++i) {
- a.construct(*i);
- emplace_impl(a);
+ // If hash function throws, or inserting > 1 element, basic exception
+ // safety. Strong otherwise
+ template <class I>
+ void insert_range(I i, I j)
+ {
+ BOOST_DEDUCED_TYPENAME ::boost::iterator_traversal<I>::type
+ iterator_traversal_tag;
+ insert_for_range(i, j, iterator_traversal_tag);
         }
- }
 
- // if hash function throws, or inserting > 1 element, basic exception safety
- // strong otherwise
- template <class T>
- template <class I>
- void hash_equivalent_table<T>::insert_range(I i, I j)
+ };
+
+ template <class H, class P, class A>
+ struct multiset : public types<
+ BOOST_DEDUCED_TYPENAME allocator_traits<A>::value_type,
+ BOOST_DEDUCED_TYPENAME allocator_traits<A>::value_type,
+ H, P, A,
+ set_extractor<BOOST_DEDUCED_TYPENAME allocator_traits<A>::value_type>,
+ false>
     {
- BOOST_DEDUCED_TYPENAME boost::iterator_traversal<I>::type
- iterator_traversal_tag;
- insert_for_range(i, j, iterator_traversal_tag);
- }
-}}
+ typedef equivalent_table<multiset<H, P, A> > impl;
+ typedef table<multiset<H, P, A> > table_base;
+ };
+
+ template <class K, class H, class P, class A>
+ struct multimap : public types<
+ K, BOOST_DEDUCED_TYPENAME allocator_traits<A>::value_type,
+ H, P, A,
+ map_extractor<K, BOOST_DEDUCED_TYPENAME allocator_traits<A>::value_type>,
+ false>
+ {
+ typedef equivalent_table<multimap<K, H, P, A> > impl;
+ typedef table<multimap<K, H, P, A> > table_base;
+ };
+}}}
 
 #endif

Modified: branches/release/boost/unordered/detail/extract_key.hpp
==============================================================================
--- branches/release/boost/unordered/detail/extract_key.hpp (original)
+++ branches/release/boost/unordered/detail/extract_key.hpp 2011-08-21 15:19:12 EDT (Sun, 21 Aug 2011)
@@ -1,17 +1,16 @@
 
-// Copyright (C) 2005-2009 Daniel James
+// Copyright (C) 2005-2011 Daniel James
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 
 #ifndef BOOST_UNORDERED_DETAIL_EXTRACT_KEY_HPP_INCLUDED
 #define BOOST_UNORDERED_DETAIL_EXTRACT_KEY_HPP_INCLUDED
 
-#include <boost/config.hpp>
-#include <boost/type_traits/remove_const.hpp>
-#include <boost/unordered/detail/fwd.hpp>
+#include <boost/unordered/detail/table.hpp>
 
 namespace boost {
-namespace unordered_detail {
+namespace unordered {
+namespace detail {
 
     // key extractors
     //
@@ -39,12 +38,19 @@
             return v;
         }
 
+#if BOOST_UNORDERED_USE_RV_REF
+ static key_type const& extract(BOOST_RV_REF(key_type) v)
+ {
+ return v;
+ }
+#endif
+
         static no_key extract()
         {
             return no_key();
         }
         
-#if defined(BOOST_UNORDERED_STD_FORWARD)
+#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
         template <class... Args>
         static no_key extract(Args const&...)
         {
@@ -75,7 +81,7 @@
     struct map_extractor
     {
         typedef ValueType value_type;
- typedef BOOST_DEDUCED_TYPENAME boost::remove_const<Key>::type key_type;
+ typedef BOOST_DEDUCED_TYPENAME ::boost::remove_const<Key>::type key_type;
 
         static key_type const& extract(value_type const& v)
         {
@@ -87,6 +93,13 @@
             return v;
         }
 
+ // TODO: Why does this cause errors?
+ //
+ //static key_type const& extract(BOOST_RV_REF(key_type) v)
+ //{
+ // return v;
+ //}
+
         template <class Second>
         static key_type const& extract(std::pair<key_type, Second> const& v)
         {
@@ -100,7 +113,7 @@
             return v.first;
         }
 
-#if defined(BOOST_UNORDERED_STD_FORWARD)
+#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
         template <class Arg1, class... Args>
         static key_type const& extract(key_type const& k,
             Arg1 const&, Args const&...)
@@ -143,6 +156,6 @@
             return x.second == y.second;
         }
     };
-}}
+}}}
 
 #endif

Copied: branches/release/boost/unordered/detail/fwd.hpp (from r72401, /trunk/boost/unordered/detail/fwd.hpp)
==============================================================================
--- /trunk/boost/unordered/detail/fwd.hpp (original)
+++ branches/release/boost/unordered/detail/fwd.hpp 2011-08-21 15:19:12 EDT (Sun, 21 Aug 2011)
@@ -25,15 +25,6 @@
         class P = std::equal_to<K>,
         class A = std::allocator<std::pair<const K, T> > >
     class unordered_map;
- template <class K, class T, class H, class P, class A>
- inline bool operator==(unordered_map<K, T, H, P, A> const&,
- unordered_map<K, T, H, P, A> const&);
- template <class K, class T, class H, class P, class A>
- inline bool operator!=(unordered_map<K, T, H, P, A> const&,
- unordered_map<K, T, H, P, A> const&);
- template <class K, class T, class H, class P, class A>
- inline void swap(unordered_map<K, T, H, P, A>&,
- unordered_map<K, T, H, P, A>&);
 
     template <class K,
         class T,
@@ -41,46 +32,18 @@
         class P = std::equal_to<K>,
         class A = std::allocator<std::pair<const K, T> > >
     class unordered_multimap;
- template <class K, class T, class H, class P, class A>
- inline bool operator==(unordered_multimap<K, T, H, P, A> const&,
- unordered_multimap<K, T, H, P, A> const&);
- template <class K, class T, class H, class P, class A>
- inline bool operator!=(unordered_multimap<K, T, H, P, A> const&,
- unordered_multimap<K, T, H, P, A> const&);
- template <class K, class T, class H, class P, class A>
- inline void swap(unordered_multimap<K, T, H, P, A>&,
- unordered_multimap<K, T, H, P, A>&);
 
     template <class T,
         class H = hash<T>,
         class P = std::equal_to<T>,
         class A = std::allocator<T> >
     class unordered_set;
- template <class T, class H, class P, class A>
- inline bool operator==(unordered_set<T, H, P, A> const&,
- unordered_set<T, H, P, A> const&);
- template <class T, class H, class P, class A>
- inline bool operator!=(unordered_set<T, H, P, A> const&,
- unordered_set<T, H, P, A> const&);
- template <class T, class H, class P, class A>
- inline void swap(unordered_set<T, H, P, A> &m1,
- unordered_set<T, H, P, A> &m2);
 
     template <class T,
         class H = hash<T>,
         class P = std::equal_to<T>,
         class A = std::allocator<T> >
     class unordered_multiset;
- template <class T, class H, class P, class A>
- inline bool operator==(unordered_multiset<T, H, P, A> const&,
- unordered_multiset<T, H, P, A> const&);
- template <class T, class H, class P, class A>
- inline bool operator!=(unordered_multiset<T, H, P, A> const&,
- unordered_multiset<T, H, P, A> const&);
- template <class T, class H, class P, class A>
- inline void swap(unordered_multiset<T, H, P, A> &m1,
- unordered_multiset<T, H, P, A> &m2);
-
 }
 }
 

Deleted: branches/release/boost/unordered/detail/move.hpp
==============================================================================
--- branches/release/boost/unordered/detail/move.hpp 2011-08-21 15:19:12 EDT (Sun, 21 Aug 2011)
+++ (empty file)
@@ -1,243 +0,0 @@
-/*
- Copyright 2005-2007 Adobe Systems Incorporated
-
- Use, modification and distribution are subject to 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_MOVE_HEADER
-#define BOOST_UNORDERED_DETAIL_MOVE_HEADER
-
-#include <boost/config.hpp>
-#include <boost/mpl/bool.hpp>
-#include <boost/mpl/and.hpp>
-#include <boost/mpl/or.hpp>
-#include <boost/mpl/not.hpp>
-#include <boost/type_traits/is_convertible.hpp>
-#include <boost/type_traits/is_same.hpp>
-#include <boost/type_traits/is_class.hpp>
-#include <boost/utility/enable_if.hpp>
-#include <boost/detail/workaround.hpp>
-
-/*************************************************************************************************/
-
-#if defined(BOOST_NO_SFINAE)
-# define BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN
-#elif defined(__GNUC__) && \
- (__GNUC__ < 3 || __GNUC__ == 3 && __GNUC_MINOR__ <= 3)
-# define BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN
-#elif BOOST_WORKAROUND(BOOST_INTEL, < 900) || \
- BOOST_WORKAROUND(__EDG_VERSION__, < 304) || \
- BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x0593))
-# define BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN
-#endif
-
-/*************************************************************************************************/
-
-namespace boost {
-namespace unordered_detail {
-
-/*************************************************************************************************/
-
-namespace move_detail {
-
-/*************************************************************************************************/
-
-#if !defined(BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN)
-
-/*************************************************************************************************/
-
-template <typename T>
-struct class_has_move_assign {
- class type {
- typedef T& (T::*E)(T t);
- typedef char (&no_type)[1];
- typedef char (&yes_type)[2];
- template <E e> struct sfinae { typedef yes_type type; };
- template <class U>
- static typename sfinae<&U::operator=>::type test(int);
- template <class U>
- static no_type test(...);
- public:
- enum {value = sizeof(test<T>(1)) == sizeof(yes_type)};
- };
- };
-
-/*************************************************************************************************/
-
-template<typename T>
-struct has_move_assign : boost::mpl::and_<boost::is_class<T>, class_has_move_assign<T> > {};
-
-/*************************************************************************************************/
-
-class test_can_convert_anything { };
-
-/*************************************************************************************************/
-
-#endif // BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN
-
-/*************************************************************************************************/
-
-/*
- REVISIT (sparent_at_[hidden]): This is a work around for Boost 1.34.1 and VC++ 2008 where
- boost::is_convertible<T, T> fails to compile.
-*/
-
-template <typename T, typename U>
-struct is_convertible : boost::mpl::or_<
- boost::is_same<T, U>,
- boost::is_convertible<T, U>
-> { };
-
-/*************************************************************************************************/
-
-} //namespace move_detail
-
-
-/*************************************************************************************************/
-
-/*!
-\ingroup move_related
-\brief move_from is used for move_ctors.
-*/
-
-template <typename T>
-struct move_from
-{
- explicit move_from(T& x) : source(x) { }
- T& source;
-private:
- move_from& operator=(move_from const&);
-};
-
-/*************************************************************************************************/
-
-#if !defined(BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN)
-
-/*************************************************************************************************/
-
-/*!
-\ingroup move_related
-\brief The is_movable trait can be used to identify movable types.
-*/
-template <typename T>
-struct is_movable : boost::mpl::and_<
- boost::is_convertible<move_from<T>, T>,
- move_detail::has_move_assign<T>,
- boost::mpl::not_<boost::is_convertible<move_detail::test_can_convert_anything, T> >
- > { };
-
-/*************************************************************************************************/
-
-#else // BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN
-
-// On compilers which don't have adequate SFINAE support, treat most types as unmovable,
-// unless the trait is specialized.
-
-template <typename T>
-struct is_movable : boost::mpl::false_ { };
-
-#endif
-
-/*************************************************************************************************/
-
-#if !defined(BOOST_NO_SFINAE)
-
-/*************************************************************************************************/
-
-/*!
-\ingroup move_related
-\brief copy_sink and move_sink are used to select between overloaded operations according to
- whether type T is movable and convertible to type U.
-\sa move
-*/
-
-template <typename T,
- typename U = T,
- typename R = void*>
-struct copy_sink : boost::enable_if<
- boost::mpl::and_<
- boost::unordered_detail::move_detail::is_convertible<T, U>,
- boost::mpl::not_<is_movable<T> >
- >,
- R
- >
-{ };
-
-/*************************************************************************************************/
-
-/*!
-\ingroup move_related
-\brief move_sink and copy_sink are used to select between overloaded operations according to
- whether type T is movable and convertible to type U.
- \sa move
-*/
-
-template <typename T,
- typename U = T,
- typename R = void*>
-struct move_sink : boost::enable_if<
- boost::mpl::and_<
- boost::unordered_detail::move_detail::is_convertible<T, U>,
- is_movable<T>
- >,
- R
- >
-{ };
-
-/*************************************************************************************************/
-
-/*!
-\ingroup move_related
-\brief This version of move is selected when T is_movable . It in turn calls the move
-constructor. This call, with the help of the return value optimization, will cause x to be moved
-instead of copied to its destination. See adobe/test/move/main.cpp for examples.
-
-*/
-template <typename T>
-T move(T& x, typename move_sink<T>::type = 0) { return T(move_from<T>(x)); }
-
-/*************************************************************************************************/
-
-/*!
-\ingroup move_related
-\brief This version of move is selected when T is not movable . The net result will be that
-x gets copied.
-*/
-template <typename T>
-T& move(T& x, typename copy_sink<T>::type = 0) { return x; }
-
-/*************************************************************************************************/
-
-#else // BOOST_NO_SFINAE
-
-// On compilers without SFINAE, define copy_sink to always use the copy function.
-
-template <typename T,
- typename U = T,
- typename R = void*>
-struct copy_sink
-{
- typedef R type;
-};
-
-// Always copy the element unless this is overloaded.
-
-template <typename T>
-T& move(T& x) {
- return x;
-}
-
-#endif // BOOST_NO_SFINAE
-
-} // namespace unordered_detail
-} // namespace boost
-
-/*************************************************************************************************/
-
-#endif
-
-/*************************************************************************************************/

Modified: branches/release/boost/unordered/detail/node.hpp
==============================================================================
--- branches/release/boost/unordered/detail/node.hpp (original)
+++ branches/release/boost/unordered/detail/node.hpp 2011-08-21 15:19:12 EDT (Sun, 21 Aug 2011)
@@ -1,6 +1,6 @@
 
 // Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
-// Copyright (C) 2005-2009 Daniel James
+// Copyright (C) 2005-2011 Daniel James
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 
@@ -11,10 +11,7 @@
 #ifndef BOOST_UNORDERED_DETAIL_NODE_HPP_INCLUDED
 #define BOOST_UNORDERED_DETAIL_NODE_HPP_INCLUDED
 
-#include <boost/config.hpp>
-#include <boost/assert.hpp>
-#include <boost/detail/workaround.hpp>
-#include <boost/unordered/detail/fwd.hpp>
+#include <boost/unordered/detail/util.hpp>
 
 #if BOOST_WORKAROUND(__BORLANDC__, <= 0X0582)
 #define BOOST_UNORDERED_BORLAND_BOOL(x) (bool)(x)
@@ -22,205 +19,348 @@
 #define BOOST_UNORDERED_BORLAND_BOOL(x) x
 #endif
 
-namespace boost { namespace unordered_detail {
+namespace boost { namespace unordered { namespace detail {
+
+ // Some forward declarations for buckets and tables
+
+ template <typename T> class table;
+ template <class A, bool Unique> class buckets;
 
     ////////////////////////////////////////////////////////////////////////////
- // ungrouped node implementation
+ //
+ // This section implements buckets and nodes. Here's a rough
+ // inheritance diagram, to show how they pull together.
+ //
+ // For unordered_set/unordered_map:
+ //
+ // bucket<A> value_base<allocator_traits<A>::value_type>
+ // | |
+ // +--------------+-------------+
+ // |
+ // ungrouped_node<A>
+ //
+ // For unordered_multiset/unordered_multimap:
+ //
+ // bucket<A> value_base<allocator_traits<A>::value_type>
+ // | |
+ // +--------------+-------------+
+ // |
+ // grouped_node<A>
+
+ // bucket
+ //
+ // bucket is used for both the buckets and as a base class for
+ // nodes. By using 'bucket_ptr' for 'node_ptr', 'next_' can point
+ // to either a bucket or a node. This is used later to implement a
+ // sentinel at the end of the bucket array.
     
     template <class A>
- inline BOOST_DEDUCED_TYPENAME ungrouped_node_base<A>::node_ptr&
- ungrouped_node_base<A>::next_group(node_ptr ptr)
+ class bucket
     {
- return ptr->next_;
- }
+ bucket& operator=(bucket const&);
+ public:
+ typedef BOOST_DEDUCED_TYPENAME
+ ::boost::unordered::detail::rebind_wrap<A, bucket>::type
+ bucket_allocator;
+ typedef BOOST_DEDUCED_TYPENAME
+ allocator_traits<bucket_allocator>::pointer bucket_ptr;
+ typedef bucket_ptr node_ptr;
+
+ node_ptr next_;
 
- template <class A>
- inline std::size_t ungrouped_node_base<A>::group_count(node_ptr)
- {
- return 1;
- }
+ bucket() : next_() {}
+ };
 
- template <class A>
- inline void ungrouped_node_base<A>::add_to_bucket(node_ptr n, bucket& b)
- {
- n->next_ = b.next_;
- b.next_ = n;
- }
+ // The space used to store values in a node.
 
- template <class A>
- inline void ungrouped_node_base<A>::add_after_node(node_ptr n,
- node_ptr position)
- {
- n->next_ = position->next_;
- position->next_ = position;
- }
-
- template <class A>
- inline void ungrouped_node_base<A>::unlink_nodes(bucket& b,
- node_ptr begin, node_ptr end)
+ template <class ValueType>
+ struct value_base
     {
- node_ptr* pos = &b.next_;
- while(*pos != begin) pos = &(*pos)->next_;
- *pos = end;
- }
+ typedef ValueType value_type;
+ BOOST_DEDUCED_TYPENAME ::boost::aligned_storage<
+ sizeof(value_type),
+ ::boost::alignment_of<value_type>::value>::type data_;
 
- template <class A>
- inline void ungrouped_node_base<A>::unlink_nodes(bucket& b, node_ptr end)
- {
- b.next_ = end;
- }
+ void* address() {
+ return this;
+ }
+ value_type& value() {
+ return *(ValueType*) this;
+ }
+ value_type* value_ptr() {
+ return (ValueType*) this;
+ }
+ private:
+ value_base& operator=(value_base const&);
+ };
 
- template <class A>
- inline void ungrouped_node_base<A>::unlink_node(bucket& b, node_ptr n)
- {
- unlink_nodes(b, n, n->next_);
- }
+ // In containers with equivalent keys (unordered_multimap and
+ // unordered_multiset) equivalent nodes are grouped together, in
+ // containers with unique keys (unordered_map and unordered_set)
+ // individual nodes are treated as groups of one. The following two
+ // classes implement the data structure.
 
- ////////////////////////////////////////////////////////////////////////////
- // grouped node implementation
-
- // If ptr is the first element in a group, return pointer to next group.
- // Otherwise returns a pointer to ptr.
- template <class A>
- inline BOOST_DEDUCED_TYPENAME grouped_node_base<A>::node_ptr&
- grouped_node_base<A>::next_group(node_ptr ptr)
- {
- return get(ptr).group_prev_->next_;
- }
+ // This is used for containers with unique keys. There are no groups
+ // so it doesn't add any extra members, and just treats individual
+ // nodes as groups of one.
 
     template <class A>
- inline BOOST_DEDUCED_TYPENAME grouped_node_base<A>::node_ptr
- grouped_node_base<A>::first_in_group(node_ptr ptr)
+ struct ungrouped_node
+ : ::boost::unordered::detail::bucket<A>,
+ value_base<BOOST_DEDUCED_TYPENAME allocator_traits<A>::value_type>
     {
- while(next_group(ptr) == ptr)
- ptr = get(ptr).group_prev_;
- return ptr;
- }
+ typedef ::boost::unordered::detail::bucket<A> bucket;
+ typedef BOOST_DEDUCED_TYPENAME bucket::bucket_ptr bucket_ptr;
+ typedef BOOST_DEDUCED_TYPENAME bucket::node_ptr node_ptr;
+ typedef BOOST_DEDUCED_TYPENAME allocator_traits<A>::value_type value_type;
 
- template <class A>
- inline std::size_t grouped_node_base<A>::group_count(node_ptr ptr)
- {
- node_ptr start = ptr;
- std::size_t size = 0;
- do {
- ++size;
- ptr = get(ptr).group_prev_;
- } while(ptr != start);
- return size;
- }
+ std::size_t hash_;
 
- template <class A>
- inline void grouped_node_base<A>::add_to_bucket(node_ptr n, bucket& b)
- {
- n->next_ = b.next_;
- get(n).group_prev_ = n;
- b.next_ = n;
- }
+ ungrouped_node() : bucket() {}
 
- template <class A>
- inline void grouped_node_base<A>::add_after_node(node_ptr n, node_ptr pos)
- {
- n->next_ = next_group(pos);
- get(n).group_prev_ = get(pos).group_prev_;
- next_group(pos) = n;
- get(pos).group_prev_ = n;
- }
-
- // Break a ciruclar list into two, with split as the beginning
- // of the second group (if split is at the beginning then don't
- // split).
- template <class A>
- inline BOOST_DEDUCED_TYPENAME grouped_node_base<A>::node_ptr
- grouped_node_base<A>::split_group(node_ptr split)
- {
- node_ptr first = first_in_group(split);
- if(first == split) return split;
+ void init(node_ptr) {}
+
+ static node_ptr next_group(node_ptr ptr)
+ {
+ return ptr->next_;
+ }
+
+ static node_ptr next_group2(node_ptr ptr)
+ {
+ return ptr->next_;
+ }
+
+ static std::size_t group_count(node_ptr n)
+ {
+ return !n ? 0 : 1;
+ }
+
+ static void add_after_node(node_ptr n, node_ptr position)
+ {
+ n->next_ = position->next_;
+ position->next_ = position;
+ }
+
+ static node_ptr unlink_node(bucket& b, node_ptr n)
+ {
+ return unlink_nodes(b, n, n->next_);
+ }
+
+ static node_ptr unlink_nodes(bucket& b, node_ptr begin, node_ptr end)
+ {
+ node_ptr prev = b.next_;
+ while(prev->next_ != begin) prev = prev->next_;
+ prev->next_ = end;
+ return prev;
+ }
+
+ static std::size_t get_hash(node_ptr p)
+ {
+ return static_cast<ungrouped_node&>(*p).hash_;
+ }
+
+ static void set_hash(node_ptr p, std::size_t hash)
+ {
+ static_cast<ungrouped_node&>(*p).hash_ = hash;
+ }
+
+ static value_type& get_value(node_ptr p)
+ {
+ return static_cast<ungrouped_node&>(*p).value();
+ }
 
- node_ptr last = get(first).group_prev_;
- get(first).group_prev_ = get(split).group_prev_;
- get(split).group_prev_ = last;
+ static value_type* get_value_ptr(node_ptr p)
+ {
+ return static_cast<ungrouped_node&>(*p).value_ptr();
+ }
+ };
 
- return first;
- }
+ // This is used for containers with equivalent keys. It implements a
+ // circular list running in the opposite direction to the linked
+ // list through the nodes.
 
     template <class A>
- void grouped_node_base<A>::unlink_node(bucket& b, node_ptr n)
+ struct grouped_node
+ : ::boost::unordered::detail::bucket<A>,
+ value_base<BOOST_DEDUCED_TYPENAME allocator_traits<A>::value_type>
     {
- node_ptr next = n->next_;
- node_ptr* pos = &next_group(n);
+ typedef ::boost::unordered::detail::bucket<A> bucket;
+ typedef BOOST_DEDUCED_TYPENAME bucket::bucket_ptr bucket_ptr;
+ typedef BOOST_DEDUCED_TYPENAME bucket::node_ptr node_ptr;
+ typedef BOOST_DEDUCED_TYPENAME allocator_traits<A>::value_type value_type;
+
+ std::size_t hash_;
+ node_ptr group_prev_;
+
+ grouped_node() : bucket(), group_prev_() {}
+ void init(node_ptr n)
+ {
+ group_prev_ = n;
+ }
+
+ static node_ptr next_group(node_ptr ptr)
+ {
+ return get(ptr).group_prev_->next_;
+ }
+
+ static node_ptr next_group2(node_ptr ptr)
+ {
+ return get(ptr->next_).group_prev_;
+ }
+
+ static std::size_t group_count(node_ptr ptr)
+ {
+ if (!ptr) return 0;
 
- if(*pos != n) {
- // The node is at the beginning of a group.
+ node_ptr start = ptr;
+ std::size_t size = 0;
+ do {
+ ++size;
+ ptr = get(ptr).group_prev_;
+ } while(ptr != start);
+ return size;
+ }
 
- // Find the previous node pointer:
- pos = &b.next_;
- while(*pos != n) pos = &next_group(*pos);
+ static void add_after_node(node_ptr n, node_ptr pos)
+ {
+ n->next_ = get(pos).group_prev_->next_;
+ get(n).group_prev_ = get(pos).group_prev_;
+ get(pos).group_prev_->next_ = n;
+ get(pos).group_prev_ = n;
+ }
 
- // Remove from group
- if(BOOST_UNORDERED_BORLAND_BOOL(next) &&
+ static node_ptr unlink_node(bucket& b, node_ptr n)
+ {
+ node_ptr next = n->next_;
+ node_ptr prev = get(n).group_prev_;
+
+ if(prev->next_ != n) {
+ // The node is at the beginning of a group.
+
+ // Find the previous node pointer:
+ prev = b.next_;
+ while(prev->next_ != n) {
+ prev = next_group2(prev);
+ }
+
+ // Remove from group
+ if(BOOST_UNORDERED_BORLAND_BOOL(next) &&
+ get(next).group_prev_ == n)
+ {
+ get(next).group_prev_ = get(n).group_prev_;
+ }
+ }
+ else if(BOOST_UNORDERED_BORLAND_BOOL(next) &&
                 get(next).group_prev_ == n)
             {
+ // The deleted node is not at the end of the group, so
+ // change the link from the next node.
                 get(next).group_prev_ = get(n).group_prev_;
             }
+ else {
+ // The deleted node is at the end of the group, so the
+ // first node in the group is pointing to it.
+ // Find that to change its pointer.
+ node_ptr x = get(n).group_prev_;
+ while(get(x).group_prev_ != n) {
+ x = get(x).group_prev_;
+ }
+ get(x).group_prev_ = get(n).group_prev_;
+ }
+ prev->next_ = next;
+
+ return prev;
         }
- else if(BOOST_UNORDERED_BORLAND_BOOL(next) &&
- get(next).group_prev_ == n)
+
+ static node_ptr unlink_nodes(bucket& b, node_ptr begin, node_ptr end)
         {
- // The deleted node is not at the end of the group, so
- // change the link from the next node.
- get(next).group_prev_ = get(n).group_prev_;
- }
- else {
- // The deleted node is at the end of the group, so the
- // first node in the group is pointing to it.
- // Find that to change its pointer.
- node_ptr x = get(n).group_prev_;
- while(get(x).group_prev_ != n) {
- x = get(x).group_prev_;
+ node_ptr prev = get(begin).group_prev_;
+
+ if(prev->next_ != begin) {
+ // The node is at the beginning of a group.
+
+ // Find the previous node pointer:
+ prev = b.next_;
+ while(prev->next_ != begin) prev = next_group2(prev);
+
+ if(BOOST_UNORDERED_BORLAND_BOOL(end)) split_group(end);
+ }
+ else {
+ node_ptr group1 = split_group(begin);
+ if(BOOST_UNORDERED_BORLAND_BOOL(end)) {
+ node_ptr group2 = split_group(end);
+
+ if(begin == group2) {
+ node_ptr end1 = get(group1).group_prev_;
+ node_ptr end2 = get(group2).group_prev_;
+ get(group1).group_prev_ = end2;
+ get(group2).group_prev_ = end1;
+ }
+ }
             }
- get(x).group_prev_ = get(n).group_prev_;
+
+ prev->next_ = end;
+
+ return prev;
         }
- *pos = next;
- }
 
- template <class A>
- void grouped_node_base<A>::unlink_nodes(bucket& b,
- node_ptr begin, node_ptr end)
- {
- node_ptr* pos = &next_group(begin);
+ // Break a ciruclar list into two, with split as the beginning
+ // of the second group (if split is at the beginning then don't
+ // split).
+ static node_ptr split_group(node_ptr split)
+ {
+ // Find first node in group.
+ node_ptr first = split;
+ while(next_group(first) == first)
+ first = get(first).group_prev_;
 
- if(*pos != begin) {
- // The node is at the beginning of a group.
+ if(first == split) return split;
+
+ node_ptr last = get(first).group_prev_;
+ get(first).group_prev_ = get(split).group_prev_;
+ get(split).group_prev_ = last;
+
+ return first;
+ }
 
- // Find the previous node pointer:
- pos = &b.next_;
- while(*pos != begin) pos = &next_group(*pos);
-
- // Remove from group
- if(BOOST_UNORDERED_BORLAND_BOOL(end)) split_group(end);
- }
- else {
- node_ptr group1 = split_group(begin);
- if(BOOST_UNORDERED_BORLAND_BOOL(end)) {
- node_ptr group2 = split_group(end);
-
- if(begin == group2) {
- node_ptr end1 = get(group1).group_prev_;
- node_ptr end2 = get(group2).group_prev_;
- get(group1).group_prev_ = end2;
- get(group2).group_prev_ = end1;
- }
- }
+ static std::size_t get_hash(node_ptr p) {
+ return static_cast<grouped_node&>(*p).hash_;
+ }
+ static void set_hash(node_ptr p, std::size_t hash) {
+ static_cast<grouped_node&>(*p).hash_ = hash;
+ }
+ static value_type& get_value(node_ptr p) {
+ return static_cast<grouped_node&>(*p).value();
+ }
+ static value_type* get_value_ptr(node_ptr p) {
+ return static_cast<grouped_node&>(*p).value_ptr();
         }
- *pos = end;
- }
 
- template <class A>
- void grouped_node_base<A>::unlink_nodes(bucket& b, node_ptr end)
+ static grouped_node& get(node_ptr ptr) {
+ return static_cast<grouped_node&>(*ptr);
+ }
+ };
+
+ // These two classes implement an easy way to pass around the node
+ // group policy classes without the messy template parameters.
+ // Whenever you see the template parameter 'G' it's one of these.
+
+ struct ungrouped
     {
- split_group(end);
- b.next_ = end;
- }
-}}
+ template <class A>
+ struct node {
+ typedef ungrouped_node<A> type;
+ };
+ };
+
+ struct grouped
+ {
+ template <class A>
+ struct node {
+ typedef grouped_node<A> type;
+ };
+ };
+
+}}}
 
 #endif

Modified: branches/release/boost/unordered/detail/table.hpp
==============================================================================
--- branches/release/boost/unordered/detail/table.hpp (original)
+++ branches/release/boost/unordered/detail/table.hpp 2011-08-21 15:19:12 EDT (Sun, 21 Aug 2011)
@@ -1,444 +1,434 @@
 
 // Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
-// Copyright (C) 2005-2009 Daniel James
+// Copyright (C) 2005-2011 Daniel James
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 
 #ifndef BOOST_UNORDERED_DETAIL_ALL_HPP_INCLUDED
 #define BOOST_UNORDERED_DETAIL_ALL_HPP_INCLUDED
 
-#include <cstddef>
-#include <stdexcept>
-#include <algorithm>
-#include <boost/config/no_tr1/cmath.hpp>
-#include <boost/iterator/iterator_categories.hpp>
-#include <boost/throw_exception.hpp>
-
 #include <boost/unordered/detail/buckets.hpp>
 
-namespace boost { namespace unordered_detail {
+namespace boost { namespace unordered { namespace detail {
 
- ////////////////////////////////////////////////////////////////////////////
- // Helper methods
+ // This implements almost all of the required functionality, apart
+ // from some things that are specific to containers with unique and
+ // equivalent keys which is implemented in unique_table and
+ // equivalent_table. See unique.hpp and equivalent.hpp for
+ // their declaration and implementation.
+
+ template <class T>
+ class table : public T::buckets, public T::functions
+ {
+ table(table const&);
+ table& operator=(table const&);
+ public:
+ typedef BOOST_DEDUCED_TYPENAME T::hasher hasher;
+ typedef BOOST_DEDUCED_TYPENAME T::key_equal key_equal;
+ typedef BOOST_DEDUCED_TYPENAME T::value_allocator value_allocator;
+ typedef BOOST_DEDUCED_TYPENAME T::key_type key_type;
+ typedef BOOST_DEDUCED_TYPENAME T::value_type value_type;
+ typedef BOOST_DEDUCED_TYPENAME T::functions functions;
+ typedef BOOST_DEDUCED_TYPENAME T::buckets buckets;
+ typedef BOOST_DEDUCED_TYPENAME T::extractor extractor;
+ typedef BOOST_DEDUCED_TYPENAME T::node_constructor node_constructor;
+
+ typedef BOOST_DEDUCED_TYPENAME T::node node;
+ typedef BOOST_DEDUCED_TYPENAME T::bucket bucket;
+ typedef BOOST_DEDUCED_TYPENAME T::node_ptr node_ptr;
+ typedef BOOST_DEDUCED_TYPENAME T::bucket_ptr bucket_ptr;
+ typedef BOOST_DEDUCED_TYPENAME T::node_allocator node_allocator;
+ typedef BOOST_DEDUCED_TYPENAME T::iterator_pair iterator_pair;
 
- // strong exception safety, no side effects
- template <class T>
- inline bool hash_table<T>::equal(
- key_type const& k, value_type const& v) const
- {
- return this->key_eq()(k, get_key(v));
- }
+ // Members
+
+ float mlf_;
+ std::size_t max_load_; // Only use if this->buckets_.
 
- // strong exception safety, no side effects
- template <class T>
- template <class Key, class Pred>
- inline BOOST_DEDUCED_TYPENAME T::node_ptr
- hash_table<T>::find_iterator(bucket_ptr bucket, Key const& k,
- Pred const& eq) const
- {
- node_ptr it = bucket->next_;
- while (BOOST_UNORDERED_BORLAND_BOOL(it) &&
- !eq(k, get_key(node::get_value(it))))
- {
- it = node::next_group(it);
- }
+ // Helper methods
 
- return it;
- }
+ key_type const& get_key(value_type const& v) const {
+ return extractor::extract(v);
+ }
 
- // strong exception safety, no side effects
- template <class T>
- inline BOOST_DEDUCED_TYPENAME T::node_ptr
- hash_table<T>::find_iterator(
- bucket_ptr bucket, key_type const& k) const
- {
- node_ptr it = bucket->next_;
- while (BOOST_UNORDERED_BORLAND_BOOL(it) &&
- !equal(k, node::get_value(it)))
+ private:
+ // pre: this->buckets_ != null
+ template <class Key, class Pred>
+ node_ptr find_node_impl(
+ std::size_t bucket_index,
+ std::size_t hash,
+ Key const& k,
+ Pred const& eq) const
         {
- it = node::next_group(it);
+ node_ptr n = this->buckets_[bucket_index].next_;
+ if (!n) return n;
+ n = n->next_;
+
+ for (;;)
+ {
+ if (!n) return n;
+ std::size_t node_hash = node::get_hash(n);
+ if (hash == node_hash)
+ {
+ if (eq(k, get_key(node::get_value(n))))
+ return n;
+ }
+ else
+ {
+ if (node_hash % this->bucket_count_ != bucket_index)
+ return node_ptr();
+ }
+ n = node::next_group(n);
+ }
         }
 
- return it;
- }
-
- // strong exception safety, no side effects
- // pre: this->buckets_
- template <class T>
- inline BOOST_DEDUCED_TYPENAME T::node_ptr
- hash_table<T>::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 <class T>
- inline BOOST_DEDUCED_TYPENAME T::node_ptr*
- hash_table<T>::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)))
+ public:
+ template <class Key, class Hash, class Pred>
+ node_ptr generic_find_node(
+ Key const& k,
+ Hash const& hash_function,
+ Pred const& eq) const
         {
- it = &node::next_group(*it);
+ if (!this->size_) return node_ptr();
+ std::size_t hash = hash_function(k);
+ return this->find_node_impl(hash % this->bucket_count_, hash, k, eq);
+ }
+
+ node_ptr find_node(
+ std::size_t bucket_index,
+ std::size_t hash,
+ key_type const& k) const
+ {
+ if (!this->size_) return node_ptr();
+ return this->find_node_impl(bucket_index, hash, k, this->key_eq());
         }
 
- return it;
- }
-
- ////////////////////////////////////////////////////////////////////////////
- // Load methods
-
- // no throw
- template <class T>
- std::size_t hash_table<T>::max_size() const
- {
- using namespace std;
-
- // size < mlf_ * count
- return double_to_size_t(ceil(
- (double) this->mlf_ * this->max_bucket_count())) - 1;
- }
-
- // strong safety
- template <class T>
- inline std::size_t hash_table<T>::bucket_index(
- key_type const& k) const
- {
- // hash_function can throw:
- return this->hash_function()(k) % this->bucket_count_;
- }
-
-
- // no throw
- template <class T>
- inline std::size_t hash_table<T>::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 <class T>
- void hash_table<T>::max_load_factor(float z)
- {
- BOOST_ASSERT(z > 0);
- mlf_ = (std::max)(z, minimum_max_load_factor);
- this->max_load_ = this->calculate_max_load();
- }
-
- // no throw
- template <class T>
- inline std::size_t hash_table<T>::min_buckets_for_size(
- std::size_t size) const
- {
- BOOST_ASSERT(this->mlf_ != 0);
+ node_ptr find_node(key_type const& k) const
+ {
+ if (!this->size_) return node_ptr();
+ std::size_t hash = this->hash_function()(k);
+ return this->find_node_impl(hash % this->bucket_count_, hash, k,
+ this->key_eq());
+ }
 
- using namespace std;
+ node_ptr find_matching_node(node_ptr n) const
+ {
+ // For some stupid reason, I decided to support equality comparison
+ // when different hash functions are used. So I can't use the hash
+ // value from the node here.
+
+ return find_node(get_key(node::get_value(n)));
+ }
 
- // From 6.3.1/13:
- // size < mlf_ * count
- // => count > size / mlf_
- //
- // Or from rehash post-condition:
- // count > size / mlf_
- return next_prime(double_to_size_t(floor(size / (double) mlf_)) + 1);
- }
+ ////////////////////////////////////////////////////////////////////////
+ // Load methods
 
- ////////////////////////////////////////////////////////////////////////////
- // recompute_begin_bucket
+ std::size_t max_size() const
+ {
+ using namespace std;
+
+ // size < mlf_ * count
+ return double_to_size_t(ceil(
+ static_cast<double>(this->mlf_) *
+ static_cast<double>(this->max_bucket_count())
+ )) - 1;
+ }
 
- // init_buckets
+ std::size_t calculate_max_load()
+ {
+ using namespace std;
+
+ // From 6.3.1/13:
+ // Only resize when size >= mlf_ * count
+ return double_to_size_t(ceil(
+ static_cast<double>(this->mlf_) *
+ static_cast<double>(this->bucket_count_)
+ ));
 
- template <class T>
- inline void hash_table<T>::init_buckets()
- {
- if (this->size_) {
- this->cached_begin_bucket_ = this->buckets_;
- while (!this->cached_begin_bucket_->next_)
- ++this->cached_begin_bucket_;
- } else {
- this->cached_begin_bucket_ = this->get_bucket(this->bucket_count_);
         }
- this->max_load_ = calculate_max_load();
- }
 
- // After an erase cached_begin_bucket_ might be left pointing to
- // an empty bucket, so this is called to update it
- //
- // no throw
+ void max_load_factor(float z)
+ {
+ BOOST_ASSERT(z > 0);
+ mlf_ = (std::max)(z, minimum_max_load_factor);
+ if (BOOST_UNORDERED_BORLAND_BOOL(this->buckets_))
+ this->max_load_ = this->calculate_max_load();
+ }
 
- template <class T>
- inline void hash_table<T>::recompute_begin_bucket(bucket_ptr b)
- {
- BOOST_ASSERT(!(b < this->cached_begin_bucket_));
+ std::size_t min_buckets_for_size(std::size_t size) const
+ {
+ BOOST_ASSERT(this->mlf_ != 0);
+
+ using namespace std;
+
+ // From 6.3.1/13:
+ // size < mlf_ * count
+ // => count > size / mlf_
+ //
+ // Or from rehash post-condition:
+ // count > size / mlf_
+ return next_prime(double_to_size_t(floor(size / (double) mlf_)) + 1);
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ // Constructors
+
+ table(std::size_t num_buckets,
+ hasher const& hf,
+ key_equal const& eq,
+ node_allocator const& a)
+ : buckets(a, next_prime(num_buckets)),
+ functions(hf, eq),
+ mlf_(1.0f),
+ max_load_(0)
+ {
+ }
 
- if(b == this->cached_begin_bucket_)
+ table(table const& x, node_allocator const& a)
+ : buckets(a, x.min_buckets_for_size(x.size_)),
+ functions(x),
+ mlf_(x.mlf_),
+ max_load_(0)
         {
- if (this->size_ != 0) {
- while (!this->cached_begin_bucket_->next_)
- ++this->cached_begin_bucket_;
- } else {
- this->cached_begin_bucket_ =
- this->get_bucket(this->bucket_count_);
+ if(x.size_) {
+ x.copy_buckets_to(*this);
+ this->max_load_ = calculate_max_load();
             }
         }
- }
-
- // This is called when a range has been erased
- //
- // no throw
 
- template <class T>
- inline void hash_table<T>::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_));
+ table(table& x, move_tag m)
+ : buckets(x, m),
+ functions(x),
+ mlf_(x.mlf_),
+ max_load_(calculate_max_load()) {}
+
+ // TODO: Why do I use x's bucket count?
+ table(table& x, node_allocator const& a, move_tag m)
+ : buckets(a, x.bucket_count_),
+ functions(x),
+ mlf_(x.mlf_),
+ max_load_(x.max_load_)
+ {
+ if(a == x.node_alloc()) {
+ this->buckets::swap(x, false_type());
+ }
+ else if(x.size_) {
+ // Use a temporary table because move_buckets_to leaves the
+ // source container in a complete mess.
+ buckets tmp(x, m);
+ tmp.move_buckets_to(*this);
+ this->max_load_ = calculate_max_load();
+ }
+ }
 
- if(b1 == this->cached_begin_bucket_ && !b1->next_)
- this->cached_begin_bucket_ = b2;
- }
+ ~table()
+ {}
 
- // no throw
- template <class T>
- inline float hash_table<T>::load_factor() const
- {
- BOOST_ASSERT(this->bucket_count_ != 0);
- return static_cast<float>(this->size_)
- / static_cast<float>(this->bucket_count_);
- }
+ // Iterators
 
- ////////////////////////////////////////////////////////////////////////////
- // Constructors
+ node_ptr begin() const {
+ return !this->buckets_ ?
+ node_ptr() : this->buckets_[this->bucket_count_].next_;
+ }
 
- template <class T>
- hash_table<T>::hash_table(std::size_t num_buckets,
- hasher const& hf, key_equal const& eq, node_allocator const& a)
- : buckets(a, next_prime(num_buckets)),
- base(hf, eq),
- size_(),
- mlf_(1.0f),
- cached_begin_bucket_(),
- max_load_(0)
- {
- }
+ void assign(table const& x)
+ {
+ assign(x, integral_constant<bool,
+ allocator_traits<node_allocator>::
+ propagate_on_container_copy_assignment::value>());
+ }
 
- // Copy Construct with allocator
+ void assign(table const& x, false_type)
+ {
+ table tmp(x, this->node_alloc());
+ this->swap(tmp, false_type());
+ }
 
- template <class T>
- hash_table<T>::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();
+ void assign(table const& x, true_type)
+ {
+ table tmp(x, x.node_alloc());
+ // Need to delete before setting the allocator so that buckets
+ // aren't deleted with the wrong allocator.
+ if(this->buckets_) this->delete_buckets();
+ // TODO: Can allocator assignment throw?
+ this->allocators_.assign(x.allocators_);
+ this->swap(tmp, false_type());
         }
- }
 
- // Move Construct
+ void move_assign(table& x)
+ {
+ move_assign(x, integral_constant<bool,
+ allocator_traits<node_allocator>::
+ propagate_on_container_move_assignment::value>());
+ }
+
+ void move_assign(table& x, true_type)
+ {
+ if(this->buckets_) this->delete_buckets();
+ this->allocators_.move_assign(x.allocators_);
+ move_assign_no_alloc(x);
+ }
 
- template <class T>
- hash_table<T>::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);
- }
+ void move_assign(table& x, false_type)
+ {
+ if(this->node_alloc() == x.node_alloc()) {
+ if(this->buckets_) this->delete_buckets();
+ move_assign_no_alloc(x);
+ }
+ else {
+ set_hash_functions<hasher, key_equal> new_func_this(*this, x);
 
- template <class T>
- hash_table<T>::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);
+ if (x.size_) {
+ buckets b(this->node_alloc(), x.min_buckets_for_size(x.size_));
+ buckets tmp(x, move_tag());
+ tmp.move_buckets_to(b);
+ b.swap(*this);
+ }
+ else {
+ this->clear();
+ }
+
+ this->mlf_ = x.mlf_;
+ if (this->buckets_) this->max_load_ = calculate_max_load();
+ new_func_this.commit();
+ }
         }
- else if(x.size_) {
- x.copy_buckets_to(*this);
- this->size_ = x.size_;
- this->init_buckets();
+
+ void move_assign_no_alloc(table& x)
+ {
+ set_hash_functions<hasher, key_equal> new_func_this(*this, x);
+ // No throw from here.
+ this->move_buckets_from(x);
+ this->mlf_ = x.mlf_;
+ this->max_load_ = x.max_load_;
+ new_func_this.commit();
         }
- }
 
- template <class T>
- hash_table<T>& hash_table<T>::operator=(
- hash_table const& x)
- {
- hash_table tmp(x, this->node_alloc());
- this->fast_swap(tmp);
- return *this;
- }
+ ////////////////////////////////////////////////////////////////////////
+ // Swap & Move
 
- ////////////////////////////////////////////////////////////////////////////
- // Swap & Move
-
- // Swap
- //
- // Strong exception safety
- //
- // Can throw if hash or predicate object's copy constructor throws
- // or if allocators are unequal.
-
- template <class T>
- inline void hash_table<T>::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_);
- }
+ void swap(table& x)
+ {
+ swap(x, integral_constant<bool,
+ allocator_traits<node_allocator>::
+ propagate_on_container_swap::value>());
+ }
 
- template <class T>
- inline void hash_table<T>::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.
+ // Only swaps the allocators if Propagate::value
+ template <typename Propagate>
+ void swap(table& x, Propagate p)
         {
             set_hash_functions<hasher, key_equal> op1(*this, x);
             set_hash_functions<hasher, key_equal> op2(x, *this);
+ // I think swap can throw if Propagate::value,
+ // since the allocators' swap can throw. Not sure though.
+ this->buckets::swap(x, p);
+ std::swap(this->mlf_, x.mlf_);
+ std::swap(this->max_load_, x.max_load_);
             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 <class T>
- inline void hash_table<T>::slow_swap(hash_table& x)
- {
- if(this == &x) return;
 
+ // Swap everything but the allocators, and the functions objects.
+ void swap_contents(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<hasher, key_equal> op1(*this, x);
- set_hash_functions<hasher, key_equal> 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();
+ this->buckets::swap(x, false_type());
+ std::swap(this->mlf_, x.mlf_);
+ std::swap(this->max_load_, x.max_load_);
         }
-
- std::swap(this->size_, x.size_);
 
- if(this->buckets_) this->init_buckets();
- if(x.buckets_) x.init_buckets();
- }
+ ////////////////////////////////////////////////////////////////////////
+ // Key methods
 
- template <class T>
- void hash_table<T>::swap(hash_table& x)
- {
- if(this->node_alloc() == x.node_alloc()) {
- if(this != &x) this->fast_swap(x);
+ std::size_t count(key_type const& k) const
+ {
+ if(!this->size_) return 0;
+ return node::group_count(find_node(k));
         }
- else {
- this->slow_swap(x);
+
+ value_type& at(key_type const& k) const
+ {
+ if (this->size_) {
+ node_ptr it = find_node(k);
+ if (BOOST_UNORDERED_BORLAND_BOOL(it))
+ return node::get_value(it);
+ }
+
+ ::boost::throw_exception(
+ std::out_of_range("Unable to find key in unordered_map."));
         }
- }
 
+ iterator_pair equal_range(key_type const& k) const
+ {
+ if(!this->size_)
+ return iterator_pair(node_ptr(), node_ptr());
     
- // 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.
+ node_ptr ptr = find_node(k);
+ return iterator_pair(ptr, !ptr ? ptr : node::next_group(ptr));
+ }
 
- template <class T>
- void hash_table<T>::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<hasher, key_equal> 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;
+ // Erase
+ //
+ // no throw
+
+ std::size_t erase_key(key_type const& k)
+ {
+ if(!this->size_) return 0;
+
+ std::size_t hash = this->hash_function()(k);
+ std::size_t bucket_index = hash % this->bucket_count_;
+ bucket_ptr bucket = this->get_bucket(bucket_index);
+
+ node_ptr prev = bucket->next_;
+ if (!prev) return 0;
+
+ for (;;)
+ {
+ if (!prev->next_) return 0;
+ std::size_t node_hash = node::get_hash(prev->next_);
+ if (node_hash % this->bucket_count_ != bucket_index)
+ return 0;
+ if (node_hash == hash &&
+ this->key_eq()(k, get_key(node::get_value(prev->next_))))
+ break;
+ prev = node::next_group2(prev);
+ }
+
+ node_ptr pos = prev->next_;
+ node_ptr end = node::next_group(pos);
+ prev->next_ = end;
+ this->fix_buckets(bucket, prev, end);
+ return this->delete_nodes(pos, end);
         }
- 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 and rehash
+
+ bool reserve_for_insert(std::size_t);
+ void rehash(std::size_t);
+ };
     
     ////////////////////////////////////////////////////////////////////////////
     // Reserve & Rehash
 
     // basic exception safety
     template <class T>
- inline void hash_table<T>::create_for_insert(std::size_t size)
+ inline bool table<T>::reserve_for_insert(std::size_t size)
     {
- this->bucket_count_ = (std::max)(this->bucket_count_,
- this->min_buckets_for_size(size));
- this->create_buckets();
- this->init_buckets();
- }
-
- // basic exception safety
- template <class T>
- inline bool hash_table<T>::reserve_for_insert(std::size_t size)
- {
- if(size >= max_load_) {
+ if (!this->buckets_) {
+ std::size_t old_bucket_count = this->bucket_count_;
+ this->bucket_count_ = (std::max)(this->bucket_count_,
+ this->min_buckets_for_size(size));
+ this->create_buckets();
+ this->max_load_ = calculate_max_load();
+ return old_bucket_count != this->bucket_count_;
+ }
+ else if(size >= max_load_) {
             std::size_t num_buckets
                 = this->min_buckets_for_size((std::max)(size,
                     this->size_ + (this->size_ >> 1)));
- if(num_buckets != this->bucket_count_) {
- rehash_impl(num_buckets);
+ if (num_buckets != this->bucket_count_) {
+ this->rehash_impl(num_buckets);
+ this->max_load_ = calculate_max_load();
                 return true;
             }
         }
@@ -450,7 +440,7 @@
     // strong otherwise.
 
     template <class T>
- inline void hash_table<T>::rehash(std::size_t min_buckets)
+ void table<T>::rehash(std::size_t min_buckets)
     {
         using namespace std;
 
@@ -462,317 +452,301 @@
             // no throw:
             min_buckets = next_prime((std::max)(min_buckets,
                     double_to_size_t(floor(this->size_ / (double) mlf_)) + 1));
- if(min_buckets != this->bucket_count_) rehash_impl(min_buckets);
- }
- }
-
- // if hash function throws, basic exception safety
- // strong otherwise
-
- template <class T>
- void hash_table<T>
- ::rehash_impl(std::size_t num_buckets)
- {
- 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(), num_buckets);
- dst.create_buckets();
-
- buckets src(this->node_alloc(), this->bucket_count_);
- src.swap(*this);
- this->size_ = 0;
-
- for(bucket_ptr bucket = this->cached_begin_bucket_;
- bucket != end; ++bucket)
- {
- node_ptr group = bucket->next_;
- while(group) {
- // Move the first group of equivalent nodes in bucket to dst.
-
- // This next line throws iff the hash function throws.
- bucket_ptr dst_bucket = dst.bucket_ptr_from_hash(
- hf(get_key_from_ptr(group)));
-
- node_ptr& next_group = node::next_group(group);
- bucket->next_ = next_group;
- next_group = dst_bucket->next_;
- dst_bucket->next_ = group;
- group = bucket->next_;
+ if(min_buckets != this->bucket_count_) {
+ this->rehash_impl(min_buckets);
+ this->max_load_ = calculate_max_load();
             }
         }
-
- // 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.
+ // types
+ //
+ // This is used to convieniently pass around a container's typedefs
+ // without having 7 template parameters.
 
- template <class T>
- void hash_table<T>
- ::copy_buckets_to(buckets& dst) const
+ template <class K, class V, class H, class P, class A, class E, bool Unique>
+ struct types
     {
- BOOST_ASSERT(this->buckets_ && !dst.buckets_);
-
- hasher const& hf = this->hash_function();
- bucket_ptr end = this->get_bucket(this->bucket_count_);
-
- node_constructor a(dst);
- dst.create_buckets();
-
- // no throw:
- for(bucket_ptr i = this->cached_begin_bucket_; i != end; ++i) {
- // no throw:
- for(node_ptr it = i->next_; it;) {
- // hash function can throw.
- bucket_ptr dst_bucket = dst.bucket_ptr_from_hash(
- hf(get_key_from_ptr(it)));
- // throws, strong
-
- node_ptr group_end = node::next_group(it);
-
- a.construct(node::get_value(it));
- node_ptr n = a.release();
- node::add_to_bucket(n, *dst_bucket);
+ public:
+ typedef K key_type;
+ typedef V value_type;
+ typedef H hasher;
+ typedef P key_equal;
+ typedef A value_allocator;
+ typedef E extractor;
         
- 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
+ typedef ::boost::unordered::detail::node_constructor<value_allocator, Unique> node_constructor;
+ typedef ::boost::unordered::detail::buckets<value_allocator, Unique> buckets;
+ typedef ::boost::unordered::detail::functions<hasher, key_equal> functions;
+
+ typedef BOOST_DEDUCED_TYPENAME buckets::node node;
+ typedef BOOST_DEDUCED_TYPENAME buckets::bucket bucket;
+ typedef BOOST_DEDUCED_TYPENAME buckets::node_ptr node_ptr;
+ typedef BOOST_DEDUCED_TYPENAME buckets::bucket_ptr bucket_ptr;
+ typedef BOOST_DEDUCED_TYPENAME buckets::node_allocator node_allocator;
+
+ typedef std::pair<node_ptr, node_ptr> iterator_pair;
+ };
+}}}
 
- // strong exception safety
+namespace boost { namespace unordered { namespace iterator_detail {
 
- // count
+ // Iterators
     //
- // strong exception safety, no side effects
+ // all no throw
 
- template <class T>
- std::size_t hash_table<T>::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;
- }
+ template <class A, bool Unique> class iterator;
+ template <class A, bool Unique> class c_iterator;
+ template <class A, bool Unique> class l_iterator;
+ template <class A, bool Unique> class cl_iterator;
 
- // find
+ // Local Iterators
     //
- // strong exception safety, no side effects
- template <class T>
- BOOST_DEDUCED_TYPENAME T::iterator_base
- hash_table<T>::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 <class T>
- template <class Key, class Hash, class Pred>
- BOOST_DEDUCED_TYPENAME T::iterator_base hash_table<T>::find(Key const& k,
- Hash const& h, Pred const& eq) const
- {
- if(!this->size_) return this->end();
-
- bucket_ptr bucket = this->get_bucket(h(k) % this->bucket_count_);
- node_ptr it = find_iterator(bucket, k, eq);
+ // all no throw
 
- if (BOOST_UNORDERED_BORLAND_BOOL(it))
- return iterator_base(bucket, it);
- else
- return this->end();
- }
+ template <class A, bool Unique>
+ class l_iterator
+ : public ::boost::iterator <
+ std::forward_iterator_tag,
+ BOOST_DEDUCED_TYPENAME boost::unordered::detail::allocator_traits<A>::value_type,
+ std::ptrdiff_t,
+ BOOST_DEDUCED_TYPENAME boost::unordered::detail::allocator_traits<A>::pointer,
+ BOOST_DEDUCED_TYPENAME boost::unordered::detail::allocator_traits<A>::value_type&>
+ {
+ public:
+ typedef BOOST_DEDUCED_TYPENAME boost::unordered::detail::allocator_traits<A>::value_type value_type;
+
+ private:
+ typedef ::boost::unordered::detail::buckets<A, Unique> buckets;
+ typedef BOOST_DEDUCED_TYPENAME buckets::node_ptr node_ptr;
+ typedef BOOST_DEDUCED_TYPENAME buckets::node node;
+ typedef cl_iterator<A, Unique> const_local_iterator;
 
- template <class T>
- BOOST_DEDUCED_TYPENAME T::value_type&
- hash_table<T>::at(key_type const& k) const
- {
- if(!this->size_)
- boost::throw_exception(std::out_of_range("Unable to find key in unordered_map."));
-
- bucket_ptr bucket = this->get_bucket(this->bucket_index(k));
- node_ptr it = find_iterator(bucket, k);
-
- if (!it)
- boost::throw_exception(std::out_of_range("Unable to find key in unordered_map."));
+ friend class cl_iterator<A, Unique>;
+
+ node_ptr ptr_;
+ std::size_t bucket_;
+ std::size_t bucket_count_;
+
+ public:
+ l_iterator() : ptr_() {}
+ l_iterator(node_ptr x, std::size_t b, std::size_t c)
+ : ptr_(x), bucket_(b), bucket_count_(c) {}
+ BOOST_DEDUCED_TYPENAME boost::unordered::detail::allocator_traits<A>::value_type& operator*() const {
+ return node::get_value(ptr_);
+ }
+ value_type* operator->() const {
+ return node::get_value_ptr(ptr_);
+ }
+ l_iterator& operator++() {
+ ptr_ = ptr_->next_;
+ if (ptr_ && node::get_hash(ptr_) % bucket_count_ != bucket_)
+ ptr_ = node_ptr();
+ return *this;
+ }
+ l_iterator operator++(int) {
+ l_iterator tmp(*this);
+ ptr_ = ptr_->next_;
+ if (ptr_ && node::get_hash(ptr_) % bucket_count_ != bucket_)
+ ptr_ = node_ptr();
+ return tmp;
+ }
+ bool operator==(l_iterator x) const {
+ return ptr_ == x.ptr_;
+ }
+ bool operator==(const_local_iterator x) const {
+ return ptr_ == x.ptr_;
+ }
+ bool operator!=(l_iterator x) const {
+ return ptr_ != x.ptr_;
+ }
+ bool operator!=(const_local_iterator x) const {
+ return ptr_ != x.ptr_;
+ }
+ };
+
+ template <class A, bool Unique>
+ class cl_iterator
+ : public ::boost::iterator <
+ std::forward_iterator_tag,
+ BOOST_DEDUCED_TYPENAME boost::unordered::detail::allocator_traits<A>::value_type,
+ std::ptrdiff_t,
+ BOOST_DEDUCED_TYPENAME boost::unordered::detail::allocator_traits<A>::const_pointer,
+ BOOST_DEDUCED_TYPENAME boost::unordered::detail::allocator_traits<A>::value_type const& >
+ {
+ public:
+ typedef BOOST_DEDUCED_TYPENAME boost::unordered::detail::allocator_traits<A>::value_type value_type;
+
+ private:
+ typedef ::boost::unordered::detail::buckets<A, Unique> buckets;
+ typedef BOOST_DEDUCED_TYPENAME buckets::node_ptr node_ptr;
+ typedef BOOST_DEDUCED_TYPENAME buckets::node node;
+ typedef l_iterator<A, Unique> local_iterator;
+
+ friend class l_iterator<A, Unique>;
+
+ node_ptr ptr_;
+ std::size_t bucket_;
+ std::size_t bucket_count_;
+
+ public:
+ cl_iterator() : ptr_() {}
+ cl_iterator(node_ptr x, std::size_t b, std::size_t c)
+ : ptr_(x), bucket_(b), bucket_count_(c) {}
+ cl_iterator(local_iterator x)
+ : ptr_(x.ptr_), bucket_(x.bucket_), bucket_count_(x.bucket_count_)
+ {}
+ BOOST_DEDUCED_TYPENAME boost::unordered::detail::allocator_traits<A>::value_type const&
+ operator*() const {
+ return node::get_value(ptr_);
+ }
+ value_type const* operator->() const {
+ return node::get_value_ptr(ptr_);
+ }
+ cl_iterator& operator++() {
+ ptr_ = ptr_->next_;
+ if (ptr_ && node::get_hash(ptr_) % bucket_count_ != bucket_)
+ ptr_ = node_ptr();
+ return *this;
+ }
+ cl_iterator operator++(int) {
+ cl_iterator tmp(*this);
+ ptr_ = ptr_->next_;
+ if (ptr_ && node::get_hash(ptr_) % bucket_count_ != bucket_)
+ ptr_ = node_ptr();
+ return tmp;
+ }
+ bool operator==(local_iterator x) const {
+ return ptr_ == x.ptr_;
+ }
+ bool operator==(cl_iterator x) const {
+ return ptr_ == x.ptr_;
+ }
+ bool operator!=(local_iterator x) const {
+ return ptr_ != x.ptr_;
+ }
+ bool operator!=(cl_iterator x) const {
+ return ptr_ != x.ptr_;
+ }
+ };
+
+ template <class A, bool Unique>
+ class iterator
+ : public ::boost::iterator <
+ std::forward_iterator_tag,
+ BOOST_DEDUCED_TYPENAME boost::unordered::detail::allocator_traits<A>::value_type,
+ std::ptrdiff_t,
+ BOOST_DEDUCED_TYPENAME boost::unordered::detail::allocator_traits<A>::pointer,
+ BOOST_DEDUCED_TYPENAME boost::unordered::detail::allocator_traits<A>::value_type& >
+ {
+ public:
+ typedef BOOST_DEDUCED_TYPENAME boost::unordered::detail::allocator_traits<A>::value_type value_type;
+
+ private:
+ typedef ::boost::unordered::detail::buckets<A, Unique> buckets;
+ typedef BOOST_DEDUCED_TYPENAME buckets::node node;
+ typedef BOOST_DEDUCED_TYPENAME buckets::node_ptr node_ptr;
+ typedef c_iterator<A, Unique> const_iterator;
+ friend class c_iterator<A, Unique>;
+ node_ptr node_;
+
+ public:
+
+ iterator() : node_() {}
+ explicit iterator(node_ptr const& x) : node_(x) {}
+ BOOST_DEDUCED_TYPENAME boost::unordered::detail::allocator_traits<A>::value_type& operator*() const {
+ return node::get_value(node_);
+ }
+ value_type* operator->() const {
+ return &node::get_value(node_);
+ }
+ iterator& operator++() {
+ node_ = node_->next_; return *this;
+ }
+ iterator operator++(int) {
+ iterator tmp(node_); node_ = node_->next_; return tmp;
+ }
+ bool operator==(iterator const& x) const {
+ return node_ == x.node_;
+ }
+ bool operator==(const_iterator const& x) const {
+ return node_ == x.node_;
+ }
+ bool operator!=(iterator const& x) const {
+ return node_ != x.node_;
+ }
+ bool operator!=(const_iterator const& x) const {
+ return node_ != x.node_;
+ }
+ };
+
+ template <class A, bool Unique>
+ class c_iterator
+ : public ::boost::iterator <
+ std::forward_iterator_tag,
+ BOOST_DEDUCED_TYPENAME boost::unordered::detail::allocator_traits<A>::value_type,
+ std::ptrdiff_t,
+ BOOST_DEDUCED_TYPENAME boost::unordered::detail::allocator_traits<A>::const_pointer,
+ BOOST_DEDUCED_TYPENAME boost::unordered::detail::allocator_traits<A>::value_type const& >
+ {
+ public:
+ typedef BOOST_DEDUCED_TYPENAME boost::unordered::detail::allocator_traits<A>::value_type value_type;
+
+ private:
+ typedef ::boost::unordered::detail::buckets<A, Unique> buckets;
+ typedef BOOST_DEDUCED_TYPENAME buckets::node node;
+ typedef BOOST_DEDUCED_TYPENAME buckets::node_ptr node_ptr;
+ typedef ::boost::unordered::iterator_detail::iterator<A, Unique>
+ iterator;
+ friend class ::boost::unordered::iterator_detail::iterator<A, Unique>;
+
+#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
+ template <class K, class T, class H, class P, class A2>
+ friend class ::boost::unordered::unordered_map;
+ template <class K, class T, class H, class P, class A2>
+ friend class ::boost::unordered::unordered_multimap;
+ template <class T, class H, class P, class A2>
+ friend class ::boost::unordered::unordered_set;
+ template <class T, class H, class P, class A2>
+ friend class ::boost::unordered::unordered_multiset;
+#else
+ public:
+#endif
 
- return node::get_value(it);
- }
+ node_ptr node_;
 
- // equal_range
- //
- // strong exception safety, no side effects
- template <class T>
- BOOST_DEDUCED_TYPENAME T::iterator_pair
- hash_table<T>::equal_range(key_type const& k) const
- {
- if(!this->size_)
- return iterator_pair(this->end(), this->end());
+ public:
 
- 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);
+ c_iterator() : node_() {}
+ explicit c_iterator(node_ptr const& x) : node_(x) {}
+ c_iterator(iterator const& x) : node_(x.node_) {}
+ BOOST_DEDUCED_TYPENAME boost::unordered::detail::allocator_traits<A>::value_type const& operator*() const {
+ return node::get_value(node_);
         }
- else {
- return iterator_pair(this->end(), this->end());
+ value_type const* operator->() const {
+ return &node::get_value(node_);
         }
- }
-
- ////////////////////////////////////////////////////////////////////////////
- // Erase methods
-
- template <class T>
- void hash_table<T>::clear()
- {
- if(!this->size_) return;
-
- bucket_ptr end = this->get_bucket(this->bucket_count_);
- for(bucket_ptr begin = this->buckets_; begin != end; ++begin) {
- this->clear_bucket(begin);
+ c_iterator& operator++() {
+ node_ = node_->next_; return *this;
         }
-
- this->size_ = 0;
- this->cached_begin_bucket_ = end;
- }
-
- template <class T>
- inline std::size_t hash_table<T>::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 <class T>
- std::size_t hash_table<T>::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 <class T>
- void hash_table<T>::erase(iterator_base r)
- {
- BOOST_ASSERT(r.node_);
- --this->size_;
- node::unlink_node(*r.bucket_, r.node_);
- this->delete_node(r.node_);
- // r has been invalidated but its bucket is still valid
- this->recompute_begin_bucket(r.bucket_);
- }
-
- template <class T>
- BOOST_DEDUCED_TYPENAME T::iterator_base
- hash_table<T>::erase_return_iterator(iterator_base r)
- {
- BOOST_ASSERT(r.node_);
- iterator_base next = r;
- next.increment();
- --this->size_;
- node::unlink_node(*r.bucket_, r.node_);
- this->delete_node(r.node_);
- // r has been invalidated but its bucket is still valid
- this->recompute_begin_bucket(r.bucket_, next.bucket_);
- return next;
- }
-
- template <class T>
- BOOST_DEDUCED_TYPENAME T::iterator_base
- hash_table<T>::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);
- }
+ c_iterator operator++(int) {
+ c_iterator tmp(node_); node_ = node_->next_; return tmp;
         }
-
- return r2;
- }
-
- template <class T>
- BOOST_DEDUCED_TYPENAME hash_table<T>::iterator_base
- hash_table<T>::emplace_empty_impl_with_node(
- node_constructor& a, std::size_t size)
- {
- key_type const& k = get_key(a.value());
- std::size_t hash_value = this->hash_function()(k);
- if(this->buckets_) this->reserve_for_insert(size);
- else this->create_for_insert(size);
- bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value);
- node_ptr n = a.release();
- node::add_to_bucket(n, *bucket);
- ++this->size_;
- this->cached_begin_bucket_ = bucket;
- return iterator_base(bucket, n);
- }
-}}
+ bool operator==(iterator const& x) const {
+ return node_ == x.node_;
+ }
+ bool operator==(c_iterator const& x) const {
+ return node_ == x.node_;
+ }
+ bool operator!=(iterator const& x) const {
+ return node_ != x.node_;
+ }
+ bool operator!=(c_iterator const& x) const {
+ return node_ != x.node_;
+ }
+ };
+}}}
 
 #endif

Modified: branches/release/boost/unordered/detail/unique.hpp
==============================================================================
--- branches/release/boost/unordered/detail/unique.hpp (original)
+++ branches/release/boost/unordered/detail/unique.hpp 2011-08-21 15:19:12 EDT (Sun, 21 Aug 2011)
@@ -1,19 +1,18 @@
 
 // Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
-// Copyright (C) 2005-2010 Daniel James
+// Copyright (C) 2005-2011 Daniel James
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 
 #ifndef BOOST_UNORDERED_DETAIL_UNIQUE_HPP_INCLUDED
 #define BOOST_UNORDERED_DETAIL_UNIQUE_HPP_INCLUDED
 
-#include <boost/unordered/detail/table.hpp>
 #include <boost/unordered/detail/extract_key.hpp>
 
-namespace boost { namespace unordered_detail {
+namespace boost { namespace unordered { namespace detail {
 
     template <class T>
- class hash_unique_table : public T::table
+ class unique_table : public T::table_base
     {
     public:
         typedef BOOST_DEDUCED_TYPENAME T::hasher hasher;
@@ -21,493 +20,398 @@
         typedef BOOST_DEDUCED_TYPENAME T::value_allocator value_allocator;
         typedef BOOST_DEDUCED_TYPENAME T::key_type key_type;
         typedef BOOST_DEDUCED_TYPENAME T::value_type value_type;
- typedef BOOST_DEDUCED_TYPENAME T::table table;
+ typedef BOOST_DEDUCED_TYPENAME T::table_base table_base;
         typedef BOOST_DEDUCED_TYPENAME T::node_constructor node_constructor;
+ typedef BOOST_DEDUCED_TYPENAME T::node_allocator node_allocator;
 
         typedef BOOST_DEDUCED_TYPENAME T::node node;
         typedef BOOST_DEDUCED_TYPENAME T::node_ptr node_ptr;
         typedef BOOST_DEDUCED_TYPENAME T::bucket_ptr bucket_ptr;
- typedef BOOST_DEDUCED_TYPENAME T::iterator_base iterator_base;
         typedef BOOST_DEDUCED_TYPENAME T::extractor extractor;
         
- typedef std::pair<iterator_base, bool> emplace_return;
+ typedef std::pair<node_ptr, bool> emplace_return;
 
         // Constructors
 
- hash_unique_table(std::size_t n, hasher const& hf, key_equal const& eq,
+ unique_table(std::size_t n, hasher const& hf, key_equal const& eq,
             value_allocator const& a)
- : table(n, hf, eq, a) {}
- hash_unique_table(hash_unique_table const& x)
- : 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,
+ : table_base(n, hf, eq, a) {}
+ unique_table(unique_table const& x)
+ : table_base(x,
+ allocator_traits<node_allocator>::
+ select_on_container_copy_construction(x.node_alloc())) {}
+ unique_table(unique_table const& x, value_allocator const& a)
+ : table_base(x, a) {}
+ unique_table(unique_table& x, move_tag m)
+ : table_base(x, m) {}
+ unique_table(unique_table& x, value_allocator const& a,
             move_tag m)
- : table(x, a, m) {}
- ~hash_unique_table() {}
-
- // Insert methods
-
- emplace_return emplace_impl_with_node(node_constructor& a);
- value_type& operator[](key_type const& k);
+ : table_base(x, a, m) {}
+ ~unique_table() {}
 
         // 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<class... Args>
- emplace_return emplace(Args&&... args);
- template<class... Args>
- emplace_return emplace_impl(key_type const& k, Args&&... args);
- template<class... Args>
- emplace_return emplace_impl(no_key, Args&&... args);
- template<class... Args>
- emplace_return emplace_empty_impl(Args&&... args);
-#else
-
-#define BOOST_UNORDERED_INSERT_IMPL(z, n, _) \
- template <BOOST_UNORDERED_TEMPLATE_ARGS(z, n)> \
- emplace_return emplace( \
- BOOST_UNORDERED_FUNCTION_PARAMS(z, n)); \
- template <BOOST_UNORDERED_TEMPLATE_ARGS(z, n)> \
- emplace_return emplace_impl(key_type const& k, \
- BOOST_UNORDERED_FUNCTION_PARAMS(z, n)); \
- template <BOOST_UNORDERED_TEMPLATE_ARGS(z, n)> \
- emplace_return emplace_impl(no_key, \
- BOOST_UNORDERED_FUNCTION_PARAMS(z, n)); \
- template <BOOST_UNORDERED_TEMPLATE_ARGS(z, n)> \
- emplace_return emplace_empty_impl( \
- 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
-
- // if hash function throws, or inserting > 1 element, basic exception
- // safety strong otherwise
- template <class InputIt>
- void insert_range(InputIt i, InputIt j);
- template <class InputIt>
- void insert_range_impl(key_type const&, InputIt i, InputIt j);
- template <class InputIt>
- void insert_range_impl2(node_constructor&, key_type const&, InputIt i, InputIt j);
- template <class InputIt>
- void insert_range_impl(no_key, InputIt i, InputIt j);
- };
-
- template <class H, class P, class A>
- struct set : public types<
- BOOST_DEDUCED_TYPENAME A::value_type,
- BOOST_DEDUCED_TYPENAME A::value_type,
- H, P, A,
- set_extractor<BOOST_DEDUCED_TYPENAME A::value_type>,
- ungrouped>
- {
- typedef hash_unique_table<set<H, P, A> > impl;
- typedef hash_table<set<H, P, A> > table;
- };
-
- template <class K, class H, class P, class A>
- struct map : public types<
- K, BOOST_DEDUCED_TYPENAME A::value_type,
- H, P, A,
- map_extractor<K, BOOST_DEDUCED_TYPENAME A::value_type>,
- ungrouped>
- {
- typedef hash_unique_table<map<K, H, P, A> > impl;
- typedef hash_table<map<K, H, P, A> > table;
- };
-
- ////////////////////////////////////////////////////////////////////////////
- // Equality
-
- template <class T>
- bool hash_unique_table<T>
- ::equals(hash_unique_table<T> 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)
+ bool equals(unique_table const& other) const
         {
- node_ptr it1 = i->next_;
- while(BOOST_UNORDERED_BORLAND_BOOL(it1))
+ if(this->size_ != other.size_) return false;
+ if(!this->size_) return true;
+
+ for(node_ptr n1 = this->get_bucket(this->bucket_count_)->next_;
+ n1; n1 = n1->next_)
             {
- node_ptr it2 = other.find_iterator(this->get_key_from_ptr(it1));
- if(!BOOST_UNORDERED_BORLAND_BOOL(it2)) return false;
- if(!extractor::compare_mapped(
- node::get_value(it1), node::get_value(it2)))
+ node_ptr n2 = other.find_matching_node(n1);
+ if(!n2 || node::get_value(n1) != node::get_value(n2))
                     return false;
- it1 = it1->next_;
             }
+
+ return true;
         }
 
- return true;
- }
-
- ////////////////////////////////////////////////////////////////////////////
- // A convenience method for adding nodes.
-
- template <class T>
- inline BOOST_DEDUCED_TYPENAME hash_unique_table<T>::node_ptr
- hash_unique_table<T>::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 <class T>
- BOOST_DEDUCED_TYPENAME hash_unique_table<T>::value_type&
- hash_unique_table<T>::operator[](key_type const& k)
- {
- typedef BOOST_DEDUCED_TYPENAME value_type::second_type mapped_type;
+ ////////////////////////////////////////////////////////////////////////
+ // A convenience method for adding nodes.
 
- 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 add_node(
+ node_constructor& a,
+ std::size_t bucket_index,
+ std::size_t hash)
+ {
+ bucket_ptr b = this->get_bucket(bucket_index);
+ node_ptr n = a.release();
+ node::set_hash(n, hash);
+
+ if (!b->next_)
+ {
+ bucket_ptr start_node = this->get_bucket(this->bucket_count_);
+
+ if (start_node->next_) {
+ this->buckets_[
+ node::get_hash(start_node->next_) % this->bucket_count_
+ ].next_ = n;
+ }
+
+ b->next_ = start_node;
+ n->next_ = start_node->next_;
+ start_node->next_ = n;
+ }
+ else
+ {
+ n->next_ = b->next_->next_;
+ b->next_->next_ = n;
+ }
+
+ ++this->size_;
+ return n;
         }
 
- node_ptr pos = this->find_iterator(bucket, k);
+ ////////////////////////////////////////////////////////////////////////////
+ // Insert methods
 
- if (BOOST_UNORDERED_BORLAND_BOOL(pos)) {
- return node::get_value(pos);
- }
- else {
- // Side effects only in this block.
+ // if hash function throws, basic exception safety
+ // strong otherwise
 
+ value_type& operator[](key_type const& k)
+ {
+ typedef BOOST_DEDUCED_TYPENAME value_type::second_type mapped_type;
+
+ std::size_t hash = this->hash_function()(k);
+ std::size_t bucket_index = hash % this->bucket_count_;
+ node_ptr pos = this->find_node(bucket_index, hash, k);
+
+ if (BOOST_UNORDERED_BORLAND_BOOL(pos)) {
+ return node::get_value(pos);
+ }
+
             // Create the node before rehashing in case it throws an
             // exception (need strong safety in such a case).
             node_constructor a(*this);
             a.construct_pair(k, (mapped_type*) 0);
-
+
             // reserve has basic exception safety if the hash function
             // throws, strong otherwise.
             if(this->reserve_for_insert(this->size_ + 1))
- bucket = this->bucket_ptr_from_hash(hash_value);
-
+ bucket_index = hash % this->bucket_count_;
+
             // Nothing after this point can throw.
-
- return node::get_value(add_node(a, bucket));
+
+ return node::get_value(add_node(a, bucket_index, hash));
         }
- }
 
- template <class T>
- inline BOOST_DEDUCED_TYPENAME hash_unique_table<T>::emplace_return
- hash_unique_table<T>::emplace_impl_with_node(node_constructor& a)
- {
- // No side effects in this initial code
- key_type const& k = this->get_key(a.value());
- std::size_t hash_value = this->hash_function()(k);
- bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value);
- node_ptr pos = this->find_iterator(bucket, k);
-
- if (BOOST_UNORDERED_BORLAND_BOOL(pos)) {
- // Found an existing key, return it (no throw).
- return emplace_return(iterator_base(bucket, pos), false);
- } else {
+ emplace_return emplace_impl_with_node(node_constructor& a)
+ {
+ // No side effects in this initial code
+ key_type const& k = this->get_key(a.value());
+ std::size_t hash = this->hash_function()(k);
+ std::size_t bucket_index = hash % this->bucket_count_;
+ node_ptr pos = this->find_node(bucket_index, hash, k);
+
+ if (BOOST_UNORDERED_BORLAND_BOOL(pos)) {
+ // Found an existing key, return it (no throw).
+ return emplace_return(pos, false);
+ }
+
             // reserve has basic exception safety if the hash function
             // throws, strong otherwise.
             if(this->reserve_for_insert(this->size_ + 1))
- bucket = this->bucket_ptr_from_hash(hash_value);
-
+ bucket_index = hash % this->bucket_count_;
+
             // Nothing after this point can throw.
+
+ return emplace_return(add_node(a, bucket_index, hash), true);
+ }
 
- return emplace_return(
- iterator_base(bucket, add_node(a, bucket)),
- true);
+ emplace_return insert(value_type const& v)
+ {
+ key_type const& k = extractor::extract(v);
+ std::size_t hash = this->hash_function()(k);
+ std::size_t bucket_index = hash % this->bucket_count_;
+ node_ptr pos = this->find_node(bucket_index, hash, k);
+
+ if (BOOST_UNORDERED_BORLAND_BOOL(pos)) {
+ // Found an existing key, return it (no throw).
+ return emplace_return(pos, false);
+ }
+
+ // Isn't in table, add to bucket.
+
+ // Create the node before rehashing in case it throws an
+ // exception (need strong safety in such a case).
+ node_constructor a(*this);
+ a.construct(v);
+
+ // reserve has basic exception safety if the hash function
+ // throws, strong otherwise.
+ if(this->reserve_for_insert(this->size_ + 1))
+ bucket_index = hash % this->bucket_count_;
+
+ // Nothing after this point can throw.
+
+ return emplace_return(add_node(a, bucket_index, hash), true);
         }
- }
 
-#if defined(BOOST_UNORDERED_STD_FORWARD)
 
- template <class T>
- template<class... Args>
- inline BOOST_DEDUCED_TYPENAME hash_unique_table<T>::emplace_return
- hash_unique_table<T>::emplace_impl(key_type const& k,
- Args&&... args)
- {
- // No side effects in this initial code
- std::size_t hash_value = this->hash_function()(k);
- bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value);
- node_ptr pos = this->find_iterator(bucket, k);
-
- if (BOOST_UNORDERED_BORLAND_BOOL(pos)) {
- // Found an existing key, return it (no throw).
- return emplace_return(iterator_base(bucket, pos), false);
+#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
 
- } else {
+ template<class... Args>
+ emplace_return emplace(Args&&... args)
+ {
+ return emplace_impl(
+ extractor::extract(std::forward<Args>(args)...),
+ std::forward<Args>(args)...);
+ }
+
+ template<class... Args>
+ emplace_return emplace_impl(key_type const& k, Args&&... args)
+ {
+ // No side effects in this initial code
+ std::size_t hash = this->hash_function()(k);
+ std::size_t bucket_index = hash % this->bucket_count_;
+ node_ptr pos = this->find_node(bucket_index, hash, k);
+
+ if (BOOST_UNORDERED_BORLAND_BOOL(pos)) {
+ // Found an existing key, return it (no throw).
+ return emplace_return(pos, false);
+ }
+
             // Doesn't already exist, add to bucket.
             // Side effects only in this block.
-
+
             // Create the node before rehashing in case it throws an
             // exception (need strong safety in such a case).
             node_constructor a(*this);
             a.construct(std::forward<Args>(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);
-
+ bucket_index = hash % this->bucket_count_;
+
             // Nothing after this point can throw.
-
- return emplace_return(
- iterator_base(bucket, add_node(a, bucket)),
- true);
+
+ return emplace_return(add_node(a, bucket_index, hash), true);
         }
- }
-
- template <class T>
- template<class... Args>
- inline BOOST_DEDUCED_TYPENAME hash_unique_table<T>::emplace_return
- hash_unique_table<T>::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>(args)...);
- return emplace_impl_with_node(a);
- }
-
- template <class T>
- template<class... Args>
- inline BOOST_DEDUCED_TYPENAME hash_unique_table<T>::emplace_return
- hash_unique_table<T>::emplace_empty_impl(Args&&... args)
- {
- node_constructor a(*this);
- a.construct(std::forward<Args>(args)...);
- return emplace_return(this->emplace_empty_impl_with_node(a, 1), true);
- }
 
+ template<class... Args>
+ emplace_return emplace_impl(no_key, Args&&... args)
+ {
+ // Construct the node regardless - in order to get the key.
+ // It will be discarded if it isn't used
+ node_constructor a(*this);
+ a.construct(std::forward<Args>(args)...);
+ return emplace_impl_with_node(a);
+ }
 #else
 
-#define BOOST_UNORDERED_INSERT_IMPL(z, num_params, _) \
- template <class T> \
- template <BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params)> \
- inline BOOST_DEDUCED_TYPENAME \
- hash_unique_table<T>::emplace_return \
- hash_unique_table<T>::emplace_impl( \
- key_type const& k, \
- BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \
- { \
- std::size_t hash_value = this->hash_function()(k); \
- bucket_ptr bucket \
- = this->bucket_ptr_from_hash(hash_value); \
- node_ptr pos = this->find_iterator(bucket, k); \
- \
- if (BOOST_UNORDERED_BORLAND_BOOL(pos)) { \
- return emplace_return(iterator_base(bucket, pos), false); \
- } else { \
- node_constructor a(*this); \
- a.construct(BOOST_UNORDERED_CALL_PARAMS(z, num_params)); \
- \
- if(this->reserve_for_insert(this->size_ + 1)) \
- bucket = this->bucket_ptr_from_hash(hash_value); \
- \
- return emplace_return(iterator_base(bucket, \
- add_node(a, bucket)), true); \
- } \
- } \
- \
- template <class T> \
- template <BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params)> \
- inline BOOST_DEDUCED_TYPENAME \
- hash_unique_table<T>::emplace_return \
- hash_unique_table<T>:: \
- emplace_impl(no_key, \
- BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \
- { \
- node_constructor a(*this); \
- a.construct(BOOST_UNORDERED_CALL_PARAMS(z, num_params)); \
- return emplace_impl_with_node(a); \
- } \
- \
- template <class T> \
- template <BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params)> \
- inline BOOST_DEDUCED_TYPENAME \
- hash_unique_table<T>::emplace_return \
- hash_unique_table<T>:: \
- emplace_empty_impl( \
- BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \
- { \
- node_constructor a(*this); \
- a.construct(BOOST_UNORDERED_CALL_PARAMS(z, num_params)); \
- return emplace_return(this->emplace_empty_impl_with_node(a, 1), true); \
- }
-
- BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
- BOOST_UNORDERED_INSERT_IMPL, _)
-
-#undef BOOST_UNORDERED_INSERT_IMPL
-
-#endif
-
-#if defined(BOOST_UNORDERED_STD_FORWARD)
-
- // Emplace (unique keys)
- // (I'm using an overloaded emplace for both 'insert' and 'emplace')
-
- // if hash function throws, basic exception safety
- // strong otherwise
-
- template <class T>
- template<class... Args>
- BOOST_DEDUCED_TYPENAME hash_unique_table<T>::emplace_return
- hash_unique_table<T>::emplace(Args&&... args)
- {
- return this->size_ ?
- emplace_impl(
- extractor::extract(std::forward<Args>(args)...),
- std::forward<Args>(args)...) :
- emplace_empty_impl(std::forward<Args>(args)...);
- }
+ template <class Arg0>
+ emplace_return emplace(BOOST_FWD_REF(Arg0) arg0)
+ {
+ return emplace_impl(
+ extractor::extract(boost::forward<Arg0>(arg0)),
+ boost::forward<Arg0>(arg0));
+ }
 
-#else
+#define BOOST_UNORDERED_INSERT1_IMPL(z, n, _) \
+ template <BOOST_UNORDERED_TEMPLATE_ARGS(z, n)> \
+ emplace_return emplace( \
+ BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \
+ { \
+ return emplace_impl(extractor::extract(arg0, arg1), \
+ BOOST_UNORDERED_CALL_PARAMS(z, n)); \
+ }
 
- template <class T>
- template <class Arg0>
- BOOST_DEDUCED_TYPENAME hash_unique_table<T>::emplace_return
- hash_unique_table<T>::emplace(Arg0 const& arg0)
- {
- return this->size_ ?
- emplace_impl(extractor::extract(arg0), arg0) :
- emplace_empty_impl(arg0);
- }
-
-#define BOOST_UNORDERED_INSERT_IMPL(z, num_params, _) \
- template <class T> \
- template <BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params)> \
- BOOST_DEDUCED_TYPENAME hash_unique_table<T>::emplace_return \
- hash_unique_table<T>::emplace( \
- BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \
- { \
- return this->size_ ? \
- emplace_impl(extractor::extract(arg0, arg1), \
- BOOST_UNORDERED_CALL_PARAMS(z, num_params)) : \
- emplace_empty_impl( \
- BOOST_UNORDERED_CALL_PARAMS(z, num_params)); \
- }
+#define BOOST_UNORDERED_INSERT2_IMPL(z, n, _) \
+ template <BOOST_UNORDERED_TEMPLATE_ARGS(z, n)> \
+ emplace_return emplace_impl(key_type const& k, \
+ BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \
+ { \
+ std::size_t hash = this->hash_function()(k); \
+ std::size_t bucket_index = hash % this->bucket_count_; \
+ node_ptr pos = this->find_node(bucket_index, hash, k); \
+ \
+ if (BOOST_UNORDERED_BORLAND_BOOL(pos)) { \
+ return emplace_return(pos, false); \
+ } else { \
+ node_constructor a(*this); \
+ a.construct(BOOST_UNORDERED_CALL_PARAMS(z, n)); \
+ \
+ if(this->reserve_for_insert(this->size_ + 1)) \
+ bucket_index = hash % this->bucket_count_; \
+ \
+ return emplace_return( \
+ add_node(a, bucket_index, hash), \
+ true); \
+ } \
+ } \
+ \
+ template <BOOST_UNORDERED_TEMPLATE_ARGS(z, n)> \
+ emplace_return emplace_impl(no_key, \
+ BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \
+ { \
+ node_constructor a(*this); \
+ a.construct(BOOST_UNORDERED_CALL_PARAMS(z, n)); \
+ return emplace_impl_with_node(a); \
+ }
 
- BOOST_PP_REPEAT_FROM_TO(2, BOOST_UNORDERED_EMPLACE_LIMIT,
- BOOST_UNORDERED_INSERT_IMPL, _)
+ BOOST_PP_REPEAT_FROM_TO(2, BOOST_UNORDERED_EMPLACE_LIMIT,
+ BOOST_UNORDERED_INSERT1_IMPL, _)
+ BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
+ BOOST_UNORDERED_INSERT2_IMPL, _)
 
-#undef BOOST_UNORDERED_INSERT_IMPL
+#undef BOOST_UNORDERED_INSERT1_IMPL
+#undef BOOST_UNORDERED_INSERT2_IMPL
 
 #endif
-
- ////////////////////////////////////////////////////////////////////////////
- // Insert range methods
 
- template <class T>
- template <class InputIt>
- inline void hash_unique_table<T>::insert_range_impl2(
- node_constructor& a, key_type const& k, InputIt i, InputIt j)
- {
- // No side effects in this initial code
- std::size_t hash_value = this->hash_function()(k);
- bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value);
- node_ptr pos = this->find_iterator(bucket, k);
+ ////////////////////////////////////////////////////////////////////////
+ // Insert range methods
+ //
+ // if hash function throws, or inserting > 1 element, basic exception
+ // safety strong otherwise
 
- if (!BOOST_UNORDERED_BORLAND_BOOL(pos)) {
- // Doesn't already exist, add to bucket.
- // Side effects only in this block.
+ template <class InputIt>
+ void insert_range(InputIt i, InputIt j)
+ {
+ if(i != j)
+ return insert_range_impl(extractor::extract(*i), i, j);
+ }
 
- // Create the node before rehashing in case it throws an
- // exception (need strong safety in such a case).
- a.construct(*i);
+ template <class InputIt>
+ void insert_range_impl(key_type const&, InputIt i, InputIt j)
+ {
+ node_constructor a(*this);
 
- // 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);
+ // Special case for empty buckets so that we can use
+ // max_load_ (which isn't valid when buckets_ is null).
+ if (!this->buckets_) {
+ insert_range_empty(a, extractor::extract(*i), i, j);
+ if (++i == j) return;
             }
 
- // Nothing after this point can throw.
- add_node(a, bucket);
+ do {
+ // Note: can't use get_key as '*i' might not be value_type - it
+ // could be a pair with first_types as key_type without const or a
+ // different second_type.
+ //
+ // TODO: Might be worth storing the value_type instead of the key
+ // here. Could be more efficient if '*i' is expensive. Could be
+ // less efficient if copying the full value_type is expensive.
+ insert_range_impl2(a, extractor::extract(*i), i, j);
+ } while(++i != j);
         }
- }
 
- template <class T>
- template <class InputIt>
- inline void hash_unique_table<T>::insert_range_impl(
- key_type const&, InputIt i, InputIt j)
- {
- node_constructor a(*this);
-
- if(!this->size_) {
+ template <class InputIt>
+ void insert_range_empty(node_constructor& a, key_type const& k,
+ InputIt i, InputIt j)
+ {
+ std::size_t hash = this->hash_function()(k);
             a.construct(*i);
- this->emplace_empty_impl_with_node(a, 1);
- ++i;
- if(i == j) return;
- }
-
- do {
- // Note: can't use get_key as '*i' might not be value_type - it
- // could be a pair with first_types as key_type without const or a
- // different second_type.
- //
- // TODO: Might be worth storing the value_type instead of the key
- // here. Could be more efficient if '*i' is expensive. Could be
- // less efficient if copying the full value_type is expensive.
- insert_range_impl2(a, extractor::extract(*i), i, j);
- } while(++i != j);
- }
+ this->reserve_for_insert(this->size_ + insert_size(i, j));
+ add_node(a, hash % this->bucket_count_, hash);
+ }
 
- template <class T>
- template <class InputIt>
- inline void hash_unique_table<T>::insert_range_impl(
- no_key, InputIt i, InputIt j)
- {
- node_constructor a(*this);
+ template <class InputIt>
+ void insert_range_impl2(node_constructor& a, key_type const& k,
+ InputIt i, InputIt j)
+ {
+ // No side effects in this initial code
+ std::size_t hash = this->hash_function()(k);
+ std::size_t bucket_index = hash % this->bucket_count_;
+ node_ptr pos = this->find_node(bucket_index, hash, k);
+
+ if (!BOOST_UNORDERED_BORLAND_BOOL(pos)) {
+ // Doesn't already exist, add to bucket.
+ // Side effects only in this block.
+
+ // Create the node before rehashing in case it throws an
+ // exception (need strong safety in such a case).
+ a.construct(*i);
+
+ // reserve has basic exception safety if the hash function
+ // throws, strong otherwise.
+ if(this->size_ + 1 >= this->max_load_) {
+ this->reserve_for_insert(this->size_ + insert_size(i, j));
+ bucket_index = hash % this->bucket_count_;
+ }
+
+ // Nothing after this point can throw.
+ add_node(a, bucket_index, hash);
+ }
+ }
 
- if(!this->size_) {
- a.construct(*i);
- this->emplace_empty_impl_with_node(a, 1);
- ++i;
- if(i == j) return;
+ template <class InputIt>
+ void insert_range_impl(no_key, InputIt i, InputIt j)
+ {
+ node_constructor a(*this);
+
+ do {
+ // No side effects in this initial code
+ a.construct(*i);
+ emplace_impl_with_node(a);
+ } while(++i != j);
         }
+ };
 
- do {
- // No side effects in this initial code
- a.construct(*i);
- emplace_impl_with_node(a);
- } while(++i != j);
- }
+ template <class H, class P, class A>
+ struct set : public types<
+ BOOST_DEDUCED_TYPENAME allocator_traits<A>::value_type,
+ BOOST_DEDUCED_TYPENAME allocator_traits<A>::value_type,
+ H, P, A,
+ set_extractor<BOOST_DEDUCED_TYPENAME allocator_traits<A>::value_type>,
+ true>
+ {
+ typedef ::boost::unordered::detail::unique_table<set<H, P, A> > impl;
+ typedef ::boost::unordered::detail::table<set<H, P, A> > table_base;
+ };
 
- // if hash function throws, or inserting > 1 element, basic exception safety
- // strong otherwise
- template <class T>
- template <class InputIt>
- void hash_unique_table<T>::insert_range(InputIt i, InputIt j)
+ template <class K, class H, class P, class A>
+ struct map : public types<
+ K, BOOST_DEDUCED_TYPENAME allocator_traits<A>::value_type,
+ H, P, A,
+ map_extractor<K, BOOST_DEDUCED_TYPENAME allocator_traits<A>::value_type>,
+ true>
     {
- if(i != j)
- return insert_range_impl(extractor::extract(*i), i, j);
- }
-}}
+ typedef ::boost::unordered::detail::unique_table<map<K, H, P, A> > impl;
+ typedef ::boost::unordered::detail::table<map<K, H, P, A> > table_base;
+ };
+}}}
 
 #endif

Modified: branches/release/boost/unordered/detail/util.hpp
==============================================================================
--- branches/release/boost/unordered/detail/util.hpp (original)
+++ branches/release/boost/unordered/detail/util.hpp 2011-08-21 15:19:12 EDT (Sun, 21 Aug 2011)
@@ -1,22 +1,127 @@
 
 // Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
-// Copyright (C) 2005-2009 Daniel James
+// Copyright (C) 2005-2011 Daniel James
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 
 #ifndef BOOST_UNORDERED_DETAIL_UTIL_HPP_INCLUDED
 #define BOOST_UNORDERED_DETAIL_UTIL_HPP_INCLUDED
 
+#include <algorithm>
 #include <cstddef>
+#include <stdexcept>
 #include <utility>
-#include <algorithm>
 #include <boost/limits.hpp>
+#include <boost/config.hpp>
+#include <boost/config/no_tr1/cmath.hpp>
+#include <boost/detail/workaround.hpp>
+#include <boost/detail/select_type.hpp>
+#include <boost/assert.hpp>
+#include <boost/iterator.hpp>
 #include <boost/iterator/iterator_categories.hpp>
+#include <boost/type_traits/aligned_storage.hpp>
+#include <boost/type_traits/alignment_of.hpp>
+#include <boost/type_traits/remove_const.hpp>
+#include <boost/type_traits/is_empty.hpp>
+#include <boost/throw_exception.hpp>
+#include <boost/unordered/detail/allocator_helpers.hpp>
 #include <boost/preprocessor/seq/size.hpp>
 #include <boost/preprocessor/seq/enum.hpp>
-#include <boost/unordered/detail/fwd.hpp>
+#include <boost/preprocessor/repetition/enum.hpp>
+#include <boost/move/move.hpp>
+#include <boost/swap.hpp>
+
+// Template parameters:
+//
+// H = Hash Function
+// P = Predicate
+// A = Value Allocator
+// G = Bucket group policy, 'grouped' or 'ungrouped'
+// E = Key Extractor
+
+#if !defined(BOOST_NO_RVALUE_REFERENCES) && \
+ !defined(BOOST_NO_VARIADIC_TEMPLATES)
+# if defined(__SGI_STL_PORT) || defined(_STLPORT_VERSION)
+# elif defined(__STD_RWCOMPILER_H__) || defined(_RWSTD_VER)
+# elif defined(_LIBCPP_VERSION)
+# define BOOST_UNORDERED_STD_FORWARD_MOVE
+# elif defined(__GLIBCPP__) || defined(__GLIBCXX__)
+# if defined(__GLIBCXX__) && __GLIBCXX__ >= 20090804
+# define BOOST_UNORDERED_STD_FORWARD_MOVE
+# endif
+# elif defined(__STL_CONFIG_H)
+# elif defined(__MSL_CPP__)
+# elif defined(__IBMCPP__)
+# elif defined(MSIPL_COMPILE_H)
+# elif (defined(_YVALS) && !defined(__IBMCPP__)) || defined(_CPPLIB_VER)
+ // Visual C++. A version check would be a good idea.
+# define BOOST_UNORDERED_STD_FORWARD_MOVE
+# endif
+#endif
+
+#if !defined(BOOST_UNORDERED_EMPLACE_LIMIT)
+#define BOOST_UNORDERED_EMPLACE_LIMIT 10
+#endif
+
+#if defined(__SUNPRO_CC)
+#define BOOST_UNORDERED_USE_RV_REF 0
+#else
+#define BOOST_UNORDERED_USE_RV_REF 1
+#endif
+
+#if !defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
+
+#include <boost/preprocessor/repetition/enum_params.hpp>
+#include <boost/preprocessor/repetition/enum_binary_params.hpp>
+#include <boost/preprocessor/repetition/repeat_from_to.hpp>
+
+#define BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params) \
+ BOOST_PP_ENUM_PARAMS_Z(z, num_params, class Arg)
+
+#define BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params) \
+ BOOST_PP_ENUM_##z(num_params, BOOST_UNORDERED_FUNCTION_PARAMS2, _)
+#define BOOST_UNORDERED_FUNCTION_PARAMS2(z, i, _) \
+ BOOST_FWD_REF(Arg##i) arg##i
+
+#define BOOST_UNORDERED_CALL_PARAMS(z, num_params) \
+ BOOST_PP_ENUM_##z(num_params, BOOST_UNORDERED_CALL_PARAMS2, _)
+#define BOOST_UNORDERED_CALL_PARAMS2(z, i, _) \
+ boost::forward<Arg##i>(arg##i)
+
+#endif
+
+namespace boost { namespace unordered { namespace detail {
+
+ static const float minimum_max_load_factor = 1e-3f;
+ static const std::size_t default_bucket_count = 11;
+ struct move_tag {};
+
+ struct empty_emplace {};
+
+ template <class T> class unique_table;
+ template <class T> class equivalent_table;
+ template <class Alloc, bool Unique> class node_constructor;
+ template <class ValueType>
+ struct set_extractor;
+ template <class Key, class ValueType>
+ struct map_extractor;
+ struct no_key;
+
+ // Explicitly call a destructor
+
+#if defined(BOOST_MSVC)
+#pragma warning(push)
+#pragma warning(disable:4100) // unreferenced formal parameter
+#endif
 
-namespace boost { namespace unordered_detail {
+ template <class T>
+ inline void destroy(T* x) {
+ x->~T();
+ }
+
+#if defined(BOOST_MSVC)
+#pragma warning(pop)
+#endif
 
     ////////////////////////////////////////////////////////////////////////////
     // convert double to std::size_t
@@ -95,12 +200,19 @@
     ////////////////////////////////////////////////////////////////////////////
     // pair_cast - because some libraries don't have the full pair constructors.
 
+#if 0
     template <class Dst1, class Dst2, class Src1, class Src2>
     inline std::pair<Dst1, Dst2> pair_cast(std::pair<Src1, Src2> const& x)
     {
         return std::pair<Dst1, Dst2>(Dst1(x.first), Dst2(x.second));
     }
 
+#define BOOST_UNORDERED_PAIR_CAST(First, Last, Argument) \
+ ::boost::unordered::detail::pair_cast<First, Last>(Argument)
+#else
+#define BOOST_UNORDERED_PAIR_CAST(First, Last, Argument) \
+ Argument
+#endif
     ////////////////////////////////////////////////////////////////////////////
     // insert_size/initial_size
 
@@ -116,13 +228,13 @@
 #endif
 
     template <class I>
- inline std::size_t insert_size(I i, I j, boost::forward_traversal_tag)
+ inline std::size_t insert_size(I i, I j, ::boost::forward_traversal_tag)
     {
         return std::distance(i, j);
     }
 
     template <class I>
- inline std::size_t insert_size(I, I, boost::incrementable_traversal_tag)
+ inline std::size_t insert_size(I, I, ::boost::incrementable_traversal_tag)
     {
         return 1;
     }
@@ -130,202 +242,114 @@
     template <class I>
     inline std::size_t insert_size(I i, I j)
     {
- BOOST_DEDUCED_TYPENAME boost::iterator_traversal<I>::type
+ BOOST_DEDUCED_TYPENAME ::boost::iterator_traversal<I>::type
             iterator_traversal_tag;
         return insert_size(i, j, iterator_traversal_tag);
     }
     
     template <class I>
     inline std::size_t initial_size(I i, I j,
- std::size_t num_buckets = boost::unordered_detail::default_bucket_count)
+ std::size_t num_buckets = ::boost::unordered::detail::default_bucket_count)
     {
         return (std::max)(static_cast<std::size_t>(insert_size(i, j)) + 1,
             num_buckets);
     }
 
     ////////////////////////////////////////////////////////////////////////////
- // Node Constructors
-
-#if defined(BOOST_UNORDERED_STD_FORWARD)
+ // compressed_pair
 
- template <class T, class... Args>
- inline void construct_impl(T*, void* address, Args&&... args)
+ template <typename T, int Index>
+ struct compressed_base : private T
     {
- new(address) T(std::forward<Args>(args)...);
- }
+ compressed_base(T const& x) : T(x) {}
+ compressed_base(T& x, move_tag) : T(boost::move(x)) {}
 
-#if defined(BOOST_UNORDERED_CPP0X_PAIR)
- template <class First, class Second, class Key, class Arg0, class... Args>
- inline void construct_impl(std::pair<First, Second>*, void* address,
- Key&& k, Arg0&& arg0, Args&&... args)
- )
+ T& get() { return *this; }
+ T const& get() const { return *this; }
+ };
+
+ template <typename T, int Index>
+ struct uncompressed_base
     {
- new(address) std::pair<First, Second>(k,
- Second(arg0, std::forward<Args>(args)...);
- }
-#endif
-
-#else
-
-#define BOOST_UNORDERED_CONSTRUCT_IMPL(z, num_params, _) \
- template < \
- class T, \
- BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params) \
- > \
- inline void construct_impl( \
- T*, void* address, \
- BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params) \
- ) \
- { \
- new(address) T( \
- BOOST_UNORDERED_CALL_PARAMS(z, num_params)); \
- } \
- \
- template <class First, class Second, class Key, \
- BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params) \
- > \
- inline void construct_impl( \
- std::pair<First, Second>*, void* address, \
- Key const& k, BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \
- { \
- new(address) std::pair<First, Second>(k, \
- Second(BOOST_UNORDERED_CALL_PARAMS(z, num_params))); \
- }
+ uncompressed_base(T const& x) : value_(x) {}
+ uncompressed_base(T& x, move_tag) : value_(boost::move(x)) {}
 
- BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
- BOOST_UNORDERED_CONSTRUCT_IMPL, _)
-
-#undef BOOST_UNORDERED_CONSTRUCT_IMPL
-#endif
-
- // hash_node_constructor
- //
- // Used to construct nodes in an exception safe manner.
-
- template <class Alloc, class Grouped>
- class hash_node_constructor
- {
- typedef hash_buckets<Alloc, Grouped> buckets;
- typedef BOOST_DEDUCED_TYPENAME buckets::node node;
- typedef BOOST_DEDUCED_TYPENAME buckets::real_node_ptr real_node_ptr;
- typedef BOOST_DEDUCED_TYPENAME buckets::value_type value_type;
-
- buckets& buckets_;
- real_node_ptr node_;
- bool node_constructed_;
- bool value_constructed_;
-
- public:
-
- hash_node_constructor(buckets& m) :
- buckets_(m),
- node_(),
- node_constructed_(false),
- value_constructed_(false)
- {
+ T& get() { return value_; }
+ T const& get() const { return value_; }
+ private:
+ T value_;
+ };
+
+ template <typename T, int Index>
+ struct generate_base
+ : boost::detail::if_true<
+ boost::is_empty<T>::value
+ >:: BOOST_NESTED_TEMPLATE then<
+ compressed_base<T, Index>,
+ uncompressed_base<T, Index>
+ >
+ {};
+
+ template <typename T1, typename T2>
+ struct compressed_pair
+ : private generate_base<T1, 1>::type,
+ private generate_base<T2, 2>::type
+ {
+ typedef BOOST_DEDUCED_TYPENAME generate_base<T1, 1>::type base1;
+ typedef BOOST_DEDUCED_TYPENAME generate_base<T2, 2>::type base2;
+
+ typedef T1 first_type;
+ typedef T2 second_type;
+
+ first_type& first() {
+ return static_cast<base1*>(this)->get();
         }
 
- ~hash_node_constructor();
- void construct_preamble();
+ first_type const& first() const {
+ return static_cast<base1 const*>(this)->get();
+ }
 
-#if defined(BOOST_UNORDERED_STD_FORWARD)
- template <class... Args>
- void construct(Args&&... args)
- {
- construct_preamble();
- construct_impl((value_type*) 0, node_->address(),
- std::forward<Args>(args)...);
- value_constructed_ = true;
+ second_type& second() {
+ return static_cast<base2*>(this)->get();
         }
-#else
 
-#define BOOST_UNORDERED_CONSTRUCT(z, num_params, _) \
- template < \
- BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params) \
- > \
- void construct( \
- BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params) \
- ) \
- { \
- construct_preamble(); \
- construct_impl( \
- (value_type*) 0, node_->address(), \
- BOOST_UNORDERED_CALL_PARAMS(z, num_params) \
- ); \
- value_constructed_ = true; \
+ second_type const& second() const {
+ return static_cast<base2 const*>(this)->get();
         }
 
- BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
- BOOST_UNORDERED_CONSTRUCT, _)
+ template <typename First, typename Second>
+ compressed_pair(First const& x1, Second const& x2)
+ : base1(x1), base2(x2) {}
 
-#undef BOOST_UNORDERED_CONSTRUCT
+ compressed_pair(compressed_pair const& x)
+ : base1(x.first()), base2(x.second()) {}
 
-#endif
- template <class K, class M>
- void construct_pair(K const& k, M*)
+ compressed_pair(compressed_pair& x, move_tag m)
+ : base1(x.first(), m), base2(x.second(), m) {}
+
+ void assign(compressed_pair const& x)
         {
- construct_preamble();
- new(node_->address()) value_type(k, M());
- value_constructed_ = true;
+ first() = x.first();
+ second() = x.second();
         }
 
- value_type& value() const
+ void move_assign(compressed_pair& x)
         {
- BOOST_ASSERT(node_);
- return node_->value();
+ first() = boost::move(x.first());
+ second() = boost::move(x.second());
         }
-
- // no throw
- BOOST_DEDUCED_TYPENAME buckets::node_ptr release()
+
+ void swap(compressed_pair& x)
         {
- real_node_ptr p = node_;
- node_ = real_node_ptr();
- // node_ptr cast
- return buckets_.bucket_alloc().address(*p);
+ boost::swap(first(), x.first());
+ boost::swap(second(), x.second());
         }
 
     private:
- hash_node_constructor(hash_node_constructor const&);
- hash_node_constructor& operator=(hash_node_constructor const&);
+ // Prevent assignment just to make use of assign or
+ // move_assign explicit.
+ compressed_pair& operator=(compressed_pair const&);
     };
-
- // hash_node_constructor
-
- template <class Alloc, class Grouped>
- inline hash_node_constructor<Alloc, Grouped>::~hash_node_constructor()
- {
- if (node_) {
- if (value_constructed_) {
-#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613))
- struct dummy { hash_node<Alloc, Grouped> x; };
-#endif
- boost::unordered_detail::destroy(node_->value_ptr());
- }
-
- if (node_constructed_)
- buckets_.node_alloc().destroy(node_);
-
- buckets_.node_alloc().deallocate(node_, 1);
- }
- }
-
- template <class Alloc, class Grouped>
- inline void hash_node_constructor<Alloc, Grouped>::construct_preamble()
- {
- if(!node_) {
- node_constructed_ = false;
- value_constructed_ = false;
-
- node_ = buckets_.node_alloc().allocate(1);
- buckets_.node_alloc().construct(node_, node());
- node_constructed_ = true;
- }
- else {
- BOOST_ASSERT(node_constructed_ && value_constructed_);
- boost::unordered_detail::destroy(node_->value_ptr());
- value_constructed_ = false;
- }
- }
-}}
+}}}
 
 #endif

Modified: branches/release/boost/unordered/unordered_map.hpp
==============================================================================
--- branches/release/boost/unordered/unordered_map.hpp (original)
+++ branches/release/boost/unordered/unordered_map.hpp 2011-08-21 15:19:12 EDT (Sun, 21 Aug 2011)
@@ -1,6 +1,6 @@
 
 // Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
-// Copyright (C) 2005-2009 Daniel James.
+// Copyright (C) 2005-2011 Daniel James.
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 
@@ -19,10 +19,6 @@
 #include <boost/unordered/detail/equivalent.hpp>
 #include <boost/unordered/detail/unique.hpp>
 
-#if defined(BOOST_NO_RVALUE_REFERENCES)
-#include <boost/unordered/detail/move.hpp>
-#endif
-
 #if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
 #include <initializer_list>
 #endif
@@ -38,9 +34,12 @@
 
 namespace boost
 {
+namespace unordered
+{
     template <class K, class T, class H, class P, class A>
     class unordered_map
     {
+ BOOST_COPYABLE_AND_MOVABLE(unordered_map)
     public:
         typedef K key_type;
         typedef std::pair<const K, T> value_type;
@@ -54,42 +53,38 @@
 #endif
 
         typedef BOOST_DEDUCED_TYPENAME
- boost::unordered_detail::rebind_wrap<
+ ::boost::unordered::detail::rebind_wrap<
                 allocator_type, value_type>::type
             value_allocator;
+ typedef ::boost::unordered::detail::allocator_traits<value_allocator> allocator_traits;
 
- typedef boost::unordered_detail::map<K, H, P,
+ typedef ::boost::unordered::detail::map<K, H, P,
             value_allocator> types;
         typedef BOOST_DEDUCED_TYPENAME types::impl table;
 
- typedef BOOST_DEDUCED_TYPENAME types::iterator_base iterator_base;
+ typedef BOOST_DEDUCED_TYPENAME types::node_ptr node_ptr;
 
     public:
 
         typedef BOOST_DEDUCED_TYPENAME
- value_allocator::pointer pointer;
- typedef BOOST_DEDUCED_TYPENAME
- value_allocator::const_pointer const_pointer;
+ allocator_traits::pointer pointer;
         typedef BOOST_DEDUCED_TYPENAME
- value_allocator::reference reference;
- typedef BOOST_DEDUCED_TYPENAME
- value_allocator::const_reference const_reference;
+ allocator_traits::const_pointer const_pointer;
+
+ typedef value_type& reference;
+ typedef value_type const& 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;
- typedef boost::unordered_detail::hash_local_iterator<
- value_allocator, boost::unordered_detail::ungrouped>
- local_iterator;
- typedef boost::unordered_detail::hash_const_iterator<
- value_allocator, boost::unordered_detail::ungrouped>
- const_iterator;
- typedef boost::unordered_detail::hash_iterator<
- value_allocator, boost::unordered_detail::ungrouped>
- iterator;
+ typedef ::boost::unordered::iterator_detail::cl_iterator<
+ value_allocator, true> const_local_iterator;
+ typedef ::boost::unordered::iterator_detail::l_iterator<
+ value_allocator, true> local_iterator;
+ typedef ::boost::unordered::iterator_detail::c_iterator<
+ value_allocator, true> const_iterator;
+ typedef ::boost::unordered::iterator_detail::iterator<
+ value_allocator, true> iterator;
 
 #if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582)
     private:
@@ -97,131 +92,76 @@
 
         table table_;
         
- BOOST_DEDUCED_TYPENAME types::iterator_base const&
- get(const_iterator const& it)
- {
- return boost::unordered_detail::iterator_access::get(it);
- }
-
     public:
 
         // construct/destroy/copy
 
         explicit unordered_map(
- size_type n = boost::unordered_detail::default_bucket_count,
- const hasher &hf = hasher(),
- const key_equal &eql = key_equal(),
- const allocator_type &a = allocator_type())
- : table_(n, hf, eql, a)
- {
- }
+ size_type = ::boost::unordered::detail::default_bucket_count,
+ const hasher& = hasher(),
+ const key_equal& = key_equal(),
+ const allocator_type& = allocator_type());
 
- explicit unordered_map(allocator_type const& a)
- : table_(boost::unordered_detail::default_bucket_count,
- hasher(), key_equal(), a)
- {
- }
+ explicit unordered_map(allocator_type const&);
 
- unordered_map(unordered_map const& other, allocator_type const& a)
- : table_(other.table_, a)
- {
- }
+ unordered_map(unordered_map const&, allocator_type const&);
 
         template <class InputIt>
- unordered_map(InputIt f, InputIt l)
- : table_(boost::unordered_detail::initial_size(f, l),
- hasher(), key_equal(), allocator_type())
- {
- table_.insert_range(f, l);
- }
+ unordered_map(InputIt f, InputIt l);
 
         template <class InputIt>
- unordered_map(InputIt f, InputIt l,
- size_type n,
- const hasher &hf = hasher(),
- const key_equal &eql = key_equal())
- : table_(boost::unordered_detail::initial_size(f, l, n),
- hf, eql, allocator_type())
- {
- table_.insert_range(f, l);
- }
+ unordered_map(
+ InputIt, InputIt,
+ size_type,
+ const hasher& = hasher(),
+ const key_equal& = key_equal());
 
         template <class InputIt>
- unordered_map(InputIt f, InputIt l,
- size_type n,
- const hasher &hf,
- const key_equal &eql,
- const allocator_type &a)
- : table_(boost::unordered_detail::initial_size(f, l, n), hf, eql, a)
- {
- table_.insert_range(f, l);
- }
-
- ~unordered_map() {}
-
-#if !defined(BOOST_NO_RVALUE_REFERENCES)
- unordered_map(unordered_map const& other)
- : table_(other.table_)
- {
- }
-
- unordered_map(unordered_map&& other)
- : table_(other.table_, boost::unordered_detail::move_tag())
- {
- }
-
- unordered_map(unordered_map&& other, allocator_type const& a)
- : table_(other.table_, a, boost::unordered_detail::move_tag())
- {
- }
+ unordered_map(
+ InputIt, InputIt,
+ size_type,
+ const hasher&,
+ const key_equal&,
+ const allocator_type&);
+
+ ~unordered_map();
 
- unordered_map& operator=(unordered_map const& x)
+ unordered_map& operator=(
+ BOOST_COPY_ASSIGN_REF(unordered_map) x)
         {
- table_ = x.table_;
+ table_.assign(x.table_);
             return *this;
         }
 
- unordered_map& operator=(unordered_map&& x)
+ unordered_map(unordered_map const&);
+
+#if BOOST_UNORDERED_USE_RV_REF
+ unordered_map& operator=(
+ BOOST_RV_REF(unordered_map) x)
         {
- table_.move(x.table_);
+ table_.move_assign(x.table_);
             return *this;
         }
-#else
- unordered_map(boost::unordered_detail::move_from<
- unordered_map<K, T, H, P, A>
- > other)
- : table_(other.source.table_, boost::unordered_detail::move_tag())
- {
- }
 
-#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0593)
- unordered_map& operator=(unordered_map x)
+ unordered_map(BOOST_RV_REF(unordered_map) other)
+ : table_(other.table_, ::boost::unordered::detail::move_tag())
         {
- table_.move(x.table_);
- return *this;
         }
 #endif
+
+#if !defined(BOOST_NO_RVALUE_REFERENCES)
+ unordered_map(unordered_map&&, allocator_type const&);
 #endif
 
 #if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
- unordered_map(std::initializer_list<value_type> list,
- size_type n = boost::unordered_detail::default_bucket_count,
- const hasher &hf = hasher(),
- const key_equal &eql = key_equal(),
- const allocator_type &a = allocator_type())
- : table_(boost::unordered_detail::initial_size(
- list.begin(), list.end(), n),
- hf, eql, a)
- {
- table_.insert_range(list.begin(), list.end());
- }
+ unordered_map(
+ std::initializer_list<value_type>,
+ size_type = ::boost::unordered::detail::default_bucket_count,
+ const hasher& = hasher(),
+ const key_equal&l = key_equal(),
+ const allocator_type& = allocator_type());
 
- unordered_map& operator=(std::initializer_list<value_type> list)
- {
- table_.clear();
- table_.insert_range(list.begin(), list.end());
- return *this;
- }
+ unordered_map& operator=(std::initializer_list<value_type>);
 #endif
 
         allocator_type get_allocator() const
@@ -241,10 +181,7 @@
             return table_.size_;
         }
 
- size_type max_size() const
- {
- return table_.max_size();
- }
+ size_type max_size() const;
 
         // iterators
 
@@ -260,12 +197,12 @@
 
         iterator end()
         {
- return iterator(table_.end());
+ return iterator();
         }
 
         const_iterator end() const
         {
- return const_iterator(table_.end());
+ return const_iterator();
         }
 
         const_iterator cbegin() const
@@ -275,39 +212,30 @@
 
         const_iterator cend() const
         {
- return const_iterator(table_.end());
+ return const_iterator();
         }
 
         // modifiers
 
-#if defined(BOOST_UNORDERED_STD_FORWARD)
+#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
         template <class... Args>
- std::pair<iterator, bool> emplace(Args&&... args)
- {
- return boost::unordered_detail::pair_cast<iterator, bool>(
- table_.emplace(std::forward<Args>(args)...));
- }
-
+ std::pair<iterator, bool> emplace(Args&&...);
         template <class... Args>
- iterator emplace_hint(const_iterator, Args&&... args)
- {
- return iterator(table_.emplace(std::forward<Args>(args)...).first);
- }
+ iterator emplace_hint(const_iterator, Args&&...);
 #else
 
- #if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100))
- std::pair<iterator, bool> emplace(value_type const& v = value_type())
- {
- return boost::unordered_detail::pair_cast<iterator, bool>(
- table_.emplace(v));
- }
-
+#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100))
+ std::pair<iterator, bool> emplace(
+ boost::unordered::detail::empty_emplace
+ = boost::unordered::detail::empty_emplace(),
+ value_type v = value_type()
+ );
         iterator emplace_hint(const_iterator,
- value_type const& v = value_type())
- {
- return iterator(table_.emplace(v).first);
- }
- #endif
+ boost::unordered::detail::empty_emplace
+ = boost::unordered::detail::empty_emplace(),
+ value_type v = value_type()
+ );
+#endif
 
 #define BOOST_UNORDERED_EMPLACE(z, n, _) \
             template < \
@@ -315,24 +243,14 @@
> \
             std::pair<iterator, bool> emplace( \
                 BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
- ) \
- { \
- return boost::unordered_detail::pair_cast<iterator, bool>( \
- table_.emplace( \
- BOOST_UNORDERED_CALL_PARAMS(z, n) \
- )); \
- } \
+ ); \
                                                                                \
             template < \
                 BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
> \
             iterator emplace_hint(const_iterator, \
                 BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
- ) \
- { \
- return iterator(table_.emplace( \
- BOOST_UNORDERED_CALL_PARAMS(z, n)).first); \
- }
+ );
 
         BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
             BOOST_UNORDERED_EMPLACE, _)
@@ -341,144 +259,61 @@
 
 #endif
 
- std::pair<iterator, bool> insert(const value_type& obj)
- {
- return boost::unordered_detail::pair_cast<iterator, bool>(
- table_.emplace(obj));
- }
-
- iterator insert(const_iterator, const value_type& obj)
- {
- return iterator(table_.emplace(obj).first);
- }
-
- template <class InputIt>
- void insert(InputIt first, InputIt last)
- {
- table_.insert_range(first, last);
- }
+ std::pair<iterator, bool> insert(value_type const&);
+ iterator insert(const_iterator, value_type const&);
+#if BOOST_UNORDERED_USE_RV_REF
+ std::pair<iterator, bool> insert(BOOST_RV_REF(value_type));
+ iterator insert(const_iterator, BOOST_RV_REF(value_type));
+#endif
+ template <class InputIt> void insert(InputIt, InputIt);
 
 #if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
- void insert(std::initializer_list<value_type> list)
- {
- table_.insert_range(list.begin(), list.end());
- }
+ void insert(std::initializer_list<value_type>);
 #endif
 
- iterator erase(const_iterator position)
- {
- return iterator(table_.erase_return_iterator(get(position)));
- }
-
- size_type erase(const key_type& k)
- {
- return table_.erase_key(k);
- }
-
- iterator erase(const_iterator first, const_iterator last)
- {
- return iterator(table_.erase_range(get(first), get(last)));
- }
-
- void quick_erase(const_iterator position)
- {
- table_.erase(get(position));
- }
-
- void erase_return_void(const_iterator position)
- {
- table_.erase(get(position));
- }
-
- void clear()
- {
- table_.clear();
- }
+ iterator erase(const_iterator);
+ size_type erase(const key_type&);
+ iterator erase(const_iterator, const_iterator);
+ void quick_erase(const_iterator it) { erase(it); }
+ void erase_return_void(const_iterator it) { erase(it); }
 
- void swap(unordered_map& other)
- {
- table_.swap(other.table_);
- }
+ void clear();
+ void swap(unordered_map&);
 
         // observers
 
- hasher hash_function() const
- {
- return table_.hash_function();
- }
-
- key_equal key_eq() const
- {
- return table_.key_eq();
- }
-
- mapped_type& operator[](const key_type &k)
- {
- return table_[k].second;
- }
-
- mapped_type& at(const key_type& k)
- {
- return table_.at(k).second;
- }
+ hasher hash_function() const;
+ key_equal key_eq() const;
 
- mapped_type const& at(const key_type& k) const
- {
- return table_.at(k).second;
- }
+ mapped_type& operator[](const key_type&);
+ mapped_type& at(const key_type&);
+ mapped_type const& at(const key_type&) const;
 
         // lookup
 
- iterator find(const key_type& k)
- {
- return iterator(table_.find(k));
- }
-
- const_iterator find(const key_type& k) const
- {
- return const_iterator(table_.find(k));
- }
+ iterator find(const key_type&);
+ const_iterator find(const key_type&) const;
 
         template <class CompatibleKey, class CompatibleHash,
             class CompatiblePredicate>
         iterator find(
- CompatibleKey const& k,
- CompatibleHash const& hash,
- CompatiblePredicate const& eq)
- {
- return iterator(table_.find(k, hash, eq));
- }
+ CompatibleKey const&,
+ CompatibleHash const&,
+ CompatiblePredicate const&);
 
         template <class CompatibleKey, class CompatibleHash,
             class CompatiblePredicate>
         const_iterator find(
- CompatibleKey const& k,
- CompatibleHash const& hash,
- CompatiblePredicate const& eq) const
- {
- return iterator(table_.find(k, hash, eq));
- }
+ CompatibleKey const&,
+ CompatibleHash const&,
+ CompatiblePredicate const&) const;
 
- size_type count(const key_type& k) const
- {
- return table_.count(k);
- }
+ size_type count(const key_type&) const;
 
         std::pair<iterator, iterator>
- equal_range(const key_type& k)
- {
- return boost::unordered_detail::pair_cast<
- iterator, iterator>(
- table_.equal_range(k));
- }
-
+ equal_range(const key_type&);
         std::pair<const_iterator, const_iterator>
- equal_range(const key_type& k) const
- {
- return boost::unordered_detail::pair_cast<
- const_iterator, const_iterator>(
- table_.equal_range(k));
- }
+ equal_range(const key_type&) const;
 
         // bucket interface
 
@@ -492,24 +327,23 @@
             return table_.max_bucket_count();
         }
 
- size_type bucket_size(size_type n) const
- {
- return table_.bucket_size(n);
- }
+ size_type bucket_size(size_type n) const;
 
         size_type bucket(const key_type& k) const
         {
- return table_.bucket_index(k);
+ return table_.hash_function()(k) % table_.bucket_count_;
         }
 
         local_iterator begin(size_type n)
         {
- return local_iterator(table_.bucket_begin(n));
+ return local_iterator(
+ table_.bucket_begin(n), n, table_.bucket_count_);
         }
 
         const_local_iterator begin(size_type n) const
         {
- return const_local_iterator(table_.bucket_begin(n));
+ return const_local_iterator(
+ table_.bucket_begin(n), n, table_.bucket_count_);
         }
 
         local_iterator end(size_type)
@@ -524,7 +358,8 @@
 
         const_local_iterator cbegin(size_type n) const
         {
- return const_local_iterator(table_.bucket_begin(n));
+ return const_local_iterator(
+ table_.bucket_begin(n), n, table_.bucket_count_);
         }
 
         const_local_iterator cend(size_type) const
@@ -534,67 +369,27 @@
 
         // hash policy
 
- float load_factor() const
- {
- return table_.load_factor();
- }
-
         float max_load_factor() const
         {
             return table_.mlf_;
         }
 
- void max_load_factor(float m)
- {
- table_.max_load_factor(m);
- }
+ float load_factor() const;
+ void max_load_factor(float);
+ void rehash(size_type n);
 
- void rehash(size_type n)
- {
- table_.rehash(n);
- }
-
 #if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582)
- friend bool operator==<K, T, H, P, A>(
- unordered_map const&, unordered_map const&);
- friend bool operator!=<K, T, H, P, A>(
- unordered_map const&, unordered_map const&);
+ friend bool operator==<K,T,H,P,A>(
+ unordered_map const&, unordered_map const&);
+ friend bool operator!=<K,T,H,P,A>(
+ unordered_map const&, unordered_map const&);
 #endif
     }; // class template unordered_map
 
     template <class K, class T, class H, class P, class A>
- inline bool operator==(unordered_map<K, T, H, P, A> const& m1,
- unordered_map<K, T, H, P, A> const& m2)
- {
-#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613))
- struct dummy { unordered_map<K,T,H,P,A> x; };
-#endif
- return m1.table_.equals(m2.table_);
- }
-
- template <class K, class T, class H, class P, class A>
- inline bool operator!=(unordered_map<K, T, H, P, A> const& m1,
- unordered_map<K, T, H, P, A> const& m2)
- {
-#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613))
- struct dummy { unordered_map<K,T,H,P,A> x; };
-#endif
- return !m1.table_.equals(m2.table_);
- }
-
- template <class K, class T, class H, class P, class A>
- inline void swap(unordered_map<K, T, H, P, A> &m1,
- unordered_map<K, T, H, P, A> &m2)
- {
-#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613))
- struct dummy { unordered_map<K,T,H,P,A> x; };
-#endif
- m1.swap(m2);
- }
-
- template <class K, class T, class H, class P, class A>
     class unordered_multimap
     {
+ BOOST_COPYABLE_AND_MOVABLE(unordered_multimap)
     public:
 
         typedef K key_type;
@@ -609,42 +404,39 @@
 #endif
 
         typedef BOOST_DEDUCED_TYPENAME
- boost::unordered_detail::rebind_wrap<
+ ::boost::unordered::detail::rebind_wrap<
                 allocator_type, value_type>::type
             value_allocator;
+ typedef ::boost::unordered::detail::allocator_traits<value_allocator>
+ allocator_traits;
 
- typedef boost::unordered_detail::multimap<K, H, P,
+ typedef ::boost::unordered::detail::multimap<K, H, P,
             value_allocator> types;
         typedef BOOST_DEDUCED_TYPENAME types::impl table;
 
- typedef BOOST_DEDUCED_TYPENAME types::iterator_base iterator_base;
+ typedef BOOST_DEDUCED_TYPENAME types::node_ptr node_ptr;
 
     public:
 
         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;
+ allocator_traits::pointer pointer;
         typedef BOOST_DEDUCED_TYPENAME
- value_allocator::const_reference const_reference;
+ allocator_traits::const_pointer const_pointer;
+
+ typedef value_type& reference;
+ typedef value_type const& 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;
- typedef boost::unordered_detail::hash_local_iterator<
- value_allocator, boost::unordered_detail::grouped>
- local_iterator;
- typedef boost::unordered_detail::hash_const_iterator<
- value_allocator, boost::unordered_detail::grouped>
- const_iterator;
- typedef boost::unordered_detail::hash_iterator<
- value_allocator, boost::unordered_detail::grouped>
- iterator;
+ typedef ::boost::unordered::iterator_detail::cl_iterator<
+ value_allocator, false> const_local_iterator;
+ typedef ::boost::unordered::iterator_detail::l_iterator<
+ value_allocator, false> local_iterator;
+ typedef ::boost::unordered::iterator_detail::c_iterator<
+ value_allocator, false> const_iterator;
+ typedef ::boost::unordered::iterator_detail::iterator<
+ value_allocator, false> iterator;
 
 #if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582)
     private:
@@ -652,132 +444,76 @@
 
         table table_;
         
- BOOST_DEDUCED_TYPENAME types::iterator_base const&
- get(const_iterator const& it)
- {
- return boost::unordered_detail::iterator_access::get(it);
- }
-
     public:
 
         // construct/destroy/copy
 
         explicit unordered_multimap(
- size_type n = boost::unordered_detail::default_bucket_count,
- const hasher &hf = hasher(),
- const key_equal &eql = key_equal(),
- const allocator_type &a = allocator_type())
- : table_(n, hf, eql, a)
- {
- }
+ size_type = ::boost::unordered::detail::default_bucket_count,
+ const hasher& = hasher(),
+ const key_equal& = key_equal(),
+ const allocator_type& = allocator_type());
 
- explicit unordered_multimap(allocator_type const& a)
- : table_(boost::unordered_detail::default_bucket_count,
- hasher(), key_equal(), a)
- {
- }
+ explicit unordered_multimap(allocator_type const&);
 
- unordered_multimap(unordered_multimap const& other,
- allocator_type const& a)
- : table_(other.table_, a)
- {
- }
+ unordered_multimap(unordered_multimap const&, allocator_type const&);
 
         template <class InputIt>
- unordered_multimap(InputIt f, InputIt l)
- : table_(boost::unordered_detail::initial_size(f, l),
- hasher(), key_equal(), allocator_type())
- {
- table_.insert_range(f, l);
- }
+ unordered_multimap(InputIt, InputIt);
 
         template <class InputIt>
- unordered_multimap(InputIt f, InputIt l,
- size_type n,
- const hasher &hf = hasher(),
- const key_equal &eql = key_equal())
- : table_(boost::unordered_detail::initial_size(f, l, n),
- hf, eql, allocator_type())
- {
- table_.insert_range(f, l);
- }
+ unordered_multimap(
+ InputIt, InputIt,
+ size_type,
+ const hasher& = hasher(),
+ const key_equal& = key_equal());
 
         template <class InputIt>
- unordered_multimap(InputIt f, InputIt l,
- size_type n,
- const hasher &hf,
- const key_equal &eql,
- const allocator_type &a)
- : table_(boost::unordered_detail::initial_size(f, l, n), hf, eql, a)
- {
- table_.insert_range(f, l);
- }
+ unordered_multimap(
+ InputIt, InputIt,
+ size_type,
+ const hasher&,
+ const key_equal&,
+ const allocator_type&);
 
- ~unordered_multimap() {}
+ ~unordered_multimap();
 
-#if !defined(BOOST_NO_RVALUE_REFERENCES)
- unordered_multimap(unordered_multimap const& other)
- : table_(other.table_)
- {
- }
-
- unordered_multimap(unordered_multimap&& other)
- : table_(other.table_, boost::unordered_detail::move_tag())
- {
- }
-
- unordered_multimap(unordered_multimap&& other, allocator_type const& a)
- : table_(other.table_, a, boost::unordered_detail::move_tag())
- {
- }
-
- unordered_multimap& operator=(unordered_multimap const& x)
+ unordered_multimap& operator=(
+ BOOST_COPY_ASSIGN_REF(unordered_multimap) x)
         {
- table_ = x.table_;
+ table_.assign(x.table_);
             return *this;
         }
 
- unordered_multimap& operator=(unordered_multimap&& x)
+ unordered_multimap(unordered_multimap const&);
+
+#if BOOST_UNORDERED_USE_RV_REF
+ unordered_multimap& operator=(
+ BOOST_RV_REF(unordered_multimap) x)
         {
- table_.move(x.table_);
+ table_.move_assign(x.table_);
             return *this;
         }
-#else
- unordered_multimap(boost::unordered_detail::move_from<
- unordered_multimap<K, T, H, P, A>
- > other)
- : table_(other.source.table_, boost::unordered_detail::move_tag())
- {
- }
 
-#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0593)
- unordered_multimap& operator=(unordered_multimap x)
+ unordered_multimap(BOOST_RV_REF(unordered_multimap) other)
+ : table_(other.table_, ::boost::unordered::detail::move_tag())
         {
- table_.move(x.table_);
- return *this;
         }
 #endif
+
+#if !defined(BOOST_NO_RVALUE_REFERENCES)
+ unordered_multimap(unordered_multimap&&, allocator_type const&);
 #endif
 
 #if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
- unordered_multimap(std::initializer_list<value_type> list,
- size_type n = boost::unordered_detail::default_bucket_count,
- const hasher &hf = hasher(),
- const key_equal &eql = key_equal(),
- const allocator_type &a = allocator_type())
- : table_(boost::unordered_detail::initial_size(
- list.begin(), list.end(), n),
- hf, eql, a)
- {
- table_.insert_range(list.begin(), list.end());
- }
+ unordered_multimap(
+ std::initializer_list<value_type>,
+ size_type = ::boost::unordered::detail::default_bucket_count,
+ const hasher& = hasher(),
+ const key_equal&l = key_equal(),
+ const allocator_type& = allocator_type());
 
- unordered_multimap& operator=(std::initializer_list<value_type> list)
- {
- table_.clear();
- table_.insert_range(list.begin(), list.end());
- return *this;
- }
+ unordered_multimap& operator=(std::initializer_list<value_type>);
 #endif
 
         allocator_type get_allocator() const
@@ -797,10 +533,7 @@
             return table_.size_;
         }
 
- size_type max_size() const
- {
- return table_.max_size();
- }
+ size_type max_size() const;
 
         // iterators
 
@@ -816,12 +549,12 @@
 
         iterator end()
         {
- return iterator(table_.end());
+ return iterator();
         }
 
         const_iterator end() const
         {
- return const_iterator(table_.end());
+ return const_iterator();
         }
 
         const_iterator cbegin() const
@@ -831,37 +564,30 @@
 
         const_iterator cend() const
         {
- return const_iterator(table_.end());
+ return const_iterator();
         }
 
         // modifiers
 
-#if defined(BOOST_UNORDERED_STD_FORWARD)
+#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
         template <class... Args>
- iterator emplace(Args&&... args)
- {
- return iterator(table_.emplace(std::forward<Args>(args)...));
- }
-
+ iterator emplace(Args&&...);
         template <class... Args>
- iterator emplace_hint(const_iterator, Args&&... args)
- {
- return iterator(table_.emplace(std::forward<Args>(args)...));
- }
+ iterator emplace_hint(const_iterator, Args&&...);
 #else
 
- #if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100))
- iterator emplace(value_type const& v = value_type())
- {
- return iterator(table_.emplace(v));
- }
-
+#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100))
+ iterator emplace(
+ boost::unordered::detail::empty_emplace
+ = boost::unordered::detail::empty_emplace(),
+ value_type v = value_type()
+ );
         iterator emplace_hint(const_iterator,
- value_type const& v = value_type())
- {
- return iterator(table_.emplace(v));
- }
- #endif
+ boost::unordered::detail::empty_emplace
+ = boost::unordered::detail::empty_emplace(),
+ value_type v = value_type()
+ );
+#endif
 
 #define BOOST_UNORDERED_EMPLACE(z, n, _) \
             template < \
@@ -869,25 +595,14 @@
> \
             iterator emplace( \
                 BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
- ) \
- { \
- return iterator( \
- table_.emplace( \
- BOOST_UNORDERED_CALL_PARAMS(z, n) \
- )); \
- } \
+ ); \
                                                                                \
             template < \
                 BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
> \
             iterator emplace_hint(const_iterator, \
                 BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
- ) \
- { \
- return iterator(table_.emplace( \
- BOOST_UNORDERED_CALL_PARAMS(z, n) \
- )); \
- }
+ );
 
         BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
             BOOST_UNORDERED_EMPLACE, _)
@@ -896,214 +611,956 @@
 
 #endif
 
- iterator insert(const value_type& obj)
+ iterator insert(value_type const&);
+ iterator insert(const_iterator, value_type const&);
+#if BOOST_UNORDERED_USE_RV_REF
+ iterator insert(BOOST_RV_REF(value_type));
+ iterator insert(const_iterator, BOOST_RV_REF(value_type));
+#endif
+ template <class InputIt> void insert(InputIt, InputIt);
+
+#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
+ void insert(std::initializer_list<value_type>);
+#endif
+
+ iterator erase(const_iterator);
+ size_type erase(const key_type&);
+ iterator erase(const_iterator, const_iterator);
+ void quick_erase(const_iterator position) { erase(position); }
+ void erase_return_void(const_iterator position) { erase(position); }
+
+ void clear();
+ void swap(unordered_multimap&);
+
+ // observers
+
+ hasher hash_function() const;
+ key_equal key_eq() const;
+
+ // lookup
+
+ iterator find(const key_type&);
+ const_iterator find(const key_type&) const;
+
+ template <class CompatibleKey, class CompatibleHash,
+ class CompatiblePredicate>
+ iterator find(
+ CompatibleKey const&,
+ CompatibleHash const&,
+ CompatiblePredicate const&);
+
+ template <class CompatibleKey, class CompatibleHash,
+ class CompatiblePredicate>
+ const_iterator find(
+ CompatibleKey const&,
+ CompatibleHash const&,
+ CompatiblePredicate const&) const;
+
+ size_type count(const key_type&) const;
+
+ std::pair<iterator, iterator>
+ equal_range(const key_type&);
+ std::pair<const_iterator, const_iterator>
+ equal_range(const key_type&) const;
+
+ // bucket interface
+
+ size_type bucket_count() const
         {
- return iterator(table_.emplace(obj));
+ return table_.bucket_count_;
         }
 
- iterator insert(const_iterator, const value_type& obj)
+ size_type max_bucket_count() const
         {
- return iterator(table_.emplace(obj));
+ return table_.max_bucket_count();
         }
 
- template <class InputIt>
- void insert(InputIt first, InputIt last)
+ size_type bucket_size(size_type) const;
+
+ size_type bucket(const key_type& k) const
         {
- table_.insert_range(first, last);
+ return table_.hash_function()(k) % table_.bucket_count_;
         }
 
-#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
- void insert(std::initializer_list<value_type> list)
+ local_iterator begin(size_type n)
         {
- table_.insert_range(list.begin(), list.end());
+ return local_iterator(
+ table_.bucket_begin(n), n, table_.bucket_count_);
         }
-#endif
 
- iterator erase(const_iterator position)
+ const_local_iterator begin(size_type n) const
         {
- return iterator(table_.erase_return_iterator(get(position)));
+ return const_local_iterator(
+ table_.bucket_begin(n), n, table_.bucket_count_);
         }
 
- size_type erase(const key_type& k)
+ local_iterator end(size_type)
         {
- return table_.erase_key(k);
+ return local_iterator();
         }
 
- iterator erase(const_iterator first, const_iterator last)
+ const_local_iterator end(size_type) const
         {
- return iterator(table_.erase_range(get(first), get(last)));
+ return const_local_iterator();
         }
 
- void quick_erase(const_iterator position)
+ const_local_iterator cbegin(size_type n) const
         {
- table_.erase(get(position));
+ return const_local_iterator(
+ table_.bucket_begin(n), n, table_.bucket_count_);
         }
 
- void erase_return_void(const_iterator position)
+ const_local_iterator cend(size_type) const
         {
- table_.erase(get(position));
+ return const_local_iterator();
         }
 
- void clear()
- {
- table_.clear();
- }
+ // hash policy
 
- void swap(unordered_multimap& other)
+ float max_load_factor() const
         {
- table_.swap(other.table_);
+ return table_.mlf_;
         }
 
- // observers
+ float load_factor() const;
+ void max_load_factor(float);
+ void rehash(size_type);
 
- hasher hash_function() const
- {
- return table_.hash_function();
- }
+#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582)
+ friend bool operator==<K,T,H,P,A>(
+ unordered_multimap const&, unordered_multimap const&);
+ friend bool operator!=<K,T,H,P,A>(
+ unordered_multimap const&, unordered_multimap const&);
+#endif
+ }; // class template unordered_multimap
 
- key_equal key_eq() const
- {
- return table_.key_eq();
- }
+////////////////////////////////////////////////////////////////////////////////
 
- // lookup
+ template <class K, class T, class H, class P, class A>
+ unordered_map<K,T,H,P,A>::unordered_map(
+ size_type n, const hasher &hf, const key_equal &eql,
+ const allocator_type &a)
+ : table_(n, hf, eql, a)
+ {
+ }
 
- iterator find(const key_type& k)
- {
- return iterator(table_.find(k));
- }
+ template <class K, class T, class H, class P, class A>
+ unordered_map<K,T,H,P,A>::unordered_map(allocator_type const& a)
+ : table_(::boost::unordered::detail::default_bucket_count,
+ hasher(), key_equal(), a)
+ {
+ }
 
- const_iterator find(const key_type& k) const
- {
- return const_iterator(table_.find(k));
+ template <class K, class T, class H, class P, class A>
+ unordered_map<K,T,H,P,A>::unordered_map(
+ unordered_map const& other, allocator_type const& a)
+ : table_(other.table_, a)
+ {
+ }
+
+ template <class K, class T, class H, class P, class A>
+ template <class InputIt>
+ unordered_map<K,T,H,P,A>::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 <class K, class T, class H, class P, class A>
+ template <class InputIt>
+ unordered_map<K,T,H,P,A>::unordered_map(
+ InputIt f, InputIt l,
+ size_type n,
+ const hasher &hf,
+ const key_equal &eql)
+ : table_(::boost::unordered::detail::initial_size(f, l, n),
+ hf, eql, allocator_type())
+ {
+ table_.insert_range(f, l);
+ }
+
+ template <class K, class T, class H, class P, class A>
+ template <class InputIt>
+ unordered_map<K,T,H,P,A>::unordered_map(
+ InputIt f, InputIt l,
+ size_type n,
+ const hasher &hf,
+ const key_equal &eql,
+ const allocator_type &a)
+ : table_(::boost::unordered::detail::initial_size(f, l, n), hf, eql, a)
+ {
+ table_.insert_range(f, l);
+ }
+
+ template <class K, class T, class H, class P, class A>
+ unordered_map<K,T,H,P,A>::~unordered_map() {}
+
+ template <class K, class T, class H, class P, class A>
+ unordered_map<K,T,H,P,A>::unordered_map(unordered_map const& other)
+ : table_(other.table_)
+ {
+ }
+
+#if !defined(BOOST_NO_RVALUE_REFERENCES)
+
+ template <class K, class T, class H, class P, class A>
+ unordered_map<K,T,H,P,A>::unordered_map(
+ unordered_map&& other, allocator_type const& a)
+ : table_(other.table_, a, ::boost::unordered::detail::move_tag())
+ {
+ }
+
+#endif
+
+#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
+
+ template <class K, class T, class H, class P, class A>
+ unordered_map<K,T,H,P,A>::unordered_map(
+ std::initializer_list<value_type> list, size_type n,
+ const hasher &hf, const key_equal &eql, const allocator_type &a)
+ : table_(
+ ::boost::unordered::detail::initial_size(
+ list.begin(), list.end(), n),
+ hf, eql, a)
+ {
+ table_.insert_range(list.begin(), list.end());
+ }
+
+ template <class K, class T, class H, class P, class A>
+ unordered_map<K,T,H,P,A>& unordered_map<K,T,H,P,A>::operator=(
+ std::initializer_list<value_type> list)
+ {
+ table_.clear();
+ table_.insert_range(list.begin(), list.end());
+ return *this;
+ }
+
+#endif
+
+ // size and capacity
+
+ template <class K, class T, class H, class P, class A>
+ std::size_t unordered_map<K,T,H,P,A>::max_size() const
+ {
+ return table_.max_size();
+ }
+
+ // modifiers
+
+#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
+ template <class K, class T, class H, class P, class A>
+ template <class... Args>
+ std::pair<BOOST_DEDUCED_TYPENAME unordered_map<K,T,H,P,A>::iterator, bool>
+ unordered_map<K,T,H,P,A>::emplace(Args&&... args)
+ {
+ return BOOST_UNORDERED_PAIR_CAST(iterator, bool,
+ table_.emplace(std::forward<Args>(args)...));
+ }
+
+ template <class K, class T, class H, class P, class A>
+ template <class... Args>
+ BOOST_DEDUCED_TYPENAME unordered_map<K,T,H,P,A>::iterator
+ unordered_map<K,T,H,P,A>::emplace_hint(const_iterator, Args&&... args)
+ {
+ return iterator(table_.emplace(std::forward<Args>(args)...).first);
+ }
+#else
+
+#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100))
+ template <class K, class T, class H, class P, class A>
+ std::pair<BOOST_DEDUCED_TYPENAME unordered_map<K,T,H,P,A>::iterator, bool>
+ unordered_map<K,T,H,P,A>::emplace(
+ boost::unordered::detail::empty_emplace,
+ value_type v
+ )
+ {
+ return BOOST_UNORDERED_PAIR_CAST(iterator, bool,
+ table_.emplace(boost::move(v)));
+ }
+
+ template <class K, class T, class H, class P, class A>
+ BOOST_DEDUCED_TYPENAME unordered_map<K,T,H,P,A>::iterator
+ unordered_map<K,T,H,P,A>::emplace_hint(const_iterator,
+ boost::unordered::detail::empty_emplace,
+ value_type v
+ )
+ {
+ return iterator(table_.emplace(boost::move(v)).first);
+ }
+#endif
+
+#define BOOST_UNORDERED_EMPLACE(z, n, _) \
+ template <class K, class T, class H, class P, class A> \
+ template < \
+ BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
+ > \
+ std::pair< \
+ BOOST_DEDUCED_TYPENAME unordered_map<K,T,H,P,A>::iterator, \
+ bool> \
+ unordered_map<K,T,H,P,A>::emplace( \
+ BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \
+ { \
+ return \
+ BOOST_UNORDERED_PAIR_CAST(iterator, bool, \
+ table_.emplace( \
+ BOOST_UNORDERED_CALL_PARAMS(z, n))); \
+ } \
+ \
+ template <class K, class T, class H, class P, class A> \
+ template < \
+ BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
+ > \
+ BOOST_DEDUCED_TYPENAME unordered_map<K,T,H,P,A>::iterator \
+ unordered_map<K,T,H,P,A>::emplace_hint( \
+ const_iterator, \
+ BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
+ ) \
+ { \
+ return iterator(table_.emplace( \
+ BOOST_UNORDERED_CALL_PARAMS(z, n)).first); \
         }
 
- template <class CompatibleKey, class CompatibleHash,
- class CompatiblePredicate>
- iterator find(
+ BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
+ BOOST_UNORDERED_EMPLACE, _)
+
+#undef BOOST_UNORDERED_EMPLACE
+
+#endif
+
+ template <class K, class T, class H, class P, class A>
+ std::pair<BOOST_DEDUCED_TYPENAME unordered_map<K,T,H,P,A>::iterator, bool>
+ unordered_map<K,T,H,P,A>::insert(value_type const& obj)
+ {
+ return BOOST_UNORDERED_PAIR_CAST(iterator, bool,
+ table_.emplace(obj));
+ }
+
+ template <class K, class T, class H, class P, class A>
+ BOOST_DEDUCED_TYPENAME unordered_map<K,T,H,P,A>::iterator
+ unordered_map<K,T,H,P,A>::insert(const_iterator,
+ value_type const& obj)
+ {
+ return iterator(table_.emplace(obj).first);
+ }
+
+#if BOOST_UNORDERED_USE_RV_REF
+ template <class K, class T, class H, class P, class A>
+ std::pair<BOOST_DEDUCED_TYPENAME unordered_map<K,T,H,P,A>::iterator, bool>
+ unordered_map<K,T,H,P,A>::insert(BOOST_RV_REF(value_type) obj)
+ {
+ return BOOST_UNORDERED_PAIR_CAST(iterator, bool,
+ table_.emplace(boost::move(obj)));
+ }
+
+ template <class K, class T, class H, class P, class A>
+ BOOST_DEDUCED_TYPENAME unordered_map<K,T,H,P,A>::iterator
+ unordered_map<K,T,H,P,A>::insert(const_iterator,
+ BOOST_RV_REF(value_type) obj)
+ {
+ return iterator(table_.emplace(boost::move(obj)).first);
+ }
+#endif
+
+ template <class K, class T, class H, class P, class A>
+ template <class InputIt>
+ void unordered_map<K,T,H,P,A>::insert(InputIt first, InputIt last)
+ {
+ table_.insert_range(first, last);
+ }
+
+#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
+ template <class K, class T, class H, class P, class A>
+ void unordered_map<K,T,H,P,A>::insert(
+ std::initializer_list<value_type> list)
+ {
+ table_.insert_range(list.begin(), list.end());
+ }
+#endif
+
+ template <class K, class T, class H, class P, class A>
+ BOOST_DEDUCED_TYPENAME unordered_map<K,T,H,P,A>::iterator
+ unordered_map<K,T,H,P,A>::erase(const_iterator position)
+ {
+ return iterator(table_.erase(position.node_));
+ }
+
+ template <class K, class T, class H, class P, class A>
+ BOOST_DEDUCED_TYPENAME unordered_map<K,T,H,P,A>::size_type
+ unordered_map<K,T,H,P,A>::erase(const key_type& k)
+ {
+ return table_.erase_key(k);
+ }
+
+ template <class K, class T, class H, class P, class A>
+ BOOST_DEDUCED_TYPENAME unordered_map<K,T,H,P,A>::iterator
+ unordered_map<K,T,H,P,A>::erase(
+ const_iterator first, const_iterator last)
+ {
+ return iterator(table_.erase_range(first.node_, last.node_));
+ }
+
+ template <class K, class T, class H, class P, class A>
+ void unordered_map<K,T,H,P,A>::clear()
+ {
+ table_.clear();
+ }
+
+ template <class K, class T, class H, class P, class A>
+ void unordered_map<K,T,H,P,A>::swap(unordered_map& other)
+ {
+ table_.swap(other.table_);
+ }
+
+ // observers
+
+ template <class K, class T, class H, class P, class A>
+ BOOST_DEDUCED_TYPENAME unordered_map<K,T,H,P,A>::hasher
+ unordered_map<K,T,H,P,A>::hash_function() const
+ {
+ return table_.hash_function();
+ }
+
+ template <class K, class T, class H, class P, class A>
+ BOOST_DEDUCED_TYPENAME unordered_map<K,T,H,P,A>::key_equal
+ unordered_map<K,T,H,P,A>::key_eq() const
+ {
+ return table_.key_eq();
+ }
+
+ template <class K, class T, class H, class P, class A>
+ BOOST_DEDUCED_TYPENAME unordered_map<K,T,H,P,A>::mapped_type&
+ unordered_map<K,T,H,P,A>::operator[](const key_type &k)
+ {
+ return table_[k].second;
+ }
+
+ template <class K, class T, class H, class P, class A>
+ BOOST_DEDUCED_TYPENAME unordered_map<K,T,H,P,A>::mapped_type&
+ unordered_map<K,T,H,P,A>::at(const key_type& k)
+ {
+ return table_.at(k).second;
+ }
+
+ template <class K, class T, class H, class P, class A>
+ BOOST_DEDUCED_TYPENAME unordered_map<K,T,H,P,A>::mapped_type const&
+ unordered_map<K,T,H,P,A>::at(const key_type& k) const
+ {
+ return table_.at(k).second;
+ }
+
+ // lookup
+
+ template <class K, class T, class H, class P, class A>
+ BOOST_DEDUCED_TYPENAME unordered_map<K,T,H,P,A>::iterator
+ unordered_map<K,T,H,P,A>::find(const key_type& k)
+ {
+ return iterator(table_.find_node(k));
+ }
+
+ template <class K, class T, class H, class P, class A>
+ BOOST_DEDUCED_TYPENAME unordered_map<K,T,H,P,A>::const_iterator
+ unordered_map<K,T,H,P,A>::find(const key_type& k) const
+ {
+ return const_iterator(table_.find_node(k));
+ }
+
+ template <class K, class T, class H, class P, class A>
+ template <class CompatibleKey, class CompatibleHash,
+ class CompatiblePredicate>
+ BOOST_DEDUCED_TYPENAME unordered_map<K,T,H,P,A>::iterator
+ unordered_map<K,T,H,P,A>::find(
             CompatibleKey const& k,
             CompatibleHash const& hash,
             CompatiblePredicate const& eq)
- {
- return iterator(table_.find(k, hash, eq));
- }
+ {
+ return iterator(table_.generic_find_node(k, hash, eq));
+ }
 
- template <class CompatibleKey, class CompatibleHash,
- class CompatiblePredicate>
- const_iterator find(
+ template <class K, class T, class H, class P, class A>
+ template <class CompatibleKey, class CompatibleHash,
+ class CompatiblePredicate>
+ BOOST_DEDUCED_TYPENAME unordered_map<K,T,H,P,A>::const_iterator
+ unordered_map<K,T,H,P,A>::find(
             CompatibleKey const& k,
             CompatibleHash const& hash,
             CompatiblePredicate const& eq) const
- {
- return iterator(table_.find(k, hash, eq));
- }
+ {
+ return const_iterator(table_.generic_find_node(k, hash, eq));
+ }
 
- size_type count(const key_type& k) const
- {
- return table_.count(k);
- }
+ template <class K, class T, class H, class P, class A>
+ BOOST_DEDUCED_TYPENAME unordered_map<K,T,H,P,A>::size_type
+ unordered_map<K,T,H,P,A>::count(const key_type& k) const
+ {
+ return table_.count(k);
+ }
 
- std::pair<iterator, iterator>
- equal_range(const key_type& k)
- {
- return boost::unordered_detail::pair_cast<
- iterator, iterator>(
- table_.equal_range(k));
- }
+ template <class K, class T, class H, class P, class A>
+ std::pair<
+ BOOST_DEDUCED_TYPENAME unordered_map<K,T,H,P,A>::iterator,
+ BOOST_DEDUCED_TYPENAME unordered_map<K,T,H,P,A>::iterator>
+ unordered_map<K,T,H,P,A>::equal_range(const key_type& k)
+ {
+ return BOOST_UNORDERED_PAIR_CAST(iterator, iterator,
+ table_.equal_range(k));
+ }
 
- std::pair<const_iterator, const_iterator>
- equal_range(const key_type& k) const
- {
- return boost::unordered_detail::pair_cast<
- const_iterator, const_iterator>(
- table_.equal_range(k));
- }
+ template <class K, class T, class H, class P, class A>
+ std::pair<
+ BOOST_DEDUCED_TYPENAME unordered_map<K,T,H,P,A>::const_iterator,
+ BOOST_DEDUCED_TYPENAME unordered_map<K,T,H,P,A>::const_iterator>
+ unordered_map<K,T,H,P,A>::equal_range(const key_type& k) const
+ {
+ return BOOST_UNORDERED_PAIR_CAST(const_iterator, const_iterator,
+ table_.equal_range(k));
+ }
 
- // bucket interface
+ template <class K, class T, class H, class P, class A>
+ BOOST_DEDUCED_TYPENAME unordered_map<K,T,H,P,A>::size_type
+ unordered_map<K,T,H,P,A>::bucket_size(size_type n) const
+ {
+ return table_.bucket_size(n);
+ }
 
- size_type bucket_count() const
- {
- return table_.bucket_count_;
- }
+ // hash policy
 
- size_type max_bucket_count() const
- {
- return table_.max_bucket_count();
- }
+ template <class K, class T, class H, class P, class A>
+ float unordered_map<K,T,H,P,A>::load_factor() const
+ {
+ return table_.load_factor();
+ }
 
- size_type bucket_size(size_type n) const
- {
- return table_.bucket_size(n);
- }
+ template <class K, class T, class H, class P, class A>
+ void unordered_map<K,T,H,P,A>::max_load_factor(float m)
+ {
+ table_.max_load_factor(m);
+ }
 
- size_type bucket(const key_type& k) const
- {
- return table_.bucket_index(k);
- }
+ template <class K, class T, class H, class P, class A>
+ void unordered_map<K,T,H,P,A>::rehash(size_type n)
+ {
+ table_.rehash(n);
+ }
 
- local_iterator begin(size_type n)
- {
- return local_iterator(table_.bucket_begin(n));
- }
+ template <class K, class T, class H, class P, class A>
+ inline bool operator==(
+ unordered_map<K,T,H,P,A> const& m1,
+ unordered_map<K,T,H,P,A> const& m2)
+ {
+#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613))
+ struct dummy { unordered_map<K,T,H,P,A> x; };
+#endif
+ return m1.table_.equals(m2.table_);
+ }
 
- const_local_iterator begin(size_type n) const
- {
- return const_local_iterator(table_.bucket_begin(n));
- }
+ template <class K, class T, class H, class P, class A>
+ inline bool operator!=(
+ unordered_map<K,T,H,P,A> const& m1,
+ unordered_map<K,T,H,P,A> const& m2)
+ {
+#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613))
+ struct dummy { unordered_map<K,T,H,P,A> x; };
+#endif
+ return !m1.table_.equals(m2.table_);
+ }
 
- local_iterator end(size_type)
- {
- return local_iterator();
- }
+ template <class K, class T, class H, class P, class A>
+ inline void swap(
+ unordered_map<K,T,H,P,A> &m1,
+ unordered_map<K,T,H,P,A> &m2)
+ {
+#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613))
+ struct dummy { unordered_map<K,T,H,P,A> x; };
+#endif
+ m1.swap(m2);
+ }
 
- const_local_iterator end(size_type) const
- {
- return const_local_iterator();
- }
+////////////////////////////////////////////////////////////////////////////////
 
- const_local_iterator cbegin(size_type n) const
- {
- return const_local_iterator(table_.bucket_begin(n));
- }
+ template <class K, class T, class H, class P, class A>
+ unordered_multimap<K,T,H,P,A>::unordered_multimap(
+ size_type n, const hasher &hf, const key_equal &eql,
+ const allocator_type &a)
+ : table_(n, hf, eql, a)
+ {
+ }
 
- const_local_iterator cend(size_type) const
- {
- return const_local_iterator();
- }
+ template <class K, class T, class H, class P, class A>
+ unordered_multimap<K,T,H,P,A>::unordered_multimap(allocator_type const& a)
+ : table_(::boost::unordered::detail::default_bucket_count,
+ hasher(), key_equal(), a)
+ {
+ }
 
- // hash policy
+ template <class K, class T, class H, class P, class A>
+ unordered_multimap<K,T,H,P,A>::unordered_multimap(
+ unordered_multimap const& other, allocator_type const& a)
+ : table_(other.table_, a)
+ {
+ }
 
- float load_factor() const
- {
- return table_.load_factor();
- }
+ template <class K, class T, class H, class P, class A>
+ template <class InputIt>
+ unordered_multimap<K,T,H,P,A>::unordered_multimap(InputIt f, InputIt l)
+ : table_(::boost::unordered::detail::initial_size(f, l),
+ hasher(), key_equal(), allocator_type())
+ {
+ table_.insert_range(f, l);
+ }
 
- float max_load_factor() const
- {
- return table_.mlf_;
- }
+ template <class K, class T, class H, class P, class A>
+ template <class InputIt>
+ unordered_multimap<K,T,H,P,A>::unordered_multimap(
+ InputIt f, InputIt l,
+ size_type n,
+ const hasher &hf,
+ const key_equal &eql)
+ : table_(::boost::unordered::detail::initial_size(f, l, n),
+ hf, eql, allocator_type())
+ {
+ table_.insert_range(f, l);
+ }
+
+ template <class K, class T, class H, class P, class A>
+ template <class InputIt>
+ unordered_multimap<K,T,H,P,A>::unordered_multimap(
+ InputIt f, InputIt l,
+ size_type n,
+ const hasher &hf,
+ const key_equal &eql,
+ const allocator_type &a)
+ : table_(::boost::unordered::detail::initial_size(f, l, n), hf, eql, a)
+ {
+ table_.insert_range(f, l);
+ }
+
+ template <class K, class T, class H, class P, class A>
+ unordered_multimap<K,T,H,P,A>::~unordered_multimap() {}
 
- void max_load_factor(float m)
- {
- table_.max_load_factor(m);
- }
+ template <class K, class T, class H, class P, class A>
+ unordered_multimap<K,T,H,P,A>::unordered_multimap(
+ unordered_multimap const& other)
+ : table_(other.table_)
+ {
+ }
 
- void rehash(size_type n)
- {
- table_.rehash(n);
+#if !defined(BOOST_NO_RVALUE_REFERENCES)
+
+ template <class K, class T, class H, class P, class A>
+ unordered_multimap<K,T,H,P,A>::unordered_multimap(
+ unordered_multimap&& other, allocator_type const& a)
+ : table_(other.table_, a, ::boost::unordered::detail::move_tag())
+ {
+ }
+
+#endif
+
+#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
+ template <class K, class T, class H, class P, class A>
+ unordered_multimap<K,T,H,P,A>::unordered_multimap(
+ std::initializer_list<value_type> list, size_type n,
+ const hasher &hf, const key_equal &eql, const allocator_type &a)
+ : table_(
+ ::boost::unordered::detail::initial_size(
+ list.begin(), list.end(), n),
+ hf, eql, a)
+ {
+ table_.insert_range(list.begin(), list.end());
+ }
+
+ template <class K, class T, class H, class P, class A>
+ unordered_multimap<K,T,H,P,A>& unordered_multimap<K,T,H,P,A>::operator=(
+ std::initializer_list<value_type> list)
+ {
+ table_.clear();
+ table_.insert_range(list.begin(), list.end());
+ return *this;
+ }
+#endif
+
+ // size and capacity
+
+ template <class K, class T, class H, class P, class A>
+ std::size_t unordered_multimap<K,T,H,P,A>::max_size() const
+ {
+ return table_.max_size();
+ }
+
+ // modifiers
+
+#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
+
+ template <class K, class T, class H, class P, class A>
+ template <class... Args>
+ BOOST_DEDUCED_TYPENAME unordered_multimap<K,T,H,P,A>::iterator
+ unordered_multimap<K,T,H,P,A>::emplace(Args&&... args)
+ {
+ return iterator(table_.emplace(std::forward<Args>(args)...));
+ }
+
+ template <class K, class T, class H, class P, class A>
+ template <class... Args>
+ BOOST_DEDUCED_TYPENAME unordered_multimap<K,T,H,P,A>::iterator
+ unordered_multimap<K,T,H,P,A>::emplace_hint(
+ const_iterator, Args&&... args)
+ {
+ return iterator(table_.emplace(std::forward<Args>(args)...));
+ }
+
+#else
+
+#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100))
+ template <class K, class T, class H, class P, class A>
+ BOOST_DEDUCED_TYPENAME unordered_multimap<K,T,H,P,A>::iterator
+ unordered_multimap<K,T,H,P,A>::emplace(
+ boost::unordered::detail::empty_emplace,
+ value_type v
+ )
+ {
+ return iterator(table_.emplace(boost::move(v)));
+ }
+
+ template <class K, class T, class H, class P, class A>
+ BOOST_DEDUCED_TYPENAME unordered_multimap<K,T,H,P,A>::iterator
+ unordered_multimap<K,T,H,P,A>::emplace_hint(const_iterator,
+ boost::unordered::detail::empty_emplace,
+ value_type v
+ )
+ {
+ return iterator(table_.emplace(boost::move(v)));
+ }
+#endif
+
+#define BOOST_UNORDERED_EMPLACE(z, n, _) \
+ template <class K, class T, class H, class P, class A> \
+ template < \
+ BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
+ > \
+ BOOST_DEDUCED_TYPENAME unordered_multimap<K,T,H,P,A>::iterator \
+ unordered_multimap<K,T,H,P,A>::emplace( \
+ BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \
+ { \
+ return iterator(table_.emplace( \
+ BOOST_UNORDERED_CALL_PARAMS(z, n))); \
+ } \
+ \
+ template <class K, class T, class H, class P, class A> \
+ template < \
+ BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
+ > \
+ BOOST_DEDUCED_TYPENAME unordered_multimap<K,T,H,P,A>::iterator \
+ unordered_multimap<K,T,H,P,A>::emplace_hint( \
+ const_iterator, \
+ BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \
+ { \
+ return iterator(table_.emplace( \
+ BOOST_UNORDERED_CALL_PARAMS(z, n))); \
         }
 
-#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582)
- friend bool operator==<K, T, H, P, A>(
- unordered_multimap const&, unordered_multimap const&);
- friend bool operator!=<K, T, H, P, A>(
- unordered_multimap const&, unordered_multimap const&);
+ BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
+ BOOST_UNORDERED_EMPLACE, _)
+
+#undef BOOST_UNORDERED_EMPLACE
+
 #endif
- }; // class template unordered_multimap
 
     template <class K, class T, class H, class P, class A>
- inline bool operator==(unordered_multimap<K, T, H, P, A> const& m1,
- unordered_multimap<K, T, H, P, A> const& m2)
+ BOOST_DEDUCED_TYPENAME unordered_multimap<K,T,H,P,A>::iterator
+ unordered_multimap<K,T,H,P,A>::insert(value_type const& obj)
+ {
+ return iterator(table_.emplace(obj));
+ }
+
+ template <class K, class T, class H, class P, class A>
+ BOOST_DEDUCED_TYPENAME unordered_multimap<K,T,H,P,A>::iterator
+ unordered_multimap<K,T,H,P,A>::insert(
+ const_iterator, value_type const& obj)
+ {
+ return iterator(table_.emplace(obj));
+ }
+
+#if BOOST_UNORDERED_USE_RV_REF
+ template <class K, class T, class H, class P, class A>
+ BOOST_DEDUCED_TYPENAME unordered_multimap<K,T,H,P,A>::iterator
+ unordered_multimap<K,T,H,P,A>::insert(BOOST_RV_REF(value_type) obj)
+ {
+ return iterator(table_.emplace(boost::move(obj)));
+ }
+
+ template <class K, class T, class H, class P, class A>
+ BOOST_DEDUCED_TYPENAME unordered_multimap<K,T,H,P,A>::iterator
+ unordered_multimap<K,T,H,P,A>::insert(
+ const_iterator, BOOST_RV_REF(value_type) obj)
+ {
+ return iterator(table_.emplace(boost::move(obj)));
+ }
+#endif
+
+ template <class K, class T, class H, class P, class A>
+ template <class InputIt>
+ void unordered_multimap<K,T,H,P,A>::insert(InputIt first, InputIt last)
+ {
+ table_.insert_range(first, last);
+ }
+
+#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
+ template <class K, class T, class H, class P, class A>
+ void unordered_multimap<K,T,H,P,A>::insert(
+ std::initializer_list<value_type> list)
+ {
+ table_.insert_range(list.begin(), list.end());
+ }
+#endif
+
+ template <class K, class T, class H, class P, class A>
+ BOOST_DEDUCED_TYPENAME unordered_multimap<K,T,H,P,A>::iterator
+ unordered_multimap<K,T,H,P,A>::erase(const_iterator position)
+ {
+ return iterator(table_.erase(position.node_));
+ }
+
+ template <class K, class T, class H, class P, class A>
+ BOOST_DEDUCED_TYPENAME unordered_multimap<K,T,H,P,A>::size_type
+ unordered_multimap<K,T,H,P,A>::erase(const key_type& k)
+ {
+ return table_.erase_key(k);
+ }
+
+ template <class K, class T, class H, class P, class A>
+ BOOST_DEDUCED_TYPENAME unordered_multimap<K,T,H,P,A>::iterator
+ unordered_multimap<K,T,H,P,A>::erase(
+ const_iterator first, const_iterator last)
+ {
+ return iterator(table_.erase_range(first.node_, last.node_));
+ }
+
+ template <class K, class T, class H, class P, class A>
+ void unordered_multimap<K,T,H,P,A>::clear()
+ {
+ table_.clear();
+ }
+
+ template <class K, class T, class H, class P, class A>
+ void unordered_multimap<K,T,H,P,A>::swap(unordered_multimap& other)
+ {
+ table_.swap(other.table_);
+ }
+
+ // observers
+
+ template <class K, class T, class H, class P, class A>
+ BOOST_DEDUCED_TYPENAME unordered_multimap<K,T,H,P,A>::hasher
+ unordered_multimap<K,T,H,P,A>::hash_function() const
+ {
+ return table_.hash_function();
+ }
+
+ template <class K, class T, class H, class P, class A>
+ BOOST_DEDUCED_TYPENAME unordered_multimap<K,T,H,P,A>::key_equal
+ unordered_multimap<K,T,H,P,A>::key_eq() const
+ {
+ return table_.key_eq();
+ }
+
+ // lookup
+
+ template <class K, class T, class H, class P, class A>
+ BOOST_DEDUCED_TYPENAME unordered_multimap<K,T,H,P,A>::iterator
+ unordered_multimap<K,T,H,P,A>::find(const key_type& k)
+ {
+ return iterator(table_.find_node(k));
+ }
+
+ template <class K, class T, class H, class P, class A>
+ BOOST_DEDUCED_TYPENAME unordered_multimap<K,T,H,P,A>::const_iterator
+ unordered_multimap<K,T,H,P,A>::find(const key_type& k) const
+ {
+ return const_iterator(table_.find_node(k));
+ }
+
+ template <class K, class T, class H, class P, class A>
+ template <class CompatibleKey, class CompatibleHash,
+ class CompatiblePredicate>
+ BOOST_DEDUCED_TYPENAME unordered_multimap<K,T,H,P,A>::iterator
+ unordered_multimap<K,T,H,P,A>::find(
+ CompatibleKey const& k,
+ CompatibleHash const& hash,
+ CompatiblePredicate const& eq)
+ {
+ return iterator(table_.generic_find_node(k, hash, eq));
+ }
+
+ template <class K, class T, class H, class P, class A>
+ template <class CompatibleKey, class CompatibleHash,
+ class CompatiblePredicate>
+ BOOST_DEDUCED_TYPENAME unordered_multimap<K,T,H,P,A>::const_iterator
+ unordered_multimap<K,T,H,P,A>::find(
+ CompatibleKey const& k,
+ CompatibleHash const& hash,
+ CompatiblePredicate const& eq) const
+ {
+ return const_iterator(table_.generic_find_node(k, hash, eq));
+ }
+
+ template <class K, class T, class H, class P, class A>
+ BOOST_DEDUCED_TYPENAME unordered_multimap<K,T,H,P,A>::size_type
+ unordered_multimap<K,T,H,P,A>::count(const key_type& k) const
+ {
+ return table_.count(k);
+ }
+
+ template <class K, class T, class H, class P, class A>
+ std::pair<
+ BOOST_DEDUCED_TYPENAME unordered_multimap<K,T,H,P,A>::iterator,
+ BOOST_DEDUCED_TYPENAME unordered_multimap<K,T,H,P,A>::iterator>
+ unordered_multimap<K,T,H,P,A>::equal_range(const key_type& k)
+ {
+ return BOOST_UNORDERED_PAIR_CAST(iterator, iterator,
+ table_.equal_range(k));
+ }
+
+ template <class K, class T, class H, class P, class A>
+ std::pair<
+ BOOST_DEDUCED_TYPENAME unordered_multimap<K,T,H,P,A>::const_iterator,
+ BOOST_DEDUCED_TYPENAME unordered_multimap<K,T,H,P,A>::const_iterator>
+ unordered_multimap<K,T,H,P,A>::equal_range(const key_type& k) const
+ {
+ return BOOST_UNORDERED_PAIR_CAST(const_iterator, const_iterator,
+ table_.equal_range(k));
+ }
+
+ template <class K, class T, class H, class P, class A>
+ BOOST_DEDUCED_TYPENAME unordered_multimap<K,T,H,P,A>::size_type
+ unordered_multimap<K,T,H,P,A>::bucket_size(size_type n) const
+ {
+ return table_.bucket_size(n);
+ }
+
+ // hash policy
+
+ template <class K, class T, class H, class P, class A>
+ float unordered_multimap<K,T,H,P,A>::load_factor() const
+ {
+ return table_.load_factor();
+ }
+
+ template <class K, class T, class H, class P, class A>
+ void unordered_multimap<K,T,H,P,A>::max_load_factor(float m)
+ {
+ table_.max_load_factor(m);
+ }
+
+ template <class K, class T, class H, class P, class A>
+ void unordered_multimap<K,T,H,P,A>::rehash(size_type n)
+ {
+ table_.rehash(n);
+ }
+
+ template <class K, class T, class H, class P, class A>
+ inline bool operator==(
+ unordered_multimap<K,T,H,P,A> const& m1,
+ unordered_multimap<K,T,H,P,A> const& m2)
     {
 #if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613))
         struct dummy { unordered_multimap<K,T,H,P,A> x; };
@@ -1112,8 +1569,9 @@
     }
 
     template <class K, class T, class H, class P, class A>
- inline bool operator!=(unordered_multimap<K, T, H, P, A> const& m1,
- unordered_multimap<K, T, H, P, A> const& m2)
+ inline bool operator!=(
+ unordered_multimap<K,T,H,P,A> const& m1,
+ unordered_multimap<K,T,H,P,A> const& m2)
     {
 #if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613))
         struct dummy { unordered_multimap<K,T,H,P,A> x; };
@@ -1122,8 +1580,9 @@
     }
 
     template <class K, class T, class H, class P, class A>
- inline void swap(unordered_multimap<K, T, H, P, A> &m1,
- unordered_multimap<K, T, H, P, A> &m2)
+ inline void swap(
+ unordered_multimap<K,T,H,P,A> &m1,
+ unordered_multimap<K,T,H,P,A> &m2)
     {
 #if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613))
         struct dummy { unordered_multimap<K,T,H,P,A> x; };
@@ -1131,6 +1590,7 @@
         m1.swap(m2);
     }
 
+} // namespace unordered
 } // namespace boost
 
 #if defined(BOOST_MSVC)

Modified: branches/release/boost/unordered/unordered_map_fwd.hpp
==============================================================================
--- branches/release/boost/unordered/unordered_map_fwd.hpp (original)
+++ branches/release/boost/unordered/unordered_map_fwd.hpp 2011-08-21 15:19:12 EDT (Sun, 21 Aug 2011)
@@ -1,5 +1,5 @@
 
-// Copyright (C) 2008-2009 Daniel James.
+// Copyright (C) 2008-2011 Daniel James.
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 
@@ -10,44 +10,38 @@
 # pragma once
 #endif
 
-#include <boost/config.hpp>
-#include <memory>
-#include <functional>
-#include <boost/functional/hash_fwd.hpp>
+#include <boost/unordered/detail/fwd.hpp>
 
 namespace boost
 {
- template <class K,
- class T,
- class H = hash<K>,
- class P = std::equal_to<K>,
- class A = std::allocator<std::pair<const K, T> > >
- class unordered_map;
- template <class K, class T, class H, class P, class A>
- inline bool operator==(unordered_map<K, T, H, P, A> const&,
- unordered_map<K, T, H, P, A> const&);
- template <class K, class T, class H, class P, class A>
- inline bool operator!=(unordered_map<K, T, H, P, A> const&,
- unordered_map<K, T, H, P, A> const&);
- template <class K, class T, class H, class P, class A>
- inline void swap(unordered_map<K, T, H, P, A>&,
- unordered_map<K, T, H, P, A>&);
-
- template <class K,
- class T,
- class H = hash<K>,
- class P = std::equal_to<K>,
- class A = std::allocator<std::pair<const K, T> > >
- class unordered_multimap;
- template <class K, class T, class H, class P, class A>
- inline bool operator==(unordered_multimap<K, T, H, P, A> const&,
- unordered_multimap<K, T, H, P, A> const&);
- template <class K, class T, class H, class P, class A>
- inline bool operator!=(unordered_multimap<K, T, H, P, A> const&,
- unordered_multimap<K, T, H, P, A> const&);
- template <class K, class T, class H, class P, class A>
- inline void swap(unordered_multimap<K, T, H, P, A>&,
- unordered_multimap<K, T, H, P, A>&);
+ namespace unordered
+ {
+ template <class K, class T, class H, class P, class A>
+ inline bool operator==(unordered_map<K, T, H, P, A> const&,
+ unordered_map<K, T, H, P, A> const&);
+ template <class K, class T, class H, class P, class A>
+ inline bool operator!=(unordered_map<K, T, H, P, A> const&,
+ unordered_map<K, T, H, P, A> const&);
+ template <class K, class T, class H, class P, class A>
+ inline void swap(unordered_map<K, T, H, P, A>&,
+ unordered_map<K, T, H, P, A>&);
+
+ template <class K, class T, class H, class P, class A>
+ inline bool operator==(unordered_multimap<K, T, H, P, A> const&,
+ unordered_multimap<K, T, H, P, A> const&);
+ template <class K, class T, class H, class P, class A>
+ inline bool operator!=(unordered_multimap<K, T, H, P, A> const&,
+ unordered_multimap<K, T, H, P, A> const&);
+ template <class K, class T, class H, class P, class A>
+ inline void swap(unordered_multimap<K, T, H, P, A>&,
+ unordered_multimap<K, T, H, P, A>&);
+ }
+
+ using ::boost::unordered::unordered_map;
+ using ::boost::unordered::unordered_multimap;
+ using ::boost::unordered::swap;
+ using ::boost::unordered::operator==;
+ using ::boost::unordered::operator!=;
 }
 
 #endif

Modified: branches/release/boost/unordered/unordered_set.hpp
==============================================================================
--- branches/release/boost/unordered/unordered_set.hpp (original)
+++ branches/release/boost/unordered/unordered_set.hpp 2011-08-21 15:19:12 EDT (Sun, 21 Aug 2011)
@@ -1,6 +1,6 @@
 
 // Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
-// Copyright (C) 2005-2009 Daniel James.
+// Copyright (C) 2005-2011 Daniel James.
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 
@@ -19,10 +19,6 @@
 #include <boost/unordered/detail/equivalent.hpp>
 #include <boost/unordered/detail/unique.hpp>
 
-#if defined(BOOST_NO_RVALUE_REFERENCES)
-#include <boost/unordered/detail/move.hpp>
-#endif
-
 #if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
 #include <initializer_list>
 #endif
@@ -38,9 +34,12 @@
 
 namespace boost
 {
+namespace unordered
+{
     template <class T, class H, class P, class A>
     class unordered_set
     {
+ BOOST_COPYABLE_AND_MOVABLE(unordered_set)
     public:
 
         typedef T key_type;
@@ -54,36 +53,35 @@
 #endif
 
         typedef BOOST_DEDUCED_TYPENAME
- boost::unordered_detail::rebind_wrap<
+ ::boost::unordered::detail::rebind_wrap<
                 allocator_type, value_type>::type
             value_allocator;
+ typedef ::boost::unordered::detail::allocator_traits<value_allocator>
+ allocator_traits;
 
- typedef boost::unordered_detail::set<H, P,
+ typedef ::boost::unordered::detail::set<H, P,
             value_allocator> types;
         typedef BOOST_DEDUCED_TYPENAME types::impl table;
 
- typedef BOOST_DEDUCED_TYPENAME types::iterator_base iterator_base;
+ typedef BOOST_DEDUCED_TYPENAME types::node_ptr node_ptr;
 
     public:
 
         typedef BOOST_DEDUCED_TYPENAME
- value_allocator::pointer pointer;
- typedef BOOST_DEDUCED_TYPENAME
- value_allocator::const_pointer const_pointer;
+ allocator_traits::pointer pointer;
         typedef BOOST_DEDUCED_TYPENAME
- value_allocator::reference reference;
- typedef BOOST_DEDUCED_TYPENAME
- value_allocator::const_reference const_reference;
+ allocator_traits::const_pointer const_pointer;
+
+ typedef value_type& reference;
+ typedef value_type const& 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;
- typedef boost::unordered_detail::hash_const_iterator<
- value_allocator, boost::unordered_detail::ungrouped>
- const_iterator;
+ typedef ::boost::unordered::iterator_detail::cl_iterator<
+ value_allocator, true> const_local_iterator;
+ typedef ::boost::unordered::iterator_detail::c_iterator<
+ value_allocator, true> const_iterator;
         typedef const_local_iterator local_iterator;
         typedef const_iterator iterator;
 
@@ -92,130 +90,77 @@
 #endif
 
         table table_;
-
- BOOST_DEDUCED_TYPENAME types::iterator_base const&
- get(const_iterator const& it)
- {
- return boost::unordered_detail::iterator_access::get(it);
- }
 
     public:
 
         // construct/destroy/copy
 
         explicit unordered_set(
- size_type n = boost::unordered_detail::default_bucket_count,
- const hasher &hf = hasher(),
- const key_equal &eql = key_equal(),
- const allocator_type &a = allocator_type())
- : table_(n, hf, eql, a)
- {
- }
+ size_type = ::boost::unordered::detail::default_bucket_count,
+ const hasher& = hasher(),
+ const key_equal& = key_equal(),
+ const allocator_type& = allocator_type());
 
- explicit unordered_set(allocator_type const& a)
- : table_(boost::unordered_detail::default_bucket_count,
- hasher(), key_equal(), a)
- {
- }
+ explicit unordered_set(allocator_type const&);
 
- unordered_set(unordered_set const& other, allocator_type const& a)
- : table_(other.table_, a)
- {
- }
+ unordered_set(unordered_set const&, allocator_type const&);
 
         template <class InputIt>
- unordered_set(InputIt f, InputIt l)
- : table_(boost::unordered_detail::initial_size(f, l),
- hasher(), key_equal(), allocator_type())
- {
- table_.insert_range(f, l);
- }
+ unordered_set(InputIt f, InputIt l);
 
         template <class InputIt>
- unordered_set(InputIt f, InputIt l, size_type n,
- const hasher &hf = hasher(),
- const key_equal &eql = key_equal())
- : table_(boost::unordered_detail::initial_size(f, l, n),
- hf, eql, allocator_type())
- {
- table_.insert_range(f, l);
- }
-
+ unordered_set(
+ InputIt, InputIt,
+ size_type,
+ const hasher& = hasher(),
+ const key_equal& = key_equal());
+
         template <class InputIt>
- unordered_set(InputIt f, InputIt l, size_type n,
- const hasher &hf,
- const key_equal &eql,
- const allocator_type &a)
- : table_(boost::unordered_detail::initial_size(f, l, n), hf, eql, a)
- {
- table_.insert_range(f, l);
- }
+ unordered_set(
+ InputIt, InputIt,
+ size_type,
+ const hasher&,
+ const key_equal&,
+ const allocator_type&);
         
- ~unordered_set() {}
-
-#if !defined(BOOST_NO_RVALUE_REFERENCES)
- unordered_set(unordered_set const& other)
- : table_(other.table_)
- {
- }
-
- unordered_set(unordered_set&& other)
- : table_(other.table_, boost::unordered_detail::move_tag())
- {
- }
-
- unordered_set(unordered_set&& other, allocator_type const& a)
- : table_(other.table_, a, boost::unordered_detail::move_tag())
- {
- }
+ ~unordered_set();
 
- unordered_set& operator=(unordered_set const& x)
+ unordered_set& operator=(
+ BOOST_COPY_ASSIGN_REF(unordered_set) x)
         {
- table_ = x.table_;
+ table_.assign(x.table_);
             return *this;
         }
 
- unordered_set& operator=(unordered_set&& x)
+ unordered_set(unordered_set const&);
+
+#if BOOST_UNORDERED_USE_RV_REF
+ unordered_set& operator=(
+ BOOST_RV_REF(unordered_set) x)
         {
- table_.move(x.table_);
+ table_.move_assign(x.table_);
             return *this;
         }
-#else
- unordered_set(boost::unordered_detail::move_from<
- unordered_set<T, H, P, A>
- > other)
- : table_(other.source.table_, boost::unordered_detail::move_tag())
- {
- }
 
-#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0593)
- unordered_set& operator=(unordered_set x)
+ unordered_set(BOOST_RV_REF(unordered_set) other)
+ : table_(other.table_, ::boost::unordered::detail::move_tag())
         {
- table_.move(x.table_);
- return *this;
         }
 #endif
+
+#if !defined(BOOST_NO_RVALUE_REFERENCES)
+ unordered_set(unordered_set&&, allocator_type const&);
 #endif
 
 #if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
- unordered_set(std::initializer_list<value_type> list,
- size_type n = boost::unordered_detail::default_bucket_count,
- const hasher &hf = hasher(),
- const key_equal &eql = key_equal(),
- const allocator_type &a = allocator_type())
- : table_(boost::unordered_detail::initial_size(
- list.begin(), list.end(), n),
- hf, eql, a)
- {
- table_.insert_range(list.begin(), list.end());
- }
+ unordered_set(
+ std::initializer_list<value_type>,
+ size_type = ::boost::unordered::detail::default_bucket_count,
+ const hasher& = hasher(),
+ const key_equal&l = key_equal(),
+ const allocator_type& = allocator_type());
 
- unordered_set& operator=(std::initializer_list<value_type> list)
- {
- table_.clear();
- table_.insert_range(list.begin(), list.end());
- return *this;
- }
+ unordered_set& operator=(std::initializer_list<value_type>);
 #endif
 
         allocator_type get_allocator() const
@@ -235,10 +180,7 @@
             return table_.size_;
         }
 
- size_type max_size() const
- {
- return table_.max_size();
- }
+ size_type max_size() const;
 
         // iterators
 
@@ -254,12 +196,12 @@
 
         iterator end()
         {
- return iterator(table_.end());
+ return iterator();
         }
 
         const_iterator end() const
         {
- return const_iterator(table_.end());
+ return const_iterator();
         }
 
         const_iterator cbegin() const
@@ -269,37 +211,28 @@
 
         const_iterator cend() const
         {
- return const_iterator(table_.end());
+ return const_iterator();
         }
 
         // modifiers
 
-#if defined(BOOST_UNORDERED_STD_FORWARD)
+#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
         template <class... Args>
- std::pair<iterator, bool> emplace(Args&&... args)
- {
- return boost::unordered_detail::pair_cast<iterator, bool>(
- table_.emplace(std::forward<Args>(args)...));
- }
-
+ std::pair<iterator, bool> emplace(Args&&...);
         template <class... Args>
- iterator emplace_hint(const_iterator, Args&&... args)
- {
- return iterator(table_.emplace(std::forward<Args>(args)...).first);
- }
+ iterator emplace_hint(const_iterator, Args&&...);
 #else
 
- std::pair<iterator, bool> emplace(value_type const& v = value_type())
- {
- return boost::unordered_detail::pair_cast<iterator, bool>(
- table_.emplace(v));
- }
-
+ std::pair<iterator, bool> emplace(
+ boost::unordered::detail::empty_emplace
+ = boost::unordered::detail::empty_emplace(),
+ value_type v = value_type()
+ );
         iterator emplace_hint(const_iterator,
- value_type const& v = value_type())
- {
- return iterator(table_.emplace(v).first);
- }
+ boost::unordered::detail::empty_emplace
+ = boost::unordered::detail::empty_emplace(),
+ value_type v = value_type()
+ );
 
 #define BOOST_UNORDERED_EMPLACE(z, n, _) \
             template < \
@@ -307,24 +240,14 @@
> \
             std::pair<iterator, bool> emplace( \
                 BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
- ) \
- { \
- return boost::unordered_detail::pair_cast<iterator, bool>( \
- table_.emplace( \
- BOOST_UNORDERED_CALL_PARAMS(z, n) \
- )); \
- } \
+ ); \
                                                                                \
             template < \
                 BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
> \
             iterator emplace_hint(const_iterator, \
                 BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
- ) \
- { \
- return iterator(table_.emplace( \
- BOOST_UNORDERED_CALL_PARAMS(z, n)).first); \
- }
+ );
 
         BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
             BOOST_UNORDERED_EMPLACE, _)
@@ -333,105 +256,46 @@
 
 #endif
 
- std::pair<iterator, bool> insert(const value_type& obj)
- {
- return boost::unordered_detail::pair_cast<iterator, bool>(
- table_.emplace(obj));
- }
-
- iterator insert(const_iterator, const value_type& obj)
- {
- return iterator(table_.emplace(obj).first);
- }
-
- template <class InputIt>
- void insert(InputIt first, InputIt last)
- {
- table_.insert_range(first, last);
- }
+ std::pair<iterator, bool> insert(value_type const&);
+ iterator insert(const_iterator, value_type const&);
+#if BOOST_UNORDERED_USE_RV_REF
+ std::pair<iterator, bool> insert(BOOST_RV_REF(value_type));
+ iterator insert(const_iterator, BOOST_RV_REF(value_type));
+#endif
+ template <class InputIt> void insert(InputIt, InputIt);
 
 #if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
- void insert(std::initializer_list<value_type> list)
- {
- table_.insert_range(list.begin(), list.end());
- }
+ void insert(std::initializer_list<value_type>);
 #endif
 
- iterator erase(const_iterator position)
- {
- return iterator(table_.erase_return_iterator(get(position)));
- }
-
- size_type erase(const key_type& k)
- {
- return table_.erase_key(k);
- }
-
- iterator erase(const_iterator first, const_iterator last)
- {
- return iterator(table_.erase_range(get(first), get(last)));
- }
-
- void quick_erase(const_iterator position)
- {
- table_.erase(get(position));
- }
-
- void erase_return_void(const_iterator position)
- {
- table_.erase(get(position));
- }
-
- void clear()
- {
- table_.clear();
- }
+ iterator erase(const_iterator);
+ size_type erase(const key_type&);
+ iterator erase(const_iterator, const_iterator);
+ void quick_erase(const_iterator it) { erase(it); }
+ void erase_return_void(const_iterator it) { erase(it); }
 
- void swap(unordered_set& other)
- {
- table_.swap(other.table_);
- }
+ void clear();
+ void swap(unordered_set&);
 
         // observers
 
- hasher hash_function() const
- {
- return table_.hash_function();
- }
-
- key_equal key_eq() const
- {
- return table_.key_eq();
- }
+ hasher hash_function() const;
+ key_equal key_eq() const;
 
         // lookup
 
- const_iterator find(const key_type& k) const
- {
- return const_iterator(table_.find(k));
- }
+ const_iterator find(const key_type&) const;
 
         template <class CompatibleKey, class CompatibleHash,
             class CompatiblePredicate>
         const_iterator find(
- CompatibleKey const& k,
- CompatibleHash const& hash,
- CompatiblePredicate const& eq) const
- {
- return iterator(table_.find(k, hash, eq));
- }
- size_type count(const key_type& k) const
- {
- return table_.count(k);
- }
+ CompatibleKey const&,
+ CompatibleHash const&,
+ CompatiblePredicate const&) const;
 
+ size_type count(const key_type&) const;
         std::pair<const_iterator, const_iterator>
- equal_range(const key_type& k) const
- {
- return boost::unordered_detail::pair_cast<
- const_iterator, const_iterator>(
- table_.equal_range(k));
- }
+ equal_range(const key_type&) const;
 
         // bucket interface
 
@@ -445,24 +309,23 @@
             return table_.max_bucket_count();
         }
 
- size_type bucket_size(size_type n) const
- {
- return table_.bucket_size(n);
- }
+ size_type bucket_size(size_type n) const;
 
         size_type bucket(const key_type& k) const
         {
- return table_.bucket_index(k);
+ return table_.hash_function()(k) % table_.bucket_count_;
         }
 
         local_iterator begin(size_type n)
         {
- return local_iterator(table_.bucket_begin(n));
+ return local_iterator(
+ table_.bucket_begin(n), n, table_.bucket_count_);
         }
 
         const_local_iterator begin(size_type n) const
         {
- return const_local_iterator(table_.bucket_begin(n));
+ return const_local_iterator(
+ table_.bucket_begin(n), n, table_.bucket_count_);
         }
 
         local_iterator end(size_type)
@@ -477,7 +340,8 @@
 
         const_local_iterator cbegin(size_type n) const
         {
- return const_local_iterator(table_.bucket_begin(n));
+ return const_local_iterator(
+ table_.bucket_begin(n), n, table_.bucket_count_);
         }
 
         const_local_iterator cend(size_type) const
@@ -487,67 +351,27 @@
 
         // hash policy
 
- float load_factor() const
- {
- return table_.load_factor();
- }
-
         float max_load_factor() const
         {
             return table_.mlf_;
         }
 
- void max_load_factor(float m)
- {
- table_.max_load_factor(m);
- }
-
- void rehash(size_type n)
- {
- table_.rehash(n);
- }
+ float load_factor() const;
+ void max_load_factor(float);
+ void rehash(size_type n);
 
 #if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582)
- friend bool operator==<T, H, P, A>(
- unordered_set const&, unordered_set const&);
- friend bool operator!=<T, H, P, A>(
- unordered_set const&, unordered_set const&);
+ friend bool operator==<T,H,P,A>(
+ unordered_set const&, unordered_set const&);
+ friend bool operator!=<T,H,P,A>(
+ unordered_set const&, unordered_set const&);
 #endif
     }; // class template unordered_set
 
     template <class T, class H, class P, class A>
- inline bool operator==(unordered_set<T, H, P, A> const& m1,
- unordered_set<T, H, P, A> const& m2)
- {
-#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613))
- struct dummy { unordered_set<T,H,P,A> x; };
-#endif
- return m1.table_.equals(m2.table_);
- }
-
- template <class T, class H, class P, class A>
- inline bool operator!=(unordered_set<T, H, P, A> const& m1,
- unordered_set<T, H, P, A> const& m2)
- {
-#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613))
- struct dummy { unordered_set<T,H,P,A> x; };
-#endif
- return !m1.table_.equals(m2.table_);
- }
-
- template <class T, class H, class P, class A>
- inline void swap(unordered_set<T, H, P, A> &m1,
- unordered_set<T, H, P, A> &m2)
- {
-#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613))
- struct dummy { unordered_set<T,H,P,A> x; };
-#endif
- m1.swap(m2);
- }
-
- template <class T, class H, class P, class A>
     class unordered_multiset
     {
+ BOOST_COPYABLE_AND_MOVABLE(unordered_multiset)
     public:
 
         typedef T key_type;
@@ -561,36 +385,35 @@
 #endif
 
         typedef BOOST_DEDUCED_TYPENAME
- boost::unordered_detail::rebind_wrap<
+ ::boost::unordered::detail::rebind_wrap<
                 allocator_type, value_type>::type
             value_allocator;
+ typedef ::boost::unordered::detail::allocator_traits<value_allocator>
+ allocator_traits;
 
- typedef boost::unordered_detail::multiset<H, P,
+ typedef ::boost::unordered::detail::multiset<H, P,
             value_allocator> types;
         typedef BOOST_DEDUCED_TYPENAME types::impl table;
 
- typedef BOOST_DEDUCED_TYPENAME types::iterator_base iterator_base;
+ typedef BOOST_DEDUCED_TYPENAME types::node_ptr node_ptr;
 
     public:
 
         typedef BOOST_DEDUCED_TYPENAME
- value_allocator::pointer pointer;
- typedef BOOST_DEDUCED_TYPENAME
- value_allocator::const_pointer const_pointer;
+ allocator_traits::pointer pointer;
         typedef BOOST_DEDUCED_TYPENAME
- value_allocator::reference reference;
- typedef BOOST_DEDUCED_TYPENAME
- value_allocator::const_reference const_reference;
+ allocator_traits::const_pointer const_pointer;
+
+ typedef value_type& reference;
+ typedef value_type const& 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;
- typedef boost::unordered_detail::hash_const_iterator<
- value_allocator, boost::unordered_detail::grouped>
- const_iterator;
+ typedef ::boost::unordered::iterator_detail::cl_iterator<
+ value_allocator, false> const_local_iterator;
+ typedef ::boost::unordered::iterator_detail::c_iterator<
+ value_allocator, false> const_iterator;
         typedef const_local_iterator local_iterator;
         typedef const_iterator iterator;
 
@@ -599,131 +422,77 @@
 #endif
 
         table table_;
-
- BOOST_DEDUCED_TYPENAME types::iterator_base const&
- get(const_iterator const& it)
- {
- return boost::unordered_detail::iterator_access::get(it);
- }
 
     public:
 
         // construct/destroy/copy
 
         explicit unordered_multiset(
- size_type n = boost::unordered_detail::default_bucket_count,
- const hasher &hf = hasher(),
- const key_equal &eql = key_equal(),
- const allocator_type &a = allocator_type())
- : table_(n, hf, eql, a)
- {
- }
+ size_type = ::boost::unordered::detail::default_bucket_count,
+ const hasher& = hasher(),
+ const key_equal& = key_equal(),
+ const allocator_type& = allocator_type());
 
- explicit unordered_multiset(allocator_type const& a)
- : table_(boost::unordered_detail::default_bucket_count,
- hasher(), key_equal(), a)
- {
- }
+ explicit unordered_multiset(allocator_type const&);
 
- unordered_multiset(unordered_multiset const& other,
- allocator_type const& a)
- : table_(other.table_, a)
- {
- }
+ unordered_multiset(unordered_multiset const&, allocator_type const&);
 
         template <class InputIt>
- unordered_multiset(InputIt f, InputIt l)
- : table_(boost::unordered_detail::initial_size(f, l),
- hasher(), key_equal(), allocator_type())
- {
- table_.insert_range(f, l);
- }
+ unordered_multiset(InputIt, InputIt);
 
         template <class InputIt>
- unordered_multiset(InputIt f, InputIt l, size_type n,
- const hasher &hf = hasher(),
- const key_equal &eql = key_equal())
- : table_(boost::unordered_detail::initial_size(f, l, n),
- hf, eql, allocator_type())
- {
- table_.insert_range(f, l);
- }
+ unordered_multiset(
+ InputIt, InputIt,
+ size_type,
+ const hasher& = hasher(),
+ const key_equal& = key_equal());
 
         template <class InputIt>
- unordered_multiset(InputIt f, InputIt l, size_type n,
- const hasher &hf,
- const key_equal &eql,
- const allocator_type &a)
- : table_(boost::unordered_detail::initial_size(f, l, n), hf, eql, a)
- {
- table_.insert_range(f, l);
- }
-
- ~unordered_multiset() {}
-
-#if !defined(BOOST_NO_RVALUE_REFERENCES)
- unordered_multiset(unordered_multiset const& other)
- : table_(other.table_)
- {
- }
-
- unordered_multiset(unordered_multiset&& other)
- : table_(other.table_, boost::unordered_detail::move_tag())
- {
- }
+ unordered_multiset(
+ InputIt, InputIt,
+ size_type,
+ const hasher&,
+ const key_equal&,
+ const allocator_type&);
 
- unordered_multiset(unordered_multiset&& other, allocator_type const& a)
- : table_(other.table_, a, boost::unordered_detail::move_tag())
- {
- }
+ ~unordered_multiset();
 
- unordered_multiset& operator=(unordered_multiset const& x)
+ unordered_multiset& operator=(
+ BOOST_COPY_ASSIGN_REF(unordered_multiset) x)
         {
- table_ = x.table_;
+ table_.assign(x.table_);
             return *this;
         }
 
- unordered_multiset& operator=(unordered_multiset&& x)
+ unordered_multiset(unordered_multiset const&);
+
+#if BOOST_UNORDERED_USE_RV_REF
+ unordered_multiset& operator=(
+ BOOST_RV_REF(unordered_multiset) x)
         {
- table_.move(x.table_);
+ table_.move_assign(x.table_);
             return *this;
         }
-#else
- unordered_multiset(boost::unordered_detail::move_from<
- unordered_multiset<T, H, P, A>
- > other)
- : table_(other.source.table_, boost::unordered_detail::move_tag())
- {
- }
 
-#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0593)
- unordered_multiset& operator=(unordered_multiset x)
+ unordered_multiset(BOOST_RV_REF(unordered_multiset) other)
+ : table_(other.table_, ::boost::unordered::detail::move_tag())
         {
- table_.move(x.table_);
- return *this;
         }
 #endif
+
+#if !defined(BOOST_NO_RVALUE_REFERENCES)
+ unordered_multiset(unordered_multiset&&, allocator_type const&);
 #endif
 
 #if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
- unordered_multiset(std::initializer_list<value_type> list,
- size_type n = boost::unordered_detail::default_bucket_count,
- const hasher &hf = hasher(),
- const key_equal &eql = key_equal(),
- const allocator_type &a = allocator_type())
- : table_(boost::unordered_detail::initial_size(
- list.begin(), list.end(), n),
- hf, eql, a)
- {
- table_.insert_range(list.begin(), list.end());
- }
+ unordered_multiset(
+ std::initializer_list<value_type>,
+ size_type = ::boost::unordered::detail::default_bucket_count,
+ const hasher& = hasher(),
+ const key_equal&l = key_equal(),
+ const allocator_type& = allocator_type());
 
- unordered_multiset& operator=(std::initializer_list<value_type> list)
- {
- table_.clear();
- table_.insert_range(list.begin(), list.end());
- return *this;
- }
+ unordered_multiset& operator=(std::initializer_list<value_type>);
 #endif
 
         allocator_type get_allocator() const
@@ -743,10 +512,7 @@
             return table_.size_;
         }
 
- size_type max_size() const
- {
- return table_.max_size();
- }
+ size_type max_size() const;
 
         // iterators
 
@@ -762,12 +528,12 @@
 
         iterator end()
         {
- return iterator(table_.end());
+ return iterator();
         }
 
         const_iterator end() const
         {
- return const_iterator(table_.end());
+ return const_iterator();
         }
 
         const_iterator cbegin() const
@@ -777,35 +543,28 @@
 
         const_iterator cend() const
         {
- return const_iterator(table_.end());
+ return const_iterator();
         }
 
         // modifiers
 
-#if defined(BOOST_UNORDERED_STD_FORWARD)
+#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
         template <class... Args>
- iterator emplace(Args&&... args)
- {
- return iterator(table_.emplace(std::forward<Args>(args)...));
- }
-
+ iterator emplace(Args&&...);
         template <class... Args>
- iterator emplace_hint(const_iterator, Args&&... args)
- {
- return iterator(table_.emplace(std::forward<Args>(args)...));
- }
+ iterator emplace_hint(const_iterator, Args&&...);
 #else
 
- iterator emplace(value_type const& v = value_type())
- {
- return iterator(table_.emplace(v));
- }
-
+ iterator emplace(
+ boost::unordered::detail::empty_emplace
+ = boost::unordered::detail::empty_emplace(),
+ value_type v = value_type()
+ );
         iterator emplace_hint(const_iterator,
- value_type const& v = value_type())
- {
- return iterator(table_.emplace(v));
- }
+ boost::unordered::detail::empty_emplace
+ = boost::unordered::detail::empty_emplace(),
+ value_type v = value_type()
+ );
 
 #define BOOST_UNORDERED_EMPLACE(z, n, _) \
             template < \
@@ -813,23 +572,14 @@
> \
             iterator emplace( \
                 BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
- ) \
- { \
- return iterator( \
- table_.emplace(BOOST_UNORDERED_CALL_PARAMS(z, n))); \
- } \
+ ); \
                                                                                \
             template < \
                 BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
> \
             iterator emplace_hint(const_iterator, \
                 BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
- ) \
- { \
- return iterator(table_.emplace( \
- BOOST_UNORDERED_CALL_PARAMS(z, n) \
- )); \
- }
+ );
 
         BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
             BOOST_UNORDERED_EMPLACE, _)
@@ -838,105 +588,47 @@
 
 #endif
 
- iterator insert(const value_type& obj)
- {
- return iterator(table_.emplace(obj));
- }
-
- iterator insert(const_iterator, const value_type& obj)
- {
- return iterator(table_.emplace(obj));
- }
-
+ iterator insert(value_type const&);
+ iterator insert(const_iterator, value_type const&);
+#if BOOST_UNORDERED_USE_RV_REF
+ iterator insert(BOOST_RV_REF(value_type));
+ iterator insert(const_iterator, BOOST_RV_REF(value_type));
+#endif
         template <class InputIt>
- void insert(InputIt first, InputIt last)
- {
- table_.insert_range(first, last);
- }
+ void insert(InputIt, InputIt);
 
 #if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
- void insert(std::initializer_list<value_type> list)
- {
- table_.insert_range(list.begin(), list.end());
- }
+ void insert(std::initializer_list<value_type>);
 #endif
 
- iterator erase(const_iterator position)
- {
- return iterator(table_.erase_return_iterator(get(position)));
- }
-
- size_type erase(const key_type& k)
- {
- return table_.erase_key(k);
- }
-
- iterator erase(const_iterator first, const_iterator last)
- {
- return iterator(table_.erase_range(get(first), get(last)));
- }
-
- void quick_erase(const_iterator position)
- {
- table_.erase(get(position));
- }
-
- void erase_return_void(const_iterator position)
- {
- table_.erase(get(position));
- }
+ iterator erase(const_iterator);
+ size_type erase(const key_type&);
+ iterator erase(const_iterator, const_iterator);
+ void quick_erase(const_iterator position) { erase(position); }
+ void erase_return_void(const_iterator position) { erase(position); }
 
- void clear()
- {
- table_.clear();
- }
-
- void swap(unordered_multiset& other)
- {
- table_.swap(other.table_);
- }
+ void clear();
+ void swap(unordered_multiset&);
 
         // observers
 
- hasher hash_function() const
- {
- return table_.hash_function();
- }
-
- key_equal key_eq() const
- {
- return table_.key_eq();
- }
+ hasher hash_function() const;
+ key_equal key_eq() const;
 
         // lookup
 
- const_iterator find(const key_type& k) const
- {
- return const_iterator(table_.find(k));
- }
+ const_iterator find(const key_type&) const;
 
         template <class CompatibleKey, class CompatibleHash,
             class CompatiblePredicate>
         const_iterator find(
- CompatibleKey const& k,
- CompatibleHash const& hash,
- CompatiblePredicate const& eq) const
- {
- return iterator(table_.find(k, hash, eq));
- }
-
- size_type count(const key_type& k) const
- {
- return table_.count(k);
- }
+ CompatibleKey const&,
+ CompatibleHash const&,
+ CompatiblePredicate const&) const;
 
+ size_type count(const key_type&) const;
         std::pair<const_iterator, const_iterator>
- equal_range(const key_type& k) const
- {
- return boost::unordered_detail::pair_cast<
- const_iterator, const_iterator>(
- table_.equal_range(k));
- }
+ equal_range(const key_type&) const;
 
         // bucket interface
 
@@ -950,24 +642,23 @@
             return table_.max_bucket_count();
         }
 
- size_type bucket_size(size_type n) const
- {
- return table_.bucket_size(n);
- }
+ size_type bucket_size(size_type) const;
 
         size_type bucket(const key_type& k) const
         {
- return table_.bucket_index(k);
+ return table_.hash_function()(k) % table_.bucket_count_;
         }
 
         local_iterator begin(size_type n)
         {
- return local_iterator(table_.bucket_begin(n));
+ return local_iterator(
+ table_.bucket_begin(n), n, table_.bucket_count_);
         }
 
         const_local_iterator begin(size_type n) const
         {
- return const_local_iterator(table_.bucket_begin(n));
+ return const_local_iterator(
+ table_.bucket_begin(n), n, table_.bucket_count_);
         }
 
         local_iterator end(size_type)
@@ -982,7 +673,8 @@
 
         const_local_iterator cbegin(size_type n) const
         {
- return const_local_iterator(table_.bucket_begin(n));
+ return const_local_iterator(
+ table_.bucket_begin(n), n, table_.bucket_count_);
         }
 
         const_local_iterator cend(size_type) const
@@ -992,37 +684,763 @@
 
         // hash policy
 
- float load_factor() const
- {
- return table_.load_factor();
- }
-
         float max_load_factor() const
         {
             return table_.mlf_;
         }
 
- void max_load_factor(float m)
- {
- table_.max_load_factor(m);
- }
-
- void rehash(size_type n)
- {
- table_.rehash(n);
- }
+ float load_factor() const;
+ void max_load_factor(float);
+ void rehash(size_type);
 
 #if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582)
- friend bool operator==<T, H, P, A>(
- unordered_multiset const&, unordered_multiset const&);
- friend bool operator!=<T, H, P, A>(
- unordered_multiset const&, unordered_multiset const&);
+ friend bool operator==<T,H,P,A>(
+ unordered_multiset const&, unordered_multiset const&);
+ friend bool operator!=<T,H,P,A>(
+ unordered_multiset const&, unordered_multiset const&);
 #endif
     }; // class template unordered_multiset
 
+////////////////////////////////////////////////////////////////////////////////
+
+ template <class T, class H, class P, class A>
+ unordered_set<T,H,P,A>::unordered_set(
+ size_type n, const hasher &hf, const key_equal &eql,
+ const allocator_type &a)
+ : table_(n, hf, eql, a)
+ {
+ }
+
+ template <class T, class H, class P, class A>
+ unordered_set<T,H,P,A>::unordered_set(allocator_type const& a)
+ : table_(::boost::unordered::detail::default_bucket_count,
+ hasher(), key_equal(), a)
+ {
+ }
+
+ template <class T, class H, class P, class A>
+ unordered_set<T,H,P,A>::unordered_set(
+ unordered_set const& other, allocator_type const& a)
+ : table_(other.table_, a)
+ {
+ }
+
+ template <class T, class H, class P, class A>
+ template <class InputIt>
+ unordered_set<T,H,P,A>::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 <class T, class H, class P, class A>
+ template <class InputIt>
+ unordered_set<T,H,P,A>::unordered_set(
+ InputIt f, InputIt l,
+ size_type n,
+ const hasher &hf,
+ const key_equal &eql)
+ : table_(::boost::unordered::detail::initial_size(f, l, n),
+ hf, eql, allocator_type())
+ {
+ table_.insert_range(f, l);
+ }
+
+ template <class T, class H, class P, class A>
+ template <class InputIt>
+ unordered_set<T,H,P,A>::unordered_set(
+ InputIt f, InputIt l,
+ size_type n,
+ const hasher &hf,
+ const key_equal &eql,
+ const allocator_type &a)
+ : table_(::boost::unordered::detail::initial_size(f, l, n), hf, eql, a)
+ {
+ table_.insert_range(f, l);
+ }
+
+ template <class T, class H, class P, class A>
+ unordered_set<T,H,P,A>::~unordered_set() {}
+
+ template <class T, class H, class P, class A>
+ unordered_set<T,H,P,A>::unordered_set(unordered_set const& other)
+ : table_(other.table_)
+ {
+ }
+
+#if !defined(BOOST_NO_RVALUE_REFERENCES)
+
+ template <class T, class H, class P, class A>
+ unordered_set<T,H,P,A>::unordered_set(
+ unordered_set&& other, allocator_type const& a)
+ : table_(other.table_, a, ::boost::unordered::detail::move_tag())
+ {
+ }
+
+#endif
+
+#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
+
+ template <class T, class H, class P, class A>
+ unordered_set<T,H,P,A>::unordered_set(
+ std::initializer_list<value_type> list, size_type n,
+ const hasher &hf, const key_equal &eql, const allocator_type &a)
+ : table_(
+ ::boost::unordered::detail::initial_size(
+ list.begin(), list.end(), n),
+ hf, eql, a)
+ {
+ table_.insert_range(list.begin(), list.end());
+ }
+
+ template <class T, class H, class P, class A>
+ unordered_set<T,H,P,A>& unordered_set<T,H,P,A>::operator=(
+ std::initializer_list<value_type> list)
+ {
+ table_.clear();
+ table_.insert_range(list.begin(), list.end());
+ return *this;
+ }
+
+#endif
+
+ // size and capacity
+
+ template <class T, class H, class P, class A>
+ std::size_t unordered_set<T,H,P,A>::max_size() const
+ {
+ return table_.max_size();
+ }
+
+ // modifiers
+
+#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
+ template <class T, class H, class P, class A>
+ template <class... Args>
+ std::pair<BOOST_DEDUCED_TYPENAME unordered_set<T,H,P,A>::iterator, bool>
+ unordered_set<T,H,P,A>::emplace(Args&&... args)
+ {
+ return BOOST_UNORDERED_PAIR_CAST(iterator, bool,
+ table_.emplace(std::forward<Args>(args)...));
+ }
+
+ template <class T, class H, class P, class A>
+ template <class... Args>
+ BOOST_DEDUCED_TYPENAME unordered_set<T,H,P,A>::iterator
+ unordered_set<T,H,P,A>::emplace_hint(const_iterator, Args&&... args)
+ {
+ return iterator(table_.emplace(std::forward<Args>(args)...).first);
+ }
+#else
+
+ template <class T, class H, class P, class A>
+ std::pair<BOOST_DEDUCED_TYPENAME unordered_set<T,H,P,A>::iterator, bool>
+ unordered_set<T,H,P,A>::emplace(
+ boost::unordered::detail::empty_emplace,
+ value_type v
+ )
+ {
+ return BOOST_UNORDERED_PAIR_CAST(iterator, bool,
+ table_.emplace(boost::move(v)));
+ }
+
+ template <class T, class H, class P, class A>
+ BOOST_DEDUCED_TYPENAME unordered_set<T,H,P,A>::iterator
+ unordered_set<T,H,P,A>::emplace_hint(const_iterator,
+ boost::unordered::detail::empty_emplace,
+ value_type v
+ )
+ {
+ return iterator(table_.emplace(boost::move(v)).first);
+ }
+
+#define BOOST_UNORDERED_EMPLACE(z, n, _) \
+ template <class T, class H, class P, class A> \
+ template < \
+ BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
+ > \
+ std::pair< \
+ BOOST_DEDUCED_TYPENAME unordered_set<T,H,P,A>::iterator, \
+ bool> \
+ unordered_set<T,H,P,A>::emplace( \
+ BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \
+ { \
+ return \
+ BOOST_UNORDERED_PAIR_CAST(iterator, bool, \
+ table_.emplace( \
+ BOOST_UNORDERED_CALL_PARAMS(z, n))); \
+ } \
+ \
+ template <class T, class H, class P, class A> \
+ template < \
+ BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
+ > \
+ BOOST_DEDUCED_TYPENAME unordered_set<T,H,P,A>::iterator \
+ unordered_set<T,H,P,A>::emplace_hint( \
+ const_iterator, \
+ BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
+ ) \
+ { \
+ return iterator(table_.emplace( \
+ BOOST_UNORDERED_CALL_PARAMS(z, n)).first); \
+ }
+
+ BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
+ BOOST_UNORDERED_EMPLACE, _)
+
+#undef BOOST_UNORDERED_EMPLACE
+
+#endif
+
+ template <class T, class H, class P, class A>
+ std::pair<BOOST_DEDUCED_TYPENAME unordered_set<T,H,P,A>::iterator, bool>
+ unordered_set<T,H,P,A>::insert(value_type const& obj)
+ {
+ return BOOST_UNORDERED_PAIR_CAST(iterator, bool,
+ table_.emplace(obj));
+ }
+
+ template <class T, class H, class P, class A>
+ BOOST_DEDUCED_TYPENAME unordered_set<T,H,P,A>::iterator
+ unordered_set<T,H,P,A>::insert(const_iterator,
+ value_type const& obj)
+ {
+ return iterator(table_.emplace(obj).first);
+ }
+
+#if BOOST_UNORDERED_USE_RV_REF
+ template <class T, class H, class P, class A>
+ std::pair<BOOST_DEDUCED_TYPENAME unordered_set<T,H,P,A>::iterator, bool>
+ unordered_set<T,H,P,A>::insert(BOOST_RV_REF(value_type) obj)
+ {
+ return BOOST_UNORDERED_PAIR_CAST(iterator, bool,
+ table_.emplace(boost::move(obj)));
+ }
+
+ template <class T, class H, class P, class A>
+ BOOST_DEDUCED_TYPENAME unordered_set<T,H,P,A>::iterator
+ unordered_set<T,H,P,A>::insert(const_iterator,
+ BOOST_RV_REF(value_type) obj)
+ {
+ return iterator(table_.emplace(boost::move(obj)).first);
+ }
+#endif
+
+ template <class T, class H, class P, class A>
+ template <class InputIt>
+ void unordered_set<T,H,P,A>::insert(InputIt first, InputIt last)
+ {
+ table_.insert_range(first, last);
+ }
+
+#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
+ template <class T, class H, class P, class A>
+ void unordered_set<T,H,P,A>::insert(std::initializer_list<value_type> list)
+ {
+ table_.insert_range(list.begin(), list.end());
+ }
+#endif
+
+ template <class T, class H, class P, class A>
+ BOOST_DEDUCED_TYPENAME unordered_set<T,H,P,A>::iterator
+ unordered_set<T,H,P,A>::erase(const_iterator position)
+ {
+ return iterator(table_.erase(position.node_));
+ }
+
+ template <class T, class H, class P, class A>
+ BOOST_DEDUCED_TYPENAME unordered_set<T,H,P,A>::size_type
+ unordered_set<T,H,P,A>::erase(const key_type& k)
+ {
+ return table_.erase_key(k);
+ }
+
+ template <class T, class H, class P, class A>
+ BOOST_DEDUCED_TYPENAME unordered_set<T,H,P,A>::iterator
+ unordered_set<T,H,P,A>::erase(const_iterator first, const_iterator last)
+ {
+ return iterator(table_.erase_range(first.node_, last.node_));
+ }
+
+ template <class T, class H, class P, class A>
+ void unordered_set<T,H,P,A>::clear()
+ {
+ table_.clear();
+ }
+
+ template <class T, class H, class P, class A>
+ void unordered_set<T,H,P,A>::swap(unordered_set& other)
+ {
+ table_.swap(other.table_);
+ }
+
+ // observers
+
+ template <class T, class H, class P, class A>
+ BOOST_DEDUCED_TYPENAME unordered_set<T,H,P,A>::hasher
+ unordered_set<T,H,P,A>::hash_function() const
+ {
+ return table_.hash_function();
+ }
+
+ template <class T, class H, class P, class A>
+ BOOST_DEDUCED_TYPENAME unordered_set<T,H,P,A>::key_equal
+ unordered_set<T,H,P,A>::key_eq() const
+ {
+ return table_.key_eq();
+ }
+
+ // lookup
+
+ template <class T, class H, class P, class A>
+ BOOST_DEDUCED_TYPENAME unordered_set<T,H,P,A>::const_iterator
+ unordered_set<T,H,P,A>::find(const key_type& k) const
+ {
+ return const_iterator(table_.find_node(k));
+ }
+
+ template <class T, class H, class P, class A>
+ template <class CompatibleKey, class CompatibleHash,
+ class CompatiblePredicate>
+ BOOST_DEDUCED_TYPENAME unordered_set<T,H,P,A>::const_iterator
+ unordered_set<T,H,P,A>::find(
+ CompatibleKey const& k,
+ CompatibleHash const& hash,
+ CompatiblePredicate const& eq) const
+ {
+ return const_iterator(table_.generic_find_node(k, hash, eq));
+ }
+
+ template <class T, class H, class P, class A>
+ BOOST_DEDUCED_TYPENAME unordered_set<T,H,P,A>::size_type
+ unordered_set<T,H,P,A>::count(const key_type& k) const
+ {
+ return table_.count(k);
+ }
+
+ template <class T, class H, class P, class A>
+ std::pair<
+ BOOST_DEDUCED_TYPENAME unordered_set<T,H,P,A>::const_iterator,
+ BOOST_DEDUCED_TYPENAME unordered_set<T,H,P,A>::const_iterator>
+ unordered_set<T,H,P,A>::equal_range(const key_type& k) const
+ {
+ return BOOST_UNORDERED_PAIR_CAST(const_iterator, const_iterator,
+ table_.equal_range(k));
+ }
+
+ template <class T, class H, class P, class A>
+ BOOST_DEDUCED_TYPENAME unordered_set<T,H,P,A>::size_type
+ unordered_set<T,H,P,A>::bucket_size(size_type n) const
+ {
+ return table_.bucket_size(n);
+ }
+
+ // hash policy
+
+ template <class T, class H, class P, class A>
+ float unordered_set<T,H,P,A>::load_factor() const
+ {
+ return table_.load_factor();
+ }
+
+ template <class T, class H, class P, class A>
+ void unordered_set<T,H,P,A>::max_load_factor(float m)
+ {
+ table_.max_load_factor(m);
+ }
+
+ template <class T, class H, class P, class A>
+ void unordered_set<T,H,P,A>::rehash(size_type n)
+ {
+ table_.rehash(n);
+ }
+
+ template <class T, class H, class P, class A>
+ inline bool operator==(
+ unordered_set<T,H,P,A> const& m1,
+ unordered_set<T,H,P,A> const& m2)
+ {
+#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613))
+ struct dummy { unordered_set<T,H,P,A> x; };
+#endif
+ return m1.table_.equals(m2.table_);
+ }
+
+ template <class T, class H, class P, class A>
+ inline bool operator!=(
+ unordered_set<T,H,P,A> const& m1,
+ unordered_set<T,H,P,A> const& m2)
+ {
+#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613))
+ struct dummy { unordered_set<T,H,P,A> x; };
+#endif
+ return !m1.table_.equals(m2.table_);
+ }
+
+ template <class T, class H, class P, class A>
+ inline void swap(
+ unordered_set<T,H,P,A> &m1,
+ unordered_set<T,H,P,A> &m2)
+ {
+#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613))
+ struct dummy { unordered_set<T,H,P,A> x; };
+#endif
+ m1.swap(m2);
+ }
+
+////////////////////////////////////////////////////////////////////////////////
+
+ template <class T, class H, class P, class A>
+ unordered_multiset<T,H,P,A>::unordered_multiset(
+ size_type n, const hasher &hf, const key_equal &eql,
+ const allocator_type &a)
+ : table_(n, hf, eql, a)
+ {
+ }
+
+ template <class T, class H, class P, class A>
+ unordered_multiset<T,H,P,A>::unordered_multiset(allocator_type const& a)
+ : table_(::boost::unordered::detail::default_bucket_count,
+ hasher(), key_equal(), a)
+ {
+ }
+
+ template <class T, class H, class P, class A>
+ unordered_multiset<T,H,P,A>::unordered_multiset(
+ unordered_multiset const& other, allocator_type const& a)
+ : table_(other.table_, a)
+ {
+ }
+
+ template <class T, class H, class P, class A>
+ template <class InputIt>
+ unordered_multiset<T,H,P,A>::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 <class T, class H, class P, class A>
+ template <class InputIt>
+ unordered_multiset<T,H,P,A>::unordered_multiset(
+ InputIt f, InputIt l,
+ size_type n,
+ const hasher &hf,
+ const key_equal &eql)
+ : table_(::boost::unordered::detail::initial_size(f, l, n),
+ hf, eql, allocator_type())
+ {
+ table_.insert_range(f, l);
+ }
+
+ template <class T, class H, class P, class A>
+ template <class InputIt>
+ unordered_multiset<T,H,P,A>::unordered_multiset(
+ InputIt f, InputIt l,
+ size_type n,
+ const hasher &hf,
+ const key_equal &eql,
+ const allocator_type &a)
+ : table_(::boost::unordered::detail::initial_size(f, l, n), hf, eql, a)
+ {
+ table_.insert_range(f, l);
+ }
+
+ template <class T, class H, class P, class A>
+ unordered_multiset<T,H,P,A>::~unordered_multiset() {}
+
+ template <class T, class H, class P, class A>
+ unordered_multiset<T,H,P,A>::unordered_multiset(
+ unordered_multiset const& other)
+ : table_(other.table_)
+ {
+ }
+
+#if !defined(BOOST_NO_RVALUE_REFERENCES)
+
+ template <class T, class H, class P, class A>
+ unordered_multiset<T,H,P,A>::unordered_multiset(
+ unordered_multiset&& other, allocator_type const& a)
+ : table_(other.table_, a, ::boost::unordered::detail::move_tag())
+ {
+ }
+
+#endif
+
+#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
+ template <class T, class H, class P, class A>
+ unordered_multiset<T,H,P,A>::unordered_multiset(
+ std::initializer_list<value_type> list, size_type n,
+ const hasher &hf, const key_equal &eql, const allocator_type &a)
+ : table_(
+ ::boost::unordered::detail::initial_size(
+ list.begin(), list.end(), n),
+ hf, eql, a)
+ {
+ table_.insert_range(list.begin(), list.end());
+ }
+
+ template <class T, class H, class P, class A>
+ unordered_multiset<T,H,P,A>& unordered_multiset<T,H,P,A>::operator=(
+ std::initializer_list<value_type> list)
+ {
+ table_.clear();
+ table_.insert_range(list.begin(), list.end());
+ return *this;
+ }
+#endif
+
+ // size and capacity
+
+ template <class T, class H, class P, class A>
+ std::size_t unordered_multiset<T,H,P,A>::max_size() const
+ {
+ return table_.max_size();
+ }
+
+ // modifiers
+
+#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
+
+ template <class T, class H, class P, class A>
+ template <class... Args>
+ BOOST_DEDUCED_TYPENAME unordered_multiset<T,H,P,A>::iterator
+ unordered_multiset<T,H,P,A>::emplace(Args&&... args)
+ {
+ return iterator(table_.emplace(std::forward<Args>(args)...));
+ }
+
+ template <class T, class H, class P, class A>
+ template <class... Args>
+ BOOST_DEDUCED_TYPENAME unordered_multiset<T,H,P,A>::iterator
+ unordered_multiset<T,H,P,A>::emplace_hint(
+ const_iterator, Args&&... args)
+ {
+ return iterator(table_.emplace(std::forward<Args>(args)...));
+ }
+
+#else
+
+ template <class T, class H, class P, class A>
+ BOOST_DEDUCED_TYPENAME unordered_multiset<T,H,P,A>::iterator
+ unordered_multiset<T,H,P,A>::emplace(
+ boost::unordered::detail::empty_emplace,
+ value_type v
+ )
+ {
+ return iterator(table_.emplace(boost::move(v)));
+ }
+
+ template <class T, class H, class P, class A>
+ BOOST_DEDUCED_TYPENAME unordered_multiset<T,H,P,A>::iterator
+ unordered_multiset<T,H,P,A>::emplace_hint(const_iterator,
+ boost::unordered::detail::empty_emplace,
+ value_type v
+ )
+ {
+ return iterator(table_.emplace(boost::move(v)));
+ }
+
+#define BOOST_UNORDERED_EMPLACE(z, n, _) \
+ template <class T, class H, class P, class A> \
+ template < \
+ BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
+ > \
+ BOOST_DEDUCED_TYPENAME unordered_multiset<T,H,P,A>::iterator \
+ unordered_multiset<T,H,P,A>::emplace( \
+ BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \
+ { \
+ return iterator(table_.emplace( \
+ BOOST_UNORDERED_CALL_PARAMS(z, n))); \
+ } \
+ \
+ template <class T, class H, class P, class A> \
+ template < \
+ BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
+ > \
+ BOOST_DEDUCED_TYPENAME unordered_multiset<T,H,P,A>::iterator \
+ unordered_multiset<T,H,P,A>::emplace_hint( \
+ const_iterator, \
+ BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \
+ { \
+ return iterator(table_.emplace( \
+ BOOST_UNORDERED_CALL_PARAMS(z, n))); \
+ }
+
+ BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
+ BOOST_UNORDERED_EMPLACE, _)
+
+#undef BOOST_UNORDERED_EMPLACE
+
+#endif
+
+ template <class T, class H, class P, class A>
+ BOOST_DEDUCED_TYPENAME unordered_multiset<T,H,P,A>::iterator
+ unordered_multiset<T,H,P,A>::insert(value_type const& obj)
+ {
+ return iterator(table_.emplace(obj));
+ }
+
+ template <class T, class H, class P, class A>
+ BOOST_DEDUCED_TYPENAME unordered_multiset<T,H,P,A>::iterator
+ unordered_multiset<T,H,P,A>::insert(const_iterator,
+ value_type const& obj)
+ {
+ return iterator(table_.emplace(obj));
+ }
+
+#if BOOST_UNORDERED_USE_RV_REF
+ template <class T, class H, class P, class A>
+ BOOST_DEDUCED_TYPENAME unordered_multiset<T,H,P,A>::iterator
+ unordered_multiset<T,H,P,A>::insert(BOOST_RV_REF(value_type) obj)
+ {
+ return iterator(table_.emplace(boost::move(obj)));
+ }
+
+ template <class T, class H, class P, class A>
+ BOOST_DEDUCED_TYPENAME unordered_multiset<T,H,P,A>::iterator
+ unordered_multiset<T,H,P,A>::insert(const_iterator,
+ BOOST_RV_REF(value_type) obj)
+ {
+ return iterator(table_.emplace(boost::move(obj)));
+ }
+#endif
+
+ template <class T, class H, class P, class A>
+ template <class InputIt>
+ void unordered_multiset<T,H,P,A>::insert(InputIt first, InputIt last)
+ {
+ table_.insert_range(first, last);
+ }
+
+#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
+ template <class T, class H, class P, class A>
+ void unordered_multiset<T,H,P,A>::insert(std::initializer_list<value_type> list)
+ {
+ table_.insert_range(list.begin(), list.end());
+ }
+#endif
+
+ template <class T, class H, class P, class A>
+ BOOST_DEDUCED_TYPENAME unordered_multiset<T,H,P,A>::iterator
+ unordered_multiset<T,H,P,A>::erase(const_iterator position)
+ {
+ return iterator(table_.erase(position.node_));
+ }
+
+ template <class T, class H, class P, class A>
+ BOOST_DEDUCED_TYPENAME unordered_multiset<T,H,P,A>::size_type
+ unordered_multiset<T,H,P,A>::erase(const key_type& k)
+ {
+ return table_.erase_key(k);
+ }
+
+ template <class T, class H, class P, class A>
+ BOOST_DEDUCED_TYPENAME unordered_multiset<T,H,P,A>::iterator
+ unordered_multiset<T,H,P,A>::erase(const_iterator first, const_iterator last)
+ {
+ return iterator(table_.erase_range(first.node_, last.node_));
+ }
+
+ template <class T, class H, class P, class A>
+ void unordered_multiset<T,H,P,A>::clear()
+ {
+ table_.clear();
+ }
+
+ template <class T, class H, class P, class A>
+ void unordered_multiset<T,H,P,A>::swap(unordered_multiset& other)
+ {
+ table_.swap(other.table_);
+ }
+
+ // observers
+
+ template <class T, class H, class P, class A>
+ BOOST_DEDUCED_TYPENAME unordered_multiset<T,H,P,A>::hasher
+ unordered_multiset<T,H,P,A>::hash_function() const
+ {
+ return table_.hash_function();
+ }
+
+ template <class T, class H, class P, class A>
+ BOOST_DEDUCED_TYPENAME unordered_multiset<T,H,P,A>::key_equal
+ unordered_multiset<T,H,P,A>::key_eq() const
+ {
+ return table_.key_eq();
+ }
+
+ // lookup
+
+ template <class T, class H, class P, class A>
+ BOOST_DEDUCED_TYPENAME unordered_multiset<T,H,P,A>::const_iterator
+ unordered_multiset<T,H,P,A>::find(const key_type& k) const
+ {
+ return const_iterator(table_.find_node(k));
+ }
+
+ template <class T, class H, class P, class A>
+ template <class CompatibleKey, class CompatibleHash,
+ class CompatiblePredicate>
+ BOOST_DEDUCED_TYPENAME unordered_multiset<T,H,P,A>::const_iterator
+ unordered_multiset<T,H,P,A>::find(
+ CompatibleKey const& k,
+ CompatibleHash const& hash,
+ CompatiblePredicate const& eq) const
+ {
+ return const_iterator(table_.generic_find_node(k, hash, eq));
+ }
+
+ template <class T, class H, class P, class A>
+ BOOST_DEDUCED_TYPENAME unordered_multiset<T,H,P,A>::size_type
+ unordered_multiset<T,H,P,A>::count(const key_type& k) const
+ {
+ return table_.count(k);
+ }
+
+ template <class T, class H, class P, class A>
+ std::pair<
+ BOOST_DEDUCED_TYPENAME unordered_multiset<T,H,P,A>::const_iterator,
+ BOOST_DEDUCED_TYPENAME unordered_multiset<T,H,P,A>::const_iterator>
+ unordered_multiset<T,H,P,A>::equal_range(const key_type& k) const
+ {
+ return BOOST_UNORDERED_PAIR_CAST(const_iterator, const_iterator,
+ table_.equal_range(k));
+ }
+
+ template <class T, class H, class P, class A>
+ BOOST_DEDUCED_TYPENAME unordered_multiset<T,H,P,A>::size_type
+ unordered_multiset<T,H,P,A>::bucket_size(size_type n) const
+ {
+ return table_.bucket_size(n);
+ }
+
+ // hash policy
+
+ template <class T, class H, class P, class A>
+ float unordered_multiset<T,H,P,A>::load_factor() const
+ {
+ return table_.load_factor();
+ }
+
+ template <class T, class H, class P, class A>
+ void unordered_multiset<T,H,P,A>::max_load_factor(float m)
+ {
+ table_.max_load_factor(m);
+ }
+
+ template <class T, class H, class P, class A>
+ void unordered_multiset<T,H,P,A>::rehash(size_type n)
+ {
+ table_.rehash(n);
+ }
+
     template <class T, class H, class P, class A>
- inline bool operator==(unordered_multiset<T, H, P, A> const& m1,
- unordered_multiset<T, H, P, A> const& m2)
+ inline bool operator==(
+ unordered_multiset<T,H,P,A> const& m1,
+ unordered_multiset<T,H,P,A> const& m2)
     {
 #if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613))
         struct dummy { unordered_multiset<T,H,P,A> x; };
@@ -1031,8 +1449,9 @@
     }
 
     template <class T, class H, class P, class A>
- inline bool operator!=(unordered_multiset<T, H, P, A> const& m1,
- unordered_multiset<T, H, P, A> const& m2)
+ inline bool operator!=(
+ unordered_multiset<T,H,P,A> const& m1,
+ unordered_multiset<T,H,P,A> const& m2)
     {
 #if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613))
         struct dummy { unordered_multiset<T,H,P,A> x; };
@@ -1041,8 +1460,9 @@
     }
 
     template <class T, class H, class P, class A>
- inline void swap(unordered_multiset<T, H, P, A> &m1,
- unordered_multiset<T, H, P, A> &m2)
+ inline void swap(
+ unordered_multiset<T,H,P,A> &m1,
+ unordered_multiset<T,H,P,A> &m2)
     {
 #if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613))
         struct dummy { unordered_multiset<T,H,P,A> x; };
@@ -1050,6 +1470,7 @@
         m1.swap(m2);
     }
 
+} // namespace unordered
 } // namespace boost
 
 #if defined(BOOST_MSVC)

Modified: branches/release/boost/unordered/unordered_set_fwd.hpp
==============================================================================
--- branches/release/boost/unordered/unordered_set_fwd.hpp (original)
+++ branches/release/boost/unordered/unordered_set_fwd.hpp 2011-08-21 15:19:12 EDT (Sun, 21 Aug 2011)
@@ -1,5 +1,5 @@
 
-// Copyright (C) 2008-2009 Daniel James.
+// Copyright (C) 2008-2011 Daniel James.
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 
@@ -10,42 +10,38 @@
 # pragma once
 #endif
 
-#include <boost/config.hpp>
-#include <memory>
-#include <functional>
-#include <boost/functional/hash_fwd.hpp>
+#include <boost/unordered/detail/fwd.hpp>
 
 namespace boost
 {
- template <class T,
- class H = hash<T>,
- class P = std::equal_to<T>,
- class A = std::allocator<T> >
- class unordered_set;
- template <class T, class H, class P, class A>
- inline bool operator==(unordered_set<T, H, P, A> const&,
- unordered_set<T, H, P, A> const&);
- template <class T, class H, class P, class A>
- inline bool operator!=(unordered_set<T, H, P, A> const&,
- unordered_set<T, H, P, A> const&);
- template <class T, class H, class P, class A>
- inline void swap(unordered_set<T, H, P, A> &m1,
- unordered_set<T, H, P, A> &m2);
-
- template <class T,
- class H = hash<T>,
- class P = std::equal_to<T>,
- class A = std::allocator<T> >
- class unordered_multiset;
- template <class T, class H, class P, class A>
- inline bool operator==(unordered_multiset<T, H, P, A> const&,
- unordered_multiset<T, H, P, A> const&);
- template <class T, class H, class P, class A>
- inline bool operator!=(unordered_multiset<T, H, P, A> const&,
- unordered_multiset<T, H, P, A> const&);
- template <class T, class H, class P, class A>
- inline void swap(unordered_multiset<T, H, P, A> &m1,
- unordered_multiset<T, H, P, A> &m2);
+ namespace unordered
+ {
+ template <class T, class H, class P, class A>
+ inline bool operator==(unordered_set<T, H, P, A> const&,
+ unordered_set<T, H, P, A> const&);
+ template <class T, class H, class P, class A>
+ inline bool operator!=(unordered_set<T, H, P, A> const&,
+ unordered_set<T, H, P, A> const&);
+ template <class T, class H, class P, class A>
+ inline void swap(unordered_set<T, H, P, A> &m1,
+ unordered_set<T, H, P, A> &m2);
+
+ template <class T, class H, class P, class A>
+ inline bool operator==(unordered_multiset<T, H, P, A> const&,
+ unordered_multiset<T, H, P, A> const&);
+ template <class T, class H, class P, class A>
+ inline bool operator!=(unordered_multiset<T, H, P, A> const&,
+ unordered_multiset<T, H, P, A> const&);
+ template <class T, class H, class P, class A>
+ inline void swap(unordered_multiset<T, H, P, A> &m1,
+ unordered_multiset<T, H, P, A> &m2);
+ }
+
+ using ::boost::unordered::unordered_set;
+ using ::boost::unordered::unordered_multiset;
+ using ::boost::unordered::swap;
+ using ::boost::unordered::operator==;
+ using ::boost::unordered::operator!=;
 }
 
 #endif

Modified: branches/release/libs/unordered/doc/changes.qbk
==============================================================================
--- branches/release/libs/unordered/doc/changes.qbk (original)
+++ branches/release/libs/unordered/doc/changes.qbk 2011-08-21 15:19:12 EDT (Sun, 21 Aug 2011)
@@ -134,4 +134,21 @@
 * Fix a bug when inserting into an `unordered_map` or `unordered_set` using
   iterators which returns `value_type` by copy.
 
+[h2 Boost 1.48.0]
+
+This is major change which has been converted to use Boost.Move's move
+emulation, and be more compliant with the C++11 standard. This has resulted
+in some breaking changes:
+
+* Equality comparison has been changed to the C++11 specification.
+ In a container with equivalent keys, elements in a group with equal
+ keys used to have to be in the same order to be considered equal,
+ now they can be a permutation of each other.
+
+* The behaviour of swap is different when the two containers to be
+ swapped has unequal allocators. It used to allocate new nodes using
+ the appropriate allocators, it now swaps the allocators if
+ the allocator has a member structure `propagate_on_container_swap`,
+ such that `propagate_on_container_swap::value` is true.
+
 [endsect]

Modified: branches/release/libs/unordered/doc/rationale.qbk
==============================================================================
--- branches/release/libs/unordered/doc/rationale.qbk (original)
+++ branches/release/libs/unordered/doc/rationale.qbk 2011-08-21 15:19:12 EDT (Sun, 21 Aug 2011)
@@ -126,7 +126,7 @@
 
 It isn't clear how to swap containers when their allocators aren't equal.
 This is
-[@http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#431
+[@http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#431
 Issue 431: Swapping containers with unequal allocators]. This has been resolved
 with the new allocator specification, so this should be fixed when
 support is added.

Copied: branches/release/libs/unordered/doc/ref.php (from r73582, /trunk/libs/unordered/doc/ref.php)
==============================================================================
--- /trunk/libs/unordered/doc/ref.php (original)
+++ branches/release/libs/unordered/doc/ref.php 2011-08-21 15:19:12 EDT (Sun, 21 Aug 2011)
@@ -792,6 +792,7 @@
                 <para>This is not specified in the draft standard, but that is probably an oversight. The issue has been raised in
                   <ulink url="http://groups.google.com/group/comp.std.c++/browse_thread/thread/ab7c22a868fd370b">comp.std.c++</ulink>.</para>
               </notes>
+ </overloaded-method>
 <?php endif; ?>
           </method-group>
           <method-group name="bucket interface">

Modified: branches/release/libs/unordered/doc/ref.xml
==============================================================================
--- branches/release/libs/unordered/doc/ref.xml (original)
+++ branches/release/libs/unordered/doc/ref.xml 2011-08-21 15:19:12 EDT (Sun, 21 Aug 2011)
@@ -40,8 +40,8 @@
                     <row>
                       <entry><emphasis>Pred</emphasis></entry>
                       <entry>A binary function object that implements an equivalence relation on values of type <code>Value</code>.
- A binary function object that induces an equivalence relation on values of type Key.
- It takes two arguments of type Key and returns a value of type bool.</entry></row>
+ A binary function object that induces an equivalence relation on values of type <code>Value</code>.
+ It takes two arguments of type <code>Value</code> and returns a value of type bool.</entry></row>
                     <row>
                       <entry><emphasis>Alloc</emphasis></entry>
                       <entry>An allocator whose value type is the same as the container's value type.</entry></row></tbody></tgroup></informaltable></para>
@@ -360,7 +360,7 @@
               <type>iterator</type>
               <description>
                 <para>Inserts an object, constructed with the arguments <code>args</code>, in the container if and only if there is no element in the container with an equivalent value.</para>
- <para>hint is a suggestion to where the element should be inserted.</para>
+ <para><code>hint</code> is a suggestion to where the element should be inserted.</para>
               </description>
               <returns>
                 <para>If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent value.</para>
@@ -383,7 +383,7 @@
               </parameter>
               <type>std::pair&lt;iterator, bool&gt;</type>
               <description>
- <para>Inserts obj in the container if and only if there is no element in the container with an equivalent value.</para>
+ <para>Inserts <code>obj</code> in the container if and only if there is no element in the container with an equivalent value.</para>
               </description>
               <returns>
                 <para>The bool component of the return type is true if an insert took place.</para>
@@ -406,7 +406,7 @@
               </parameter>
               <type>iterator</type>
               <description>
- <para>Inserts obj in the container if and only if there is no element in the container with an equivalent value.</para>
+ <para>Inserts <code>obj</code> in the container if and only if there is no element in the container with an equivalent value.</para>
                 <para>hint is a suggestion to where the element should be inserted.</para>
               </description>
               <returns>
@@ -815,8 +815,8 @@
           <free-function-group name="Equality Comparisons">
             <function name="operator==">
               <template>
- <template-type-parameter name="Value">
- </template-type-parameter>
+ <template-type-parameter name="Value">
+ </template-type-parameter>
                 <template-type-parameter name="Hash">
                 </template-type-parameter>
                 <template-type-parameter name="Pred">
@@ -839,8 +839,8 @@
             </function>
             <function name="operator!=">
               <template>
- <template-type-parameter name="Value">
- </template-type-parameter>
+ <template-type-parameter name="Value">
+ </template-type-parameter>
                 <template-type-parameter name="Hash">
                 </template-type-parameter>
                 <template-type-parameter name="Pred">
@@ -865,8 +865,8 @@
           <free-function-group name="swap">
             <function name="swap">
               <template>
- <template-type-parameter name="Value">
- </template-type-parameter>
+ <template-type-parameter name="Value">
+ </template-type-parameter>
                 <template-type-parameter name="Hash">
                 </template-type-parameter>
                 <template-type-parameter name="Pred">
@@ -909,7 +909,7 @@
             </template-type-parameter>
           </template>
           <purpose><simpara>
- An unordered associative container that stores values. The same key can be stored multiple times.
+ An unordered associative container that stores values. The same key can be stored multiple times.
           </simpara></purpose>
           <description>
             <para>Based on chapter 23 of
@@ -929,8 +929,8 @@
                     <row>
                       <entry><emphasis>Pred</emphasis></entry>
                       <entry>A binary function object that implements an equivalence relation on values of type <code>Value</code>.
- A binary function object that induces an equivalence relation on values of type Key.
- It takes two arguments of type Key and returns a value of type bool.</entry></row>
+ A binary function object that induces an equivalence relation on values of type <code>Value</code>.
+ It takes two arguments of type <code>Value</code> and returns a value of type bool.</entry></row>
                     <row>
                       <entry><emphasis>Alloc</emphasis></entry>
                       <entry>An allocator whose value type is the same as the container's value type.</entry></row></tbody></tgroup></informaltable></para>
@@ -1248,7 +1248,7 @@
               <type>iterator</type>
               <description>
                 <para>Inserts an object, constructed with the arguments <code>args</code>, in the container.</para>
- <para>hint is a suggestion to where the element should be inserted.</para>
+ <para><code>hint</code> is a suggestion to where the element should be inserted.</para>
               </description>
               <returns>
                 <para>An iterator pointing to the inserted element.</para>
@@ -1271,7 +1271,7 @@
               </parameter>
               <type>iterator</type>
               <description>
- <para>Inserts obj in the container.</para>
+ <para>Inserts <code>obj</code> in the container.</para>
               </description>
               <returns>
                 <para>An iterator pointing to the inserted element.</para>
@@ -1293,7 +1293,7 @@
               </parameter>
               <type>iterator</type>
               <description>
- <para>Inserts obj in the container.</para>
+ <para>Inserts <code>obj</code> in the container.</para>
                 <para>hint is a suggestion to where the element should be inserted.</para>
               </description>
               <returns>
@@ -1321,7 +1321,7 @@
               </parameter>
               <type>void</type>
               <description>
- <para>Inserts a range of elements into the container.</para>
+ <para>Inserts a range of elements into the container. Elements are inserted if and only if there is no element in the container with an equivalent value.</para>
               </description>
               <throws>
                 <para>When inserting a single element, if an exception is thrown by an operation other than a call to <code>hasher</code> the function has no effect.</para>
@@ -1702,8 +1702,8 @@
           <free-function-group name="Equality Comparisons">
             <function name="operator==">
               <template>
- <template-type-parameter name="Value">
- </template-type-parameter>
+ <template-type-parameter name="Value">
+ </template-type-parameter>
                 <template-type-parameter name="Hash">
                 </template-type-parameter>
                 <template-type-parameter name="Pred">
@@ -1726,8 +1726,8 @@
             </function>
             <function name="operator!=">
               <template>
- <template-type-parameter name="Value">
- </template-type-parameter>
+ <template-type-parameter name="Value">
+ </template-type-parameter>
                 <template-type-parameter name="Hash">
                 </template-type-parameter>
                 <template-type-parameter name="Pred">
@@ -1752,8 +1752,8 @@
           <free-function-group name="swap">
             <function name="swap">
               <template>
- <template-type-parameter name="Value">
- </template-type-parameter>
+ <template-type-parameter name="Value">
+ </template-type-parameter>
                 <template-type-parameter name="Hash">
                 </template-type-parameter>
                 <template-type-parameter name="Pred">
@@ -1798,7 +1798,7 @@
               <default><type>std::equal_to&lt;Key&gt;</type></default>
             </template-type-parameter>
             <template-type-parameter name="Alloc">
- <default><type>std::allocator&lt;std::pair&lt;Key const, Mapped&gt; &gt;</type></default>
+ <default><type>std::allocator&lt;std::pair&lt;Key const, Mapped&gt;&gt;</type></default>
             </template-type-parameter>
           </template>
           <purpose><simpara>
@@ -1825,8 +1825,8 @@
                     <row>
                       <entry><emphasis>Pred</emphasis></entry>
                       <entry>A binary function object that implements an equivalence relation on values of type <code>Key</code>.
- A binary function object that induces an equivalence relation on values of type Key.
- It takes two arguments of type Key and returns a value of type bool.</entry></row>
+ A binary function object that induces an equivalence relation on values of type <code>Key</code>.
+ It takes two arguments of type <code>Key</code> and returns a value of type bool.</entry></row>
                     <row>
                       <entry><emphasis>Alloc</emphasis></entry>
                       <entry>An allocator whose value type is the same as the container's value type.</entry></row></tbody></tgroup></informaltable></para>
@@ -1882,7 +1882,7 @@
           <typedef name="iterator">
             <type><emphasis>implementation-defined</emphasis></type>
             <description>
- <para>A iterator whose value type is <type>value_type</type>. </para>
+ <para>An iterator whose value type is <type>value_type</type>. </para>
               <para>The iterator category is at least a forward iterator.</para>
               <para>Convertible to <type>const_iterator</type>.</para>
             </description>
@@ -2148,7 +2148,7 @@
               <type>iterator</type>
               <description>
                 <para>Inserts an object, constructed with the arguments <code>args</code>, in the container if and only if there is no element in the container with an equivalent key.</para>
- <para>hint is a suggestion to where the element should be inserted.</para>
+ <para><code>hint</code> is a suggestion to where the element should be inserted.</para>
               </description>
               <returns>
                 <para>If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key.</para>
@@ -2171,7 +2171,7 @@
               </parameter>
               <type>std::pair&lt;iterator, bool&gt;</type>
               <description>
- <para>Inserts obj in the container if and only if there is no element in the container with an equivalent key.</para>
+ <para>Inserts <code>obj</code> in the container if and only if there is no element in the container with an equivalent key.</para>
               </description>
               <returns>
                 <para>The bool component of the return type is true if an insert took place.</para>
@@ -2194,7 +2194,7 @@
               </parameter>
               <type>iterator</type>
               <description>
- <para>Inserts obj in the container if and only if there is no element in the container with an equivalent key.</para>
+ <para>Inserts <code>obj</code> in the container if and only if there is no element in the container with an equivalent key.</para>
                 <para>hint is a suggestion to where the element should be inserted.</para>
               </description>
               <returns>
@@ -2638,10 +2638,10 @@
           <free-function-group name="Equality Comparisons">
             <function name="operator==">
               <template>
- <template-type-parameter name="Key">
- </template-type-parameter>
- <template-type-parameter name="Mapped">
- </template-type-parameter>
+ <template-type-parameter name="Key">
+ </template-type-parameter>
+ <template-type-parameter name="Mapped">
+ </template-type-parameter>
                 <template-type-parameter name="Hash">
                 </template-type-parameter>
                 <template-type-parameter name="Pred">
@@ -2664,10 +2664,10 @@
             </function>
             <function name="operator!=">
               <template>
- <template-type-parameter name="Key">
- </template-type-parameter>
- <template-type-parameter name="Mapped">
- </template-type-parameter>
+ <template-type-parameter name="Key">
+ </template-type-parameter>
+ <template-type-parameter name="Mapped">
+ </template-type-parameter>
                 <template-type-parameter name="Hash">
                 </template-type-parameter>
                 <template-type-parameter name="Pred">
@@ -2692,10 +2692,10 @@
           <free-function-group name="swap">
             <function name="swap">
               <template>
- <template-type-parameter name="Key">
- </template-type-parameter>
- <template-type-parameter name="Mapped">
- </template-type-parameter>
+ <template-type-parameter name="Key">
+ </template-type-parameter>
+ <template-type-parameter name="Mapped">
+ </template-type-parameter>
                 <template-type-parameter name="Hash">
                 </template-type-parameter>
                 <template-type-parameter name="Pred">
@@ -2736,11 +2736,11 @@
               <default><type>std::equal_to&lt;Key&gt;</type></default>
             </template-type-parameter>
             <template-type-parameter name="Alloc">
- <default><type>std::allocator&lt;std::pair&lt;Key const, Mapped&gt; &gt;</type></default>
+ <default><type>std::allocator&lt;std::pair&lt;Key const, Mapped&gt;&gt;</type></default>
             </template-type-parameter>
           </template>
           <purpose><simpara>
- An unordered associative container that associates keys with another value. The same key can be stored multiple times.
+ An unordered associative container that associates keys with another value. The same key can be stored multiple times.
           </simpara></purpose>
           <description>
             <para>Based on chapter 23 of
@@ -2763,8 +2763,8 @@
                     <row>
                       <entry><emphasis>Pred</emphasis></entry>
                       <entry>A binary function object that implements an equivalence relation on values of type <code>Key</code>.
- A binary function object that induces an equivalence relation on values of type Key.
- It takes two arguments of type Key and returns a value of type bool.</entry></row>
+ A binary function object that induces an equivalence relation on values of type <code>Key</code>.
+ It takes two arguments of type <code>Key</code> and returns a value of type bool.</entry></row>
                     <row>
                       <entry><emphasis>Alloc</emphasis></entry>
                       <entry>An allocator whose value type is the same as the container's value type.</entry></row></tbody></tgroup></informaltable></para>
@@ -2820,7 +2820,7 @@
           <typedef name="iterator">
             <type><emphasis>implementation-defined</emphasis></type>
             <description>
- <para>A iterator whose value type is <type>value_type</type>. </para>
+ <para>An iterator whose value type is <type>value_type</type>. </para>
               <para>The iterator category is at least a forward iterator.</para>
               <para>Convertible to <type>const_iterator</type>.</para>
             </description>
@@ -3085,7 +3085,7 @@
               <type>iterator</type>
               <description>
                 <para>Inserts an object, constructed with the arguments <code>args</code>, in the container.</para>
- <para>hint is a suggestion to where the element should be inserted.</para>
+ <para><code>hint</code> is a suggestion to where the element should be inserted.</para>
               </description>
               <returns>
                 <para>An iterator pointing to the inserted element.</para>
@@ -3108,7 +3108,7 @@
               </parameter>
               <type>iterator</type>
               <description>
- <para>Inserts obj in the container.</para>
+ <para>Inserts <code>obj</code> in the container.</para>
               </description>
               <returns>
                 <para>An iterator pointing to the inserted element.</para>
@@ -3130,7 +3130,7 @@
               </parameter>
               <type>iterator</type>
               <description>
- <para>Inserts obj in the container.</para>
+ <para>Inserts <code>obj</code> in the container.</para>
                 <para>hint is a suggestion to where the element should be inserted.</para>
               </description>
               <returns>
@@ -3158,7 +3158,7 @@
               </parameter>
               <type>void</type>
               <description>
- <para>Inserts a range of elements into the container.</para>
+ <para>Inserts a range of elements into the container. Elements are inserted if and only if there is no element in the container with an equivalent key.</para>
               </description>
               <throws>
                 <para>When inserting a single element, if an exception is thrown by an operation other than a call to <code>hasher</code> the function has no effect.</para>
@@ -3539,10 +3539,10 @@
           <free-function-group name="Equality Comparisons">
             <function name="operator==">
               <template>
- <template-type-parameter name="Key">
- </template-type-parameter>
- <template-type-parameter name="Mapped">
- </template-type-parameter>
+ <template-type-parameter name="Key">
+ </template-type-parameter>
+ <template-type-parameter name="Mapped">
+ </template-type-parameter>
                 <template-type-parameter name="Hash">
                 </template-type-parameter>
                 <template-type-parameter name="Pred">
@@ -3565,10 +3565,10 @@
             </function>
             <function name="operator!=">
               <template>
- <template-type-parameter name="Key">
- </template-type-parameter>
- <template-type-parameter name="Mapped">
- </template-type-parameter>
+ <template-type-parameter name="Key">
+ </template-type-parameter>
+ <template-type-parameter name="Mapped">
+ </template-type-parameter>
                 <template-type-parameter name="Hash">
                 </template-type-parameter>
                 <template-type-parameter name="Pred">
@@ -3593,10 +3593,10 @@
           <free-function-group name="swap">
             <function name="swap">
               <template>
- <template-type-parameter name="Key">
- </template-type-parameter>
- <template-type-parameter name="Mapped">
- </template-type-parameter>
+ <template-type-parameter name="Key">
+ </template-type-parameter>
+ <template-type-parameter name="Mapped">
+ </template-type-parameter>
                 <template-type-parameter name="Hash">
                 </template-type-parameter>
                 <template-type-parameter name="Pred">

Modified: branches/release/libs/unordered/doc/unordered.qbk
==============================================================================
--- branches/release/libs/unordered/doc/unordered.qbk (original)
+++ branches/release/libs/unordered/doc/unordered.qbk 2011-08-21 15:19:12 EDT (Sun, 21 Aug 2011)
@@ -31,6 +31,7 @@
 [include:unordered buckets.qbk]
 [include:unordered hash_equality.qbk]
 [include:unordered comparison.qbk]
+[include:unordered compliance.qbk]
 [include:unordered rationale.qbk]
 [include:unordered changes.qbk]
 [xinclude ref.xml]

Modified: branches/release/libs/unordered/test/exception/swap_exception_tests.cpp
==============================================================================
--- branches/release/libs/unordered/test/exception/swap_exception_tests.cpp (original)
+++ branches/release/libs/unordered/test/exception/swap_exception_tests.cpp 2011-08-21 15:19:12 EDT (Sun, 21 Aug 2011)
@@ -27,13 +27,12 @@
     void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x) const {
         std::string scope(test::scope);
 
-#if BOOST_UNORDERED_SWAP_METHOD != 2
+ // TODO: In C++11 exceptions are only allowed in the swap function.
         BOOST_TEST(
- scope == "hash::operator(hash)" ||
+ scope == "hash::hash(hash)" ||
                 scope == "hash::operator=(hash)" ||
- scope == "equal_to::operator(equal_to)" ||
+ scope == "equal_to::equal_to(equal_to)" ||
                 scope == "equal_to::operator=(equal_to)");
-#endif
 
         test::check_equivalent_keys(x);
     }
@@ -82,13 +81,12 @@
     void check BOOST_PREVENT_MACRO_SUBSTITUTION(data_type const& d) const {
         std::string scope(test::scope);
 
-#if BOOST_UNORDERED_SWAP_METHOD != 2
+ // TODO: In C++11 exceptions are only allowed in the swap function.
         BOOST_TEST(
- scope == "hash::operator(hash)" ||
+ scope == "hash::hash(hash)" ||
                 scope == "hash::operator=(hash)" ||
- scope == "equal_to::operator(equal_to)" ||
+ scope == "equal_to::equal_to(equal_to)" ||
                 scope == "equal_to::operator=(equal_to)");
-#endif
         
         test::check_equivalent_keys(d.x);
         test::check_equivalent_keys(d.y);

Modified: branches/release/libs/unordered/test/helpers/count.hpp
==============================================================================
--- branches/release/libs/unordered/test/helpers/count.hpp (original)
+++ branches/release/libs/unordered/test/helpers/count.hpp 2011-08-21 15:19:12 EDT (Sun, 21 Aug 2011)
@@ -75,6 +75,13 @@
     namespace {
         object_count& global_object_count = globally_counted_object::count_;
     }
+
+ struct check_instances {
+ int instances;
+
+ check_instances() : instances(global_object_count.instances) {}
+ ~check_instances() { BOOST_TEST(global_object_count.instances == instances); }
+ };
 }
 
 #endif

Modified: branches/release/libs/unordered/test/helpers/invariants.hpp
==============================================================================
--- branches/release/libs/unordered/test/helpers/invariants.hpp (original)
+++ branches/release/libs/unordered/test/helpers/invariants.hpp 2011-08-21 15:19:12 EDT (Sun, 21 Aug 2011)
@@ -65,37 +65,32 @@
                 std::cerr<<x1.count(key)<<","<<count<<"\n";
             }
 
- // I'm not bothering with the following test for now, as the
- // previous test is probably more enough to catch the kind of
- // errors that this would catch (if an element was in the wrong
- // bucket it not be found by the call to count, if elements are not
- // adjacent then they would be caught when checking against
- // found_.
-
- // // Check that the keys are in the correct bucket and are
- // // adjacent in the bucket.
- // BOOST_DEDUCED_TYPENAME X::size_type bucket = x1.bucket(key);
- // BOOST_DEDUCED_TYPENAME X::const_local_iterator
- // lit = x1.begin(bucket), lend = x1.end(bucket);
- // for(; lit != lend && !eq(get_key<X>(*lit), key); ++lit) continue;
- // if(lit == lend)
- // BOOST_ERROR("Unable to find element with a local_iterator");
- // unsigned int count2 = 0;
- // for(; lit != lend && eq(get_key<X>(*lit), key); ++lit) ++count2;
- // if(count != count2)
- // BOOST_ERROR("Element count doesn't match local_iterator.");
- // for(; lit != lend; ++lit) {
- // if(eq(get_key<X>(*lit), key)) {
- // BOOST_ERROR("Non-adjacent element with equivalent key "
- // "in bucket.");
- // break;
- // }
- // }
+ // Check that the keys are in the correct bucket and are
+ // adjacent in the bucket.
+ BOOST_DEDUCED_TYPENAME X::size_type bucket = x1.bucket(key);
+ BOOST_DEDUCED_TYPENAME X::const_local_iterator
+ lit = x1.begin(bucket), lend = x1.end(bucket);
+ for(; lit != lend && !eq(get_key<X>(*lit), key); ++lit) continue;
+ if(lit == lend)
+ BOOST_ERROR("Unable to find element with a local_iterator");
+ unsigned int count2 = 0;
+ for(; lit != lend && eq(get_key<X>(*lit), key); ++lit) ++count2;
+ if(count != count2)
+ BOOST_ERROR("Element count doesn't match local_iterator.");
+ for(; lit != lend; ++lit) {
+ if(eq(get_key<X>(*lit), key)) {
+ BOOST_ERROR("Non-adjacent element with equivalent key "
+ "in bucket.");
+ break;
+ }
+ }
         };
 
         // Finally, check that size matches up.
- if(x1.size() != size)
+ if(x1.size() != size) {
             BOOST_ERROR("x1.size() doesn't match actual size.");
+ std::cout<<x1.size()<<"/"<<size<<std::endl;
+ }
         float load_factor =
             static_cast<float>(size) / static_cast<float>(x1.bucket_count());
         using namespace std;

Modified: branches/release/libs/unordered/test/helpers/memory.hpp
==============================================================================
--- branches/release/libs/unordered/test/helpers/memory.hpp (original)
+++ branches/release/libs/unordered/test/helpers/memory.hpp 2011-08-21 15:19:12 EDT (Sun, 21 Aug 2011)
@@ -70,7 +70,7 @@
         template <class Alloc = std::allocator<int> >
         struct memory_tracker {
             typedef BOOST_DEDUCED_TYPENAME
- boost::unordered_detail::rebind_wrap<Alloc,
+ ::boost::unordered::detail::rebind_wrap<Alloc,
                     std::pair<memory_area const, memory_track> >::type
                 allocator_type;
 
@@ -137,7 +137,7 @@
             }
 
             void track_deallocate(void* ptr, std::size_t n, std::size_t size,
- int tag)
+ int tag, bool check_tag_ = true)
             {
                 BOOST_DEDUCED_TYPENAME allocated_memory_type::iterator pos =
                     allocated_memory.find(
@@ -147,7 +147,7 @@
                 } else {
                     BOOST_TEST(pos->first.start == ptr);
                     BOOST_TEST(pos->first.end == (char*) ptr + n * size);
- BOOST_TEST(pos->second.tag_ == tag);
+ if (check_tag_) BOOST_TEST(pos->second.tag_ == tag);
                     allocated_memory.erase(pos);
                 }
                 BOOST_TEST(count_allocations > 0);
@@ -168,6 +168,37 @@
             }
         };
     }
+
+ namespace detail
+ {
+ // This won't be a problem as I'm only using a single compile unit
+ // in each test (this is actually required by the minimal test
+ // framework).
+ //
+ // boostinspect:nounnamed
+ namespace {
+ test::detail::memory_tracker<std::allocator<int> > tracker;
+ }
+ }
+
+ template <int Value>
+ struct bool_type {
+ enum { value = (Value ? true : false) };
+ };
+
+ struct true_type {
+ enum { value = true };
+ };
+
+ struct false_type {
+ enum { value = false };
+ };
+
+ template <typename Alloc>
+ int selected_count(Alloc const&)
+ {
+ return 0;
+ }
 }
 
 #endif

Modified: branches/release/libs/unordered/test/objects/exception.hpp
==============================================================================
--- branches/release/libs/unordered/test/objects/exception.hpp (original)
+++ branches/release/libs/unordered/test/objects/exception.hpp 2011-08-21 15:19:12 EDT (Sun, 21 Aug 2011)
@@ -34,6 +34,16 @@
     template <class T> class allocator;
     object generate(object const*);
 
+ struct true_type
+ {
+ enum { value = true };
+ };
+
+ struct false_type
+ {
+ enum { value = false };
+ };
+
     class object
     {
     public:
@@ -340,15 +350,15 @@
         }
 
         void construct(pointer p, T const& t) {
- UNORDERED_SCOPE(allocator::construct(pointer, T)) {
+ UNORDERED_SCOPE(allocator::construct(T*, T)) {
                 UNORDERED_EPOINT("Mock allocator construct function.");
                 new(p) T(t);
             }
             detail::tracker.track_construct((void*) p, sizeof(T), tag_);
         }
 
-#if defined(BOOST_UNORDERED_STD_FORWARD)
- template<class... Args> void construct(pointer p, Args&&... args) {
+#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
+ template<class... Args> void construct(T* p, Args&&... args) {
             UNORDERED_SCOPE(allocator::construct(pointer, Args&&...)) {
                 UNORDERED_EPOINT("Mock allocator construct function.");
                 new(p) T(std::forward<Args>(args)...);
@@ -357,7 +367,7 @@
         }
 #endif
 
- void destroy(pointer p) {
+ void destroy(T* p) {
             detail::tracker.track_destroy((void*) p, sizeof(T), tag_);
             p->~T();
         }
@@ -368,6 +378,10 @@
             }
             return (std::numeric_limits<std::size_t>::max)();
         }
+
+ typedef true_type propagate_on_container_copy_assignment;
+ typedef true_type propagate_on_container_move_assignment;
+ typedef true_type propagate_on_container_swap;
     };
 
     template <class T>

Modified: branches/release/libs/unordered/test/objects/minimal.hpp
==============================================================================
--- branches/release/libs/unordered/test/objects/minimal.hpp (original)
+++ branches/release/libs/unordered/test/objects/minimal.hpp 2011-08-21 15:19:12 EDT (Sun, 21 Aug 2011)
@@ -11,6 +11,8 @@
 #define BOOST_UNORDERED_OBJECTS_MINIMAL_HEADER
 
 #include <cstddef>
+#include <boost/move/move.hpp>
+#include <utility>
 
 #if defined(BOOST_MSVC)
 #pragma warning(push)
@@ -21,6 +23,7 @@
 {
 namespace minimal
 {
+ class destructible;
     class copy_constructible;
     class copy_constructible_equality_comparable;
     class default_copy_constructible;
@@ -33,11 +36,27 @@
     template <class T> class ptr;
     template <class T> class const_ptr;
     template <class T> class allocator;
+ template <class T> class cxx11_allocator;
+
+ struct constructor_param
+ {
+ operator int() const { return 0; }
+ };
+
+ class destructible
+ {
+ public:
+ destructible(constructor_param const&) {}
+ ~destructible() {}
+ private:
+ destructible(destructible const&);
+ destructible& operator=(destructible const&);
+ };
 
     class copy_constructible
     {
     public:
- static copy_constructible create() { return copy_constructible(); }
+ copy_constructible(constructor_param const&) {}
         copy_constructible(copy_constructible const&) {}
         ~copy_constructible() {}
     private:
@@ -48,9 +67,7 @@
     class copy_constructible_equality_comparable
     {
     public:
- static copy_constructible_equality_comparable create() {
- return copy_constructible_equality_comparable();
- }
+ copy_constructible_equality_comparable(constructor_param const&) {}
 
         copy_constructible_equality_comparable(
             copy_constructible_equality_comparable const&)
@@ -85,10 +102,7 @@
     class default_copy_constructible
     {
     public:
- static default_copy_constructible create()
- {
- return default_copy_constructible();
- }
+ default_copy_constructible(constructor_param const&) {}
 
         default_copy_constructible()
         {
@@ -105,13 +119,14 @@
     private:
         default_copy_constructible& operator=(
             default_copy_constructible const&);
- ampersand_operator_used operator&() const { return ampersand_operator_used(); }
+ ampersand_operator_used operator&() const {
+ return ampersand_operator_used(); }
     };
 
     class assignable
     {
     public:
- static assignable create() { return assignable(); }
+ assignable(constructor_param const&) {}
         assignable(assignable const&) {}
         assignable& operator=(assignable const&) { return *this; }
         ~assignable() {}
@@ -122,11 +137,43 @@
         //ampersand_operator_used operator&() const { return ampersand_operator_used(); }
     };
 
+ struct movable_init {};
+
+ class movable1
+ {
+ BOOST_MOVABLE_BUT_NOT_COPYABLE(movable1)
+
+ public:
+ movable1(constructor_param const&) {}
+ movable1() {}
+ explicit movable1(movable_init) {}
+ movable1(BOOST_RV_REF(movable1)) {}
+ movable1& operator=(BOOST_RV_REF(movable1));
+ ~movable1() {}
+ };
+
+#if !defined(BOOST_NO_RVALUE_REFERENCES)
+ class movable2
+ {
+ public:
+ movable2(constructor_param const&) {}
+ explicit movable2(movable_init) {}
+ movable2(movable2&&) {}
+ ~movable2() {}
+ private:
+ movable2() {}
+ movable2(movable2 const&);
+ movable2& operator=(movable2 const&);
+ };
+#else
+ typedef movable1 movable2;
+#endif
+
     template <class T>
     class hash
     {
     public:
- static hash create() { return hash<T>(); }
+ hash(constructor_param const&) {}
         hash() {}
         hash(hash const&) {}
         hash& operator=(hash const&) { return *this; }
@@ -141,7 +188,7 @@
     class equal_to
     {
     public:
- static equal_to create() { return equal_to<T>(); }
+ equal_to(constructor_param const&) {}
         equal_to() {}
         equal_to(equal_to const&) {}
         equal_to& operator=(equal_to const&) { return *this; }
@@ -278,15 +325,15 @@
             ::operator delete((void*) p.ptr_);
         }
 
- void construct(pointer p, T const& t) { new((void*)p.ptr_) T(t); }
+ void construct(T* p, T const& t) { new((void*)p) T(t); }
 
-#if defined(BOOST_UNORDERED_STD_FORWARD)
- template<class... Args> void construct(pointer p, Args&&... args) {
- new((void*)p.ptr_) T(std::forward<Args>(args)...);
+#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
+ template<class... Args> void construct(T* p, Args&&... args) {
+ new((void*)p) T(std::forward<Args>(args)...);
         }
 #endif
 
- void destroy(pointer p) { ((T*)p.ptr_)->~T(); }
+ void destroy(T* p) { p->~T(); }
 
         size_type max_size() const { return 1000; }
 
@@ -316,6 +363,69 @@
     void swap(allocator<T>&, allocator<T>&)
     {
     }
+
+ // C++11 allocator
+ //
+ // Not a fully minimal C++11 allocator, just what I support. Hopefully will
+ // cut down further in the future.
+
+ template <class T>
+ class cxx11_allocator
+ {
+ public:
+ typedef T value_type;
+ template <class U> struct rebind { typedef cxx11_allocator<U> other; };
+
+ cxx11_allocator() {}
+ template <class Y> cxx11_allocator(cxx11_allocator<Y> const&) {}
+ cxx11_allocator(cxx11_allocator const&) {}
+ ~cxx11_allocator() {}
+
+ T* address(T& r) { return &r; }
+ T const* address(T const& r) { return &r; }
+
+ T* allocate(std::size_t n) {
+ return static_cast<T*>(::operator new(n * sizeof(T)));
+ }
+
+ template <class Y>
+ T* allocate(std::size_t n, const_ptr<Y> u) {
+ return static_cast<T*>(::operator new(n * sizeof(T)));
+ }
+
+ void deallocate(T* p, std::size_t) {
+ ::operator delete((void*) p);
+ }
+
+ void construct(T* p, T const& t) { new((void*)p) T(t); }
+
+#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
+ template<class... Args> void construct(T* p, Args&&... args) {
+ new((void*)p) T(std::forward<Args>(args)...);
+ }
+#endif
+
+ void destroy(T* p) { p->~T(); }
+
+ std::size_t max_size() const { return 1000u; }
+ };
+
+ template <class T>
+ inline bool operator==(cxx11_allocator<T> const&, cxx11_allocator<T> const&)
+ {
+ return true;
+ }
+
+ template <class T>
+ inline bool operator!=(cxx11_allocator<T> const&, cxx11_allocator<T> const&)
+ {
+ return false;
+ }
+
+ template <class T>
+ void swap(cxx11_allocator<T>&, cxx11_allocator<T>&)
+ {
+ }
 }
 }
 

Modified: branches/release/libs/unordered/test/objects/test.hpp
==============================================================================
--- branches/release/libs/unordered/test/objects/test.hpp (original)
+++ branches/release/libs/unordered/test/objects/test.hpp 2011-08-21 15:19:12 EDT (Sun, 21 Aug 2011)
@@ -9,11 +9,9 @@
 #include <boost/config.hpp>
 #include <boost/limits.hpp>
 #include <cstddef>
-#include <iostream>
 #include "../helpers/fwd.hpp"
 #include "../helpers/count.hpp"
 #include "../helpers/memory.hpp"
-#include <map>
 
 namespace test
 {
@@ -27,7 +25,7 @@
     template <class T> class allocator;
     object generate(object const*);
     implicitly_convertible generate(implicitly_convertible const*);
-
+
     class object : globally_counted_object
     {
         friend class hash;
@@ -185,18 +183,6 @@
         }
     };
 
- namespace detail
- {
- // This won't be a problem as I'm only using a single compile unit
- // in each test (this is actually require by the minimal test
- // framework).
- //
- // boostinspect:nounnamed
- namespace {
- test::detail::memory_tracker<std::allocator<int> > tracker;
- }
- }
-
     template <class T>
     class allocator
     {
@@ -268,19 +254,19 @@
             ::operator delete((void*) p);
         }
 
- void construct(pointer p, T const& t) {
+ void construct(T* p, T const& t) {
             detail::tracker.track_construct((void*) p, sizeof(T), tag_);
             new(p) T(t);
         }
 
-#if defined(BOOST_UNORDERED_STD_FORWARD)
- template<class... Args> void construct(pointer p, Args&&... args) {
+#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
+ template<class... Args> void construct(T* p, Args&&... args) {
             detail::tracker.track_construct((void*) p, sizeof(T), tag_);
             new(p) T(std::forward<Args>(args)...);
         }
 #endif
 
- void destroy(pointer p) {
+ void destroy(T* p) {
             detail::tracker.track_destroy((void*) p, sizeof(T), tag_);
             p->~T();
         }
@@ -298,6 +284,13 @@
         {
             return tag_ != x.tag_;
         }
+
+ enum {
+ is_select_on_copy = false,
+ is_propagate_on_swap = false,
+ is_propagate_on_assign = false,
+ is_propagate_on_move = false
+ };
     };
 
     template <class T>

Modified: branches/release/libs/unordered/test/unordered/Jamfile.v2
==============================================================================
--- branches/release/libs/unordered/test/unordered/Jamfile.v2 (original)
+++ branches/release/libs/unordered/test/unordered/Jamfile.v2 2011-08-21 15:19:12 EDT (Sun, 21 Aug 2011)
@@ -43,5 +43,5 @@
         [ run load_factor_tests.cpp ]
         [ run rehash_tests.cpp ]
         [ run equality_tests.cpp ]
- [ run swap_tests.cpp : : : <define>BOOST_UNORDERED_SWAP_METHOD=2 ]
+ [ run swap_tests.cpp ]
     ;

Modified: branches/release/libs/unordered/test/unordered/assign_tests.cpp
==============================================================================
--- branches/release/libs/unordered/test/unordered/assign_tests.cpp (original)
+++ branches/release/libs/unordered/test/unordered/assign_tests.cpp 2011-08-21 15:19:12 EDT (Sun, 21 Aug 2011)
@@ -9,12 +9,17 @@
 #include <boost/unordered_map.hpp>
 #include "../helpers/test.hpp"
 #include "../objects/test.hpp"
+#include "../objects/cxx11_allocator.hpp"
 #include "../helpers/random_values.hpp"
 #include "../helpers/tracker.hpp"
 #include "../helpers/equivalent.hpp"
 
 #include <iostream>
 
+#if defined(BOOST_MSVC)
+#pragma warning(disable:4127) // conditional expression is constant
+#endif
+
 namespace assign_tests {
 
 test::seed_t seed(96785);
@@ -28,6 +33,8 @@
 
     std::cerr<<"assign_tests1.1\n";
     {
+ test::check_instances check_;
+
         T x;
         x = x;
         BOOST_TEST(x.empty());
@@ -37,6 +44,8 @@
 
     std::cerr<<"assign_tests1.2\n";
     {
+ test::check_instances check_;
+
         test::random_values<T> v(1000, generator);
         T x(v.begin(), v.end());
 
@@ -64,9 +73,13 @@
     BOOST_DEDUCED_TYPENAME T::key_equal eq2(2);
     BOOST_DEDUCED_TYPENAME T::allocator_type al1(1);
     BOOST_DEDUCED_TYPENAME T::allocator_type al2(2);
-
+
+ typedef BOOST_DEDUCED_TYPENAME T::allocator_type allocator_type;
+
     std::cerr<<"assign_tests2.1\n";
     {
+ test::check_instances check_;
+
         test::random_values<T> v(1000, generator);
         T x1(v.begin(), v.end(), 0, hf1, eq1);
         T x2(0, hf2, eq2);
@@ -78,13 +91,22 @@
 
     std::cerr<<"assign_tests2.2\n";
     {
+ test::check_instances check_;
+
         test::random_values<T> v1(100, generator), v2(100, generator);
         T x1(v1.begin(), v1.end(), 0, hf1, eq1, al1);
         T x2(v2.begin(), v2.end(), 0, hf2, eq2, al2);
         x2 = x1;
         BOOST_TEST(test::equivalent(x2.hash_function(), hf1));
         BOOST_TEST(test::equivalent(x2.key_eq(), eq1));
- BOOST_TEST(test::equivalent(x2.get_allocator(), al2));
+ if (allocator_type::is_propagate_on_assign) {
+ BOOST_TEST(test::equivalent(x2.get_allocator(), al1));
+ BOOST_TEST(!test::equivalent(x2.get_allocator(), al2));
+ }
+ else {
+ BOOST_TEST(test::equivalent(x2.get_allocator(), al2));
+ BOOST_TEST(!test::equivalent(x2.get_allocator(), al1));
+ }
         test::check_container(x2, v1);
     }
 }
@@ -102,16 +124,69 @@
     test::hash, test::equal_to,
     test::allocator<test::object> >* test_multimap;
 
+boost::unordered_set<test::object,
+ test::hash, test::equal_to,
+ test::cxx11_allocator<test::object, test::propagate_assign> >*
+ test_set_prop_assign;
+boost::unordered_multiset<test::object,
+ test::hash, test::equal_to,
+ test::cxx11_allocator<test::object, test::propagate_assign> >*
+ test_multiset_prop_assign;
+boost::unordered_map<test::object, test::object,
+ test::hash, test::equal_to,
+ test::cxx11_allocator<test::object, test::propagate_assign> >*
+ test_map_prop_assign;
+boost::unordered_multimap<test::object, test::object,
+ test::hash, test::equal_to,
+ test::cxx11_allocator<test::object, test::propagate_assign> >*
+ test_multimap_prop_assign;
+
+boost::unordered_set<test::object,
+ test::hash, test::equal_to,
+ test::cxx11_allocator<test::object, test::no_propagate_assign> >*
+ test_set_no_prop_assign;
+boost::unordered_multiset<test::object,
+ test::hash, test::equal_to,
+ test::cxx11_allocator<test::object, test::no_propagate_assign> >*
+ test_multiset_no_prop_assign;
+boost::unordered_map<test::object, test::object,
+ test::hash, test::equal_to,
+ test::cxx11_allocator<test::object, test::no_propagate_assign> >*
+ test_map_no_prop_assign;
+boost::unordered_multimap<test::object, test::object,
+ test::hash, test::equal_to,
+ test::cxx11_allocator<test::object, test::no_propagate_assign> >*
+ test_multimap_no_prop_assign;
+
 using test::default_generator;
 using test::generate_collisions;
 
-UNORDERED_TEST(assign_tests1,
- ((test_set)(test_multiset)(test_map)(test_multimap))
+template <typename T>
+bool is_propagate(T*)
+{
+ return T::allocator_type::is_propagate_on_assign;
+}
+
+UNORDERED_AUTO_TEST(check_traits)
+{
+ BOOST_TEST(!is_propagate(test_set));
+ BOOST_TEST(is_propagate(test_set_prop_assign));
+ BOOST_TEST(!is_propagate(test_set_no_prop_assign));
+}
+
+UNORDERED_TEST(assign_tests1, (
+ (test_set)(test_multiset)(test_map)(test_multimap)
+ (test_set_prop_assign)(test_multiset_prop_assign)(test_map_prop_assign)(test_multimap_prop_assign)
+ (test_set_no_prop_assign)(test_multiset_no_prop_assign)(test_map_no_prop_assign)(test_multimap_no_prop_assign)
+ )
     ((default_generator)(generate_collisions))
 )
 
-UNORDERED_TEST(assign_tests2,
- ((test_set)(test_multiset)(test_map)(test_multimap))
+UNORDERED_TEST(assign_tests2, (
+ (test_set)(test_multiset)(test_map)(test_multimap)
+ (test_set_prop_assign)(test_multiset_prop_assign)(test_map_prop_assign)(test_multimap_prop_assign)
+ (test_set_no_prop_assign)(test_multiset_no_prop_assign)(test_map_no_prop_assign)(test_multimap_no_prop_assign)
+ )
     ((default_generator)(generate_collisions))
 )
 

Modified: branches/release/libs/unordered/test/unordered/bucket_tests.cpp
==============================================================================
--- branches/release/libs/unordered/test/unordered/bucket_tests.cpp (original)
+++ branches/release/libs/unordered/test/unordered/bucket_tests.cpp 2011-08-21 15:19:12 EDT (Sun, 21 Aug 2011)
@@ -25,6 +25,8 @@
 template <class X>
 void tests(X* = 0, test::random_generator generator = test::default_generator)
 {
+ test::check_instances check_;
+
     typedef BOOST_DEDUCED_TYPENAME X::size_type size_type;
     typedef BOOST_DEDUCED_TYPENAME X::const_local_iterator const_local_iterator;
     test::random_values<X> v(1000, generator);

Modified: branches/release/libs/unordered/test/unordered/compile_map.cpp
==============================================================================
--- branches/release/libs/unordered/test/unordered/compile_map.cpp (original)
+++ branches/release/libs/unordered/test/unordered/compile_map.cpp 2011-08-21 15:19:12 EDT (Sun, 21 Aug 2011)
@@ -18,6 +18,19 @@
 // Explicit instantiation to catch compile-time errors
 
 template class boost::unordered_map<
+ int,
+ int,
+ boost::hash<int>,
+ std::equal_to<int>,
+ test::minimal::allocator<std::pair<int const, int> > >;
+template class boost::unordered_multimap<
+ int,
+ int,
+ boost::hash<int>,
+ std::equal_to<int>,
+ test::minimal::allocator<std::pair<int const, int> > >;
+
+template class boost::unordered_map<
     test::minimal::assignable,
     test::minimal::default_copy_constructible,
     test::minimal::hash<test::minimal::assignable>,
@@ -32,16 +45,21 @@
 
 UNORDERED_AUTO_TEST(test0)
 {
+ test::minimal::constructor_param x;
+
     typedef std::pair<test::minimal::assignable const,
             test::minimal::copy_constructible> value_type;
- value_type value(
- test::minimal::assignable::create(),
- test::minimal::copy_constructible::create());
+ value_type value(x, x);
 
     std::cout<<"Test unordered_map.\n";
 
     boost::unordered_map<int, int> int_map;
 
+ boost::unordered_map<int, int,
+ boost::hash<int>, std::equal_to<int>,
+ test::minimal::cxx11_allocator<std::pair<int const, int> >
+ > int_map2;
+
     boost::unordered_map<
         test::minimal::assignable,
         test::minimal::copy_constructible,
@@ -50,12 +68,18 @@
         test::minimal::allocator<value_type> > map;
 
     container_test(int_map, std::pair<int const, int>(0, 0));
+ container_test(int_map2, std::pair<int const, int>(0, 0));
     container_test(map, value);
 
     std::cout<<"Test unordered_multimap.\n";
 
     boost::unordered_multimap<int, int> int_multimap;
 
+ boost::unordered_multimap<int, int,
+ boost::hash<int>, std::equal_to<int>,
+ test::minimal::cxx11_allocator<std::pair<int const, int> >
+ > int_multimap2;
+
     boost::unordered_multimap<
         test::minimal::assignable,
         test::minimal::copy_constructible,
@@ -64,35 +88,49 @@
         test::minimal::allocator<value_type> > multimap;
 
     container_test(int_multimap, std::pair<int const, int>(0, 0));
+ container_test(int_multimap2, std::pair<int const, int>(0, 0));
     container_test(multimap, value);
 }
 
 UNORDERED_AUTO_TEST(equality_tests) {
- typedef std::pair<test::minimal::assignable const,
+ typedef std::pair<
+ test::minimal::copy_constructible_equality_comparable const,
             test::minimal::copy_constructible> value_type;
 
     boost::unordered_map<int, int> int_map;
 
+ boost::unordered_map<int, int,
+ boost::hash<int>, std::equal_to<int>,
+ test::minimal::cxx11_allocator<std::pair<int const, int> >
+ > int_map2;
+
     boost::unordered_map<
- test::minimal::assignable,
         test::minimal::copy_constructible_equality_comparable,
- test::minimal::hash<test::minimal::assignable>,
- test::minimal::equal_to<test::minimal::assignable>,
+ test::minimal::copy_constructible_equality_comparable,
+ test::minimal::hash<test::minimal::copy_constructible_equality_comparable>,
+ test::minimal::equal_to<test::minimal::copy_constructible_equality_comparable>,
         test::minimal::allocator<value_type> > map;
 
     equality_test(int_map);
+ equality_test(int_map2);
     equality_test(map);
 
     boost::unordered_multimap<int, int> int_multimap;
 
+ boost::unordered_multimap<int, int,
+ boost::hash<int>, std::equal_to<int>,
+ test::minimal::cxx11_allocator<std::pair<int const, int> >
+ > int_multimap2;
+
     boost::unordered_multimap<
- test::minimal::assignable,
         test::minimal::copy_constructible_equality_comparable,
- test::minimal::hash<test::minimal::assignable>,
- test::minimal::equal_to<test::minimal::assignable>,
+ test::minimal::copy_constructible_equality_comparable,
+ test::minimal::hash<test::minimal::copy_constructible_equality_comparable>,
+ test::minimal::equal_to<test::minimal::copy_constructible_equality_comparable>,
         test::minimal::allocator<value_type> > multimap;
 
     equality_test(int_multimap);
+ equality_test(int_multimap2);
     equality_test(multimap);
 }
 
@@ -106,30 +144,47 @@
 
     boost::unordered_map<int, int> map;
 
+ boost::unordered_map<int, int,
+ boost::hash<int>, std::equal_to<int>,
+ test::minimal::cxx11_allocator<std::pair<int const, int> >
+ > map2;
+
     unordered_unique_test(map, map_value);
     unordered_map_test(map, value, value);
- unordered_test(map, value, map_value, hash, equal_to);
+ unordered_copyable_test(map, value, map_value, hash, equal_to);
     unordered_map_functions(map, value, value);
 
+ unordered_unique_test(map2, map_value);
+ unordered_map_test(map2, value, value);
+ unordered_copyable_test(map2, value, map_value, hash, equal_to);
+ unordered_map_functions(map2, value, value);
+
     std::cout<<"Test unordered_multimap.\n";
 
     boost::unordered_multimap<int, int> multimap;
 
+ boost::unordered_multimap<int, int,
+ boost::hash<int>, std::equal_to<int>,
+ test::minimal::cxx11_allocator<std::pair<int const, int> >
+ > multimap2;
+
     unordered_equivalent_test(multimap, map_value);
     unordered_map_test(multimap, value, value);
- unordered_test(multimap, value, map_value, hash, equal_to);
+ unordered_copyable_test(multimap, value, map_value, hash, equal_to);
+
+ unordered_equivalent_test(multimap2, map_value);
+ unordered_map_test(multimap2, value, value);
+ unordered_copyable_test(multimap2, value, map_value, hash, equal_to);
 }
 
 UNORDERED_AUTO_TEST(test2)
 {
- test::minimal::assignable assignable
- = test::minimal::assignable::create();
- test::minimal::copy_constructible copy_constructible
- = test::minimal::copy_constructible::create();
- test::minimal::hash<test::minimal::assignable> hash
- = test::minimal::hash<test::minimal::assignable>::create();
- test::minimal::equal_to<test::minimal::assignable> equal_to
- = test::minimal::equal_to<test::minimal::assignable>::create();
+ test::minimal::constructor_param x;
+
+ test::minimal::assignable assignable(x);
+ test::minimal::copy_constructible copy_constructible(x);
+ test::minimal::hash<test::minimal::assignable> hash(x);
+ test::minimal::equal_to<test::minimal::assignable> equal_to(x);
 
     typedef std::pair<test::minimal::assignable const,
             test::minimal::copy_constructible> map_value_type;
@@ -146,8 +201,7 @@
 
     unordered_unique_test(map, map_value);
     unordered_map_test(map, assignable, copy_constructible);
- unordered_test(map, assignable, map_value, hash, equal_to);
-
+ unordered_copyable_test(map, assignable, map_value, hash, equal_to);
 
     boost::unordered_map<
         test::minimal::assignable,
@@ -171,7 +225,7 @@
 
     unordered_equivalent_test(multimap, map_value);
     unordered_map_test(multimap, assignable, copy_constructible);
- unordered_test(multimap, assignable, map_value, hash, equal_to);
+ unordered_copyable_test(multimap, assignable, map_value, hash, equal_to);
 }
 
 RUN_TESTS()

Modified: branches/release/libs/unordered/test/unordered/compile_set.cpp
==============================================================================
--- branches/release/libs/unordered/test/unordered/compile_set.cpp (original)
+++ branches/release/libs/unordered/test/unordered/compile_set.cpp 2011-08-21 15:19:12 EDT (Sun, 21 Aug 2011)
@@ -16,7 +16,18 @@
 #include "./compile_tests.hpp"
 
 // Explicit instantiation to catch compile-time errors
-
+/*
+template class boost::unordered_set<
+ int,
+ boost::hash<int>,
+ std::equal_to<int>,
+ test::minimal::allocator<int> >;
+template class boost::unordered_multiset<
+ int,
+ boost::hash<int>,
+ std::equal_to<int>,
+ test::minimal::allocator<int> >;
+*/
 template class boost::unordered_set<
     test::minimal::assignable,
     test::minimal::hash<test::minimal::assignable>,
@@ -30,10 +41,19 @@
 
 UNORDERED_AUTO_TEST(test0)
 {
- test::minimal::assignable assignable = test::minimal::assignable::create();
+ test::minimal::constructor_param x;
+
+ test::minimal::assignable assignable(x);
 
     std::cout<<"Test unordered_set.\n";
+
     boost::unordered_set<int> int_set;
+
+ boost::unordered_set<int,
+ boost::hash<int>, std::equal_to<int>,
+ test::minimal::cxx11_allocator<int>
+ > int_set2;
+
     boost::unordered_set<
         test::minimal::assignable,
         test::minimal::hash<test::minimal::assignable>,
@@ -41,10 +61,18 @@
         test::minimal::allocator<test::minimal::assignable> > set;
 
     container_test(int_set, 0);
+ container_test(int_set2, 0);
     container_test(set, assignable);
 
     std::cout<<"Test unordered_multiset.\n";
+
     boost::unordered_multiset<int> int_multiset;
+
+ boost::unordered_multiset<int,
+ boost::hash<int>, std::equal_to<int>,
+ test::minimal::cxx11_allocator<int>
+ > int_multiset2;
+
     boost::unordered_multiset<
         test::minimal::assignable,
         test::minimal::hash<test::minimal::assignable>,
@@ -52,32 +80,45 @@
         test::minimal::allocator<test::minimal::assignable> > multiset;
 
     container_test(int_multiset, 0);
+ container_test(int_multiset2, 0);
     container_test(multiset, assignable);
 }
 
 UNORDERED_AUTO_TEST(equality_tests) {
- typedef test::minimal::assignable value_type;
+ typedef test::minimal::copy_constructible_equality_comparable value_type;
 
     boost::unordered_set<int> int_set;
 
+ boost::unordered_set<int,
+ boost::hash<int>, std::equal_to<int>,
+ test::minimal::cxx11_allocator<int>
+ > int_set2;
+
     boost::unordered_set<
- test::minimal::assignable,
- test::minimal::hash<test::minimal::assignable>,
- test::minimal::equal_to<test::minimal::assignable>,
+ test::minimal::copy_constructible_equality_comparable,
+ test::minimal::hash<test::minimal::copy_constructible_equality_comparable>,
+ test::minimal::equal_to<test::minimal::copy_constructible_equality_comparable>,
         test::minimal::allocator<value_type> > set;
 
     equality_test(int_set);
+ equality_test(int_set2);
     equality_test(set);
 
     boost::unordered_multiset<int> int_multiset;
 
+ boost::unordered_multiset<int,
+ boost::hash<int>, std::equal_to<int>,
+ test::minimal::cxx11_allocator<int>
+ > int_multiset2;
+
     boost::unordered_multiset<
- test::minimal::assignable,
- test::minimal::hash<test::minimal::assignable>,
- test::minimal::equal_to<test::minimal::assignable>,
+ test::minimal::copy_constructible_equality_comparable,
+ test::minimal::hash<test::minimal::copy_constructible_equality_comparable>,
+ test::minimal::equal_to<test::minimal::copy_constructible_equality_comparable>,
         test::minimal::allocator<value_type> > multiset;
 
     equality_test(int_multiset);
+ equality_test(int_multiset2);
     equality_test(multiset);
 }
 
@@ -91,29 +132,45 @@
 
     boost::unordered_set<int> set;
     
+ boost::unordered_set<int,
+ boost::hash<int>, std::equal_to<int>,
+ test::minimal::cxx11_allocator<int>
+ > set2;
+
     unordered_unique_test(set, value);
     unordered_set_test(set, value);
- unordered_test(set, value, value, hash, equal_to);
+ unordered_copyable_test(set, value, value, hash, equal_to);
+
+ unordered_unique_test(set2, value);
+ unordered_set_test(set2, value);
+ unordered_copyable_test(set2, value, value, hash, equal_to);
 
     std::cout<<"Test unordered_multiset.\n";
 
     boost::unordered_multiset<int> multiset;
     
+ boost::unordered_multiset<int,
+ boost::hash<int>, std::equal_to<int>,
+ test::minimal::cxx11_allocator<int>
+ > multiset2;
+
     unordered_equivalent_test(multiset, value);
     unordered_set_test(multiset, value);
- unordered_test(multiset, value, value, hash, equal_to);
+ unordered_copyable_test(multiset, value, value, hash, equal_to);
+
+ unordered_equivalent_test(multiset2, value);
+ unordered_set_test(multiset2, value);
+ unordered_copyable_test(multiset2, value, value, hash, equal_to);
 }
 
 UNORDERED_AUTO_TEST(test2)
 {
- test::minimal::assignable assignable
- = test::minimal::assignable::create();
- test::minimal::copy_constructible copy_constructible
- = test::minimal::copy_constructible::create();
- test::minimal::hash<test::minimal::assignable> hash
- = test::minimal::hash<test::minimal::assignable>::create();
- test::minimal::equal_to<test::minimal::assignable> equal_to
- = test::minimal::equal_to<test::minimal::assignable>::create();
+ test::minimal::constructor_param x;
+
+ test::minimal::assignable assignable(x);
+ test::minimal::copy_constructible copy_constructible(x);
+ test::minimal::hash<test::minimal::assignable> hash(x);
+ test::minimal::equal_to<test::minimal::assignable> equal_to(x);
 
     std::cout<<"Test unordered_set.\n";
 
@@ -125,7 +182,7 @@
 
     unordered_unique_test(set, assignable);
     unordered_set_test(set, assignable);
- unordered_test(set, assignable, assignable, hash, equal_to);
+ unordered_copyable_test(set, assignable, assignable, hash, equal_to);
 
     std::cout<<"Test unordered_multiset.\n";
 
@@ -137,7 +194,100 @@
 
     unordered_equivalent_test(multiset, assignable);
     unordered_set_test(multiset, assignable);
- unordered_test(multiset, assignable, assignable, hash, equal_to);
+ unordered_copyable_test(multiset, assignable, assignable, hash, equal_to);
+}
+
+UNORDERED_AUTO_TEST(movable1_tests)
+{
+ test::minimal::constructor_param x;
+
+ test::minimal::movable1 movable1(x);
+ test::minimal::hash<test::minimal::movable1> hash(x);
+ test::minimal::equal_to<test::minimal::movable1> equal_to(x);
+
+ std::cout<<"Test unordered_set.\n";
+
+ boost::unordered_set<
+ test::minimal::movable1,
+ test::minimal::hash<test::minimal::movable1>,
+ test::minimal::equal_to<test::minimal::movable1>,
+ test::minimal::allocator<test::minimal::movable1> > set;
+
+ //unordered_unique_test(set, movable1);
+ unordered_set_test(set, movable1);
+ unordered_movable_test(set, movable1, movable1, hash, equal_to);
+
+ std::cout<<"Test unordered_multiset.\n";
+
+ boost::unordered_multiset<
+ test::minimal::movable1,
+ test::minimal::hash<test::minimal::movable1>,
+ test::minimal::equal_to<test::minimal::movable1>,
+ test::minimal::allocator<test::minimal::movable1> > multiset;
+
+ //unordered_equivalent_test(multiset, movable1);
+ unordered_set_test(multiset, movable1);
+ unordered_movable_test(multiset, movable1, movable1, hash, equal_to);
+}
+
+UNORDERED_AUTO_TEST(movable2_tests)
+{
+ test::minimal::constructor_param x;
+
+ test::minimal::movable2 movable2(x);
+ test::minimal::hash<test::minimal::movable2> hash(x);
+ test::minimal::equal_to<test::minimal::movable2> equal_to(x);
+
+ std::cout<<"Test unordered_set.\n";
+
+ boost::unordered_set<
+ test::minimal::movable2,
+ test::minimal::hash<test::minimal::movable2>,
+ test::minimal::equal_to<test::minimal::movable2>,
+ test::minimal::allocator<test::minimal::movable2> > set;
+
+ //unordered_unique_test(set, movable2);
+ unordered_set_test(set, movable2);
+ unordered_movable_test(set, movable2, movable2, hash, equal_to);
+
+ std::cout<<"Test unordered_multiset.\n";
+
+ boost::unordered_multiset<
+ test::minimal::movable2,
+ test::minimal::hash<test::minimal::movable2>,
+ test::minimal::equal_to<test::minimal::movable2>,
+ test::minimal::allocator<test::minimal::movable2> > multiset;
+
+ //unordered_equivalent_test(multiset, movable2);
+ unordered_set_test(multiset, movable2);
+ unordered_movable_test(multiset, movable2, movable2, hash, equal_to);
+}
+
+UNORDERED_AUTO_TEST(destructible_tests)
+{
+ test::minimal::constructor_param x;
+
+ test::minimal::destructible destructible(x);
+ test::minimal::hash<test::minimal::destructible> hash(x);
+ test::minimal::equal_to<test::minimal::destructible> equal_to(x);
+
+ std::cout<<"Test unordered_set.\n";
+
+ boost::unordered_set<
+ test::minimal::destructible,
+ test::minimal::hash<test::minimal::destructible>,
+ test::minimal::equal_to<test::minimal::destructible> > set;
+
+ unordered_destructible_test(set);
+
+ std::cout<<"Test unordered_multiset.\n";
+
+ boost::unordered_multiset<
+ test::minimal::destructible,
+ test::minimal::hash<test::minimal::destructible>,
+ test::minimal::equal_to<test::minimal::destructible> > multiset;
+
+ unordered_destructible_test(multiset);
 }
 
 RUN_TESTS()

Modified: branches/release/libs/unordered/test/unordered/compile_tests.hpp
==============================================================================
--- branches/release/libs/unordered/test/unordered/compile_tests.hpp (original)
+++ branches/release/libs/unordered/test/unordered/compile_tests.hpp 2011-08-21 15:19:12 EDT (Sun, 21 Aug 2011)
@@ -28,6 +28,7 @@
 
 template <class T> void sink(T const&) {}
 template <class T> T rvalue(T const& v) { return v; }
+template <class T> T rvalue_default() { return T(); }
 
 template <class X, class T>
 void container_test(X& r, T const&)
@@ -109,15 +110,50 @@
     BOOST_TEST(X().size() == 0);
 
     X a,b;
+ X a_const;
 
     sink(X(a));
     X u2(a);
     X u3 = a;
 
+ a.swap(b);
+ boost::swap(a, b);
+ test::check_return_type<X>::equals_ref(r = a);
+
+ // Allocator
+
+ typedef BOOST_DEDUCED_TYPENAME X::allocator_type allocator_type;
+ test::check_return_type<allocator_type>::equals(a_const.get_allocator());
+
+ // Avoid unused variable warnings:
+
+ sink(u);
+ sink(u2);
+ sink(u3);
+}
+
+template <class X>
+void unordered_destructible_test(X&)
+{
+ typedef BOOST_DEDUCED_TYPENAME X::iterator iterator;
+ typedef BOOST_DEDUCED_TYPENAME X::const_iterator const_iterator;
+ typedef BOOST_DEDUCED_TYPENAME X::size_type size_type;
+
+ X x1;
+
+#if !defined(BOOST_NO_RVALUE_REFERENCES)
+ X x2(rvalue_default<X>());
+ X x3 = rvalue_default<X>();
+ // This can only be done if propagate_on_container_move_assignment::value
+ // is true.
+ // x2 = rvalue_default<X>();
+#endif
+
     X* ptr = new X();
     X& a1 = *ptr;
     (&a1)->~X();
 
+ X a,b;
     X const a_const;
     test::check_return_type<iterator>::equals(a.begin());
     test::check_return_type<const_iterator>::equals(a_const.begin());
@@ -129,7 +165,8 @@
     test::check_return_type<const_iterator>::equals(a_const.cend());
 
     a.swap(b);
- test::check_return_type<X>::equals_ref(r = a);
+ boost::swap(a, b);
+
     test::check_return_type<size_type>::equals(a.size());
     test::check_return_type<size_type>::equals(a.max_size());
     test::check_return_type<bool>::convertible(a.empty());
@@ -138,12 +175,6 @@
 
     typedef BOOST_DEDUCED_TYPENAME X::allocator_type allocator_type;
     test::check_return_type<allocator_type>::equals(a_const.get_allocator());
-
- // Avoid unused variable warnings:
-
- sink(u);
- sink(u2);
- sink(u3);
 }
 
 template <class X, class Key>
@@ -160,6 +191,7 @@
 {
     typedef BOOST_DEDUCED_TYPENAME X::value_type value_type;
     typedef BOOST_DEDUCED_TYPENAME X::key_type key_type;
+
     BOOST_MPL_ASSERT((
         boost::is_same<value_type, std::pair<key_type const, T> >));
 
@@ -180,6 +212,8 @@
 
     test::check_return_type<bool>::equals(a == b);
     test::check_return_type<bool>::equals(a != b);
+ test::check_return_type<bool>::equals(boost::operator==(a, b));
+ test::check_return_type<bool>::equals(boost::operator!=(a, b));
 }
 
 template <class X, class T>
@@ -211,9 +245,11 @@
     test::check_return_type<mapped_type const>::equals_ref(b.at(k));
 }
 
-template <class X, class Key, class T, class Hash, class Pred>
-void unordered_test(X&, Key& k, T& t, Hash& hf, Pred& eq)
+template <class X, class Key, class Hash, class Pred>
+void unordered_test(X& x, Key& k, Hash& hf, Pred& eq)
 {
+ unordered_destructible_test(x);
+
     typedef BOOST_DEDUCED_TYPENAME X::key_type key_type;
     typedef BOOST_DEDUCED_TYPENAME X::hasher hasher;
     typedef BOOST_DEDUCED_TYPENAME X::key_equal key_equal;
@@ -277,8 +313,8 @@
         const_local_iterator_reference;
 
     BOOST_MPL_ASSERT((boost::is_same<Key, key_type>));
- boost::function_requires<boost::CopyConstructibleConcept<key_type> >();
- boost::function_requires<boost::AssignableConcept<key_type> >();
+ //boost::function_requires<boost::CopyConstructibleConcept<key_type> >();
+ //boost::function_requires<boost::AssignableConcept<key_type> >();
 
     BOOST_MPL_ASSERT((boost::is_same<Hash, hasher>));
     test::check_return_type<std::size_t>::equals(hf(k));
@@ -316,45 +352,18 @@
     X();
     X a4;
 
- BOOST_DEDUCED_TYPENAME X::value_type* i = 0;
- BOOST_DEDUCED_TYPENAME X::value_type* j = 0;
-
- X(i, j, 10, hf, eq);
- X a5(i, j, 10, hf, eq);
- X(i, j, 10, hf);
- X a6(i, j, 10, hf);
- X(i, j, 10);
- X a7(i, j, 10);
- X(i, j);
- X a8(i, j);
-
- X const b;
- sink(X(b));
- X a9(b);
- a = b;
-
- test::check_return_type<hasher>::equals(b.hash_function());
- test::check_return_type<key_equal>::equals(b.key_eq());
-
- const_iterator q = a.cbegin();
- test::check_return_type<iterator>::equals(a.insert(q, t));
- test::check_return_type<iterator>::equals(a.emplace_hint(q, t));
-
- a.insert(i, j);
     test::check_return_type<size_type>::equals(a.erase(k));
 
- BOOST_TEST(a.empty());
- if(a.empty()) {
- a.insert(t);
- q = a.cbegin();
- test::check_return_type<iterator>::equals(a.erase(q));
- }
-
     const_iterator q1 = a.cbegin(), q2 = a.cend();
     test::check_return_type<iterator>::equals(a.erase(q1, q2));
 
     a.clear();
 
+ X const b;
+
+ test::check_return_type<hasher>::equals(b.hash_function());
+ test::check_return_type<key_equal>::equals(b.key_eq());
+
     test::check_return_type<iterator>::equals(a.find(k));
     test::check_return_type<const_iterator>::equals(b.find(k));
     test::check_return_type<size_type>::equals(b.count(k));
@@ -388,9 +397,117 @@
     sink(a2);
     sink(a3);
     sink(a4);
+}
+
+template <class X, class Key, class T, class Hash, class Pred>
+void unordered_copyable_test(X& x, Key& k, T& t, Hash& hf, Pred& eq)
+{
+ unordered_test(x, k, hf, eq);
+
+ typedef BOOST_DEDUCED_TYPENAME X::iterator iterator;
+ typedef BOOST_DEDUCED_TYPENAME X::const_iterator const_iterator;
+
+ X a;
+
+ BOOST_DEDUCED_TYPENAME X::value_type* i = 0;
+ BOOST_DEDUCED_TYPENAME X::value_type* j = 0;
+
+ X(i, j, 10, hf, eq);
+ X a5(i, j, 10, hf, eq);
+ X(i, j, 10, hf);
+ X a6(i, j, 10, hf);
+ X(i, j, 10);
+ X a7(i, j, 10);
+ X(i, j);
+ X a8(i, j);
+
+ X const b;
+ sink(X(b));
+ X a9(b);
+ a = b;
+
+ const_iterator q = a.cbegin();
+
+ test::check_return_type<iterator>::equals(a.insert(q, t));
+ test::check_return_type<iterator>::equals(a.emplace_hint(q, t));
+
+ a.insert(i, j);
+
+ X a10;
+ a10.insert(t);
+ q = a10.cbegin();
+ test::check_return_type<iterator>::equals(a10.erase(q));
+
+ // Avoid unused variable warnings:
+
+ sink(a);
     sink(a5);
     sink(a6);
     sink(a7);
     sink(a8);
     sink(a9);
 }
+
+template <class X, class Key, class T, class Hash, class Pred>
+void unordered_movable_test(X& x, Key& k, T& /* t */, Hash& hf, Pred& eq)
+{
+ unordered_test(x, k, hf, eq);
+
+ typedef BOOST_DEDUCED_TYPENAME X::iterator iterator;
+ typedef BOOST_DEDUCED_TYPENAME X::const_iterator const_iterator;
+
+#if !defined(BOOST_NO_RVALUE_REFERENCES)
+ X x1(rvalue_default<X>());
+ X x2(boost::move(x1));
+ x1 = rvalue_default<X>();
+ x2 = boost::move(x1);
+#endif
+
+ test::minimal::constructor_param* i = 0;
+ test::minimal::constructor_param* j = 0;
+
+ X(i, j, 10, hf, eq);
+ X a5(i, j, 10, hf, eq);
+ X(i, j, 10, hf);
+ X a6(i, j, 10, hf);
+ X(i, j, 10);
+ X a7(i, j, 10);
+ X(i, j);
+ X a8(i, j);
+
+ X a;
+
+ const_iterator q = a.cbegin();
+
+ test::minimal::constructor_param v;
+ a.emplace(v);
+ test::check_return_type<iterator>::equals(a.emplace_hint(q, v));
+
+ T v1(v);
+ a.emplace(boost::move(v1));
+ T v2(v);
+ a.insert(boost::move(v2));
+ T v3(v);
+ test::check_return_type<iterator>::equals(
+ a.emplace_hint(q, boost::move(v3)));
+ T v4(v);
+ test::check_return_type<iterator>::equals(
+ a.insert(q, boost::move(v4)));
+
+ a.insert(i, j);
+
+ X a10;
+ T v5(v);
+ a10.insert(boost::move(v5));
+ q = a10.cbegin();
+ test::check_return_type<iterator>::equals(a10.erase(q));
+
+ // Avoid unused variable warnings:
+
+ sink(a);
+ sink(a5);
+ sink(a6);
+ sink(a7);
+ sink(a8);
+ sink(a10);
+}

Modified: branches/release/libs/unordered/test/unordered/constructor_tests.cpp
==============================================================================
--- branches/release/libs/unordered/test/unordered/constructor_tests.cpp (original)
+++ branches/release/libs/unordered/test/unordered/constructor_tests.cpp 2011-08-21 15:19:12 EDT (Sun, 21 Aug 2011)
@@ -31,6 +31,8 @@
 
     std::cerr<<"Construct 1\n";
     {
+ test::check_instances check_;
+
         T x(0, hf, eq);
         BOOST_TEST(x.empty());
         BOOST_TEST(test::equivalent(x.hash_function(), hf));
@@ -41,6 +43,8 @@
 
     std::cerr<<"Construct 2\n";
     {
+ test::check_instances check_;
+
         T x(100, hf);
         BOOST_TEST(x.empty());
         BOOST_TEST(x.bucket_count() >= 100);
@@ -52,6 +56,8 @@
 
     std::cerr<<"Construct 3\n";
     {
+ test::check_instances check_;
+
         T x(2000);
         BOOST_TEST(x.empty());
         BOOST_TEST(x.bucket_count() >= 2000);
@@ -63,6 +69,8 @@
 
     std::cerr<<"Construct 4\n";
     {
+ test::check_instances check_;
+
         T x;
         BOOST_TEST(x.empty());
         BOOST_TEST(test::equivalent(x.hash_function(), hf));
@@ -73,6 +81,8 @@
 
     std::cerr<<"Construct 5\n";
     {
+ test::check_instances check_;
+
         test::random_values<T> v(1000, generator);
         T x(v.begin(), v.end(), 10000, hf, eq);
         BOOST_TEST(x.bucket_count() >= 10000);
@@ -85,6 +95,8 @@
 
     std::cerr<<"Construct 6\n";
     {
+ test::check_instances check_;
+
         test::random_values<T> v(10, generator);
         T x(v.begin(), v.end(), 10000, hf);
         BOOST_TEST(x.bucket_count() >= 10000);
@@ -97,6 +109,8 @@
 
     std::cerr<<"Construct 7\n";
     {
+ test::check_instances check_;
+
         test::random_values<T> v(100, generator);
         T x(v.begin(), v.end(), 100);
         BOOST_TEST(x.bucket_count() >= 100);
@@ -109,6 +123,8 @@
 
     std::cerr<<"Construct 8\n";
     {
+ test::check_instances check_;
+
         test::random_values<T> v(1, generator);
         T x(v.begin(), v.end());
         BOOST_TEST(test::equivalent(x.hash_function(), hf));
@@ -120,6 +136,8 @@
 
     std::cerr<<"Construct 9\n";
     {
+ test::check_instances check_;
+
         T x(0, hf, eq, al);
         BOOST_TEST(x.empty());
         BOOST_TEST(test::equivalent(x.hash_function(), hf));
@@ -130,6 +148,8 @@
 
     std::cerr<<"Construct 10\n";
     {
+ test::check_instances check_;
+
         test::random_values<T> v(1000, generator);
         T x(v.begin(), v.end(), 10000, hf, eq, al);
         BOOST_TEST(x.bucket_count() >= 10000);
@@ -142,6 +162,8 @@
 
     std::cerr<<"Construct 11\n";
     {
+ test::check_instances check_;
+
         T x(al);
         BOOST_TEST(x.empty());
         BOOST_TEST(test::equivalent(x.hash_function(), hf));
@@ -167,6 +189,7 @@
 
     std::cerr<<"Construct 1\n";
     {
+ test::check_instances check_;
         T x(10000, hf1, eq1);
         BOOST_TEST(x.bucket_count() >= 10000);
         BOOST_TEST(test::equivalent(x.hash_function(), hf1));
@@ -177,6 +200,7 @@
 
     std::cerr<<"Construct 2\n";
     {
+ test::check_instances check_;
         T x(100, hf1);
         BOOST_TEST(x.empty());
         BOOST_TEST(x.bucket_count() >= 100);
@@ -188,6 +212,7 @@
 
     std::cerr<<"Construct 3\n";
     {
+ test::check_instances check_;
         test::random_values<T> v(100, generator);
         T x(v.begin(), v.end(), 0, hf1, eq1);
         BOOST_TEST(test::equivalent(x.hash_function(), hf1));
@@ -199,6 +224,7 @@
 
     std::cerr<<"Construct 4\n";
     {
+ test::check_instances check_;
         test::random_values<T> v(5, generator);
         T x(v.begin(), v.end(), 1000, hf1);
         BOOST_TEST(x.bucket_count() >= 1000);
@@ -212,6 +238,7 @@
 
     std::cerr<<"Construct 5\n";
     {
+ test::check_instances check_;
         test::random_values<T> v(100, generator);
         T x(v.begin(), v.end(), 0, hf, eq, al1);
         T y(x.begin(), x.end(), 0, hf1, eq1, al2);
@@ -223,6 +250,7 @@
 
     std::cerr<<"Construct 6\n";
     {
+ test::check_instances check_;
         test::random_values<T> v(100, generator);
         T x(v.begin(), v.end(), 0, hf1, eq1);
         T y(x.begin(), x.end(), 0, hf, eq);
@@ -234,6 +262,7 @@
 
     std::cerr<<"Construct 7\n";
     {
+ test::check_instances check_;
         test::random_values<T> v(100, generator);
         T x(v.begin(), v.end(), 0, hf1, eq1);
         T y(x.begin(), x.end(), 0, hf2, eq2);
@@ -245,6 +274,7 @@
 
     std::cerr<<"Construct 8 - from input iterator\n";
     {
+ test::check_instances check_;
         test::random_values<T> v(100, generator);
         BOOST_DEDUCED_TYPENAME test::random_values<T>::const_iterator
             v_begin = v.begin(), v_end = v.end();
@@ -262,6 +292,7 @@
     
     std::cerr<<"Construct 8.5 - from copy iterator\n";
     {
+ test::check_instances check_;
         test::random_values<T> v(100, generator);
         T x(test::copy_iterator(v.begin()),
             test::copy_iterator(v.end()), 0, hf1, eq1);
@@ -275,6 +306,8 @@
     
     std::cerr<<"Construct 9\n";
     {
+ test::check_instances check_;
+
         test::random_values<T> v(100, generator);
         T x(50);
         BOOST_TEST(x.bucket_count() >= 50);
@@ -291,6 +324,8 @@
     
     std::cerr<<"Initializer list construct 1\n";
     {
+ test::check_instances check_;
+
         T x(list);
         BOOST_TEST(x.empty());
         BOOST_TEST(test::equivalent(x.hash_function(), hf));
@@ -300,6 +335,8 @@
 
     std::cerr<<"Initializer list construct 2\n";
     {
+ test::check_instances check_;
+
         T x(list, 1000);
         BOOST_TEST(x.empty());
         BOOST_TEST(x.bucket_count() >= 1000);
@@ -310,6 +347,8 @@
 
     std::cerr<<"Initializer list construct 3\n";
     {
+ test::check_instances check_;
+
         T x(list, 10, hf1);
         BOOST_TEST(x.empty());
         BOOST_TEST(x.bucket_count() >= 10);
@@ -320,6 +359,8 @@
 
     std::cerr<<"Initializer list construct 4\n";
     {
+ test::check_instances check_;
+
         T x(list, 10, hf1, eq1);
         BOOST_TEST(x.empty());
         BOOST_TEST(x.bucket_count() >= 10);
@@ -330,6 +371,8 @@
 
     std::cerr<<"Initializer list construct 5\n";
     {
+ test::check_instances check_;
+
         T x(list, 10, hf1, eq1, al1);
         BOOST_TEST(x.empty());
         BOOST_TEST(x.bucket_count() >= 10);

Modified: branches/release/libs/unordered/test/unordered/copy_tests.cpp
==============================================================================
--- branches/release/libs/unordered/test/unordered/copy_tests.cpp (original)
+++ branches/release/libs/unordered/test/unordered/copy_tests.cpp 2011-08-21 15:19:12 EDT (Sun, 21 Aug 2011)
@@ -9,6 +9,7 @@
 #include <boost/unordered_map.hpp>
 #include "../helpers/test.hpp"
 #include "../objects/test.hpp"
+#include "../objects/cxx11_allocator.hpp"
 #include "../helpers/random_values.hpp"
 #include "../helpers/tracker.hpp"
 #include "../helpers/equivalent.hpp"
@@ -23,11 +24,15 @@
 void copy_construct_tests1(T*,
     test::random_generator const& generator = test::default_generator)
 {
+ typedef BOOST_DEDUCED_TYPENAME T::allocator_type allocator_type;
+
     BOOST_DEDUCED_TYPENAME T::hasher hf;
     BOOST_DEDUCED_TYPENAME T::key_equal eq;
- BOOST_DEDUCED_TYPENAME T::allocator_type al;
+ BOOST_DEDUCED_TYPENAME T::allocator_type al;
 
     {
+ test::check_instances check_;
+
         T x;
         T y(x);
         BOOST_TEST(y.empty());
@@ -35,20 +40,28 @@
         BOOST_TEST(test::equivalent(y.key_eq(), eq));
         BOOST_TEST(test::equivalent(y.get_allocator(), al));
         BOOST_TEST(x.max_load_factor() == y.max_load_factor());
+ BOOST_TEST(test::selected_count(y.get_allocator()) ==
+ (allocator_type::is_select_on_copy));
         test::check_equivalent_keys(y);
     }
 
     {
+ test::check_instances check_;
+
         test::random_values<T> v(1000, generator);
 
         T x(v.begin(), v.end());
         T y(x);
         test::unordered_equivalence_tester<T> equivalent(x);
         BOOST_TEST(equivalent(y));
+ BOOST_TEST(test::selected_count(y.get_allocator()) ==
+ (allocator_type::is_select_on_copy));
         test::check_equivalent_keys(y);
     }
 
     {
+ test::check_instances check_;
+
         // In this test I drop the original containers max load factor, so it
         // is much lower than the load factor. The hash table is not allowed
         // to rehash, but the destination container should probably allocate
@@ -61,6 +74,8 @@
         BOOST_TEST(equivalent(y));
         // This isn't guaranteed:
         BOOST_TEST(y.load_factor() < y.max_load_factor());
+ BOOST_TEST(test::selected_count(y.get_allocator()) ==
+ (allocator_type::is_select_on_copy));
         test::check_equivalent_keys(y);
     }
 }
@@ -75,8 +90,12 @@
     BOOST_DEDUCED_TYPENAME T::key_equal eq(1);
     BOOST_DEDUCED_TYPENAME T::allocator_type al(1);
     BOOST_DEDUCED_TYPENAME T::allocator_type al2(2);
+
+ typedef BOOST_DEDUCED_TYPENAME T::allocator_type allocator_type;
 
     {
+ test::check_instances check_;
+
         T x(10000, hf, eq, al);
         T y(x);
         BOOST_TEST(y.empty());
@@ -84,10 +103,14 @@
         BOOST_TEST(test::equivalent(y.key_eq(), eq));
         BOOST_TEST(test::equivalent(y.get_allocator(), al));
         BOOST_TEST(x.max_load_factor() == y.max_load_factor());
+ BOOST_TEST(test::selected_count(y.get_allocator()) ==
+ (allocator_type::is_select_on_copy));
         test::check_equivalent_keys(y);
     }
 
     {
+ test::check_instances check_;
+
         T x(1000, hf, eq, al);
         T y(x, al2);
         BOOST_TEST(y.empty());
@@ -95,10 +118,13 @@
         BOOST_TEST(test::equivalent(y.key_eq(), eq));
         BOOST_TEST(test::equivalent(y.get_allocator(), al2));
         BOOST_TEST(x.max_load_factor() == y.max_load_factor());
+ BOOST_TEST(test::selected_count(y.get_allocator()) == 0);
         test::check_equivalent_keys(y);
     }
 
     {
+ test::check_instances check_;
+
         test::random_values<T> v(1000, generator);
 
         T x(v.begin(), v.end(), 0, hf, eq, al);
@@ -106,10 +132,14 @@
         test::unordered_equivalence_tester<T> equivalent(x);
         BOOST_TEST(equivalent(y));
         test::check_equivalent_keys(y);
+ BOOST_TEST(test::selected_count(y.get_allocator()) ==
+ (allocator_type::is_select_on_copy));
         BOOST_TEST(test::equivalent(y.get_allocator(), al));
     }
 
     {
+ test::check_instances check_;
+
         test::random_values<T> v(500, generator);
 
         T x(v.begin(), v.end(), 0, hf, eq, al);
@@ -117,6 +147,7 @@
         test::unordered_equivalence_tester<T> equivalent(x);
         BOOST_TEST(equivalent(y));
         test::check_equivalent_keys(y);
+ BOOST_TEST(test::selected_count(y.get_allocator()) == 0);
         BOOST_TEST(test::equivalent(y.get_allocator(), al2));
     }
 }
@@ -134,15 +165,55 @@
     test::hash, test::equal_to,
     test::allocator<test::object> >* test_multimap;
 
+boost::unordered_set<test::object,
+ test::hash, test::equal_to,
+ test::cxx11_allocator<test::object, test::select_copy> >*
+ test_set_select_copy;
+boost::unordered_multiset<test::object,
+ test::hash, test::equal_to,
+ test::cxx11_allocator<test::object, test::select_copy> >*
+ test_multiset_select_copy;
+boost::unordered_map<test::object, test::object,
+ test::hash, test::equal_to,
+ test::cxx11_allocator<test::object, test::select_copy> >*
+ test_map_select_copy;
+boost::unordered_multimap<test::object, test::object,
+ test::hash, test::equal_to,
+ test::cxx11_allocator<test::object, test::select_copy> >*
+ test_multimap_select_copy;
+
+boost::unordered_set<test::object,
+ test::hash, test::equal_to,
+ test::cxx11_allocator<test::object, test::no_select_copy> >*
+ test_set_no_select_copy;
+boost::unordered_multiset<test::object,
+ test::hash, test::equal_to,
+ test::cxx11_allocator<test::object, test::no_select_copy> >*
+ test_multiset_no_select_copy;
+boost::unordered_map<test::object, test::object,
+ test::hash, test::equal_to,
+ test::cxx11_allocator<test::object, test::no_select_copy> >*
+ test_map_no_select_copy;
+boost::unordered_multimap<test::object, test::object,
+ test::hash, test::equal_to,
+ test::cxx11_allocator<test::object, test::no_select_copy> >*
+ test_multimap_no_select_copy;
+
 using test::default_generator;
 using test::generate_collisions;
 
-UNORDERED_TEST(copy_construct_tests1,
- ((test_set)(test_multiset)(test_map)(test_multimap))
+UNORDERED_TEST(copy_construct_tests1, (
+ (test_set)(test_multiset)(test_map)(test_multimap)
+ (test_set_select_copy)(test_multiset_select_copy)(test_map_select_copy)(test_multimap_select_copy)
+ (test_set_no_select_copy)(test_multiset_no_select_copy)(test_map_no_select_copy)(test_multimap_no_select_copy)
+ )
 )
 
-UNORDERED_TEST(copy_construct_tests2,
- ((test_set)(test_multiset)(test_map)(test_multimap))
+UNORDERED_TEST(copy_construct_tests2, (
+ (test_set)(test_multiset)(test_map)(test_multimap)
+ (test_set_select_copy)(test_multiset_select_copy)(test_map_select_copy)(test_multimap_select_copy)
+ (test_set_no_select_copy)(test_multiset_no_select_copy)(test_map_no_select_copy)(test_multimap_no_select_copy)
+ )
     ((default_generator)(generate_collisions))
 )
 

Modified: branches/release/libs/unordered/test/unordered/equality_tests.cpp
==============================================================================
--- branches/release/libs/unordered/test/unordered/equality_tests.cpp (original)
+++ branches/release/libs/unordered/test/unordered/equality_tests.cpp 2011-08-21 15:19:12 EDT (Sun, 21 Aug 2011)
@@ -136,15 +136,17 @@
         UNORDERED_EQUALITY_MULTIMAP_TEST(
             ((1)(1))((1)(1)), !=, ((1)(1))((1)(2)))
         UNORDERED_EQUALITY_MULTIMAP_TEST(
- ((1)(2))((1)(1)), !=, ((1)(1))((1)(2)))
+ ((1)(2))((1)(1)), ==, ((1)(1))((1)(2)))
+ UNORDERED_EQUALITY_MULTIMAP_TEST(
+ ((1)(2))((1)(1)), !=, ((1)(1))((1)(3)))
     }
 
     UNORDERED_AUTO_TEST(equality_predicate_test)
     {
         UNORDERED_EQUALITY_SET_TEST(
- (1), ==, (1001))
+ (1), !=, (1001))
         UNORDERED_EQUALITY_MAP_TEST(
- ((1)(2))((1001)(1)), ==, ((1001)(2))((1)(1)))
+ ((1)(2))((1001)(1)), !=, ((1001)(2))((1)(1)))
     }
 
     // Test that equality still works when the two containers have

Modified: branches/release/libs/unordered/test/unordered/erase_tests.cpp
==============================================================================
--- branches/release/libs/unordered/test/unordered/erase_tests.cpp (original)
+++ branches/release/libs/unordered/test/unordered/erase_tests.cpp 2011-08-21 15:19:12 EDT (Sun, 21 Aug 2011)
@@ -28,6 +28,8 @@
 {
     std::cerr<<"Erase by key.\n";
     {
+ test::check_instances check_;
+
         test::random_values<Container> v(1000, generator);
         Container x(v.begin(), v.end());
         for(BOOST_DEDUCED_TYPENAME test::random_values<Container>::iterator
@@ -44,6 +46,8 @@
 
     std::cerr<<"erase(begin()).\n";
     {
+ test::check_instances check_;
+
         test::random_values<Container> v(1000, generator);
         Container x(v.begin(), v.end());
         std::size_t size = x.size();
@@ -64,6 +68,8 @@
 
     std::cerr<<"erase(random position).\n";
     {
+ test::check_instances check_;
+
         test::random_values<Container> v(1000, generator);
         Container x(v.begin(), v.end());
         std::size_t size = x.size();
@@ -96,6 +102,8 @@
 
     std::cerr<<"erase(ranges).\n";
     {
+ test::check_instances check_;
+
         test::random_values<Container> v(500, generator);
         Container x(v.begin(), v.end());
 
@@ -118,6 +126,8 @@
 
     std::cerr<<"quick_erase(begin()).\n";
     {
+ test::check_instances check_;
+
         test::random_values<Container> v(1000, generator);
         Container x(v.begin(), v.end());
         std::size_t size = x.size();
@@ -136,6 +146,8 @@
 
     std::cerr<<"quick_erase(random position).\n";
     {
+ test::check_instances check_;
+
         test::random_values<Container> v(1000, generator);
         Container x(v.begin(), v.end());
         std::size_t size = x.size();
@@ -169,6 +181,8 @@
 
     std::cerr<<"clear().\n";
     {
+ test::check_instances check_;
+
         test::random_values<Container> v(500, generator);
         Container x(v.begin(), v.end());
         x.clear();

Modified: branches/release/libs/unordered/test/unordered/find_tests.cpp
==============================================================================
--- branches/release/libs/unordered/test/unordered/find_tests.cpp (original)
+++ branches/release/libs/unordered/test/unordered/find_tests.cpp 2011-08-21 15:19:12 EDT (Sun, 21 Aug 2011)
@@ -24,6 +24,8 @@
     typedef BOOST_DEDUCED_TYPENAME X::iterator iterator;
 
     {
+ test::check_instances check_;
+
         test::random_values<X> v(500, generator);
         X x(v.begin(), v.end());
         X const& x_const = x;
@@ -69,6 +71,8 @@
     }
 
     {
+ test::check_instances check_;
+
         X x;
 
         test::random_values<X> v2(5, generator);

Modified: branches/release/libs/unordered/test/unordered/insert_tests.cpp
==============================================================================
--- branches/release/libs/unordered/test/unordered/insert_tests.cpp (original)
+++ branches/release/libs/unordered/test/unordered/insert_tests.cpp 2011-08-21 15:19:12 EDT (Sun, 21 Aug 2011)
@@ -26,6 +26,8 @@
 void unique_insert_tests1(X*,
     test::random_generator generator = test::default_generator)
 {
+ test::check_instances check_;
+
     typedef BOOST_DEDUCED_TYPENAME X::iterator iterator;
     typedef test::ordered<X> ordered;
 
@@ -65,6 +67,9 @@
 {
     std::cerr<<"insert(value) tests for containers with equivalent keys.\n";
 
+ test::check_instances check_;
+
+
     X x;
     test::ordered<X> tracker = test::create_ordered(x);
 
@@ -102,6 +107,8 @@
     std::cerr<<"insert(begin(), value) tests.\n";
 
     {
+ test::check_instances check_;
+
         X x;
         tracker_type tracker = test::create_ordered(x);
 
@@ -128,6 +135,8 @@
     std::cerr<<"insert(end(), value) tests.\n";
 
     {
+ test::check_instances check_;
+
         X x;
         X const& x_const = x;
         tracker_type tracker = test::create_ordered(x);
@@ -155,6 +164,8 @@
     std::cerr<<"insert(pos, value) tests.\n";
 
     {
+ test::check_instances check_;
+
         X x;
         const_iterator pos = x.begin();
         tracker_type tracker = test::create_ordered(x);
@@ -182,6 +193,8 @@
     std::cerr<<"insert single item range tests.\n";
 
     {
+ test::check_instances check_;
+
         X x;
         tracker_type tracker = test::create_ordered(x);
 
@@ -207,6 +220,8 @@
     std::cerr<<"insert range tests.\n";
 
     {
+ test::check_instances check_;
+
         X x;
 
         test::random_values<X> v(1000, generator);
@@ -219,6 +234,8 @@
     std::cerr<<"insert input iterator range tests.\n";
 
     {
+ test::check_instances check_;
+
         X x;
 
         test::random_values<X> v(1000, generator);
@@ -233,6 +250,8 @@
     std::cerr<<"insert copy iterator range tests.\n";
 
     {
+ test::check_instances check_;
+
         X x;
 
         test::random_values<X> v(1000, generator);
@@ -351,6 +370,8 @@
 {
     std::cerr<<"map_insert_range_test1\n";
 
+ test::check_instances check_;
+
     typedef test::list<
         std::pair<
             BOOST_DEDUCED_TYPENAME X::key_type,
@@ -371,6 +392,8 @@
 {
     std::cerr<<"map_insert_range_test2\n";
 
+ test::check_instances check_;
+
     typedef test::list<
         std::pair<BOOST_DEDUCED_TYPENAME X::key_type const, test::implicitly_convertible>
> list;

Modified: branches/release/libs/unordered/test/unordered/move_tests.cpp
==============================================================================
--- branches/release/libs/unordered/test/unordered/move_tests.cpp (original)
+++ branches/release/libs/unordered/test/unordered/move_tests.cpp 2011-08-21 15:19:12 EDT (Sun, 21 Aug 2011)
@@ -9,11 +9,16 @@
 #include <boost/unordered_map.hpp>
 #include "../helpers/test.hpp"
 #include "../objects/test.hpp"
+#include "../objects/cxx11_allocator.hpp"
 #include "../helpers/random_values.hpp"
 #include "../helpers/tracker.hpp"
 #include "../helpers/equivalent.hpp"
 #include "../helpers/invariants.hpp"
 
+#if defined(BOOST_MSVC)
+#pragma warning(disable:4127) // conditional expression is constant
+#endif
+
 namespace move_tests
 {
     test::seed_t seed(98624);
@@ -54,6 +59,8 @@
         BOOST_DEDUCED_TYPENAME T::allocator_type al;
 
         {
+ test::check_instances check_;
+
             T y(empty(ptr));
             BOOST_TEST(y.empty());
             BOOST_TEST(test::equivalent(y.hash_function(), hf));
@@ -64,6 +71,8 @@
         }
 
         {
+ test::check_instances check_;
+
             test::random_values<T> v(1000, generator);
             test::object_count count;
             T y(create(v, count));
@@ -80,6 +89,8 @@
         test::random_generator const& generator = test::default_generator)
     {
         {
+ test::check_instances check_;
+
             test::random_values<T> v(500, generator);
             test::object_count count;
             T y;
@@ -104,6 +115,8 @@
         test::object_count count;
 
         {
+ test::check_instances check_;
+
             test::random_values<T> v(500, generator);
             T y(create(v, count, hf, eq, al, 0.5));
 #if defined(BOOST_HAS_NRVO)
@@ -118,6 +131,8 @@
         }
 
         {
+ test::check_instances check_;
+
             // TODO: To do this correctly requires the fancy new allocator
             // stuff.
             test::random_values<T> v(500, generator);
@@ -130,17 +145,24 @@
             BOOST_TEST(y.max_load_factor() == 2.0); // Not necessarily required.
             test::check_equivalent_keys(y);
         }
-/*
+
         {
+ test::check_instances check_;
+
             test::random_values<T> v(25, generator);
             T y(create(v, count, hf, eq, al, 1.0), al);
 #if !defined(BOOST_NO_RVALUE_REFERENCES)
             BOOST_TEST(count == test::global_object_count);
-#else
+#elif defined(BOOST_HAS_NRVO)
             BOOST_TEST(
                 test::global_object_count.constructions - count.constructions <=
                 (test::is_map<T>::value ? 50 : 25));
             BOOST_TEST(count.instances == test::global_object_count.instances);
+#else
+ BOOST_TEST(
+ test::global_object_count.constructions - count.constructions <=
+ (test::is_map<T>::value ? 100 : 50));
+ BOOST_TEST(count.instances == test::global_object_count.instances);
 #endif
             test::check_container(y, v);
             BOOST_TEST(test::equivalent(y.hash_function(), hf));
@@ -149,7 +171,57 @@
             BOOST_TEST(y.max_load_factor() == 1.0); // Not necessarily required.
             test::check_equivalent_keys(y);
         }
-*/ }
+ }
+
+ template <class T>
+ void move_assign_tests2(T*,
+ test::random_generator const& generator = test::default_generator)
+ {
+ BOOST_DEDUCED_TYPENAME T::hasher hf(1);
+ BOOST_DEDUCED_TYPENAME T::key_equal eq(1);
+ BOOST_DEDUCED_TYPENAME T::allocator_type al1(1);
+ BOOST_DEDUCED_TYPENAME T::allocator_type al2(2);
+ typedef BOOST_DEDUCED_TYPENAME T::allocator_type allocator_type;
+
+ {
+ test::random_values<T> v(500, generator);
+ test::random_values<T> v2(0, generator);
+ T y(v.begin(), v.end(), 0, hf, eq, al1);
+ test::object_count count;
+ y = create(v2, count, hf, eq, al2, 2.0);
+ BOOST_TEST(y.empty());
+ test::check_container(y, v2);
+ test::check_equivalent_keys(y);
+ BOOST_TEST(y.max_load_factor() == 2.0);
+ if (allocator_type::is_propagate_on_move) {
+ BOOST_TEST(test::equivalent(y.get_allocator(), al2));
+ }
+ else {
+ BOOST_TEST(test::equivalent(y.get_allocator(), al1));
+ }
+ }
+
+ {
+ test::random_values<T> v(500, generator);
+ test::object_count count;
+ T y(0, hf, eq, al1);
+ y = create(v, count, hf, eq, al2, 0.5);
+#if defined(BOOST_HAS_NRVO)
+ if (allocator_type::is_propagate_on_move) {
+ BOOST_TEST(count == test::global_object_count);
+ }
+#endif
+ test::check_container(y, v);
+ test::check_equivalent_keys(y);
+ BOOST_TEST(y.max_load_factor() == 0.5);
+ if (allocator_type::is_propagate_on_move) {
+ BOOST_TEST(test::equivalent(y.get_allocator(), al2));
+ }
+ else {
+ BOOST_TEST(test::equivalent(y.get_allocator(), al1));
+ }
+ }
+ }
 
     boost::unordered_set<test::object,
         test::hash, test::equal_to,
@@ -164,19 +236,68 @@
         test::hash, test::equal_to,
         test::allocator<test::object> >* test_multimap;
 
+boost::unordered_set<test::object,
+ test::hash, test::equal_to,
+ test::cxx11_allocator<test::object, test::propagate_move> >*
+ test_set_prop_move;
+boost::unordered_multiset<test::object,
+ test::hash, test::equal_to,
+ test::cxx11_allocator<test::object, test::propagate_move> >*
+ test_multiset_prop_move;
+boost::unordered_map<test::object, test::object,
+ test::hash, test::equal_to,
+ test::cxx11_allocator<test::object, test::propagate_move> >*
+ test_map_prop_move;
+boost::unordered_multimap<test::object, test::object,
+ test::hash, test::equal_to,
+ test::cxx11_allocator<test::object, test::propagate_move> >*
+ test_multimap_prop_move;
+
+boost::unordered_set<test::object,
+ test::hash, test::equal_to,
+ test::cxx11_allocator<test::object, test::no_propagate_move> >*
+ test_set_no_prop_move;
+boost::unordered_multiset<test::object,
+ test::hash, test::equal_to,
+ test::cxx11_allocator<test::object, test::no_propagate_move> >*
+ test_multiset_no_prop_move;
+boost::unordered_map<test::object, test::object,
+ test::hash, test::equal_to,
+ test::cxx11_allocator<test::object, test::no_propagate_move> >*
+ test_map_no_prop_move;
+boost::unordered_multimap<test::object, test::object,
+ test::hash, test::equal_to,
+ test::cxx11_allocator<test::object, test::no_propagate_move> >*
+ test_multimap_no_prop_move;
+
     using test::default_generator;
     using test::generate_collisions;
 
- UNORDERED_TEST(move_construct_tests1,
- ((test_set)(test_multiset)(test_map)(test_multimap))
+ UNORDERED_TEST(move_construct_tests1, (
+ (test_set)(test_multiset)(test_map)(test_multimap)
+ (test_set_prop_move)(test_multiset_prop_move)(test_map_prop_move)(test_multimap_prop_move)
+ (test_set_no_prop_move)(test_multiset_no_prop_move)(test_map_no_prop_move)(test_multimap_no_prop_move)
+ )
     )
- UNORDERED_TEST(move_assign_tests1,
- ((test_set)(test_multiset)(test_map)(test_multimap))
+ UNORDERED_TEST(move_assign_tests1, (
+ (test_set)(test_multiset)(test_map)(test_multimap)
+ (test_set_prop_move)(test_multiset_prop_move)(test_map_prop_move)(test_multimap_prop_move)
+ (test_set_no_prop_move)(test_multiset_no_prop_move)(test_map_no_prop_move)(test_multimap_no_prop_move)
+ )
     )
- UNORDERED_TEST(move_construct_tests2,
- ((test_set)(test_multiset)(test_map)(test_multimap))
+ UNORDERED_TEST(move_construct_tests2, (
+ (test_set)(test_multiset)(test_map)(test_multimap)
+ (test_set_prop_move)(test_multiset_prop_move)(test_map_prop_move)(test_multimap_prop_move)
+ (test_set_no_prop_move)(test_multiset_no_prop_move)(test_map_no_prop_move)(test_multimap_no_prop_move)
+ )
         ((default_generator)(generate_collisions))
     )
+ UNORDERED_TEST(move_assign_tests2, (
+ (test_set)(test_multiset)(test_map)(test_multimap)
+ (test_set_prop_move)(test_multiset_prop_move)(test_map_prop_move)(test_multimap_prop_move)
+ (test_set_no_prop_move)(test_multiset_no_prop_move)(test_map_no_prop_move)(test_multimap_no_prop_move)
+ )
+ )
 }
 
 RUN_TESTS()

Modified: branches/release/libs/unordered/test/unordered/swap_tests.cpp
==============================================================================
--- branches/release/libs/unordered/test/unordered/swap_tests.cpp (original)
+++ branches/release/libs/unordered/test/unordered/swap_tests.cpp 2011-08-21 15:19:12 EDT (Sun, 21 Aug 2011)
@@ -12,10 +12,15 @@
 #include <boost/unordered_map.hpp>
 #include "../helpers/test.hpp"
 #include "../objects/test.hpp"
+#include "../objects/cxx11_allocator.hpp"
 #include "../helpers/random_values.hpp"
 #include "../helpers/tracker.hpp"
 #include "../helpers/invariants.hpp"
 
+#if defined(BOOST_MSVC)
+#pragma warning(disable:4127) // conditional expression is constant
+#endif
+
 namespace swap_tests
 {
 
@@ -37,16 +42,22 @@
 void swap_tests1(X*, test::random_generator generator = test::default_generator)
 {
     {
+ test::check_instances check_;
+
         X x;
         swap_test_impl(x, x);
     }
 
     {
+ test::check_instances check_;
+
         X x,y;
         swap_test_impl(x, y);
     }
 
     {
+ test::check_instances check_;
+
         test::random_values<X> v(1000, generator);
         X x, y(v.begin(), v.end());
         swap_test_impl(x, y);
@@ -54,6 +65,8 @@
     }
 
     {
+ test::check_instances check_;
+
         test::random_values<X> vx(1000, generator), vy(1000, generator);
         X x(vx.begin(), vx.end()), y(vy.begin(), vy.end());
         swap_test_impl(x, y);
@@ -72,12 +85,16 @@
     typedef BOOST_DEDUCED_TYPENAME X::allocator_type allocator_type;
 
     {
+ test::check_instances check_;
+
         X x(0, hasher(1), key_equal(1));
         X y(0, hasher(2), key_equal(2));
         swap_test_impl(x, y);
     }
 
     {
+ test::check_instances check_;
+
         test::random_values<X> v(1000, generator);
         X x(v.begin(), v.end(), 0, hasher(1), key_equal(1));
         X y(0, hasher(2), key_equal(2));
@@ -85,6 +102,8 @@
     }
 
     {
+ test::check_instances check_;
+
         test::random_values<X> vx(100, generator), vy(50, generator);
         X x(vx.begin(), vx.end(), 0, hasher(1), key_equal(1));
         X y(vy.begin(), vy.end(), 0, hasher(2), key_equal(2));
@@ -92,57 +111,113 @@
         swap_test_impl(x, y);
     }
 
-#if BOOST_UNORDERED_SWAP_METHOD == 1
- {
- test::random_values<X> vx(100, generator), vy(50, generator);
- X x(vx.begin(), vx.end(), 0, hasher(), key_equal(), allocator_type(1));
- X y(vy.begin(), vy.end(), 0, hasher(), key_equal(), allocator_type(2));
- try {
- swap_test_impl(x, y);
- BOOST_ERROR("Using swap method 1, "
- "swapping with unequal allocators didn't throw.");
- } catch (std::runtime_error) {}
- }
-#else
     {
+ test::force_equal_allocator force_(
+ !allocator_type::is_propagate_on_swap);
+ test::check_instances check_;
+
         test::random_values<X> vx(50, generator), vy(100, generator);
         X x(vx.begin(), vx.end(), 0, hasher(), key_equal(), allocator_type(1));
         X y(vy.begin(), vy.end(), 0, hasher(), key_equal(), allocator_type(2));
- swap_test_impl(x, y);
+
+ if (allocator_type::is_propagate_on_swap ||
+ x.get_allocator() == y.get_allocator())
+ {
+ swap_test_impl(x, y);
+ }
     }
 
     {
+ test::force_equal_allocator force_(
+ !allocator_type::is_propagate_on_swap);
+ test::check_instances check_;
+
         test::random_values<X> vx(100, generator), vy(100, generator);
         X x(vx.begin(), vx.end(), 0, hasher(1), key_equal(1),
             allocator_type(1));
         X y(vy.begin(), vy.end(), 0, hasher(2), key_equal(2),
             allocator_type(2));
- swap_test_impl(x, y);
- swap_test_impl(x, y);
+
+ if (allocator_type::is_propagate_on_swap ||
+ x.get_allocator() == y.get_allocator())
+ {
+ swap_test_impl(x, y);
+ swap_test_impl(x, y);
+ }
     }
-#endif
 }
 
 boost::unordered_set<test::object,
- test::hash, test::equal_to,
- test::allocator<test::object> >* test_set;
+ test::hash, test::equal_to,
+ test::allocator<test::object> >* test_set;
 boost::unordered_multiset<test::object,
- test::hash, test::equal_to,
- test::allocator<test::object> >* test_multiset;
+ test::hash, test::equal_to,
+ test::allocator<test::object> >* test_multiset;
 boost::unordered_map<test::object, test::object,
- test::hash, test::equal_to,
- test::allocator<test::object> >* test_map;
+ test::hash, test::equal_to,
+ test::allocator<test::object> >* test_map;
 boost::unordered_multimap<test::object, test::object,
- test::hash, test::equal_to,
- test::allocator<test::object> >* test_multimap;
+ test::hash, test::equal_to,
+ test::allocator<test::object> >* test_multimap;
+
+boost::unordered_set<test::object,
+ test::hash, test::equal_to,
+ test::cxx11_allocator<test::object, test::propagate_swap> >*
+ test_set_prop_swap;
+boost::unordered_multiset<test::object,
+ test::hash, test::equal_to,
+ test::cxx11_allocator<test::object, test::propagate_swap> >*
+ test_multiset_prop_swap;
+boost::unordered_map<test::object, test::object,
+ test::hash, test::equal_to,
+ test::cxx11_allocator<test::object, test::propagate_swap> >*
+ test_map_prop_swap;
+boost::unordered_multimap<test::object, test::object,
+ test::hash, test::equal_to,
+ test::cxx11_allocator<test::object, test::propagate_swap> >*
+ test_multimap_prop_swap;
+
+boost::unordered_set<test::object,
+ test::hash, test::equal_to,
+ test::cxx11_allocator<test::object, test::no_propagate_swap> >*
+ test_set_no_prop_swap;
+boost::unordered_multiset<test::object,
+ test::hash, test::equal_to,
+ test::cxx11_allocator<test::object, test::no_propagate_swap> >*
+ test_multiset_no_prop_swap;
+boost::unordered_map<test::object, test::object,
+ test::hash, test::equal_to,
+ test::cxx11_allocator<test::object, test::no_propagate_swap> >*
+ test_map_no_prop_swap;
+boost::unordered_multimap<test::object, test::object,
+ test::hash, test::equal_to,
+ test::cxx11_allocator<test::object, test::no_propagate_swap> >*
+ test_multimap_no_prop_swap;
+
+template <typename T>
+bool is_propagate(T*)
+{
+ return T::allocator_type::is_propagate_on_swap;
+}
+
+UNORDERED_AUTO_TEST(check_traits)
+{
+ BOOST_TEST(!is_propagate(test_set));
+ BOOST_TEST(is_propagate(test_set_prop_swap));
+ BOOST_TEST(!is_propagate(test_set_no_prop_swap));
+}
 
-UNORDERED_TEST(swap_tests1,
- ((test_set)(test_multiset)(test_map)(test_multimap))
-)
-
-UNORDERED_TEST(swap_tests2,
- ((test_set)(test_multiset)(test_map)(test_multimap))
-)
+UNORDERED_TEST(swap_tests1, (
+ (test_set)(test_multiset)(test_map)(test_multimap)
+ (test_set_prop_swap)(test_multiset_prop_swap)(test_map_prop_swap)(test_multimap_prop_swap)
+ (test_set_no_prop_swap)(test_multiset_no_prop_swap)(test_map_no_prop_swap)(test_multimap_no_prop_swap)
+))
+
+UNORDERED_TEST(swap_tests2, (
+ (test_set)(test_multiset)(test_map)(test_multimap)
+ (test_set_prop_swap)(test_multiset_prop_swap)(test_map_prop_swap)(test_multimap_prop_swap)
+ (test_set_no_prop_swap)(test_multiset_no_prop_swap)(test_map_no_prop_swap)(test_multimap_no_prop_swap)
+))
 
 }
 RUN_TESTS()

Modified: branches/release/libs/unordered/test/unordered/unnecessary_copy_tests.cpp
==============================================================================
--- branches/release/libs/unordered/test/unordered/unnecessary_copy_tests.cpp (original)
+++ branches/release/libs/unordered/test/unordered/unnecessary_copy_tests.cpp 2011-08-21 15:19:12 EDT (Sun, 21 Aug 2011)
@@ -13,6 +13,9 @@
 {
     struct count_copies
     {
+ private:
+ BOOST_COPYABLE_AND_MOVABLE(count_copies)
+ public:
         static int copies;
         static int moves;
         count_copies() : tag_(0) { ++copies; }
@@ -31,14 +34,25 @@
             : tag_(x.tag_) { ++copies; }
 
         count_copies(count_copies const& x) : tag_(x.tag_) { ++copies; }
-#if !defined(BOOST_NO_RVALUE_REFERENCES)
- count_copies(count_copies&& x) : tag_(x.tag_) {
+ count_copies(BOOST_RV_REF(count_copies) x) : tag_(x.tag_) {
             x.tag_ = -1; ++moves;
         }
-#endif
- int tag_;
- private:
- count_copies& operator=(count_copies const&);
+
+ count_copies& operator=(BOOST_COPY_ASSIGN_REF(count_copies) p) // Copy assignment
+ {
+ tag_ = p.tag_;
+ ++copies;
+ return *this;
+ }
+
+ count_copies& operator=(BOOST_RV_REF(count_copies) p) //Move assignment
+ {
+ tag_ = p.tag_;
+ ++moves;
+ return *this;
+ }
+
+ int tag_;
     };
 
     bool operator==(count_copies const& x, count_copies const& y) {
@@ -68,31 +82,37 @@
 }
 
 #define COPY_COUNT(n) \
- if(count_copies::copies != n) { \
+ if(::unnecessary_copy_tests::count_copies::copies != n) { \
         BOOST_ERROR("Wrong number of copies."); \
         std::cerr \
- << "Number of copies: " << count_copies::copies \
+ << "Number of copies: " \
+ << ::unnecessary_copy_tests::count_copies::copies \
             << " expecting: " << n << std::endl; \
     }
 #define MOVE_COUNT(n) \
- if(count_copies::moves != n) { \
+ if(::unnecessary_copy_tests::count_copies::moves != n) { \
         BOOST_ERROR("Wrong number of moves."); \
         std::cerr \
- << "Number of moves: " << count_copies::moves \
+ << "Number of moves: " \
+ << ::unnecessary_copy_tests::count_copies::moves \
             << " expecting: " <<n << std::endl; \
     }
 #define COPY_COUNT_RANGE(a, b) \
- if(count_copies::copies < a || count_copies::copies > b) { \
+ if(::unnecessary_copy_tests::count_copies::copies < a || \
+ ::unnecessary_copy_tests::count_copies::copies > b) { \
         BOOST_ERROR("Wrong number of copies."); \
         std::cerr \
- << "Number of copies: " << count_copies::copies \
+ << "Number of copies: " \
+ << ::unnecessary_copy_tests::count_copies::copies \
             << " expecting: [" << a << ", " << b << "]" << std::endl; \
     }
 #define MOVE_COUNT_RANGE(a, b) \
- if(count_copies::moves < a || count_copies::moves > b) { \
+ if(::unnecessary_copy_tests::count_copies::moves < a || \
+ ::unnecessary_copy_tests::count_copies::moves > b) { \
         BOOST_ERROR("Wrong number of moves."); \
         std::cerr \
- << "Number of moves: " << count_copies::copies \
+ << "Number of moves: " \
+ << ::unnecessary_copy_tests::count_copies::copies \
             << " expecting: [" << a << ", " << b << "]" << std::endl; \
     }
 
@@ -136,7 +156,7 @@
         reset();
         T x;
         x.emplace(source<BOOST_DEDUCED_TYPENAME T::value_type>());
-#if !defined(BOOST_NO_RVALUE_REFERENCES) && !defined(BOOST_NO_VARIADIC_TEMPLATES)
+#if !defined(BOOST_NO_RVALUE_REFERENCES)
         COPY_COUNT(1);
 #else
         COPY_COUNT(2);
@@ -148,7 +168,7 @@
     UNORDERED_TEST(unnecessary_copy_emplace_rvalue_test,
             ((set)(multiset)(map)(multimap)))
 
-#if !defined(BOOST_NO_RVALUE_REFERENCES) && !defined(BOOST_NO_VARIADIC_TEMPLATES)
+#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
     template <class T>
     void unnecessary_copy_emplace_move_test(T*)
     {
@@ -162,11 +182,51 @@
 
     UNORDERED_TEST(unnecessary_copy_emplace_move_test,
             ((set)(multiset)(map)(multimap)))
+#endif
 
+ template <class T>
+ void unnecessary_copy_emplace_boost_move_set_test(T*)
+ {
+ reset();
+ T x;
+ BOOST_DEDUCED_TYPENAME T::value_type a;
+ COPY_COUNT(1); MOVE_COUNT(0);
+ x.emplace(boost::move(a));
+ COPY_COUNT(1); MOVE_COUNT(1);
+ }
+
+ UNORDERED_TEST(unnecessary_copy_emplace_boost_move_set_test,
+ ((set)(multiset)))
+
+ template <class T>
+ void unnecessary_copy_emplace_boost_move_map_test(T*)
+ {
+ reset();
+ T x;
+ BOOST_DEDUCED_TYPENAME T::value_type a;
+ COPY_COUNT(1); MOVE_COUNT(0);
+ x.emplace(boost::move(a));
+#if defined(BOOST_NO_RVALUE_REFERENCES)
+ COPY_COUNT(2); MOVE_COUNT(0);
+#else
+ COPY_COUNT(1); MOVE_COUNT(1);
 #endif
+ }
+
+ UNORDERED_TEST(unnecessary_copy_emplace_boost_move_map_test,
+ ((map)(multimap)))
 
     UNORDERED_AUTO_TEST(unnecessary_copy_emplace_set_test)
     {
+ // When calling 'source' the object is moved on some compilers, but not
+ // others. So count that here to adjust later.
+
+ reset();
+ source<count_copies>();
+ int source_cost = ::unnecessary_copy_tests::count_copies::moves;
+
+ //
+
         reset();
         boost::unordered_set<count_copies> x;
         count_copies a;
@@ -181,7 +241,12 @@
         // the existing element.
         reset();
         x.emplace();
+#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
         COPY_COUNT(1); MOVE_COUNT(0);
+#else
+ // source_cost doesn't make much sense here, but it seems to fit.
+ COPY_COUNT(1); MOVE_COUNT(source_cost);
+#endif
 
         //
         // 1 argument
@@ -197,9 +262,9 @@
         // copied.
         reset();
         x.emplace(source<count_copies>());
- COPY_COUNT(1); MOVE_COUNT(0);
+ COPY_COUNT(1); MOVE_COUNT(source_cost);
 
-#if !defined(BOOST_NO_RVALUE_REFERENCES)
+#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
         // No move should take place.
         reset();
         x.emplace(std::move(a));
@@ -233,6 +298,19 @@
 
     UNORDERED_AUTO_TEST(unnecessary_copy_emplace_map_test)
     {
+ // When calling 'source' the object is moved on some compilers, but not
+ // others. So count that here to adjust later.
+
+ reset();
+ source<count_copies>();
+ int source_cost = ::unnecessary_copy_tests::count_copies::moves;
+
+ reset();
+ source<std::pair<count_copies, count_copies> >();
+ int source_pair_cost = ::unnecessary_copy_tests::count_copies::moves;
+
+ //
+
         reset();
         boost::unordered_map<count_copies, count_copies> x;
         // TODO: Run tests for pairs without const etc.
@@ -261,17 +339,17 @@
         // copied.
         reset();
         x.emplace(source<std::pair<count_copies, count_copies> >());
- COPY_COUNT(2); MOVE_COUNT_RANGE(0,2);
+ COPY_COUNT(2); MOVE_COUNT(source_pair_cost);
 
- // TODO: This doesn't work on older versions of gcc.
- //count_copies part;
- std::pair<count_copies const, count_copies> b;
- //reset();
- //std::pair<count_copies const&, count_copies const&> a_ref(part, part);
- //x.emplace(a_ref);
- //COPY_COUNT(0); MOVE_COUNT(0);
+#if !defined(__GNUC__) || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 2)
+ count_copies part;
+ reset();
+ std::pair<count_copies const&, count_copies const&> a_ref(part, part);
+ x.emplace(a_ref);
+ COPY_COUNT(2); MOVE_COUNT(0);
+#endif
 
-#if !defined(BOOST_NO_RVALUE_REFERENCES)
+#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
         // No move should take place.
         // (since a is already in the container)
         reset();
@@ -279,23 +357,24 @@
         COPY_COUNT(0); MOVE_COUNT(0);
 #endif
 
-
         //
         // 2 arguments
         //
 
+ std::pair<count_copies const, count_copies> b;
+
         reset();
         x.emplace(b.first, b.second);
         COPY_COUNT(0); MOVE_COUNT(0);
 
         reset();
         x.emplace(source<count_copies>(), source<count_copies>());
- COPY_COUNT(2); MOVE_COUNT(0);
+ COPY_COUNT(2); MOVE_COUNT(source_cost * 2);
 
         // source<count_copies> creates a single copy.
         reset();
         x.emplace(b.first, source<count_copies>());
- COPY_COUNT(1); MOVE_COUNT(0);
+ COPY_COUNT(1); MOVE_COUNT(source_cost);
 
         reset();
         x.emplace(count_copies(b.first.tag_), count_copies(b.second.tag_));


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk