hash: solo hashing interface, override for SigBit

This commit is contained in:
Emil J. Tywoniak 2024-11-04 12:41:00 +01:00
parent b7991ed1f5
commit 52b0fc03b7
2 changed files with 66 additions and 20 deletions

View File

@ -56,11 +56,25 @@ const int hashtable_size_factor = 3;
#define DJB2_32 #define DJB2_32
namespace legacy {
inline uint32_t mkhash_add(uint32_t a, uint32_t b) {
return ((a << 5) + a) + b;
}
};
/**
* Hash a type with an accumulator in a record or array context
*/
template<typename T> template<typename T>
struct hash_ops; struct hash_ops;
/**
* Hash a single instance in isolation.
* Can have explicit specialization, but the default redirects to hash_ops
*/
template<typename T>
struct hash_top_ops;
inline unsigned int mkhash_xorshift(unsigned int a) { inline unsigned int mkhash_xorshift(unsigned int a) {
if (sizeof(a) == 4) { if (sizeof(a) == 4) {
a ^= a << 13; a ^= a << 13;
@ -141,6 +155,16 @@ class Hasher {
} }
}; };
template<typename T>
struct hash_top_ops {
static inline bool cmp(const T &a, const T &b) {
return hash_ops<T>::cmp(a, b);
}
static inline Hasher hash(const T &a) {
return hash_ops<T>::hash_acc(a, Hasher());
}
};
template<typename T> template<typename T>
struct hash_ops { struct hash_ops {
static inline bool cmp(const T &a, const T &b) { static inline bool cmp(const T &a, const T &b) {
@ -339,12 +363,12 @@ inline int hashtable_size(int min_size)
throw std::length_error("hash table exceeded maximum size."); throw std::length_error("hash table exceeded maximum size.");
} }
template<typename K, typename T> class dict; template<typename K, typename T, typename OPS = hash_top_ops<K>> class dict;
template<typename K, int offset = 0> class idict; template<typename K, int offset = 0, typename OPS = hash_top_ops<K>> class idict;
template<typename K> class pool; template<typename K, typename OPS = hash_top_ops<K>> class pool;
template<typename K> class mfp; template<typename K, typename OPS = hash_top_ops<K>> class mfp;
template<typename K, typename T> template<typename K, typename T, typename OPS>
class dict { class dict {
struct entry_t struct entry_t
{ {
@ -359,7 +383,7 @@ class dict {
std::vector<int> hashtable; std::vector<int> hashtable;
std::vector<entry_t> entries; std::vector<entry_t> entries;
hash_ops<K> ops; OPS ops;
#ifdef NDEBUG #ifdef NDEBUG
static inline void do_assert(bool) { } static inline void do_assert(bool) { }
@ -373,7 +397,7 @@ class dict {
{ {
Hasher::hash_t hash = 0; Hasher::hash_t hash = 0;
if (!hashtable.empty()) if (!hashtable.empty())
hash = run_hash<K>(key) % (unsigned int)(hashtable.size()); hash = ops.hash(key).yield() % (unsigned int)(hashtable.size());
return hash; return hash;
} }
@ -800,10 +824,10 @@ public:
const_iterator end() const { return const_iterator(nullptr, -1); } const_iterator end() const { return const_iterator(nullptr, -1); }
}; };
template<typename K> template<typename K, typename OPS>
class pool class pool
{ {
template<typename, int> friend class idict; template<typename, int, typename> friend class idict;
protected: protected:
struct entry_t struct entry_t
@ -818,7 +842,7 @@ protected:
std::vector<int> hashtable; std::vector<int> hashtable;
std::vector<entry_t> entries; std::vector<entry_t> entries;
hash_ops<K> ops; OPS ops;
#ifdef NDEBUG #ifdef NDEBUG
static inline void do_assert(bool) { } static inline void do_assert(bool) { }
@ -832,7 +856,7 @@ protected:
{ {
Hasher::hash_t hash = 0; Hasher::hash_t hash = 0;
if (!hashtable.empty()) if (!hashtable.empty())
hash = run_hash<K>(key) % (unsigned int)(hashtable.size()); hash = ops.hash(key).yield() % (unsigned int)(hashtable.size());
return hash; return hash;
} }
@ -1148,7 +1172,7 @@ public:
Hasher hash_acc(Hasher h) const { Hasher hash_acc(Hasher h) const {
h.acc(entries.size()); h.acc(entries.size());
for (auto &it : entries) { for (auto &it : entries) {
h.commutative_acc(run_hash(it.udata)); h.commutative_acc(ops.hash(it.udata).yield());
} }
return h; return h;
} }
@ -1167,10 +1191,10 @@ public:
const_iterator end() const { return const_iterator(nullptr, -1); } const_iterator end() const { return const_iterator(nullptr, -1); }
}; };
template<typename K, int offset> template<typename K, int offset, typename OPS>
class idict class idict
{ {
pool<K> database; pool<K, OPS> database;
public: public:
class const_iterator class const_iterator
@ -1264,10 +1288,10 @@ public:
* mfp stands for "merge, find, promote" * mfp stands for "merge, find, promote"
* i-prefixed methods operate on indices in parents * i-prefixed methods operate on indices in parents
*/ */
template<typename K> template<typename K, typename OPS>
class mfp class mfp
{ {
mutable idict<K, 0> database; mutable idict<K, 0, OPS> database;
mutable std::vector<int> parents; mutable std::vector<int> parents;
public: public:

View File

@ -896,6 +896,19 @@ struct RTLIL::SigBit
bool operator ==(const RTLIL::SigBit &other) const; bool operator ==(const RTLIL::SigBit &other) const;
bool operator !=(const RTLIL::SigBit &other) const; bool operator !=(const RTLIL::SigBit &other) const;
Hasher hash_acc(Hasher h) const; Hasher hash_acc(Hasher h) const;
Hasher hash_top() const;
};
namespace hashlib {
template <>
struct hash_top_ops<RTLIL::SigBit> {
static inline bool cmp(const RTLIL::SigBit &a, const RTLIL::SigBit &b) {
return a == b;
}
static inline Hasher hash(const RTLIL::SigBit sb) {
return sb.hash_top();
}
};
}; };
struct RTLIL::SigSpecIterator struct RTLIL::SigSpecIterator
@ -1825,15 +1838,24 @@ inline bool RTLIL::SigBit::operator!=(const RTLIL::SigBit &other) const {
inline Hasher RTLIL::SigBit::hash_acc(Hasher h) const { inline Hasher RTLIL::SigBit::hash_acc(Hasher h) const {
if (wire) { if (wire) {
h.acc(offset); h.acc(offset);
// hash_acc isn't allowed to come first, or it might hash trivially h.acc(wire->name);
// and possibly ruin things
h = wire->name.hash_acc(h);
return h; return h;
} }
h.acc(data); h.acc(data);
return h; return h;
} }
inline Hasher RTLIL::SigBit::hash_top() const {
Hasher h;
if (wire) {
h.force(hashlib::legacy::mkhash_add(wire->name.index_, offset));
return h;
}
h.force(data);
return h;
}
inline RTLIL::SigBit &RTLIL::SigSpecIterator::operator*() const { inline RTLIL::SigBit &RTLIL::SigSpecIterator::operator*() const {
return (*sig_p)[index]; return (*sig_p)[index];
} }