Move the support for hashing containers into the extension header, and improve the standard tests.

[SVN r54144]
This commit is contained in:
Daniel James
2009-06-21 09:42:40 +00:00
parent 8b98036bb8
commit c51bebf8a4
11 changed files with 170 additions and 110 deletions

View File

@@ -13,12 +13,13 @@
#if !defined(BOOST_FUNCTIONAL_HASH_EXTENSIONS_HPP) #if !defined(BOOST_FUNCTIONAL_HASH_EXTENSIONS_HPP)
#define BOOST_FUNCTIONAL_HASH_EXTENSIONS_HPP #define BOOST_FUNCTIONAL_HASH_EXTENSIONS_HPP
#include <boost/functional/hash/hash.hpp>
#include <boost/detail/container_fwd.hpp>
#if defined(_MSC_VER) && (_MSC_VER >= 1020) #if defined(_MSC_VER) && (_MSC_VER >= 1020)
# pragma once # pragma once
#endif #endif
#include <boost/functional/hash/hash.hpp>
#if defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) #if defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING)
#include <boost/type_traits/is_array.hpp> #include <boost/type_traits/is_array.hpp>
#endif #endif
@@ -29,6 +30,85 @@
namespace boost namespace boost
{ {
template <class A, class B>
std::size_t hash_value(std::pair<A, B> const&);
template <class T, class A>
std::size_t hash_value(std::vector<T, A> const&);
template <class T, class A>
std::size_t hash_value(std::list<T, A> const& v);
template <class T, class A>
std::size_t hash_value(std::deque<T, A> const& v);
template <class K, class C, class A>
std::size_t hash_value(std::set<K, C, A> const& v);
template <class K, class C, class A>
std::size_t hash_value(std::multiset<K, C, A> const& v);
template <class K, class T, class C, class A>
std::size_t hash_value(std::map<K, T, C, A> const& v);
template <class K, class T, class C, class A>
std::size_t hash_value(std::multimap<K, T, C, A> const& v);
template <class T>
std::size_t hash_value(std::complex<T> const&);
template <class A, class B>
std::size_t hash_value(std::pair<A, B> const& v)
{
std::size_t seed = 0;
hash_combine(seed, v.first);
hash_combine(seed, v.second);
return seed;
}
template <class T, class A>
std::size_t hash_value(std::vector<T, A> const& v)
{
return hash_range(v.begin(), v.end());
}
template <class T, class A>
std::size_t hash_value(std::list<T, A> const& v)
{
return hash_range(v.begin(), v.end());
}
template <class T, class A>
std::size_t hash_value(std::deque<T, A> const& v)
{
return hash_range(v.begin(), v.end());
}
template <class K, class C, class A>
std::size_t hash_value(std::set<K, C, A> const& v)
{
return hash_range(v.begin(), v.end());
}
template <class K, class C, class A>
std::size_t hash_value(std::multiset<K, C, A> const& v)
{
return hash_range(v.begin(), v.end());
}
template <class K, class T, class C, class A>
std::size_t hash_value(std::map<K, T, C, A> const& v)
{
return hash_range(v.begin(), v.end());
}
template <class K, class T, class C, class A>
std::size_t hash_value(std::multimap<K, T, C, A> const& v)
{
return hash_range(v.begin(), v.end());
}
template <class T>
std::size_t hash_value(std::complex<T> const& v)
{
boost::hash<T> hasher;
std::size_t seed = hasher(v.imag());
seed ^= hasher(v.real()) + (seed<<6) + (seed>>2);
return seed;
}
// //
// call_hash_impl // call_hash_impl

View File

@@ -13,7 +13,6 @@
#include <boost/functional/hash/hash_fwd.hpp> #include <boost/functional/hash/hash_fwd.hpp>
#include <functional> #include <functional>
#include <boost/functional/hash/detail/hash_float.hpp> #include <boost/functional/hash/detail/hash_float.hpp>
#include <boost/detail/container_fwd.hpp>
#include <string> #include <string>
#include <boost/limits.hpp> #include <boost/limits.hpp>
@@ -70,26 +69,6 @@ namespace boost
template <class Ch, class A> template <class Ch, class A>
std::size_t hash_value(std::basic_string<Ch, std::BOOST_HASH_CHAR_TRAITS<Ch>, A> const&); std::size_t hash_value(std::basic_string<Ch, std::BOOST_HASH_CHAR_TRAITS<Ch>, A> const&);
template <class A, class B>
std::size_t hash_value(std::pair<A, B> const&);
template <class T, class A>
std::size_t hash_value(std::vector<T, A> const&);
template <class T, class A>
std::size_t hash_value(std::list<T, A> const& v);
template <class T, class A>
std::size_t hash_value(std::deque<T, A> const& v);
template <class K, class C, class A>
std::size_t hash_value(std::set<K, C, A> const& v);
template <class K, class C, class A>
std::size_t hash_value(std::multiset<K, C, A> const& v);
template <class K, class T, class C, class A>
std::size_t hash_value(std::map<K, T, C, A> const& v);
template <class K, class T, class C, class A>
std::size_t hash_value(std::multimap<K, T, C, A> const& v);
template <class T>
std::size_t hash_value(std::complex<T> const&);
// Implementation // Implementation
namespace hash_detail namespace hash_detail
@@ -313,66 +292,6 @@ namespace boost
return boost::hash_detail::float_hash_value(v); return boost::hash_detail::float_hash_value(v);
} }
template <class A, class B>
std::size_t hash_value(std::pair<A, B> const& v)
{
std::size_t seed = 0;
hash_combine(seed, v.first);
hash_combine(seed, v.second);
return seed;
}
template <class T, class A>
std::size_t hash_value(std::vector<T, A> const& v)
{
return hash_range(v.begin(), v.end());
}
template <class T, class A>
std::size_t hash_value(std::list<T, A> const& v)
{
return hash_range(v.begin(), v.end());
}
template <class T, class A>
std::size_t hash_value(std::deque<T, A> const& v)
{
return hash_range(v.begin(), v.end());
}
template <class K, class C, class A>
std::size_t hash_value(std::set<K, C, A> const& v)
{
return hash_range(v.begin(), v.end());
}
template <class K, class C, class A>
std::size_t hash_value(std::multiset<K, C, A> const& v)
{
return hash_range(v.begin(), v.end());
}
template <class K, class T, class C, class A>
std::size_t hash_value(std::map<K, T, C, A> const& v)
{
return hash_range(v.begin(), v.end());
}
template <class K, class T, class C, class A>
std::size_t hash_value(std::multimap<K, T, C, A> const& v)
{
return hash_range(v.begin(), v.end());
}
template <class T>
std::size_t hash_value(std::complex<T> const& v)
{
boost::hash<T> hasher;
std::size_t seed = hasher(v.imag());
seed ^= hasher(v.real()) + (seed<<6) + (seed>>2);
return seed;
}
// //
// boost::hash // boost::hash
// //
@@ -472,6 +391,11 @@ namespace boost
BOOST_HASH_SPECIALIZE_REF(std::wstring) BOOST_HASH_SPECIALIZE_REF(std::wstring)
#endif #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
#undef BOOST_HASH_SPECIALIZE_REF #undef BOOST_HASH_SPECIALIZE_REF

