From d214c2a8e66686175b5b437cb8b4a3780f39d269 Mon Sep 17 00:00:00 2001 From: Oleg Shatov <8730199@gmail.com> Date: Mon, 10 Feb 2020 19:43:44 +0300 Subject: [PATCH 1/5] Hashmap written! --- hashmap.h | 307 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 307 insertions(+) create mode 100644 hashmap.h diff --git a/hashmap.h b/hashmap.h new file mode 100644 index 0000000..556b88a --- /dev/null +++ b/hashmap.h @@ -0,0 +1,307 @@ +#include +#include +#include +#include + +template> +class HashMap { +private: + static const size_t sizes[]; + + size_t cur_size = 0, cur_len = 0; + std::vector>> buckets; + Hash hasher; + + void change_size(size_t new_sz) { + if (new_sz == cur_len) { + return; + } + new_sz = sizes[cur_len = new_sz]; + std::vector>> new_buckets(new_sz); + for (auto &b : buckets) { + for (auto &x : b) { + new_buckets[hasher(x.first) % new_sz].push_front(std::move(x)); + } + } + buckets.swap(new_buckets); + } + + size_t load_factor() const { + return cur_size * 100 / sizes[cur_len]; + } + + bool trySizeUp() { + if (load_factor() > 130) { + change_size(cur_len + 1); + return true; + } + return false; + } + + bool trySizeDown() { + if (load_factor() < 30 && cur_len) { + change_size(cur_len - 1); + return true; + } + return false; + } + +public: + HashMap(const Hash &Hasher = Hash()) : buckets(sizes[0]), hasher(Hasher) {} + + template + HashMap(Iter beg, Iter end, const Hash &Hasher = Hash()) : HashMap(Hasher) { + for (Iter it = beg; it != end; ++it) { + insert(*it); + } + } + + HashMap(const std::initializer_list> &l, const Hash &Hasher = Hash()) : HashMap(l.begin(), l.end(), Hasher) {} + + HashMap(const std::vector> &vals, const Hash &Hasher = Hash()) : HashMap(vals.begin(), vals.end(), Hasher) {} + + size_t size() const { + return cur_size; + } + + bool empty() const { + return cur_size == 0; + } + + const Hash& hash_function() const { + return hasher; + } + + size_t count(const KeyType &key) const { + size_t h = hasher(key) % buckets.size(); + for (auto &[x, y] : buckets[h]) { + if (x == key) { + return 1; + } + } + return 0; + } + + void insert(const std::pair &val) { + if (count(val.first)) + return; + buckets[hasher(val.first) % buckets.size()].push_front(val); + ++cur_size; + trySizeUp(); + } + + void erase(const KeyType &key) { + size_t h = hasher(key) % buckets.size(); + for (auto it = buckets[h].before_begin(); next(it) != buckets[h].end(); ++it) { + if (next(it)->first == key) { + buckets[h].erase_after(it); + --cur_size; + break; + } + } + trySizeDown(); + } + + ValueType& operator[](const KeyType &key) { + size_t h = hasher(key) % sizes[cur_len]; + for (auto &[x, y] : buckets[h]) { + if (x == key) { + return y; + } + } + buckets[h].push_front({key, ValueType()}); + ++cur_size; + if (trySizeUp()) { + return this->operator[](key); + } + return buckets[h].front().second; + } + + const ValueType& at(const KeyType &key) const { + size_t h = hasher(key) % buckets.size(); + for (auto &[x, y] : buckets[h]) { + if (x == key) { + return y; + } + } + throw std::out_of_range("No such key"); + } + + void clear() { + for (auto &b : buckets) { + b.clear(); + } + cur_size = 0; + change_size(0); + } + + class const_iterator { + friend HashMap; + private: + typename std::vector>>::const_iterator cur, end; + typename std::forward_list>::const_iterator biter; + + void push() { + while (cur != end && biter == cur->end()) { + ++cur; + if (cur != end) { + biter = cur->begin(); + } + } + } + + public: + const_iterator() {} + const_iterator(const HashMap &mp) : cur(mp.buckets.begin()), end(mp.buckets.end()), biter(cur->begin()) {} + const_iterator(const const_iterator &it) : cur(it.cur), end(it.end), biter(it.biter) {} + + const_iterator& operator++() { + ++biter; + push(); + return *this; + } + + const_iterator operator++(int) { + const_iterator cp(*this); + ++(*this); + return cp; + } + + const_iterator& operator=(const const_iterator &iter) { + cur = iter.cur; + end = iter.end; + biter = iter.biter; + return *this; + } + + const std::pair& operator*() { + return *biter; + } + + typename std::forward_list>::const_iterator operator->() { + return biter; + } + + bool operator==(const const_iterator &it) { + return it.cur == cur && it.biter == biter; + } + + bool operator!=(const const_iterator &it) { + return !(*this == it); + } + }; + + class iterator { + friend HashMap; + private: + typename std::vector>>::iterator cur, end; + typename std::forward_list>::iterator biter; + + void push() { + while (cur != end && biter == cur->end()) { + ++cur; + if (cur != end) { + biter = cur->begin(); + } + } + } + + public: + iterator() {} + iterator(HashMap &mp) : cur(mp.buckets.begin()), end(mp.buckets.end()), biter(cur->begin()) {} + iterator(const iterator &it) : cur(it.cur), end(it.end), biter(it.biter) {} + + iterator& operator++() { + ++biter; + push(); + return *this; + } + + iterator operator++(int) { + iterator cp(*this); + ++(*this); + return cp; + } + + iterator& operator=(const iterator &iter) { + cur = iter.cur; + end = iter.end; + biter = iter.biter; + return *this; + } + + const std::pair& operator*() { + return *biter; + } + + typename std::forward_list>::iterator operator->() { + return biter; + } + + bool operator==(const iterator &it) { + return it.cur == cur && it.biter == biter; + } + + bool operator!=(const iterator &it) { + return !(*this == it); + } + }; + + const_iterator find(const KeyType &val) const { + size_t h = hasher(val) % buckets.size(); + for (auto it = buckets[h].begin(); it != buckets[h].end(); ++it) { + if (it->first == val) { + const_iterator iter(*this); + iter.cur = buckets.begin() + h; + iter.biter = it; + return iter; + } + } + return end(); + } + + iterator find(const KeyType &val) { + size_t h = hasher(val) % buckets.size(); + for (auto it = buckets[h].begin(); it != buckets[h].end(); ++it) { + if (it->first == val) { + iterator iter(*this); + iter.cur = buckets.begin() + h; + iter.biter = it; + return iter; + } + } + return end(); + } + + iterator begin() { + iterator iter(*this); + iter.push(); + return iter; + } + + iterator end() { + iterator iter(*this); + iter.cur = iter.end; + iter.biter = buckets.back().end(); + return iter; + } + + const_iterator begin() const { + const_iterator iter(*this); + iter.push(); + return iter; + } + + const_iterator end() const { + const_iterator iter(*this); + iter.cur = iter.end; + iter.biter = buckets.back().end(); + return iter; + } +}; + +template +const size_t HashMap::sizes[] = { + 5, 11, 23, 47, 97, 197, 397, 797, 1597, 3203, 6421, + 12853, 25717, 51437, 102877, 205759, 411527, 823117, + 1646237, 3292489, 6584983, 13169977, 26339969, 52679969}; From 88e2c663fe4a9d791fed69515a93e2b716d0feed Mon Sep 17 00:00:00 2001 From: Oleg Shatov <8730199@gmail.com> Date: Mon, 10 Feb 2020 19:47:46 +0300 Subject: [PATCH 2/5] Minor changes --- hashmap.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hashmap.h b/hashmap.h index 556b88a..65daf39 100644 --- a/hashmap.h +++ b/hashmap.h @@ -112,7 +112,7 @@ class HashMap { buckets[h].push_front({key, ValueType()}); ++cur_size; if (trySizeUp()) { - return this->operator[](key); + return operator[](key); } return buckets[h].front().second; } From f4796f1ba97147c002c74481c453553dcfd23647 Mon Sep 17 00:00:00 2001 From: Oleg Shatov <35371391+domwst@users.noreply.github.com> Date: Wed, 1 Apr 2020 01:11:48 +0300 Subject: [PATCH 3/5] Enchanced iterators and minor changes --- hash_map.h | 286 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 286 insertions(+) create mode 100644 hash_map.h diff --git a/hash_map.h b/hash_map.h new file mode 100644 index 0000000..ac032b5 --- /dev/null +++ b/hash_map.h @@ -0,0 +1,286 @@ +#include +#include +#include +#include +#include +#include + +template +class base_hashmap_iterator { +private: + vector_iter cur, end; + list_iter biter; + + void push() { + while (cur != end && biter == cur->end()) { + ++cur; + if (cur != end) { + biter = cur->begin(); + } + } + } + +public: + base_hashmap_iterator() = default; + base_hashmap_iterator(const base_hashmap_iterator &it) = default; + + base_hashmap_iterator(const vector_iter &_cur, const list_iter &_biter, const vector_iter &_end) : + cur(_cur), end(_end), biter(_biter) {} + + template + base_hashmap_iterator(std::vector &buckets, bool back = false) : + cur(buckets.begin()), end(buckets.end()), biter(cur->begin()) { + + if (!back) { + push(); + } else { + cur = end = buckets.end(); + biter = buckets.back().end(); + } + } + + template + base_hashmap_iterator(const std::vector &buckets, bool back = false) : + cur(buckets.begin()), end(buckets.end()), biter(cur->begin()) { + + if (!back) { + push(); + } else { + cur = end = buckets.end(); + biter = buckets.back().end(); + } + } + + void bucket_advance(size_t l) { + cur += l; + } + + base_hashmap_iterator& operator++() { + ++biter; + push(); + return *this; + } + + base_hashmap_iterator operator++(int) { + base_hashmap_iterator cp(*this); + ++(*this); + return cp; + } + + base_hashmap_iterator& operator=(const base_hashmap_iterator &iter) { + cur = iter.cur; + end = iter.end; + biter = iter.biter; + return *this; + } + + typename list_iter::value_type operator*() { + return *biter; + } + + list_iter operator->() { + return biter; + } + + bool operator==(const base_hashmap_iterator &it) { + return it.cur == cur && it.biter == biter; + } + + bool operator!=(const base_hashmap_iterator &it) { + return !(*this == it); + } +}; + +template> +class HashMap { +private: + static constexpr size_t sizes[] = { + 5, 11, 23, 47, 97, 197, 397, 797, 1597, 3203, 6421, + 12853, 25717, 51437, 102877, 205759, 411527, 823117, + 1646237, 3292489, 6584983, 13169977, 26339969, 52679969}; + static constexpr size_t growLoadFactorThreshold = 130, shrintLoadFactorThreshold = 30; + + using stored_type = std::pair; + using list_type = std::forward_list; + using vector_type = std::vector; + + size_t cur_size = 0, cur_capacity = 0; + vector_type buckets; + Hash hasher; + + void change_size(size_t new_capacity) { + if (new_capacity == cur_capacity) { + return; + } + cur_capacity = new_capacity; + new_capacity = sizes[cur_capacity]; + vector_type new_buckets(new_capacity); + for (auto &b : buckets) { + for (auto &x : b) { + new_buckets[hasher(x.first) % new_capacity].push_front(std::move(x)); + } + } + buckets.swap(new_buckets); + } + + size_t load_factor() const { // returns cur_size / cur_capacity in percents. i.e. returns load factor in percents + return cur_size * 100 / sizes[cur_capacity]; + } + + bool trySizeUp() { + if (load_factor() > growLoadFactorThreshold) { + change_size(cur_capacity + 1); + return true; + } + return false; + } + + bool trySizeDown() { + if (load_factor() < shrintLoadFactorThreshold && cur_capacity > 0) { + change_size(cur_capacity - 1); + return true; + } + return false; + } + + std::pair base_find(const KeyType &val) const { + size_t h = hasher(val) % buckets.size(); + for (auto it = buckets[h].begin(), cur = 0ull; it != buckets[h].end(); ++it, ++cur) { + if (it->first == val) { + return std::make_pair(h, (size_t)cur); + } + } + return std::make_pair(buckets.size(), std::distance(buckets.back().begin(), buckets.back().end())); + } + +public: + explicit HashMap(const Hash &Hasher = Hash()) : buckets(sizes[0]), hasher(Hasher) {} + + template + HashMap(Iter beg, Iter end, const Hash &Hasher = Hash()) : HashMap(Hasher) { + for (Iter it = beg; it != end; ++it) { + insert(*it); + } + } + + HashMap(const std::initializer_list &l, const Hash &Hasher = Hash()) : + HashMap(l.begin(), l.end(), Hasher) {} + + HashMap(const std::vector &vals, const Hash &Hasher = Hash()) : + HashMap(vals.begin(), vals.end(), Hasher) {} + + using iterator = base_hashmap_iterator; + using const_iterator = base_hashmap_iterator; + + size_t size() const { + return cur_size; + } + + bool empty() const { + return cur_size == 0; + } + + const Hash& hash_function() const { + return hasher; + } + + size_t count(const KeyType &key) const { + size_t h = hasher(key) % buckets.size(); + for (auto &[x, y] : buckets[h]) { + if (x == key) { + return 1; + } + } + return 0; + } + + void insert(const stored_type &val) { + if (count(val.first)) + return; + buckets[hasher(val.first) % buckets.size()].push_front(val); + ++cur_size; + trySizeUp(); + } + + void erase(const KeyType &key) { + size_t h = hasher(key) % buckets.size(); + for (auto it = buckets[h].before_begin(); next(it) != buckets[h].end(); ++it) { + if (next(it)->first == key) { + buckets[h].erase_after(it); + --cur_size; + break; + } + } + trySizeDown(); + } + + ValueType& operator[](const KeyType &key) { + size_t h = hasher(key) % sizes[cur_capacity]; + for (auto &[x, y] : buckets[h]) { + if (x == key) { + return y; + } + } + buckets[h].emplace_front(key, ValueType()); + ++cur_size; + if (trySizeUp()) { + return operator[](key); + } + return buckets[h].front().second; + } + + const ValueType& at(const KeyType &key) const { + size_t h = hasher(key) % buckets.size(); + for (auto &[x, y] : buckets[h]) { + if (x == key) { + return y; + } + } + throw std::out_of_range("No such key"); + } + + void clear() { + for (auto &bucket : buckets) { + bucket.clear(); + } + cur_size = 0; + change_size(0); + } + + const_iterator find(const KeyType &val) const { + auto [block_idx, item_idx] = base_find(val); + auto item_iterator = buckets[std::min(block_idx, buckets.size() - 1)].begin(); // For case of end iterator + std::advance(item_iterator, item_idx); + return const_iterator(buckets.begin() + block_idx, + item_iterator, buckets.end()); + } + + iterator find(const KeyType &val) { + auto [block_idx, item_idx] = base_find(val); + auto item_iterator = buckets[std::min(block_idx, buckets.size() - 1)].begin(); + std::advance(item_iterator, item_idx); + return iterator(buckets.begin() + block_idx, + item_iterator, buckets.end()); + } + + iterator begin() { + iterator iter(buckets); + return iter; + } + + iterator end() { + iterator iter(buckets, true); + return iter; + } + + const_iterator begin() const { + const_iterator iter(buckets); + return iter; + } + + const_iterator end() const { + const_iterator iter(buckets, true); + return iter; + } +}; From 58434cd6b57ae85e1601827aedbc50a621b7e2c5 Mon Sep 17 00:00:00 2001 From: Oleg Shatov <35371391+domwst@users.noreply.github.com> Date: Wed, 1 Apr 2020 01:13:43 +0300 Subject: [PATCH 4/5] Enchanced iterators and minor changes --- hashmap.h | 319 +++++++++++++++++++++++++----------------------------- 1 file changed, 149 insertions(+), 170 deletions(-) diff --git a/hashmap.h b/hashmap.h index 65daf39..ac032b5 100644 --- a/hashmap.h +++ b/hashmap.h @@ -2,52 +2,159 @@ #include #include #include +#include +#include + +template +class base_hashmap_iterator { +private: + vector_iter cur, end; + list_iter biter; + + void push() { + while (cur != end && biter == cur->end()) { + ++cur; + if (cur != end) { + biter = cur->begin(); + } + } + } + +public: + base_hashmap_iterator() = default; + base_hashmap_iterator(const base_hashmap_iterator &it) = default; + + base_hashmap_iterator(const vector_iter &_cur, const list_iter &_biter, const vector_iter &_end) : + cur(_cur), end(_end), biter(_biter) {} + + template + base_hashmap_iterator(std::vector &buckets, bool back = false) : + cur(buckets.begin()), end(buckets.end()), biter(cur->begin()) { + + if (!back) { + push(); + } else { + cur = end = buckets.end(); + biter = buckets.back().end(); + } + } + + template + base_hashmap_iterator(const std::vector &buckets, bool back = false) : + cur(buckets.begin()), end(buckets.end()), biter(cur->begin()) { + + if (!back) { + push(); + } else { + cur = end = buckets.end(); + biter = buckets.back().end(); + } + } + + void bucket_advance(size_t l) { + cur += l; + } + + base_hashmap_iterator& operator++() { + ++biter; + push(); + return *this; + } + + base_hashmap_iterator operator++(int) { + base_hashmap_iterator cp(*this); + ++(*this); + return cp; + } + + base_hashmap_iterator& operator=(const base_hashmap_iterator &iter) { + cur = iter.cur; + end = iter.end; + biter = iter.biter; + return *this; + } + + typename list_iter::value_type operator*() { + return *biter; + } + + list_iter operator->() { + return biter; + } + + bool operator==(const base_hashmap_iterator &it) { + return it.cur == cur && it.biter == biter; + } + + bool operator!=(const base_hashmap_iterator &it) { + return !(*this == it); + } +}; template> class HashMap { private: - static const size_t sizes[]; + static constexpr size_t sizes[] = { + 5, 11, 23, 47, 97, 197, 397, 797, 1597, 3203, 6421, + 12853, 25717, 51437, 102877, 205759, 411527, 823117, + 1646237, 3292489, 6584983, 13169977, 26339969, 52679969}; + static constexpr size_t growLoadFactorThreshold = 130, shrintLoadFactorThreshold = 30; - size_t cur_size = 0, cur_len = 0; - std::vector>> buckets; + using stored_type = std::pair; + using list_type = std::forward_list; + using vector_type = std::vector; + + size_t cur_size = 0, cur_capacity = 0; + vector_type buckets; Hash hasher; - void change_size(size_t new_sz) { - if (new_sz == cur_len) { + void change_size(size_t new_capacity) { + if (new_capacity == cur_capacity) { return; } - new_sz = sizes[cur_len = new_sz]; - std::vector>> new_buckets(new_sz); + cur_capacity = new_capacity; + new_capacity = sizes[cur_capacity]; + vector_type new_buckets(new_capacity); for (auto &b : buckets) { for (auto &x : b) { - new_buckets[hasher(x.first) % new_sz].push_front(std::move(x)); + new_buckets[hasher(x.first) % new_capacity].push_front(std::move(x)); } } buckets.swap(new_buckets); } - size_t load_factor() const { - return cur_size * 100 / sizes[cur_len]; + size_t load_factor() const { // returns cur_size / cur_capacity in percents. i.e. returns load factor in percents + return cur_size * 100 / sizes[cur_capacity]; } bool trySizeUp() { - if (load_factor() > 130) { - change_size(cur_len + 1); + if (load_factor() > growLoadFactorThreshold) { + change_size(cur_capacity + 1); return true; } return false; } bool trySizeDown() { - if (load_factor() < 30 && cur_len) { - change_size(cur_len - 1); + if (load_factor() < shrintLoadFactorThreshold && cur_capacity > 0) { + change_size(cur_capacity - 1); return true; } return false; } + std::pair base_find(const KeyType &val) const { + size_t h = hasher(val) % buckets.size(); + for (auto it = buckets[h].begin(), cur = 0ull; it != buckets[h].end(); ++it, ++cur) { + if (it->first == val) { + return std::make_pair(h, (size_t)cur); + } + } + return std::make_pair(buckets.size(), std::distance(buckets.back().begin(), buckets.back().end())); + } + public: - HashMap(const Hash &Hasher = Hash()) : buckets(sizes[0]), hasher(Hasher) {} + explicit HashMap(const Hash &Hasher = Hash()) : buckets(sizes[0]), hasher(Hasher) {} template HashMap(Iter beg, Iter end, const Hash &Hasher = Hash()) : HashMap(Hasher) { @@ -56,9 +163,15 @@ class HashMap { } } - HashMap(const std::initializer_list> &l, const Hash &Hasher = Hash()) : HashMap(l.begin(), l.end(), Hasher) {} + HashMap(const std::initializer_list &l, const Hash &Hasher = Hash()) : + HashMap(l.begin(), l.end(), Hasher) {} + + HashMap(const std::vector &vals, const Hash &Hasher = Hash()) : + HashMap(vals.begin(), vals.end(), Hasher) {} - HashMap(const std::vector> &vals, const Hash &Hasher = Hash()) : HashMap(vals.begin(), vals.end(), Hasher) {} + using iterator = base_hashmap_iterator; + using const_iterator = base_hashmap_iterator; size_t size() const { return cur_size; @@ -82,7 +195,7 @@ class HashMap { return 0; } - void insert(const std::pair &val) { + void insert(const stored_type &val) { if (count(val.first)) return; buckets[hasher(val.first) % buckets.size()].push_front(val); @@ -103,13 +216,13 @@ class HashMap { } ValueType& operator[](const KeyType &key) { - size_t h = hasher(key) % sizes[cur_len]; + size_t h = hasher(key) % sizes[cur_capacity]; for (auto &[x, y] : buckets[h]) { if (x == key) { return y; } } - buckets[h].push_front({key, ValueType()}); + buckets[h].emplace_front(key, ValueType()); ++cur_size; if (trySizeUp()) { return operator[](key); @@ -128,180 +241,46 @@ class HashMap { } void clear() { - for (auto &b : buckets) { - b.clear(); + for (auto &bucket : buckets) { + bucket.clear(); } cur_size = 0; change_size(0); } - class const_iterator { - friend HashMap; - private: - typename std::vector>>::const_iterator cur, end; - typename std::forward_list>::const_iterator biter; - - void push() { - while (cur != end && biter == cur->end()) { - ++cur; - if (cur != end) { - biter = cur->begin(); - } - } - } - - public: - const_iterator() {} - const_iterator(const HashMap &mp) : cur(mp.buckets.begin()), end(mp.buckets.end()), biter(cur->begin()) {} - const_iterator(const const_iterator &it) : cur(it.cur), end(it.end), biter(it.biter) {} - - const_iterator& operator++() { - ++biter; - push(); - return *this; - } - - const_iterator operator++(int) { - const_iterator cp(*this); - ++(*this); - return cp; - } - - const_iterator& operator=(const const_iterator &iter) { - cur = iter.cur; - end = iter.end; - biter = iter.biter; - return *this; - } - - const std::pair& operator*() { - return *biter; - } - - typename std::forward_list>::const_iterator operator->() { - return biter; - } - - bool operator==(const const_iterator &it) { - return it.cur == cur && it.biter == biter; - } - - bool operator!=(const const_iterator &it) { - return !(*this == it); - } - }; - - class iterator { - friend HashMap; - private: - typename std::vector>>::iterator cur, end; - typename std::forward_list>::iterator biter; - - void push() { - while (cur != end && biter == cur->end()) { - ++cur; - if (cur != end) { - biter = cur->begin(); - } - } - } - - public: - iterator() {} - iterator(HashMap &mp) : cur(mp.buckets.begin()), end(mp.buckets.end()), biter(cur->begin()) {} - iterator(const iterator &it) : cur(it.cur), end(it.end), biter(it.biter) {} - - iterator& operator++() { - ++biter; - push(); - return *this; - } - - iterator operator++(int) { - iterator cp(*this); - ++(*this); - return cp; - } - - iterator& operator=(const iterator &iter) { - cur = iter.cur; - end = iter.end; - biter = iter.biter; - return *this; - } - - const std::pair& operator*() { - return *biter; - } - - typename std::forward_list>::iterator operator->() { - return biter; - } - - bool operator==(const iterator &it) { - return it.cur == cur && it.biter == biter; - } - - bool operator!=(const iterator &it) { - return !(*this == it); - } - }; - const_iterator find(const KeyType &val) const { - size_t h = hasher(val) % buckets.size(); - for (auto it = buckets[h].begin(); it != buckets[h].end(); ++it) { - if (it->first == val) { - const_iterator iter(*this); - iter.cur = buckets.begin() + h; - iter.biter = it; - return iter; - } - } - return end(); + auto [block_idx, item_idx] = base_find(val); + auto item_iterator = buckets[std::min(block_idx, buckets.size() - 1)].begin(); // For case of end iterator + std::advance(item_iterator, item_idx); + return const_iterator(buckets.begin() + block_idx, + item_iterator, buckets.end()); } iterator find(const KeyType &val) { - size_t h = hasher(val) % buckets.size(); - for (auto it = buckets[h].begin(); it != buckets[h].end(); ++it) { - if (it->first == val) { - iterator iter(*this); - iter.cur = buckets.begin() + h; - iter.biter = it; - return iter; - } - } - return end(); + auto [block_idx, item_idx] = base_find(val); + auto item_iterator = buckets[std::min(block_idx, buckets.size() - 1)].begin(); + std::advance(item_iterator, item_idx); + return iterator(buckets.begin() + block_idx, + item_iterator, buckets.end()); } iterator begin() { - iterator iter(*this); - iter.push(); + iterator iter(buckets); return iter; } iterator end() { - iterator iter(*this); - iter.cur = iter.end; - iter.biter = buckets.back().end(); + iterator iter(buckets, true); return iter; } const_iterator begin() const { - const_iterator iter(*this); - iter.push(); + const_iterator iter(buckets); return iter; } const_iterator end() const { - const_iterator iter(*this); - iter.cur = iter.end; - iter.biter = buckets.back().end(); + const_iterator iter(buckets, true); return iter; } }; - -template -const size_t HashMap::sizes[] = { - 5, 11, 23, 47, 97, 197, 397, 797, 1597, 3203, 6421, - 12853, 25717, 51437, 102877, 205759, 411527, 823117, - 1646237, 3292489, 6584983, 13169977, 26339969, 52679969}; From 8216adbeb819ea7ce736cd42a138172cda7a9e97 Mon Sep 17 00:00:00 2001 From: Oleg Shatov <35371391+domwst@users.noreply.github.com> Date: Wed, 1 Apr 2020 01:15:28 +0300 Subject: [PATCH 5/5] Fixed mistakes of past --- hash_map.h | 286 ----------------------------------------------------- 1 file changed, 286 deletions(-) delete mode 100644 hash_map.h diff --git a/hash_map.h b/hash_map.h deleted file mode 100644 index ac032b5..0000000 --- a/hash_map.h +++ /dev/null @@ -1,286 +0,0 @@ -#include -#include -#include -#include -#include -#include - -template -class base_hashmap_iterator { -private: - vector_iter cur, end; - list_iter biter; - - void push() { - while (cur != end && biter == cur->end()) { - ++cur; - if (cur != end) { - biter = cur->begin(); - } - } - } - -public: - base_hashmap_iterator() = default; - base_hashmap_iterator(const base_hashmap_iterator &it) = default; - - base_hashmap_iterator(const vector_iter &_cur, const list_iter &_biter, const vector_iter &_end) : - cur(_cur), end(_end), biter(_biter) {} - - template - base_hashmap_iterator(std::vector &buckets, bool back = false) : - cur(buckets.begin()), end(buckets.end()), biter(cur->begin()) { - - if (!back) { - push(); - } else { - cur = end = buckets.end(); - biter = buckets.back().end(); - } - } - - template - base_hashmap_iterator(const std::vector &buckets, bool back = false) : - cur(buckets.begin()), end(buckets.end()), biter(cur->begin()) { - - if (!back) { - push(); - } else { - cur = end = buckets.end(); - biter = buckets.back().end(); - } - } - - void bucket_advance(size_t l) { - cur += l; - } - - base_hashmap_iterator& operator++() { - ++biter; - push(); - return *this; - } - - base_hashmap_iterator operator++(int) { - base_hashmap_iterator cp(*this); - ++(*this); - return cp; - } - - base_hashmap_iterator& operator=(const base_hashmap_iterator &iter) { - cur = iter.cur; - end = iter.end; - biter = iter.biter; - return *this; - } - - typename list_iter::value_type operator*() { - return *biter; - } - - list_iter operator->() { - return biter; - } - - bool operator==(const base_hashmap_iterator &it) { - return it.cur == cur && it.biter == biter; - } - - bool operator!=(const base_hashmap_iterator &it) { - return !(*this == it); - } -}; - -template> -class HashMap { -private: - static constexpr size_t sizes[] = { - 5, 11, 23, 47, 97, 197, 397, 797, 1597, 3203, 6421, - 12853, 25717, 51437, 102877, 205759, 411527, 823117, - 1646237, 3292489, 6584983, 13169977, 26339969, 52679969}; - static constexpr size_t growLoadFactorThreshold = 130, shrintLoadFactorThreshold = 30; - - using stored_type = std::pair; - using list_type = std::forward_list; - using vector_type = std::vector; - - size_t cur_size = 0, cur_capacity = 0; - vector_type buckets; - Hash hasher; - - void change_size(size_t new_capacity) { - if (new_capacity == cur_capacity) { - return; - } - cur_capacity = new_capacity; - new_capacity = sizes[cur_capacity]; - vector_type new_buckets(new_capacity); - for (auto &b : buckets) { - for (auto &x : b) { - new_buckets[hasher(x.first) % new_capacity].push_front(std::move(x)); - } - } - buckets.swap(new_buckets); - } - - size_t load_factor() const { // returns cur_size / cur_capacity in percents. i.e. returns load factor in percents - return cur_size * 100 / sizes[cur_capacity]; - } - - bool trySizeUp() { - if (load_factor() > growLoadFactorThreshold) { - change_size(cur_capacity + 1); - return true; - } - return false; - } - - bool trySizeDown() { - if (load_factor() < shrintLoadFactorThreshold && cur_capacity > 0) { - change_size(cur_capacity - 1); - return true; - } - return false; - } - - std::pair base_find(const KeyType &val) const { - size_t h = hasher(val) % buckets.size(); - for (auto it = buckets[h].begin(), cur = 0ull; it != buckets[h].end(); ++it, ++cur) { - if (it->first == val) { - return std::make_pair(h, (size_t)cur); - } - } - return std::make_pair(buckets.size(), std::distance(buckets.back().begin(), buckets.back().end())); - } - -public: - explicit HashMap(const Hash &Hasher = Hash()) : buckets(sizes[0]), hasher(Hasher) {} - - template - HashMap(Iter beg, Iter end, const Hash &Hasher = Hash()) : HashMap(Hasher) { - for (Iter it = beg; it != end; ++it) { - insert(*it); - } - } - - HashMap(const std::initializer_list &l, const Hash &Hasher = Hash()) : - HashMap(l.begin(), l.end(), Hasher) {} - - HashMap(const std::vector &vals, const Hash &Hasher = Hash()) : - HashMap(vals.begin(), vals.end(), Hasher) {} - - using iterator = base_hashmap_iterator; - using const_iterator = base_hashmap_iterator; - - size_t size() const { - return cur_size; - } - - bool empty() const { - return cur_size == 0; - } - - const Hash& hash_function() const { - return hasher; - } - - size_t count(const KeyType &key) const { - size_t h = hasher(key) % buckets.size(); - for (auto &[x, y] : buckets[h]) { - if (x == key) { - return 1; - } - } - return 0; - } - - void insert(const stored_type &val) { - if (count(val.first)) - return; - buckets[hasher(val.first) % buckets.size()].push_front(val); - ++cur_size; - trySizeUp(); - } - - void erase(const KeyType &key) { - size_t h = hasher(key) % buckets.size(); - for (auto it = buckets[h].before_begin(); next(it) != buckets[h].end(); ++it) { - if (next(it)->first == key) { - buckets[h].erase_after(it); - --cur_size; - break; - } - } - trySizeDown(); - } - - ValueType& operator[](const KeyType &key) { - size_t h = hasher(key) % sizes[cur_capacity]; - for (auto &[x, y] : buckets[h]) { - if (x == key) { - return y; - } - } - buckets[h].emplace_front(key, ValueType()); - ++cur_size; - if (trySizeUp()) { - return operator[](key); - } - return buckets[h].front().second; - } - - const ValueType& at(const KeyType &key) const { - size_t h = hasher(key) % buckets.size(); - for (auto &[x, y] : buckets[h]) { - if (x == key) { - return y; - } - } - throw std::out_of_range("No such key"); - } - - void clear() { - for (auto &bucket : buckets) { - bucket.clear(); - } - cur_size = 0; - change_size(0); - } - - const_iterator find(const KeyType &val) const { - auto [block_idx, item_idx] = base_find(val); - auto item_iterator = buckets[std::min(block_idx, buckets.size() - 1)].begin(); // For case of end iterator - std::advance(item_iterator, item_idx); - return const_iterator(buckets.begin() + block_idx, - item_iterator, buckets.end()); - } - - iterator find(const KeyType &val) { - auto [block_idx, item_idx] = base_find(val); - auto item_iterator = buckets[std::min(block_idx, buckets.size() - 1)].begin(); - std::advance(item_iterator, item_idx); - return iterator(buckets.begin() + block_idx, - item_iterator, buckets.end()); - } - - iterator begin() { - iterator iter(buckets); - return iter; - } - - iterator end() { - iterator iter(buckets, true); - return iter; - } - - const_iterator begin() const { - const_iterator iter(buckets); - return iter; - } - - const_iterator end() const { - const_iterator iter(buckets, true); - return iter; - } -};