mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-10-31 03:32:29 +00:00 
			
		
		
		
	Merge pull request #4849 from YosysHQ/emil/hashlib-merge-top-ops
hashlib: merge hash_ops with hash_top_ops for plugin compat
This commit is contained in:
		
						commit
						da5c20dcfb
					
				
					 3 changed files with 47 additions and 32 deletions
				
			
		|  | @ -97,8 +97,8 @@ Making a type hashable | ||||||
| 
 | 
 | ||||||
| Let's first take a look at the external interface on a simplified level. | Let's first take a look at the external interface on a simplified level. | ||||||
| Generally, to get the hash for ``T obj``, you would call the utility function | Generally, to get the hash for ``T obj``, you would call the utility function | ||||||
| ``run_hash<T>(const T& obj)``, corresponding to ``hash_top_ops<T>::hash(obj)``, | ``run_hash<T>(const T& obj)``, corresponding to ``hash_ops<T>::hash(obj)``, | ||||||
| the default implementation of which is ``hash_ops<T>::hash_into(Hasher(), obj)``. | the default implementation of which uses ``hash_ops<T>::hash_into(Hasher(), obj)``. | ||||||
| ``Hasher`` is the class actually implementing the hash function, hiding its | ``Hasher`` is the class actually implementing the hash function, hiding its | ||||||
| initialized internal state, and passing it out on ``hash_t yield()`` with | initialized internal state, and passing it out on ``hash_t yield()`` with | ||||||
| perhaps some finalization steps. | perhaps some finalization steps. | ||||||
|  | @ -121,8 +121,14 @@ size containers like ``std::vector<U>`` the size of the container is hashed | ||||||
| first. That is also how implementing hashing for a custom record data type | first. That is also how implementing hashing for a custom record data type | ||||||
| should be - unless there is strong reason to do otherwise, call ``h.eat(m)`` on | should be - unless there is strong reason to do otherwise, call ``h.eat(m)`` on | ||||||
| the ``Hasher h`` you have received for each member in sequence and ``return | the ``Hasher h`` you have received for each member in sequence and ``return | ||||||
| h;``. If you do have a strong reason to do so, look at how | h;``. | ||||||
| ``hash_top_ops<RTLIL::SigBit>`` is implemented in ``kernel/rtlil.h``. | 
 | ||||||
|  | The ``hash_ops<T>::hash(obj)`` method is not indended to be called when | ||||||
|  | context of implementing the hashing for a record or other compound type. | ||||||
|  | When writing it, you should connect it to ``hash_ops<T>::hash_into(Hasher h)`` | ||||||
|  | as shown below. If you have a strong reason to do so, and you have | ||||||
|  | to create a special implementation for top-level hashing, look at how | ||||||
|  | ``hash_ops<RTLIL::SigBit>::hash(...)`` is implemented in ``kernel/rtlil.h``. | ||||||
| 
 | 
 | ||||||
