Add lazy_emplace_l which is similar to try_emplace_l

lazy_emplace returns an iterator that is not thread-safe
This commit is contained in:
Brian McKinnon
2020-10-16 20:05:51 -05:00
parent f15998ac30
commit 02127f7bec
2 changed files with 33 additions and 8 deletions
+23 -6
View File
@@ -1424,9 +1424,7 @@ public:
iterator lazy_emplace(const key_arg<K>& key, F&& f) {
auto res = find_or_prepare_insert(key);
if (res.second) {
slot_type* slot = slots_ + res.first;
std::forward<F>(f)(constructor(&alloc_ref(), &slot));
assert(!slot);
lazy_emplace_at(res.first, std::forward<F>(f));
}
return iterator_at(res.first);
}
@@ -1435,13 +1433,18 @@ public:
iterator lazy_emplace_with_hash(const key_arg<K>& key, size_t &hash, F&& f) {
auto res = find_or_prepare_insert(key, hash);
if (res.second) {
slot_type* slot = slots_ + res.first;
std::forward<F>(f)(constructor(&alloc_ref(), &slot));
assert(!slot);
lazy_emplace_at(res.first, std::forward<F>(f));
}
return iterator_at(res.first);
}
template <class K = key_type, class F>
void lazy_emplace_at(size_t& idx, F&& f) {
slot_type* slot = slots_ + idx;
std::forward<F>(f)(constructor(&alloc_ref(), &slot));
assert(!slot);
}
// Extension API: support for heterogeneous keys.
//
@@ -2930,6 +2933,20 @@ public:
return make_iterator(&inner, set.lazy_emplace_with_hash(key, hashval, std::forward<F>(f)));
}
template <class K = key_type, class FExists, class FEmplace>
bool lazy_emplace_l(const key_arg<K>& key, FExists&& fExists, FEmplace&& fEmplace) {
typename Lockable::UniqueLock m;
auto res = this->find_or_prepare_insert(key, m);
typename Inner* inner = std::get<0>(res);
if (std::get<2>(res))
inner->set_.lazy_emplace_at(std::get<1>(res), std::forward<FEmplace>(fEmplace));
else {
auto it = this->iterator_at(inner, inner->set_.iterator_at(std::get<1>(res)));
std::forward<FExists>(fExists)(Policy::value(&*it));
}
return std::get<2>(res);
}
// Extension API: support for heterogeneous keys.
//
// std::unordered_set<std::string> s;
+10 -2
View File
@@ -32,13 +32,21 @@ TEST(THIS_TEST_NAME, ThreadSafeContains) {
m.try_emplace_l(2, [](int& v) { v = 5; });
EXPECT_EQ(m[2], 5);
// insert a valye that is not already present. Will be default initialised to 0 and lambda not called
// insert a value that is not already present. Will be default initialised to 0 and lambda not called
m.try_emplace_l(3, [](int& v) { assert(v == 0); /* should not be called when value constructed */ v = 6; });
EXPECT_EQ(m[3], 0);
// insert a valye that is not already present, provide argument to value-construct it
// insert a value that is not already present, provide argument to value-construct it
m.try_emplace_l(4, [](int& ) { assert(0); /* should not be called when value constructed */ }, 999);
EXPECT_EQ(m[4], 999);
// insert a value that is not already present.
m.lazy_emplace_l(5, [](int& v) { assert(0); /* should not be called when value constructed */ v = 6; }, [](const auto& ctor) { ctor(5, 13); });
EXPECT_EQ(m[5], 13);
// change a value that is present
m.lazy_emplace_l(5, [](int& v) { v = 6; }, [](const auto& ctor) { assert(0); /* should not be called when value exists */ctor(5, 13); });
EXPECT_EQ(m[5], 6);
}