Skip to content

Commit fd57fb6

Browse files
committed
Code improvements, bucket validation, const correctness, optional, ostream print
1 parent f79d59b commit fd57fb6

File tree

3 files changed

+89
-76
lines changed

3 files changed

+89
-76
lines changed

ConcurrentHashMap.h

Lines changed: 55 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -16,85 +16,95 @@
1616
#include <shared_mutex>
1717
#include <functional>
1818
#include <list>
19+
#include <optional>
20+
#include <algorithm> // For std::max
1921

2022
template <typename Key, typename Value, typename Hash = std::hash<Key>>
21-
class ConcurrentHashMap {
23+
class ConcurrentHashMap
24+
{
2225
private:
2326
// Define the structure of each node in the hash map
24-
struct Node {
27+
struct Node
28+
{
2529
Key key;
2630
Value value;
2731
};
2832

2933
// Define the hash map buckets and associated mutexes
3034
std::vector<std::list<Node>> buckets;
31-
std::vector<std::shared_mutex> mutexes;
35+
mutable std::vector<std::shared_mutex> mutexes;
3236
Hash hashFunction;
3337

34-
// Get the mutex for a given key
35-
std::shared_mutex& getMutex(const Key& key) {
38+
// Get mutex for a key
39+
std::shared_mutex &getMutex(const Key &key) const
40+
{
3641
std::size_t hashValue = hashFunction(key);
3742
return mutexes[hashValue % mutexes.size()];
3843
}
3944

4045
public:
41-
explicit ConcurrentHashMap(std::size_t num_buckets = 16) : buckets(num_buckets), mutexes(num_buckets) {}
46+
explicit ConcurrentHashMap(std::size_t num_buckets = 16)
47+
: buckets(std::max<std::size_t>(1, num_buckets)),
48+
mutexes(std::max<std::size_t>(1, num_buckets)) {}
4249

4350
// Insert a key-value pair into the hash map
44-
void insert(const Key& key, const Value& value) {
51+
void insert(const Key &key, const Value &value)
52+
{
4553
std::unique_lock lock(getMutex(key));
46-
std::size_t hashValue = hashFunction(key);
47-
std::size_t index = hashValue % buckets.size();
48-
49-
auto& bucket = buckets[index];
50-
auto it = std::find_if(bucket.begin(), bucket.end(), [&](const Node& node) { return node.key == key; });
51-
52-
if (it != bucket.end()) {
53-
// Update existing key
54+
std::size_t index = hashFunction(key) % buckets.size();
55+
auto &bucket = buckets[index];
56+
auto it = std::find_if(bucket.begin(), bucket.end(),
57+
[&](const Node & node)
58+
{
59+
return node.key == key;
60+
});
61+
62+
if(it != bucket.end())
63+
{
5464
it->value = value;
55-
} else {
56-
// Insert new key-value pair
57-
bucket.push_back({key, value});
5865
}
66+
else bucket.push_back({key, value});
5967
}
6068

6169
// Retrieve the value associated with a key from the hash map
62-
bool get(const Key& key, Value& value) {
70+
std::optional<Value> get(const Key &key) const
71+
{
6372
std::shared_lock lock(getMutex(key));
64-
std::size_t hashValue = hashFunction(key);
65-
std::size_t index = hashValue % buckets.size();
66-
67-
const auto& bucket = buckets[index];
68-
auto it = std::find_if(bucket.begin(), bucket.end(), [&](const Node& node) { return node.key == key; });
69-
70-
if (it != bucket.end()) {
71-
value = it->value;
72-
return true; // Found the key
73-
}
74-
75-
return false; // Key not found
73+
std::size_t index = hashFunction(key) % buckets.size();
74+
const auto &bucket = buckets[index];
75+
auto it = std::find_if(bucket.begin(), bucket.end(),
76+
[&](const Node & node)
77+
{
78+
return node.key == key;
79+
});
80+
return (it != bucket.end()) ? std::optional<Value>(it->value) : std::nullopt;
7681
}
7782

7883
// Remove a key-value pair from the hash map
79-
void remove(const Key& key) {
84+
void remove(const Key &key)
85+
{
8086
std::unique_lock lock(getMutex(key));
81-
std::size_t hashValue = hashFunction(key);
82-
std::size_t index = hashValue % buckets.size();
83-
84-
auto& bucket = buckets[index];
85-
bucket.remove_if([&](const Node& node) { return node.key == key; });
87+
std::size_t index = hashFunction(key) % buckets.size();
88+
buckets[index].remove_if([&](const Node & node)
89+
{
90+
return node.key == key;
91+
});
8692
}
8793

88-
// Print the contents of the hash map
89-
void print() {
90-
for (std::size_t i = 0; i < buckets.size(); ++i) {
94+
// Print to any ostream
95+
void print(std::ostream &os = std::cout) const
96+
{
97+
for(std::size_t i = 0; i < buckets.size(); ++i)
98+
{
9199
std::shared_lock lock(mutexes[i]);
92-
std::cout << "Bucket " << i << ": ";
93-
const auto& bucket = buckets[i];
94-
for (const auto& node : bucket) {
95-
std::cout << "(" << node.key << ", " << node.value << ") ";
100+
os << "Bucket " << i << ": ";
101+
102+
for(const auto &node : buckets[i])
103+
{
104+
os << "(" << node.key << ", " << node.value << ") ";
96105
}
97-
std::cout << std::endl;
106+
107+
os << "\n";
98108
}
99109
}
100110

demo_basic.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#include "ConcurrentHashMap.h"
2+
#include <iostream>
3+
#include <string>
4+
5+
int main()
6+
{
7+
ConcurrentHashMap<std::string, int> concurrentMap;
8+
concurrentMap.insert("one", 1);
9+
concurrentMap.insert("two", 2);
10+
concurrentMap.insert("three", 3);
11+
12+
if(auto value = concurrentMap.get("two"))
13+
{
14+
std::cout << "Value for key 'two': " << *value << "\n";
15+
}
16+
else
17+
{
18+
std::cout << "Key 'two' not found.\n";
19+
}
20+
21+
concurrentMap.remove("two");
22+
23+
if(auto value = concurrentMap.get("two"))
24+
{
25+
std::cout << "Value for key 'two': " << *value << "\n";
26+
}
27+
else
28+
{
29+
std::cout << "Key 'two' not found.\n";
30+
}
31+
32+
concurrentMap.print();
33+
return 0;
34+
}

test.cpp

Lines changed: 0 additions & 31 deletions
This file was deleted.

0 commit comments

Comments
 (0)