#ifndef SPROUT_FUNCTIONAL_HASH_HASH_HPP #define SPROUT_FUNCTIONAL_HASH_HASH_HPP #include #include #include #include #include #include #include namespace sprout { namespace hash_detail { struct enable_hash_value { public: typedef std::size_t type; }; template struct basic_numbers {}; template struct basic_numbers< T, typename std::enable_if< (std::is_integral::value && sizeof(T) <= sizeof(std::size_t)) >::type > : public sprout::hash_detail::enable_hash_value {}; template struct long_numbers {}; template struct long_numbers< T, typename std::enable_if< (std::is_integral::value && std::is_signed::value && sizeof(T) > sizeof(std::size_t)) >::type > : public sprout::hash_detail::enable_hash_value {}; template struct ulong_numbers {}; template struct ulong_numbers< T, typename std::enable_if< (std::is_integral::value && std::is_unsigned::value && sizeof(T) > sizeof(std::size_t)) >::type > : public sprout::hash_detail::enable_hash_value {}; template struct float_numbers {}; template struct float_numbers< T, typename std::enable_if< (std::is_floating_point::value) >::type > : public sprout::hash_detail::enable_hash_value {}; } // namespace hash_detail // // hash_value // template inline SPROUT_CONSTEXPR typename sprout::hash_detail::basic_numbers::type hash_value(T); template inline SPROUT_CONSTEXPR typename sprout::hash_detail::long_numbers::type hash_value(T); template inline SPROUT_CONSTEXPR typename sprout::hash_detail::ulong_numbers::type hash_value(T); // template // inline SPROUT_CONSTEXPR typename sprout::hash_detail::float_numbers::type // hash_value(T); template< typename T, typename sprout::enabler_if::type>::value>::type > inline SPROUT_CONSTEXPR std::size_t hash_value(T&& v); template inline SPROUT_CONSTEXPR std::size_t hash_value(T const (&v)[N]); namespace hash_detail { template inline SPROUT_CONSTEXPR std::size_t hash_value_signed_2(T val, int length, std::size_t seed, T positive, std::size_t i) { return i > 0 ? hash_value_signed_2( val, length, seed ^ static_cast((positive >> i) + (seed << 6) + (seed >> 2)), positive, i - std::numeric_limits::digits ) : seed ^ static_cast(val + (seed << 6) + (seed >> 2)) ; } template inline SPROUT_CONSTEXPR std::size_t hash_value_signed_1(T val, int length, std::size_t seed, T positive) { return hash_value_signed_2(val, length, seed, positive, length * std::numeric_limits::digits); } template inline SPROUT_CONSTEXPR std::size_t hash_value_signed(T val) { return sprout::hash_detail::hash_value_signed_1( val, (std::numeric_limits::digits - 1) / std::numeric_limits::digits, 0, val < 0 ? -1 - val : val ); } template inline SPROUT_CONSTEXPR std::size_t hash_value_unsigned_2(T val, int length, std::size_t seed, std::size_t i) { return i > 0 ? hash_value_unsigned_2( val, length, seed ^ static_cast((val >> i) + (seed << 6) + (seed >> 2)), i - std::numeric_limits::digits ) : seed ^ static_cast(val + (seed << 6) + (seed >> 2)) ; } template inline SPROUT_CONSTEXPR std::size_t hash_value_unsigned_1(T val, int length, std::size_t seed) { return hash_value_unsigned_2(val, length, seed, length * std::numeric_limits::digits); } template inline SPROUT_CONSTEXPR std::size_t hash_value_unsigned(T val) { return sprout::hash_detail::hash_value_unsigned_1( val, (std::numeric_limits::digits - 1) / std::numeric_limits::digits, 0 ); } inline std::size_t hash_value_pointer_1(std::size_t x) { return x + (x >> 3); } template std::size_t hash_value_pointer(T const* v) { return sprout::hash_detail::hash_value_pointer_1(static_cast(reinterpret_cast(v))); } } // namespace hash_detail // // hash_value // template inline SPROUT_CONSTEXPR typename sprout::hash_detail::basic_numbers::type hash_value(T v) { return static_cast(v); } template inline SPROUT_CONSTEXPR typename sprout::hash_detail::long_numbers::type hash_value(T v) { return sprout::hash_detail::hash_value_signed(v); } template inline SPROUT_CONSTEXPR typename sprout::hash_detail::ulong_numbers::type hash_value(T v) { return sprout::hash_detail::hash_value_unsigned(v); } // template // inline SPROUT_CONSTEXPR typename sprout::hash_detail::float_numbers::type // hash_value(T v) { // return sprout::hash_detail::hash_value_float(v); // } template< typename T, typename sprout::enabler_if::type>::value>::type = sprout::enabler > inline SPROUT_CONSTEXPR std::size_t hash_value(T&& v) { return sprout::hash_detail::hash_value_pointer(v); } template inline SPROUT_CONSTEXPR std::size_t hash_value(T const (&v)[N]) { return sprout::hash_range(&v[0], &v[0] + N); } // // to_hash // template inline SPROUT_CONSTEXPR std::size_t to_hash(T const& v) { using sprout::hash_value; return hash_value(v); } // // hash_combine // template inline SPROUT_CONSTEXPR std::size_t hash_combine(std::size_t seed, T const& v) { return seed ^ (sprout::to_hash(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2)); } // // hash_range // template inline SPROUT_CONSTEXPR std::size_t hash_range(std::size_t seed, Iterator first, Iterator last) { return first != last ? sprout::hash_range(sprout::hash_combine(seed, *first), sprout::next(first), last) : seed ; } template inline SPROUT_CONSTEXPR std::size_t hash_range(Iterator first, Iterator last) { return sprout::hash_range(0, first, last); } namespace detail { template inline SPROUT_CONSTEXPR std::size_t hash_values_combine_impl(std::size_t seed, T const& v) { return sprout::hash_combine(seed, v); } template inline SPROUT_CONSTEXPR std::size_t hash_values_combine_impl(std::size_t seed, Head const& head, Tail const&... tail) { return sprout::detail::hash_values_combine_impl(sprout::hash_combine(seed, head), tail...); } } // namespace detail // // hash_values_combine // template inline SPROUT_CONSTEXPR std::size_t hash_values_combine(std::size_t seed, Args const&... args) { return sprout::detail::hash_values_combine_impl(seed, args...); } // // hash_values // template inline SPROUT_CONSTEXPR std::size_t hash_values(Args const&... args) { return sprout::hash_values_combine(0, args...); } // // hash // template struct hash { public: typedef T argument_type; typedef std::size_t result_type; public: SPROUT_CONSTEXPR std::size_t operator()(T const& v) const { return sprout::to_hash(v); } }; template struct hash : public sprout::hash {}; template struct hash : public sprout::hash {}; template struct hash : public sprout::hash {}; #define SPROUT_HASH_SPECIALIZE(type) \ template<> \ struct hash { \ public: \ typedef type argument_type; \ typedef std::size_t result_type; \ public: \ SPROUT_CONSTEXPR std::size_t operator()(type v) const { \ return sprout::to_hash(v); \ } \ } #define SPROUT_HASH_SPECIALIZE_REF(type) \ template<> \ struct hash { \ public: \ typedef type argument_type; \ typedef std::size_t result_type; \ public: \ SPROUT_CONSTEXPR std::size_t operator()(type const& v) const { \ return sprout::to_hash(v); \ } \ } SPROUT_HASH_SPECIALIZE(bool); SPROUT_HASH_SPECIALIZE(char); SPROUT_HASH_SPECIALIZE(signed char); SPROUT_HASH_SPECIALIZE(unsigned char); SPROUT_HASH_SPECIALIZE(char16_t); SPROUT_HASH_SPECIALIZE(char32_t); SPROUT_HASH_SPECIALIZE(wchar_t); SPROUT_HASH_SPECIALIZE(short); SPROUT_HASH_SPECIALIZE(unsigned short); SPROUT_HASH_SPECIALIZE(int); SPROUT_HASH_SPECIALIZE(unsigned int); SPROUT_HASH_SPECIALIZE(long); SPROUT_HASH_SPECIALIZE(unsigned long); SPROUT_HASH_SPECIALIZE(long long); SPROUT_HASH_SPECIALIZE(unsigned long long); #undef SPROUT_HASH_SPECIALIZE #undef SPROUT_HASH_SPECIALIZE_REF template struct hash { public: typedef T* argument_type; typedef std::size_t result_type; public: std::size_t operator()(T* v) const { return sprout::to_hash(v); } }; } //namespace sprout #endif // #ifndef SPROUT_FUNCTIONAL_HASH_HASH_HPP