Skip to content

[libc++] Simplify the implementation of std::hash #140407

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
143 changes: 26 additions & 117 deletions libcxx/include/__functional/hash.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
#include <__type_traits/invoke.h>
#include <__type_traits/is_constructible.h>
#include <__type_traits/is_enum.h>
#include <__type_traits/is_floating_point.h>
#include <__type_traits/is_integral.h>
#include <__type_traits/underlying_type.h>
#include <__utility/pair.h>
#include <__utility/swap.h>
Expand Down Expand Up @@ -345,122 +347,43 @@ struct hash<_Tp*> : public __unary_function<_Tp*, size_t> {
}
};

template <>
struct hash<bool> : public __unary_function<bool, size_t> {
_LIBCPP_HIDE_FROM_ABI size_t operator()(bool __v) const _NOEXCEPT { return static_cast<size_t>(__v); }
};

template <>
struct hash<char> : public __unary_function<char, size_t> {
_LIBCPP_HIDE_FROM_ABI size_t operator()(char __v) const _NOEXCEPT { return static_cast<size_t>(__v); }
};

template <>
struct hash<signed char> : public __unary_function<signed char, size_t> {
_LIBCPP_HIDE_FROM_ABI size_t operator()(signed char __v) const _NOEXCEPT { return static_cast<size_t>(__v); }
};

template <>
struct hash<unsigned char> : public __unary_function<unsigned char, size_t> {
_LIBCPP_HIDE_FROM_ABI size_t operator()(unsigned char __v) const _NOEXCEPT { return static_cast<size_t>(__v); }
};

#if _LIBCPP_HAS_CHAR8_T
template <>
struct hash<char8_t> : public __unary_function<char8_t, size_t> {
_LIBCPP_HIDE_FROM_ABI size_t operator()(char8_t __v) const _NOEXCEPT { return static_cast<size_t>(__v); }
};
#endif // _LIBCPP_HAS_CHAR8_T

template <>
struct hash<char16_t> : public __unary_function<char16_t, size_t> {
_LIBCPP_HIDE_FROM_ABI size_t operator()(char16_t __v) const _NOEXCEPT { return static_cast<size_t>(__v); }
};

template <>
struct hash<char32_t> : public __unary_function<char32_t, size_t> {
_LIBCPP_HIDE_FROM_ABI size_t operator()(char32_t __v) const _NOEXCEPT { return static_cast<size_t>(__v); }
};

#if _LIBCPP_HAS_WIDE_CHARACTERS
template <>
struct hash<wchar_t> : public __unary_function<wchar_t, size_t> {
_LIBCPP_HIDE_FROM_ABI size_t operator()(wchar_t __v) const _NOEXCEPT { return static_cast<size_t>(__v); }
};
#endif // _LIBCPP_HAS_WIDE_CHARACTERS

template <>
struct hash<short> : public __unary_function<short, size_t> {
_LIBCPP_HIDE_FROM_ABI size_t operator()(short __v) const _NOEXCEPT { return static_cast<size_t>(__v); }
};

