-
Notifications
You must be signed in to change notification settings - Fork 0
/
concurrent_hash_map.h
84 lines (67 loc) · 2 KB
/
concurrent_hash_map.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#ifndef CONCURRENT_HASHMAP_H
#define CONCURRENT_HASHMAP_H
#include <array>
#include <atomic>
#include <cstddef>
#include <deque>
#include <functional>
#include <iostream>
#include <mutex>
#include <optional>
#include <shared_mutex>
#include <unordered_map>
#include <utility>
namespace ds {
template <class KeyT,
class ValueT,
class HashFn = std::hash<KeyT>,
const size_t BUCKETS = 1031>
class ConcurrentHashMap {
struct Bucket {
std::unordered_map<KeyT, ValueT> bucket_;
mutable std::shared_mutex rwlock_;
};
std::array<Bucket, BUCKETS> m_buckets;
HashFn m_hasher;
std::atomic<size_t> m_size{0};
inline size_t get_bucket(const KeyT& key) const {
return m_hasher(key) % BUCKETS;
}
public:
void insert(KeyT&& key, ValueT&& value) {
auto bucket_id = get_bucket(key);
auto& bucket = m_buckets[bucket_id].bucket_;
auto& rwlock = m_buckets[bucket_id].rwlock_;
std::lock_guard<std::shared_mutex> guard(rwlock);
bucket.emplace(std::forward<KeyT>(key), std::forward<ValueT>(value));
++m_size;
}
std::optional<ValueT> remove(const KeyT& key) {
auto bucket_id = get_bucket(key);
auto& bucket = m_buckets[bucket_id].bucket_;
auto& rwlock = m_buckets[bucket_id].rwlock_;
std::lock_guard<std::shared_mutex> guard(rwlock);
auto pos = bucket.find(key);
if (pos != bucket.end()) {
auto retVal = std::move(pos->second);
bucket.erase(pos);
--m_size;
return {retVal};
}
return {}; // key not found
}
std::optional<ValueT> get(const KeyT& key) const {
auto bucket_id = get_bucket(key);
const auto& bucket = m_buckets[bucket_id].bucket_;
auto& rwlock = m_buckets[bucket_id].rwlock_;
std::shared_lock<std::shared_mutex> guard(rwlock);
auto pos = bucket.find(key);
if (pos != bucket.end())
return {pos->second};
return {};
}
size_t was_size() const { return m_size; }
bool was_empty() const { return !m_size; }
};
} // namespace ds
#endif // CONCURRENT_HASMAP