Looking for a general review:
#ifndef HASH_TABLE_HASH_TABLE_H
#define HASH_TABLE_HASH_TABLE_H
#include <utility>
#include <stdexcept>
namespace mds {
template<typename K, typename V >
class hash_table {
std::size_t M;
std::pair<K, V> *table;
bool *mark;
std::size_t N;
std::size_t hash(std::size_t h, std::size_t i) const {
auto hash2 = (std::hash<std::size_t>()(h) % (M - 1));
return ((h % M) + i * (hash2 | 0x1)) % M;
}
std::size_t power_of_2_ceiling(std::size_t x) const {
auto bits = sizeof(std::size_t) << 3;
--x;
for (auto i = 1u; i != bits; i <<= 1) {
x |= x >> i;
}
return x + 1;
}
public:
hash_table() : hash_table(0) { }
hash_table(std::size_t m)
: M(power_of_2_ceiling(m)),
table(new std::pair<K, V>[M]),
mark(new bool[M]), N(0)
{
for (std::size_t i = 0; i < M; ++i) {
mark[i] = false;
}
}
hash_table(hash_table<K, V>&& map)
: M(map.M), table(map.table),
mark(map.mark), N(map.N) {
map.M = map.N = 0;
map.mark = nullptr;
map.table = nullptr;
}
hash_table(const hash_table<K, V>& map)
: M(map.M), table(new std::pair<K, V>[map.M]),
mark(new bool[map.M]), N(map.N) {
for (std::size_t i = 0; i < M; ++i) {
mark[i] = map.mark[i];
table[i] = map.table[i];
}
}
hash_table(std::unordered_map<K, V>&& map)
: M(power_of_2_ceiling(map.size())),
table(new std::pair<K, V>[M]),
mark(new bool[M]), N(0)
{
for (std::size_t i = 0; i < M; ++i) {
mark[i] = false;
}
for (auto &p : map) {
insert(std::move(p));
}
}
hash_table<K, V>& operator=(hash_table<K, V> other) {
swap(*this, other);
return *this;
}
friend void swap(hash_table<K, V>& first, hash_table<K, V>& second) noexcept {
using std::swap;
swap(first.M, second.M);
swap(first.N, second.N);
swap(first.table, second.table);
swap(first.mark, second.mark);
}
~hash_table() {
delete[] table;
delete[] mark;
}
const std::pair<K, V>* find(const K& key) const {
auto hash_code = std::hash<K>()(key);
auto i = 0u;
auto h = hash(hash_code, i);
while (i < M && mark[h]) {
if (table[h].first == key ) {
return &table[h];
}
h = hash(hash_code, ++i);
}
return nullptr;
}
bool insert(std::pair<K, V>&& p) {
auto hash_code = std::hash<K>()(p.first);
for (std::size_t i = 0; i < M; ++i) {
auto h = hash(hash_code, i);
if (!mark[h]) {
table[h] = std::move(p);
++N;
return mark[h] = true;
}
else if (table[h].first == p.first) {
return false;
}
}
throw std::overflow_error("overflow");
}
bool constains(const K& key) const {
return find(key) != nullptr;
}
std::size_t size() {
return N;
}
};
}
#endif // !HASH_TABLE_HASH_TABLE_H