Skip to content
Open
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
29 changes: 27 additions & 2 deletions include/tl/optional.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2045,11 +2045,36 @@ template <class T> class optional<T &> {



} // namespace tl

namespace tl {
namespace detail {
// based off libc++
// SFINAE guard for std::hash<> specialization
template <class Key, class Hash>
using check_hash_requirements = std::integral_constant<
bool, std::is_copy_constructible<Hash>::value &&
std::is_move_constructible<Hash>::value &&
std::is_same<std::size_t, invoke_result_t<Hash, Key>>::value>;

template <class Key, class Hash = std::hash<Key>>
using has_enabled_hash =
std::integral_constant<bool,
check_hash_requirements<Key, Hash>::value &&
std::is_default_constructible<Hash>::value>;

template <class T, class> using enable_hash_impl = T;

template <class T, class Key>
using enable_hash =
enable_hash_impl<T, enable_if_t<has_enabled_hash<Key>::value>>;
} // namespace detail
} // namespace tl

namespace std {
// TODO SFINAE
template <class T> struct hash<tl::optional<T>> {
template <class T>
struct hash<
tl::detail::enable_hash<tl::optional<T>, tl::detail::remove_const_t<T>>> {
::std::size_t operator()(const tl::optional<T> &o) const {
if (!o.has_value())
return 0;
Expand Down
28 changes: 27 additions & 1 deletion tests/hash.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,30 @@
#include "catch.hpp"
#include <tl/optional.hpp>

TEST_CASE("Hashing", "[hash]") {}
template <typename T, typename = tl::detail::void_t<>>
struct is_hashable : std::false_type {};

template <typename T>
struct is_hashable<T, tl::detail::void_t<decltype(std::declval<std::hash<T>>()(
std::declval<T>()))>> : std::true_type {};

template <typename T> constexpr bool is_hashable_v = is_hashable<T>::value;

struct not_hashable {};

TEST_CASE("Hashing", "[hash]") {
SECTION("with value") {
tl::optional<int> op1(1);

static_assert(is_hashable_v<tl::optional<int>>,
"tl::optional<int> should be hashable");
static_assert(!is_hashable_v<tl::optional<not_hashable>>,
"tl::optional<not_hashable> should not be hashable");

REQUIRE(std::hash<int>{}(1) == std::hash<tl::optional<int>>{}(op1));
}
SECTION("nullopt") {
tl::optional<int> op1(tl::nullopt);
REQUIRE(std::hash<tl::optional<int>>{}(op1) == 0);
}
}