diff --git a/hash/test/Jamfile.v2 b/hash/test/Jamfile.v2 index ff149a7..ea19365 100644 --- a/hash/test/Jamfile.v2 +++ b/hash/test/Jamfile.v2 @@ -36,10 +36,23 @@ test-suite functional/hash [ run hash_complex_test.cpp ] [ run link_test.cpp link_test_2.cpp ] [ run link_ext_test.cpp link_no_ext_test.cpp ] + [ run extensions_hpp_test.cpp ] [ run container_fwd_test.cpp ] [ compile-fail hash_no_ext_fail_test.cpp ] + [ compile-fail namespace_fail_test.cpp ] [ run hash_no_ext_macro_1.cpp ] [ run hash_no_ext_macro_2.cpp ] ; +test-suite functional/hash_no_ext + : + [ run hash_number_test.cpp : : : BOOST_HASH_NO_EXTENSIONS : no_ext_number_test ] + [ run hash_pointer_test.cpp : : : BOOST_HASH_NO_EXTENSIONS : no_ext_pointer_test ] + [ run hash_function_pointer_test.cpp : : : BOOST_HASH_NO_EXTENSIONS : no_ext_function_pointer_test ] + [ run hash_float_test.cpp : : : BOOST_HASH_NO_EXTENSIONS : no_ext_float_test ] + [ run hash_long_double_test.cpp : : : BOOST_HASH_NO_EXTENSIONS : no_ext_long_double_test ] + [ run hash_string_test.cpp : : : BOOST_HASH_NO_EXTENSIONS : no_ext_string_test ] + [ run link_test.cpp link_test_2.cpp : : : BOOST_HASH_NO_EXTENSIONS : no_ext_link_test ] + ; + build-project ../examples ; diff --git a/hash/test/config.hpp b/hash/test/config.hpp index 0f84cc7..1fd0f5f 100644 --- a/hash/test/config.hpp +++ b/hash/test/config.hpp @@ -5,7 +5,7 @@ #if defined(TEST_STD) # define TEST_STD_INCLUDES -# define HASH_NAMESPACE std::tr1 +# define HASH_NAMESPACE std #else # define HASH_NAMESPACE boost # if !defined(BOOST_HASH_NO_EXTENSIONS) diff --git a/hash/test/extensions_hpp_test.cpp b/hash/test/extensions_hpp_test.cpp new file mode 100644 index 0000000..182ec01 --- /dev/null +++ b/hash/test/extensions_hpp_test.cpp @@ -0,0 +1,17 @@ + +// Copyright 2009 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) + +// Check that boost/functional/hash/extensions.hpp works okay. +// +// It probably should be in boost/functional/hash/detail, but since it isn't it +// should work. + +#include + +int main() { + int x[2] = { 2, 3 }; + boost::hash hf; + hf(x); +} diff --git a/hash/test/hash_complex_test.cpp b/hash/test/hash_complex_test.cpp index dd519c9..f791391 100644 --- a/hash/test/hash_complex_test.cpp +++ b/hash/test/hash_complex_test.cpp @@ -5,18 +5,20 @@ #include "./config.hpp" -#ifdef TEST_EXTENSIONS -# ifdef TEST_STD_INCLUDES -# include -# else -# include -# endif +#if !defined(TEST_EXTENSIONS) + +int main() {} + +#else + +#ifdef TEST_STD_INCLUDES +# include +#else +# include #endif #include -#ifdef TEST_EXTENSIONS - #include #include #include @@ -27,11 +29,6 @@ #pragma warning(disable:4512) // assignment operator could not be generated #endif -#include -#include -#include -#include - #if defined(BOOST_MSVC) #pragma warning(pop) #endif @@ -61,33 +58,24 @@ void generic_complex_tests(std::complex v) template void complex_float_tests(Float*) { - boost::mt19937 rng; - boost::uniform_real uniform; - boost::variate_generator > - uniform_generator(rng, uniform); - - for(int i = 0; i < 100; ++i) - { - std::complex v(uniform_generator(), uniform_generator()); - generic_complex_tests(v); - } + typedef std::complex complex; + generic_complex_tests(complex(0,0)); + generic_complex_tests(complex(0.5,0)); + generic_complex_tests(complex(25,0)); + generic_complex_tests(complex(25,0)); + generic_complex_tests(complex(-67.5324535,56.23578678)); } template void complex_integral_tests(Integer*) { - boost::mt19937 rng; - boost::uniform_int uniform( - (std::numeric_limits::min)(), - (std::numeric_limits::max)()); - boost::variate_generator > - uniform_generator(rng, uniform); - - for(int i = 0; i < 100; ++i) - { - std::complexv(uniform_generator(), uniform_generator()); - generic_complex_tests(v); - } + typedef std::complex complex; + generic_complex_tests(complex(0,0)); + generic_complex_tests(complex(15342,124)); + generic_complex_tests(complex(25,54356)); + generic_complex_tests(complex(5325,2346)); + generic_complex_tests(complex(-243897,-49923874)); + generic_complex_tests(complex(-543,763)); } int main() @@ -105,4 +93,4 @@ int main() return boost::report_errors(); } -#endif +#endif // TEST_EXTENSIONS diff --git a/hash/test/hash_float_test.hpp b/hash/test/hash_float_test.hpp index 77c652c..b1c19fc 100644 --- a/hash/test/hash_float_test.hpp +++ b/hash/test/hash_float_test.hpp @@ -15,6 +15,8 @@ #include #include +#include +#include #include @@ -42,8 +44,6 @@ void float_tests(char const* name, T* = 0) <<"\n" <<"boost::hash_detail::call_ldexp::float_type = " <::float_type*)0)<<"\n" - <<"boost::call_frexp::float_type = " - <::float_type*)0)<<"\n" <<"boost::hash_detail::call_frexp::float_type = " <::float_type*)0)<<"\n" <<"boost::hash_detail::select_hash_type::type = " @@ -59,8 +59,10 @@ void float_tests(char const* name, T* = 0) BOOST_TEST(zero == minus_zero); BOOST_TEST(x1(zero) == x1(minus_zero)); +#if defined(TEST_EXTENSIONS) BOOST_TEST(x1(zero) == HASH_NAMESPACE::hash_value(zero)); BOOST_TEST(x1(minus_zero) == HASH_NAMESPACE::hash_value(minus_zero)); +#endif using namespace std; @@ -78,9 +80,11 @@ void float_tests(char const* name, T* = 0) T minus_infinity2 = (T) -1. / zero; T minus_infinity3 = (T) 1. / minus_zero; +#if defined(TEST_EXTENSIONS) BOOST_TEST(x1(infinity) == HASH_NAMESPACE::hash_value(infinity)); BOOST_TEST(x1(minus_infinity) == HASH_NAMESPACE::hash_value(minus_infinity)); +#endif if(infinity == infinity2) BOOST_TEST(x1(infinity) == x1(infinity2)); @@ -134,10 +138,12 @@ void float_tests(char const* name, T* = 0) BOOST_TEST(half_max != three_quarter_max); BOOST_TEST(quarter_max != three_quarter_max); +#if defined(TEST_EXTENSIONS) BOOST_TEST(x1(max) == HASH_NAMESPACE::hash_value(max)); BOOST_TEST(x1(half_max) == HASH_NAMESPACE::hash_value(half_max)); BOOST_TEST(x1(quarter_max) == HASH_NAMESPACE::hash_value(quarter_max)); BOOST_TEST(x1(three_quarter_max) == HASH_NAMESPACE::hash_value(three_quarter_max)); +#endif // The '!=' tests could legitimately fail, but with my hash it indicates a bug. BOOST_TEST(x1(max) == x1(max)); @@ -159,12 +165,18 @@ void float_tests(char const* name, T* = 0) T v2 = acos((T) 0); if(v1 == v2) BOOST_TEST(x1(v1) == x1(v2)); + +#if defined(TEST_EXTENSIONS) BOOST_TEST(x1(v1) == HASH_NAMESPACE::hash_value(v1)); BOOST_TEST(x1(v2) == HASH_NAMESPACE::hash_value(v2)); #endif + +#endif +#if defined(TEST_EXTENSIONS) BOOST_TEST(x1(boost::hash_detail::limits::epsilon()) == HASH_NAMESPACE::hash_value(boost::hash_detail::limits::epsilon())); +#endif BOOST_TEST(boost::hash_detail::limits::epsilon() != (T) 0); if(x1(boost::hash_detail::limits::epsilon()) == x1((T) 0)) @@ -195,7 +207,7 @@ void float_tests(char const* name, T* = 0) if(x1(boost::hash_detail::limits::denorm_min()) == x1(zero)) { std::cerr<<"x1(denorm_min) == x1(zero) == "<::has_quiet_NaN) { if(x1(boost::hash_detail::limits::quiet_NaN()) == x1(1.0)) { std::cerr<<"x1(quiet_NaN) == x1(1.0) == "< template void unused(T const&) {} @@ -30,10 +35,11 @@ void fwd_test() unused(y1); unused(y2); unused(y3); } - int main() { fwd_test(); + return boost::report_errors(); } +#endif // defined(TEST_EXTENSIONS) && !defined(TEST_STD_INCLUDES) diff --git a/hash/test/hash_no_ext_macro_1.cpp b/hash/test/hash_no_ext_macro_1.cpp index 640c36a..1d238c0 100644 --- a/hash/test/hash_no_ext_macro_1.cpp +++ b/hash/test/hash_no_ext_macro_1.cpp @@ -4,9 +4,17 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #define HASH_NAMESPACE boost + +// Include header without BOOST_HASH_NO_EXTENSIONS defined +#if defined(BOOST_HASH_NO_EXTENSIONS) +#undef BOOST_HASH_NO_EXTENSIONS +#endif #include + +// Include header with BOOST_HASH_NO_EXTENSIONS defined #define BOOST_HASH_NO_EXTENSIONS #include + #include #include #include diff --git a/hash/test/hash_no_ext_macro_2.cpp b/hash/test/hash_no_ext_macro_2.cpp index 2f53779..6ab083e 100644 --- a/hash/test/hash_no_ext_macro_2.cpp +++ b/hash/test/hash_no_ext_macro_2.cpp @@ -4,10 +4,17 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #define HASH_NAMESPACE boost + +// Include header with BOOST_HASH_NO_EXTENSIONS defined +#if !defined(BOOST_HASH_NO_EXTENSIONS) #define BOOST_HASH_NO_EXTENSIONS +#endif #include + +// Include header without BOOST_HASH_NO_EXTENSIONS defined #undef BOOST_HASH_NO_EXTENSIONS #include + #include #include diff --git a/hash/test/hash_range_test.cpp b/hash/test/hash_range_test.cpp index 66aad26..7d71f45 100644 --- a/hash/test/hash_range_test.cpp +++ b/hash/test/hash_range_test.cpp @@ -5,18 +5,20 @@ #include "./config.hpp" -#ifdef TEST_EXTENSIONS -# ifdef TEST_STD_INCLUDES -# include -# else -# include -# endif +#if !defined(TEST_EXTENSIONS) + +int main() {} + +#else + +#ifdef TEST_STD_INCLUDES +# include +#else +# include #endif #include -#ifdef TEST_EXTENSIONS - #include #include #include @@ -74,8 +76,6 @@ void hash_range_tests() BOOST_TEST(seed == HASH_NAMESPACE::hash_range(values5.begin(), values5.end())); } -#endif - int main() { hash_range_tests(); @@ -83,3 +83,4 @@ int main() return boost::report_errors(); } +#endif // TEST_EXTESNIONS diff --git a/hash/test/link_ext_test.cpp b/hash/test/link_ext_test.cpp index ca4c8f3..d334035 100644 --- a/hash/test/link_ext_test.cpp +++ b/hash/test/link_ext_test.cpp @@ -9,14 +9,23 @@ #include int f(std::size_t hash1, int* x1) { + // Check that HASH_NAMESPACE::hash works in both files. HASH_NAMESPACE::hash ptr_hasher; BOOST_TEST(hash1 == ptr_hasher(x1)); +#if defined(TEST_EXTENSIONS) + // Check that std::vector is avaiable in this file. std::vector x; x.push_back(*x1); HASH_NAMESPACE::hash > vector_hasher; return vector_hasher(x) != HASH_NAMESPACE::hash_value(x); + +#else + + return 0; + +#endif } diff --git a/hash/test/namespace_fail_test.cpp b/hash/test/namespace_fail_test.cpp new file mode 100644 index 0000000..d3c13aa --- /dev/null +++ b/hash/test/namespace_fail_test.cpp @@ -0,0 +1,14 @@ + +// Copyright 2009 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) + +// Check that I haven't inadvertantly pulled namespace std into the global +// namespace. + +#include +#include + +typedef list foo; + +int main() {} \ No newline at end of file diff --git a/include/boost/functional/hash/detail/float_functions.hpp b/include/boost/functional/hash/detail/float_functions.hpp index 60dbb2a..01cac09 100644 --- a/include/boost/functional/hash/detail/float_functions.hpp +++ b/include/boost/functional/hash/detail/float_functions.hpp @@ -96,10 +96,16 @@ namespace BOOST_HASH_DETECT_FLOAT_FUNCTIONS { // Then the call_* functions select an appropriate implementation. // // I used c99_func in a few places just to get a unique name. +// +// Important: when using 'using namespace' at namespace level, include as +// little as possible in that namespace, as Visual C++ has an odd bug which +// can cause the namespace to be imported at the global level. This seems to +// happen mainly when there's a template in the same namesapce. #define BOOST_HASH_CALL_FLOAT_FUNC(cpp_func, c99_func, type1, type2) \ namespace BOOST_HASH_DETECT_FLOAT_FUNCTIONS { \ - boost::hash_detail::not_found c99_func(int, type2); \ + template \ + boost::hash_detail::not_found c99_func(Float, type2); \ } \ \ namespace boost { \ @@ -117,44 +123,46 @@ namespace boost { \ BOOST_STATIC_CONSTANT(bool, c99 = \ sizeof(float_type(c99_func(x,y))) \ == sizeof(is)); \ - }; \ - \ - template \ - struct call_c99 : \ - boost::hash_detail::call_##cpp_func {}; \ - \ - template <> \ - struct call_c99 { \ - typedef type1 float_type; \ - \ - template \ - inline type1 operator()(type1 a, T b) const \ - { \ - return c99_func(a, b); \ - } \ - }; \ - \ - template \ - struct call_cpp : \ - call_c99< \ - ::boost::hash_detail::c99_func##_detect::check::c99 \ - > {}; \ - \ - template <> \ - struct call_cpp { \ - typedef type1 float_type; \ - \ - template \ - inline type1 operator()(type1 a, T b) const \ - { \ - return cpp_func(a, b); \ - } \ }; \ } \ \ + template \ + struct call_c99_##c99_func : \ + boost::hash_detail::call_##cpp_func {}; \ + \ + template <> \ + struct call_c99_##c99_func { \ + typedef type1 float_type; \ + \ + template \ + inline type1 operator()(type1 a, T b) const \ + { \ + using namespace std; \ + return c99_func(a, b); \ + } \ + }; \ + \ + template \ + struct call_cpp_##c99_func : \ + call_c99_##c99_func< \ + ::boost::hash_detail::c99_func##_detect::check::c99 \ + > {}; \ + \ + template <> \ + struct call_cpp_##c99_func { \ + typedef type1 float_type; \ + \ + template \ + inline type1 operator()(type1 a, T b) const \ + { \ + using namespace std; \ + return cpp_func(a, b); \ + } \ + }; \ + \ template <> \ struct call_##cpp_func : \ - c99_func##_detect::call_cpp< \ + call_cpp_##c99_func< \ ::boost::hash_detail::c99_func##_detect::check::cpp \ > {}; \ } \ diff --git a/include/boost/functional/hash/extensions.hpp b/include/boost/functional/hash/extensions.hpp index d173314..3c587a3 100644 --- a/include/boost/functional/hash/extensions.hpp +++ b/include/boost/functional/hash/extensions.hpp @@ -7,15 +7,114 @@ // http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2005/n1756.pdf // issue 6.18. +// This implements the extensions to the standard. +// It's undocumented, so you shouldn't use it.... + #if !defined(BOOST_FUNCTIONAL_HASH_EXTENSIONS_HPP) #define BOOST_FUNCTIONAL_HASH_EXTENSIONS_HPP +#include +#include + #if defined(_MSC_VER) && (_MSC_VER >= 1020) # pragma once #endif +#if defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) +#include +#endif + +#if BOOST_WORKAROUND(BOOST_MSVC, < 1300) +#include +#endif + namespace boost { + template + std::size_t hash_value(std::pair const&); + template + std::size_t hash_value(std::vector const&); + template + std::size_t hash_value(std::list const& v); + template + std::size_t hash_value(std::deque const& v); + template + std::size_t hash_value(std::set const& v); + template + std::size_t hash_value(std::multiset const& v); + template + std::size_t hash_value(std::map const& v); + template + std::size_t hash_value(std::multimap const& v); + + template + std::size_t hash_value(std::complex const&); + + template + std::size_t hash_value(std::pair const& v) + { + std::size_t seed = 0; + hash_combine(seed, v.first); + hash_combine(seed, v.second); + return seed; + } + + template + std::size_t hash_value(std::vector const& v) + { + return hash_range(v.begin(), v.end()); + } + + template + std::size_t hash_value(std::list const& v) + { + return hash_range(v.begin(), v.end()); + } + + template + std::size_t hash_value(std::deque const& v) + { + return hash_range(v.begin(), v.end()); + } + + template + std::size_t hash_value(std::set const& v) + { + return hash_range(v.begin(), v.end()); + } + + template + std::size_t hash_value(std::multiset const& v) + { + return hash_range(v.begin(), v.end()); + } + + template + std::size_t hash_value(std::map const& v) + { + return hash_range(v.begin(), v.end()); + } + + template + std::size_t hash_value(std::multimap const& v) + { + return hash_range(v.begin(), v.end()); + } + + template + std::size_t hash_value(std::complex const& v) + { + boost::hash hasher; + std::size_t seed = hasher(v.imag()); + seed ^= hasher(v.real()) + (seed<<6) + (seed>>2); + return seed; + } + + // + // call_hash_impl + // + + // On compilers without function template ordering, this deals with arrays. #if defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) namespace hash_detail @@ -61,6 +160,11 @@ namespace boost } #endif // BOOST_NO_FUNCTION_TEMPLATE_ORDERING + // + // boost::hash + // + + #if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) template struct hash @@ -94,7 +198,7 @@ namespace boost // On compilers without partial specialization, boost::hash // has already been declared to deal with pointers, so just - // need to supply the non-pointer version. + // need to supply the non-pointer version of hash_impl. namespace hash_detail { @@ -126,8 +230,8 @@ namespace boost #else // Visual C++ 6.5 - // There's probably a more elegant way to Visual C++ 6.5 to work - // but I don't know what it is. + // Visual C++ 6.5 has problems with nested member functions and + // applying const to const types in templates. So we get this: template struct hash_impl_msvc diff --git a/include/boost/functional/hash/hash.hpp b/include/boost/functional/hash/hash.hpp index 12283ff..89196bc 100644 --- a/include/boost/functional/hash/hash.hpp +++ b/include/boost/functional/hash/hash.hpp @@ -13,7 +13,6 @@ #include #include #include -#include #include #include @@ -21,12 +20,10 @@ #include #endif -#if defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) -#include -#endif - -#if BOOST_WORKAROUND(BOOST_MSVC, < 1300) -#include +#if BOOST_WORKAROUND(__GNUC__, < 3) && !defined(__SGI_STL_PORT) && !defined(_STLPORT_VERSION) +#define BOOST_HASH_CHAR_TRAITS string_char_traits +#else +#define BOOST_HASH_CHAR_TRAITS char_traits #endif namespace boost @@ -72,26 +69,6 @@ namespace boost template std::size_t hash_value(std::basic_string, A> const&); - template - std::size_t hash_value(std::pair const&); - template - std::size_t hash_value(std::vector const&); - template - std::size_t hash_value(std::list const& v); - template - std::size_t hash_value(std::deque const& v); - template - std::size_t hash_value(std::set const& v); - template - std::size_t hash_value(std::multiset const& v); - template - std::size_t hash_value(std::map const& v); - template - std::size_t hash_value(std::multimap const& v); - - template - std::size_t hash_value(std::complex const&); - // Implementation namespace hash_detail @@ -315,69 +292,21 @@ namespace boost return boost::hash_detail::float_hash_value(v); } - template - std::size_t hash_value(std::pair const& v) - { - std::size_t seed = 0; - hash_combine(seed, v.first); - hash_combine(seed, v.second); - return seed; - } - - template - std::size_t hash_value(std::vector const& v) - { - return hash_range(v.begin(), v.end()); - } - - template - std::size_t hash_value(std::list const& v) - { - return hash_range(v.begin(), v.end()); - } - - template - std::size_t hash_value(std::deque const& v) - { - return hash_range(v.begin(), v.end()); - } - - template - std::size_t hash_value(std::set const& v) - { - return hash_range(v.begin(), v.end()); - } - - template - std::size_t hash_value(std::multiset const& v) - { - return hash_range(v.begin(), v.end()); - } - - template - std::size_t hash_value(std::map const& v) - { - return hash_range(v.begin(), v.end()); - } - - template - std::size_t hash_value(std::multimap const& v) - { - return hash_range(v.begin(), v.end()); - } - - template - std::size_t hash_value(std::complex const& v) - { - boost::hash hasher; - std::size_t seed = hasher(v.imag()); - seed ^= hasher(v.real()) + (seed<<6) + (seed>>2); - return seed; - } - // // boost::hash // + + // Define the specializations required by the standard. The general purpose + // boost::hash is defined later in extensions.hpp if BOOST_HASH_NO_EXTENSIONS + // is not defined. + + // BOOST_HASH_SPECIALIZE - define a specialization for a type which is + // passed by copy. + // + // BOOST_HASH_SPECIALIZE_REF - define a specialization for a type which is + // passed by copy. + // + // These are undefined later. #if !BOOST_WORKAROUND(BOOST_MSVC, < 1300) #define BOOST_HASH_SPECIALIZE(type) \ @@ -462,10 +391,18 @@ namespace boost BOOST_HASH_SPECIALIZE_REF(std::wstring) #endif +#if defined(BOOST_HAS_LONG_LONG) + BOOST_HASH_SPECIALIZE(boost::long_long_type); + BOOST_HASH_SPECIALIZE(boost::ulong_long_type); +#endif + #undef BOOST_HASH_SPECIALIZE #undef BOOST_HASH_SPECIALIZE_REF +// Specializing boost::hash for pointers. + #if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) + template struct hash : public std::unary_function @@ -482,7 +419,15 @@ namespace boost #endif } }; + #else + + // For compilers without partial specialization, we define a + // boost::hash for all remaining types. But hash_impl is only defined + // for pointers in 'extensions.hpp' - so when BOOST_HASH_NO_EXTENSIONS + // is defined there will still be a compile error for types not supported + // in the standard. + namespace hash_detail { template @@ -515,9 +460,12 @@ namespace boost ::BOOST_NESTED_TEMPLATE inner { }; + #endif } +#undef BOOST_HASH_CHAR_TRAITS + #endif // BOOST_FUNCTIONAL_HASH_HASH_HPP // Include this outside of the include guards in case the file is included