mirror of
https://github.com/ETLCPP/etl.git
synced 2026-06-16 00:46:03 +08:00
Fixed unordered container equality tests to match STL
This commit is contained in:
parent
60204d95b6
commit
7c5a6e49a1
@ -142,11 +142,11 @@ namespace etl
|
||||
typedef const value_type* const_pointer;
|
||||
typedef size_t size_type;
|
||||
|
||||
|
||||
typedef const TKey& key_parameter_t;
|
||||
|
||||
typedef etl::forward_link<0> link_t; // Default link.
|
||||
|
||||
// The nodes that store the elements.
|
||||
// The nodes that store the elements.
|
||||
struct node_t : public link_t
|
||||
{
|
||||
@ -158,6 +158,17 @@ namespace etl
|
||||
value_type key_value_pair;
|
||||
};
|
||||
|
||||
friend bool operator ==(const node_t& lhs, const node_t& rhs)
|
||||
{
|
||||
return (lhs.key_value_pair.first == rhs.key_value_pair.first) &&
|
||||
(lhs.key_value_pair.second == rhs.key_value_pair.second);
|
||||
}
|
||||
|
||||
friend bool operator !=(const node_t& lhs, const node_t& rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
typedef etl::intrusive_forward_list<node_t, link_t> bucket_t;
|
||||
@ -167,7 +178,7 @@ namespace etl
|
||||
|
||||
// Local iterators iterate over one bucket.
|
||||
typedef typename bucket_t::iterator local_iterator;
|
||||
typedef typename bucket_t::const_iterator local_const_iterator;
|
||||
typedef typename bucket_t::const_iterator const_local_iterator;
|
||||
|
||||
//*********************************************************************
|
||||
class iterator : public etl::iterator<ETL_OR_STD::forward_iterator_tag, T>
|
||||
@ -505,7 +516,7 @@ namespace etl
|
||||
/// Returns a const_iterator to the beginning of the unordered_map bucket.
|
||||
///\return A const iterator to the beginning of the unordered_map bucket.
|
||||
//*********************************************************************
|
||||
local_const_iterator begin(size_t i) const
|
||||
const_local_iterator begin(size_t i) const
|
||||
{
|
||||
return pbuckets[i].cbegin();
|
||||
}
|
||||
@ -514,7 +525,7 @@ namespace etl
|
||||
/// Returns a const_iterator to the beginning of the unordered_map bucket.
|
||||
///\return A const iterator to the beginning of the unordered_map bucket.
|
||||
//*********************************************************************
|
||||
local_const_iterator cbegin(size_t i) const
|
||||
const_local_iterator cbegin(size_t i) const
|
||||
{
|
||||
return pbuckets[i].cbegin();
|
||||
}
|
||||
@ -559,7 +570,7 @@ namespace etl
|
||||
/// Returns a const_iterator to the end of the unordered_map bucket.
|
||||
///\return A const iterator to the end of the unordered_map bucket.
|
||||
//*********************************************************************
|
||||
local_const_iterator end(size_t i) const
|
||||
const_local_iterator end(size_t i) const
|
||||
{
|
||||
return pbuckets[i].cend();
|
||||
}
|
||||
@ -568,7 +579,7 @@ namespace etl
|
||||
/// Returns a const_iterator to the end of the unordered_map bucket.
|
||||
///\return A const iterator to the end of the unordered_map bucket.
|
||||
//*********************************************************************
|
||||
local_const_iterator cend(size_t i) const
|
||||
const_local_iterator cend(size_t i) const
|
||||
{
|
||||
return pbuckets[i].cend();
|
||||
}
|
||||
@ -1501,7 +1512,21 @@ namespace etl
|
||||
template <typename TKey, typename T, typename TKeyCompare>
|
||||
bool operator ==(const etl::iunordered_map<TKey, T, TKeyCompare>& lhs, const etl::iunordered_map<TKey, T, TKeyCompare>& rhs)
|
||||
{
|
||||
return (lhs.size() == rhs.size()) && etl::equal(lhs.begin(), lhs.end(), rhs.begin());
|
||||
const bool sizes_match = (lhs.size() == rhs.size());
|
||||
bool elements_match = true;
|
||||
|
||||
if (sizes_match)
|
||||
{
|
||||
for (size_t i = 0; (i < lhs.bucket_count()) && elements_match; ++i)
|
||||
{
|
||||
if (!etl::is_permutation(lhs.begin(i), lhs.end(i), rhs.begin(i)))
|
||||
{
|
||||
elements_match = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (sizes_match && elements_match);
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
|
||||
@ -146,7 +146,9 @@ namespace etl
|
||||
|
||||
typedef etl::forward_link<0> link_t; // Default link.
|
||||
|
||||
struct node_t : public link_t // The nodes that store the elements.
|
||||
//*********************************************************************
|
||||
// The nodes that store the elements.
|
||||
struct node_t : public link_t
|
||||
{
|
||||
node_t(const_reference key_value_pair_)
|
||||
: key_value_pair(key_value_pair_)
|
||||
@ -156,6 +158,17 @@ namespace etl
|
||||
value_type key_value_pair;
|
||||
};
|
||||
|
||||
friend bool operator ==(const node_t& lhs, const node_t& rhs)
|
||||
{
|
||||
return (lhs.key_value_pair.first == rhs.key_value_pair.first) &&
|
||||
(lhs.key_value_pair.second == rhs.key_value_pair.second);
|
||||
}
|
||||
|
||||
friend bool operator !=(const node_t& lhs, const node_t& rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
typedef etl::intrusive_forward_list<node_t, link_t> bucket_t;
|
||||
@ -165,7 +178,7 @@ namespace etl
|
||||
|
||||
// Local iterators iterate over one bucket.
|
||||
typedef typename bucket_t::iterator local_iterator;
|
||||
typedef typename bucket_t::const_iterator local_const_iterator;
|
||||
typedef typename bucket_t::const_iterator const_local_iterator;
|
||||
|
||||
//*********************************************************************
|
||||
class iterator : public etl::iterator<ETL_OR_STD::forward_iterator_tag, T>
|
||||
@ -504,7 +517,7 @@ namespace etl
|
||||
/// Returns a const_iterator to the beginning of the unordered_multimap bucket.
|
||||
///\return A const iterator to the beginning of the unordered_multimap bucket.
|
||||
//*********************************************************************
|
||||
local_const_iterator begin(size_t i) const
|
||||
const_local_iterator begin(size_t i) const
|
||||
{
|
||||
return pbuckets[i].cbegin();
|
||||
}
|
||||
@ -513,7 +526,7 @@ namespace etl
|
||||
/// Returns a const_iterator to the beginning of the unordered_multimap bucket.
|
||||
///\return A const iterator to the beginning of the unordered_multimap bucket.
|
||||
//*********************************************************************
|
||||
local_const_iterator cbegin(size_t i) const
|
||||
const_local_iterator cbegin(size_t i) const
|
||||
{
|
||||
return pbuckets[i].cbegin();
|
||||
}
|
||||
@ -558,7 +571,7 @@ namespace etl
|
||||
/// Returns a const_iterator to the end of the unordered_multimap bucket.
|
||||
///\return A const iterator to the end of the unordered_multimap bucket.
|
||||
//*********************************************************************
|
||||
local_const_iterator end(size_t i) const
|
||||
const_local_iterator end(size_t i) const
|
||||
{
|
||||
return pbuckets[i].cend();
|
||||
}
|
||||
@ -567,7 +580,7 @@ namespace etl
|
||||
/// Returns a const_iterator to the end of the unordered_multimap bucket.
|
||||
///\return A const iterator to the end of the unordered_multimap bucket.
|
||||
//*********************************************************************
|
||||
local_const_iterator cend(size_t i) const
|
||||
const_local_iterator cend(size_t i) const
|
||||
{
|
||||
return pbuckets[i].cend();
|
||||
}
|
||||
@ -1407,7 +1420,21 @@ namespace etl
|
||||
template <typename TKey, typename TMapped, typename TKeyCompare>
|
||||
bool operator ==(const etl::iunordered_multimap<TKey, TMapped, TKeyCompare>& lhs, const etl::iunordered_multimap<TKey, TMapped, TKeyCompare>& rhs)
|
||||
{
|
||||
return (lhs.size() == rhs.size()) && etl::equal(lhs.begin(), lhs.end(), rhs.begin());
|
||||
const bool sizes_match = (lhs.size() == rhs.size());
|
||||
bool elements_match = true;
|
||||
|
||||
if (sizes_match)
|
||||
{
|
||||
for (size_t i = 0; (i < lhs.bucket_count()) && elements_match; ++i)
|
||||
{
|
||||
if (!etl::is_permutation(lhs.begin(i), lhs.end(i), rhs.begin(i)))
|
||||
{
|
||||
elements_match = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (sizes_match && elements_match);
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
|
||||
@ -143,6 +143,7 @@ namespace etl
|
||||
|
||||
typedef etl::forward_link<0> link_t;
|
||||
|
||||
//*********************************************************************
|
||||
// The nodes that store the elements.
|
||||
struct node_t : public link_t
|
||||
{
|
||||
@ -154,6 +155,16 @@ namespace etl
|
||||
value_type key;
|
||||
};
|
||||
|
||||
friend bool operator ==(const node_t& lhs, const node_t& rhs)
|
||||
{
|
||||
return (lhs.key == rhs.key);
|
||||
}
|
||||
|
||||
friend bool operator !=(const node_t& lhs, const node_t& rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
typedef etl::intrusive_forward_list<node_t, link_t> bucket_t;
|
||||
@ -163,7 +174,7 @@ namespace etl
|
||||
|
||||
// Local iterators iterate over one bucket.
|
||||
typedef typename bucket_t::iterator local_iterator;
|
||||
typedef typename bucket_t::const_iterator local_const_iterator;
|
||||
typedef typename bucket_t::const_iterator const_local_iterator;
|
||||
|
||||
//*********************************************************************
|
||||
class iterator : public etl::iterator<ETL_OR_STD::forward_iterator_tag, TKey>
|
||||
@ -500,7 +511,7 @@ namespace etl
|
||||
/// Returns a const_iterator to the beginning of the unordered_multiset bucket.
|
||||
///\return A const iterator to the beginning of the unordered_multiset bucket.
|
||||
//*********************************************************************
|
||||
local_const_iterator begin(size_t i) const
|
||||
const_local_iterator begin(size_t i) const
|
||||
{
|
||||
return pbuckets[i].cbegin();
|
||||
}
|
||||
@ -509,7 +520,7 @@ namespace etl
|
||||
/// Returns a const_iterator to the beginning of the unordered_multiset bucket.
|
||||
///\return A const iterator to the beginning of the unordered_multiset bucket.
|
||||
//*********************************************************************
|
||||
local_const_iterator cbegin(size_t i) const
|
||||
const_local_iterator cbegin(size_t i) const
|
||||
{
|
||||
return pbuckets[i].cbegin();
|
||||
}
|
||||
@ -554,7 +565,7 @@ namespace etl
|
||||
/// Returns a const_iterator to the end of the unordered_multiset bucket.
|
||||
///\return A const iterator to the end of the unordered_multiset bucket.
|
||||
//*********************************************************************
|
||||
local_const_iterator end(size_t i) const
|
||||
const_local_iterator end(size_t i) const
|
||||
{
|
||||
return pbuckets[i].cend();
|
||||
}
|
||||
@ -563,7 +574,7 @@ namespace etl
|
||||
/// Returns a const_iterator to the end of the unordered_multiset bucket.
|
||||
///\return A const iterator to the end of the unordered_multiset bucket.
|
||||
//*********************************************************************
|
||||
local_const_iterator cend(size_t i) const
|
||||
const_local_iterator cend(size_t i) const
|
||||
{
|
||||
return pbuckets[i].cend();
|
||||
}
|
||||
@ -1390,7 +1401,21 @@ namespace etl
|
||||
template <typename TKey, typename TMapped, typename TKeyCompare>
|
||||
bool operator ==(const etl::iunordered_multiset<TKey, TMapped, TKeyCompare>& lhs, const etl::iunordered_multiset<TKey, TMapped, TKeyCompare>& rhs)
|
||||
{
|
||||
return (lhs.size() == rhs.size()) && etl::equal(lhs.begin(), lhs.end(), rhs.begin());
|
||||
const bool sizes_match = (lhs.size() == rhs.size());
|
||||
bool elements_match = true;
|
||||
|
||||
if (sizes_match)
|
||||
{
|
||||
for (size_t i = 0; (i < lhs.bucket_count()) && elements_match; ++i)
|
||||
{
|
||||
if (!etl::is_permutation(lhs.begin(i), lhs.end(i), rhs.begin(i)))
|
||||
{
|
||||
elements_match = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (sizes_match && elements_match);
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
|
||||
@ -144,6 +144,7 @@ namespace etl
|
||||
|
||||
typedef etl::forward_link<0> link_t;
|
||||
|
||||
//*********************************************************************
|
||||
// The nodes that store the elements.
|
||||
struct node_t : public link_t
|
||||
{
|
||||
@ -155,6 +156,16 @@ namespace etl
|
||||
value_type key;
|
||||
};
|
||||
|
||||
friend bool operator ==(const node_t& lhs, const node_t& rhs)
|
||||
{
|
||||
return (lhs.key == rhs.key);
|
||||
}
|
||||
|
||||
friend bool operator !=(const node_t& lhs, const node_t& rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
typedef etl::intrusive_forward_list<node_t, link_t> bucket_t;
|
||||
@ -164,7 +175,7 @@ namespace etl
|
||||
|
||||
// Local iterators iterate over one bucket.
|
||||
typedef typename bucket_t::iterator local_iterator;
|
||||
typedef typename bucket_t::const_iterator local_const_iterator;
|
||||
typedef typename bucket_t::const_iterator const_local_iterator;
|
||||
|
||||
//*********************************************************************
|
||||
class iterator : public etl::iterator<ETL_OR_STD::forward_iterator_tag, TKey>
|
||||
@ -501,7 +512,7 @@ namespace etl
|
||||
/// Returns a const_iterator to the beginning of the unordered_set bucket.
|
||||
///\return A const iterator to the beginning of the unordered_set bucket.
|
||||
//*********************************************************************
|
||||
local_const_iterator begin(size_t i) const
|
||||
const_local_iterator begin(size_t i) const
|
||||
{
|
||||
return pbuckets[i].cbegin();
|
||||
}
|
||||
@ -510,7 +521,7 @@ namespace etl
|
||||
/// Returns a const_iterator to the beginning of the unordered_set bucket.
|
||||
///\return A const iterator to the beginning of the unordered_set bucket.
|
||||
//*********************************************************************
|
||||
local_const_iterator cbegin(size_t i) const
|
||||
const_local_iterator cbegin(size_t i) const
|
||||
{
|
||||
return pbuckets[i].cbegin();
|
||||
}
|
||||
@ -555,7 +566,7 @@ namespace etl
|
||||
/// Returns a const_iterator to the end of the unordered_set bucket.
|
||||
///\return A const iterator to the end of the unordered_set bucket.
|
||||
//*********************************************************************
|
||||
local_const_iterator end(size_t i) const
|
||||
const_local_iterator end(size_t i) const
|
||||
{
|
||||
return pbuckets[i].cend();
|
||||
}
|
||||
@ -564,7 +575,7 @@ namespace etl
|
||||
/// Returns a const_iterator to the end of the unordered_set bucket.
|
||||
///\return A const iterator to the end of the unordered_set bucket.
|
||||
//*********************************************************************
|
||||
local_const_iterator cend(size_t i) const
|
||||
const_local_iterator cend(size_t i) const
|
||||
{
|
||||
return pbuckets[i].cend();
|
||||
}
|
||||
@ -1303,40 +1314,40 @@ namespace etl
|
||||
//*********************************************************************
|
||||
void adjust_first_last_markers_after_erase(bucket_t* pcurrent)
|
||||
{
|
||||
if (empty())
|
||||
if (empty())
|
||||
{
|
||||
first = pbuckets;
|
||||
last = pbuckets;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pcurrent == first)
|
||||
{
|
||||
// We erased the first so, we need to search again from where we erased.
|
||||
while (first->empty())
|
||||
{
|
||||
++first;
|
||||
}
|
||||
}
|
||||
else if (pcurrent == last)
|
||||
{
|
||||
// We erased the last, so we need to search again. Start from the first, go no further than the current last.
|
||||
bucket_t* pcurrent = first;
|
||||
bucket_t* pend = last;
|
||||
|
||||
last = first;
|
||||
|
||||
while (pcurrent != pend)
|
||||
{
|
||||
if (!pcurrent->empty())
|
||||
{
|
||||
first = pbuckets;
|
||||
last = pbuckets;
|
||||
last = pcurrent;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pcurrent == first)
|
||||
{
|
||||
// We erased the first so, we need to search again from where we erased.
|
||||
while (first->empty())
|
||||
{
|
||||
++first;
|
||||
}
|
||||
}
|
||||
else if (pcurrent == last)
|
||||
{
|
||||
// We erased the last, so we need to search again. Start from the first, go no further than the current last.
|
||||
bucket_t* pcurrent = first;
|
||||
bucket_t* pend = last;
|
||||
|
||||
last = first;
|
||||
|
||||
while (pcurrent != pend)
|
||||
{
|
||||
if (!pcurrent->empty())
|
||||
{
|
||||
last = pcurrent;
|
||||
}
|
||||
|
||||
++pcurrent;
|
||||
}
|
||||
}
|
||||
}
|
||||
++pcurrent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Disable copy construction.
|
||||
@ -1364,9 +1375,9 @@ namespace etl
|
||||
/// For library debugging purposes only.
|
||||
ETL_DECLARE_DEBUG_COUNT
|
||||
|
||||
//*************************************************************************
|
||||
/// Destructor.
|
||||
//*************************************************************************
|
||||
//*************************************************************************
|
||||
/// Destructor.
|
||||
//*************************************************************************
|
||||
#if defined(ETL_POLYMORPHIC_UNORDERED_SET) || defined(ETL_POLYMORPHIC_CONTAINERS)
|
||||
public:
|
||||
virtual ~iunordered_set()
|
||||
@ -1384,20 +1395,34 @@ namespace etl
|
||||
/// Equal operator.
|
||||
///\param lhs Reference to the first unordered_set.
|
||||
///\param rhs Reference to the second unordered_set.
|
||||
///\return <b>true</b> if the arrays are equal, otherwise <b>false</b>
|
||||
///\return <b>true</b> if the sets are equal, otherwise <b>false</b>
|
||||
///\ingroup unordered_set
|
||||
//***************************************************************************
|
||||
template <typename TKey, typename TMapped, typename TKeyCompare>
|
||||
bool operator ==(const etl::iunordered_set<TKey, TMapped, TKeyCompare>& lhs, const etl::iunordered_set<TKey, TMapped, TKeyCompare>& rhs)
|
||||
{
|
||||
return (lhs.size() == rhs.size()) && etl::equal(lhs.begin(), lhs.end(), rhs.begin());
|
||||
const bool sizes_match = (lhs.size() == rhs.size());
|
||||
bool elements_match = true;
|
||||
|
||||
if (sizes_match)
|
||||
{
|
||||
for (size_t i = 0; (i < lhs.bucket_count()) && elements_match; ++i)
|
||||
{
|
||||
if (!etl::is_permutation(lhs.begin(i), lhs.end(i), rhs.begin(i)))
|
||||
{
|
||||
elements_match = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (sizes_match && elements_match);
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
/// Not equal operator.
|
||||
///\param lhs Reference to the first unordered_set.
|
||||
///\param rhs Reference to the second unordered_set.
|
||||
///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b>
|
||||
///\return <b>true</b> if the sets are not equal, otherwise <b>false</b>
|
||||
///\ingroup unordered_set
|
||||
//***************************************************************************
|
||||
template <typename TKey, typename TMapped, typename TKeyCompare>
|
||||
|
||||
@ -960,6 +960,75 @@ namespace
|
||||
CHECK_CLOSE(2.0, data.load_factor(), 0.01);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_equality_comparison_fails_when_hash_collisions_occur_582)
|
||||
{
|
||||
struct bad_hash
|
||||
{
|
||||
// Force hash collisions
|
||||
size_t operator()(int key) const
|
||||
{
|
||||
return key % 4;
|
||||
}
|
||||
};
|
||||
|
||||
using etl_map = etl::unordered_map<int, std::string, 20, 20, bad_hash>;
|
||||
using stl_map = std::unordered_map<int, std::string, bad_hash>;
|
||||
|
||||
std::vector<etl_map::value_type> random_keys1 =
|
||||
{
|
||||
{17, "17"}, {14, "14"}, { 3, "3"}, { 7, "7"}, { 2, "2"},
|
||||
{ 6, "6"}, { 9, "9"}, { 3, "3"}, {18, "18"}, {10, "10"},
|
||||
{ 8, "8"}, {11, "11"}, { 4, "4"}, { 1, "1"}, {12, "12"},
|
||||
{15, "15"}, {16, "16"}, { 0, "0"}, { 5, "5"}, {19, "19"}
|
||||
};
|
||||
|
||||
std::vector<etl_map::value_type> random_keys2 =
|
||||
{
|
||||
{ 3, "3"}, { 6, "6"}, { 5, "5"}, {17, "17"}, { 2, "2"},
|
||||
{ 7, "7"}, { 3, "3"}, {19, "19"}, { 8, "8"}, {15, "15"},
|
||||
{14, "14"}, { 0, "0"}, {18, "18"}, { 4, "4"}, {10, "10"},
|
||||
{ 9, "9"}, {16, "16"}, {11, "11"}, {12, "12"}, { 1, "1"}
|
||||
};
|
||||
|
||||
// Check that the input data is valid.
|
||||
CHECK_EQUAL(random_keys1.size(), random_keys2.size());
|
||||
CHECK(std::is_permutation(random_keys1.begin(), random_keys1.end(), random_keys2.begin()));
|
||||
|
||||
//***************************************************
|
||||
// Fill ETL
|
||||
etl_map etlmap1;
|
||||
etl_map etlmap2;
|
||||
|
||||
for (auto i : random_keys1)
|
||||
{
|
||||
etlmap1.insert(i);
|
||||
}
|
||||
|
||||
for (auto i : random_keys2)
|
||||
{
|
||||
etlmap2.insert(i);
|
||||
}
|
||||
|
||||
//***************************************************
|
||||
// Fill STD
|
||||
stl_map stdmap1;
|
||||
stl_map stdmap2;
|
||||
|
||||
for (auto i : random_keys1)
|
||||
{
|
||||
stdmap1.insert(i);
|
||||
}
|
||||
|
||||
for (auto i : random_keys2)
|
||||
{
|
||||
stdmap2.insert(i);
|
||||
}
|
||||
|
||||
//***************************************************
|
||||
CHECK_EQUAL((stdmap1 == stdmap2), (etlmap1 == etlmap2));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST_FIXTURE(SetupFixture, test_insert_and_erase_bug)
|
||||
{
|
||||
@ -1065,11 +1134,11 @@ namespace
|
||||
CustomHashFunction chf(1);
|
||||
CustomKeyEq ceq(2);
|
||||
|
||||
etl::unordered_map<uint32_t, uint32_t, 5, 5, CustomHashFunction, CustomKeyEq> set1(chf, ceq);
|
||||
etl::unordered_map<uint32_t, uint32_t, 5, 5, CustomHashFunction, CustomKeyEq> set2(set1);
|
||||
etl::unordered_map<uint32_t, uint32_t, 5, 5, CustomHashFunction, CustomKeyEq> map1(chf, ceq);
|
||||
etl::unordered_map<uint32_t, uint32_t, 5, 5, CustomHashFunction, CustomKeyEq> map2(map1);
|
||||
|
||||
CHECK_EQUAL(chf.id, set2.hash_function().id);
|
||||
CHECK_EQUAL(ceq.id, set2.key_eq().id);
|
||||
CHECK_EQUAL(chf.id, map2.hash_function().id);
|
||||
CHECK_EQUAL(ceq.id, map2.key_eq().id);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
@ -1081,13 +1150,13 @@ namespace
|
||||
CustomHashFunction chf3(3);
|
||||
CustomKeyEq ceq4(4);
|
||||
|
||||
etl::unordered_map<uint32_t, uint32_t, 5, 5, CustomHashFunction, CustomKeyEq> set1(chf1, ceq2);
|
||||
etl::unordered_map<uint32_t, uint32_t, 5, 5, CustomHashFunction, CustomKeyEq> set2(chf3, ceq4);
|
||||
etl::unordered_map<uint32_t, uint32_t, 5, 5, CustomHashFunction, CustomKeyEq> map1(chf1, ceq2);
|
||||
etl::unordered_map<uint32_t, uint32_t, 5, 5, CustomHashFunction, CustomKeyEq> map2(chf3, ceq4);
|
||||
|
||||
set2.operator=(set1);
|
||||
map2.operator=(map1);
|
||||
|
||||
CHECK_EQUAL(chf1.id, set2.hash_function().id);
|
||||
CHECK_EQUAL(ceq2.id, set2.key_eq().id);
|
||||
CHECK_EQUAL(chf1.id, map2.hash_function().id);
|
||||
CHECK_EQUAL(ceq2.id, map2.key_eq().id);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
@ -1106,10 +1175,10 @@ namespace
|
||||
value_type{5, 55}
|
||||
};
|
||||
|
||||
etl::unordered_map<uint32_t, uint32_t, 5, 5, CustomHashFunction, CustomKeyEq> set1(data.begin(), data.end(), chf1, ceq2);
|
||||
etl::unordered_map<uint32_t, uint32_t, 5, 5, CustomHashFunction, CustomKeyEq> map1(data.begin(), data.end(), chf1, ceq2);
|
||||
|
||||
CHECK_EQUAL(chf1.id, set1.hash_function().id);
|
||||
CHECK_EQUAL(ceq2.id, set1.key_eq().id);
|
||||
CHECK_EQUAL(chf1.id, map1.hash_function().id);
|
||||
CHECK_EQUAL(ceq2.id, map1.key_eq().id);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
@ -1120,10 +1189,10 @@ namespace
|
||||
|
||||
using value_type = etl::unordered_map<uint32_t, uint32_t, 5, 5, CustomHashFunction, CustomKeyEq>::value_type;
|
||||
|
||||
etl::unordered_map<uint32_t, uint32_t, 5, 5, CustomHashFunction, CustomKeyEq> set1({ value_type{1, 11}, value_type{2, 22}, value_type{3, 33}, value_type{4, 44}, value_type{5, 55} }, chf1, ceq2);
|
||||
etl::unordered_map<uint32_t, uint32_t, 5, 5, CustomHashFunction, CustomKeyEq> map1({ value_type{1, 11}, value_type{2, 22}, value_type{3, 33}, value_type{4, 44}, value_type{5, 55} }, chf1, ceq2);
|
||||
|
||||
CHECK_EQUAL(chf1.id, set1.hash_function().id);
|
||||
CHECK_EQUAL(ceq2.id, set1.key_eq().id);
|
||||
CHECK_EQUAL(chf1.id, map1.hash_function().id);
|
||||
CHECK_EQUAL(ceq2.id, map1.key_eq().id);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ -839,6 +839,75 @@ namespace
|
||||
CHECK_CLOSE(2.0, data.load_factor(), 0.01);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_equality_comparison_fails_when_hash_collisions_occur_582)
|
||||
{
|
||||
struct bad_hash
|
||||
{
|
||||
// Force hash collisions
|
||||
size_t operator()(int key) const
|
||||
{
|
||||
return key % 4;
|
||||
}
|
||||
};
|
||||
|
||||
using etl_map = etl::unordered_multimap<int, std::string, 20, 20, bad_hash>;
|
||||
using stl_map = std::unordered_multimap<int, std::string, bad_hash>;
|
||||
|
||||
std::vector<etl_map::value_type> random_keys1 =
|
||||
{
|
||||
{17, "17"}, {14, "14"}, { 3, "3"}, { 7, "7"}, { 2, "2"},
|
||||
{ 6, "6"}, { 9, "9"}, { 3, "3"}, {18, "18"}, {10, "10"},
|
||||
{ 8, "8"}, {11, "11"}, { 4, "4"}, { 1, "1"}, {12, "12"},
|
||||
{15, "15"}, {16, "16"}, { 0, "0"}, { 5, "5"}, {19, "19"}
|
||||
};
|
||||
|
||||
std::vector<etl_map::value_type> random_keys2 =
|
||||
{
|
||||
{ 3, "3"}, { 6, "6"}, { 5, "5"}, {17, "17"}, { 2, "2"},
|
||||
{ 7, "7"}, { 3, "3"}, {19, "19"}, { 8, "8"}, {15, "15"},
|
||||
{14, "14"}, { 0, "0"}, {18, "18"}, { 4, "4"}, {10, "10"},
|
||||
{ 9, "9"}, {16, "16"}, {11, "11"}, {12, "12"}, { 1, "1"}
|
||||
};
|
||||
|
||||
// Check that the input data is valid.
|
||||
CHECK_EQUAL(random_keys1.size(), random_keys2.size());
|
||||
CHECK(std::is_permutation(random_keys1.begin(), random_keys1.end(), random_keys2.begin()));
|
||||
|
||||
//***************************************************
|
||||
// Fill ETL
|
||||
etl_map etlmap1;
|
||||
etl_map etlmap2;
|
||||
|
||||
for (auto i : random_keys1)
|
||||
{
|
||||
etlmap1.insert(i);
|
||||
}
|
||||
|
||||
for (auto i : random_keys2)
|
||||
{
|
||||
etlmap2.insert(i);
|
||||
}
|
||||
|
||||
//***************************************************
|
||||
// Fill STD
|
||||
stl_map stdmap1;
|
||||
stl_map stdmap2;
|
||||
|
||||
for (auto i : random_keys1)
|
||||
{
|
||||
stdmap1.insert(i);
|
||||
}
|
||||
|
||||
for (auto i : random_keys2)
|
||||
{
|
||||
stdmap2.insert(i);
|
||||
}
|
||||
|
||||
//***************************************************
|
||||
CHECK_EQUAL((stdmap1 == stdmap2), (etlmap1 == etlmap2));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST_FIXTURE(SetupFixture, test_insert_and_erase_bug)
|
||||
{
|
||||
@ -875,11 +944,11 @@ namespace
|
||||
CustomHashFunction chf(1);
|
||||
CustomKeyEq ceq(2);
|
||||
|
||||
etl::unordered_multimap<uint32_t, uint32_t, 5, 5, CustomHashFunction, CustomKeyEq> set1(chf, ceq);
|
||||
etl::unordered_multimap<uint32_t, uint32_t, 5, 5, CustomHashFunction, CustomKeyEq> set2(set1);
|
||||
etl::unordered_multimap<uint32_t, uint32_t, 5, 5, CustomHashFunction, CustomKeyEq> map1(chf, ceq);
|
||||
etl::unordered_multimap<uint32_t, uint32_t, 5, 5, CustomHashFunction, CustomKeyEq> map2(map1);
|
||||
|
||||
CHECK_EQUAL(chf.id, set2.hash_function().id);
|
||||
CHECK_EQUAL(ceq.id, set2.key_eq().id);
|
||||
CHECK_EQUAL(chf.id, map2.hash_function().id);
|
||||
CHECK_EQUAL(ceq.id, map2.key_eq().id);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
@ -891,13 +960,13 @@ namespace
|
||||
CustomHashFunction chf3(3);
|
||||
CustomKeyEq ceq4(4);
|
||||
|
||||
etl::unordered_multimap<uint32_t, uint32_t, 5, 5, CustomHashFunction, CustomKeyEq> set1(chf1, ceq2);
|
||||
etl::unordered_multimap<uint32_t, uint32_t, 5, 5, CustomHashFunction, CustomKeyEq> set2(chf3, ceq4);
|
||||
etl::unordered_multimap<uint32_t, uint32_t, 5, 5, CustomHashFunction, CustomKeyEq> map1(chf1, ceq2);
|
||||
etl::unordered_multimap<uint32_t, uint32_t, 5, 5, CustomHashFunction, CustomKeyEq> map2(chf3, ceq4);
|
||||
|
||||
set2.operator=(set1);
|
||||
map2.operator=(map1);
|
||||
|
||||
CHECK_EQUAL(chf1.id, set2.hash_function().id);
|
||||
CHECK_EQUAL(ceq2.id, set2.key_eq().id);
|
||||
CHECK_EQUAL(chf1.id, map2.hash_function().id);
|
||||
CHECK_EQUAL(ceq2.id, map2.key_eq().id);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
@ -916,10 +985,10 @@ namespace
|
||||
value_type{5, 55}
|
||||
};
|
||||
|
||||
etl::unordered_multimap<uint32_t, uint32_t, 5, 5, CustomHashFunction, CustomKeyEq> set1(data.begin(), data.end(), chf1, ceq2);
|
||||
etl::unordered_multimap<uint32_t, uint32_t, 5, 5, CustomHashFunction, CustomKeyEq> map1(data.begin(), data.end(), chf1, ceq2);
|
||||
|
||||
CHECK_EQUAL(chf1.id, set1.hash_function().id);
|
||||
CHECK_EQUAL(ceq2.id, set1.key_eq().id);
|
||||
CHECK_EQUAL(chf1.id, map1.hash_function().id);
|
||||
CHECK_EQUAL(ceq2.id, map1.key_eq().id);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
@ -930,10 +999,10 @@ namespace
|
||||
|
||||
using value_type = etl::unordered_multimap<uint32_t, uint32_t, 5, 5, CustomHashFunction, CustomKeyEq>::value_type;
|
||||
|
||||
etl::unordered_multimap<uint32_t, uint32_t, 5, 5, CustomHashFunction, CustomKeyEq> set1({ value_type{1, 11}, value_type{2, 22}, value_type{3, 33}, value_type{4, 44}, value_type{5, 55} }, chf1, ceq2);
|
||||
etl::unordered_multimap<uint32_t, uint32_t, 5, 5, CustomHashFunction, CustomKeyEq> map1({ value_type{1, 11}, value_type{2, 22}, value_type{3, 33}, value_type{4, 44}, value_type{5, 55} }, chf1, ceq2);
|
||||
|
||||
CHECK_EQUAL(chf1.id, set1.hash_function().id);
|
||||
CHECK_EQUAL(ceq2.id, set1.key_eq().id);
|
||||
CHECK_EQUAL(chf1.id, map1.hash_function().id);
|
||||
CHECK_EQUAL(ceq2.id, map1.key_eq().id);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ -36,6 +36,7 @@ SOFTWARE.
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <numeric>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "data.h"
|
||||
|
||||
@ -770,6 +771,59 @@ namespace
|
||||
CHECK_CLOSE(2.0, data.load_factor(), 0.01);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_equality_comparison_fails_when_hash_collisions_occur_582)
|
||||
{
|
||||
struct bad_hash
|
||||
{
|
||||
// Force hash collisions
|
||||
size_t operator()(int key) const
|
||||
{
|
||||
return key % 4;
|
||||
}
|
||||
};
|
||||
|
||||
std::vector<int> random_keys1 = { 17, 14, 3, 7, 2, 6, 9, 3, 18, 10, 8, 11, 4, 1, 12, 15, 16, 0, 5, 19 };
|
||||
std::vector<int> random_keys2 = { 3, 6, 5, 17, 2, 7, 3, 19, 8, 15, 14, 0, 18, 4, 10, 9, 16, 11, 12, 1 };
|
||||
|
||||
// Check that the input data is valid.
|
||||
CHECK_EQUAL(random_keys1.size(), random_keys2.size());
|
||||
CHECK(std::is_permutation(random_keys1.begin(), random_keys1.end(), random_keys2.begin()));
|
||||
|
||||
//***************************************************
|
||||
// Fill ETL
|
||||
etl::unordered_multiset<int, 20, 20, bad_hash> etlset1;
|
||||
etl::unordered_multiset<int, 20, 20, bad_hash> etlset2;
|
||||
|
||||
for (auto i : random_keys1)
|
||||
{
|
||||
etlset1.insert(i);
|
||||
}
|
||||
|
||||
for (auto i : random_keys2)
|
||||
{
|
||||
etlset2.insert(i);
|
||||
}
|
||||
|
||||
//***************************************************
|
||||
// Fill STD
|
||||
std::unordered_multiset<int, bad_hash> stdset1;
|
||||
std::unordered_multiset<int, bad_hash> stdset2;
|
||||
|
||||
for (auto i : random_keys1)
|
||||
{
|
||||
stdset1.insert(i);
|
||||
}
|
||||
|
||||
for (auto i : random_keys2)
|
||||
{
|
||||
stdset2.insert(i);
|
||||
}
|
||||
|
||||
//***************************************************
|
||||
CHECK_EQUAL((stdset1 == stdset2), (etlset1 == etlset2));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_copying_of_hash_and_key_compare_with_copy_construct)
|
||||
{
|
||||
|
||||
@ -713,31 +713,31 @@ namespace
|
||||
{
|
||||
struct bad_hash
|
||||
{
|
||||
// Often has hash collisions
|
||||
// Force hash collisions
|
||||
size_t operator()(int key) const
|
||||
{
|
||||
return key % 4;
|
||||
}
|
||||
};
|
||||
|
||||
std::vector<int> keys1 = { 17, 14, 3, 7, 2, 6, 9, 3, 18, 10, 8, 11, 4, 1, 12, 15, 16, 0, 5, 19 };
|
||||
std::vector<int> keys2 = { 3, 6, 5, 17, 2, 7, 3, 19, 8, 15, 14, 0, 18, 4, 10, 9, 16, 11, 12, 1 };
|
||||
std::vector<int> random_keys1 = { 17, 14, 3, 7, 2, 6, 9, 3, 18, 10, 8, 11, 4, 1, 12, 15, 16, 0, 5, 19 };
|
||||
std::vector<int> random_keys2 = { 3, 6, 5, 17, 2, 7, 3, 19, 8, 15, 14, 0, 18, 4, 10, 9, 16, 11, 12, 1 };
|
||||
|
||||
// Check that the input data is valid.
|
||||
CHECK_EQUAL(keys1.size(), keys2.size());
|
||||
CHECK(std::is_permutation(keys1.begin(), keys1.end(), keys2.begin()));
|
||||
CHECK_EQUAL(random_keys1.size(), random_keys2.size());
|
||||
CHECK(std::is_permutation(random_keys1.begin(), random_keys1.end(), random_keys2.begin()));
|
||||
|
||||
//***************************************************
|
||||
// Fill ETL
|
||||
etl::unordered_set<int, 20, 20, bad_hash> etlset1;
|
||||
etl::unordered_set<int, 20, 20, bad_hash> etlset2;
|
||||
|
||||
for (auto i : keys1)
|
||||
for (auto i : random_keys1)
|
||||
{
|
||||
etlset1.insert(i);
|
||||
}
|
||||
|
||||
for (auto i : keys2)
|
||||
for (auto i : random_keys2)
|
||||
{
|
||||
etlset2.insert(i);
|
||||
}
|
||||
@ -747,19 +747,18 @@ namespace
|
||||
std::unordered_set<int, bad_hash> stdset1;
|
||||
std::unordered_set<int, bad_hash> stdset2;
|
||||
|
||||
for (auto i : keys1)
|
||||
for (auto i : random_keys1)
|
||||
{
|
||||
stdset1.insert(i);
|
||||
}
|
||||
|
||||
for (auto i : keys2)
|
||||
for (auto i : random_keys2)
|
||||
{
|
||||
stdset2.insert(i);
|
||||
}
|
||||
|
||||
//***************************************************
|
||||
CHECK(etlset1 == etlset2);
|
||||
CHECK(stdset1 == stdset2);
|
||||
CHECK_EQUAL((stdset1 == stdset2), (etlset1 == etlset2));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user