ccia_code_samples
ccia_code_samples copied to clipboard
6.11 doesn't compile
typedef typename bucket_data::iterator bucket_iterator;
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;
});
}
This returns a const_iterator, the compiler issues an error because it can't convert between the two.
Yes, I modified some codes as below. Hope can help :)
template<typename Key, typename Value, typename Hash=std::hash<Key> >
class threadsafe_lookup_table {
private:
class bucket_type {
public:
using bucket_value = std::pair<Key, Value>;
using bucket_data = std::list<bucket_value>;
using bucket_iterator = typename std::list<bucket_value>::iterator;
// properties
bucket_data data;
mutable boost::shared_mutex mutex;
bucket_iterator find_entry_for(Key const& key) {
return std::find_if(std::begin(data), std::end(data),
[&](bucket_value const& item) { return item.first == key; });
}
public:
Value value_for(Key const& key, Value const& default_val) {
boost::shared_lock_guard<boost::shared_mutex> lock(mutex);
bucket_iterator const found_entry = find_entry_for(key);
return ((found_entry == data.end()) ? default_val : found_entry->second);
}
void add_or_update_mapping(Key const& key, Value const& value) {
boost::shared_lock_guard<boost::shared_mutex> lock(mutex);
bucket_iterator const found_entry = find_entry_for(key);
if (found_entry == data.end()) {
data.emplace_back(std::make_pair(key, value));
} else {
found_entry->second = value;
}
}
void remove_mapping(Key const& key) {
boost::shared_lock_guard<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:
threadsafe_lookup_table(unsigned num_buckets = 19, Hash const& hash_=Hash()) :
buckets(num_buckets), hasher(hash_) {
for (unsigned i=0; i < num_buckets; i++) {
buckets[i].reset(new bucket_type);
}
}
threadsafe_lookup_table(const threadsafe_lookup_table&) = delete;
threadsafe_lookup_table& operator=(const threadsafe_lookup_table&) = 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() {
std::vector<boost::unique_lock<boost::shared_mutex> > locks;
for (unsigned i = 0; i < buckets.size(); ++i) {
locks.emplace_back(boost::unique_lock<boost::shared_mutex> (buckets[i]->mutex));
}
std::map<Key, Value> res;
for(unsigned i = 0; i < buckets.size(); ++i) {
for(auto it = std::begin(buckets[i]->data); it != std::end(buckets[i]->data); ++it) {
res.insert(*it);
}
}
return res;
}
};
Happy three year anniversary!
A quick solution would be to remove const
from the end of find_entry_for()
, so this...
https://github.com/anthonywilliams/ccia_code_samples/blob/6e7ae1d66dbd2e8f1ad18a5cf5c6d25a37b92388/listings/listing_6.11.cpp#L23
...would become this...
https://github.com/anthonywilliams/ccia_code_samples/blob/e893b0c531110546abf2d2677c1144ea3e290a3d/listings/listing_6.11.cpp#L23
https://github.com/anthonywilliams/ccia_code_samples/compare/main...ITHelpDec:ccia_code_samples:patch-4
A nicer alternative would be to respect const-ness by making tweaks elsewhere in the code, but I've raised a PR here to help anyone else that might be looking for an answer in the meantime.