Merge pull request #2295 from epfl-vlsc/firrtl_blackbox_generic_parameters
[yosys.git] / kernel / hashlib.h
index 3cc95b6e4b5fa5cc5599f7dcca4277a67a458278..a523afadd080db4ddfb6d0e3558252bf1cab068f 100644 (file)
@@ -10,6 +10,7 @@
 // -------------------------------------------------------
 
 #ifndef HASHLIB_H
+#define HASHLIB_H
 
 #include <stdexcept>
 #include <algorithm>
@@ -74,7 +75,7 @@ template<> struct hash_ops<int32_t> : hash_int_ops
 template<> struct hash_ops<int64_t> : hash_int_ops
 {
        static inline unsigned int hash(int64_t a) {
-               return mkhash(a, a >> 32);
+               return mkhash((unsigned int)(a), (unsigned int)(a >> 32));
        }
 };
 
@@ -95,9 +96,7 @@ template<typename P, typename Q> struct hash_ops<std::pair<P, Q>> {
                return a == b;
        }
        static inline unsigned int hash(std::pair<P, Q> a) {
-               hash_ops<P> p_ops;
-               hash_ops<Q> q_ops;
-               return mkhash(p_ops.hash(a.first), q_ops.hash(a.second));
+               return mkhash(hash_ops<P>::hash(a.first), hash_ops<Q>::hash(a.second));
        }
 };
 
@@ -111,8 +110,8 @@ template<typename... T> struct hash_ops<std::tuple<T...>> {
        }
        template<size_t I = 0>
        static inline typename std::enable_if<I != sizeof...(T), unsigned int>::type hash(std::tuple<T...> a) {
-               hash_ops<typename std::tuple_element<I, std::tuple<T...>>::type> element_ops;
-               return mkhash(hash<I+1>(a), element_ops.hash(std::get<I>(a)));
+               typedef hash_ops<typename std::tuple_element<I, std::tuple<T...>>::type> element_ops_t;
+               return mkhash(hash<I+1>(a), element_ops_t::hash(std::get<I>(a)));
        }
 };
 
@@ -138,8 +137,8 @@ struct hash_cstr_ops {
        static inline unsigned int hash(const char *a) {
                unsigned int hash = mkhash_init;
                while (*a)
-                        hash = mkhash(hash, *(a++));
-                return hash;
+                       hash = mkhash(hash, *(a++));
+               return hash;
        }
 };
 
@@ -148,7 +147,7 @@ struct hash_ptr_ops {
                return a == b;
        }
        static inline unsigned int hash(const void *a) {
-               return (unsigned long)a;
+               return (uintptr_t)a;
        }
 };
 
@@ -158,10 +157,15 @@ struct hash_obj_ops {
        }
        template<typename T>
        static inline unsigned int hash(const T *a) {
-               return a->hash();
+               return a ? a->hash() : 0;
        }
 };
 
