From 3fb4990579829b62c9243bfc44ee410febadfef9 Mon Sep 17 00:00:00 2001 From: greg Date: Mon, 29 Apr 2019 22:01:08 -0400 Subject: [PATCH] reorganize headers so that phmap_fwd_decl.h is more usable --- README.md | 2 +- parallel_hashmap/phmap.h | 238 +--------------------------- parallel_hashmap/phmap_fwd_decl.h | 5 + parallel_hashmap/phmap_utils.h | 253 ++++++++++++++++++++++++++++-- 4 files changed, 247 insertions(+), 251 deletions(-) diff --git a/README.md b/README.md index 9f77a30..05ae2de 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ This repository aims to provide an set of excellent hash map implementations, wi - Supports **heterogeneous lookup** -- Easy to **forward declare**: just include `phmap_fwd_decl.h` in your header files to forward declare Parallel Hashmap containers. This header is only 111 lines including comments. +- Easy to **forward declare**: just include `phmap_fwd_decl.h` in your header files to forward declare Parallel Hashmap containers. - **Tested** on Windows (vs2015 & vs2017), linux (g++ 5, 6, 7, 8, clang++ 3.9, 4.0, 5.0) and MacOS (g++ and clang++) - click on travis and appveyor icons above for detailed test status. diff --git a/parallel_hashmap/phmap.h b/parallel_hashmap/phmap.h index d046ef4..0263eaf 100644 --- a/parallel_hashmap/phmap.h +++ b/parallel_hashmap/phmap.h @@ -51,6 +51,7 @@ #include "phmap_bits.h" #include "phmap_base.h" #include "phmap_fwd_decl.h" +#include "phmap_utils.h" #if PHMAP_HAVE_STD_STRING_VIEW #include @@ -58,243 +59,6 @@ namespace phmap { -// --------------------------------------------------------------- -// --------------------------------------------------------------- -template -struct phmap_mix -{ - inline size_t operator()(size_t) const; -}; - -template<> -struct phmap_mix<4> -{ - inline size_t operator()(size_t a) const - { - static constexpr uint64_t kmul = 0xcc9e2d51UL; - // static constexpr uint64_t kmul = 0x3B9ACB93UL; // [greg] my own random prime - uint64_t l = a * kmul; - return static_cast(l ^ (l >> 32)); - } -}; - -#if defined(PHMAP_HAS_UMUL128) - template<> - struct phmap_mix<8> - { - // Very fast mixing (similar to Abseil) - inline size_t operator()(size_t a) const - { - static constexpr uint64_t k = 0xde5fb9d2630458e9ULL; - // static constexpr uint64_t k = 0x7C9D0BF0567102A5ULL; // [greg] my own random prime - uint64_t h; - uint64_t l = umul128(a, k, &h); - return static_cast(h + l); - } - }; -#else - template<> - struct phmap_mix<8> - { - inline size_t operator()(size_t a) const - { - a = (~a) + (a << 21); // a = (a << 21) - a - 1; - a = a ^ (a >> 24); - a = (a + (a << 3)) + (a << 8); // a * 265 - a = a ^ (a >> 14); - a = (a + (a << 2)) + (a << 4); // a * 21 - a = a ^ (a >> 28); - a = a + (a << 31); - return static_cast(a); - } - }; -#endif - -// -------------------------------------------- -template -struct fold_if_needed -{ - inline size_t operator()(uint64_t) const; -}; - -template<> -struct fold_if_needed<4> -{ - inline size_t operator()(uint64_t a) const - { - return static_cast(a ^ (a >> 32)); - } -}; - -template<> -struct fold_if_needed<8> -{ - inline size_t operator()(uint64_t a) const - { - return static_cast(a); - } -}; - -// --------------------------------------------------------------- -// see if class T has a hash_value() friend method -// --------------------------------------------------------------- -template -struct has_hash_value -{ -private: - typedef std::true_type yes; - typedef std::false_type no; - - template static auto test(int) -> decltype(hash_value(std::declval()) == 1, yes()); - - template static no test(...); - -public: - static constexpr bool value = std::is_same(0)), yes>::value; -}; - -// --------------------------------------------------------------- -// phmap::Hash -// --------------------------------------------------------------- -template -struct Hash -{ - template ::value, int>::type = 0> - size_t _hash(const T& val) const - { - return hash_value(val); - } - - template ::value, int>::type = 0> - size_t _hash(const T& val) const - { - return std::hash()(val); - } - - inline size_t operator()(const T& val) const - { - return _hash(val); - } -}; - -template -struct Hash -{ - inline size_t operator()(const T *val) const noexcept - { - return static_cast(reinterpret_cast(val)); - } -}; - -template -struct phmap_unary_function -{ - typedef ArgumentType argument_type; - typedef ResultType result_type; -}; - -template <> -struct Hash : public phmap_unary_function -{ - inline size_t operator()(bool val) const noexcept - { return static_cast(val); } -}; - -template <> -struct Hash : public phmap_unary_function -{ - inline size_t operator()(char val) const noexcept - { return static_cast(val); } -}; - -template <> -struct Hash : public phmap_unary_function -{ - inline size_t operator()(signed char val) const noexcept - { return static_cast(val); } -}; - -template <> -struct Hash : public phmap_unary_function -{ - inline size_t operator()(unsigned char val) const noexcept - { return static_cast(val); } -}; - -template <> -struct Hash : public phmap_unary_function -{ - inline size_t operator()(wchar_t val) const noexcept - { return static_cast(val); } -}; - -template <> -struct Hash : public phmap_unary_function -{ - inline size_t operator()(int16_t val) const noexcept - { return static_cast(val); } -}; - -template <> -struct Hash : public phmap_unary_function -{ - inline size_t operator()(uint16_t val) const noexcept - { return static_cast(val); } -}; - -template <> -struct Hash : public phmap_unary_function -{ - inline size_t operator()(int32_t val) const noexcept - { return static_cast(val); } -}; - -template <> -struct Hash : public phmap_unary_function -{ - inline size_t operator()(uint32_t val) const noexcept - { return static_cast(val); } -}; - -template <> -struct Hash : public phmap_unary_function -{ - inline size_t operator()(int64_t val) const noexcept - { return fold_if_needed()(static_cast(val)); } -}; - -template <> -struct Hash : public phmap_unary_function -{ - inline size_t operator()(uint64_t val) const noexcept - { return fold_if_needed()(val); } -}; - -template <> -struct Hash : public phmap_unary_function -{ - inline size_t operator()(float val) const noexcept - { - // -0.0 and 0.0 should return same hash - uint32_t *as_int = reinterpret_cast(&val); - return (val == 0) ? static_cast(0) : - static_cast(*as_int); - } -}; - -template <> -struct Hash : public phmap_unary_function -{ - inline size_t operator()(double val) const noexcept - { - // -0.0 and 0.0 should return same hash - uint64_t *as_int = reinterpret_cast(&val); - return (val == 0) ? static_cast(0) : - fold_if_needed()(*as_int); - } -}; - - namespace container_internal { // -------------------------------------------------------------------------- diff --git a/parallel_hashmap/phmap_fwd_decl.h b/parallel_hashmap/phmap_fwd_decl.h index 5a072f5..a9fb514 100644 --- a/parallel_hashmap/phmap_fwd_decl.h +++ b/parallel_hashmap/phmap_fwd_decl.h @@ -11,10 +11,15 @@ // https://www.apache.org/licenses/LICENSE-2.0 // --------------------------------------------------------------------------- +#include +#include + namespace phmap { template struct Hash; template struct EqualTo; + template using Allocator = typename std::allocator; + template using Pair = typename std::pair; class NullMutex; diff --git a/parallel_hashmap/phmap_utils.h b/parallel_hashmap/phmap_utils.h index 336d585..58dd5b5 100644 --- a/parallel_hashmap/phmap_utils.h +++ b/parallel_hashmap/phmap_utils.h @@ -19,22 +19,249 @@ // limitations under the License. // --------------------------------------------------------------------------- -#if defined(__APPLE__) - // forward declaration of std::hash does not work on mac. It is not really supposed - // to work, I know, but it is nice to reduce the amount of headers included. - #include -#else - #include // for size_t - - namespace std - { - template struct hash; - } -#endif +#include +#include +#include "phmap_bits.h" namespace phmap { +// --------------------------------------------------------------- +// --------------------------------------------------------------- +template +struct phmap_mix +{ + inline size_t operator()(size_t) const; +}; + +template<> +struct phmap_mix<4> +{ + inline size_t operator()(size_t a) const + { + static constexpr uint64_t kmul = 0xcc9e2d51UL; + // static constexpr uint64_t kmul = 0x3B9ACB93UL; // [greg] my own random prime + uint64_t l = a * kmul; + return static_cast(l ^ (l >> 32)); + } +}; + +#if defined(PHMAP_HAS_UMUL128) + template<> + struct phmap_mix<8> + { + // Very fast mixing (similar to Abseil) + inline size_t operator()(size_t a) const + { + static constexpr uint64_t k = 0xde5fb9d2630458e9ULL; + // static constexpr uint64_t k = 0x7C9D0BF0567102A5ULL; // [greg] my own random prime + uint64_t h; + uint64_t l = umul128(a, k, &h); + return static_cast(h + l); + } + }; +#else + template<> + struct phmap_mix<8> + { + inline size_t operator()(size_t a) const + { + a = (~a) + (a << 21); // a = (a << 21) - a - 1; + a = a ^ (a >> 24); + a = (a + (a << 3)) + (a << 8); // a * 265 + a = a ^ (a >> 14); + a = (a + (a << 2)) + (a << 4); // a * 21 + a = a ^ (a >> 28); + a = a + (a << 31); + return static_cast(a); + } + }; +#endif + +// -------------------------------------------- +template +struct fold_if_needed +{ + inline size_t operator()(uint64_t) const; +}; + +template<> +struct fold_if_needed<4> +{ + inline size_t operator()(uint64_t a) const + { + return static_cast(a ^ (a >> 32)); + } +}; + +template<> +struct fold_if_needed<8> +{ + inline size_t operator()(uint64_t a) const + { + return static_cast(a); + } +}; + +// --------------------------------------------------------------- +// see if class T has a hash_value() friend method +// --------------------------------------------------------------- +template +struct has_hash_value +{ +private: + typedef std::true_type yes; + typedef std::false_type no; + + template static auto test(int) -> decltype(hash_value(std::declval()) == 1, yes()); + + template static no test(...); + +public: + static constexpr bool value = std::is_same(0)), yes>::value; +}; + +// --------------------------------------------------------------- +// phmap::Hash +// --------------------------------------------------------------- +template +struct Hash +{ + template ::value, int>::type = 0> + size_t _hash(const T& val) const + { + return hash_value(val); + } + + template ::value, int>::type = 0> + size_t _hash(const T& val) const + { + return std::hash()(val); + } + + inline size_t operator()(const T& val) const + { + return _hash(val); + } +}; + +template +struct Hash +{ + inline size_t operator()(const T *val) const noexcept + { + return static_cast(reinterpret_cast(val)); + } +}; + +template +struct phmap_unary_function +{ + typedef ArgumentType argument_type; + typedef ResultType result_type; +}; + +template <> +struct Hash : public phmap_unary_function +{ + inline size_t operator()(bool val) const noexcept + { return static_cast(val); } +}; + +template <> +struct Hash : public phmap_unary_function +{ + inline size_t operator()(char val) const noexcept + { return static_cast(val); } +}; + +template <> +struct Hash : public phmap_unary_function +{ + inline size_t operator()(signed char val) const noexcept + { return static_cast(val); } +}; + +template <> +struct Hash : public phmap_unary_function +{ + inline size_t operator()(unsigned char val) const noexcept + { return static_cast(val); } +}; + +template <> +struct Hash : public phmap_unary_function +{ + inline size_t operator()(wchar_t val) const noexcept + { return static_cast(val); } +}; + +template <> +struct Hash : public phmap_unary_function +{ + inline size_t operator()(int16_t val) const noexcept + { return static_cast(val); } +}; + +template <> +struct Hash : public phmap_unary_function +{ + inline size_t operator()(uint16_t val) const noexcept + { return static_cast(val); } +}; + +template <> +struct Hash : public phmap_unary_function +{ + inline size_t operator()(int32_t val) const noexcept + { return static_cast(val); } +}; + +template <> +struct Hash : public phmap_unary_function +{ + inline size_t operator()(uint32_t val) const noexcept + { return static_cast(val); } +}; + +template <> +struct Hash : public phmap_unary_function +{ + inline size_t operator()(int64_t val) const noexcept + { return fold_if_needed()(static_cast(val)); } +}; + +template <> +struct Hash : public phmap_unary_function +{ + inline size_t operator()(uint64_t val) const noexcept + { return fold_if_needed()(val); } +}; + +template <> +struct Hash : public phmap_unary_function +{ + inline size_t operator()(float val) const noexcept + { + // -0.0 and 0.0 should return same hash + uint32_t *as_int = reinterpret_cast(&val); + return (val == 0) ? static_cast(0) : + static_cast(*as_int); + } +}; + +template <> +struct Hash : public phmap_unary_function +{ + inline size_t operator()(double val) const noexcept + { + // -0.0 and 0.0 should return same hash + uint64_t *as_int = reinterpret_cast(&val); + return (val == 0) ? static_cast(0) : + fold_if_needed()(*as_int); + } +}; + template struct Combiner { H operator()(H seed, size_t value); @@ -72,7 +299,7 @@ template H HashStateBase::combine(H seed, const T& v, const Ts&... vs) { return HashStateBase::combine(Combiner()( - seed, std::hash()(v)), vs...); + seed, phmap::Hash()(v)), vs...); } using HashState = HashStateBase;