SHOW:
|
|
- or go back to the newest paste.
1 | #include <future> | |
2 | #include <mutex> | |
3 | #include <unordered_map> | |
4 | #include <vector> | |
5 | #include <utility> | |
6 | #include <algorithm> | |
7 | #include <random> | |
8 | #include <thread> | |
9 | #include <shared_mutex> | |
10 | ||
11 | using namespace std; | |
12 | ||
13 | template<typename K, typename V, typename Hash = std::hash<K>> | |
14 | class ConcurrentMap { | |
15 | struct Key { | |
16 | K data; | |
17 | size_t hash; | |
18 | ||
19 | explicit Key(K data) : data(std::move(data)), hash(Hash()(this->data)) {} | |
20 | ||
21 | bool operator==(const Key &other) const { | |
22 | return data == other.data; | |
23 | } | |
24 | }; | |
25 | ||
26 | struct KeyHasher { | |
27 | auto operator()(const Key &value) const { | |
28 | return value.hash; | |
29 | } | |
30 | }; | |
31 | ||
32 | using InnerMapType = std::unordered_map<Key, V, KeyHasher>; | |
33 | ||
34 | struct SharedMap { | |
35 | mutable std::shared_mutex mtx; | |
36 | InnerMapType map; | |
37 | }; | |
38 | ||
39 | public: | |
40 | using MapType = std::unordered_map<K, V, Hash>; | |
41 | ||
42 | class WriteAccess { | |
43 | std::lock_guard<std::shared_mutex> guard; | |
44 | public: | |
45 | V &ref_to_value; | |
46 | ||
47 | WriteAccess(InnerMapType &map, Key &key, std::shared_mutex &mtx) : guard(mtx), | |
48 | ref_to_value(map[std::move(key)]) {}; | |
49 | }; | |
50 | ||
51 | class ReadAccess { | |
52 | std::shared_lock<std::shared_mutex> lock; | |
53 | public: | |
54 | const V &ref_to_value; | |
55 | ||
56 | ReadAccess(const InnerMapType &map, const Key &key, std::shared_mutex &mtx) : lock(mtx), | |
57 | ref_to_value(map.at(key)) {}; | |
58 | }; | |
59 | ||
60 | explicit ConcurrentMap(size_t bucket_count) : data(bucket_count) {} | |
61 | ||
62 | WriteAccess operator[](const K &key) { | |
63 | Key map_key(key); | |
64 | auto &[mtx, map] = data[map_key.hash % data.size()]; | |
65 | return {map, map_key, mtx}; | |
66 | } | |
67 | ||
68 | ReadAccess At(const K &key) const { | |
69 | const Key map_key(key); | |
70 | auto &[mtx, map] = data[map_key.hash % data.size()]; | |
71 | return {map, map_key, mtx}; | |
72 | } | |
73 | ||
74 | bool Has(const K &key) const { | |
75 | const Key map_key(key); | |
76 | auto &[mtx, map] = data[map_key.hash % data.size()]; | |
77 | std::shared_lock locker(mtx); | |
78 | return map.find(map_key) != map.end(); | |
79 | } | |
80 | ||
81 | MapType BuildOrdinaryMap() const { | |
82 | MapType to_ret; | |
83 | for (auto &[mtx, map] : data) { | |
84 | std::shared_lock locker(mtx); | |
85 | for (auto &[key, val] : map) { | |
86 | to_ret[key.data] = val; | |
87 | } | |
88 | } | |
89 | return to_ret; | |
90 | } | |
91 | ||
92 | private: | |
93 | std::vector<SharedMap> data; | |
94 | }; |