-
Notifications
You must be signed in to change notification settings - Fork 0
/
thread_safe_lookup_table.cpp
executable file
·99 lines (84 loc) · 3.34 KB
/
thread_safe_lookup_table.cpp
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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#include <mutex>
#include <memory>
#include <map>
#include <vector>
#include <list>
template<typename Key, typename Value, typename Hash=std::hash<key>>
class threadsafe_lookup_table{
private:
class bucket_type{
using bucket_value = std::pair<Key, Value>;
using bucket_data = std::list<bucket_value>;
using bucket_iterator = typename bucket_data::iterator;
bucket_data data;
mutable boost::shared_mutex mutex;
bucket_iterator find_entry_for(Key const& key) const{
return std::find_if(data.begin(),data.end(),[&](bucket_value const& item){return item.first==key});
}
public:
Value value_for(Key const& key, Value const& default_value) const{
boost::shared_lock<boost_shared_mutex> lock(mutex);
bucket_iterator const found_entry = find_entry_for(key);
return (found_entry == data.end())? default_value : found_entry->second;
}
void add_or_update_mapping(Key const& key, Value const& value){
std::unique_lock<boost::shared_mutex> lock(mutex);
bucket_iterator const found_entry = find_entry_for(key);
if(found_entry == data.end()){
data.push_back(bucket_value(key, value));
}
else{
found_entry->second = value;
}
}
void remove_mapping(Key const& key){
std::unique_lock<boost::shared_mutex> lock(mutex);
bucket_iterator const found_entry = find_entry_for(key);
if(found_entry != data.end()){
data.erase(found_entry);
}
}
};
std::vector<std::unique_ptr<bucket_type>> buckets;
Hash hasher;
bucket_type& get_bucket(Key const& key) const{
std::size_t const bucket_index = hasher(key)%buckets.size();
return *buckets[bucket_index];
}
public:
using key_type = Key;
using mapped_type = Value;
using hash_type = Hash;
threadsafe_lookup_table(
unsigned num_buckets=19, Hash const& hasher_= Hash()) :
buckets(num_buckets), hasher(hasher_){
for(unsigned i = 0; i < num_buckets; ++i){
buckets[i].reset(new bucket_type)
}
}
threadsafe_lookup_table(threadsafe_lookup_table const& other) = delete;
threadsafe_lookup_table& operator=(threadsafe_lookup_table const& other) = delete;
Value value_for(Key const& key, Value const& default_value=Value()) const{
return get_bucket(key).value_for(key, default_value);
}
void add_or_update_mapping(Key const& key, Value const& value){
get_bucket(key).add_or_update_mapping(key, value);
}
void remove_mapping(Key const& key){
get_bucket(key).remove_mapping(key);
}
std::map<Key,Value> get_map() const{
std::vector<std::unique_lock<boost::shared_mutex> > locks;
for(unsigned i = 0; i < buckets.size(); ++i){
locks.push_back(std::unique_lock<boost::shared_mutex>(buckets[i].mutex))
}
std::map<Key,Value> res;
for(unsigned i = 0; i < buckets.size(); ++i){
for(bucket_iterator it = buckets[i].data.begin();
it != buckets[i].data.end(); ++it){
res.insert(*it);
}
}
return res;
}
};