aboutsummaryrefslogtreecommitdiff
path: root/libstdc++-v3
diff options
context:
space:
mode:
authorPaolo Carlini <pcarlini@suse.de>2005-07-15 00:05:44 +0000
committerPaolo Carlini <paolo@gcc.gnu.org>2005-07-15 00:05:44 +0000
commitdbd160bff8ca492b8e14fe347f0995d70f23065b (patch)
treefd4d3d335b870f0c8c475f54839d0be2acaef633 /libstdc++-v3
parent06277571f475f065d79e7d7b107200b2eb970580 (diff)
downloadgcc-dbd160bff8ca492b8e14fe347f0995d70f23065b.zip
gcc-dbd160bff8ca492b8e14fe347f0995d70f23065b.tar.gz
gcc-dbd160bff8ca492b8e14fe347f0995d70f23065b.tar.bz2
PR libstdc++/21193 (float, double, long double)
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
Diffstat (limited to 'libstdc++-v3')
-rw-r--r--libstdc++-v3/ChangeLog9
-rw-r--r--libstdc++-v3/include/tr1/functional76
2 files changed, 77 insertions, 8 deletions
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog
index 18bd770..15862e3 100644
--- a/libstdc++-v3/ChangeLog
+++ b/libstdc++-v3/ChangeLog
@@ -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)
diff --git a/libstdc++-v3/include/tr1/functional b/libstdc++-v3/include/tr1/functional
index 6866357..f609fd3 100644
--- a/libstdc++-v3/include/tr1/functional
+++ b/libstdc++-v3/include/tr1/functional
@@ -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;
+ }
+ };
}
}