HashTable fix bug during resize with nonstandard grower

This commit is contained in:
Maksim Kita 2021-02-15 01:12:02 +03:00
parent 4f919261bd
commit e3003add57
2 changed files with 50 additions and 1 deletions

View File

@ -539,7 +539,8 @@ protected:
* after transferring all the elements from the old halves you need to [ o x ]
* process tail from the collision resolution chain immediately after it [ o x ]
*/
for (; !buf[i].isZero(*this); ++i)
size_t new_size = grower.bufSize();
for (; i < new_size && !buf[i].isZero(*this); ++i)
{
size_t updated_place_value = reinsert(buf[i], buf[i].getHash(*this));

View File

@ -317,3 +317,51 @@ TEST(HashTable, SerializationDeserialization)
ASSERT_EQ(convertToSet(cont), convertToSet(deserialized));
}
}
template <typename T>
struct IdentityHash
{
size_t operator()(T x) const { return x; }
};
struct OneElementResizeGrower
{
/// If collision resolution chains are contiguous, we can implement erase operation by moving the elements.
static constexpr auto performs_linear_probing_with_single_step = true;
static constexpr size_t initial_count = 1;
size_t bufSize() const { return buf_size; }
size_t place(size_t x) const { return x % buf_size; }
size_t next(size_t pos) const { return (pos + 1) % buf_size; }
bool overflow(size_t elems) const { return elems >= buf_size; }
void increaseSize() { ++buf_size; }
void set(size_t) { }
void setBufSize(size_t buf_size_) { buf_size = buf_size_; }
size_t buf_size = initial_count;
};
TEST(HashTable, Resize)
{
{
/// Test edge case if after resize all cells are resized in end of buf and will take half of
/// hash table place.
using HashSet = HashSet<int, IdentityHash<int>, OneElementResizeGrower>;
HashSet cont;
cont.insert(3);
cont.insert(1);
std::set<int> expected = {1, 3};
std::set<int> actual = convertToSet(cont);
ASSERT_EQ(actual, expected);
}
}