View File

@@ -44,4 +44,15 @@ test-suite functional/hash
[ run hash_no_ext_macro_2.cpp ] [ run hash_no_ext_macro_2.cpp ]
; ;
build-project ../examples ; test-suite functional/hash_no_ext
:
[ run hash_number_test.cpp : : : <define>BOOST_HASH_NO_EXTENSIONS : no_ext_number_test ]
[ run hash_pointer_test.cpp : : : <define>BOOST_HASH_NO_EXTENSIONS : no_ext_pointer_test ]
[ run hash_function_pointer_test.cpp : : : <define>BOOST_HASH_NO_EXTENSIONS : no_ext_function_pointer_test ]
[ run hash_float_test.cpp : : : <define>BOOST_HASH_NO_EXTENSIONS : no_ext_float_test ]
[ run hash_long_double_test.cpp : : : <define>BOOST_HASH_NO_EXTENSIONS : no_ext_long_double_test ]
[ run hash_string_test.cpp : : : <define>BOOST_HASH_NO_EXTENSIONS : no_ext_string_test ]
[ run link_test.cpp link_test_2.cpp : : : <define>BOOST_HASH_NO_EXTENSIONS : no_ext_link_test ]
;
# build-project ../examples ;

View File

@@ -5,7 +5,7 @@
#if defined(TEST_STD) #if defined(TEST_STD)
# define TEST_STD_INCLUDES # define TEST_STD_INCLUDES
# define HASH_NAMESPACE std::tr1 # define HASH_NAMESPACE std
#else #else
# define HASH_NAMESPACE boost # define HASH_NAMESPACE boost
# if !defined(BOOST_HASH_NO_EXTENSIONS) # if !defined(BOOST_HASH_NO_EXTENSIONS)

