diff --git a/parallel_hashmap/phmap.h b/parallel_hashmap/phmap.h index 438a0af..004edc8 100644 --- a/parallel_hashmap/phmap.h +++ b/parallel_hashmap/phmap.h @@ -1424,9 +1424,7 @@ public: iterator lazy_emplace(const key_arg& key, F&& f) { auto res = find_or_prepare_insert(key); if (res.second) { - slot_type* slot = slots_ + res.first; - std::forward(f)(constructor(&alloc_ref(), &slot)); - assert(!slot); + lazy_emplace_at(res.first, std::forward(f)); } return iterator_at(res.first); } @@ -1435,13 +1433,18 @@ public: iterator lazy_emplace_with_hash(const key_arg& 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)(constructor(&alloc_ref(), &slot)); - assert(!slot); + lazy_emplace_at(res.first, std::forward(f)); } return iterator_at(res.first); } + template + void lazy_emplace_at(size_t& idx, F&& f) { + slot_type* slot = slots_ + idx; + std::forward(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))); } + template + bool lazy_emplace_l(const key_arg& 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)); + else { + auto it = this->iterator_at(inner, inner->set_.iterator_at(std::get<1>(res))); + std::forward(fExists)(Policy::value(&*it)); + } + return std::get<2>(res); + } + // Extension API: support for heterogeneous keys. // // std::unordered_set s; diff --git a/tests/parallel_hash_map_test.cc b/tests/parallel_hash_map_test.cc index 793622c..cdef5b9 100644 --- a/tests/parallel_hash_map_test.cc +++ b/tests/parallel_hash_map_test.cc @@ -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); }