mirror of
https://github.com/boostorg/container_hash.git
synced 2026-02-24 03:52:15 +00:00
in hash and seperate out some of the detail headers. Merged revisions 53159-53161,53167-53169,53175,53185,53205,53247-53248,53254 via svnmerge from https://svn.boost.org/svn/boost/trunk ........ r53159 | danieljames | 2009-05-21 22:21:11 +0100 (Thu, 21 May 2009) | 1 line Move the hash limits workaround into its own file. ........ r53160 | danieljames | 2009-05-21 22:21:44 +0100 (Thu, 21 May 2009) | 1 line Move the two different hash float implementation into their own header. ........ r53161 | danieljames | 2009-05-21 22:22:04 +0100 (Thu, 21 May 2009) | 1 line Try to automatically detect which float functions are available. ........ r53167 | danieljames | 2009-05-22 07:00:56 +0100 (Fri, 22 May 2009) | 1 line Fix a typo. ........ r53168 | danieljames | 2009-05-22 07:01:19 +0100 (Fri, 22 May 2009) | 3 lines Spell out exactly which functions can be used with which types. I was hitting some ambiguity errors when the function was for the wrong type. ........ r53169 | danieljames | 2009-05-22 07:01:35 +0100 (Fri, 22 May 2009) | 1 line Some STLport fixes for hash. ........ r53175 | danieljames | 2009-05-22 14:35:56 +0100 (Fri, 22 May 2009) | 2 lines Rename struct to avoid using 'type::'type' which confuses some compilers. ........ r53185 | danieljames | 2009-05-22 20:00:35 +0100 (Fri, 22 May 2009) | 1 line Explicitly qualify 'none' to avoid confusion with boost::none. ........ r53205 | danieljames | 2009-05-23 16:21:38 +0100 (Sat, 23 May 2009) | 4 lines Try to deal with macros for frexpl and ldexpl. The error message for msvc-9.0~wm5~stlport5.2 suggests that frexpl and ldexpl are macros. ........ r53247 | danieljames | 2009-05-25 14:45:16 +0100 (Mon, 25 May 2009) | 4 lines Check for float functions with less templates. The only template mechanism now used is full specialization, so this should hopefully be more portable to compilers we don't test. ........ r53248 | danieljames | 2009-05-25 15:27:00 +0100 (Mon, 25 May 2009) | 1 line Fix a couple of clumsy errors in the last commit. ........ r53254 | danieljames | 2009-05-25 20:44:52 +0100 (Mon, 25 May 2009) | 1 line Hash change log. ........ [SVN r53361]
230 lines
9.3 KiB
C++
230 lines
9.3 KiB
C++
|
|
// Copyright 2005-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)
|
|
|
|
#include "./config.hpp"
|
|
|
|
#ifdef TEST_STD_INCLUDES
|
|
# include <functional>
|
|
#else
|
|
# include <boost/functional/hash.hpp>
|
|
#endif
|
|
|
|
#include <boost/detail/lightweight_test.hpp>
|
|
|
|
#include <cmath>
|
|
#include <boost/functional/hash/detail/limits.hpp>
|
|
|
|
#include <iostream>
|
|
|
|
#if defined(BOOST_MSVC)
|
|
#pragma warning(push)
|
|
#pragma warning(disable:4127) // conditional expression is constant
|
|
#endif
|
|
|
|
char const* float_type(float*) { return "float"; }
|
|
char const* float_type(double*) { return "double"; }
|
|
char const* float_type(long double*) { return "long double"; }
|
|
|
|
template <class T>
|
|
void float_tests(char const* name, T* = 0)
|
|
{
|
|
std::cerr<<"\n"
|
|
<<"Testing " BOOST_STRINGIZE(HASH_NAMESPACE) "::hash<"<<name<<">\n"
|
|
<<"\n"
|
|
<<"boost::hash_detail::limits<T>::digits = "
|
|
<<boost::hash_detail::limits<T>::digits<<"\n"
|
|
<<"boost::hash_detail::limits<int>::digits = "
|
|
<<boost::hash_detail::limits<int>::digits<<"\n"
|
|
<<"boost::hash_detail::limits<std::size_t>::digits = "
|
|
<<boost::hash_detail::limits<std::size_t>::digits<<"\n"
|
|
<<"\n"
|
|
<<"boost::hash_detail::call_ldexp<T>::float_type = "
|
|
<<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 = "
|
|
<<float_type((BOOST_DEDUCED_TYPENAME boost::hash_detail::call_frexp<T>::float_type*)0)<<"\n"
|
|
<<"boost::hash_detail::select_hash_type<T>::type = "
|
|
<<float_type((BOOST_DEDUCED_TYPENAME boost::hash_detail::select_hash_type<T>::type*)0)<<"\n"
|
|
<<"\n"
|
|
;
|
|
|
|
HASH_NAMESPACE::hash<T> x1;
|
|
|
|
T zero = 0;
|
|
T minus_zero = (T) -1 * zero;
|
|
|
|
BOOST_TEST(zero == minus_zero);
|
|
BOOST_TEST(x1(zero) == x1(minus_zero));
|
|
|
|
BOOST_TEST(x1(zero) == HASH_NAMESPACE::hash_value(zero));
|
|
BOOST_TEST(x1(minus_zero) == HASH_NAMESPACE::hash_value(minus_zero));
|
|
|
|
using namespace std;
|
|
|
|
// Doing anything with infinity causes borland to crash.
|
|
#if defined(__BORLANDC__)
|
|
std::cerr<<"Not running infinity checks on Borland, as it causes it to crash.\n";
|
|
#else
|
|
if(boost::hash_detail::limits<T>::has_infinity) {
|
|
T infinity = -log(zero);
|
|
T infinity2 = (T) 1. / zero;
|
|
T infinity3 = (T) -1. / minus_zero;
|
|
T infinity4 = boost::hash_detail::limits<T>::infinity();
|
|
|
|
T minus_infinity = log(zero);
|
|
T minus_infinity2 = (T) -1. / zero;
|
|
T minus_infinity3 = (T) 1. / minus_zero;
|
|
|
|
BOOST_TEST(x1(infinity) == HASH_NAMESPACE::hash_value(infinity));
|
|
BOOST_TEST(x1(minus_infinity)
|
|
== HASH_NAMESPACE::hash_value(minus_infinity));
|
|
|
|
if(infinity == infinity2)
|
|
BOOST_TEST(x1(infinity) == x1(infinity2));
|
|
if(infinity == infinity3)
|
|
BOOST_TEST(x1(infinity) == x1(infinity3));
|
|
if(infinity == infinity4)
|
|
BOOST_TEST(x1(infinity) == x1(infinity4));
|
|
|
|
if(minus_infinity == minus_infinity2)
|
|
BOOST_TEST(x1(minus_infinity) == x1(minus_infinity2));
|
|
if(minus_infinity == minus_infinity3)
|
|
BOOST_TEST(x1(minus_infinity) == x1(minus_infinity3));
|
|
|
|
BOOST_TEST(infinity != minus_infinity);
|
|
|
|
if(x1(infinity) == x1(minus_infinity)) {
|
|
std::cerr<<"x1(infinity) == x1(-infinity) == "<<x1(infinity)<<"\n";
|
|
}
|
|
|
|
// This should really be 'has_denorm == denorm_present' but some
|
|
// compilers don't have 'denorm_present'. See also a later use.
|
|
if(boost::hash_detail::limits<T>::has_denorm) {
|
|
if(x1(boost::hash_detail::limits<T>::denorm_min()) == x1(infinity)) {
|
|
std::cerr<<"x1(denorm_min) == x1(infinity) == "<<x1(infinity)<<"\n";
|
|
}
|
|
if(x1(boost::hash_detail::limits<T>::denorm_min()) == x1(minus_infinity)) {
|
|
std::cerr<<"x1(denorm_min) == x1(-infinity) == "<<x1(minus_infinity)<<"\n";
|
|
}
|
|
}
|
|
if(boost::hash_detail::limits<T>::has_quiet_NaN) {
|
|
if(x1(boost::hash_detail::limits<T>::quiet_NaN()) == x1(infinity)) {
|
|
std::cerr<<"x1(quiet_NaN) == x1(infinity) == "<<x1(infinity)<<"\n";
|
|
}
|
|
if(x1(boost::hash_detail::limits<T>::quiet_NaN()) == x1(minus_infinity)) {
|
|
std::cerr<<"x1(quiet_NaN) == x1(-infinity) == "<<x1(minus_infinity)<<"\n";
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
T max = (boost::hash_detail::limits<T>::max)();
|
|
T half_max = max / 2;
|
|
T quarter_max = max / 4;
|
|
T three_quarter_max = max - quarter_max;
|
|
|
|
// Check the limits::max is in range.
|
|
BOOST_TEST(max != half_max);
|
|
BOOST_TEST(max != quarter_max);
|
|
BOOST_TEST(max != three_quarter_max);
|
|
BOOST_TEST(half_max != quarter_max);
|
|
BOOST_TEST(half_max != three_quarter_max);
|
|
BOOST_TEST(quarter_max != three_quarter_max);
|
|
|
|
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));
|
|
|
|
// The '!=' tests could legitimately fail, but with my hash it indicates a bug.
|
|
BOOST_TEST(x1(max) == x1(max));
|
|
BOOST_TEST(x1(max) != x1(quarter_max));
|
|
BOOST_TEST(x1(max) != x1(half_max));
|
|
BOOST_TEST(x1(max) != x1(three_quarter_max));
|
|
BOOST_TEST(x1(quarter_max) == x1(quarter_max));
|
|
BOOST_TEST(x1(quarter_max) != x1(half_max));
|
|
BOOST_TEST(x1(quarter_max) != x1(three_quarter_max));
|
|
BOOST_TEST(x1(half_max) == x1(half_max));
|
|
BOOST_TEST(x1(half_max) != x1(three_quarter_max));
|
|
BOOST_TEST(x1(three_quarter_max) == x1(three_quarter_max));
|
|
|
|
// Intel with gcc stdlib sometimes segfaults on calls to asin and acos.
|
|
#if !((defined(__INTEL_COMPILER) || defined(__ICL) || \
|
|
defined(__ICC) || defined(__ECC)) && \
|
|
(defined(__GLIBCPP__) || defined(__GLIBCXX__)))
|
|
T v1 = asin((T) 1);
|
|
T v2 = acos((T) 0);
|
|
if(v1 == v2)
|
|
BOOST_TEST(x1(v1) == x1(v2));
|
|
BOOST_TEST(x1(v1) == HASH_NAMESPACE::hash_value(v1));
|
|
BOOST_TEST(x1(v2) == HASH_NAMESPACE::hash_value(v2));
|
|
#endif
|
|
|
|
BOOST_TEST(x1(boost::hash_detail::limits<T>::epsilon()) ==
|
|
HASH_NAMESPACE::hash_value(boost::hash_detail::limits<T>::epsilon()));
|
|
|
|
BOOST_TEST(boost::hash_detail::limits<T>::epsilon() != (T) 0);
|
|
if(x1(boost::hash_detail::limits<T>::epsilon()) == x1((T) 0))
|
|
std::cerr<<"x1(epsilon) == x1(0) == "<<x1((T) 0)<<"\n";
|
|
|
|
BOOST_TEST(-boost::hash_detail::limits<T>::epsilon() != (T) 0);
|
|
if(x1(-boost::hash_detail::limits<T>::epsilon()) == x1((T) 0))
|
|
std::cerr<<"x1(-epsilon) == x1(0) == "<<x1((T) 0)<<"\n";
|
|
|
|
BOOST_TEST((T) 1 + boost::hash_detail::limits<T>::epsilon() != (T) 1);
|
|
if(x1((T) 1 + boost::hash_detail::limits<T>::epsilon()) == x1((T) 1))
|
|
std::cerr<<"x1(1 + epsilon) == x1(1) == "<<x1((T) 1)<<"\n";
|
|
|
|
BOOST_TEST((T) 1 - boost::hash_detail::limits<T>::epsilon() != (T) 1);
|
|
if(x1((T) 1 - boost::hash_detail::limits<T>::epsilon()) == x1((T) 1))
|
|
std::cerr<<"x1(1 - epsilon) == x1(1) == "<<x1((T) 1)<<"\n";
|
|
|
|
BOOST_TEST((T) -1 + boost::hash_detail::limits<T>::epsilon() != (T) -1);
|
|
if(x1((T) -1 + boost::hash_detail::limits<T>::epsilon()) == x1((T) -1))
|
|
std::cerr<<"x1(-1 + epsilon) == x1(-1) == "<<x1((T) -1)<<"\n";
|
|
|
|
BOOST_TEST((T) -1 - boost::hash_detail::limits<T>::epsilon() != (T) -1);
|
|
if(x1((T) -1 - boost::hash_detail::limits<T>::epsilon()) == x1((T) -1))
|
|
std::cerr<<"x1(-1 - epsilon) == x1(-1) == "<<x1((T) -1)<<"\n";
|
|
|
|
// As before.
|
|
if(boost::hash_detail::limits<T>::has_denorm) {
|
|
if(x1(boost::hash_detail::limits<T>::denorm_min()) == x1(zero)) {
|
|
std::cerr<<"x1(denorm_min) == x1(zero) == "<<x1(zero)<<"\n";
|
|
}
|
|
#if !BOOST_WORKAROUND(__DECCXX_VER,<70190006)
|
|
// The Tru64/CXX standard library prior to 7.1 contains a bug in the
|
|
// specialization of boost::hash_detail::limits::denorm_min() for long
|
|
// doubles which causes this test to fail.
|
|
if(x1(boost::hash_detail::limits<T>::denorm_min()) !=
|
|
HASH_NAMESPACE::hash_value(boost::hash_detail::limits<T>::denorm_min()))
|
|
{
|
|
std::cerr<<"x1(boost::hash_detail::limits<T>::denorm_min()) = "
|
|
<< x1(boost::hash_detail::limits<T>::denorm_min())
|
|
<< "\nhash_value(boost::hash_detail::limits<T>::denorm_min()) = "
|
|
<< HASH_NAMESPACE::hash_value(
|
|
boost::hash_detail::limits<T>::denorm_min())
|
|
<< "\nx1(0) = "<<x1(0)<<"\n";
|
|
}
|
|
#endif
|
|
}
|
|
|
|
// NaN also causes borland to crash.
|
|
#if !defined(__BORLANDC__)
|
|
if(boost::hash_detail::limits<T>::has_quiet_NaN) {
|
|
if(x1(boost::hash_detail::limits<T>::quiet_NaN()) == x1(1.0)) {
|
|
std::cerr<<"x1(quiet_NaN) == x1(1.0) == "<<x1(1.0)<<"\n";
|
|
}
|
|
BOOST_TEST(x1(boost::hash_detail::limits<T>::quiet_NaN()) ==
|
|
HASH_NAMESPACE::hash_value(boost::hash_detail::limits<T>::quiet_NaN()));
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#if defined(BOOST_MSVC)
|
|
#pragma warning(pop)
|
|
#endif
|