diff --git a/parallel_hashmap/phmap.h b/parallel_hashmap/phmap.h index 48e53ab..d02f846 100644 --- a/parallel_hashmap/phmap.h +++ b/parallel_hashmap/phmap.h @@ -3159,8 +3159,8 @@ class parallel_hash_set Inner& inner = sets_[subidx(hashval)]; auto& set = inner.set_; UniqueLock m(inner); - typename EmbeddedSet::template InsertSlotWithHash f { inner, std::move(*slot), hashval }; - return make_rv(PolicyTraits::apply(f, elem)); + typename EmbeddedSet::template InsertSlotWithHash f { inner.set_, std::move(*slot), hashval }; + return make_rv(&inner, PolicyTraits::apply(std::move(f), elem)); } template @@ -3227,15 +3227,15 @@ class parallel_hash_set std::pair emplace(Args&&... args) { typename phmap::aligned_storage::type raw; slot_type* slot = reinterpret_cast(&raw); - size_t hashval = this->hash(PolicyTraits::key(slot)); - PolicyTraits::construct(&alloc_ref(), slot, std::forward(args)...); + const auto& elem = PolicyTraits::element(slot); + size_t hashval = this->hash(PolicyTraits::key(slot)); Inner& inner = sets_[subidx(hashval)]; auto& set = inner.set_; UniqueLock m(inner); - typename EmbeddedSet::template InsertSlotWithHash f { inner, std::move(*slot), hashval }; - return make_rv(PolicyTraits::apply(f, elem)); + typename EmbeddedSet::template InsertSlotWithHash f { inner.set_, std::move(*slot), hashval }; + return make_rv(&inner, PolicyTraits::apply(std::move(f), elem)); } template diff --git a/parallel_hashmap/phmap_base.h b/parallel_hashmap/phmap_base.h index 968a548..2410dc3 100644 --- a/parallel_hashmap/phmap_base.h +++ b/parallel_hashmap/phmap_base.h @@ -424,18 +424,30 @@ namespace priv { template struct hash_policy_traits { + // The type of the keys stored in the hashtable. + using key_type = typename Policy::key_type; private: - struct ReturnKey - { - // We return `Key` here. - // When Key=T&, we forward the lvalue reference. - // When Key=T, we return by value to avoid a dangling reference. - // eg, for string_hash_map. - template - Key operator()(Key&& k, const Args&...) const { - return std::forward(k); - } - }; + struct ReturnKey { + template ::value, int> = 0> + static key_type& Impl(Key&& k, int) { + return *const_cast(std::addressof(std::forward(k))); + } + + template + static Key Impl(Key&& k, char) { + return std::forward(k); + } + + // When Key=T&, we forward the lvalue reference. + // When Key=T, we return by value to avoid a dangling reference. + // eg, for string_hash_map. + template + auto operator()(Key&& k, const Args&...) const + -> decltype(Impl(std::forward(k), 0)) { + return Impl(std::forward(k), 0); + } + }; template struct ConstantIteratorsImpl : std::false_type {}; @@ -448,9 +460,6 @@ struct hash_policy_traits // The actual object stored in the hash table. using slot_type = typename Policy::slot_type; - // The type of the keys stored in the hashtable. - using key_type = typename Policy::key_type; - // The argument type for insertions into the hashtable. This is different // from value_type for increased performance. See initializer_list constructor // and insert() member functions for more details. diff --git a/tests/node_hash_set_test.cc b/tests/node_hash_set_test.cc index 549ba4e..d4716ac 100644 --- a/tests/node_hash_set_test.cc +++ b/tests/node_hash_set_test.cc @@ -105,6 +105,14 @@ TEST(THIS_TEST_NAME, MergeExtractInsert) { EXPECT_THAT(set2, UnorderedElementsAre(Pointee(7), Pointee(23))); } +TEST(THIS_TEST_NAME, Emplace) { + using Thing = std::tuple; + phmap::THIS_HASH_SET hs; + hs.emplace(Thing(0, 1.25)); + hs.emplace(0, 1.3); + assert(hs.find(Thing(0, 1.3)) != hs.end()); +} + } // namespace } // namespace priv } // namespace phmap