Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r53161 - trunk/boost/functional/hash/detail
From: daniel_james_at_[hidden]
Date: 2009-05-21 17:22:05


Author: danieljames
Date: 2009-05-21 17:22:04 EDT (Thu, 21 May 2009)
New Revision: 53161
URL: http://svn.boost.org/trac/boost/changeset/53161

Log:
Try to automatically detect which float functions are available.
Text files modified:
   trunk/boost/functional/hash/detail/float_functions.hpp | 316 ++++++++++++++++++++++-----------------
   trunk/boost/functional/hash/detail/hash_float_generic.hpp | 24 ++-
   2 files changed, 196 insertions(+), 144 deletions(-)

Modified: trunk/boost/functional/hash/detail/float_functions.hpp
==============================================================================
--- trunk/boost/functional/hash/detail/float_functions.hpp (original)
+++ trunk/boost/functional/hash/detail/float_functions.hpp 2009-05-21 17:22:04 EDT (Thu, 21 May 2009)
@@ -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.
-
-// 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
+// The following tries to automatically detect which are available.
 
-// 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
-
-// libstdc++ (gcc 3.0 onwards, I think)
-#elif defined(__GLIBCPP__) || defined(__GLIBCXX__)
-# define BOOST_HASH_USE_OVERLOAD_FLOAT_FUNCS
-
-// 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
-
-// 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)
- {
- 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
- }
-
- inline double call_ldexp(double v, int exp)
- {
- using namespace std;
- return ldexp(v, exp);
- }
-
- 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
- }
-
- 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
- }
+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).
+
+ struct none {};
+
+ none ldexpf(int, int);
+ none ldexpl(int, int);
+ none frexpf(int, int*);
+ none frexpl(int, int*);
 
- inline double call_frexp(double v, int* exp)
- {
- using namespace std;
- return frexp(v, exp);
- }
+ template <class Float> none ldexp(Float, int);
+ template <class Float> none frexp(Float, int*);
+}
 
- inline long double call_frexp(long double v, int* exp)
- {
- using namespace std;
-#if defined(BOOST_HASH_USE_OVERLOAD_FLOAT_FUNCS)
- return frexp(v, exp);
-#else
- return frexpl(v, exp);
-#endif
- }
+namespace boost {
+ namespace hash_detail {
+ namespace detect {
+ using namespace std;
+ 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); \
+ } \
+ }; \
+ }
+
+ 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
+ }
+
+ // check
+ //
+ // Use in select_impl to help old compilers with a value template.
+
+ template <typename Float, typename Access>
+ struct check : Access::BOOST_NESTED_TEMPLATE check<Float> {};
+
+ // found_impl
+ //
+ // Used in select_impl when an appropriate function has
+ // been found.
+
+ template <typename Float, typename Access>
+ struct found_impl
+ {
+ // 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

Modified: trunk/boost/functional/hash/detail/hash_float_generic.hpp
==============================================================================
--- trunk/boost/functional/hash/detail/hash_float_generic.hpp (original)
+++ trunk/boost/functional/hash/detail/hash_float_generic.hpp 2009-05-21 17:22:04 EDT (Thu, 21 May 2009)
@@ -34,14 +34,17 @@
         }
 
         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 @@
             // 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 @@
 
             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 @@
             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));
         }
     }
 }
@@ -82,4 +90,4 @@
 #pragma warning(pop)
 #endif
 
-#endif
\ No newline at end of file
+#endif


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk