libc++ hashtable 源码简析
本文分析的是 https://github.com/llvm-mirror/libcxx/ 中截止至 2016 年 1 月 30 日最新的 libc++
。
libc++
中, hashtable
的实现为链式结构。 在教科书(Introduction To Algorithm 3rd Edition
)中,介绍的实现是由一个数组作为buckets
,每个数组中存储一个链表。但是 libc++
中,使用一个单向链表贯穿整个 hashtable
,每个 slot
存储的是上一个元素结点的指针,这个元素充当当前链表的头结点。也就是说,每个 slot
的链表存储的实际上是一个左开右闭的区间。在 libc++
中,实现链表普遍使用了一个技巧:有一个基类 xxx_node_base
,这个里面仅存储指向下一个(或者还有上一个)结点的指针,而真正的 xxx_node
里面才有元素。选用 xxx_node_base
作为头结点,这样就减少了单个元素的内存占用。在 hashtable
中,可以找到:
template <class _NodePtr>
struct __hash_node_base
{
typedef __hash_node_base __first_node;
_NodePtr __next_;
_LIBCPP_INLINE_VISIBILITY __hash_node_base() _NOEXCEPT : __next_(nullptr) {}
};
template <class _Tp, class _VoidPtr>
struct __hash_node
: public __hash_node_base
<
typename __rebind_pointer<_VoidPtr, __hash_node<_Tp, _VoidPtr> >::type
>
{
typedef _Tp value_type;
size_t __hash_;
value_type __value_;
};
以下是 hashtable
的关键成员变量:
typedef unique_ptr<__node_pointer[], __bucket_list_deleter> __bucket_list;
// --- Member data begin ---
__bucket_list __bucket_list_;
__compressed_pair<__first_node, __node_allocator> __p1_;
__compressed_pair<size_type, hasher> __p2_;
__compressed_pair<float, key_equal> __p3_;