mirror of
https://github.com/boostorg/functional.git
synced 2025-08-02 14:04:27 +02:00
Try to automatically detect which float functions are available.
[SVN r53161]
This commit is contained in:
@@ -6,7 +6,11 @@
|
||||
#if !defined(BOOST_FUNCTIONAL_HASH_DETAIL_FLOAT_FUNCTIONS_HPP)
|
||||
#define BOOST_FUNCTIONAL_HASH_DETAIL_FLOAT_FUNCTIONS_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/config/no_tr1/cmath.hpp>
|
||||
#include <boost/type_traits/ice.hpp>
|
||||
#include <boost/detail/select_type.hpp>
|
||||
//#include <boost/assert.hpp>
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
|
||||
# pragma once
|
||||
@@ -17,146 +21,186 @@
|
||||
// library implementations don't support this. On some that don't, the C99
|
||||
// float functions (frexpf, frexpl, etc.) are available.
|
||||
//
|
||||
// Some of this is based on guess work. If I don't know any better I assume that
|
||||
// the standard C++ overloaded functions are available. If they're not then this
|
||||
// means that the argument is cast to a double and back, which is inefficient
|
||||
// and will give pretty bad results for long doubles - so if you know better
|
||||
// let me know.
|
||||
// The following tries to automatically detect which are available.
|
||||
|
||||
// STLport:
|
||||
#if defined(__SGI_STL_PORT) || defined(_STLPORT_VERSION)
|
||||
# if (defined(__GNUC__) && __GNUC__ < 3 && (defined(linux) || defined(__linux) || defined(__linux__))) || defined(__DMC__)
|
||||
# define BOOST_HASH_USE_C99_FLOAT_FUNCS
|
||||
# elif defined(BOOST_MSVC) && BOOST_MSVC < 1300
|
||||
# define BOOST_HASH_USE_C99_FLOAT_FUNCS
|
||||
# else
|
||||
# define BOOST_HASH_USE_OVERLOAD_FLOAT_FUNCS
|
||||
# endif
|
||||
namespace BOOST_HASH_DETECT_FLOAT_FUNCTIONS {
|
||||
// Dummy functions to detect when the actual function we want isn't
|
||||
// available.
|
||||
//
|
||||
// AFAICT these have to be outside of the boost namespace, as if they're in
|
||||
// the boost namespace they'll always be preferable to any other function
|
||||
// (since the arguments are built in types, ADL can't be used).
|
||||
|
||||
// Roguewave:
|
||||
//
|
||||
// On borland 5.51, with roguewave 2.1.1 the standard C++ overloads aren't
|
||||
// defined, but for the same version of roguewave on sunpro they are.
|
||||
#elif defined(_RWSTD_VER)
|
||||
# if defined(__BORLANDC__)
|
||||
# define BOOST_HASH_USE_C99_FLOAT_FUNCS
|
||||
# define BOOST_HASH_C99_NO_FLOAT_FUNCS
|
||||
# elif defined(__DECCXX)
|
||||
# define BOOST_HASH_USE_C99_FLOAT_FUNCS
|
||||
# else
|
||||
# define BOOST_HASH_USE_OVERLOAD_FLOAT_FUNCS
|
||||
# endif
|
||||
struct none {};
|
||||
|
||||
// libstdc++ (gcc 3.0 onwards, I think)
|
||||
#elif defined(__GLIBCPP__) || defined(__GLIBCXX__)
|
||||
# define BOOST_HASH_USE_OVERLOAD_FLOAT_FUNCS
|
||||
none ldexpf(int, int);
|
||||
none ldexpl(int, int);
|
||||
none frexpf(int, int*);
|
||||
none frexpl(int, int*);
|
||||
|
||||
// SGI:
|
||||
#elif defined(__STL_CONFIG_H)
|
||||
# if defined(linux) || defined(__linux) || defined(__linux__)
|
||||
# define BOOST_HASH_USE_C99_FLOAT_FUNCS
|
||||
# else
|
||||
# define BOOST_HASH_USE_OVERLOAD_FLOAT_FUNCS
|
||||
# endif
|
||||
template <class Float> none ldexp(Float, int);
|
||||
template <class Float> none frexp(Float, int*);
|
||||
}
|
||||
|
||||
// vxWorks. It has its own math library, but uses Dinkumware STL
|
||||
#elif defined(__VXWORKS__)
|
||||
# define BOOST_HASH_USE_OVERLOAD_FLOAT_FUNCS
|
||||
|
||||
// Dinkumware.
|
||||
#elif (defined(_YVALS) && !defined(__IBMCPP__)) || defined(_CPPLIB_VER)
|
||||
// Some versions of Visual C++ don't seem to have the C++ overloads but they
|
||||
// all seem to have the c99 float overloads
|
||||
# if defined(BOOST_MSVC)
|
||||
# define BOOST_HASH_USE_C99_FLOAT_FUNCS
|
||||
// On other platforms the C++ overloads seem to have been introduced sometime
|
||||
// before 402.
|
||||
# elif defined(_CPPLIB_VER) && (_CPPLIB_VER >= 402)
|
||||
# define BOOST_HASH_USE_OVERLOAD_FLOAT_FUNCS
|
||||
# else
|
||||
# define BOOST_HASH_USE_C99_FLOAT_FUNCS
|
||||
# endif
|
||||
|
||||
// Digital Mars
|
||||
#elif defined(__DMC__)
|
||||
# define BOOST_HASH_USE_C99_FLOAT_FUNCS
|
||||
|
||||
// Use overloaded float functions by default.
|
||||
#else
|
||||
# define BOOST_HASH_USE_OVERLOAD_FLOAT_FUNCS
|
||||
#endif
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace hash_detail
|
||||
{
|
||||
|
||||
inline float call_ldexp(float v, int exp)
|
||||
{
|
||||
namespace boost {
|
||||
namespace hash_detail {
|
||||
namespace detect {
|
||||
using namespace std;
|
||||
#if defined(BOOST_HASH_USE_OVERLOAD_FLOAT_FUNCS) || \
|
||||
defined(BOOST_HASH_C99_NO_FLOAT_FUNCS)
|
||||
return ldexp(v, exp);
|
||||
#else
|
||||
return ldexpf(v, exp);
|
||||
#endif
|
||||
using namespace BOOST_HASH_DETECT_FLOAT_FUNCTIONS;
|
||||
|
||||
// A type for detecting return type of functions.
|
||||
template <typename T> struct is;
|
||||
template <> struct is<float> { char x[10]; };
|
||||
template <> struct is<double> { char x[20]; };
|
||||
template <> struct is<long double> { char x[30]; };
|
||||
template <> struct is<none> { char x[40]; };
|
||||
|
||||
// Convert the return type of a function to a type we can use.
|
||||
template <typename T> is<T> float_type(T);
|
||||
|
||||
#define BOOST_HASH_CALL_FLOAT_FUNC(func, type2) \
|
||||
struct func##_access { \
|
||||
template <typename Float> \
|
||||
struct check \
|
||||
{ \
|
||||
static Float x; \
|
||||
static type2 y; \
|
||||
BOOST_STATIC_CONSTANT(bool, value = \
|
||||
sizeof(float_type(func(x,y))) \
|
||||
== sizeof(is<Float>)); \
|
||||
}; \
|
||||
\
|
||||
template <typename Float> \
|
||||
struct call \
|
||||
{ \
|
||||
Float operator()(Float a, type2 b) const \
|
||||
{ \
|
||||
return func(a, b); \
|
||||
} \
|
||||
}; \
|
||||
}
|
||||
|
||||
inline double call_ldexp(double v, int exp)
|
||||
{
|
||||
using namespace std;
|
||||
return ldexp(v, exp);
|
||||
BOOST_HASH_CALL_FLOAT_FUNC(ldexpf, int);
|
||||
BOOST_HASH_CALL_FLOAT_FUNC(ldexpl, int);
|
||||
BOOST_HASH_CALL_FLOAT_FUNC(ldexp, int);
|
||||
BOOST_HASH_CALL_FLOAT_FUNC(frexpf, int*);
|
||||
BOOST_HASH_CALL_FLOAT_FUNC(frexpl, int*);
|
||||
BOOST_HASH_CALL_FLOAT_FUNC(frexp, int*);
|
||||
|
||||
#undef BOOST_CALL_HAS_FLOAT_FUNC
|
||||
}
|
||||
|
||||
inline long double call_ldexp(long double v, int exp)
|
||||
{
|
||||
using namespace std;
|
||||
#if defined(BOOST_HASH_USE_OVERLOAD_FLOAT_FUNCS)
|
||||
return ldexp(v, exp);
|
||||
#else
|
||||
return ldexpl(v, exp);
|
||||
#endif
|
||||
}
|
||||
// check
|
||||
//
|
||||
// Use in select_impl to help old compilers with a value template.
|
||||
|
||||
inline float call_frexp(float v, int* exp)
|
||||
{
|
||||
using namespace std;
|
||||
#if defined(BOOST_HASH_USE_OVERLOAD_FLOAT_FUNCS) || \
|
||||
defined(BOOST_HASH_C99_NO_FLOAT_FUNCS)
|
||||
return frexp(v, exp);
|
||||
#else
|
||||
return frexpf(v, exp);
|
||||
#endif
|
||||
}
|
||||
template <typename Float, typename Access>
|
||||
struct check : Access::BOOST_NESTED_TEMPLATE check<Float> {};
|
||||
|
||||
inline double call_frexp(double v, int* exp)
|
||||
{
|
||||
using namespace std;
|
||||
return frexp(v, exp);
|
||||
}
|
||||
// found_impl
|
||||
//
|
||||
// Used in select_impl when an appropriate function has
|
||||
// been found.
|
||||
|
||||
inline long double call_frexp(long double v, int* exp)
|
||||
template <typename Float, typename Access>
|
||||
struct found_impl
|
||||
{
|
||||
using namespace std;
|
||||
#if defined(BOOST_HASH_USE_OVERLOAD_FLOAT_FUNCS)
|
||||
return frexp(v, exp);
|
||||
#else
|
||||
return frexpl(v, exp);
|
||||
#endif
|
||||
}
|
||||
// Ignore further types
|
||||
|
||||
template <typename Float2, typename Access2>
|
||||
struct x {
|
||||
typedef found_impl type;
|
||||
};
|
||||
|
||||
// Use Access for result
|
||||
|
||||
struct type : Access::BOOST_NESTED_TEMPLATE call<Float>
|
||||
{
|
||||
BOOST_STATIC_CONSTANT(bool, value = true);
|
||||
};
|
||||
};
|
||||
|
||||
// select_impl
|
||||
//
|
||||
// Used to choose which floating point function to use for a particular
|
||||
// floating point type.
|
||||
|
||||
struct select_impl
|
||||
{
|
||||
// Check if Access is appropriate for Float
|
||||
|
||||
template <typename Float, typename Access>
|
||||
struct x :
|
||||
boost::detail::if_true <
|
||||
::boost::hash_detail::check<Float, Access>::value
|
||||
>
|
||||
::BOOST_NESTED_TEMPLATE then<
|
||||
found_impl<Float, Access>, select_impl
|
||||
> {};
|
||||
|
||||
// Result for nothing found.
|
||||
|
||||
struct type
|
||||
{
|
||||
BOOST_STATIC_CONSTANT(bool, value = false);
|
||||
};
|
||||
};
|
||||
|
||||
// call_ldexp
|
||||
//
|
||||
// call_ldexp::value = Is there an appropriate version of call_ldexp
|
||||
// for this type?
|
||||
// Is there is, this is a function object that will call that overload
|
||||
|
||||
template <typename Float>
|
||||
struct call_ldexp : select_impl
|
||||
:: BOOST_NESTED_TEMPLATE x<Float, detect::ldexp_access>::type
|
||||
:: BOOST_NESTED_TEMPLATE x<Float, detect::ldexpf_access>::type
|
||||
:: BOOST_NESTED_TEMPLATE x<Float, detect::ldexpl_access>::type
|
||||
:: type {};
|
||||
|
||||
// call_frexp
|
||||
//
|
||||
// call_frexp::value = Is there an appropriate version of call_frexp
|
||||
// for this type?
|
||||
// Is there is, this is a function object that will call that overload
|
||||
|
||||
template <typename Float>
|
||||
struct call_frexp : select_impl
|
||||
:: BOOST_NESTED_TEMPLATE x<Float, detect::frexp_access>::type
|
||||
:: BOOST_NESTED_TEMPLATE x<Float, detect::frexpf_access>::type
|
||||
:: BOOST_NESTED_TEMPLATE x<Float, detect::frexpl_access>::type
|
||||
:: type {};
|
||||
|
||||
// has_float_functions
|
||||
//
|
||||
// Have we fround frexp and ldexp for the given float type.
|
||||
|
||||
template<typename Float>
|
||||
struct has_float_functions
|
||||
{
|
||||
BOOST_STATIC_CONSTANT(bool, value = (
|
||||
::boost::type_traits::ice_and<
|
||||
::boost::hash_detail::call_ldexp<Float>::value,
|
||||
::boost::hash_detail::call_frexp<Float>::value
|
||||
>::value
|
||||
));
|
||||
};
|
||||
|
||||
|
||||
// select_hash_type
|
||||
//
|
||||
// If there is support for a particular floating point type, use that
|
||||
// otherwise use double (there's always support for double).
|
||||
|
||||
template <typename Float>
|
||||
struct select_hash_type :
|
||||
boost::detail::if_true <
|
||||
::boost::hash_detail::has_float_functions<Float>::value
|
||||
> ::BOOST_NESTED_TEMPLATE then <
|
||||
Float, double
|
||||
> {};
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(BOOST_HASH_USE_C99_FLOAT_FUNCS)
|
||||
#undef BOOST_HASH_USE_C99_FLOAT_FUNCS
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_HASH_USE_OVERLOAD_FLOAT_FUNCS)
|
||||
#undef BOOST_HASH_USE_OVERLOAD_FLOAT_FUNCS
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_HASH_C99_NO_FLOAT_FUNCS)
|
||||
#undef BOOST_HASH_C99_NO_FLOAT_FUNCS
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@@ -34,14 +34,17 @@ namespace boost
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline std::size_t float_hash_impl(T v)
|
||||
inline std::size_t float_hash_impl2(T v)
|
||||
{
|
||||
boost::hash_detail::call_frexp<T> frexp;
|
||||
boost::hash_detail::call_ldexp<T> ldexp;
|
||||
|
||||
int exp = 0;
|
||||
|
||||
v = boost::hash_detail::call_frexp(v, &exp);
|
||||
v = frexp(v, &exp);
|
||||
|
||||
// A postive value is easier to hash, so combine the
|
||||
// sign with the exponent.
|
||||
// sign with the exponent and use the absolute value.
|
||||
if(v < 0) {
|
||||
v = -v;
|
||||
exp += limits<T>::max_exponent -
|
||||
@@ -51,8 +54,7 @@ namespace boost
|
||||
// The result of frexp is always between 0.5 and 1, so its
|
||||
// top bit will always be 1. Subtract by 0.5 to remove that.
|
||||
v -= T(0.5);
|
||||
v = boost::hash_detail::call_ldexp(v,
|
||||
limits<std::size_t>::digits + 1);
|
||||
v = ldexp(v, limits<std::size_t>::digits + 1);
|
||||
std::size_t seed = static_cast<std::size_t>(v);
|
||||
v -= seed;
|
||||
|
||||
@@ -64,8 +66,7 @@ namespace boost
|
||||
|
||||
for(std::size_t i = 0; i != length; ++i)
|
||||
{
|
||||
v = boost::hash_detail::call_ldexp(v,
|
||||
limits<std::size_t>::digits);
|
||||
v = ldexp(v, limits<std::size_t>::digits);
|
||||
std::size_t part = static_cast<std::size_t>(v);
|
||||
v -= part;
|
||||
hash_float_combine(seed, part);
|
||||
@@ -74,6 +75,13 @@ namespace boost
|
||||
hash_float_combine(seed, exp);
|
||||
|
||||
return seed;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
inline std::size_t float_hash_impl(T v)
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME select_hash_type<T>::type type;
|
||||
return float_hash_impl2(static_cast<type>(v));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user