diff --git a/parallel_hashmap/phmap.h b/parallel_hashmap/phmap.h index fd1be36..163e925 100644 --- a/parallel_hashmap/phmap.h +++ b/parallel_hashmap/phmap.h @@ -3622,6 +3622,17 @@ public: return modify_if_impl(key, std::forward(f)); } + + // if map contains key, lambda is called with the mapped value (under write lock protection). + // If the lambda returns true, the key is subsequently erased from the map (the write lock + // is only released after erase). + // returns true if key was erased, false otherwise. + // ---------------------------------------------------------------------------------------------------- + template + bool erase_if(const key_arg& key, F&& f) { + return erase_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. // if map already contains key, then the lambda is called with the mapped value (under @@ -3670,6 +3681,24 @@ private: return true; } + template + bool erase_if_impl(const key_arg& key, F&& f) { +#if __cplusplus >= 201703L + static_assert(std::is_invocable::value); +#endif + L m; + auto it = this->template find(key, this->hash(key), m); + if (it == this->end()) + return false; + if (std::forward(f)(Policy::value(&*it))) + { + this->erase(it); + return true; + } + return false; + } + + template std::pair insert_or_assign_impl(K&& k, V&& v) { typename Lockable::UniqueLock m; diff --git a/tests/parallel_hash_map_test.cc b/tests/parallel_hash_map_test.cc index 637babd..8cdbf5e 100644 --- a/tests/parallel_hash_map_test.cc +++ b/tests/parallel_hash_map_test.cc @@ -59,6 +59,16 @@ TEST(THIS_TEST_NAME, ThreadSafeContains) { [](int& v) { v = 6; }, // called only when key was already present [](const Map::constructor& ctor) { ctor(5, 13); }); // construct value_type in place when key not present EXPECT_EQ(m[5], 6); + + // test erase_if + // ------------- + EXPECT_EQ(m.erase_if(4, [](int& v) { assert(0); return v==12; }), false); // m[4] not present - lambda not called + EXPECT_EQ(m.erase_if(5, [](int& v) { return v==12; }), false); // m[5] == 6, so erase not performed + EXPECT_EQ(m[5], 6); + EXPECT_EQ(m.erase_if(5, [](int& v) { return v==6; }), true); // lambda returns true, so m[5] erased + EXPECT_EQ(m[5], 0); + + } } // namespace