en	:idprefix: rationale_

en	= Implementation Rationale
zh-hans	= 实现设计依据

en	Closed-addressing Containers
zh-hans	闭寻址容器

en	`boost::unordered_[multi]set` and `boost::unordered_[multi]map` adhere to the standard requirements for unordered associative containers, so the interface was fixed. But there are still some implementation decisions to make. The priorities are conformance to the standard and portability.
zh-hans	`boost::unordered++_[++multi++]++set` 与 `boost::unordered++_[++multi++]++map` 遵循无序关联容器的标准规范，因此其接口是确定的。但在实现层面仍需做出一些决策，其首要考量是标准符合性与跨平台移植性。

en	The http://en.wikipedia.org/wiki/Hash_table[Wikipedia article on hash tables^] has a good summary of the implementation issues for hash tables in general.
zh-hans	关于哈希表的通用实现问题的详细综述，可参阅 http://en.wikipedia.org/wiki/Hash_table[维基百科哈希表条目] 。

en	Data Structure
zh-hans	数据结构

en	By specifying an interface for accessing the buckets of the container the standard pretty much requires that the hash table uses closed addressing.
zh-hans	通过制定用于访问容器桶的接口，该标准实质上要求哈希表必须采用闭寻址方案。

en	It would be conceivable to write a hash table that uses another method. For example, it could use open addressing, and use the lookup chain to act as a bucket but there are some serious problems with this:
zh-hans	理论上完全可以设计采用其他实现方式的哈希表。例如，采用开放寻址法，利用查找链来模拟桶的行为，但这种做法会带来一些严重问题：

en	The standard requires that pointers to elements aren't invalidated, so
zh-hans	该标准要求指向元素的指针不得失效，因此

en	the elements can't be stored in one array, but will need a layer of indirection instead - losing the efficiency and most of the memory gain, the main advantages of open addressing.
zh-hans	元素无法存储在一个连续的数组中，而需要增加一层间接寻址——这将损失开放定址法的主要优势，即效率和大部分内存收益。

en	Local iterators would be very inefficient and may not be able to
zh-hans	局部迭代器的实现将极为低效，且可能无法

en	meet the complexity requirements.
zh-hans	满足复杂度要求。

en	There are also the restrictions on when iterators can be invalidated. Since
zh-hans	此外，标准对迭代器失效的时机也存在限制。由于

en	open addressing degrades badly when there are a high number of collisions the restrictions could prevent a rehash when it's really needed. The maximum load factor could be set to a fairly low value to work around this - but the standard requires that it is initially set to 1.0.
zh-hans	开放寻址法在发生大量冲突时性能会急剧下降，这些限制可能会阻止必要的重新哈希操作。虽然可以通过设置较低的最大负载因子来规避此问题——但标准要求该值初始必须设为 1.0。

en	And since the standard is written with a eye towards closed
zh-hans	由于该标准的制定主要着眼于闭寻址方案，

en	addressing, users will be surprised if the performance doesn't reflect that.
zh-hans	若性能表现不符预期，将会引发用户的困惑。

en	So closed addressing is used.
zh-hans	因此采用闭寻址方式。

en	Number of Buckets
zh-hans	桶数量

en	There are two popular methods for choosing the number of buckets in a hash table. One is to have a prime number of buckets, another is to use a power of 2.
zh-hans	选择哈希表桶数量有两种主流方法：一种是采用质数作为桶的数量，另一种则是使用2的幂次方。

en	Using a prime number of buckets, and choosing a bucket by using the modulus of the hash function's result will usually give a good result. The downside is that the required modulus operation is fairly expensive. This is what the containers used to do in most cases.
zh-hans	使用质数数量的桶，并通过哈希函数结果取模来选择桶，通常能获得良好的分布效果。其缺点在于所需的取模运算开销较大。这是该容器在大多数情况下之前的做法。

en	Using a power of 2 allows for much quicker selection of the bucket to use, but at the expense of losing the upper bits of the hash value. For some specially designed hash functions it is possible to do this and still get a good result but as the containers can take arbitrary hash functions this can't be relied on.
zh-hans	使用2的幂次方可加快桶选择速度，但代价是牺牲哈希值的高位比特。对于一些特殊设计的哈希函数，这样做仍能获得良好效果，但由于容器需要兼容任意哈希函数，因此不能依赖这种方法。

en	To avoid this a transformation could be applied to the hash function, for an example see http://web.archive.org/web/20121102023700/http://www.concentric.net/~Ttwang/tech/inthash.htm[Thomas Wang's article on integer hash functions^]. Unfortunately, a transformation like Wang's requires knowledge of the number of bits in the hash value, so it was only used when `size_t` was 64 bit.
zh-hans	为避免此问题，可对哈希函数施加转换操作（具体示例可参阅 http://web.archive.org/web/20121102023700/http://www.concentric.net/~Ttwang/tech/inthash.htm[Thomas Wang整数哈希函数文章]）。但此类变换需知晓哈希值比特数，故仅在 `size++_++t` 为64位时才会启用。

