#pragma once #include #include #include #include #include #include #include #include template class HashTable { public: HashTable(size_t size) : size { size } , table(size) , bucket_mutexes(size) { } bool insert(K key, V value) { size_t index = get_bucket_index(key); std::unique_lock lock(bucket_mutexes.at(index)); std::list>& list = table.at(index); if (bucket_contains_key(list, key)) { return false; } list.push_back(std::pair(key, value)); return true; } std::optional get(K key) { size_t index = get_bucket_index(key); std::shared_lock lock(bucket_mutexes.at(index)); std::list>& list = table.at(index); auto iter = bucket_find_key(list, key); if (iter != list.end()) { return std::optional((*iter).second); } return std::optional(); } bool remove(K key) { size_t index = get_bucket_index(key); std::unique_lock lock(bucket_mutexes.at(index)); std::list>& list = table.at(index); auto iter = bucket_find_key(list, key); if (iter != list.end()) { list.erase(iter); return true; } return false; } std::string string() { std::ostringstream output; size_t index { 0 }; for (auto bucket : table) { output << "Bucket " << index << ": ["; std::shared_lock lock(bucket_mutexes.at(index)); for (auto pair : bucket) { output << "(" << pair.first << ", " << pair.second << ")"; } output << "]" << "\n"; ++index; } return output.str(); } private: size_t size; std::vector>> table; std::vector bucket_mutexes; std::hash hash_function; auto bucket_find_key(std::list>& list, K key) { return std::find_if(list.begin(), list.end(), [&key](const std::pair& pair) { return pair.first == key; }); } bool bucket_contains_key(std::list>& list, K key) { return list.begin() != list.end() && bucket_find_key(list, key) != list.end(); } size_t get_bucket_index(K key) { return hash_function(key) % size; } };