diff --git a/parallel_hashmap/phmap.h b/parallel_hashmap/phmap.h index f8de239..4636533 100644 --- a/parallel_hashmap/phmap.h +++ b/parallel_hashmap/phmap.h @@ -1466,6 +1466,15 @@ public: assert(!slot); } + template + void emplace_single_with_hash(const key_arg& key, size_t &hashval, F&& f) { + auto res = find_or_prepare_insert(key, hashval); + if (res.second) + lazy_emplace_at(res.first, std::forward(f)); + else + _erase(iterator_at(res.first)); + } + // Extension API: support for heterogeneous keys. // @@ -3080,19 +3089,14 @@ public: typename Lockable::UniqueLock m(inner); 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); - 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); + + template + void emplace_single(const key_arg& key, F&& f) { + auto hashval = this->hash(key); + Inner& inner = sets_[subidx(hashval)]; + auto& set = inner.set_; + typename Lockable::UniqueLock m(inner); + set.emplace_single_with_hash(key, hashval, std::forward(f)); } // Extension API: support iterating over all values @@ -3715,7 +3719,6 @@ 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). @@ -3748,6 +3751,20 @@ public: return std::get<2>(res); } + 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 Base::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); + } + // ----------- end of phmap extensions -------------------------- template diff --git a/tests/parallel_flat_hash_set_test.cc b/tests/parallel_flat_hash_set_test.cc index 3c193de..b1924bd 100644 --- a/tests/parallel_flat_hash_set_test.cc +++ b/tests/parallel_flat_hash_set_test.cc @@ -1,4 +1,5 @@ #define THIS_HASH_SET parallel_flat_hash_set #define THIS_TEST_NAME ParallelFlatHashSet -#include "flat_hash_set_test.cc" +#include "parallel_hash_set_test.cc" + diff --git a/tests/parallel_hash_map_test.cc b/tests/parallel_hash_map_test.cc index 3bfb1e6..59d91d6 100644 --- a/tests/parallel_hash_map_test.cc +++ b/tests/parallel_hash_map_test.cc @@ -68,7 +68,7 @@ TEST(THIS_TEST_NAME, ThreadSafeContains) { { // -------------------- - // test lazy__emplace_l + // test lazy_emplace_l // -------------------- Map m = { {1, 7}, {2, 9} }; diff --git a/tests/parallel_hash_set_test.cc b/tests/parallel_hash_set_test.cc new file mode 100644 index 0000000..0f0143b --- /dev/null +++ b/tests/parallel_hash_set_test.cc @@ -0,0 +1,36 @@ +#ifndef THIS_HASH_SET + #define THIS_HASH_SET parallel_flat_hash_set + #define THIS_TEST_NAME ParallelFlatHashSet +#endif + +#include "flat_hash_set_test.cc" + +namespace phmap { +namespace priv { +namespace { + +TEST(THIS_TEST_NAME, ThreadSafeContains) { + // We can't test mutable keys, or non-copyable keys with ThisSet. + // Test that the nodes have the proper API. + using Set = phmap::THIS_HASH_SET; + + { + // -------------------- + // test emplace_single + // -------------------- + Set m = { {1}, {11} }; + + // emplace_single insert a value if not already present, else removes it + for (int i=0; i<12; ++i) + m.emplace_single(i, [i](const Set::constructor& ctor) { ctor(i); }); + EXPECT_EQ(m.count(0), 1); + EXPECT_EQ(m.count(1), 0); + EXPECT_EQ(m.count(2), 1); + EXPECT_EQ(m.count(11), 0); + } + +} + +} // namespace +} // namespace priv +} // namespace phmap