vs-stl实现中 std::unordered_map计算哈希值:
class unordered_map
: public _Hash<_Umap_traits<_Kty, _Ty,
_Uhash_compare<_Kty, _Hasher, _Keyeq>, _Alloc, false>>
{}
template<class _Traits>
class _Hash
{ // hash table -- list with vector of iterators for quick access
public:
using key_type = typename _Traits::key_type;
using key_compare = typename _Traits::key_compare;
using value_compare = typename _Traits::value_compare;
enum
{ // various constants
_Bucket_size = key_compare::bucket_size,
_Min_buckets = 8, // min_buckets = 2 ^^ N, 0 < N
_Multi = _Traits::_Multi};
using _Mylist = list<typename _Traits::value_type, typename _Traits::allocator_type>; // using value_type = pair<const _Kty, _Ty>;
using _Alnode = typename _Mylist::_Alnode;
using _Alnode_traits = typename _Mylist::_Alnode_traits;
using value_type = typename _Mylist::value_type;
using allocator_type = typename _Mylist::allocator_type;
using size_type = typename _Mylist::size_type;
using difference_type = typename _Mylist::difference_type;
using pointer = typename _Mylist::pointer;
using const_pointer = typename _Mylist::const_pointer;
using reference = value_type&;
using const_reference = const value_type&;
using iterator = conditional_t<is_same_v<key_type, value_type>,
typename _Mylist::const_iterator,
typename _Mylist::iterator>;
using const_iterator = typename _Mylist::const_iterator;
using _Unchecked_iterator = conditional_t<is_same_v<key_type, value_type>,
typename _Mylist::_Unchecked_const_iterator,
typename _Mylist::_Unchecked_iterator>;
using _Unchecked_const_iterator = typename _Mylist::_Unchecked_const_iterator;
using _Aliter = _Rebind_alloc_t<_Alnode, _Unchecked_iterator>;
using _Myvec = vector<_Unchecked_iterator, _Aliter>;
void _Init(size_type _Buckets = _Min_buckets)
{ // initialize hash table with _Buckets buckets, leave list alone
_Vec.reserve(2 * _Buckets); // avoid curdling _Vec if exception occurs
_Vec.assign(2 * _Buckets, _Unchecked_end());
_Mask = _Buckets - 1;
_Maxidx = _Buckets;
}
_Traits _Traitsobj; // traits to customize behavior
_Mylist _List; // list of elements, must initialize before _Vec // 实际的pair<k,v>保存在链表_List里, unordered_map.find/begin/end返回的迭代器其实就是该_List的迭代器
_Myvec _Vec; // vector of list iterators, begin() then end()-1 // _Vec里保存着_List的迭代器, 用于快速查询访问
size_type _Mask; // the key mask
size_type _Maxidx; // current maximum key value
};
size_type _Hashval(const key_type& _Keyval) const
{ // return hash value, masked to current table size
return (_Traitsobj(_Keyval) & _Mask); // size_type _Mask; // the key mask : _Mask = _Buckets - 1;
_Maxidx = _Buckets;
// _Maxidx 桶数; _Mask 桶数 - 1, 用于哈希掩码。_Min_buckets = 8, // min_buckets = 2 ^^ N, 0 < N
}
......
->
template<class _Kty>
struct hash
: _Conditionally_enabled_hash<_Kty, !is_const_v<_Kty> && !is_volatile_v<_Kty>
&& (is_enum_v<_Kty> || is_integral_v<_Kty> || is_pointer_v<_Kty>)>
{ // hash functor primary template (handles enums, integrals, and pointers)
static size_t _Do_hash(const _Kty& _Keyval) noexcept
{ // hash _Keyval to size_t value by pseudorandomizing transform
return (_Hash_representation(_Keyval));
}
};
->
template<class _Kty>
_NODISCARD inline size_t _Hash_representation(const _Kty& _Keyval) noexcept
{ // bitwise hashes the representation of a key
return (_Fnv1a_append_value(_FNV_offset_basis, _Keyval));
}
->
#if defined(_WIN64)
_INLINE_VAR constexpr size_t _FNV_offset_basis = 14695981039346656037ULL;
_INLINE_VAR constexpr size_t _FNV_prime = 1099511628211ULL; // prime: 一个很大的素数
#else /* defined(_WIN64) */
_INLINE_VAR constexpr size_t _FNV_offset_basis = 2166136261U;
_INLINE_VAR constexpr size_t _FNV_prime = 16777619U;
#endif /* defined(_WIN64) */
template<class _Kty>
_NODISCARD inline size_t _Fnv1a_append_value(const size_t _Val, const _Kty& _Keyval) noexcept
{ // accumulate _Keyval into partial FNV-1a hash _Val
static_assert(is_trivial_v<_Kty>, "Only trivial types can be directly hashed.");
return (_Fnv1a_append_bytes(_Val,
&reinterpret_cast<const unsigned char&>(_Keyval), sizeof(_Kty))); // 将值重解释为长度为sizeof(_Kty)的"二进制字符串"
}
->
_NODISCARD inline size_t _Fnv1a_append_bytes(size_t _Val,
const unsigned char * const _First, const size_t _Count) noexcept
{ // accumulate range [_First, _First + _Count) into partial FNV-1a hash _Val
for (size_t _Idx = 0; _Idx < _Count; ++_Idx)
{
_Val ^= static_cast<size_t>(_First[_Idx]); // 异或 1^1=0; 0^0=0; 1^0=1; 0^1=1
_Val *= _FNV_prime; // 再乘以一个很大的素数
}
return (_Val);
}