Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r53247 - in trunk: boost/functional/hash/detail libs/functional/hash/test
From: daniel_james_at_[hidden]
Date: 2009-05-25 09:45:18


Author: danieljames
Date: 2009-05-25 09:45:16 EDT (Mon, 25 May 2009)
New Revision: 53247
URL: http://svn.boost.org/trac/boost/changeset/53247

Log:
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.
Text files modified:
   trunk/boost/functional/hash/detail/float_functions.hpp | 381 +++++++++++++++++----------------------
   trunk/boost/functional/hash/detail/limits.hpp | 2
   trunk/libs/functional/hash/test/hash_float_test.hpp | 21 ++
   3 files changed, 192 insertions(+), 212 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-25 09:45:16 EDT (Mon, 25 May 2009)
@@ -8,8 +8,6 @@
 
 #include <boost/config.hpp>
 #include <boost/config/no_tr1/cmath.hpp>
-#include <boost/type_traits/ice.hpp>
-#include <boost/detail/select_type.hpp>
 
 #if defined(_MSC_VER) && (_MSC_VER >= 1020)
 # pragma once
@@ -22,240 +20,203 @@
 //
 // The following tries to automatically detect which are available.
 
-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 {};
-
-#if !defined(ldexpf)
- none ldexpf(int, int);
-#endif
-#if !defined(ldexpl)
- none ldexpl(int, int);
-#endif
-#if !defined(frexpf)
- none frexpf(int, int*);
-#endif
-#if !defined(frexpl)
- none frexpl(int, int*);
-#endif
-
- template <class Float> none ldexp(Float, int);
- template <class Float> none frexp(Float, int*);
-}
-
 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<BOOST_HASH_DETECT_FLOAT_FUNCTIONS::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); \
- } \
- }; \
- }
-
-#define BOOST_HASH_CALL_FLOAT_MACRO(func, type, type2) \
- struct func##_access { \
- template <typename Float> \
- struct check { \
- BOOST_STATIC_CONSTANT(bool, value = true); \
- }; \
- \
- template <typename Float> \
- struct call \
- { \
- Float operator()(Float a, type2 b) const \
- { \
- return func(a, b); \
- } \
- }; \
- }
 
-#if defined(ldexpf)
- BOOST_HASH_CALL_FLOAT_MACRO(ldexpf, float, int);
-#else
- BOOST_HASH_CALL_FLOAT_FUNC(ldexpf, int);
-#endif
+ // Returned by dummy versions of the float functions.
+
+ struct not_found {
+ // Implicitly convertible to float and long double in order to avoid
+ // a compile error when the dummy float functions are used.
 
-#if defined(ldexpl)
- BOOST_HASH_CALL_FLOAT_MACRO(ldexpl, long double, int);
-#else
- BOOST_HASH_CALL_FLOAT_FUNC(ldexpl, int);
-#endif
+ inline operator float() const { return 0; }
+ inline operator long double() const { return 0; }
+ };
+
+ // A type for detecting the return type of functions.
 
-#if defined(frexpf)
- BOOST_HASH_CALL_FLOAT_MACRO(frexpf, float, int*);
-#else
- BOOST_HASH_CALL_FLOAT_FUNC(frexpf, int*);
-#endif
+ 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<boost::hash_detail::not_found> { char x[40]; };
+
+ // Used to convert the return type of a function to a type for sizeof.
 
-#if defined(frexpl)
- BOOST_HASH_CALL_FLOAT_MACRO(frexpl, long double, int*);
-#else
- BOOST_HASH_CALL_FLOAT_FUNC(frexpl, int*);
-#endif
+ template <typename T> is<T> float_type(T);
 
- BOOST_HASH_CALL_FLOAT_FUNC(ldexp, int);
- BOOST_HASH_CALL_FLOAT_FUNC(frexp, int*);
-
-#undef BOOST_CALL_HAS_FLOAT_FUNC
- }
-
- // check
+ // call_ldexp
         //
- // Use in select_impl to help old compilers with a value template.
+ // This will get specialized for float and long double
         
