diff options
Diffstat (limited to 'kernel/hashmap.h')
-rw-r--r-- | kernel/hashmap.h | 230 |
1 files changed, 209 insertions, 21 deletions
diff --git a/kernel/hashmap.h b/kernel/hashmap.h index bd4fc4d22..d5f8c4e98 100644 --- a/kernel/hashmap.h +++ b/kernel/hashmap.h @@ -19,6 +19,7 @@ #ifndef YOSYS_HASHMAP_H +#include <stdexcept> #include <string> #include <vector> @@ -27,28 +28,28 @@ inline unsigned int mkhash(unsigned int a, unsigned int b) { } template<typename T> struct hash_ops { - bool cmp(const T &a, const T &b) { + bool cmp(const T &a, const T &b) const { return a == b; } - unsigned int hash(const T &a) { + unsigned int hash(const T &a) const { return a.hash(); } }; template<> struct hash_ops<int> { - bool cmp(int a, int b) { + bool cmp(int a, int b) const { return a == b; } - unsigned int hash(int a) { + unsigned int hash(int a) const { return a; } }; template<> struct hash_ops<std::string> { - bool cmp(const std::string &a, const std::string &b) { + bool cmp(const std::string &a, const std::string &b) const { return a == b; } - unsigned int hash(const std::string &a) { + unsigned int hash(const std::string &a) const { unsigned int v = 0; for (auto c : a) v = mkhash(v, c); @@ -56,14 +57,25 @@ template<> struct hash_ops<std::string> { } }; +struct hash_ptr_ops { + bool cmp(const void *a, const void *b) const { + return a == b; + } + unsigned int hash(const void *a) const { + return (unsigned long)a; + } +}; + template<typename K, typename T, typename OPS = hash_ops<K>> -class new_dict +class dict { struct entry_t { int link; std::pair<K, T> udata; + entry_t() : link(-1) { } + entry_t(const std::pair<K, T> &udata) : link(1), udata(udata) { } bool is_free() const { return link < 0; } int get_next() const { return (link > 0 ? link : -link) - 2; } @@ -79,17 +91,61 @@ class new_dict void init() { + free_list = -1; counter = 0; - entries.resize(61); + } + + void init_from(const dict<K, T, OPS> &other) + { + hashtable.clear(); + entries.clear(); + + counter = other.size(); + int new_size = grow_size(counter); + entries.reserve(new_size); + + for (auto &it : other) + entries.push_back(entry_t(it)); + entries.resize(new_size); rehash(); } - int mkhash(const K &key) + size_t grow_size(size_t old_size) { - return ops.hash(key) % int(hashtable.size()); + if (old_size < 53) return 53; + if (old_size < 113) return 113; + if (old_size < 251) return 251; + if (old_size < 503) return 503; + if (old_size < 1130) return 1130; + if (old_size < 2510) return 2510; + if (old_size < 5030) return 5030; + if (old_size < 11300) return 11300; + if (old_size < 25100) return 25100; + if (old_size < 50300) return 50300; + if (old_size < 113000) return 113000; + if (old_size < 251000) return 251000; + if (old_size < 503000) return 503000; + if (old_size < 1130000) return 1130000; + if (old_size < 2510000) return 2510000; + if (old_size < 5030000) return 5030000; + if (old_size < 11300000) return 11300000; + if (old_size < 25100000) return 25100000; + if (old_size < 50300000) return 50300000; + if (old_size < 113000000) return 113000000; + if (old_size < 251000000) return 251000000; + if (old_size < 503000000) return 503000000; + if (old_size < 1130000000) return 1130000000; + throw std::length_error("maximum size for dict reached"); + } + + int mkhash(const K &key) const + { + unsigned int hash = 0; + if (!hashtable.empty()) + hash = ops.hash(key) % (unsigned int)(hashtable.size()); + return hash; } -public: void rehash() { free_list = -1; @@ -112,7 +168,7 @@ public: void do_erase(const K &key, int hash) { int last_index = -1; - int index = hashtable[hash]; + int index = hashtable.empty() ? -1 : hashtable[hash]; while (1) { if (index < 0) return; @@ -124,7 +180,8 @@ public: entries[index].udata = std::pair<K, T>(); entries[index].set_next_free(free_list); free_list = index; - counter--; + if (--counter == 0) + init(); return; } last_index = index; @@ -132,9 +189,9 @@ public: } } - int lookup_index(const K &key, int hash) + int lookup_index(const K &key, int hash) const { - int index = hashtable[hash]; + int index = hashtable.empty() ? -1 : hashtable[hash]; while (1) { if (index < 0) return -1; @@ -149,7 +206,7 @@ public: if (free_list < 0) { int i = entries.size(); - entries.resize(2*entries.size()); + entries.resize(grow_size(i)); entries[i].udata = value; entries[i].set_next_used(0); counter++; @@ -169,24 +226,74 @@ public: public: class iterator { - new_dict<K, T, OPS> *ptr; + dict<K, T, OPS> *ptr; int index; public: - iterator(new_dict<K, T, OPS> *ptr, int index) : ptr(ptr), index(index) { } + iterator() { } + iterator(dict<K, T, OPS> *ptr, int index) : ptr(ptr), index(index) { } iterator operator++() { do index++; while (index != int(ptr->entries.size()) && ptr->entries[index].is_free()); return *this; } iterator operator--() { do index--; while (index != 0 && ptr->entries[index].is_free()); return *this; } bool operator==(const iterator &other) const { return index == other.index; } bool operator!=(const iterator &other) const { return index != other.index; } std::pair<K, T> &operator*() { return ptr->entries[index].udata; } + std::pair<K, T> *operator->() { return &ptr->entries[index].udata; } + const std::pair<K, T> &operator*() const { return ptr->entries[index].udata; } + const std::pair<K, T> *operator->() const { return &ptr->entries[index].udata; } }; - new_dict() + class const_iterator + { + const dict<K, T, OPS> *ptr; + int index; + public: + const_iterator() { } + const_iterator(const dict<K, T, OPS> *ptr, int index) : ptr(ptr), index(index) { } + const_iterator operator++() { do index++; while (index != int(ptr->entries.size()) && ptr->entries[index].is_free()); return *this; } + const_iterator operator--() { do index--; while (index != 0 && ptr->entries[index].is_free()); return *this; } + bool operator==(const const_iterator &other) const { return index == other.index; } + bool operator!=(const const_iterator &other) const { return index != other.index; } + const std::pair<K, T> &operator*() const { return ptr->entries[index].udata; } + const std::pair<K, T> *operator->() const { return &ptr->entries[index].udata; } + }; + + dict() { init(); } + dict(const dict<K, T, OPS> &other) + { + init_from(other); + } + + dict(dict<K, T, OPS> &&other) + { + free_list = -1; + counter = 0; + swap(other); + } + + dict<K, T, OPS> &operator=(const dict<K, T, OPS> &other) { + clear(); + init_from(other); + return *this; + } + + dict<K, T, OPS> &operator=(dict<K, T, OPS> &&other) { + clear(); + swap(other); + return *this; + } + + dict(const std::initializer_list<std::pair<K, T>> &list) + { + init(); + for (auto &it : list) + insert(it); + } + template<class InputIterator> - new_dict(InputIterator first, InputIterator last) + dict(InputIterator first, InputIterator last) { init(); insert(first, last); @@ -215,13 +322,55 @@ public: do_erase(key, hash); } - int count(const K &key) + void erase(const iterator it) + { + int hash = mkhash(it->first); + do_erase(it->first, hash); + } + + int count(const K &key) const { int hash = mkhash(key); int i = lookup_index(key, hash); return i < 0 ? 0 : 1; } + iterator find(const K &key) + { + int hash = mkhash(key); + int i = lookup_index(key, hash); + if (i < 0) + return end(); + return iterator(this, i); + } + + const_iterator find(const K &key) const + { + int hash = mkhash(key); + int i = lookup_index(key, hash); + if (i < 0) + return end(); + return const_iterator(this, i); + } + + T& at(const K &key) + { + int hash = mkhash(key); + int i = lookup_index(key, hash); + if (i < 0) + throw std::out_of_range("dict::at()"); + return entries[i].udata.second; + } + + const T& at(const K &key) const + { + int hash = mkhash(key); + int i = lookup_index(key, hash); + if (i < 0) + throw std::out_of_range("dict::at()"); + return entries[i].udata.second; + } + T& operator[](const K &key) { int hash = mkhash(key); @@ -231,8 +380,47 @@ public: return entries[i].udata.second; } + void swap(dict<K, T, OPS> &other) + { + hashtable.swap(other.hashtable); + entries.swap(other.entries); + std::swap(free_list, other.free_list); + std::swap(counter, other.counter); + } + + bool operator==(const dict<K, T, OPS> &other) const { + if (counter != other.counter) + return false; + if (counter == 0) + return true; + if (entries.size() < other.entries.size()) + for (auto &it : *this) { + auto oit = other.find(it.first); + if (oit == other.end() || oit->second != it.second) + return false; + } + else + for (auto &oit : other) { + auto it = find(oit.first); + if (it == end() || it->second != oit.second) + return false; + } + return true; + } + + bool operator!=(const dict<K, T, OPS> &other) const { + return !(*this == other); + } + + size_t size() const { return counter; } + bool empty() const { return counter == 0; } + void clear() { hashtable.clear(); entries.clear(); init(); } + iterator begin() { int index = 0; while (index != int(entries.size()) && entries[index].is_free()) index++; return iterator(this, index); } iterator end() { return iterator(this, entries.size()); } + + const_iterator begin() const { int index = 0; while (index != int(entries.size()) && entries[index].is_free()) index++; return const_iterator(this, index); } + const_iterator end() const { return const_iterator(this, entries.size()); } }; #endif |