6#include "cplib/hash/wyhash.hpp"
14 enum State { EMPTY, PHANTOM, SENTINEL };
16 std::variant<State, T> inner;
18 HashCell() : inner(State::EMPTY) {}
20 bool empty()
const {
return inner.index() == 0 && std::get<0>(inner) == State::EMPTY; }
22 bool occupied()
const {
return inner.index() == 1; }
24 bool phantom()
const {
return inner.index() == 0 && std::get<0>(inner) == State::PHANTOM; }
26 bool sentinel()
const {
return inner.index() == 0 && std::get<0>(inner) == State::SENTINEL; }
28 void insert(
const T& val) { inner = val; }
30 void insert(T&& val) { inner = std::move(val); }
32 const T& value()
const {
return std::get<1>(inner); }
34 T& value() {
return std::get<1>(inner); }
36 void erase() { inner = State::PHANTOM; }
61template <
typename T,
typename Hash = WyHash<T>,
typename Eq = std::equal_to<T>>
64 using size_type = std::size_t;
66 using cell_iterator =
typename std::vector<impl::HashCell<T>>::iterator;
73 HashTable() : nonempty(0), occupied(0), disable_shrink(false) { _allocate_cells(4); }
81 template <
typename InputIt>
82 HashTable(InputIt first, InputIt last) : nonempty(0), occupied(0), disable_shrink(false) {
84 if (std::is_base_of_v<std::random_access_iterator_tag, std::iterator_traits<InputIt>::iterator_category>) {
85 auto dist = std::distance(first, last);
86 while (dist > (cap >> 1)) {
91 for (; first != last; ++first) {
97 size_type
size()
const {
return occupied; }
100 bool empty()
const {
return occupied == 0; }
107 size_type
capacity()
const {
return cap_mask + 1; }
126 template <
bool Revive = false>
128 size_type loc = hash(x) & cap_mask;
129 std::optional<cell_iterator> phantom;
130 while (!cells[loc].
empty()) {
131 if (cells[loc].occupied() && eq(x, cells[loc].value())) {
132 return cells.begin() + loc;
134 if (Revive && cells[loc].phantom()) {
135 phantom = cells.begin() + loc;
137 loc = (loc + 1) & cap_mask;
139 if (Revive && phantom) {
142 return cells.begin() + loc;
155 template <
bool Replace = false>
157 cell_iterator cell = find_cell<true>(x);
158 bool do_insert =
true;
159 if (!cell->occupied()) {
166 }
else if (Replace) {
175 template <
bool Replace = false>
177 cell_iterator cell = find_cell<true>(x);
178 bool do_insert =
true;
179 if (!cell->occupied()) {
184 cell->insert(std::move(x));
186 }
else if (Replace) {
187 cell->insert(std::move(x));
197 bool do_erase = !cell->empty();
212 assert(new_cap >= 4 && (new_cap & (new_cap - 1)) == 0);
213 std::vector<impl::HashCell<T>> old_cells = std::move(cells);
214 size_type old_cap = cap_mask + 1;
215 _allocate_cells(new_cap);
217 for (size_type i = 0; i < old_cap; ++i) {
218 if (old_cells[i].occupied()) {
219 size_type loc = hash(old_cells[i].value()) & cap_mask;
220 while (!cells[loc].
empty()) {
221 loc = (loc + 1) & cap_mask;
223 cells[loc] = std::move(old_cells[i]);
244 while (new_size > (new_cap >> 1)) {
249 disable_shrink =
true;
254 std::vector<impl::HashCell<T>> cells;
255 size_type nonempty, occupied, cap_mask;
261 void _allocate_cells(size_type cap) {
262 cells = std::vector<impl::HashCell<T>>(cap + 1);
263 cells.back().inner = impl::HashCell<T>::State::SENTINEL;
268 void _check_rehash() {
270 if (!disable_shrink && occupied < (cap >> 3)) {
273 }
while (occupied < (cap >> 3));
275 }
else if (nonempty > (cap >> 1)) {
276 disable_shrink =
false;
277 if (occupied > (cap >> 2)) {
Linear probing hash table with std non-compliant interface.
Definition: table.hpp:62
bool insert(T &&x)
Insert an element if there is no element already present that compares equal to it.
Definition: table.hpp:176
cell_iterator cell_begin()
Returns pointer to the beginning of the cell array.
Definition: table.hpp:110
size_type capacity() const
Returns the size of the underlying array of cells.
Definition: table.hpp:107
bool insert(const T &x)
Insert an element if there is no element already present that compares equal to it.
Definition: table.hpp:156
bool erase(const T &x)
Remove the element that compares equal to the given value if it is present.
Definition: table.hpp:195
cell_iterator find_cell(const T &x)
Find an element that compares equal to the given value, or an empty cell if not found.
Definition: table.hpp:127
bool contains(const T &x) const
Returns whether an element that compares equal to the given value is found in the hash table.
Definition: table.hpp:147
bool empty() const
Returns whether the hash table contains no element.
Definition: table.hpp:100
HashTable()
Constructs an empty hash table.
Definition: table.hpp:73
HashTable(InputIt first, InputIt last)
Constructs a hash table containing elements from a pair of iterators.
Definition: table.hpp:82
void rehash(size_type new_cap)
Allocate the given capacity, and rehash all elements.
Definition: table.hpp:211
void reserve(size_type new_size)
Reserve capacity and temporary disable shrinking.
Definition: table.hpp:242
size_type size() const
Returns the number of elements in the hash table.
Definition: table.hpp:97
cell_iterator cell_end()
Returns pointer to the end of the cell array.
Definition: table.hpp:118