en	Since release 1.79.0, https://en.wikipedia.org/wiki/Hash_function#Fibonacci_hashing[Fibonacci hashing] is used instead. With this implementation, the bucket number is determined by using `(h * m) >> (w - k)`, where `h` is the hash value, `m` is `2^w` divided by the golden ratio, `w` is the word size (32 or 64), and `2^k` is the number of buckets. This provides a good compromise between speed and distribution.
zh-hans	自1.79.0版起，改用 https://en.wikipedia.org/wiki/Hash_function#Fibonacci_hashing[斐波那契哈希] 。在此实现中，桶编号通过公式 `(h * m) >> (w - k)` 确定：其中 `h` 为哈希值， `m` 为 `2^w` 除以黄金分割比的值， `w` 为字长（32位或64位）， `2^k` 表示桶的数量。此方法在速度和分布均匀性之间实现了较好的平衡。

en	Since release 1.80.0, prime numbers are chosen for the number of buckets in tandem with sophisticated modulo arithmetic. This removes the need for "mixing" the result of the user's hash function as was used for release 1.79.0.
zh-hans	自1.80.0版起，结合精密取模运算选用质数桶量，无需1.79.0版所用的用户哈希函数结果"混合"处理。

en	Open-addresing Containers
zh-hans	开地址容器

en	The C++ standard specification of unordered associative containers impose severe limitations on permissible implementations, the most important being that closed addressing is implicitly assumed. Slightly relaxing this specification opens up the possibility of providing container variations taking full advantage of open-addressing techniques.
zh-hans	C++ 标准中对无序关联容器的规范对允许的实现方式施加了严格的限制，其中最重要的一点是隐式假定使用闭地址法。稍微放宽这一规范，则为提供能够充分利用开放寻址技术的容器变体开辟了可能性。

en	The design of `boost::unordered_flat_set`/`unordered_node_set` and `boost::unordered_flat_map`/`unordered_node_map` has been guided by Peter Dimov's https://pdimov.github.io/articles/unordered_dev_plan.html[Development Plan for Boost.Unordered^]. We discuss here the most relevant principles.
zh-hans	`boost::unordered++_++flat++_++set` / `unordered++_++node++_++set` 及 `boost::unordered++_++flat++_++map` / `unordered++_++node++_++map` 的设计遵循Peter Dimov的 https://pdimov.github.io/articles/unordered_dev_plan.html[Boost.Unordered开发计划] 中提出的指导原则。下文将探讨其中最核心的设计理念。

en	Hash Function
zh-hans	哈希函数

en	Given its rich functionality and cross-platform interoperability, `boost::hash` remains the default hash function of open-addressing containers. As it happens, `boost::hash` for integral and other basic types does not possess the statistical properties required by open addressing; to cope with this, we implement a post-mixing stage:
zh-hans	基于其丰富功能与跨平台互操作性， `boost::hash` 仍是开放寻址容器的默认哈希函数。但由于其对整型等基础类型实现的 boost::hash 缺乏开放寻址所需的统计特性，我们额外增加了后混合处理阶段：

en	{nbsp}{nbsp}{nbsp}{nbsp} _a_ <- _h_ *mul* _C_, + {nbsp}{nbsp}{nbsp}{nbsp} _h_ <- *high*(_a_) *xor* *low*(_a_),
zh-hans	{nbsp}{nbsp}{nbsp}{nbsp} _a_ &lt;- _h_ *mul* _C_, + {nbsp}{nbsp}{nbsp}{nbsp} _h_ &lt;- *high*(_a_) *xor* *low*(_a_),

en	where *mul* is an _extended multiplication_ (128 bits in 64-bit architectures, 64 bits in 32-bit environments), and *high* and *low* are the upper and lower halves of an extended word, respectively. In 64-bit architectures, _C_ is the integer part of 2^64^&#8725;https://en.wikipedia.org/wiki/Golden_ratio[_&phi;_], whereas in 32 bits _C_ = 0xE817FB2Du has been obtained from https://arxiv.org/abs/2001.05304[Steele and Vigna (2021)^].
zh-hans	其中 *mul* 是 _扩展乘法_（64 位架构中为 128 位，32 位环境中为 64 位），*high* 和 *low* 分别表示扩展字的高位部分和低位部分。在 64 位架构中，_C_ 是 2^64^∕https://en.wikipedia.org/wiki/Golden_ratio[_φ_] 的整数部分；而在 32 位架构中，_C_ = 0xE817FB2Du 取自 https://arxiv.org/abs/2001.05304[Steele and Vigna (2021)^]。

