diff --git a/hash/doc/changes.qbk b/hash/doc/changes.qbk index c98bd86..b20e58d 100644 --- a/hash/doc/changes.qbk +++ b/hash/doc/changes.qbk @@ -142,7 +142,13 @@ [h2 Boost 1.52.0] * Restore `enum` support, which was accidentally removed in the last version. +* Add support for `boost::int128_type` and `boost::uint128_type` where + available - currently only `__int128` and `unsigned __int128` on some + versions of gcc. * New floating point hasher - will hash the binary representation on more platforms, which should be faster. +* On platforms that are known to have standard floating point, don't use the + automatic detection of floating point functions - which can break if there + are ambiguous overloads. [endsect] diff --git a/hash/test/Jamfile.v2 b/hash/test/Jamfile.v2 index 34b69e6..5325b19 100644 --- a/hash/test/Jamfile.v2 +++ b/hash/test/Jamfile.v2 @@ -12,7 +12,7 @@ project hash-tests intel:-strict-ansi gcc:"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wconversion -Wfloat-equal -Wshadow" darwin:"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wconversion -Wfloat-equal -Wshadow" - msvc:on + #msvc:on #gcc:on #darwin:on ; diff --git a/hash/test/extra/Jamfile.v2 b/hash/test/extra/Jamfile.v2 new file mode 100644 index 0000000..243c1b1 --- /dev/null +++ b/hash/test/extra/Jamfile.v2 @@ -0,0 +1,13 @@ + +# Copyright 2012 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) + +import testing ; + +build-project .. ; + +test-suite functional/hash/config + : + [ compile check_float_funcs.cpp ] + ; \ No newline at end of file diff --git a/hash/test/extra/check_float_funcs.cpp b/hash/test/extra/check_float_funcs.cpp new file mode 100644 index 0000000..01d5168 --- /dev/null +++ b/hash/test/extra/check_float_funcs.cpp @@ -0,0 +1,58 @@ + +// Copyright 2012 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 +#include +#include +#include + +namespace test +{ + template + struct check_return_type + { + template + static void equals(T2) + { + BOOST_STATIC_ASSERT((boost::is_same::value)); + } + + template + static void equals_ref(T2&) + { + BOOST_STATIC_ASSERT((boost::is_same::value)); + } + + template + static void convertible(T2) + { + BOOST_STATIC_ASSERT((boost::is_convertible::value)); + } + }; +} + +int main() { + float f = 0; + double d = 0; + long double l = 0; + + test::check_return_type::equals(std::ldexp(f, 0)); + test::check_return_type::equals(std::ldexp(d, 0)); + test::check_return_type::equals(std::ldexp(l, 0)); + + int dummy = 0; + + test::check_return_type::equals(std::frexp(f, &dummy)); + test::check_return_type::equals(std::frexp(d, &dummy)); + test::check_return_type::equals(std::frexp(l, &dummy)); + +#if BOOST_HASH_USE_FPCLASSIFY + + int (*fpc1)(float) = std::fpclassify; + int (*fpc2)(double) = std::fpclassify; + int (*fpc3)(long double) = std::fpclassify; + +#endif +} diff --git a/hash/test/hash_complex_test.cpp b/hash/test/hash_complex_test.cpp index bb1592c..36d2673 100644 --- a/hash/test/hash_complex_test.cpp +++ b/hash/test/hash_complex_test.cpp @@ -35,7 +35,7 @@ int main() {} #endif #endif -#if defined(__GNUC__) +#if defined(__GNUC__) && !defined(BOOST_INTEL_CXX_VERSION) #pragma GCC diagnostic ignored "-Wfloat-equal" #endif diff --git a/hash/test/hash_enum_test.cpp b/hash/test/hash_enum_test.cpp index 30444e5..016ea69 100644 --- a/hash/test/hash_enum_test.cpp +++ b/hash/test/hash_enum_test.cpp @@ -15,49 +15,49 @@ #include "./compile_time.hpp" namespace test { - enum enum_override { enum_override1, enum_override2 }; - std::size_t hash_value(enum_override) { return 896532; } + enum enum_override { enum_override1, enum_override2 }; + std::size_t hash_value(enum_override) { return 896532; } - enum enum1 { enum1a }; - enum enum2 { enum2a, enum2b }; - enum enum3 { enum3a = 574, enum3b }; - enum enum4 { enum4a = -12574, enum4b }; + enum enum1 { enum1a }; + enum enum2 { enum2a, enum2b }; + enum enum3 { enum3a = 574, enum3b }; + enum enum4 { enum4a = -12574, enum4b }; } int main() { - compile_time_tests((test::enum1*) 0); - compile_time_tests((test::enum2*) 0); - compile_time_tests((test::enum3*) 0); - compile_time_tests((test::enum4*) 0); - compile_time_tests((test::enum_override*) 0); + compile_time_tests((test::enum1*) 0); + compile_time_tests((test::enum2*) 0); + compile_time_tests((test::enum3*) 0); + compile_time_tests((test::enum4*) 0); + compile_time_tests((test::enum_override*) 0); - HASH_NAMESPACE::hash hash1; - HASH_NAMESPACE::hash hash2; - HASH_NAMESPACE::hash hash3; - HASH_NAMESPACE::hash hash4; - - BOOST_TEST(hash1(test::enum1a) == hash1(test::enum1a)); + HASH_NAMESPACE::hash hash1; + HASH_NAMESPACE::hash hash2; + HASH_NAMESPACE::hash hash3; + HASH_NAMESPACE::hash hash4; - BOOST_TEST(hash2(test::enum2a) == hash2(test::enum2a)); - BOOST_TEST(hash2(test::enum2a) != hash2(test::enum2b)); - BOOST_TEST(hash2(test::enum2b) == hash2(test::enum2b)); + BOOST_TEST(hash1(test::enum1a) == hash1(test::enum1a)); - BOOST_TEST(hash3(test::enum3a) == hash3(test::enum3a)); - BOOST_TEST(hash3(test::enum3a) != hash3(test::enum3b)); - BOOST_TEST(hash3(test::enum3b) == hash3(test::enum3b)); + BOOST_TEST(hash2(test::enum2a) == hash2(test::enum2a)); + BOOST_TEST(hash2(test::enum2a) != hash2(test::enum2b)); + BOOST_TEST(hash2(test::enum2b) == hash2(test::enum2b)); - BOOST_TEST(hash4(test::enum4a) == hash4(test::enum4a)); - BOOST_TEST(hash4(test::enum4a) != hash4(test::enum4b)); - BOOST_TEST(hash4(test::enum4b) == hash4(test::enum4b)); + BOOST_TEST(hash3(test::enum3a) == hash3(test::enum3a)); + BOOST_TEST(hash3(test::enum3a) != hash3(test::enum3b)); + BOOST_TEST(hash3(test::enum3b) == hash3(test::enum3b)); - HASH_NAMESPACE::hash hash_override; + BOOST_TEST(hash4(test::enum4a) == hash4(test::enum4a)); + BOOST_TEST(hash4(test::enum4a) != hash4(test::enum4b)); + BOOST_TEST(hash4(test::enum4b) == hash4(test::enum4b)); - BOOST_TEST(hash_override(test::enum_override1) == - hash_override(test::enum_override1)); - BOOST_TEST(hash_override(test::enum_override1) == - hash_override(test::enum_override2)); - BOOST_TEST(hash_override(test::enum_override1) == - hash_override(test::enum_override1)); + HASH_NAMESPACE::hash hash_override; - return boost::report_errors(); + BOOST_TEST(hash_override(test::enum_override1) == + hash_override(test::enum_override1)); + BOOST_TEST(hash_override(test::enum_override1) == + hash_override(test::enum_override2)); + BOOST_TEST(hash_override(test::enum_override1) == + hash_override(test::enum_override1)); + + return boost::report_errors(); } diff --git a/hash/test/hash_float_test.hpp b/hash/test/hash_float_test.hpp index c608915..a61d9de 100644 --- a/hash/test/hash_float_test.hpp +++ b/hash/test/hash_float_test.hpp @@ -30,7 +30,7 @@ #endif #endif -#if defined(__GNUC__) +#if defined(__GNUC__) && !defined(BOOST_INTEL_CXX_VERSION) #pragma GCC diagnostic ignored "-Wfloat-equal" #endif diff --git a/hash/test/hash_number_test.cpp b/hash/test/hash_number_test.cpp index 2645dfa..e4555e3 100644 --- a/hash/test/hash_number_test.cpp +++ b/hash/test/hash_number_test.cpp @@ -16,6 +16,7 @@ #include #include +#include #include "./compile_time.hpp" @@ -26,10 +27,34 @@ #pragma warning(disable:4310) // cast truncates constant value #endif -#if defined(__GNUC__) +#if defined(__GNUC__) && !defined(BOOST_INTEL_CXX_VERSION) #pragma GCC diagnostic ignored "-Wfloat-equal" #endif +template +void numeric_extra_tests(typename + boost::enable_if_c::is_integer, + void*>::type = 0) +{ + typedef boost::hash_detail::limits limits; + + if(limits::is_signed || + limits::digits <= boost::hash_detail::limits::digits) + { + BOOST_TEST(HASH_NAMESPACE::hash_value(T(-5)) == (std::size_t)T(-5)); + } + BOOST_TEST(HASH_NAMESPACE::hash_value(T(0)) == (std::size_t)T(0u)); + BOOST_TEST(HASH_NAMESPACE::hash_value(T(10)) == (std::size_t)T(10u)); + BOOST_TEST(HASH_NAMESPACE::hash_value(T(25)) == (std::size_t)T(25u)); +} + +template +void numeric_extra_tests(typename + boost::disable_if_c::is_integer, + void*>::type = 0) +{ +} + template void numeric_test(T*) { @@ -55,17 +80,7 @@ void numeric_test(T*) BOOST_TEST(x1(T(10)) == HASH_NAMESPACE::hash_value(T(10))); BOOST_TEST(x1(T(25)) == HASH_NAMESPACE::hash_value(T(25))); - if (limits::is_integer) - { - if(limits::is_signed || - limits::digits <= boost::hash_detail::limits::digits) - { - BOOST_TEST(HASH_NAMESPACE::hash_value(T(-5)) == (std::size_t)T(-5)); - } - BOOST_TEST(HASH_NAMESPACE::hash_value(T(0)) == (std::size_t)T(0u)); - BOOST_TEST(HASH_NAMESPACE::hash_value(T(10)) == (std::size_t)T(10u)); - BOOST_TEST(HASH_NAMESPACE::hash_value(T(25)) == (std::size_t)T(25u)); - } + numeric_extra_tests(); #endif } @@ -160,6 +175,11 @@ int main() NUMERIC_TEST_NO_LIMITS(boost::ulong_long_type, ulong_long) #endif +#if defined(BOOST_HAS_INT128) + NUMERIC_TEST_NO_LIMITS(boost::int128_type, int128) + NUMERIC_TEST_NO_LIMITS(boost::uint128_type, uint128) +#endif + NUMERIC_TEST(float, float) NUMERIC_TEST(double, double) diff --git a/include/boost/functional/hash/detail/container_fwd_0x.hpp b/include/boost/functional/hash/detail/container_fwd_0x.hpp deleted file mode 100644 index bed7730..0000000 --- a/include/boost/functional/hash/detail/container_fwd_0x.hpp +++ /dev/null @@ -1,29 +0,0 @@ - -// Copyright 2012 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) - -#if !defined(BOOST_DETAIL_CONTAINER_FWD_0X_HPP) -#define BOOST_DETAIL_CONTAINER_FWD_0X_HPP - -#include - -// std::array - -#if !defined(BOOST_NO_CXX11_HDR_ARRAY) -# include -#endif - -// std::tuple - -#if !defined(BOOST_NO_CXX11_HDR_TUPLE) -# include -#endif - -// std::shared_ptr/std::unique_ptr - -#if !defined(BOOST_NO_CXX11_HDR_MEMORY) -# include -#endif - -#endif diff --git a/include/boost/functional/hash/detail/float_functions.hpp b/include/boost/functional/hash/detail/float_functions.hpp index ae03ff0..4b8374d 100644 --- a/include/boost/functional/hash/detail/float_functions.hpp +++ b/include/boost/functional/hash/detail/float_functions.hpp @@ -13,6 +13,94 @@ # pragma once #endif +// Set BOOST_HASH_CONFORMANT_FLOATS to 1 for libraries known to have +// sufficiently good floating point support to not require any +// workarounds. +// +// When set to 0, the library tries to automatically +// use the best available implementation. This normally works well, but +// breaks when ambiguities are created by odd namespacing of the functions. +// +// Note that if this is set to 0, the library should still take full +// advantage of the platform's floating point support. + +#if defined(__SGI_STL_PORT) || defined(_STLPORT_VERSION) +# define BOOST_HASH_CONFORMANT_FLOATS 0 +#elif defined(__LIBCOMO__) +# define BOOST_HASH_CONFORMANT_FLOATS 0 +#elif defined(__STD_RWCOMPILER_H__) || defined(_RWSTD_VER) +// Rogue Wave library: +# define BOOST_HASH_CONFORMANT_FLOATS 0 +#elif defined(_LIBCPP_VERSION) +// libc++ +# define BOOST_HASH_CONFORMANT_FLOATS 1 +#elif defined(__GLIBCPP__) || defined(__GLIBCXX__) +// GNU libstdc++ 3 +# if defined(__GNUC__) && __GNUC__ >= 4 +# define BOOST_HASH_CONFORMANT_FLOATS 1 +# else +# define BOOST_HASH_CONFORMANT_FLOATS 0 +# endif +#elif defined(__STL_CONFIG_H) +// generic SGI STL +# define BOOST_HASH_CONFORMANT_FLOATS 0 +#elif defined(__MSL_CPP__) +// MSL standard lib: +# define BOOST_HASH_CONFORMANT_FLOATS 0 +#elif defined(__IBMCPP__) +// VACPP std lib (probably conformant for much earlier version). +# if __IBMCPP__ >= 1210 +# define BOOST_HASH_CONFORMANT_FLOATS 1 +# else +# define BOOST_HASH_CONFORMANT_FLOATS 0 +# endif +#elif defined(MSIPL_COMPILE_H) +// Modena C++ standard library +# define BOOST_HASH_CONFORMANT_FLOATS 0 +#elif (defined(_YVALS) && !defined(__IBMCPP__)) || defined(_CPPLIB_VER) +// Dinkumware Library (this has to appear after any possible replacement libraries): +# if _CPPLIB_VER >= 405 +# define BOOST_HASH_CONFORMANT_FLOATS 1 +# else +# define BOOST_HASH_CONFORMANT_FLOATS 0 +# endif +#else +# define BOOST_HASH_CONFORMANT_FLOATS 0 +#endif + +#if BOOST_HASH_CONFORMANT_FLOATS + +// The standard library is known to be compliant, so don't use the +// configuration mechanism. + +namespace boost { + namespace hash_detail { + template + struct call_ldexp { + typedef Float float_type; + inline Float operator()(Float x, int y) const { + return std::ldexp(x, y); + } + }; + + template + struct call_frexp { + typedef Float float_type; + inline Float operator()(Float x, int* y) const { + return std::frexp(x, y); + } + }; + + template + struct select_hash_type + { + typedef Float type; + }; + } +} + +#else // BOOST_HASH_CONFORMANT_FLOATS == 0 + // The C++ standard requires that the C float functions are overloarded // for float, double and long double in the std namespace, but some of the older // library implementations don't support this. On some that don't, the C99 @@ -243,4 +331,6 @@ namespace boost } } +#endif // BOOST_HASH_CONFORMANT_FLOATS + #endif diff --git a/include/boost/functional/hash/detail/hash_float.hpp b/include/boost/functional/hash/detail/hash_float.hpp index 3edc6ab..5e20b9c 100644 --- a/include/boost/functional/hash/detail/hash_float.hpp +++ b/include/boost/functional/hash/detail/hash_float.hpp @@ -210,8 +210,15 @@ namespace boost template inline std::size_t float_hash_value(T v) { +#if defined(fpclassify) + switch (fpclassify(v)) +#elif BOOST_HASH_CONFORMANT_FLOATS + switch (std::fpclassify(v)) +#else using namespace std; - switch (fpclassify(v)) { + switch (fpclassify(v)) +#endif + { case FP_ZERO: return 0; case FP_INFINITE: diff --git a/include/boost/functional/hash/extensions.hpp b/include/boost/functional/hash/extensions.hpp index 4358736..998c08e 100644 --- a/include/boost/functional/hash/extensions.hpp +++ b/include/boost/functional/hash/extensions.hpp @@ -14,12 +14,24 @@ #define BOOST_FUNCTIONAL_HASH_EXTENSIONS_HPP #include -#include +#include #include #include #include #include +#if !defined(BOOST_NO_CXX11_HDR_ARRAY) +# include +#endif + +#if !defined(BOOST_NO_CXX11_HDR_TUPLE) +# include +#endif + +#if !defined(BOOST_NO_CXX11_HDR_MEMORY) +# include +#endif + #if defined(_MSC_VER) && (_MSC_VER >= 1020) # pragma once #endif @@ -149,7 +161,7 @@ namespace boost } } -#if !defined(BOOST_NO_VARIADIC_TEMPLATES) +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) template inline std::size_t hash_value(std::tuple const& v) { diff --git a/include/boost/functional/hash/hash.hpp b/include/boost/functional/hash/hash.hpp index 647fd68..aa4e49f 100644 --- a/include/boost/functional/hash/hash.hpp +++ b/include/boost/functional/hash/hash.hpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #if defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) @@ -40,8 +41,8 @@ namespace boost struct enable_hash_value { typedef std::size_t type; }; template struct basic_numbers {}; - template struct long_numbers {}; - template struct ulong_numbers {}; + template struct long_numbers; + template struct ulong_numbers; template struct float_numbers {}; template <> struct basic_numbers : @@ -70,6 +71,14 @@ namespace boost boost::hash_detail::enable_hash_value {}; #endif + // long_numbers is defined like this to allow for separate + // specialization for long_long and int128_type, in case + // they conflict. + template struct long_numbers2 {}; + template struct ulong_numbers2 {}; + template struct long_numbers : long_numbers2 {}; + template struct ulong_numbers : ulong_numbers2 {}; + #if !defined(BOOST_NO_LONG_LONG) template <> struct long_numbers : boost::hash_detail::enable_hash_value {}; @@ -77,6 +86,13 @@ namespace boost boost::hash_detail::enable_hash_value {}; #endif +#if defined(BOOST_HAS_INT128) + template <> struct long_numbers2 : + boost::hash_detail::enable_hash_value {}; + template <> struct ulong_numbers2 : + boost::hash_detail::enable_hash_value {}; +#endif + template <> struct float_numbers : boost::hash_detail::enable_hash_value {}; template <> struct float_numbers : @@ -94,7 +110,7 @@ namespace boost template typename boost::enable_if, std::size_t>::type - hash_value(T); + hash_value(T); #if !BOOST_WORKAROUND(__DMC__, <= 0x848) template std::size_t hash_value(T* const&); @@ -187,9 +203,9 @@ namespace boost template typename boost::enable_if, std::size_t>::type - hash_value(T v) + hash_value(T v) { - return static_cast(v); + return static_cast(v); } // Implementation by Alberto Barbati and Dave Harris. @@ -423,6 +439,11 @@ namespace boost BOOST_HASH_SPECIALIZE(boost::ulong_long_type) #endif +#if defined(BOOST_HAS_INT128) + BOOST_HASH_SPECIALIZE(boost::int128_type) + BOOST_HASH_SPECIALIZE(boost::uint128_type) +#endif + #if !defined(BOOST_NO_CXX11_HDR_TYPEINDEX) BOOST_HASH_SPECIALIZE(std::type_index) #endif