[ox/std] Add support for integral types as keys in HashMap
This commit is contained in:
		
							
								
								
									
										30
									
								
								deps/ox/src/ox/std/hashmap.hpp
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										30
									
								
								deps/ox/src/ox/std/hashmap.hpp
									
									
									
									
										vendored
									
									
								
							@@ -76,7 +76,7 @@ class HashMap {
 | 
				
			|||||||
		/**
 | 
							/**
 | 
				
			||||||
		 * K is assumed to be a null terminated string.
 | 
							 * K is assumed to be a null terminated string.
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		constexpr static uint64_t hash(K, int len = 0xFFFF) noexcept;
 | 
							constexpr static uint64_t hash(auto) noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/**
 | 
							/**
 | 
				
			||||||
		 * K is assumed to be a null terminated string.
 | 
							 * K is assumed to be a null terminated string.
 | 
				
			||||||
@@ -182,16 +182,13 @@ constexpr void HashMap<K, T>::erase(const K &k) {
 | 
				
			|||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	auto h = hash(k) % m_pairs.size();
 | 
						auto h = hash(k) % m_pairs.size();
 | 
				
			||||||
	char hashStr[sizeof(h) + 1];
 | 
					 | 
				
			||||||
	ox_memcpy(hashStr, &h, sizeof(h));
 | 
					 | 
				
			||||||
	hashStr[sizeof(h)] = 0;
 | 
					 | 
				
			||||||
	while (true) {
 | 
						while (true) {
 | 
				
			||||||
		const auto &p = m_pairs[h];
 | 
							const auto &p = m_pairs[h];
 | 
				
			||||||
		if (p == nullptr || ox_strcmp(p->key, k) == 0) {
 | 
							if (p == nullptr || ox_strcmp(p->key, k) == 0) {
 | 
				
			||||||
			oxIgnoreError(m_pairs.erase(h));
 | 
								oxIgnoreError(m_pairs.erase(h));
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			h = hash(hashStr, 8) % m_pairs.size();
 | 
								h = hash(h) % m_pairs.size();
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	oxIgnoreError(m_keys.erase(ox::find(m_keys.begin(), m_keys.end(), k)));
 | 
						oxIgnoreError(m_keys.erase(ox::find(m_keys.begin(), m_keys.end(), k)));
 | 
				
			||||||
@@ -232,10 +229,18 @@ constexpr void HashMap<K, T>::expand() {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template<typename K, typename T>
 | 
					template<typename K, typename T>
 | 
				
			||||||
constexpr uint64_t HashMap<K, T>::hash(K k, int len) noexcept {
 | 
					constexpr uint64_t HashMap<K, T>::hash(auto k) noexcept {
 | 
				
			||||||
	uint64_t sum = 1;
 | 
						uint64_t sum = 1;
 | 
				
			||||||
	for (auto i = 0u; i < static_cast<uint64_t>(len) && k[i]; ++i) {
 | 
						if constexpr(is_integral_v<decltype(k)>) {
 | 
				
			||||||
		sum += ((sum + static_cast<uint64_t>(k[i])) * 7) * sum;
 | 
							for (auto i = 0u; i < sizeof(K); ++i) {
 | 
				
			||||||
 | 
								const auto shift = i * 8;
 | 
				
			||||||
 | 
								const auto v = static_cast<uint64_t>(k >> shift & 0xff);
 | 
				
			||||||
 | 
								sum += (sum + v) * 7 * sum;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							for (auto i = 0u; k[i]; ++i) {
 | 
				
			||||||
 | 
								sum += ((sum + static_cast<uint64_t>(k[i])) * 7) * sum;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return sum;
 | 
						return sum;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -258,7 +263,14 @@ constexpr typename HashMap<K, T>::Pair *&HashMap<K, T>::access(Vector<Pair*> &pa
 | 
				
			|||||||
	auto h = hash(k) % pairs.size();
 | 
						auto h = hash(k) % pairs.size();
 | 
				
			||||||
	while (true) {
 | 
						while (true) {
 | 
				
			||||||
		auto &p = pairs[h];
 | 
							auto &p = pairs[h];
 | 
				
			||||||
		if (p == nullptr || ox_strcmp(p->key, k) == 0) {
 | 
							bool matches = [&] {
 | 
				
			||||||
 | 
								if constexpr (is_integral_v<K>) {
 | 
				
			||||||
 | 
									return p == nullptr || k == p->key;
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									return p == nullptr || ox_strcmp(p->key, k) == 0;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}();
 | 
				
			||||||
 | 
							if (matches) {
 | 
				
			||||||
			return p;
 | 
								return p;
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			h = (h + 1) % pairs.size();
 | 
								h = (h + 1) % pairs.size();
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										15
									
								
								deps/ox/src/ox/std/test/tests.cpp
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										15
									
								
								deps/ox/src/ox/std/test/tests.cpp
									
									
									
									
										vendored
									
									
								
							@@ -109,11 +109,16 @@ std::map<ox::String, ox::Error(*)()> tests = {
 | 
				
			|||||||
	{
 | 
						{
 | 
				
			||||||
		"HashMap",
 | 
							"HashMap",
 | 
				
			||||||
		[] {
 | 
							[] {
 | 
				
			||||||
			ox::HashMap<const char*, int> v;
 | 
								ox::HashMap<const char*, int> si;
 | 
				
			||||||
			v["asdf"] = 42;
 | 
								si["asdf"] = 42;
 | 
				
			||||||
			v["aoeu"] = 100;
 | 
								si["aoeu"] = 100;
 | 
				
			||||||
			oxAssert(v["asdf"] == 42, "asdf != 42");
 | 
								oxAssert(si["asdf"] == 42, "asdf != 42");
 | 
				
			||||||
			oxAssert(v["aoeu"] == 100, "aoeu != 100");
 | 
								oxAssert(si["aoeu"] == 100, "aoeu != 100");
 | 
				
			||||||
 | 
								ox::HashMap<int, int> ii;
 | 
				
			||||||
 | 
								ii[4] = 42;
 | 
				
			||||||
 | 
								ii[5] = 100;
 | 
				
			||||||
 | 
								oxAssert(ii[4] == 42, "4 != 42");
 | 
				
			||||||
 | 
								oxAssert(ii[5] == 100, "5 != 100");
 | 
				
			||||||
			return OxError(0);
 | 
								return OxError(0);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user