#include <list>
#include <vector>
#include <array>
template<typename K, typename V, typename H = std::hash<K>, typename P = std::equal_to<K>> class hash_map {
struct item {
std::pair<const K, V> data;
std::size_t cached_hash;
};
std::list<item> data;
H hash;
P predicate;
static const auto items_per_bucket = 5; // Arbitrary- determine by profile if performance undesirable
public:
struct iterator {
typename std::list<item>::iterator it;
std::pair<const K, V>& operator*() { return it->data; }
std::pair<const K, V>* operator->() { return &it->data; }
iterator operator++(int) {
auto ret(*this);
++it;
return ret;
}
iterator& operator++() {
++it;
return *this;
}
iterator operator--(int) {
auto ret(*this);
--it;
return ret;
}
iterator& operator--() {
--it;
return *this;
}
};
iterator begin() { return iterator { data.begin() }; }
iterator end() { return iterator { data.end() }; }
std::size_t size() const { return data.size(); }
void clear() { data.clear(); buckets.clear(); }
private:
std::vector<std::vector<iterator>> buckets;
void insert_into_buckets(iterator it) {
if (buckets.size() == 0)
rehash(10); // Arbitrary- determine by profile if performance undesirable
auto&& bucket = buckets[it->cached_hash % buckets.size()];
if (bucket.size() >= items_per_bucket)
rehash(buckets.size() * 2);
buckets[it->cached_hash % buckets.size()].push_back(it);
}
public:
void rehash(std::size_t size) {
auto oldbuckets = std::move(buckets);
buckets.resize(size);
for(auto&& iterators : oldbuckets) {
for(auto&& i : iterators) {
insert_into_buckets(i);
}
}
}
std::pair<iterator, bool> insert(K k, V v) {
auto it = find(k);
if (it == end()) {
std::size_t val = hash(k);
data.push_back(item { { std::move(k), std::move(v) }, val });
try {
insert_into_buckets(--data.end());
} catch(...) {
data.pop_back();
throw;
}
return { --data.end(), true };
}
return { it, false };
}
template<typename AK> iterator find(AK&& k) {
return find(std::forward<AK>(k), hash, predicate);
}
template<typename AK, typename AH> iterator find(AK&& k, AH&& h = AH()) {
return find(std::forward<AK>(k), std::forward<AH>(h), predicate);
}
template<typename AK, typename AH, typename AP> iterator find(AK&& k, AH&& h = AH(), AP&& p = AP()) {
auto&& bucket = buckets[h(k) % buckets.size()];
for(auto it : bucket) {
if (p(k, it->data.first))
return it;
}
return end();
}
template<typename AK> iterator erase(AK&& k) {
return erase(find(std::forward<AK>(k), hash, predicate));
}
template<typename AK, typename AH> iterator erase(AK&& k, AH&& h = AH()) {
return erase(find(std::forward<AK>(k), std::forward<AH>(h), predicate));
}
template<typename AK, typename AH, typename AP> iterator erase(AK&& k, AH&& h = AH(), AP&& p = AP()) {
return erase(find(std::forward<AK>(k), std::forward<AH>(h), std:forward<AP>(p)));
}
iterator erase(iterator it) {
auto&& bucket = buckets[it->cached_hash % buckets.size()];
for(int i = 0; i < bucket.size(); i++) {
if (bucket[i] == it) {
bucket.erase(bucket.begin() + i);
return data.erase(it.it);
}
}
return end();
}
template<typename AK> V& operator[](AK&& ak) {
auto it = find(std::forward<AK>(ak));
if (it == end())
return insert(ak, V()).first->data.second;
return it->data.second;
}
};
int main() {
hash_map<int, int> x;
}