diff --git a/include/boost/unordered/detail/equivalent.hpp b/include/boost/unordered/detail/equivalent.hpp index 66183a67..d92d273d 100644 --- a/include/boost/unordered/detail/equivalent.hpp +++ b/include/boost/unordered/detail/equivalent.hpp @@ -67,7 +67,9 @@ namespace boost { namespace unordered { namespace detail { return true; } - + +#if !defined(BOOST_UNORDERED_DEPRECATED_EQUALITY) + static bool group_equals(node_ptr n1, node_ptr end1, node_ptr n2, node_ptr end2) { @@ -108,7 +110,30 @@ namespace boost { namespace unordered { namespace detail { return true; } - + +#else + + static bool group_equals(node_ptr n1, node_ptr end1, + node_ptr n2, node_ptr end2) + { + for(;;) + { + if(!extractor::compare_mapped( + node::get_value(n1), node::get_value(n2))) + return false; + + n1 = n1->next_; + n2 = n2->next_; + + if (n1 == end1) return n2 == end2; + if (n2 == end2) return false; + } + + return true; + } + +#endif + static bool find(node_ptr n, node_ptr end, value_type const& v) { for(;n != end; n = n->next_) diff --git a/include/boost/unordered/detail/unique.hpp b/include/boost/unordered/detail/unique.hpp index 38dcba9c..f81437e3 100644 --- a/include/boost/unordered/detail/unique.hpp +++ b/include/boost/unordered/detail/unique.hpp @@ -60,8 +60,15 @@ namespace boost { namespace unordered { namespace detail { n1; n1 = n1->next_) { node_ptr n2 = other.find_matching_node(n1); + +#if !defined(BOOST_UNORDERED_DEPRECATED_EQUALITY) if(!n2 || node::get_value(n1) != node::get_value(n2)) return false; +#else + if(!n2 || !extractor::compare_mapped( + node::get_value(n1), node::get_value(n2))) + return false; +#endif } return true; diff --git a/test/unordered/Jamfile.v2 b/test/unordered/Jamfile.v2 index 7e33a92e..86fc0221 100644 --- a/test/unordered/Jamfile.v2 +++ b/test/unordered/Jamfile.v2 @@ -45,5 +45,6 @@ test-suite unordered [ run load_factor_tests.cpp ] [ run rehash_tests.cpp ] [ run equality_tests.cpp ] + [ run equality_deprecated.cpp ] [ run swap_tests.cpp ] ; diff --git a/test/unordered/equality_deprecated.cpp b/test/unordered/equality_deprecated.cpp new file mode 100644 index 00000000..826b11f4 --- /dev/null +++ b/test/unordered/equality_deprecated.cpp @@ -0,0 +1,173 @@ + +// Copyright 2008-2009 Daniel James. +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_UNORDERED_DEPRECATED_EQUALITY + +#include "../helpers/prefix.hpp" + +#include +#include +#include +#include +#include "../helpers/test.hpp" + +namespace equality_tests +{ + struct mod_compare + { + bool alt_hash_; + + explicit mod_compare(bool alt_hash = false) : alt_hash_(alt_hash) {} + + bool operator()(int x, int y) const + { + return x % 1000 == y % 1000; + } + + int operator()(int x) const + { + return alt_hash_ ? x % 250 : (x + 5) % 250; + } + }; + +#define UNORDERED_EQUALITY_SET_TEST(seq1, op, seq2) \ + { \ + boost::unordered_set set1, set2; \ + BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set1, seq1) \ + BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set2, seq2) \ + BOOST_TEST(set1 op set2); \ + } + +#define UNORDERED_EQUALITY_MULTISET_TEST(seq1, op, seq2) \ + { \ + boost::unordered_multiset \ + set1, set2; \ + BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set1, seq1) \ + BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set2, seq2) \ + BOOST_TEST(set1 op set2); \ + } + +#define UNORDERED_EQUALITY_MAP_TEST(seq1, op, seq2) \ + { \ + boost::unordered_map \ + map1, map2; \ + BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map1, seq1) \ + BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map2, seq2) \ + BOOST_TEST(map1 op map2); \ + } + +#define UNORDERED_EQUALITY_MULTIMAP_TEST(seq1, op, seq2) \ + { \ + boost::unordered_multimap \ + map1, map2; \ + BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map1, seq1) \ + BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map2, seq2) \ + BOOST_TEST(map1 op map2); \ + } + +#define UNORDERED_SET_INSERT(r, set, item) set.insert(item); +#define UNORDERED_MAP_INSERT(r, map, item) \ + map.insert(std::pair BOOST_PP_SEQ_TO_TUPLE(item)); + + UNORDERED_AUTO_TEST(equality_size_tests) + { + boost::unordered_set x1, x2; + BOOST_TEST(x1 == x2); + BOOST_TEST(!(x1 != x2)); + + x1.insert(1); + BOOST_TEST(x1 != x2); + BOOST_TEST(!(x1 == x2)); + BOOST_TEST(x2 != x1); + BOOST_TEST(!(x2 == x1)); + + x2.insert(1); + BOOST_TEST(x1 == x2); + BOOST_TEST(!(x1 != x2)); + + x2.insert(2); + BOOST_TEST(x1 != x2); + BOOST_TEST(!(x1 == x2)); + BOOST_TEST(x2 != x1); + BOOST_TEST(!(x2 == x1)); + } + + UNORDERED_AUTO_TEST(equality_key_value_tests) + { + UNORDERED_EQUALITY_MULTISET_TEST((1), !=, (2)) + UNORDERED_EQUALITY_SET_TEST((2), ==, (2)) + UNORDERED_EQUALITY_MAP_TEST(((1)(1))((2)(1)), !=, ((1)(1))((3)(1))) + } + + UNORDERED_AUTO_TEST(equality_collision_test) + { + UNORDERED_EQUALITY_MULTISET_TEST( + (1), !=, (501)) + UNORDERED_EQUALITY_MULTISET_TEST( + (1)(251), !=, (1)(501)) + UNORDERED_EQUALITY_MULTIMAP_TEST( + ((251)(1))((1)(1)), !=, ((501)(1))((1)(1))) + UNORDERED_EQUALITY_MULTISET_TEST( + (1)(501), ==, (1)(501)) + UNORDERED_EQUALITY_SET_TEST( + (1)(501), ==, (501)(1)) + } + + UNORDERED_AUTO_TEST(equality_group_size_test) + { + UNORDERED_EQUALITY_MULTISET_TEST( + (10)(20)(20), !=, (10)(10)(20)) + UNORDERED_EQUALITY_MULTIMAP_TEST( + ((10)(1))((20)(1))((20)(1)), !=, + ((10)(1))((20)(1))((10)(1))) + UNORDERED_EQUALITY_MULTIMAP_TEST( + ((20)(1))((10)(1))((10)(1)), ==, + ((10)(1))((20)(1))((10)(1))) + } + + UNORDERED_AUTO_TEST(equality_map_value_test) + { + UNORDERED_EQUALITY_MAP_TEST( + ((1)(1)), !=, ((1)(2))) + UNORDERED_EQUALITY_MAP_TEST( + ((1)(1)), ==, ((1)(1))) + UNORDERED_EQUALITY_MULTIMAP_TEST( + ((1)(1)), !=, ((1)(2))) + UNORDERED_EQUALITY_MULTIMAP_TEST( + ((1)(1))((1)(1)), !=, ((1)(1))((1)(2))) + UNORDERED_EQUALITY_MULTIMAP_TEST( + ((1)(2))((1)(1)), !=, ((1)(1))((1)(2))) + } + + UNORDERED_AUTO_TEST(equality_predicate_test) + { + UNORDERED_EQUALITY_SET_TEST( + (1), ==, (1001)) + UNORDERED_EQUALITY_MAP_TEST( + ((1)(2))((1001)(1)), ==, ((1001)(2))((1)(1))) + } + + // Test that equality still works when the two containers have + // different hash functions but the same equality predicate. + + UNORDERED_AUTO_TEST(equality_different_hash_test) + { + typedef boost::unordered_set set; + set set1(0, mod_compare(false), mod_compare(false)); + set set2(0, mod_compare(true), mod_compare(true)); + BOOST_TEST(set1 == set2); + set1.insert(1); set2.insert(2); + BOOST_TEST(set1 != set2); + set1.insert(2); set2.insert(1); + BOOST_TEST(set1 == set2); + set1.insert(10); set2.insert(20); + BOOST_TEST(set1 != set2); + set1.insert(20); set2.insert(10); + BOOST_TEST(set1 == set2); + } + +} + +RUN_TESTS()