diff --git a/parallel_hashmap/phmap.h b/parallel_hashmap/phmap.h index 7cf22b3..b6a856d 100644 --- a/parallel_hashmap/phmap.h +++ b/parallel_hashmap/phmap.h @@ -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 bool if_contains(const key_arg& key, F&& f) const { - return const_cast(this)->template modify_if_impl(key, std::forward(f)); + return const_cast(this)->template + modify_if_impl(key, std::forward(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 bool modify_if(const key_arg& key, F&& f) { return modify_if_impl(key, std::forward(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 + 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)), + std::forward_as_tuple(std::forward(args)...)); + auto it = this->iterator_at(inner, inner->set_.iterator_at(std::get<1>(res))); + std::forward(f)(Policy::value(&*it)); + return std::get<2>(res); + } + + // ----------- end of phmap extensions -------------------------- + template MappedReference

operator[](key_arg&& key) { return Policy::value(&*try_emplace(std::forward(key)).first); diff --git a/tests/parallel_hash_map_test.cc b/tests/parallel_hash_map_test.cc index 48241eb..5810b19 100644 --- a/tests/parallel_hash_map_test.cc +++ b/tests/parallel_hash_map_test.cc @@ -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