diff --git a/include/boost/container_hash/hash/hash.hpp b/include/boost/container_hash/hash/hash.hpp index 21296f3..c1b873e 100644 --- a/include/boost/container_hash/hash/hash.hpp +++ b/include/boost/container_hash/hash/hash.hpp @@ -58,6 +58,33 @@ # define BOOST_FUNCTIONAL_HASH_ROTL32(x, r) (x << r) | (x >> (32 - r)) #endif +// Detect whether standard library has . + +#if !defined(BOOST_HASH_HAS_STRING_VIEW) && defined(__has_include) +# if __has_include() +# if defined(BOOST_MSVC) + // On Visual C++ the header exists, but causes an + // error if it isn't in C++17 mode. +# if defined(_HAS_CXX17) && _HAS_CXX17 +# define BOOST_HASH_HAS_STRING_VIEW 1 +# include +# endif +# else +# include +# if defined(__cpp_lib_string_view) && __cpp_lib_string_view >= 201603 +# define BOOST_HASH_HAS_STRING_VIEW 1 +# endif +# endif +# endif +#endif + +#if !defined(BOOST_HASH_HAS_STRING_VIEW) +# define BOOST_HASH_HAS_STRING_VIEW 0 +#endif + +#if BOOST_HASH_HAS_STRING_VIEW +#endif + namespace boost { namespace hash_detail @@ -176,6 +203,12 @@ namespace boost std::size_t hash_value( std::basic_string, A> const&); +#if BOOST_HASH_HAS_STRING_VIEW + template + std::size_t hash_value( + std::basic_string_view > const&); +#endif + template typename boost::hash_detail::float_numbers::type hash_value(T); @@ -410,6 +443,15 @@ namespace boost return hash_range(v.begin(), v.end()); } +#if BOOST_HASH_HAS_STRING_VIEW + template + inline std::size_t hash_value( + std::basic_string_view > const& v) + { + return hash_range(v.begin(), v.end()); + } +#endif + template typename boost::hash_detail::float_numbers::type hash_value(T v) { @@ -494,6 +536,19 @@ namespace boost BOOST_HASH_SPECIALIZE_REF(std::basic_string) #endif +#if BOOST_HASH_HAS_STRING_VIEW + BOOST_HASH_SPECIALIZE_REF(std::string_view) +# if !defined(BOOST_NO_STD_WSTRING) && !defined(BOOST_NO_INTRINSIC_WCHAR_T) + BOOST_HASH_SPECIALIZE_REF(std::wstring_view) +# endif +# if !defined(BOOST_NO_CXX11_CHAR16_T) + BOOST_HASH_SPECIALIZE_REF(std::basic_string_view) +# endif +# if !defined(BOOST_NO_CXX11_CHAR32_T) + BOOST_HASH_SPECIALIZE_REF(std::basic_string_view) +# endif +#endif + #if !defined(BOOST_NO_LONG_LONG) BOOST_HASH_SPECIALIZE(boost::long_long_type) BOOST_HASH_SPECIALIZE(boost::ulong_long_type) diff --git a/test/hash_string_test.cpp b/test/hash_string_test.cpp index f84eb74..712c639 100644 --- a/test/hash_string_test.cpp +++ b/test/hash_string_test.cpp @@ -130,6 +130,37 @@ void u32string_tests() } #endif +template +void generic_string_tests(StringType*) +{ + std::string x1(1, '\0'); + std::string x2(2, '\0'); + std::string x3(3, '\0'); + std::string x4(10, '\0'); + std::string x5 = x2 + "hello" + x2; + + StringType strings[] = { + "", + "hello", + x1, + x2, + x3, + x4, + x5 + }; + + std::size_t const strings_length = sizeof(strings) / sizeof(StringType); + boost::hash hash; + + for (std::size_t i = 0; i < strings_length; ++i) { + std::size_t hash_i = hash(strings[i]); + for (std::size_t j = 0; j < strings_length; ++j) { + std::size_t hash_j = hash(strings[j]); + BOOST_TEST((hash_i == hash_j) == (i == j)); + } + } +} + int main() { string_tests(); @@ -143,5 +174,11 @@ int main() #if !defined(BOOST_NO_CXX11_CHAR32_T) u32string_tests(); #endif + + generic_string_tests((std::string*) 0); +#if BOOST_HASH_HAS_STRING_VIEW + generic_string_tests((std::string_view*) 0); +#endif + return boost::report_errors(); }