From ddc05d17dff6cab3edac55ddd965853242c46868 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 21 Jan 2018 18:38:35 +0000 Subject: [PATCH] std::optional support --- include/boost/container_hash/hash/hash.hpp | 34 +++++++++++ test/Jamfile.v2 | 1 + test/hash_optional_test.cpp | 70 ++++++++++++++++++++++ 3 files changed, 105 insertions(+) create mode 100644 test/hash_optional_test.cpp diff --git a/include/boost/container_hash/hash/hash.hpp b/include/boost/container_hash/hash/hash.hpp index 41cab8a..a524aa2 100644 --- a/include/boost/container_hash/hash/hash.hpp +++ b/include/boost/container_hash/hash/hash.hpp @@ -230,6 +230,11 @@ namespace boost template typename boost::hash_detail::float_numbers::type hash_value(T); +#if BOOST_HASH_HAS_OPTIONAL + template + std::size_t hash_value(std::optional const&); +#endif + #if !defined(BOOST_NO_CXX11_HDR_TYPEINDEX) std::size_t hash_value(std::type_index); #endif @@ -481,6 +486,19 @@ namespace boost return boost::hash_detail::float_hash_value(v); } +#if BOOST_HASH_HAS_OPTIONAL + template + inline std::size_t hash_value(std::optional const& v) { + if (!v) { + // Arbitray value for empty optional. + return 0x12345678; + } else { + boost::hash hf; + return hf(*v); + } + } +#endif + #if !defined(BOOST_NO_CXX11_HDR_TYPEINDEX) inline std::size_t hash_value(std::type_index v) { @@ -540,6 +558,16 @@ namespace boost } \ }; +#define BOOST_HASH_SPECIALIZE_TEMPLATE_REF(type) \ + struct hash \ + : public boost::hash_detail::hash_base \ + { \ + std::size_t operator()(type const& v) const \ + { \ + return boost::hash_value(v); \ + } \ + }; + BOOST_HASH_SPECIALIZE(bool) BOOST_HASH_SPECIALIZE(char) BOOST_HASH_SPECIALIZE(signed char) @@ -598,12 +626,18 @@ namespace boost BOOST_HASH_SPECIALIZE(boost::uint128_type) #endif +#if BOOST_HASH_HAS_OPTIONAL + template + BOOST_HASH_SPECIALIZE_TEMPLATE_REF(std::optional) +#endif + #if !defined(BOOST_NO_CXX11_HDR_TYPEINDEX) BOOST_HASH_SPECIALIZE(std::type_index) #endif #undef BOOST_HASH_SPECIALIZE #undef BOOST_HASH_SPECIALIZE_REF +#undef BOOST_HASH_SPECIALIZE_TEMPLATE_REF // Specializing boost::hash for pointers. diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 6b11b7f..96c3b67 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -43,6 +43,7 @@ test-suite container_hash/hash [ run hash_set_test.cpp ] [ run hash_map_test.cpp ] [ run hash_complex_test.cpp ] + [ run hash_optional_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_optional_test.cpp b/test/hash_optional_test.cpp new file mode 100644 index 0000000..4469395 --- /dev/null +++ b/test/hash_optional_test.cpp @@ -0,0 +1,70 @@ + +// 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_OPTIONAL + +#include +#include + +void test_optional_int() +{ + std::optional x1a; + std::optional x1b; + std::optional x2a(10); + std::optional x2b(x2a); + std::optional 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)); +} + +void test_optional_string() +{ + std::optional x1a; + std::optional x1b; + std::optional x2a("10"); + std::optional x2b(x2a); + std::optional 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)); +} + +#endif + +int main() +{ +#if BOOST_HASH_HAS_OPTIONAL + test_optional_int(); + test_optional_string(); +#else + BOOST_LIGHTWEIGHT_TEST_OSTREAM << " not available." << std::endl; +#endif + return boost::report_errors(); +}