线程安全的查找表
template<typename Key, typename Value, typename Hash = std::hash<Key>>
class ThreadsafeLookupTable
{
private:
class BucketType
{
private:
typedef std::pair<Key, Value> bucketValue;
typedef std::list<bucketValue> bucketData;
typedef typename bucketData::iterator bucketIterator;
bucketData data;
mutable boost::shared_mutex mutex;
bucketIterator findEntryFor(Key const& key) const
{
return std::find_if(data.cbegin (), data.cend (),
[&](bucketValue const& item)
{return item.first == key;});
}
public:
Value valueFor(Key const& key, Value const& defaultValue) const
{
boost::shared_lock<boost::shared_mutex> lock(mutex);
auto const foundEntry = findEntryFor (key);
return (foundEntry == data.cend ()? defaultValue : foundEntry->second);
}
void addOrUpdate(Key const& key, Value const& value)
{
std::unique_lock<boost::shared_mutex> lock(mutex);
auto const foundEntry = findEntryFor (key);
if (foundEntry == data.cend ()){
data.push_back ({key, value});
}
else{
foundEntry->second = value;
}
}
void removeMapping(Key const& key)
{
std::unique_lock<boost::shared_mutex> lock(mutex);
auto const foundEntry = findEntryFor (key);
if (foundEntry != data.cend ()){
data.erase (foundEntry);
}
}
};
std::vector<std::unique_ptr<BucketType>> buckets;
Hash hasher;
BucketType& getBucket(Key const& key) const
{
auto const bucketIdnex = hasher(key) % buckets.size ();
return *buckets[bucketIdnex];
}
public:
ThreadsafeLookupTable(const ThreadsafeLookupTable&) = delete;
ThreadsafeLookupTable& operator=(const ThreadsafeLookupTable&) = delete;
typedef Key KeyType;
typedef Value MappedValue;
ThreadsafeLookupTable(size_t numBuckets = 19, Hash const& hasher_ = Hash()):
buckets(std::vector<std::unique_ptr<BucketType>>(numBuckets)),
hasher(hasher_)
{
for (size_t i = 0; i < numBuckets; ++i){
buckets[i].reset(std::make_unique<BucketType>());
}
}
Value valueFor(Key const& key, Value const& defaultValue)
{
getBucket (key).valueFor (key, defaultValue);
}
void addOrUpdateMapping(Key const& key, Value const& value)
{
getBucket (key).addOrUpdate (key, value);
}
void removeMapping(Key const& key)
{
getBucket (key).removeMapping (key);
}
};