From 40c13d31c580d904d0c400f6bab1addf1535cf69 Mon Sep 17 00:00:00 2001 From: Howard Hinnant Date: Mon, 5 Dec 2011 00:08:45 +0000 Subject: [PATCH] Starting using murmur2 when combining multiple size_t's into a single hash, and also for basic_string. Also made hash ever so slighly more portable. I had to tweak one test which is questionable (definitely not portable) anyway. git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@145795 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/memory | 95 ++++++++++++++++++- include/string | 12 +-- include/thread | 9 +- .../unord.hash/integral.pass.cpp | 3 +- 4 files changed, 101 insertions(+), 18 deletions(-) diff --git a/include/memory b/include/memory index bab71b4da..e6cfa07de 100644 --- a/include/memory +++ b/include/memory @@ -2719,6 +2719,95 @@ operator>=(const unique_ptr<_T1, _D1>& __x, const unique_ptr<_T2, _D2>& __y) {re template struct hash; +template +struct __murmur2; + +template +struct __murmur2<_Size, 32> +{ + _Size operator()(const void* __key, _Size __len); +}; + +template +_Size +__murmur2<_Size, 32>::operator()(const void* __key, _Size __len) +{ + const _Size __m = 0x5bd1e995; + const _Size __r = 24; + _Size __h = __len; + const unsigned char* __data = static_cast(__key); + for (; __len >= 4; __data += 4, __len -= 4) + { + _Size __k = *(const _Size*)__data; + __k *= __m; + __k ^= __k >> __r; + __k *= __m; + __h *= __m; + __h ^= __k; + } + switch (__len) + { + case 3: + __h ^= __data[2] << 16; + case 2: + __h ^= __data[1] << 8; + case 1: + __h ^= __data[0]; + __h *= __m; + } + __h ^= __h >> 13; + __h *= __m; + __h ^= __h >> 15; + return __h; +} + +template +struct __murmur2<_Size, 64> +{ + _Size operator()(const void* __key, _Size __len); +}; + +template +_Size +__murmur2<_Size, 64>::operator()(const void* __key, _Size __len) +{ + const _Size __m = 0xc6a4a7935bd1e995ull; + const _Size __r = 47; + _Size __h = __len * __m; + const unsigned char* __data = static_cast(__key); + for (; __len >= 8; __data += 8, __len -= 8) + { + _Size __k = *(const _Size*)__data; + __k *= __m; + __k ^= __k >> __r; + __k *= __m; + __h ^= __k; + __h *= __m; + } + switch (__len) + { + case 7: + __h ^= __data[6] << 48; + case 6: + __h ^= __data[5] << 40; + case 5: + __h ^= __data[4] << 32; + case 4: + __h ^= __data[3] << 24; + case 3: + __h ^= __data[2] << 16; + case 2: + __h ^= __data[1] << 8; + case 1: + __h ^= __data[0]; + __h *= __m; + } + __h ^= __h >> __r; + __h *= __m; + __h ^= __h >> __r; + return __h; +} + template struct __scalar_hash; @@ -2774,7 +2863,7 @@ struct __scalar_hash<_Tp, 2> }; } __u; __u.__t = __v; - return __u.__a ^ __u.__b; + return __murmur2()(&__u, sizeof(__u)); } }; @@ -2796,7 +2885,7 @@ struct __scalar_hash<_Tp, 3> }; } __u; __u.__t = __v; - return __u.__a ^ __u.__b ^ __u.__c; + return __murmur2()(&__u, sizeof(__u)); } }; @@ -2819,7 +2908,7 @@ struct __scalar_hash<_Tp, 4> }; } __u; __u.__t = __v; - return __u.__a ^ __u.__b ^ __u.__c ^ __u.__d; + return __murmur2()(&__u, sizeof(__u)); } }; diff --git a/include/string b/include/string index 575b9e15e..4457e4ade 100644 --- a/include/string +++ b/include/string @@ -3915,16 +3915,8 @@ template template size_t _LIBCPP_INLINE_VISIBILITY __do_string_hash(_Ptr __p, _Ptr __e) { - size_t __r = 0; - const size_t __sr = __CHAR_BIT__ * sizeof(size_t) - 8; - const size_t __m = size_t(0xF) << (__sr + 4); - for (; __p != __e; ++__p) - { - __r = (__r << 4) + *__p; - size_t __g = __r & __m; - __r ^= __g | (__g >> __sr); - } - return __r; + typedef typename iterator_traits<_Ptr>::value_type value_type; + return __murmur2()(__p, (__e-__p)*sizeof(value_type)); } template diff --git a/include/thread b/include/thread index 2e8284692..23b191589 100644 --- a/include/thread +++ b/include/thread @@ -183,6 +183,9 @@ __thread_id get_id(); } // this_thread +class _LIBCPP_VISIBLE __thread_id; +template<> struct _LIBCPP_VISIBLE hash<__thread_id>; + class _LIBCPP_VISIBLE __thread_id { // FIXME: pthread_t is a pointer on Darwin but a long on Linux. @@ -226,10 +229,9 @@ private: friend __thread_id this_thread::get_id(); friend class _LIBCPP_VISIBLE thread; + friend struct _LIBCPP_VISIBLE hash<__thread_id>; }; -template struct hash; - template<> struct _LIBCPP_VISIBLE hash<__thread_id> : public unary_function<__thread_id, size_t> @@ -237,8 +239,7 @@ struct _LIBCPP_VISIBLE hash<__thread_id> _LIBCPP_INLINE_VISIBILITY size_t operator()(__thread_id __v) const { - const size_t* const __p = reinterpret_cast(&__v); - return *__p; + return hash()(__v.__id_); } }; diff --git a/test/utilities/function.objects/unord.hash/integral.pass.cpp b/test/utilities/function.objects/unord.hash/integral.pass.cpp index 358253ad6..e5f7ca616 100644 --- a/test/utilities/function.objects/unord.hash/integral.pass.cpp +++ b/test/utilities/function.objects/unord.hash/integral.pass.cpp @@ -33,7 +33,8 @@ test() for (int i = 0; i <= 5; ++i) { T t(i); - assert(h(t) == t); + if (sizeof(T) <= sizeof(std::size_t)) + assert(h(t) == t); } }