Skip to content

Commit

Permalink
Merge pull request #69 from steve-downey/hash
Browse files Browse the repository at this point in the history
Implement std::hash for beman::optional
  • Loading branch information
steve-downey authored Oct 16, 2024
2 parents 105f209 + b2e6f6c commit 863a89c
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 11 deletions.
17 changes: 17 additions & 0 deletions include/beman/optional26/optional.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1147,4 +1147,21 @@ class optional<T&> {

} // namespace beman::optional26

namespace std {
template <typename T>
requires requires(T a) {
{ std::hash<remove_const_t<T>>{}(a) } -> std::convertible_to<std::size_t>;
}
struct hash<beman::optional26::optional<T>> {
static_assert(!is_reference_v<T>, "hash is not enabled for reference types");
size_t operator()(const beman::optional26::optional<T>& o) const
noexcept(noexcept(hash<remove_const_t<T>>{}(*o))) {
if (o) {
return std::hash<std::remove_const_t<T>>{}(*o);
} else {
return 0;
}
}
};
} // namespace std
#endif // BEMAN_OPTIONAL26_OPTIONAL_HPP
45 changes: 34 additions & 11 deletions src/beman/optional26/tests/optional.t.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <functional>
#include <ranges>
#include <tuple>
#include <algorithm>

#include <gtest/gtest.h>

Expand Down Expand Up @@ -596,7 +597,7 @@ TEST(OptionalTest, RangeTest) {
}
}

TEST(ViewMaybeTest, Constructors) {
TEST(OptionalTest, RangeConstructors) {
std::ranges::single_view<std::optional<int>> s;
std::ranges::single_view<std::optional<int>> s2{s};
std::ranges::single_view<std::optional<int>> s3{std::optional<int>{}};
Expand All @@ -610,7 +611,7 @@ TEST(ViewMaybeTest, Constructors) {
std::ignore = n3;
}

TEST(ViewMaybeTest, ConceptCheckRef) {
TEST(OptionalTest, ConceptCheckRef) {
static_assert(std::ranges::range<beman::optional26::optional<int&>>);
static_assert(std::ranges::view<beman::optional26::optional<int&>>);
static_assert(std::ranges::input_range<beman::optional26::optional<int&>>);
Expand Down Expand Up @@ -646,7 +647,7 @@ TEST(ViewMaybeTest, ConceptCheckRef) {
static_assert(std::ranges::random_access_range<beman::optional26::optional<ref>>);
}

TEST(ViewMaybeTest, BreathingTest) {
TEST(OptionalTest, BreathingTest) {
beman::optional26::optional<int> m;
beman::optional26::optional<int> m1{1};

Expand All @@ -664,7 +665,7 @@ TEST(ViewMaybeTest, BreathingTest) {
ASSERT_EQ(*std::begin(d0), 1.0);
}

TEST(ViewMaybeTest, BreathingTestRef) {
TEST(OptionalTest, BreathingTestRef) {
beman::optional26::optional<int&> m;

int one = 1;
Expand All @@ -683,7 +684,7 @@ TEST(ViewMaybeTest, BreathingTestRef) {
ASSERT_EQ(*std::begin(d0), 1.0);
}

TEST(ViewMaybe, CompTest) {
TEST(OptionalTest, CompTest) {
beman::optional26::optional<int> m;
beman::optional26::optional<int> m0{0};
beman::optional26::optional<int> m1{1};
Expand All @@ -703,7 +704,7 @@ TEST(ViewMaybe, CompTest) {
ASSERT_TRUE(m1 <= m1a);
}

TEST(ViewMaybe, CompTestRef) {
TEST(OptionalTest, CompTestRef) {
beman::optional26::optional<int&> m;
int zero = 0;
int one = 1;
Expand Down Expand Up @@ -743,7 +744,7 @@ inline constexpr auto yield_if = []<class T>(bool b, T x) {
return b ? beman::optional26::optional<T>{std::move(x)} : beman::optional26::nullopt;
};

TEST(ViewMaybeTest, PythTripleTest) {
TEST(OptionalTest, PythTripleTest) {
using std::views::iota;
auto triples = and_then(iota(1), [](int z) {
return and_then(iota(1, z + 1), [=](int x) {
Expand All @@ -757,7 +758,7 @@ TEST(ViewMaybeTest, PythTripleTest) {

using namespace beman;

TEST(ViewMaybeTest, ValueBase) {
TEST(OptionalTest, ValueBase) {
int i = 7;
beman::optional26::optional<int> v1{};

Expand All @@ -769,7 +770,7 @@ TEST(ViewMaybeTest, ValueBase) {
ASSERT_EQ(i, 7);
}

TEST(ViewMaybeTest, RefWrapper) {
TEST(OptionalTest, RefWrapper) {
int i = 7;

beman::optional26::optional<int> v2{std::ref(i)};
Expand All @@ -778,7 +779,7 @@ TEST(ViewMaybeTest, RefWrapper) {
ASSERT_EQ(i, 7);
}

TEST(ViewMaybeTest, ValueNonDefaultConstruct) {
TEST(OptionalTest, ValueNonDefaultConstruct) {
using beman::optional26::tests::int_ctor;
int_ctor i = 7;
beman::optional26::optional<int_ctor> v1{};
Expand All @@ -787,7 +788,7 @@ TEST(ViewMaybeTest, ValueNonDefaultConstruct) {
std::ignore = v2;
}

TEST(ViewMaybeTest, RefBase) {
TEST(OptionalTest, RefBase) {
int i = 7;
beman::optional26::optional<int&> v1{};
// ASSERT_TRUE(v1.size() == 0);
Expand Down Expand Up @@ -820,3 +821,25 @@ TEST(ViewMaybeTest, RefBase) {
}
ASSERT_EQ(s, 9);
}

TEST(OptionalTest, HashTest) {
beman::optional26::optional<int> o1 = beman::optional26::nullopt;
beman::optional26::optional<int> o2 = beman::optional26::nullopt;
beman::optional26::optional<int> o3 = 42;
beman::optional26::optional<int> o4 = 42;

auto h1 = std::hash<beman::optional26::optional<int>>{}(o1);
auto h2 = std::hash<beman::optional26::optional<int>>{}(o2);
auto h3 = std::hash<beman::optional26::optional<int>>{}(o3);
auto h4 = std::hash<beman::optional26::optional<int>>{}(o4);

EXPECT_EQ(h1, h2);
EXPECT_EQ(h3, h4);
EXPECT_NE(h1, h3);

for(int i : std::views::iota(0, 1000)) {
auto h1 = std::hash<beman::optional26::optional<int>>{}(i);
auto h2 = std::hash<int>{}(i);
EXPECT_EQ(h1, h2);
}
}

0 comments on commit 863a89c

Please sign in to comment.