- 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
+ template <typename Float> struct call_ldexp
         {
- // Ignore further types
-
- template <typename Float2, typename Access2>
- struct x {
- typedef found_impl type;
- };
+ typedef double float_type;
             
- // Use Access for result
-
- struct result : Access::BOOST_NESTED_TEMPLATE call<Float>
+ inline double operator()(double a, int b) const
             {
- BOOST_STATIC_CONSTANT(bool, value = true);
- };
+ using namespace std;
+ return ldexp(a, b);
+ }
         };
-
- // select_impl
+
+ // call_frexp
         //
- // Used to choose which floating point function to use for a particular
- // floating point type.
+ // This will get specialized for float and long double
 
- struct select_impl
+ template <typename Float> struct call_frexp
         {
- // 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 result
+ typedef double float_type;
+
+ inline double operator()(double a, int* b) const
             {
- BOOST_STATIC_CONSTANT(bool, value = false);
- };
+ using namespace std;
+ return frexp(a, b);
+ }
         };
+ }
+}
+
+// A namespace for dummy functions to detect when the actual function we want
+// isn't available. ldexpl, ldexpf etc. might be added tby the macros below.
+//
+// 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).
 
- // 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
+namespace BOOST_HASH_DETECT_FLOAT_FUNCTIONS {
+ template <class Float> boost::hash_detail::not_found ldexp(Float, int);
+ template <class Float> boost::hash_detail::not_found frexp(Float, int*);
+}
 
- template <typename Float>
- struct call_ldexp;
+// Macros for generating specializations of call_ldexp and call_frexp.
+//
+// check_cpp and check_c99 check if the C++ or C99 functions are available.
+//
+// Then the call_* functions select an appropriate implementation.
+//
+// I used c99_func in a few places just to get a unique name.
 
- template <>
- struct call_ldexp<float> : select_impl
- :: x<float, detect::ldexp_access>::type
- :: x<float, detect::ldexpf_access>::type
- :: result {};
+#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); \
+} \
+ \
+namespace boost { \
+ namespace hash_detail { \
+ namespace c99_func##_detect { \
+ using namespace std; \
+ using namespace BOOST_HASH_DETECT_FLOAT_FUNCTIONS; \
+ \
+ struct check { \
+ static type1 x; \
+ static type2 y; \
+ BOOST_STATIC_CONSTANT(bool, cpp = \
+ sizeof(float_type(cpp_func(x,y))) \
+ == sizeof(is<type1>)); \
+ BOOST_STATIC_CONSTANT(bool, c99 = \
+ sizeof(float_type(c99_func(x,y))) \
+ == sizeof(is<type1>)); \
+ }; \
+ } \
+ \
+ template <bool x> \
+ struct call_##c99_func##_c99 : \
+ call_##cpp_func<double> {}; \
+ \
+ template <> \
+ struct call_##c99_func##_c99<true> { \
+ typedef type1 float_type; \
+ \
+ inline type1 operator()(type1 a, type2 b) const \
+ { \
+ return c99_func(a, b); \
+ } \
+ }; \
+ \
+ template <bool x> \
+ struct call_##c99_func##_cpp : \
+ call_##c99_func##_c99< \
+ ::boost::hash_detail::c99_func##_detect::check::c99 \
+ > {}; \
+ \
+ template <> \
+ struct call_##c99_func##_cpp<true> { \
+ typedef type1 float_type; \
+ \
+ inline type1 operator()(type1 a, type2 b) const \
+ { \
+ return cpp_func(a, b); \
+ } \
+ }; \
+ \
+ template <> \
+ struct call_##cpp_func<type1> : \
+ call_##c99_func##_cpp< \
+ ::boost::hash_detail::c99_func##_detect::check::cpp \
+ > {}; \
+ } \
+}
 
