PR libstdc++/21193 (float, double, long double)
authorPaolo Carlini <pcarlini@suse.de>
Fri, 15 Jul 2005 00:05:44 +0000 (00:05 +0000)
committerPaolo Carlini <paolo@gcc.gnu.org>
Fri, 15 Jul 2005 00:05:44 +0000 (00:05 +0000)
2005-07-14  Paolo Carlini  <pcarlini@suse.de>

PR libstdc++/21193 (float, double, long double)
* include/tr1/functional (hash<float>, hash<double>):
Reimplement exploiting the Fnv_hash<>::hash helper.
(hash<long double>): Reimplement using frexp (in this
case, due to random padding bits, the former approach
is not generally viable).

From-SVN: r102043

libstdc++-v3/ChangeLog
libstdc++-v3/include/tr1/functional

index 18bd770..15862e3 100644 (file)
@@ -1,3 +1,12 @@
+2005-07-14  Paolo Carlini  <pcarlini@suse.de>
+
+       PR libstdc++/21193 (float, double, long double)
+       * include/tr1/functional (hash<float>, hash<double>):
+       Reimplement exploiting the Fnv_hash<>::hash helper.
+       (hash<long double>): Reimplement using frexp (in this
+       case, due to random padding bits, the former approach
+       is not generally viable).
+
 2005-07-13  Paolo Carlini  <pcarlini@suse.de>
 
        PR libstdc++/21193 (string & wstring)
index 6866357..f609fd3 100644 (file)
@@ -40,6 +40,7 @@
 #include <bits/cpp_type_traits.h>
 #include <string>               // for std::tr1::hash
 #include <cstdlib>              // for std::abort
+#include <cmath>                // for std::frexp
 #include <tr1/tuple>
 
 namespace std
@@ -1116,10 +1117,6 @@ namespace tr1
   tr1_hashtable_define_trivial_hash(unsigned int);
   tr1_hashtable_define_trivial_hash(unsigned long);
 
-  tr1_hashtable_define_trivial_hash(float);
-  tr1_hashtable_define_trivial_hash(double);
-  tr1_hashtable_define_trivial_hash(long double);
-
 #undef tr1_hashtable_define_trivial_hash
 
   template<typename T>
@@ -1133,7 +1130,7 @@ namespace tr1
   // Fowler / Noll / Vo (FNV) Hash (type FNV-1a)
   // (used by the next specializations of std::tr1::hash<>)
 
-  // Dummy generic implementation (for sizeof(size_t) != 4,8).
+  // Dummy generic implementation (for sizeof(size_t) != 4, 8).
   template<std::size_t = sizeof(std::size_t)>
     struct Fnv_hash
     {
@@ -1179,9 +1176,9 @@ namespace tr1
       }
     };
 
-  // XXX String hash probably shouldn't be an inline member function,
-  // since it's nontrivial.  Once we have the framework for TR1 .cc
-  // files, this should go in one.
+  // XXX String and floating point hashes probably shouldn't be inline
+  // member functions, since are nontrivial.  Once we have the framework
+  // for TR1 .cc files, these should go in one.
   template<>
     struct hash<std::string>
     {
@@ -1203,6 +1200,69 @@ namespace tr1
     };
 #endif
 
+  template<>
+    struct hash<float>
+    {
+      std::size_t
+      operator()(float fval) const
+      {
+       std::size_t result = 0;
+
+       // 0 and -0 both hash to zero.
+       if (fval != 0.0f)
+         result = Fnv_hash<>::hash(reinterpret_cast<const char*>(&fval),
+                                   sizeof(fval));
+       return result;
+      }
+    };
+
+  template<>
+    struct hash<double>
+    {
+      std::size_t
+      operator()(double dval) const
+      {
+       std::size_t result = 0;
+
+       // 0 and -0 both hash to zero.
+       if (dval != 0.0)
+         result = Fnv_hash<>::hash(reinterpret_cast<const char*>(&dval),
+                                   sizeof(dval));
+       return result;
+      }
+    };
+
+  // For long double, careful with random padding bits (e.g., on x86,
+  // 10 bytes -> 12 bytes) and resort to frexp.
+  template<>
+    struct hash<long double>
+    {
+      std::size_t
+      operator()(long double ldval) const
+      {
+       std::size_t result = 0;
+
+       int exponent;
+       ldval = std::frexp(ldval, &exponent);
+       ldval = ldval < 0.0l ? -(ldval + 0.5l) : ldval;
+
+       const long double mult = std::numeric_limits<std::size_t>::max() + 1.0l;
+       ldval *= mult;
+
+       // Try to use all the bits of the mantissa (really necessary only
+       // on 32-bit targets, at least for 80-bit floating point formats).
+       const std::size_t hibits = (std::size_t)ldval;
+       ldval = (ldval - (long double)hibits) * mult;
+
+       const std::size_t coeff =
+         (std::numeric_limits<std::size_t>::max()
+          / std::numeric_limits<long double>::max_exponent);
+
+       result = hibits + (std::size_t)ldval + coeff * exponent;
+
+       return result;
+      }
+    };
 }
 }