diff --git a/doc/ref.xml b/doc/ref.xml
index 01a8d2b1..c0e4bc30 100644
--- a/doc/ref.xml
+++ b/doc/ref.xml
@@ -591,6 +591,52 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ unordered_set<Value, Hash, Pred, Alloc> const&
+
+
+ unordered_set<Value, Hash, Pred, Alloc> const&
+
+ bool
+
+ This is a boost extension.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ unordered_set<Value, Hash, Pred, Alloc> const&
+
+
+ unordered_set<Value, Hash, Pred, Alloc> const&
+
+ bool
+
+ This is a boost extension.
+
+
+
@@ -1202,6 +1248,52 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ unordered_multiset<Value, Hash, Pred, Alloc> const&
+
+
+ unordered_multiset<Value, Hash, Pred, Alloc> const&
+
+ bool
+
+ This is a boost extension.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ unordered_multiset<Value, Hash, Pred, Alloc> const&
+
+
+ unordered_multiset<Value, Hash, Pred, Alloc> const&
+
+ bool
+
+ This is a boost extension.
+
+
+
@@ -1864,6 +1956,56 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ unordered_map<Key, Mapped, Hash, Pred, Alloc> const&
+
+
+ unordered_map<Key, Mapped, Hash, Pred, Alloc> const&
+
+ bool
+
+ This is a boost extension.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ unordered_map<Key, Mapped, Hash, Pred, Alloc> const&
+
+
+ unordered_map<Key, Mapped, Hash, Pred, Alloc> const&
+
+ bool
+
+ This is a boost extension.
+
+
+
@@ -2485,6 +2627,56 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ unordered_multimap<Key, Mapped, Hash, Pred, Alloc> const&
+
+
+ unordered_multimap<Key, Mapped, Hash, Pred, Alloc> const&
+
+ bool
+
+ This is a boost extension.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ unordered_multimap<Key, Mapped, Hash, Pred, Alloc> const&
+
+
+ unordered_multimap<Key, Mapped, Hash, Pred, Alloc> const&
+
+ bool
+
+ This is a boost extension.
+
+
+
diff --git a/include/boost/unordered/detail/hash_table_impl.hpp b/include/boost/unordered/detail/hash_table_impl.hpp
index e4d4ca1f..30e662a6 100644
--- a/include/boost/unordered/detail/hash_table_impl.hpp
+++ b/include/boost/unordered/detail/hash_table_impl.hpp
@@ -290,6 +290,11 @@ namespace boost {
return get_value(node_);
}
+ value_type* operator->() const
+ {
+ return &get_value(node_);
+ }
+
void increment()
{
BOOST_ASSERT(node_);
@@ -1862,6 +1867,65 @@ namespace boost {
}
}
+ //
+ // equals
+ //
+
+private:
+#if BOOST_UNORDERED_HASH_EQUIVALENT
+ inline bool group_equals(local_iterator_base it1,
+ local_iterator_base it2, type_wrapper*) const
+ {
+ return this->group_count(it1) == this->group_count(it2);
+ }
+
+ inline bool group_equals(local_iterator_base it1,
+ local_iterator_base it2, void*) const
+ {
+ if(!it2.not_finished()) return false;
+ local_iterator_base end1 = it1, end2 = it2;
+ end1.next_group(); end2.next_group();
+ do {
+ if(it1->second != it2->second) return false;
+ it1.increment();
+ it2.increment();
+ } while(it1 != end1 && it2 != end2);
+ return it1 == end1 && it2 == end2;
+ }
+#else
+ inline bool group_equals(local_iterator_base it1,
+ local_iterator_base it2, type_wrapper*) const
+ {
+ return true;
+ }
+
+ inline bool group_equals(local_iterator_base it1,
+ local_iterator_base it2, void*) const
+ {
+ return it1->second == it2->second;
+ }
+#endif
+
+public:
+ bool equals(BOOST_UNORDERED_TABLE const& other) const
+ {
+ if(this->size() != other.size()) return false;
+
+ for(bucket_ptr i = this->cached_begin_bucket_,
+ j = this->buckets_ + this->bucket_count_; i != j; ++i)
+ {
+ for(local_iterator_base it(i->next_); it.not_finished(); it.next_group())
+ {
+ local_iterator_base other_pos = other.find_iterator(other.extract_key(*it));
+ if(!other_pos.not_finished() ||
+ !group_equals(it, other_pos, (type_wrapper*)0))
+ return false;
+ }
+ }
+
+ return true;
+ }
+
private:
// strong exception safety, no side effects
diff --git a/include/boost/unordered_map.hpp b/include/boost/unordered_map.hpp
index 48609ce0..6fe05b69 100644
--- a/include/boost/unordered_map.hpp
+++ b/include/boost/unordered_map.hpp
@@ -325,6 +325,16 @@ namespace boost
{
base.rehash(n);
}
+
+ friend bool operator==(unordered_map const& m1, unordered_map const& m2)
+ {
+ return m1.base.equals(m2.base);
+ }
+
+ friend bool operator!=(unordered_map const& m1, unordered_map const& m2)
+ {
+ return !m1.base.equals(m2.base);
+ }
}; // class template unordered_map
template
@@ -622,6 +632,16 @@ namespace boost
{
base.rehash(n);
}
+
+ friend bool operator==(unordered_multimap const& m1, unordered_multimap const& m2)
+ {
+ return m1.base.equals(m2.base);
+ }
+
+ friend bool operator!=(unordered_multimap const& m1, unordered_multimap const& m2)
+ {
+ return !m1.base.equals(m2.base);
+ }
}; // class template unordered_multimap
template
diff --git a/include/boost/unordered_set.hpp b/include/boost/unordered_set.hpp
index 011440a4..9f713587 100644
--- a/include/boost/unordered_set.hpp
+++ b/include/boost/unordered_set.hpp
@@ -295,6 +295,16 @@ namespace boost
{
base.rehash(n);
}
+
+ friend bool operator==(unordered_set const& m1, unordered_set const& m2)
+ {
+ return m1.base.equals(m2.base);
+ }
+
+ friend bool operator!=(unordered_set const& m1, unordered_set const& m2)
+ {
+ return !m1.base.equals(m2.base);
+ }
}; // class template unordered_set
template
@@ -577,6 +587,16 @@ namespace boost
{
base.rehash(n);
}
+
+ friend bool operator==(unordered_multiset const& m1, unordered_multiset const& m2)
+ {
+ return m1.base.equals(m2.base);
+ }
+
+ friend bool operator!=(unordered_multiset const& m1, unordered_multiset const& m2)
+ {
+ return !m1.base.equals(m2.base);
+ }
}; // class template unordered_multiset
template
diff --git a/test/container/compile_tests.hpp b/test/container/compile_tests.hpp
index b5fe1ab3..19455aba 100644
--- a/test/container/compile_tests.hpp
+++ b/test/container/compile_tests.hpp
@@ -111,6 +111,7 @@ void container_test(X& r, T&)
(&a1)->~X();
X const a_const;
+
test::check_return_type::equals(a.begin());
test::check_return_type::equals(a_const.begin());
test::check_return_type::equals(a.cbegin());
@@ -119,12 +120,13 @@ void container_test(X& r, T&)
test::check_return_type::equals(a_const.end());
test::check_return_type::equals(a.cend());
test::check_return_type::equals(a_const.cend());
-
- // No tests for ==, != since they're not required for unordered containers.
-
- a.swap(b);
- test::check_return_type::equals_ref(r = a);
- test::check_return_type::equals(a.size());
- test::check_return_type::equals(a.max_size());
- test::check_return_type::convertible(a.empty());
+}
+
+template
+void equality_test(X& r, T&)
+{
+ X const a = r, b = r;
+
+ test::check_return_type::equals(a == b);
+ test::check_return_type::equals(a != b);
}
diff --git a/test/container/map_compile.cpp b/test/container/map_compile.cpp
index e498a934..1ac721b4 100644
--- a/test/container/map_compile.cpp
+++ b/test/container/map_compile.cpp
@@ -13,7 +13,7 @@
#include "../objects/minimal.hpp"
#include "./compile_tests.hpp"
-int main()
+void container_tests()
{
typedef std::pair value_type;
@@ -40,6 +40,36 @@ int main()
test::minimal::allocator > multimap;
container_test(multimap, value);
+}
+void equality_tests() {
+ typedef std::pair value_type;
+ value_type value(
+ test::minimal::assignable::create(),
+ test::minimal::copy_constructible_equality_comparable::create());
+
+ boost::unordered_map<
+ test::minimal::assignable,
+ test::minimal::copy_constructible_equality_comparable,
+ test::minimal::hash,
+ test::minimal::equal_to,
+ test::minimal::allocator > map;
+
+ equality_test(map, value);
+
+ boost::unordered_multimap<
+ test::minimal::assignable,
+ test::minimal::copy_constructible_equality_comparable,
+ test::minimal::hash,
+ test::minimal::equal_to,
+ test::minimal::allocator > multimap;
+
+ equality_test(multimap, value);
+}
+
+int main() {
+ container_tests();
+ equality_tests();
return boost::report_errors();
}
diff --git a/test/container/set_compile.cpp b/test/container/set_compile.cpp
index f34de5d7..a557f8eb 100644
--- a/test/container/set_compile.cpp
+++ b/test/container/set_compile.cpp
@@ -25,6 +25,7 @@ int main()
test::minimal::allocator > set;
container_test(set, assignable);
+ equality_test(set, assignable);
std::cout<<"Test unordered_multiset.\n";
boost::unordered_multiset<
@@ -34,6 +35,7 @@ int main()
test::minimal::allocator > multiset;
container_test(multiset, assignable);
+ equality_test(multiset, assignable);
return boost::report_errors();
}
diff --git a/test/objects/minimal.hpp b/test/objects/minimal.hpp
index 2932b387..a1450437 100644
--- a/test/objects/minimal.hpp
+++ b/test/objects/minimal.hpp
@@ -18,6 +18,7 @@ namespace test
namespace minimal
{
class copy_constructible;
+ class copy_constructible_equality_comparable;
class default_copy_constructible;
class assignable;
template class hash;
@@ -37,6 +38,25 @@ namespace minimal
copy_constructible() {}
};
+ class copy_constructible_equality_comparable
+ {
+ public:
+ static copy_constructible_equality_comparable create() { return copy_constructible_equality_comparable(); }
+ copy_constructible_equality_comparable(copy_constructible_equality_comparable const&) {}
+ ~copy_constructible_equality_comparable() {}
+ private:
+ copy_constructible_equality_comparable& operator=(copy_constructible_equality_comparable const&);
+ copy_constructible_equality_comparable() {}
+ };
+
+ bool operator==(copy_constructible_equality_comparable, copy_constructible_equality_comparable) {
+ return true;
+ }
+
+ bool operator!=(copy_constructible_equality_comparable, copy_constructible_equality_comparable) {
+ return false;
+ }
+
class default_copy_constructible
{
public: