Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable noexcept for special member functions #64

Merged
merged 3 commits into from
Sep 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions include/tsl/bhopscotch_map.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,8 @@ class bhopscotch_map {
/*
* Constructors
*/
bhopscotch_map() : bhopscotch_map(ht::DEFAULT_INIT_BUCKETS_SIZE) {}
bhopscotch_map() noexcept(std::is_nothrow_default_constructible<ht>::value)
: m_ht() {}

explicit bhopscotch_map(size_type bucket_count, const Hash& hash = Hash(),
const KeyEqual& equal = KeyEqual(),
Expand Down Expand Up @@ -414,7 +415,7 @@ class bhopscotch_map {
return m_ht.erase(key, precalculated_hash);
}

void swap(bhopscotch_map& other) { other.m_ht.swap(m_ht); }
void swap(bhopscotch_map& other) noexcept(noexcept(other.m_ht.swap(m_ht))) { other.m_ht.swap(m_ht); }

/*
* Lookup
Expand Down Expand Up @@ -785,7 +786,7 @@ class bhopscotch_map {
return !operator==(lhs, rhs);
}

friend void swap(bhopscotch_map& lhs, bhopscotch_map& rhs) { lhs.swap(rhs); }
friend void swap(bhopscotch_map& lhs, bhopscotch_map& rhs) noexcept(noexcept(lhs.swap(rhs))) { lhs.swap(rhs); }

private:
ht m_ht;
Expand Down
7 changes: 4 additions & 3 deletions include/tsl/bhopscotch_set.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,8 @@ class bhopscotch_set {
/*
* Constructors
*/
bhopscotch_set() : bhopscotch_set(ht::DEFAULT_INIT_BUCKETS_SIZE) {}
bhopscotch_set() noexcept(std::is_nothrow_default_constructible<ht>::value)
: m_ht() {}

explicit bhopscotch_set(size_type bucket_count, const Hash& hash = Hash(),
const KeyEqual& equal = KeyEqual(),
Expand Down Expand Up @@ -309,7 +310,7 @@ class bhopscotch_set {
return m_ht.erase(key, precalculated_hash);
}

void swap(bhopscotch_set& other) { other.m_ht.swap(m_ht); }
void swap(bhopscotch_set& other) noexcept(noexcept(other.m_ht.swap(m_ht))) { other.m_ht.swap(m_ht); }

/*
* Lookup
Expand Down Expand Up @@ -597,7 +598,7 @@ class bhopscotch_set {
return !operator==(lhs, rhs);
}

friend void swap(bhopscotch_set& lhs, bhopscotch_set& rhs) { lhs.swap(rhs); }
friend void swap(bhopscotch_set& lhs, bhopscotch_set& rhs) noexcept(noexcept(lhs.swap(rhs))) { lhs.swap(rhs); }

private:
ht m_ht;
Expand Down
13 changes: 13 additions & 0 deletions include/tsl/hopscotch_growth_policy.h
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,19 @@ class prime_growth_policy {
"The type of m_iprime is not big enough.");
};

/**
* SFINAE helper to detect growth policies which can be noexcept-initialized
* with a zero min bucket count.
*/
template<typename>
struct is_noexcept_on_zero_init : std::false_type {};
template<std::size_t GrowthFactor>
struct is_noexcept_on_zero_init<power_of_two_growth_policy<GrowthFactor>> : std::true_type {};
template<class GrowthFactor>
struct is_noexcept_on_zero_init<mod_growth_policy<GrowthFactor>> : std::true_type {};
template<>
struct is_noexcept_on_zero_init<prime_growth_policy> : std::true_type {};

} // namespace hh
} // namespace tsl

Expand Down
30 changes: 28 additions & 2 deletions include/tsl/hopscotch_hash.h
Original file line number Diff line number Diff line change
Expand Up @@ -593,6 +593,17 @@ class hopscotch_hash : private Hash, private KeyEqual, private GrowthPolicy {
};

public:
template <
class OC = OverflowContainer,
typename std::enable_if<!has_key_compare<OC>::value>::type* = nullptr>
hopscotch_hash() noexcept(DEFAULT_INIT_BUCKETS_SIZE == 0 &&
std::is_nothrow_default_constructible<Hash>::value &&
std::is_nothrow_default_constructible<KeyEqual>::value &&
std::is_nothrow_default_constructible<Allocator>::value &&
(std::is_nothrow_constructible<GrowthPolicy, std::size_t&>::value ||
hh::is_noexcept_on_zero_init<GrowthPolicy>::value))
: hopscotch_hash(DEFAULT_INIT_BUCKETS_SIZE, Hash(), KeyEqual(), Allocator(), DEFAULT_MAX_LOAD_FACTOR) {}

template <
class OC = OverflowContainer,
typename std::enable_if<!has_key_compare<OC>::value>::type* = nullptr>
Expand Down Expand Up @@ -630,6 +641,17 @@ class hopscotch_hash : private Hash, private KeyEqual, private GrowthPolicy {
"move constructible.");
}

template <
class OC = OverflowContainer,
typename std::enable_if<has_key_compare<OC>::value>::type* = nullptr>
hopscotch_hash() noexcept(DEFAULT_INIT_BUCKETS_SIZE == 0 &&
std::is_nothrow_default_constructible<Hash>::value &&
std::is_nothrow_default_constructible<KeyEqual>::value &&
std::is_nothrow_default_constructible<Allocator>::value &&
(std::is_nothrow_constructible<GrowthPolicy, std::size_t&>::value ||
hh::is_noexcept_on_zero_init<GrowthPolicy>::value))
: hopscotch_hash(DEFAULT_INIT_BUCKETS_SIZE, Hash(), KeyEqual(), Allocator(), DEFAULT_MAX_LOAD_FACTOR, typename OC::key_compare()) {}

template <
class OC = OverflowContainer,
typename std::enable_if<has_key_compare<OC>::value>::type* = nullptr>
Expand Down Expand Up @@ -730,7 +752,7 @@ class hopscotch_hash : private Hash, private KeyEqual, private GrowthPolicy {
return *this;
}

hopscotch_hash& operator=(hopscotch_hash&& other) {
hopscotch_hash& operator=(hopscotch_hash&& other) noexcept(noexcept(other.swap(*this))) {
other.swap(*this);
other.clear();

Expand Down Expand Up @@ -1035,7 +1057,11 @@ class hopscotch_hash : private Hash, private KeyEqual, private GrowthPolicy {
return 0;
}

void swap(hopscotch_hash& other) {
void swap(hopscotch_hash& other) noexcept(std::is_nothrow_swappable<Hash>::value &&
std::is_nothrow_swappable<KeyEqual>::value &&
std::is_nothrow_swappable<GrowthPolicy>::value &&
std::is_nothrow_swappable<buckets_container_type>::value &&
std::is_nothrow_swappable<overflow_container_type>::value) {
using std::swap;

swap(static_cast<Hash&>(*this), static_cast<Hash&>(other));
Expand Down
7 changes: 4 additions & 3 deletions include/tsl/hopscotch_map.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,8 @@ class hopscotch_map {
/*
* Constructors
*/
hopscotch_map() : hopscotch_map(ht::DEFAULT_INIT_BUCKETS_SIZE) {}
hopscotch_map() noexcept(std::is_nothrow_default_constructible<ht>::value)
: m_ht() {}

explicit hopscotch_map(size_type bucket_count, const Hash& hash = Hash(),
const KeyEqual& equal = KeyEqual(),
Expand Down Expand Up @@ -424,7 +425,7 @@ class hopscotch_map {
return m_ht.erase(key, precalculated_hash);
}

void swap(hopscotch_map& other) { other.m_ht.swap(m_ht); }
void swap(hopscotch_map& other) noexcept(noexcept(other.m_ht.swap(m_ht))) { other.m_ht.swap(m_ht); }

/*
* Lookup
Expand Down Expand Up @@ -783,7 +784,7 @@ class hopscotch_map {
return !operator==(lhs, rhs);
}

friend void swap(hopscotch_map& lhs, hopscotch_map& rhs) { lhs.swap(rhs); }
friend void swap(hopscotch_map& lhs, hopscotch_map& rhs) noexcept(noexcept(lhs.swap(rhs))) { lhs.swap(rhs); }

private:
ht m_ht;
Expand Down
7 changes: 4 additions & 3 deletions include/tsl/hopscotch_set.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,8 @@ class hopscotch_set {
/*
* Constructors
*/
hopscotch_set() : hopscotch_set(ht::DEFAULT_INIT_BUCKETS_SIZE) {}
hopscotch_set() noexcept(std::is_nothrow_default_constructible<ht>::value)
: m_ht() {}

explicit hopscotch_set(size_type bucket_count, const Hash& hash = Hash(),
const KeyEqual& equal = KeyEqual(),
Expand Down Expand Up @@ -323,7 +324,7 @@ class hopscotch_set {
return m_ht.erase(key, precalculated_hash);
}

void swap(hopscotch_set& other) { other.m_ht.swap(m_ht); }
void swap(hopscotch_set& other) noexcept(noexcept(other.m_ht.swap(m_ht))) { other.m_ht.swap(m_ht); }

/*
* Lookup
Expand Down Expand Up @@ -600,7 +601,7 @@ class hopscotch_set {
return !operator==(lhs, rhs);
}

friend void swap(hopscotch_set& lhs, hopscotch_set& rhs) { lhs.swap(rhs); }
friend void swap(hopscotch_set& lhs, hopscotch_set& rhs) noexcept(noexcept(lhs.swap(rhs))) { lhs.swap(rhs); }

private:
ht m_ht;
Expand Down
7 changes: 7 additions & 0 deletions tests/hopscotch_map_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1510,4 +1510,11 @@ BOOST_AUTO_TEST_CASE(test_precalculated_hash) {
BOOST_CHECK_EQUAL(map.erase(4, map.hash_function()(2)), 0);
}

BOOST_AUTO_TEST_CASE_TEMPLATE(test_noexcept, HSet, test_types) {
static_assert(std::is_nothrow_default_constructible<HSet>::value, "");
static_assert(std::is_nothrow_move_constructible<HSet>::value, "");
static_assert(std::is_nothrow_move_assignable<HSet>::value, "");
static_assert(std::is_nothrow_swappable<HSet>::value, "");
}

BOOST_AUTO_TEST_SUITE_END()
7 changes: 7 additions & 0 deletions tests/hopscotch_set_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -163,4 +163,11 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_insert_transparent_hint, HSet,
BOOST_CHECK_EQUAL(*otherIt, 2);
}

BOOST_AUTO_TEST_CASE_TEMPLATE(test_noexcept, HSet, test_types) {
static_assert(std::is_nothrow_default_constructible<HSet>::value, "");
static_assert(std::is_nothrow_move_constructible<HSet>::value, "");
static_assert(std::is_nothrow_move_assignable<HSet>::value, "");
static_assert(std::is_nothrow_swappable<HSet>::value, "");
}

BOOST_AUTO_TEST_SUITE_END()
Loading