hashbrown 库是 Rust 转写的 Google SwissTable,算法细节可以看 CppCon talk。 它也是 1.36 之后版本的 Rust 标准库 HashTable 实现。
Layout
大体架构上,它实现了一个 RawTable<T>
。不同于 CppCon 中提到的一个 ctrl 一个 bucket 两个向量,它的实现只用了一个 ctrl
指针。
源码中有以下说明:
`self.table.ctrl.cast()` returns pointer that
points here (to the end of `T0`)
∨
[Pad], T_n, ..., T1, T0, |CT0, CT1, ..., CT_n|, CTa_0, CTa_1, ..., CTa_m
\________ ________/
\/
`n = buckets - 1`, i.e. `RawTable::buckets() - 1`
where: T0...T_n - our stored data;
CT0...CT_n - control bytes or metadata for `data`.
CTa_0...CTa_m - additional control bytes, where `m = Group::WIDTH - 1` (so that the search
with loading `Group` bytes from the heap works properly, even if the result
of `h1(hash) & self.bucket_mask` is equal to `self.bucket_mask`). See also
`RawTableInner::set_ctrl` function.
P.S. `h1(hash) & self.bucket_mask` is the same as `hash as usize % self.buckets()` because the number
of buckets is a power of two, and `self.bucket_mask = self.buckets() - 1`.
本质上是 Grouped Vector,让人眼前一亮!这种做法感觉对缓存非常友好。
Allocator
随着 no_std Rust 的日益发展和 Rust Allocator api 还没有 stablize 的矛盾,allocator-api2
诞生了。它类似于 proc-macro2
,在 stable Rust 下会实现自己的 Allocator api 镜像,在 unstable Rust 下会用 Rust 的 Allocator api。
不过大部分情况都不需要一个数据结构单独配置 Allocator 吧;global allocator 其实已经很够用了。