Add new API try_emplace_l (issue #60)

This commit is contained in:
greg
2020-08-16 18:27:20 -04:00
parent 16a5e67b33
commit 0d229b1159
2 changed files with 47 additions and 3 deletions
+31 -1
View File
@@ -3424,16 +3424,46 @@ public:
return Policy::value(&*it);
}
// ----------- phmap extensions --------------------------
// if map contains key, lambda is called with the mapped value (under read lock protection),
// and if_contains returns true. This is a const API and lambda should not modify the value
// -----------------------------------------------------------------------------------------
template <class K = key_type, class F>
bool if_contains(const key_arg<K>& key, F&& f) const {
return const_cast<parallel_hash_map*>(this)->template modify_if_impl<K, F, typename Lockable::SharedLock>(key, std::forward<F>(f));
return const_cast<parallel_hash_map*>(this)->template
modify_if_impl<K, F, typename Lockable::SharedLock>(key, std::forward<F>(f));
}
// if map contains key, lambda is called with the mapped value (under write lock protection),
// and modify_if returns true. This is a non-const API and lambda is allowed to modify the mapped value
// ----------------------------------------------------------------------------------------------------
template <class K = key_type, class F>
bool modify_if(const key_arg<K>& key, F&& f) {
return modify_if_impl<K, F, typename Lockable::UniqueLock>(key, std::forward<F>(f));
}
// if map does not contains key, it is inserted and the mapped value is value-constructed
// with the provided arguments (if any), as with try_emplace.
// Then the lambda is called with the mapped value (under write lock protection) and can
// update the mapped value.
// ---------------------------------------------------------------------------------------
template <class K = key_type, class F, class... Args>
bool try_emplace_l(K&& k, F&& f, Args&&... args) {
typename Lockable::UniqueLock m;
auto res = this->find_or_prepare_insert(k, m);
typename Base::Inner *inner = std::get<0>(res);
if (std::get<2>(res))
inner->set_.emplace_at(std::get<1>(res), std::piecewise_construct,
std::forward_as_tuple(std::forward<K>(k)),
std::forward_as_tuple(std::forward<Args>(args)...));
auto it = this->iterator_at(inner, inner->set_.iterator_at(std::get<1>(res)));
std::forward<F>(f)(Policy::value(&*it));
return std::get<2>(res);
}
// ----------- end of phmap extensions --------------------------
template <class K = key_type, class P = Policy, K* = nullptr>
MappedReference<P> operator[](key_arg<K>&& key) {
return Policy::value(&*try_emplace(std::forward<K>(key)).first);
+16 -2
View File
@@ -22,11 +22,25 @@ TEST(THIS_TEST_NAME, ThreadSafeContains) {
EXPECT_FALSE(m.if_contains(3, get_value));
auto set_value = [&val](int& v) { v = 11; };
EXPECT_TRUE(m. modify_if(2, set_value));
auto set_value = [](int& v) { v = 11; };
EXPECT_TRUE(m.modify_if(2, set_value));
EXPECT_EQ(m[2], 11);
EXPECT_FALSE(m.modify_if(3, set_value));
// overwrite an existing value
m.try_emplace_l(2, [](int& v) { v = 5; });
EXPECT_EQ(m[2], 5);
// insert a valye that is not already present
m.try_emplace_l(3, [](int& v) { assert(v == 0); v = 6; });
EXPECT_EQ(m[3], 6);
// insert a valye that is not already present, provide argument to value-construct it
m.try_emplace_l(4, [](int& v) { assert(v == 999); v = 5; }, 999);
EXPECT_EQ(m[4], 5);
}
} // namespace