+template<typename T>
+inline unsigned int mkhash(const T &v) {
+       return hash_ops<T>().hash(v);
+}
+
 inline int hashtable_size(int min_size)
 {
        static std::vector<int> zero_and_some_primes = {
@@ -190,6 +194,7 @@ inline int hashtable_size(int min_size)
 template<typename K, typename T, typename OPS = hash_ops<K>> class dict;
 template<typename K, int offset = 0, typename OPS = hash_ops<K>> class idict;
 template<typename K, typename OPS = hash_ops<K>> class pool;
+template<typename K, typename OPS = hash_ops<K>> class mfp;
 
 template<typename K, typename T, typename OPS>
 class dict
@@ -202,6 +207,7 @@ class dict
                entry_t() { }
                entry_t(const std::pair<K, T> &udata, int next) : udata(udata), next(next) { }
                entry_t(std::pair<K, T> &&udata, int next) : udata(std::move(udata)), next(next) { }
+               bool operator<(const entry_t &other) const { return udata.first < other.udata.first; }
        };
 
        std::vector<int> hashtable;
@@ -227,7 +233,7 @@ class dict
        void do_rehash()
        {
                hashtable.clear();
-               hashtable.resize(hashtable_size(entries.size() * hashtable_size_factor), -1);
+               hashtable.resize(hashtable_size(entries.capacity() * hashtable_size_factor), -1);
 
                for (int i = 0; i < int(entries.size()); i++) {
                        do_assert(-1 <= entries[i].next && entries[i].next < int(entries.size()));
@@ -309,11 +315,11 @@ class dict
        int do_insert(const K &key, int &hash)
        {
                if (hashtable.empty()) {
-                       entries.push_back(entry_t(std::pair<K, T>(key, T()), -1));
+                       entries.emplace_back(std::pair<K, T>(key, T()), -1);
                        do_rehash();
                        hash = do_hash(key);
                } else {
-                       entries.push_back(entry_t(std::pair<K, T>(key, T()), hashtable[hash]));
+                       entries.emplace_back(std::pair<K, T>(key, T()), hashtable[hash]);
                        hashtable[hash] = entries.size() - 1;
                }
                return entries.size() - 1;
@@ -322,11 +328,25 @@ class dict
        int do_insert(const std::pair<K, T> &value, int &hash)
        {
                if (hashtable.empty()) {
-                       entries.push_back(entry_t(value, -1));
+                       entries.emplace_back(value, -1);
                        do_rehash();
                        hash = do_hash(value.first);
                } else {
-                       entries.push_back(entry_t(value, hashtable[hash]));
+                       entries.emplace_back(value, hashtable[hash]);
+                       hashtable[hash] = entries.size() - 1;
+               }
+               return entries.size() - 1;
+       }
+
+       int do_insert(std::pair<K, T> &&rvalue, int &hash)
+       {
+               if (hashtable.empty()) {
+                       auto key = rvalue.first;
+                       entries.emplace_back(std::forward<std::pair<K, T>>(rvalue), -1);
+                       do_rehash();
+                       hash = do_hash(key);
+               } else {
+                       entries.emplace_back(std::forward<std::pair<K, T>>(rvalue), hashtable[hash]);
                        hashtable[hash] = entries.size() - 1;
                }
                return entries.size() - 1;
@@ -343,6 +363,7 @@ public:
        public:
                const_iterator() { }
                const_iterator operator++() { index--; return *this; }
+               const_iterator operator+=(int amt) { index -= amt; return *this; }
                bool operator<(const const_iterator &other) const { return index > other.index; }
                bool operator==(const const_iterator &other) const { return index == other.index; }
                bool operator!=(const const_iterator &other) const { return index != other.index; }
@@ -360,6 +381,7 @@ public:
        public:
                iterator() { }
                iterator operator++() { index--; return *this; }
+               iterator operator+=(int amt) { index -= amt; return *this; }
                bool operator<(const iterator &other) const { return index > other.index; }
                bool operator==(const iterator &other) const { return index == other.index; }
                bool operator!=(const iterator &other) const { return index != other.index; }
@@ -436,6 +458,56 @@ public:
                return std::pair<iterator, bool>(iterator(this, i), true);
        }
 
+       std::pair<iterator, bool> insert(std::pair<K, T> &&rvalue)
+       {
+               int hash = do_hash(rvalue.first);
+               int i = do_lookup(rvalue.first, hash);
+               if (i >= 0)
+                       return std::pair<iterator, bool>(iterator(this, i), false);
+               i = do_insert(std::forward<std::pair<K, T>>(rvalue), hash);
+               return std::pair<iterator, bool>(iterator(this, i), true);
+       }
+
+       std::pair<iterator, bool> emplace(K const &key, T const &value)
+       {
+               int hash = do_hash(key);
+               int i = do_lookup(key, hash);
+               if (i >= 0)
+                       return std::pair<iterator, bool>(iterator(this, i), false);
+               i = do_insert(std::make_pair(key, value), hash);
+               return std::pair<iterator, bool>(iterator(this, i), true);
+       }
+
+       std::pair<iterator, bool> emplace(K const &key, T &&rvalue)
+       {
+               int hash = do_hash(key);
+               int i = do_lookup(key, hash);
+               if (i >= 0)
+                       return std::pair<iterator, bool>(iterator(this, i), false);
+               i = do_insert(std::make_pair(key, std::forward<T>(rvalue)), hash);
+               return std::pair<iterator, bool>(iterator(this, i), true);
+       }
+
+       std::pair<iterator, bool> emplace(K &&rkey, T const &value)
+       {
+               int hash = do_hash(rkey);
+               int i = do_lookup(rkey, hash);
+               if (i >= 0)
+                       return std::pair<iterator, bool>(iterator(this, i), false);
+               i = do_insert(std::make_pair(std::forward<K>(rkey), value), hash);
+               return std::pair<iterator, bool>(iterator(this, i), true);
+       }
+
+       std::pair<iterator, bool> emplace(K &&rkey, T &&rvalue)
+       {
+               int hash = do_hash(rkey);
+               int i = do_lookup(rkey, hash);
+               if (i >= 0)
+                       return std::pair<iterator, bool>(iterator(this, i), false);
+               i = do_insert(std::make_pair(std::forward<K>(rkey), std::forward<T>(rvalue)), hash);
+               return std::pair<iterator, bool>(iterator(this, i), true);
+       }
+
        int erase(const K &key)
        {
                int hash = do_hash(key);
@@ -500,6 +572,15 @@ public:
                return entries[i].udata.second;
        }
 
+       const T& at(const K &key, const T &defval) const
+       {
+               int hash = do_hash(key);
+               int i = do_lookup(key, hash);
+               if (i < 0)
+                       return defval;
+               return entries[i].udata.second;
+       }
+
        T& operator[](const K &key)
        {
                int hash = do_hash(key);
@@ -537,14 +618,26 @@ public:
                return !operator==(other);
        }
 
+       unsigned int hash() const {
+               unsigned int h = mkhash_init;
+               for (auto &entry : entries) {
+                       h ^= hash_ops<K>::hash(entry.udata.first);
+                       h ^= hash_ops<T>::hash(entry.udata.second);
+               }
+               return h;
+       }
+
+       void reserve(size_t n) { entries.reserve(n); }
        size_t size() const { return entries.size(); }
        bool empty() const { return entries.empty(); }
        void clear() { hashtable.clear(); entries.clear(); }
 
        iterator begin() { return iterator(this, int(entries.size())-1); }
+       iterator element(int n) { return iterator(this, int(entries.size())-1-n); }
        iterator end() { return iterator(nullptr, -1); }
 
        const_iterator begin() const { return const_iterator(this, int(entries.size())-1); }
+       const_iterator element(int n) const { return const_iterator(this, int(entries.size())-1-n); }
        const_iterator end() const { return const_iterator(nullptr, -1); }
 };
 
@@ -561,6 +654,7 @@ protected:
 
                entry_t() { }
                entry_t(const K &udata, int next) : udata(udata), next(next) { }
+               entry_t(K &&udata, int next) : udata(std::move(udata)), next(next) { }
        };
 
        std::vector<int> hashtable;
@@ -586,7 +680,7 @@ protected:
        void do_rehash()
        {
                hashtable.clear();
-               hashtable.resize(hashtable_size(entries.size() * hashtable_size_factor), -1);
+               hashtable.resize(hashtable_size(entries.capacity() * hashtable_size_factor), -1);
 
                for (int i = 0; i < int(entries.size()); i++) {
                        do_assert(-1 <= entries[i].next && entries[i].next < int(entries.size()));
@@ -664,11 +758,24 @@ protected:
        int do_insert(const K &value, int &hash)
        {
                if (hashtable.empty()) {
-                       entries.push_back(entry_t(value, -1));
+                       entries.emplace_back(value, -1);
                        do_rehash();
                        hash = do_hash(value);
                } else {
-                       entries.push_back(entry_t(value, hashtable[hash]));
+                       entries.emplace_back(value, hashtable[hash]);
+                       hashtable[hash] = entries.size() - 1;
+               }
+               return entries.size() - 1;
+       }
+
+       int do_insert(K &&rvalue, int &hash)
+       {
+               if (hashtable.empty()) {
+                       entries.emplace_back(std::forward<K>(rvalue), -1);
+                       do_rehash();
+                       hash = do_hash(rvalue);
+               } else {
+                       entries.emplace_back(std::forward<K>(rvalue), hashtable[hash]);
                        hashtable[hash] = entries.size() - 1;
                }
                return entries.size() - 1;
@@ -766,6 +873,22 @@ public:
                return std::pair<iterator, bool>(iterator(this, i), true);
        }
 
+       std::pair<iterator, bool> insert(K &&rvalue)
+       {
+               int hash = do_hash(rvalue);
+               int i = do_lookup(rvalue, hash);
+               if (i >= 0)
+                       return std::pair<iterator, bool>(iterator(this, i), false);
+               i = do_insert(std::forward<K>(rvalue), hash);
+               return std::pair<iterator, bool>(iterator(this, i), true);
+       }
+
+       template<typename... Args>
+       std::pair<iterator, bool> emplace(Args&&... args)
+       {
+               return insert(K(std::forward<Args>(args)...));
+       }
+
        int erase(const K &key)
        {
                int hash = do_hash(key);
@@ -853,14 +976,24 @@ public:
                return !operator==(other);
        }
 
+       bool hash() const {
+               unsigned int hashval = mkhash_init;
+               for (auto &it : entries)
+                       hashval ^= ops.hash(it.udata);
+               return hashval;
+       }
+
+       void reserve(size_t n) { entries.reserve(n); }
        size_t size() const { return entries.size(); }
        bool empty() const { return entries.empty(); }
        void clear() { hashtable.clear(); entries.clear(); }
 
        iterator begin() { return iterator(this, int(entries.size())-1); }
+       iterator element(int n) { return iterator(this, int(entries.size())-1-n); }
        iterator end() { return iterator(nullptr, -1); }
 
        const_iterator begin() const { return const_iterator(this, int(entries.size())-1); }
+       const_iterator element(int n) const { return const_iterator(this, int(entries.size())-1-n); }
        const_iterator end() const { return const_iterator(nullptr, -1); }
 };
 
@@ -870,7 +1003,21 @@ class idict
        pool<K, OPS> database;
 
 public:
-       typedef typename pool<K, OPS>::const_iterator const_iterator;
+       class const_iterator : public std::iterator<std::forward_iterator_tag, K>
+       {
+               friend class idict;
+       protected:
+               const idict &container;
+               int index;
+               const_iterator(const idict &container, int index) : container(container), index(index) { }
+       public:
+               const_iterator() { }
+               const_iterator operator++() { index++; 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 K &operator*() const { return container[index]; }
+               const K *operator->() const { return &container[index]; }
+       };
 
        int operator()(const K &key)
        {
@@ -890,6 +1037,15 @@ public:
                return i + offset;
        }
 
+       int at(const K &key, int defval) const
+       {
+               int hash = database.do_hash(key);
+               int i = database.do_lookup(key, hash);
+               if (i < 0)
+                       return defval;
+               return i + offset;
+       }
+
        int count(const K &key) const
        {
                int hash = database.do_hash(key);
@@ -909,7 +1065,118 @@ public:
                return database.entries.at(index - offset).udata;
        }
 
+       void swap(idict &other)
+       {
+               database.swap(other.database);
+       }
+
+       void reserve(size_t n) { database.reserve(n); }
+       size_t size() const { return database.size(); }
+       bool empty() const { return database.empty(); }
+       void clear() { database.clear(); }
+
+       const_iterator begin() const { return const_iterator(*this, offset); }
+       const_iterator element(int n) const { return const_iterator(*this, n); }
+       const_iterator end() const { return const_iterator(*this, offset + size()); }
+};
+
+template<typename K, typename OPS>
+class mfp
+{
+       mutable idict<K, 0, OPS> database;
+       mutable std::vector<int> parents;
+
+public:
+       typedef typename idict<K, 0, OPS>::const_iterator const_iterator;
+
+       int operator()(const K &key) const
+       {
+               int i = database(key);
+               parents.resize(database.size(), -1);
+               return i;
+       }
+
+       const K &operator[](int index) const
+       {
+               return database[index];
+       }
+
+       int ifind(int i) const
+       {
+               int p = i, k = i;
+
+               while (parents[p] != -1)
+                       p = parents[p];
+
+               while (k != p) {
+                       int next_k = parents[k];
+                       parents[k] = p;
+                       k = next_k;
+               }
+
+               return p;
+       }
+
+       void imerge(int i, int j)
+       {
+               i = ifind(i);
+               j = ifind(j);
+
+               if (i != j)
+                       parents[i] = j;
+       }
+
+       void ipromote(int i)
+       {
+               int k = i;
+
+               while (k != -1) {
+                       int next_k = parents[k];
+                       parents[k] = i;
+                       k = next_k;
+               }
+
+               parents[i] = -1;
+       }
+
+       int lookup(const K &a) const
+       {
+               return ifind((*this)(a));
+       }
+
+       const K &find(const K &a) const
+       {
+               int i = database.at(a, -1);
+               if (i < 0)
+                       return a;
+               return (*this)[ifind(i)];
+       }
+
+       void merge(const K &a, const K &b)
+       {
+               imerge((*this)(a), (*this)(b));
+       }
+
+       void promote(const K &a)
+       {
+               int i = database.at(a, -1);
+               if (i >= 0)
+                       ipromote(i);
+       }
+
+       void swap(mfp &other)
+       {
+               database.swap(other.database);
+               parents.swap(other.parents);
+       }
+
+       void reserve(size_t n) { database.reserve(n); }
+       size_t size() const { return database.size(); }
+       bool empty() const { return database.empty(); }
+       void clear() { database.clear(); parents.clear(); }
+
        const_iterator begin() const { return database.begin(); }
+       const_iterator element(int n) const { return database.element(n); }
        const_iterator end() const { return database.end(); }
 };