Skip to content

Commit

Permalink
Allow swap() to work with parallel hash maps/sets with different mute…
Browse files Browse the repository at this point in the history
…x types, so you can use the same container with or without locking.
  • Loading branch information
greg7mdp committed Sep 16, 2022
1 parent 36607cb commit ba9386e
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 8 deletions.
28 changes: 20 additions & 8 deletions include/gtl/phmap.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3989,6 +3989,11 @@ class parallel_hash_set
fCallback(set);
}

// unsafe, for internal use only
Inner& get_inner(size_t idx) {
return sets_[idx];
}

// Extension API: support for heterogeneous keys.
//
// std::unordered_set<std::string> s;
Expand Down Expand Up @@ -4084,15 +4089,19 @@ class parallel_hash_set
return it == end() ? node_type() : extract(const_iterator{it});
}

void swap(parallel_hash_set& that) noexcept(
template<class Mtx2_>
void swap(parallel_hash_set<N, RefSet, Mtx2_, AuxCont, Policy, Hash, Eq, Alloc>& that) noexcept(
IsNoThrowSwappable<EmbeddedSet>() &&
(!AllocTraits::propagate_on_container_swap::value ||
IsNoThrowSwappable<allocator_type>())) {
using std::swap;
using Lockable2 = LockableImpl<Mtx2_>;

for (size_t i=0; i<num_tables; ++i)
{
typename Lockable::UniqueLocks l(sets_[i], that.sets_[i]);
swap(sets_[i].set_, that.sets_[i].set_);
typename Lockable::UniqueLock l(sets_[i]);
typename Lockable2::UniqueLock l2(that.get_inner(i));
swap(sets_[i].set_, that.get_inner(i).set_);
}
}

Expand Down Expand Up @@ -4231,8 +4240,9 @@ class parallel_hash_set
return !(a == b);
}

template<class Mtx2_>
friend void swap(parallel_hash_set& a,
parallel_hash_set& b) noexcept(noexcept(a.swap(b))) {
parallel_hash_set<N, RefSet, Mtx2_, AuxCont, Policy, Hash, Eq, Alloc>& b) noexcept(noexcept(a.swap(b))) {
a.swap(b);
}

Expand Down Expand Up @@ -4311,14 +4321,16 @@ class parallel_hash_set

// TODO(alkis): Optimize this assuming *this and that don't overlap.
// --------------------------------------------------------------------
parallel_hash_set& move_assign(parallel_hash_set&& that, std::true_type) {
parallel_hash_set tmp(std::move(that));
template<class Mtx2_>
parallel_hash_set& move_assign(parallel_hash_set<N, RefSet, Mtx2_, AuxCont, Policy, Hash, Eq, Alloc>&& that, std::true_type) {
parallel_hash_set<N, RefSet, Mtx2_, AuxCont, Policy, Hash, Eq, Alloc> tmp(std::move(that));
swap(tmp);
return *this;
}

parallel_hash_set& move_assign(parallel_hash_set&& that, std::false_type) {
parallel_hash_set tmp(std::move(that), alloc_ref());
template<class Mtx2_>
parallel_hash_set& move_assign(parallel_hash_set<N, RefSet, Mtx2_, AuxCont, Policy, Hash, Eq, Alloc>&& that, std::false_type) {
parallel_hash_set<N, RefSet, Mtx2_, AuxCont, Policy, Hash, Eq, Alloc> tmp(std::move(that), alloc_ref());
swap(tmp);
return *this;
}
Expand Down
11 changes: 11 additions & 0 deletions tests/phmap/flat_hash_map_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@
#define THIS_EXTRA_TPL_PARAMS
#endif

#ifndef THIS_EXTRA_TPL_PARAMS_NULLMUTEX
#define THIS_EXTRA_TPL_PARAMS_NULLMUTEX
#endif

#include "gtl/phmap.hpp"

#if defined(GTL_HAVE_STD_ANY)
Expand Down Expand Up @@ -63,6 +67,13 @@ template <class K, class V, class H = gtl::priv::hash_default_hash<K>,
gtl::priv::Pair<const K, V>>>
using ThisMap = THIS_HASH_MAP<K, V, H, Eq, Alloc THIS_EXTRA_TPL_PARAMS>;


template <class K, class V, class H = gtl::priv::hash_default_hash<K>,
class Eq = gtl::priv::hash_default_eq<K>,
class Alloc = gtl::priv::Allocator<
gtl::priv::Pair<const K, V>>>
using ThisMap_NullMutex = THIS_HASH_MAP<K, V, H, Eq, Alloc THIS_EXTRA_TPL_PARAMS_NULLMUTEX>;

static_assert(!std::is_standard_layout<NonStandardLayout>(), "");

using MapTypes =
Expand Down
17 changes: 17 additions & 0 deletions tests/phmap/parallel_hash_map_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,23 @@ namespace gtl {
namespace priv {
namespace {

TEST(THIS_TEST_NAME, Swap) {
using Map = ThisMap<int, int>;
using MapB = ThisMap_NullMutex<int, int>;

Map t;
EXPECT_TRUE(t.find(0) == t.end());
auto res = t.emplace(0, 1);
EXPECT_TRUE(res.second);
EXPECT_EQ(1, t.size());
MapB u;
t.swap(u);
EXPECT_EQ(0, t.size());
EXPECT_EQ(1, u.size());
EXPECT_TRUE(t.find(0) == t.end());
EXPECT_TRUE(u[0] == 1);
}

TEST(THIS_TEST_NAME, IfContains) {
// ----------------
// test if_contains
Expand Down

0 comments on commit ba9386e

Please sign in to comment.