| Porting plugins from the legacy interface | Porting plugins from the legacy interface | ||||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||||
|  | @ -148,6 +154,11 @@ based on the existance and value of `YS_HASHING_VERSION`. | ||||||
|       h.eat(b); |       h.eat(b); | ||||||
|       return h; |       return h; | ||||||
|    } |    } | ||||||
|  |    Hasher T::hash() const { | ||||||
|  |       Hasher h; | ||||||
|  |       h.eat(*this); | ||||||
|  |       return h; | ||||||
|  |    } | ||||||
|    #else |    #else | ||||||
|    #error "Unsupported hashing interface" |    #error "Unsupported hashing interface" | ||||||
|    #endif |    #endif | ||||||
|  |  | ||||||
|  | @ -61,19 +61,9 @@ namespace legacy { | ||||||
| 	} | 	} | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /**
 |  | ||||||
|  * 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; | ||||||
|  | @ -147,15 +137,14 @@ private: | ||||||
| 
 | 
 | ||||||
| using Hasher = HasherDJB32; | using Hasher = HasherDJB32; | ||||||
| 
 | 
 | ||||||
| template<typename T> | // Boilerplate compressor for trivially implementing
 | ||||||
| struct hash_top_ops { | // top-level hash method with hash_into
 | ||||||
| 	static inline bool cmp(const T &a, const T &b) { | #define HASH_TOP_LOOP_FST [[nodiscard]] static inline Hasher hash | ||||||
| 		return hash_ops<T>::cmp(a, b); | #define HASH_TOP_LOOP_SND { \ | ||||||
| 	} | 	Hasher h; \ | ||||||
| 	static inline Hasher hash(const T &a) { | 	h = hash_into(a, h); \ | ||||||
| 		return hash_ops<T>::hash_into(a, Hasher()); | 	return h; \ | ||||||
| 	} | } | ||||||
| }; |  | ||||||
| 
 | 
 | ||||||
| template<typename T> | template<typename T> | ||||||
| struct hash_ops { | struct hash_ops { | ||||||
|  | @ -183,6 +172,7 @@ struct hash_ops { | ||||||
| 			return a.hash_into(h); | 			return a.hash_into(h); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | 	HASH_TOP_LOOP_FST (const T &a) HASH_TOP_LOOP_SND | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| template<typename P, typename Q> struct hash_ops<std::pair<P, Q>> { | template<typename P, typename Q> struct hash_ops<std::pair<P, Q>> { | ||||||
|  | @ -194,6 +184,7 @@ template<typename P, typename Q> struct hash_ops<std::pair<P, Q>> { | ||||||
| 		h = hash_ops<Q>::hash_into(a.second, h); | 		h = hash_ops<Q>::hash_into(a.second, h); | ||||||
| 		return h; | 		return h; | ||||||
| 	} | 	} | ||||||
|  | 	HASH_TOP_LOOP_FST (std::pair<P, Q> a) HASH_TOP_LOOP_SND | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| template<typename... T> struct hash_ops<std::tuple<T...>> { | template<typename... T> struct hash_ops<std::tuple<T...>> { | ||||||
|  | @ -211,6 +202,7 @@ template<typename... T> struct hash_ops<std::tuple<T...>> { | ||||||
| 		h = element_ops_t::hash_into(std::get<I>(a), h); | 		h = element_ops_t::hash_into(std::get<I>(a), h); | ||||||
| 		return h; | 		return h; | ||||||
| 	} | 	} | ||||||
|  | 	HASH_TOP_LOOP_FST (std::tuple<T...> a) HASH_TOP_LOOP_SND | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| template<typename T> struct hash_ops<std::vector<T>> { | template<typename T> struct hash_ops<std::vector<T>> { | ||||||
|  | @ -223,6 +215,7 @@ template<typename T> struct hash_ops<std::vector<T>> { | ||||||
| 			h.eat(k); | 			h.eat(k); | ||||||
| 		return h; | 		return h; | ||||||
| 	} | 	} | ||||||
|  | 	HASH_TOP_LOOP_FST (std::vector<T> a) HASH_TOP_LOOP_SND | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| template<typename T, size_t N> struct hash_ops<std::array<T, N>> { | template<typename T, size_t N> struct hash_ops<std::array<T, N>> { | ||||||
|  | @ -234,6 +227,7 @@ template<typename T, size_t N> struct hash_ops<std::array<T, N>> { | ||||||
|             h = hash_ops<T>::hash_into(k, h); |             h = hash_ops<T>::hash_into(k, h); | ||||||
|         return h; |         return h; | ||||||
|     } |     } | ||||||
|  | 	HASH_TOP_LOOP_FST (std::array<T, N> a) HASH_TOP_LOOP_SND | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct hash_cstr_ops { | struct hash_cstr_ops { | ||||||
|  | @ -245,6 +239,7 @@ struct hash_cstr_ops { | ||||||
| 			h.hash32(*(a++)); | 			h.hash32(*(a++)); | ||||||
| 		return h; | 		return h; | ||||||
| 	} | 	} | ||||||
|  | 	HASH_TOP_LOOP_FST (const char *a) HASH_TOP_LOOP_SND | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| template <> struct hash_ops<char*> : hash_cstr_ops {}; | template <> struct hash_ops<char*> : hash_cstr_ops {}; | ||||||
|  | @ -256,6 +251,7 @@ struct hash_ptr_ops { | ||||||
| 	[[nodiscard]] static inline Hasher hash_into(const void *a, Hasher h) { | 	[[nodiscard]] static inline Hasher hash_into(const void *a, Hasher h) { | ||||||
| 		return hash_ops<uintptr_t>::hash_into((uintptr_t)a, h); | 		return hash_ops<uintptr_t>::hash_into((uintptr_t)a, h); | ||||||
| 	} | 	} | ||||||
|  | 	HASH_TOP_LOOP_FST (const void *a) HASH_TOP_LOOP_SND | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct hash_obj_ops { | struct hash_obj_ops { | ||||||
|  | @ -270,6 +266,8 @@ struct hash_obj_ops { | ||||||
| 			h.eat(0); | 			h.eat(0); | ||||||
| 		return h; | 		return h; | ||||||
| 	} | 	} | ||||||
|  | 	template<typename T> | ||||||
|  | 	HASH_TOP_LOOP_FST (const T *a) HASH_TOP_LOOP_SND | ||||||
| }; | }; | ||||||
| /**
 | /**
 | ||||||
|  * If you find yourself using this function, think hard |  * If you find yourself using this function, think hard | ||||||
|  | @ -280,7 +278,7 @@ struct hash_obj_ops { | ||||||
| template<typename T> | template<typename T> | ||||||
| [[nodiscard]] | [[nodiscard]] | ||||||
| Hasher::hash_t run_hash(const T& obj) { | Hasher::hash_t run_hash(const T& obj) { | ||||||
| 	return hash_top_ops<T>::hash(obj).yield(); | 	return hash_ops<T>::hash(obj).yield(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /** Refer to docs/source/yosys_internals/hashing.rst */ | /** Refer to docs/source/yosys_internals/hashing.rst */ | ||||||
|  | @ -352,10 +350,10 @@ inline unsigned int hashtable_size(unsigned 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, typename OPS = hash_top_ops<K>> class dict; | template<typename K, typename T, typename OPS = hash_ops<K>> class dict; | ||||||
| template<typename K, int offset = 0, typename OPS = hash_top_ops<K>> class idict; | template<typename K, int offset = 0, typename OPS = hash_ops<K>> class idict; | ||||||
| template<typename K, typename OPS = hash_top_ops<K>> class pool; | template<typename K, typename OPS = hash_ops<K>> class pool; | ||||||
| template<typename K, typename OPS = hash_top_ops<K>> class mfp; | template<typename K, typename OPS = hash_ops<K>> class mfp; | ||||||
| 
 | 
 | ||||||
| template<typename K, typename T, typename OPS> | template<typename K, typename T, typename OPS> | ||||||
| class dict { | class dict { | ||||||
|  |  | ||||||
|  | @ -398,13 +398,16 @@ struct RTLIL::IdString | ||||||
| 
 | 
 | ||||||
| namespace hashlib { | namespace hashlib { | ||||||
| 	template <> | 	template <> | ||||||
| 	struct hash_top_ops<RTLIL::IdString> { | 	struct hash_ops<RTLIL::IdString> { | ||||||
| 		static inline bool cmp(const RTLIL::IdString &a, const RTLIL::IdString &b) { | 		static inline bool cmp(const RTLIL::IdString &a, const RTLIL::IdString &b) { | ||||||
| 			return a == b; | 			return a == b; | ||||||
| 		} | 		} | ||||||
| 		static inline Hasher hash(const RTLIL::IdString id) { | 		[[nodiscard]] static inline Hasher hash(const RTLIL::IdString id) { | ||||||
| 			return id.hash_top(); | 			return id.hash_top(); | ||||||
| 		} | 		} | ||||||
|  | 		[[nodiscard]] static inline Hasher hash_into(const RTLIL::IdString id, Hasher h) { | ||||||
|  | 			return id.hash_into(h); | ||||||
|  | 		} | ||||||
| 	}; | 	}; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | @ -920,13 +923,16 @@ struct RTLIL::SigBit | ||||||
| 
 | 
 | ||||||
| namespace hashlib { | namespace hashlib { | ||||||
| 	template <> | 	template <> | ||||||
| 	struct hash_top_ops<RTLIL::SigBit> { | 	struct hash_ops<RTLIL::SigBit> { | ||||||
| 		static inline bool cmp(const RTLIL::SigBit &a, const RTLIL::SigBit &b) { | 		static inline bool cmp(const RTLIL::SigBit &a, const RTLIL::SigBit &b) { | ||||||
| 			return a == b; | 			return a == b; | ||||||
| 		} | 		} | ||||||
| 		static inline Hasher hash(const RTLIL::SigBit sb) { | 		[[nodiscard]] static inline Hasher hash(const RTLIL::SigBit sb) { | ||||||
| 			return sb.hash_top(); | 			return sb.hash_top(); | ||||||
| 		} | 		} | ||||||
|  | 		[[nodiscard]] static inline Hasher hash_into(const RTLIL::SigBit sb, Hasher h) { | ||||||
|  | 			return sb.hash_into(h); | ||||||
|  | 		} | ||||||
| 	}; | 	}; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue