1 | // Copyright 2021-2023 Peter Dimov |
2 | // Distributed under the Boost Software License, Version 1.0. |
3 | // https://www.boost.org/LICENSE_1_0.txt |
4 | |
5 | #ifndef BOOST_HASH_DETAIL_HASH_INTEGRAL_HPP |
6 | #define BOOST_HASH_DETAIL_HASH_INTEGRAL_HPP |
7 | |
8 | #include <boost/container_hash/detail/hash_mix.hpp> |
9 | #include <type_traits> |
10 | #include <cstddef> |
11 | #include <climits> |
12 | |
13 | namespace boost |
14 | { |
15 | namespace hash_detail |
16 | { |
17 | |
18 | // libstdc++ doesn't provide support for __int128 in the standard traits |
19 | |
20 | template<class T> struct is_integral: public std::is_integral<T> |
21 | { |
22 | }; |
23 | |
24 | template<class T> struct is_unsigned: public std::is_unsigned<T> |
25 | { |
26 | }; |
27 | |
28 | template<class T> struct make_unsigned: public std::make_unsigned<T> |
29 | { |
30 | }; |
31 | |
32 | #if defined(__SIZEOF_INT128__) |
33 | |
34 | template<> struct is_integral<__int128_t>: public std::true_type |
35 | { |
36 | }; |
37 | |
38 | template<> struct is_integral<__uint128_t>: public std::true_type |
39 | { |
40 | }; |
41 | |
42 | template<> struct is_unsigned<__int128_t>: public std::false_type |
43 | { |
44 | }; |
45 | |
46 | template<> struct is_unsigned<__uint128_t>: public std::true_type |
47 | { |
48 | }; |
49 | |
50 | template<> struct make_unsigned<__int128_t> |
51 | { |
52 | typedef __uint128_t type; |
53 | }; |
54 | |
55 | template<> struct make_unsigned<__uint128_t> |
56 | { |
57 | typedef __uint128_t type; |
58 | }; |
59 | |
60 | #endif |
61 | |
62 | template<class T, |
63 | bool bigger_than_size_t = (sizeof(T) > sizeof(std::size_t)), |
64 | bool is_unsigned = is_unsigned<T>::value, |
65 | std::size_t size_t_bits = sizeof(std::size_t) * CHAR_BIT, |
66 | std::size_t type_bits = sizeof(T) * CHAR_BIT> |
67 | struct hash_integral_impl; |
68 | |
69 | template<class T, bool is_unsigned, std::size_t size_t_bits, std::size_t type_bits> struct hash_integral_impl<T, false, is_unsigned, size_t_bits, type_bits> |
70 | { |
71 | static std::size_t fn( T v ) |
72 | { |
73 | return static_cast<std::size_t>( v ); |
74 | } |
75 | }; |
76 | |
77 | template<class T, std::size_t size_t_bits, std::size_t type_bits> struct hash_integral_impl<T, true, false, size_t_bits, type_bits> |
78 | { |
79 | static std::size_t fn( T v ) |
80 | { |
81 | typedef typename make_unsigned<T>::type U; |
82 | |
83 | if( v >= 0 ) |
84 | { |
85 | return hash_integral_impl<U>::fn( static_cast<U>( v ) ); |
86 | } |
87 | else |
88 | { |
89 | return ~hash_integral_impl<U>::fn( static_cast<U>( ~static_cast<U>( v ) ) ); |
90 | } |
91 | } |
92 | }; |
93 | |
94 | template<class T> struct hash_integral_impl<T, true, true, 32, 64> |
95 | { |
96 | static std::size_t fn( T v ) |
97 | { |
98 | std::size_t seed = 0; |
99 | |
100 | seed = static_cast<std::size_t>( v >> 32 ) + hash_detail::hash_mix( v: seed ); |
101 | seed = static_cast<std::size_t>( v & 0xFFFFFFFF ) + hash_detail::hash_mix( v: seed ); |
102 | |
103 | return seed; |
104 | } |
105 | }; |
106 | |
107 | template<class T> struct hash_integral_impl<T, true, true, 32, 128> |
108 | { |
109 | static std::size_t fn( T v ) |
110 | { |
111 | std::size_t seed = 0; |
112 | |
113 | seed = static_cast<std::size_t>( v >> 96 ) + hash_detail::hash_mix( v: seed ); |
114 | seed = static_cast<std::size_t>( v >> 64 ) + hash_detail::hash_mix( v: seed ); |
115 | seed = static_cast<std::size_t>( v >> 32 ) + hash_detail::hash_mix( v: seed ); |
116 | seed = static_cast<std::size_t>( v ) + hash_detail::hash_mix( v: seed ); |
117 | |
118 | return seed; |
119 | } |
120 | }; |
121 | |
122 | template<class T> struct hash_integral_impl<T, true, true, 64, 128> |
123 | { |
124 | static std::size_t fn( T v ) |
125 | { |
126 | std::size_t seed = 0; |
127 | |
128 | seed = static_cast<std::size_t>( v >> 64 ) + hash_detail::hash_mix( v: seed ); |
129 | seed = static_cast<std::size_t>( v ) + hash_detail::hash_mix( v: seed ); |
130 | |
131 | return seed; |
132 | } |
133 | }; |
134 | |
135 | } // namespace hash_detail |
136 | |
137 | template <typename T> |
138 | typename std::enable_if<hash_detail::is_integral<T>::value, std::size_t>::type |
139 | hash_value( T v ) |
140 | { |
141 | return hash_detail::hash_integral_impl<T>::fn( v ); |
142 | } |
143 | |
144 | } // namespace boost |
145 | |
146 | #endif // #ifndef BOOST_HASH_DETAIL_HASH_INTEGRAL_HPP |
147 | |