template <>
struct hash<unsigned short> : public __unary_function<unsigned short, size_t> {
_LIBCPP_HIDE_FROM_ABI size_t operator()(unsigned short __v) const _NOEXCEPT { return static_cast<size_t>(__v); }
template <class _Tp, class = void>
struct __hash_impl {
__hash_impl() = delete;
__hash_impl(__hash_impl const&) = delete;
__hash_impl& operator=(__hash_impl const&) = delete;
};

template <>
struct hash<int> : public __unary_function<int, size_t> {
_LIBCPP_HIDE_FROM_ABI size_t operator()(int __v) const _NOEXCEPT { return static_cast<size_t>(__v); }
};

template <>
struct hash<unsigned int> : public __unary_function<unsigned int, size_t> {
_LIBCPP_HIDE_FROM_ABI size_t operator()(unsigned int __v) const _NOEXCEPT { return static_cast<size_t>(__v); }
};

template <>
struct hash<long> : public __unary_function<long, size_t> {
_LIBCPP_HIDE_FROM_ABI size_t operator()(long __v) const _NOEXCEPT { return static_cast<size_t>(__v); }
};

template <>
struct hash<unsigned long> : public __unary_function<unsigned long, size_t> {
_LIBCPP_HIDE_FROM_ABI size_t operator()(unsigned long __v) const _NOEXCEPT {
static_assert(sizeof(size_t) >= sizeof(unsigned long),
"This would be a terrible hash function on a platform where size_t is smaller than unsigned long");
return static_cast<size_t>(__v);
template <class _Tp>
struct __hash_impl<_Tp, __enable_if_t<is_enum<_Tp>::value> > : __unary_function<_Tp, size_t> {
_LIBCPP_HIDE_FROM_ABI size_t operator()(_Tp __v) const _NOEXCEPT {
using type = __underlying_type_t<_Tp>;
return hash<type>()(static_cast<type>(__v));
}
};

template <>
struct hash<long long> : public __scalar_hash<long long> {};

template <>
struct hash<unsigned long long> : public __scalar_hash<unsigned long long> {};

#if _LIBCPP_HAS_INT128

template <>
struct hash<__int128_t> : public __scalar_hash<__int128_t> {};

template <>
struct hash<__uint128_t> : public __scalar_hash<__uint128_t> {};
template <class _Tp>
struct __hash_impl<_Tp, __enable_if_t<is_integral<_Tp>::value && (sizeof(_Tp) <= sizeof(size_t))> >
: __unary_function<_Tp, size_t> {
_LIBCPP_HIDE_FROM_ABI size_t operator()(_Tp __v) const _NOEXCEPT { return static_cast<size_t>(__v); }
};

#endif
template <class _Tp>
struct __hash_impl<_Tp, __enable_if_t<is_integral<_Tp>::value && (sizeof(_Tp) > sizeof(size_t))> >
: __scalar_hash<_Tp> {};

template <>
struct hash<float> : public __scalar_hash<float> {
_LIBCPP_HIDE_FROM_ABI size_t operator()(float __v) const _NOEXCEPT {
template <class _Tp>
struct __hash_impl<_Tp, __enable_if_t<is_floating_point<_Tp>::value> > : __scalar_hash<_Tp> {
_LIBCPP_HIDE_FROM_ABI size_t operator()(_Tp __v) const _NOEXCEPT {
// -0.0 and 0.0 should return same hash
if (__v == 0.0f)
return 0;
return __scalar_hash<float>::operator()(__v);
}
};

template <>
struct hash<double> : public __scalar_hash<double> {
_LIBCPP_HIDE_FROM_ABI size_t operator()(double __v) const _NOEXCEPT {
// -0.0 and 0.0 should return same hash
if (__v == 0.0)
return 0;
return __scalar_hash<double>::operator()(__v);
return __scalar_hash<_Tp>::operator()(__v);
}
};

template <>
struct hash<long double> : public __scalar_hash<long double> {
struct __hash_impl<long double, void> : __scalar_hash<long double> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
struct __hash_impl<long double, void> : __scalar_hash<long double> {
struct __hash_impl<long double> : __scalar_hash<long double> {

_LIBCPP_HIDE_FROM_ABI size_t operator()(long double __v) const _NOEXCEPT {
// -0.0 and 0.0 should return same hash
if (__v == 0.0L)
Expand Down Expand Up @@ -501,22 +424,8 @@ struct hash<long double> : public __scalar_hash<long double> {
}
};

template <class _Tp, bool = is_enum<_Tp>::value>
struct __enum_hash : public __unary_function<_Tp, size_t> {
_LIBCPP_HIDE_FROM_ABI size_t operator()(_Tp __v) const _NOEXCEPT {
using type = __underlying_type_t<_Tp>;
return hash<type>()(static_cast<type>(__v));
}
};
template <class _Tp>
struct __enum_hash<_Tp, false> {
__enum_hash() = delete;
__enum_hash(__enum_hash const&) = delete;
__enum_hash& operator=(__enum_hash const&) = delete;
};

template <class _Tp>
struct hash : public __enum_hash<_Tp> {};
struct hash : public __hash_impl<_Tp> {};

#if _LIBCPP_STD_VER >= 17

Expand Down
Loading