View File

@@ -5,18 +5,20 @@
#include "./config.hpp" #include "./config.hpp"
#ifdef TEST_EXTENSIONS #if !defined(TEST_EXTENSIONS)
int main() {}
#else
#ifdef TEST_STD_INCLUDES #ifdef TEST_STD_INCLUDES
# include <functional> # include <functional>
#else #else
# include <boost/functional/hash.hpp> # include <boost/functional/hash.hpp>
#endif #endif
#endif
#include <boost/detail/lightweight_test.hpp> #include <boost/detail/lightweight_test.hpp>
#ifdef TEST_EXTENSIONS
#include <complex> #include <complex>
#include <sstream> #include <sstream>
#include <boost/limits.hpp> #include <boost/limits.hpp>
@@ -91,4 +93,4 @@ int main()
return boost::report_errors(); return boost::report_errors();
} }
#endif #endif // TEST_EXTENSIONS

View File

@@ -15,6 +15,8 @@
#include <cmath> #include <cmath>
#include <boost/functional/hash/detail/limits.hpp> #include <boost/functional/hash/detail/limits.hpp>
#include <boost/functional/hash/detail/float_functions.hpp>
#include <boost/detail/workaround.hpp>
#include <iostream> #include <iostream>
@@ -42,8 +44,6 @@ void float_tests(char const* name, T* = 0)
<<"\n" <<"\n"
<<"boost::hash_detail::call_ldexp<T>::float_type = " <<"boost::hash_detail::call_ldexp<T>::float_type = "
<<float_type((BOOST_DEDUCED_TYPENAME boost::hash_detail::call_ldexp<T>::float_type*)0)<<"\n" <<float_type((BOOST_DEDUCED_TYPENAME boost::hash_detail::call_ldexp<T>::float_type*)0)<<"\n"
<<"boost::call_frexp<T>::float_type = "
<<float_type((BOOST_DEDUCED_TYPENAME boost::hash_detail::call_frexp<T>::float_type*)0)<<"\n"
<<"boost::hash_detail::call_frexp<T>::float_type = " <<"boost::hash_detail::call_frexp<T>::float_type = "
<<float_type((BOOST_DEDUCED_TYPENAME boost::hash_detail::call_frexp<T>::float_type*)0)<<"\n" <<float_type((BOOST_DEDUCED_TYPENAME boost::hash_detail::call_frexp<T>::float_type*)0)<<"\n"
<<"boost::hash_detail::select_hash_type<T>::type = " <<"boost::hash_detail::select_hash_type<T>::type = "
@@ -59,8 +59,10 @@ void float_tests(char const* name, T* = 0)
BOOST_TEST(zero == minus_zero); BOOST_TEST(zero == minus_zero);
BOOST_TEST(x1(zero) == x1(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(zero) == HASH_NAMESPACE::hash_value(zero));
BOOST_TEST(x1(minus_zero) == HASH_NAMESPACE::hash_value(minus_zero)); BOOST_TEST(x1(minus_zero) == HASH_NAMESPACE::hash_value(minus_zero));
#endif
using namespace std; using namespace std;
@@ -78,9 +80,11 @@ void float_tests(char const* name, T* = 0)
T minus_infinity2 = (T) -1. / zero; T minus_infinity2 = (T) -1. / zero;
T minus_infinity3 = (T) 1. / minus_zero; T minus_infinity3 = (T) 1. / minus_zero;
#if defined(TEST_EXTENSIONS)
BOOST_TEST(x1(infinity) == HASH_NAMESPACE::hash_value(infinity)); BOOST_TEST(x1(infinity) == HASH_NAMESPACE::hash_value(infinity));
BOOST_TEST(x1(minus_infinity) BOOST_TEST(x1(minus_infinity)
== HASH_NAMESPACE::hash_value(minus_infinity)); == HASH_NAMESPACE::hash_value(minus_infinity));
#endif
if(infinity == infinity2) if(infinity == infinity2)
BOOST_TEST(x1(infinity) == x1(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(half_max != three_quarter_max);
BOOST_TEST(quarter_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(max) == HASH_NAMESPACE::hash_value(max));
BOOST_TEST(x1(half_max) == HASH_NAMESPACE::hash_value(half_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(quarter_max) == HASH_NAMESPACE::hash_value(quarter_max));
BOOST_TEST(x1(three_quarter_max) == HASH_NAMESPACE::hash_value(three_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. // The '!=' tests could legitimately fail, but with my hash it indicates a bug.
BOOST_TEST(x1(max) == x1(max)); BOOST_TEST(x1(max) == x1(max));
@@ -159,12 +165,18 @@ void float_tests(char const* name, T* = 0)
T v2 = acos((T) 0); T v2 = acos((T) 0);
if(v1 == v2) if(v1 == v2)
BOOST_TEST(x1(v1) == x1(v2)); BOOST_TEST(x1(v1) == x1(v2));
#if defined(TEST_EXTENSIONS)
BOOST_TEST(x1(v1) == HASH_NAMESPACE::hash_value(v1)); BOOST_TEST(x1(v1) == HASH_NAMESPACE::hash_value(v1));
BOOST_TEST(x1(v2) == HASH_NAMESPACE::hash_value(v2)); BOOST_TEST(x1(v2) == HASH_NAMESPACE::hash_value(v2));
#endif #endif
#endif
#if defined(TEST_EXTENSIONS)
BOOST_TEST(x1(boost::hash_detail::limits<T>::epsilon()) == BOOST_TEST(x1(boost::hash_detail::limits<T>::epsilon()) ==
HASH_NAMESPACE::hash_value(boost::hash_detail::limits<T>::epsilon())); HASH_NAMESPACE::hash_value(boost::hash_detail::limits<T>::epsilon()));
#endif
BOOST_TEST(boost::hash_detail::limits<T>::epsilon() != (T) 0); BOOST_TEST(boost::hash_detail::limits<T>::epsilon() != (T) 0);
if(x1(boost::hash_detail::limits<T>::epsilon()) == x1((T) 0)) if(x1(boost::hash_detail::limits<T>::epsilon()) == x1((T) 0))
@@ -195,7 +207,7 @@ void float_tests(char const* name, T* = 0)
if(x1(boost::hash_detail::limits<T>::denorm_min()) == x1(zero)) { if(x1(boost::hash_detail::limits<T>::denorm_min()) == x1(zero)) {
std::cerr<<"x1(denorm_min) == x1(zero) == "<<x1(zero)<<"\n"; std::cerr<<"x1(denorm_min) == x1(zero) == "<<x1(zero)<<"\n";
} }
#if !BOOST_WORKAROUND(__DECCXX_VER,<70190006) #if !BOOST_WORKAROUND(__DECCXX_VER,<70190006) && defined(TEST_EXTENSIONS)
// The Tru64/CXX standard library prior to 7.1 contains a bug in the // The Tru64/CXX standard library prior to 7.1 contains a bug in the
// specialization of boost::hash_detail::limits::denorm_min() for long // specialization of boost::hash_detail::limits::denorm_min() for long
// doubles which causes this test to fail. // doubles which causes this test to fail.
@@ -213,7 +225,7 @@ void float_tests(char const* name, T* = 0)
} }
// NaN also causes borland to crash. // NaN also causes borland to crash.
#if !defined(__BORLANDC__) #if !defined(__BORLANDC__) && defined(TEST_EXTENSIONS)
if(boost::hash_detail::limits<T>::has_quiet_NaN) { if(boost::hash_detail::limits<T>::has_quiet_NaN) {
if(x1(boost::hash_detail::limits<T>::quiet_NaN()) == x1(1.0)) { if(x1(boost::hash_detail::limits<T>::quiet_NaN()) == x1(1.0)) {
std::cerr<<"x1(quiet_NaN) == x1(1.0) == "<<x1(1.0)<<"\n"; std::cerr<<"x1(quiet_NaN) == x1(1.0) == "<<x1(1.0)<<"\n";

View File

@@ -6,8 +6,13 @@
// This test just makes sure a header which uses hash_fwd can compile without // This test just makes sure a header which uses hash_fwd can compile without
// the main hash headers. // the main hash headers.
#include "./hash_fwd_test.hpp" #if !defined(TEST_EXTENSIONS) || defined(TEST_STD_INCLUDES)
int main() {}
#else
#include "./hash_fwd_test.hpp"
#include <boost/detail/lightweight_test.hpp> #include <boost/detail/lightweight_test.hpp>
template <class T> void unused(T const&) {} template <class T> void unused(T const&) {}
@@ -30,10 +35,11 @@ void fwd_test()
unused(y1); unused(y2); unused(y3); unused(y1); unused(y2); unused(y3);
} }
int main() int main()
{ {
fwd_test(); fwd_test();
return boost::report_errors(); return boost::report_errors();
} }
#endif // defined(TEST_EXTENSIONS) && !defined(TEST_STD_INCLUDES)

View File

@@ -4,9 +4,17 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#define HASH_NAMESPACE boost #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 <boost/functional/hash.hpp> #include <boost/functional/hash.hpp>
// Include header with BOOST_HASH_NO_EXTENSIONS defined
#define BOOST_HASH_NO_EXTENSIONS #define BOOST_HASH_NO_EXTENSIONS
#include <boost/functional/hash.hpp> #include <boost/functional/hash.hpp>
#include <boost/detail/lightweight_test.hpp> #include <boost/detail/lightweight_test.hpp>
#include <deque> #include <deque>
#include <cassert> #include <cassert>

View File

@@ -4,10 +4,17 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#define HASH_NAMESPACE boost #define HASH_NAMESPACE boost
// Include header with BOOST_HASH_NO_EXTENSIONS defined
#if !defined(BOOST_HASH_NO_EXTENSIONS)
#define BOOST_HASH_NO_EXTENSIONS #define BOOST_HASH_NO_EXTENSIONS
#endif
#include <boost/functional/hash.hpp> #include <boost/functional/hash.hpp>
// Include header without BOOST_HASH_NO_EXTENSIONS defined
#undef BOOST_HASH_NO_EXTENSIONS #undef BOOST_HASH_NO_EXTENSIONS
#include <boost/functional/hash.hpp> #include <boost/functional/hash.hpp>
#include <boost/detail/lightweight_test.hpp> #include <boost/detail/lightweight_test.hpp>
#include <map> #include <map>

View File

@@ -5,18 +5,20 @@
#include "./config.hpp" #include "./config.hpp"
#ifdef TEST_EXTENSIONS #if !defined(TEST_EXTENSIONS)
int main() {}
#else
#ifdef TEST_STD_INCLUDES #ifdef TEST_STD_INCLUDES
# include <functional> # include <functional>
#else #else
# include <boost/functional/hash.hpp> # include <boost/functional/hash.hpp>
#endif #endif
#endif
#include <boost/detail/lightweight_test.hpp> #include <boost/detail/lightweight_test.hpp>
#ifdef TEST_EXTENSIONS
#include <boost/limits.hpp> #include <boost/limits.hpp>
#include <boost/mpl/assert.hpp> #include <boost/mpl/assert.hpp>
#include <boost/type_traits/is_base_and_derived.hpp> #include <boost/type_traits/is_base_and_derived.hpp>
@@ -74,8 +76,6 @@ void hash_range_tests()
BOOST_TEST(seed == HASH_NAMESPACE::hash_range(values5.begin(), values5.end())); BOOST_TEST(seed == HASH_NAMESPACE::hash_range(values5.begin(), values5.end()));
} }
#endif
int main() int main()
{ {
hash_range_tests(); hash_range_tests();
@@ -83,3 +83,4 @@ int main()
return boost::report_errors(); return boost::report_errors();
} }
#endif // TEST_EXTESNIONS

View File

@@ -9,14 +9,23 @@
#include <vector> #include <vector>
int f(std::size_t hash1, int* x1) { int f(std::size_t hash1, int* x1) {
// Check that HASH_NAMESPACE::hash<int*> works in both files. // Check that HASH_NAMESPACE::hash<int*> works in both files.
HASH_NAMESPACE::hash<int*> ptr_hasher; HASH_NAMESPACE::hash<int*> ptr_hasher;
BOOST_TEST(hash1 == ptr_hasher(x1)); BOOST_TEST(hash1 == ptr_hasher(x1));
#if defined(TEST_EXTENSIONS)
// Check that std::vector<std::size_t> is avaiable in this file. // Check that std::vector<std::size_t> is avaiable in this file.
std::vector<std::size_t> x; std::vector<std::size_t> x;
x.push_back(*x1); x.push_back(*x1);
HASH_NAMESPACE::hash<std::vector<std::size_t> > vector_hasher; HASH_NAMESPACE::hash<std::vector<std::size_t> > vector_hasher;
return vector_hasher(x) != HASH_NAMESPACE::hash_value(x); return vector_hasher(x) != HASH_NAMESPACE::hash_value(x);
#else
return 0;
#endif
} }