- template <>
- struct call_ldexp<double> : select_impl
- :: x<double, detect::ldexp_access>::type
- :: result {};
+#define BOOST_HASH_CALL_FLOAT_MACRO(cpp_func, c99_func, type1, type2) \
+namespace boost { \
+ namespace hash_detail { \
+ \
+ template <> \
+ struct call_##cpp_func<type1> { \
+ typedef type1 float_type; \
+ inline type1 operator()(type1 x, type2 y) const { \
+ return c99_func(x, y); \
+ } \
+ }; \
+ } \
+}
 
- template <>
- struct call_ldexp<long double> : select_impl
- :: x<long double, detect::ldexp_access>::type
- :: x<long double, detect::ldexpl_access>::type
- :: result {};
+#if defined(ldexpf)
+BOOST_HASH_CALL_FLOAT_MACRO(ldexp, ldexpf, float, int)
+#else
+BOOST_HASH_CALL_FLOAT_FUNC(ldexp, ldexpf, float, int)
+#endif
 
+#if defined(ldexpl)
+BOOST_HASH_CALL_FLOAT_MACRO(ldexp, ldexpl, long double, int)
+#else
+BOOST_HASH_CALL_FLOAT_FUNC(ldexp, ldexpl, long double, int)
+#endif
 
- // 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
+#if defined(frexpf)
+BOOST_HASH_CALL_FLOAT_MACRO(frexp, frexpf, float, int*)
+#else
+BOOST_HASH_CALL_FLOAT_FUNC(frexp, frexpf, float, int*)
+#endif
 
- template <typename Float>
- struct call_frexp;
+#if defined(frexpl)
+BOOST_HASH_CALL_FLOAT_MACRO(frexp, frexpl, long double, int*)
+#else
+BOOST_HASH_CALL_FLOAT_FUNC(frexp, frexpl, long double, int*)
+#endif
 
- template <>
- struct call_frexp<float> : select_impl
- :: x<float, detect::frexp_access>::type
- :: x<float, detect::frexpf_access>::type
- :: result {};
+#undef BOOST_HASH_CALL_FLOAT_MACRO
+#undef BOOST_HASH_CALL_FLOAT_FUNC
 
- template <>
- struct call_frexp<double> : select_impl
- :: x<double, detect::frexp_access>::type
- :: result {};
 
- template <>
- struct call_frexp<long double> : select_impl
- :: x<long double, detect::frexp_access>::type
- :: x<long double, detect::frexpl_access>::type
- :: result {};
+namespace boost
+{
+ namespace hash_detail
+ {
+ template <typename Float1, typename Float2>
+ struct select_hash_type_impl {
+ typedef double type;
+ };
 
- // has_float_functions
- //
- // Is there an overload of frexp and ldexp for the given float type.
+ template <>
+ struct select_hash_type_impl<float, float> {
+ typedef 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
- ));
+ template <>
+ struct select_hash_type_impl<long double, long double> {
+ typedef long double type;
         };
 
 
@@ -265,12 +226,10 @@
         // 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
- > {};
+ struct select_hash_type : select_hash_type_impl<
+ BOOST_DEDUCED_TYPENAME call_ldexp<Float>::float_type,
+ BOOST_DEDUCED_TYPENAME call_frexp<Float>::float_type
+ > {};
     }
 }
 

Modified: trunk/boost/functional/hash/detail/limits.hpp
==============================================================================
--- trunk/boost/functional/hash/detail/limits.hpp (original)
+++ trunk/boost/functional/hash/detail/limits.hpp 2009-05-25 09:45:16 EDT (Mon, 25 May 2009)
@@ -58,4 +58,4 @@
     }
 }
 
-#endif
\ No newline at end of file
+#endif

Modified: trunk/libs/functional/hash/test/hash_float_test.hpp
==============================================================================
--- trunk/libs/functional/hash/test/hash_float_test.hpp (original)
+++ trunk/libs/functional/hash/test/hash_float_test.hpp 2009-05-25 09:45:16 EDT (Mon, 25 May 2009)
@@ -23,6 +23,10 @@
 #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)
 {
@@ -36,6 +40,15 @@
         <<"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;
@@ -112,6 +125,14 @@
     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-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