Fixed bug in hash_table that made rehash() function run forever (#2745)

* Fixed bug in hash_table that made rehash() function to run infinitely on specific conditions when inserting an already existing element

Signed-off-by: Garcia Ruiz <aljanru@amazon.co.uk>

* Replaced erasing to happen in the source list instead

Signed-off-by: Garcia Ruiz <aljanru@amazon.co.uk>

* minor comment improvement

Signed-off-by: Garcia Ruiz <aljanru@amazon.co.uk>

* Small commment improvement

Signed-off-by: Garcia Ruiz <aljanru@amazon.co.uk>

* Small comment fix

Signed-off-by: Garcia Ruiz <aljanru@amazon.co.uk>

* Added assert and fixed code with incorrect hashing

Signed-off-by: Garcia Ruiz <aljanru@amazon.co.uk>

* .

Signed-off-by: Garcia Ruiz <aljanru@amazon.co.uk>

* Addressed PR comments, reverted to void* as it size_t hash is different

Signed-off-by: Garcia Ruiz <aljanru@amazon.co.uk>

* Fixed build on linux

Signed-off-by: Garcia Ruiz <aljanru@amazon.co.uk>

* Addressed PR comments

Signed-off-by: Garcia Ruiz <aljanru@amazon.co.uk>

Co-authored-by: Garcia Ruiz <aljanru@amazon.co.uk>
This commit is contained in:
AMZN-AlexOteiza
2021-08-04 02:38:18 +01:00
committed by GitHub
parent 24740b3f86
commit 45ebf57d3f
4 changed files with 95 additions and 27 deletions
@@ -287,6 +287,55 @@ namespace UnitTest
}
}
TEST_F(HashedContainers, HashTable_InsertionDuplicateOnRehash)
{
struct TwoPtrs
{
void* m_ptr1;
void* m_ptr2;
bool operator==(const TwoPtrs& other) const
{
if (m_ptr1 == other.m_ptr1)
{
return m_ptr2 == other.m_ptr2;
}
else if (m_ptr1 == other.m_ptr2)
{
return m_ptr2 == other.m_ptr1;
}
return false;
}
};
// This hashing function produces different hashes for two equal values,
// which violates the requirement for hashing functions.
// The test makes sure that this does not reproduce an issue that caused the insert() function to loop infinitely.
struct TwoPtrsHasher
{
size_t operator()(const TwoPtrs& p) const
{
size_t hash{ 0 };
AZStd::hash_combine(hash, p.m_ptr1, p.m_ptr2);
return hash;
}
};
using PairSet = AZStd::unordered_set<TwoPtrs, TwoPtrsHasher>;
PairSet set;
set.insert({ (void*)1, (void*)2 });
set.insert({ (void*)3, (void*)4 });
set.insert({ (void*)5, (void*)6 });
set.insert({ (void*)7, (void*)8 });
// Elements with different hashes, but equal
set.insert({ (void*)0x000001ceddd9ca20, (void*)0x000001ceddd9cba0 }); // hash(148335135725641)
set.insert({ (void*)0x000001ceddd9cba0, (void*)0x000001ceddd9ca20 }); // hash(148335135764189)
AZ_TEST_START_TRACE_SUPPRESSION;
// This will trigger the assertion of duplicated elements found
// A bucket size of 23 since is where the collision between different hashes happens
set.rehash(23);
AZ_TEST_STOP_TRACE_SUPPRESSION(1); // 1 assertion
}
TEST_F(HashedContainers, HashTable_Fixed)
{
array<int, 5> elements = {