en	When using a hash function directly suitable for open addressing, post-mixing can be opted out of via a dedicated `link:../../../../container_hash/doc/html/hash.html#ref_hash_is_avalanchinghash[hash_is_avalanching]` trait. `boost::hash` specializations for string types are marked as avalanching.
zh-hans	当使用直接适合开放定址的哈希函数时，可以通过专用的 `link:../../../../container_hash/doc/html/hash.html#ref_hash_is_avalanching[hash_is_avalanching]` 特征来退出后混合操作。针对字符串类型的 `boost::hash` 特化已被标记为雪崩式哈希。

en	Platform Interoperability
zh-hans	平台互操作性

en	The observable behavior of `boost::unordered_flat_set`/`unordered_node_set` and `boost::unordered_flat_map`/`unordered_node_map` is deterministically identical across different compilers as long as their ``std::size_t``s are the same size and the user-provided hash function and equality predicate are also interoperable —this includes elements being ordered in exactly the same way for the same sequence of operations.
zh-hans	只要不同编译器中的 `std::size_t` 大小相同，并且用户提供的哈希函数和相等谓词也具有互操作性，那么 `boost::unordered_flat_set`/`unordered_node_set` 和 `boost::unordered_flat_map`/`unordered_node_map` 的可观测行为在不同编译器之间是确定相同的——这包括对于相同的操作序列，元素的排列顺序也完全相同。

en	Although the implementation internally uses SIMD technologies, such as https://en.wikipedia.org/wiki/SSE2[SSE2^] and https://en.wikipedia.org/wiki/ARM_architecture_family#Advanced_SIMD_(NEON)[Neon^], when available, this does not affect interoperatility. For instance, the behavior is the same for Visual Studio on an x64-mode Intel CPU with SSE2 and for GCC on an IBM s390x without any supported SIMD technology.
zh-hans	尽管实现内部在可用时会使用 SIMD 技术，例如 https://en.wikipedia.org/wiki/SSE2[SSE2^] 和 https://en.wikipedia.org/wiki/ARM_architecture_family#Advanced_SIMD_(NEON)[Neon^]，但这并不影响互操作性。例如，在带有 SSE2 的 x64 模式 Intel CPU 上使用 Visual Studio 的行为，与在不支持任何 SIMD 技术的 IBM s390x 上使用 GCC 的行为相同。

en	Concurrent Containers
zh-hans	并发容器

en	The same data structure used by Boost.Unordered open-addressing containers has been chosen also as the foundation of `boost::concurrent_flat_set`/`boost::concurrent_node_set` and `boost::concurrent_flat_map`/`boost::concurrent_node_map`:
zh-hans	Boost.Unordered 开放寻址容器所使用的相同数据结构也被选为 `boost::concurrent_flat_set`/`boost::concurrent_node_set` 和 `boost::concurrent_flat_map`/`boost::concurrent_node_map` 的基础：

en	Open-addressing is faster than closed-addressing alternatives, both in non-concurrent and
zh-hans	无论是在非并发环境还是并发环境下，开放寻址都比闭地址方案更快。

en	concurrent scenarios.
zh-hans	并发场景中也是如此。

en	Open-addressing layouts are eminently suitable for concurrent access and modification
zh-hans	开放寻址的内存布局极其适合在最小化锁竞争的条件下进行并发访问与修改。

en	with minimal locking. In particular, the metadata array can be used for implementations of lookup that are lock-free up to the last step of actual element comparison.
zh-hans	通过最小化锁定。特别是，元数据数组可用于实现查找操作，该操作在实际元素比较的最后一步之前都是无锁的。

en	Layout compatibility with Boost.Unordered flat containers allows for
zh-hans	并发容器与 Boost.Unordered 扁平容器具有

en	xref:concurrent.adoc#concurrent_interoperability_with_non_concurrent_containers[fast transfer] of all elements between a concurrent container and its non-concurrent counterpart, and vice versa.
zh-hans	内存布局兼容性，支持其与非并发对应容器之间 xref:concurrent.adoc#concurrent_interoperability_with_non_concurrent_containers[快速双向传输] 所有元素。

en	Hash Function and Platform Interoperability
zh-hans	哈希函数与平台互操作性

en	Concurrent containers make the same decisions and provide the same guarantees as Boost.Unordered open-addressing containers with regards to xref:#rationale_hash_function[hash function defaults] and xref:#rationale_platform_interoperability[platform interoperability].
zh-hans	在 xref:#rationale_hash_function[哈希函数默认值] 和 xref:#rationale_platform_interoperability[平台互操作性] 方面，并发容器与 Boost.Unordered 开放寻址容器做出了相同的决策并提供了相同的保证。