cpp/map/unordered_map.h

572 lines
16 KiB
C
Raw Normal View History

2023-07-16 07:03:47 +00:00
#include <utility>
#include <list>
#include <vector>
#include <functional>
#include <cassert>
#include <iostream>
#include <memory>
#include <utility>
using std::prev;
template<typename T, typename Allocator=std::allocator<T>>
class List {
private:
class Node;
template<bool is_const>
class base_iterator;
public:
using iterator = base_iterator<false>;
using const_iterator = base_iterator<true>;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
explicit List(const Allocator& alloc = Allocator()) : allocator_node_(alloc) {
AllocateEnd();
}
List(size_t count, const T& value, const Allocator& alloc = Allocator()) : allocator_node_(alloc) {
AllocateEnd();
for (size_t i = 0; i < count; ++i) {
Node* tmp = allocator_node_.allocate(1);
alloc_traits_::construct(allocator_node_, tmp, value);
Link(end_->l, tmp);
}
size_ = count;
}
List(size_t count, const Allocator& alloc = Allocator()) : allocator_node_(alloc) {
AllocateEnd();
for (size_t i = 0; i < count; ++i) {
Node* tmp = allocator_node_.allocate(1);
alloc_traits_::construct(allocator_node_, tmp);
Link(end_->l, tmp);
}
size_ = count;
}
List(const List& another) {
allocator_node_ = alloc_traits_::select_on_container_copy_construction(another.allocator_node_);
AllocateEnd();
for (const T& i: another) {
Node* tmp = allocator_node_.allocate(1);
alloc_traits_::construct(allocator_node_, tmp, i);
Link(end_->l, tmp);
}
size_ = another.size();
}
List(List&& another) : end_(std::move(another.end_)), size_(std::move(another.size_)) {
another.end_ = nullptr;
}
List& operator=(const List& another) {
if (this == &another) return *this;
if (alloc_traits_::propagate_on_container_copy_assignment::value && allocator_node_ != another.allocator_node_) {
allocator_node_ = another.allocator_node_;
}
auto it1 = begin();
auto it2 = another.begin();
for (size_t i = 0; i < std::min(another.size(), size()); ++i) {
*it1 = *it2;
++it1;
++it2;
}
if (another.size() > size()) {
while (size() != another.size()) {
push_back(*it2);
++it2;
}
} else {
while (size() != another.size()) {
pop_back();
}
}
return *this;
}
List& operator=(List&& another) {
auto tmp(std::move(another));
std::swap(end_, tmp.end_);
std::swap(size_, tmp.size_);
return *this;
}
~List() {
if (end_) {
while (end_ != end_->r) {
erase(iterator(end_->r));
}
allocator_node_.deallocate(end_, 1); // TODO
}
}
Allocator get_allocator() {
return allocator_node_;
}
void push_back(const T& value) {
insert(end(), value);
}
void push_back(T&& value) {
insert(end(), std::move(value));
}
void push_front(const T& value) {
insert(begin(), value);
}
void pop_back() {
erase(std::prev(end()));
}
void pop_front() {
erase(begin());
}
template<class... Args>
iterator emplace_back(Args&&... args) {
Node* tmp = allocator_node_.allocate(1);
tmp->l = nullptr;
tmp->r = nullptr;
Allocator tmp1 = allocator_node_;
std::allocator_traits<Allocator>::construct(tmp1, &tmp->value, std::forward<Args>(args)...);
Link(std::prev(end()).it, tmp);
++size_;
return iterator(tmp);
}
size_t size() const { return size_; }
iterator begin() { return iterator(end_->r); }
iterator end() { return iterator(end_); }
const_iterator begin() const { return const_iterator(end_->r); }
const_iterator end() const { return const_iterator(end_); }
const_iterator cbegin() const { return const_iterator(end_->r); }
const_iterator cend() const { return const_iterator(end_); }
reverse_iterator rbegin() { return reverse_iterator(end()); }
reverse_iterator rend() { return reverse_iterator(begin()); }
const_reverse_iterator rbegin() const { return const_reverse_iterator(cend()); }
const_reverse_iterator rend() const { return const_reverse_iterator(cbegin()); }
const_reverse_iterator crbegin() const { return const_reverse_iterator(cend()); }
const_reverse_iterator crend() const { return const_reverse_iterator(cbegin()); }
iterator insert(const_iterator it, const T& value) {
Node* tmp = allocator_node_.allocate(1);
tmp->l = nullptr;
tmp->r = nullptr;
std::allocator_traits<decltype(allocator_node_)>::construct(allocator_node_, tmp, value);
Link(const_cast<Node*>(std::prev(it).it), tmp);
++size_;
return iterator(tmp);
}
iterator insert(const_iterator it, T&& value) {
Node* tmp = allocator_node_.allocate(1);
tmp->l = nullptr;
tmp->r = nullptr;
alloc_traits_::construct(allocator_node_, tmp, std::move(value));
Link(const_cast<Node*>(std::prev(it).it), tmp);
++size_;
return iterator(tmp);
}
void erase(const_iterator it) {
Node* tmp = const_cast<Node*>(it.it);
tmp->l->r = tmp->r;
tmp->r->l = tmp->l;
std::allocator_traits<decltype(allocator_node_)>::destroy(allocator_node_, tmp);
allocator_node_.deallocate(tmp, 1);
--size_;
}
void relink(iterator a, iterator b) {
Link(a.it, b.it);
}
private:
void AllocateEnd() {
end_ = allocator_node_.allocate(1);
end_->l = end_;
end_->r = end_;
}
void Link(Node* l, Node* x) {
Node* r = l->r;
if (r == x)
return;
auto xl = x->l, xr = x->r;
if (xl)
xl->r = xr;
if (xr)
xr->l = xl;
x->l = l;
x->r = r;
l->r = x;
r->l = x;
}
template<bool is_const>
class base_iterator {
friend List;
std::conditional_t<is_const, const Node*, Node*> it;
using U = std::conditional_t<is_const, const T, T>;
public:
using iterator_category = std::bidirectional_iterator_tag;
using value_type = U;
using pointer = U*;
using reference = U&;
using difference_type = int;
base_iterator() : it(nullptr) {}
base_iterator(Node* v) { it = v; }
base_iterator(const base_iterator&) = default;
operator base_iterator<true>() { return base_iterator<true>(it); }
U& operator*() const { return it->value; }
U* operator->() const { return &it->value; }
base_iterator& operator++()& {
it = it->r;
return *this;
}
base_iterator operator++(int)& {
base_iterator tmp = *this;
it = it->r;
return tmp;
}
base_iterator& operator--()& {
it = it->l;
return *this;
}
base_iterator operator--(int)& {
base_iterator tmp = *this;
it = it->l;
return tmp;
}
friend bool operator==(base_iterator first, base_iterator second) { return first.it == second.it; }
friend bool operator!=(base_iterator first, base_iterator second) { return first.it != second.it; }
base_iterator& operator=(const base_iterator<false>& another) {
it = another.it;
return *this;
}
};
struct Node {
Node* l = nullptr;
Node* r = nullptr;
T value;
Node() = default;
Node(const T& value) : value(value) {}
Node(T&& value) : value(std::move(value)) {}
Node& operator=(const Node& another) { value = another.value; }
};
typename std::allocator_traits<Allocator>::template rebind_alloc<Node> allocator_node_;
using alloc_traits_ = std::allocator_traits<decltype(allocator_node_)>;
Node* end_ = nullptr;
size_t size_ = 0;
};
template<typename Key, typename Value, typename Hash = std::hash<Key>, typename Equal = std::equal_to<Key>, typename Alloc = std::allocator<std::pair<const Key, Value>>>
class UnorderedMap {
private:
using NonConstNodeType = std::pair<Key, Value>;
using ListNonConstNodeType = List<NonConstNodeType, typename std::allocator_traits<Alloc>::template rebind_alloc<std::pair<Key, Value>>>;
struct Node {
std::pair<Key, Value> pair;
size_t hash;
Node() {}
Node(const Node& another) : pair(another.pair), hash(another.hash) {}
Node(Node&& another) : pair(std::move(another.pair)), hash(another.hash) { another.hash = 0; }
Node(Key&& key, Value&& value, const Hash& hash_) : pair(std::make_pair(std::move(key), std::move(value))) {
hash = hash_(key);
}
Node(const Key& key, const Value& value, const Hash& hash_) : pair(std::make_pair(key, value)){
hash = hash_(key);
}
Node(std::pair<Key, Value>&& pair_, const Hash& hash_) : pair(std::move(pair_)) {
hash = hash_(pair.first);
}
Node(const std::pair<Key, Value>& pair_, const Hash& hash_) : pair(pair_) {
hash = hash_(pair.first);
}
};
using NewList = List<Node, typename std::allocator_traits<Alloc>::template rebind_alloc<Node>>;
NewList new_all_pairs;
std::vector<typename NewList::iterator> new_hash_table;
size_t GetBucketIdx(const Key& key) {
return hash_(key) % new_hash_table.size();
}
size_t GetBucketIdx(const Node& node) {
return node.hash % new_hash_table.size();
}
public:
using new_iterator = typename NewList::iterator;
template<bool is_const>
struct base_iterator {
using value_type = std::conditional_t<is_const, const std::pair<const Key, Value>, std::pair<const Key, Value>>;
using iterator_category = std::bidirectional_iterator_tag;
using pointer = value_type*;
using reference = value_type&;
using difference_type = int;
new_iterator it;
base_iterator() {}
base_iterator(const base_iterator&) = default;
base_iterator(const new_iterator& another) : it(another) {}
operator base_iterator<true>() { return base_iterator<true>(it); }
base_iterator& operator=(const base_iterator&) = default;
reference operator*() { return *reinterpret_cast<std::pair<const Key, Value>*>(&it->pair); }
pointer operator->() { return reinterpret_cast<std::pair<const Key, Value>*>(&it->pair); }
base_iterator& operator++()& { ++it; return *this; }
base_iterator operator++(int)& { base_iterator tmp(*this); ++it; return tmp; }
base_iterator& operator--()& { --it; return *this; }
base_iterator operator--(int)& { base_iterator tmp(*this); --it; return tmp; }
bool operator==(const base_iterator& another) { return it == another.it; }
bool operator!=(const base_iterator& another) { return it != another.it; }
};
using iterator = base_iterator<false>;
using const_iterator = base_iterator<true>;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
using NodeType = std::pair<const Key, Value>;
UnorderedMap() {
new_hash_table.resize(1000, new_all_pairs.end());
}
UnorderedMap(const UnorderedMap& another) : new_all_pairs(another.new_all_pairs), hash_(another.hash_), equal_(another.equal_) {
new_hash_table.resize(another.new_hash_table.size(), new_all_pairs.end());
new_hash_table[GetBucketIdx(*new_all_pairs.begin())] = new_all_pairs.begin();
for (auto it = std::next(new_all_pairs.begin()); it != new_all_pairs.end(); ++it) {
if (GetBucketIdx(*it) != GetBucketIdx(*prev(it)))
new_hash_table[GetBucketIdx(*it)] = it;
}
}
UnorderedMap(UnorderedMap&&) = default;
UnorderedMap& operator=(const UnorderedMap& another) {
this->all_pairs = another.all_pairs;
this->hash_table_ = another.hash_table_;
this->hash_ = another.hash_;
this->equal_ = another.equal_;
this->max_load_factor_ = another.max_load_factor_;
return *this;
}
UnorderedMap& operator=(UnorderedMap&&) = default;
size_t size() const {
return new_all_pairs.size();
}
Value& at(const Key& key) {
auto it = find(key);
if (it == end()) {
throw std::out_of_range("uhaha");
} else {
return it->second;
}
}
Value& operator[](const Key& key) {
return insert(std::make_pair(key, Value())).first->second;
}
template<class... Args>
std::pair<iterator, bool> emplace(Args&&... args) {
if (new_hash_table.size() < new_all_pairs.size())
rehash(new_hash_table.size() * 1.8);
new_all_pairs.emplace_back(std::forward<Args>(args)..., hash_);
auto& node = *std::prev(new_all_pairs.end());
auto& key = node.pair.first;
size_t hash = GetBucketIdx(node);
if (new_hash_table[hash] != new_all_pairs.end()) {
auto i = new_hash_table[hash];
while (i != prev(new_all_pairs.end()) && GetBucketIdx(*i) == hash) {
if (equal_(i->pair.first, key)) break;
++i;
}
if (i != std::prev(new_all_pairs.end()) && equal_(i->pair.first, key)) {
new_all_pairs.pop_back();
return {i, false};
} else {
auto it = std::prev(new_all_pairs.end());
new_all_pairs.relink(std::prev(i), it);
return {it, true};
}
} else {
new_hash_table[hash] = prev(new_all_pairs.end());
return {new_hash_table[hash], true};
}
}
std::pair<iterator, bool> insert(const std::pair<Key, Value>& tmp) {
return emplace(tmp);
}
std::pair<iterator, bool> insert(std::pair<Key, Value>&& tmp) {
return emplace(std::move(tmp));
}
template<class InputIterator>
void insert(InputIterator begin, InputIterator end) {
for (; begin != end; ++begin) {
insert(*begin);
}
}
iterator erase(const Key& key) {
return erase(find(key));
}
iterator erase(iterator it1) {
auto it = it1.it;
size_t hash = GetBucketIdx(*it);
if (new_hash_table[hash] != it) {
auto i = std::next(it);
new_all_pairs.erase(it);
return i;
} else {
if (GetBucketIdx(*std::next(it)) == hash) {
auto i = std::next(it);
new_all_pairs.erase(it);
new_hash_table[hash] = i;
return i;
} else {
auto i = std::next(it);
new_all_pairs.erase(it);
new_hash_table[hash] = new_all_pairs.end();
return i;
}
}
}
iterator erase(iterator begin, iterator end) {
for (; begin != end;) {
begin = erase(begin);
}
return end;
}
const_iterator erase(const_iterator begin, const_iterator end) {
for (; begin != end; ++begin) {
erase(begin);
}
return end;
}
iterator find(const Key& key) {
size_t hash = GetBucketIdx(key);
if (new_hash_table[hash] != new_all_pairs.end()) {
auto i = new_hash_table[hash];
while (i != new_all_pairs.end() && GetBucketIdx(*i) == hash) {
if (equal_(i->pair.first, key)) break;
++i;
}
if (i != new_all_pairs.end() && equal_(i->pair.first, key)) {
return i;
} else {
return end();
}
} else {
return end();
}
}
const_iterator find(const Key& key) const {
return const_cast<UnorderedMap&>(*this).find(key);
}
void rehash(size_t count) {
if (count <= new_hash_table.size())
return;
std::vector<new_iterator> v(count, new_all_pairs.end());
for (auto it = begin_(); it != end_(); ++it) {
auto& i = *it;
size_t hash = hash_(i.pair.first);
if (v[hash % v.size()] != new_all_pairs.end()) {
new_all_pairs.relink(v[hash % v.size()], it);
} else {
v[hash % v.size()] = it;
}
}
std::swap(new_hash_table, v);
}
void reserve(size_t count) {
rehash(count);
}
float load_factor() const {
return static_cast<float>(size()) / new_hash_table.size();
}
float max_load_factor() const {
return max_load_factor_;
}
void max_load_factor(float ml) {
max_load_factor_ = ml;
}
iterator begin() { return new_all_pairs.begin(); }
iterator end() { return new_all_pairs.end(); }
new_iterator begin_() { return new_all_pairs.begin(); }
new_iterator end_() { return new_all_pairs.end(); }
const_iterator begin() const { return const_iterator(const_cast<NewList&>(new_all_pairs).begin()); }
const_iterator end() const { return const_iterator(const_cast<NewList&>(new_all_pairs).end()); }
const_iterator cbegin() const { return const_iterator(const_cast<NewList&>(new_all_pairs).begin()); }
const_iterator cend() const { return const_iterator(const_cast<NewList&>(new_all_pairs).end()); }
reverse_iterator rbegin() { return reverse_iterator(end()); }
reverse_iterator rend() { return reverse_iterator(begin()); }
const_reverse_iterator rbegin() const { return const_reverse_iterator(cend()); }
const_reverse_iterator rend() const { return const_reverse_iterator(cbegin()); }
const_reverse_iterator crbegin() const { return const_reverse_iterator(cend()); }
const_reverse_iterator crend() const { return const_reverse_iterator(cbegin()); }
private:
Hash hash_;
Equal equal_;
float max_load_factor_;
};