diff --git a/include/boost/container_hash/hash/hash.hpp b/include/boost/container_hash/hash/hash.hpp index a524aa2..4b10870 100644 --- a/include/boost/container_hash/hash/hash.hpp +++ b/include/boost/container_hash/hash/hash.hpp @@ -85,6 +85,9 @@ # if !defined(BOOST_HASH_HAS_OPTIONAL) && __has_include() # define BOOST_HASH_HAS_OPTIONAL 1 # endif +# if !defined(BOOST_HASH_HAS_VARIANT) && __has_include() +# define BOOST_HASH_HAS_VARIANT 1 +# endif #endif #if !defined(BOOST_HASH_HAS_STRING_VIEW) @@ -95,6 +98,10 @@ # define BOOST_HASH_HAS_OPTIONAL 0 #endif +#if !defined(BOOST_HASH_HAS_VARIANT) +# define BOOST_HASH_HAS_VARIANT 0 +#endif + #if BOOST_HASH_HAS_STRING_VIEW # include #endif @@ -103,6 +110,10 @@ # include #endif +#if BOOST_HASH_HAS_VARIANT +# include +#endif + namespace boost { namespace hash_detail @@ -235,6 +246,12 @@ namespace boost std::size_t hash_value(std::optional const&); #endif +#if BOOST_HASH_HAS_VARIANT + std::size_t hash_value(std::monostate); + template + std::size_t hash_value(std::variant const&); +#endif + #if !defined(BOOST_NO_CXX11_HDR_TYPEINDEX) std::size_t hash_value(std::type_index); #endif @@ -499,6 +516,21 @@ namespace boost } #endif +#if BOOST_HASH_HAS_VARIANT + std::size_t hash_value(std::monostate) { + return 0x87654321; + } + + template + inline std::size_t hash_value(std::variant const& v) { + std::size_t seed = 0; + hash_combine(seed, v.index()); + std::visit([&seed](auto&& x) { hash_combine(seed, x); }, v); + return seed; + } +#endif + + #if !defined(BOOST_NO_CXX11_HDR_TYPEINDEX) inline std::size_t hash_value(std::type_index v) { @@ -631,6 +663,12 @@ namespace boost BOOST_HASH_SPECIALIZE_TEMPLATE_REF(std::optional) #endif +#if !defined(BOOST_HASH_HAS_VARIANT) + template + BOOST_HASH_SPECIALIZE_TEMPLATE_REF(std::variant) + BOOST_HASH_SPECIALIZE(std::monostate) +#endif + #if !defined(BOOST_NO_CXX11_HDR_TYPEINDEX) BOOST_HASH_SPECIALIZE(std::type_index) #endif diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 96c3b67..a9dddfb 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -44,6 +44,7 @@ test-suite container_hash/hash [ run hash_map_test.cpp ] [ run hash_complex_test.cpp ] [ run hash_optional_test.cpp ] + [ run hash_variant_test.cpp ] [ run hash_type_index_test.cpp ] [ run hash_system_error_test.cpp ] [ run hash_std_array_test.cpp ] diff --git a/test/hash_info.cpp b/test/hash_info.cpp index c7b8ec8..7159d1f 100644 --- a/test/hash_info.cpp +++ b/test/hash_info.cpp @@ -85,6 +85,10 @@ int main() { << BOOST_HASH_HAS_OPTIONAL << std::endl; + std::cout << "BOOST_HASH_HAS_VARIANT: " + << BOOST_HASH_HAS_VARIANT + << std::endl; + #if defined(BOOST_NO_CXX11_HDR_TYPEINDEX) std::cout << "No " << std::endl; #else diff --git a/test/hash_variant_test.cpp b/test/hash_variant_test.cpp new file mode 100644 index 0000000..80f317a --- /dev/null +++ b/test/hash_variant_test.cpp @@ -0,0 +1,100 @@ + +// Copyright 2018 Daniel James +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include "./config.hpp" + +#ifndef BOOST_HASH_TEST_STD_INCLUDES +# include +#endif +#include +#include + +#if BOOST_HASH_HAS_VARIANT + +#include +#include + +void test_monostate() +{ + std::monostate x1; + std::monostate x2; + + boost::hash hasher; + + BOOST_TEST(hasher(x1) == hasher(x2)); +} + +void test_variant_int() +{ + std::variant x1a; + std::variant x1b; + std::variant x2a(10); + std::variant x2b(x2a); + std::variant x3(20); + + boost::hash > hasher; + + BOOST_TEST(hasher(x1a) == hasher(x1a)); + BOOST_TEST(hasher(x1a) == hasher(x1b)); + BOOST_TEST(hasher(x1a) != hasher(x2a)); + BOOST_TEST(hasher(x1a) != hasher(x3)); + BOOST_TEST(hasher(x2a) == hasher(x2a)); + BOOST_TEST(hasher(x2b) == hasher(x2b)); + BOOST_TEST(hasher(x2a) != hasher(x3)); + BOOST_TEST(hasher(x3) == hasher(x3)); +} + +struct custom1 { + int value; + friend std::size_t hash_value(custom1 v) { return v.value; } +}; + +struct custom2 { + int value; + friend std::size_t hash_value(custom2 v) { return v.value; } +}; + +void test_variant_unique_types() +{ + custom1 x11 = { 0 }; + custom1 x12 = { 1 }; + custom2 x21 = { 0 }; + custom2 x22 = { 1 }; + + boost::hash hasher1; + boost::hash hasher2; + + BOOST_TEST(hasher1(x11) == hasher2(x21)); + BOOST_TEST(hasher1(x11) != hasher2(x22)); + BOOST_TEST(hasher1(x12) != hasher2(x21)); + BOOST_TEST(hasher1(x12) == hasher2(x22)); + + typedef std::variant variant_type; + + variant_type y11(x11); + variant_type y12(x12); + variant_type y21(x21); + variant_type y22(x22); + + boost::hash hasher; + + BOOST_TEST(hasher(y11) != hasher(y21)); + BOOST_TEST(hasher(y11) != hasher(y22)); + BOOST_TEST(hasher(y12) != hasher(y21)); + BOOST_TEST(hasher(y12) != hasher(y22)); +} + +#endif + +int main() +{ +#if BOOST_HASH_HAS_VARIANT + test_variant_int(); + test_variant_unique_types(); +#else + BOOST_LIGHTWEIGHT_TEST_OSTREAM << " not available." << std::endl; +#endif + return boost::report_errors(); +}